tako-cli 0.1.13 → 0.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -50,6 +50,6 @@ ${h.default.gray(R)} ${r}
50
50
  `)}
51
51
  `)},info:(r)=>{g.message(r,{symbol:h.default.blue(xm)})},success:(r)=>{g.message(r,{symbol:h.default.green(gm)})},step:(r)=>{g.message(r,{symbol:h.default.green(c$)})},warn:(r)=>{g.message(r,{symbol:h.default.yellow(lm)})},warning:(r)=>{g.warn(r)},error:(r)=>{g.message(r,{symbol:h.default.red(dm)})}},f=()=>{let r=o$?["\u25D2","\u25D0","\u25D3","\u25D1"]:["\u2022","o","O","0"],m=o$?80:120,e,a,t=!1,s="",$=(v="")=>{t=!0,e=u$(),s=v.replace(/\.+$/,""),process.stdout.write(`${h.default.gray(y)}
52
52
  `);let c=0,d=0;a=setInterval(()=>{let G=h.default.magenta(r[c]),k=".".repeat(Math.floor(d)).slice(0,3);process.stdout.write(j.cursor.move(-999,0)),process.stdout.write(j.erase.down(1)),process.stdout.write(`${G} ${s}${k}`),c=c+1<r.length?c+1:0,d=d<r.length?d+0.125:0},m)},b=(v="",c=0)=>{s=v??s,t=!1,clearInterval(a);let d=c===0?h.default.green(c$):c===1?h.default.red(F$):h.default.red(D$);process.stdout.write(j.cursor.move(-999,0)),process.stdout.write(j.erase.down(1)),process.stdout.write(`${d} ${s}
53
- `),e()},i=(v="")=>{s=v??s},o=(v)=>{let c=v>1?"Something went wrong":"Canceled";t&&b(c,v)};return process.on("uncaughtExceptionMonitor",()=>o(2)),process.on("unhandledRejection",()=>o(2)),process.on("SIGINT",()=>o(1)),process.on("SIGTERM",()=>o(1)),process.on("exit",o),{start:$,stop:b,message:i}};function wm(r){return r.startsWith("cr_")&&r.length>10}async function nm(r){try{let e=await(await fetch(`${M}/apiStats/api/get-key-id`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKey:r})})).json();if(e.success&&e.data?.id)return{valid:!0,apiId:e.data.id};return{valid:!1,error:e.error||"Key \u9A8C\u8BC1\u5931\u8D25"}}catch(m){return{valid:!1,error:m instanceof Error?m.message:"\u7F51\u7EDC\u8BF7\u6C42\u5931\u8D25"}}}async function er(r){if(!wm(r))return{success:!1,error:"Key \u683C\u5F0F\u4E0D\u6B63\u786E\uFF0C\u5FC5\u987B\u4EE5 cr_ \u5F00\u5934"};let m=await nm(r);if(!m.valid)return{success:!1,error:m.error};return await T({apiKey:r,apiId:m.apiId}),{success:!0}}import{join as hr}from"path";var C=null,v$={cn:{npm:"https://registry.npmmirror.com",bun:"https://bun.sh/install",bunMirror:"https://registry.npmmirror.com/-/binary/bun"},global:{npm:"https://registry.npmjs.org",bun:"https://bun.sh/install",bunMirror:null}};async function x$(){if(C)return C;let r=[pm,Sm,Mm];for(let m of r)try{let e=await Promise.race([m(),new Promise((a,t)=>setTimeout(()=>t(Error("timeout")),3000))]);if(e)return C=e,e}catch{}return C="cn","cn"}async function pm(){try{let r=await fetch("http://ip-api.com/json/?fields=countryCode",{signal:AbortSignal.timeout(2000)});if(!r.ok)return null;return(await r.json()).countryCode==="CN"?"cn":"global"}catch{return null}}async function Sm(){try{let r=await fetch("https://ipinfo.io/json",{signal:AbortSignal.timeout(2000)});if(!r.ok)return null;return(await r.json()).country==="CN"?"cn":"global"}catch{return null}}async function Mm(){try{let r=await fetch("https://api.ip.sb/geoip",{signal:AbortSignal.timeout(2000)});if(!r.ok)return null;return(await r.json()).country_code==="CN"?"cn":"global"}catch{return null}}async function qm(){let r=await x$();return v$[r]}async function Y(){return(await qm()).npm}async function ar(){if(await x$()==="cn")return`curl -fsSL https://bun.sh/install | BUN_INSTALL_MIRROR="${v$.cn.bunMirror}" bash`;return"curl -fsSL https://bun.sh/install | bash"}async function tr(){let r=await x$(),m=v$[r];if(r==="cn")g.info("\u68C0\u6D4B\u5230\u4E2D\u56FD\u5927\u9646\u7F51\u7EDC\uFF0C\u4F7F\u7528\u56FD\u5185\u955C\u50CF\u6E90"),g.message(` npm: ${m.npm}`);else g.info("\u4F7F\u7528\u56FD\u9645\u6E90")}var z=null;function Wm(r){return r.startsWith(Q)}async function br(){try{if(!await Bun.file(p).exists())return!1;let m=Bun.spawn([p,"--version"],{stdout:"pipe",stderr:"pipe"});return await m.exited,m.exitCode===0}catch{return!1}}async function fm(){try{let m=Bun.spawn(["which","unzip"],{stdout:"pipe",stderr:"pipe"});if(await m.exited,m.exitCode===0)return!0}catch{}g.warn("\u6B63\u5728\u5B89\u88C5\u7CFB\u7EDF\u4F9D\u8D56 (unzip)...");let r=["apt-get update -qq && apt-get install -y -qq unzip","yum install -y -q unzip","dnf install -y -q unzip","pacman -S --noconfirm unzip","apk add --quiet unzip"];for(let m of r)try{let e=Bun.spawn(["bash","-c",`sudo ${m} 2>/dev/null || ${m}`],{stdout:"pipe",stderr:"pipe"});if(await e.exited,e.exitCode===0)return!0}catch{}return!1}async function Gm(){let r=f();if(!await fm())return g.error("\u8BF7\u5148\u624B\u52A8\u5B89\u88C5 unzip: apt install unzip / yum install unzip"),!1;await tr(),r.start("\u6B63\u5728\u5B89\u88C5 Tako \u4E13\u5C5E Bun \u8FD0\u884C\u65F6...");try{await(await import("fs/promises")).mkdir(Q,{recursive:!0});let e=await ar(),a=`BUN_INSTALL="${Q}" ${e}`;if(await Bun.spawn(["bash","-c",a],{stdout:"inherit",stderr:"inherit"}).exited!==0)return r.stop("Bun \u5B89\u88C5\u5931\u8D25"),!1;return z=p,r.stop("Tako \u4E13\u5C5E Bun \u5B89\u88C5\u5B8C\u6210"),g.info(`\u5B89\u88C5\u4F4D\u7F6E: ${Q}`),!0}catch(m){return r.stop("Bun \u5B89\u88C5\u5931\u8D25"),!1}}async function Zm(){if(await br())return z=p,!0;return g.warn("\u672A\u68C0\u6D4B\u5230 Tako \u4E13\u5C5E Bun\uFF0C\u6B63\u5728\u81EA\u52A8\u5B89\u88C5..."),g.info("\uFF08\u4E0D\u4F1A\u5F71\u54CD\u60A8\u7CFB\u7EDF\u4E2D\u5DF2\u5B89\u88C5\u7684 Node.js \u6216 Bun\uFF09"),await Gm()}async function g$(){if(z){if(!Wm(z))z=p;return z}if(await br())return z=p,p;return p}async function or(r){try{let m=await Y(),e=await fetch(`${m}/${r}/latest`);if(!e.ok)return null;return(await e.json()).version}catch{return null}}async function zm(r){return(await Z()).installedClients[r.id]?.version||null}async function cr(r){let m=P(r.id),e=hr(m,"package.json");try{return await Bun.file(e).exists()}catch{return!1}}async function ir(r){let m=await zm(r);if(!m)return!0;let e=await or(r.package);if(!e)return!1;return m!==e}async function sr(r,m=!1){let e=f(),a=P(r.id);try{if(!await Zm())return{success:!1,error:"Tako \u4E13\u5C5E Bun \u5B89\u88C5\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u6216\u624B\u52A8\u5220\u9664 ~/.tako/bun \u76EE\u5F55\u540E\u91CD\u8BD5"};let t=await cr(r),s=m||await ir(r);if(t&&!s)return{success:!0};let $=t?"\u66F4\u65B0":"\u5B89\u88C5";e.start(`\u6B63\u5728${$} ${r.name}...`),await(await import("fs/promises")).mkdir(a,{recursive:!0});let i=hr(a,"package.json");if(!await Bun.file(i).exists())await Bun.write(i,JSON.stringify({name:`tako-${r.id}`,private:!0,dependencies:{}},null,2));let v=await g$(),c=await Y(),d=Bun.spawn([v,"add",r.package,"--registry",c],{cwd:a,stdout:"pipe",stderr:"pipe"});if(await d.exited!==0){let B=await new Response(d.stderr).text();return e.stop(`${$} ${r.name} \u5931\u8D25`),{success:!1,error:B}}let k=await or(r.package);if(k){let B=await Z();B.installedClients[r.id]={version:k,installedAt:new Date().toISOString()},await T(B)}return e.stop(`${r.name} ${$}\u5B8C\u6210`),{success:!0}}catch(t){return e.stop("\u64CD\u4F5C\u5931\u8D25"),{success:!1,error:t instanceof Error?t.message:"\u672A\u77E5\u9519\u8BEF"}}}async function vr(r){if(!await cr(r))return await sr(r);if(await ir(r))return await sr(r,!0);return{success:!0}}async function xr(r){try{let m=await vr(r);if(!m.success)return m;let e=await q$();if(!e)return{success:!1,error:"\u672A\u914D\u7F6E API Key"};if(r.setupConfigFiles)await r.setupConfigFiles(e);let a=Z$(r);if(!await Bun.file(a).exists())return{success:!1,error:`\u627E\u4E0D\u5230\u53EF\u6267\u884C\u6587\u4EF6: ${a}`};let s=r.getEnvVars(e),$={...process.env,...s};g.info(`\u542F\u52A8 ${r.name}...`);let b;if(r.runtime==="native")b=[a];else b=[await g$(),a];return await Bun.spawn(b,{env:$,stdio:["inherit","inherit","inherit"],cwd:process.cwd()}).exited,{success:!0}}catch(m){return{success:!1,error:m instanceof Error?m.message:"\u542F\u52A8\u5931\u8D25"}}}async function l$(){try{let r=await W$();if(!r)return{success:!1,error:"\u672A\u627E\u5230 API ID\uFF0C\u8BF7\u91CD\u65B0\u914D\u7F6E Key"};let e=await(await fetch(`${M}/apiStats/api/user-stats`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiId:r})})).json(),t=await(await fetch(`${M}/apiStats/api/user-model-stats`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiId:r,period:"daily"})})).json();if(!e.success)return{success:!1,error:e.error||e.message||"\u83B7\u53D6\u7EDF\u8BA1\u5931\u8D25"};let s=(t.data||[]).map(($)=>({model:$.model,requests:$.requests,cost:$.formatted?.total||"$0.00"}));return{success:!0,data:{totalRequests:e.data?.usage?.total?.requests||0,totalCost:e.data?.usage?.total?.formattedCost||"$0.00",todayCost:`$${(e.data?.limits?.currentDailyCost||0).toFixed(2)}`,modelStats:s}}}catch(r){return{success:!1,error:r instanceof Error?r.message:"\u7F51\u7EDC\u8BF7\u6C42\u5931\u8D25"}}}function d$(r){return r.toLocaleString("en-US")}var gr="tako-cli",H="0.1.13";function Jm(r,m){let e=r.split(".").map(Number),a=m.split(".").map(Number);for(let t=0;t<3;t++){let s=e[t]||0,$=a[t]||0;if(s>$)return 1;if(s<$)return-1}return 0}async function Qm(){try{let r=await Y(),m=await fetch(`${r}/${gr}/latest`,{signal:AbortSignal.timeout(5000)});if(!m.ok)return null;return(await m.json()).version||null}catch{return null}}async function jm(){let r=await Qm();if(!r)return{hasUpdate:!1,currentVersion:H};return{hasUpdate:Jm(r,H)>0,latestVersion:r,currentVersion:H}}async function Ym(r){let m=f();m.start(`\u6B63\u5728\u66F4\u65B0\u5230 v${r}...`);try{let e=await Y(),a=Bun.spawn([p,"add","-g",`${gr}@latest`,"--registry",e],{stdout:"pipe",stderr:"pipe"});if(await a.exited,a.exitCode===0)return m.stop(`\u66F4\u65B0\u6210\u529F\uFF01\u5DF2\u66F4\u65B0\u5230 v${r}`),!0;else{let t=await new Response(a.stderr).text();return m.stop(`\u66F4\u65B0\u5931\u8D25: ${t||"\u672A\u77E5\u9519\u8BEF"}`),!1}}catch(e){return m.stop(`\u66F4\u65B0\u5931\u8D25: ${e instanceof Error?e.message:"\u672A\u77E5\u9519\u8BEF"}`),!1}}async function lr(){try{let r=await jm();if(r.hasUpdate&&r.latestVersion){if(g.warn(`\u53D1\u73B0\u65B0\u7248\u672C v${r.latestVersion}\uFF08\u5F53\u524D v${H}\uFF09`),await Ym(r.latestVersion))g.info("\u8BF7\u91CD\u65B0\u542F\u52A8 Tako CLI \u4EE5\u4F7F\u7528\u65B0\u7248\u672C"),process.exit(0)}}catch{}}function Hm(){console.log(),console.log(` \uD83D\uDC19 Tako CLI v${H}`),console.log(" \x1B[90m\u6B22\u8FCE\u4F7F\u7528\uFF01\x1B[0m"),console.log()}async function dr(r=!1){if(!r)g.warn("\u672A\u68C0\u6D4B\u5230 API Key"),console.log();let m=await rr({message:r?"\u8BF7\u8F93\u5165\u65B0\u7684 API Key (cr_xxx):":"\u8BF7\u8F93\u5165\u4F60\u7684 API Key (cr_xxx):",placeholder:"cr_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",validate(t){if(!t)return"\u8BF7\u8F93\u5165 API Key";if(!t.startsWith("cr_"))return"Key \u5FC5\u987B\u4EE5 cr_ \u5F00\u5934";if(t.length<10)return"Key \u683C\u5F0F\u4E0D\u6B63\u786E"}});if(X(m))return!1;let e=f();e.start("\u9A8C\u8BC1 Key \u4E2D...");let a=await er(m);if(a.success)return e.stop("Key \u9A8C\u8BC1\u6210\u529F\uFF01\u5DF2\u4FDD\u5B58\u5230\u914D\u7F6E\u6587\u4EF6"),!0;else return e.stop(`\u9A8C\u8BC1\u5931\u8D25: ${a.error}`),!1}function Lm(r,m){let e=[];if(e.push(""),e.push(" \uD83D\uDCCA \u7528\u91CF\u7EDF\u8BA1"),e.push(""),e.push(` \u603B\u8C03\u7528\u6B21\u6570: ${d$(r.totalRequests)} \u6B21`),e.push(` \u603B\u6D88\u8D39: ${r.totalCost}`),e.push(` \u4ECA\u65E5\u6D88\u8D39: ${r.todayCost}`),r.modelStats.length>0)e.push(""),e.push(" \u6A21\u578B\u4F7F\u7528\u5206\u5E03 (\u4ECA\u65E5):"),r.modelStats.forEach((a,t)=>{let s=t===r.modelStats.length-1?"\u2514\u2500":"\u251C\u2500",$=a.model.length>25?a.model.slice(0,22)+"...":a.model;e.push(` ${s} ${$.padEnd(25)} ${d$(a.requests).padStart(6)} \u6B21 ${a.cost.padStart(8)}`)});return e.push(""),e.push(` \x1B[90m${m}s \u540E\u5237\u65B0 | \u6309\u4EFB\u610F\u952E\u8FD4\u56DE\x1B[0m`),e.join(`
53
+ `),e()},i=(v="")=>{s=v??s},o=(v)=>{let c=v>1?"Something went wrong":"Canceled";t&&b(c,v)};return process.on("uncaughtExceptionMonitor",()=>o(2)),process.on("unhandledRejection",()=>o(2)),process.on("SIGINT",()=>o(1)),process.on("SIGTERM",()=>o(1)),process.on("exit",o),{start:$,stop:b,message:i}};function wm(r){return r.startsWith("cr_")&&r.length>10}async function nm(r){try{let e=await(await fetch(`${M}/apiStats/api/get-key-id`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiKey:r})})).json();if(e.success&&e.data?.id)return{valid:!0,apiId:e.data.id};return{valid:!1,error:e.error||"Key \u9A8C\u8BC1\u5931\u8D25"}}catch(m){return{valid:!1,error:m instanceof Error?m.message:"\u7F51\u7EDC\u8BF7\u6C42\u5931\u8D25"}}}async function er(r){if(!wm(r))return{success:!1,error:"Key \u683C\u5F0F\u4E0D\u6B63\u786E\uFF0C\u5FC5\u987B\u4EE5 cr_ \u5F00\u5934"};let m=await nm(r);if(!m.valid)return{success:!1,error:m.error};return await T({apiKey:r,apiId:m.apiId}),{success:!0}}import{join as hr}from"path";var C=null,v$={cn:{npm:"https://registry.npmmirror.com",bun:"https://bun.sh/install",bunMirror:"https://registry.npmmirror.com/-/binary/bun"},global:{npm:"https://registry.npmjs.org",bun:"https://bun.sh/install",bunMirror:null}};async function x$(){if(C)return C;let r=[pm,Sm,Mm];for(let m of r)try{let e=await Promise.race([m(),new Promise((a,t)=>setTimeout(()=>t(Error("timeout")),3000))]);if(e)return C=e,e}catch{}return C="cn","cn"}async function pm(){try{let r=await fetch("http://ip-api.com/json/?fields=countryCode",{signal:AbortSignal.timeout(2000)});if(!r.ok)return null;return(await r.json()).countryCode==="CN"?"cn":"global"}catch{return null}}async function Sm(){try{let r=await fetch("https://ipinfo.io/json",{signal:AbortSignal.timeout(2000)});if(!r.ok)return null;return(await r.json()).country==="CN"?"cn":"global"}catch{return null}}async function Mm(){try{let r=await fetch("https://api.ip.sb/geoip",{signal:AbortSignal.timeout(2000)});if(!r.ok)return null;return(await r.json()).country_code==="CN"?"cn":"global"}catch{return null}}async function qm(){let r=await x$();return v$[r]}async function Y(){return(await qm()).npm}async function ar(){if(await x$()==="cn")return`curl -fsSL https://bun.sh/install | BUN_INSTALL_MIRROR="${v$.cn.bunMirror}" bash`;return"curl -fsSL https://bun.sh/install | bash"}async function tr(){let r=await x$(),m=v$[r];if(r==="cn")g.info("\u68C0\u6D4B\u5230\u4E2D\u56FD\u5927\u9646\u7F51\u7EDC\uFF0C\u4F7F\u7528\u56FD\u5185\u955C\u50CF\u6E90"),g.message(` npm: ${m.npm}`);else g.info("\u4F7F\u7528\u56FD\u9645\u6E90")}var z=null;function Wm(r){return r.startsWith(Q)}async function br(){try{if(!await Bun.file(p).exists())return!1;let m=Bun.spawn([p,"--version"],{stdout:"pipe",stderr:"pipe"});return await m.exited,m.exitCode===0}catch{return!1}}async function fm(){try{let m=Bun.spawn(["which","unzip"],{stdout:"pipe",stderr:"pipe"});if(await m.exited,m.exitCode===0)return!0}catch{}g.warn("\u6B63\u5728\u5B89\u88C5\u7CFB\u7EDF\u4F9D\u8D56 (unzip)...");let r=["apt-get update -qq && apt-get install -y -qq unzip","yum install -y -q unzip","dnf install -y -q unzip","pacman -S --noconfirm unzip","apk add --quiet unzip"];for(let m of r)try{let e=Bun.spawn(["bash","-c",`sudo ${m} 2>/dev/null || ${m}`],{stdout:"pipe",stderr:"pipe"});if(await e.exited,e.exitCode===0)return!0}catch{}return!1}async function Gm(){let r=f();if(!await fm())return g.error("\u8BF7\u5148\u624B\u52A8\u5B89\u88C5 unzip: apt install unzip / yum install unzip"),!1;await tr(),r.start("\u6B63\u5728\u5B89\u88C5 Tako \u4E13\u5C5E Bun \u8FD0\u884C\u65F6...");try{await(await import("fs/promises")).mkdir(Q,{recursive:!0});let e=await ar(),a=`BUN_INSTALL="${Q}" ${e}`;if(await Bun.spawn(["bash","-c",a],{stdout:"inherit",stderr:"inherit"}).exited!==0)return r.stop("Bun \u5B89\u88C5\u5931\u8D25"),!1;return z=p,r.stop("Tako \u4E13\u5C5E Bun \u5B89\u88C5\u5B8C\u6210"),g.info(`\u5B89\u88C5\u4F4D\u7F6E: ${Q}`),!0}catch(m){return r.stop("Bun \u5B89\u88C5\u5931\u8D25"),!1}}async function Zm(){if(await br())return z=p,!0;return g.warn("\u672A\u68C0\u6D4B\u5230 Tako \u4E13\u5C5E Bun\uFF0C\u6B63\u5728\u81EA\u52A8\u5B89\u88C5..."),g.info("\uFF08\u4E0D\u4F1A\u5F71\u54CD\u60A8\u7CFB\u7EDF\u4E2D\u5DF2\u5B89\u88C5\u7684 Node.js \u6216 Bun\uFF09"),await Gm()}async function g$(){if(z){if(!Wm(z))z=p;return z}if(await br())return z=p,p;return p}async function or(r){try{let m=await Y(),e=await fetch(`${m}/${r}/latest`);if(!e.ok)return null;return(await e.json()).version}catch{return null}}async function zm(r){return(await Z()).installedClients[r.id]?.version||null}async function cr(r){let m=P(r.id),e=hr(m,"package.json");try{return await Bun.file(e).exists()}catch{return!1}}async function ir(r){let m=await zm(r);if(!m)return!0;let e=await or(r.package);if(!e)return!1;return m!==e}async function sr(r,m=!1){let e=f(),a=P(r.id);try{if(!await Zm())return{success:!1,error:"Tako \u4E13\u5C5E Bun \u5B89\u88C5\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u6216\u624B\u52A8\u5220\u9664 ~/.tako/bun \u76EE\u5F55\u540E\u91CD\u8BD5"};let t=await cr(r),s=m||await ir(r);if(t&&!s)return{success:!0};let $=t?"\u66F4\u65B0":"\u5B89\u88C5";e.start(`\u6B63\u5728${$} ${r.name}...`),await(await import("fs/promises")).mkdir(a,{recursive:!0});let i=hr(a,"package.json");if(!await Bun.file(i).exists())await Bun.write(i,JSON.stringify({name:`tako-${r.id}`,private:!0,dependencies:{}},null,2));let v=await g$(),c=await Y(),d=Bun.spawn([v,"add",r.package,"--registry",c],{cwd:a,stdout:"pipe",stderr:"pipe"});if(await d.exited!==0){let B=await new Response(d.stderr).text();return e.stop(`${$} ${r.name} \u5931\u8D25`),{success:!1,error:B}}let k=await or(r.package);if(k){let B=await Z();B.installedClients[r.id]={version:k,installedAt:new Date().toISOString()},await T(B)}return e.stop(`${r.name} ${$}\u5B8C\u6210`),{success:!0}}catch(t){return e.stop("\u64CD\u4F5C\u5931\u8D25"),{success:!1,error:t instanceof Error?t.message:"\u672A\u77E5\u9519\u8BEF"}}}async function vr(r){if(!await cr(r))return await sr(r);if(await ir(r))return await sr(r,!0);return{success:!0}}async function xr(r){try{let m=await vr(r);if(!m.success)return m;let e=await q$();if(!e)return{success:!1,error:"\u672A\u914D\u7F6E API Key"};if(r.setupConfigFiles)await r.setupConfigFiles(e);let a=Z$(r);if(!await Bun.file(a).exists())return{success:!1,error:`\u627E\u4E0D\u5230\u53EF\u6267\u884C\u6587\u4EF6: ${a}`};let s=r.getEnvVars(e),$={...process.env,...s};g.info(`\u542F\u52A8 ${r.name}...`);let b;if(r.runtime==="native")b=[a];else b=[await g$(),a];return await Bun.spawn(b,{env:$,stdio:["inherit","inherit","inherit"],cwd:process.cwd()}).exited,{success:!0}}catch(m){return{success:!1,error:m instanceof Error?m.message:"\u542F\u52A8\u5931\u8D25"}}}async function l$(){try{let r=await W$();if(!r)return{success:!1,error:"\u672A\u627E\u5230 API ID\uFF0C\u8BF7\u91CD\u65B0\u914D\u7F6E Key"};let e=await(await fetch(`${M}/apiStats/api/user-stats`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiId:r})})).json(),t=await(await fetch(`${M}/apiStats/api/user-model-stats`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({apiId:r,period:"daily"})})).json();if(!e.success)return{success:!1,error:e.error||e.message||"\u83B7\u53D6\u7EDF\u8BA1\u5931\u8D25"};let s=(t.data||[]).map(($)=>({model:$.model,requests:$.requests,cost:$.formatted?.total||"$0.00"}));return{success:!0,data:{totalRequests:e.data?.usage?.total?.requests||0,totalCost:e.data?.usage?.total?.formattedCost||"$0.00",todayCost:`$${(e.data?.limits?.currentDailyCost||0).toFixed(2)}`,modelStats:s}}}catch(r){return{success:!1,error:r instanceof Error?r.message:"\u7F51\u7EDC\u8BF7\u6C42\u5931\u8D25"}}}function d$(r){return r.toLocaleString("en-US")}var gr="tako-cli",H="0.1.14";function Jm(r,m){let e=r.split(".").map(Number),a=m.split(".").map(Number);for(let t=0;t<3;t++){let s=e[t]||0,$=a[t]||0;if(s>$)return 1;if(s<$)return-1}return 0}async function Qm(){try{let r=await Y(),m=await fetch(`${r}/${gr}/latest`,{signal:AbortSignal.timeout(5000)});if(!m.ok)return null;return(await m.json()).version||null}catch{return null}}async function jm(){let r=await Qm();if(!r)return{hasUpdate:!1,currentVersion:H};return{hasUpdate:Jm(r,H)>0,latestVersion:r,currentVersion:H}}async function Ym(r){let m=f();m.start(`\u6B63\u5728\u66F4\u65B0\u5230 v${r}...`);try{let e=await Y(),a=Bun.spawn([p,"add","-g",`${gr}@latest`,"--registry",e],{stdout:"pipe",stderr:"pipe"});if(await a.exited,a.exitCode===0)return m.stop(`\u66F4\u65B0\u6210\u529F\uFF01\u5DF2\u66F4\u65B0\u5230 v${r}`),!0;else{let t=await new Response(a.stderr).text();return m.stop(`\u66F4\u65B0\u5931\u8D25: ${t||"\u672A\u77E5\u9519\u8BEF"}`),!1}}catch(e){return m.stop(`\u66F4\u65B0\u5931\u8D25: ${e instanceof Error?e.message:"\u672A\u77E5\u9519\u8BEF"}`),!1}}async function lr(){try{let r=await jm();if(r.hasUpdate&&r.latestVersion){if(g.warn(`\u53D1\u73B0\u65B0\u7248\u672C v${r.latestVersion}\uFF08\u5F53\u524D v${H}\uFF09`),await Ym(r.latestVersion))g.info("\u8BF7\u91CD\u65B0\u542F\u52A8 Tako CLI \u4EE5\u4F7F\u7528\u65B0\u7248\u672C"),process.exit(0)}}catch{}}function Hm(){console.log(),console.log(` \uD83D\uDC19 Tako CLI v${H}`),console.log(" \x1B[90m\u6B22\u8FCE\u4F7F\u7528\uFF01\x1B[0m"),console.log()}async function dr(r=!1){if(!r)g.warn("\u672A\u68C0\u6D4B\u5230 API Key"),console.log();let m=await rr({message:r?"\u8BF7\u8F93\u5165\u65B0\u7684 API Key (cr_xxx):":"\u8BF7\u8F93\u5165\u4F60\u7684 API Key (cr_xxx):",placeholder:"cr_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",validate(t){if(!t)return"\u8BF7\u8F93\u5165 API Key";if(!t.startsWith("cr_"))return"Key \u5FC5\u987B\u4EE5 cr_ \u5F00\u5934";if(t.length<10)return"Key \u683C\u5F0F\u4E0D\u6B63\u786E"}});if(X(m))return!1;let e=f();e.start("\u9A8C\u8BC1 Key \u4E2D...");let a=await er(m);if(a.success)return e.stop("Key \u9A8C\u8BC1\u6210\u529F\uFF01\u5DF2\u4FDD\u5B58\u5230\u914D\u7F6E\u6587\u4EF6"),!0;else return e.stop(`\u9A8C\u8BC1\u5931\u8D25: ${a.error}`),!1}function Lm(r,m){let e=[];if(e.push(""),e.push(" \uD83D\uDCCA \u7528\u91CF\u7EDF\u8BA1"),e.push(""),e.push(` \u603B\u8C03\u7528\u6B21\u6570: ${d$(r.totalRequests)} \u6B21`),e.push(` \u603B\u6D88\u8D39: ${r.totalCost}`),e.push(` \u4ECA\u65E5\u6D88\u8D39: ${r.todayCost}`),r.modelStats.length>0)e.push(""),e.push(" \u6A21\u578B\u4F7F\u7528\u5206\u5E03 (\u4ECA\u65E5):"),r.modelStats.forEach((a,t)=>{let s=t===r.modelStats.length-1?"\u2514\u2500":"\u251C\u2500",$=a.model.length>25?a.model.slice(0,22)+"...":a.model;e.push(` ${s} ${$.padEnd(25)} ${d$(a.requests).padStart(6)} \u6B21 ${a.cost.padStart(8)}`)});return e.push(""),e.push(` \x1B[90m${m}s \u540E\u5237\u65B0 | \u6309\u4EFB\u610F\u952E\u8FD4\u56DE\x1B[0m`),e.join(`
54
54
  `)}async function Vm(){let m=f();m.start("\u83B7\u53D6\u7528\u91CF\u7EDF\u8BA1...");let e=await l$();if(!e.success){m.stop(`\u83B7\u53D6\u5931\u8D25: ${e.error}`);return}m.stop("");let a=10,t="",s=()=>{if(t){let b=t.split(`
55
55
  `).length;process.stdout.write(`\x1B[${b}A\x1B[0J`)}t=Lm(e.data,a),console.log(t)};s();let $=process.stdin.isRaw;if(process.stdin.isTTY)process.stdin.setRawMode(!0);return process.stdin.resume(),new Promise((b)=>{let i=!0,o=()=>{if(!i)return;i=!1,c(),b()},v=setInterval(async()=>{if(!i)return;if(a--,a<=0){a=10;let d=await l$();if(d.success)e=d}s()},1000),c=()=>{if(clearInterval(v),process.stdin.removeListener("data",o),process.stdin.isTTY)process.stdin.setRawMode($??!1);process.stdin.pause()};process.stdin.on("data",o)})}async function Xm(){let m=[...J$().map((a)=>({value:{type:"launch",client:a},label:`\u542F\u52A8 ${a.name}`,hint:a.package})),{value:{type:"stats"},label:"\u67E5\u770B\u7528\u91CF\u7EDF\u8BA1"},{value:{type:"config"},label:"\u914D\u7F6E API Key"},{value:{type:"exit"},label:"\u9000\u51FA"}],e=await mr({message:"\u8BF7\u9009\u62E9\u64CD\u4F5C:",options:m});if(X(e))return null;return e}async function km(r){switch(r.type){case"launch":let m=await xr(r.client);if(!m.success)g.error(m.error||"\u542F\u52A8\u5931\u8D25");return!0;case"stats":return await Vm(),!0;case"config":return await dr(!0),!0;case"exit":return!1}}async function yr(){if(Hm(),!await M$()){if(!await dr()){i$("\u518D\u89C1\uFF01");return}}while(!0){let m=await Xm();if(m===null)break;if(!await km(m))break}i$("\u518D\u89C1\uFF01")}async function Bm(){await lr(),await yr()}Bm().catch((r)=>{console.error("Tako CLI \u53D1\u751F\u9519\u8BEF:",r),process.exit(1)});
