tenicli 0.1.2 → 0.1.3

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.
Files changed (2) hide show
  1. package/dist/index.js +8 -8
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import{createRequire as XQ}from"node:module";var p=XQ(import.meta.url);import{existsSync as F,readFileSync as h,writeFileSync as YQ,mkdirSync as KQ}from"fs";import{join as I}from"path";var O=[{id:"claude-sonnet-4-20250514",name:"Claude Sonnet 4",provider:"anthropic",speed:"fast"},{id:"claude-haiku-3-5-20241022",name:"Claude Haiku 3.5",provider:"anthropic",speed:"fast"},{id:"claude-opus-4-20250514",name:"Claude Opus 4",provider:"anthropic",speed:"slow"},{id:"gpt-4o",name:"GPT-4o",provider:"openai",speed:"fast"},{id:"gpt-4o-mini",name:"GPT-4o Mini",provider:"openai",speed:"fast"},{id:"o3-mini",name:"o3-mini",provider:"openai",speed:"normal"}];function x(){let Q=process.env.HOME||process.env.USERPROFILE||"";return I(Q,".tenicli")}function b(){return I(x(),"config.json")}function P(){try{if(F(b()))return JSON.parse(h(b(),"utf8"))}catch{}return{}}function L(Q){let Z=x();if(!F(Z))KQ(Z,{recursive:!0});let $=P(),z={...$,...Q,keys:{...$.keys,...Q.keys},baseUrls:{...$.baseUrls,...Q.baseUrls}};YQ(b(),JSON.stringify(z,null,2),"utf8")}function l(){let Q=process.cwd();d(I(Q,".tenicli.env")),d(I(Q,".env"));let Z=P(),$=process.env,z=$.TENICLI_MODEL||Z.activeModel||O[0].id,Y=O.find((W)=>W.id===z)?.provider||$.TENICLI_PROVIDER||"anthropic",X=qQ(Y,Z,$),K=Y==="openai"?"https://api.openai.com":"https://api.anthropic.com",q=$.TENICLI_BASE_URL||Z.baseUrls?.[Y]||K;return{provider:{type:Y,baseUrl:q,apiKey:X,model:z},maxTokens:parseInt($.TENICLI_MAX_TOKENS||"8192"),systemPrompt:WQ(Q),cwd:Q}}function qQ(Q,Z,$){if(Q==="anthropic")return $.TENICLI_API_KEY||$.ANTHROPIC_API_KEY||Z.keys?.anthropic||"";if(Q==="openai")return $.TENICLI_API_KEY||$.OPENAI_API_KEY||Z.keys?.openai||"";return $.TENICLI_API_KEY||""}function d(Q){try{if(!F(Q))return;for(let Z of h(Q,"utf8").split(`
3
- `)){let $=Z.trim();if(!$||$.startsWith("#"))continue;let z=$.indexOf("=");if(z===-1)continue;let V=$.slice(0,z).trim(),Y=$.slice(z+1).trim();if(Y.startsWith('"')&&Y.endsWith('"')||Y.startsWith("'")&&Y.endsWith("'"))Y=Y.slice(1,-1);if(!process.env[V])process.env[V]=Y}}catch{}}function WQ(Q){for(let Z of[I(Q,"TENICLI.md"),I(x(),"TENICLI.md")])if(F(Z))return h(Z,"utf8");return JQ}var JQ=`You are TeniCLI, a fast AI coding assistant in the terminal.
2
+ import{createRequire as XQ}from"node:module";var p=XQ(import.meta.url);import{existsSync as F,readFileSync as b,writeFileSync as YQ,mkdirSync as KQ}from"fs";import{join as I}from"path";var O=[{id:"claude-sonnet-4-20250514",name:"Claude Sonnet 4",provider:"anthropic",speed:"fast"},{id:"claude-haiku-3-5-20241022",name:"Claude Haiku 3.5",provider:"anthropic",speed:"fast"},{id:"claude-opus-4-20250514",name:"Claude Opus 4",provider:"anthropic",speed:"slow"},{id:"gpt-4o",name:"GPT-4o",provider:"openai",speed:"fast"},{id:"gpt-4o-mini",name:"GPT-4o Mini",provider:"openai",speed:"fast"},{id:"o3-mini",name:"o3-mini",provider:"openai",speed:"normal"}];function x(){let Q=process.env.HOME||process.env.USERPROFILE||"";return I(Q,".tenicli")}function h(){return I(x(),"config.json")}function P(){try{if(F(h()))return JSON.parse(b(h(),"utf8"))}catch{}return{}}function L(Q){let Z=x();if(!F(Z))KQ(Z,{recursive:!0});let $=P(),z={...$,...Q,keys:{...$.keys,...Q.keys},baseUrls:{...$.baseUrls,...Q.baseUrls}};YQ(h(),JSON.stringify(z,null,2),"utf8")}function l(){let Q=process.cwd();d(I(Q,".tenicli.env")),d(I(Q,".env"));let Z=P(),$=process.env,z=$.TENICLI_MODEL||Z.activeModel||O[0].id,Y=O.find((W)=>W.id===z)?.provider||$.TENICLI_PROVIDER||"anthropic",X=qQ(Y,Z,$),K=Y==="openai"?"https://api.openai.com":"https://api.anthropic.com",q=$.TENICLI_BASE_URL||Z.baseUrls?.[Y]||K;return{provider:{type:Y,baseUrl:q,apiKey:X,model:z},maxTokens:parseInt($.TENICLI_MAX_TOKENS||"8192"),systemPrompt:WQ(Q),cwd:Q}}function qQ(Q,Z,$){if(Q==="anthropic")return $.TENICLI_API_KEY||$.ANTHROPIC_API_KEY||Z.keys?.anthropic||"";if(Q==="openai")return $.TENICLI_API_KEY||$.OPENAI_API_KEY||Z.keys?.openai||"";return $.TENICLI_API_KEY||""}function d(Q){try{if(!F(Q))return;for(let Z of b(Q,"utf8").split(`
3
+ `)){let $=Z.trim();if(!$||$.startsWith("#"))continue;let z=$.indexOf("=");if(z===-1)continue;let V=$.slice(0,z).trim(),Y=$.slice(z+1).trim();if(Y.startsWith('"')&&Y.endsWith('"')||Y.startsWith("'")&&Y.endsWith("'"))Y=Y.slice(1,-1);if(!process.env[V])process.env[V]=Y}}catch{}}function WQ(Q){for(let Z of[I(Q,"TENICLI.md"),I(x(),"TENICLI.md")])if(F(Z))return b(Z,"utf8");return JQ}var JQ=`You are TeniCLI, a fast AI coding assistant in the terminal.
4
4
 
