@yuandc/aica 0.1.78 → 0.1.79

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,4 +1,4 @@
1
- import{Command as I}from"commander";import C from"node:crypto";import h from"node:fs";import P from"node:os";import f from"node:path";import x from"node:readline/promises";import{stdin as S,stdout as c}from"node:process";import{extractCodexSession as _}from"../acp/providers/codex/session-import.js";import{acaServerRequest as s}from"../core/aca-server-client.js";import{loadAcaConfig as l,upsertLocalProject as E}from"../core/aca-config.js";import{applyRuntimePathOptions as T}from"../core/runtime-options.js";function Z(){return new I("codex").description("管理本机 Codex 会话").addCommand(new I("import").description("将本机 Codex Session 导入 ACA Project").argument("<session-id>","Codex Session ID").option("--aica-home <path>","Runtime home directory (defaults to ~/.aica)").option("--aica-config <path>","Config file path").option("--aca-home <path>","Deprecated alias for --aica-home").option("--aca-config <path>","Deprecated alias for --aica-config").option("--path <path>","项目目录,支持相对路径;默认使用当前目录").option("--workspace <id>","新建 Project 时使用的 Workspace ID").option("--project-name <name>","自动创建 Project 时使用的名称").option("--turns <count>","导入最近多少个 Codex Turn,范围 1-20","20").option("--detail <mode>","详情模式:auto、compact、standard 或 diagnostic","auto").option("--title <name>","导入后的 ACA Session 标题").option("--dry-run","只读取和校验,不写入 ACA Server").option("-y, --yes","跳过交互确认,适用于脚本或非交互环境").action(b))}async function b(t,e){T(e);const o=l();if(!o.token)throw new Error("Worker 尚未登录,请先执行 aica login。");await R();const r=await N(o.machineId,t);if(r){console.log(`Codex Session 已存在:session=${r.sessionId} project=${r.projectId} title=${r.title||"未命名"}`);return}const i=k(e.path||process.cwd()),d=q(e.turns),p=await v(),a=D(e.detail,p),n=await _({sessionId:t,turnLimit:d,detailMode:a,diffEnabled:a==="diagnostic"&&p.diffEnabled===!0});M(i,n.cwd);const m=await W({targetPath:i,workspaceId:e.workspace,projectName:e.projectName,machineId:o.machineId}),g=e.title?.trim()||n.title;if(e.dryRun){console.log(JSON.stringify({dryRun:!0,action:m.action,projectId:m.project.project_id,projectName:m.project.name,providerSessionId:n.providerSessionId,path:i,detailMode:a,turns:n.turns.length,truncated:n.truncated,title:g},null,2));return}if(!e.yes&&!await G({sessionId:n.providerSessionId,targetPath:i,plan:m,turnCount:n.turns.length,detailMode:a})){console.log("已取消导入。");return}const u=await A(m);await L();const j=await s("POST","/api/codex-session-imports",{projectId:u.project_id,workspaceId:u.workspace_id,machineId:o.machineId,title:g,import:n}),$=j.item;console.log(`${j.imported?"已导入":"已存在"} session=${String($.session_id||"")} project=${u.project_id} turns=${n.turns.length} mode=${a}`)}async function N(t,e){const o=new URLSearchParams({machineId:t,providerSessionId:e.trim()});try{const r=await s("GET",`/api/codex-session-imports/status?${o.toString()}`);return r.exists?r.item:null}catch(r){const i=r instanceof Error?r.message:String(r);if(/\b404\b/.test(i))return null;throw r}}async function L(){const t=l();await s("POST","/api/heartbeat",{machineId:t.machineId,machineName:t.machineName,workspaceId:t.defaultWorkspaceId,projects:t.projects.map(e=>({projectId:e.projectId,workspaceId:e.workspaceId,name:e.name,rootPath:e.rootPath}))})}async function R(){try{await s("GET","/api/auth/me")}catch(t){const e=t instanceof Error?t.message:String(t);throw/\b401\b|unauthorized/i.test(e)?new Error("Worker 登录已失效,请先执行 aica login 重新登录。"):t}}async function v(){try{return(await s("GET","/api/process-details/capabilities")).item||{}}catch{return{}}}function D(t,e){const o=String(t||"auto").trim().toLowerCase();if(o==="auto")return e.mode==="diagnostic"?"diagnostic":e.mode==="compact"?"compact":"standard";if(o==="compact"||o==="standard"||o==="diagnostic")return o;throw new Error("--detail 必须是 auto、compact、standard 或 diagnostic。")}async function W(t){const e=l(),o=e.projects.find(a=>t.workspaceId&&a.workspaceId!==t.workspaceId?!1:w(a.rootPath)===t.targetPath),r=t.workspaceId||o?.workspaceId||e.defaultWorkspaceId,i=await s("GET",`/api/projects?workspaceId=${encodeURIComponent(r)}`);if(o){const a=i.items.find(n=>n.project_id===o.projectId&&w(n.root_path)===t.targetPath);if(a)return{action:"reuse",project:a}}const d=i.items.find(a=>w(a.root_path)===t.targetPath);if(d)return{action:"attach",project:d};const p=t.projectName?.trim()||o?.name||f.basename(t.targetPath);return{action:"create",project:{project_id:o?.projectId||O(r,t.machineId,t.targetPath,p),workspace_id:r,name:p,root_path:t.targetPath}}}async function A(t){if(t.action==="reuse")return t.project;if(t.action==="attach")return y(t.project),t.project;const e=await s("POST","/api/projects",{projectId:t.project.project_id,workspaceId:t.project.workspace_id,name:t.project.name,rootPath:t.project.root_path,source:"aica-codex-import",projectType:"project"});return y(e.item),e.item}function y(t){E({projectId:t.project_id,workspaceId:t.workspace_id,name:t.name,rootPath:t.root_path})}function M(t,e){const o=h.realpathSync(e);if(t!==o)throw new Error(`指定目录与 Codex Session 工作目录不一致:path=${t} session=${o}`)}function k(t){const e=t==="~"?P.homedir():t.startsWith("~/")?f.join(P.homedir(),t.slice(2)):t,o=f.resolve(e);if(!h.existsSync(o)||!h.statSync(o).isDirectory())throw new Error(`Project 工作目录不存在:${o}`);return h.realpathSync(o)}function w(t){try{return k(t)}catch{return null}}function O(t,e,o,r){const i=r.toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"project",d=C.createHash("sha256").update(`${t}\0${e}\0${o}`).digest("hex").slice(0,12);return`aica-${i}-${d}`}async function G(t){if(!S.isTTY||!c.isTTY)throw new Error("当前为非交互环境,请确认参数无误后添加 --yes 执行导入。");const e=t.plan.action==="reuse"?`在已有 Project「${t.plan.project.name}」中创建 Session`:t.plan.action==="attach"?`将目录关联到已有 Project「${t.plan.project.name}」,再创建 Session`:`创建 Project「${t.plan.project.name}」,再创建 Session`;c.write(`
1
+ import{Command as j}from"commander";import C from"node:crypto";import h from"node:fs";import P from"node:os";import f from"node:path";import x from"node:readline/promises";import{stdin as S,stdout as c}from"node:process";import{extractCodexSession as _}from"../acp/providers/codex/session-import.js";import{acaServerRequest as s}from"../core/aca-server-client.js";import{loadAcaConfig as l,upsertLocalProject as E}from"../core/aca-config.js";import{applyRuntimePathOptions as T}from"../core/runtime-options.js";function Z(){return new j("codex").description("管理本机 Codex 会话").addCommand(new j("import").description("将本机 Codex Session 导入 ACA Project").argument("<session-id>","Codex Session ID").option("--aica-home <path>","Runtime home directory (defaults to ~/.aica)").option("--aica-config <path>","Config file path").option("--aca-home <path>","Deprecated alias for --aica-home").option("--aca-config <path>","Deprecated alias for --aica-config").option("--path <path>","项目目录,支持相对路径;默认使用当前目录").option("--workspace <id>","新建 Project 时使用的 Workspace ID").option("--project-name <name>","自动创建 Project 时使用的名称").option("--turns <count>","导入最近多少个 Codex Turn,范围 1-20","20").option("--detail <mode>","详情模式:auto、compact、standard 或 diagnostic","auto").option("--title <name>","导入后的 ACA Session 标题").option("--dry-run","只读取和校验,不写入 ACA Server").option("-y, --yes","跳过交互确认,适用于脚本或非交互环境").action(b))}async function b(t,e){T(e);const o=l();if(!o.token)throw new Error("Worker 尚未登录,请先执行 aica login。");await R();const r=await N(o.machineId,t);if(r){console.log(`Codex Session 已存在:session=${r.sessionId} project=${r.projectId} title=${r.title||"未命名"}`);return}const i=k(e.path||process.cwd()),d=q(e.turns),p=await v(),a=D(e.detail,p),n=await _({sessionId:t,turnLimit:d,detailMode:a,diffEnabled:a==="diagnostic"&&p.diffEnabled===!0});M(i,n.cwd);const m=await W({targetPath:i,workspaceId:e.workspace,projectName:e.projectName,machineId:o.machineId}),g=e.title?.trim()||n.title;if(e.dryRun){console.log(JSON.stringify({dryRun:!0,action:m.action,projectId:m.project.project_id,projectName:m.project.name,providerSessionId:n.providerSessionId,path:i,detailMode:a,turns:n.turns.length,truncated:n.truncated,title:g},null,2));return}if(!e.yes&&!await G({sessionId:n.providerSessionId,targetPath:i,plan:m,turnCount:n.turns.length,detailMode:a})){console.log("已取消导入。");return}const u=await A(m);await L();const I=await s("POST","/api/codex-session-imports",{projectId:u.project_id,workspaceId:u.workspace_id,machineId:o.machineId,title:g,import:n}),$=I.item;console.log(`${I.imported?"已导入":"已存在"} session=${String($.session_id||"")} project=${u.project_id} turns=${n.turns.length} mode=${a}`)}async function N(t,e){const o=new URLSearchParams({machineId:t,providerSessionId:e.trim()});try{const r=await s("GET",`/api/codex-session-imports/status?${o.toString()}`);return r.exists?r.item:null}catch(r){const i=r instanceof Error?r.message:String(r);if(/\b404\b/.test(i))return null;throw r}}async function L(){const t=l();await s("POST","/api/heartbeat",{machineId:t.machineId,machineName:t.machineName,workspaceId:t.defaultWorkspaceId,projects:t.projects.map(e=>({projectId:e.projectId,workspaceId:e.workspaceId,name:e.name,rootPath:e.rootPath}))})}async function R(){try{await s("GET","/api/auth/me")}catch(t){const e=t instanceof Error?t.message:String(t);throw/\b401\b|unauthorized/i.test(e)?new Error("Worker 登录已失效,请先执行 aica login 重新登录。"):t}}async function v(){try{return(await s("GET","/api/process-details/capabilities")).item||{}}catch{return{}}}function D(t,e){const o=String(t||"auto").trim().toLowerCase();if(o==="auto")return e.mode==="diagnostic"?"diagnostic":e.mode==="compact"?"compact":"standard";if(o==="compact"||o==="standard"||o==="diagnostic")return o;throw new Error("--detail 必须是 auto、compact、standard 或 diagnostic。")}async function W(t){const e=l(),o=e.projects.find(a=>t.workspaceId&&a.workspaceId!==t.workspaceId?!1:w(a.rootPath)===t.targetPath),r=t.workspaceId||o?.workspaceId||e.defaultWorkspaceId,i=await s("GET",`/api/projects?workspaceId=${encodeURIComponent(r)}`);if(o){const a=i.items.find(n=>(!n.machine_id||n.machine_id===t.machineId)&&n.project_id===o.projectId&&w(n.root_path)===t.targetPath);if(a)return{action:"reuse",project:a}}const d=i.items.find(a=>(!a.machine_id||a.machine_id===t.machineId)&&w(a.root_path)===t.targetPath);if(d)return{action:"attach",project:d};const p=t.projectName?.trim()||o?.name||f.basename(t.targetPath);return{action:"create",project:{project_id:o?.projectId||O(r,t.machineId,t.targetPath,p),workspace_id:r,name:p,root_path:t.targetPath}}}async function A(t){if(t.action==="reuse")return t.project;if(t.action==="attach")return y(t.project),t.project;const e=await s("POST","/api/projects",{projectId:t.project.project_id,workspaceId:t.project.workspace_id,name:t.project.name,rootPath:t.project.root_path,source:"aica-codex-import",projectType:"project"});return y(e.item),e.item}function y(t){E({projectId:t.project_id,workspaceId:t.workspace_id,name:t.name,rootPath:t.root_path})}function M(t,e){const o=h.realpathSync(e);if(t!==o)throw new Error(`指定目录与 Codex Session 工作目录不一致:path=${t} session=${o}`)}function k(t){const e=t==="~"?P.homedir():t.startsWith("~/")?f.join(P.homedir(),t.slice(2)):t,o=f.resolve(e);if(!h.existsSync(o)||!h.statSync(o).isDirectory())throw new Error(`Project 工作目录不存在:${o}`);return h.realpathSync(o)}function w(t){try{return k(t)}catch{return null}}function O(t,e,o,r){const i=r.toLowerCase().replace(/[^a-z0-9._-]+/g,"-").replace(/^-+|-+$/g,"")||"project",d=C.createHash("sha256").update(`${t}\0${e}\0${o}`).digest("hex").slice(0,12);return`aica-${i}-${d}`}async function G(t){if(!S.isTTY||!c.isTTY)throw new Error("当前为非交互环境,请确认参数无误后添加 --yes 执行导入。");const e=t.plan.action==="reuse"?`在已有 Project「${t.plan.project.name}」中创建 Session`:t.plan.action==="attach"?`将目录关联到已有 Project「${t.plan.project.name}」,再创建 Session`:`创建 Project「${t.plan.project.name}」,再创建 Session`;c.write(`
2
2
  即将导入 Codex Session:
3
3
  `),c.write(` 项目路径:${t.targetPath}
4
4
  `),c.write(` Session ID:${t.sessionId}
@@ -1 +1 @@
1
- import l from"node:fs";import n from"node:path";import{mimeForPath as x}from"../affected-files.js";const A=new Set([".pdf",".doc",".docx",".odt",".rtf",".xls",".xlsx",".xlsm",".ods",".csv",".ppt",".pptx",".odp",".png",".jpg",".jpeg",".gif",".webp",".bmp",".tif",".tiff",".svg",".avif"]),_=new Set([".git","node_modules",".venv","venv","__pycache__"]),z=[".aca/attachments",".aica/attachments",".aca/artifacts",".aica/artifacts",".aca/logs",".aica/logs",".aca/server-data",".aica/server-data"],M=8192,S=1e4,u=new Map;function m(o){const t=n.basename(o);return!f(o)&&!t.startsWith("~$")&&A.has(n.extname(t).toLowerCase())}function f(o){const t=o.split(n.sep).join("/");return t.split("/").some(e=>_.has(e))||z.some(e=>t===e||t.startsWith(`${e}/`))}class N{root;warn;watches=new Map;subscribers=new Set;pending=new Set;timer;closed=!1;warned=!1;draining=!1;constructor(t,e){this.root=t,this.warn=e}degraded(t){this.warned||this.closed||(this.warned=!0,this.warn(`文档监听部分不可用,将以结束扫描补偿(仍可能遗漏瞬时变化):${String(t)}`))}watchDirectory(t){if(!(this.closed||this.watches.has(t))){if(this.watches.size>=M){this.degraded("目录监听数量达到上限");return}try{const e=l.watch(t,{persistent:!1},(i,s)=>{if(this.closed||!s)return;const a=n.join(t,s.toString()),r=n.relative(this.root,a);if(!f(r)){if(m(r))for(const c of this.subscribers)c.size<S?c.add(r):this.degraded("文件事件候选数量达到上限");i==="rename"&&this.schedule(a)}});e.on("error",i=>{e.close(),this.watches.get(t)===e&&this.watches.delete(t),this.degraded(i)}),this.watches.set(t,e)}catch(e){this.degraded(e)}}}schedule(t){if(this.pending.size>=S){this.degraded("目录事件积压");return}this.pending.add(t),!(this.timer||this.draining)&&(this.timer=setTimeout(()=>{this.timer=void 0,this.drain()},50),this.timer.unref())}async drain(){this.draining=!0;try{for(;!this.closed&&this.pending.size>0;){const t=this.pending.values().next().value;if(this.pending.delete(t),this.watches.has(t))for(const[e,i]of this.watches)(e===t||e.startsWith(`${t}${n.sep}`))&&(i.close(),this.watches.delete(e));await this.walk(t,new Map)}}finally{this.draining=!1}}async snapshot(){const t=new Map;return await this.walk(this.root,t),t}async walk(t,e){if(this.closed)return;const i=n.relative(this.root,t);if(!f(i))try{const s=await l.promises.lstat(t);if(s.isSymbolicLink())return;if(s.isDirectory()){this.watchDirectory(t);const a=await l.promises.opendir(t);for await(const r of a){if(this.closed)break;if(r.isSymbolicLink())continue;const c=n.join(t,r.name),d=n.relative(this.root,c);f(d)||(r.isDirectory()||m(d))&&await this.walk(c,e)}}else if(s.isFile()&&m(i)){const a=await l.promises.realpath(t),r=n.relative(this.root,a);if(r.startsWith(`..${n.sep}`)||n.isAbsolute(r)||f(r))return;e.set(i,{size:s.size,signature:`${s.dev}:${s.ino}:${s.size}:${s.mtimeMs}:${s.ctimeMs}`})}}catch(s){const a=s.code;a!=="ENOENT"&&a!=="ENOTDIR"&&this.degraded(s)}}close(){this.closed=!0,this.timer&&clearTimeout(this.timer);for(const t of this.watches.values())t.close();this.watches.clear(),this.pending.clear()}}async function j(o,t){const e=await l.promises.realpath(o);let i=u.get(e);i||(i=new N(e,t),u.set(e,i));const s=i,a=new Set;s.subscribers.add(a);let r=!1;const c=()=>{r||(r=!0,s.subscribers.delete(a),s.subscribers.size===0&&(s.close(),u.delete(e)))};let d;try{d=await s.snapshot(),a.clear()}catch(w){throw c(),w}let b;return{dispose:c,finish(){return b??=(async()=>{if(r)return[];try{const w=await s.snapshot(),g=[];for(const[h,p]of w){const v=d.get(h);if(!a.has(h)&&v?.signature===p.signature)continue;const y=n.join(e,h);g.push({path:y,absolutePath:y,relativePath:h.split(n.sep).join("/"),changeType:v?"modified":"created",source:"job_time_window",exists:!0,downloadable:!0,size:p.size,mime:x(h)})}return g.sort((h,p)=>h.relativePath.localeCompare(p.relativePath))}finally{c()}})()}}}function k(o,t){const e=new Map(o.map(i=>[i.relativePath,i]));for(const i of t)e.set(i.relativePath,i);return[...e.values()]}export{m as isArtifactPath,f as isIgnoredArtifactPath,k as mergeArtifactFiles,j as startJobArtifactMonitor};
1
+ import l from"node:fs";import n from"node:path";import{mimeForPath as S}from"../affected-files.js";const _=new Set([".pdf",".doc",".docx",".odt",".rtf",".xls",".xlsx",".xlsm",".ods",".csv",".ppt",".pptx",".odp",".png",".jpg",".jpeg",".gif",".webp",".bmp",".tif",".tiff",".svg",".avif"]),N=new Set([".git","node_modules",".venv","venv","__pycache__"]),T=[["target","classes"],["target","test-classes"],[".next","cache"],[".angular","cache"],[".gradle","caches"]],x=[["build","resources","main"],["build","resources","test"],["build","intermediates","merged_res"],["build","intermediates","packaged_res"],["build","intermediates","merged_assets"]],A=[".aca/attachments",".aica/attachments",".aca/artifacts",".aica/artifacts",".aca/logs",".aica/logs",".aca/server-data",".aica/server-data"],j=8192,b=1e4,w=new Map;function g(c,e){const t=n.basename(c);return!f(c,e)&&!t.startsWith("~$")&&_.has(n.extname(t).toLowerCase())}function f(c,e){const t=c.split(n.sep).join("/"),i=t.split("/"),s=(r,a)=>a.some(o=>o.every((d,p)=>i[r+p]===d));return i.some((r,a)=>N.has(r)||s(a,T)||r==="build"&&e?.has(i.slice(0,a+1).join("/"))&&s(a,x))||A.some(r=>t===r||t.startsWith(`${r}/`))}class z{root;warn;watches=new Map;gradleBuildPaths=new Set;subscribers=new Set;pending=new Set;timer;closed=!1;warned=!1;draining=!1;constructor(e,t){this.root=e,this.warn=t}degraded(e){this.warned||this.closed||(this.warned=!0,this.warn(`文档监听部分不可用,将以结束扫描补偿(仍可能遗漏瞬时变化):${String(e)}`))}watchDirectory(e){if(!(this.closed||this.watches.has(e))){if(this.watches.size>=j){this.degraded("目录监听数量达到上限");return}try{const t=l.watch(e,{persistent:!1},(i,s)=>{if(this.closed||!s)return;const r=n.join(e,s.toString()),a=n.relative(this.root,r);if(!f(a,this.gradleBuildPaths)){if(g(a,this.gradleBuildPaths))for(const o of this.subscribers)o.size<b?o.add(a):this.degraded("文件事件候选数量达到上限");i==="rename"&&this.schedule(r)}});t.on("error",i=>{t.close(),this.watches.get(e)===t&&this.watches.delete(e),this.degraded(i)}),this.watches.set(e,t)}catch(t){this.degraded(t)}}}schedule(e){if(this.pending.size>=b){this.degraded("目录事件积压");return}this.pending.add(e),!(this.timer||this.draining)&&(this.timer=setTimeout(()=>{this.timer=void 0,this.drain()},50),this.timer.unref())}async drain(){this.draining=!0;try{for(;!this.closed&&this.pending.size>0;){const e=this.pending.values().next().value;if(this.pending.delete(e),this.watches.has(e))for(const[t,i]of this.watches)(t===e||t.startsWith(`${e}${n.sep}`))&&(i.close(),this.watches.delete(t));await this.walk(e,new Map)}}finally{this.draining=!1}}async snapshot(){const e=new Map;return await this.walk(this.root,e),e}async updateGradleContext(e,t){if(!t||n.basename(e)!=="build")return;const i=await Promise.all(["build.gradle","build.gradle.kts"].map(async r=>{try{return(await l.promises.lstat(n.join(n.dirname(e),r))).isFile()}catch(a){const o=a.code;return o!=="ENOENT"&&o!=="ENOTDIR"&&this.degraded(a),!1}})),s=t.split(n.sep).join("/");i.some(Boolean)?this.gradleBuildPaths.add(s):this.gradleBuildPaths.delete(s)}async walk(e,t){if(this.closed)return;const i=n.relative(this.root,e);if(!f(i,this.gradleBuildPaths))try{const s=await l.promises.lstat(e);if(s.isSymbolicLink())return;if(s.isDirectory()){await this.updateGradleContext(e,i),this.watchDirectory(e);const r=await l.promises.opendir(e);for await(const a of r){if(this.closed)break;if(a.isSymbolicLink())continue;const o=n.join(e,a.name),d=n.relative(this.root,o);f(d,this.gradleBuildPaths)||(a.isDirectory()||g(d,this.gradleBuildPaths))&&await this.walk(o,t)}}else if(s.isFile()&&g(i,this.gradleBuildPaths)){const r=await l.promises.realpath(e),a=n.relative(this.root,r);if(a.startsWith(`..${n.sep}`)||n.isAbsolute(a)||f(a,this.gradleBuildPaths))return;t.set(i,{size:s.size,signature:`${s.dev}:${s.ino}:${s.size}:${s.mtimeMs}:${s.ctimeMs}`})}}catch(s){const r=s.code;r!=="ENOENT"&&r!=="ENOTDIR"&&this.degraded(s)}}close(){this.closed=!0,this.timer&&clearTimeout(this.timer);for(const e of this.watches.values())e.close();this.watches.clear(),this.pending.clear()}}async function M(c,e){const t=await l.promises.realpath(c);let i=w.get(t);i||(i=new z(t,e),w.set(t,i));const s=i,r=new Set;s.subscribers.add(r);let a=!1;const o=()=>{a||(a=!0,s.subscribers.delete(r),s.subscribers.size===0&&(s.close(),w.delete(t)))};let d;try{d=await s.snapshot(),r.clear()}catch(m){throw o(),m}let p;return{dispose:o,finish(){return p??=(async()=>{if(a)return[];try{const m=await s.snapshot(),v=[];for(const[h,u]of m){const y=d.get(h);if(!r.has(h)&&y?.signature===u.signature)continue;const E=n.join(t,h);v.push({path:E,absolutePath:E,relativePath:h.split(n.sep).join("/"),changeType:y?"modified":"created",source:"job_time_window",exists:!0,downloadable:!0,size:u.size,mime:S(h)})}return v.sort((h,u)=>h.relativePath.localeCompare(u.relativePath))}finally{o()}})()}}}function P(c,e){const t=new Map(c.map(i=>[i.relativePath,i]));for(const i of e)t.set(i.relativePath,i);return[...t.values()]}export{g as isArtifactPath,f as isIgnoredArtifactPath,P as mergeArtifactFiles,M as startJobArtifactMonitor};
@@ -1,5 +1,5 @@
1
- import{executeExternalCodexOperation as Z}from"./external-codex-worker.js";import{managementActivity as T}from"./management/activity.js";import{managedClaim as q}from"./management/claims.js";import{activeTerminalService as tt}from"./terminal/service.js";import{execFileSync as y}from"node:child_process";import{randomUUID as F}from"node:crypto";import l from"node:fs";import I from"node:os";import u from"node:path";import{acaServerDownloadToFile as et,acaServerRequest as E}from"./aca-server-client.js";import{loadAcaConfig as rt,upsertLocalProject as ot}from"./aca-config.js";import{startLongPollWorker as nt}from"./long-poll-worker.js";import{expandWorkerRuntimePath as it}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";const L=25e3,ct=L+1e4,x=300,lt=3e4;let b=null;function ae(t){return nt({run:async()=>{const e=rt();if(!e.token)throw new Error("Worker 尚未配置认证令牌");const r=await q("machine",()=>E("GET",`/api/client/machine-operations/claim?machineId=${encodeURIComponent(e.machineId)}&waitMs=${L}`,void 0,{timeoutMs:ct}));if(!r.item)return;const o=T.track("machine");try{const n=await ut(r.item);await E("POST",`/api/client/machine-operations/${encodeURIComponent(r.item.requestId)}/complete`,{result:n})}catch(n){const s=n instanceof Error?n.message:String(n);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 Z(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 $t();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 G(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=N(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=G({rootPath:r}),n=String(t.baseCommit||"").trim(),s=n&&/^[0-9a-f]{7,64}$/i.test(n)?At(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 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 仓库,无法提交。");y("git",["-C",e,"add","-A"],{windowsHide:!0,stdio:"pipe",timeout:3e4});try{return y("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 y("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=N(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(tt?.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],{windowsHide:!0,stdio:"pipe",timeout:6e4}),t.deleteBranch===!0&&n)try{y("git",["-C",r,"branch","-D",n],{windowsHide:!0,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 mt(t){const e=p(String(t.rootPath||"")),r=S(String(t.relativePath||"")),o=v(e,r,!0),n=Math.max(0,Number(t.offset||0)),s=Math.min(300,Math.max(20,Number(t.limit||200))),i=t.sort==="modified-desc"||t.sort==="modified-asc"?t.sort:"name",a=l.readdirSync(o,{withFileTypes:!0}).filter(c=>!c.isSymbolicLink()).map(c=>({name:c.name,path:V(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():"",modifiedAt:i==="name"?void 0:pt(u.join(o,c.name))})).filter(c=>c.type!=="other").sort((c,f)=>{if(c.type!==f.type)return c.type==="directory"?-1:1;if(i!=="name"){if(c.modifiedAt==null&&f.modifiedAt!=null)return 1;if(f.modifiedAt==null&&c.modifiedAt!=null)return-1;const P=(c.modifiedAt??0)-(f.modifiedAt??0);if(P)return i==="modified-desc"?-P:P}return c.name.localeCompare(f.name,void 0,{numeric:!0,sensitivity:"base"})}),d=a.slice(n,n+s);return{path:r,rootKind:t.rootKind==="worktree"?"worktree":"project",items:d,total:a.length,nextOffset:n+d.length<a.length?n+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=S(String(t.relativeDirectory||"")),n=v(r,o,!0),s=M(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 d=u.join(n,`.aca-upload-${F()}.tmp`);try{const c=await et(`/api/client/project-uploads/${encodeURIComponent(e)}`,d,{maxBytes:i,timeoutMs:3e5});if(c.sizeBytes!==i)throw new Error("项目上传文件大小校验失败。");if(c.sha256.toLowerCase()!==a)throw new Error("项目上传文件完整性校验失败。");const f=St(r,o,s,d);return{name:u.basename(f),path:V(r,f),directory:o,size:c.sizeBytes,sha256:c.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 n=S(e);if(!n)throw new Error("project_file_root_protected");gt(n);const s=n.split("/"),i=s.slice(0,-1).join("/"),a=v(t,i,!0),d=u.join(a,s.at(-1)||"");let c;try{c=l.lstatSync(d)}catch(f){throw f.code==="ENOENT"?new Error("project_file_not_found"):f}if(c.isSymbolicLink())throw new Error("project_file_symbolic_link");if(!c.isFile()&&!c.isDirectory())throw new Error("project_file_type_unsupported");if(c.isDirectory()&&!r&&l.readdirSync(d).length>0)throw new Error("project_directory_not_empty");return c.isDirectory()&&r?l.rmSync(d,{recursive:!0,force:!1,maxRetries:2,retryDelay:150}):c.isDirectory()?l.rmdirSync(d):l.unlinkSync(d),{operation:"delete",path:n,entryType:c.isDirectory()?"directory":"file",parentPath:i,affectedDirectories:[i],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 n=p(t),s=S(e),i=v(n,s,!0),a=M(r);if(l.realpathSync.native(u.dirname(o))!==i)throw new Error("项目上传临时文件不在目标目录中。");const c=l.lstatSync(o);if(!c.isFile()||c.isSymbolicLink())throw new Error("项目上传临时文件无效。");for(let f=1;f<=1e4;f+=1){const P=f===1?a:_t(a,f),_=u.join(i,P);try{return l.linkSync(o,_),l.chmodSync(_,420),l.rmSync(o,{force:!0}),_}catch(A){if(O(A))continue;if(!Pt(A))throw A;try{return l.copyFileSync(o,_,l.constants.COPYFILE_EXCL),l.chmodSync(_,420),l.rmSync(o,{force:!0}),_}catch($){if(O($))continue;throw $}}}throw new Error("同名文件过多,无法生成可用文件名。")}function M(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 O(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 H=500,j=2*1024*1024,g=2*1024*1024;function G(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,H),n=o.map(a=>vt(a)).filter(a=>!!a),s=D(m(e,["diff","--no-ext-diff","--numstat","-z","--no-renames","HEAD","--","."],j));for(const a of n){const d=s.get(a.path);if(d)a.additions=d.additions,a.deletions=d.deletions;else if(a.status==="untracked"){const c=W(e,a.path);a.additions=c.additions,a.deletions=c.deletions}}const i=Nt(e);return{isRepository:!0,branch:Rt(e),files:n,ahead:i.ahead,behind:i.behind,truncated:o.length>=H}}function Et(t){const e=p(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=U(e,r),n=Dt(e,r),s=n?m(e,["diff","--no-ext-diff","--unified=80","HEAD","--",r],g):z(e,["diff","--no-ext-diff","--no-index","--unified=80",process.platform==="win32"?"NUL":"/dev/null",o],g),i=n?D(m(e,["diff","--no-ext-diff","--numstat","-z","--no-renames","HEAD","--",r],32*1024)).get(r):W(e,r);return{isRepository:!0,path:r,diff:K(s),additions:i?.additions??0,deletions:i?.deletions??0,truncated:s.length>g}}function xt(t){const e=p(String(t.rootPath||""));if(!w(e))return{isRepository:!1,items:[]};if(!Ct(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(i=>jt(i)).filter(i=>!!i),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],g),n=[...D(m(e,["show","--no-ext-diff","--numstat","-z","--no-renames","--format=",r],j)).values()];return{isRepository:!0,commit:r,diff:K(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 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=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 D(t){const e=new Map;for(const r of t.split("\0")){if(!r)continue;const o=B(r);if(!o||!o.path)continue;const n=S(o.path);n&&e.set(n,{additions:o.additions,deletions:o.deletions})}return e}function W(t,e){const r=U(t,e),n=z(t,["diff","--no-ext-diff","--no-index","--numstat","-z","--",process.platform==="win32"?"NUL":"/dev/null",r],32*1024).split("\0",1)[0]||"",s=B(n);return s?{additions:s.additions,deletions:s.deletions}:{additions:null,deletions:null}}function B(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 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 Ct(t){try{return m(t,["rev-parse","--verify","HEAD"],8*1024),!0}catch{return!1}}function Rt(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 Nt(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 U(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 y("git",["-C",t,...e],{windowsHide:!0,encoding:"utf8",timeout:2e4,maxBuffer:r,stdio:["ignore","pipe","pipe"]})}function z(t,e,r){try{return m(t,e,r)}catch(o){const n=String(o.stdout||"");if(n)return n;if(Number(o.status)===1)return"";throw o}}function K(t){return t.length<=g?t:`${t.slice(0,g)}
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 y}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 nt}from"./long-poll-worker.js";import{expandWorkerRuntimePath as it}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";const M=25e3,ct=M+1e4,x=300,lt=3e4;let b=null;function ae(t){return nt({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=${M}`,void 0,{timeoutMs:ct}));if(!r.item)return;const o=T.track("machine");try{const n=await ut(r.item);await E("POST",`/api/client/machine-operations/${encodeURIComponent(r.item.requestId)}/complete`,{result:n})}catch(n){const s=n instanceof Error?n.message:String(n);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 $t();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 W(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=N(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=W({rootPath:r}),n=String(t.baseCommit||"").trim(),s=n&&/^[0-9a-f]{7,64}$/i.test(n)?At(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 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 仓库,无法提交。");y("git",["-C",e,"add","-A"],{windowsHide:!0,stdio:"pipe",timeout:3e4});try{return y("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 y("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=N(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 n=String(t.branchName||"").trim(),s=w(o)&&w(r);if(s){if(y("git",["-C",r,"worktree","remove","--force",o],{windowsHide:!0,stdio:"pipe",timeout:6e4}),t.deleteBranch===!0&&n)try{y("git",["-C",r,"branch","-D",n],{windowsHide:!0,stdio:"pipe",timeout:3e4})}catch(i){const c=String(i.stderr||i);if(!/not found|not exist/i.test(c))throw i}}else l.rmSync(o,{recursive:!0,force:!0,maxRetries:2,retryDelay:200});return{removed:!0,branchDeleted:!!(s&&t.deleteBranch===!0&&n)}}function mt(t){const e=p(String(t.rootPath||"")),r=S(String(t.relativePath||"")),o=v(e,r,!0),n=Math.max(0,Number(t.offset||0)),s=Math.min(300,Math.max(20,Number(t.limit||200))),i=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:Y(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:i==="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(i!=="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 i==="modified-desc"?-P:P}return a.name.localeCompare(f.name,void 0,{numeric:!0,sensitivity:"base"})}),d=c.slice(n,n+s);return{path:r,rootKind:t.rootKind==="worktree"?"worktree":"project",items:d,total:c.length,nextOffset:n+d.length<c.length?n+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=S(String(t.relativeDirectory||"")),n=v(r,o,!0),s=O(String(t.fileName||"")),i=Number(t.sizeBytes),c=String(t.sha256||"").trim().toLowerCase();if(!Number.isSafeInteger(i)||i<0)throw new Error("项目上传文件大小无效。");if(!/^[0-9a-f]{64}$/.test(c))throw new Error("项目上传文件摘要无效。");const d=u.join(n,`.aca-upload-${I()}.tmp`);try{const a=await rt(`/api/client/project-uploads/${encodeURIComponent(e)}`,d,{maxBytes:i,timeoutMs:3e5});if(a.sizeBytes!==i)throw new Error("项目上传文件大小校验失败。");if(a.sha256.toLowerCase()!==c)throw new Error("项目上传文件完整性校验失败。");const f=St(r,o,s,d);return{name:u.basename(f),path:Y(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 n=S(e);if(!n)throw new Error("project_file_root_protected");gt(n);const s=n.split("/"),i=s.slice(0,-1).join("/"),c=v(t,i,!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:n,entryType:a.isDirectory()?"directory":"file",parentPath:i,affectedDirectories:[i],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 n=p(t),s=S(e),i=v(n,s,!0),c=O(r);if(l.realpathSync.native(u.dirname(o))!==i)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),_=u.join(i,P);try{return l.linkSync(o,_),l.chmodSync(_,420),l.rmSync(o,{force:!0}),_}catch(A){if(H(A))continue;if(!Pt(A))throw A;try{return l.copyFileSync(o,_,l.constants.COPYFILE_EXCL),l.chmodSync(_,420),l.rmSync(o,{force:!0}),_}catch($){if(H($))continue;throw $}}}throw new Error("同名文件过多,无法生成可用文件名。")}function O(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 H(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 G=500,j=2*1024*1024,g=2*1024*1024;function W(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,G),n=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 n){const d=s.get(c.path);if(d)c.additions=d.additions,c.deletions=d.deletions;else if(c.status==="untracked"){const a=B(e,c.path);c.additions=a.additions,c.deletions=a.deletions}}const i=Nt(e);return{isRepository:!0,branch:Rt(e),files:n,ahead:i.ahead,behind:i.behind,truncated:o.length>=G}}function Et(t){const e=p(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=z(e,r),n=Dt(e,r),s=n?m(e,["diff","--no-ext-diff","--unified=80","HEAD","--",r],g):K(e,["diff","--no-ext-diff","--no-index","--unified=80",process.platform==="win32"?"NUL":"/dev/null",o],g),i=n?D(m(e,["diff","--no-ext-diff","--numstat","-z","--no-renames","HEAD","--",r],32*1024)).get(r):B(e,r);return{isRepository:!0,path:r,diff:X(s),additions:i?.additions??0,deletions:i?.deletions??0,truncated:s.length>g}}function xt(t){const e=p(String(t.rootPath||""));if(!w(e))return{isRepository:!1,items:[]};if(!Ct(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(i=>jt(i)).filter(i=>!!i),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],g),n=[...D(m(e,["show","--no-ext-diff","--numstat","-z","--no-renames","--format=",r],j)).values()];return{isRepository:!0,commit:r,diff:X(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 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=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 D(t){const e=new Map;for(const r of t.split("\0")){if(!r)continue;const o=U(r);if(!o||!o.path)continue;const n=S(o.path);n&&e.set(n,{additions:o.additions,deletions:o.deletions})}return e}function B(t,e){const r=z(t,e),n=K(t,["diff","--no-ext-diff","--no-index","--numstat","-z","--",process.platform==="win32"?"NUL":"/dev/null",r],32*1024).split("\0",1)[0]||"",s=U(n);return s?{additions:s.additions,deletions:s.deletions}:{additions:null,deletions:null}}function U(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 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 Ct(t){try{return m(t,["rev-parse","--verify","HEAD"],8*1024),!0}catch{return!1}}function Rt(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 Nt(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 z(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 y("git",["-C",t,...e],{windowsHide:!0,encoding:"utf8",timeout:2e4,maxBuffer:r,stdio:["ignore","pipe","pipe"]})}function K(t,e,r){try{return m(t,e,r)}catch(o){const n=String(o.stdout||"");if(n)return n;if(Number(o.status)===1)return"";throw o}}function X(t){return t.length<=g?t:`${t.slice(0,g)}
2
2
 
3
- [Diff 内容过大,已截断]`}function $t(){const t=process.platform,e=C(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),n=r.parse(o).root,s=o.length>n.length?o.replace(/[\\/]+$/,""):o;return e==="win32"?s.toLocaleLowerCase("en-US"):s}function Ft(){const t=l.realpathSync(I.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 C(t){if(b?.platform===t&&b.expiresAtMs>Date.now())return b.roots;const e=t==="win32"?It():Ft();return b={platform:t,roots:e,expiresAtMs:Date.now()+lt},e}function It(){const t=l.realpathSync.native(I.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=Q(J(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(/[\\/]+$/,"")),d=String(n.VolumeName||"").trim();e.set(h(s,"win32"),{id:`drive-${a.replace(/[^a-z0-9]+/gi,"").toLowerCase()}`,label:d?`${d} (${a})`:zt(a,i),path:s,kind:Ut(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 Lt(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,x).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"})),X(r,s,n.length>x,"linux")}function Mt(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=Q(J(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,x).sort((i,a)=>i.name.localeCompare(a.name,void 0,{numeric:!0,sensitivity:"base"}));return X(r,s,n.length>x,"win32")}function X(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:Ot(t,o),readable:Y(t,l.constants.R_OK),writable:Y(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),n=t.slice(o.root.length).split(/[\\/]+/).filter(Boolean),s=[{label:o.root.replace(/[\\/]+$/,"")||o.root,path:o.root}];let i=o.root;for(const a of n)i=r.join(i,a),s.push({label:a,path:i});return s}async function Ht(t){const e=String(t.workspaceId||"").trim(),r=String(t.name||"").trim(),o=t.projectType==="chat_room"?"chat_room":"project";if(!e||!r)throw new Error("项目名称和工作区不能为空。");const n=R(String(t.path||""));l.accessSync(n,l.constants.R_OK|l.constants.W_OK);const i=(await E("GET",`/api/projects?workspaceId=${encodeURIComponent(e)}`)).items.find(d=>h(d.root_path)===h(n)),a=i||(await E("POST","/api/projects",{projectId:F(),workspaceId:e,name:r,rootPath:n,source:"aica",projectType:o})).item;return ot(Gt(a)),{project:a,duplicate:!!i}}function Gt(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(Wt(t),!l.statSync(t).isDirectory())throw new Error("选择的路径不是目录。");const r=l.realpathSync.native(t);return Bt(r),r}function p(t){const e=N(t),r=l.realpathSync.native(e);if(!l.statSync(r).isDirectory())throw new Error("项目根目录不存在。");return r}function N(t){const e=it(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 v(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 V(t,e){return u.relative(t,e).split(u.sep).join("/")}function Wt(t){const e=process.platform==="win32"?u.win32:u.posix;if(!C(process.platform).some(o=>{const n=String(o.path||"");if(!n)return!1;const s=e.relative(n,t);return s===""||!s.startsWith("..")&&!e.isAbsolute(s)}))throw new Error("目录不在允许浏览的位置内。")}function Bt(t){const e=process.platform==="win32"?u.win32:u.posix;if(!C(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 Y(t,e){try{return l.accessSync(t,e),!0}catch{return!1}}function J(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 Q(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,G as getProjectGitStatus,k as getWorktreeStatus,Tt as listMachineDirectory,$t as listMachineFilesystemRoots,mt as listProjectDirectory,wt as mutateProjectFiles,ae as startMachineFilesystemWorkerLoop,ht as uploadProjectFile};
3
+ [Diff 内容过大,已截断]`}function $t(){const t=process.platform,e=C(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),n=r.parse(o).root,s=o.length>n.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 C(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(Q(r));for(const n of o){const s=String(n.Root||"");if(!s)continue;const i=Number(n.DriveType||0),c=String(n.Name||s.replace(/[\\/]+$/,"")),d=String(n.VolumeName||"").trim();e.set(h(s,"win32"),{id:`drive-${c.replace(/[^a-z0-9]+/gi,"").toLowerCase()}`,label:d?`${d} (${c})`:zt(c,i),path:s,kind:Ut(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 Lt(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,x).map(i=>({name:i.name,path:u.join(r,i.name),kind:"directory",hidden:i.name.startsWith("."),hasChildren:!0}));return s.sort((i,c)=>i.name.localeCompare(c.name,void 0,{numeric:!0,sensitivity:"base"})),V(r,s,n.length>x,"linux")}function Mt(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=Z(Q(o,{ACA_MACHINE_FS_PATH:r})),s=n.map(i=>{const c=String(i.Attributes||"");return{name:String(i.Name||""),path:String(i.FullName||""),kind:"directory",hidden:/Hidden|System/i.test(c),hasChildren:!0,reparsePoint:/ReparsePoint/i.test(c)}}).filter(i=>i.name&&i.path&&!i.reparsePoint&&(e||!i.hidden)).slice(0,x).sort((i,c)=>i.name.localeCompare(c.name,void 0,{numeric:!0,sensitivity:"base"}));return V(r,s,n.length>x,"win32")}function V(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:Ot(t,o),readable:J(t,l.constants.R_OK),writable:J(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),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 c of n)i=r.join(i,c),s.push({label:c,path:i});return s}async function Ht(t){const e=String(t.workspaceId||"").trim(),r=String(t.name||"").trim(),o=t.projectType==="chat_room"?"chat_room":"project";if(!e||!r)throw new Error("项目名称和工作区不能为空。");const n=R(String(t.path||""));l.accessSync(n,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(n)),d=c||(await E("POST","/api/projects",{projectId:I(),workspaceId:e,name:r,rootPath:n,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 R(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=N(t),r=l.realpathSync.native(e);if(!l.statSync(r).isDirectory())throw new Error("项目根目录不存在。");return r}function N(t){const e=it(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 v(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 Y(t,e){return u.relative(t,e).split(u.sep).join("/")}function Wt(t){const e=process.platform==="win32"?u.win32:u.posix;if(!C(process.platform).some(o=>{const n=String(o.path||"");if(!n)return!1;const s=e.relative(n,t);return s===""||!s.startsWith("..")&&!e.isAbsolute(s)}))throw new Error("目录不在允许浏览的位置内。")}function Bt(t){const e=process.platform==="win32"?u.win32:u.posix;if(!C(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 J(t,e){try{return l.accessSync(t,e),!0}catch{return!1}}function Q(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 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,W as getProjectGitStatus,k as getWorktreeStatus,Tt as listMachineDirectory,$t as listMachineFilesystemRoots,mt as listProjectDirectory,wt as mutateProjectFiles,ae as startMachineFilesystemWorkerLoop,ht as uploadProjectFile};
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- const o="0.1.78";export{o as AICA_VERSION};
1
+ const o="0.1.79";export{o as AICA_VERSION};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuandc/aica",
3
- "version": "0.1.78",
3
+ "version": "0.1.79",
4
4
  "description": "AICA remote Agent worker",
5
5
  "author": "yuandc",
6
6
  "type": "module",