@snapcommit/cli 1.0.0 → 1.0.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/dist/ai/git-interpreter.js +33 -171
- package/package.json +1 -1
- package/dist/utils/auth-storage.js +0 -65
|
@@ -1,188 +1,50 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
3
|
* Natural Language Git Command Interpreter
|
|
4
|
-
* Uses Claude to understand user intent and map to Git operations
|
|
4
|
+
* Uses backend API (Claude/Gemini) to understand user intent and map to Git operations
|
|
5
5
|
*/
|
|
6
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
-
if (k2 === undefined) k2 = k;
|
|
8
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
-
}
|
|
12
|
-
Object.defineProperty(o, k2, desc);
|
|
13
|
-
}) : (function(o, m, k, k2) {
|
|
14
|
-
if (k2 === undefined) k2 = k;
|
|
15
|
-
o[k2] = m[k];
|
|
16
|
-
}));
|
|
17
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
-
}) : function(o, v) {
|
|
20
|
-
o["default"] = v;
|
|
21
|
-
});
|
|
22
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
-
var ownKeys = function(o) {
|
|
24
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
-
var ar = [];
|
|
26
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
-
return ar;
|
|
28
|
-
};
|
|
29
|
-
return ownKeys(o);
|
|
30
|
-
};
|
|
31
|
-
return function (mod) {
|
|
32
|
-
if (mod && mod.__esModule) return mod;
|
|
33
|
-
var result = {};
|
|
34
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
-
__setModuleDefault(result, mod);
|
|
36
|
-
return result;
|
|
37
|
-
};
|
|
38
|
-
})();
|
|
39
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
40
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
41
|
-
};
|
|
42
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
7
|
exports.interpretGitCommand = interpretGitCommand;
|
|
44
8
|
exports.suggestNextActions = suggestNextActions;
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
9
|
+
const auth_1 = require("../lib/auth");
|
|
10
|
+
// API URL - defaults to production
|
|
11
|
+
const API_BASE_URL = process.env.SNAPCOMMIT_API_URL || 'https://snapcommit.dev';
|
|
12
|
+
/**
|
|
13
|
+
* Interpret natural language command using backend API
|
|
14
|
+
*/
|
|
50
15
|
async function interpretGitCommand(userInput, context) {
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
Current context:
|
|
56
|
-
- Branch: ${context.currentBranch}
|
|
57
|
-
- Uncommitted changes: ${context.hasUncommittedChanges}
|
|
58
|
-
- Last commit: ${context.lastCommitHash || 'none'}
|
|
59
|
-
- Remote: ${context.remoteBranch || 'none'}
|
|
60
|
-
|
|
61
|
-
Respond with a JSON object (and ONLY JSON, no markdown):
|
|
62
|
-
{
|
|
63
|
-
"action": "commit|revert|merge|branch|reset|stash|push|pull|rebase|cherry-pick|etc",
|
|
64
|
-
"target": "specific target if any (branch, commit, file)",
|
|
65
|
-
"options": {"key": "value"},
|
|
66
|
-
"confidence": 0.95,
|
|
67
|
-
"explanation": "This will undo your last commit but keep all your changes staged",
|
|
68
|
-
"gitCommands": ["git reset --soft HEAD~1", "git status"],
|
|
69
|
-
"riskLevel": "safe|medium|high",
|
|
70
|
-
"needsConfirmation": true,
|
|
71
|
-
"educationalTip": "The --soft flag keeps your changes staged. Use --hard to discard changes entirely (dangerous!)"
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
Risk levels:
|
|
75
|
-
- safe: Read-only, undo-able (status, log, diff)
|
|
76
|
-
- medium: Changes state but recoverable (commit, stash, branch)
|
|
77
|
-
- high: Destructive, affects remote, or hard to undo (push --force, reset --hard, delete branch)
|
|
78
|
-
|
|
79
|
-
Common patterns:
|
|
80
|
-
- "commit" / "save" / "commit this" → action: "commit"
|
|
81
|
-
- "undo" / "go back" → action: "reset" (if uncommitted) or "revert" (if committed)
|
|
82
|
-
- "push" / "send" / "upload" → action: "push"
|
|
83
|
-
- "merge X" → action: "merge", target: "X"
|
|
84
|
-
- "create branch X" → action: "branch", target: "X"
|
|
85
|
-
- "switch to X" → action: "checkout", target: "X"
|
|
86
|
-
- "delete branch X" → action: "delete_branch", target: "X"
|
|
87
|
-
|
|
88
|
-
Be smart about context:
|
|
89
|
-
- If user says "undo that" and last action was commit → revert
|
|
90
|
-
- If user says "merge" without target → suggest merging current branch to main
|
|
91
|
-
- If user says "fix conflicts" → action: "resolve_conflicts"
|
|
92
|
-
|
|
93
|
-
Respond with ONLY the JSON object, no other text.`;
|
|
16
|
+
const token = (0, auth_1.getToken)();
|
|
17
|
+
if (!token) {
|
|
18
|
+
throw new Error('Authentication required. Please run: snapcommit login');
|
|
19
|
+
}
|
|
94
20
|
try {
|
|
95
|
-
const response = await (
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
21
|
+
const response = await fetch(`${API_BASE_URL}/api/ai/interpret`, {
|
|
22
|
+
method: 'POST',
|
|
23
|
+
headers: { 'Content-Type': 'application/json' },
|
|
24
|
+
body: JSON.stringify({
|
|
25
|
+
userInput,
|
|
26
|
+
context,
|
|
27
|
+
token
|
|
28
|
+
}),
|
|
29
|
+
});
|
|
30
|
+
const data = await response.json();
|
|
31
|
+
if (!response.ok) {
|
|
32
|
+
if (response.status === 401) {
|
|
33
|
+
throw new Error('Authentication failed. Please log in again: snapcommit logout && snapcommit login');
|
|
34
|
+
}
|
|
35
|
+
if (response.status === 403) {
|
|
36
|
+
throw new Error(data.message || 'Subscription required. Visit https://snapcommit.dev/pricing');
|
|
37
|
+
}
|
|
38
|
+
throw new Error(data.error || 'Failed to interpret command');
|
|
109
39
|
}
|
|
110
|
-
return intent;
|
|
40
|
+
return data.intent;
|
|
111
41
|
}
|
|
112
42
|
catch (error) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const { interpretGitCommandGemini } = await Promise.resolve().then(() => __importStar(require('./gemini-client')));
|
|
116
|
-
return await interpretGitCommandGemini(userInput, context);
|
|
43
|
+
if (error.message.includes('fetch')) {
|
|
44
|
+
throw new Error('Network error. Please check your internet connection.');
|
|
117
45
|
}
|
|
118
|
-
|
|
119
|
-
// Ultimate fallback: simple pattern matching
|
|
120
|
-
return getFallbackIntent(userInput, context);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Fallback intent parser for common commands (if AI fails)
|
|
126
|
-
*/
|
|
127
|
-
function getFallbackIntent(userInput, context) {
|
|
128
|
-
const input = userInput.toLowerCase().trim();
|
|
129
|
-
// Common patterns
|
|
130
|
-
if (input.includes('commit') || input === 'save' || input === 'snap') {
|
|
131
|
-
return {
|
|
132
|
-
action: 'commit',
|
|
133
|
-
confidence: 0.9,
|
|
134
|
-
explanation: 'This will commit all your changes with an AI-generated message',
|
|
135
|
-
gitCommands: ['git add -A', 'git commit -m "[AI generated]"'],
|
|
136
|
-
riskLevel: 'medium',
|
|
137
|
-
needsConfirmation: false,
|
|
138
|
-
educationalTip: 'git add -A stages all changes (new, modified, deleted files)',
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
if (input.includes('undo') || input.includes('go back')) {
|
|
142
|
-
if (context.hasUncommittedChanges) {
|
|
143
|
-
return {
|
|
144
|
-
action: 'reset',
|
|
145
|
-
confidence: 0.8,
|
|
146
|
-
explanation: 'This will discard all uncommitted changes',
|
|
147
|
-
gitCommands: ['git reset --hard HEAD'],
|
|
148
|
-
riskLevel: 'high',
|
|
149
|
-
needsConfirmation: true,
|
|
150
|
-
educationalTip: '⚠️ --hard permanently deletes changes. Use --soft to keep changes.',
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
else {
|
|
154
|
-
return {
|
|
155
|
-
action: 'revert',
|
|
156
|
-
confidence: 0.8,
|
|
157
|
-
explanation: 'This will revert your last commit',
|
|
158
|
-
gitCommands: ['git revert HEAD'],
|
|
159
|
-
riskLevel: 'medium',
|
|
160
|
-
needsConfirmation: true,
|
|
161
|
-
educationalTip: 'git revert creates a new commit that undoes changes (safe for pushed commits)',
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
if (input.includes('push') || input.includes('send')) {
|
|
166
|
-
return {
|
|
167
|
-
action: 'push',
|
|
168
|
-
confidence: 0.9,
|
|
169
|
-
explanation: `This will push your commits to remote (${context.currentBranch})`,
|
|
170
|
-
gitCommands: [`git push origin ${context.currentBranch}`],
|
|
171
|
-
riskLevel: 'medium',
|
|
172
|
-
needsConfirmation: false,
|
|
173
|
-
educationalTip: 'git push uploads your local commits to GitHub/remote',
|
|
174
|
-
};
|
|
46
|
+
throw error;
|
|
175
47
|
}
|
|
176
|
-
// Default: show help
|
|
177
|
-
return {
|
|
178
|
-
action: 'help',
|
|
179
|
-
confidence: 0.5,
|
|
180
|
-
explanation: 'I\'m not sure what you want to do. Try being more specific.',
|
|
181
|
-
gitCommands: ['git status'],
|
|
182
|
-
riskLevel: 'safe',
|
|
183
|
-
needsConfirmation: false,
|
|
184
|
-
educationalTip: 'Try commands like: "commit", "push", "undo", "merge", "create branch"',
|
|
185
|
-
};
|
|
186
48
|
}
|
|
187
49
|
/**
|
|
188
50
|
* Generate suggestions for next actions
|
package/package.json
CHANGED
|
@@ -1,65 +0,0 @@
|
|
|
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
|
-
}
|