linguclaw 0.4.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.
Files changed (168) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +161 -0
  3. package/dist/agent-system.d.ts +196 -0
  4. package/dist/agent-system.d.ts.map +1 -0
  5. package/dist/agent-system.js +738 -0
  6. package/dist/agent-system.js.map +1 -0
  7. package/dist/alphabeta.d.ts +54 -0
  8. package/dist/alphabeta.d.ts.map +1 -0
  9. package/dist/alphabeta.js +193 -0
  10. package/dist/alphabeta.js.map +1 -0
  11. package/dist/browser.d.ts +62 -0
  12. package/dist/browser.d.ts.map +1 -0
  13. package/dist/browser.js +224 -0
  14. package/dist/browser.js.map +1 -0
  15. package/dist/cli.d.ts +7 -0
  16. package/dist/cli.d.ts.map +1 -0
  17. package/dist/cli.js +565 -0
  18. package/dist/cli.js.map +1 -0
  19. package/dist/code-parser.d.ts +39 -0
  20. package/dist/code-parser.d.ts.map +1 -0
  21. package/dist/code-parser.js +385 -0
  22. package/dist/code-parser.js.map +1 -0
  23. package/dist/config.d.ts +66 -0
  24. package/dist/config.d.ts.map +1 -0
  25. package/dist/config.js +232 -0
  26. package/dist/config.js.map +1 -0
  27. package/dist/core/engine.d.ts +359 -0
  28. package/dist/core/engine.d.ts.map +1 -0
  29. package/dist/core/engine.js +127 -0
  30. package/dist/core/engine.js.map +1 -0
  31. package/dist/daemon.d.ts +29 -0
  32. package/dist/daemon.d.ts.map +1 -0
  33. package/dist/daemon.js +212 -0
  34. package/dist/daemon.js.map +1 -0
  35. package/dist/email-receiver.d.ts +63 -0
  36. package/dist/email-receiver.d.ts.map +1 -0
  37. package/dist/email-receiver.js +553 -0
  38. package/dist/email-receiver.js.map +1 -0
  39. package/dist/git-integration.d.ts +180 -0
  40. package/dist/git-integration.d.ts.map +1 -0
  41. package/dist/git-integration.js +850 -0
  42. package/dist/git-integration.js.map +1 -0
  43. package/dist/inbox.d.ts +84 -0
  44. package/dist/inbox.d.ts.map +1 -0
  45. package/dist/inbox.js +198 -0
  46. package/dist/inbox.js.map +1 -0
  47. package/dist/index.d.ts +6 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +41 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/languages/cpp.d.ts +51 -0
  52. package/dist/languages/cpp.d.ts.map +1 -0
  53. package/dist/languages/cpp.js +930 -0
  54. package/dist/languages/cpp.js.map +1 -0
  55. package/dist/languages/csharp.d.ts +79 -0
  56. package/dist/languages/csharp.d.ts.map +1 -0
  57. package/dist/languages/csharp.js +1776 -0
  58. package/dist/languages/csharp.js.map +1 -0
  59. package/dist/languages/go.d.ts +50 -0
  60. package/dist/languages/go.d.ts.map +1 -0
  61. package/dist/languages/go.js +882 -0
  62. package/dist/languages/go.js.map +1 -0
  63. package/dist/languages/java.d.ts +47 -0
  64. package/dist/languages/java.d.ts.map +1 -0
  65. package/dist/languages/java.js +649 -0
  66. package/dist/languages/java.js.map +1 -0
  67. package/dist/languages/python.d.ts +47 -0
  68. package/dist/languages/python.d.ts.map +1 -0
  69. package/dist/languages/python.js +655 -0
  70. package/dist/languages/python.js.map +1 -0
  71. package/dist/languages/rust.d.ts +61 -0
  72. package/dist/languages/rust.d.ts.map +1 -0
  73. package/dist/languages/rust.js +1064 -0
  74. package/dist/languages/rust.js.map +1 -0
  75. package/dist/logger.d.ts +20 -0
  76. package/dist/logger.d.ts.map +1 -0
  77. package/dist/logger.js +133 -0
  78. package/dist/logger.js.map +1 -0
  79. package/dist/longterm-memory.d.ts +47 -0
  80. package/dist/longterm-memory.d.ts.map +1 -0
  81. package/dist/longterm-memory.js +300 -0
  82. package/dist/longterm-memory.js.map +1 -0
  83. package/dist/memory.d.ts +42 -0
  84. package/dist/memory.d.ts.map +1 -0
  85. package/dist/memory.js +274 -0
  86. package/dist/memory.js.map +1 -0
  87. package/dist/messaging.d.ts +103 -0
  88. package/dist/messaging.d.ts.map +1 -0
  89. package/dist/messaging.js +645 -0
  90. package/dist/messaging.js.map +1 -0
  91. package/dist/multi-provider.d.ts +69 -0
  92. package/dist/multi-provider.d.ts.map +1 -0
  93. package/dist/multi-provider.js +484 -0
  94. package/dist/multi-provider.js.map +1 -0
  95. package/dist/orchestrator.d.ts +65 -0
  96. package/dist/orchestrator.d.ts.map +1 -0
  97. package/dist/orchestrator.js +441 -0
  98. package/dist/orchestrator.js.map +1 -0
  99. package/dist/plugins.d.ts +52 -0
  100. package/dist/plugins.d.ts.map +1 -0
  101. package/dist/plugins.js +215 -0
  102. package/dist/plugins.js.map +1 -0
  103. package/dist/prism-orchestrator.d.ts +26 -0
  104. package/dist/prism-orchestrator.d.ts.map +1 -0
  105. package/dist/prism-orchestrator.js +191 -0
  106. package/dist/prism-orchestrator.js.map +1 -0
  107. package/dist/prism.d.ts +46 -0
  108. package/dist/prism.d.ts.map +1 -0
  109. package/dist/prism.js +188 -0
  110. package/dist/prism.js.map +1 -0
  111. package/dist/privacy.d.ts +23 -0
  112. package/dist/privacy.d.ts.map +1 -0
  113. package/dist/privacy.js +220 -0
  114. package/dist/privacy.js.map +1 -0
  115. package/dist/proactive.d.ts +30 -0
  116. package/dist/proactive.d.ts.map +1 -0
  117. package/dist/proactive.js +260 -0
  118. package/dist/proactive.js.map +1 -0
  119. package/dist/refactoring-engine.d.ts +100 -0
  120. package/dist/refactoring-engine.d.ts.map +1 -0
  121. package/dist/refactoring-engine.js +717 -0
  122. package/dist/refactoring-engine.js.map +1 -0
  123. package/dist/resilience.d.ts +43 -0
  124. package/dist/resilience.d.ts.map +1 -0
  125. package/dist/resilience.js +200 -0
  126. package/dist/resilience.js.map +1 -0
  127. package/dist/safety.d.ts +40 -0
  128. package/dist/safety.d.ts.map +1 -0
  129. package/dist/safety.js +133 -0
  130. package/dist/safety.js.map +1 -0
  131. package/dist/sandbox.d.ts +33 -0
  132. package/dist/sandbox.d.ts.map +1 -0
  133. package/dist/sandbox.js +173 -0
  134. package/dist/sandbox.js.map +1 -0
  135. package/dist/scheduler.d.ts +72 -0
  136. package/dist/scheduler.d.ts.map +1 -0
  137. package/dist/scheduler.js +374 -0
  138. package/dist/scheduler.js.map +1 -0
  139. package/dist/semantic-memory.d.ts +70 -0
  140. package/dist/semantic-memory.d.ts.map +1 -0
  141. package/dist/semantic-memory.js +430 -0
  142. package/dist/semantic-memory.js.map +1 -0
  143. package/dist/skills.d.ts +97 -0
  144. package/dist/skills.d.ts.map +1 -0
  145. package/dist/skills.js +575 -0
  146. package/dist/skills.js.map +1 -0
  147. package/dist/static/dashboard.html +853 -0
  148. package/dist/static/hub.html +772 -0
  149. package/dist/static/index.html +818 -0
  150. package/dist/static/logo.svg +24 -0
  151. package/dist/static/workflow-editor.html +913 -0
  152. package/dist/tools.d.ts +67 -0
  153. package/dist/tools.d.ts.map +1 -0
  154. package/dist/tools.js +303 -0
  155. package/dist/tools.js.map +1 -0
  156. package/dist/types.d.ts +295 -0
  157. package/dist/types.d.ts.map +1 -0
  158. package/dist/types.js +90 -0
  159. package/dist/types.js.map +1 -0
  160. package/dist/web.d.ts +76 -0
  161. package/dist/web.d.ts.map +1 -0
  162. package/dist/web.js +2139 -0
  163. package/dist/web.js.map +1 -0
  164. package/dist/workflow-engine.d.ts +114 -0
  165. package/dist/workflow-engine.d.ts.map +1 -0
  166. package/dist/workflow-engine.js +855 -0
  167. package/dist/workflow-engine.js.map +1 -0
  168. package/package.json +77 -0
