bit-cli-ai 1.0.0

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/.env.example ADDED
@@ -0,0 +1,15 @@
1
+ # Bit CLI Environment Variables
2
+ # Copy this file to .env and fill in your values
3
+
4
+ # AI Provider API Keys
5
+ OPENAI_API_KEY=sk-your-openai-key-here
6
+ ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here
7
+
8
+ # AI Configuration (optional)
9
+ BIT_AI_PROVIDER=openai
10
+ BIT_AI_MODEL=gpt-4o-mini
11
+
12
+ # Debug Mode (optional)
13
+ BIT_DEBUG=false
14
+ BIT_LOG_LEVEL=info
15
+ BIT_VERBOSE=false
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,178 @@
1
+ # Bit CLI
2
+
3
+ > Git with a brain - An intelligent Git wrapper with AI-powered commits, ghost branches, and predictive merge analysis.
4
+
5
+ [![CI](https://github.com/yourusername/bit-cli/actions/workflows/ci.yml/badge.svg)](https://github.com/yourusername/bit-cli/actions/workflows/ci.yml)
6
+ [![npm version](https://badge.fury.io/js/bit-cli.svg)](https://badge.fury.io/js/bit-cli)
7
+ [![Node.js Version](https://img.shields.io/node/v/bit-cli.svg)](https://nodejs.org/)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
10
+
11
+ ## Features
12
+
13
+ ### Level 1: Foundation
14
+ - **Transparent Passthrough** - All git commands work through bit (`bit status` = `git status`)
15
+ - **Smart Init** - Auto-detects project type and generates appropriate `.gitignore`
16
+ - **AI Commits** - Generates meaningful commit messages using AI or rule-based analysis
17
+
18
+ ### Level 2: Architect
19
+ - **Ghost Branches** - Hidden experimental branches that don't clutter your branch list
20
+ - **Virtual Merge** - Preview merge conflicts before actually merging
21
+ - **`.bit` Directory** - Intelligent metadata storage separate from `.git`
22
+
23
+ ### Level 3: Visionary
24
+ - **Symbol Tracking** - Track function-level changes, not just file-level
25
+ - **Hot Zone Detection** - Warns when teammates are editing the same functions
26
+
27
+ ## Installation
28
+
29
+ ```bash
30
+ # Install globally
31
+ npm install -g bit-cli
32
+
33
+ # Or use npx
34
+ npx bit-cli <command>
35
+ ```
36
+
37
+ ## Quick Start
38
+
39
+ ```bash
40
+ # Initialize a new repository with smart defaults
41
+ bit init
42
+
43
+ # Make some changes, then commit with AI
44
+ git add .
45
+ bit commit
46
+
47
+ # Create a ghost branch for experiments
48
+ bit branch --ghost experiment
49
+
50
+ # Preview merge conflicts before merging
51
+ bit merge --preview feature-branch
52
+
53
+ # Check for team conflicts
54
+ bit hotzone
55
+
56
+ # Analyze code changes
57
+ bit analyze
58
+ ```
59
+
60
+ ## Commands
61
+
62
+ | Command | Description |
63
+ |---------|-------------|
64
+ | `bit init` | Initialize repo with smart .gitignore and .bit directory |
65
+ | `bit commit` | AI-powered commit message generation |
66
+ | `bit commit -m "msg"` | Manual commit message |
67
+ | `bit branch --ghost <name>` | Create a ghost (hidden) branch |
68
+ | `bit branch` | List all branches including ghost branches |
69
+ | `bit checkout <branch> --ghost` | Checkout a ghost branch |
70
+ | `bit merge --preview <branch>` | Preview merge conflicts |
71
+ | `bit merge <branch>` | Smart merge with conflict preview |
72
+ | `bit hotzone` | Detect overlapping work with team |
73
+ | `bit analyze` | Analyze code at function/symbol level |
74
+ | `bit <any-git-cmd>` | Passthrough to git |
75
+
76
+ ## Configuration
77
+
78
+ ### Environment Variables
79
+
80
+ ```bash
81
+ # Required for AI features
82
+ OPENAI_API_KEY=sk-your-key-here
83
+
84
+ # Optional
85
+ BIT_AI_MODEL=gpt-4o-mini
86
+ BIT_DEBUG=true
87
+ BIT_LOG_LEVEL=debug
88
+ BIT_VERBOSE=true
89
+ ```
90
+
91
+ ### Global Configuration
92
+
93
+ Config stored in `~/.bit/config.json`:
94
+
95
+ ```json
96
+ {
97
+ "ai": {
98
+ "provider": "openai",
99
+ "model": "gpt-4o-mini",
100
+ "maxTokens": 500,
101
+ "temperature": 0.7
102
+ },
103
+ "git": {
104
+ "ghostPrefix": "ghost/",
105
+ "autoStage": false
106
+ },
107
+ "ui": {
108
+ "colors": true,
109
+ "spinners": true
110
+ }
111
+ }
112
+ ```
113
+
114
+ ### Project Configuration
115
+
116
+ Project-specific config in `.bit/config.json` overrides global settings.
117
+
118
+ ## Architecture
119
+
120
+ ```
121
+ bit-cli/
122
+ ├── src/
123
+ │ ├── index.js # CLI entry point
124
+ │ ├── commands/ # Command implementations
125
+ │ │ ├── init.js
126
+ │ │ ├── commit.js
127
+ │ │ ├── branch.js
128
+ │ │ ├── merge.js
129
+ │ │ ├── hotzone.js
130
+ │ │ └── analyze.js
131
+ │ └── utils/ # Shared utilities
132
+ │ ├── ai.js # AI service
133
+ │ ├── config.js # Configuration management
134
+ │ ├── errors.js # Error handling
135
+ │ ├── git.js # Git operations
136
+ │ ├── logger.js # Logging
137
+ │ └── validation.js # Input validation
138
+ ├── tests/ # Test files
139
+ └── .github/workflows/ # CI/CD
140
+ ```
141
+
142
+ ## Development
143
+
144
+ ```bash
145
+ # Clone repository
146
+ git clone https://github.com/yourusername/bit-cli.git
147
+ cd bit-cli
148
+
149
+ # Install dependencies
150
+ npm install
151
+
152
+ # Run in development
153
+ npm run dev
154
+
155
+ # Run tests
156
+ npm test
157
+
158
+ # Run tests with coverage
159
+ npm run test:coverage
160
+
161
+ # Lint code
162
+ npm run lint
163
+
164
+ # Format code
165
+ npm run format
166
+ ```
167
+
168
+ ## Contributing
169
+
170
+ 1. Fork the repository
171
+ 2. Create a feature branch (`git checkout -b feature/amazing`)
172
+ 3. Commit your changes (`bit commit`)
173
+ 4. Push to the branch (`git push origin feature/amazing`)
174
+ 5. Open a Pull Request
175
+
176
+ ## License
177
+
178
+ MIT License - see [LICENSE](LICENSE) for details.
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "bit-cli-ai",
3
+ "version": "1.0.0",
4
+ "description": "Git with a brain - intelligent Git wrapper with AI-powered commits, ghost branches, and predictive merge",
5
+ "type": "module",
6
+ "main": "src/index.js",
7
+ "bin": {
8
+ "bit": "./src/index.js"
9
+ },
10
+ "files": [
11
+ "src",
12
+ "README.md",
13
+ "LICENSE",
14
+ ".env.example"
15
+ ],
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "scripts": {
20
+ "start": "node src/index.js",
21
+ "dev": "node --watch src/index.js",
22
+ "test": "node --test tests/**/*.test.js",
23
+ "test:watch": "node --test --watch tests/**/*.test.js",
24
+ "test:coverage": "c8 node --test tests/**/*.test.js",
25
+ "lint": "eslint src/**/*.js",
26
+ "lint:fix": "eslint src/**/*.js --fix",
27
+ "format": "prettier --write \"src/**/*.js\"",
28
+ "validate": "npm run lint && npm run test",
29
+ "prepublishOnly": "npm run validate"
30
+ },
31
+ "keywords": [
32
+ "git",
33
+ "cli",
34
+ "ai",
35
+ "developer-tools",
36
+ "productivity",
37
+ "version-control"
38
+ ],
39
+ "author": "Shubhashis Baral <shubhashis9556@gmail.com>",
40
+ "license": "MIT",
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "git+https://github.com/shubhashis9556/bit-cli.git"
44
+ },
45
+ "homepage": "https://github.com/shubhashis9556/bit-cli#readme",
46
+ "bugs": {
47
+ "url": "https://github.com/shubhashis9556/bit-cli/issues"
48
+ },
49
+ "funding": {
50
+ "type": "github",
51
+ "url": "https://github.com/sponsors/shubhashis9556"
52
+ },
53
+ "engines": {
54
+ "node": ">=18.0.0"
55
+ },
56
+ "dependencies": {
57
+ "chalk": "^5.3.0",
58
+ "commander": "^12.1.0",
59
+ "ora": "^8.0.1",
60
+ "openai": "^4.52.0",
61
+ "dotenv": "^16.4.5",
62
+ "winston": "^3.13.0",
63
+ "conf": "^12.0.0",
64
+ "zod": "^3.23.8",
65
+ "simple-git": "^3.25.0",
66
+ "inquirer": "^9.2.23"
67
+ },
68
+ "devDependencies": {
69
+ "c8": "^9.1.0",
70
+ "eslint": "^9.5.0",
71
+ "prettier": "^3.3.2"
72
+ }
73
+ }
@@ -0,0 +1,230 @@
1
+ import { execSync } from 'child_process';
2
+ import fs from 'fs';
3
+ import chalk from 'chalk';
4
+ import ora from 'ora';
5
+
6
+ const SYMBOLS_PATH = '.bit/symbols.json';
7
+
8
+
9
+
10
+ // Analyze diff to find changed symbols
11
+ function analyzeChangedSymbols(diff) {
12
+ const changedSymbols = {
13
+ added: [],
14
+ modified: [],
15
+ removed: []
16
+ };
17
+
18
+ const lines = diff.split('\n');
19
+ let currentFile = null;
20
+
21
+ for (let i = 0; i < lines.length; i++) {
22
+ const line = lines[i];
23
+
24
+ // Track current file
25
+ if (line.startsWith('diff --git')) {
26
+ const match = line.match(/b\/(.+)$/);
27
+ if (match) {
28
+ currentFile = match[1];
29
+ }
30
+ continue;
31
+ }
32
+
33
+ // Added lines
34
+ if (line.startsWith('+') && !line.startsWith('+++')) {
35
+ const functionMatch = line.match(/(?:function|const|let|var)\s+(\w+)/);
36
+ const classMatch = line.match(/class\s+(\w+)/);
37
+
38
+ if (functionMatch) {
39
+ changedSymbols.added.push({
40
+ name: functionMatch[1],
41
+ type: 'function',
42
+ file: currentFile
43
+ });
44
+ }
45
+ if (classMatch) {
46
+ changedSymbols.added.push({
47
+ name: classMatch[1],
48
+ type: 'class',
49
+ file: currentFile
50
+ });
51
+ }
52
+ }
53
+
54
+ // Removed lines
55
+ if (line.startsWith('-') && !line.startsWith('---')) {
56
+ const functionMatch = line.match(/(?:function|const|let|var)\s+(\w+)/);
57
+ const classMatch = line.match(/class\s+(\w+)/);
58
+
59
+ if (functionMatch) {
60
+ changedSymbols.removed.push({
61
+ name: functionMatch[1],
62
+ type: 'function',
63
+ file: currentFile
64
+ });
65
+ }
66
+ if (classMatch) {
67
+ changedSymbols.removed.push({
68
+ name: classMatch[1],
69
+ type: 'class',
70
+ file: currentFile
71
+ });
72
+ }
73
+ }
74
+ }
75
+
76
+ // Modified = appears in both added and removed
77
+ const addedNames = changedSymbols.added.map(s => s.name);
78
+ const removedNames = changedSymbols.removed.map(s => s.name);
79
+
80
+ for (const name of addedNames) {
81
+ if (removedNames.includes(name)) {
82
+ changedSymbols.modified.push({
83
+ name,
84
+ file: changedSymbols.added.find(s => s.name === name)?.file
85
+ });
86
+ }
87
+ }
88
+
89
+ // Clean up: remove modified from added/removed
90
+ const modifiedNames = changedSymbols.modified.map(s => s.name);
91
+ changedSymbols.added = changedSymbols.added.filter(s => !modifiedNames.includes(s.name));
92
+ changedSymbols.removed = changedSymbols.removed.filter(s => !modifiedNames.includes(s.name));
93
+
94
+ return changedSymbols;
95
+ }
96
+
97
+ // Load symbol database
98
+ function loadSymbols() {
99
+ if (!fs.existsSync(SYMBOLS_PATH)) {
100
+ return { functions: {}, classes: {}, lastAnalyzed: null };
101
+ }
102
+ return JSON.parse(fs.readFileSync(SYMBOLS_PATH, 'utf-8'));
103
+ }
104
+
105
+ // Save symbol database
106
+ function saveSymbols(data) {
107
+ if (!fs.existsSync('.bit')) {
108
+ fs.mkdirSync('.bit');
109
+ }
110
+ fs.writeFileSync(SYMBOLS_PATH, JSON.stringify(data, null, 2));
111
+ }
112
+
113
+ // Get frequently changed symbols
114
+ function getHotSymbols(symbolDb) {
115
+ const all = [];
116
+
117
+ for (const [name, data] of Object.entries(symbolDb.functions)) {
118
+ all.push({ name, type: 'function', ...data });
119
+ }
120
+ for (const [name, data] of Object.entries(symbolDb.classes)) {
121
+ all.push({ name, type: 'class', ...data });
122
+ }
123
+
124
+ return all.sort((a, b) => b.changes - a.changes).slice(0, 10);
125
+ }
126
+
127
+ export async function analyzeSymbols() {
128
+ const spinner = ora('Analyzing code symbols...').start();
129
+
130
+ try {
131
+ // Check if in git repo
132
+ try {
133
+ execSync('git rev-parse --git-dir', { stdio: 'pipe' });
134
+ } catch {
135
+ spinner.fail('Not a git repository');
136
+ return;
137
+ }
138
+
139
+ // Get staged diff
140
+ let diff = execSync('git diff --cached', { encoding: 'utf-8' });
141
+
142
+ // If no staged changes, get unstaged
143
+ if (!diff.trim()) {
144
+ diff = execSync('git diff', { encoding: 'utf-8' });
145
+ }
146
+
147
+ if (!diff.trim()) {
148
+ spinner.info('No changes to analyze');
149
+ console.log(chalk.gray('\nMake some changes or stage files first.'));
150
+ return;
151
+ }
152
+
153
+ // Analyze changed symbols
154
+ const changedSymbols = analyzeChangedSymbols(diff);
155
+
156
+ // Update symbol database
157
+ const symbolDb = loadSymbols();
158
+
159
+ for (const symbol of [...changedSymbols.added, ...changedSymbols.modified]) {
160
+ const db = symbol.type === 'class' ? symbolDb.classes : symbolDb.functions;
161
+ db[symbol.name] = db[symbol.name] || { changes: 0, files: [] };
162
+ db[symbol.name].changes++;
163
+ db[symbol.name].lastModified = new Date().toISOString();
164
+ if (symbol.file && !db[symbol.name].files.includes(symbol.file)) {
165
+ db[symbol.name].files.push(symbol.file);
166
+ }
167
+ }
168
+
169
+ symbolDb.lastAnalyzed = new Date().toISOString();
170
+ saveSymbols(symbolDb);
171
+
172
+ spinner.stop();
173
+
174
+ // Display results
175
+ console.log(chalk.cyan('\n--- Symbol Analysis ---\n'));
176
+
177
+ // Changed symbols in current diff
178
+ const totalChanges = changedSymbols.added.length + changedSymbols.modified.length + changedSymbols.removed.length;
179
+
180
+ if (totalChanges === 0) {
181
+ console.log(chalk.gray('No function/class changes detected in diff.'));
182
+ console.log(chalk.gray('(Only structural changes like functions/classes are tracked)'));
183
+ } else {
184
+ if (changedSymbols.added.length > 0) {
185
+ console.log(chalk.green(`Added (${changedSymbols.added.length}):`));
186
+ changedSymbols.added.forEach(s => {
187
+ console.log(chalk.green(` + ${s.name}() in ${s.file || 'unknown'}`));
188
+ });
189
+ console.log('');
190
+ }
191
+
192
+ if (changedSymbols.modified.length > 0) {
193
+ console.log(chalk.yellow(`Modified (${changedSymbols.modified.length}):`));
194
+ changedSymbols.modified.forEach(s => {
195
+ console.log(chalk.yellow(` ~ ${s.name}() in ${s.file || 'unknown'}`));
196
+ });
197
+ console.log('');
198
+ }
199
+
200
+ if (changedSymbols.removed.length > 0) {
201
+ console.log(chalk.red(`Removed (${changedSymbols.removed.length}):`));
202
+ changedSymbols.removed.forEach(s => {
203
+ console.log(chalk.red(` - ${s.name}() in ${s.file || 'unknown'}`));
204
+ });
205
+ console.log('');
206
+ }
207
+ }
208
+
209
+ // Show hot symbols (most frequently changed)
210
+ console.log(chalk.gray('─'.repeat(50)));
211
+ console.log(chalk.cyan('\nMost Changed Symbols (all time):'));
212
+
213
+ const hotSymbols = getHotSymbols(symbolDb);
214
+
215
+ if (hotSymbols.length === 0) {
216
+ console.log(chalk.gray(' No symbol history yet. Make more commits!'));
217
+ } else {
218
+ hotSymbols.slice(0, 5).forEach((s, i) => {
219
+ const bar = '█'.repeat(Math.min(s.changes, 10));
220
+ console.log(chalk.gray(` ${i + 1}. ${s.name}() - ${s.changes} changes ${chalk.blue(bar)}`));
221
+ });
222
+ }
223
+
224
+ console.log('');
225
+
226
+ } catch (error) {
227
+ spinner.fail('Analysis failed');
228
+ console.error(chalk.red(error.message));
229
+ }
230
+ }