@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,524 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.executeNaturalLanguageCommand = executeNaturalLanguageCommand;
|
|
40
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
41
|
+
const child_process_1 = require("child_process");
|
|
42
|
+
const git_interpreter_1 = require("../ai/git-interpreter");
|
|
43
|
+
const gemini_client_1 = require("../ai/gemini-client");
|
|
44
|
+
const quick_1 = require("../commands/quick");
|
|
45
|
+
const stats_1 = require("../commands/stats");
|
|
46
|
+
const readline_1 = __importDefault(require("readline"));
|
|
47
|
+
const github = __importStar(require("../lib/github"));
|
|
48
|
+
const gitAdvanced = __importStar(require("../commands/git-advanced"));
|
|
49
|
+
/**
|
|
50
|
+
* Execute a natural language command in the REPL
|
|
51
|
+
*/
|
|
52
|
+
async function executeNaturalLanguageCommand(input, context) {
|
|
53
|
+
// Normalize input (handle references like "that", "it", etc.)
|
|
54
|
+
const normalizedInput = normalizeInput(input, context);
|
|
55
|
+
// Check for clarification needs
|
|
56
|
+
const clarification = await (0, gemini_client_1.needsClarificationGemini)(normalizedInput);
|
|
57
|
+
if (clarification.needsClarification && clarification.options) {
|
|
58
|
+
const choice = await askForClarification(clarification.options);
|
|
59
|
+
if (!choice) {
|
|
60
|
+
console.log(chalk_1.default.gray('\n🚫 Cancelled\n'));
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// Re-execute with clarified intent
|
|
64
|
+
await executeNaturalLanguageCommand(choice, context);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
// Get Git context
|
|
68
|
+
const gitContext = getGitContext();
|
|
69
|
+
// Pattern matching for common commands (fast path)
|
|
70
|
+
const handled = await tryQuickCommands(normalizedInput, context);
|
|
71
|
+
if (handled) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
// AI interpretation
|
|
75
|
+
console.log(chalk_1.default.gray('\n🤖 Understanding your request...\n'));
|
|
76
|
+
try {
|
|
77
|
+
const intent = await (0, git_interpreter_1.interpretGitCommand)(normalizedInput, gitContext);
|
|
78
|
+
// Show what we'll do
|
|
79
|
+
console.log(chalk_1.default.bold(intent.action));
|
|
80
|
+
console.log(chalk_1.default.gray(intent.explanation));
|
|
81
|
+
// Safety warning for high-risk operations
|
|
82
|
+
if (intent.riskLevel === 'high' && intent.safetyWarning) {
|
|
83
|
+
console.log(chalk_1.default.yellow(`\n⚠️ ${intent.safetyWarning}`));
|
|
84
|
+
}
|
|
85
|
+
// Show commands (learning mode)
|
|
86
|
+
if (intent.gitCommands.length > 0) {
|
|
87
|
+
console.log(chalk_1.default.gray(`\n💡 Commands: ${intent.gitCommands.join(' && ')}`));
|
|
88
|
+
}
|
|
89
|
+
// Ask for confirmation for medium/high risk operations
|
|
90
|
+
if (intent.riskLevel === 'medium' || intent.riskLevel === 'high') {
|
|
91
|
+
const confirmed = await askForConfirmation();
|
|
92
|
+
if (!confirmed) {
|
|
93
|
+
console.log(chalk_1.default.gray('\n🚫 Cancelled\n'));
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Execute commands
|
|
98
|
+
if (intent.gitCommands.length > 0) {
|
|
99
|
+
console.log('');
|
|
100
|
+
for (const cmd of intent.gitCommands) {
|
|
101
|
+
try {
|
|
102
|
+
console.log(chalk_1.default.gray(` Running: ${cmd}`));
|
|
103
|
+
(0, child_process_1.execSync)(cmd, { stdio: 'inherit' });
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
console.log(chalk_1.default.red(`\n❌ Command failed: ${cmd}`));
|
|
107
|
+
// Try smart problem solving
|
|
108
|
+
console.log(chalk_1.default.gray('\n🤔 Let me try to fix this...\n'));
|
|
109
|
+
const solution = await (0, gemini_client_1.solveGitProblemGemini)(normalizedInput, {
|
|
110
|
+
currentBranch: gitContext.currentBranch,
|
|
111
|
+
gitStatus: gitContext.gitStatus || '',
|
|
112
|
+
recentError: String(error),
|
|
113
|
+
});
|
|
114
|
+
if (solution.success && solution.gitCommands) {
|
|
115
|
+
console.log(chalk_1.default.cyan(`💡 ${solution.message}\n`));
|
|
116
|
+
for (const fixCmd of solution.gitCommands) {
|
|
117
|
+
console.log(chalk_1.default.gray(` Running: ${fixCmd}`));
|
|
118
|
+
(0, child_process_1.execSync)(fixCmd, { stdio: 'inherit' });
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
console.log(chalk_1.default.red(`\n❌ ${solution.message}\n`));
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
console.log(chalk_1.default.green('\n✅ Done!\n'));
|
|
128
|
+
// Update context
|
|
129
|
+
updateContext(context, intent, normalizedInput);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
console.log(chalk_1.default.yellow('\n⚠️ No commands to execute\n'));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
console.log(chalk_1.default.red(`\n❌ Error: ${error.message}\n`));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Normalize user input (handle "that", "it", etc.)
|
|
141
|
+
*/
|
|
142
|
+
function normalizeInput(input, context) {
|
|
143
|
+
let normalized = input;
|
|
144
|
+
// Replace "that" with last context
|
|
145
|
+
if (normalized.includes('that') && context.lastBranch) {
|
|
146
|
+
normalized = normalized.replace(/\bthat\b/gi, context.lastBranch);
|
|
147
|
+
}
|
|
148
|
+
// Replace "it" with last action
|
|
149
|
+
if (normalized.includes('it') && context.lastBranch) {
|
|
150
|
+
normalized = normalized.replace(/\bit\b/gi, context.lastBranch);
|
|
151
|
+
}
|
|
152
|
+
return normalized;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Try to handle common commands quickly (pattern matching)
|
|
156
|
+
*/
|
|
157
|
+
async function tryQuickCommands(input, context) {
|
|
158
|
+
const lower = input.toLowerCase();
|
|
159
|
+
// Commit commands
|
|
160
|
+
if (lower === 'commit' ||
|
|
161
|
+
lower === 'commit my changes' ||
|
|
162
|
+
lower === 'commit my work' ||
|
|
163
|
+
lower.startsWith('commit ')) {
|
|
164
|
+
await (0, quick_1.quickCommand)();
|
|
165
|
+
context.lastAction = 'commit';
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
// Stats commands
|
|
169
|
+
if (lower === 'stats' ||
|
|
170
|
+
lower === 'show me my stats' ||
|
|
171
|
+
lower === 'show stats' ||
|
|
172
|
+
lower === 'show me my progress' ||
|
|
173
|
+
lower === 'show progress') {
|
|
174
|
+
(0, stats_1.statsCommand)();
|
|
175
|
+
return true;
|
|
176
|
+
}
|
|
177
|
+
// Push commands
|
|
178
|
+
if (lower === 'push' || lower === 'push it' || lower === 'push that') {
|
|
179
|
+
try {
|
|
180
|
+
console.log(chalk_1.default.gray('\n📤 Pushing to remote...\n'));
|
|
181
|
+
(0, child_process_1.execSync)('git push', { stdio: 'inherit' });
|
|
182
|
+
console.log(chalk_1.default.green('\n✅ Pushed!\n'));
|
|
183
|
+
context.lastAction = 'push';
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
console.log(chalk_1.default.red('\n❌ Push failed\n'));
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// Pull commands
|
|
192
|
+
if (lower === 'pull' || lower === 'pull latest' || lower === 'pull changes') {
|
|
193
|
+
try {
|
|
194
|
+
console.log(chalk_1.default.gray('\n📥 Pulling from remote...\n'));
|
|
195
|
+
(0, child_process_1.execSync)('git pull', { stdio: 'inherit' });
|
|
196
|
+
console.log(chalk_1.default.green('\n✅ Pulled!\n'));
|
|
197
|
+
context.lastAction = 'pull';
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
console.log(chalk_1.default.red('\n❌ Pull failed\n'));
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// Status commands
|
|
206
|
+
if (lower === 'status' || lower === 'show status' || lower === 'what changed') {
|
|
207
|
+
try {
|
|
208
|
+
console.log('');
|
|
209
|
+
(0, child_process_1.execSync)('git status', { stdio: 'inherit' });
|
|
210
|
+
console.log('');
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
213
|
+
catch (error) {
|
|
214
|
+
console.log(chalk_1.default.red('\n❌ Failed to get status\n'));
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
// GitHub: Create PR
|
|
219
|
+
if (lower === 'create pr' ||
|
|
220
|
+
lower === 'create a pr' ||
|
|
221
|
+
lower === 'make a pr' ||
|
|
222
|
+
lower === 'open pr' ||
|
|
223
|
+
lower === 'create pull request' ||
|
|
224
|
+
lower.includes('create pr')) {
|
|
225
|
+
await handleCreatePR(context);
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
// GitHub: Check CI
|
|
229
|
+
if (lower === 'check ci' ||
|
|
230
|
+
lower === 'ci status' ||
|
|
231
|
+
lower === 'check status' ||
|
|
232
|
+
lower === 'did ci pass' ||
|
|
233
|
+
lower === 'check if ci passed') {
|
|
234
|
+
await handleCheckCI();
|
|
235
|
+
return true;
|
|
236
|
+
}
|
|
237
|
+
// GitHub: List PRs
|
|
238
|
+
if (lower === 'list prs' ||
|
|
239
|
+
lower === 'show prs' ||
|
|
240
|
+
lower === 'my prs' ||
|
|
241
|
+
lower === 'pull requests') {
|
|
242
|
+
await handleListPRs();
|
|
243
|
+
return true;
|
|
244
|
+
}
|
|
245
|
+
// GitHub: Merge PR
|
|
246
|
+
const mergePRMatch = lower.match(/merge pr (\d+)/);
|
|
247
|
+
if (mergePRMatch) {
|
|
248
|
+
await handleMergePR(parseInt(mergePRMatch[1], 10));
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
// Git Advanced: Stash
|
|
252
|
+
if (lower === 'stash' ||
|
|
253
|
+
lower === 'stash my changes' ||
|
|
254
|
+
lower === 'stash changes' ||
|
|
255
|
+
lower === 'save my work' ||
|
|
256
|
+
lower.startsWith('stash ')) {
|
|
257
|
+
const messageMatch = input.match(/stash (?:my changes |changes )?(.+)/i);
|
|
258
|
+
await gitAdvanced.stashChanges(messageMatch ? messageMatch[1] : undefined);
|
|
259
|
+
context.lastAction = 'stash';
|
|
260
|
+
return true;
|
|
261
|
+
}
|
|
262
|
+
// Git Advanced: List stash
|
|
263
|
+
if (lower === 'list stash' || lower === 'show stash' || lower === 'stash list') {
|
|
264
|
+
gitAdvanced.listStash();
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
// Git Advanced: Apply stash
|
|
268
|
+
if (lower === 'apply stash' || lower === 'pop stash' || lower.includes('unstash')) {
|
|
269
|
+
if (lower.includes('pop')) {
|
|
270
|
+
await gitAdvanced.popStash();
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
await gitAdvanced.applyStash();
|
|
274
|
+
}
|
|
275
|
+
context.lastAction = 'apply_stash';
|
|
276
|
+
return true;
|
|
277
|
+
}
|
|
278
|
+
// Git Advanced: Create branch
|
|
279
|
+
const createBranchMatch = input.match(/(?:create|make|new) (?:a )?branch (?:called )?(.+)/i);
|
|
280
|
+
if (createBranchMatch) {
|
|
281
|
+
const branchName = createBranchMatch[1].trim();
|
|
282
|
+
await gitAdvanced.createBranch(branchName);
|
|
283
|
+
context.lastBranch = branchName;
|
|
284
|
+
context.lastAction = 'create_branch';
|
|
285
|
+
return true;
|
|
286
|
+
}
|
|
287
|
+
// Git Advanced: Switch branch
|
|
288
|
+
const switchBranchMatch = input.match(/(?:switch to|checkout|go to) (?:branch )?(.+)/i);
|
|
289
|
+
if (switchBranchMatch && !lower.includes('main') && !lower.includes('master')) {
|
|
290
|
+
const branchName = switchBranchMatch[1].trim();
|
|
291
|
+
await gitAdvanced.switchBranch(branchName);
|
|
292
|
+
context.lastBranch = branchName;
|
|
293
|
+
context.lastAction = 'switch_branch';
|
|
294
|
+
return true;
|
|
295
|
+
}
|
|
296
|
+
// Git Advanced: Merge branch
|
|
297
|
+
const mergeBranchMatch = input.match(/merge (?:branch )?(.+?)(?: into| to)?/i);
|
|
298
|
+
if (mergeBranchMatch && !lower.includes('pr')) {
|
|
299
|
+
const branchName = mergeBranchMatch[1].trim();
|
|
300
|
+
await gitAdvanced.mergeBranch(branchName);
|
|
301
|
+
context.lastAction = 'merge';
|
|
302
|
+
return true;
|
|
303
|
+
}
|
|
304
|
+
// Git Advanced: Delete branch
|
|
305
|
+
const deleteBranchMatch = input.match(/delete (?:branch )?(.+)/i);
|
|
306
|
+
if (deleteBranchMatch) {
|
|
307
|
+
const branchName = deleteBranchMatch[1].trim();
|
|
308
|
+
await gitAdvanced.deleteBranch(branchName);
|
|
309
|
+
context.lastAction = 'delete_branch';
|
|
310
|
+
return true;
|
|
311
|
+
}
|
|
312
|
+
// Git Advanced: Rebase
|
|
313
|
+
const rebaseMatch = input.match(/rebase (?:onto )?(.+)/i);
|
|
314
|
+
if (rebaseMatch) {
|
|
315
|
+
const targetBranch = rebaseMatch[1].trim();
|
|
316
|
+
await gitAdvanced.rebaseOnto(targetBranch);
|
|
317
|
+
context.lastAction = 'rebase';
|
|
318
|
+
return true;
|
|
319
|
+
}
|
|
320
|
+
// Git Advanced: Cherry-pick
|
|
321
|
+
const cherryPickMatch = input.match(/cherry[- ]?pick (.+)/i);
|
|
322
|
+
if (cherryPickMatch) {
|
|
323
|
+
const commitHash = cherryPickMatch[1].trim();
|
|
324
|
+
await gitAdvanced.cherryPick(commitHash);
|
|
325
|
+
context.lastAction = 'cherry_pick';
|
|
326
|
+
return true;
|
|
327
|
+
}
|
|
328
|
+
// Git Advanced: Amend
|
|
329
|
+
if (lower === 'amend' || lower === 'amend commit' || lower === 'fix commit') {
|
|
330
|
+
await gitAdvanced.amendCommit();
|
|
331
|
+
context.lastAction = 'amend';
|
|
332
|
+
return true;
|
|
333
|
+
}
|
|
334
|
+
// Git Advanced: Show log
|
|
335
|
+
if (lower === 'log' ||
|
|
336
|
+
lower === 'show log' ||
|
|
337
|
+
lower === 'history' ||
|
|
338
|
+
lower === 'show history' ||
|
|
339
|
+
lower.includes('last commits')) {
|
|
340
|
+
gitAdvanced.showLog();
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
// Git Advanced: Show diff
|
|
344
|
+
if (lower === 'diff' || lower === 'show diff' || lower === 'what changed' || lower === 'changes') {
|
|
345
|
+
gitAdvanced.showDiff();
|
|
346
|
+
return true;
|
|
347
|
+
}
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Handle creating a PR
|
|
352
|
+
*/
|
|
353
|
+
async function handleCreatePR(context) {
|
|
354
|
+
try {
|
|
355
|
+
console.log(chalk_1.default.gray('\n🔄 Creating pull request...\n'));
|
|
356
|
+
const pr = await github.createPullRequest({});
|
|
357
|
+
console.log(chalk_1.default.green(`✅ PR #${pr.number} created: ${pr.title}`));
|
|
358
|
+
console.log(chalk_1.default.gray(` URL: ${pr.html_url}\n`));
|
|
359
|
+
context.lastAction = 'create_pr';
|
|
360
|
+
}
|
|
361
|
+
catch (error) {
|
|
362
|
+
console.log(chalk_1.default.red(`\n❌ Failed to create PR: ${error.message}\n`));
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Handle checking CI status
|
|
367
|
+
*/
|
|
368
|
+
async function handleCheckCI() {
|
|
369
|
+
try {
|
|
370
|
+
console.log(chalk_1.default.gray('\n🔍 Checking CI/CD status...\n'));
|
|
371
|
+
const { status, checks } = await github.getCommitStatus();
|
|
372
|
+
console.log(chalk_1.default.bold('⏳ CI Status:\n'));
|
|
373
|
+
// Show overall status
|
|
374
|
+
if (status.state === 'success') {
|
|
375
|
+
console.log(chalk_1.default.green(` ✅ All checks passed`));
|
|
376
|
+
}
|
|
377
|
+
else if (status.state === 'pending') {
|
|
378
|
+
console.log(chalk_1.default.yellow(` ⏳ Checks running...`));
|
|
379
|
+
}
|
|
380
|
+
else if (status.state === 'failure') {
|
|
381
|
+
console.log(chalk_1.default.red(` ❌ Some checks failed`));
|
|
382
|
+
}
|
|
383
|
+
// Show individual checks
|
|
384
|
+
if (checks.length > 0) {
|
|
385
|
+
console.log('');
|
|
386
|
+
checks.forEach((check) => {
|
|
387
|
+
const icon = check.status === 'completed' && check.conclusion === 'success'
|
|
388
|
+
? chalk_1.default.green('✅')
|
|
389
|
+
: check.status === 'in_progress'
|
|
390
|
+
? chalk_1.default.yellow('⏳')
|
|
391
|
+
: chalk_1.default.red('❌');
|
|
392
|
+
console.log(` ${icon} ${check.name}`);
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
console.log('');
|
|
396
|
+
}
|
|
397
|
+
catch (error) {
|
|
398
|
+
console.log(chalk_1.default.red(`\n❌ Failed to check CI: ${error.message}\n`));
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Handle listing PRs
|
|
403
|
+
*/
|
|
404
|
+
async function handleListPRs() {
|
|
405
|
+
try {
|
|
406
|
+
console.log(chalk_1.default.gray('\n🔍 Fetching pull requests...\n'));
|
|
407
|
+
const prs = await github.listPullRequests({ limit: 5 });
|
|
408
|
+
if (prs.length === 0) {
|
|
409
|
+
console.log(chalk_1.default.gray(' No open pull requests\n'));
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
console.log(chalk_1.default.bold('📋 Open Pull Requests:\n'));
|
|
413
|
+
prs.forEach((pr) => {
|
|
414
|
+
console.log(chalk_1.default.cyan(` #${pr.number}`) + ` ${pr.title}`);
|
|
415
|
+
console.log(chalk_1.default.gray(` ${pr.user.login} → ${pr.base.ref}`));
|
|
416
|
+
});
|
|
417
|
+
console.log('');
|
|
418
|
+
}
|
|
419
|
+
catch (error) {
|
|
420
|
+
console.log(chalk_1.default.red(`\n❌ Failed to list PRs: ${error.message}\n`));
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Handle merging a PR
|
|
425
|
+
*/
|
|
426
|
+
async function handleMergePR(prNumber) {
|
|
427
|
+
try {
|
|
428
|
+
console.log(chalk_1.default.gray(`\n🔄 Merging PR #${prNumber}...\n`));
|
|
429
|
+
const result = await github.mergePullRequest(prNumber);
|
|
430
|
+
console.log(chalk_1.default.green(`✅ PR #${prNumber} merged!`));
|
|
431
|
+
console.log(chalk_1.default.gray(` SHA: ${result.sha}\n`));
|
|
432
|
+
}
|
|
433
|
+
catch (error) {
|
|
434
|
+
console.log(chalk_1.default.red(`\n❌ Failed to merge PR: ${error.message}\n`));
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Get current Git context
|
|
439
|
+
*/
|
|
440
|
+
function getGitContext() {
|
|
441
|
+
try {
|
|
442
|
+
const currentBranch = (0, child_process_1.execSync)('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8' }).trim();
|
|
443
|
+
const gitStatus = (0, child_process_1.execSync)('git status', { encoding: 'utf-8' }).trim();
|
|
444
|
+
const hasUncommittedChanges = gitStatus.includes('Changes not staged') || gitStatus.includes('Changes to be committed');
|
|
445
|
+
let lastCommitHash;
|
|
446
|
+
try {
|
|
447
|
+
lastCommitHash = (0, child_process_1.execSync)('git rev-parse HEAD', { encoding: 'utf-8' }).trim();
|
|
448
|
+
}
|
|
449
|
+
catch {
|
|
450
|
+
lastCommitHash = undefined;
|
|
451
|
+
}
|
|
452
|
+
return {
|
|
453
|
+
currentBranch,
|
|
454
|
+
hasUncommittedChanges,
|
|
455
|
+
lastCommitHash,
|
|
456
|
+
gitStatus,
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
catch (error) {
|
|
460
|
+
return {
|
|
461
|
+
currentBranch: 'unknown',
|
|
462
|
+
hasUncommittedChanges: false,
|
|
463
|
+
gitStatus: '',
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Ask user for confirmation
|
|
469
|
+
*/
|
|
470
|
+
async function askForConfirmation() {
|
|
471
|
+
return new Promise((resolve) => {
|
|
472
|
+
const rl = readline_1.default.createInterface({
|
|
473
|
+
input: process.stdin,
|
|
474
|
+
output: process.stdout,
|
|
475
|
+
});
|
|
476
|
+
rl.question(chalk_1.default.cyan('\nContinue? (y/N): '), (answer) => {
|
|
477
|
+
rl.close();
|
|
478
|
+
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
|
|
479
|
+
});
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* Ask user for clarification
|
|
484
|
+
*/
|
|
485
|
+
async function askForClarification(options) {
|
|
486
|
+
return new Promise((resolve) => {
|
|
487
|
+
console.log(chalk_1.default.yellow('\n🤔 I need clarification:\n'));
|
|
488
|
+
options.forEach((opt, i) => {
|
|
489
|
+
console.log(chalk_1.default.cyan(` ${i + 1}) ${opt.label}`));
|
|
490
|
+
});
|
|
491
|
+
console.log('');
|
|
492
|
+
const rl = readline_1.default.createInterface({
|
|
493
|
+
input: process.stdin,
|
|
494
|
+
output: process.stdout,
|
|
495
|
+
});
|
|
496
|
+
rl.question(chalk_1.default.cyan('Choose (1-' + options.length + ') or (c)ancel: '), (answer) => {
|
|
497
|
+
rl.close();
|
|
498
|
+
if (answer.toLowerCase() === 'c' || answer.toLowerCase() === 'cancel') {
|
|
499
|
+
resolve(null);
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
const choice = parseInt(answer, 10);
|
|
503
|
+
if (choice >= 1 && choice <= options.length) {
|
|
504
|
+
resolve(options[choice - 1].value);
|
|
505
|
+
}
|
|
506
|
+
else {
|
|
507
|
+
console.log(chalk_1.default.red('\n❌ Invalid choice\n'));
|
|
508
|
+
resolve(null);
|
|
509
|
+
}
|
|
510
|
+
});
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
/**
|
|
514
|
+
* Update context after successful command
|
|
515
|
+
*/
|
|
516
|
+
function updateContext(context, intent, input) {
|
|
517
|
+
// Extract branch names from commands
|
|
518
|
+
const branchMatch = intent.gitCommands.join(' ').match(/(?:checkout|branch|switch) (\S+)/);
|
|
519
|
+
if (branchMatch) {
|
|
520
|
+
context.lastBranch = branchMatch[1];
|
|
521
|
+
}
|
|
522
|
+
// Store last action
|
|
523
|
+
context.lastAction = intent.action;
|
|
524
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Privacy-focused analytics tracking
|
|
4
|
+
* Stores locally for insights, no external tracking
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.EVENTS = void 0;
|
|
8
|
+
exports.trackEvent = trackEvent;
|
|
9
|
+
const database_1 = require("../db/database");
|
|
10
|
+
/**
|
|
11
|
+
* Track an event (privacy-friendly, local only)
|
|
12
|
+
*/
|
|
13
|
+
function trackEvent(eventData) {
|
|
14
|
+
try {
|
|
15
|
+
(0, database_1.logAnalyticsEvent)(eventData.event, eventData.data || {});
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
// Silent fail - don't break user experience for analytics
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Get common event types (for consistency)
|
|
23
|
+
*/
|
|
24
|
+
exports.EVENTS = {
|
|
25
|
+
COMMIT_SUCCESS: 'commit_success',
|
|
26
|
+
COMMIT_ERROR: 'commit_error',
|
|
27
|
+
COMMIT_BLOCKED: 'commit_blocked',
|
|
28
|
+
RATE_LIMITED: 'rate_limited',
|
|
29
|
+
TRIAL_STARTED: 'trial_started',
|
|
30
|
+
PRO_ACTIVATED: 'pro_activated',
|
|
31
|
+
NATURAL_COMMAND_SUCCESS: 'natural_command_success',
|
|
32
|
+
NATURAL_COMMAND_ERROR: 'natural_command_error',
|
|
33
|
+
CONFLICT_RESOLVED: 'conflict_resolved',
|
|
34
|
+
ONBOARDING_COMPLETED: 'onboarding_completed',
|
|
35
|
+
SETUP_COMPLETED: 'setup_completed',
|
|
36
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Auth token storage utilities
|
|
4
|
+
* Stores Supabase auth tokens securely in local database
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.saveAuthToken = saveAuthToken;
|
|
11
|
+
exports.getAuthToken = getAuthToken;
|
|
12
|
+
exports.clearAuthToken = clearAuthToken;
|
|
13
|
+
const database_1 = require("../db/database");
|
|
14
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
15
|
+
/**
|
|
16
|
+
* Save auth tokens to local database
|
|
17
|
+
*/
|
|
18
|
+
async function saveAuthToken(accessToken, refreshToken) {
|
|
19
|
+
try {
|
|
20
|
+
const db = (0, database_1.getDB)();
|
|
21
|
+
db.prepare(`
|
|
22
|
+
INSERT OR REPLACE INTO auth_tokens (id, access_token, refresh_token, updated_at)
|
|
23
|
+
VALUES (1, ?, ?, ?)
|
|
24
|
+
`).run(accessToken, refreshToken || null, Date.now());
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
console.error(chalk_1.default.red('Failed to save auth token:'), error.message);
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Get auth tokens from local database
|
|
34
|
+
*/
|
|
35
|
+
function getAuthToken() {
|
|
36
|
+
try {
|
|
37
|
+
const db = (0, database_1.getDB)();
|
|
38
|
+
const row = db.prepare(`
|
|
39
|
+
SELECT access_token, refresh_token FROM auth_tokens WHERE id = 1
|
|
40
|
+
`).get();
|
|
41
|
+
if (!row)
|
|
42
|
+
return null;
|
|
43
|
+
return {
|
|
44
|
+
accessToken: row.access_token,
|
|
45
|
+
refreshToken: row.refresh_token || undefined,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Clear auth tokens from local database
|
|
54
|
+
*/
|
|
55
|
+
async function clearAuthToken() {
|
|
56
|
+
try {
|
|
57
|
+
const db = (0, database_1.getDB)();
|
|
58
|
+
db.prepare('DELETE FROM auth_tokens').run();
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
console.error(chalk_1.default.red('Failed to clear auth token:'), error.message);
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|