pushai 0.0.5 → 0.1.1
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/.turbo/turbo-build.log +17 -0
- package/README.md +79 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.mjs +34 -0
- package/package.json +29 -21
- package/dist/pai.d.ts +0 -1
- package/dist/pai.js +0 -3
- package/dist/pai.js.map +0 -1
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
> pushai@0.1.0 build /Users/holiday/Desktop/pushai/v2/apps/cli
|
|
4
|
+
> tsup src/index.ts --format esm --clean --minify
|
|
5
|
+
|
|
6
|
+
[34mCLI[39m Building entry: src/index.ts
|
|
7
|
+
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
8
|
+
[34mCLI[39m tsup v8.5.1
|
|
9
|
+
[34mCLI[39m Using tsup config: /Users/holiday/Desktop/pushai/v2/apps/cli/tsup.config.ts
|
|
10
|
+
[34mCLI[39m Target: esnext
|
|
11
|
+
[34mCLI[39m Cleaning output folder
|
|
12
|
+
[34mESM[39m Build start
|
|
13
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m3.88 KB[39m
|
|
14
|
+
[32mESM[39m ⚡️ Build success in 11ms
|
|
15
|
+
DTS Build start
|
|
16
|
+
DTS ⚡️ Build success in 763ms
|
|
17
|
+
DTS dist/index.d.mts 13.00 B
|
package/README.md
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
## pushai (pai)
|
|
2
|
+
|
|
3
|
+
The only Git CLI you'll ever need. Stop wasting time thinking of commit messages. Let AI do it, then push in one click.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/pushai)
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
- **Multi-Provider:** Google Gemini, OpenAI, and HuggingFace support.
|
|
10
|
+
- **Privacy First:** Support for Local LLMs (Ollama/LM Studio) via custom base URLs.
|
|
11
|
+
- **Conventional Commits:** Automatically generates standard, readable messages.
|
|
12
|
+
- **Auto-Push:** Stages, commits, and pushes to remote in one flow.
|
|
13
|
+
- **Smart Init:** Automatically detects and offers to initialize git in new folders.
|
|
14
|
+
|
|
15
|
+
### Installation
|
|
16
|
+
|
|
17
|
+
**Run instantly**
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx pushai
|
|
21
|
+
# or
|
|
22
|
+
pnpm dlx pushai
|
|
23
|
+
# or
|
|
24
|
+
yarn pushai
|
|
25
|
+
# or
|
|
26
|
+
bunx --bun pushai
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Install globally**
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm install -g pushai
|
|
33
|
+
# or
|
|
34
|
+
pnpm add -g pushai
|
|
35
|
+
# or
|
|
36
|
+
yarn global add pushai
|
|
37
|
+
# or
|
|
38
|
+
bunx --bun pushai
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Usage
|
|
42
|
+
|
|
43
|
+
You can use the full command `pushai` or the shorthand `pai`.
|
|
44
|
+
|
|
45
|
+
**1. Initial Setup**
|
|
46
|
+
|
|
47
|
+
The first time you run `pai`, it will guide you through configuring your AI provider and API key.
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
pai config
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**2. The Main Workflow**
|
|
54
|
+
|
|
55
|
+
Simply run `pai` when you have unstaged or modified changes.
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pai
|
|
59
|
+
# or
|
|
60
|
+
pai commit
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Commands
|
|
64
|
+
|
|
65
|
+
| Command | Description |
|
|
66
|
+
| --------------- | -------------------------------------------------------------- |
|
|
67
|
+
| `pai` | Default action: stages changes, generates message, and pushes. |
|
|
68
|
+
| `pai commit` | Explicitly triggers the commit/push workflow. |
|
|
69
|
+
| `pai config` | Update your API key, provider, or model choice. |
|
|
70
|
+
| `pai reset` | Deletes the entire `pushai` config directory. |
|
|
71
|
+
| `pai --version` | Display current version. |
|
|
72
|
+
| `pai --help` | Display help message. |
|
|
73
|
+
|
|
74
|
+
### Supported Providers
|
|
75
|
+
|
|
76
|
+
- **Google Gemini:** `gemini-1.5-flash` (Fast & Free tier available).
|
|
77
|
+
- **OpenAI:** `gpt-4o`, `gpt-4o-mini`.
|
|
78
|
+
- **HuggingFace:** `Llama 3`, `Mistral`, etc.
|
|
79
|
+
- **Local/Custom:** Anything OpenAI-compatible (Ollama, Groq).
|
package/dist/index.d.mts
ADDED
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
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(`
|
|
3
|
+
\u2714 Successfully removed the PushAI directory.
|
|
4
|
+
`):g.dim(`
|
|
5
|
+
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(`
|
|
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.
|
|
11
|
+
|
|
12
|
+
Rules:
|
|
13
|
+
1. Use lowercase.
|
|
14
|
+
2. Max 50 characters.
|
|
15
|
+
3. Format: type(scope): description.
|
|
16
|
+
|
|
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(`
|
|
22
|
+
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(`
|
|
29
|
+
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(`
|
|
31
|
+
Git reported an error: ${c.message}
|
|
32
|
+
`)),process.exit(1)}}catch(e){e.name==="ExitPromptError"&&(console.log(r.dim(`
|
|
33
|
+
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();
|
package/package.json
CHANGED
|
@@ -1,40 +1,48 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pushai",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
5
|
-
"type": "module",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "AI-powered CLI for effortless git commits and pushes",
|
|
6
5
|
"bin": {
|
|
7
|
-
"pai": "./
|
|
6
|
+
"pai": "./dist/index.mjs"
|
|
8
7
|
},
|
|
9
|
-
"exports": "./dist/pai.js",
|
|
10
|
-
"files": [
|
|
11
|
-
"dist",
|
|
12
|
-
"bin",
|
|
13
|
-
"package.json"
|
|
14
|
-
],
|
|
15
|
-
"homepage": "https://pushai.vercel.app",
|
|
16
8
|
"scripts": {
|
|
17
|
-
"dev": "
|
|
18
|
-
"build": "tsup",
|
|
19
|
-
"start": "node dist/
|
|
20
|
-
"pushout": "npm publish
|
|
21
|
-
"pushout
|
|
22
|
-
"pushout:inc": "pnpm build && pnpm run pushout:patch && pnpm run pushout"
|
|
9
|
+
"dev": "tsup src/index.ts --format esm --watch --clean",
|
|
10
|
+
"build": "tsup src/index.ts --format esm --clean --minify",
|
|
11
|
+
"start": "pnpm build && clear && node dist/index.mjs",
|
|
12
|
+
"pushout": "npm publish",
|
|
13
|
+
"pushout-inc": "npm version patch --no-git-tag-version && pnpm pushout"
|
|
23
14
|
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"cli",
|
|
17
|
+
"git",
|
|
18
|
+
"push",
|
|
19
|
+
"ai",
|
|
20
|
+
"commit",
|
|
21
|
+
"message",
|
|
22
|
+
"generate",
|
|
23
|
+
"robotics"
|
|
24
|
+
],
|
|
24
25
|
"author": {
|
|
25
26
|
"name": "Holiday",
|
|
26
27
|
"url": "https://thelastofinusa.vercel.app"
|
|
27
28
|
},
|
|
28
|
-
"license": "
|
|
29
|
+
"license": "ISC",
|
|
29
30
|
"dependencies": {
|
|
31
|
+
"@google/generative-ai": "^0.24.1",
|
|
32
|
+
"@huggingface/inference": "^4.13.15",
|
|
30
33
|
"@inquirer/prompts": "^8.4.3",
|
|
31
34
|
"chalk": "^5.6.2",
|
|
32
35
|
"commander": "^14.0.3",
|
|
33
|
-
"
|
|
36
|
+
"conf": "^15.1.0",
|
|
37
|
+
"openai": "^6.37.0",
|
|
38
|
+
"ora": "^9.4.0",
|
|
39
|
+
"simple-git": "^3.36.0",
|
|
40
|
+
"zod": "^3.25.76"
|
|
34
41
|
},
|
|
35
42
|
"devDependencies": {
|
|
43
|
+
"@types/node": "^25.1.0",
|
|
44
|
+
"@types/ora": "^3.2.0",
|
|
36
45
|
"tsup": "^8.5.1",
|
|
37
|
-
"
|
|
38
|
-
"typescript": "^6.0.3"
|
|
46
|
+
"typescript": "^5.9.3"
|
|
39
47
|
}
|
|
40
48
|
}
|
package/dist/pai.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
package/dist/pai.js
DELETED
package/dist/pai.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/pai.ts"],"sourcesContent":["#!/usr/bin/env node\nconsole.log(\"PushAI CLI is ready!\");\n"],"mappings":";AACA,QAAQ,IAAI,sBAAsB","names":[]}
|