package/install.ps1 ADDED
@@ -0,0 +1,223 @@
1
+ # Tako CLI Windows 安装脚本
2
+ # 用法: irm https://cdn.jsdelivr.net/npm/tako-cli/install.ps1 | iex
3
+ # 或者: powershell -c "irm https://cdn.jsdelivr.net/npm/tako-cli/install.ps1 | iex"
4
+
5
+ $ErrorActionPreference = "Stop"
6
+
7
+ # 配置
8
+ $TAKO_DIR = "$env:USERPROFILE\.tako"
9
+ $TAKO_BUN_DIR = "$TAKO_DIR\bun"
10
+ $TAKO_CLI_DIR = "$TAKO_DIR\cli"
11
+ $TAKO_BIN_DIR = "$TAKO_DIR\bin"
12
+
13
+ # 颜色输出
14
+ function Write-Info { Write-Host "[INFO] $args" -ForegroundColor Green }
15
+ function Write-Warn { Write-Host "[WARN] $args" -ForegroundColor Yellow }
16
+ function Write-Err { Write-Host "[ERROR] $args" -ForegroundColor Red; exit 1 }
17
+
18
+ # 检测网络环境
19
+ function Detect-Region {
20
+ Write-Info "检测网络环境..."
21
+
22
+ $region = "global"
23
+
24
+ try {
25
+ $response = Invoke-RestMethod -Uri "http://ip-api.com/line/?fields=countryCode" -TimeoutSec 3 -ErrorAction SilentlyContinue
26
+ if ($response -match "CN") {
27
+ $region = "cn"
28
+ }
29
+ } catch {
30
+ try {
31
+ $response = Invoke-RestMethod -Uri "https://ipinfo.io/country" -TimeoutSec 3 -ErrorAction SilentlyContinue
32
+ if ($response -match "CN") {
33
+ $region = "cn"
34
+ }
35
+ } catch {}
36
+ }
37
+
38
+ if ($region -eq "cn") {
39
+ Write-Info "检测到中国大陆网络,使用国内镜像"
40
+ } else {
41
+ Write-Info "使用国际源"
42
+ }
43
+
44
+ return $region
45
+ }
46
+
47
+ # 安装 Tako 专属 Bun
48
+ function Install-Bun {
49
+ param([string]$Region)
50
+
51
+ $bunExe = "$TAKO_BUN_DIR\bin\bun.exe"
52
+
53
+ if (Test-Path $bunExe) {
54
+ Write-Info "Tako 专属 Bun 已安装: $TAKO_BUN_DIR"
55
+ return
56
+ }
57
+
58
+ Write-Info "安装 Tako 专属 Bun 运行时..."
59
+ Write-Info "(不会影响您系统中已安装的 Node.js 或 Bun)"
60
+
61
+ # 创建目录
62
+ New-Item -ItemType Directory -Force -Path $TAKO_BUN_DIR | Out-Null
63
+
64
+ # 设置环境变量确保安装到正确位置
65
+ $env:BUN_INSTALL = $TAKO_BUN_DIR
66
+
67
+ # 国内镜像
68
+ if ($Region -eq "cn") {
69
+ $env:BUN_INSTALL_MIRROR = "https://registry.npmmirror.com/-/binary/bun"
70
+ }
71
+
72
+ # 下载并执行 Bun 安装脚本
73
+ try {
74
+ # Bun 官方 Windows 安装
75
+ irm bun.sh/install.ps1 | iex
76
+ } catch {
77
+ Write-Err "Bun 安装失败: $_"
78
+ }
79
+
80
+ # 清理环境变量
81
+ Remove-Item Env:BUN_INSTALL_MIRROR -ErrorAction SilentlyContinue
82
+
83
+ if (-not (Test-Path $bunExe)) {
84
+ Write-Err "Bun 安装失败,请检查网络连接"
85
+ }
86
+
87
+ Write-Info "Tako 专属 Bun 安装完成: $TAKO_BUN_DIR"
88
+ }
89
+
90
+ # 安装 Tako CLI
91
+ function Install-Tako {
92
+ param([string]$Region)
93
+
94
+ Write-Info "安装 Tako CLI..."
95
+
96
+ $bun = "$TAKO_BUN_DIR\bin\bun.exe"
97
+ $registry = "https://registry.npmjs.org"
98
+
99
+ if ($Region -eq "cn") {
100
+ $registry = "https://registry.npmmirror.com"
101
+ }
102
+
103
+ # 创建本地安装目录
104
+ New-Item -ItemType Directory -Force -Path $TAKO_CLI_DIR | Out-Null
105
+
106
+ # 切换到安装目录
107
+ Push-Location $TAKO_CLI_DIR
108
+
109
+ try {
110
+ # 初始化 package.json
111
+ if (-not (Test-Path "package.json")) {
112
+ '{"name":"tako-local","private":true}' | Out-File -FilePath "package.json" -Encoding UTF8
113
+ }
114
+
115
+ # 安装 tako-cli
116
+ & $bun add tako-cli --registry $registry
117
+
118
+ if ($LASTEXITCODE -ne 0) {
119
+ Write-Err "Tako CLI 安装失败"
120
+ }
121
+ } finally {
122
+ Pop-Location
123
+ }
124
+
125
+ $takoEntry = "$TAKO_CLI_DIR\node_modules\tako-cli\dist\index.js"
126
+ if (-not (Test-Path $takoEntry)) {
127
+ Write-Err "Tako CLI 安装异常: $takoEntry 不存在"
128
+ }
129
+
130
+ Write-Info "Tako CLI 安装完成: $TAKO_CLI_DIR"
131
+
132
+ return $takoEntry
133
+ }
134
+
135
+ # 创建命令
136
+ function Create-Command {
137
+ param([string]$TakoEntry)
138
+
139
+ Write-Info "配置 tako 命令..."
140
+
141
+ $bun = "$TAKO_BUN_DIR\bin\bun.exe"
142
+
143
+ # 创建 bin 目录
144
+ New-Item -ItemType Directory -Force -Path $TAKO_BIN_DIR | Out-Null
145
+
146
+ # 创建 tako.cmd 批处理文件
147
+ $cmdContent = @"
148
+ @echo off
149
+ "$bun" "$TakoEntry" %*
150
+ "@
151
+ $cmdContent | Out-File -FilePath "$TAKO_BIN_DIR\tako.cmd" -Encoding ASCII
152
+
153
+ # 创建 tako.ps1 PowerShell 脚本(可选)
154
+ $ps1Content = @"
155
+ & "$bun" "$TakoEntry" @args
156
+ "@
157
+ $ps1Content | Out-File -FilePath "$TAKO_BIN_DIR\tako.ps1" -Encoding UTF8
158
+
159
+ Write-Info "tako 命令已创建: $TAKO_BIN_DIR\tako.cmd"
160
+ }
161
+
162
+ # 配置 PATH 环境变量
163
+ function Setup-Path {
164
+ Write-Info "配置 PATH 环境变量..."
165
+
166
+ # 获取当前用户 PATH
167
+ $userPath = [Environment]::GetEnvironmentVariable("Path", "User")
168
+
169
+ # 检查是否已包含 Tako bin 目录
170
+ if ($userPath -notlike "*$TAKO_BIN_DIR*") {
171
+ # 添加到用户 PATH
172
+ $newPath = "$TAKO_BIN_DIR;$userPath"
173
+ [Environment]::SetEnvironmentVariable("Path", $newPath, "User")
174
+ Write-Info "已将 $TAKO_BIN_DIR 添加到用户 PATH"
175
+
176
+ # 同时更新当前会话的 PATH
177
+ $env:Path = "$TAKO_BIN_DIR;$env:Path"
178
+ } else {
179
+ Write-Info "PATH 已包含 Tako bin 目录"
180
+ }
181
+ }
182
+
183
+ # 验证安装
184
+ function Verify-Installation {
185
+ # 刷新环境变量
186
+ $env:Path = "$TAKO_BIN_DIR;$env:Path"
187
+
188
+ $takoCmd = "$TAKO_BIN_DIR\tako.cmd"
189
+
190
+ if (Test-Path $takoCmd) {
191
+ Write-Host ""
192
+ Write-Info "安装成功!"
193
+ Write-Host ""
194
+ Write-Host " 运行 'tako' 开始使用" -ForegroundColor Cyan
195
+ Write-Host ""
196
+ Write-Host " 注意: 如果 'tako' 命令无法识别,请重新打开终端或运行:" -ForegroundColor Yellow
197
+ Write-Host " `$env:Path = `"$TAKO_BIN_DIR;`$env:Path`"" -ForegroundColor Cyan
198
+ Write-Host ""
199
+ } else {
200
+ Write-Err "安装验证失败"
201
+ }
202
+ }
203
+
204
+ # 主流程
205
+ function Main {
206
+ Write-Host ""
207
+ Write-Host " +====================================+" -ForegroundColor Cyan
208
+ Write-Host " | Tako CLI 安装程序 |" -ForegroundColor Cyan
209
+ Write-Host " +====================================+" -ForegroundColor Cyan
210
+ Write-Host ""
211
+
212
+ $region = Detect-Region
213
+ Install-Bun -Region $region
214
+ $takoEntry = Install-Tako -Region $region
215
+ Create-Command -TakoEntry $takoEntry
216
+ Setup-Path
217
+ Verify-Installation
218
+
219
+ Write-Host ""
220
+ }
221
+
222
+ # 执行
223
+ Main
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tako-cli",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "Tako CLI - AI coding tools launcher",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,6 +8,7 @@
8
8
  },
9
9
  "files": [
10
10
  "install.sh",
11
+ "install.ps1",
11
12
  "dist"
12
13
  ],
13
14
  "scripts": {