5
5
  TOOLS: read/write files, execute commands, search code, list directories.
6
6
 
@@ -11,9 +11,9 @@ RULES:
11
11
  - The user may write in Vietnamese — respond in the same language they use.
12
12
  - Write production-quality code matching the project's style.`;async function*y(Q,Z,$,z,V){if(Q.type==="openai")yield*_Q(Q,Z,$,z,V);else yield*NQ(Q,Z,$,z,V)}async function*NQ(Q,Z,$,z,V){let Y=`${Q.baseUrl.replace(/\/$/,"")}/v1/messages`,X={model:Q.model,max_tokens:V,system:$,messages:Z,stream:!0};if(z.length)X.tools=z;let K=await a(Y,X,{"anthropic-version":"2023-06-01","x-api-key":Q.apiKey,authorization:`Bearer ${Q.apiKey}`});for await(let q of c(K))switch(q.type){case"message_start":if(q.message?.usage)yield{type:"usage",input:q.message.usage.input_tokens||0,output:0};break;case"content_block_start":if(q.content_block?.type==="text")yield{type:"text",text:""};else if(q.content_block?.type==="tool_use")yield{type:"tool_start",id:q.content_block.id,name:q.content_block.name};break;case"content_block_delta":if(q.delta?.type==="text_delta")yield{type:"text",text:q.delta.text};else if(q.delta?.type==="input_json_delta")yield{type:"tool_input",partial:q.delta.partial_json};break;case"content_block_stop":yield{type:"tool_end"};break;case"message_delta":if(q.usage)yield{type:"usage",input:0,output:q.usage.output_tokens||0};yield{type:"done",stopReason:q.delta?.stop_reason||"end_turn"};break}}async function*_Q(Q,Z,$,z,V){let Y=`${Q.baseUrl.replace(/\/$/,"")}/v1/chat/completions`,X=BQ(Z,$),K=z.map((_)=>({type:"function",function:{name:_.name,description:_.description,parameters:_.input_schema}})),q={model:Q.model,max_tokens:V,messages:X,stream:!0,stream_options:{include_usage:!0}};if(K.length)q.tools=K;let W=await a(Y,q,{authorization:`Bearer ${Q.apiKey}`}),B=new Map;for await(let _ of c(W)){let N=_.choices?.[0];if(!N){if(_.usage)yield{type:"usage",input:_.usage.prompt_tokens||0,output:_.usage.completion_tokens||0};continue}let j=N.delta||{};if(j.content)yield{type:"text",text:j.content};if(j.tool_calls)for(let R of j.tool_calls){if(R.id)B.set(R.index,{id:R.id,name:R.function?.name||"",args:""}),yield{type:"tool_start",id:R.id,name:R.function?.name||""};if(R.function?.arguments){let m=B.get(R.index);if(m)m.args+=R.function.arguments;yield{type:"tool_input",partial:R.function.arguments}}}if(N.finish_reason){for(let[,R]of B)yield{type:"tool_end"};yield{type:"done",stopReason:N.finish_reason==="tool_calls"?"tool_use":N.finish_reason}}}}function BQ(Q,Z){let $=[{role:"system",content:Z}];for(let z of Q)if(z.role==="user")if(typeof z.content==="string")$.push({role:"user",content:z.content});else{let V=z.content;for(let Y of V)if(Y.type==="tool_result")$.push({role:"tool",tool_call_id:Y.tool_use_id,content:Y.content||""});else $.push({role:"user",content:Y.text||""})}else if(typeof z.content==="string")$.push({role:"assistant",content:z.content});else{let V=z.content,Y=V.filter((K)=>K.type==="tool_use"),X=V.filter((K)=>K.type==="text").map((K)=>K.text).join("");if(Y.length)$.push({role:"assistant",content:X||null,tool_calls:Y.map((K)=>({id:K.id,type:"function",function:{name:K.name,arguments:JSON.stringify(K.input||{})}}))});else $.push({role:"assistant",content:X})}return $}async function a(Q,Z,$){let z=await fetch(Q,{method:"POST",headers:{"content-type":"application/json",...$},body:JSON.stringify(Z)});if(!z.ok){let V=await z.text();throw Error(`API ${z.status}: ${V.slice(0,300)}`)}return z}async function*c(Q){let Z=Q.body.getReader(),$=new TextDecoder,z="";while(!0){let{done:V,value:Y}=await Z.read();if(V)break;z+=$.decode(Y,{stream:!0});let X=z.split(`
