pushai 0.1.0 → 0.1.2

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.
@@ -1,17 +1,17 @@
1
1
 
2
2
  
3
- > pushai@0.1.0 build /Users/holiday/Desktop/pushai/v2/apps/cli
3
+ > pushai@0.1.2 build /Users/holiday/Desktop/pushai/apps/cli
4
4
  > tsup src/index.ts --format esm --clean --minify
5
5
 
6
6
  CLI Building entry: src/index.ts
7
7
  CLI Using tsconfig: tsconfig.json
8
8
  CLI tsup v8.5.1
9
- CLI Using tsup config: /Users/holiday/Desktop/pushai/v2/apps/cli/tsup.config.ts
9
+ CLI Using tsup config: /Users/holiday/Desktop/pushai/apps/cli/tsup.config.ts
10
10
  CLI Target: esnext
11
11
  CLI Cleaning output folder
12
12
  ESM Build start
13
- ESM dist/index.mjs 3.88 KB
13
+ ESM dist/index.mjs 10.17 KB
14
14
  ESM ⚡️ Build success in 11ms
15
15
  DTS Build start
16
- DTS ⚡️ Build success in 763ms
16
+ DTS ⚡️ Build success in 932ms
17
17
  DTS dist/index.d.mts 13.00 B
package/README.md CHANGED
@@ -77,7 +77,3 @@ pai commit
77
77
  - **OpenAI:** `gpt-4o`, `gpt-4o-mini`.
78
78
  - **HuggingFace:** `Llama 3`, `Mistral`, etc.
79
79
  - **Local/Custom:** Anything OpenAI-compatible (Ollama, Groq).
