tako-cli 0.1.10 → 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 +1 -1
- package/install.sh +38 -23
- 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.10";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,34 +126,42 @@ 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
|
-
#
|
|
135
|
-
|
|
136
|
-
|
|
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
|
-
#
|
|
141
|
-
|
|
142
|
-
if [ ! -f "$
|
|
143
|
-
error "Tako CLI 安装异常: $
|
|
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 不存在"
|
|
144
153
|
fi
|
|
145
154
|
|
|
146
|
-
info "Tako CLI
|
|
155
|
+
info "Tako CLI 安装完成: $tako_install_dir"
|
|
147
156
|
}
|
|
148
157
|
|
|
149
158
|
# 添加 PATH 配置到指定文件
|
|
150
159
|
add_path_to_file() {
|
|
151
160
|
local file="$1"
|
|
152
161
|
local content="$2"
|
|
153
|
-
local bun_bin="$TAKO_BUN_DIR/bin"
|
|
154
162
|
|
|
155
|
-
#
|
|
156
|
-
if grep -q "
|
|
163
|
+
# 检查是否已存在 Tako CLI 配置
|
|
164
|
+
if grep -q "Tako CLI PATH" "$file" 2>/dev/null; then
|
|
157
165
|
return 0
|
|
158
166
|
fi
|
|
159
167
|
|
|
@@ -165,7 +173,8 @@ add_path_to_file() {
|
|
|
165
173
|
|
|
166
174
|
# 配置 PATH 到 shell 配置文件
|
|
167
175
|
setup_shell_path() {
|
|
168
|
-
|
|
176
|
+
# 使用动态检测的目录(由 create_command 设置)或默认值
|
|
177
|
+
local bun_bin="${TAKO_BIN_DIR:-$TAKO_BUN_DIR/bin}"
|
|
169
178
|
local path_export="export PATH=\"$bun_bin:\$PATH\""
|
|
170
179
|
local configured=false
|
|
171
180
|
|
|
@@ -216,35 +225,41 @@ setup_shell_path() {
|
|
|
216
225
|
create_command() {
|
|
217
226
|
info "配置 tako 命令..."
|
|
218
227
|
|
|
219
|
-
local
|
|
220
|
-
local
|
|
228
|
+
local bun="$TAKO_BUN_DIR/bin/bun"
|
|
229
|
+
local tako_bin_dir="$TAKO_DIR/bin"
|
|
221
230
|
|
|
222
|
-
#
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
231
|
+
# 创建 Tako 的 bin 目录
|
|
232
|
+
mkdir -p "$tako_bin_dir"
|
|
233
|
+
|
|
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"
|
|
226
240
|
|
|
227
241
|
# 方案1: 尝试创建符号链接到 /usr/local/bin
|
|
228
242
|
if [ -w "$INSTALL_DIR" ] 2>/dev/null; then
|
|
229
|
-
ln -sf "$
|
|
230
|
-
info "tako 命令已创建: $INSTALL_DIR/tako
|
|
243
|
+
ln -sf "$tako_bin_dir/tako" "$INSTALL_DIR/tako"
|
|
244
|
+
info "tako 命令已创建: $INSTALL_DIR/tako"
|
|
231
245
|
return 0
|
|
232
246
|
fi
|
|
233
247
|
|
|
234
248
|
# 方案2: 尝试 sudo 创建符号链接
|
|
235
249
|
if command -v sudo &> /dev/null; then
|
|
236
250
|
warn "需要 sudo 权限写入 $INSTALL_DIR"
|
|
237
|
-
if sudo ln -sf "$
|
|
238
|
-
info "tako 命令已创建: $INSTALL_DIR/tako
|
|
251
|
+
if sudo ln -sf "$tako_bin_dir/tako" "$INSTALL_DIR/tako" 2>/dev/null; then
|
|
252
|
+
info "tako 命令已创建: $INSTALL_DIR/tako"
|
|
239
253
|
return 0
|
|
240
254
|
fi
|
|
241
255
|
fi
|
|
242
256
|
|
|
243
257
|
# 方案3: 配置 PATH(无需 sudo)
|
|
244
258
|
warn "无法写入 $INSTALL_DIR,使用 PATH 配置方案"
|
|
259
|
+
TAKO_BIN_DIR="$tako_bin_dir"
|
|
245
260
|
setup_shell_path
|
|
246
261
|
|
|
247
|
-
info "tako 命令已配置到 $
|
|
262
|
+
info "tako 命令已配置到 $tako_bin_dir"
|
|
248
263
|
}
|
|
249
264
|
|
|
250
265
|
# 验证安装
|