@yuandc/aica 0.1.86 → 0.1.88

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.
Files changed (36) hide show
  1. package/dist/acp/client/acp-runtime-pool.js +1 -1
  2. package/dist/acp/providers/codex/codex-path.js +1 -1
  3. package/dist/acp/providers/codex/permissions.js +1 -1
  4. package/dist/acp/providers/codex/provider.js +1 -1
  5. package/dist/acp/providers/codex-acp/adapter.js +4 -4
  6. package/dist/acp/providers/codex-acp/provider.js +1 -1
  7. package/dist/acp/providers/mimo/provider.js +5 -5
  8. package/dist/acp/providers/opencode/provider.js +4 -4
  9. package/dist/acp/providers/registry.js +1 -1
  10. package/dist/acp/providers/workbuddy/auth-environment.js +1 -0
  11. package/dist/acp/providers/workbuddy/auth-gate.js +1 -0
  12. package/dist/acp/providers/workbuddy/auth-manager.js +1 -0
  13. package/dist/acp/providers/workbuddy/auth-transport.js +3 -0
  14. package/dist/acp/providers/workbuddy/config.js +1 -0
  15. package/dist/acp/providers/workbuddy/discovery.js +1 -0
  16. package/dist/acp/providers/workbuddy/events.js +1 -0
  17. package/dist/acp/providers/workbuddy/interactions.js +1 -0
  18. package/dist/acp/providers/workbuddy/launch.js +1 -0
  19. package/dist/acp/providers/workbuddy/provider.js +1 -0
  20. package/dist/acp/providers/workbuddy/supplements.js +1 -0
  21. package/dist/commands/start.js +1 -1
  22. package/dist/core/desktop-control.js +1 -1
  23. package/dist/core/heartbeat.js +3 -3
  24. package/dist/core/job-worker.js +1 -1
  25. package/dist/core/machine-filesystem/powershell.js +2 -2
  26. package/dist/core/machine-filesystem-worker.js +4 -4
  27. package/dist/core/provider-health.js +1 -1
  28. package/dist/core/provider-install-mimo.js +1 -0
  29. package/dist/core/provider-install-paths.js +1 -0
  30. package/dist/core/provider-installer.js +1 -0
  31. package/dist/core/workbuddy-auth-worker.js +1 -0
  32. package/dist/interactions/job-interactions.js +2 -0
  33. package/dist/interactions/provider-input.js +1 -0
  34. package/dist/interactions/types.js +1 -0
  35. package/dist/version.js +1 -1
  36. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
