@snapcommit/cli 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/README.md +162 -0
- package/dist/ai/anthropic-client.js +92 -0
- package/dist/ai/commit-generator.js +200 -0
- package/dist/ai/gemini-client.js +201 -0
- package/dist/ai/git-interpreter.js +209 -0
- package/dist/ai/smart-solver.js +260 -0
- package/dist/auth/supabase-client.js +288 -0
- package/dist/commands/activate.js +108 -0
- package/dist/commands/commit.js +255 -0
- package/dist/commands/conflict.js +233 -0
- package/dist/commands/doctor.js +113 -0
- package/dist/commands/git-advanced.js +311 -0
- package/dist/commands/github-auth.js +193 -0
- package/dist/commands/login.js +11 -0
- package/dist/commands/natural.js +305 -0
- package/dist/commands/onboard.js +111 -0
- package/dist/commands/quick.js +173 -0
- package/dist/commands/setup.js +163 -0
- package/dist/commands/stats.js +128 -0
- package/dist/commands/uninstall.js +131 -0
- package/dist/db/database.js +99 -0
- package/dist/index.js +144 -0
- package/dist/lib/auth.js +171 -0
- package/dist/lib/github.js +280 -0
- package/dist/lib/multi-repo.js +276 -0
- package/dist/lib/supabase.js +153 -0
- package/dist/license/manager.js +203 -0
- package/dist/repl/index.js +185 -0
- package/dist/repl/interpreter.js +524 -0
- package/dist/utils/analytics.js +36 -0
- package/dist/utils/auth-storage.js +65 -0
- package/dist/utils/dopamine.js +211 -0
- package/dist/utils/errors.js +56 -0
- package/dist/utils/git.js +105 -0
- package/dist/utils/heatmap.js +265 -0
- package/dist/utils/rate-limit.js +68 -0
- package/dist/utils/retry.js +46 -0
- package/dist/utils/ui.js +189 -0
- package/dist/utils/version.js +81 -0
- package/package.json +69 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Rate limiting to prevent API abuse and control costs
|
|
4
|
+
*/
|
|
5
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
6
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.checkRateLimit = checkRateLimit;
|
|
10
|
+
exports.trackRateLimit = trackRateLimit;
|
|
11
|
+
exports.formatResetTime = formatResetTime;
|
|
12
|
+
const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
|
|
13
|
+
const path_1 = __importDefault(require("path"));
|
|
14
|
+
const os_1 = __importDefault(require("os"));
|
|
15
|
+
const DB_PATH = path_1.default.join(os_1.default.homedir(), '.snapcommit', 'snapcommit.db');
|
|
16
|
+
const db = new better_sqlite3_1.default(DB_PATH);
|
|
17
|
+
// Ensure rate_limit table exists
|
|
18
|
+
db.exec(`
|
|
19
|
+
CREATE TABLE IF NOT EXISTS rate_limit (
|
|
20
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
21
|
+
action TEXT NOT NULL,
|
|
22
|
+
timestamp INTEGER NOT NULL
|
|
23
|
+
);
|
|
24
|
+
`);
|
|
25
|
+
const RATE_LIMITS = {
|
|
26
|
+
free: { limit: 10, windowMs: 60 * 60 * 1000 }, // 10 per hour
|
|
27
|
+
pro: { limit: 100, windowMs: 60 * 60 * 1000 }, // 100 per hour
|
|
28
|
+
};
|
|
29
|
+
function checkRateLimit(plan) {
|
|
30
|
+
const config = RATE_LIMITS[plan];
|
|
31
|
+
const now = Date.now();
|
|
32
|
+
const windowStart = now - config.windowMs;
|
|
33
|
+
// Count recent actions
|
|
34
|
+
const count = db.prepare(`
|
|
35
|
+
SELECT COUNT(*) as count FROM rate_limit
|
|
36
|
+
WHERE action = 'commit' AND timestamp >= ?
|
|
37
|
+
`).get(windowStart);
|
|
38
|
+
const remaining = Math.max(0, config.limit - count.count);
|
|
39
|
+
const allowed = remaining > 0;
|
|
40
|
+
// Calculate reset time (start of next window)
|
|
41
|
+
const oldestInWindow = db.prepare(`
|
|
42
|
+
SELECT MIN(timestamp) as oldest FROM rate_limit
|
|
43
|
+
WHERE action = 'commit' AND timestamp >= ?
|
|
44
|
+
`).get(windowStart);
|
|
45
|
+
const resetAt = oldestInWindow?.oldest
|
|
46
|
+
? oldestInWindow.oldest + config.windowMs
|
|
47
|
+
: now + config.windowMs;
|
|
48
|
+
return { allowed, remaining, resetAt };
|
|
49
|
+
}
|
|
50
|
+
function trackRateLimit(action = 'commit') {
|
|
51
|
+
db.prepare(`
|
|
52
|
+
INSERT INTO rate_limit (action, timestamp)
|
|
53
|
+
VALUES (?, ?)
|
|
54
|
+
`).run(action, Date.now());
|
|
55
|
+
// Cleanup old entries (keep last 7 days)
|
|
56
|
+
const sevenDaysAgo = Date.now() - (7 * 24 * 60 * 60 * 1000);
|
|
57
|
+
db.prepare('DELETE FROM rate_limit WHERE timestamp < ?').run(sevenDaysAgo);
|
|
58
|
+
}
|
|
59
|
+
function formatResetTime(resetAt) {
|
|
60
|
+
const seconds = Math.floor((resetAt - Date.now()) / 1000);
|
|
61
|
+
if (seconds < 60)
|
|
62
|
+
return `${seconds}s`;
|
|
63
|
+
const minutes = Math.floor(seconds / 60);
|
|
64
|
+
if (minutes < 60)
|
|
65
|
+
return `${minutes}m`;
|
|
66
|
+
const hours = Math.floor(minutes / 60);
|
|
67
|
+
return `${hours}h ${minutes % 60}m`;
|
|
68
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Retry utility with exponential backoff
|
|
4
|
+
* For handling transient API errors gracefully
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.retryWithBackoff = retryWithBackoff;
|
|
8
|
+
async function retryWithBackoff(fn, options = {}) {
|
|
9
|
+
const { maxAttempts = 3, initialDelay = 1000, maxDelay = 10000, backoffMultiplier = 2, } = options;
|
|
10
|
+
let lastError;
|
|
11
|
+
let delay = initialDelay;
|
|
12
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
13
|
+
try {
|
|
14
|
+
return await fn();
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
lastError = error;
|
|
18
|
+
// Don't retry on certain errors (e.g., auth failures, invalid requests)
|
|
19
|
+
if (isNonRetryableError(error)) {
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
// If this was the last attempt, throw
|
|
23
|
+
if (attempt === maxAttempts) {
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
// Wait before retrying
|
|
27
|
+
await sleep(Math.min(delay, maxDelay));
|
|
28
|
+
delay *= backoffMultiplier;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
throw lastError;
|
|
32
|
+
}
|
|
33
|
+
function isNonRetryableError(error) {
|
|
34
|
+
// Don't retry on 4xx errors (client errors)
|
|
35
|
+
if (error.status && error.status >= 400 && error.status < 500) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
// Don't retry on authentication errors
|
|
39
|
+
if (error.message?.includes('authentication') || error.message?.includes('API key')) {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
function sleep(ms) {
|
|
45
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
46
|
+
}
|
package/dist/utils/ui.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Beautiful terminal UI utilities
|
|
4
|
+
*/
|
|
5
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
6
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.SPINNER_FRAMES = void 0;
|
|
10
|
+
exports.createBox = createBox;
|
|
11
|
+
exports.createProgressBar = createProgressBar;
|
|
12
|
+
exports.createSpinner = createSpinner;
|
|
13
|
+
exports.formatNumber = formatNumber;
|
|
14
|
+
exports.formatDuration = formatDuration;
|
|
15
|
+
exports.createTable = createTable;
|
|
16
|
+
exports.displaySuccess = displaySuccess;
|
|
17
|
+
exports.displayError = displayError;
|
|
18
|
+
exports.displayWarning = displayWarning;
|
|
19
|
+
exports.displayInfo = displayInfo;
|
|
20
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
21
|
+
/**
|
|
22
|
+
* Create a beautiful box around text
|
|
23
|
+
*/
|
|
24
|
+
function createBox(title, lines, width = 50) {
|
|
25
|
+
const border = '─'.repeat(width);
|
|
26
|
+
let box = chalk_1.default.gray(`┌${border}┐\n`);
|
|
27
|
+
box += chalk_1.default.white.bold(`│ ${title.padEnd(width - 2)} │\n`);
|
|
28
|
+
box += chalk_1.default.gray(`├${border}┤\n`);
|
|
29
|
+
lines.forEach(line => {
|
|
30
|
+
box += chalk_1.default.gray(`│ `) + line.padEnd(width - 2) + chalk_1.default.gray(` │\n`);
|
|
31
|
+
});
|
|
32
|
+
box += chalk_1.default.gray(`└${border}┘`);
|
|
33
|
+
return box;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Create a progress bar
|
|
37
|
+
*/
|
|
38
|
+
function createProgressBar(current, total, width = 20) {
|
|
39
|
+
const percentage = Math.min(100, (current / total) * 100);
|
|
40
|
+
const filled = Math.floor((percentage / 100) * width);
|
|
41
|
+
const empty = width - filled;
|
|
42
|
+
const bar = chalk_1.default.green('█'.repeat(filled)) + chalk_1.default.gray('░'.repeat(empty));
|
|
43
|
+
return `${bar} ${percentage.toFixed(0)}%`;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Spinner animation frames
|
|
47
|
+
*/
|
|
48
|
+
exports.SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
49
|
+
/**
|
|
50
|
+
* Create a spinner
|
|
51
|
+
*/
|
|
52
|
+
function createSpinner(message = 'Loading...') {
|
|
53
|
+
let intervalId = null;
|
|
54
|
+
let frame = 0;
|
|
55
|
+
let currentMessage = message;
|
|
56
|
+
const start = () => {
|
|
57
|
+
frame = 0;
|
|
58
|
+
intervalId = setInterval(() => {
|
|
59
|
+
process.stdout.write(chalk_1.default.blue(`\r${exports.SPINNER_FRAMES[frame++ % exports.SPINNER_FRAMES.length]} ${currentMessage}`));
|
|
60
|
+
}, 100);
|
|
61
|
+
};
|
|
62
|
+
const stop = () => {
|
|
63
|
+
if (intervalId) {
|
|
64
|
+
clearInterval(intervalId);
|
|
65
|
+
intervalId = null;
|
|
66
|
+
process.stdout.write('\r' + ' '.repeat(currentMessage.length + 5) + '\r');
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
const update = (msg) => {
|
|
70
|
+
currentMessage = msg;
|
|
71
|
+
};
|
|
72
|
+
return { start, stop, update };
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Format large numbers
|
|
76
|
+
*/
|
|
77
|
+
function formatNumber(num) {
|
|
78
|
+
if (num >= 1000000) {
|
|
79
|
+
return (num / 1000000).toFixed(1) + 'M';
|
|
80
|
+
}
|
|
81
|
+
if (num >= 1000) {
|
|
82
|
+
return (num / 1000).toFixed(1) + 'K';
|
|
83
|
+
}
|
|
84
|
+
return num.toString();
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Format time duration
|
|
88
|
+
*/
|
|
89
|
+
function formatDuration(ms) {
|
|
90
|
+
const seconds = Math.floor(ms / 1000);
|
|
91
|
+
if (seconds < 60)
|
|
92
|
+
return `${seconds}s`;
|
|
93
|
+
const minutes = Math.floor(seconds / 60);
|
|
94
|
+
if (minutes < 60)
|
|
95
|
+
return `${minutes}m ${seconds % 60}s`;
|
|
96
|
+
const hours = Math.floor(minutes / 60);
|
|
97
|
+
if (hours < 24)
|
|
98
|
+
return `${hours}h ${minutes % 60}m`;
|
|
99
|
+
const days = Math.floor(hours / 24);
|
|
100
|
+
return `${days}d ${hours % 24}h`;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Create a table
|
|
104
|
+
*/
|
|
105
|
+
function createTable(headers, rows) {
|
|
106
|
+
const colWidths = headers.map((header, i) => {
|
|
107
|
+
const maxWidth = Math.max(header.length, ...rows.map(row => (row[i] || '').length));
|
|
108
|
+
return maxWidth + 2; // Add padding
|
|
109
|
+
});
|
|
110
|
+
let table = '';
|
|
111
|
+
// Header
|
|
112
|
+
table += chalk_1.default.gray('┌');
|
|
113
|
+
table += colWidths.map(w => chalk_1.default.gray('─'.repeat(w))).join(chalk_1.default.gray('┬'));
|
|
114
|
+
table += chalk_1.default.gray('┐\n');
|
|
115
|
+
table += chalk_1.default.gray('│');
|
|
116
|
+
headers.forEach((header, i) => {
|
|
117
|
+
table += chalk_1.default.white.bold(` ${header.padEnd(colWidths[i] - 1)}`);
|
|
118
|
+
table += chalk_1.default.gray('│');
|
|
119
|
+
});
|
|
120
|
+
table += '\n';
|
|
121
|
+
table += chalk_1.default.gray('├');
|
|
122
|
+
table += colWidths.map(w => chalk_1.default.gray('─'.repeat(w))).join(chalk_1.default.gray('┼'));
|
|
123
|
+
table += chalk_1.default.gray('┤\n');
|
|
124
|
+
// Rows
|
|
125
|
+
rows.forEach(row => {
|
|
126
|
+
table += chalk_1.default.gray('│');
|
|
127
|
+
row.forEach((cell, i) => {
|
|
128
|
+
table += chalk_1.default.white(` ${cell.padEnd(colWidths[i] - 1)}`);
|
|
129
|
+
table += chalk_1.default.gray('│');
|
|
130
|
+
});
|
|
131
|
+
table += '\n';
|
|
132
|
+
});
|
|
133
|
+
table += chalk_1.default.gray('└');
|
|
134
|
+
table += colWidths.map(w => chalk_1.default.gray('─'.repeat(w))).join(chalk_1.default.gray('┴'));
|
|
135
|
+
table += chalk_1.default.gray('┘');
|
|
136
|
+
return table;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Display a success message
|
|
140
|
+
*/
|
|
141
|
+
function displaySuccess(message, details) {
|
|
142
|
+
console.log();
|
|
143
|
+
console.log(chalk_1.default.green.bold(`✅ ${message}`));
|
|
144
|
+
if (details && details.length > 0) {
|
|
145
|
+
details.forEach(detail => {
|
|
146
|
+
console.log(chalk_1.default.gray(` ${detail}`));
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
console.log();
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Display an error message
|
|
153
|
+
*/
|
|
154
|
+
function displayError(message, details) {
|
|
155
|
+
console.log();
|
|
156
|
+
console.log(chalk_1.default.red.bold(`❌ ${message}`));
|
|
157
|
+
if (details && details.length > 0) {
|
|
158
|
+
details.forEach(detail => {
|
|
159
|
+
console.log(chalk_1.default.gray(` ${detail}`));
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
console.log();
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Display a warning message
|
|
166
|
+
*/
|
|
167
|
+
function displayWarning(message, details) {
|
|
168
|
+
console.log();
|
|
169
|
+
console.log(chalk_1.default.yellow.bold(`⚠️ ${message}`));
|
|
170
|
+
if (details && details.length > 0) {
|
|
171
|
+
details.forEach(detail => {
|
|
172
|
+
console.log(chalk_1.default.gray(` ${detail}`));
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
console.log();
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Display an info message
|
|
179
|
+
*/
|
|
180
|
+
function displayInfo(message, details) {
|
|
181
|
+
console.log();
|
|
182
|
+
console.log(chalk_1.default.blue.bold(`ℹ️ ${message}`));
|
|
183
|
+
if (details && details.length > 0) {
|
|
184
|
+
details.forEach(detail => {
|
|
185
|
+
console.log(chalk_1.default.gray(` ${detail}`));
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
console.log();
|
|
189
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Version checking and auto-update notifications
|
|
4
|
+
*/
|
|
5
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
6
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.checkForUpdates = checkForUpdates;
|
|
10
|
+
const https_1 = __importDefault(require("https"));
|
|
11
|
+
const fs_1 = __importDefault(require("fs"));
|
|
12
|
+
const path_1 = __importDefault(require("path"));
|
|
13
|
+
const os_1 = __importDefault(require("os"));
|
|
14
|
+
const CACHE_FILE = path_1.default.join(os_1.default.homedir(), '.snapcommit', 'version-cache.json');
|
|
15
|
+
const CHECK_INTERVAL = 24 * 60 * 60 * 1000; // 24 hours
|
|
16
|
+
async function checkForUpdates() {
|
|
17
|
+
try {
|
|
18
|
+
// Read current version from package.json
|
|
19
|
+
const packageJsonPath = path_1.default.join(__dirname, '../../package.json');
|
|
20
|
+
const packageJson = JSON.parse(fs_1.default.readFileSync(packageJsonPath, 'utf-8'));
|
|
21
|
+
const currentVersion = packageJson.version;
|
|
22
|
+
// Check cache
|
|
23
|
+
let cache = null;
|
|
24
|
+
if (fs_1.default.existsSync(CACHE_FILE)) {
|
|
25
|
+
cache = JSON.parse(fs_1.default.readFileSync(CACHE_FILE, 'utf-8'));
|
|
26
|
+
if (cache && Date.now() - cache.lastCheck < CHECK_INTERVAL) {
|
|
27
|
+
// Use cached version
|
|
28
|
+
return {
|
|
29
|
+
hasUpdate: isNewerVersion(cache.latestVersion, currentVersion),
|
|
30
|
+
currentVersion,
|
|
31
|
+
latestVersion: cache.latestVersion,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Fetch latest version from npm
|
|
36
|
+
const latestVersion = await getLatestVersionFromNpm('snapcommit');
|
|
37
|
+
// Update cache
|
|
38
|
+
const newCache = {
|
|
39
|
+
lastCheck: Date.now(),
|
|
40
|
+
latestVersion,
|
|
41
|
+
};
|
|
42
|
+
fs_1.default.writeFileSync(CACHE_FILE, JSON.stringify(newCache));
|
|
43
|
+
return {
|
|
44
|
+
hasUpdate: isNewerVersion(latestVersion, currentVersion),
|
|
45
|
+
currentVersion,
|
|
46
|
+
latestVersion,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
// Silent fail - don't interrupt user
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function getLatestVersionFromNpm(packageName) {
|
|
55
|
+
return new Promise((resolve, reject) => {
|
|
56
|
+
https_1.default.get(`https://registry.npmjs.org/${packageName}/latest`, (res) => {
|
|
57
|
+
let data = '';
|
|
58
|
+
res.on('data', (chunk) => data += chunk);
|
|
59
|
+
res.on('end', () => {
|
|
60
|
+
try {
|
|
61
|
+
const json = JSON.parse(data);
|
|
62
|
+
resolve(json.version);
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
reject(new Error('Failed to parse npm response'));
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}).on('error', reject);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
function isNewerVersion(latest, current) {
|
|
72
|
+
const latestParts = latest.split('.').map(Number);
|
|
73
|
+
const currentParts = current.split('.').map(Number);
|
|
74
|
+
for (let i = 0; i < 3; i++) {
|
|
75
|
+
if (latestParts[i] > currentParts[i])
|
|
76
|
+
return true;
|
|
77
|
+
if (latestParts[i] < currentParts[i])
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
return false;
|
|
81
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@snapcommit/cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Instant AI commits. Beautiful progress tracking. Never write commit messages again.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"snapcommit": "./dist/index.js",
|
|
8
|
+
"snap": "./dist/index.js",
|
|
9
|
+
"sc": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"dev": "tsx src/index.ts",
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"start": "node dist/index.js",
|
|
15
|
+
"prepublishOnly": "npm run build",
|
|
16
|
+
"test": "echo \"Tests coming soon\""
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"cli",
|
|
20
|
+
"terminal",
|
|
21
|
+
"ai",
|
|
22
|
+
"git",
|
|
23
|
+
"commit",
|
|
24
|
+
"claude",
|
|
25
|
+
"gemini",
|
|
26
|
+
"productivity",
|
|
27
|
+
"developer-tools",
|
|
28
|
+
"automation",
|
|
29
|
+
"progress-tracking"
|
|
30
|
+
],
|
|
31
|
+
"author": "SnapCommit",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"homepage": "https://snapcommit.dev",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/Arjun0606/snapcommit.git"
|
|
37
|
+
},
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/Arjun0606/snapcommit/issues"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=18.0.0"
|
|
43
|
+
},
|
|
44
|
+
"os": [
|
|
45
|
+
"darwin",
|
|
46
|
+
"linux",
|
|
47
|
+
"win32"
|
|
48
|
+
],
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@anthropic-ai/sdk": "^0.30.1",
|
|
51
|
+
"@google/generative-ai": "^0.21.0",
|
|
52
|
+
"@supabase/supabase-js": "^2.78.0",
|
|
53
|
+
"better-sqlite3": "^11.5.0",
|
|
54
|
+
"chalk": "^5.3.0",
|
|
55
|
+
"commander": "^12.1.0",
|
|
56
|
+
"dotenv": "^16.4.5",
|
|
57
|
+
"ink": "^5.0.1",
|
|
58
|
+
"node-pty": "^1.0.0",
|
|
59
|
+
"open": "^10.2.0",
|
|
60
|
+
"react": "^18.3.1"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@types/better-sqlite3": "^7.6.12",
|
|
64
|
+
"@types/node": "^22.8.7",
|
|
65
|
+
"@types/react": "^18.3.12",
|
|
66
|
+
"tsx": "^4.19.2",
|
|
67
|
+
"typescript": "^5.6.3"
|
|
68
|
+
}
|
|
69
|
+
}
|