tako-cli 0.1.11 → 0.1.12

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 @@ ${i.default.gray(R)} ${r}
50
50
  `)}
51
51
  `)},info:(r)=>{g.message(r,{symbol:i.default.blue(lm)})},success:(r)=>{g.message(r,{symbol:i.default.green(gm)})},step:(r)=>{g.message(r,{symbol:i.default.green(h$)})},warn:(r)=>{g.message(r,{symbol:i.default.yellow(xm)})},warning:(r)=>{g.warn(r)},error:(r)=>{g.message(r,{symbol:i.default.red(dm)})}},W=()=>{let r=c$?["\u25D2","\u25D0","\u25D3","\u25D1"]:["\u2022","o","O","0"],m=c$?80:120,e,a,t=!1,o="",$=(v="")=>{t=!0,e=u$(),o=v.replace(/\.+$/,""),process.stdout.write(`${i.default.gray(n)}
52
52
  `);let h=0,d=0;a=setInterval(()=>{let G=i.default.magenta(r[h]),B=".".repeat(Math.floor(d)).slice(0,3);process.stdout.write(Y.cursor.move(-999,0)),process.stdout.write(Y.erase.down(1)),process.stdout.write(`${G} ${o}${B}`),h=h+1<r.length?h+1:0,d=d<r.length?d+0.125:0},m)},s=(v="",h=0)=>{o=v??o,t=!1,clearInterval(a);let d=h===0?i.default.green(h$):h===1?i.default.red(F$):i.default.red(D$);process.stdout.write(Y.cursor.move(-999,0)),process.stdout.write(Y.erase.down(1)),process.stdout.write(`${d} ${o}
53
- `),e()},b=(v="")=>{o=v??o},c=(v)=>{let h=v>1?"Something went wrong":"Canceled";t&&s(h,v)};return process.on("uncaughtExceptionMonitor",()=>c(2)),process.on("unhandledRejection",()=>c(2)),process.on("SIGINT",()=>c(1)),process.on("SIGTERM",()=>c(1)),process.on("exit",c),{start:$,stop:s,message:b}};function ym(r){return r.startsWith("cr_")&&r.length>10}async function pm(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(!ym(r))return{success:!1,error:"Key \u683C\u5F0F\u4E0D\u6B63\u786E\uFF0C\u5FC5\u987B\u4EE5 cr_ \u5F00\u5934"};let m=await pm(r);if(!m.valid)return{success:!1,error:m.error};return await T({apiKey:r,apiId:m.apiId}),{success:!0}}import{join as ir}from"path";var N=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 l$(){if(N)return N;let r=[wm,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 N=e,e}catch{}return N="cn","cn"}async function wm(){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 fm(){let r=await l$();return v$[r]}async function j(){return(await fm()).npm}async function ar(){if(await l$()==="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 l$(),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 qm(r){return r.startsWith(Q)}async function sr(){try{if(!await Bun.file(w).exists())return!1;let m=Bun.spawn([w,"--version"],{stdout:"pipe",stderr:"pipe"});return await m.exited,m.exitCode===0}catch{return!1}}async function Wm(){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=W();if(!await Wm())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=w,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 sr())return z=w,!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(!qm(z))z=w;return z}if(await sr())return z=w,w;return w}async function cr(r){try{let m=await j(),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 hr(r){let m=P(r.id),e=ir(m,"package.json");try{return await Bun.file(e).exists()}catch{return!1}}async function br(r){let m=await zm(r);if(!m)return!0;let e=await cr(r.package);if(!e)return!1;return m!==e}async function or(r,m=!1){let e=W(),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 hr(r),o=m||await br(r);if(t&&!o)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 b=ir(a,"package.json");if(!await Bun.file(b).exists())await Bun.write(b,JSON.stringify({name:`tako-${r.id}`,private:!0,dependencies:{}},null,2));let v=await g$(),h=await j(),d=Bun.spawn([v,"add",r.package,"--registry",h],{cwd:a,stdout:"pipe",stderr:"pipe"});if(await d.exited!==0){let k=await new Response(d.stderr).text();return e.stop(`${$} ${r.name} \u5931\u8D25`),{success:!1,error:k}}let B=await cr(r.package);if(B){let k=await Z();k.installedClients[r.id]={version:B,installedAt:new Date().toISOString()},await T(k)}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 hr(r))return await or(r);if(await br(r))return await or(r,!0);return{success:!0}}async function lr(r){try{let m=await vr(r);if(!m.success)return m;let e=await f$();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 o=r.getEnvVars(e),$={...process.env,...o};g.info(`\u542F\u52A8 ${r.name}...`);let s;if(r.runtime==="bun")s=[await g$(),a];else s=[a];return await Bun.spawn(s,{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 x$(){try{let r=await q$();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 o=(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:o}}}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.11";function Jm(r,m){let e=r.split(".").map(Number),a=m.split(".").map(Number);for(let t=0;t<3;t++){let o=e[t]||0,$=a[t]||0;if(o>$)return 1;if(o<$)return-1}return 0}async function Qm(){try{let r=await j(),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 Ym(){let r=await Qm();if(!r)return{hasUpdate:!1,currentVersion:H};return{hasUpdate:Jm(r,H)>0,latestVersion:r,currentVersion:H}}async function jm(r){let m=W();m.start(`\u6B63\u5728\u66F4\u65B0\u5230 v${r}...`);try{let e=await j(),a=Bun.spawn([w,"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 xr(){try{let r=await Ym();if(r.hasUpdate&&r.latestVersion){if(g.warn(`\u53D1\u73B0\u65B0\u7248\u672C v${r.latestVersion}\uFF08\u5F53\u524D v${H}\uFF09`),await jm(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=W();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 o=t===r.modelStats.length-1?"\u2514\u2500":"\u251C\u2500",$=a.model.length>25?a.model.slice(0,22)+"...":a.model;e.push(` ${o} ${$.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()},b=(v="")=>{o=v??o},c=(v)=>{let h=v>1?"Something went wrong":"Canceled";t&&s(h,v)};return process.on("uncaughtExceptionMonitor",()=>c(2)),process.on("unhandledRejection",()=>c(2)),process.on("SIGINT",()=>c(1)),process.on("SIGTERM",()=>c(1)),process.on("exit",c),{start:$,stop:s,message:b}};function ym(r){return r.startsWith("cr_")&&r.length>10}async function pm(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(!ym(r))return{success:!1,error:"Key \u683C\u5F0F\u4E0D\u6B63\u786E\uFF0C\u5FC5\u987B\u4EE5 cr_ \u5F00\u5934"};let m=await pm(r);if(!m.valid)return{success:!1,error:m.error};return await T({apiKey:r,apiId:m.apiId}),{success:!0}}import{join as ir}from"path";var N=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 l$(){if(N)return N;let r=[wm,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 N=e,e}catch{}return N="cn","cn"}async function wm(){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 fm(){let r=await l$();return v$[r]}async function j(){return(await fm()).npm}async function ar(){if(await l$()==="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 l$(),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 qm(r){return r.startsWith(Q)}async function sr(){try{if(!await Bun.file(w).exists())return!1;let m=Bun.spawn([w,"--version"],{stdout:"pipe",stderr:"pipe"});return await m.exited,m.exitCode===0}catch{return!1}}async function Wm(){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=W();if(!await Wm())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=w,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 sr())return z=w,!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(!qm(z))z=w;return z}if(await sr())return z=w,w;return w}async function cr(r){try{let m=await j(),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 hr(r){let m=P(r.id),e=ir(m,"package.json");try{return await Bun.file(e).exists()}catch{return!1}}async function br(r){let m=await zm(r);if(!m)return!0;let e=await cr(r.package);if(!e)return!1;return m!==e}async function or(r,m=!1){let e=W(),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 hr(r),o=m||await br(r);if(t&&!o)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 b=ir(a,"package.json");if(!await Bun.file(b).exists())await Bun.write(b,JSON.stringify({name:`tako-${r.id}`,private:!0,dependencies:{}},null,2));let v=await g$(),h=await j(),d=Bun.spawn([v,"add",r.package,"--registry",h],{cwd:a,stdout:"pipe",stderr:"pipe"});if(await d.exited!==0){let k=await new Response(d.stderr).text();return e.stop(`${$} ${r.name} \u5931\u8D25`),{success:!1,error:k}}let B=await cr(r.package);if(B){let k=await Z();k.installedClients[r.id]={version:B,installedAt:new Date().toISOString()},await T(k)}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 hr(r))return await or(r);if(await br(r))return await or(r,!0);return{success:!0}}async function lr(r){try{let m=await vr(r);if(!m.success)return m;let e=await f$();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 o=r.getEnvVars(e),$={...process.env,...o};g.info(`\u542F\u52A8 ${r.name}...`);let s;if(r.runtime==="bun")s=[await g$(),a];else s=[a];return await Bun.spawn(s,{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 x$(){try{let r=await q$();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 o=(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:o}}}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.12";function Jm(r,m){let e=r.split(".").map(Number),a=m.split(".").map(Number);for(let t=0;t<3;t++){let o=e[t]||0,$=a[t]||0;if(o>$)return 1;if(o<$)return-1}return 0}async function Qm(){try{let r=await j(),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 Ym(){let r=await Qm();if(!r)return{hasUpdate:!1,currentVersion:H};return{hasUpdate:Jm(r,H)>0,latestVersion:r,currentVersion:H}}async function jm(r){let m=W();m.start(`\u6B63\u5728\u66F4\u65B0\u5230 v${r}...`);try{let e=await j(),a=Bun.spawn([w,"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 xr(){try{let r=await Ym();if(r.hasUpdate&&r.latestVersion){if(g.warn(`\u53D1\u73B0\u65B0\u7248\u672C v${r.latestVersion}\uFF08\u5F53\u524D v${H}\uFF09`),await jm(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=W();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 o=t===r.modelStats.length-1?"\u2514\u2500":"\u251C\u2500",$=a.model.length>25?a.model.slice(0,22)+"...":a.model;e.push(` ${o} ${$.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=W();m.start("\u83B7\u53D6\u7528\u91CF\u7EDF\u8BA1...");let e=await x$();if(!e.success){m.stop(`\u83B7\u53D6\u5931\u8D25: ${e.error}`);return}m.stop("");let a=10,t="",o=()=>{if(t){let s=t.split(`
55
55
  `).length;process.stdout.write(`\x1B[${s}A\x1B[0J`)}t=Lm(e.data,a),console.log(t)};o();let $=process.stdin.isRaw;if(process.stdin.isTTY)process.stdin.setRawMode(!0);return process.stdin.resume(),new Promise((s)=>{let b=!0,c=()=>{if(!b)return;b=!1,h(),s()},v=setInterval(async()=>{if(!b)return;if(a--,a<=0){a=10;let d=await x$();if(d.success)e=d}o()},1000),h=()=>{if(clearInterval(v),process.stdin.removeListener("data",c),process.stdin.isTTY)process.stdin.setRawMode($??!1);process.stdin.pause()};process.stdin.on("data",c)})}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 Bm(r){switch(r.type){case"launch":let m=await lr(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 nr(){if(Hm(),!await M$()){if(!await dr()){b$("\u518D\u89C1\uFF01");return}}while(!0){let m=await Xm();if(m===null)break;if(!await Bm(m))break}b$("\u518D\u89C1\uFF01")}async function km(){await xr(),await nr()}km().catch((r)=>{console.error("Tako CLI \u53D1\u751F\u9519\u8BEF:",r),process.exit(1)});
package/install.sh CHANGED
@@ -126,28 +126,33 @@ install_tako() {
126
126
 
127
127
  local bun="$TAKO_BUN_DIR/bin/bun"
128
128
  local registry="https://registry.npmjs.org"
129
+ local tako_install_dir="$TAKO_DIR/cli"
129
130
 
130
131
  if [ "$REGION" = "cn" ]; then
131
132
  registry="https://registry.npmmirror.com"
132
133
  fi
133
134
 
134
- # 使用 Tako 专属 Bun 全局安装 tako-cli
135
- export BUN_INSTALL="$TAKO_BUN_DIR"
136
- if ! "$bun" add -g tako-cli --registry "$registry"; then
135
+ # 使用本地安装而非全局安装,避免污染 ~/.bun
136
+ mkdir -p "$tako_install_dir"
137
+ cd "$tako_install_dir"
138
+
139
+ # 初始化 package.json(如果不存在)
140
+ if [ ! -f "package.json" ]; then
141
+ echo '{"name":"tako-local","private":true}' > package.json
142
+ fi
143
+
144
+ # 安装 tako-cli 到本地目录
145
+ if ! "$bun" add tako-cli --registry "$registry"; then
137
146
  error "Tako CLI 安装失败"
138
147
  fi
139
148
 
140
- # 检测 tako 实际安装位置(bun 可能安装到 ~/.bun 或 ~/.tako/bun)
141
- if [ -f "$TAKO_BUN_DIR/bin/tako" ]; then
142
- TAKO_BIN="$TAKO_BUN_DIR/bin/tako"
143
- elif [ -f "$HOME/.bun/bin/tako" ]; then
144
- TAKO_BIN="$HOME/.bun/bin/tako"
145
- warn "Tako 安装到了 ~/.bun(bun 默认目录)"
146
- else
147
- error "Tako CLI 安装异常: 找不到 tako 可执行文件"
149
+ # 设置 tako 可执行文件路径
150
+ TAKO_ENTRY="$tako_install_dir/node_modules/tako-cli/dist/index.js"
151
+ if [ ! -f "$TAKO_ENTRY" ]; then
152
+ error "Tako CLI 安装异常: $TAKO_ENTRY 不存在"
148
153
  fi
149
154
 
150
- info "Tako CLI 安装完成: $TAKO_BIN"
155
+ info "Tako CLI 安装完成: $tako_install_dir"
151
156
  }
152
157
 
153
158
  # 添加 PATH 配置到指定文件
@@ -220,34 +225,37 @@ setup_shell_path() {
220
225
  create_command() {
221
226
  info "配置 tako 命令..."
222
227
 
223
- # 使用 install_tako 中检测到的实际路径
224
- local tako_source="$TAKO_BIN"
225
- local tako_bin_dir="$(dirname "$TAKO_BIN")"
228
+ local bun="$TAKO_BUN_DIR/bin/bun"
229
+ local tako_bin_dir="$TAKO_DIR/bin"
230
+
231
+ # 创建 Tako 的 bin 目录
232
+ mkdir -p "$tako_bin_dir"
226
233
 
227
- # 检查 tako 是否存在
228
- if [ ! -f "$tako_source" ]; then
229
- error "tako 可执行文件未找到: $tako_source"
230
- fi
234
+ # 创建 wrapper 脚本(使用 Tako 专属 bun 运行本地安装的 tako-cli)
235
+ local wrapper="#!/bin/bash
236
+ exec \"$bun\" \"$TAKO_ENTRY\" \"\$@\"
237
+ "
238
+ echo "$wrapper" > "$tako_bin_dir/tako"
239
+ chmod +x "$tako_bin_dir/tako"
231
240
 
232
241
  # 方案1: 尝试创建符号链接到 /usr/local/bin
233
242
  if [ -w "$INSTALL_DIR" ] 2>/dev/null; then
234
- ln -sf "$tako_source" "$INSTALL_DIR/tako"
235
- info "tako 命令已创建: $INSTALL_DIR/tako -> $tako_source"
243
+ ln -sf "$tako_bin_dir/tako" "$INSTALL_DIR/tako"
244
+ info "tako 命令已创建: $INSTALL_DIR/tako"
236
245
  return 0
237
246
  fi
238
247
 
239
248
  # 方案2: 尝试 sudo 创建符号链接
240
249
  if command -v sudo &> /dev/null; then
241
250
  warn "需要 sudo 权限写入 $INSTALL_DIR"
242
- if sudo ln -sf "$tako_source" "$INSTALL_DIR/tako" 2>/dev/null; then
243
- info "tako 命令已创建: $INSTALL_DIR/tako -> $tako_source"
251
+ if sudo ln -sf "$tako_bin_dir/tako" "$INSTALL_DIR/tako" 2>/dev/null; then
252
+ info "tako 命令已创建: $INSTALL_DIR/tako"
244
253
  return 0
245
254
  fi
246
255
  fi
247
256
 
248
257
  # 方案3: 配置 PATH(无需 sudo)
249
258
  warn "无法写入 $INSTALL_DIR,使用 PATH 配置方案"
250
- # 设置正确的 bin 目录用于 PATH 配置
251
259
  TAKO_BIN_DIR="$tako_bin_dir"
252
260
  setup_shell_path
253
261
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tako-cli",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "Tako CLI - AI coding tools launcher",
5
5
  "type": "module",
6
6
  "bin": {