tako-cli 0.1.9 → 0.1.11
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 +1 -1
- package/install.sh +73 -51
- package/package.json +1 -1
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.9";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.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(`
|
|
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
|
@@ -90,7 +90,7 @@ install_dependencies() {
|
|
|
90
90
|
install_bun() {
|
|
91
91
|
# 检查是否已安装
|
|
92
92
|
if [ -x "$TAKO_BUN_DIR/bin/bun" ]; then
|
|
93
|
-
info "Tako 专属 Bun
|
|
93
|
+
info "Tako 专属 Bun 已安装: $TAKO_BUN_DIR"
|
|
94
94
|
return 0
|
|
95
95
|
fi
|
|
96
96
|
|
|
@@ -99,17 +99,22 @@ install_bun() {
|
|
|
99
99
|
|
|
100
100
|
mkdir -p "$TAKO_BUN_DIR"
|
|
101
101
|
|
|
102
|
-
|
|
102
|
+
# 设置环境变量确保 bun 安装到正确位置
|
|
103
|
+
export BUN_INSTALL="$TAKO_BUN_DIR"
|
|
103
104
|
|
|
104
105
|
# 国内用户使用镜像
|
|
105
106
|
if [ "$REGION" = "cn" ]; then
|
|
106
|
-
|
|
107
|
+
export BUN_INSTALL_MIRROR="https://registry.npmmirror.com/-/binary/bun"
|
|
107
108
|
fi
|
|
108
109
|
|
|
109
|
-
|
|
110
|
+
# 执行 bun 安装脚本
|
|
111
|
+
curl -fsSL https://bun.sh/install | bash
|
|
112
|
+
|
|
113
|
+
# 清理环境变量
|
|
114
|
+
unset BUN_INSTALL_MIRROR
|
|
110
115
|
|
|
111
116
|
if [ ! -x "$TAKO_BUN_DIR/bin/bun" ]; then
|
|
112
|
-
error "Bun
|
|
117
|
+
error "Bun 安装失败,请检查网络连接"
|
|
113
118
|
fi
|
|
114
119
|
|
|
115
120
|
info "Tako 专属 Bun 安装完成: $TAKO_BUN_DIR"
|
|
@@ -127,70 +132,84 @@ install_tako() {
|
|
|
127
132
|
fi
|
|
128
133
|
|
|
129
134
|
# 使用 Tako 专属 Bun 全局安装 tako-cli
|
|
130
|
-
|
|
131
|
-
|
|
135
|
+
export BUN_INSTALL="$TAKO_BUN_DIR"
|
|
136
|
+
if ! "$bun" add -g tako-cli --registry "$registry"; then
|
|
137
|
+
error "Tako CLI 安装失败"
|
|
138
|
+
fi
|
|
139
|
+
|
|
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 可执行文件"
|
|
148
|
+
fi
|
|
149
|
+
|
|
150
|
+
info "Tako CLI 安装完成: $TAKO_BIN"
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
# 添加 PATH 配置到指定文件
|
|
154
|
+
add_path_to_file() {
|
|
155
|
+
local file="$1"
|
|
156
|
+
local content="$2"
|
|
157
|
+
|
|
158
|
+
# 检查是否已存在 Tako CLI 配置
|
|
159
|
+
if grep -q "Tako CLI PATH" "$file" 2>/dev/null; then
|
|
160
|
+
return 0
|
|
161
|
+
fi
|
|
132
162
|
|
|
133
|
-
|
|
163
|
+
echo "" >> "$file"
|
|
164
|
+
echo "# Tako CLI PATH" >> "$file"
|
|
165
|
+
echo "$content" >> "$file"
|
|
166
|
+
info "已添加 PATH 配置到 $file"
|
|
134
167
|
}
|
|
135
168
|
|
|
136
169
|
# 配置 PATH 到 shell 配置文件
|
|
137
170
|
setup_shell_path() {
|
|
138
|
-
|
|
171
|
+
# 使用动态检测的目录(由 create_command 设置)或默认值
|
|
172
|
+
local bun_bin="${TAKO_BIN_DIR:-$TAKO_BUN_DIR/bin}"
|
|
139
173
|
local path_export="export PATH=\"$bun_bin:\$PATH\""
|
|
140
174
|
local configured=false
|
|
141
175
|
|
|
142
176
|
# 检测当前 shell
|
|
143
177
|
local current_shell=""
|
|
144
|
-
current_shell=$(basename "$SHELL" 2>/dev/null || echo "")
|
|
178
|
+
current_shell=$(basename "$SHELL" 2>/dev/null || echo "bash")
|
|
145
179
|
|
|
146
180
|
# ===== Bash =====
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if [ -f "$bashrc" ]
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
181
|
+
if [ "$current_shell" = "bash" ]; then
|
|
182
|
+
# 优先使用 .bashrc(交互式),其次 .bash_profile(登录)
|
|
183
|
+
if [ -f "$HOME/.bashrc" ]; then
|
|
184
|
+
add_path_to_file "$HOME/.bashrc" "$path_export"
|
|
185
|
+
configured=true
|
|
186
|
+
elif [ -f "$HOME/.bash_profile" ]; then
|
|
187
|
+
add_path_to_file "$HOME/.bash_profile" "$path_export"
|
|
188
|
+
configured=true
|
|
189
|
+
else
|
|
190
|
+
# 创建 .bashrc
|
|
191
|
+
add_path_to_file "$HOME/.bashrc" "$path_export"
|
|
192
|
+
configured=true
|
|
157
193
|
fi
|
|
158
|
-
|
|
194
|
+
fi
|
|
159
195
|
|
|
160
196
|
# ===== Zsh =====
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
echo "" >> "$zshrc"
|
|
165
|
-
echo "# Tako CLI PATH" >> "$zshrc"
|
|
166
|
-
echo "$path_export" >> "$zshrc"
|
|
167
|
-
info "已添加 PATH 配置到 $zshrc"
|
|
168
|
-
configured=true
|
|
169
|
-
fi
|
|
197
|
+
if [ "$current_shell" = "zsh" ] || [ -f "$HOME/.zshrc" ]; then
|
|
198
|
+
add_path_to_file "$HOME/.zshrc" "$path_export"
|
|
199
|
+
configured=true
|
|
170
200
|
fi
|
|
171
201
|
|
|
172
202
|
# ===== Fish =====
|
|
173
203
|
local fish_config="$HOME/.config/fish/config.fish"
|
|
174
|
-
if [
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
echo "# Tako CLI PATH" >> "$fish_config"
|
|
179
|
-
echo "set -gx PATH \"$bun_bin\" \$PATH" >> "$fish_config"
|
|
180
|
-
info "已添加 PATH 配置到 $fish_config"
|
|
181
|
-
configured=true
|
|
182
|
-
fi
|
|
204
|
+
if [ "$current_shell" = "fish" ] || [ -f "$fish_config" ]; then
|
|
205
|
+
mkdir -p "$(dirname "$fish_config")"
|
|
206
|
+
add_path_to_file "$fish_config" "set -gx PATH \"$bun_bin\" \$PATH"
|
|
207
|
+
configured=true
|
|
183
208
|
fi
|
|
184
209
|
|
|
185
210
|
# ===== 通用 .profile (sh, dash 等 POSIX shell) =====
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
if ! grep -q "$bun_bin" "$profile_rc" 2>/dev/null; then
|
|
189
|
-
echo "" >> "$profile_rc"
|
|
190
|
-
echo "# Tako CLI PATH" >> "$profile_rc"
|
|
191
|
-
echo "$path_export" >> "$profile_rc"
|
|
192
|
-
info "已添加 PATH 配置到 $profile_rc"
|
|
193
|
-
fi
|
|
211
|
+
if [ "$configured" = false ] || [ -f "$HOME/.profile" ]; then
|
|
212
|
+
add_path_to_file "$HOME/.profile" "$path_export"
|
|
194
213
|
fi
|
|
195
214
|
|
|
196
215
|
# 导出到当前 session
|
|
@@ -201,10 +220,11 @@ setup_shell_path() {
|
|
|
201
220
|
create_command() {
|
|
202
221
|
info "配置 tako 命令..."
|
|
203
222
|
|
|
204
|
-
|
|
205
|
-
local tako_source="$
|
|
223
|
+
# 使用 install_tako 中检测到的实际路径
|
|
224
|
+
local tako_source="$TAKO_BIN"
|
|
225
|
+
local tako_bin_dir="$(dirname "$TAKO_BIN")"
|
|
206
226
|
|
|
207
|
-
# 检查
|
|
227
|
+
# 检查 tako 是否存在
|
|
208
228
|
if [ ! -f "$tako_source" ]; then
|
|
209
229
|
error "tako 可执行文件未找到: $tako_source"
|
|
210
230
|
fi
|
|
@@ -227,9 +247,11 @@ create_command() {
|
|
|
227
247
|
|
|
228
248
|
# 方案3: 配置 PATH(无需 sudo)
|
|
229
249
|
warn "无法写入 $INSTALL_DIR,使用 PATH 配置方案"
|
|
250
|
+
# 设置正确的 bin 目录用于 PATH 配置
|
|
251
|
+
TAKO_BIN_DIR="$tako_bin_dir"
|
|
230
252
|
setup_shell_path
|
|
231
253
|
|
|
232
|
-
info "tako 命令已配置到 $
|
|
254
|
+
info "tako 命令已配置到 $tako_bin_dir"
|
|
233
255
|
}
|
|
234
256
|
|
|
235
257
|
# 验证安装
|