- import{executeExternalCodexOperation as q}from"./external-codex-worker.js";import{managementActivity as T}from"./management/activity.js";import{managedClaim as tt}from"./management/claims.js";import{activeTerminalService as et}from"./terminal/service.js";import{execFileSync as _}from"node:child_process";import{randomUUID as I}from"node:crypto";import l from"node:fs";import F from"node:os";import u from"node:path";import{acaServerDownloadToFile as rt,acaServerRequest as E}from"./aca-server-client.js";import{loadAcaConfig as L,upsertLocalProject as ot}from"./aca-config.js";import{startLongPollWorker as it}from"./long-poll-worker.js";import{expandWorkerRuntimePath as nt}from"./worker-runtime-paths.js";import{syncCodexProviderRuntimeConfig as st}from"./codex-provider-runtime-config.js";import{defaultAcpRuntimePool as at}from"../acp/client/acp-runtime-pool.js";import{execPowerShell as M}from"./machine-filesystem/powershell.js";const O=25e3,ct=O+1e4,x=300,lt=3e4;let b=null;function ce(t){return it({run:async()=>{const e=L();if(!e.token)throw new Error("Worker 尚未配置认证令牌");const r=await tt("machine",()=>E("GET",`/api/client/machine-operations/claim?machineId=${encodeURIComponent(e.machineId)}&waitMs=${O}`,void 0,{timeoutMs:ct}));if(!r.item)return;const o=T.track("machine");try{const i=await ut(r.item);await E("POST",`/api/client/machine-operations/${encodeURIComponent(r.item.requestId)}/complete`,{result:i})}catch(i){const s=i instanceof Error?i.message:String(i);t.warn(`machine filesystem request failed request=${r.item.requestId}: ${s}`),await E("POST",`/api/client/machine-operations/${encodeURIComponent(r.item.requestId)}/fail`,{message:s}).catch(()=>{T.uncertain.add("machine-finalize")})}finally{o()}},onError:(e,r)=>t.warn(`machine filesystem worker failed, retry in ${r}ms: ${e instanceof Error?e.message:String(e)}`)})}async function ut(t){if(t.operation.startsWith("external_codex_"))return q(t.operation,t.payload);if(t.operation==="sync_codex_provider_config"){const e=await st(),r=await at.retireProviderRuntimes("codex-acp");return{configured:!!e,revision:e?.revision??null,retiredRuntimes:r}}if(t.operation==="filesystem_roots")return Nt();if(t.operation==="list_directory")return Tt({directoryPath:String(t.payload.path||""),includeHidden:t.payload.includeHidden===!0});if(t.operation==="register_project")return Ht(t.payload);if(t.operation==="list_project_directory")return mt(t.payload);if(t.operation==="upload_project_file")return ht(t.payload);if(t.operation==="mutate_project_files")return wt(t.payload);if(t.operation==="get_project_git_status")return B(t.payload);if(t.operation==="get_project_git_diff")return Et(t.payload);if(t.operation==="get_project_git_log")return xt(t.payload);if(t.operation==="get_project_git_commit")return bt(t.payload);if(t.operation==="get_worktree_status")return k(t.payload);if(t.operation==="commit_worktree")return dt(t.payload);if(t.operation==="cleanup_worktree")return ft(t.payload);throw new Error("不支持的 Machine 文件系统操作。 ")}function k(t){const e=$(String(t.worktreePath||""));if(!l.existsSync(e))return{exists:!1,isRepository:!1,dirty:!1,changedFiles:0,ahead:0};const r=p(e);if(!w(r))return{exists:!0,isRepository:!1,dirty:kt(r),changedFiles:null,ahead:0};const o=B({rootPath:r}),i=String(t.baseCommit||"").trim(),s=i&&/^[0-9a-f]{7,64}$/i.test(i)?At(r,i):0;return{exists:!0,isRepository:!0,dirty:Array.isArray(o.files)&&o.files.length>0,changedFiles:Array.isArray(o.files)?o.files.length:0,branch:o.branch,ahead:s,files:Array.isArray(o.files)?o.files.slice(0,50):[],truncated:o.truncated===!0}}function dt(t){const e=p(String(t.worktreePath||"")),r=String(t.message||"").trim();if(!r)throw new Error("提交说明不能为空。");if(!w(e))throw new Error("当前 Worktree 不是 Git 仓库,无法提交。");_("git",["-C",e,"add","-A"],{windowsHide:!0,stdio:"pipe",timeout:3e4});try{return _("git",["-C",e,"diff","--cached","--quiet"],{windowsHide:!0,stdio:"pipe",timeout:1e4}),{committed:!1,reason:"no_changes",...k(t)}}catch(o){if(Number(o.status)!==1)throw o}return _("git",["-C",e,"commit","-m",r],{windowsHide:!0,stdio:"pipe",timeout:6e4}),{committed:!0,commit:m(e,["rev-parse","HEAD"],8*1024).trim(),...k(t)}}function ft(t){const e=$(String(t.worktreePath||"")),r=p(String(t.projectRoot||""));if(h(e)===h(r))throw new Error("不能清理项目主目录。");if(!l.existsSync(e))return{removed:!1,reason:"not_found"};const o=p(e);if(et?.hasRunningInDirectory(o,String(t.sessionId||"")))throw new Error("请先结束此目录中的会话终端,再清理 Worktree。");const i=String(t.branchName||"").trim(),s=w(o)&&w(r);if(s){if(_("git",["-C",r,"worktree","remove","--force",o],{windowsHide:!0,stdio:"pipe",timeout:6e4}),t.deleteBranch===!0&&i)try{_("git",["-C",r,"branch","-D",i],{windowsHide:!0,stdio:"pipe",timeout:3e4})}catch(n){const c=String(n.stderr||n);if(!/not found|not exist/i.test(c))throw n}}else l.rmSync(o,{recursive:!0,force:!0,maxRetries:2,retryDelay:200});return{removed:!0,branchDeleted:!!(s&&t.deleteBranch===!0&&i)}}function mt(t){const e=p(String(t.rootPath||"")),r=g(String(t.relativePath||"")),o=v(e,r,!0),i=Math.max(0,Number(t.offset||0)),s=Math.min(300,Math.max(20,Number(t.limit||200))),n=t.sort==="modified-desc"||t.sort==="modified-asc"?t.sort:"name",c=l.readdirSync(o,{withFileTypes:!0}).filter(a=>!a.isSymbolicLink()).map(a=>({name:a.name,path:J(e,u.join(o,a.name)),type:a.isDirectory()?"directory":a.isFile()?"file":"other",hidden:a.name.startsWith("."),extension:a.isFile()?u.extname(a.name).slice(1).toLowerCase():"",modifiedAt:n==="name"?void 0:pt(u.join(o,a.name))})).filter(a=>a.type!=="other").sort((a,f)=>{if(a.type!==f.type)return a.type==="directory"?-1:1;if(n!=="name"){if(a.modifiedAt==null&&f.modifiedAt!=null)return 1;if(f.modifiedAt==null&&a.modifiedAt!=null)return-1;const P=(a.modifiedAt??0)-(f.modifiedAt??0);if(P)return n==="modified-desc"?-P:P}return a.name.localeCompare(f.name,void 0,{numeric:!0,sensitivity:"base"})}),d=c.slice(i,i+s);return{path:r,rootKind:t.rootKind==="worktree"?"worktree":"project",items:d,total:c.length,nextOffset:i+d.length<c.length?i+d.length:null}}function pt(t){try{const e=l.lstatSync(t);return e.isSymbolicLink()?null:e.mtimeMs}catch{return null}}async function ht(t){const e=String(t.uploadId||"").trim();if(!e)throw new Error("项目上传任务缺少 uploadId。");const r=p(String(t.rootPath||"")),o=g(String(t.relativeDirectory||"")),i=v(r,o,!0),s=H(String(t.fileName||"")),n=Number(t.sizeBytes),c=String(t.sha256||"").trim().toLowerCase();if(!Number.isSafeInteger(n)||n<0)throw new Error("项目上传文件大小无效。");if(!/^[0-9a-f]{64}$/.test(c))throw new Error("项目上传文件摘要无效。");const d=u.join(i,`.aca-upload-${I()}.tmp`);try{const a=await rt(`/api/client/project-uploads/${encodeURIComponent(e)}`,d,{maxBytes:n,timeoutMs:3e5});if(a.sizeBytes!==n)throw new Error("项目上传文件大小校验失败。");if(a.sha256.toLowerCase()!==c)throw new Error("项目上传文件完整性校验失败。");const f=St(r,o,s,d);return{name:u.basename(f),path:J(r,f),directory:o,size:a.sizeBytes,sha256:a.sha256,renamed:u.basename(f)!==s,rootKind:t.rootKind==="worktree"?"worktree":"project"}}finally{l.rmSync(d,{force:!0})}}function wt(t){const e=p(String(t.rootPath||"")),r=t.action&&typeof t.action=="object"?t.action:{};if(r.type==="delete")return yt(e,String(r.path||""),r.recursive===!0,t.rootKind);throw new Error("project_file_operation_unsupported")}function yt(t,e,r,o){const i=g(e);if(!i)throw new Error("project_file_root_protected");gt(i);const s=i.split("/"),n=s.slice(0,-1).join("/"),c=v(t,n,!0),d=u.join(c,s.at(-1)||"");let a;try{a=l.lstatSync(d)}catch(f){throw f.code==="ENOENT"?new Error("project_file_not_found"):f}if(a.isSymbolicLink())throw new Error("project_file_symbolic_link");if(!a.isFile()&&!a.isDirectory())throw new Error("project_file_type_unsupported");if(a.isDirectory()&&!r&&l.readdirSync(d).length>0)throw new Error("project_directory_not_empty");return a.isDirectory()&&r?l.rmSync(d,{recursive:!0,force:!1,maxRetries:2,retryDelay:150}):a.isDirectory()?l.rmdirSync(d):l.unlinkSync(d),{operation:"delete",path:i,entryType:a.isDirectory()?"directory":"file",parentPath:n,affectedDirectories:[n],rootKind:o==="worktree"?"worktree":"project"}}function gt(t){const e=t.split("/")[0].toLocaleLowerCase("en-US");if([".git",".aca",".aica"].includes(e))throw new Error("project_file_protected")}function St(t,e,r,o){const i=p(t),s=g(e),n=v(i,s,!0),c=H(r);if(l.realpathSync.native(u.dirname(o))!==n)throw new Error("项目上传临时文件不在目标目录中。");const a=l.lstatSync(o);if(!a.isFile()||a.isSymbolicLink())throw new Error("项目上传临时文件无效。");for(let f=1;f<=1e4;f+=1){const P=f===1?c:_t(c,f),S=u.join(n,P);try{return l.linkSync(o,S),l.chmodSync(S,420),l.rmSync(o,{force:!0}),S}catch(A){if(G(A))continue;if(!Pt(A))throw A;try{return l.copyFileSync(o,S,l.constants.COPYFILE_EXCL),l.chmodSync(S,420),l.rmSync(o,{force:!0}),S}catch(N){if(G(N))continue;throw N}}}throw new Error("同名文件过多,无法生成可用文件名。")}function H(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 _t(t,e){const r=u.extname(t);return`${r?t.slice(0,-r.length):t} (${e})${r}`}function G(t){return!!(t&&typeof t=="object"&&t.code==="EEXIST")}function Pt(t){const e=t&&typeof t=="object"?t.code:"";return["EPERM","EACCES","EXDEV","ENOTSUP","EOPNOTSUPP"].includes(String(e||""))}const W=500,j=2*1024*1024,y=2*1024*1024;function B(t){const e=p(String(t.rootPath||""));if(!w(e))return{isRepository:!1,branch:null,files:[],ahead:0,behind:0};const o=m(e,["status","--porcelain=v1","-z","--untracked-files=all","--no-renames"],j).split("\0").filter(Boolean).slice(0,W),i=o.map(c=>vt(c)).filter(c=>!!c),s=D(m(e,["diff","--no-ext-diff","--numstat","-z","--no-renames","HEAD","--","."],j));for(const c of i){const d=s.get(c.path);if(d)c.additions=d.additions,c.deletions=d.deletions;else if(c.status==="untracked"){const a=U(e,c.path);c.additions=a.additions,c.deletions=a.deletions}}const n=$t(e);return{isRepository:!0,branch:Ct(e),files:i,ahead:n.ahead,behind:n.behind,truncated:o.length>=W}}function Et(t){const e=p(String(t.rootPath||"")),r=g(String(t.relativePath||""));if(!r)throw new Error("Diff 文件路径不能为空。");if(!w(e))return{isRepository:!1,path:r,diff:"",additions:0,deletions:0};const o=K(e,r),i=Dt(e,r),s=i?m(e,["diff","--no-ext-diff","--unified=80","HEAD","--",r],y):X(e,["diff","--no-ext-diff","--no-index","--unified=80",process.platform==="win32"?"NUL":"/dev/null",o],y),n=i?D(m(e,["diff","--no-ext-diff","--numstat","-z","--no-renames","HEAD","--",r],32*1024)).get(r):U(e,r);return{isRepository:!0,path:r,diff:V(s),additions:n?.additions??0,deletions:n?.deletions??0,truncated:s.length>y}}function xt(t){const e=p(String(t.rootPath||""));if(!w(e))return{isRepository:!1,items:[]};if(!Rt(e))return{isRepository:!0,items:[]};const r=Math.min(200,Math.max(20,Number(t.limit||100)));return{isRepository:!0,items:m(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"],j).split("").map(n=>jt(n)).filter(n=>!!n),limit:r}}function bt(t){const e=p(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};m(e,["cat-file","-e",`${r}^{commit}`],8*1024);const o=m(e,["show","--no-ext-diff","--no-color","--format=","--stat","--patch","--unified=40",r],y),i=[...D(m(e,["show","--no-ext-diff","--numstat","-z","--no-renames","--format=",r],j)).values()];return{isRepository:!0,commit:r,diff:V(o),additions:i.reduce((s,n)=>s+(n.additions||0),0),deletions:i.reduce((s,n)=>s+(n.deletions||0),0),changedFiles:i.length,truncated:o.length>y}}function jt(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 vt(t){if(t.length<4)return null;const e=t[0]||" ",r=t[1]||" ",o=g(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 D(t){const e=new Map;for(const r of t.split("\0")){if(!r)continue;const o=z(r);if(!o||!o.path)continue;const i=g(o.path);i&&e.set(i,{additions:o.additions,deletions:o.deletions})}return e}function U(t,e){const r=K(t,e),i=X(t,["diff","--no-ext-diff","--no-index","--numstat","-z","--",process.platform==="win32"?"NUL":"/dev/null",r],32*1024).split("\0",1)[0]||"",s=z(i);return s?{additions:s.additions,deletions:s.deletions}:{additions:null,deletions:null}}function z(t){const e=t.indexOf(" "),r=e<0?-1:t.indexOf(" ",e+1);if(e<0||r<0)return null;const o=t.slice(0,e),i=t.slice(e+1,r);return{additions:/^\d+$/.test(o)?Number(o):null,deletions:/^\d+$/.test(i)?Number(i):null,path:t.slice(r+1)}}function w(t){try{return m(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 At(t,e){try{const r=m(t,["rev-list","--count",`${e}..HEAD`],8192).trim(),o=Number(r);return Number.isSafeInteger(o)&&o>0?o:0}catch{return 0}}function kt(t){try{return l.readdirSync(t).length>0}catch{return!1}}function Dt(t,e){try{return m(t,["ls-files","--error-unmatch","--",e],8*1024),!0}catch{return!1}}function Rt(t){try{return m(t,["rev-parse","--verify","HEAD"],8*1024),!0}catch{return!1}}function Ct(t){try{return m(t,["symbolic-ref","--quiet","--short","HEAD"],8*1024).trim()||null}catch{try{return`HEAD (${m(t,["rev-parse","--short","HEAD"],8*1024).trim()})`}catch{return null}}}function $t(t){try{const e=m(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 K(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 m(t,e,r){return _("git",["-C",t,...e],{windowsHide:!0,encoding:"utf8",timeout:2e4,maxBuffer:r,stdio:["ignore","pipe","pipe"]})}function X(t,e,r){try{return m(t,e,r)}catch(o){const i=String(o.stdout||"");if(i)return i;if(Number(o.status)===1)return"";throw o}}function V(t){return t.length<=y?t:`${t.slice(0,y)}
1
+ import{providerInstallOperation as q}from"./provider-installer.js";import{executeExternalCodexOperation as tt}from"./external-codex-worker.js";import{workBuddyAuthManager as et}from"./workbuddy-auth-worker.js";import{managementActivity as T}from"./management/activity.js";import{managedClaim as rt}from"./management/claims.js";import{activeTerminalService as ot}from"./terminal/service.js";import{execFileSync as _}from"node:child_process";import{randomUUID as I}from"node:crypto";import l from"node:fs";import F from"node:os";import u from"node:path";import{acaServerDownloadToFile as it,acaServerRequest as E}from"./aca-server-client.js";import{loadAcaConfig as M,upsertLocalProject as nt}from"./aca-config.js";import{startLongPollWorker as st}from"./long-poll-worker.js";import{expandWorkerRuntimePath as at}from"./worker-runtime-paths.js";import{syncCodexProviderRuntimeConfig as ct}from"./codex-provider-runtime-config.js";import{defaultAcpRuntimePool as lt}from"../acp/client/acp-runtime-pool.js";import{execPowerShell as L}from"./machine-filesystem/powershell.js";const O=25e3,ut=O+1e4,x=300,dt=3e4;let b=null;function fe(t){return st({run:async()=>{const e=M();if(!e.token)throw new Error("Worker 尚未配置认证令牌");const r=await rt("machine",()=>E("GET",`/api/client/machine-operations/claim?machineId=${encodeURIComponent(e.machineId)}&waitMs=${O}`,void 0,{timeoutMs:ut}));if(!r.item)return;const o=T.track("machine");try{const i=await ft(r.item);await E("POST",`/api/client/machine-operations/${encodeURIComponent(r.item.requestId)}/complete`,{result:i})}catch(i){const s=i instanceof Error?i.message:String(i);t.warn(`machine filesystem request failed request=${r.item.requestId}: ${s}`),await E("POST",`/api/client/machine-operations/${encodeURIComponent(r.item.requestId)}/fail`,{message:s}).catch(()=>{T.uncertain.add("machine-finalize")})}finally{o()}},onError:(e,r)=>t.warn(`machine filesystem worker failed, retry in ${r}ms: ${e instanceof Error?e.message:String(e)}`)})}async function ft(t){if(t.operation==="provider_install")return q(t.payload);if(t.operation==="workbuddy_auth")return et.execute(String(t.payload.action||""),t.payload);if(t.operation.startsWith("external_codex_"))return tt(t.operation,t.payload);if(t.operation==="sync_codex_provider_config"){const e=await ct(),r=await lt.retireProviderRuntimes("codex-acp");return{configured:!!e,revision:e?.revision??null,retiredRuntimes:r}}if(t.operation==="filesystem_roots")return It();if(t.operation==="list_directory")return Ft({directoryPath:String(t.payload.path||""),includeHidden:t.payload.includeHidden===!0});if(t.operation==="register_project")return Wt(t.payload);if(t.operation==="list_project_directory")return ht(t.payload);if(t.operation==="upload_project_file")return yt(t.payload);if(t.operation==="mutate_project_files")return gt(t.payload);if(t.operation==="get_project_git_status")return B(t.payload);if(t.operation==="get_project_git_diff")return bt(t.payload);if(t.operation==="get_project_git_log")return jt(t.payload);if(t.operation==="get_project_git_commit")return vt(t.payload);if(t.operation==="get_worktree_status")return k(t.payload);if(t.operation==="commit_worktree")return mt(t.payload);if(t.operation==="cleanup_worktree")return pt(t.payload);throw new Error("不支持的 Machine 文件系统操作。 ")}function k(t){const e=$(String(t.worktreePath||""));if(!l.existsSync(e))return{exists:!1,isRepository:!1,dirty:!1,changedFiles:0,ahead:0};const r=p(e);if(!w(r))return{exists:!0,isRepository:!1,dirty:Rt(r),changedFiles:null,ahead:0};const o=B({rootPath:r}),i=String(t.baseCommit||"").trim(),s=i&&/^[0-9a-f]{7,64}$/i.test(i)?Dt(r,i):0;return{exists:!0,isRepository:!0,dirty:Array.isArray(o.files)&&o.files.length>0,changedFiles:Array.isArray(o.files)?o.files.length:0,branch:o.branch,ahead:s,files:Array.isArray(o.files)?o.files.slice(0,50):[],truncated:o.truncated===!0}}function mt(t){const e=p(String(t.worktreePath||"")),r=String(t.message||"").trim();if(!r)throw new Error("提交说明不能为空。");if(!w(e))throw new Error("当前 Worktree 不是 Git 仓库,无法提交。");_("git",["-C",e,"add","-A"],{windowsHide:!0,stdio:"pipe",timeout:3e4});try{return _("git",["-C",e,"diff","--cached","--quiet"],{windowsHide:!0,stdio:"pipe",timeout:1e4}),{committed:!1,reason:"no_changes",...k(t)}}catch(o){if(Number(o.status)!==1)throw o}return _("git",["-C",e,"commit","-m",r],{windowsHide:!0,stdio:"pipe",timeout:6e4}),{committed:!0,commit:m(e,["rev-parse","HEAD"],8*1024).trim(),...k(t)}}function pt(t){const e=$(String(t.worktreePath||"")),r=p(String(t.projectRoot||""));if(h(e)===h(r))throw new Error("不能清理项目主目录。");if(!l.existsSync(e))return{removed:!1,reason:"not_found"};const o=p(e);if(ot?.hasRunningInDirectory(o,String(t.sessionId||"")))throw new Error("请先结束此目录中的会话终端,再清理 Worktree。");const i=String(t.branchName||"").trim(),s=w(o)&&w(r);if(s){if(_("git",["-C",r,"worktree","remove","--force",o],{windowsHide:!0,stdio:"pipe",timeout:6e4}),t.deleteBranch===!0&&i)try{_("git",["-C",r,"branch","-D",i],{windowsHide:!0,stdio:"pipe",timeout:3e4})}catch(n){const c=String(n.stderr||n);if(!/not found|not exist/i.test(c))throw n}}else l.rmSync(o,{recursive:!0,force:!0,maxRetries:2,retryDelay:200});return{removed:!0,branchDeleted:!!(s&&t.deleteBranch===!0&&i)}}function ht(t){const e=p(String(t.rootPath||"")),r=g(String(t.relativePath||"")),o=v(e,r,!0),i=Math.max(0,Number(t.offset||0)),s=Math.min(300,Math.max(20,Number(t.limit||200))),n=t.sort==="modified-desc"||t.sort==="modified-asc"?t.sort:"name",c=l.readdirSync(o,{withFileTypes:!0}).filter(a=>!a.isSymbolicLink()).map(a=>({name:a.name,path:J(e,u.join(o,a.name)),type:a.isDirectory()?"directory":a.isFile()?"file":"other",hidden:a.name.startsWith("."),extension:a.isFile()?u.extname(a.name).slice(1).toLowerCase():"",modifiedAt:n==="name"?void 0:wt(u.join(o,a.name))})).filter(a=>a.type!=="other").sort((a,f)=>{if(a.type!==f.type)return a.type==="directory"?-1:1;if(n!=="name"){if(a.modifiedAt==null&&f.modifiedAt!=null)return 1;if(f.modifiedAt==null&&a.modifiedAt!=null)return-1;const P=(a.modifiedAt??0)-(f.modifiedAt??0);if(P)return n==="modified-desc"?-P:P}return a.name.localeCompare(f.name,void 0,{numeric:!0,sensitivity:"base"})}),d=c.slice(i,i+s);return{path:r,rootKind:t.rootKind==="worktree"?"worktree":"project",items:d,total:c.length,nextOffset:i+d.length<c.length?i+d.length:null}}function wt(t){try{const e=l.lstatSync(t);return e.isSymbolicLink()?null:e.mtimeMs}catch{return null}}async function yt(t){const e=String(t.uploadId||"").trim();if(!e)throw new Error("项目上传任务缺少 uploadId。");const r=p(String(t.rootPath||"")),o=g(String(t.relativeDirectory||"")),i=v(r,o,!0),s=H(String(t.fileName||"")),n=Number(t.sizeBytes),c=String(t.sha256||"").trim().toLowerCase();if(!Number.isSafeInteger(n)||n<0)throw new Error("项目上传文件大小无效。");if(!/^[0-9a-f]{64}$/.test(c))throw new Error("项目上传文件摘要无效。");const d=u.join(i,`.aca-upload-${I()}.tmp`);try{const a=await it(`/api/client/project-uploads/${encodeURIComponent(e)}`,d,{maxBytes:n,timeoutMs:3e5});if(a.sizeBytes!==n)throw new Error("项目上传文件大小校验失败。");if(a.sha256.toLowerCase()!==c)throw new Error("项目上传文件完整性校验失败。");const f=Pt(r,o,s,d);return{name:u.basename(f),path:J(r,f),directory:o,size:a.sizeBytes,sha256:a.sha256,renamed:u.basename(f)!==s,rootKind:t.rootKind==="worktree"?"worktree":"project"}}finally{l.rmSync(d,{force:!0})}}function gt(t){const e=p(String(t.rootPath||"")),r=t.action&&typeof t.action=="object"?t.action:{};if(r.type==="delete")return St(e,String(r.path||""),r.recursive===!0,t.rootKind);throw new Error("project_file_operation_unsupported")}function St(t,e,r,o){const i=g(e);if(!i)throw new Error("project_file_root_protected");_t(i);const s=i.split("/"),n=s.slice(0,-1).join("/"),c=v(t,n,!0),d=u.join(c,s.at(-1)||"");let a;try{a=l.lstatSync(d)}catch(f){throw f.code==="ENOENT"?new Error("project_file_not_found"):f}if(a.isSymbolicLink())throw new Error("project_file_symbolic_link");if(!a.isFile()&&!a.isDirectory())throw new Error("project_file_type_unsupported");if(a.isDirectory()&&!r&&l.readdirSync(d).length>0)throw new Error("project_directory_not_empty");return a.isDirectory()&&r?l.rmSync(d,{recursive:!0,force:!1,maxRetries:2,retryDelay:150}):a.isDirectory()?l.rmdirSync(d):l.unlinkSync(d),{operation:"delete",path:i,entryType:a.isDirectory()?"directory":"file",parentPath:n,affectedDirectories:[n],rootKind:o==="worktree"?"worktree":"project"}}function _t(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 i=p(t),s=g(e),n=v(i,s,!0),c=H(r);if(l.realpathSync.native(u.dirname(o))!==n)throw new Error("项目上传临时文件不在目标目录中。");const a=l.lstatSync(o);if(!a.isFile()||a.isSymbolicLink())throw new Error("项目上传临时文件无效。");for(let f=1;f<=1e4;f+=1){const P=f===1?c:Et(c,f),S=u.join(n,P);try{return l.linkSync(o,S),l.chmodSync(S,420),l.rmSync(o,{force:!0}),S}catch(A){if(G(A))continue;if(!xt(A))throw A;try{return l.copyFileSync(o,S,l.constants.COPYFILE_EXCL),l.chmodSync(S,420),l.rmSync(o,{force:!0}),S}catch(N){if(G(N))continue;throw N}}}throw new Error("同名文件过多,无法生成可用文件名。")}function H(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 Et(t,e){const r=u.extname(t);return`${r?t.slice(0,-r.length):t} (${e})${r}`}function G(t){return!!(t&&typeof t=="object"&&t.code==="EEXIST")}function xt(t){const e=t&&typeof t=="object"?t.code:"";return["EPERM","EACCES","EXDEV","ENOTSUP","EOPNOTSUPP"].includes(String(e||""))}const W=500,j=2*1024*1024,y=2*1024*1024;function B(t){const e=p(String(t.rootPath||""));if(!w(e))return{isRepository:!1,branch:null,files:[],ahead:0,behind:0};const o=m(e,["status","--porcelain=v1","-z","--untracked-files=all","--no-renames"],j).split("\0").filter(Boolean).slice(0,W),i=o.map(c=>kt(c)).filter(c=>!!c),s=D(m(e,["diff","--no-ext-diff","--numstat","-z","--no-renames","HEAD","--","."],j));for(const c of i){const d=s.get(c.path);if(d)c.additions=d.additions,c.deletions=d.deletions;else if(c.status==="untracked"){const a=U(e,c.path);c.additions=a.additions,c.deletions=a.deletions}}const n=Tt(e);return{isRepository:!0,branch:Nt(e),files:i,ahead:n.ahead,behind:n.behind,truncated:o.length>=W}}function bt(t){const e=p(String(t.rootPath||"")),r=g(String(t.relativePath||""));if(!r)throw new Error("Diff 文件路径不能为空。");if(!w(e))return{isRepository:!1,path:r,diff:"",additions:0,deletions:0};const o=K(e,r),i=Ct(e,r),s=i?m(e,["diff","--no-ext-diff","--unified=80","HEAD","--",r],y):X(e,["diff","--no-ext-diff","--no-index","--unified=80",process.platform==="win32"?"NUL":"/dev/null",o],y),n=i?D(m(e,["diff","--no-ext-diff","--numstat","-z","--no-renames","HEAD","--",r],32*1024)).get(r):U(e,r);return{isRepository:!0,path:r,diff:V(s),additions:n?.additions??0,deletions:n?.deletions??0,truncated:s.length>y}}function jt(t){const e=p(String(t.rootPath||""));if(!w(e))return{isRepository:!1,items:[]};if(!$t(e))return{isRepository:!0,items:[]};const r=Math.min(200,Math.max(20,Number(t.limit||100)));return{isRepository:!0,items:m(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"],j).split("").map(n=>At(n)).filter(n=>!!n),limit:r}}function vt(t){const e=p(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};m(e,["cat-file","-e",`${r}^{commit}`],8*1024);const o=m(e,["show","--no-ext-diff","--no-color","--format=","--stat","--patch","--unified=40",r],y),i=[...D(m(e,["show","--no-ext-diff","--numstat","-z","--no-renames","--format=",r],j)).values()];return{isRepository:!0,commit:r,diff:V(o),additions:i.reduce((s,n)=>s+(n.additions||0),0),deletions:i.reduce((s,n)=>s+(n.deletions||0),0),changedFiles:i.length,truncated:o.length>y}}function At(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 kt(t){if(t.length<4)return null;const e=t[0]||" ",r=t[1]||" ",o=g(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 D(t){const e=new Map;for(const r of t.split("\0")){if(!r)continue;const o=z(r);if(!o||!o.path)continue;const i=g(o.path);i&&e.set(i,{additions:o.additions,deletions:o.deletions})}return e}function U(t,e){const r=K(t,e),i=X(t,["diff","--no-ext-diff","--no-index","--numstat","-z","--",process.platform==="win32"?"NUL":"/dev/null",r],32*1024).split("\0",1)[0]||"",s=z(i);return s?{additions:s.additions,deletions:s.deletions}:{additions:null,deletions:null}}function z(t){const e=t.indexOf(" "),r=e<0?-1:t.indexOf(" ",e+1);if(e<0||r<0)return null;const o=t.slice(0,e),i=t.slice(e+1,r);return{additions:/^\d+$/.test(o)?Number(o):null,deletions:/^\d+$/.test(i)?Number(i):null,path:t.slice(r+1)}}function w(t){try{return m(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 Dt(t,e){try{const r=m(t,["rev-list","--count",`${e}..HEAD`],8192).trim(),o=Number(r);return Number.isSafeInteger(o)&&o>0?o:0}catch{return 0}}function Rt(t){try{return l.readdirSync(t).length>0}catch{return!1}}function Ct(t,e){try{return m(t,["ls-files","--error-unmatch","--",e],8*1024),!0}catch{return!1}}function $t(t){try{return m(t,["rev-parse","--verify","HEAD"],8*1024),!0}catch{return!1}}function Nt(t){try{return m(t,["symbolic-ref","--quiet","--short","HEAD"],8*1024).trim()||null}catch{try{return`HEAD (${m(t,["rev-parse","--short","HEAD"],8*1024).trim()})`}catch{return null}}}function Tt(t){try{const e=m(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 K(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 m(t,e,r){return _("git",["-C",t,...e],{windowsHide:!0,encoding:"utf8",timeout:2e4,maxBuffer:r,stdio:["ignore","pipe","pipe"]})}function X(t,e,r){try{return m(t,e,r)}catch(o){const i=String(o.stdout||"");if(i)return i;if(Number(o.status)===1)return"";throw o}}function V(t){return t.length<=y?t:`${t.slice(0,y)}
2
2
 
3
- [Diff 内容过大,已截断]`}function Nt(){const t=process.platform,e=R(t);return{platform:t,roots:e}}function Tt(t){if(!t.directoryPath.trim())throw new Error("目录路径不能为空。");return process.platform==="win32"?Mt(t.directoryPath,!!t.includeHidden):Lt(t.directoryPath,!!t.includeHidden)}function h(t,e=process.platform){const r=e==="win32"?u.win32:u.posix,o=r.normalize(t),i=r.parse(o).root,s=o.length>i.length?o.replace(/[\\/]+$/,""):o;return e==="win32"?s.toLocaleLowerCase("en-US"):s}function It(){const t=l.realpathSync(F.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 R(t){if(b?.platform===t&&b.expiresAtMs>Date.now())return b.roots;const e=t==="win32"?Ft():It();return b={platform:t,roots:e,expiresAtMs:Date.now()+lt},e}function Ft(){const t=l.realpathSync.native(F.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=Z(M(r));for(const i of o){const s=String(i.Root||"");if(!s)continue;const n=Number(i.DriveType||0),c=String(i.Name||s.replace(/[\\/]+$/,"")),d=String(i.VolumeName||"").trim();e.set(h(s,"win32"),{id:`drive-${c.replace(/[^a-z0-9]+/gi,"").toLowerCase()}`,label:d?`${d} (${c})`:zt(c,n),path:s,kind:Ut(n),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 Lt(t,e){const r=C(t),i=l.readdirSync(r,{withFileTypes:!0}).filter(n=>n.isDirectory()&&!n.isSymbolicLink()&&(e||!n.name.startsWith("."))),s=i.slice(0,x).map(n=>({name:n.name,path:u.join(r,n.name),kind:"directory",hidden:n.name.startsWith("."),hasChildren:!0}));return s.sort((n,c)=>n.name.localeCompare(c.name,void 0,{numeric:!0,sensitivity:"base"})),Y(r,s,i.length>x,"linux")}function Mt(t,e){const r=C(t),o=["$items = Get-ChildItem -LiteralPath $env:ACA_MACHINE_FS_PATH -Directory -Force -ErrorAction Stop | ForEach-Object {"," [PSCustomObject]@{ Name = $_.Name; FullName = $_.FullName; Attributes = $_.Attributes.ToString() }","}","@($items) | ConvertTo-Json -Compress"].join(`
5
- `),i=Z(M(o,{ACA_MACHINE_FS_PATH:r})),s=i.map(n=>{const c=String(n.Attributes||"");return{name:String(n.Name||""),path:String(n.FullName||""),kind:"directory",hidden:/Hidden|System/i.test(c),hasChildren:!0,reparsePoint:/ReparsePoint/i.test(c)}}).filter(n=>n.name&&n.path&&!n.reparsePoint&&(e||!n.hidden)).slice(0,x).sort((n,c)=>n.name.localeCompare(c.name,void 0,{numeric:!0,sensitivity:"base"}));return Y(r,s,i.length>x,"win32")}function Y(t,e,r,o){const i=o==="win32"?u.win32:u.posix,s=i.parse(t).root,n=h(t,o)===h(s,o)?null:i.dirname(t);return{platform:o,path:t,parentPath:n,breadcrumbs:Ot(t,o),readable:Q(t,l.constants.R_OK),writable:Q(t,l.constants.W_OK),items:e,truncated:r}}function Ot(t,e){const r=e==="win32"?u.win32:u.posix,o=r.parse(t),i=t.slice(o.root.length).split(/[\\/]+/).filter(Boolean),s=[{label:o.root.replace(/[\\/]+$/,"")||o.root,path:o.root}];let n=o.root;for(const c of i)n=r.join(n,c),s.push({label:c,path:n});return s}async function Ht(t){const e=String(t.workspaceId||"").trim(),r=String(t.name||"").trim(),o=t.projectType==="chat_room"?"chat_room":"project";if(!e||!r)throw new Error("项目名称和工作区不能为空。");const i=C(String(t.path||""));l.accessSync(i,l.constants.R_OK|l.constants.W_OK);const s=L().machineId,c=(await E("GET",`/api/projects?workspaceId=${encodeURIComponent(e)}`)).items.find(a=>(!a.machine_id||a.machine_id===s)&&h(a.root_path)===h(i)),d=c||(await E("POST","/api/projects",{projectId:I(),workspaceId:e,name:r,rootPath:i,source:"aica",projectType:o})).item;return ot(Gt(d)),{project:d,duplicate:!!c}}function Gt(t){return{projectId:t.project_id,workspaceId:t.workspace_id,name:t.name,rootPath:t.root_path}}function C(t){if(!t.trim()||!u.isAbsolute(t))throw new Error("必须选择绝对目录路径。");if(Wt(t),!l.statSync(t).isDirectory())throw new Error("选择的路径不是目录。");const r=l.realpathSync.native(t);return Bt(r),r}function p(t){const e=$(t),r=l.realpathSync.native(e);if(!l.statSync(r).isDirectory())throw new Error("项目根目录不存在。");return r}function $(t){const e=nt(t);if(!e||!u.isAbsolute(e))throw new Error("项目根目录无效。");return u.resolve(e)}function g(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 v(t,e,r){const o=e?u.join(t,...e.split("/")):t,i=l.realpathSync.native(o),s=u.relative(t,i);if(s.startsWith("..")||u.isAbsolute(s))throw new Error("目录超出项目范围。");const n=l.statSync(i);if(r&&!n.isDirectory())throw new Error("请求路径不是目录。");return i}function J(t,e){return u.relative(t,e).split(u.sep).join("/")}function Wt(t){const e=process.platform==="win32"?u.win32:u.posix;if(!R(process.platform).some(o=>{const i=String(o.path||"");if(!i)return!1;const s=e.relative(i,t);return s===""||!s.startsWith("..")&&!e.isAbsolute(s)}))throw new Error("目录不在允许浏览的位置内。")}function Bt(t){const e=process.platform==="win32"?u.win32:u.posix;if(!R(process.platform).some(o=>{const i=String(o.path||"");if(!i)return!1;const s=e.relative(i,t);return s===""||!s.startsWith("..")&&!e.isAbsolute(s)}))throw new Error("目录不在允许浏览的位置内。")}function Q(t,e){try{return l.accessSync(t,e),!0}catch{return!1}}function Z(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 Ut(t){return t===2?"removable":t===3?"fixed":t===4?"network":t===5?"optical":"drive"}function zt(t,e){return e===2?`移动磁盘 (${t})`:e===4?`网络驱动器 (${t})`:e===5?`光驱 (${t})`:`本地磁盘 (${t})`}export{ft as cleanupWorktree,St as commitProjectUploadTempFile,dt as commitWorktree,h as comparableMachinePath,bt as getProjectGitCommit,Et as getProjectGitDiff,xt as getProjectGitLog,B as getProjectGitStatus,k as getWorktreeStatus,Tt as listMachineDirectory,Nt as listMachineFilesystemRoots,mt as listProjectDirectory,wt as mutateProjectFiles,ce as startMachineFilesystemWorkerLoop,ht as uploadProjectFile};
3
+ [Diff 内容过大,已截断]`}function It(){const t=process.platform,e=R(t);return{platform:t,roots:e}}function Ft(t){if(!t.directoryPath.trim())throw new Error("目录路径不能为空。");return process.platform==="win32"?Ht(t.directoryPath,!!t.includeHidden):Ot(t.directoryPath,!!t.includeHidden)}function h(t,e=process.platform){const r=e==="win32"?u.win32:u.posix,o=r.normalize(t),i=r.parse(o).root,s=o.length>i.length?o.replace(/[\\/]+$/,""):o;return e==="win32"?s.toLocaleLowerCase("en-US"):s}function Mt(){const t=l.realpathSync(F.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 R(t){if(b?.platform===t&&b.expiresAtMs>Date.now())return b.roots;const e=t==="win32"?Lt():Mt();return b={platform:t,roots:e,expiresAtMs:Date.now()+dt},e}function Lt(){const t=l.realpathSync.native(F.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=Z(L(r));for(const i of o){const s=String(i.Root||"");if(!s)continue;const n=Number(i.DriveType||0),c=String(i.Name||s.replace(/[\\/]+$/,"")),d=String(i.VolumeName||"").trim();e.set(h(s,"win32"),{id:`drive-${c.replace(/[^a-z0-9]+/gi,"").toLowerCase()}`,label:d?`${d} (${c})`:Xt(c,n),path:s,kind:Kt(n),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 Ot(t,e){const r=C(t),i=l.readdirSync(r,{withFileTypes:!0}).filter(n=>n.isDirectory()&&!n.isSymbolicLink()&&(e||!n.name.startsWith("."))),s=i.slice(0,x).map(n=>({name:n.name,path:u.join(r,n.name),kind:"directory",hidden:n.name.startsWith("."),hasChildren:!0}));return s.sort((n,c)=>n.name.localeCompare(c.name,void 0,{numeric:!0,sensitivity:"base"})),Y(r,s,i.length>x,"linux")}function Ht(t,e){const r=C(t),o=["$items = Get-ChildItem -LiteralPath $env:ACA_MACHINE_FS_PATH -Directory -Force -ErrorAction Stop | ForEach-Object {"," [PSCustomObject]@{ Name = $_.Name; FullName = $_.FullName; Attributes = $_.Attributes.ToString() }","}","@($items) | ConvertTo-Json -Compress"].join(`
5
+ `),i=Z(L(o,{ACA_MACHINE_FS_PATH:r})),s=i.map(n=>{const c=String(n.Attributes||"");return{name:String(n.Name||""),path:String(n.FullName||""),kind:"directory",hidden:/Hidden|System/i.test(c),hasChildren:!0,reparsePoint:/ReparsePoint/i.test(c)}}).filter(n=>n.name&&n.path&&!n.reparsePoint&&(e||!n.hidden)).slice(0,x).sort((n,c)=>n.name.localeCompare(c.name,void 0,{numeric:!0,sensitivity:"base"}));return Y(r,s,i.length>x,"win32")}function Y(t,e,r,o){const i=o==="win32"?u.win32:u.posix,s=i.parse(t).root,n=h(t,o)===h(s,o)?null:i.dirname(t);return{platform:o,path:t,parentPath:n,breadcrumbs:Gt(t,o),readable:Q(t,l.constants.R_OK),writable:Q(t,l.constants.W_OK),items:e,truncated:r}}function Gt(t,e){const r=e==="win32"?u.win32:u.posix,o=r.parse(t),i=t.slice(o.root.length).split(/[\\/]+/).filter(Boolean),s=[{label:o.root.replace(/[\\/]+$/,"")||o.root,path:o.root}];let n=o.root;for(const c of i)n=r.join(n,c),s.push({label:c,path:n});return s}async function Wt(t){const e=String(t.workspaceId||"").trim(),r=String(t.name||"").trim(),o=t.projectType==="chat_room"?"chat_room":"project";if(!e||!r)throw new Error("项目名称和工作区不能为空。");const i=C(String(t.path||""));l.accessSync(i,l.constants.R_OK|l.constants.W_OK);const s=M().machineId,c=(await E("GET",`/api/projects?workspaceId=${encodeURIComponent(e)}`)).items.find(a=>(!a.machine_id||a.machine_id===s)&&h(a.root_path)===h(i)),d=c||(await E("POST","/api/projects",{projectId:I(),workspaceId:e,name:r,rootPath:i,source:"aica",projectType:o})).item;return nt(Bt(d)),{project:d,duplicate:!!c}}function Bt(t){return{projectId:t.project_id,workspaceId:t.workspace_id,name:t.name,rootPath:t.root_path}}function C(t){if(!t.trim()||!u.isAbsolute(t))throw new Error("必须选择绝对目录路径。");if(Ut(t),!l.statSync(t).isDirectory())throw new Error("选择的路径不是目录。");const r=l.realpathSync.native(t);return zt(r),r}function p(t){const e=$(t),r=l.realpathSync.native(e);if(!l.statSync(r).isDirectory())throw new Error("项目根目录不存在。");return r}function $(t){const e=at(t);if(!e||!u.isAbsolute(e))throw new Error("项目根目录无效。");return u.resolve(e)}function g(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 v(t,e,r){const o=e?u.join(t,...e.split("/")):t,i=l.realpathSync.native(o),s=u.relative(t,i);if(s.startsWith("..")||u.isAbsolute(s))throw new Error("目录超出项目范围。");const n=l.statSync(i);if(r&&!n.isDirectory())throw new Error("请求路径不是目录。");return i}function J(t,e){return u.relative(t,e).split(u.sep).join("/")}function Ut(t){const e=process.platform==="win32"?u.win32:u.posix;if(!R(process.platform).some(o=>{const i=String(o.path||"");if(!i)return!1;const s=e.relative(i,t);return s===""||!s.startsWith("..")&&!e.isAbsolute(s)}))throw new Error("目录不在允许浏览的位置内。")}function zt(t){const e=process.platform==="win32"?u.win32:u.posix;if(!R(process.platform).some(o=>{const i=String(o.path||"");if(!i)return!1;const s=e.relative(i,t);return s===""||!s.startsWith("..")&&!e.isAbsolute(s)}))throw new Error("目录不在允许浏览的位置内。")}function Q(t,e){try{return l.accessSync(t,e),!0}catch{return!1}}function Z(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 Kt(t){return t===2?"removable":t===3?"fixed":t===4?"network":t===5?"optical":"drive"}function Xt(t,e){return e===2?`移动磁盘 (${t})`:e===4?`网络驱动器 (${t})`:e===5?`光驱 (${t})`:`本地磁盘 (${t})`}export{pt as cleanupWorktree,Pt as commitProjectUploadTempFile,mt as commitWorktree,h as comparableMachinePath,vt as getProjectGitCommit,bt as getProjectGitDiff,jt as getProjectGitLog,B as getProjectGitStatus,k as getWorktreeStatus,Ft as listMachineDirectory,It as listMachineFilesystemRoots,ht as listProjectDirectory,gt as mutateProjectFiles,fe as startMachineFilesystemWorkerLoop,yt as uploadProjectFile};
@@ -1 +1 @@
1
- import{execFileSync as m}from"node:child_process";import i from"node:fs";import l from"node:os";import u from"node:path";import{resolveCodexPath as f}from"../acp/providers/codex/codex-process.js";const d=360*60*1e3,p="aica-provider-probe-",E=3600*1e3;let c=null;function A(){const t=Date.now();if(c&&c.expiresAtMs>t)return c.items;const e={codex:s(f()),mimo:s(process.env.ACA_MIMO_COMMAND||"mimo"),opencode:s(process.env.ACA_OPENCODE_COMMAND||"opencode")};return c={expiresAtMs:t+d,items:e},e}function s(t){const e=Date.now();let r=null;try{_(e),r=i.mkdtempSync(u.join(l.tmpdir(),p));const o=m(t,["--version"],{windowsHide:!0,encoding:"utf8",timeout:8e3,maxBuffer:256*1024,stdio:["ignore","pipe","pipe"],env:{...process.env,TMPDIR:r,TEMP:r,TMP:r}});return{available:!0,status:"ready",version:v(o),checkedAtMs:e,errorCode:null}}catch(o){const n=y(o);return{available:!1,status:n==="ENOENT"?"unavailable":"error",version:null,checkedAtMs:e,errorCode:n==="ENOENT"?"not_installed":"probe_failed"}}finally{r&&i.rmSync(r,{recursive:!0,force:!0})}}function _(t){const e=l.tmpdir();let r;try{r=i.readdirSync(e).filter(o=>o.startsWith(p))}catch{return}for(const o of r){const n=u.join(e,o);try{const a=i.lstatSync(n);if(!a.isDirectory()||t-a.mtimeMs<E)continue;i.rmSync(n,{recursive:!0,force:!0})}catch{}}}function v(t){const e=t.split(/\r?\n/).map(r=>r.trim()).find(Boolean);return e?e.slice(0,120):null}function y(t){if(!t||typeof t!="object")return null;const e=t.code;return typeof e=="string"?e:null}export{s as probeProvider,A as providerHealthSnapshot};
1
+ import{resolveInstalledLaunch as m}from"./provider-install-paths.js";import{execFileSync as f}from"node:child_process";import c from"node:fs";import l from"node:os";import u from"node:path";import{resolveCodexPath as v}from"../acp/providers/codex/codex-process.js";import{resolveWorkBuddyExecutable as y}from"../acp/providers/workbuddy/launch.js";const D=360*60*1e3,d="aica-provider-probe-",_=3600*1e3;let s=null;function T(){s=null}function B(){const e=Date.now();if(s&&s.expiresAtMs>e)return s.items;const r={codex:a(v()),mimo:p("mimo"),opencode:p("opencode"),workbuddy:b()};return s={expiresAtMs:e+D,items:r},r}function p(e){const r=m(e);return a(r.command,[...r.args,"--version"])}function b(){try{const e=y(process.env.ACA_WORKBUDDY_COMMAND||process.env.ACA_CODEBUDDY_COMMAND||"codebuddy");return a(e.command,[...e.args,"--version"])}catch{return{available:!1,status:"error",version:null,checkedAtMs:Date.now(),errorCode:"probe_failed"}}}function a(e,r=["--version"]){const o=Date.now();let t=null;try{E(o),t=c.mkdtempSync(u.join(l.tmpdir(),d));const n=f(e,r,{windowsHide:!0,encoding:"utf8",timeout:8e3,maxBuffer:256*1024,stdio:["ignore","pipe","pipe"],env:{...process.env,TMPDIR:t,TEMP:t,TMP:t}});return{available:!0,status:"ready",version:h(n),checkedAtMs:o,errorCode:null}}catch(n){const i=M(n);return{available:!1,status:i==="ENOENT"?"unavailable":"error",version:null,checkedAtMs:o,errorCode:i==="ENOENT"?"not_installed":"probe_failed"}}finally{t&&c.rmSync(t,{recursive:!0,force:!0})}}function E(e){const r=l.tmpdir();let o;try{o=c.readdirSync(r).filter(t=>t.startsWith(d))}catch{return}for(const t of o){const n=u.join(r,t);try{const i=c.lstatSync(n);if(!i.isDirectory()||e-i.mtimeMs<_)continue;c.rmSync(n,{recursive:!0,force:!0})}catch{}}}function h(e){const r=e.split(/\r?\n/).map(o=>o.trim()).find(Boolean);return r?r.slice(0,120):null}function M(e){if(!e||typeof e!="object")return null;const r=e.code;return typeof r=="string"?r:null}export{a as probeProvider,B as providerHealthSnapshot,T as resetProviderHealth};
@@ -0,0 +1 @@
1
+ import e from"node:fs";import a from"node:path";import{Readable as $}from"node:stream";import{pipeline as l}from"node:stream/promises";import{createHash as y}from"node:crypto";import{providerPackages as h}from"./provider-install-paths.js";async function z(c,r,w){const o=process.platform==="win32"?"windows":process.platform;if(!["linux","darwin","windows"].includes(o)||!["x64","arm64"].includes(process.arch))throw new Error("unsupported-platform");const u=o==="linux"&&(e.existsSync("/etc/alpine-release")||!process.report.getReport().header.glibcVersionRuntime),x=`mimocode-${o}-${process.arch}${process.arch==="x64"?"-baseline":""}${u?"-musl":""}`,n=o==="linux"?".tar.gz":".zip",m=`https://mimocode.cnbj1.mi-fds.com/mimocode/mimocode/releases/v${h.mimo.version}/${x}${n}`,t=a.join(c,`mimo${n}`),i=await fetch(m,{signal:r});if(!i.ok||!i.body)throw new Error("download-failed");await l($.fromWeb(i.body),e.createWriteStream(t),{signal:r});const p=await fetch(`${m}.sha256`,{signal:AbortSignal.any([r,AbortSignal.timeout(3e4)])}).catch(()=>null);if(p?.ok){const d=(await p.text()).trim().split(/\s+/)[0];if(/^[a-f0-9]{64}$/i.test(d)){const f=y("sha256");if(await l(e.createReadStream(t),f,{signal:r}),f.digest("hex")!==d.toLowerCase())throw new Error("checksum-mismatch")}}const s=a.join(c,"node_modules",h.mimo.package,"vendor");e.mkdirSync(s,{recursive:!0}),await w("tar",[o==="linux"?"-xzf":"-xf",t,"-C",s]);const b=a.join(s,o==="windows"?"mimo.exe":"mimo");e.chmodSync(b,493),e.rmSync(t,{force:!0})}export{z as prepareMimoBinary};
@@ -0,0 +1 @@
1
+ import r from"node:fs";import t from"node:path";import{isSea as x}from"node:sea";import{getAcaHome as y}from"./paths.js";const l={codex:{package:"@openai/codex",version:"0.163.0",command:"codex",env:"CODEX_PATH"},mimo:{package:"@mimo-ai/cli",version:"0.1.16",command:"mimo",env:"ACA_MIMO_COMMAND"},opencode:{package:"opencode-ai",version:"1.19.5",command:"opencode",env:"ACA_OPENCODE_COMMAND"},workbuddy:{package:"@tencent-ai/codebuddy-code",version:"2.179.3",command:"codebuddy",env:"ACA_WORKBUDDY_COMMAND"}};function E(e){return Object.hasOwn(l,e)}function g(e){return t.resolve(y(),"providers",e)}function b(e){try{const o=g(e),n=JSON.parse(r.readFileSync(t.join(o,"current.json"),"utf8"));return/^[a-f0-9-]{36}$/.test(n.release)?O(e,t.join(o,n.release)):null}catch{return null}}function A(){return x()||process.env.ACA_SINGLE_FILE_WORKER==="1"?process.env.ACA_PROVIDER_NODE||"node":process.execPath}function k(e){const o=l[e],n=process.env[o.env];if(n)return{command:n,args:[]};const s=b(e);return s?S(s):{command:o.command,args:[]}}function O(e,o){const n=l[e],s=t.join(o,"node_modules",n.package);try{if(e==="mimo"){const i=t.join(s,"vendor",process.platform==="win32"?"mimo.exe":"mimo");return r.existsSync(i)?i:null}if(e==="opencode"){const p=`opencode-${process.platform==="win32"?"windows":process.platform}-${process.arch}`,m=process.platform==="linux"&&(r.existsSync("/etc/alpine-release")||!process.report.getReport().header.glibcVersionRuntime)?"-musl":"",f=process.arch==="x64"?[`${p}-baseline${m}`,`${p}${m}`]:[`${p}${m}`];for(const v of f){const u=t.join(o,"node_modules",v,"bin",`${n.command}${process.platform==="win32"?".exe":""}`);if(r.existsSync(u))return u}return null}const c=JSON.parse(r.readFileSync(t.join(s,"package.json"),"utf8")),d=typeof c.bin=="string"?c.bin:c.bin?.[n.command];if(typeof d!="string")return null;const a=t.resolve(s,d);return!a.startsWith(s+t.sep)||!r.existsSync(a)?null:a}catch{return null}}function S(e){const o=r.openSync(e,"r");try{const n=Buffer.alloc(128);return r.readSync(o,n,0,n.length,0),/\.[cm]?js$/i.test(e)||/^#![^\r\n]*\bnode\b/.test(n.toString("utf8"))?{command:A(),args:[e]}:{command:e,args:[]}}finally{r.closeSync(o)}}export{S as entryLaunch,b as installedProviderEntry,E as isInstallProvider,O as packageEntry,g as providerInstallRoot,A as providerNode,l as providerPackages,k as resolveInstalledLaunch};
@@ -0,0 +1 @@
1
+ import{prepareMimoBinary as P}from"./provider-install-mimo.js";import{resetWorkBuddyDiscovery as O}from"../acp/providers/workbuddy/discovery.js";import{resolveCodexPath as h}from"../acp/providers/codex/codex-path.js";import u from"node:fs";import o from"node:path";import{spawn as C,execFileSync as D}from"node:child_process";import{randomUUID as L}from"node:crypto";import{isInstallProvider as _,providerPackages as E,providerInstallRoot as $,providerNode as x,packageEntry as G,entryLaunch as M}from"./provider-install-paths.js";import{managementActivity as H}from"./management/activity.js";import{resetProviderHealth as b}from"./provider-health.js";import{sendHeartbeat as U}from"./heartbeat.js";const a=new Map;let c=null,y=!1;function V(e){const r=String(e.provider||"");if(!_(r)||!["status","install"].includes(String(e.action)))throw new Error("无效的 Provider 安装操作");if(e.action==="status")return a.get(r)||{state:"idle",message:""};if(a.get(r)?.state==="installing")return a.get(r);if(c||y)return{state:"error",message:"Worker 正在安装其他 CLI 或退出,请稍后重试。"};if(process.env[E[r].env]||r==="workbuddy"&&process.env.ACA_CODEBUDDY_COMMAND)return{state:"error",message:"此 Provider 已指定自定义命令,请先在 Worker 配置中移除该覆盖项。"};a.set(r,{state:"installing",message:"正在下载并安装 CLI,关闭页面后仍会继续。"});const s={done:Promise.resolve(),controller:new AbortController};return c=s,s.done=F(r,s).finally(()=>{c===s&&(c=null)}),a.get(r)}async function F(e,r){const s=H.track("provider-install"),m=$(e),f=L(),n=o.join(m,f);let p=!1,i="准备 Node/npm";const g=setTimeout(()=>{r.controller.abort(),r.child&&N(r.child)},15*6e4);try{u.mkdirSync(n,{recursive:!0});const t=x(),d=D(t,["-p","process.execPath"],{encoding:"utf8",timeout:8e3,windowsHide:!0}).trim(),l=[o.join(o.dirname(d),"node_modules/npm/bin/npm-cli.js"),o.resolve(o.dirname(d),"../lib/node_modules/npm/bin/npm-cli.js")].find(w=>u.existsSync(w));if(!l)throw new Error("missing-npm");i="下载 npm 包",await I(d,[l,"install","--prefix",n,"--no-audit","--no-fund","--no-package-lock","--ignore-scripts","--include=optional","--registry=https://registry.npmjs.org",`${E[e].package}@${E[e].version}`],n,r,10*6e4),e==="mimo"&&(i="下载 MiMoCode 原生程序",a.set(e,{state:"installing",message:"正在从小米官方下载 MiMoCode 程序…"}),await P(n,r.controller.signal,(w,T)=>I(w,T,n,r,6e4))),i="验证 CLI",a.set(e,{state:"installing",message:"正在验证 CLI 能否启动…"});const v=G(e,n);if(!v)throw new Error("missing-entry");const S=M(e==="codex"?h({env:{...process.env,CODEX_PATH:v}}):v);await I(S.command,[...S.args,"--version"],n,r,6e4);const A=JSON.parse(u.readFileSync(o.join(n,"node_modules",E[e].package,"package.json"),"utf8")).version,k=o.join(m,`${f}.json`);u.writeFileSync(k,JSON.stringify({release:f})),u.renameSync(k,o.join(m,"current.json")),p=!0,b(),e==="workbuddy"&&O(),a.set(e,{state:"installed",message:"安装完成,正在同步设备状态。",version:String(A).slice(0,120)}),U().catch(()=>{})}catch(t){a.set(e,{state:"error",message:t instanceof Error&&(t.message==="npm-ENOSPC"||t.code==="ENOSPC")?"Worker 磁盘空间不足,请清理空间后重试安装。":t instanceof Error&&t.message==="missing-npm"?"Worker 的 Node 环境缺少 npm,请安装含 npm 的 Node.js 后重试。":`${i}失败,请检查 Node.js 版本、网络及磁盘权限后重试。${t instanceof Error&&/^npm-(ETARGET|EAI_AGAIN|ENOTFOUND|EACCES|ENOSPC|ECONNRESET|ETIMEDOUT|EBADENGINE)$/.test(t.message)?`(${t.message})`:""}`})}finally{clearTimeout(g);try{p||u.rmSync(n,{recursive:!0,force:!0})}catch{}s()}}function I(e,r,s,m,f){return new Promise((n,p)=>{if(y||m.controller.signal.aborted)return p(new Error("stopping"));const i=C(e,r,{cwd:s,windowsHide:!0,detached:process.platform!=="win32",stdio:["ignore","ignore","pipe"],env:{...process.env,PATH:o.isAbsolute(e)?`${o.dirname(e)}${o.delimiter}${process.env.PATH||""}`:process.env.PATH}});m.child=i;let g="";i.stderr?.on("data",l=>{g=(g+String(l)).slice(-16384)});let t=!1;const d=setTimeout(()=>{t=!0,N(i)},f);i.once("error",l=>{clearTimeout(d),p(l)}),i.once("close",l=>{clearTimeout(d),m.child=void 0,l===0&&!t?n():p(new Error(`npm-${/\b(ENOSPC|EACCES|ETARGET|EAI_AGAIN|ENOTFOUND|ECONNRESET|ETIMEDOUT|EBADENGINE)\b/.exec(g)?.[1]||"failed"}`))})})}async function Z(){y=!0,c?.controller.abort(),c?.child&&N(c.child),await c?.done}function N(e){if(!(!e.pid||e.exitCode!==null||e.signalCode!==null))if(process.platform==="win32"){const r=C("taskkill",["/pid",String(e.pid),"/T","/F"],{windowsHide:!0,stdio:"ignore"});r.once("error",()=>{e.kill("SIGKILL")}),r.once("close",s=>{s!==0&&e.kill("SIGKILL")})}else try{process.kill(-e.pid,"SIGKILL")}catch{e.kill("SIGKILL")}}export{V as providerInstallOperation,Z as stopProviderInstaller};
@@ -0,0 +1 @@
1
+ import{WorkBuddyAuthManager as r}from"../acp/providers/workbuddy/auth-manager.js";import{sendHeartbeat as a}from"./heartbeat.js";const n=new r(void 0,async()=>{await a()});export{n as workBuddyAuthManager};
@@ -0,0 +1,2 @@
1
+ import{randomUUID as S}from"node:crypto";import{setTimeout as T}from"node:timers/promises";import{acaServerRequest as l,AcaServerHttpError as A}from"../core/aca-server-client.js";import{INTERACTION_TIMEOUT_MS as v}from"./types.js";function U(a,n,d,s){const o=S(),w=new AbortController,r=AbortSignal.any([s,w.signal]),f=`/api/client/jobs/${encodeURIComponent(a)}`;let c=!1,g;const b=()=>g??=(async()=>{try{c=(await l("GET","/api/interactions/capabilities",void 0,{signal:r})).interactionVersion===1}catch(t){if(!(t instanceof A)||t.status!==404)throw t}c&&await l("POST",`${f}/interactions/runtime`,{machineId:n,runtimeId:o},{signal:r})})();async function M(t,m){if(await b(),m&&!c)throw new Error("ACA Server 不支持结构化回答,请先更新 Server;本次请求未提交给旧接口。");const h=m?t.interaction:void 0,u=h?{...h,runtimeId:o}:{version:1,kind:"approval",provider:d,method:t.method??"session/request_permission",requestId:t.requestId,runtimeId:o,expiresAtMs:t.expiresAtMs??Date.now()+v,prompt:x(t.params),options:t.options},y={machineId:n,request:{...t,...m?{kind:"elicitation"}:{},...c?{interaction:u}:{}}};let e;for(;!r.aborted&&Date.now()<u.expiresAtMs;){try{const i={signal:r,timeoutMs:Math.max(1,Math.min(15e3,u.expiresAtMs-Date.now()))};if(e?e=(await l("GET",`/api/client/permissions/${encodeURIComponent(e.permission_id)}`,void 0,i)).item:e=(await l("POST",`${f}/permissions`,y,i)).item,e.status!=="pending"){const p=e.response?.outcome;return e.status==="resolved"&&p?.outcome==="selected"&&!m&&t.options.some(I=>I.optionId===p.optionId)?{outcome:p}:e.status==="resolved"&&p?.outcome==="submitted"&&m?{outcome:p}:{outcome:{outcome:"cancelled"}}}}catch(i){if(r.aborted)break;if(i instanceof A&&i.status<500){if([404,409,410].includes(i.status))break;throw i}}await T(Math.min(1e3,Math.max(1,u.expiresAtMs-Date.now())),void 0,{signal:r}).catch(()=>{})}return{outcome:{outcome:"cancelled"}}}return{initialize:b,permission:t=>M(t,!1),input:t=>M(t,!0),close:async()=>{w.abort(),c&&await l("POST",`${f}/interactions/runtime`,{machineId:n,runtimeId:o,closed:!0},{timeoutMs:3e3}).catch(()=>{})}}}function x(a){const n=a&&typeof a=="object"?a:{},d=n.request??n,s=d.params??d;return[s.reason,s.description,s.command,s.title].filter(o=>typeof o=="string"&&o.trim()).join(`
2
+ `)||"Agent 请求继续执行。"}export{U as createJobInteractions};
@@ -0,0 +1 @@
1
+ import{randomUUID as E}from"node:crypto";import{INTERACTION_TIMEOUT_MS as q,validateInteractionAnswers as x}from"./types.js";const w="item/tool/requestUserInput",O="mcpServer/elicitation/request";function I(s){return s===w||s===O}function d(s){return s&&typeof s=="object"&&!Array.isArray(s)?s:{}}function S(s,i,p,c){const r=d(p),o=Object.keys(d(r.request)).length?d(r.request):r,e=typeof o.method=="string"?o.method:i;if(!(e==="elicitation/create"||(s==="native-codex"||s==="codex-acp")&&I(e)))throw new Error(`Unsupported user input method: ${e}`);const y=String(c??o.requestId??o.id??E()),u=String(o.prompt??o.message??o.question??"");let m,h="questions";if(e!==w&&o.requestedSchema){if(o.mode&&!["form","openai/form","openaiForm"].includes(String(o.mode)))throw new Error("Unsupported elicitation mode");h="form",m=U(o.requestedSchema)}else if(e===w&&Array.isArray(o.questions))m=o.questions.map(t=>{const n=d(t),f=Array.isArray(n.options)?n.options.map(g=>{const l=d(g),b=String(l.label??l.value??"");return{value:String(l.value??l.label??""),label:b,description:typeof l.description=="string"?l.description:void 0,recommended:l.recommended===!0||/\(Recommended\)|(推荐)|\(推荐\)/i.test(b)}}):void 0;if(n.multiple===!0||n.multiSelect===!0)throw new Error("Unsupported multi-select question protocol");return{id:String(n.id??""),label:String(n.question??n.title??""),description:typeof n.header=="string"?n.header:void 0,type:"string",required:!0,secret:n.isSecret===!0,allowOther:n.isOther===!0||!f?.length,options:f?.length?f:void 0}});else throw new Error("Unsupported user input payload: missing questions or form schema");if(!m.length||m.length>100||m.some(t=>!t.id||!t.label||["__proto__","constructor","prototype"].includes(t.id))||new Set(m.map(t=>t.id)).size!==m.length)throw new Error("Unsupported user input fields: missing/duplicate IDs or too many fields");return{requestId:y,prompt:u,params:p,interaction:{version:1,kind:h,provider:s,method:e,requestId:y,runtimeId:"",expiresAtMs:Date.now()+q,prompt:u,fields:m}}}function U(s){const i=d(s);if(i.type!=="object"||!i.properties)throw new Error("Unsupported elicitation schema: expected an object");const p=new Set(["type","properties","required","title","description","$schema","additionalProperties"]);if(Object.keys(i).some(r=>!p.has(r))||i.additionalProperties!==void 0&&i.additionalProperties!==!1||i.required!==void 0&&!Array.isArray(i.required))throw new Error("Unsupported form root validation");const c=Array.isArray(i.required)?i.required:[];if(c.some(r=>typeof r!="string"||!Object.hasOwn(d(i.properties),r)))throw new Error("Unsupported required field");return Object.entries(d(i.properties)).map(([r,o])=>{if(["__proto__","constructor","prototype"].includes(r))throw new Error("Unsupported field ID");const e=d(o),a=e.type==="array"?"string[]":e.type;if(!["string","number","integer","boolean","string[]"].includes(String(a)))throw new Error(`Unsupported form field type: ${r}`);const y=new Set(["type","title","description","enum","enumNames","oneOf","anyOf","items","default","minLength","maxLength","minimum","maximum","minItems","maxItems","uniqueItems","format"]);for(const t of Object.keys(e))if(!y.has(t))throw new Error(`Unsupported form validation: ${r}.${t}`);const u=a==="string[]"?d(e.items):e;if(a==="string[]"&&(u.type!=="string"||Object.keys(u).some(t=>!["type","enum","oneOf","anyOf","enumNames"].includes(t))))throw new Error(`Unsupported array item schema: ${r}`);if(["enum","oneOf","anyOf"].filter(t=>u[t]!==void 0).length>1)throw new Error(`Unsupported combined enum: ${r}`);for(const t of["enum","oneOf","anyOf"])if(u[t]!==void 0&&!Array.isArray(u[t]))throw new Error(`Unsupported enum schema: ${r}`);let m;if(Array.isArray(u.enum)){if(!u.enum.every(t=>typeof t=="string"))throw new Error(`Unsupported non-string enum: ${r}`);m=u.enum.map((t,n)=>({value:String(t),label:String(Array.isArray(u.enumNames)?u.enumNames[n]??t:t)}))}else(Array.isArray(u.oneOf)||Array.isArray(u.anyOf))&&(m=(Array.isArray(u.oneOf)?u.oneOf:u.anyOf).map(t=>{const n=d(t);if(typeof n.const!="string"||Object.keys(n).some(f=>!["const","title","description"].includes(f)))throw new Error(`Unsupported enum option: ${r}`);return{value:n.const,label:String(n.title??n.const),...typeof n.description=="string"?{description:n.description}:{}}}));if(a==="string[]"&&!m)throw new Error(`Unsupported free-form array: ${r}`);if(m&&(!m.length||new Set(m.map(t=>t.value)).size!==m.length||!["string","string[]"].includes(String(a))))throw new Error(`Unsupported enum field: ${r}`);if(e.format&&!["email","uri","date","password"].includes(String(e.format)))throw new Error(`Unsupported form format: ${r}`);for(const t of["minLength","maxLength","minimum","maximum","minItems","maxItems"]){const n=e[t],f=["minimum","maximum"].includes(t)?["number","integer"].includes(String(a)):t.endsWith("Length")?a==="string":a==="string[]";if(n!==void 0&&(!f||typeof n!="number"||!Number.isFinite(n)||!["minimum","maximum"].includes(t)&&(!Number.isSafeInteger(n)||n<0)))throw new Error(`Unsupported form bound: ${r}.${t}`)}if(e.format!==void 0&&a!=="string"||e.items!==void 0&&a!=="string[]"||e.uniqueItems!==void 0&&(a!=="string[]"||typeof e.uniqueItems!="boolean"))throw new Error(`Unsupported form constraints: ${r}`);for(const[t,n]of[["minimum","maximum"],["minLength","maxLength"],["minItems","maxItems"]]){const f=e[t],g=e[n];if(typeof f=="number"&&typeof g=="number"&&f>g)throw new Error(`Unsupported inverted bounds: ${r}`)}const h=Object.fromEntries(["minLength","maxLength","minimum","maximum","minItems","maxItems"].filter(t=>typeof e[t]=="number").map(t=>[t,e[t]]));return{id:r,label:String(e.title??r),description:typeof e.description=="string"?e.description:void 0,type:a,required:c.includes(r),secret:e.format==="password",options:m,...h,...typeof e.format=="string"?{format:e.format}:{},...e.default!==void 0&&e.format!=="password"?{defaultValue:e.default}:{}}})}async function _(s,i,p,c,r){const o=d(p);if(s==="codex-acp"&&o.acaInteractionBridge===1){const y=d(o.request);return c?c(y):{outcome:{outcome:"cancelled"}}}const e=S(s,i,p,r),a=c?await c(e):{outcome:{outcome:"cancelled"}};return A(e,a)}function A(s,i){const p=s.interaction;if(!p)throw new Error("Missing structured interaction contract");const c=i.outcome.outcome==="submitted",r=i.outcome.outcome==="submitted"?i.outcome.answers:void 0;if(c&&Object.keys(x(p,r)).length)throw new Error("Invalid structured answers");if(p.kind==="form")return{action:c?"accept":"cancel",content:c?Object.fromEntries(Object.entries(r).map(([o,e])=>[o,e.value])):null,...p.method===O?{_meta:null}:{}};if(p.method===w)return{answers:c?Object.fromEntries(Object.entries(r).map(([o,e])=>[o,{answers:Array.isArray(e.value)?e.value:[String(e.value)]}])):{}};throw new Error(`Unsupported interaction response method: ${p.method}`)}export{O as CODEX_FORM_METHOD,w as CODEX_QUESTIONS_METHOD,_ as handleProviderInput,I as isCodexInputMethod,S as normalizeProviderInput,d as object,A as providerInputResponse};
@@ -0,0 +1 @@
1
+ const c=6e5;function u(a,s){const t=Object.create(null);if(!s||typeof s!="object"||Array.isArray(s))return{_form:"请填写回答后提交。"};const o=s,f=a.fields??[];for(const e of Object.keys(o))f.some(r=>r.id===e)||(t[e]="回答包含未知字段。");for(const e of f){const r=Object.hasOwn(o,e.id)?o[e.id]:void 0;if(r===void 0){e.required&&(t[e.id]="此项为必填。");continue}if(!r||typeof r!="object"||Array.isArray(r)||Object.keys(r).some(n=>n!=="type"&&n!=="value")){t[e.id]="回答格式不正确。";continue}const i=r.value,d=e.type==="string[]"?Array.isArray(i)&&i.every(n=>typeof n=="string"):e.type==="integer"?typeof i=="number"&&Number.isSafeInteger(i):typeof i===e.type&&(typeof i!="number"||Number.isFinite(i));if(r.type!==e.type||!d){t[e.id]="回答类型不正确。";continue}if(typeof i=="string"){if(e.required&&!i.trim()&&(t[e.id]="此项为必填。"),i.length<(e.minLength??0)&&(t[e.id]=`至少填写 ${e.minLength} 个字符。`),i.length>Math.min(e.maxLength??16e3,16e3)&&(t[e.id]="填写内容过长。"),e.format==="email"&&!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(i)&&(t[e.id]="请输入有效的邮箱地址。"),e.format==="uri")try{new URL(i)}catch{t[e.id]="请输入完整的网址。"}e.format==="date"&&(!/^\d{4}-\d{2}-\d{2}$/.test(i)||!Number.isFinite(Date.parse(i))||new Date(i).toISOString().slice(0,10)!==i)&&(t[e.id]="请输入有效的日期。")}typeof i=="number"&&(i<(e.minimum??-1/0)||i>(e.maximum??1/0))&&(t[e.id]="数值超出允许范围。"),Array.isArray(i)&&((i.length<(e.minItems??(e.required?1:0))||i.length>(e.maxItems??100))&&(t[e.id]="选择数量不符合要求。"),new Set(i).size!==i.length&&(t[e.id]="不能重复选择同一项。")),e.options&&!e.allowOther&&(Array.isArray(i)?i:[i]).some(m=>!e.options.some(y=>y.value===m))&&(t[e.id]="请选择提供的选项。")}return t}export{c as INTERACTION_TIMEOUT_MS,u as validateInteractionAnswers};
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- const o="0.1.86";export{o as AICA_VERSION};
1
+ const o="0.1.88";export{o as AICA_VERSION};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuandc/aica",
3
- "version": "0.1.86",
3
+ "version": "0.1.88",
4
4
  "description": "AICA remote Agent worker",
5
5
  "author": "yuandc",
6
6
  "type": "module",