80
-
81
- ---
82
-
83
- Built with ❤️ by [Holiday](https://github.com/thelastofinusa)
package/dist/index.mjs CHANGED
@@ -1,34 +1,50 @@
1
1
  #!/usr/bin/env node
2
- import{Command as oe}from"commander";import g from"chalk";import{confirm as L}from"@inquirer/prompts";import k from"os";import x from"path";import l from"fs";var I=()=>{let e=h();if(!l.existsSync(e))return{};try{let o=l.readFileSync(e,"utf-8");return JSON.parse(o)}catch{return{}}},O=()=>{try{let e=k.homedir(),o=x.join(e,".config","pushai");return l.existsSync(o)?(l.rmSync(o,{recursive:!0,force:!0}),!0):!1}catch(e){return console.error("Failed to reset config:",e),!1}},T=e=>{try{let o=h();l.writeFileSync(o,JSON.stringify(e,null,2),"utf-8")}catch(o){console.error("Failed to write config file:",o)}};function h(){let e=x.join(k.homedir(),".config","pushai");return l.existsSync(e)||l.mkdirSync(e,{recursive:!0}),x.join(e,"config.json")}async function K(){try{if(await L({message:g.red("Delete all PushAI configurations and API keys?"),default:!1})){let o=O();console.log(o?g.green(`
2
+ import{Command as se}from"commander";import h from"chalk";import{confirm as J}from"@inquirer/prompts";import K from"os";import b from"path";import l from"fs";import A from"keytar";var E="pushai",S="api-key";async function R(){let e=y(),o={};if(l.existsSync(e))try{o=JSON.parse(l.readFileSync(e,"utf-8"))}catch{}let r=await A.getPassword(E,S);return r&&(o.apiKey=r),o}async function D(e){let o=y(),{apiKey:r,...i}=e;r&&await A.setPassword(E,S,r);let n={};if(l.existsSync(o))try{n=JSON.parse(l.readFileSync(o,"utf-8"))}catch{}let a={...n,...i};l.writeFileSync(o,JSON.stringify(a,null,2),"utf-8")}async function _(){try{let e=K.homedir(),o=b.join(e,".config","pushai"),r=!1;return l.existsSync(o)&&(l.rmSync(o,{recursive:!0,force:!0}),r=!0),await A.deletePassword(E,S),r}catch(e){return console.error("Failed to reset config:",e),!1}}function y(){let e=b.join(K.homedir(),".config","pushai");return l.existsSync(e)||l.mkdirSync(e,{recursive:!0}),b.join(e,"config.json")}async function L(){try{if(!await J({message:h.red("Delete all PushAI configurations and API keys?"),default:!1})){console.log(h.dim(`
3
+ Operation cancelled.
4
+ `));return}let o=await _();console.log(o?h.green(`
3
5
  \u2714 Successfully removed the PushAI directory.
4
- `):g.dim(`
6
+ `):h.dim(`
5
7
  No configuration directory found. Nothing to delete.
6
- `))}else console.log(g.dim(`
7
- Operation cancelled.
8
- `))}catch(e){if(e.name==="ExitPromptError"){console.log(g.dim(`
8
+ `))}catch(e){if(e.name==="ExitPromptError"){console.log(h.dim(`
9
9
  Operation cancelled.
10
- `));return}throw e}}import a from"chalk";import{select as _,input as N,password as Q,Separator as J}from"@inquirer/prompts";import{GoogleGenerativeAI as q}from"@google/generative-ai";var m=class{apiKey;model;constructor(o,n){this.apiKey=o,this.model=n}};var d=e=>`You are an expert developer. Analyze the following "git diff" and generate a single-line commit message following the Conventional Commits format. Return ONLY the message. No markdown, no quotes.
10
+ `));return}throw e}}import s from"chalk";import{select as F,input as B,password as Z,Separator as X}from"@inquirer/prompts";import{GoogleGenerativeAI as Q}from"@google/generative-ai";var d=class{apiKey;model;constructor(o,r){this.apiKey=o,this.model=r}};var u=e=>`You are a Senior Software Engineer. Your task is to write a concise, technical, and impactful commit message based on a git diff.
11
+
12
+ ### CONSTRAINTS
13
+ - Format: <type>(<scope>): <description>
14
+ - Style: Conventional Commits (feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert).
15
+ - Length: Maximum 100 characters.
16
+ - Casing: Lowercase only.
17
+ - Content: Focus on the "why" or the "what", not the "how". Avoid generic words like "updates" or "changes".
18
+ - Output: Return ONLY the raw string. No quotes, no markdown, no explanations.
11
19
 
12
- Rules:
13
- 1. Use lowercase.
14
- 2. Max 50 characters.
15
- 3. Format: type(scope): description.
20
+ ### TECHNICAL GUIDELINES
21
+ - If the diff involves UI/CSS, use the "style" or "feat" type.
22
+ - If the diff involves Web3/Contract logic or API integration, use a specific scope (e.g., "wallet", "chain").
23
+ - If multiple changes are present, focus on the most significant one.
16
24
 
17
- Diff: ${e}`;var y=class extends m{async generateCommitMessage(o){return(await new q(this.apiKey).getGenerativeModel({model:this.model}).generateContent(d(o))).response.text().trim().replace(/['"]/g,"")}};import{InferenceClient as z}from"@huggingface/inference";var v=class extends m{async generateCommitMessage(o){let n=new z(this.apiKey,{endpointUrl:"https://router.huggingface.co/v1"});try{return((await n.chatCompletion({model:this.model,messages:[{role:"user",content:d(o)}],max_tokens:100,temperature:.2})).choices[0]?.message.content||"").trim().replace(/['"]/g,"").replace(/^commit:\s*/i,"")}catch(t){throw new Error(`Hugging Face Error: ${t.message}`)}}};import H from"openai";var w=class extends m{baseUrl;constructor(o,n,t){super(o,n),this.baseUrl=t}async generateCommitMessage(o){let n=new H({apiKey:this.apiKey,baseURL:this.baseUrl||void 0});try{return(await n.chat.completions.create({model:this.model,messages:[{role:"user",content:d(o)}],temperature:.7,max_tokens:100})).choices[0]?.message.content?.trim().replace(/['"]/g,"")||""}catch(t){throw new Error(`OpenAI Error: ${t.message}`)}}};var A=[{name:"Gemini (Google)",value:"gemini",models:[{name:"Gemini 1.5 Flash (Recommended)",value:"gemini-1.5-flash"},{name:"Gemini 1.5 Pro",value:"gemini-1.5-pro"}]},{name:"OpenAI (GPT-4)",value:"openai",models:[{name:"GPT-4o (Recommended)",value:"gpt-4o"},{name:"GPT-4o mini",value:"gpt-4o-mini"},{name:"GPT-4 Turbo",value:"gpt-4-turbo"}]},{name:"HuggingFace (Open Source)",value:"huggingface",models:[{name:"Llama 3 8B Instruct (Recommended)",value:"meta-llama/Meta-Llama-3-8B-Instruct"},{name:"Mistral 7B v0.3",value:"mistralai/Mistral-7B-Instruct-v0.3"},{name:"Qwen 2 7B",value:"Qwen/Qwen2-7B-Instruct"}]},{name:"Custom (Ollama/Local)",value:"custom",models:[{name:"Llama 3 (Ollama Default)",value:"llama3"},{name:"Mistral",value:"mistral"},{name:"Phi-3",value:"phi3"}]}];function D(e){switch(e.provider){case"gemini":return new y(e.apiKey,e.model);case"huggingface":return new v(e.apiKey,e.model);case"openai":case"custom":return new w(e.apiKey,e.model,e.baseUrl);default:throw new Error(`Provider ${e.provider} is not supported.`)}}async function P(){console.log(a.blue.bold(`
18
- \u{1F680} PushAI Configuration
19
- `));try{let e=await _({message:"Select your AI provider:",choices:A.map(i=>({name:i.name,value:i.value}))}),o=A.find(i=>i.value===e),n=await Q({message:`Enter your ${e} API Key:`,validate:i=>i.length===0?"Key is required":!0}),t=await _({message:"Select a model:",choices:[...o?.models||[],new J,{name:"Custom model ID",value:"custom_id"}]});t==="custom_id"&&(t=await N({message:"Enter the custom model ID:",validate:i=>i.length===0?"Model ID is required":!0}));let s=await N({message:"Base URL (Optional, press Enter to skip):",default:""});T({provider:e,apiKey:n,model:t,baseUrl:s||void 0});let u=h();console.log(a.green(`
20
- \u2705 Configuration saved successfully!`)),console.log(a.dim("----------------------------------------")),console.log(`${a.bold("Provider:")} ${e}`),console.log(`${a.bold("Model: ")} ${t}`),console.log(`${a.bold("API Key: ")} ****${n.slice(-4)}`),console.log(a.dim("----------------------------------------")),console.log(a.dim(`File: ${u}
21
- `))}catch(e){if(e.name==="ExitPromptError"){console.log(a.dim(`
25
+ ### GIT DIFF TO ANALYZE:
26
+ ${e}`;var w=class extends d{async generateCommitMessage(o){return(await new Q(this.apiKey).getGenerativeModel({model:this.model}).generateContent(u(o))).response.text().trim().replace(/['"]/g,"")}};import{InferenceClient as W}from"@huggingface/inference";var v=class extends d{async generateCommitMessage(o){let r=new W(this.apiKey,{endpointUrl:"https://router.huggingface.co/v1"});try{return((await r.chatCompletion({model:this.model,messages:[{role:"user",content:u(o)}],max_tokens:100,temperature:.2})).choices[0]?.message.content||"").trim().replace(/['"]/g,"").replace(/^commit:\s*/i,"")}catch(i){throw new Error(`Hugging Face Error: ${i.message}`)}}};import V from"openai";var P=class extends d{baseUrl;constructor(o,r,i){super(o,r),this.baseUrl=i}async generateCommitMessage(o){let r=new V({apiKey:this.apiKey,baseURL:this.baseUrl||void 0});try{return(await r.chat.completions.create({model:this.model,messages:[{role:"user",content:u(o)}],temperature:.7,max_tokens:100})).choices[0]?.message.content?.trim().replace(/['"]/g,"")||""}catch(i){throw new Error(`OpenAI Error: ${i.message}`)}}};var $=[{name:"Gemini (Google)",value:"gemini",models:[{name:"Gemini 1.5 Flash (Recommended)",value:"gemini-1.5-flash"},{name:"Gemini 1.5 Pro",value:"gemini-1.5-pro"}]},{name:"OpenAI (GPT-4)",value:"openai",models:[{name:"GPT-4o (Recommended)",value:"gpt-4o"},{name:"GPT-4o mini",value:"gpt-4o-mini"},{name:"GPT-4 Turbo",value:"gpt-4-turbo"}]},{name:"HuggingFace (Open Source)",value:"huggingface",models:[{name:"Llama 3 8B Instruct (Recommended)",value:"meta-llama/Meta-Llama-3-8B-Instruct"},{name:"Mistral 7B v0.3",value:"mistralai/Mistral-7B-Instruct-v0.3"},{name:"Qwen 2 7B",value:"Qwen/Qwen2-7B-Instruct"}]},{name:"Custom (Ollama/Local)",value:"custom",models:[{name:"Llama 3 (Ollama Default)",value:"llama3"},{name:"Mistral",value:"mistral"},{name:"Phi-3",value:"phi3"}]}];function U(e){switch(e.provider){case"gemini":return Promise.resolve(new w(e.apiKey,e.model));case"huggingface":return Promise.resolve(new v(e.apiKey,e.model));case"openai":case"custom":return Promise.resolve(new P(e.apiKey,e.model,e.baseUrl));default:throw new Error(`Provider ${e.provider} is not supported.`)}}async function C(){console.log(s.blue.bold(`
27
+ PushAI Configuration
28
+ `));try{let e=await F({message:"Select your AI provider:",choices:$.map(m=>({name:m.name,value:m.value}))}),o=$.find(m=>m.value===e),r=await Z({message:`Enter your ${e} API Key:`,validate:m=>m.length===0?"Key is required":!0}),i=await F({message:"Select a model:",choices:[...o?.models||[],new X,{name:"Custom model ID",value:"custom_id"}]});i==="custom_id"&&(i=await B({message:"Enter the custom model ID:",validate:m=>m.length===0?"Model ID is required":!0}));let n=await B({message:"Base URL (Optional, press Enter to skip):",default:""});await D({provider:e,apiKey:r,model:i,baseUrl:n||void 0});let a=y();console.log(s.green(`
29
+ Configuration saved successfully!`)),console.log(s.dim("----------------------------------------")),console.log(`${s.bold("Provider:")} ${e}`),console.log(`${s.bold("Model: ")} ${i}`),console.log(`${s.bold("API Key: ")} ****${r.slice(-4)}`),console.log(s.dim("----------------------------------------")),console.log(s.dim(`File: ${a}
30
+ `)),console.log(s.cyan("Try running these commands:")),console.log(` ${s.white.bold("pai commit")} ${s.white("\u2192 Just the AI generation")}`),console.log(` ${s.white.bold("pai config")} ${s.white("\u2192 Change model or keys")}`),console.log(` ${s.white.bold("pai reset")} ${s.white("\u2192 Wipe all local settings")}
31
+ `)}catch(e){if(e.name==="ExitPromptError"){console.log(s.dim(`
22
32
  Setup cancelled.
23
- `));return}throw e}}import W from"ora";import r from"chalk";import V from"simple-git";import{confirm as X,input as Z,select as ee}from"@inquirer/prompts";import E from"chalk";function b(e){if(e.name==="ExitPromptError")return;e.message?.includes("API key not valid")||e.message?.includes("Authorization header")||[400,401,403].includes(e.status)?(console.log(E.red(`
24
- It looks like your API key/Token is invalid.`)),console.log(E.yellow("\u{1F449} Run `pai reset` to update your credentials."))):console.log(E.red(`
25
- ${e.message||"An unknown error occurred."}`))}import{simpleGit as Y}from"simple-git";var f=Y();async function M(){if(!await f.checkIsRepo())return{isRepo:!1};let o=await f.status();return(o.not_added.length>0||o.modified.length>0||o.deleted.length>0)&&await f.add("."),{isRepo:!0,diff:await f.diff(["--cached"])}}async function U(){await f.init()}var B=V();async function R(){try{let e=I();e.apiKey?console.log(r.dim(`Active provider: ${e.provider} \u2022 Model: ${e.model}`)):(await P(),Object.assign(e,I()));let o=await M();o.isRepo||(console.log(r.yellow("Git repository not found in the current directory.")),await X({message:"Initialize a new Git repository here?",default:!0})?(await U(),console.log(r.green("Git repository initialized successfully.")),o=await M()):(console.log(r.dim(`
26
- Command aborted. A Git repository is required to continue.`)),process.exit(0)));let n=o.diff;n||(console.log(r.red("There are no staged or unstaged changes to commit.")),process.exit(0));let t=W({color:"cyan"}),s="",u;try{t.start(r.blue("Generating commit message...")),u=D(e),s=await u.generateCommitMessage(n),t.succeed(r.green("Commit message generated."))}catch(c){t.fail(r.red.bold("Commit message generation failed.")),b(c),process.exit(1)}let i=!1;for(;!i;){let c="\u2500".repeat(Math.max(s.length+2,20));console.log(`
27
- ${r.cyan("\u250C"+c+"\u2510")}`),console.log(`${r.cyan("\u2502")} ${r.bold(s)} ${r.cyan("\u2502")}`),console.log(`${r.cyan("\u2514"+c+"\u2518")}
28
- `);let C=await ee({message:"Select how you want to continue:",choices:[{name:"Continue with Commit & Push",value:"accept"},{name:"Modify Commit Message",value:"edit"},{name:"Generate a Different Message",value:"regenerate"},{name:"Exit Without Pushing",value:"cancel"}]});if(C==="accept")i=!0;else if(C==="edit")s=await Z({message:"Refine commit message:",default:s}),i=!0;else if(C==="regenerate"){t.start(r.blue("Generating new message..."));try{s=await u.generateCommitMessage(n),t.succeed(r.green("New commit message generated."))}catch(j){t.fail(r.red(`Could not generate a new message: ${j.message}`))}}else console.log(r.dim(`
33
+ `));return}throw e}}import oe from"ora";import t from"chalk";import te from"simple-git";import{confirm as re,input as ie,select as ne}from"@inquirer/prompts";import G from"chalk";function M(e){if(e.name==="ExitPromptError")return;e.message?.includes("API key not valid")||e.message?.includes("Authorization header")||[400,401,403].includes(e.status)?(console.log(G.red(`
34
+ It looks like your API key/Token is invalid.`)),console.log(G.yellow("\u{1F449} Run `pai reset` to update your credentials."))):console.log(G.red(`
35
+ ${e.message||"An unknown error occurred."}`))}import{simpleGit as ee}from"simple-git";var g=ee();async function k(){if(!await g.checkIsRepo())return{isRepo:!1};let o=await g.status();return(o.not_added.length>0||o.modified.length>0||o.deleted.length>0)&&await g.add("."),{isRepo:!0,diff:await g.diff(["--cached"])}}async function j(){await g.init()}async function q(){try{return(await g.getRemotes()).length>0}catch{return!1}}var Y=te();async function I(e=!1){try{let o=await R();if(!o.apiKey||!o.provider||!o.model){await C(),Object.assign(o,await R());return}else{let c=o.provider.toUpperCase(),f=`${t.bgCyan.black.bold(` ${c} `)} ${t.dim("\u2022")} ${t.white(o.model)}`;console.log(`
36
+ ${t.cyan("\u25CF")} ${f}
37
+ `)}let r=await k();r.isRepo||(console.log(t.yellow("Git repository not found in the current directory.")),await re({message:"Initialize a new Git repository here?",default:!0})?(await j(),console.log(t.green("Git repository initialized successfully.")),r=await k()):(console.log(t.dim(`
38
+ Command aborted. A Git repository is required to continue.`)),process.exit(0)));let i=r.diff;i||(console.log(t.red("There are no staged or unstaged changes to commit.")),process.exit(0));let n=oe({color:"cyan"}),a="",m;try{n.start(t.blue("Generating commit message...")),m=await U(o),a=await m.generateCommitMessage(i),n.succeed(t.green("Commit message generated."))}catch(c){n.fail(t.red.bold("Commit message generation failed.")),M(c),process.exit(1)}let x=!1;for(;!x;){let c="\u2500".repeat(Math.max(a.length+2,20));console.log(`
39
+ ${t.cyan("\u250C"+c+"\u2510")}`),console.log(`${t.cyan("\u2502")} ${t.bold(a)} ${t.cyan("\u2502")}`),console.log(`${t.cyan("\u2514"+c+"\u2518")}
40
+ `);let f=await ne({message:"Select how you want to continue:",choices:[{name:"Continue with Commit & Push",value:"accept"},{name:"Modify Commit Message",value:"edit"},{name:"Generate a Different Message",value:"regenerate"},{name:"Exit Without Pushing",value:"cancel"}]});if(f==="accept")x=!0;else if(f==="edit")a=await ie({message:"Refine commit message:",default:a}),x=!0;else if(f==="regenerate"){n.start(t.blue("Generating new message..."));try{a=await m.generateCommitMessage(i),n.succeed(t.green("New commit message generated."))}catch(H){n.fail(t.red(`Could not generate a new message: ${H.message}`))}}else console.log(t.dim(`
29
41
  Process stopped. No commits or pushes were made.
30
- `)),process.exit(0)}try{t.start(r.blue("Pushing changes...")),await B.commit(s),await B.push(),t.succeed(r.green.bold("Repository updated and pushed successfully."))}catch(c){t.fail(r.red.bold("Push operation could not be completed.")),console.log(r.red(`
42
+ `)),process.exit(0)}if(e&&(console.log(t.yellow(`
43
+ [DRY RUN] No commits or pushes were made.
44
+ `)),console.log(t.dim(`Proposed commit message:
45
+ ${a}
46
+ `)),process.exit(0)),!e){await q()||(n.fail(t.red.bold("No Git remote found.")),console.log(t.yellow("Please add a remote (e.g., `git remote add origin <url>`) and try again.\n")),process.exit(1));try{n.start(t.blue("Pushing changes...")),await Y.commit(a),await Y.push(),n.succeed(t.green.bold("Repository updated and pushed successfully."))}catch(c){n.fail(t.red.bold("Push operation could not be completed.")),console.log(t.red(`
31
47
  Git reported an error: ${c.message}
32
- `)),process.exit(1)}}catch(e){e.name==="ExitPromptError"&&(console.log(r.dim(`
48
+ `)),process.exit(1)}}}catch(o){o.name==="ExitPromptError"&&(console.log(t.dim(`
33
49
  Exited by user request.
34
- `)),process.exit(0)),b(e),process.exit(1)}}var S="pushai",F="0.1.0",$="AI-powered CLI for effortless git commits and pushes";var p=new oe;p.name(S).description($).action(R);p.name(S).description($).version(F,"-v, --version","output the version number");p.command("commit").description("Stage changes, generate a message, and push").action(R);p.command("config").description("Configure AI providers and API keys").action(P);p.command("reset").description("Delete the local config.json file").action(K);p.parse();
50
+ `)),process.exit(0)),M(o),process.exit(1)}}var O="pushai",z="0.1.2",N="AI-powered CLI for effortless git commits and pushes";var p=new se;p.name(O).description(N).option("--dry-run","Generate commit message but do not commit or push").action(e=>I(e.dryRun));p.name(O).description(N).version(z,"-v, --version","output the version number");p.action(()=>I(!1));p.command("commit").description("Stage changes, generate a message, and push").option("--dry-run","Generate commit message but do not commit or push").action(e=>I(e.dryRun));p.command("config").description("Configure AI providers and API keys").action(C);p.command("reset").description("Delete the local config.json file").action(L);p.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pushai",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "AI-powered CLI for effortless git commits and pushes",
5
5
  "bin": {
6
6
  "pai": "./dist/index.mjs"
@@ -12,7 +12,16 @@
12
12
  "pushout": "npm publish",
13
13
  "pushout-inc": "npm version patch --no-git-tag-version && pnpm pushout"
14
14
  },
15
- "keywords": [],
15
+ "keywords": [
16
+ "cli",
17
+ "git",
18
+ "push",
19
+ "ai",
20
+ "commit",
21
+ "message",
22
+ "generate",
23
+ "robotics"
24
+ ],
16
25
  "author": {
17
26
  "name": "Holiday",
18
27
  "url": "https://thelastofinusa.vercel.app"
@@ -25,12 +34,14 @@
25
34
  "chalk": "^5.6.2",
26
35
  "commander": "^14.0.3",
27
36
  "conf": "^15.1.0",
37
+ "keytar": "^7.9.0",
28
38
  "openai": "^6.37.0",
29
39
  "ora": "^9.4.0",
30
40
  "simple-git": "^3.36.0",
31
41
  "zod": "^3.25.76"
32
42
  },
33
43
  "devDependencies": {
44
+ "@types/keytar": "^4.4.2",
34
45
  "@types/node": "^25.1.0",
35
46
  "@types/ora": "^3.2.0",
36
47
  "tsup": "^8.5.1",