@snapcommit/cli 1.0.3 → 1.0.5
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/dist/commands/github-connect.js +207 -0
- package/dist/commands/natural.js +141 -1
- package/dist/index.js +23 -0
- package/dist/lib/auth.js +8 -0
- package/dist/repl.js +19 -1
- package/package.json +2 -1
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Simple GitHub authentication via Personal Access Token (PAT)
|
|
4
|
+
* Users generate token on GitHub.com and paste it here
|
|
5
|
+
* No OAuth complexity, instant setup!
|
|
6
|
+
*/
|
|
7
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
8
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
9
|
+
};
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.getGitHubToken = getGitHubToken;
|
|
12
|
+
exports.getGitHubConfig = getGitHubConfig;
|
|
13
|
+
exports.isGitHubConnected = isGitHubConnected;
|
|
14
|
+
exports.clearGitHubToken = clearGitHubToken;
|
|
15
|
+
exports.githubConnectCommand = githubConnectCommand;
|
|
16
|
+
exports.githubStatusCommand = githubStatusCommand;
|
|
17
|
+
exports.githubDisconnectCommand = githubDisconnectCommand;
|
|
18
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
19
|
+
const fs_1 = __importDefault(require("fs"));
|
|
20
|
+
const path_1 = __importDefault(require("path"));
|
|
21
|
+
const os_1 = __importDefault(require("os"));
|
|
22
|
+
const readline_1 = __importDefault(require("readline"));
|
|
23
|
+
const rest_1 = require("@octokit/rest");
|
|
24
|
+
const CONFIG_DIR = path_1.default.join(os_1.default.homedir(), '.snapcommit');
|
|
25
|
+
const GITHUB_TOKEN_FILE = path_1.default.join(CONFIG_DIR, 'github.json');
|
|
26
|
+
/**
|
|
27
|
+
* Ensure config directory exists
|
|
28
|
+
*/
|
|
29
|
+
function ensureConfigDir() {
|
|
30
|
+
if (!fs_1.default.existsSync(CONFIG_DIR)) {
|
|
31
|
+
fs_1.default.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Ask a question and return the answer
|
|
36
|
+
*/
|
|
37
|
+
function askQuestion(query) {
|
|
38
|
+
const rl = readline_1.default.createInterface({
|
|
39
|
+
input: process.stdin,
|
|
40
|
+
output: process.stdout,
|
|
41
|
+
});
|
|
42
|
+
return new Promise((resolve) => rl.question(query, (ans) => {
|
|
43
|
+
rl.close();
|
|
44
|
+
resolve(ans);
|
|
45
|
+
}));
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Verify GitHub token and get user info
|
|
49
|
+
*/
|
|
50
|
+
async function verifyGitHubToken(token) {
|
|
51
|
+
try {
|
|
52
|
+
const octokit = new rest_1.Octokit({ auth: token });
|
|
53
|
+
const { data: user } = await octokit.users.getAuthenticated();
|
|
54
|
+
return { valid: true, user };
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
if (error.status === 401) {
|
|
58
|
+
return { valid: false };
|
|
59
|
+
}
|
|
60
|
+
throw new Error('Failed to verify token. Please check your internet connection.');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Save GitHub token
|
|
65
|
+
*/
|
|
66
|
+
function saveGitHubToken(config) {
|
|
67
|
+
ensureConfigDir();
|
|
68
|
+
fs_1.default.writeFileSync(GITHUB_TOKEN_FILE, JSON.stringify(config, null, 2));
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get saved GitHub token
|
|
72
|
+
*/
|
|
73
|
+
function getGitHubToken() {
|
|
74
|
+
if (!fs_1.default.existsSync(GITHUB_TOKEN_FILE)) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
const data = fs_1.default.readFileSync(GITHUB_TOKEN_FILE, 'utf-8');
|
|
79
|
+
const config = JSON.parse(data);
|
|
80
|
+
return config.token;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Get GitHub config
|
|
88
|
+
*/
|
|
89
|
+
function getGitHubConfig() {
|
|
90
|
+
if (!fs_1.default.existsSync(GITHUB_TOKEN_FILE)) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
const data = fs_1.default.readFileSync(GITHUB_TOKEN_FILE, 'utf-8');
|
|
95
|
+
return JSON.parse(data);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Check if GitHub is connected
|
|
103
|
+
*/
|
|
104
|
+
function isGitHubConnected() {
|
|
105
|
+
return getGitHubToken() !== null;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Clear GitHub token
|
|
109
|
+
*/
|
|
110
|
+
function clearGitHubToken() {
|
|
111
|
+
if (fs_1.default.existsSync(GITHUB_TOKEN_FILE)) {
|
|
112
|
+
fs_1.default.unlinkSync(GITHUB_TOKEN_FILE);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Connect GitHub command
|
|
117
|
+
*/
|
|
118
|
+
async function githubConnectCommand(tokenArg) {
|
|
119
|
+
console.log(chalk_1.default.bold.cyan('\n╔════════════════════════════════════════╗'));
|
|
120
|
+
console.log(chalk_1.default.bold.cyan('║ Connect GitHub to SnapCommit ║'));
|
|
121
|
+
console.log(chalk_1.default.bold.cyan('╚════════════════════════════════════════╝\n'));
|
|
122
|
+
console.log(chalk_1.default.gray('GitHub integration allows you to:\n'));
|
|
123
|
+
console.log(chalk_1.default.white(' • Create pull requests'));
|
|
124
|
+
console.log(chalk_1.default.white(' • Check CI/workflow status'));
|
|
125
|
+
console.log(chalk_1.default.white(' • List and manage PRs'));
|
|
126
|
+
console.log(chalk_1.default.white(' • All with natural language!\n'));
|
|
127
|
+
console.log(chalk_1.default.yellow('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
|
|
128
|
+
console.log(chalk_1.default.bold.white('How to get your GitHub token:\n'));
|
|
129
|
+
console.log(chalk_1.default.gray(' 1. Go to: ') + chalk_1.default.cyan('https://github.com/settings/tokens'));
|
|
130
|
+
console.log(chalk_1.default.gray(' 2. Click "Generate new token (classic)"'));
|
|
131
|
+
console.log(chalk_1.default.gray(' 3. Give it a name: ') + chalk_1.default.white('"SnapCommit"'));
|
|
132
|
+
console.log(chalk_1.default.gray(' 4. Select scopes: ') + chalk_1.default.white('repo, workflow, read:user'));
|
|
133
|
+
console.log(chalk_1.default.gray(' 5. Click "Generate token" and copy it\n'));
|
|
134
|
+
console.log(chalk_1.default.yellow('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
|
|
135
|
+
let token = tokenArg;
|
|
136
|
+
if (!token) {
|
|
137
|
+
token = await askQuestion(chalk_1.default.yellow('Paste your GitHub token: '));
|
|
138
|
+
}
|
|
139
|
+
if (!token || token.trim().length === 0) {
|
|
140
|
+
console.log(chalk_1.default.red('\n❌ No token provided. Cancelled.\n'));
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
token = token.trim();
|
|
144
|
+
console.log(chalk_1.default.gray('\n🔄 Verifying token with GitHub...\n'));
|
|
145
|
+
try {
|
|
146
|
+
const result = await verifyGitHubToken(token);
|
|
147
|
+
if (result.valid && result.user) {
|
|
148
|
+
const config = {
|
|
149
|
+
token,
|
|
150
|
+
username: result.user.login,
|
|
151
|
+
userId: result.user.id,
|
|
152
|
+
connectedAt: new Date().toISOString(),
|
|
153
|
+
};
|
|
154
|
+
saveGitHubToken(config);
|
|
155
|
+
console.log(chalk_1.default.green.bold('✅ GITHUB CONNECTED! 🎉\n'));
|
|
156
|
+
console.log(chalk_1.default.white(` Connected as: ${chalk_1.default.bold('@' + result.user.login)}`));
|
|
157
|
+
console.log(chalk_1.default.gray(` User ID: ${result.user.id}`));
|
|
158
|
+
console.log(chalk_1.default.gray(` Name: ${result.user.name || 'N/A'}\n`));
|
|
159
|
+
console.log(chalk_1.default.yellow('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
|
|
160
|
+
console.log(chalk_1.default.bold('🚀 You can now use GitHub features!\n'));
|
|
161
|
+
console.log(chalk_1.default.gray(' Try these commands in snap REPL:\n'));
|
|
162
|
+
console.log(chalk_1.default.cyan(' • "create a pull request"'));
|
|
163
|
+
console.log(chalk_1.default.cyan(' • "check CI status"'));
|
|
164
|
+
console.log(chalk_1.default.cyan(' • "list my open PRs"\n'));
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
console.log(chalk_1.default.red('\n❌ Invalid GitHub token.\n'));
|
|
168
|
+
console.log(chalk_1.default.yellow('Troubleshooting:'));
|
|
169
|
+
console.log(chalk_1.default.gray(' • Make sure you copied the ENTIRE token'));
|
|
170
|
+
console.log(chalk_1.default.gray(' • Token should start with: ghp_'));
|
|
171
|
+
console.log(chalk_1.default.gray(' • Make sure the token has correct scopes'));
|
|
172
|
+
console.log(chalk_1.default.gray(' • Generate a new token at: https://github.com/settings/tokens\n'));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
console.log(chalk_1.default.red(`\n❌ ${error.message}\n`));
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* GitHub status command
|
|
181
|
+
*/
|
|
182
|
+
async function githubStatusCommand() {
|
|
183
|
+
const config = getGitHubConfig();
|
|
184
|
+
if (!config) {
|
|
185
|
+
console.log(chalk_1.default.yellow('\n⚠️ GitHub not connected\n'));
|
|
186
|
+
console.log(chalk_1.default.gray('Run: ') + chalk_1.default.cyan('snap github connect') + chalk_1.default.gray(' to connect GitHub\n'));
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
console.log(chalk_1.default.green('\n✅ GitHub Connected\n'));
|
|
190
|
+
console.log(chalk_1.default.white(` Username: ${chalk_1.default.bold('@' + config.username)}`));
|
|
191
|
+
console.log(chalk_1.default.gray(` Connected: ${new Date(config.connectedAt).toLocaleString()}\n`));
|
|
192
|
+
console.log(chalk_1.default.gray('You can use GitHub features in snap REPL!\n'));
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* GitHub disconnect command
|
|
196
|
+
*/
|
|
197
|
+
async function githubDisconnectCommand() {
|
|
198
|
+
const config = getGitHubConfig();
|
|
199
|
+
if (!config) {
|
|
200
|
+
console.log(chalk_1.default.gray('\n GitHub is not connected.\n'));
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
console.log(chalk_1.default.yellow(`\n Disconnecting GitHub (@${config.username})...\n`));
|
|
204
|
+
clearGitHubToken();
|
|
205
|
+
console.log(chalk_1.default.green(' ✅ GitHub disconnected successfully!\n'));
|
|
206
|
+
console.log(chalk_1.default.gray(' Run "snap github connect" to reconnect.\n'));
|
|
207
|
+
}
|
package/dist/commands/natural.js
CHANGED
|
@@ -174,7 +174,14 @@ async function naturalCommand(userInput) {
|
|
|
174
174
|
}
|
|
175
175
|
clearInterval(interval);
|
|
176
176
|
process.stdout.write('\r' + ' '.repeat(20) + '\r');
|
|
177
|
-
//
|
|
177
|
+
// Check if this is a GitHub operation
|
|
178
|
+
const intentType = intent.type || 'git';
|
|
179
|
+
if (intentType === 'github') {
|
|
180
|
+
// Handle GitHub operations
|
|
181
|
+
await handleGitHubOperation(intent);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
// Show intent (for Git operations)
|
|
178
185
|
console.log(chalk_1.default.green(`✨ I understand: ${chalk_1.default.white.bold(intent.action)}\n`));
|
|
179
186
|
console.log(chalk_1.default.white('This will:'));
|
|
180
187
|
console.log(chalk_1.default.gray(`• ${intent.explanation}\n`));
|
|
@@ -310,3 +317,136 @@ async function showDopamineStats() {
|
|
|
310
317
|
const { displayQuickDopamine } = await Promise.resolve().then(() => __importStar(require('../utils/dopamine')));
|
|
311
318
|
displayQuickDopamine();
|
|
312
319
|
}
|
|
320
|
+
/**
|
|
321
|
+
* Handle GitHub operations (PRs, CI checks, issues)
|
|
322
|
+
*/
|
|
323
|
+
async function handleGitHubOperation(intent) {
|
|
324
|
+
// Import GitHub connection utilities
|
|
325
|
+
const { getGitHubToken, isGitHubConnected } = await Promise.resolve().then(() => __importStar(require('./github-connect')));
|
|
326
|
+
const { Octokit } = await Promise.resolve().then(() => __importStar(require('@octokit/rest')));
|
|
327
|
+
// Check if GitHub is connected
|
|
328
|
+
if (!isGitHubConnected()) {
|
|
329
|
+
console.log(chalk_1.default.red('❌ GitHub not connected!\n'));
|
|
330
|
+
console.log(chalk_1.default.yellow('To connect GitHub:'));
|
|
331
|
+
console.log(chalk_1.default.cyan(' Run: ') + chalk_1.default.white('snap github connect'));
|
|
332
|
+
console.log(chalk_1.default.gray('\nYou\'ll need a GitHub Personal Access Token'));
|
|
333
|
+
console.log(chalk_1.default.gray('Get one at: https://github.com/settings/tokens\n'));
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
const githubToken = getGitHubToken();
|
|
337
|
+
if (!githubToken) {
|
|
338
|
+
console.log(chalk_1.default.red('❌ GitHub token not found\n'));
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
const octokit = new Octokit({ auth: githubToken });
|
|
342
|
+
console.log(chalk_1.default.green(`✨ ${intent.explanation}\n`));
|
|
343
|
+
// Show confirmation if needed
|
|
344
|
+
if (intent.needsConfirmation) {
|
|
345
|
+
const answer = await askQuestion(chalk_1.default.yellow('Continue? (Y/n): '));
|
|
346
|
+
if (answer.toLowerCase() === 'n') {
|
|
347
|
+
console.log(chalk_1.default.gray('\nCancelled.\n'));
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
// Get repo info from git remote
|
|
352
|
+
let owner, repo;
|
|
353
|
+
try {
|
|
354
|
+
const remote = (0, child_process_1.execSync)('git remote get-url origin', { encoding: 'utf-8' }).trim();
|
|
355
|
+
const match = remote.match(/github\.com[/:]([\w-]+)\/([\w-]+?)(\.git)?$/);
|
|
356
|
+
if (!match) {
|
|
357
|
+
console.log(chalk_1.default.red('❌ Not a GitHub repository\n'));
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
owner = match[1];
|
|
361
|
+
repo = match[2];
|
|
362
|
+
}
|
|
363
|
+
catch {
|
|
364
|
+
console.log(chalk_1.default.red('❌ Not a GitHub repository\n'));
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
console.log(chalk_1.default.blue('🔄 Executing GitHub operation...\n'));
|
|
368
|
+
try {
|
|
369
|
+
if (intent.action === 'pr_create') {
|
|
370
|
+
// Create PR using Octokit
|
|
371
|
+
const currentBranch = (0, child_process_1.execSync)('git branch --show-current', { encoding: 'utf-8' }).trim();
|
|
372
|
+
const { data: pr } = await octokit.pulls.create({
|
|
373
|
+
owner,
|
|
374
|
+
repo,
|
|
375
|
+
title: intent.options?.title || `PR from ${currentBranch}`,
|
|
376
|
+
body: intent.options?.body || '',
|
|
377
|
+
head: intent.options?.head || currentBranch,
|
|
378
|
+
base: intent.options?.base || 'main',
|
|
379
|
+
});
|
|
380
|
+
console.log(chalk_1.default.green.bold('✅ Pull Request Created!\n'));
|
|
381
|
+
console.log(chalk_1.default.white(` Title: ${pr.title}`));
|
|
382
|
+
console.log(chalk_1.default.white(` Number: #${pr.number}`));
|
|
383
|
+
console.log(chalk_1.default.white(` URL: ${chalk_1.default.cyan(pr.html_url)}\n`));
|
|
384
|
+
}
|
|
385
|
+
else if (intent.action === 'pr_list') {
|
|
386
|
+
// List PRs using Octokit
|
|
387
|
+
const state = intent.options?.state || 'open';
|
|
388
|
+
const { data: prs } = await octokit.pulls.list({
|
|
389
|
+
owner,
|
|
390
|
+
repo,
|
|
391
|
+
state: state,
|
|
392
|
+
per_page: 20,
|
|
393
|
+
});
|
|
394
|
+
if (prs.length === 0) {
|
|
395
|
+
console.log(chalk_1.default.yellow(`No ${state} pull requests found.\n`));
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
console.log(chalk_1.default.green.bold(`📋 ${state.toUpperCase()} Pull Requests:\n`));
|
|
399
|
+
prs.forEach((pr) => {
|
|
400
|
+
console.log(chalk_1.default.white(` #${pr.number} - ${pr.title}`));
|
|
401
|
+
console.log(chalk_1.default.gray(` ${pr.head.ref} → ${pr.base.ref} by @${pr.user?.login}`));
|
|
402
|
+
console.log(chalk_1.default.cyan(` ${pr.html_url}\n`));
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
else if (intent.action === 'ci_check') {
|
|
406
|
+
// Check CI status using Octokit
|
|
407
|
+
const ref = intent.options?.ref || (0, child_process_1.execSync)('git branch --show-current', { encoding: 'utf-8' }).trim();
|
|
408
|
+
// Get commit status checks
|
|
409
|
+
const { data: statusData } = await octokit.repos.getCombinedStatusForRef({
|
|
410
|
+
owner,
|
|
411
|
+
repo,
|
|
412
|
+
ref,
|
|
413
|
+
});
|
|
414
|
+
// Get workflow runs
|
|
415
|
+
const { data: workflowRuns } = await octokit.actions.listWorkflowRunsForRepo({
|
|
416
|
+
owner,
|
|
417
|
+
repo,
|
|
418
|
+
per_page: 10,
|
|
419
|
+
});
|
|
420
|
+
// Filter workflow runs for this ref
|
|
421
|
+
const relevantRuns = workflowRuns.workflow_runs.filter(run => run.head_branch === ref || run.head_sha === ref);
|
|
422
|
+
const stateColor = statusData.state === 'success' ? chalk_1.default.green :
|
|
423
|
+
statusData.state === 'pending' ? chalk_1.default.yellow : chalk_1.default.red;
|
|
424
|
+
console.log(stateColor.bold(`CI Status: ${statusData.state.toUpperCase()}\n`));
|
|
425
|
+
if (statusData.statuses.length > 0) {
|
|
426
|
+
console.log(chalk_1.default.white('Status Checks:'));
|
|
427
|
+
statusData.statuses.forEach((status) => {
|
|
428
|
+
const icon = status.state === 'success' ? '✅' : status.state === 'pending' ? '⏳' : '❌';
|
|
429
|
+
console.log(chalk_1.default.gray(` ${icon} ${status.context}: ${status.description}`));
|
|
430
|
+
});
|
|
431
|
+
console.log();
|
|
432
|
+
}
|
|
433
|
+
if (relevantRuns.length > 0) {
|
|
434
|
+
console.log(chalk_1.default.white('Workflows:'));
|
|
435
|
+
relevantRuns.forEach((workflow) => {
|
|
436
|
+
const icon = workflow.conclusion === 'success' ? '✅' :
|
|
437
|
+
workflow.status === 'in_progress' ? '⏳' : '❌';
|
|
438
|
+
console.log(chalk_1.default.gray(` ${icon} ${workflow.name}: ${workflow.conclusion || workflow.status}`));
|
|
439
|
+
});
|
|
440
|
+
console.log();
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
else {
|
|
444
|
+
console.log(chalk_1.default.yellow(`⚠️ GitHub operation "${intent.action}" not yet implemented\n`));
|
|
445
|
+
}
|
|
446
|
+
(0, analytics_1.trackEvent)({ event: analytics_1.EVENTS.NATURAL_COMMAND_SUCCESS });
|
|
447
|
+
}
|
|
448
|
+
catch (error) {
|
|
449
|
+
console.log(chalk_1.default.red(`❌ ${error.message}\n`));
|
|
450
|
+
(0, analytics_1.trackEvent)({ event: analytics_1.EVENTS.NATURAL_COMMAND_ERROR });
|
|
451
|
+
}
|
|
452
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -20,6 +20,7 @@ const login_1 = require("./commands/login");
|
|
|
20
20
|
const natural_1 = require("./commands/natural");
|
|
21
21
|
const conflict_1 = require("./commands/conflict");
|
|
22
22
|
const uninstall_1 = require("./commands/uninstall");
|
|
23
|
+
const github_connect_1 = require("./commands/github-connect");
|
|
23
24
|
const repl_1 = require("./repl");
|
|
24
25
|
// Load environment variables from root .env
|
|
25
26
|
(0, dotenv_1.config)({ path: path_1.default.join(__dirname, '../../.env') });
|
|
@@ -120,6 +121,28 @@ program
|
|
|
120
121
|
.action(async () => {
|
|
121
122
|
await (0, conflict_1.conflictCommand)();
|
|
122
123
|
});
|
|
124
|
+
// Command: snapcommit github
|
|
125
|
+
const githubCmd = program
|
|
126
|
+
.command('github')
|
|
127
|
+
.description('GitHub integration commands');
|
|
128
|
+
githubCmd
|
|
129
|
+
.command('connect [token]')
|
|
130
|
+
.description('Connect your GitHub account')
|
|
131
|
+
.action(async (token) => {
|
|
132
|
+
await (0, github_connect_1.githubConnectCommand)(token);
|
|
133
|
+
});
|
|
134
|
+
githubCmd
|
|
135
|
+
.command('status')
|
|
136
|
+
.description('Check GitHub connection status')
|
|
137
|
+
.action(async () => {
|
|
138
|
+
await (0, github_connect_1.githubStatusCommand)();
|
|
139
|
+
});
|
|
140
|
+
githubCmd
|
|
141
|
+
.command('disconnect')
|
|
142
|
+
.description('Disconnect GitHub account')
|
|
143
|
+
.action(async () => {
|
|
144
|
+
await (0, github_connect_1.githubDisconnectCommand)();
|
|
145
|
+
});
|
|
123
146
|
// Command: snapcommit uninstall
|
|
124
147
|
program
|
|
125
148
|
.command('uninstall')
|
package/dist/lib/auth.js
CHANGED
|
@@ -133,6 +133,14 @@ async function promptAuth() {
|
|
|
133
133
|
console.log(chalk_1.default.gray(' • ') + chalk_1.default.cyan('snap quick') + chalk_1.default.gray(' - AI commit in any repo'));
|
|
134
134
|
console.log(chalk_1.default.gray(' • ') + chalk_1.default.cyan('snap') + chalk_1.default.gray(' - Natural language Git commands'));
|
|
135
135
|
console.log(chalk_1.default.gray(' • Type ') + chalk_1.default.cyan('exit') + chalk_1.default.gray(' to leave SnapCommit\n'));
|
|
136
|
+
console.log(chalk_1.default.yellow('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
|
|
137
|
+
console.log(chalk_1.default.bold('💡 Want GitHub features too?\n'));
|
|
138
|
+
console.log(chalk_1.default.gray(' Create PRs, check CI, and more with natural language!'));
|
|
139
|
+
console.log(chalk_1.default.gray(' Run: ') + chalk_1.default.cyan('snap github connect'));
|
|
140
|
+
console.log(chalk_1.default.gray(' (You\'ll need a GitHub Personal Access Token - Classic)\n'));
|
|
141
|
+
console.log(chalk_1.default.gray(' Get one at: ') + chalk_1.default.cyan('https://github.com/settings/tokens'));
|
|
142
|
+
console.log(chalk_1.default.gray(' Scopes needed: ') + chalk_1.default.white('repo, workflow, read:user'));
|
|
143
|
+
console.log(chalk_1.default.gray(' 💡 Tip: Set no expiration or remember to renew!\n'));
|
|
136
144
|
return true;
|
|
137
145
|
}
|
|
138
146
|
else {
|
package/dist/repl.js
CHANGED
|
@@ -10,6 +10,7 @@ const auth_1 = require("./lib/auth");
|
|
|
10
10
|
const natural_1 = require("./commands/natural");
|
|
11
11
|
const quick_1 = require("./commands/quick");
|
|
12
12
|
const stats_1 = require("./commands/stats");
|
|
13
|
+
const github_connect_1 = require("./commands/github-connect");
|
|
13
14
|
/**
|
|
14
15
|
* Start SnapCommit REPL (Read-Eval-Print-Loop)
|
|
15
16
|
* Interactive mode for natural language Git commands
|
|
@@ -27,12 +28,29 @@ async function startREPL() {
|
|
|
27
28
|
process.exit(1);
|
|
28
29
|
}
|
|
29
30
|
console.log(chalk_1.default.green(`✅ Logged in as ${chalk_1.default.bold(authConfig.email)}\n`));
|
|
31
|
+
// Check GitHub connection status
|
|
32
|
+
const githubConnected = (0, github_connect_1.isGitHubConnected)();
|
|
33
|
+
if (githubConnected) {
|
|
34
|
+
const githubConfig = (0, github_connect_1.getGitHubConfig)();
|
|
35
|
+
console.log(chalk_1.default.green(`✅ GitHub connected as ${chalk_1.default.bold('@' + githubConfig?.username)}\n`));
|
|
36
|
+
}
|
|
30
37
|
console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
|
|
31
38
|
console.log(chalk_1.default.bold('💡 What can SnapCommit do?\n'));
|
|
32
39
|
console.log(chalk_1.default.gray(' • ') + chalk_1.default.white('Natural language Git: ') + chalk_1.default.cyan('"undo my last commit"'));
|
|
33
40
|
console.log(chalk_1.default.gray(' • ') + chalk_1.default.white('Quick AI commits: ') + chalk_1.default.cyan('quick'));
|
|
34
|
-
|
|
41
|
+
if (githubConnected) {
|
|
42
|
+
console.log(chalk_1.default.gray(' • ') + chalk_1.default.white('GitHub operations: ') + chalk_1.default.cyan('"create a PR", "check CI"'));
|
|
43
|
+
}
|
|
35
44
|
console.log(chalk_1.default.gray(' • ') + chalk_1.default.white('Exit SnapCommit: ') + chalk_1.default.cyan('exit') + chalk_1.default.gray(' or ') + chalk_1.default.cyan('quit\n'));
|
|
45
|
+
// Show GitHub setup reminder if not connected
|
|
46
|
+
if (!githubConnected) {
|
|
47
|
+
console.log(chalk_1.default.yellow('💡 Want GitHub features? (Create PRs, check CI, etc.)\n'));
|
|
48
|
+
console.log(chalk_1.default.gray(' Run: ') + chalk_1.default.cyan('snap github connect'));
|
|
49
|
+
console.log(chalk_1.default.gray(' You\'ll need a GitHub Personal Access Token (Classic)'));
|
|
50
|
+
console.log(chalk_1.default.gray(' Get one at: ') + chalk_1.default.cyan('https://github.com/settings/tokens'));
|
|
51
|
+
console.log(chalk_1.default.gray(' Scopes: ') + chalk_1.default.white('repo, workflow, read:user'));
|
|
52
|
+
console.log(chalk_1.default.gray(' 💡 Set no expiration or remember to renew!\n'));
|
|
53
|
+
}
|
|
36
54
|
console.log(chalk_1.default.gray('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
|
|
37
55
|
console.log(chalk_1.default.bold.yellow('🎯 Try it now! Type what you want to do:\n'));
|
|
38
56
|
const rl = readline_1.default.createInterface({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@snapcommit/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Instant AI commits. Beautiful progress tracking. Never write commit messages again.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@anthropic-ai/sdk": "^0.30.1",
|
|
51
51
|
"@google/generative-ai": "^0.21.0",
|
|
52
|
+
"@octokit/rest": "^22.0.1",
|
|
52
53
|
"@supabase/supabase-js": "^2.78.0",
|
|
53
54
|
"better-sqlite3": "^11.5.0",
|
|
54
55
|
"chalk": "^5.3.0",
|