@dreamor/atlas-cli 0.7.24 → 0.7.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/atlas.cjs +1 -1
- package/package.json +1 -1
- package/README.github.md +0 -230
package/atlas.cjs
CHANGED
|
@@ -186,7 +186,7 @@ ${_c(A.agentCode,"\u6D4F\u89C8\u5668\u62C9\u8D77\u5931\u8D25")}`,"INTERACTIVE_RE
|
|
|
186
186
|
`),(t.json||j())&&y("\uFF08JSON \u6A21\u5F0F\u4E0B base64 \u4F18\u5148\u5199 stdout\uFF1B\u4FE1\u5C01\u7701\u7565\uFF09");return}if(t.base64&&t.out){let s=await xi(r,t.out,!0);e&&y(qc),y(`\u5DF2\u5BFC\u51FA\u5230 ${s}\uFF08refresh-only=${e}\uFF0Cbase64 \u6587\u672C\uFF09`),(t.json||j())&&se({exported:!0,path:s,refreshOnly:e,base64:!0,count:r.cookies.length});return}if(t.out){let s=await xi(r,t.out,!1);e&&y(qc),y(`\u5DF2\u5BFC\u51FA\u5230 ${s}\uFF08refresh-only=${e}\uFF0Cgzip \u4E8C\u8FDB\u5236\uFF09`),(t.json||j())&&se({exported:!0,path:s,refreshOnly:e,base64:!1,count:r.cookies.length});return}y(qc);let n=await io(r);process.stdout.write(n+`
|
|
187
187
|
`)}async function Wc(t){let e=t.persist!==!1,A,r=!1;if(t.base64&&!t.input){let s=(0,rD.readFileSync)(0,"utf-8").trim(),o=await Mi(s);A=o.bundle,r=o.warning.osMismatch}else if(t.input){let s=await Ml(t.input);A=s.bundle,r=s.warning.osMismatch}else throw new re("\u8BF7\u6307\u5B9A\u5BFC\u5165\u6E90\uFF1A-i <\u6587\u4EF6> \u6216 --base64 \u4ECE stdin \u8BFB\u53D6\uFF08\u5982 ATLAS_COOKIES_B64 \u73AF\u5883\u53D8\u91CF\u81EA\u52A8\u5BFC\u5165\u8BF7\u4F7F\u7528\u73AF\u5883\u53D8\u91CF\u65B9\u5F0F\uFF09");if(A.cookies.length===0)throw new re("\u5BFC\u5165\u7684 bundle \u4E0D\u542B\u4EFB\u4F55 cookies\uFF0C\u8BF7\u786E\u8BA4\u5BFC\u51FA\u6E90\u5DF2\u767B\u5F55");r&&y(`\u26A0\uFE0F bundle \u5728 ${A.manifest.os} \u5BFC\u51FA\uFF0C\u5F53\u524D\u4E3A ${process.platform}\uFF0C\u8DE8\u5E73\u53F0 cookies \u53EF\u80FD\u5931\u6548`);let n=await $t();if(n&&n.length>0&&!t.force)throw new re("\u672C\u5730\u5DF2\u5B58\u5728\u767B\u5F55\u6001\uFF0C\u62D2\u7EDD\u8986\u76D6\u3002\u4F7F\u7528 --force \u5F3A\u5236\u8986\u76D6\uFF08\u5C06\u4E22\u5931\u65E7 cookies\uFF09");if(e)await xr(A.cookies),y(`\u5DF2\u5BFC\u5165 ${A.cookies.length} \u4E2A cookies \u5230 ${BA()}`),(t.json||j())&&se({imported:!0,count:A.cookies.length,osMismatch:r,refreshOnly:A.manifest.refreshOnly,persisted:!0});else{let{__setCachedCookiesForImport:s}=await Promise.resolve().then(()=>(xA(),BE));s(A.cookies),y(`\u5DF2\u5185\u5B58\u5BFC\u5165 ${A.cookies.length} \u4E2A cookies\uFF08\u672A\u843D\u76D8\uFF09`),(t.json||j())&&se({imported:!0,count:A.cookies.length,osMismatch:r,refreshOnly:A.manifest.refreshOnly,persisted:!1})}}function nD(t){return t.canLaunchBrowser?"browser":t.daemonReachable?"daemon":t.cookiesReady?"manual_export_hint":"import"}async function jc(t){let e=hE(),A=EE(),r=await dE(A.url??void 0,A.token??void 0),n=nD({canLaunchBrowser:e.canLaunchBrowser,cookiesReady:e.cookiesReady,daemonReachable:r,daemonVia:A.via}),s={agentCode:e.agentCode,agentSignal:e.agentSignal,sandbox:!e.canLaunchBrowser,canLaunchBrowser:e.canLaunchBrowser,cookies:{path:BA(),present:e.cookiesReady,expired:null},daemon:{url:A.url,reachable:r,via:A.via},recommendedPath:n};if(t.json||j()){se(s);return}y("Atlas auth \u8BCA\u65AD"),y(` agent: ${e.agentCode||"(\u672A\u8BC6\u522B)"} ${e.agentSignal?`[${e.agentSignal}]`:""}`),y(` \u6C99\u76D2\u73AF\u5883: ${s.sandbox?"\u662F":"\u5426"}`),y(` \u53EF\u62C9\u8D77\u6D4F\u89C8\u5668: ${e.canLaunchBrowser?"\u662F":"\u5426"} (TTY=${e.hasTTY}, DISPLAY=${e.hasDisplay}, container=${e.isContainer})`),y(` \u672C\u5730 cookies: ${e.cookiesReady?"\u5DF2\u5C31\u7EEA":"\u7F3A\u5931"} (${BA()})`),y(` Daemon: ${A.url?`${A.url} (${A.via})`:"\u672A\u914D\u7F6E"} - ${r?"\u53EF\u8FBE":"\u4E0D\u53EF\u8FBE"}`),y(` \u63A8\u8350\u8DEF\u5F84: ${n}`),s.sandbox&&!e.cookiesReady&&!r&&(y(""),y("\u6C99\u76D2\u767B\u5F55\u5F15\u5BFC\uFF1A"),y(" [\u63A8\u8350] \u4ECE\u672C\u5730\u5BFC\u51FA \u2192 \u6C99\u76D2\u5BFC\u5165\uFF1A"),y(" (\u672C\u5730) atlas auth export --base64"),y(" (\u6C99\u76D2) export ATLAS_COOKIES_B64=<\u7C98\u8D34\u4E0A\u4E00\u6B65\u8F93\u51FA> && atlas auth doctor"),y(" [\u6216] \u590D\u7528\u5BBF\u4E3B\u673A daemon\uFF1A"),y(" (\u672C\u5730) atlas daemon"),y(" (\u6C99\u76D2) export ATLAS_DAEMON_URL=http://host.docker.internal:8765"),y(" export ATLAS_DAEMON_TOKEN=<~/.atlas/daemon.token \u5185\u5BB9>"))}var Zc=_r(Tc(),1);je();xA();var e1={TOKEN_INVALID:()=>new We("\u4F1A\u8BDD token \u5DF2\u5931\u6548\uFF0C\u8BF7\u5148\u6267\u884C\uFF1Aatlas auth refresh\uFF1B\u5931\u8D25\u518D\u6267\u884C\uFF1Aatlas auth login"),TOKEN_EXPIRED:()=>new We("\u4F1A\u8BDD token \u5DF2\u8FC7\u671F\uFF0C\u8BF7\u5148\u6267\u884C\uFF1Aatlas auth refresh\uFF1B\u5931\u8D25\u518D\u6267\u884C\uFF1Aatlas auth login"),SESSION_EXPIRED:()=>new We("\u4F1A\u8BDD\u5DF2\u8FC7\u671F\uFF0C\u8BF7\u5148\u6267\u884C\uFF1Aatlas auth refresh\uFF1B\u5931\u8D25\u518D\u6267\u884C\uFF1Aatlas auth login"),501:()=>new We("\u4F1A\u8BDD token \u5DF2\u5931\u6548\uFF0C\u8BF7\u5148\u6267\u884C\uFF1Aatlas auth refresh\uFF1B\u5931\u8D25\u518D\u6267\u884C\uFF1Aatlas auth login")};function t1(t){if(!t)return!1;let A=t.toLowerCase().includes("token"),r=t.includes("\u5931\u6548")||t.includes("\u8FC7\u671F");return A&&r}var A1="https://banma-yuntu.alibaba-inc.com",yE=class{baseUrl;baseOrigin;timeout;constructor(e={}){this.baseUrl=(e.baseUrl??A1).replace(/\/+$/,""),this.baseOrigin=new URL(this.baseUrl).origin,this.timeout=e.timeout??3e4}async buildHeaders(){let e=await $t(),A={Accept:"application/json, text/plain, */*","Content-Type":"application/json","User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) atlas-cli",Referer:"https://banma-yuntu.alibaba-inc.com/",Origin:"https://banma-yuntu.alibaba-inc.com"};e&&e.length>0&&(A.Cookie=e.map(n=>`${n.name}=${n.value}`).join("; "));let r=await Lr();return r&&(r.token&&(A.token=r.token,A["x-banma-token"]=r.token),r.user&&(A["x-banma-user"]=r.user),r.staffId&&(A["x-banma-staff-id"]=r.staffId),A["x-banma-company-id"]=""),A}async get(e,A,r){if(!e.startsWith("/"))throw new Ne("path must be relative (start with /)","CONFIG_ERROR");let n=new URL(e,this.baseUrl+"/");if(A&&Object.entries(A).forEach(([i,a])=>n.searchParams.set(i,a)),n.origin!==this.baseOrigin)throw new Ne("origin mismatch \u2014 possible SSRF","CONFIG_ERROR");let s=await this.buildHeaders(),o=await(0,Zc.request)(n.toString(),{method:"GET",headers:s,headersTimeout:this.timeout,bodyTimeout:this.timeout});return this.parseResponse(o,r)}async post(e,A,r){if(!e.startsWith("/"))throw new Ne("path must be relative (start with /)","CONFIG_ERROR");let n=new URL(e,this.baseUrl+"/");if(n.origin!==this.baseOrigin)throw new Ne("origin mismatch \u2014 possible SSRF","CONFIG_ERROR");let s=await this.buildHeaders(),o=await(0,Zc.request)(n.toString(),{method:"POST",headers:s,body:A?JSON.stringify(A):void 0,headersTimeout:this.timeout,bodyTimeout:this.timeout});return this.parseResponse(o,r)}async multipartUpload(e,A,r){if(!e.startsWith("/"))throw new Ne("path must be relative (start with /)","CONFIG_ERROR");let n=new URL(e,this.baseUrl+"/");if(n.origin!==this.baseOrigin)throw new Ne("origin mismatch \u2014 possible SSRF","CONFIG_ERROR");let s=await this.buildHeaders(),o=`----FormBoundary${Math.random().toString(36).slice(2)}`,i=`\r
|
|
188
188
|
`,a=[];for(let l of A)a.push(Buffer.from(`--${o}${i}Content-Disposition: form-data; name="${l.name}"${i}${i}${l.value}${i}`));a.push(Buffer.from(`--${o}${i}Content-Disposition: form-data; name="${r.name}"; filename="${r.filename}"${i}Content-Type: application/octet-stream${i}${i}`)),a.push(r.buffer),a.push(Buffer.from(`${i}--${o}--${i}`));let c=await(0,Zc.request)(n.toString(),{method:"POST",headers:{...s,"Content-Type":`multipart/form-data; boundary=${o}`},body:Buffer.concat(a),headersTimeout:this.timeout*2,bodyTimeout:this.timeout*2});return this.parseResponse(c)}async parseResponse(e,A){let r=e.statusCode,n=await e.body.text();if(r===401||r===403)throw new We;if(r===302)throw new We("\u4F1A\u8BDD\u5DF2\u5931\u6548\u6216\u672A\u6388\u6743\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55");if(r===429)throw new Ne("\u8BF7\u6C42\u8FC7\u4E8E\u9891\u7E41\uFF08429 \u9650\u6D41\uFF09\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5","RATE_LIMITED");let s;try{s=JSON.parse(n)}catch{throw new AA("PARSE_ERROR",`Failed to parse: ${n.slice(0,200)}`)}if(s.errCode&&s.errCode!=="SUCCESS"){let a=e1[s.errCode];if(a)throw a();if(t1(s.errorMsg))throw new We("\u4F1A\u8BDD token \u5DF2\u5931\u6548\uFF0C\u8BF7\u5148\u6267\u884C\uFF1Aatlas auth refresh\uFF1B\u5931\u8D25\u518D\u6267\u884C\uFF1Aatlas auth login")}if(r>=200&&r<300)return A?A.parse(s.data):s.data;let o=s.errCode??String(s.code)??`HTTP_${r}`,i=s.errorMsg??s.detail??`HTTP ${r}`;throw new AA(o,i,s.detail??void 0)}};function Ar(){return new yE}var Zs=require("fs");ur();je();function sD(){return process.env.BANMA_PROJECT_ID}function Xs(t){if(t)return t;if(process.env.BANMA_PROJECT_ID)return process.env.BANMA_PROJECT_ID;try{let e=os();if((0,Zs.existsSync)(e)){let A=JSON.parse((0,Zs.readFileSync)(e,"utf-8"));if(A.projectId)return A.projectId}}catch{}throw new re("\u8BF7\u6307\u5B9A --project-id\u3001\u8BBE\u7F6E BANMA_PROJECT_ID\u3001\u6216\u5148\u7528 atlas link <project> \u7ED1\u5B9A\u9879\u76EE")}function Xc(t){if(t)return{id:t};if(process.env.BANMA_PROJECT_ID)return{id:process.env.BANMA_PROJECT_ID};try{let e=os();if((0,Zs.existsSync)(e)){let A=JSON.parse((0,Zs.readFileSync)(e,"utf-8"));if(A.projectId)return{id:A.projectId,name:A.projectName}}}catch{}throw new re("\u8BF7\u6307\u5B9A --project-id\u3001\u8BBE\u7F6E BANMA_PROJECT_ID\u3001\u6216\u5148\u7528 atlas link <project> \u7ED1\u5B9A\u9879\u76EE")}je();var fi=require("fs/promises"),DE=require("fs");ur();sn();var zc=os(),wE=bl("projects");async function oD(){try{return(0,DE.existsSync)(zc)?JSON.parse(await(0,fi.readFile)(zc,"utf-8")):null}catch{return null}}async function r1(t){await nn(nA(),{recursive:!0}),await St(zc,JSON.stringify(t,null,2))}async function n1(){try{await(0,fi.unlink)(zc)}catch{}}function Pn(t){return t.name??t.projectName??String(t.id)}function Wn(t){return String(t.id)}async function SE(t){if(!t)try{if((0,DE.existsSync)(wE))return JSON.parse(await(0,fi.readFile)(wE,"utf-8"))}catch{}let r=await Ar().post("/yuntu-service/project/selectHasPermisValidProject.json",{})??[];return await nn(kl(),{recursive:!0}),await St(wE,JSON.stringify(r,null,2)),r}function s1(t,e){let A=t.find(n=>Wn(n)===e||Pn(n)===e);if(A)return{id:Wn(A),name:Pn(A)};let r=t.filter(n=>Wn(n).includes(e)||Pn(n).includes(e));if(r.length===1)return{id:Wn(r[0]),name:Pn(r[0])};if(r.length>1)throw new Ne(`\u9879\u76EE\u5339\u914D\u6B67\u4E49: "${e}" \u5339\u914D\u4E86 ${r.length} \u4E2A\u9879\u76EE`,"AMBIGUOUS_PROJECT");return null}async function iD(t,e,A){let r=Ar(),n=[];if(t==="project"){if(n=(await SE(A.refresh)??[]).filter(i=>Wn(i).includes(e)||Pn(i).includes(e)).map(i=>({id:Wn(i),name:Pn(i),kind:"project"})),n.length===0){try{let i=await r.get("/yuntu-service/projApi/queryProjById.json",{projId:e});i?.projInfo?.id&&i?.projInfo?.projName&&(n=[{id:String(i.projInfo.id),name:i.projInfo.projName,kind:"project"}])}catch{}if(n.length===0)try{let i=await r.get("/yuntu-service/projApi/queryProjList.json",{projName:e,staffId:""});Array.isArray(i)&&(n=i.filter(a=>a.id&&a.projName).slice(0,parseInt(A.limit??"20",10)).map(a=>({id:String(a.id),name:a.projName,kind:"project"})))}catch{}}}else if(t==="department"){let o=await r.post("/yuntu-service/department/tree/select.json",{}),i=Array.isArray(o)?o:[],a=c=>{let l=[];for(let u of c){let h=u.deptName??"";h.includes(e)&&l.push({id:String(u.id??u.deptCode??""),name:h,kind:"department"}),u.children&&l.push(...a(u.children))}return l};n=a(i)}else{let o=await r.post("/yuntu-service/dictionary/select.json",{dictType:t}),i=Array.isArray(o)?o:[],c={"manpower-type":"\u4EBA\u529B\u7C7B\u578B",role:"\u4EBA\u529B\u57FA\u7EBF\u89D2\u8272",area:"\u5730\u57DF"}[t];n=(c?i.filter(u=>u.typeDesc===c):i).filter(u=>(u.attrName??"").includes(e)).map(u=>({id:u.attrValue??"",name:u.attrName??"",kind:t}))}let s=parseInt(A.limit??"20",10);if(!Number.isFinite(s)||s<=0)throw new re(`--limit \u5FC5\u987B\u4E3A\u6B63\u6574\u6570\uFF0C\u5B9E\u9645: "${A.limit}"`);if(n=n.slice(0,s),A.json||j()){se(n,{count:n.length,kind:t,query:e});return}y(`\u627E\u5230 ${n.length} \u4E2A${t}:`),mE(n)}async function aD(t){let r=(await SE(t.refresh)??[]).map(n=>({id:Wn(n),name:Pn(n)}));if(t.json||j()){se(r);return}y(`\u4F60\u6709 ${r.length} \u4E2A\u9879\u76EE\u7684\u6743\u9650:`),mE(r)}async function cD(t,e){let A=await SE(e.refreshProjects),r=s1(A,t);if(!r)throw new Ne(`\u672A\u627E\u5230\u9879\u76EE: "${t}"`,"PROJECT_NOT_FOUND");let n={projectId:r.id,projectName:r.name,linkedAt:new Date().toISOString()};if(e.dryRun){if(y(`[dry-run] \u5C06\u4F1A\u7ED1\u5B9A\u9879\u76EE: ${r.name} (${r.id})`),e.json||j()){se({dryRun:!0,link:n});return}return}await r1(n),y(`\u5DF2\u7ED1\u5B9A\u9879\u76EE: ${r.name} (${r.id})`),(e.json||j())&&se(n)}async function lD(t){let e=await oD(),A=sD();if(t.json||j()){se({linked:e??null,envProjectId:A??null});return}e?y(`\u5F53\u524D\u7ED1\u5B9A\u9879\u76EE: ${e.projectName} (${e.projectId})
|
|
189
|
-
\u7ED1\u5B9A\u65F6\u95F4: ${e.linkedAt}`):y("\u672A\u7ED1\u5B9A\u9879\u76EE\u3002\u4F7F\u7528 atlas link <project> \u7ED1\u5B9A"),A&&y(`\u73AF\u5883\u53D8\u91CF BANMA_PROJECT_ID=${A}`)}async function uD(t){let e=await oD();if(!e){if(y("\u5F53\u524D\u672A\u7ED1\u5B9A\u9879\u76EE"),t.json||j()){se({unlinked:!1});return}return}if(t.dryRun){if(y(`[dry-run] \u5C06\u4F1A\u6E05\u9664\u9879\u76EE\u7ED1\u5B9A: ${e.projectName}`),t.json||j()){se({dryRun:!0,link:e});return}return}await n1(),y(`\u5DF2\u6E05\u9664\u9879\u76EE\u7ED1\u5B9A: ${e.projectName}`),(t.json||j())&&se({unlinked:!0,projectName:e.projectName})}je();var o1="ATLAS_MAX_OUTPUT_BYTES";function Kc(t){let e=process.env[o1];if(!e)return;let A=Number(e);if(!Number.isFinite(A)||A<=0)return;let r=Buffer.byteLength(t,"utf-8");if(r>A)throw new IA(r,A)}je();function zs(t){let e=new Date(t+288e5);return`${e.getUTCFullYear()}-${String(e.getUTCMonth()+1).padStart(2,"0")}`}function gD(){let t=new Date;return`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}`}var hD=/^(\d{4})-(0[1-9]|1[0-2])$/,dD=36;function gA(t,e){if(!t||!e)return[gD()];if(!hD.test(t))throw new re(`\u6708\u4EFD\u683C\u5F0F\u5E94\u4E3A YYYY-MM\uFF08\u5982 2026-03\uFF09\uFF0C\u5B9E\u9645: "${t}"`);if(!hD.test(e))throw new re(`\u6708\u4EFD\u683C\u5F0F\u5E94\u4E3A YYYY-MM\uFF08\u5982 2026-03\uFF09\uFF0C\u5B9E\u9645: "${e}"`);let[A,r]=t.split("-").map(Number),[n,s]=e.split("-").map(Number),o=[],i=A,a=r;for(;i<n||i===n&&a<=s;)o.push(`${i}-${String(a).padStart(2,"0")}`),a++,a>12&&(a=1,i++);if(o.length>dD)throw new re(`\u6708\u4EFD\u8303\u56F4\u8FC7\u5927: ${o.length} \u4E2A\u6708\uFF08\u4E0A\u9650 ${dD} \u4E2A\u6708\uFF09\uFF0C\u8BF7\u7F29\u5C0F\u67E5\u8BE2\u8303\u56F4`);return o}function Ks(){let t=new Date,e=t.getFullYear(),A=t.getMonth()+1,r=e,n=A-12;for(;n<1;)n+=12,r--;let s=e,o=A+12;for(;o>12;)o-=12,s++;let i=`${r}-${String(n).padStart(2,"0")}`,a=`${s}-${String(o).padStart(2,"0")}`;return gA(i,a)}sn();function i1(t){let e=Xc(t.projectId);return e.name??e.id}function kE(t){return Xs(t.projectId)}async function FE(t,e){let A=Ar(),r={projectId:t,month:e};return A.post("/yuntu-service/line/plan/month/select.json",r)}function UE(t){return typeof t=="object"&&t!==null&&typeof t.month=="number"&&Number.isFinite(t.month)}var a1={0:"\u6591\u9A6C",1:"\u667A\u8F6F"};function ED(t,e){return t.filter(A=>(!e.department||A.departmentName&&A.departmentName.includes(e.department))&&(!e.role||A.role&&A.role.includes(e.role))&&(!e.area||A.areaCode&&A.areaCode.includes(e.area))&&(!e.manpowerType||A.mpType&&a1[A.mpType]?.includes(e.manpowerType)))}async function fD(t){let e=kE(t),A=t.month?[t.month]:gA(t.from,t.to),r=await FE(e,A[0]),n=[];for(let c of r??[]){let l=c.linePlanMonthDetailList??[],u=String(c.mpType??""),h=c.areaCode;for(let g of l)UE(g)&&n.push({month:zs(g.month),manpower:g.manpower??0,role:c.role,departmentName:c.departmentName,mpType:u,areaCode:h})}let s=ED(n,t),o=new Map;for(let c of s)o.set(c.month,(o.get(c.month)??0)+c.manpower);let i=[...o.keys()].sort(),a=i.reduce((c,l)=>c+(o.get(l)??0),0);if(t.json||j()){se({projectId:e,months:i,entries:n,totalManpower:Math.round(a*100)/100});return}y(`\u9879\u76EE ${i1(t)} \u57FA\u7EBF\u4EBA\u529B:`);for(let c of i)y(` ${c}: ${(o.get(c)??0).toFixed(2)} \u4EBA\u6708`);y(` \u5408\u8BA1: ${a.toFixed(2)} \u4EBA\u6708`)}async function QD(t){let e=kE(t),A=t.month?[t.month]:gA(t.from,t.to),r=await FE(e,A[0]),n=[];for(let c of r??[]){let l=String(c.mpType??""),u=c.areaCode;for(let h of c.linePlanMonthDetailList??[])UE(h)&&n.push({month:zs(h.month),manpower:h.manpower??0,role:c.role,departmentName:c.departmentName,mpType:l,areaCode:u})}let s=ED(n,t),o=t.by??"month",i=new Map;for(let c of s){let l=o==="month"?c.month:o==="department"?c.departmentName??"\u5176\u4ED6":c.role??"\u5176\u4ED6";i.set(l,(i.get(l)??0)+c.manpower)}let a=[...i.entries()].map(([c,l])=>({[o]:c,manpower:Math.round(l*100)/100}));if(t.json||j()){se({rows:a});return}y("\u6C47\u603B:");for(let c of a)y(` ${String(c[o])}: ${c.manpower.toFixed(2)} \u4EBA\u6708`)}async function CD(t){let e=kE(t),A=gA(t.from,t.to),r=await FE(e,A[0]),n=[];for(let i of r??[])for(let a of i.linePlanMonthDetailList??[])UE(a)&&n.push({projectId:e,month:zs(a.month),role:i.role??"",manpower:a.manpower??0});let s=t.format==="csv"?(await Promise.resolve().then(()=>_r(bE(),1))).default.unparse(n):JSON.stringify(n,null,2);Kc(s);let o=Ni(t.out);await St(o,s),y(`\u5DF2\u5BFC\u51FA ${n.length} \u6761\u8BB0\u5F55`),(t.json||j())&&se({exported:n.length,format:t.format,out:o})}sn();function $c(t,e){return t.map(A=>({...A,month:e}))}function jn(t){return t==="all"||t==="pending"||t==="approved"?t:"approved"}function c1(t,e){let A=Number(t);return e==="approved"?A===2:e==="pending"?A!==2:!0}function ID(t,e){let A=new Map;for(let r of t){let n=e==="month"?r.month:e==="department"?r.departmentName??"\u5176\u4ED6":r.role??"\u5176\u4ED6";A.set(n,(A.get(n)??0)+(r.manpower??0))}return[...A.entries()].map(([r,n])=>({[e]:r,manpower:Math.round(n*100)/100}))}function BD(t,e){return t.filter(A=>A.staffId===e||A.staffName?.includes(e))}function el(t,e,A="approved"){let r=new Map;function n(o){let i=o.children;return!Array.isArray(i)||i.length===0}function s(o){for(let i of o??[]){let a=i;if(n(a)){let c=a.detail??[],l=0;for(let u of c)String(u.projectId)===e&&c1(u.status,A)&&(l+=Number(u.manpower??0));if(l>0){let u=String(a.staffId??""),h=l/22,d=(r.get(u)?.manpower??0)+h;r.set(u,{staffId:u,staffName:String(a.realname??""),manpower:Math.round(d*100)/100,departmentName:String(a.department??""),role:String(a.role??"")})}}else s(a.children)}}return s(t),[...r.values()]}xA();function tl(t){return Xs(t.projectId)}async function Al(t,e,A){let r=Ar(),s=(await Lr())?.staffId??"",o=await r.post("/yuntu-service/manpower/weekly/summaryByProject.json",{month:e,staffIds:[],projectIds:[t],isConfirm:!1,loginStaffId:s}),i=Array.isArray(o)?o:[];return i.length>0&&i[0].children?el(i[0].children,t,A):[]}async function pD(t,e){let A=tl(e),r=e.month??Ks()[0],n=await Al(A,r,jn(e.status)),s=BD(n,t);if(e.json||j()){se({staffId:t,month:r,personnel:s});return}if(s.length===0){y(`${t} \u5728 ${r} \u65E0\u5B9E\u9645\u5DE5\u65F6\u6570\u636E`);return}for(let o of s)y(` ${o.staffName} (${o.staffId}): ${o.manpower.toFixed(2)} \u4EBA\u6708`)}async function mD(t){let e=tl(t),A=t.month?[t.month]:t.from||t.to?gA(t.from,t.to):Ks(),r=jn(t.status),n=[],s=[];for(let i of A)try{let a=await Al(e,i,r);n.push(...$c(a,i))}catch(a){s.push({month:i,error:a instanceof Error?a.message:String(a)}),y(`\u6708 ${i} \u65E0\u5B9E\u9645\u5DE5\u65F6\u6570\u636E`)}let o=n.filter(i=>(!t.department||i.departmentName&&i.departmentName.includes(t.department))&&(!t.role||i.role&&i.role.includes(t.role)));if(t.json||j()){se({projectId:e,entries:o},{failedMonths:s});return}if(o.length===0){y("\u65E0\u5B9E\u9645\u5DE5\u65F6\u6570\u636E");return}for(let i of o)y(` ${i.staffName}: ${i.manpower.toFixed(2)} (${i.role??""})`)}async function yD(t){let e=tl(t),A=t.month?[t.month]:t.from||t.to?gA(t.from,t.to):Ks(),r=jn(t.status),n=[],s=[];for(let c of A)try{n.push(...$c(await Al(e,c,r),c))}catch(l){s.push({month:c,error:l instanceof Error?l.message:String(l)}),y(`\u6708 ${c} \u65E0\u5B9E\u9645\u5DE5\u65F6\u6570\u636E`)}let o=n.filter(c=>(!t.department||c.departmentName&&c.departmentName.includes(t.department))&&(!t.role||c.role&&c.role.includes(t.role))),i=t.by??"month",a=ID(o,i);if(t.json||j()){se({rows:a},{failedMonths:s});return}for(let c of a)y(` ${c[i]}: ${c.manpower.toFixed(2)} \u4EBA\u6708`)}async function wD(t){let e=tl(t),A=gA(t.from,t.to),r=jn(t.status),n=[],s=[];for(let c of A)try{let l=await Al(e,c,r);n.push(...$c(l,c))}catch(l){s.push({month:c,error:l instanceof Error?l.message:String(l)}),y(`\u6708 ${c} \u65E0\u5B9E\u9645\u5DE5\u65F6\u6570\u636E`)}let o=n.filter(c=>(!t.department||c.departmentName&&c.departmentName.includes(t.department))&&(!t.role||c.role&&c.role.includes(t.role))),i=t.format==="csv"?(await Promise.resolve().then(()=>_r(bE(),1))).default.unparse(o):JSON.stringify(o,null,2);Kc(i);let a=Ni(t.out);await St(a,i),y(`\u5DF2\u5BFC\u51FA ${o.length} \u6761\u8BB0\u5F55`),(t.json||j())&&se({exported:o.length,format:t.format,out:a},{failedMonths:s})}je();function TE(t,e){let A=new Map;for(let r of t){let n=e==="department"?r.departmentName??"\u5176\u4ED6":e==="role"?r.role??"\u5176\u4ED6":r.month;A.set(n,(A.get(n)??0)+r.manpower)}return A}function DD(t,e,A,r){let s=[...new Set([...t.keys(),...e.keys()])].sort().map(o=>({[A]:o,baselineManpower:Math.round((t.get(o)??0)*100)/100,actualManpower:Math.round((e.get(o)??0)*100)/100,diff:Math.round(((e.get(o)??0)-(t.get(o)??0))*100)/100}));return r>0&&(s=s.filter(o=>Math.abs(o.diff)>=r)),s}xA();function l1(t){return Xs(t.projectId)}async function SD(t){let e=l1(t),A=t.month?[t.month]:t.from||t.to?gA(t.from,t.to):Ks(),r=jn(t.status),n=[],s=[],o=Ar(),i=[];try{let d=await o.post("/yuntu-service/line/plan/month/select.json",{projectId:e,month:A[0]??""});for(let I of d??[]){let R=I.linePlanMonthDetailList??[];for(let B of R)if(B&&typeof B=="object"){let m=B.month,w=typeof m=="number"?zs(m):A[0];n.push({month:w,manpower:Number(B.manpower??0),role:I.role,departmentName:I.departmentName})}}}catch(d){if(d instanceof We)throw d;y(`\u57FA\u7EBF\u6570\u636E\u62C9\u53D6\u5931\u8D25: ${d instanceof Error?d.message:String(d)}`)}for(let d of A)try{let R=(await Lr())?.staffId??"",B=await o.post("/yuntu-service/manpower/weekly/summaryByProject.json",{month:d,staffIds:[],projectIds:[e],isConfirm:!1,loginStaffId:R}),m=Array.isArray(B)?B:[],w=[];if(m.length>0&&m[0].children){let z=el(m[0].children,e,r);for(let G of z)w.push({month:d,manpower:G.manpower??0,role:G.role,departmentName:G.departmentName})}for(let z of w)s.push(z)}catch(I){i.push({month:d,error:`\u5B9E\u9645\u5DE5\u65F6\u62C9\u53D6\u5931\u8D25: ${I instanceof Error?I.message:String(I)}`})}let a=t.by??"month",c=TE(n,a),l=TE(s,a),u=Number(t.threshold??"0");if(!Number.isFinite(u)||u<0)throw new re(`--threshold \u5FC5\u987B\u4E3A\u975E\u8D1F\u6570\uFF0C\u5B9E\u9645: "${t.threshold}"`);let h=DD(c,l,a,u);if(t.json||j()){se({rows:h},{failedMonths:i});return}let g=Xc(t.projectId);y(`\u9879\u76EE ${g.name??e} \u5BF9\u6BD4:${a==="month"?"\u6309\u6708\u4EFD":a==="department"?"\u6309\u90E8\u95E8":"\u6309\u89D2\u8272"}`);for(let d of h){let I=t.flagOverrun&&d.actualManpower>d.baselineManpower?" \u26A0\uFE0F":"";y(` ${String(d[a])}: \u57FA\u7EBF ${d.baselineManpower} / \u5B9E\u9645 ${d.actualManpower} / \u5DEE\u5F02 ${d.diff>0?"+":""}${d.diff}${I}`)}}var TD=require("http"),MD=require("https"),Qi=require("crypto"),ME=require("fs"),xD=require("path");ur();sn();je();je();var RD="(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)",bD=new RegExp(`^${RD}(\\.${RD}){3}$`),u1=/^[0-9a-fA-F:]+$/;function kD(t){if(!t)return!1;let e=t.toLowerCase().trim();return!!(e==="localhost"||e==="::1"||bD.test(e)&&e.startsWith("127."))}function g1(t){if(!t)return"";let e=t.trim(),A=e.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/i);return A?A[1]:e}function rl(t){if(!bD.test(t))return null;let e=t.split(".").map(Number);return(e[0]<<24>>>0)+(e[1]<<16)+(e[2]<<8)+e[3]>>>0}function ND(t){return[t>>>24&255,t>>>16&255,t>>>8&255,t&255].join(".")}function FD(t){if(!t||t.length===0)return[];let e=[];for(let A of t){let r=A.trim();if(r){if(r.includes(":")){if(r.includes("/"))throw new re(`\u6682\u4E0D\u652F\u6301 IPv6 CIDR\uFF08\u4EC5\u5355 IP\uFF09\uFF1A${A}`);if(!u1.test(r))throw new re(`\u975E\u6CD5 IPv6 \u5730\u5740\uFF1A${A}`);e.push({raw:A,family:"ipv6",network:r.toLowerCase(),prefix:128});continue}if(r.includes("/")){let[n,s]=r.split("/"),o=rl(n),i=Number(s);if(o===null)throw new re(`\u975E\u6CD5 IPv4 \u7F51\u7EDC\u5730\u5740\uFF1A${A}`);if(!Number.isInteger(i)||i<0||i>32)throw new re(`\u975E\u6CD5 IPv4 \u524D\u7F00\u957F\u5EA6\uFF1A${A}`);let a=i===0?0:4294967295<<32-i>>>0,c=(o&a)>>>0;e.push({raw:A,family:"ipv4",network:ND(c),prefix:i})}else{let n=rl(r);if(n===null)throw new re(`\u975E\u6CD5 IPv4 \u5730\u5740\uFF1A${A}`);e.push({raw:A,family:"ipv4",network:ND(n),prefix:32})}}}return e}function UD(t,e){if(e.length===0)return!0;let A=g1(t);if(!A)return!1;for(let r of e){if(r.family==="ipv6"){if(A.toLowerCase()===r.network)return!0;continue}let n=rl(A);if(n===null)continue;let s=r.prefix===0?0:4294967295<<32-r.prefix>>>0;if((n&s)>>>0===rl(r.network)>>>0)return!0}return!1}function h1(){return(0,Qi.randomBytes)(32).toString("hex")}function d1(t,e){let A=t.headers.authorization??"",r=`Bearer ${e}`,n=Buffer.from(A),s=Buffer.from(r);return n.length!==s.length?((0,Qi.timingSafeEqual)(Buffer.alloc(1),Buffer.alloc(1)),!1):(0,Qi.timingSafeEqual)(n,s)}function E1(t){return(e,A)=>{let r=(o,i)=>{A.writeHead(o,{"Content-Type":"application/json"}),A.end(JSON.stringify(i))},n=e.url??"/";if(n==="/api/health"||n==="/"){r(200,{ok:!0,pid:process.pid});return}if(!UD(e.socket.remoteAddress,t.allowList)){r(403,{ok:!1,error:"forbidden: ip not allowed"});return}if(!d1(e,t.token)){r(401,{ok:!1,error:"unauthorized"});return}if(n==="/api/cookies"){t.readCookies().then(o=>r(200,{ok:!0,cookies:o??[]})).catch(()=>r(500,{ok:!1,error:"read cookies failed"}));return}r(404,{ok:!1,error:"not found"})}}var f1=8765;async function LD(t){let e=Number(process.env.ATLAS_DAEMON_PORT),A=t.port!==void 0?Number(t.port):NaN,r=Number.isFinite(A)&&A>0?A:Number.isFinite(e)&&e>0?e:f1,n=t.host??"127.0.0.1",s=kD(n),o=!!t.tlsCert&&!!t.tlsKey;if(t.tlsCert&&!t.tlsKey||t.tlsKey&&!t.tlsCert)throw new Ne("--tls-cert \u4E0E --tls-key \u5FC5\u987B\u540C\u65F6\u6307\u5B9A","CONFIG_ERROR");if(!s&&!t.insecure&&(!t.allowIp||t.allowIp.length===0))throw new Ne("\u975E loopback \u76D1\u542C\u5FC5\u987B\u6307\u5B9A --allow-ip \u6216\u663E\u5F0F --insecure\uFF08\u660E\u6587\u4F20\u8F93 token \u4EC5\u5EFA\u8BAE\u672C\u673A\u5F00\u53D1\uFF09","CONFIG_ERROR");!s&&!o&&t.insecure&&y("\u26A0\u26A0\u26A0 \u660E\u6587\u76D1\u542C\u975E loopback \u63A5\u53E3\uFF0CBearer token \u5C06\u4EE5\u660E\u6587\u4F20\u8F93\uFF0C\u4EC5\u5EFA\u8BAE\u672C\u673A\u5F00\u53D1\u4F7F\u7528 \u26A0\u26A0\u26A0");let i=FD(t.allowIp),a=h1(),c=is();await nn((0,xD.dirname)(c),{recursive:!0}),await St(c,a),y(`Daemon token \u5DF2\u5199\u5165 ${c}`);let u=E1({token:a,allowList:i,readCookies:async()=>{let{readCookies:d}=await Promise.resolve().then(()=>(xA(),BE));return d()}}),h;if(o){let d,I;try{d=(0,ME.readFileSync)(t.tlsCert),I=(0,ME.readFileSync)(t.tlsKey)}catch(R){throw new Ne(`TLS \u8BC1\u4E66\u8BFB\u53D6\u5931\u8D25\uFF1A${R.message}`,"CONFIG_ERROR")}h=(0,MD.createServer)({cert:d,key:I},u)}else h=(0,TD.createServer)(u);await new Promise((d,I)=>{h.on("error",R=>{R.code==="EADDRINUSE"?I(new Ne(`\u7AEF\u53E3 ${r} \u5DF2\u88AB\u5360\u7528`,"CONFIG_ERROR")):I(R)}),h.listen(r,n,d)}),y(`\u5B88\u62A4\u8FDB\u7A0B\u5DF2\u542F\u52A8\uFF0C\u76D1\u542C ${o?"https":"http"}://${n}:${r}${!s&&!o&&t.insecure?"\uFF08\u660E\u6587\uFF09":""}`),await new Promise(()=>{})}function vD(t,e){let A=[];if(t.commands.forEach(r=>{A.push(r.name()),r.commands.length>0&&r.commands.forEach(n=>{A.push(`${r.name()} ${n.name()}`)})}),e.describe){t.commands.forEach(r=>{xE(r)});return}if(e.json||j()){se({commands:A});return}y("\u53EF\u7528\u547D\u4EE4:"),A.sort().forEach(r=>y(` ${r}`))}var OD=require("fs/promises"),YD=require("child_process");hf();je();var Q1=CA.object({command:CA.string().regex(/^atlas( [a-z\-]+)+$/,'command \u5FC5\u987B\u662F atlas \u5B50\u547D\u4EE4\uFF0C\u5982 "atlas auth login"'),args:CA.array(CA.string()).optional()}),C1=CA.object({steps:CA.array(Q1).max(100,"\u6B65\u9AA4\u6570\u4E0D\u80FD\u8D85\u8FC7 100")});function I1(t,e=[]){let A=t.split(/\s+/),r=[process.argv[1],...A.slice(1),...e];return new Promise((n,s)=>{let o=(0,YD.spawn)(process.execPath,r,{stdio:"inherit",env:{...process.env}});o.on("close",i=>{i===0?n():s(new Error(`\u8FDB\u7A0B\u9000\u51FA\u7801 ${i}`))}),o.on("error",i=>{s(new Error(`\u65E0\u6CD5\u542F\u52A8\u8FDB\u7A0B: ${i.message}`))})})}async function HD(t){let e;try{e=await(0,OD.readFile)(t.planFile,"utf-8")}catch(n){throw new re(`\u65E0\u6CD5\u8BFB\u53D6\u8BA1\u5212\u6587\u4EF6: ${n instanceof Error?n.message:String(n)}`)}let A;try{A=C1.parse(JSON.parse(e))}catch(n){throw n instanceof CA.ZodError?new re(`\u8BA1\u5212\u6587\u4EF6\u6821\u9A8C\u5931\u8D25: ${n.errors.map(s=>`${s.path.join(".")}: ${s.message}`).join("; ")}`):new re(`\u8BA1\u5212\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF: ${n instanceof Error?n.message:String(n)}`)}y(`\u6267\u884C\u8BA1\u5212: ${A.steps.length} \u4E2A\u6B65\u9AA4`);let r=[];for(let n=0;n<A.steps.length;n++){let s=A.steps[n];y(`[${n+1}/${A.steps.length}] ${s.command}`);try{await I1(s.command,s.args),r.push({step:n+1,command:s.command,status:"success"})}catch(o){let i=o instanceof Error?o.message:String(o);r.push({step:n+1,command:s.command,status:`failed: ${i}`}),(t.json||j())&&se({results:r},{completed:n,total:A.steps.length}),process.exit(1)}}t.json||j()?se({results:r}):y("\u8BA1\u5212\u6267\u884C\u5B8C\u6BD5")}var B1=[{pattern:/登录|login|sso|auth/i,command:"atlas auth login",description:"SSO \u767B\u5F55\uFF08\u9700\u7EC8\u7AEF\u4EA4\u4E92\uFF09",weight:10,requiresAuth:!1,exitCodes:[0,1,64]},{pattern:/状态|status|会话/i,command:"atlas auth status",description:"\u67E5\u770B\u4F1A\u8BDD\u72B6\u6001",weight:10,requiresAuth:!1,exitCodes:[0]},{pattern:/项目.*列表|列出.*项目|projects/i,command:"atlas projects",description:"\u5217\u51FA\u6240\u6709\u9879\u76EE",weight:10,requiresAuth:!0,exitCodes:[0,2]},{pattern:/绑定|link|关联/i,command:"atlas link <project>",description:"\u7ED1\u5B9A\u9879\u76EE\uFF08\u53EF\u7701\u540E\u7EED --project-id\uFF09",weight:10,requiresAuth:!0,exitCodes:[0,4,5]},{pattern:/解绑|unlink/i,command:"atlas unlink",description:"\u89E3\u7ED1\u9879\u76EE",weight:10,requiresAuth:!0,exitCodes:[0]},{pattern:/搜索|找|find|查询项目/i,command:"atlas find project <query>",description:"\u641C\u7D22\u9879\u76EE\uFF08\u4E5F\u652F\u6301 department/manpower-type/role/area\uFF09",weight:10,requiresAuth:!0,exitCodes:[0,2]},{pattern:/部门|department/i,command:"atlas find department <query>",description:"\u641C\u7D22\u90E8\u95E8",weight:7,requiresAuth:!0,exitCodes:[0,2]},{pattern:/字典|类型|mp.type|line.plan/i,command:"atlas find manpower-type <query>",description:"\u641C\u7D22 MP \u7C7B\u578B\u5B57\u5178\u503C",weight:7,requiresAuth:!0,exitCodes:[0,2]},{pattern:/基线|计划|baseline|人月.*计划/i,command:"atlas baseline month --month YYYY-MM",description:"\u67E5\u770B\u6307\u5B9A\u6708\u4EFD\u57FA\u7EBF\u4EBA\u529B",weight:5,requiresAuth:!0,exitCodes:[0,2,3,4,5]},{pattern:/基线.*汇总|baseline.*summar/i,command:"atlas baseline summary [--by month|department|role]",description:"\u6309\u6708/\u90E8\u95E8/\u89D2\u8272\u6C47\u603B\u57FA\u7EBF\u4EBA\u529B",weight:5,requiresAuth:!0,exitCodes:[0,2,3]},{pattern:/基线.*导出|baseline.*export/i,command:"atlas baseline export --from YYYY-MM --to YYYY-MM [--format csv|json] [--out <path>]",description:"\u5BFC\u51FA\u57FA\u7EBF\u6761\u76EE",weight:5,requiresAuth:!0,exitCodes:[0,2,3,65]},{pattern:/实际|actual|工时|人月.*实际/i,command:"atlas actual month --month YYYY-MM",description:"\u67E5\u770B\u6307\u5B9A\u6708\u4EFD\u5B9E\u9645\u5DE5\u65F6\uFF08\u4EBA\u6708\uFF09",weight:5,requiresAuth:!0,exitCodes:[0,2,3,4,5]},{pattern:/实际.*汇总|actual.*summar/i,command:"atlas actual summary [--by month|department|role]",description:"\u6C47\u603B\u5B9E\u9645\u5DE5\u65F6",weight:5,requiresAuth:!0,exitCodes:[0,2,3]},{pattern:/实际.*导出|actual.*export/i,command:"atlas actual export --from YYYY-MM --to YYYY-MM [--format csv|json] [--out <path>]",description:"\u5BFC\u51FA\u5B9E\u9645\u5DE5\u65F6",weight:5,requiresAuth:!0,exitCodes:[0,2,3,65]},{pattern:/实际.*人员|人员.*明细|staff|成员.*工时/i,command:"atlas actual show <staffId> --month YYYY-MM",description:"\u67E5\u770B\u5355\u4EBA\u5458\u5DE5\u5B9E\u9645\u5DE5\u65F6\u660E\u7EC6",weight:5,requiresAuth:!0,exitCodes:[0,2,3]},{pattern:/对比|比较|compare|差异|偏差/i,command:"atlas compare --from YYYY-MM --to YYYY-MM",description:"\u57FA\u7EBF vs \u5B9E\u9645\u5BF9\u6BD4\uFF08diff = \u5B9E\u9645 - \u57FA\u7EBF\uFF0C\u4EBA\u6708\uFF09",weight:10,requiresAuth:!0,exitCodes:[0,2,3,4,5]},{pattern:/批量|batch|exec|编排/i,command:"atlas exec --plan-file <path>",description:"\u6309 plan-file \u987A\u5E8F\u6267\u884C\u591A\u6761 atlas \u547D\u4EE4",weight:7,requiresAuth:!1,exitCodes:[0,1]},{pattern:/命令.*列表|命令树|帮助|自省|schema/i,command:"atlas schema commands [--describe]",description:"\u5217\u51FA\u6240\u6709\u547D\u4EE4 + \u8F93\u51FA schema\uFF08agent \u81EA\u7701\u5165\u53E3\uFF09",weight:8,requiresAuth:!1,exitCodes:[0]},{pattern:/升级|更新|update/i,command:"atlas update",description:"\u5347\u7EA7\u5230\u6700\u65B0\u7248\u672C",weight:10,requiresAuth:!1,exitCodes:[0]},{pattern:/守护|daemon/i,command:"atlas daemon",description:"\u542F\u52A8\u672C\u5730\u5B88\u62A4\u8FDB\u7A0B\uFF08\u4FDD\u6301\u6D4F\u89C8\u5668\u4F1A\u8BDD\uFF09",weight:5,requiresAuth:!1,exitCodes:[0]},{pattern:/项目\S+|(\S+项目)/i,command:"atlas find project <query>",description:"\u641C\u7D22\u9879\u76EE\uFF08\u542B\u6A21\u7CCA\u5339\u914D\u53C2\u6570\uFF09",weight:3,requiresAuth:!0,exitCodes:[0,2]},{pattern:/上个月|本月|上月|这个月|当月|当前月/i,command:"atlas baseline month --month $(date +%Y-%m)",description:"\u67E5\u770B\u5F53\u524D/\u4E0A\u4E2A\u6708\u57FA\u7EBF\uFF08\u6708\u4EFD\u53C2\u6570\u53EF\u63A8\u7B97\uFF09",weight:3,requiresAuth:!0,exitCodes:[0,2,3]},{pattern:/上季度|上个季度|本季度/i,command:'atlas compare --from $(date -d "$(date +%Y-%m-01) -3 months" +%Y-%m) --to $(date +%Y-%m)',description:"\u6309\u5B63\u5EA6\u8303\u56F4\u5BF9\u6BD4\uFF08\u6708\u4EFD\u53C2\u6570\u81EA\u52A8\u63A8\u7B97\uFF09",weight:3,requiresAuth:!0,exitCodes:[0,2,3]}];function _D(t,e){let A=[];for(let n of B1)n.pattern.test(t)&&A.push({command:n.command,description:n.description,score:n.weight,requiresAuth:n.requiresAuth,exitCodes:n.exitCodes});let r=t.toLowerCase();for(let n of A){let s=n.command.toLowerCase(),o=0;for(let i of r.split(/\s+/))i.length>=2&&s.includes(i)&&(o+=.5),/^\d{4}[-\/]\d{2}$/.test(i)&&(o+=1),/^\d+$/.test(i)&&i.length>=2&&s.includes(i)&&(o+=1);n.score+=o}if(A.sort((n,s)=>s.score-n.score),e.json||j()){se({query:t,suggestions:A.slice(0,5)});return}if(A.length===0){y(`\u672A\u627E\u5230\u5339\u914D\u7684 atlas \u547D\u4EE4: "${t}"`),y("\u63D0\u793A: \u8BD5\u8BD5 atlas --help \u67E5\u770B\u6240\u6709\u547D\u4EE4");return}y(`\u81EA\u7136\u8BED\u8A00\u67E5\u8BE2: "${t}"`),y("\u5EFA\u8BAE\u547D\u4EE4:");for(let n of A.slice(0,5)){let s=n.requiresAuth?"\u{1F511}":" ";y(` ${s} ${n.command} \u2014 ${n.description}`)}y(""),y("\u6807\u8BB0 \u{1F511}=\u9700\u8981\u767B\u5F55\uFF0C\u65E0\u6807\u8BB0=\u65E0\u9700\u9274\u6743")}var GD=require("url");je();var Zn="0.7.24";var m1={};function p1(){try{let t=new URL(m1.url),e=(0,GD.fileURLToPath)(t);return/node_modules[\\/]@dreamor[\\/]atlas-cli/.test(e)?"npm":"other"}catch{return"other"}}async function VD(t){if(process.env.ATLAS_DISABLE_UPDATE==="1"){y("\u66F4\u65B0\u5DF2\u88AB ATLAS_DISABLE_UPDATE \u7981\u7528"),(t.json||j())&&se({disabled:!0});return}let e=p1(),A="npm update -g @dreamor/atlas-cli";if(e==="npm"){y(`\u5F53\u524D\u7248\u672C ${Zn}`),y("\u901A\u8FC7 npm \u5B89\u88C5\u7684 atlas \u7531 npm registry \u7BA1\u7406\u5347\u7EA7\uFF0C\u8BF7\u8FD0\u884C:"),y(` ${A}`),(t.json||j())&&se({mode:"npm",current:Zn,updateCommand:A});return}y(`\u5F53\u524D\u7248\u672C ${Zn}`),y("\u5F53\u524D\u4EE5\u975E npm \u65B9\u5F0F\u8FD0\u884C\uFF0C\u81EA\u66F4\u65B0\u5DF2\u7981\u7528\u3002"),y("\u63A8\u8350\u8FC1\u79FB\u5230 npm \u5B89\u88C5\uFF1A"),y(" npm i -g @dreamor/atlas-cli"),y("\u968F\u540E\u901A\u8FC7 `npm update -g @dreamor/atlas-cli` \u5347\u7EA7\u3002"),(t.json||j())&&se({mode:"other",current:Zn,migrationCommand:"npm i -g @dreamor/atlas-cli",updateCommand:A})}je();var y1={"atlas auth login":{jsonSchema:{type:"object",properties:{ok:{type:"boolean",const:!0},data:{type:"object",properties:{status:{type:"string",enum:["logged_in"]},via:{type:"string",enum:["daemon"]}}}}}},"atlas auth status":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{loggedIn:{type:"boolean"},expiresAt:{type:"number"}}}}}},"atlas auth refresh":{jsonSchema:{type:"object",properties:{ok:{type:"boolean",const:!0},data:{type:"object",properties:{status:{type:"string",enum:["refreshed","still_valid"]},account:{type:"string"}}}}}},"atlas projects":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"array",items:{type:"object"}}}}},"atlas find":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"array",items:{type:"object"}},meta:{type:"object",properties:{count:{type:"number"},kind:{type:"string"},query:{type:"string"}}}}}},"atlas link":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{projectId:{type:"string"},projectName:{type:"string"},linkedAt:{type:"string"},linked:{type:"object",description:"\u5DF2\u7ED1\u5B9A\u7684\u9879\u76EE\u4FE1\u606F\uFF08link \u65E0\u53C2\u65F6\uFF09"},envProjectId:{type:"string",description:"BANMA_PROJECT_ID \u73AF\u5883\u53D8\u91CF\u503C"},dryRun:{type:"boolean"}}}}}},"atlas unlink":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{unlinked:{type:"boolean"},projectName:{type:"string"}}}}}},"atlas baseline month":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{projectId:{type:"string"},months:{type:"array",items:{type:"string"},description:"YYYY-MM \u683C\u5F0F\u6708\u4EFD\u5217\u8868"},entries:{type:"array",items:{type:"object",description:"\u5355\u4E2A\u6708\u4EFD\u7684\u57FA\u7EBF\u6761\u76EE"}},totalManpower:{type:"number",description:"\u5355\u4F4D\uFF1A\u4EBA\u6708"}}}}}},"atlas baseline summary":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"array",items:{type:"object",properties:{month:{type:"string",description:"YYYY-MM"},manpower:{type:"number",description:"\u5355\u4F4D\uFF1A\u4EBA\u6708"}}}}}}},"atlas baseline export":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{exported:{type:"number",description:"\u5BFC\u51FA\u884C\u6570"},format:{type:"string",enum:["csv","json"]},out:{type:"string",description:"\u5BFC\u51FA\u6587\u4EF6\u7EDD\u5BF9\u8DEF\u5F84\uFF08\u7ECF\u8FC7\u767D\u540D\u5355\u6821\u9A8C\uFF09"}}}}}},"atlas actual show":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{staffId:{type:"string"},month:{type:"string",description:"YYYY-MM"},personnel:{type:"array",items:{type:"object"}}}}}}},"atlas actual month":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{projectId:{type:"string"},entries:{type:"array",items:{type:"object"}}}},meta:{type:"object",properties:{failedMonths:{type:"array",items:{type:"string"}}}}}}},"atlas actual summary":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{rows:{type:"array",items:{type:"object"}}}},meta:{type:"object",properties:{failedMonths:{type:"array",items:{type:"string"}}}}}}},"atlas actual export":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{exported:{type:"number",description:"\u5BFC\u51FA\u884C\u6570"},format:{type:"string",enum:["csv","json"]},out:{type:"string",description:"\u5BFC\u51FA\u6587\u4EF6\u7EDD\u5BF9\u8DEF\u5F84"}}},meta:{type:"object",properties:{failedMonths:{type:"array",items:{type:"string"}}}}}}},"atlas compare":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{rows:{type:"array",items:{type:"object",properties:{month:{type:"string",description:"YYYY-MM"},plan:{type:"number",description:"\u57FA\u7EBF\u4EBA\u6708"},actual:{type:"number",description:"\u5B9E\u9645\u4EBA\u6708"},diff:{type:"number",description:"\u5B9E\u9645 - \u57FA\u7EBF\uFF08\u4EBA\u6708\uFF09"}}}}}},meta:{type:"object",properties:{failedMonths:{type:"array",items:{type:"string"}}}}}}},"atlas schema commands":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{commands:{type:"array",items:{type:"string"}}}}}}},"atlas exec":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{results:{type:"array",items:{type:"object",properties:{step:{type:"number"},command:{type:"string"},status:{type:"string",description:"success | failed: <msg>"}}}}}}}}},"atlas suggest":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{query:{type:"string"},suggestions:{type:"array",maxItems:5,items:{type:"object",properties:{command:{type:"string",description:"atlas \u5B50\u547D\u4EE4\u7247\u6BB5"},description:{type:"string"},score:{type:"number"}}}}}}}}},"atlas update":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{mode:{type:"string",enum:["npm","other"]},disabled:{type:"boolean"},current:{type:"string",description:"\u5F53\u524D\u7248\u672C\u53F7"},updateCommand:{type:"string",description:"npm \u66F4\u65B0\u547D\u4EE4"},migrationCommand:{type:"string",description:"\u8FC1\u79FB\u5230 npm \u5B89\u88C5\u7684\u547D\u4EE4"}}}}}},"atlas daemon":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object"}}}}};function JD(t){return y1[t]??{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{}}}}}function Le(t){if(j()&&(pE(t,{json:!0}),process.exit(w1(t))),t instanceof We&&(console.error(t.message),process.exit(2)),t instanceof re&&(console.error(`Config error: ${t.message}`),process.exit(64)),t instanceof AA&&(console.error(`Banma API error [${t.errCode}] ${t.errorMsg}`),process.exit(3)),t instanceof IA){let A=process.env.DEBUG==="1";console.error(A?t.stack??t.message:t.message),process.exit(65)}let e=process.env.DEBUG==="1";console.error(t instanceof Error?e?t.stack??t.message:t.message:String(t)),process.exit(1)}function w1(t){if(t instanceof We)return 2;if(t instanceof AA)return 3;if(t instanceof IA)return 65;if(df(t))switch(t.code){case"AMBIGUOUS_PROJECT":return 4;case"PROJECT_NOT_FOUND":return 5;case"RATE_LIMITED":return 6;case"NETWORK_ERROR":return 7;case"UPDATE_ERROR":return 8;case"CONFIG_ERROR":return 64;case"INTERACTIVE_REQUIRED":return 64;default:return 1}return 1}function xE(t){let e=[],A=t;for(;A&&A.name()!=="atlas";)e.unshift(A.name()),A=A.parent;let r=["atlas",...e].join(" "),n=JD(r),o={ok:!0,data:{command:r,description:t.description()??"",options:t.options.map(i=>{let a=i;return{flags:a.flags,description:a.description??"",required:a.mandatory??!1,...a.defaultValue!==void 0?{default:a.defaultValue}:{}}}),args:t.registeredArguments?.map(i=>({name:i.name(),required:i.required}))??[],subcommands:t.commands.map(i=>i.name()),outputSchema:n.jsonSchema}};process.stdout.write(JSON.stringify(o)+`
|
|
189
|
+
\u7ED1\u5B9A\u65F6\u95F4: ${e.linkedAt}`):y("\u672A\u7ED1\u5B9A\u9879\u76EE\u3002\u4F7F\u7528 atlas link <project> \u7ED1\u5B9A"),A&&y(`\u73AF\u5883\u53D8\u91CF BANMA_PROJECT_ID=${A}`)}async function uD(t){let e=await oD();if(!e){if(y("\u5F53\u524D\u672A\u7ED1\u5B9A\u9879\u76EE"),t.json||j()){se({unlinked:!1});return}return}if(t.dryRun){if(y(`[dry-run] \u5C06\u4F1A\u6E05\u9664\u9879\u76EE\u7ED1\u5B9A: ${e.projectName}`),t.json||j()){se({dryRun:!0,link:e});return}return}await n1(),y(`\u5DF2\u6E05\u9664\u9879\u76EE\u7ED1\u5B9A: ${e.projectName}`),(t.json||j())&&se({unlinked:!0,projectName:e.projectName})}je();var o1="ATLAS_MAX_OUTPUT_BYTES";function Kc(t){let e=process.env[o1];if(!e)return;let A=Number(e);if(!Number.isFinite(A)||A<=0)return;let r=Buffer.byteLength(t,"utf-8");if(r>A)throw new IA(r,A)}je();function zs(t){let e=new Date(t+288e5);return`${e.getUTCFullYear()}-${String(e.getUTCMonth()+1).padStart(2,"0")}`}function gD(){let t=new Date;return`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}`}var hD=/^(\d{4})-(0[1-9]|1[0-2])$/,dD=36;function gA(t,e){if(!t||!e)return[gD()];if(!hD.test(t))throw new re(`\u6708\u4EFD\u683C\u5F0F\u5E94\u4E3A YYYY-MM\uFF08\u5982 2026-03\uFF09\uFF0C\u5B9E\u9645: "${t}"`);if(!hD.test(e))throw new re(`\u6708\u4EFD\u683C\u5F0F\u5E94\u4E3A YYYY-MM\uFF08\u5982 2026-03\uFF09\uFF0C\u5B9E\u9645: "${e}"`);let[A,r]=t.split("-").map(Number),[n,s]=e.split("-").map(Number),o=[],i=A,a=r;for(;i<n||i===n&&a<=s;)o.push(`${i}-${String(a).padStart(2,"0")}`),a++,a>12&&(a=1,i++);if(o.length>dD)throw new re(`\u6708\u4EFD\u8303\u56F4\u8FC7\u5927: ${o.length} \u4E2A\u6708\uFF08\u4E0A\u9650 ${dD} \u4E2A\u6708\uFF09\uFF0C\u8BF7\u7F29\u5C0F\u67E5\u8BE2\u8303\u56F4`);return o}function Ks(){let t=new Date,e=t.getFullYear(),A=t.getMonth()+1,r=e,n=A-12;for(;n<1;)n+=12,r--;let s=e,o=A+12;for(;o>12;)o-=12,s++;let i=`${r}-${String(n).padStart(2,"0")}`,a=`${s}-${String(o).padStart(2,"0")}`;return gA(i,a)}sn();function i1(t){let e=Xc(t.projectId);return e.name??e.id}function kE(t){return Xs(t.projectId)}async function FE(t,e){let A=Ar(),r={projectId:t,month:e};return A.post("/yuntu-service/line/plan/month/select.json",r)}function UE(t){return typeof t=="object"&&t!==null&&typeof t.month=="number"&&Number.isFinite(t.month)}var a1={0:"\u6591\u9A6C",1:"\u667A\u8F6F"};function ED(t,e){return t.filter(A=>(!e.department||A.departmentName&&A.departmentName.includes(e.department))&&(!e.role||A.role&&A.role.includes(e.role))&&(!e.area||A.areaCode&&A.areaCode.includes(e.area))&&(!e.manpowerType||A.mpType&&a1[A.mpType]?.includes(e.manpowerType)))}async function fD(t){let e=kE(t),A=t.month?[t.month]:gA(t.from,t.to),r=await FE(e,A[0]),n=[];for(let c of r??[]){let l=c.linePlanMonthDetailList??[],u=String(c.mpType??""),h=c.areaCode;for(let g of l)UE(g)&&n.push({month:zs(g.month),manpower:g.manpower??0,role:c.role,departmentName:c.departmentName,mpType:u,areaCode:h})}let s=ED(n,t),o=new Map;for(let c of s)o.set(c.month,(o.get(c.month)??0)+c.manpower);let i=[...o.keys()].sort(),a=i.reduce((c,l)=>c+(o.get(l)??0),0);if(t.json||j()){se({projectId:e,months:i,entries:n,totalManpower:Math.round(a*100)/100});return}y(`\u9879\u76EE ${i1(t)} \u57FA\u7EBF\u4EBA\u529B:`);for(let c of i)y(` ${c}: ${(o.get(c)??0).toFixed(2)} \u4EBA\u6708`);y(` \u5408\u8BA1: ${a.toFixed(2)} \u4EBA\u6708`)}async function QD(t){let e=kE(t),A=t.month?[t.month]:gA(t.from,t.to),r=await FE(e,A[0]),n=[];for(let c of r??[]){let l=String(c.mpType??""),u=c.areaCode;for(let h of c.linePlanMonthDetailList??[])UE(h)&&n.push({month:zs(h.month),manpower:h.manpower??0,role:c.role,departmentName:c.departmentName,mpType:l,areaCode:u})}let s=ED(n,t),o=t.by??"month",i=new Map;for(let c of s){let l=o==="month"?c.month:o==="department"?c.departmentName??"\u5176\u4ED6":c.role??"\u5176\u4ED6";i.set(l,(i.get(l)??0)+c.manpower)}let a=[...i.entries()].map(([c,l])=>({[o]:c,manpower:Math.round(l*100)/100}));if(t.json||j()){se({rows:a});return}y("\u6C47\u603B:");for(let c of a)y(` ${String(c[o])}: ${c.manpower.toFixed(2)} \u4EBA\u6708`)}async function CD(t){let e=kE(t),A=gA(t.from,t.to),r=await FE(e,A[0]),n=[];for(let i of r??[])for(let a of i.linePlanMonthDetailList??[])UE(a)&&n.push({projectId:e,month:zs(a.month),role:i.role??"",manpower:a.manpower??0});let s=t.format==="csv"?(await Promise.resolve().then(()=>_r(bE(),1))).default.unparse(n):JSON.stringify(n,null,2);Kc(s);let o=Ni(t.out);await St(o,s),y(`\u5DF2\u5BFC\u51FA ${n.length} \u6761\u8BB0\u5F55`),(t.json||j())&&se({exported:n.length,format:t.format,out:o})}sn();function $c(t,e){return t.map(A=>({...A,month:e}))}function jn(t){return t==="all"||t==="pending"||t==="approved"?t:"approved"}function c1(t,e){let A=Number(t);return e==="approved"?A===2:e==="pending"?A!==2:!0}function ID(t,e){let A=new Map;for(let r of t){let n=e==="month"?r.month:e==="department"?r.departmentName??"\u5176\u4ED6":r.role??"\u5176\u4ED6";A.set(n,(A.get(n)??0)+(r.manpower??0))}return[...A.entries()].map(([r,n])=>({[e]:r,manpower:Math.round(n*100)/100}))}function BD(t,e){return t.filter(A=>A.staffId===e||A.staffName?.includes(e))}function el(t,e,A="approved"){let r=new Map;function n(o){let i=o.children;return!Array.isArray(i)||i.length===0}function s(o){for(let i of o??[]){let a=i;if(n(a)){let c=a.detail??[],l=0;for(let u of c)String(u.projectId)===e&&c1(u.status,A)&&(l+=Number(u.manpower??0));if(l>0){let u=String(a.staffId??""),h=l/22,d=(r.get(u)?.manpower??0)+h;r.set(u,{staffId:u,staffName:String(a.realname??""),manpower:Math.round(d*100)/100,departmentName:String(a.department??""),role:String(a.role??"")})}}else s(a.children)}}return s(t),[...r.values()]}xA();function tl(t){return Xs(t.projectId)}async function Al(t,e,A){let r=Ar(),s=(await Lr())?.staffId??"",o=await r.post("/yuntu-service/manpower/weekly/summaryByProject.json",{month:e,staffIds:[],projectIds:[t],isConfirm:!1,loginStaffId:s}),i=Array.isArray(o)?o:[];return i.length>0&&i[0].children?el(i[0].children,t,A):[]}async function pD(t,e){let A=tl(e),r=e.month??Ks()[0],n=await Al(A,r,jn(e.status)),s=BD(n,t);if(e.json||j()){se({staffId:t,month:r,personnel:s});return}if(s.length===0){y(`${t} \u5728 ${r} \u65E0\u5B9E\u9645\u5DE5\u65F6\u6570\u636E`);return}for(let o of s)y(` ${o.staffName} (${o.staffId}): ${o.manpower.toFixed(2)} \u4EBA\u6708`)}async function mD(t){let e=tl(t),A=t.month?[t.month]:t.from||t.to?gA(t.from,t.to):Ks(),r=jn(t.status),n=[],s=[];for(let i of A)try{let a=await Al(e,i,r);n.push(...$c(a,i))}catch(a){s.push({month:i,error:a instanceof Error?a.message:String(a)}),y(`\u6708 ${i} \u65E0\u5B9E\u9645\u5DE5\u65F6\u6570\u636E`)}let o=n.filter(i=>(!t.department||i.departmentName&&i.departmentName.includes(t.department))&&(!t.role||i.role&&i.role.includes(t.role)));if(t.json||j()){se({projectId:e,entries:o},{failedMonths:s});return}if(o.length===0){y("\u65E0\u5B9E\u9645\u5DE5\u65F6\u6570\u636E");return}for(let i of o)y(` ${i.staffName}: ${i.manpower.toFixed(2)} (${i.role??""})`)}async function yD(t){let e=tl(t),A=t.month?[t.month]:t.from||t.to?gA(t.from,t.to):Ks(),r=jn(t.status),n=[],s=[];for(let c of A)try{n.push(...$c(await Al(e,c,r),c))}catch(l){s.push({month:c,error:l instanceof Error?l.message:String(l)}),y(`\u6708 ${c} \u65E0\u5B9E\u9645\u5DE5\u65F6\u6570\u636E`)}let o=n.filter(c=>(!t.department||c.departmentName&&c.departmentName.includes(t.department))&&(!t.role||c.role&&c.role.includes(t.role))),i=t.by??"month",a=ID(o,i);if(t.json||j()){se({rows:a},{failedMonths:s});return}for(let c of a)y(` ${c[i]}: ${c.manpower.toFixed(2)} \u4EBA\u6708`)}async function wD(t){let e=tl(t),A=gA(t.from,t.to),r=jn(t.status),n=[],s=[];for(let c of A)try{let l=await Al(e,c,r);n.push(...$c(l,c))}catch(l){s.push({month:c,error:l instanceof Error?l.message:String(l)}),y(`\u6708 ${c} \u65E0\u5B9E\u9645\u5DE5\u65F6\u6570\u636E`)}let o=n.filter(c=>(!t.department||c.departmentName&&c.departmentName.includes(t.department))&&(!t.role||c.role&&c.role.includes(t.role))),i=t.format==="csv"?(await Promise.resolve().then(()=>_r(bE(),1))).default.unparse(o):JSON.stringify(o,null,2);Kc(i);let a=Ni(t.out);await St(a,i),y(`\u5DF2\u5BFC\u51FA ${o.length} \u6761\u8BB0\u5F55`),(t.json||j())&&se({exported:o.length,format:t.format,out:a},{failedMonths:s})}je();function TE(t,e){let A=new Map;for(let r of t){let n=e==="department"?r.departmentName??"\u5176\u4ED6":e==="role"?r.role??"\u5176\u4ED6":r.month;A.set(n,(A.get(n)??0)+r.manpower)}return A}function DD(t,e,A,r){let s=[...new Set([...t.keys(),...e.keys()])].sort().map(o=>({[A]:o,baselineManpower:Math.round((t.get(o)??0)*100)/100,actualManpower:Math.round((e.get(o)??0)*100)/100,diff:Math.round(((e.get(o)??0)-(t.get(o)??0))*100)/100}));return r>0&&(s=s.filter(o=>Math.abs(o.diff)>=r)),s}xA();function l1(t){return Xs(t.projectId)}async function SD(t){let e=l1(t),A=t.month?[t.month]:t.from||t.to?gA(t.from,t.to):Ks(),r=jn(t.status),n=[],s=[],o=Ar(),i=[];try{let d=await o.post("/yuntu-service/line/plan/month/select.json",{projectId:e,month:A[0]??""});for(let I of d??[]){let R=I.linePlanMonthDetailList??[];for(let B of R)if(B&&typeof B=="object"){let m=B.month,w=typeof m=="number"?zs(m):A[0];n.push({month:w,manpower:Number(B.manpower??0),role:I.role,departmentName:I.departmentName})}}}catch(d){if(d instanceof We)throw d;y(`\u57FA\u7EBF\u6570\u636E\u62C9\u53D6\u5931\u8D25: ${d instanceof Error?d.message:String(d)}`)}for(let d of A)try{let R=(await Lr())?.staffId??"",B=await o.post("/yuntu-service/manpower/weekly/summaryByProject.json",{month:d,staffIds:[],projectIds:[e],isConfirm:!1,loginStaffId:R}),m=Array.isArray(B)?B:[],w=[];if(m.length>0&&m[0].children){let z=el(m[0].children,e,r);for(let G of z)w.push({month:d,manpower:G.manpower??0,role:G.role,departmentName:G.departmentName})}for(let z of w)s.push(z)}catch(I){i.push({month:d,error:`\u5B9E\u9645\u5DE5\u65F6\u62C9\u53D6\u5931\u8D25: ${I instanceof Error?I.message:String(I)}`})}let a=t.by??"month",c=TE(n,a),l=TE(s,a),u=Number(t.threshold??"0");if(!Number.isFinite(u)||u<0)throw new re(`--threshold \u5FC5\u987B\u4E3A\u975E\u8D1F\u6570\uFF0C\u5B9E\u9645: "${t.threshold}"`);let h=DD(c,l,a,u);if(t.json||j()){se({rows:h},{failedMonths:i});return}let g=Xc(t.projectId);y(`\u9879\u76EE ${g.name??e} \u5BF9\u6BD4:${a==="month"?"\u6309\u6708\u4EFD":a==="department"?"\u6309\u90E8\u95E8":"\u6309\u89D2\u8272"}`);for(let d of h){let I=t.flagOverrun&&d.actualManpower>d.baselineManpower?" \u26A0\uFE0F":"";y(` ${String(d[a])}: \u57FA\u7EBF ${d.baselineManpower} / \u5B9E\u9645 ${d.actualManpower} / \u5DEE\u5F02 ${d.diff>0?"+":""}${d.diff}${I}`)}}var TD=require("http"),MD=require("https"),Qi=require("crypto"),ME=require("fs"),xD=require("path");ur();sn();je();je();var RD="(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)",bD=new RegExp(`^${RD}(\\.${RD}){3}$`),u1=/^[0-9a-fA-F:]+$/;function kD(t){if(!t)return!1;let e=t.toLowerCase().trim();return!!(e==="localhost"||e==="::1"||bD.test(e)&&e.startsWith("127."))}function g1(t){if(!t)return"";let e=t.trim(),A=e.match(/^::ffff:(\d+\.\d+\.\d+\.\d+)$/i);return A?A[1]:e}function rl(t){if(!bD.test(t))return null;let e=t.split(".").map(Number);return(e[0]<<24>>>0)+(e[1]<<16)+(e[2]<<8)+e[3]>>>0}function ND(t){return[t>>>24&255,t>>>16&255,t>>>8&255,t&255].join(".")}function FD(t){if(!t||t.length===0)return[];let e=[];for(let A of t){let r=A.trim();if(r){if(r.includes(":")){if(r.includes("/"))throw new re(`\u6682\u4E0D\u652F\u6301 IPv6 CIDR\uFF08\u4EC5\u5355 IP\uFF09\uFF1A${A}`);if(!u1.test(r))throw new re(`\u975E\u6CD5 IPv6 \u5730\u5740\uFF1A${A}`);e.push({raw:A,family:"ipv6",network:r.toLowerCase(),prefix:128});continue}if(r.includes("/")){let[n,s]=r.split("/"),o=rl(n),i=Number(s);if(o===null)throw new re(`\u975E\u6CD5 IPv4 \u7F51\u7EDC\u5730\u5740\uFF1A${A}`);if(!Number.isInteger(i)||i<0||i>32)throw new re(`\u975E\u6CD5 IPv4 \u524D\u7F00\u957F\u5EA6\uFF1A${A}`);let a=i===0?0:4294967295<<32-i>>>0,c=(o&a)>>>0;e.push({raw:A,family:"ipv4",network:ND(c),prefix:i})}else{let n=rl(r);if(n===null)throw new re(`\u975E\u6CD5 IPv4 \u5730\u5740\uFF1A${A}`);e.push({raw:A,family:"ipv4",network:ND(n),prefix:32})}}}return e}function UD(t,e){if(e.length===0)return!0;let A=g1(t);if(!A)return!1;for(let r of e){if(r.family==="ipv6"){if(A.toLowerCase()===r.network)return!0;continue}let n=rl(A);if(n===null)continue;let s=r.prefix===0?0:4294967295<<32-r.prefix>>>0;if((n&s)>>>0===rl(r.network)>>>0)return!0}return!1}function h1(){return(0,Qi.randomBytes)(32).toString("hex")}function d1(t,e){let A=t.headers.authorization??"",r=`Bearer ${e}`,n=Buffer.from(A),s=Buffer.from(r);return n.length!==s.length?((0,Qi.timingSafeEqual)(Buffer.alloc(1),Buffer.alloc(1)),!1):(0,Qi.timingSafeEqual)(n,s)}function E1(t){return(e,A)=>{let r=(o,i)=>{A.writeHead(o,{"Content-Type":"application/json"}),A.end(JSON.stringify(i))},n=e.url??"/";if(n==="/api/health"||n==="/"){r(200,{ok:!0,pid:process.pid});return}if(!UD(e.socket.remoteAddress,t.allowList)){r(403,{ok:!1,error:"forbidden: ip not allowed"});return}if(!d1(e,t.token)){r(401,{ok:!1,error:"unauthorized"});return}if(n==="/api/cookies"){t.readCookies().then(o=>r(200,{ok:!0,cookies:o??[]})).catch(()=>r(500,{ok:!1,error:"read cookies failed"}));return}r(404,{ok:!1,error:"not found"})}}var f1=8765;async function LD(t){let e=Number(process.env.ATLAS_DAEMON_PORT),A=t.port!==void 0?Number(t.port):NaN,r=Number.isFinite(A)&&A>0?A:Number.isFinite(e)&&e>0?e:f1,n=t.host??"127.0.0.1",s=kD(n),o=!!t.tlsCert&&!!t.tlsKey;if(t.tlsCert&&!t.tlsKey||t.tlsKey&&!t.tlsCert)throw new Ne("--tls-cert \u4E0E --tls-key \u5FC5\u987B\u540C\u65F6\u6307\u5B9A","CONFIG_ERROR");if(!s&&!t.insecure&&(!t.allowIp||t.allowIp.length===0))throw new Ne("\u975E loopback \u76D1\u542C\u5FC5\u987B\u6307\u5B9A --allow-ip \u6216\u663E\u5F0F --insecure\uFF08\u660E\u6587\u4F20\u8F93 token \u4EC5\u5EFA\u8BAE\u672C\u673A\u5F00\u53D1\uFF09","CONFIG_ERROR");!s&&!o&&t.insecure&&y("\u26A0\u26A0\u26A0 \u660E\u6587\u76D1\u542C\u975E loopback \u63A5\u53E3\uFF0CBearer token \u5C06\u4EE5\u660E\u6587\u4F20\u8F93\uFF0C\u4EC5\u5EFA\u8BAE\u672C\u673A\u5F00\u53D1\u4F7F\u7528 \u26A0\u26A0\u26A0");let i=FD(t.allowIp),a=h1(),c=is();await nn((0,xD.dirname)(c),{recursive:!0}),await St(c,a),y(`Daemon token \u5DF2\u5199\u5165 ${c}`);let u=E1({token:a,allowList:i,readCookies:async()=>{let{readCookies:d}=await Promise.resolve().then(()=>(xA(),BE));return d()}}),h;if(o){let d,I;try{d=(0,ME.readFileSync)(t.tlsCert),I=(0,ME.readFileSync)(t.tlsKey)}catch(R){throw new Ne(`TLS \u8BC1\u4E66\u8BFB\u53D6\u5931\u8D25\uFF1A${R.message}`,"CONFIG_ERROR")}h=(0,MD.createServer)({cert:d,key:I},u)}else h=(0,TD.createServer)(u);await new Promise((d,I)=>{h.on("error",R=>{R.code==="EADDRINUSE"?I(new Ne(`\u7AEF\u53E3 ${r} \u5DF2\u88AB\u5360\u7528`,"CONFIG_ERROR")):I(R)}),h.listen(r,n,d)}),y(`\u5B88\u62A4\u8FDB\u7A0B\u5DF2\u542F\u52A8\uFF0C\u76D1\u542C ${o?"https":"http"}://${n}:${r}${!s&&!o&&t.insecure?"\uFF08\u660E\u6587\uFF09":""}`),await new Promise(()=>{})}function vD(t,e){let A=[];if(t.commands.forEach(r=>{A.push(r.name()),r.commands.length>0&&r.commands.forEach(n=>{A.push(`${r.name()} ${n.name()}`)})}),e.describe){t.commands.forEach(r=>{xE(r)});return}if(e.json||j()){se({commands:A});return}y("\u53EF\u7528\u547D\u4EE4:"),A.sort().forEach(r=>y(` ${r}`))}var OD=require("fs/promises"),YD=require("child_process");hf();je();var Q1=CA.object({command:CA.string().regex(/^atlas( [a-z\-]+)+$/,'command \u5FC5\u987B\u662F atlas \u5B50\u547D\u4EE4\uFF0C\u5982 "atlas auth login"'),args:CA.array(CA.string()).optional()}),C1=CA.object({steps:CA.array(Q1).max(100,"\u6B65\u9AA4\u6570\u4E0D\u80FD\u8D85\u8FC7 100")});function I1(t,e=[]){let A=t.split(/\s+/),r=[process.argv[1],...A.slice(1),...e];return new Promise((n,s)=>{let o=(0,YD.spawn)(process.execPath,r,{stdio:"inherit",env:{...process.env}});o.on("close",i=>{i===0?n():s(new Error(`\u8FDB\u7A0B\u9000\u51FA\u7801 ${i}`))}),o.on("error",i=>{s(new Error(`\u65E0\u6CD5\u542F\u52A8\u8FDB\u7A0B: ${i.message}`))})})}async function HD(t){let e;try{e=await(0,OD.readFile)(t.planFile,"utf-8")}catch(n){throw new re(`\u65E0\u6CD5\u8BFB\u53D6\u8BA1\u5212\u6587\u4EF6: ${n instanceof Error?n.message:String(n)}`)}let A;try{A=C1.parse(JSON.parse(e))}catch(n){throw n instanceof CA.ZodError?new re(`\u8BA1\u5212\u6587\u4EF6\u6821\u9A8C\u5931\u8D25: ${n.errors.map(s=>`${s.path.join(".")}: ${s.message}`).join("; ")}`):new re(`\u8BA1\u5212\u6587\u4EF6\u683C\u5F0F\u9519\u8BEF: ${n instanceof Error?n.message:String(n)}`)}y(`\u6267\u884C\u8BA1\u5212: ${A.steps.length} \u4E2A\u6B65\u9AA4`);let r=[];for(let n=0;n<A.steps.length;n++){let s=A.steps[n];y(`[${n+1}/${A.steps.length}] ${s.command}`);try{await I1(s.command,s.args),r.push({step:n+1,command:s.command,status:"success"})}catch(o){let i=o instanceof Error?o.message:String(o);r.push({step:n+1,command:s.command,status:`failed: ${i}`}),(t.json||j())&&se({results:r},{completed:n,total:A.steps.length}),process.exit(1)}}t.json||j()?se({results:r}):y("\u8BA1\u5212\u6267\u884C\u5B8C\u6BD5")}var B1=[{pattern:/登录|login|sso|auth/i,command:"atlas auth login",description:"SSO \u767B\u5F55\uFF08\u9700\u7EC8\u7AEF\u4EA4\u4E92\uFF09",weight:10,requiresAuth:!1,exitCodes:[0,1,64]},{pattern:/状态|status|会话/i,command:"atlas auth status",description:"\u67E5\u770B\u4F1A\u8BDD\u72B6\u6001",weight:10,requiresAuth:!1,exitCodes:[0]},{pattern:/项目.*列表|列出.*项目|projects/i,command:"atlas projects",description:"\u5217\u51FA\u6240\u6709\u9879\u76EE",weight:10,requiresAuth:!0,exitCodes:[0,2]},{pattern:/绑定|link|关联/i,command:"atlas link <project>",description:"\u7ED1\u5B9A\u9879\u76EE\uFF08\u53EF\u7701\u540E\u7EED --project-id\uFF09",weight:10,requiresAuth:!0,exitCodes:[0,4,5]},{pattern:/解绑|unlink/i,command:"atlas unlink",description:"\u89E3\u7ED1\u9879\u76EE",weight:10,requiresAuth:!0,exitCodes:[0]},{pattern:/搜索|找|find|查询项目/i,command:"atlas find project <query>",description:"\u641C\u7D22\u9879\u76EE\uFF08\u4E5F\u652F\u6301 department/manpower-type/role/area\uFF09",weight:10,requiresAuth:!0,exitCodes:[0,2]},{pattern:/部门|department/i,command:"atlas find department <query>",description:"\u641C\u7D22\u90E8\u95E8",weight:7,requiresAuth:!0,exitCodes:[0,2]},{pattern:/字典|类型|mp.type|line.plan/i,command:"atlas find manpower-type <query>",description:"\u641C\u7D22 MP \u7C7B\u578B\u5B57\u5178\u503C",weight:7,requiresAuth:!0,exitCodes:[0,2]},{pattern:/基线|计划|baseline|人月.*计划/i,command:"atlas baseline month --month YYYY-MM",description:"\u67E5\u770B\u6307\u5B9A\u6708\u4EFD\u57FA\u7EBF\u4EBA\u529B",weight:5,requiresAuth:!0,exitCodes:[0,2,3,4,5]},{pattern:/基线.*汇总|baseline.*summar/i,command:"atlas baseline summary [--by month|department|role]",description:"\u6309\u6708/\u90E8\u95E8/\u89D2\u8272\u6C47\u603B\u57FA\u7EBF\u4EBA\u529B",weight:5,requiresAuth:!0,exitCodes:[0,2,3]},{pattern:/基线.*导出|baseline.*export/i,command:"atlas baseline export --from YYYY-MM --to YYYY-MM [--format csv|json] [--out <path>]",description:"\u5BFC\u51FA\u57FA\u7EBF\u6761\u76EE",weight:5,requiresAuth:!0,exitCodes:[0,2,3,65]},{pattern:/实际|actual|工时|人月.*实际/i,command:"atlas actual month --month YYYY-MM",description:"\u67E5\u770B\u6307\u5B9A\u6708\u4EFD\u5B9E\u9645\u5DE5\u65F6\uFF08\u4EBA\u6708\uFF09",weight:5,requiresAuth:!0,exitCodes:[0,2,3,4,5]},{pattern:/实际.*汇总|actual.*summar/i,command:"atlas actual summary [--by month|department|role]",description:"\u6C47\u603B\u5B9E\u9645\u5DE5\u65F6",weight:5,requiresAuth:!0,exitCodes:[0,2,3]},{pattern:/实际.*导出|actual.*export/i,command:"atlas actual export --from YYYY-MM --to YYYY-MM [--format csv|json] [--out <path>]",description:"\u5BFC\u51FA\u5B9E\u9645\u5DE5\u65F6",weight:5,requiresAuth:!0,exitCodes:[0,2,3,65]},{pattern:/实际.*人员|人员.*明细|staff|成员.*工时/i,command:"atlas actual show <staffId> --month YYYY-MM",description:"\u67E5\u770B\u5355\u4EBA\u5458\u5DE5\u5B9E\u9645\u5DE5\u65F6\u660E\u7EC6",weight:5,requiresAuth:!0,exitCodes:[0,2,3]},{pattern:/对比|比较|compare|差异|偏差/i,command:"atlas compare --from YYYY-MM --to YYYY-MM",description:"\u57FA\u7EBF vs \u5B9E\u9645\u5BF9\u6BD4\uFF08diff = \u5B9E\u9645 - \u57FA\u7EBF\uFF0C\u4EBA\u6708\uFF09",weight:10,requiresAuth:!0,exitCodes:[0,2,3,4,5]},{pattern:/批量|batch|exec|编排/i,command:"atlas exec --plan-file <path>",description:"\u6309 plan-file \u987A\u5E8F\u6267\u884C\u591A\u6761 atlas \u547D\u4EE4",weight:7,requiresAuth:!1,exitCodes:[0,1]},{pattern:/命令.*列表|命令树|帮助|自省|schema/i,command:"atlas schema commands [--describe]",description:"\u5217\u51FA\u6240\u6709\u547D\u4EE4 + \u8F93\u51FA schema\uFF08agent \u81EA\u7701\u5165\u53E3\uFF09",weight:8,requiresAuth:!1,exitCodes:[0]},{pattern:/升级|更新|update/i,command:"atlas update",description:"\u5347\u7EA7\u5230\u6700\u65B0\u7248\u672C",weight:10,requiresAuth:!1,exitCodes:[0]},{pattern:/守护|daemon/i,command:"atlas daemon",description:"\u542F\u52A8\u672C\u5730\u5B88\u62A4\u8FDB\u7A0B\uFF08\u4FDD\u6301\u6D4F\u89C8\u5668\u4F1A\u8BDD\uFF09",weight:5,requiresAuth:!1,exitCodes:[0]},{pattern:/项目\S+|(\S+项目)/i,command:"atlas find project <query>",description:"\u641C\u7D22\u9879\u76EE\uFF08\u542B\u6A21\u7CCA\u5339\u914D\u53C2\u6570\uFF09",weight:3,requiresAuth:!0,exitCodes:[0,2]},{pattern:/上个月|本月|上月|这个月|当月|当前月/i,command:"atlas baseline month --month $(date +%Y-%m)",description:"\u67E5\u770B\u5F53\u524D/\u4E0A\u4E2A\u6708\u57FA\u7EBF\uFF08\u6708\u4EFD\u53C2\u6570\u53EF\u63A8\u7B97\uFF09",weight:3,requiresAuth:!0,exitCodes:[0,2,3]},{pattern:/上季度|上个季度|本季度/i,command:'atlas compare --from $(date -d "$(date +%Y-%m-01) -3 months" +%Y-%m) --to $(date +%Y-%m)',description:"\u6309\u5B63\u5EA6\u8303\u56F4\u5BF9\u6BD4\uFF08\u6708\u4EFD\u53C2\u6570\u81EA\u52A8\u63A8\u7B97\uFF09",weight:3,requiresAuth:!0,exitCodes:[0,2,3]}];function _D(t,e){let A=[];for(let n of B1)n.pattern.test(t)&&A.push({command:n.command,description:n.description,score:n.weight,requiresAuth:n.requiresAuth,exitCodes:n.exitCodes});let r=t.toLowerCase();for(let n of A){let s=n.command.toLowerCase(),o=0;for(let i of r.split(/\s+/))i.length>=2&&s.includes(i)&&(o+=.5),/^\d{4}[-\/]\d{2}$/.test(i)&&(o+=1),/^\d+$/.test(i)&&i.length>=2&&s.includes(i)&&(o+=1);n.score+=o}if(A.sort((n,s)=>s.score-n.score),e.json||j()){se({query:t,suggestions:A.slice(0,5)});return}if(A.length===0){y(`\u672A\u627E\u5230\u5339\u914D\u7684 atlas \u547D\u4EE4: "${t}"`),y("\u63D0\u793A: \u8BD5\u8BD5 atlas --help \u67E5\u770B\u6240\u6709\u547D\u4EE4");return}y(`\u81EA\u7136\u8BED\u8A00\u67E5\u8BE2: "${t}"`),y("\u5EFA\u8BAE\u547D\u4EE4:");for(let n of A.slice(0,5)){let s=n.requiresAuth?"\u{1F511}":" ";y(` ${s} ${n.command} \u2014 ${n.description}`)}y(""),y("\u6807\u8BB0 \u{1F511}=\u9700\u8981\u767B\u5F55\uFF0C\u65E0\u6807\u8BB0=\u65E0\u9700\u9274\u6743")}var GD=require("url");je();var Zn="0.7.25";var m1={};function p1(){try{let t=new URL(m1.url),e=(0,GD.fileURLToPath)(t);return/node_modules[\\/]@dreamor[\\/]atlas-cli/.test(e)?"npm":"other"}catch{return"other"}}async function VD(t){if(process.env.ATLAS_DISABLE_UPDATE==="1"){y("\u66F4\u65B0\u5DF2\u88AB ATLAS_DISABLE_UPDATE \u7981\u7528"),(t.json||j())&&se({disabled:!0});return}let e=p1(),A="npm update -g @dreamor/atlas-cli";if(e==="npm"){y(`\u5F53\u524D\u7248\u672C ${Zn}`),y("\u901A\u8FC7 npm \u5B89\u88C5\u7684 atlas \u7531 npm registry \u7BA1\u7406\u5347\u7EA7\uFF0C\u8BF7\u8FD0\u884C:"),y(` ${A}`),(t.json||j())&&se({mode:"npm",current:Zn,updateCommand:A});return}y(`\u5F53\u524D\u7248\u672C ${Zn}`),y("\u5F53\u524D\u4EE5\u975E npm \u65B9\u5F0F\u8FD0\u884C\uFF0C\u81EA\u66F4\u65B0\u5DF2\u7981\u7528\u3002"),y("\u63A8\u8350\u8FC1\u79FB\u5230 npm \u5B89\u88C5\uFF1A"),y(" npm i -g @dreamor/atlas-cli"),y("\u968F\u540E\u901A\u8FC7 `npm update -g @dreamor/atlas-cli` \u5347\u7EA7\u3002"),(t.json||j())&&se({mode:"other",current:Zn,migrationCommand:"npm i -g @dreamor/atlas-cli",updateCommand:A})}je();var y1={"atlas auth login":{jsonSchema:{type:"object",properties:{ok:{type:"boolean",const:!0},data:{type:"object",properties:{status:{type:"string",enum:["logged_in"]},via:{type:"string",enum:["daemon"]}}}}}},"atlas auth status":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{loggedIn:{type:"boolean"},expiresAt:{type:"number"}}}}}},"atlas auth refresh":{jsonSchema:{type:"object",properties:{ok:{type:"boolean",const:!0},data:{type:"object",properties:{status:{type:"string",enum:["refreshed","still_valid"]},account:{type:"string"}}}}}},"atlas projects":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"array",items:{type:"object"}}}}},"atlas find":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"array",items:{type:"object"}},meta:{type:"object",properties:{count:{type:"number"},kind:{type:"string"},query:{type:"string"}}}}}},"atlas link":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{projectId:{type:"string"},projectName:{type:"string"},linkedAt:{type:"string"},linked:{type:"object",description:"\u5DF2\u7ED1\u5B9A\u7684\u9879\u76EE\u4FE1\u606F\uFF08link \u65E0\u53C2\u65F6\uFF09"},envProjectId:{type:"string",description:"BANMA_PROJECT_ID \u73AF\u5883\u53D8\u91CF\u503C"},dryRun:{type:"boolean"}}}}}},"atlas unlink":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{unlinked:{type:"boolean"},projectName:{type:"string"}}}}}},"atlas baseline month":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{projectId:{type:"string"},months:{type:"array",items:{type:"string"},description:"YYYY-MM \u683C\u5F0F\u6708\u4EFD\u5217\u8868"},entries:{type:"array",items:{type:"object",description:"\u5355\u4E2A\u6708\u4EFD\u7684\u57FA\u7EBF\u6761\u76EE"}},totalManpower:{type:"number",description:"\u5355\u4F4D\uFF1A\u4EBA\u6708"}}}}}},"atlas baseline summary":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"array",items:{type:"object",properties:{month:{type:"string",description:"YYYY-MM"},manpower:{type:"number",description:"\u5355\u4F4D\uFF1A\u4EBA\u6708"}}}}}}},"atlas baseline export":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{exported:{type:"number",description:"\u5BFC\u51FA\u884C\u6570"},format:{type:"string",enum:["csv","json"]},out:{type:"string",description:"\u5BFC\u51FA\u6587\u4EF6\u7EDD\u5BF9\u8DEF\u5F84\uFF08\u7ECF\u8FC7\u767D\u540D\u5355\u6821\u9A8C\uFF09"}}}}}},"atlas actual show":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{staffId:{type:"string"},month:{type:"string",description:"YYYY-MM"},personnel:{type:"array",items:{type:"object"}}}}}}},"atlas actual month":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{projectId:{type:"string"},entries:{type:"array",items:{type:"object"}}}},meta:{type:"object",properties:{failedMonths:{type:"array",items:{type:"string"}}}}}}},"atlas actual summary":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{rows:{type:"array",items:{type:"object"}}}},meta:{type:"object",properties:{failedMonths:{type:"array",items:{type:"string"}}}}}}},"atlas actual export":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{exported:{type:"number",description:"\u5BFC\u51FA\u884C\u6570"},format:{type:"string",enum:["csv","json"]},out:{type:"string",description:"\u5BFC\u51FA\u6587\u4EF6\u7EDD\u5BF9\u8DEF\u5F84"}}},meta:{type:"object",properties:{failedMonths:{type:"array",items:{type:"string"}}}}}}},"atlas compare":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{rows:{type:"array",items:{type:"object",properties:{month:{type:"string",description:"YYYY-MM"},plan:{type:"number",description:"\u57FA\u7EBF\u4EBA\u6708"},actual:{type:"number",description:"\u5B9E\u9645\u4EBA\u6708"},diff:{type:"number",description:"\u5B9E\u9645 - \u57FA\u7EBF\uFF08\u4EBA\u6708\uFF09"}}}}}},meta:{type:"object",properties:{failedMonths:{type:"array",items:{type:"string"}}}}}}},"atlas schema commands":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{commands:{type:"array",items:{type:"string"}}}}}}},"atlas exec":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{results:{type:"array",items:{type:"object",properties:{step:{type:"number"},command:{type:"string"},status:{type:"string",description:"success | failed: <msg>"}}}}}}}}},"atlas suggest":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{query:{type:"string"},suggestions:{type:"array",maxItems:5,items:{type:"object",properties:{command:{type:"string",description:"atlas \u5B50\u547D\u4EE4\u7247\u6BB5"},description:{type:"string"},score:{type:"number"}}}}}}}}},"atlas update":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object",properties:{mode:{type:"string",enum:["npm","other"]},disabled:{type:"boolean"},current:{type:"string",description:"\u5F53\u524D\u7248\u672C\u53F7"},updateCommand:{type:"string",description:"npm \u66F4\u65B0\u547D\u4EE4"},migrationCommand:{type:"string",description:"\u8FC1\u79FB\u5230 npm \u5B89\u88C5\u7684\u547D\u4EE4"}}}}}},"atlas daemon":{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{type:"object"}}}}};function JD(t){return y1[t]??{jsonSchema:{type:"object",properties:{ok:{type:"boolean"},data:{}}}}}function Le(t){if(j()&&(pE(t,{json:!0}),process.exit(w1(t))),t instanceof We&&(console.error(t.message),process.exit(2)),t instanceof re&&(console.error(`Config error: ${t.message}`),process.exit(64)),t instanceof AA&&(console.error(`Banma API error [${t.errCode}] ${t.errorMsg}`),process.exit(3)),t instanceof IA){let A=process.env.DEBUG==="1";console.error(A?t.stack??t.message:t.message),process.exit(65)}let e=process.env.DEBUG==="1";console.error(t instanceof Error?e?t.stack??t.message:t.message:String(t)),process.exit(1)}function w1(t){if(t instanceof We)return 2;if(t instanceof AA)return 3;if(t instanceof IA)return 65;if(df(t))switch(t.code){case"AMBIGUOUS_PROJECT":return 4;case"PROJECT_NOT_FOUND":return 5;case"RATE_LIMITED":return 6;case"NETWORK_ERROR":return 7;case"UPDATE_ERROR":return 8;case"CONFIG_ERROR":return 64;case"INTERACTIVE_REQUIRED":return 64;default:return 1}return 1}function xE(t){let e=[],A=t;for(;A&&A.name()!=="atlas";)e.unshift(A.name()),A=A.parent;let r=["atlas",...e].join(" "),n=JD(r),o={ok:!0,data:{command:r,description:t.description()??"",options:t.options.map(i=>{let a=i;return{flags:a.flags,description:a.description??"",required:a.mandatory??!1,...a.defaultValue!==void 0?{default:a.defaultValue}:{}}}),args:t.registeredArguments?.map(i=>({name:i.name(),required:i.required}))??[],subcommands:t.commands.map(i=>i.name()),outputSchema:n.jsonSchema}};process.stdout.write(JSON.stringify(o)+`
|
|
190
190
|
`)}function vr(t){return t.option("--project-id <id>","\u9879\u76EEID\uFF0C\u7CBE\u786E\u540D\u79F0\u6216\u552F\u4E00\u5B50\u4E32\uFF08\u6216\u4F7F\u7528 BANMA_PROJECT_ID \u73AF\u5883\u53D8\u91CF\uFF09").option("--refresh-projects","\u89E3\u6790 --project-id \u524D\u91CD\u65B0\u83B7\u53D6\u9879\u76EE\u76EE\u5F55\u7F13\u5B58")}function D1(t){let e=t.command("auth").description("SSO \u4F1A\u8BDD\u7BA1\u7406");e.command("login").description("\u6253\u5F00\u6D4F\u89C8\u5668\u5B8C\u6210 SSO \u767B\u5F55\u5E76\u6301\u4E45\u5316\u4F1A\u8BDD").option("--json","\u8F93\u51FA JSON \u4FE1\u5C01").action(async A=>{try{await Gc(A)}catch(r){Le(r)}}),e.command("status").description("\u663E\u793A\u5F53\u524D\u4F1A\u8BDD\u4FE1\u606F").option("--json","\u8F93\u51FA JSON").action(async A=>{try{await Vc(A)}catch(r){Le(r)}}),e.command("refresh").description("\u65E0\u5934\u6A21\u5F0F\u9759\u9ED8\u5237\u65B0 access_token\uFF08\u4F9D\u8D56 SSO_REFRESH_TOKEN\uFF0C\u5931\u8D25\u964D\u7EA7\u5230 atlas auth login\uFF09").option("--json","\u8F93\u51FA JSON \u4FE1\u5C01").action(async A=>{try{await Jc(A)}catch(r){Le(r)}}),e.command("export").description("\u5BFC\u51FA\u767B\u5F55\u6001\u4E3A\u4FBF\u643A bundle\uFF08\u9ED8\u8BA4 --refresh-only \u5265\u79BB\u77ED\u547D token\uFF09").option("-o, --out <path>","\u8F93\u51FA\u6587\u4EF6\u8DEF\u5F84\uFF08\u7701\u7565\u65F6 --base64 \u5199 stdout\uFF09").option("--base64","base64 \u6587\u672C\u683C\u5F0F\uFF08gzip+JSON\uFF09\uFF0C\u65B9\u4FBF\u7BA1\u9053/env \u4F20\u8F93").option("--refresh-only","\u4EC5\u957F\u671F\u51ED\u8BC1\uFF08\u9ED8\u8BA4\u5F00\u542F\uFF09",!0).option("--include-access-token","\u5305\u542B\u77ED\u547D access_token\uFF08\u9ED8\u8BA4\u5265\u79BB\uFF09").option("--json","\u8F93\u51FA JSON \u4FE1\u5C01").action(async A=>{try{await Pc(A)}catch(r){Le(r)}}),e.command("import").description("\u4ECE\u4FBF\u643A bundle \u5BFC\u5165\u767B\u5F55\u6001\uFF08\u8986\u76D6\u672C\u5730 cookies\uFF09").option("-i, --input <path>","\u5BFC\u5165\u6587\u4EF6\u8DEF\u5F84\uFF08\u7701\u7565 --base64 \u65F6\u4ECE stdin \u8BFB\uFF09").option("--base64","\u8F93\u5165\u4E3A base64 \u6587\u672C\u683C\u5F0F").option("--force","\u672C\u5730\u5DF2\u6709\u767B\u5F55\u6001\u65F6\u5F3A\u5236\u8986\u76D6").option("--persist","\u843D\u76D8\u5230 ~/.atlas/cookies.json\uFF08\u9ED8\u8BA4\u5F00\u542F\uFF09",!0).option("--json","\u8F93\u51FA JSON \u4FE1\u5C01").action(async A=>{try{await Wc(A)}catch(r){Le(r)}}),e.command("doctor").description("\u8BCA\u65AD\u5F53\u524D\u73AF\u5883\u7684\u767B\u5F55\u8DEF\u5F84\uFF08\u6C99\u76D2 agent \u81EA\u7701\u7528\uFF09").option("--json","\u8F93\u51FA JSON \u4FE1\u5C01").action(async A=>{try{await jc(A)}catch(r){Le(r)}})}function S1(t){t.command("find <kind> <query>").description("\u641C\u7D22\u9879\u76EE/\u90E8\u95E8/\u5B57\u5178\u503C\uFF08kind: project|department|manpower-type|role|area\uFF09").option("--json","\u8F93\u51FA JSON \u4FE1\u5C01").option("--refresh","\u5237\u65B0\u5B57\u5178/\u90E8\u95E8/\u9879\u76EE\u7F13\u5B58").option("--limit <n>","\u6700\u591A\u8FD4\u56DE N \u4E2A\u5019\u9009\uFF08\u9ED8\u8BA4 20\uFF09").addHelpText("after",`
|
|
191
191
|
kind \u8BF4\u660E:
|
|
192
192
|
|
package/package.json
CHANGED
package/README.github.md
DELETED
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
# Atlas CLI
|
|
2
|
-
|
|
3
|
-
斑马云图(Banma Yuntu)人力基线管理 CLI 工具。
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
npm i -g @dreamor/atlas-cli
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
> 需要 Node.js 20+
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## 目录
|
|
14
|
-
|
|
15
|
-
- [快速开始](#快速开始)
|
|
16
|
-
- [命令结构](#命令结构)
|
|
17
|
-
- [源码开发](#源码开发)
|
|
18
|
-
- [发布流程](#发布流程)
|
|
19
|
-
- [测试](#测试)
|
|
20
|
-
- [架构](#架构)
|
|
21
|
-
- [文档](#文档)
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
## 快速开始
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
# SSO 登录
|
|
29
|
-
atlas auth login
|
|
30
|
-
|
|
31
|
-
# 搜索项目
|
|
32
|
-
atlas find project 斑马
|
|
33
|
-
|
|
34
|
-
# 绑定默认项目
|
|
35
|
-
atlas link <project-name>
|
|
36
|
-
|
|
37
|
-
# 查询基线
|
|
38
|
-
atlas baseline month --project-id 2496
|
|
39
|
-
|
|
40
|
-
# 查询实际工时
|
|
41
|
-
atlas actual month --project-id 2496
|
|
42
|
-
|
|
43
|
-
# 基线 vs 实际对比
|
|
44
|
-
atlas compare --project-id 2496 --from 2026-01 --to 2026-06
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
### 沙盒环境(无 GUI 容器)
|
|
48
|
-
|
|
49
|
-
Claude Code、悟空、AntCode WebIDE 等沙盒环境无法直接 `atlas auth login`,推荐:
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
# 先诊断环境
|
|
53
|
-
atlas auth doctor
|
|
54
|
-
|
|
55
|
-
# 方案 A:从宿主机导入登录态
|
|
56
|
-
export ATLAS_COOKIES_B64='<宿主机 atlas auth export --base64 输出>'
|
|
57
|
-
atlas auth refresh # 补发 access_token
|
|
58
|
-
|
|
59
|
-
# 方案 B:通过 daemon 代理
|
|
60
|
-
export ATLAS_DAEMON_URL=http://host.docker.internal:8765
|
|
61
|
-
export ATLAS_DAEMON_TOKEN=$(cat ~/.atlas/daemon.token)
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
详见 [docs/sandbox-login.md](docs/sandbox-login.md)。
|
|
65
|
-
|
|
66
|
-
## 命令结构
|
|
67
|
-
|
|
68
|
-
```
|
|
69
|
-
atlas
|
|
70
|
-
├── auth {login,status,refresh,export,import,doctor}
|
|
71
|
-
├── find <kind> <query> # project/department/manpower-type/role/area
|
|
72
|
-
├── projects
|
|
73
|
-
├── link / unlink
|
|
74
|
-
├── baseline {month,summary,export}
|
|
75
|
-
├── actual {show,month,summary,export}
|
|
76
|
-
├── compare
|
|
77
|
-
├── schema {commands,export}
|
|
78
|
-
├── daemon
|
|
79
|
-
├── exec --plan-file <path>
|
|
80
|
-
├── update
|
|
81
|
-
└── suggest <query>
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
### 全局选项
|
|
85
|
-
|
|
86
|
-
- `--json` — JSON 信封输出(stdout);日志走 stderr,不污染管道
|
|
87
|
-
- `--quiet` — 静默模式
|
|
88
|
-
- `--describe` — 输出参数 schema,不执行
|
|
89
|
-
|
|
90
|
-
### 退出码
|
|
91
|
-
|
|
92
|
-
| 码 | 含义 | agent 应对 |
|
|
93
|
-
|----|------|-----------|
|
|
94
|
-
| 0 | 成功 | 继续 |
|
|
95
|
-
| 2 | 会话过期 | 先试 `atlas auth refresh` |
|
|
96
|
-
| 3 | API 错误 | 不重试 |
|
|
97
|
-
| 4 | 项目匹配歧义 | 用 `atlas find project` 让用户挑 |
|
|
98
|
-
| 5 | 项目未找到 | 改关键词重试 1 次后报告 |
|
|
99
|
-
| 6 | 限流 | 退避 10s 重试 ≤1 次 |
|
|
100
|
-
| 7 | 网络错误 | 退避 5s 重试 ≤1 次 |
|
|
101
|
-
| 8 | 升级异常 | 忽略 |
|
|
102
|
-
| 64 | 配置/未实现 | 不重试 |
|
|
103
|
-
| 65 | 输出超限 | 改用 `--out <file>` |
|
|
104
|
-
|
|
105
|
-
### 数据单位
|
|
106
|
-
|
|
107
|
-
- **基线**:`manpower` = 人月
|
|
108
|
-
- **实际工时**:`mp` / `weeklyActuals[].manpower` = 人月
|
|
109
|
-
- **compare**:`diff = 实际 - 基线`(人月,已自动统一单位,**不要二次换算**)
|
|
110
|
-
- 月份格式 `YYYY-MM`,已修正 CST(UTC+8) 偏移
|
|
111
|
-
|
|
112
|
-
## 源码开发
|
|
113
|
-
|
|
114
|
-
### 技术栈
|
|
115
|
-
|
|
116
|
-
TypeScript + Commander (CLI 框架) + Zod (输入验证) + undici (HTTP 客户端) + Playwright (SSO 登录)
|
|
117
|
-
|
|
118
|
-
### 本地开发
|
|
119
|
-
|
|
120
|
-
```bash
|
|
121
|
-
git clone <repo>
|
|
122
|
-
cd atlas-cli
|
|
123
|
-
pnpm install
|
|
124
|
-
|
|
125
|
-
# 构建
|
|
126
|
-
npm run build
|
|
127
|
-
|
|
128
|
-
# 类型检查
|
|
129
|
-
npm run lint
|
|
130
|
-
|
|
131
|
-
# 测试
|
|
132
|
-
npm test
|
|
133
|
-
|
|
134
|
-
# 验证 CLI
|
|
135
|
-
npm run verify
|
|
136
|
-
|
|
137
|
-
# 本地运行
|
|
138
|
-
node atlas.js --help
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
## 测试
|
|
142
|
-
|
|
143
|
-
| 类型 | 位置 | 测试数 | 说明 |
|
|
144
|
-
|------|------|--------|------|
|
|
145
|
-
| 单元测试 | `adapters/atlas/tests/` | 354(27 文件) | Vitest,覆盖率 80%+ |
|
|
146
|
-
| E2E 真实 API | `scripts/run-e2e-real.mjs` | 41 | 需登录态(~/.atlas/cookies.json) |
|
|
147
|
-
| E2E 沙盒登录 | `scripts/run-e2e-sandbox-login.mjs` | 12 | 验证 export/import/COOKIES_B64/daemon |
|
|
148
|
-
|
|
149
|
-
### CI 流程
|
|
150
|
-
|
|
151
|
-
- **CI**(`.github/workflows/ci.yml`):push/PR 自动 lint → test → build → 源码泄漏检查
|
|
152
|
-
- **Publish**(`.github/workflows/publish-npm.yml`):tag `v*` 触发 OIDC Trusted Publisher → npmjs
|
|
153
|
-
|
|
154
|
-
## 发布流程
|
|
155
|
-
|
|
156
|
-
```bash
|
|
157
|
-
# 更新版本号
|
|
158
|
-
# package.json + adapters/atlas/util/version.ts
|
|
159
|
-
|
|
160
|
-
# 本地验证
|
|
161
|
-
npm run build
|
|
162
|
-
npm test
|
|
163
|
-
npm run lint
|
|
164
|
-
npm run verify
|
|
165
|
-
|
|
166
|
-
# 提交并打 tag
|
|
167
|
-
git add -A && git commit -m "chore: bump X.Y.Z → X.Y.Z"
|
|
168
|
-
git tag vX.Y.Z
|
|
169
|
-
git push dist main && git push dist vX.Y.Z
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
> npm 包名 `@dreamor/atlas-cli`,仅 `dist/` 编译产物(零源码、零 sourcemap、零测试文件)。发布由 GitHub CI 自动完成,无需本地 `npm publish`。
|
|
173
|
-
|
|
174
|
-
## 架构
|
|
175
|
-
|
|
176
|
-
```
|
|
177
|
-
adapters/atlas/
|
|
178
|
-
├── cli.ts # Commander 入口
|
|
179
|
-
├── commands/ # 命令处理
|
|
180
|
-
│ ├── auth.ts # auth login/status/refresh/export/import/doctor
|
|
181
|
-
│ ├── project/ # find, projects, link, unlink
|
|
182
|
-
│ ├── baseline/ # month, summary, export
|
|
183
|
-
│ ├── actual/ # show, month, summary, export
|
|
184
|
-
│ ├── compare/ # 基线 vs 实际对比
|
|
185
|
-
│ ├── schema.ts # 命令树自省
|
|
186
|
-
│ ├── exec.ts # 批量命令执行
|
|
187
|
-
│ ├── suggest.ts # 自然语言→命令翻译
|
|
188
|
-
│ └── update.ts # 自动升级
|
|
189
|
-
├── auth/ # 鉴权
|
|
190
|
-
│ ├── login.ts # Playwright SSO + daemon 自动登录
|
|
191
|
-
│ ├── session.ts # cookies 读写 + ATLAS_COOKIES_B64 + daemon 客户端
|
|
192
|
-
│ ├── portable.ts # export/import/doctor 便携登录态打包
|
|
193
|
-
│ └── refresh.ts # 无头 token 刷新
|
|
194
|
-
├── daemon/ # 本地守护进程
|
|
195
|
-
│ ├── index.ts # HTTP server + token 鉴权 + IP 白名单
|
|
196
|
-
│ └── ipmask.ts # CIDR 位运算匹配
|
|
197
|
-
├── http/ # Banma API HTTP 客户端
|
|
198
|
-
├── util/ # 工具函数
|
|
199
|
-
│ ├── environment.ts # 沙盒环境识别(agent_code/容器/GUI/daemon)
|
|
200
|
-
│ ├── output.ts # JSON 信封、日志
|
|
201
|
-
│ ├── errors.ts # 错误类型 + 退出码
|
|
202
|
-
│ └── ...
|
|
203
|
-
└── tests/ # 单元测试(27 文件)
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
## 环境变量
|
|
207
|
-
|
|
208
|
-
| 变量 | 必需 | 说明 | 默认值 |
|
|
209
|
-
|------|------|------|--------|
|
|
210
|
-
| `BANMA_PROJECT_ID` | 是(或 `--project-id` / `atlas link`) | 默认项目 ID | — |
|
|
211
|
-
| `ATLAS_HOME` | 否 | 数据目录根路径 | `~/.atlas` |
|
|
212
|
-
| `ATLAS_COOKIES_B64` | 否 | 沙盒免命令登录:base64 bundle 内存导入 | — |
|
|
213
|
-
| `ATLAS_DAEMON_URL` | 否 | 沙盒连宿主机 daemon URL | — |
|
|
214
|
-
| `ATLAS_DAEMON_TOKEN` | 否 | daemon Bearer token | — |
|
|
215
|
-
| `ATLAS_DAEMON_PORT` | 否 | 守护进程端口 | `8765` |
|
|
216
|
-
| `ATLAS_AGENT_CODE` | 否 | 显式声明 agent 类型 | 自动识别 |
|
|
217
|
-
| `ATLAS_SANDBOX` | 否 | 强制沙盒模式(禁用浏览器拉起) | — |
|
|
218
|
-
| `ATLAS_OUTPUT` | 否 | 设为 `json` 启用 JSON 信封输出 | — |
|
|
219
|
-
| `ATLAS_QUIET` | 否 | 抑制 stderr 日志 | — |
|
|
220
|
-
| `ATLAS_DISABLE_UPDATE` | 否 | 禁用升级检查 | — |
|
|
221
|
-
| `ATLAS_MAX_OUTPUT_BYTES` | 否 | 导出字节上限 | 无限制 |
|
|
222
|
-
| `DEBUG` | 否 | 显示详细错误堆栈 | — |
|
|
223
|
-
|
|
224
|
-
## 文档
|
|
225
|
-
|
|
226
|
-
- [贡献指南](docs/CONTRIBUTING.md) — 开发环境、测试、PR 流程
|
|
227
|
-
- [运维手册](docs/RUNBOOK.md) — 安装、发布、故障排查
|
|
228
|
-
- [项目状态](docs/STATUS.md) — 当前版本、测试状态、已知问题
|
|
229
|
-
- [沙盒登录](docs/sandbox-login.md) — 沙盒环境登录全攻略
|
|
230
|
-
- [CLI 完整契约](.claude/skills/atlas/SKILL.md) — AI agent 调用契约
|