@@ -0,0 +1,850 @@
1
+ "use strict";
2
+ /**
3
+ * Git Integration for LinguClaw
4
+ * Advanced Git operations with blame, diff, history, and branch management
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
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.GitIntegration = void 0;
41
+ const child_process_1 = require("child_process");
42
+ const path = __importStar(require("path"));
43
+ const fs = __importStar(require("fs"));
44
+ const logger_1 = require("./logger");
45
+ const logger = (0, logger_1.getLogger)();
46
+ class GitIntegration {
47
+ repoPath;
48
+ isGitRepo = false;
49
+ constructor(repoPath) {
50
+ this.repoPath = path.resolve(repoPath);
51
+ this.checkIsRepo();
52
+ }
53
+ checkIsRepo() {
54
+ try {
55
+ const gitDir = path.join(this.repoPath, '.git');
56
+ this.isGitRepo = fs.existsSync(gitDir) && fs.statSync(gitDir).isDirectory();
57
+ }
58
+ catch {
59
+ this.isGitRepo = false;
60
+ }
61
+ }
62
+ isRepository() {
63
+ return this.isGitRepo;
64
+ }
65
+ execGit(args) {
66
+ try {
67
+ return (0, child_process_1.execSync)(`git ${args.join(' ')}`, {
68
+ cwd: this.repoPath,
69
+ encoding: 'utf-8',
70
+ maxBuffer: 50 * 1024 * 1024, // 50MB buffer
71
+ }).trim();
72
+ }
73
+ catch (error) {
74
+ logger.error(`Git command failed: git ${args.join(' ')} - ${error.message}`);
75
+ throw new Error(`Git command failed: ${error.message}`);
76
+ }
77
+ }
78
+ // ============================================
79
+ // COMMIT OPERATIONS
80
+ // ============================================
81
+ getLog(options = {}) {
82
+ if (!this.isGitRepo)
83
+ return [];
84
+ const format = '%H|%h|%an|%ae|%ad|%s';
85
+ const args = ['log', `--format=${format}`, '--date=iso'];
86
+ if (options.maxCount)
87
+ args.push('-n', options.maxCount.toString());
88
+ if (options.since)
89
+ args.push(`--since=${options.since.toISOString()}`);
90
+ if (options.until)
91
+ args.push(`--until=${options.until.toISOString()}`);
92
+ if (options.author)
93
+ args.push(`--author=${options.author}`);
94
+ if (options.grep)
95
+ args.push(`--grep=${options.grep}`);
96
+ if (options.file)
97
+ args.push('--follow', '--', options.file);
98
+ if (options.branch)
99
+ args.push(options.branch);
100
+ const output = this.execGit(args);
101
+ if (!output)
102
+ return [];
103
+ return output.split('\n').map(line => {
104
+ const parts = line.split('|');
105
+ return {
106
+ hash: parts[0],
107
+ shortHash: parts[1],
108
+ author: parts[2],
109
+ email: parts[3],
110
+ date: new Date(parts[4]),
111
+ message: parts[5],
112
+ filesChanged: 0,
113
+ insertions: 0,
114
+ deletions: 0,
115
+ };
116
+ });
117
+ }
118
+ getCommitDetails(hash) {
119
+ if (!this.isGitRepo)
120
+ return null;
121
+ try {
122
+ const format = '%H|%h|%an|%ae|%ad|%s';
123
+ const output = this.execGit(['show', hash, `--format=${format}`, '--date=iso', '--quiet', '--numstat']);
124
+ const lines = output.split('\n');
125
+ const mainInfo = lines[0].split('|');
126
+ let filesChanged = 0;
127
+ let insertions = 0;
128
+ let deletions = 0;
129
+ for (const line of lines.slice(1)) {
130
+ const match = line.match(/(\d+)\s+(\d+)\s+/);
131
+ if (match) {
132
+ filesChanged++;
133
+ insertions += parseInt(match[1]) || 0;
134
+ deletions += parseInt(match[2]) || 0;
135
+ }
136
+ }
137
+ return {
138
+ hash: mainInfo[0],
139
+ shortHash: mainInfo[1],
140
+ author: mainInfo[2],
141
+ email: mainInfo[3],
142
+ date: new Date(mainInfo[4]),
143
+ message: mainInfo[5],
144
+ filesChanged,
145
+ insertions,
146
+ deletions,
147
+ };
148
+ }
149
+ catch {
150
+ return null;
151
+ }
152
+ }
153
+ // ============================================
154
+ // BLAME OPERATIONS
155
+ // ============================================
156
+ blame(filePath, options = {}) {
157
+ if (!this.isGitRepo)
158
+ return [];
159
+ const fullPath = path.join(this.repoPath, filePath);
160
+ if (!fs.existsSync(fullPath)) {
161
+ throw new Error(`File not found: ${filePath}`);
162
+ }
163
+ const args = ['blame', '--line-porcelain'];
164
+ if (options.lineStart && options.lineEnd) {
165
+ args.push(`-L ${options.lineStart},${options.lineEnd}`);
166
+ }
167
+ args.push(filePath);
168
+ const output = this.execGit(args);
169
+ const lines = output.split('\n');
170
+ const result = [];
171
+ let currentBlame = {};
172
+ let currentLine = '';
173
+ for (const line of lines) {
174
+ if (line.match(/^[0-9a-f]{40} \d+ \d+/)) {
175
+ // New blame entry starts
176
+ if (currentBlame.line !== undefined) {
177
+ result.push(currentBlame);
178
+ }
179
+ const parts = line.split(' ');
180
+ currentBlame = {
181
+ line: parseInt(parts[2]),
182
+ commit: parts[0],
183
+ };
184
+ }
185
+ else if (line.startsWith('author ')) {
186
+ currentBlame.author = line.substring(7);
187
+ }
188
+ else if (line.startsWith('author-time ')) {
189
+ currentBlame.date = new Date(parseInt(line.substring(12)) * 1000);
190
+ }
191
+ else if (line.startsWith('summary ')) {
192
+ currentBlame.summary = line.substring(8);
193
+ }
194
+ else if (line.startsWith('\t')) {
195
+ currentBlame.content = line.substring(1);
196
+ }
197
+ }
198
+ // Add the last entry
199
+ if (currentBlame.line !== undefined) {
200
+ result.push(currentBlame);
201
+ }
202
+ return result;
203
+ }
204
+ getBlameSummary(filePath) {
205
+ const blame = this.blame(filePath);
206
+ const authorLines = new Map();
207
+ for (const line of blame) {
208
+ const count = authorLines.get(line.author) || 0;
209
+ authorLines.set(line.author, count + 1);
210
+ }
211
+ const total = blame.length;
212
+ return Array.from(authorLines.entries())
213
+ .map(([author, lines]) => ({
214
+ author,
215
+ lines,
216
+ percentage: Math.round((lines / total) * 100),
217
+ }))
218
+ .sort((a, b) => b.lines - a.lines);
219
+ }
220
+ // ============================================
221
+ // DIFF OPERATIONS
222
+ // ============================================
223
+ diff(options = {}) {
224
+ if (!this.isGitRepo)
225
+ return [];
226
+ const args = ['diff', '--no-ext-diff', '-p', '--diff-filter=MADCR'];
227
+ if (options.staged || options.cached)
228
+ args.push('--cached');
229
+ if (options.from && options.to) {
230
+ args.push(`${options.from}..${options.to}`);
231
+ }
232
+ else if (options.from) {
233
+ args.push(options.from);
234
+ }
235
+ if (options.file)
236
+ args.push('--', options.file);
237
+ const output = this.execGit(args);
238
+ return this.parseDiffOutput(output);
239
+ }
240
+ parseDiffOutput(output) {
241
+ const diffs = [];
242
+ const files = output.split('diff --git');
243
+ for (const file of files.slice(1)) {
244
+ const diff = {
245
+ oldFile: '',
246
+ newFile: '',
247
+ hunks: [],
248
+ isBinary: false,
249
+ };
250
+ const lines = file.split('\n');
251
+ for (const line of lines) {
252
+ if (line.startsWith('--- ')) {
253
+ diff.oldFile = line.substring(4).replace(/^a\//, '');
254
+ }
255
+ else if (line.startsWith('+++ ')) {
256
+ diff.newFile = line.substring(4).replace(/^b\//, '');
257
+ }
258
+ else if (line.includes('Binary files')) {
259
+ diff.isBinary = true;
260
+ }
261
+ else if (line.startsWith('@@')) {
262
+ // New hunk
263
+ const match = line.match(/@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@/);
264
+ if (match) {
265
+ diff.hunks.push({
266
+ oldStart: parseInt(match[1]),
267
+ oldCount: parseInt(match[2]) || 1,
268
+ newStart: parseInt(match[3]),
269
+ newCount: parseInt(match[4]) || 1,
270
+ lines: [],
271
+ header: line,
272
+ });
273
+ }
274
+ }
275
+ else if (diff.hunks.length > 0 && line.length > 0) {
276
+ const hunk = diff.hunks[diff.hunks.length - 1];
277
+ const type = line[0] === '+' ? 'added' : line[0] === '-' ? 'removed' : 'context';
278
+ hunk.lines.push({
279
+ type,
280
+ content: line.substring(1),
281
+ oldLine: type !== 'added' ? hunk.oldStart + hunk.lines.filter(l => l.type !== 'added').length - 1 : undefined,
282
+ newLine: type !== 'removed' ? hunk.newStart + hunk.lines.filter(l => l.type !== 'removed').length - 1 : undefined,
283
+ });
284
+ }
285
+ }
286
+ diffs.push(diff);
287
+ }
288
+ return diffs;
289
+ }
290
+ getFileDiff(filePath, fromCommit, toCommit) {
291
+ const diffs = this.diff({
292
+ from: fromCommit,
293
+ to: toCommit,
294
+ file: filePath,
295
+ });
296
+ return diffs[0] || null;
297
+ }
298
+ // ============================================
299
+ // BRANCH OPERATIONS
300
+ // ============================================
301
+ getBranches(options = {}) {
302
+ if (!this.isGitRepo)
303
+ return [];
304
+ const args = ['branch', '-v'];
305
+ if (options.remote)
306
+ args.push('-r');
307
+ if (options.all)
308
+ args.push('-a');
309
+ const output = this.execGit(args);
310
+ const branches = [];
311
+ for (const line of output.split('\n')) {
312
+ if (!line.trim())
313
+ continue;
314
+ const isCurrent = line.startsWith('*');
315
+ const cleanLine = line.replace(/^\*\s*/, '').trim();
316
+ const match = cleanLine.match(/^(\S+)\s+(\S+)\s+\[(.+?)\]\s+(.+)/);
317
+ if (match) {
318
+ branches.push({
319
+ name: match[1],
320
+ isCurrent,
321
+ isRemote: match[1].startsWith('remotes/'),
322
+ upstream: match[3],
323
+ lastCommit: match[4],
324
+ });
325
+ }
326
+ else {
327
+ const parts = cleanLine.split(/\s+/);
328
+ branches.push({
329
+ name: parts[0],
330
+ isCurrent,
331
+ isRemote: parts[0].startsWith('remotes/'),
332
+ lastCommit: parts[1] || undefined,
333
+ });
334
+ }
335
+ }
336
+ return branches;
337
+ }
338
+ createBranch(name, from) {
339
+ if (!this.isGitRepo)
340
+ return false;
341
+ try {
342
+ const args = ['checkout', '-b', name];
343
+ if (from)
344
+ args.push(from);
345
+ this.execGit(args);
346
+ return true;
347
+ }
348
+ catch {
349
+ return false;
350
+ }
351
+ }
352
+ checkoutBranch(name) {
353
+ if (!this.isGitRepo)
354
+ return false;
355
+ try {
356
+ this.execGit(['checkout', name]);
357
+ return true;
358
+ }
359
+ catch {
360
+ return false;
361
+ }
362
+ }
363
+ deleteBranch(name, force = false) {
364
+ if (!this.isGitRepo)
365
+ return false;
366
+ try {
367
+ const args = ['branch', force ? '-D' : '-d', name];
368
+ this.execGit(args);
369
+ return true;
370
+ }
371
+ catch {
372
+ return false;
373
+ }
374
+ }
375
+ mergeBranch(source, target, options = {}) {
376
+ if (!this.isGitRepo)
377
+ return false;
378
+ try {
379
+ // Checkout target if specified
380
+ if (target) {
381
+ this.checkoutBranch(target);
382
+ }
383
+ const args = ['merge'];
384
+ if (options.noFastForward)
385
+ args.push('--no-ff');
386
+ if (options.squash)
387
+ args.push('--squash');
388
+ args.push(source);
389
+ this.execGit(args);
390
+ return true;
391
+ }
392
+ catch {
393
+ return false;
394
+ }
395
+ }
396
+ rebaseBranch(upstream, branch) {
397
+ if (!this.isGitRepo)
398
+ return false;
399
+ try {
400
+ if (branch) {
401
+ this.checkoutBranch(branch);
402
+ }
403
+ this.execGit(['rebase', upstream]);
404
+ return true;
405
+ }
406
+ catch {
407
+ return false;
408
+ }
409
+ }
410
+ // ============================================
411
+ // STATUS OPERATIONS
412
+ // ============================================
413
+ getStatus() {
414
+ if (!this.isGitRepo)
415
+ return [];
416
+ const output = this.execGit(['status', '--porcelain', '-u']);
417
+ if (!output)
418
+ return [];
419
+ return output.split('\n').map(line => {
420
+ const staged = line[0] !== ' ' && line[0] !== '?';
421
+ const unstaged = line[1] !== ' ';
422
+ const statusMap = {
423
+ 'M': 'modified',
424
+ 'A': 'added',
425
+ 'D': 'deleted',
426
+ 'R': 'renamed',
427
+ 'C': 'copied',
428
+ '?': 'untracked',
429
+ '!': 'ignored',
430
+ };
431
+ const code = staged ? line[0] : line[1];
432
+ let filePath = line.substring(3).trim();
433
+ // Handle renamed files (R100 old -> new)
434
+ let originalPath;
435
+ if (code === 'R' && filePath.includes(' -> ')) {
436
+ const parts = filePath.split(' -> ');
437
+ originalPath = parts[0];
438
+ filePath = parts[1];
439
+ }
440
+ return {
441
+ path: filePath,
442
+ status: statusMap[code] || 'modified',
443
+ staged,
444
+ originalPath,
445
+ };
446
+ });
447
+ }
448
+ getUntrackedFiles() {
449
+ return this.getStatus()
450
+ .filter(s => s.status === 'untracked')
451
+ .map(s => s.path);
452
+ }
453
+ getModifiedFiles() {
454
+ return this.getStatus()
455
+ .filter(s => s.status === 'modified' || s.status === 'added')
456
+ .map(s => s.path);
457
+ }
458
+ // ============================================
459
+ // STASH OPERATIONS
460
+ // ============================================
461
+ getStashes() {
462
+ if (!this.isGitRepo)
463
+ return [];
464
+ const output = this.execGit(['stash', 'list', '--format=%H|%gd|%gs']);
465
+ if (!output)
466
+ return [];
467
+ return output.split('\n').map((line, index) => {
468
+ const parts = line.split('|');
469
+ return {
470
+ index,
471
+ message: parts[2] || parts[1],
472
+ branch: '',
473
+ hash: parts[0],
474
+ };
475
+ });
476
+ }
477
+ stash(message, options = {}) {
478
+ if (!this.isGitRepo)
479
+ return false;
480
+ try {
481
+ const args = ['stash', 'push'];
482
+ if (message)
483
+ args.push('-m', message);
484
+ if (options.includeUntracked)
485
+ args.push('-u');
486
+ if (options.keepIndex)
487
+ args.push('--keep-index');
488
+ this.execGit(args);
489
+ return true;
490
+ }
491
+ catch {
492
+ return false;
493
+ }
494
+ }
495
+ stashPop(index = 0) {
496
+ if (!this.isGitRepo)
497
+ return false;
498
+ try {
499
+ this.execGit(['stash', 'pop', `stash@{${index}}`]);
500
+ return true;
501
+ }
502
+ catch {
503
+ return false;
504
+ }
505
+ }
506
+ stashApply(index = 0) {
507
+ if (!this.isGitRepo)
508
+ return false;
509
+ try {
510
+ this.execGit(['stash', 'apply', `stash@{${index}}`]);
511
+ return true;
512
+ }
513
+ catch {
514
+ return false;
515
+ }
516
+ }
517
+ stashDrop(index = 0) {
518
+ if (!this.isGitRepo)
519
+ return false;
520
+ try {
521
+ this.execGit(['stash', 'drop', `stash@{${index}}`]);
522
+ return true;
523
+ }
524
+ catch {
525
+ return false;
526
+ }
527
+ }
528
+ // ============================================
529
+ // TAG OPERATIONS
530
+ // ============================================
531
+ getTags() {
532
+ if (!this.isGitRepo)
533
+ return [];
534
+ const output = this.execGit(['tag', '-l', '-n1']);
535
+ if (!output)
536
+ return [];
537
+ return output.split('\n').map(line => {
538
+ const parts = line.trim().split(/\s+/);
539
+ return {
540
+ name: parts[0],
541
+ message: parts.slice(1).join(' ') || undefined,
542
+ hash: '',
543
+ };
544
+ });
545
+ }
546
+ createTag(name, message, commit) {
547
+ if (!this.isGitRepo)
548
+ return false;
549
+ try {
550
+ const args = ['tag'];
551
+ if (message)
552
+ args.push('-a', '-m', message);
553
+ args.push(name);
554
+ if (commit)
555
+ args.push(commit);
556
+ this.execGit(args);
557
+ return true;
558
+ }
559
+ catch {
560
+ return false;
561
+ }
562
+ }
563
+ deleteTag(name) {
564
+ if (!this.isGitRepo)
565
+ return false;
566
+ try {
567
+ this.execGit(['tag', '-d', name]);
568
+ return true;
569
+ }
570
+ catch {
571
+ return false;
572
+ }
573
+ }
574
+ pushTag(name, remote = 'origin') {
575
+ if (!this.isGitRepo)
576
+ return false;
577
+ try {
578
+ this.execGit(['push', remote, name]);
579
+ return true;
580
+ }
581
+ catch {
582
+ return false;
583
+ }
584
+ }
585
+ // ============================================
586
+ // REMOTE OPERATIONS
587
+ // ============================================
588
+ getRemotes() {
589
+ if (!this.isGitRepo)
590
+ return [];
591
+ try {
592
+ const output = this.execGit(['remote', '-v']);
593
+ const remotes = [];
594
+ for (const line of output.split('\n')) {
595
+ const match = line.match(/^(\S+)\s+(\S+)\s+\((\w+)\)/);
596
+ if (match) {
597
+ remotes.push({
598
+ name: match[1],
599
+ url: match[2],
600
+ fetch: match[3],
601
+ });
602
+ }
603
+ }
604
+ return remotes;
605
+ }
606
+ catch {
607
+ return [];
608
+ }
609
+ }
610
+ fetch(remote, branch) {
611
+ if (!this.isGitRepo)
612
+ return false;
613
+ try {
614
+ const args = ['fetch'];
615
+ if (remote)
616
+ args.push(remote);
617
+ if (branch)
618
+ args.push(branch);
619
+ this.execGit(args);
620
+ return true;
621
+ }
622
+ catch {
623
+ return false;
624
+ }
625
+ }
626
+ pull(remote, branch, options = {}) {
627
+ if (!this.isGitRepo)
628
+ return false;
629
+ try {
630
+ const args = ['pull'];
631
+ if (options.rebase)
632
+ args.push('--rebase');
633
+ if (remote)
634
+ args.push(remote);
635
+ if (branch)
636
+ args.push(branch);
637
+ this.execGit(args);
638
+ return true;
639
+ }
640
+ catch {
641
+ return false;
642
+ }
643
+ }
644
+ push(remote, branch, options = {}) {
645
+ if (!this.isGitRepo)
646
+ return false;
647
+ try {
648
+ const args = ['push'];
649
+ if (options.force)
650
+ args.push('--force-with-lease');
651
+ if (options.setUpstream)
652
+ args.push('-u');
653
+ if (remote)
654
+ args.push(remote);
655
+ if (branch)
656
+ args.push(branch);
657
+ this.execGit(args);
658
+ return true;
659
+ }
660
+ catch {
661
+ return false;
662
+ }
663
+ }
664
+ // ============================================
665
+ // ADVANCED ANALYSIS
666
+ // ============================================
667
+ getContributors() {
668
+ if (!this.isGitRepo)
669
+ return [];
670
+ try {
671
+ const output = this.execGit(['shortlog', '-sne', '--all']);
672
+ const contributors = [];
673
+ for (const line of output.split('\n')) {
674
+ const match = line.match(/^\s*(\d+)\s+(.+?)\s+<(.+?)>$/);
675
+ if (match) {
676
+ contributors.push({
677
+ name: match[2],
678
+ email: match[3],
679
+ commits: parseInt(match[1]),
680
+ linesAdded: 0,
681
+ linesDeleted: 0,
682
+ });
683
+ }
684
+ }
685
+ return contributors;
686
+ }
687
+ catch {
688
+ return [];
689
+ }
690
+ }
691
+ getCodeChurn(filePath, since) {
692
+ if (!this.isGitRepo)
693
+ return [];
694
+ const args = ['log', '--format=%ad', '--date=short', '--numstat'];
695
+ if (since)
696
+ args.push(`--since=${since.toISOString()}`);
697
+ if (filePath)
698
+ args.push('--follow', '--', filePath);
699
+ const output = this.execGit(args);
700
+ const churn = new Map();
701
+ let currentDate = '';
702
+ for (const line of output.split('\n')) {
703
+ if (line.match(/^\d{4}-\d{2}-\d{2}$/)) {
704
+ currentDate = line;
705
+ }
706
+ else {
707
+ const match = line.match(/(\d+)\s+(\d+)\s+/);
708
+ if (match && currentDate) {
709
+ const existing = churn.get(currentDate) || { insertions: 0, deletions: 0 };
710
+ existing.insertions += parseInt(match[1]) || 0;
711
+ existing.deletions += parseInt(match[2]) || 0;
712
+ churn.set(currentDate, existing);
713
+ }
714
+ }
715
+ }
716
+ return Array.from(churn.entries())
717
+ .map(([date, stats]) => ({ date, ...stats }))
718
+ .sort((a, b) => a.date.localeCompare(b.date));
719
+ }
720
+ getFileHistory(filePath) {
721
+ return this.getLog({ file: filePath, maxCount: 50 });
722
+ }
723
+ findBugs(filePath) {
724
+ const blame = this.blame(filePath);
725
+ // Find lines that might contain bugs based on keywords
726
+ const bugKeywords = ['TODO', 'FIXME', 'HACK', 'BUG', 'XXX', 'temporary', 'workaround'];
727
+ return blame.filter(line => bugKeywords.some(keyword => line.content.toLowerCase().includes(keyword.toLowerCase())));
728
+ }
729
+ getRepositoryStats() {
730
+ if (!this.isGitRepo) {
731
+ return {
732
+ totalCommits: 0,
733
+ totalFiles: 0,
734
+ branches: 0,
735
+ tags: 0,
736
+ contributors: 0,
737
+ linesOfCode: 0,
738
+ };
739
+ }
740
+ try {
741
+ const totalCommits = parseInt(this.execGit(['rev-list', '--count', 'HEAD'])) || 0;
742
+ const totalFiles = this.execGit(['ls-files']).split('\n').length;
743
+ const branches = this.getBranches({ all: true }).length;
744
+ const tags = this.getTags().length;
745
+ const contributors = this.getContributors().length;
746
+ // Count lines of code (simplified)
747
+ let linesOfCode = 0;
748
+ try {
749
+ const files = this.execGit(['ls-files']).split('\n');
750
+ for (const file of files.slice(0, 100)) { // Sample first 100 files
751
+ if (file.match(/\.(ts|js|py|java|go|rs|cpp|c|cs|tsx|jsx|php|rb|swift|kt)$/)) {
752
+ linesOfCode += 100; // Rough estimate
753
+ }
754
+ }
755
+ linesOfCode = Math.round(linesOfCode * (totalFiles / Math.min(totalFiles, 100)));
756
+ }
757
+ catch {
758
+ linesOfCode = totalFiles * 50; // Fallback estimate
759
+ }
760
+ return {
761
+ totalCommits,
762
+ totalFiles,
763
+ branches,
764
+ tags,
765
+ contributors,
766
+ linesOfCode,
767
+ };
768
+ }
769
+ catch {
770
+ return {
771
+ totalCommits: 0,
772
+ totalFiles: 0,
773
+ branches: 0,
774
+ tags: 0,
775
+ contributors: 0,
776
+ linesOfCode: 0,
777
+ };
778
+ }
779
+ }
780
+ // ============================================
781
+ // WORKTREE OPERATIONS
782
+ // ============================================
783
+ getWorktrees() {
784
+ if (!this.isGitRepo)
785
+ return [];
786
+ try {
787
+ const output = this.execGit(['worktree', 'list', '--porcelain']);
788
+ const worktrees = [];
789
+ let current = {};
790
+ for (const line of output.split('\n')) {
791
+ if (line.startsWith('worktree ')) {
792
+ if (current.path)
793
+ worktrees.push(current);
794
+ current = { path: line.substring(9), isMain: false, isLocked: false };
795
+ }
796
+ else if (line.startsWith('HEAD ')) {
797
+ current.commit = line.substring(5);
798
+ }
799
+ else if (line.startsWith('branch ')) {
800
+ current.branch = line.substring(7).replace('refs/heads/', '');
801
+ }
802
+ else if (line === 'bare') {
803
+ current.isMain = true;
804
+ }
805
+ else if (line === 'locked') {
806
+ current.isLocked = true;
807
+ }
808
+ }
809
+ if (current.path)
810
+ worktrees.push(current);
811
+ return worktrees;
812
+ }
813
+ catch {
814
+ return [];
815
+ }
816
+ }
817
+ createWorktree(path, branch) {
818
+ if (!this.isGitRepo)
819
+ return false;
820
+ try {
821
+ const args = ['worktree', 'add'];
822
+ if (branch)
823
+ args.push('-b', branch);
824
+ args.push(path);
825
+ this.execGit(args);
826
+ return true;
827
+ }
828
+ catch {
829
+ return false;
830
+ }
831
+ }
832
+ removeWorktree(path, force = false) {
833
+ if (!this.isGitRepo)
834
+ return false;
835
+ try {
836
+ const args = ['worktree', 'remove'];
837
+ if (force)
838
+ args.push('--force');
839
+ args.push(path);
840
+ this.execGit(args);
841
+ return true;
842
+ }
843
+ catch {
844
+ return false;
845
+ }
846
+ }
847
+ }
848
+ exports.GitIntegration = GitIntegration;
849
+ exports.default = GitIntegration;
850
+ //# sourceMappingURL=git-integration.js.map