13
13
  `);z=X.pop();for(let K of X)if(K.startsWith("data: ")){let q=K.slice(6).trim();if(q==="[DONE]")return;try{yield JSON.parse(q)}catch{}}}}import{readFileSync as g,writeFileSync as t,existsSync as w,readdirSync as s,statSync as e,mkdirSync as HQ}from"fs";import{resolve as UQ,relative as S,join as QQ,dirname as AQ}from"path";var n=(Q)=>`\x1B[${Q}m`,T=(Q,Z)=>($)=>`${n(Q)}${$}${n(Z)}`,U=(Q)=>(Z)=>`\x1B[38;5;${Q}m${Z}\x1B[39m`,G={bold:T("1","22"),dim:T("2","22"),italic:T("3","23"),under:T("4","24"),blue:U(111),purple:U(141),green:U(149),yellow:U(179),pink:U(210),cyan:U(117),gray:U(60),text:U(146),orange:U(215)};var J={prompt:G.blue("❯"),ai:G.purple("◆"),tool:G.yellow("⚙"),ok:G.green("✓"),err:G.pink("✗"),warn:G.yellow("⚠"),arrow:G.gray("→"),dot:G.gray("•"),spinner:["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"]};function RQ(){let Q=[" ██ ██ ","██████████","███ ██ █","██████████","██████████"," ██ ██ ██ "],Z={T:["█████"," █ "," █ "," █ "," █ "],E:["████ ","█ ","███ ","█ ","████ "],N:["█ █ ","██ █ ","█ ██ ","█ █ ","█ █ "],I:["███"," █ "," █ "," █ ","███"],space:[" "," "," "," "," "],C:[" ███","█ ","█ ","█ "," ███"],L:["█ ","█ ","█ ","█ ","████"]},$=[Z.T,Z.E,Z.N,Z.I,Z.space,Z.C,Z.L,Z.I],z=["","","","",""];for(let X=0;X<5;X++)z[X]=$.map((K)=>K[X]).join(" ");let V=Q.map((X)=>G.cyan(X.padEnd(14," "))),Y=[" ".repeat(z[0].length),...z].map((X)=>G.blue(X));return V.map((X,K)=>`${X} ${Y[K]||""}`).join(`
14
- `)}var H={h:"─",v:"│",tl:"╭",tr:"╮",bl:"╰",br:"╯",line:(Q)=>"─".repeat(Q)};function v(Q,Z=60){let $=(z,V)=>{let Y=z.replace(/\x1b\[[0-9;]*m/g,""),X=V-Y.length;return X>0?z+" ".repeat(X):z};console.log(G.gray(` ${H.tl}${H.line(Z)}${H.tr}`));for(let z of Q)console.log(G.gray(` ${H.v}`)+` ${$(z,Z-2)} `+G.gray(H.v));console.log(G.gray(` ${H.bl}${H.line(Z)}${H.br}`))}function r(){console.clear(),console.log(),console.log(RQ()),console.log(),v([G.gray("type to chat")+` ${J.dot} `+G.gray("/help for commands")+` ${J.dot} `+G.gray("v0.1.0")],60),console.log()}class k{i=0;timer=null;msg;constructor(Q="Thinking"){this.msg=Q}start(){return this.timer=setInterval(()=>{process.stdout.write(`\x1B[2K\r ${G.blue(J.spinner[this.i%J.spinner.length])} ${G.gray(this.msg)}`),this.i++},80),this}stop(){if(this.timer)clearInterval(this.timer),this.timer=null;process.stdout.write("\x1B[2K\r")}}function A(Q){return new Promise((Z,$)=>{process.stdout.write(Q);let z=[],V=(X)=>{if(X[0]===3)process.stdout.write(`
15
- `),process.exit(0);if(X[0]===4){Y(),$(Error("EOF"));return}z.push(X);let K=Buffer.concat(z).toString("utf8"),q=K.indexOf(`
16
- `);if(q!==-1)Y(),Z(K.slice(0,q).replace(/\r$/,""))},Y=()=>{process.stdin.removeListener("data",V)};process.stdin.setEncoding("utf8"),process.stdin.on("data",V),process.stdin.resume()})}async function i(){let Q=[],Z=!0;while(!0){let $=Z?`
14
+ `)}var H={h:"─",v:"│",tl:"╭",tr:"╮",bl:"╰",br:"╯",line:(Q)=>"─".repeat(Q)};function v(Q,Z=60){let $=(z,V)=>{let Y=z.replace(/\x1b\[[0-9;]*m/g,""),X=V-Y.length;return X>0?z+" ".repeat(X):z};console.log(G.gray(` ${H.tl}${H.line(Z)}${H.tr}`));for(let z of Q)console.log(G.gray(` ${H.v}`)+` ${$(z,Z-2)} `+G.gray(H.v));console.log(G.gray(` ${H.bl}${H.line(Z)}${H.br}`))}function r(){console.clear(),console.log(),console.log(RQ()),console.log(),v([G.gray("type to chat")+` ${J.dot} `+G.gray("/help for commands")+` ${J.dot} `+G.gray("v0.1.0")],60),console.log()}class k{i=0;timer=null;msg;constructor(Q="Thinking"){this.msg=Q}start(){return this.timer=setInterval(()=>{process.stdout.write(`\x1B[2K\r ${G.blue(J.spinner[this.i%J.spinner.length])} ${G.gray(this.msg)}`),this.i++},80),this}stop(){if(this.timer)clearInterval(this.timer),this.timer=null;process.stdout.write("\x1B[2K\r")}}function A(Q){return new Promise((Z,$)=>{process.stdout.write(Q);let z="",V=(X)=>{let K=typeof X==="string"?X:X.toString("utf8");if(K.charCodeAt(0)===3)process.stdout.write(`
15
+ `),process.exit(0);if(K.charCodeAt(0)===4){Y(),$(Error("EOF"));return}z+=K;let q=z.indexOf(`
16
+ `);if(q!==-1)Y(),Z(z.slice(0,q).replace(/\r$/,""))},Y=()=>{process.stdin.removeListener("data",V)};if(!process.stdin.readableEncoding)process.stdin.setEncoding("utf8");process.stdin.on("data",V),process.stdin.resume()})}async function i(){let Q=[],Z=!0;while(!0){let $=Z?`
17
17
  ${G.gray(H.tl+H.line(3))} ${J.prompt} `:` ${G.gray(H.v)} `,z=await A($);if(Z=!1,z.endsWith("\\"))Q.push(z.slice(0,-1));else{Q.push(z);break}}return Q.join(`
18
18
  `)}async function f(Q,Z){console.log(`
19
19
  ${G.bold(Q)}`),Z.forEach(($,z)=>{let V=G.blue(` ${z+1}.`),Y=$.desc?G.gray(` (${$.desc})`):"";console.log(`${V} ${$.label}${Y}`)});while(!0){let $=await A(`
@@ -64,7 +64,7 @@ ${G.bold("IN-CHAT")}
64
64
  `)}async function wQ(Q,Z){switch(Q.toLowerCase().split(" ")[0]){case"/exit":case"/quit":case"/q":console.log(`
65
65
  ${G.gray("Bye!")} \uD83D\uDC4B
66
66
  `),process.exit(0);case"/clear":return Z.clear(),C.clear(),console.log(` ${J.ok} Conversation cleared`),!0;case"/compact":return await Z.compact(),!0;case"/diff":{let $=C.getChanges();if($.length===0)console.log(` ${G.gray("No files changed in this session.")}`);else{console.log(`
67
- ${G.bold("Files changed this session:")}`);for(let z of $){let V=VQ(Z.cfg.cwd,z.path),Y=z.isNew?G.green("[NEW]"):G.yellow("[MOD]");console.log(` ${Y} ${G.cyan(V)} ${G.gray(`(${z.lines} lines)`)}`)}console.log(` ${G.gray(`total: ${$.length} files`)}`)}return!0}case"/undo":{let $=C.undo();if(!$)console.log(` ${G.gray("Nothing to undo.")}`);else{let z=VQ(Z.cfg.cwd,$.path);if($.restored)console.log(` ${J.ok} Restored: ${G.cyan(z)}`);else console.log(` ${J.ok} Deleted (was new): ${G.cyan(z)}`)}return!0}case"/init":{let $=LQ(Z.cfg.cwd,"TENICLI.md");if(PQ($))console.log(` ${J.warn} TENICLI.md already exists.`);else FQ($,hQ,"utf8"),console.log(` ${J.ok} Created ${G.cyan("TENICLI.md")}`);return!0}case"/mode":{Z.autoMode=!Z.autoMode;let $=Z.autoMode?G.yellow("auto"):G.green("ask");return console.log(` ${J.ok} Mode: ${$} ${G.gray(Z.autoMode?"(tools run without asking)":"(confirm write/exec)")}`),!0}case"/cost":{let $=Z.stats;return console.log(` ${J.ai} ${G.blue(String($.input))}↑ input ${G.blue(String($.output))}↓ output ${G.gray(`(${Z.messageCount} msgs)`)}`),!0}case"/model":{let $=O.map((V)=>({label:`${V.name} ${Z.cfg.provider.model===V.id?G.green("●"):""}`,desc:`${V.provider} • ${V.speed}`}));$.push({label:"Custom model...",desc:"type model ID"});let z=await f("Select model",$);if(z<O.length){let V=O[z];Z.cfg.provider.model=V.id,Z.cfg.provider.type=V.provider;let Y=P(),X=V.provider==="openai"?process.env.OPENAI_API_KEY||Y.keys?.openai||"":process.env.ANTHROPIC_API_KEY||Y.keys?.anthropic||"";if(X)Z.cfg.provider.apiKey=X;if(!Y.baseUrls?.[V.provider])Z.cfg.provider.baseUrl=V.provider==="openai"?"https://api.openai.com":"https://api.anthropic.com";L({activeModel:V.id}),console.log(` ${J.ok} Model: ${G.blue(V.name)}`)}else{let V=await A(` ${G.gray("model ID")} ${G.blue("❯")} `);if(V.trim())Z.cfg.provider.model=V.trim(),L({activeModel:V.trim()}),console.log(` ${J.ok} Model: ${G.blue(V.trim())}`)}return!0}case"/auth":{let $=await f("Provider",[{label:"Anthropic",desc:"Claude models"},{label:"OpenAI",desc:"GPT models"},{label:"Custom",desc:"Anthropic-compatible proxy"}]),V=["anthropic","openai","anthropic"][$],Y=await A(` ${G.gray("API Key")} ${G.blue("❯")} `);if(!Y.trim())return console.log(` ${J.warn} Cancelled`),!0;let X={[V]:Y.trim()},K={};if($===2){let q=await A(` ${G.gray("Base URL")} ${G.blue("❯")} `);if(q.trim())K[V]=q.trim()}if(L({keys:X,baseUrls:K}),Z.cfg.provider.apiKey=Y.trim(),Z.cfg.provider.type=V,K[V])Z.cfg.provider.baseUrl=K[V];return console.log(` ${J.ok} ${V} key saved to ~/.tenicli/config.json`),!0}case"/help":return console.log(`
67
+ ${G.bold("Files changed this session:")}`);for(let z of $){let V=VQ(Z.cfg.cwd,z.path),Y=z.isNew?G.green("[NEW]"):G.yellow("[MOD]");console.log(` ${Y} ${G.cyan(V)} ${G.gray(`(${z.lines} lines)`)}`)}console.log(` ${G.gray(`total: ${$.length} files`)}`)}return!0}case"/undo":{let $=C.undo();if(!$)console.log(` ${G.gray("Nothing to undo.")}`);else{let z=VQ(Z.cfg.cwd,$.path);if($.restored)console.log(` ${J.ok} Restored: ${G.cyan(z)}`);else console.log(` ${J.ok} Deleted (was new): ${G.cyan(z)}`)}return!0}case"/init":{let $=LQ(Z.cfg.cwd,"TENICLI.md");if(PQ($))console.log(` ${J.warn} TENICLI.md already exists.`);else FQ($,bQ,"utf8"),console.log(` ${J.ok} Created ${G.cyan("TENICLI.md")}`);return!0}case"/mode":{Z.autoMode=!Z.autoMode;let $=Z.autoMode?G.yellow("auto"):G.green("ask");return console.log(` ${J.ok} Mode: ${$} ${G.gray(Z.autoMode?"(tools run without asking)":"(confirm write/exec)")}`),!0}case"/cost":{let $=Z.stats;return console.log(` ${J.ai} ${G.blue(String($.input))}↑ input ${G.blue(String($.output))}↓ output ${G.gray(`(${Z.messageCount} msgs)`)}`),!0}case"/model":{let $=O.map((V)=>({label:`${V.name} ${Z.cfg.provider.model===V.id?G.green("●"):""}`,desc:`${V.provider} • ${V.speed}`}));$.push({label:"Custom model...",desc:"type model ID"});let z=await f("Select model",$);if(z<O.length){let V=O[z];Z.cfg.provider.model=V.id,Z.cfg.provider.type=V.provider;let Y=P(),X=V.provider==="openai"?process.env.OPENAI_API_KEY||Y.keys?.openai||"":process.env.ANTHROPIC_API_KEY||Y.keys?.anthropic||"";if(X)Z.cfg.provider.apiKey=X;if(!Y.baseUrls?.[V.provider])Z.cfg.provider.baseUrl=V.provider==="openai"?"https://api.openai.com":"https://api.anthropic.com";L({activeModel:V.id}),console.log(` ${J.ok} Model: ${G.blue(V.name)}`)}else{let V=await A(` ${G.gray("model ID")} ${G.blue("❯")} `);if(V.trim())Z.cfg.provider.model=V.trim(),L({activeModel:V.trim()}),console.log(` ${J.ok} Model: ${G.blue(V.trim())}`)}return!0}case"/auth":{let $=await f("Provider",[{label:"Anthropic",desc:"Claude models"},{label:"OpenAI",desc:"GPT models"},{label:"Custom",desc:"Anthropic-compatible proxy"}]),V=["anthropic","openai","anthropic"][$],Y=await A(` ${G.gray("API Key")} ${G.blue("❯")} `);if(!Y.trim())return console.log(` ${J.warn} Cancelled`),!0;let X={[V]:Y.trim()},K={};if($===2){let q=await A(` ${G.gray("Base URL")} ${G.blue("❯")} `);if(q.trim())K[V]=q.trim()}if(L({keys:X,baseUrls:K}),Z.cfg.provider.apiKey=Y.trim(),Z.cfg.provider.type=V,K[V])Z.cfg.provider.baseUrl=K[V];return console.log(` ${J.ok} ${V} key saved to ~/.tenicli/config.json`),!0}case"/help":return console.log(`
68
68
  ${G.bold("Commands")}
69
69
  ${G.blue("/model")} Select AI model
70
70
  ${G.blue("/auth")} Set API key
@@ -79,9 +79,9 @@ ${G.bold("IN-CHAT")}
79
79
  ${G.blue("/exit")} Quit
80
80
  ${G.gray("\\\\")} Continue on next line`),!0;case"/update":{console.log(`
81
81
  ${J.tool} ${G.yellow("Checking for updates...")}`);try{let{execSync:$}=await import("child_process"),z=$("npm i -g tenicli@latest 2>&1",{encoding:"utf8"});console.log(` ${J.ok} ${G.green("Updated!")} Restart teni to use the new version.`),console.log(G.gray(` ${z.trim().split(`
82
- `).pop()}`))}catch($){D(`Update failed: ${$.message}`)}return!0}default:return console.log(` ${J.warn} Unknown: ${Q.split(" ")[0]} — try /help`),!0}}async function bQ(){let Q=kQ(process.argv.slice(2)),Z=l();if(Q.model)Z.provider.model=Q.model;if(Q.baseUrl)Z.provider.baseUrl=Q.baseUrl;let $=new u(Z);if(Q.print&&Q.prompt){if(!Z.provider.apiKey)D("No API key. Run: teni then /auth"),process.exit(1);await $.send(Q.prompt),process.exit(0)}r();let z=O.find((X)=>X.id===Z.provider.model)?.name||Z.provider.model,V=$.autoMode?G.yellow("auto"):G.green("ask"),Y=[`${G.gray("model")} ${G.blue(z)} ${G.gray("mode")} ${V} ${G.gray("cwd")} ${G.cyan(Z.cwd)}`];if(!Z.provider.apiKey)Y.push(""),Y.push(`${J.warn} ${G.yellow("No API key configured. Run /auth to set one.")}`);if(v(Y,60),console.log(),Q.prompt){if(console.log(` ${J.prompt} ${Q.prompt}`),Z.provider.apiKey)await $.send(Q.prompt)}while(!0)try{let K=(await i()).trim();if(!K)continue;if(K.startsWith("/")){await wQ(K,$);continue}if(!$.cfg.provider.apiKey){console.log(` ${J.warn} ${G.yellow("No API key. Run /auth first.")}`);continue}await $.send(K)}catch(X){if(X.message==="EOF")console.log(`
82
+ `).pop()}`))}catch($){D(`Update failed: ${$.message}`)}return!0}default:return console.log(` ${J.warn} Unknown: ${Q.split(" ")[0]} — try /help`),!0}}async function hQ(){let Q=kQ(process.argv.slice(2)),Z=l();if(Q.model)Z.provider.model=Q.model;if(Q.baseUrl)Z.provider.baseUrl=Q.baseUrl;let $=new u(Z);if(Q.print&&Q.prompt){if(!Z.provider.apiKey)D("No API key. Run: teni then /auth"),process.exit(1);await $.send(Q.prompt),process.exit(0)}r();let z=O.find((X)=>X.id===Z.provider.model)?.name||Z.provider.model,V=$.autoMode?G.yellow("auto"):G.green("ask"),Y=[`${G.gray("model")} ${G.blue(z)} ${G.gray("mode")} ${V} ${G.gray("cwd")} ${G.cyan(Z.cwd)}`];if(!Z.provider.apiKey)Y.push(""),Y.push(`${J.warn} ${G.yellow("No API key configured. Run /auth to set one.")}`);if(v(Y,60),console.log(),Q.prompt){if(console.log(` ${J.prompt} ${Q.prompt}`),Z.provider.apiKey)await $.send(Q.prompt)}while(!0)try{let K=(await i()).trim();if(!K)continue;if(K.startsWith("/")){await wQ(K,$);continue}if(!$.cfg.provider.apiKey){console.log(` ${J.warn} ${G.yellow("No API key. Run /auth first.")}`);continue}await $.send(K)}catch(X){if(X.message==="EOF")console.log(`
83
83
  ${G.gray("Bye!")} \uD83D\uDC4B
84
- `),process.exit(0);D(X.message)}}bQ().catch((Q)=>{D(Q.message),process.exit(1)});var hQ=`# Project Instructions
84
+ `),process.exit(0);D(X.message)}}hQ().catch((Q)=>{D(Q.message),process.exit(1)});var bQ=`# Project Instructions
85
85
 
86
86
  ## Overview
87
87
  Describe your project here so the AI understands the context.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tenicli",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Lightweight AI coding CLI — fast, compact, multi-provider",
5
5
  "type": "module",
6
6
  "bin": {