xibecode 0.0.1 → 0.0.2

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.
@@ -0,0 +1,343 @@
1
+ import { exec } from 'child_process';
2
+ import { promisify } from 'util';
3
+ const execAsync = promisify(exec);
4
+ export class GitUtils {
5
+ workingDir;
6
+ constructor(workingDir = process.cwd()) {
7
+ this.workingDir = workingDir;
8
+ }
9
+ /**
10
+ * Check if the current directory is inside a git repository
11
+ */
12
+ async isGitRepository() {
13
+ try {
14
+ const { stdout } = await execAsync('git rev-parse --git-dir', {
15
+ cwd: this.workingDir,
16
+ timeout: 5000,
17
+ });
18
+ return stdout.trim().length > 0;
19
+ }
20
+ catch {
21
+ return false;
22
+ }
23
+ }
24
+ /**
25
+ * Get current git status with detailed information
26
+ */
27
+ async getStatus() {
28
+ const isRepo = await this.isGitRepository();
29
+ if (!isRepo) {
30
+ return { isGitRepo: false };
31
+ }
32
+ try {
33
+ // Get branch name
34
+ const branchResult = await execAsync('git branch --show-current', {
35
+ cwd: this.workingDir,
36
+ timeout: 5000,
37
+ });
38
+ const branch = branchResult.stdout.trim();
39
+ // Get status porcelain for parsing
40
+ const statusResult = await execAsync('git status --porcelain', {
41
+ cwd: this.workingDir,
42
+ timeout: 5000,
43
+ });
44
+ const staged = [];
45
+ const unstaged = [];
46
+ const untracked = [];
47
+ const lines = statusResult.stdout.trim().split('\n').filter(l => l);
48
+ for (const line of lines) {
49
+ const status = line.substring(0, 2);
50
+ const file = line.substring(3);
51
+ if (status[0] !== ' ' && status[0] !== '?') {
52
+ staged.push(file);
53
+ }
54
+ if (status[1] !== ' ' && status[1] !== '?') {
55
+ unstaged.push(file);
56
+ }
57
+ if (status === '??') {
58
+ untracked.push(file);
59
+ }
60
+ }
61
+ const isClean = lines.length === 0;
62
+ // Get ahead/behind info
63
+ let ahead = 0;
64
+ let behind = 0;
65
+ try {
66
+ const revListResult = await execAsync('git rev-list --left-right --count HEAD...@{upstream}', {
67
+ cwd: this.workingDir,
68
+ timeout: 5000,
69
+ });
70
+ const [aheadStr, behindStr] = revListResult.stdout.trim().split('\t');
71
+ ahead = parseInt(aheadStr, 10) || 0;
72
+ behind = parseInt(behindStr, 10) || 0;
73
+ }
74
+ catch {
75
+ // No upstream or other error, ignore
76
+ }
77
+ return {
78
+ isGitRepo: true,
79
+ branch,
80
+ isClean,
81
+ staged,
82
+ unstaged,
83
+ untracked,
84
+ ahead,
85
+ behind,
86
+ };
87
+ }
88
+ catch (error) {
89
+ return {
90
+ isGitRepo: true,
91
+ branch: undefined,
92
+ };
93
+ }
94
+ }
95
+ /**
96
+ * Get list of changed files (staged + unstaged)
97
+ */
98
+ async getChangedFiles() {
99
+ const status = await this.getStatus();
100
+ if (!status.isGitRepo)
101
+ return [];
102
+ const changed = new Set();
103
+ status.staged?.forEach(f => changed.add(f));
104
+ status.unstaged?.forEach(f => changed.add(f));
105
+ return Array.from(changed);
106
+ }
107
+ /**
108
+ * Get diff summary with line count statistics
109
+ */
110
+ async getDiffSummary(target = 'HEAD') {
111
+ const isRepo = await this.isGitRepository();
112
+ if (!isRepo) {
113
+ return { files: [], totalInsertions: 0, totalDeletions: 0, totalFiles: 0 };
114
+ }
115
+ try {
116
+ const { stdout } = await execAsync(`git diff --numstat ${target}`, {
117
+ cwd: this.workingDir,
118
+ timeout: 10000,
119
+ });
120
+ const files = [];
121
+ let totalInsertions = 0;
122
+ let totalDeletions = 0;
123
+ const lines = stdout.trim().split('\n').filter(l => l);
124
+ for (const line of lines) {
125
+ const [insertions, deletions, filepath] = line.split('\t');
126
+ const ins = parseInt(insertions, 10) || 0;
127
+ const del = parseInt(deletions, 10) || 0;
128
+ files.push({
129
+ path: filepath,
130
+ insertions: ins,
131
+ deletions: del,
132
+ changes: ins + del,
133
+ });
134
+ totalInsertions += ins;
135
+ totalDeletions += del;
136
+ }
137
+ return {
138
+ files,
139
+ totalInsertions,
140
+ totalDeletions,
141
+ totalFiles: files.length,
142
+ };
143
+ }
144
+ catch (error) {
145
+ return { files: [], totalInsertions: 0, totalDeletions: 0, totalFiles: 0 };
146
+ }
147
+ }
148
+ /**
149
+ * Get unified diff for a file or entire repo
150
+ */
151
+ async getUnifiedDiff(filePath, target = 'HEAD') {
152
+ const isRepo = await this.isGitRepository();
153
+ if (!isRepo)
154
+ return '';
155
+ try {
156
+ const command = filePath
157
+ ? `git diff ${target} -- ${filePath}`
158
+ : `git diff ${target}`;
159
+ const { stdout } = await execAsync(command, {
160
+ cwd: this.workingDir,
161
+ timeout: 10000,
162
+ maxBuffer: 1024 * 1024 * 10,
163
+ });
164
+ return stdout;
165
+ }
166
+ catch (error) {
167
+ return '';
168
+ }
169
+ }
170
+ /**
171
+ * Create a git checkpoint (stash or commit)
172
+ */
173
+ async createCheckpoint(message, strategy = 'stash') {
174
+ const isRepo = await this.isGitRepository();
175
+ if (!isRepo) {
176
+ return { success: false, error: 'Not a git repository' };
177
+ }
178
+ try {
179
+ const timestamp = new Date();
180
+ const fullMessage = `xibecode checkpoint: ${message}`;
181
+ if (strategy === 'stash') {
182
+ // Create a stash with keep-index to preserve staged files
183
+ const { stdout } = await execAsync(`git stash push -u -m "${fullMessage}"`, {
184
+ cwd: this.workingDir,
185
+ timeout: 30000,
186
+ });
187
+ // Check if stash was created (git stash says "No local changes" if nothing to stash)
188
+ if (stdout.includes('No local changes')) {
189
+ return { success: false, error: 'No changes to checkpoint' };
190
+ }
191
+ // Get the stash id
192
+ const stashList = await execAsync('git stash list', {
193
+ cwd: this.workingDir,
194
+ timeout: 5000,
195
+ });
196
+ const stashId = stashList.stdout.split('\n')[0]?.split(':')[0] || 'stash@{0}';
197
+ return {
198
+ success: true,
199
+ checkpoint: {
200
+ type: 'stash',
201
+ id: stashId,
202
+ message: fullMessage,
203
+ timestamp,
204
+ },
205
+ };
206
+ }
207
+ else {
208
+ // Create a commit with --no-verify to skip hooks
209
+ // First add all changes
210
+ await execAsync('git add -A', {
211
+ cwd: this.workingDir,
212
+ timeout: 10000,
213
+ });
214
+ const { stdout } = await execAsync(`git commit --no-verify -m "${fullMessage}"`, {
215
+ cwd: this.workingDir,
216
+ timeout: 30000,
217
+ });
218
+ // Get the commit hash
219
+ const hashResult = await execAsync('git rev-parse HEAD', {
220
+ cwd: this.workingDir,
221
+ timeout: 5000,
222
+ });
223
+ const commitHash = hashResult.stdout.trim();
224
+ return {
225
+ success: true,
226
+ checkpoint: {
227
+ type: 'commit',
228
+ id: commitHash,
229
+ message: fullMessage,
230
+ timestamp,
231
+ },
232
+ };
233
+ }
234
+ }
235
+ catch (error) {
236
+ return { success: false, error: error.message };
237
+ }
238
+ }
239
+ /**
240
+ * Revert to a git checkpoint
241
+ */
242
+ async revertToCheckpoint(checkpoint, confirm = false) {
243
+ if (!confirm) {
244
+ return { success: false, error: 'Revert requires explicit confirmation. Set confirm: true' };
245
+ }
246
+ const isRepo = await this.isGitRepository();
247
+ if (!isRepo) {
248
+ return { success: false, error: 'Not a git repository' };
249
+ }
250
+ try {
251
+ if (checkpoint.type === 'stash') {
252
+ // Apply the stash
253
+ await execAsync(`git stash apply ${checkpoint.id}`, {
254
+ cwd: this.workingDir,
255
+ timeout: 30000,
256
+ });
257
+ return { success: true };
258
+ }
259
+ else {
260
+ // Reset to commit (soft reset to preserve changes as uncommitted)
261
+ await execAsync(`git reset --soft ${checkpoint.id}`, {
262
+ cwd: this.workingDir,
263
+ timeout: 10000,
264
+ });
265
+ return { success: true };
266
+ }
267
+ }
268
+ catch (error) {
269
+ return { success: false, error: error.message };
270
+ }
271
+ }
272
+ /**
273
+ * List recent checkpoints created by XibeCode
274
+ */
275
+ async listCheckpoints(limit = 10) {
276
+ const isRepo = await this.isGitRepository();
277
+ if (!isRepo)
278
+ return [];
279
+ const checkpoints = [];
280
+ try {
281
+ // Get stashes
282
+ const { stdout: stashList } = await execAsync('git stash list', {
283
+ cwd: this.workingDir,
284
+ timeout: 5000,
285
+ });
286
+ const stashLines = stashList.trim().split('\n').filter(l => l);
287
+ for (const line of stashLines) {
288
+ if (line.includes('xibecode checkpoint')) {
289
+ const match = line.match(/^(stash@\{(\d+)\}): (.+): (.+)$/);
290
+ if (match) {
291
+ const [, id, , , message] = match;
292
+ checkpoints.push({
293
+ type: 'stash',
294
+ id,
295
+ message,
296
+ timestamp: new Date(), // Git stash doesn't expose timestamp easily
297
+ });
298
+ }
299
+ }
300
+ }
301
+ // Get commits
302
+ const { stdout: commitList } = await execAsync(`git log -${limit} --pretty=format:"%H|%s|%cd" --date=iso`, {
303
+ cwd: this.workingDir,
304
+ timeout: 5000,
305
+ });
306
+ const commitLines = commitList.trim().split('\n').filter(l => l);
307
+ for (const line of commitLines) {
308
+ const [hash, message, dateStr] = line.split('|');
309
+ if (message.includes('xibecode checkpoint')) {
310
+ checkpoints.push({
311
+ type: 'commit',
312
+ id: hash,
313
+ message,
314
+ timestamp: new Date(dateStr),
315
+ });
316
+ }
317
+ }
318
+ }
319
+ catch {
320
+ // Ignore errors
321
+ }
322
+ return checkpoints.slice(0, limit);
323
+ }
324
+ /**
325
+ * Get files changed compared to a specific branch or commit
326
+ */
327
+ async getChangedFilesSince(target) {
328
+ const isRepo = await this.isGitRepository();
329
+ if (!isRepo)
330
+ return [];
331
+ try {
332
+ const { stdout } = await execAsync(`git diff --name-only ${target}`, {
333
+ cwd: this.workingDir,
334
+ timeout: 10000,
335
+ });
336
+ return stdout.trim().split('\n').filter(l => l);
337
+ }
338
+ catch {
339
+ return [];
340
+ }
341
+ }
342
+ }
343
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/utils/git.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAGjC,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;AAgClC,MAAM,OAAO,QAAQ;IACX,UAAU,CAAS;IAE3B,YAAY,aAAqB,OAAO,CAAC,GAAG,EAAE;QAC5C,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe;QACnB,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,yBAAyB,EAAE;gBAC5D,GAAG,EAAE,IAAI,CAAC,UAAU;gBACpB,OAAO,EAAE,IAAI;aACd,CAAC,CAAC;YACH,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;QAClC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,SAAS;QACb,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC;QAC5C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;QAC9B,CAAC;QAED,IAAI,CAAC;YACH,kBAAkB;YAClB,MAAM,YAAY,GAAG,MAAM,SAAS,CAAC,2BAA2B,EAAE;gBAChE,GAAG,EAAE,IAAI,CAAC,UAAU;gBACpB,OAAO,EAAE,IAAI;aACd,CAAC,CAAC;YACH,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;YAE1C,mCAAmC;YACnC,MAAM,YAAY,GAAG,MAAM,SAAS,CAAC,wBAAwB,EAAE;gBAC7D,GAAG,EAAE,IAAI,CAAC,UAAU;gBACpB,OAAO,EAAE,IAAI;aACd,CAAC,CAAC;YAEH,MAAM,MAAM,GAAa,EAAE,CAAC;YAC5B,MAAM,QAAQ,GAAa,EAAE,CAAC;YAC9B,MAAM,SAAS,GAAa,EAAE,CAAC;YAE/B,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACpE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBACpC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;gBAE/B,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;oBAC3C,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACpB,CAAC;gBACD,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;oBAC3C,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACtB,CAAC;gBACD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;oBACpB,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACvB,CAAC;YACH,CAAC;YAED,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC;YAEnC,wBAAwB;YACxB,IAAI,KAAK,GAAG,CAAC,CAAC;YACd,IAAI,MAAM,GAAG,CAAC,CAAC;YACf,IAAI,CAAC;gBACH,MAAM,aAAa,GAAG,MAAM,SAAS,CAAC,sDAAsD,EAAE;oBAC5F,GAAG,EAAE,IAAI,CAAC,UAAU;oBACpB,OAAO,EAAE,IAAI;iBACd,CAAC,CAAC;gBACH,MAAM,CAAC,QAAQ,EAAE,SAAS,CAAC,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACtE,KAAK,GAAG,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;gBACpC,MAAM,GAAG,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;YACxC,CAAC;YAAC,MAAM,CAAC;gBACP,qCAAqC;YACvC,CAAC;YAED,OAAO;gBACL,SAAS,EAAE,IAAI;gBACf,MAAM;gBACN,OAAO;gBACP,MAAM;gBACN,QAAQ;gBACR,SAAS;gBACT,KAAK;gBACL,MAAM;aACP,CAAC;QACJ,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO;gBACL,SAAS,EAAE,IAAI;gBACf,MAAM,EAAE,SAAS;aAClB,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe;QACnB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QACtC,IAAI,CAAC,MAAM,CAAC,SAAS;YAAE,OAAO,EAAE,CAAC;QAEjC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;QAClC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5C,MAAM,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAE9C,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc,CAAC,SAAiB,MAAM;QAC1C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC;QAC5C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,eAAe,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;QAC7E,CAAC;QAED,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,sBAAsB,MAAM,EAAE,EAAE;gBACjE,GAAG,EAAE,IAAI,CAAC,UAAU;gBACpB,OAAO,EAAE,KAAK;aACf,CAAC,CAAC;YAEH,MAAM,KAAK,GAA4B,EAAE,CAAC;YAC1C,IAAI,eAAe,GAAG,CAAC,CAAC;YACxB,IAAI,cAAc,GAAG,CAAC,CAAC;YAEvB,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACvD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,MAAM,CAAC,UAAU,EAAE,SAAS,EAAE,QAAQ,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC3D,MAAM,GAAG,GAAG,QAAQ,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;gBAC1C,MAAM,GAAG,GAAG,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;gBAEzC,KAAK,CAAC,IAAI,CAAC;oBACT,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE,GAAG;oBACf,SAAS,EAAE,GAAG;oBACd,OAAO,EAAE,GAAG,GAAG,GAAG;iBACnB,CAAC,CAAC;gBAEH,eAAe,IAAI,GAAG,CAAC;gBACvB,cAAc,IAAI,GAAG,CAAC;YACxB,CAAC;YAED,OAAO;gBACL,KAAK;gBACL,eAAe;gBACf,cAAc;gBACd,UAAU,EAAE,KAAK,CAAC,MAAM;aACzB,CAAC;QACJ,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,eAAe,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;QAC7E,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,cAAc,CAAC,QAAiB,EAAE,SAAiB,MAAM;QAC7D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC;QAC5C,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,CAAC;QAEvB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,QAAQ;gBACtB,CAAC,CAAC,YAAY,MAAM,OAAO,QAAQ,EAAE;gBACrC,CAAC,CAAC,YAAY,MAAM,EAAE,CAAC;YAEzB,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,OAAO,EAAE;gBAC1C,GAAG,EAAE,IAAI,CAAC,UAAU;gBACpB,OAAO,EAAE,KAAK;gBACd,SAAS,EAAE,IAAI,GAAG,IAAI,GAAG,EAAE;aAC5B,CAAC,CAAC;YAEH,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,gBAAgB,CACpB,OAAe,EACf,WAA+B,OAAO;QAEtC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC;QAC5C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC;QAC3D,CAAC;QAED,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;YAC7B,MAAM,WAAW,GAAG,wBAAwB,OAAO,EAAE,CAAC;YAEtD,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;gBACzB,0DAA0D;gBAC1D,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,yBAAyB,WAAW,GAAG,EAAE;oBAC1E,GAAG,EAAE,IAAI,CAAC,UAAU;oBACpB,OAAO,EAAE,KAAK;iBACf,CAAC,CAAC;gBAEH,qFAAqF;gBACrF,IAAI,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;oBACxC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAC;gBAC/D,CAAC;gBAED,mBAAmB;gBACnB,MAAM,SAAS,GAAG,MAAM,SAAS,CAAC,gBAAgB,EAAE;oBAClD,GAAG,EAAE,IAAI,CAAC,UAAU;oBACpB,OAAO,EAAE,IAAI;iBACd,CAAC,CAAC;gBACH,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,WAAW,CAAC;gBAE9E,OAAO;oBACL,OAAO,EAAE,IAAI;oBACb,UAAU,EAAE;wBACV,IAAI,EAAE,OAAO;wBACb,EAAE,EAAE,OAAO;wBACX,OAAO,EAAE,WAAW;wBACpB,SAAS;qBACV;iBACF,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,iDAAiD;gBACjD,wBAAwB;gBACxB,MAAM,SAAS,CAAC,YAAY,EAAE;oBAC5B,GAAG,EAAE,IAAI,CAAC,UAAU;oBACpB,OAAO,EAAE,KAAK;iBACf,CAAC,CAAC;gBAEH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,8BAA8B,WAAW,GAAG,EAAE;oBAC/E,GAAG,EAAE,IAAI,CAAC,UAAU;oBACpB,OAAO,EAAE,KAAK;iBACf,CAAC,CAAC;gBAEH,sBAAsB;gBACtB,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,oBAAoB,EAAE;oBACvD,GAAG,EAAE,IAAI,CAAC,UAAU;oBACpB,OAAO,EAAE,IAAI;iBACd,CAAC,CAAC;gBACH,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;gBAE5C,OAAO;oBACL,OAAO,EAAE,IAAI;oBACb,UAAU,EAAE;wBACV,IAAI,EAAE,QAAQ;wBACd,EAAE,EAAE,UAAU;wBACd,OAAO,EAAE,WAAW;wBACpB,SAAS;qBACV;iBACF,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;QAClD,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,kBAAkB,CACtB,UAAyB,EACzB,UAAmB,KAAK;QAExB,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,0DAA0D,EAAE,CAAC;QAC/F,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC;QAC5C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC;QAC3D,CAAC;QAED,IAAI,CAAC;YACH,IAAI,UAAU,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBAChC,kBAAkB;gBAClB,MAAM,SAAS,CAAC,mBAAmB,UAAU,CAAC,EAAE,EAAE,EAAE;oBAClD,GAAG,EAAE,IAAI,CAAC,UAAU;oBACpB,OAAO,EAAE,KAAK;iBACf,CAAC,CAAC;gBAEH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YAC3B,CAAC;iBAAM,CAAC;gBACN,kEAAkE;gBAClE,MAAM,SAAS,CAAC,oBAAoB,UAAU,CAAC,EAAE,EAAE,EAAE;oBACnD,GAAG,EAAE,IAAI,CAAC,UAAU;oBACpB,OAAO,EAAE,KAAK;iBACf,CAAC,CAAC;gBAEH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YAC3B,CAAC;QACH,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;QAClD,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe,CAAC,QAAgB,EAAE;QACtC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC;QAC5C,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,CAAC;QAEvB,MAAM,WAAW,GAAoB,EAAE,CAAC;QAExC,IAAI,CAAC;YACH,cAAc;YACd,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,SAAS,CAAC,gBAAgB,EAAE;gBAC9D,GAAG,EAAE,IAAI,CAAC,UAAU;gBACpB,OAAO,EAAE,IAAI;aACd,CAAC,CAAC;YAEH,MAAM,UAAU,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAC/D,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;gBAC9B,IAAI,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAAC;oBACzC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;oBAC5D,IAAI,KAAK,EAAE,CAAC;wBACV,MAAM,CAAC,EAAE,EAAE,EAAE,AAAD,EAAG,AAAD,EAAG,OAAO,CAAC,GAAG,KAAK,CAAC;wBAClC,WAAW,CAAC,IAAI,CAAC;4BACf,IAAI,EAAE,OAAO;4BACb,EAAE;4BACF,OAAO;4BACP,SAAS,EAAE,IAAI,IAAI,EAAE,EAAE,4CAA4C;yBACpE,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;YAED,cAAc;YACd,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,SAAS,CAC5C,YAAY,KAAK,yCAAyC,EAC1D;gBACE,GAAG,EAAE,IAAI,CAAC,UAAU;gBACpB,OAAO,EAAE,IAAI;aACd,CACF,CAAC;YAEF,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACjE,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;gBAC/B,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBACjD,IAAI,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAAC;oBAC5C,WAAW,CAAC,IAAI,CAAC;wBACf,IAAI,EAAE,QAAQ;wBACd,EAAE,EAAE,IAAI;wBACR,OAAO;wBACP,SAAS,EAAE,IAAI,IAAI,CAAC,OAAO,CAAC;qBAC7B,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,gBAAgB;QAClB,CAAC;QAED,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACrC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,oBAAoB,CAAC,MAAc;QACvC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC;QAC5C,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,CAAC;QAEvB,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,wBAAwB,MAAM,EAAE,EAAE;gBACnE,GAAG,EAAE,IAAI,CAAC,UAAU;gBACpB,OAAO,EAAE,KAAK;aACf,CAAC,CAAC;YAEH,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAClD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Safety utilities for classifying and managing risky operations
3
+ */
4
+ export type RiskLevel = 'low' | 'medium' | 'high';
5
+ export interface RiskAssessment {
6
+ level: RiskLevel;
7
+ reasons: string[];
8
+ warnings: string[];
9
+ }
10
+ export declare class SafetyChecker {
11
+ /**
12
+ * Assess the risk level of a tool operation
13
+ */
14
+ assessToolRisk(toolName: string, params: any): RiskAssessment;
15
+ /**
16
+ * Assess the risk level of a shell command
17
+ */
18
+ assessCommandRisk(command: string): RiskLevel;
19
+ /**
20
+ * Check if a command should be blocked entirely
21
+ */
22
+ isCommandBlocked(command: string): {
23
+ blocked: boolean;
24
+ reason?: string;
25
+ };
26
+ /**
27
+ * Suggest safer alternatives for risky commands
28
+ */
29
+ suggestSaferAlternative(command: string): string | null;
30
+ /**
31
+ * Check if a file path is sensitive
32
+ */
33
+ isSensitivePath(filepath: string): boolean;
34
+ /**
35
+ * Validate dry-run compatibility for a tool
36
+ */
37
+ canDryRun(toolName: string): boolean;
38
+ }
39
+ //# sourceMappingURL=safety.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safety.d.ts","sourceRoot":"","sources":["../../src/utils/safety.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAElD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,qBAAa,aAAa;IACxB;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,cAAc;IAqG7D;;OAEG;IACH,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS;IAkD7C;;OAEG;IACH,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;IAqBxE;;OAEG;IACH,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAsBvD;;OAEG;IACH,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAgB1C;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;CAgBrC"}
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Safety utilities for classifying and managing risky operations
3
+ */
4
+ export class SafetyChecker {
5
+ /**
6
+ * Assess the risk level of a tool operation
7
+ */
8
+ assessToolRisk(toolName, params) {
9
+ const reasons = [];
10
+ const warnings = [];
11
+ let level = 'low';
12
+ switch (toolName) {
13
+ case 'delete_file':
14
+ level = 'high';
15
+ reasons.push('Deletes files/directories permanently');
16
+ warnings.push('Ensure backups exist before deletion');
17
+ // Check if deleting important directories
18
+ if (params.path) {
19
+ const dangerousPaths = [
20
+ 'node_modules',
21
+ '.git',
22
+ 'dist',
23
+ 'build',
24
+ 'src',
25
+ '/',
26
+ '~',
27
+ ];
28
+ for (const dangerous of dangerousPaths) {
29
+ if (params.path.includes(dangerous)) {
30
+ level = 'high';
31
+ warnings.push(`Deleting ${dangerous} directory - HIGH RISK`);
32
+ }
33
+ }
34
+ }
35
+ break;
36
+ case 'write_file':
37
+ // Writing is generally safe but can overwrite
38
+ if (params.path) {
39
+ // Check for important files
40
+ const importantFiles = [
41
+ 'package.json',
42
+ 'tsconfig.json',
43
+ '.gitignore',
44
+ 'README.md',
45
+ '.env',
46
+ ];
47
+ if (importantFiles.some(f => params.path.endsWith(f))) {
48
+ level = 'medium';
49
+ reasons.push('Modifying important configuration file');
50
+ warnings.push('Verify changes to avoid breaking the project');
51
+ }
52
+ }
53
+ break;
54
+ case 'edit_file':
55
+ case 'edit_lines':
56
+ case 'insert_at_line':
57
+ level = 'low';
58
+ reasons.push('File edits are backed up automatically');
59
+ break;
60
+ case 'move_file':
61
+ level = 'medium';
62
+ reasons.push('Moving files can break imports and references');
63
+ warnings.push('Update imports after moving files');
64
+ break;
65
+ case 'run_command':
66
+ level = this.assessCommandRisk(params.command);
67
+ if (level === 'high') {
68
+ reasons.push('Command can make irreversible changes');
69
+ }
70
+ break;
71
+ case 'create_git_checkpoint':
72
+ level = 'low';
73
+ reasons.push('Creates a safe restore point');
74
+ break;
75
+ case 'revert_to_git_checkpoint':
76
+ level = 'high';
77
+ reasons.push('Reverts code changes');
78
+ warnings.push('Ensure correct checkpoint before reverting');
79
+ if (!params.confirm) {
80
+ warnings.push('Requires explicit confirmation');
81
+ }
82
+ break;
83
+ case 'revert_file':
84
+ level = 'medium';
85
+ reasons.push('Reverts file to previous version');
86
+ warnings.push('Verify backup index before reverting');
87
+ break;
88
+ default:
89
+ level = 'low';
90
+ }
91
+ return { level, reasons, warnings };
92
+ }
93
+ /**
94
+ * Assess the risk level of a shell command
95
+ */
96
+ assessCommandRisk(command) {
97
+ const cmd = command.toLowerCase().trim();
98
+ // High-risk commands
99
+ const highRiskPatterns = [
100
+ /rm\s+-rf/,
101
+ /git\s+reset\s+--hard/,
102
+ /git\s+push\s+--force/,
103
+ /git\s+push\s+-f/,
104
+ /dd\s+if=/,
105
+ /mkfs/,
106
+ /format/,
107
+ /:\(\)\{.*\}/, // Fork bomb pattern
108
+ /chmod\s+777/,
109
+ /chown\s+-R/,
110
+ /sudo\s+rm/,
111
+ /> \/dev\//,
112
+ /curl.*\|\s*(bash|sh)/,
113
+ /wget.*\|\s*(bash|sh)/,
114
+ ];
115
+ for (const pattern of highRiskPatterns) {
116
+ if (pattern.test(cmd)) {
117
+ return 'high';
118
+ }
119
+ }
120
+ // Medium-risk commands
121
+ const mediumRiskPatterns = [
122
+ /git\s+push/,
123
+ /npm\s+publish/,
124
+ /rm\s+/,
125
+ /git\s+reset/,
126
+ /git\s+rebase/,
127
+ /git\s+merge/,
128
+ /docker\s+rm/,
129
+ /docker\s+rmi/,
130
+ /kill\s+-9/,
131
+ /pkill/,
132
+ ];
133
+ for (const pattern of mediumRiskPatterns) {
134
+ if (pattern.test(cmd)) {
135
+ return 'medium';
136
+ }
137
+ }
138
+ return 'low';
139
+ }
140
+ /**
141
+ * Check if a command should be blocked entirely
142
+ */
143
+ isCommandBlocked(command) {
144
+ const cmd = command.toLowerCase().trim();
145
+ // Block extremely dangerous commands
146
+ const blockedPatterns = [
147
+ { pattern: /:\(\)\{.*\}/, reason: 'Fork bomb detected' },
148
+ { pattern: /rm\s+-rf\s+\/($|\s)/, reason: 'Attempting to delete root directory' },
149
+ { pattern: /rm\s+-rf\s+~($|\s)/, reason: 'Attempting to delete home directory' },
150
+ { pattern: /> \/dev\/sda/, reason: 'Attempting to write directly to disk' },
151
+ { pattern: /mkfs/, reason: 'Attempting to format filesystem' },
152
+ ];
153
+ for (const { pattern, reason } of blockedPatterns) {
154
+ if (pattern.test(cmd)) {
155
+ return { blocked: true, reason };
156
+ }
157
+ }
158
+ return { blocked: false };
159
+ }
160
+ /**
161
+ * Suggest safer alternatives for risky commands
162
+ */
163
+ suggestSaferAlternative(command) {
164
+ const cmd = command.toLowerCase().trim();
165
+ if (cmd.includes('git reset --hard')) {
166
+ return 'Use "git stash" to save changes, then "git stash drop" if you really want to discard them';
167
+ }
168
+ if (cmd.includes('git push --force') || cmd.includes('git push -f')) {
169
+ return 'Use "git push --force-with-lease" to avoid overwriting others\' work';
170
+ }
171
+ if (cmd.match(/rm\s+-rf/)) {
172
+ return 'Consider using "mv" to move files to a temporary location first';
173
+ }
174
+ if (cmd.includes('npm install') && !cmd.includes('-g')) {
175
+ return 'Consider using "pnpm install" or "bun install" for faster, more efficient installs';
176
+ }
177
+ return null;
178
+ }
179
+ /**
180
+ * Check if a file path is sensitive
181
+ */
182
+ isSensitivePath(filepath) {
183
+ const sensitive = [
184
+ '.env',
185
+ '.env.local',
186
+ '.env.production',
187
+ 'credentials.json',
188
+ 'secrets.yaml',
189
+ 'private.key',
190
+ '.ssh/',
191
+ 'id_rsa',
192
+ 'id_ed25519',
193
+ ];
194
+ return sensitive.some(pattern => filepath.includes(pattern));
195
+ }
196
+ /**
197
+ * Validate dry-run compatibility for a tool
198
+ */
199
+ canDryRun(toolName) {
200
+ const dryRunnable = [
201
+ 'write_file',
202
+ 'edit_file',
203
+ 'edit_lines',
204
+ 'insert_at_line',
205
+ 'delete_file',
206
+ 'move_file',
207
+ 'create_directory',
208
+ 'create_git_checkpoint',
209
+ 'revert_to_git_checkpoint',
210
+ 'revert_file',
211
+ ];
212
+ return dryRunnable.includes(toolName);
213
+ }
214
+ }
215
+ //# sourceMappingURL=safety.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safety.js","sourceRoot":"","sources":["../../src/utils/safety.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ export interface TestRunnerInfo {
2
+ detected: boolean;
3
+ runner?: string;
4
+ command?: string;
5
+ packageManager?: 'pnpm' | 'bun' | 'npm';
6
+ scriptName?: string;
7
+ }
8
+ export interface TestResult {
9
+ success: boolean;
10
+ exitCode?: number;
11
+ output: string;
12
+ errors: string;
13
+ duration?: number;
14
+ testsRun?: number;
15
+ testsPassed?: number;
16
+ testsFailed?: number;
17
+ }
18
+ export declare class TestRunnerDetector {
19
+ private workingDir;
20
+ constructor(workingDir?: string);
21
+ /**
22
+ * Detect which package manager is available
23
+ * Priority: pnpm > bun > npm (as per user preference)
24
+ */
25
+ detectPackageManager(): Promise<'pnpm' | 'bun' | 'npm'>;
26
+ /**
27
+ * Detect test runner and command
28
+ */
29
+ detectTestRunner(customCommand?: string): Promise<TestRunnerInfo>;
30
+ /**
31
+ * Detect test runner from package.json dependencies
32
+ */
33
+ private detectRunnerFromDeps;
34
+ /**
35
+ * Parse test output to extract statistics
36
+ */
37
+ parseTestOutput(output: string, runner?: string): Partial<TestResult>;
38
+ /**
39
+ * Extract failure details from test output
40
+ */
41
+ extractFailures(output: string): string[];
42
+ }
43
+ //# sourceMappingURL=testRunner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testRunner.d.ts","sourceRoot":"","sources":["../../src/utils/testRunner.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,KAAK,CAAC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,UAAU,CAAS;gBAEf,UAAU,GAAE,MAAsB;IAI9C;;;OAGG;IACG,oBAAoB,IAAI,OAAO,CAAC,MAAM,GAAG,KAAK,GAAG,KAAK,CAAC;IAiC7D;;OAEG;IACG,gBAAgB,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IA+FvE;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAgB5B;;OAEG;IACH,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAkErE;;OAEG;IACH,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE;CAiD1C"}