@yuandc/aica 0.1.55 → 0.1.56

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- import d from"node:fs";import{createRequire as T}from"node:module";import F from"node:os";import L from"node:path";const g=T(import.meta.url);function v(n={}){const e=n.env??process.env,r=n.platform??process.platform,c=n.arch??process.arch,o=n.homeDir??F.homedir(),i=n.execPath??process.execPath,t=r==="win32"?L.win32:L.posix,u=l(e.CODEX_PATH);if(u){const s=C(u,e,r,t);return s?$(s,r,c,t)??s:u}const f=n.bundledCodexLauncher===void 0?O():l(n.bundledCodexLauncher??void 0),a=x([f,C("codex",e,r,t),...k(e,r,o,i,t)]);let P=null;for(const s of a){if(!s||!w(s,r))continue;const b=S(s,r,c,t);if(b)return b;if(!D(s))return s;P??=s}for(const s of M(e,r,o,i,t)){const b=j(s,r,c,t);if(b)return b}return P??"codex"}function O(){try{return g.resolve("@openai/codex/bin/codex.js")}catch{return null}}function k(n,e,r,c,o){const i=e==="win32"?"codex.exe":"codex",t=e==="win32"?"codex.cmd":"codex",u=l(n.npm_config_prefix),f=l(n.APPDATA),a=l(n.LOCALAPPDATA);return x([o.join(r,".codex","packages","standalone","current","bin",i),n.NVM_BIN?o.join(n.NVM_BIN,i):null,n.VOLTA_HOME?o.join(n.VOLTA_HOME,"bin",i):null,u?o.join(u,e==="win32"?"":"bin",t):null,o.join(o.dirname(c),t),e==="win32"&&f?o.join(f,"npm",t):null,e==="win32"&&a?o.join(a,"npm",t):null,e!=="win32"?o.join(r,".local","bin",i):null,e==="darwin"?"/opt/homebrew/bin/codex":null,e!=="win32"?"/usr/local/bin/codex":null,e!=="win32"?"/usr/bin/codex":null])}function M(n,e,r,c,o){const i=x([l(n.npm_config_prefix),l(n.NVM_BIN)?o.dirname(l(n.NVM_BIN)):null,o.dirname(o.dirname(c)),e==="win32"?l(n.APPDATA):null,e==="win32"?l(n.LOCALAPPDATA):null,e!=="win32"?o.join(r,".local"):null,e!=="win32"?"/usr/local":null,e!=="win32"?"/usr":null]);return x(i.flatMap(t=>_(t,e,o)))}function S(n,e,r,c){const o=E(n,e,c);for(const i of o){const t=j(i,e,r,c);if(t)return t}return null}function $(n,e,r,c){for(const o of B(n,c)){const i=j(o,e,r,c);if(i)return i}return null}function E(n,e,r){const c=[];let o=y(n)??n;o=r.dirname(o);for(let i=0;i<8;i+=1){r.basename(o)==="codex"&&r.basename(r.dirname(o))==="@openai"&&c.push(o),c.push(..._(o,e,r));const t=r.dirname(o);if(t===o)break;o=t}return x(c)}function B(n,e){const r=[];let c=e.dirname(y(n)??n);for(let o=0;o<8;o+=1){e.basename(c)==="codex"&&e.basename(e.dirname(c))==="@openai"&&r.push(c);const i=e.dirname(c);if(i===c)break;c=i}return x(r)}function _(n,e,r){return e==="win32"?[r.join(n,"node_modules","@openai","codex")]:[r.join(n,"lib","node_modules","@openai","codex"),r.join(n,"node_modules","@openai","codex")]}function j(n,e,r,c){if(!N(n))return null;const o=`codex-${e}-${r==="x64"?"x64":r}`,i=c.join(n,"node_modules","@openai",o),t=c.dirname(n),u=c.basename(n)==="codex"&&c.basename(t)==="@openai"?c.join(t,o):null;return m(i,e,c)??(u?m(u,e,c):null)??m(n,e,c)}function m(n,e,r,c=0){if(c>8||!N(n))return null;let o;try{o=d.readdirSync(n,{withFileTypes:!0})}catch{return null}const i=e==="win32"?"codex.exe":"codex";for(const t of o){const u=r.join(n,t.name);if(t.isFile()&&t.name.toLowerCase()===i&&w(u,e)&&!D(u))return u}for(const t of o){if(!t.isDirectory())continue;const u=m(r.join(n,t.name),e,r,c+1);if(u)return u}return null}function C(n,e,r,c){if(c.isAbsolute(n)||n.includes("/")||n.includes("\\"))return w(n,r)?n:null;const o=r==="win32"?n.includes(".")?[""]:(e.PATHEXT||".EXE;.CMD;.BAT;.COM").split(";").map(t=>t.toLowerCase()):[""],i=r==="win32"?";":":";for(const t of(e.PATH||"").split(i)){const u=l(t);if(u)for(const f of o){const a=c.join(u,`${n}${f}`);if(w(a,r))return a}}return null}function w(n,e){try{return d.accessSync(n,e==="win32"?d.constants.F_OK:d.constants.X_OK),d.statSync(n).isFile()}catch{return!1}}function N(n){try{return d.statSync(n).isDirectory()}catch{return!1}}function D(n){const e=y(n)??n;if(/\.(?:js|mjs|cjs|cmd|bat)$/i.test(e))return!0;try{const r=d.readFileSync(e,{encoding:"utf8",flag:"r"}).slice(0,256);return/^#!.*\bnode\b/m.test(r)}catch{return!1}}function y(n){try{return d.realpathSync(n)}catch{return null}}function l(n){return n?.trim().replace(/^(?:"(.*)"|'(.*)')$/,"$1$2")||null}function x(n){return[...new Set(n.filter(e=>e!=null))]}export{v as resolveCodexPath};
1
+ import d from"node:fs";import{createRequire as T}from"node:module";import{isSea as F}from"node:sea";import g from"node:os";import L from"node:path";const O=T(F()?process.execPath:import.meta.url);function q(n={}){const e=n.env??process.env,r=n.platform??process.platform,c=n.arch??process.arch,o=n.homeDir??g.homedir(),i=n.execPath??process.execPath,t=r==="win32"?L.win32:L.posix,u=l(e.CODEX_PATH);if(u){const s=C(u,e,r,t);return s?E(s,r,c,t)??s:u}const f=n.bundledCodexLauncher===void 0?S():l(n.bundledCodexLauncher??void 0),a=x([f,C("codex",e,r,t),...k(e,r,o,i,t)]);let y=null;for(const s of a){if(!s||!w(s,r))continue;const m=$(s,r,c,t);if(m)return m;if(!D(s))return s;y??=s}for(const s of M(e,r,o,i,t)){const m=j(s,r,c,t);if(m)return m}return y??"codex"}function S(){try{return O.resolve("@openai/codex/bin/codex.js")}catch{return null}}function k(n,e,r,c,o){const i=e==="win32"?"codex.exe":"codex",t=e==="win32"?"codex.cmd":"codex",u=l(n.npm_config_prefix),f=l(n.APPDATA),a=l(n.LOCALAPPDATA);return x([o.join(r,".codex","packages","standalone","current","bin",i),n.NVM_BIN?o.join(n.NVM_BIN,i):null,n.VOLTA_HOME?o.join(n.VOLTA_HOME,"bin",i):null,u?o.join(u,e==="win32"?"":"bin",t):null,o.join(o.dirname(c),t),e==="win32"&&f?o.join(f,"npm",t):null,e==="win32"&&a?o.join(a,"npm",t):null,e!=="win32"?o.join(r,".local","bin",i):null,e==="darwin"?"/opt/homebrew/bin/codex":null,e!=="win32"?"/usr/local/bin/codex":null,e!=="win32"?"/usr/bin/codex":null])}function M(n,e,r,c,o){const i=x([l(n.npm_config_prefix),l(n.NVM_BIN)?o.dirname(l(n.NVM_BIN)):null,o.dirname(o.dirname(c)),e==="win32"?l(n.APPDATA):null,e==="win32"?l(n.LOCALAPPDATA):null,e!=="win32"?o.join(r,".local"):null,e!=="win32"?"/usr/local":null,e!=="win32"?"/usr":null]);return x(i.flatMap(t=>_(t,e,o)))}function $(n,e,r,c){const o=B(n,e,c);for(const i of o){const t=j(i,e,r,c);if(t)return t}return null}function E(n,e,r,c){for(const o of R(n,c)){const i=j(o,e,r,c);if(i)return i}return null}function B(n,e,r){const c=[];let o=P(n)??n;o=r.dirname(o);for(let i=0;i<8;i+=1){r.basename(o)==="codex"&&r.basename(r.dirname(o))==="@openai"&&c.push(o),c.push(..._(o,e,r));const t=r.dirname(o);if(t===o)break;o=t}return x(c)}function R(n,e){const r=[];let c=e.dirname(P(n)??n);for(let o=0;o<8;o+=1){e.basename(c)==="codex"&&e.basename(e.dirname(c))==="@openai"&&r.push(c);const i=e.dirname(c);if(i===c)break;c=i}return x(r)}function _(n,e,r){return e==="win32"?[r.join(n,"node_modules","@openai","codex")]:[r.join(n,"lib","node_modules","@openai","codex"),r.join(n,"node_modules","@openai","codex")]}function j(n,e,r,c){if(!N(n))return null;const o=`codex-${e}-${r==="x64"?"x64":r}`,i=c.join(n,"node_modules","@openai",o),t=c.dirname(n),u=c.basename(n)==="codex"&&c.basename(t)==="@openai"?c.join(t,o):null;return b(i,e,c)??(u?b(u,e,c):null)??b(n,e,c)}function b(n,e,r,c=0){if(c>8||!N(n))return null;let o;try{o=d.readdirSync(n,{withFileTypes:!0})}catch{return null}const i=e==="win32"?"codex.exe":"codex";for(const t of o){const u=r.join(n,t.name);if(t.isFile()&&t.name.toLowerCase()===i&&w(u,e)&&!D(u))return u}for(const t of o){if(!t.isDirectory())continue;const u=b(r.join(n,t.name),e,r,c+1);if(u)return u}return null}function C(n,e,r,c){if(c.isAbsolute(n)||n.includes("/")||n.includes("\\"))return w(n,r)?n:null;const o=r==="win32"?n.includes(".")?[""]:(e.PATHEXT||".EXE;.CMD;.BAT;.COM").split(";").map(t=>t.toLowerCase()):[""],i=r==="win32"?";":":";for(const t of(e.PATH||"").split(i)){const u=l(t);if(u)for(const f of o){const a=c.join(u,`${n}${f}`);if(w(a,r))return a}}return null}function w(n,e){try{return d.accessSync(n,e==="win32"?d.constants.F_OK:d.constants.X_OK),d.statSync(n).isFile()}catch{return!1}}function N(n){try{return d.statSync(n).isDirectory()}catch{return!1}}function D(n){const e=P(n)??n;if(/\.(?:js|mjs|cjs|cmd|bat)$/i.test(e))return!0;try{const r=d.readFileSync(e,{encoding:"utf8",flag:"r"}).slice(0,256);return/^#!.*\bnode\b/m.test(r)}catch{return!1}}function P(n){try{return d.realpathSync(n)}catch{return null}}function l(n){return n?.trim().replace(/^(?:"(.*)"|'(.*)')$/,"$1$2")||null}function x(n){return[...new Set(n.filter(e=>e!=null))]}export{q as resolveCodexPath};
@@ -1 +1 @@
1
- function u(t){const n=i(t),r=i(n.turn);return{threadId:e(n,"threadId")||null,turnId:e(n,"turnId")||e(r,"id")||null}}function d(t,n,r){const o=u(t);return!(o.threadId&&n&&o.threadId!==n||o.turnId&&r&&o.turnId!==r)}function i(t){return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}function e(t,n){const r=t[n];return typeof r=="string"?r:""}export{d as codexNotificationBelongsToCurrentTurn,u as codexNotificationRouting};
1
+ const d=new Set(["thread/status/changed","thread/name/updated","thread/tokenUsage/updated","thread/archived","thread/unarchived","account/updated","account/rateLimits/updated"]);function i(t){return d.has(t)}function u(t){const e=a(t),n=a(e.turn);return{threadId:o(e,"threadId")||null,turnId:o(e,"turnId")||o(n,"id")||null}}function c(t,e,n){const r=u(t);return!(r.threadId&&e&&r.threadId!==e||r.turnId&&n&&r.turnId!==n)}function a(t){return t&&typeof t=="object"&&!Array.isArray(t)?t:{}}function o(t,e){const n=t[e];return typeof n=="string"?n:""}export{c as codexNotificationBelongsToCurrentTurn,i as codexNotificationIsSubtaskMetadata,u as codexNotificationRouting};
@@ -1 +1 @@
1
- import{randomUUID as g}from"node:crypto";class T{runs=new Map;starts=new Set;closedTurns=new Map;pending=new Map;reset(){this.runs.clear(),this.starts.clear(),this.closedTurns.clear(),this.pending.clear()}get(s){return this.runs.get(s)?.snapshot}hasStart(s,n){return this.starts.has(`${s}:${n}`)}activeThreadIds(){return[...this.runs].filter(([,s])=>c(s.snapshot.state)).map(([s])=>s)}start(s,n,t,o={}){const u=`${s.sourceThreadId}:${n}`;if(this.starts.has(u))return;this.starts.add(u);const a=this.runs.get(s.sourceThreadId);if(a&&c(a.snapshot.state)){this.change(a,{...o,state:a.snapshot.state==="running"?"running":t});return}const e={route:{...s},generation:(a?.generation??0)+1,snapshot:{...o,runId:g(),state:t,startedAtMs:Date.now()}};this.runs.set(s.sourceThreadId,e),this.pending.set(e.snapshot.runId,e)}observeState(s,n){let t=this.runs.get(s.sourceThreadId);if(!t)t={route:{...s},generation:1,snapshot:{runId:g(),state:"unknown"}},this.runs.set(s.sourceThreadId,t),this.pending.set(t.snapshot.runId,t);else if(i(t.snapshot.state))return;if(!(t.snapshot.state==="running"&&n==="pending")){if(t.generation>1&&i(n)){this.change(t,{state:"unknown",outputIncomplete:!0,reason:"收到无法确认执行归属的结束通知"});return}this.change(t,{state:n,...i(n)?{endedAtMs:Date.now()}:{}})}}accept(s,n,t){const o=s.sourceThreadId,u=l(t.turn),a=h(t.turnId)||h(u.id);if(a&&this.closedTurns.get(o)?.has(a))return!1;let e=this.runs.get(o);if(n==="turn/started"&&a&&(e?.snapshot.sourceTurnId&&e.snapshot.sourceTurnId!==a&&c(e.snapshot.state)&&(this.closeTurn(o,e.snapshot.sourceTurnId),this.change(e,{state:"unknown",outputIncomplete:!0,reason:"新执行开始前未收到旧执行结束事件"})),this.start(s,`turn:${a}`,"running"),e=this.runs.get(o)),e||(this.observeState(s,"unknown"),e=this.runs.get(o)),i(e.snapshot.state)||a&&e.snapshot.sourceTurnId&&a!==e.snapshot.sourceTurnId)return!1;if(e.generation>1&&!e.snapshot.sourceTurnId&&n!=="turn/started")return this.change(e,{outputIncomplete:!0,reason:"部分事件缺少新执行归属,已隔离"}),!1;if(!a&&e.generation>1&&n!=="turn/started")return this.change(e,{outputIncomplete:!0,reason:"部分事件缺少新执行归属,已隔离"}),!1;if(a&&!e.snapshot.sourceTurnId&&this.change(e,{sourceTurnId:a}),n==="turn/completed"){const d=h(u.status).toLowerCase(),p=d==="failed"?"failed":["interrupted","cancelled","canceled"].includes(d)?"interrupted":d==="completed"?"completed":"unknown";this.change(e,{state:p,...p==="unknown"?{outputIncomplete:!0,reason:"结束通知未提供可识别的执行结果"}:{endedAtMs:Date.now()}}),a&&this.closeTurn(o,a)}return!0}progress(s,n){const t=this.runs.get(s);!t||i(t.snapshot.state)||(t.snapshot={...t.snapshot,lastProgressAtMs:Date.now(),...n?{lastAction:n}:{}})}action(s,n){const t=this.runs.get(s);t&&!i(t.snapshot.state)&&(t.snapshot={...t.snapshot,lastAction:n})}loseObservation(s){for(const n of this.runs.values())c(n.snapshot.state)&&this.change(n,{state:"unknown",outputIncomplete:!0,reason:s})}drainUpdates(){const s=[...this.pending.values()].map(({route:n,snapshot:t})=>f({sessionUpdate:"tool_call_update",toolCallId:`run.${t.runId}`,kind:"other",title:"子代理执行状态",status:t.state==="failed"?"failed":t.state==="interrupted"?"cancelled":t.state==="completed"?"completed":"in_progress",_meta:{aca:{subtaskLifecycle:!0,processKind:"subtask"}}},n,t.sourceTurnId||null,t));return this.pending.clear(),s}closeTurn(s,n){const t=this.closedTurns.get(s)??new Set;t.add(n),this.closedTurns.set(s,t)}change(s,n){const t={...s.snapshot,...n};JSON.stringify(t)!==JSON.stringify(s.snapshot)&&(i(t.state)&&t.sourceTurnId&&this.closeTurn(s.route.sourceThreadId,t.sourceTurnId),s.snapshot=t,this.pending.set(t.runId,s))}}function f(r,s,n,t){const o={...r},u=t?.runId||s.sourceThreadId;["tool_call","tool_call_update"].includes(String(r.sessionUpdate))&&r.toolCallId&&(o.toolCallId=`subtask.${u}.${r.toolCallId}`),["plan","plan_update","plan_removed"].includes(String(r.sessionUpdate))&&(o.planId=`subtask.${u}.${r.planId||r.plan_id||r.id||"current"}`,delete o.plan_id);const a=l(r._meta);return o._meta={...a,aca:{...l(a.aca),subtask:{...s,sourceTurnId:n,...t?{runId:t.runId,run:{...t}}:{}}}},o}function i(r){return["completed","failed","interrupted"].includes(r)}function c(r){return r==="pending"||r==="running"}function l(r){return r&&typeof r=="object"?r:{}}function h(r){return typeof r=="string"?r:""}export{T as CodexSubtaskExecutions,f as decorateSubtaskUpdate};
1
+ import{randomUUID as f}from"node:crypto";import{codexNotificationIsSubtaskMetadata as g}from"./notification-routing.js";class m{runs=new Map;starts=new Set;closedTurns=new Map;pending=new Map;reset(){this.runs.clear(),this.starts.clear(),this.closedTurns.clear(),this.pending.clear()}get(s){return this.runs.get(s)?.snapshot}hasStart(s,n){return this.starts.has(`${s}:${n}`)}activeThreadIds(){return[...this.runs].filter(([,s])=>d(s.snapshot.state)).map(([s])=>s)}start(s,n,t,i={}){const o=`${s.sourceThreadId}:${n}`;if(this.starts.has(o))return;this.starts.add(o);const a=this.runs.get(s.sourceThreadId);if(a&&d(a.snapshot.state)){this.change(a,{...i,state:a.snapshot.state==="running"?"running":t});return}const e={route:{...s},generation:(a?.generation??0)+1,snapshot:{...i,runId:f(),state:t,startedAtMs:Date.now()}};this.runs.set(s.sourceThreadId,e),this.pending.set(e.snapshot.runId,e)}observeState(s,n){let t=this.runs.get(s.sourceThreadId);if(!t)t={route:{...s},generation:1,snapshot:{runId:f(),state:"unknown"}},this.runs.set(s.sourceThreadId,t),this.pending.set(t.snapshot.runId,t);else if(u(t.snapshot.state))return;if(!(t.snapshot.state==="running"&&n==="pending")){if(t.generation>1&&u(n)){this.change(t,{state:"unknown",reason:t.outputRiskReason??"收到无法确认执行归属的结束通知"});return}this.change(t,{state:n,...u(n)?{endedAtMs:Date.now()}:{}})}}accept(s,n,t){if(g(n))return!1;const i=s.sourceThreadId,o=h(t.turn),a=p(t.turnId)||p(o.id);if(a&&this.closedTurns.get(i)?.has(a))return!1;let e=this.runs.get(i);if(n==="turn/started"&&a&&(e?.snapshot.sourceTurnId&&e.snapshot.sourceTurnId!==a&&d(e.snapshot.state)&&(this.closeTurn(i,e.snapshot.sourceTurnId),this.markOutputRisk(e,"新执行开始前未收到旧执行结束事件","unknown")),this.start(s,`turn:${a}`,"running"),e=this.runs.get(i)),e||(this.observeState(s,"unknown"),e=this.runs.get(i)),u(e.snapshot.state)||a&&e.snapshot.sourceTurnId&&a!==e.snapshot.sourceTurnId)return!1;if(e.generation>1&&!e.snapshot.sourceTurnId&&n!=="turn/started")return this.markOutputRisk(e,`部分事件缺少新执行归属,已隔离(${n.slice(0,120)})`),!1;if(!a&&e.generation>1&&n!=="turn/started")return this.markOutputRisk(e,`部分事件缺少新执行归属,已隔离(${n.slice(0,120)})`),!1;if(a&&!e.snapshot.sourceTurnId&&this.change(e,{sourceTurnId:a}),n==="turn/completed"){const c=p(o.status).toLowerCase(),l=c==="failed"?"failed":["interrupted","cancelled","canceled"].includes(c)?"interrupted":c==="completed"?"completed":"unknown";l==="unknown"?this.markOutputRisk(e,"结束通知未提供可识别的执行结果",l):this.change(e,{state:l,endedAtMs:Date.now(),reason:e.outputRiskReason}),a&&this.closeTurn(i,a)}return!0}progress(s,n){const t=this.runs.get(s);!t||u(t.snapshot.state)||(t.snapshot={...t.snapshot,lastProgressAtMs:Date.now(),...n?{lastAction:n}:{}})}action(s,n){const t=this.runs.get(s);t&&!u(t.snapshot.state)&&(t.snapshot={...t.snapshot,lastAction:n})}loseObservation(s){for(const n of this.runs.values())(d(n.snapshot.state)||n.snapshot.state==="unknown"&&n.snapshot.startedAtMs!==void 0)&&this.markOutputRisk(n,s,"unknown")}drainUpdates(){const s=[...this.pending.values()].map(({route:n,snapshot:t})=>I({sessionUpdate:"tool_call_update",toolCallId:`run.${t.runId}`,kind:"other",title:"子代理执行状态",status:t.state==="failed"?"failed":t.state==="interrupted"?"cancelled":t.state==="completed"?"completed":"in_progress",_meta:{aca:{subtaskLifecycle:!0,processKind:"subtask"}}},n,t.sourceTurnId||null,t));return this.pending.clear(),s}markOutputRisk(s,n,t){s.outputRiskReason??=n,this.change(s,{outputIncomplete:!0,reason:s.outputRiskReason,...t?{state:t}:{}})}closeTurn(s,n){const t=this.closedTurns.get(s)??new Set;t.add(n),this.closedTurns.set(s,t)}change(s,n){const t={...s.snapshot,...n};JSON.stringify(t)!==JSON.stringify(s.snapshot)&&(u(t.state)&&t.sourceTurnId&&this.closeTurn(s.route.sourceThreadId,t.sourceTurnId),s.snapshot=t,this.pending.set(t.runId,s))}}function I(r,s,n,t){const i={...r},o=t?.runId||s.sourceThreadId;["tool_call","tool_call_update"].includes(String(r.sessionUpdate))&&r.toolCallId&&(i.toolCallId=`subtask.${o}.${r.toolCallId}`),["plan","plan_update","plan_removed"].includes(String(r.sessionUpdate))&&(i.planId=`subtask.${o}.${r.planId||r.plan_id||r.id||"current"}`,delete i.plan_id);const a=h(r._meta);return i._meta={...a,aca:{...h(a.aca),subtask:{...s,sourceTurnId:n,...t?{runId:t.runId,run:{...t}}:{}}}},i}function u(r){return["completed","failed","interrupted"].includes(r)}function d(r){return r==="pending"||r==="running"}function h(r){return r&&typeof r=="object"?r:{}}function p(r){return typeof r=="string"?r:""}export{m as CodexSubtaskExecutions,I as decorateSubtaskUpdate};
@@ -1 +1 @@
1
- import{Command as D}from"commander";import _ from"node:fs";import k from"node:os";import p from"node:path";import i from"node:process";import{randomUUID as x}from"node:crypto";import{Logger as W}from"../core/logger.js";import{loadCredentials as j,saveApiKeyCredential as N}from"../core/auth.js";import{getRuntimeStatePath as O}from"../core/paths.js";import{writeJsonFile as L}from"../core/fs.js";import{HEARTBEAT_INTERVAL_MS as M,startHeartbeatLoop as U}from"../core/heartbeat.js";import{startJobWorkerLoop as F}from"../core/job-worker.js";import{startFileTransferWorkerLoop as H}from"../core/file-transfer-worker.js";import{startMachineFilesystemWorkerLoop as K}from"../core/machine-filesystem-worker.js";import{cleanupOrphanedAcpProcesses as V}from"../core/acp-orphan-cleanup.js";import{defaultAcpRuntimePool as S}from"../acp/client/acp-runtime-pool.js";import{isProcessAlive as u,readPidFile as h,writePidFile as B,removePidFile as y}from"../core/process.js";import{applyRuntimePathOptions as C}from"../core/runtime-options.js";import{loadAcaConfig as P,updateAcaConfig as b}from"../core/aca-config.js";import{acaServerRequest as G}from"../core/aca-server-client.js";import{restoreProjectsAfterLogin as J}from"../core/project-recovery.js";import{syncCodexProviderRuntimeConfig as q}from"../core/codex-provider-runtime-config.js";import{ACA_WORKER_INSTANCE_ENV as E,ACA_WORKER_PID_ENV as z,ACA_WORKER_START_TICKS_ENV as Q,readProcessStartTicks as X}from"../core/process-identity.js";import{printStartTips as Y,spawnDaemon as Z}from"./daemon.js";function Re(){return new D("start").description("Start agent service in native mode").option("--aica-home <path>","Runtime home directory (defaults to ~/.aica or AICA_HOME)").option("--aica-config <path>","Config file path (defaults to <aica-home>/config.json)").option("--aca-home <path>","Deprecated alias for --aica-home").option("--aca-config <path>","Deprecated alias for --aica-config").option("--server <url>","ACA Server URL override").option("--machine-id <id>","Machine ID override for this runtime").option("--machine-name <name>","Machine name to register (defaults to hostname)").option("--cli-types <types...>","Specify CLI types to register, `claude` or `codex`").option("--debug","enable debug output").option("--heartbeat-log","output current timestamp every 5 seconds").option("--auth <api-key>","Use a CLI API key for non-interactive authentication").option("--token <enrollment-token>","Use a one-time Web-generated token to register this machine").option("-b, --background","在后台启动 Worker").action(async e=>{if(e.background){await ee(e);return}await ie(e)})}async function ee(e){C(e);const n=h();if(n&&u(n))throw new Error(`Worker 已在后台运行,PID ${n}。`);n&&y();const o=Z(te());if(o.unref(),!o.pid)throw new Error("后台 Worker 启动失败:未获得进程 PID。");if(!await re(o.pid,3e3)&&!u(o.pid))throw new Error(`后台 Worker 启动失败,请检查 ${p.join(i.env.AICA_HOME||i.env.ACA_HOME||p.join(k.homedir(),".aica"),"logs")}。`);console.log(`Worker 已在后台启动,PID ${o.pid}。`),Y()}function te(){const e=i.argv.findIndex((n,o)=>o>=2&&n==="start");return e<0?[]:i.argv.slice(e+1).filter(n=>n!=="--background"&&n!=="-b")}async function re(e,n){const o=Date.now();for(;Date.now()-o<n;){if(h()===e)return!0;if(!u(e))return!1;await new Promise(t=>setTimeout(t,50))}return h()===e}async function ie(e){C(e);const n=i.env[E]||x(),o=X(i.pid)||"";i.env[E]=n,i.env[z]=String(i.pid),i.env[Q]=o;const t=new W("start",e.debug?"debug":"info"),$=P(),g={...e.server?.trim()?{serverUrl:e.server.trim()}:{},...e.machineId?{machineId:e.machineId.trim()}:{},...e.machineName?{machineName:e.machineName.trim()}:{}};let s=Object.keys(g).length>0?b(g):$;const m=e.machineName?.trim()||s.machineName||k.hostname();if(e.token?.trim()){const r=await G("POST","/api/auth/machine-enroll",{token:e.token.trim(),machineId:s.machineId,machineName:m},{serverUrl:s.serverUrl});s=b({machineId:r.machineId,machineName:m,token:r.token,username:r.username}),t.info(`Machine enrollment completed for user ${r.username}`);try{const a=await J();a.restored>0&&t.info(`restored ${a.restored} local project(s) after machine enrollment`),a.unavailable>0&&t.warn(`skipped ${a.unavailable} unavailable project path(s) during machine enrollment recovery`),s=P()}catch(a){t.warn(`project recovery after machine enrollment failed: ${a instanceof Error?a.message:String(a)}`)}}const R=e.auth?N(e.auth,m):j();B(i.pid),T({pid:i.pid,workerInstanceId:n,workerStartTicks:o,phase:"running",startupStage:"local-compatible",machineId:s.machineId||R?.machine?.machineId||"local-machine",machineName:m,cliTypes:e.cliTypes??ne(),startedAt:new Date().toISOString(),heartbeatIntervalMs:M,issues:[{severity:"info",message:"aca is running in aca-server compatibility mode; ACP execution happens on this machine."}]}),t.info(`Starting aca local-compatible service on machine ${m}`),t.info(`PID ${i.pid}`);const f=await V();f.terminated>0&&t.warn(`terminated ${f.terminated} orphaned ACP process(es): ${f.pids.join(",")}`),q().then(r=>t.info(r?`Codex Provider runtime config loaded revision=${r.revision}`:"Codex Provider runtime config is not configured")).catch(r=>t.warn(`Codex Provider runtime config sync failed: ${r instanceof Error?r.message:String(r)}`));let v=!1,l,w,I,A;const d=async r=>{if(v)return;v=!0,t.info("Shutting down"),l&&clearInterval(l),I?.stop(),A?.stop(),await w?.stop().catch(c=>t.warn(`job worker shutdown failed: ${c instanceof Error?c.message:String(c)}`));const a=S.stats();await S.disposeAll().catch(c=>t.warn(`ACP runtime shutdown failed: ${c instanceof Error?c.message:String(c)}`)),t.info(`ACP runtimes stopped total=${a.total} inUse=${a.inUse} idle=${a.idle}`),T({pid:i.pid,phase:"stopped",stoppedAt:new Date().toISOString(),issues:[]}),y(),i.exit(r)};i.once("SIGINT",()=>{d(130)}),i.once("SIGTERM",()=>{d(0)}),i.once("uncaughtException",r=>{t.error(`uncaught exception: ${r.stack||r.message}`),d(1)}),i.once("unhandledRejection",r=>{const a=r instanceof Error?r.stack||r.message:String(r);t.error(`unhandled rejection: ${a}`),d(1)}),e.heartbeatLog&&setInterval(()=>t.info(`heartbeat: ${new Date().toISOString()}`),5e3),l=U(t),w=F(t),I=H(t),A=K(t),await new Promise(()=>{})}function ne(){return["codex","claude"].filter(e=>oe(e))}function oe(e){const n=i.env.PATH||"";for(const o of n.split(":"))try{if(o&&_.existsSync(p.join(o,e)))return!0}catch{}return!1}function T(e){L(O(),e)}export{Re as createStartCommand};
1
+ import{Command as D}from"commander";import _ from"node:fs";import S from"node:os";import p from"node:path";import i from"node:process";import{randomUUID as x}from"node:crypto";import{Logger as j}from"../core/logger.js";import{loadCredentials as N,saveApiKeyCredential as O}from"../core/auth.js";import{getRuntimeStatePath as L}from"../core/paths.js";import{writeJsonFile as M}from"../core/fs.js";import{HEARTBEAT_INTERVAL_MS as U,startHeartbeatLoop as F}from"../core/heartbeat.js";import{startJobWorkerLoop as H}from"../core/job-worker.js";import{startFileTransferWorkerLoop as K}from"../core/file-transfer-worker.js";import{startTerminalWorker as V}from"../core/terminal/worker.js";import{startMachineFilesystemWorkerLoop as B}from"../core/machine-filesystem-worker.js";import{cleanupOrphanedAcpProcesses as G}from"../core/acp-orphan-cleanup.js";import{defaultAcpRuntimePool as y}from"../acp/client/acp-runtime-pool.js";import{isProcessAlive as u,readPidFile as h,writePidFile as J,removePidFile as C}from"../core/process.js";import{applyRuntimePathOptions as P}from"../core/runtime-options.js";import{loadAcaConfig as b,updateAcaConfig as E}from"../core/aca-config.js";import{acaServerRequest as q}from"../core/aca-server-client.js";import{restoreProjectsAfterLogin as z}from"../core/project-recovery.js";import{syncCodexProviderRuntimeConfig as Q}from"../core/codex-provider-runtime-config.js";import{ACA_WORKER_INSTANCE_ENV as T,ACA_WORKER_PID_ENV as X,ACA_WORKER_START_TICKS_ENV as Y,readProcessStartTicks as Z}from"../core/process-identity.js";import{printStartTips as ee,spawnDaemon as te}from"./daemon.js";function _e(){return new D("start").description("Start agent service in native mode").option("--aica-home <path>","Runtime home directory (defaults to ~/.aica or AICA_HOME)").option("--aica-config <path>","Config file path (defaults to <aica-home>/config.json)").option("--aca-home <path>","Deprecated alias for --aica-home").option("--aca-config <path>","Deprecated alias for --aica-config").option("--server <url>","ACA Server URL override").option("--machine-id <id>","Machine ID override for this runtime").option("--machine-name <name>","Machine name to register (defaults to hostname)").option("--cli-types <types...>","Specify CLI types to register, `claude` or `codex`").option("--debug","enable debug output").option("--heartbeat-log","output current timestamp every 5 seconds").option("--auth <api-key>","Use a CLI API key for non-interactive authentication").option("--token <enrollment-token>","Use a one-time Web-generated token to register this machine").option("-b, --background","在后台启动 Worker").action(async e=>{if(e.background){await re(e);return}await ne(e)})}async function re(e){P(e);const o=h();if(o&&u(o))throw new Error(`Worker 已在后台运行,PID ${o}。`);o&&C();const n=te(ie());if(n.unref(),!n.pid)throw new Error("后台 Worker 启动失败:未获得进程 PID。");if(!await oe(n.pid,3e3)&&!u(n.pid))throw new Error(`后台 Worker 启动失败,请检查 ${p.join(i.env.AICA_HOME||i.env.ACA_HOME||p.join(S.homedir(),".aica"),"logs")}。`);console.log(`Worker 已在后台启动,PID ${n.pid}。`),ee()}function ie(){const e=i.argv.findIndex((o,n)=>n>=2&&o==="start");return e<0?[]:i.argv.slice(e+1).filter(o=>o!=="--background"&&o!=="-b")}async function oe(e,o){const n=Date.now();for(;Date.now()-n<o;){if(h()===e)return!0;if(!u(e))return!1;await new Promise(t=>setTimeout(t,50))}return h()===e}async function ne(e){P(e);const o=i.env[T]||x(),n=Z(i.pid)||"";i.env[T]=o,i.env[X]=String(i.pid),i.env[Y]=n;const t=new j("start",e.debug?"debug":"info"),R=b(),g={...e.server?.trim()?{serverUrl:e.server.trim()}:{},...e.machineId?{machineId:e.machineId.trim()}:{},...e.machineName?{machineName:e.machineName.trim()}:{}};let s=Object.keys(g).length>0?E(g):R;const m=e.machineName?.trim()||s.machineName||S.hostname();if(e.token?.trim()){const r=await q("POST","/api/auth/machine-enroll",{token:e.token.trim(),machineId:s.machineId,machineName:m},{serverUrl:s.serverUrl});s=E({machineId:r.machineId,machineName:m,token:r.token,username:r.username}),t.info(`Machine enrollment completed for user ${r.username}`);try{const a=await z();a.restored>0&&t.info(`restored ${a.restored} local project(s) after machine enrollment`),a.unavailable>0&&t.warn(`skipped ${a.unavailable} unavailable project path(s) during machine enrollment recovery`),s=b()}catch(a){t.warn(`project recovery after machine enrollment failed: ${a instanceof Error?a.message:String(a)}`)}}const W=e.auth?O(e.auth,m):N();J(i.pid),$({pid:i.pid,workerInstanceId:o,workerStartTicks:n,phase:"running",startupStage:"local-compatible",machineId:s.machineId||W?.machine?.machineId||"local-machine",machineName:m,cliTypes:e.cliTypes??ae(),startedAt:new Date().toISOString(),heartbeatIntervalMs:U,issues:[{severity:"info",message:"aca is running in aca-server compatibility mode; ACP execution happens on this machine."}]}),t.info(`Starting aca local-compatible service on machine ${m}`),t.info(`PID ${i.pid}`);const l=await G();l.terminated>0&&t.warn(`terminated ${l.terminated} orphaned ACP process(es): ${l.pids.join(",")}`),Q().then(r=>t.info(r?`Codex Provider runtime config loaded revision=${r.revision}`:"Codex Provider runtime config is not configured")).catch(r=>t.warn(`Codex Provider runtime config sync failed: ${r instanceof Error?r.message:String(r)}`));let v=!1,f,w,I,k,A;const d=async r=>{if(v)return;v=!0,t.info("Shutting down"),f&&clearInterval(f),I?.stop(),A?.stop(),k?.stop(),await w?.stop().catch(c=>t.warn(`job worker shutdown failed: ${c instanceof Error?c.message:String(c)}`));const a=y.stats();await y.disposeAll().catch(c=>t.warn(`ACP runtime shutdown failed: ${c instanceof Error?c.message:String(c)}`)),t.info(`ACP runtimes stopped total=${a.total} inUse=${a.inUse} idle=${a.idle}`),$({pid:i.pid,phase:"stopped",stoppedAt:new Date().toISOString(),issues:[]}),C(),i.exit(r)};i.once("SIGINT",()=>{d(130)}),i.once("SIGTERM",()=>{d(0)}),i.once("uncaughtException",r=>{t.error(`uncaught exception: ${r.stack||r.message}`),d(1)}),i.once("unhandledRejection",r=>{const a=r instanceof Error?r.stack||r.message:String(r);t.error(`unhandled rejection: ${a}`),d(1)}),e.heartbeatLog&&setInterval(()=>t.info(`heartbeat: ${new Date().toISOString()}`),5e3),f=F(t),w=H(t),I=K(t),A=B(t),k=V(t),await new Promise(()=>{})}function ae(){return["codex","claude"].filter(e=>ce(e))}function ce(e){const o=i.env.PATH||"";for(const n of o.split(":"))try{if(n&&_.existsSync(p.join(n,e)))return!0}catch{}return!1}function $(e){M(L(),e)}export{_e as createStartCommand};
@@ -1,5 +1,5 @@
1
- import{execFileSync as y}from"node:child_process";import{randomUUID as $}from"node:crypto";import l from"node:fs";import T from"node:os";import u from"node:path";import{acaServerDownloadToFile as Q,acaServerRequest as P}from"./aca-server-client.js";import{loadAcaConfig as Z,upsertLocalProject as q}from"./aca-config.js";import{startLongPollWorker as tt}from"./long-poll-worker.js";import{expandWorkerRuntimePath as et}from"./worker-runtime-paths.js";import{syncCodexProviderRuntimeConfig as rt}from"./codex-provider-runtime-config.js";import{defaultAcpRuntimePool as ot}from"../acp/client/acp-runtime-pool.js";const F=25e3,nt=F+1e4,E=300,it=3e4;let b=null;function Zt(t){return tt({run:async()=>{const e=Z();if(!e.token)throw new Error("Worker 尚未配置认证令牌");const r=await P("GET",`/api/client/machine-operations/claim?machineId=${encodeURIComponent(e.machineId)}&waitMs=${F}`,void 0,{timeoutMs:nt});if(r.item)try{const o=await st(r.item);await P("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 P("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 st(t){if(t.operation==="sync_codex_provider_config"){const e=await rt(),r=await ot.retireProviderRuntimes("codex-acp");return{configured:!!e,revision:e?.revision??null,retiredRuntimes:r}}if(t.operation==="filesystem_roots")return kt();if(t.operation==="list_directory")return Dt({directoryPath:String(t.payload.path||""),includeHidden:t.payload.includeHidden===!0});if(t.operation==="register_project")return Ft(t.payload);if(t.operation==="list_project_directory")return lt(t.payload);if(t.operation==="upload_project_file")return ut(t.payload);if(t.operation==="mutate_project_files")return ft(t.payload);if(t.operation==="get_project_git_status")return O(t.payload);if(t.operation==="get_project_git_diff")return yt(t.payload);if(t.operation==="get_project_git_log")return gt(t.payload);if(t.operation==="get_project_git_commit")return St(t.payload);if(t.operation==="get_worktree_status")return A(t.payload);if(t.operation==="commit_worktree")return at(t.payload);if(t.operation==="cleanup_worktree")return ct(t.payload);throw new Error("不支持的 Machine 文件系统操作。 ")}function A(t){const e=C(String(t.worktreePath||""));if(!l.existsSync(e))return{exists:!1,isRepository:!1,dirty:!1,changedFiles:0,ahead:0};const r=m(e);if(!w(r))return{exists:!0,isRepository:!1,dirty:bt(r),changedFiles:null,ahead:0};const o=O({rootPath:r}),n=String(t.baseCommit||"").trim(),s=n&&/^[0-9a-f]{7,64}$/i.test(n)?Et(r,n):0;return{exists:!0,isRepository:!0,dirty:Array.isArray(o.files)&&o.files.length>0,changedFiles:Array.isArray(o.files)?o.files.length:0,branch:o.branch,ahead:s,files:Array.isArray(o.files)?o.files.slice(0,50):[],truncated:o.truncated===!0}}function at(t){const e=m(String(t.worktreePath||"")),r=String(t.message||"").trim();if(!r)throw new Error("提交说明不能为空。");if(!w(e))throw new Error("当前 Worktree 不是 Git 仓库,无法提交。");y("git",["-C",e,"add","-A"],{stdio:"pipe",timeout:3e4});try{return y("git",["-C",e,"diff","--cached","--quiet"],{stdio:"pipe",timeout:1e4}),{committed:!1,reason:"no_changes",...A(t)}}catch(o){if(Number(o.status)!==1)throw o}return y("git",["-C",e,"commit","-m",r],{stdio:"pipe",timeout:6e4}),{committed:!0,commit:d(e,["rev-parse","HEAD"],8*1024).trim(),...A(t)}}function ct(t){const e=C(String(t.worktreePath||"")),r=m(String(t.projectRoot||""));if(h(e)===h(r))throw new Error("不能清理项目主目录。");if(!l.existsSync(e))return{removed:!1,reason:"not_found"};const o=m(e),n=String(t.branchName||"").trim(),s=w(o)&&w(r);if(s){if(y("git",["-C",r,"worktree","remove","--force",o],{stdio:"pipe",timeout:6e4}),t.deleteBranch===!0&&n)try{y("git",["-C",r,"branch","-D",n],{stdio:"pipe",timeout:3e4})}catch(i){const a=String(i.stderr||i);if(!/not found|not exist/i.test(a))throw i}}else l.rmSync(o,{recursive:!0,force:!0,maxRetries:2,retryDelay:200});return{removed:!0,branchDeleted:!!(s&&t.deleteBranch===!0&&n)}}function lt(t){const e=m(String(t.rootPath||"")),r=S(String(t.relativePath||"")),o=j(e,r,!0),n=Math.max(0,Number(t.offset||0)),s=Math.min(300,Math.max(20,Number(t.limit||200))),i=l.readdirSync(o,{withFileTypes:!0}).filter(c=>!c.isSymbolicLink()).map(c=>({name:c.name,path:K(e,u.join(o,c.name)),type:c.isDirectory()?"directory":c.isFile()?"file":"other",hidden:c.name.startsWith("."),extension:c.isFile()?u.extname(c.name).slice(1).toLowerCase():""})).filter(c=>c.type!=="other").sort((c,f)=>c.type!==f.type?c.type==="directory"?-1:1:c.name.localeCompare(f.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}}async function ut(t){const e=String(t.uploadId||"").trim();if(!e)throw new Error("项目上传任务缺少 uploadId。");const r=m(String(t.rootPath||"")),o=S(String(t.relativeDirectory||"")),n=j(r,o,!0),s=I(String(t.fileName||"")),i=Number(t.sizeBytes),a=String(t.sha256||"").trim().toLowerCase();if(!Number.isSafeInteger(i)||i<0)throw new Error("项目上传文件大小无效。");if(!/^[0-9a-f]{64}$/.test(a))throw new Error("项目上传文件摘要无效。");const c=u.join(n,`.aca-upload-${$()}.tmp`);try{const f=await Q(`/api/client/project-uploads/${encodeURIComponent(e)}`,c,{maxBytes:i,timeoutMs:3e5});if(f.sizeBytes!==i)throw new Error("项目上传文件大小校验失败。");if(f.sha256.toLowerCase()!==a)throw new Error("项目上传文件完整性校验失败。");const p=pt(r,o,s,c);return{name:u.basename(p),path:K(r,p),directory:o,size:f.sizeBytes,sha256:f.sha256,renamed:u.basename(p)!==s,rootKind:t.rootKind==="worktree"?"worktree":"project"}}finally{l.rmSync(c,{force:!0})}}function ft(t){const e=m(String(t.rootPath||"")),r=t.action&&typeof t.action=="object"?t.action:{};if(r.type==="delete")return dt(e,String(r.path||""),r.recursive===!0,t.rootKind);throw new Error("project_file_operation_unsupported")}function dt(t,e,r,o){const n=S(e);if(!n)throw new Error("project_file_root_protected");mt(n);const s=n.split("/"),i=s.slice(0,-1).join("/"),a=j(t,i,!0),c=u.join(a,s.at(-1)||"");let f;try{f=l.lstatSync(c)}catch(p){throw p.code==="ENOENT"?new Error("project_file_not_found"):p}if(f.isSymbolicLink())throw new Error("project_file_symbolic_link");if(!f.isFile()&&!f.isDirectory())throw new Error("project_file_type_unsupported");if(f.isDirectory()&&!r&&l.readdirSync(c).length>0)throw new Error("project_directory_not_empty");return f.isDirectory()&&r?l.rmSync(c,{recursive:!0,force:!1,maxRetries:2,retryDelay:150}):f.isDirectory()?l.rmdirSync(c):l.unlinkSync(c),{operation:"delete",path:n,entryType:f.isDirectory()?"directory":"file",parentPath:i,affectedDirectories:[i],rootKind:o==="worktree"?"worktree":"project"}}function mt(t){const e=t.split("/")[0].toLocaleLowerCase("en-US");if([".git",".aca",".aica"].includes(e))throw new Error("project_file_protected")}function pt(t,e,r,o){const n=m(t),s=S(e),i=j(n,s,!0),a=I(r);if(l.realpathSync.native(u.dirname(o))!==i)throw new Error("项目上传临时文件不在目标目录中。");const f=l.lstatSync(o);if(!f.isFile()||f.isSymbolicLink())throw new Error("项目上传临时文件无效。");for(let p=1;p<=1e4;p+=1){const J=p===1?a:ht(a,p),_=u.join(i,J);try{return l.linkSync(o,_),l.chmodSync(_,420),l.rmSync(o,{force:!0}),_}catch(v){if(L(v))continue;if(!wt(v))throw v;try{return l.copyFileSync(o,_,l.constants.COPYFILE_EXCL),l.chmodSync(_,420),l.rmSync(o,{force:!0}),_}catch(N){if(L(N))continue;throw N}}}throw new Error("同名文件过多,无法生成可用文件名。")}function I(t){const e=t.trim();if(!e||e==="."||e===".."||/[\\/\x00-\x1F]/.test(e))throw new Error("项目上传文件名无效。");if(process.platform==="win32"&&(/[<>:"|?*]/.test(e)||/[. ]$/.test(e)))throw new Error("项目上传文件名在 Windows 上无效。");return e.slice(0,180)}function ht(t,e){const r=u.extname(t);return`${r?t.slice(0,-r.length):t} (${e})${r}`}function L(t){return!!(t&&typeof t=="object"&&t.code==="EEXIST")}function wt(t){const e=t&&typeof t=="object"?t.code:"";return["EPERM","EACCES","EXDEV","ENOTSUP","EOPNOTSUPP"].includes(String(e||""))}const M=500,x=2*1024*1024,g=2*1024*1024;function O(t){const e=m(String(t.rootPath||""));if(!w(e))return{isRepository:!1,branch:null,files:[],ahead:0,behind:0};const o=d(e,["status","--porcelain=v1","-z","--untracked-files=all","--no-renames"],x).split("\0").filter(Boolean).slice(0,M),n=o.map(a=>Pt(a)).filter(a=>!!a),s=k(d(e,["diff","--no-ext-diff","--numstat","-z","--no-renames","HEAD","--","."],x));for(const a of n){const c=s.get(a.path);if(c)a.additions=c.additions,a.deletions=c.deletions;else if(a.status==="untracked"){const f=G(e,a.path);a.additions=f.additions,a.deletions=f.deletions}}const i=At(e);return{isRepository:!0,branch:vt(e),files:n,ahead:i.ahead,behind:i.behind,truncated:o.length>=M}}function yt(t){const e=m(String(t.rootPath||"")),r=S(String(t.relativePath||""));if(!r)throw new Error("Diff 文件路径不能为空。");if(!w(e))return{isRepository:!1,path:r,diff:"",additions:0,deletions:0};const o=B(e,r),n=xt(e,r),s=n?d(e,["diff","--no-ext-diff","--unified=80","HEAD","--",r],g):W(e,["diff","--no-ext-diff","--no-index","--unified=80",process.platform==="win32"?"NUL":"/dev/null",o],g),i=n?k(d(e,["diff","--no-ext-diff","--numstat","-z","--no-renames","HEAD","--",r],32*1024)).get(r):G(e,r);return{isRepository:!0,path:r,diff:U(s),additions:i?.additions??0,deletions:i?.deletions??0,truncated:s.length>g}}function gt(t){const e=m(String(t.rootPath||""));if(!w(e))return{isRepository:!1,items:[]};if(!jt(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"],x).split("").map(i=>_t(i)).filter(i=>!!i),limit:r}}function St(t){const e=m(String(t.rootPath||"")),r=String(t.commit||"").trim();if(!/^[0-9a-f]{7,64}$/i.test(r))throw new Error("Git 提交标识无效。");if(!w(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],g),n=[...k(d(e,["show","--no-ext-diff","--numstat","-z","--no-renames","--format=",r],x)).values()];return{isRepository:!0,commit:r,diff:U(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>g}}function _t(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 Pt(t){if(t.length<4)return null;const e=t[0]||" ",r=t[1]||" ",o=S(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 k(t){const e=new Map;for(const r of t.split("\0")){if(!r)continue;const o=H(r);if(!o||!o.path)continue;const n=S(o.path);n&&e.set(n,{additions:o.additions,deletions:o.deletions})}return e}function G(t,e){const r=B(t,e),n=W(t,["diff","--no-ext-diff","--no-index","--numstat","-z","--",process.platform==="win32"?"NUL":"/dev/null",r],32*1024).split("\0",1)[0]||"",s=H(n);return s?{additions:s.additions,deletions:s.deletions}:{additions:null,deletions:null}}function H(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 w(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 Et(t,e){try{const r=d(t,["rev-list","--count",`${e}..HEAD`],8192).trim(),o=Number(r);return Number.isSafeInteger(o)&&o>0?o:0}catch{return 0}}function bt(t){try{return l.readdirSync(t).length>0}catch{return!1}}function xt(t,e){try{return d(t,["ls-files","--error-unmatch","--",e],8*1024),!0}catch{return!1}}function jt(t){try{return d(t,["rev-parse","--verify","HEAD"],8*1024),!0}catch{return!1}}function vt(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 At(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 B(t,e){const r=u.resolve(t,...e.split("/")),o=u.relative(t,r);if(o.startsWith("..")||u.isAbsolute(o))throw new Error("Diff 路径超出项目范围。");return r}function d(t,e,r){return y("git",["-C",t,...e],{encoding:"utf8",timeout:2e4,maxBuffer:r,stdio:["ignore","pipe","pipe"]})}function W(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 U(t){return t.length<=g?t:`${t.slice(0,g)}
1
+ import{activeTerminalService as Q}from"./terminal/service.js";import{execFileSync as y}from"node:child_process";import{randomUUID as $}from"node:crypto";import l from"node:fs";import T from"node:os";import u from"node:path";import{acaServerDownloadToFile as Z,acaServerRequest as P}from"./aca-server-client.js";import{loadAcaConfig as q,upsertLocalProject as tt}from"./aca-config.js";import{startLongPollWorker as et}from"./long-poll-worker.js";import{expandWorkerRuntimePath as rt}from"./worker-runtime-paths.js";import{syncCodexProviderRuntimeConfig as ot}from"./codex-provider-runtime-config.js";import{defaultAcpRuntimePool as nt}from"../acp/client/acp-runtime-pool.js";const F=25e3,it=F+1e4,E=300,st=3e4;let b=null;function te(t){return et({run:async()=>{const e=q();if(!e.token)throw new Error("Worker 尚未配置认证令牌");const r=await P("GET",`/api/client/machine-operations/claim?machineId=${encodeURIComponent(e.machineId)}&waitMs=${F}`,void 0,{timeoutMs:it});if(r.item)try{const o=await at(r.item);await P("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 P("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 at(t){if(t.operation==="sync_codex_provider_config"){const e=await ot(),r=await nt.retireProviderRuntimes("codex-acp");return{configured:!!e,revision:e?.revision??null,retiredRuntimes:r}}if(t.operation==="filesystem_roots")return Dt();if(t.operation==="list_directory")return Rt({directoryPath:String(t.payload.path||""),includeHidden:t.payload.includeHidden===!0});if(t.operation==="register_project")return It(t.payload);if(t.operation==="list_project_directory")return ut(t.payload);if(t.operation==="upload_project_file")return ft(t.payload);if(t.operation==="mutate_project_files")return dt(t.payload);if(t.operation==="get_project_git_status")return O(t.payload);if(t.operation==="get_project_git_diff")return gt(t.payload);if(t.operation==="get_project_git_log")return St(t.payload);if(t.operation==="get_project_git_commit")return _t(t.payload);if(t.operation==="get_worktree_status")return k(t.payload);if(t.operation==="commit_worktree")return ct(t.payload);if(t.operation==="cleanup_worktree")return lt(t.payload);throw new Error("不支持的 Machine 文件系统操作。 ")}function k(t){const e=C(String(t.worktreePath||""));if(!l.existsSync(e))return{exists:!1,isRepository:!1,dirty:!1,changedFiles:0,ahead:0};const r=m(e);if(!w(r))return{exists:!0,isRepository:!1,dirty:xt(r),changedFiles:null,ahead:0};const o=O({rootPath:r}),n=String(t.baseCommit||"").trim(),s=n&&/^[0-9a-f]{7,64}$/i.test(n)?bt(r,n):0;return{exists:!0,isRepository:!0,dirty:Array.isArray(o.files)&&o.files.length>0,changedFiles:Array.isArray(o.files)?o.files.length:0,branch:o.branch,ahead:s,files:Array.isArray(o.files)?o.files.slice(0,50):[],truncated:o.truncated===!0}}function ct(t){const e=m(String(t.worktreePath||"")),r=String(t.message||"").trim();if(!r)throw new Error("提交说明不能为空。");if(!w(e))throw new Error("当前 Worktree 不是 Git 仓库,无法提交。");y("git",["-C",e,"add","-A"],{stdio:"pipe",timeout:3e4});try{return y("git",["-C",e,"diff","--cached","--quiet"],{stdio:"pipe",timeout:1e4}),{committed:!1,reason:"no_changes",...k(t)}}catch(o){if(Number(o.status)!==1)throw o}return y("git",["-C",e,"commit","-m",r],{stdio:"pipe",timeout:6e4}),{committed:!0,commit:d(e,["rev-parse","HEAD"],8*1024).trim(),...k(t)}}function lt(t){const e=C(String(t.worktreePath||"")),r=m(String(t.projectRoot||""));if(h(e)===h(r))throw new Error("不能清理项目主目录。");if(!l.existsSync(e))return{removed:!1,reason:"not_found"};const o=m(e);if(Q?.hasRunningInDirectory(o,String(t.sessionId||"")))throw new Error("请先结束此目录中的会话终端,再清理 Worktree。");const n=String(t.branchName||"").trim(),s=w(o)&&w(r);if(s){if(y("git",["-C",r,"worktree","remove","--force",o],{stdio:"pipe",timeout:6e4}),t.deleteBranch===!0&&n)try{y("git",["-C",r,"branch","-D",n],{stdio:"pipe",timeout:3e4})}catch(i){const a=String(i.stderr||i);if(!/not found|not exist/i.test(a))throw i}}else l.rmSync(o,{recursive:!0,force:!0,maxRetries:2,retryDelay:200});return{removed:!0,branchDeleted:!!(s&&t.deleteBranch===!0&&n)}}function ut(t){const e=m(String(t.rootPath||"")),r=S(String(t.relativePath||"")),o=j(e,r,!0),n=Math.max(0,Number(t.offset||0)),s=Math.min(300,Math.max(20,Number(t.limit||200))),i=l.readdirSync(o,{withFileTypes:!0}).filter(c=>!c.isSymbolicLink()).map(c=>({name:c.name,path:K(e,u.join(o,c.name)),type:c.isDirectory()?"directory":c.isFile()?"file":"other",hidden:c.name.startsWith("."),extension:c.isFile()?u.extname(c.name).slice(1).toLowerCase():""})).filter(c=>c.type!=="other").sort((c,f)=>c.type!==f.type?c.type==="directory"?-1:1:c.name.localeCompare(f.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}}async function ft(t){const e=String(t.uploadId||"").trim();if(!e)throw new Error("项目上传任务缺少 uploadId。");const r=m(String(t.rootPath||"")),o=S(String(t.relativeDirectory||"")),n=j(r,o,!0),s=I(String(t.fileName||"")),i=Number(t.sizeBytes),a=String(t.sha256||"").trim().toLowerCase();if(!Number.isSafeInteger(i)||i<0)throw new Error("项目上传文件大小无效。");if(!/^[0-9a-f]{64}$/.test(a))throw new Error("项目上传文件摘要无效。");const c=u.join(n,`.aca-upload-${$()}.tmp`);try{const f=await Z(`/api/client/project-uploads/${encodeURIComponent(e)}`,c,{maxBytes:i,timeoutMs:3e5});if(f.sizeBytes!==i)throw new Error("项目上传文件大小校验失败。");if(f.sha256.toLowerCase()!==a)throw new Error("项目上传文件完整性校验失败。");const p=ht(r,o,s,c);return{name:u.basename(p),path:K(r,p),directory:o,size:f.sizeBytes,sha256:f.sha256,renamed:u.basename(p)!==s,rootKind:t.rootKind==="worktree"?"worktree":"project"}}finally{l.rmSync(c,{force:!0})}}function dt(t){const e=m(String(t.rootPath||"")),r=t.action&&typeof t.action=="object"?t.action:{};if(r.type==="delete")return mt(e,String(r.path||""),r.recursive===!0,t.rootKind);throw new Error("project_file_operation_unsupported")}function mt(t,e,r,o){const n=S(e);if(!n)throw new Error("project_file_root_protected");pt(n);const s=n.split("/"),i=s.slice(0,-1).join("/"),a=j(t,i,!0),c=u.join(a,s.at(-1)||"");let f;try{f=l.lstatSync(c)}catch(p){throw p.code==="ENOENT"?new Error("project_file_not_found"):p}if(f.isSymbolicLink())throw new Error("project_file_symbolic_link");if(!f.isFile()&&!f.isDirectory())throw new Error("project_file_type_unsupported");if(f.isDirectory()&&!r&&l.readdirSync(c).length>0)throw new Error("project_directory_not_empty");return f.isDirectory()&&r?l.rmSync(c,{recursive:!0,force:!1,maxRetries:2,retryDelay:150}):f.isDirectory()?l.rmdirSync(c):l.unlinkSync(c),{operation:"delete",path:n,entryType:f.isDirectory()?"directory":"file",parentPath:i,affectedDirectories:[i],rootKind:o==="worktree"?"worktree":"project"}}function pt(t){const e=t.split("/")[0].toLocaleLowerCase("en-US");if([".git",".aca",".aica"].includes(e))throw new Error("project_file_protected")}function ht(t,e,r,o){const n=m(t),s=S(e),i=j(n,s,!0),a=I(r);if(l.realpathSync.native(u.dirname(o))!==i)throw new Error("项目上传临时文件不在目标目录中。");const f=l.lstatSync(o);if(!f.isFile()||f.isSymbolicLink())throw new Error("项目上传临时文件无效。");for(let p=1;p<=1e4;p+=1){const J=p===1?a:wt(a,p),_=u.join(i,J);try{return l.linkSync(o,_),l.chmodSync(_,420),l.rmSync(o,{force:!0}),_}catch(v){if(L(v))continue;if(!yt(v))throw v;try{return l.copyFileSync(o,_,l.constants.COPYFILE_EXCL),l.chmodSync(_,420),l.rmSync(o,{force:!0}),_}catch(N){if(L(N))continue;throw N}}}throw new Error("同名文件过多,无法生成可用文件名。")}function I(t){const e=t.trim();if(!e||e==="."||e===".."||/[\\/\x00-\x1F]/.test(e))throw new Error("项目上传文件名无效。");if(process.platform==="win32"&&(/[<>:"|?*]/.test(e)||/[. ]$/.test(e)))throw new Error("项目上传文件名在 Windows 上无效。");return e.slice(0,180)}function wt(t,e){const r=u.extname(t);return`${r?t.slice(0,-r.length):t} (${e})${r}`}function L(t){return!!(t&&typeof t=="object"&&t.code==="EEXIST")}function yt(t){const e=t&&typeof t=="object"?t.code:"";return["EPERM","EACCES","EXDEV","ENOTSUP","EOPNOTSUPP"].includes(String(e||""))}const M=500,x=2*1024*1024,g=2*1024*1024;function O(t){const e=m(String(t.rootPath||""));if(!w(e))return{isRepository:!1,branch:null,files:[],ahead:0,behind:0};const o=d(e,["status","--porcelain=v1","-z","--untracked-files=all","--no-renames"],x).split("\0").filter(Boolean).slice(0,M),n=o.map(a=>Et(a)).filter(a=>!!a),s=A(d(e,["diff","--no-ext-diff","--numstat","-z","--no-renames","HEAD","--","."],x));for(const a of n){const c=s.get(a.path);if(c)a.additions=c.additions,a.deletions=c.deletions;else if(a.status==="untracked"){const f=G(e,a.path);a.additions=f.additions,a.deletions=f.deletions}}const i=At(e);return{isRepository:!0,branch:kt(e),files:n,ahead:i.ahead,behind:i.behind,truncated:o.length>=M}}function gt(t){const e=m(String(t.rootPath||"")),r=S(String(t.relativePath||""));if(!r)throw new Error("Diff 文件路径不能为空。");if(!w(e))return{isRepository:!1,path:r,diff:"",additions:0,deletions:0};const o=W(e,r),n=jt(e,r),s=n?d(e,["diff","--no-ext-diff","--unified=80","HEAD","--",r],g):B(e,["diff","--no-ext-diff","--no-index","--unified=80",process.platform==="win32"?"NUL":"/dev/null",o],g),i=n?A(d(e,["diff","--no-ext-diff","--numstat","-z","--no-renames","HEAD","--",r],32*1024)).get(r):G(e,r);return{isRepository:!0,path:r,diff:U(s),additions:i?.additions??0,deletions:i?.deletions??0,truncated:s.length>g}}function St(t){const e=m(String(t.rootPath||""));if(!w(e))return{isRepository:!1,items:[]};if(!vt(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"],x).split("").map(i=>Pt(i)).filter(i=>!!i),limit:r}}function _t(t){const e=m(String(t.rootPath||"")),r=String(t.commit||"").trim();if(!/^[0-9a-f]{7,64}$/i.test(r))throw new Error("Git 提交标识无效。");if(!w(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],g),n=[...A(d(e,["show","--no-ext-diff","--numstat","-z","--no-renames","--format=",r],x)).values()];return{isRepository:!0,commit:r,diff:U(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>g}}function Pt(t){const e=t.replace(/^\s+|\s+$/g,"");if(!e)return null;const r=e.split(""),o=String(r[0]||"").trim();return o?{hash:o,shortHash:String(r[1]||o.slice(0,8)).trim(),authorName:String(r[2]||"").trim(),authorEmail:String(r[3]||"").trim(),authoredAt:String(r[4]||"").trim(),refs:String(r[5]||"").trim(),subject:String(r[6]||"").trim(),body:r.slice(7).join("").trim()}:null}function Et(t){if(t.length<4)return null;const e=t[0]||" ",r=t[1]||" ",o=S(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 A(t){const e=new Map;for(const r of t.split("\0")){if(!r)continue;const o=H(r);if(!o||!o.path)continue;const n=S(o.path);n&&e.set(n,{additions:o.additions,deletions:o.deletions})}return e}function G(t,e){const r=W(t,e),n=B(t,["diff","--no-ext-diff","--no-index","--numstat","-z","--",process.platform==="win32"?"NUL":"/dev/null",r],32*1024).split("\0",1)[0]||"",s=H(n);return s?{additions:s.additions,deletions:s.deletions}:{additions:null,deletions:null}}function H(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 w(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 bt(t,e){try{const r=d(t,["rev-list","--count",`${e}..HEAD`],8192).trim(),o=Number(r);return Number.isSafeInteger(o)&&o>0?o:0}catch{return 0}}function xt(t){try{return l.readdirSync(t).length>0}catch{return!1}}function jt(t,e){try{return d(t,["ls-files","--error-unmatch","--",e],8*1024),!0}catch{return!1}}function vt(t){try{return d(t,["rev-parse","--verify","HEAD"],8*1024),!0}catch{return!1}}function kt(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 At(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 W(t,e){const r=u.resolve(t,...e.split("/")),o=u.relative(t,r);if(o.startsWith("..")||u.isAbsolute(o))throw new Error("Diff 路径超出项目范围。");return r}function d(t,e,r){return y("git",["-C",t,...e],{encoding:"utf8",timeout:2e4,maxBuffer:r,stdio:["ignore","pipe","pipe"]})}function B(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 U(t){return t.length<=g?t:`${t.slice(0,g)}
2
2
 
3
- [Diff 内容过大,已截断]`}function kt(){const t=process.platform,e=D(t);return{platform:t,roots:e}}function Dt(t){if(!t.directoryPath.trim())throw new Error("目录路径不能为空。");return process.platform==="win32"?$t(t.directoryPath,!!t.includeHidden):Nt(t.directoryPath,!!t.includeHidden)}function h(t,e=process.platform){const r=e==="win32"?u.win32:u.posix,o=r.normalize(t),n=r.parse(o).root,s=o.length>n.length?o.replace(/[\\/]+$/,""):o;return e==="win32"?s.toLocaleLowerCase("en-US"):s}function Rt(){const t=l.realpathSync(T.homedir()),e=[{id:"home",label:"用户目录",path:t,kind:"home",available:!0}];return t!==u.parse(t).root&&e.push({id:"root",label:"文件系统",path:"/",kind:"root",available:!0}),e}function D(t){if(b?.platform===t&&b.expiresAtMs>Date.now())return b.roots;const e=t==="win32"?Ct():Rt();return b={platform:t,roots:e,expiresAtMs:Date.now()+it},e}function Ct(){const t=l.realpathSync.native(T.homedir()),e=new Map;e.set(h(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=Y(V(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(/[\\/]+$/,"")),c=String(n.VolumeName||"").trim();e.set(h(s,"win32"),{id:`drive-${a.replace(/[^a-z0-9]+/gi,"").toLowerCase()}`,label:c?`${c} (${a})`:Gt(a,i),path:s,kind:Ot(i),available:!0})}}catch{const r=u.win32.parse(t).root;e.set(h(r,"win32"),{id:"drive-system",label:`系统盘 (${r.replace(/\\$/,"")})`,path:r,kind:"fixed",available:!0})}return[...e.values()]}function Nt(t,e){const r=R(t),n=l.readdirSync(r,{withFileTypes:!0}).filter(i=>i.isDirectory()&&!i.isSymbolicLink()&&(e||!i.name.startsWith("."))),s=n.slice(0,E).map(i=>({name:i.name,path:u.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"})),z(r,s,n.length>E,"linux")}function $t(t,e){const r=R(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=Y(V(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,E).sort((i,a)=>i.name.localeCompare(a.name,void 0,{numeric:!0,sensitivity:"base"}));return z(r,s,n.length>E,"win32")}function z(t,e,r,o){const n=o==="win32"?u.win32:u.posix,s=n.parse(t).root,i=h(t,o)===h(s,o)?null:n.dirname(t);return{platform:o,path:t,parentPath:i,breadcrumbs:Tt(t,o),readable:X(t,l.constants.R_OK),writable:X(t,l.constants.W_OK),items:e,truncated:r}}function Tt(t,e){const r=e==="win32"?u.win32:u.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 Ft(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=R(String(t.path||""));l.accessSync(n,l.constants.R_OK|l.constants.W_OK);const i=(await P("GET",`/api/projects?workspaceId=${encodeURIComponent(e)}`)).items.find(c=>h(c.root_path)===h(n)),a=i||(await P("POST","/api/projects",{projectId:$(),workspaceId:e,name:r,rootPath:n,source:"aica",projectType:o})).item;return q(It(a)),{project:a,duplicate:!!i}}function It(t){return{projectId:t.project_id,workspaceId:t.workspace_id,name:t.name,rootPath:t.root_path}}function R(t){if(!t.trim()||!u.isAbsolute(t))throw new Error("必须选择绝对目录路径。");if(Lt(t),!l.statSync(t).isDirectory())throw new Error("选择的路径不是目录。");const r=l.realpathSync.native(t);return Mt(r),r}function m(t){const e=C(t),r=l.realpathSync.native(e);if(!l.statSync(r).isDirectory())throw new Error("项目根目录不存在。");return r}function C(t){const e=et(t);if(!e||!u.isAbsolute(e))throw new Error("项目根目录无效。");return u.resolve(e)}function S(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 j(t,e,r){const o=e?u.join(t,...e.split("/")):t,n=l.realpathSync.native(o),s=u.relative(t,n);if(s.startsWith("..")||u.isAbsolute(s))throw new Error("目录超出项目范围。");const i=l.statSync(n);if(r&&!i.isDirectory())throw new Error("请求路径不是目录。");return n}function K(t,e){return u.relative(t,e).split(u.sep).join("/")}function Lt(t){const e=process.platform==="win32"?u.win32:u.posix;if(!D(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"?u.win32:u.posix;if(!D(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 X(t,e){try{return l.accessSync(t,e),!0}catch{return!1}}function V(t,e={}){return y("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 Y(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 Ot(t){return t===2?"removable":t===3?"fixed":t===4?"network":t===5?"optical":"drive"}function Gt(t,e){return e===2?`移动磁盘 (${t})`:e===4?`网络驱动器 (${t})`:e===5?`光驱 (${t})`:`本地磁盘 (${t})`}export{ct as cleanupWorktree,pt as commitProjectUploadTempFile,at as commitWorktree,h as comparableMachinePath,St as getProjectGitCommit,yt as getProjectGitDiff,gt as getProjectGitLog,O as getProjectGitStatus,A as getWorktreeStatus,Dt as listMachineDirectory,kt as listMachineFilesystemRoots,lt as listProjectDirectory,ft as mutateProjectFiles,Zt as startMachineFilesystemWorkerLoop,ut as uploadProjectFile};
3
+ [Diff 内容过大,已截断]`}function Dt(){const t=process.platform,e=D(t);return{platform:t,roots:e}}function Rt(t){if(!t.directoryPath.trim())throw new Error("目录路径不能为空。");return process.platform==="win32"?Tt(t.directoryPath,!!t.includeHidden):$t(t.directoryPath,!!t.includeHidden)}function h(t,e=process.platform){const r=e==="win32"?u.win32:u.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 Ct(){const t=l.realpathSync(T.homedir()),e=[{id:"home",label:"用户目录",path:t,kind:"home",available:!0}];return t!==u.parse(t).root&&e.push({id:"root",label:"文件系统",path:"/",kind:"root",available:!0}),e}function D(t){if(b?.platform===t&&b.expiresAtMs>Date.now())return b.roots;const e=t==="win32"?Nt():Ct();return b={platform:t,roots:e,expiresAtMs:Date.now()+st},e}function Nt(){const t=l.realpathSync.native(T.homedir()),e=new Map;e.set(h(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=Y(V(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(/[\\/]+$/,"")),c=String(n.VolumeName||"").trim();e.set(h(s,"win32"),{id:`drive-${a.replace(/[^a-z0-9]+/gi,"").toLowerCase()}`,label:c?`${c} (${a})`:Ht(a,i),path:s,kind:Gt(i),available:!0})}}catch{const r=u.win32.parse(t).root;e.set(h(r,"win32"),{id:"drive-system",label:`系统盘 (${r.replace(/\\$/,"")})`,path:r,kind:"fixed",available:!0})}return[...e.values()]}function $t(t,e){const r=R(t),n=l.readdirSync(r,{withFileTypes:!0}).filter(i=>i.isDirectory()&&!i.isSymbolicLink()&&(e||!i.name.startsWith("."))),s=n.slice(0,E).map(i=>({name:i.name,path:u.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"})),z(r,s,n.length>E,"linux")}function Tt(t,e){const r=R(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=Y(V(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,E).sort((i,a)=>i.name.localeCompare(a.name,void 0,{numeric:!0,sensitivity:"base"}));return z(r,s,n.length>E,"win32")}function z(t,e,r,o){const n=o==="win32"?u.win32:u.posix,s=n.parse(t).root,i=h(t,o)===h(s,o)?null:n.dirname(t);return{platform:o,path:t,parentPath:i,breadcrumbs:Ft(t,o),readable:X(t,l.constants.R_OK),writable:X(t,l.constants.W_OK),items:e,truncated:r}}function Ft(t,e){const r=e==="win32"?u.win32:u.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 It(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=R(String(t.path||""));l.accessSync(n,l.constants.R_OK|l.constants.W_OK);const i=(await P("GET",`/api/projects?workspaceId=${encodeURIComponent(e)}`)).items.find(c=>h(c.root_path)===h(n)),a=i||(await P("POST","/api/projects",{projectId:$(),workspaceId:e,name:r,rootPath:n,source:"aica",projectType:o})).item;return tt(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 R(t){if(!t.trim()||!u.isAbsolute(t))throw new Error("必须选择绝对目录路径。");if(Mt(t),!l.statSync(t).isDirectory())throw new Error("选择的路径不是目录。");const r=l.realpathSync.native(t);return Ot(r),r}function m(t){const e=C(t),r=l.realpathSync.native(e);if(!l.statSync(r).isDirectory())throw new Error("项目根目录不存在。");return r}function C(t){const e=rt(t);if(!e||!u.isAbsolute(e))throw new Error("项目根目录无效。");return u.resolve(e)}function S(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 j(t,e,r){const o=e?u.join(t,...e.split("/")):t,n=l.realpathSync.native(o),s=u.relative(t,n);if(s.startsWith("..")||u.isAbsolute(s))throw new Error("目录超出项目范围。");const i=l.statSync(n);if(r&&!i.isDirectory())throw new Error("请求路径不是目录。");return n}function K(t,e){return u.relative(t,e).split(u.sep).join("/")}function Mt(t){const e=process.platform==="win32"?u.win32:u.posix;if(!D(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 Ot(t){const e=process.platform==="win32"?u.win32:u.posix;if(!D(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 X(t,e){try{return l.accessSync(t,e),!0}catch{return!1}}function V(t,e={}){return y("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 Y(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 Gt(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{lt as cleanupWorktree,ht as commitProjectUploadTempFile,ct as commitWorktree,h as comparableMachinePath,_t as getProjectGitCommit,gt as getProjectGitDiff,St as getProjectGitLog,O as getProjectGitStatus,k as getWorktreeStatus,Rt as listMachineDirectory,Dt as listMachineFilesystemRoots,ut as listProjectDirectory,dt as mutateProjectFiles,te as startMachineFilesystemWorkerLoop,ft as uploadProjectFile};
@@ -0,0 +1 @@
1
+ import e from"node:fs";import r from"node:path";import{createRequire as c}from"node:module";import{getAsset as a,isSea as s}from"node:sea";import{getAcaHome as f}from"../paths.js";async function S(){if(!s())return import("node-pty");const n=JSON.parse(a("terminal-manifest","utf8")),t=r.join(f(),"native",`pty-${n.hash}`);if(!e.existsSync(r.join(t,".ready"))){e.mkdirSync(r.dirname(t),{recursive:!0,mode:448});const o=e.mkdtempSync(`${t}-`);try{for(const i of n.files){const m=r.join(o,i.name);e.mkdirSync(r.dirname(m),{recursive:!0}),e.writeFileSync(m,Buffer.from(a(`terminal/${i.name}`)),{mode:i.executable?448:384})}e.writeFileSync(r.join(o,".ready"),"");try{e.renameSync(o,t)}catch(i){if(!e.existsSync(r.join(t,".ready")))throw i}}finally{e.rmSync(o,{recursive:!0,force:!0})}}return c(r.join(t,"package.json"))(r.join(t,"lib","index.js"))}export{S as loadPty};
@@ -0,0 +1 @@
1
+ import{randomUUID as M}from"node:crypto";import p from"node:fs";import u from"node:path";import S from"@xterm/headless";import q from"@xterm/addon-serialize";import{loadPty as D}from"./native.js";import{expandWorkerRuntimePath as E}from"../worker-runtime-paths.js";import{terminalShell as T}from"./shell.js";const y=8,z=1440*6e4;class O{emit;entries=new Map;sweep=setInterval(()=>{for(const[e,t]of this.entries)!t.attachmentId&&Date.now()-t.detachedAt>z&&this.remove(e)},6e4);opening=new Map;epoch=0;disposed=!1;constructor(e){this.emit=e,this.sweep.unref()}async handle(e){const{sessionId:t,attachmentId:i}=e;if(!t||!i||this.disposed)return;const s=this.epoch,n=(this.opening.get(t)||Promise.resolve()).catch(()=>{}).then(async()=>{s!==this.epoch||this.disposed||(e.type==="open"?await this.open(e,s):this.control(e))});this.opening.set(t,n);try{await n}finally{this.opening.get(t)===n&&this.opening.delete(t)}}control(e){const{sessionId:t,attachmentId:i}=e,s=this.entries.get(t);if(!(!s||s.attachmentId!==i))if(e.type==="detach")s.attachmentId=void 0,s.detachedAt=Date.now();else if(e.type==="input"&&s.exitCode===void 0&&typeof e.data=="string"&&e.data.length<=16384)s.pty.write(e.binary?Buffer.from(e.data,"binary"):e.data);else if(e.type==="resize"&&s.exitCode===void 0){const[o,n]=C(e);s.screen.resize(o,n),s.pty.resize(o,n)}else e.type==="end"&&s.exitCode===void 0&&s.pty.kill()}detachAll(){this.epoch++;for(const e of this.entries.values())e.attachmentId&&(e.detachedAt=Date.now()),e.attachmentId=void 0}hasRunningInDirectory(e,t){const i=p.realpathSync(e);return[...this.entries.values()].some(s=>s.exitCode===void 0&&(s.sessionId===t||s.cwd===i||s.cwd.startsWith(i+u.sep)||this.shellIsInside(s,i)))}shellIsInside(e,t){if(process.platform!=="linux")return!1;try{const i=p.realpathSync(`/proc/${e.pty.pid}/cwd`);return i===t||i.startsWith(t+u.sep)}catch{return!1}}dispose(){this.disposed=!0,this.epoch++,clearInterval(this.sweep);for(const e of this.entries.keys())this.remove(e)}async open(e,t){const{sessionId:i,attachmentId:s}=e;let o=this.entries.get(i);if(e.restart&&o?.exitCode!==void 0&&(this.remove(i),o=void 0),!o){if(!e.create){this.emit({type:"missing",sessionId:i,attachmentId:s});return}const d=E(e.cwd||"");if(!d||!u.isAbsolute(d))throw new Error("终端启动目录无效。");const l=p.realpathSync(d);if(!p.statSync(l).isDirectory())throw new Error("终端启动目录不存在。");const A=await D();if(this.disposed||t!==this.epoch)return;if(this.entries.size>=y){const a=[...this.entries.values()].find(v=>v.exitCode!==void 0&&!v.attachmentId);a&&this.remove(a.sessionId)}if(this.entries.size>=y)throw new Error("此设备最多保留 8 个终端,请先结束并收起其他终端。");const[w,m]=C(e),I=process.platform==="win32"?process.env.COMSPEC||"powershell.exe":process.env.SHELL||"/bin/sh",g=T(I),c=A.spawn(I,g.args,{name:"xterm-256color",cwd:l,cols:w,rows:m,env:g.env}),f=new S.Terminal({cols:w,rows:m,scrollback:1e3,allowProposedApi:!0}),x=new q.SerializeAddon;f.loadAddon(x),o={id:M(),sessionId:i,cwd:l,pty:c,screen:f,serializer:x,detachedAt:Date.now(),seq:0,pending:"",queued:0},this.entries.set(i,o);const r=o;f.onData(a=>{if(!r.attachmentId&&r.exitCode===void 0)try{c.write(a)}catch{}}),c.onData(a=>{r.pending+=a,r.pending.length>=32768?this.flush(r):r.timer||(r.timer=setTimeout(()=>this.flush(r),24))}),c.onExit(({exitCode:a})=>{this.entries.get(i)===r&&(this.flush(r),r.screen.write("",()=>{r.exitCode=a,r.attachmentId&&this.emit({type:"exit",sessionId:i,attachmentId:r.attachmentId,exitCode:a})}))})}o.attachmentId=void 0,this.flush(o);const n=o;await new Promise(d=>n.screen.write("",()=>{if(this.disposed||t!==this.epoch){d();return}n.attachmentId=s,this.emit({type:"snapshot",sessionId:i,attachmentId:s,terminalId:n.id,seq:n.seq,cwd:n.cwd,cols:n.screen.cols,rows:n.screen.rows,data:n.serializer.serialize(),exitCode:n.exitCode,retentionHours:24}),d()}))}flush(e){if(clearTimeout(e.timer),e.timer=void 0,!e.pending)return;const t=e.pending;e.pending="",e.queued+=t.length,e.queued>256e3&&e.pty.pause(),e.screen.write(t,()=>{this.entries.get(e.sessionId)===e&&(e.queued-=t.length,e.queued<64e3&&e.exitCode===void 0&&e.pty.resume(),e.seq++,e.attachmentId&&this.emit({type:"output",sessionId:e.sessionId,attachmentId:e.attachmentId,seq:e.seq,data:t}))})}remove(e){const t=this.entries.get(e);t&&(this.entries.delete(e),clearTimeout(t.timer),t.exitCode===void 0&&t.pty.kill(),t.screen.dispose())}}function C(h){return[Math.max(20,Math.min(240,Math.floor(Number(h.cols)||80))),Math.max(5,Math.min(80,Math.floor(Number(h.rows)||24)))]}let _;function U(h){_=h}export{O as TerminalService,_ as activeTerminalService,U as setActiveTerminalService};
@@ -0,0 +1,19 @@
1
+ import e from"node:fs";import a from"node:path";import{createHash as m,randomUUID as f}from"node:crypto";import{getAcaHome as h}from"../paths.js";const s=`# ACA 交互终端默认配色;用户配置始终优先。
2
+ __aca_terminal_initial_ps1=\${PS1-}
3
+ if [[ -r "$HOME/.bashrc" ]]; then
4
+ . "$HOME/.bashrc"
5
+ fi
6
+ if [[ -z \${NO_COLOR:-} ]]; then
7
+ if [[ \${PS1-} == "$__aca_terminal_initial_ps1" && -z \${PROMPT_COMMAND[*]-} ]]; then
8
+ PS1='\\[\\e[32m\\]\\u@\\h\\[\\e[0m\\]:\\[\\e[34m\\]\\w\\[\\e[0m\\]\\$ '
9
+ fi
10
+ if ! alias ls >/dev/null 2>&1 && ! declare -F ls >/dev/null 2>&1; then
11
+ if command ls --color=auto -d . >/dev/null 2>&1; then
12
+ alias ls='ls --color=auto'
13
+ elif [[ $OSTYPE == darwin* || $OSTYPE == *bsd* ]]; then
14
+ alias ls='ls -G'
15
+ fi
16
+ fi
17
+ fi
18
+ unset __aca_terminal_initial_ps1
19
+ `;function $(o,l=process.env){const t={...l,TERM:"xterm-256color",COLORTERM:"truecolor"};if(process.platform==="win32"||a.basename(o)!=="bash")return{args:[],env:t};const n=a.join(h(),"terminal"),c=m("sha256").update(s).digest("hex").slice(0,16),r=a.join(n,`bashrc-${c}`);if(e.mkdirSync(n,{recursive:!0,mode:448}),!e.existsSync(r)){const i=`${r}.${f()}.tmp`;try{e.writeFileSync(i,s,{mode:384,flag:"wx"}),e.renameSync(i,r)}finally{e.rmSync(i,{force:!0})}}return{args:["--rcfile",r,"-i"],env:t}}export{$ as terminalShell};
@@ -0,0 +1 @@
1
+ import p from"ws";import{loadAcaConfig as w}from"../aca-config.js";import{TerminalService as y,setActiveTerminalService as h}from"./service.js";function v(l){let r,m=!1,s,f,d=Date.now();const i=new y(n=>{if(r?.readyState===p.OPEN){if(r.bufferedAmount>2e6){r.terminate();return}r.send(JSON.stringify(n))}});h(i);function c(){if(m)return;const n=w();if(!n.serverUrl||!n.token){s=setTimeout(c,5e3);return}try{const o=new URL("api/terminal/worker",n.serverUrl.replace(/\/?$/,"/"));o.protocol=o.protocol==="https:"?"wss:":"ws:";const e=new p(o,{headers:{authorization:`Bearer ${n.token}`},rejectUnauthorized:!["1","true","yes"].includes((process.env.ACA_SERVER_INSECURE_TLS||"").toLowerCase()),maxPayload:65536,perMessageDeflate:!1,handshakeTimeout:1e4});r=e,e.on("open",()=>{d=Date.now(),f=setInterval(()=>{Date.now()-d>45e3&&e.terminate()},15e3)}),e.on("ping",()=>{d=Date.now()}),e.on("message",a=>{let t;try{t=JSON.parse(a.toString())}catch{e.close(1008);return}if(!t||typeof t!="object"||typeof t.sessionId!="string"||typeof t.attachmentId!="string"){e.close(1008);return}i.handle(t).catch(u=>{e.readyState===p.OPEN&&e.send(JSON.stringify({type:"error",sessionId:t.sessionId,attachmentId:t.attachmentId,message:u instanceof Error?u.message:"终端操作失败。"}))})}),e.on("error",a=>l.warn(`Terminal connection: ${a.message}`)),e.on("close",a=>{clearInterval(f),i.detachAll(),a===4001?l.warn("Terminal channel replaced by another Worker on this machine; restart this Worker to reconnect."):m||(s=setTimeout(c,3e3+Math.random()*2e3))})}catch(o){l.warn(`Terminal connection: ${String(o)}`),s=setTimeout(c,5e3)}}return c(),{stop(){m=!0,clearTimeout(s),clearInterval(f),r?.terminate(),i.dispose(),h(void 0)}}}export{v as startTerminalWorker};
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- const o="0.1.55";export{o as AICA_VERSION};
1
+ const o="0.1.56";export{o as AICA_VERSION};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuandc/aica",
3
- "version": "0.1.55",
3
+ "version": "0.1.56",
4
4
  "description": "AICA remote Agent worker",
5
5
  "author": "yuandc",
6
6
  "type": "module",
@@ -27,10 +27,14 @@
27
27
  ],
28
28
  "dependencies": {
29
29
  "@openai/codex": "0.156.1",
30
+ "@xterm/addon-serialize": "^0.14.0",
31
+ "@xterm/headless": "^6.0.0",
30
32
  "chalk": "^5.4.1",
31
33
  "commander": "^12.1.0",
32
34
  "diff": "^9.0.0",
35
+ "node-pty": "^1.1.0",
33
36
  "undici": "^7.28.0",
37
+ "ws": "^8.22.0",
34
38
  "zod": "^3.25.76"
35
39
  }
36
40
  }