xibecode 0.5.7 → 0.6.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 (80) hide show
  1. package/README.md +6 -8
  2. package/dist/commands/chat.d.ts.map +1 -1
  3. package/dist/commands/chat.js +132 -33
  4. package/dist/commands/chat.js.map +1 -1
  5. package/dist/commands/config.d.ts.map +1 -1
  6. package/dist/commands/config.js +10 -22
  7. package/dist/commands/config.js.map +1 -1
  8. package/dist/commands/run.d.ts +1 -0
  9. package/dist/commands/run.d.ts.map +1 -1
  10. package/dist/commands/run.js +7 -1
  11. package/dist/commands/run.js.map +1 -1
  12. package/dist/core/agent.d.ts +4 -0
  13. package/dist/core/agent.d.ts.map +1 -1
  14. package/dist/core/agent.js +52 -11
  15. package/dist/core/agent.js.map +1 -1
  16. package/dist/core/background-agent.d.ts +23 -0
  17. package/dist/core/background-agent.d.ts.map +1 -0
  18. package/dist/core/background-agent.js +138 -0
  19. package/dist/core/background-agent.js.map +1 -0
  20. package/dist/core/code-graph.d.ts +18 -0
  21. package/dist/core/code-graph.d.ts.map +1 -0
  22. package/dist/core/code-graph.js +105 -0
  23. package/dist/core/code-graph.js.map +1 -0
  24. package/dist/core/conflict-solver.d.ts +26 -0
  25. package/dist/core/conflict-solver.d.ts.map +1 -0
  26. package/dist/core/conflict-solver.js +108 -0
  27. package/dist/core/conflict-solver.js.map +1 -0
  28. package/dist/core/modes.d.ts +1 -1
  29. package/dist/core/modes.d.ts.map +1 -1
  30. package/dist/core/modes.js +105 -5
  31. package/dist/core/modes.js.map +1 -1
  32. package/dist/core/pattern-miner.d.ts +43 -0
  33. package/dist/core/pattern-miner.d.ts.map +1 -0
  34. package/dist/core/pattern-miner.js +123 -0
  35. package/dist/core/pattern-miner.js.map +1 -0
  36. package/dist/core/planMode.d.ts.map +1 -1
  37. package/dist/core/planMode.js +6 -2
  38. package/dist/core/planMode.js.map +1 -1
  39. package/dist/core/session-bridge.d.ts +5 -1
  40. package/dist/core/session-bridge.d.ts.map +1 -1
  41. package/dist/core/session-bridge.js +13 -0
  42. package/dist/core/session-bridge.js.map +1 -1
  43. package/dist/core/swarm.d.ts +19 -0
  44. package/dist/core/swarm.d.ts.map +1 -0
  45. package/dist/core/swarm.js +77 -0
  46. package/dist/core/swarm.js.map +1 -0
  47. package/dist/core/tools.d.ts +8 -0
  48. package/dist/core/tools.d.ts.map +1 -1
  49. package/dist/core/tools.js +289 -8
  50. package/dist/core/tools.js.map +1 -1
  51. package/dist/core/visual-feedback.d.ts +20 -0
  52. package/dist/core/visual-feedback.d.ts.map +1 -0
  53. package/dist/core/visual-feedback.js +117 -0
  54. package/dist/core/visual-feedback.js.map +1 -0
  55. package/dist/index.js +1 -0
  56. package/dist/index.js.map +1 -1
  57. package/dist/utils/config.d.ts +0 -2
  58. package/dist/utils/config.d.ts.map +1 -1
  59. package/dist/utils/config.js +18 -23
  60. package/dist/utils/config.js.map +1 -1
  61. package/dist/utils/git.d.ts +14 -0
  62. package/dist/utils/git.d.ts.map +1 -1
  63. package/dist/utils/git.js +101 -0
  64. package/dist/utils/git.js.map +1 -1
  65. package/dist/webui/server.d.ts.map +1 -1
  66. package/dist/webui/server.js +6 -9
  67. package/dist/webui/server.js.map +1 -1
  68. package/package.json +23 -22
  69. package/webui-dist/assets/index-CSla6Lzy.css +32 -0
  70. package/webui-dist/assets/{index-C2cXuEP4.js → index-jeWUzIG0.js} +110 -103
  71. package/webui-dist/assets/index-jeWUzIG0.js.map +1 -0
  72. package/webui-dist/assets/{xterm-EDtERSgU.js → xterm-B4aZdZLt.js} +2 -2
  73. package/webui-dist/assets/{xterm-EDtERSgU.js.map → xterm-B4aZdZLt.js.map} +1 -1
  74. package/webui-dist/assets/{xterm-addon-fit-CDWriKNb.js → xterm-addon-fit-CY2T_uda.js} +2 -2
  75. package/webui-dist/assets/{xterm-addon-fit-CDWriKNb.js.map → xterm-addon-fit-CY2T_uda.js.map} +1 -1
  76. package/webui-dist/assets/{xterm-addon-web-links--YKXSM2J.js → xterm-addon-web-links-D93WX0PV.js} +2 -2
  77. package/webui-dist/assets/{xterm-addon-web-links--YKXSM2J.js.map → xterm-addon-web-links-D93WX0PV.js.map} +1 -1
  78. package/webui-dist/index.html +2 -2
  79. package/webui-dist/assets/index-C2cXuEP4.js.map +0 -1
  80. package/webui-dist/assets/index-Jga8KONu.css +0 -32
@@ -3,7 +3,7 @@ import * as path from 'path';
3
3
  import { exec, spawn } from 'child_process';
4
4
  import { promisify } from 'util';
5
5
  import { ContextManager } from './context.js';
6
- import { MODE_CONFIG, isToolAllowed } from './modes.js';
6
+ import { MODE_CONFIG, isToolAllowed, isValidMode } from './modes.js';
7
7
  import { FileEditor } from './editor.js';
8
8
  import { GitUtils } from '../utils/git.js';
9
9
  import { TestRunnerDetector } from '../utils/testRunner.js';
@@ -13,6 +13,12 @@ import { BrowserManager } from '../tools/browser.js';
13
13
  import * as os from 'os';
14
14
  import { SkillManager } from './skills.js';
15
15
  import { TestGenerator, writeTestFile } from '../tools/test-generator.js';
16
+ import { VisualFeedbackProvider } from './visual-feedback.js';
17
+ import { PatternMiner } from './pattern-miner.js';
18
+ import { BackgroundAgentManager } from './background-agent.js';
19
+ import { CodeGraph } from './code-graph.js';
20
+ import { ConflictSolver } from './conflict-solver.js';
21
+ import { SwarmOrchestrator } from './swarm.js';
16
22
  const execAsync = promisify(exec);
17
23
  /**
18
24
  * Main tool executor for XibeCode agent
@@ -70,7 +76,13 @@ export class CodingToolExecutor {
70
76
  mcpClientManager;
71
77
  memory;
72
78
  browserManager;
79
+ visualFeedback;
73
80
  skillManager;
81
+ patternMiner;
82
+ backgroundAgent;
83
+ codeGraph;
84
+ conflictSolver;
85
+ swarmOrchestrator;
74
86
  platform;
75
87
  dryRun;
76
88
  testCommandOverride;
@@ -116,6 +128,12 @@ export class CodingToolExecutor {
116
128
  this.mcpClientManager = options?.mcpClientManager;
117
129
  this.memory = options?.memory;
118
130
  this.browserManager = new BrowserManager();
131
+ this.visualFeedback = new VisualFeedbackProvider(workingDir);
132
+ this.patternMiner = new PatternMiner(workingDir);
133
+ this.backgroundAgent = new BackgroundAgentManager(workingDir);
134
+ this.codeGraph = new CodeGraph(workingDir);
135
+ this.conflictSolver = new ConflictSolver(workingDir);
136
+ this.swarmOrchestrator = new SwarmOrchestrator(this.backgroundAgent);
119
137
  // Initialize skill manager if provided, otherwise create a default one
120
138
  this.skillManager = options?.skillManager || new SkillManager(workingDir);
121
139
  this.platform = os.platform();
@@ -215,8 +233,22 @@ export class CodingToolExecutor {
215
233
  * @since 0.1.0
216
234
  */
217
235
  async execute(toolName, input) {
218
- // Check tool permissions first
219
- const permission = isToolAllowed(this.currentMode, toolName);
236
+ const p = this.parseInput(input);
237
+ // Check tool permissions
238
+ // Special exception: Allow writing implementations.md in plan mode
239
+ let permission = isToolAllowed(this.currentMode, toolName);
240
+ if (this.currentMode === 'plan' && toolName === 'write_file') {
241
+ const isImplPlan = p.path && (p.path === 'implementations.md' || p.path.endsWith('/implementations.md'));
242
+ if (isImplPlan) {
243
+ permission = { allowed: true };
244
+ }
245
+ }
246
+ if (this.currentMode === 'pentest' && toolName === 'write_file') {
247
+ const isPentestReport = p.path && (p.path === 'pentest-report.md' || p.path.endsWith('/pentest-report.md'));
248
+ if (isPentestReport) {
249
+ permission = { allowed: true };
250
+ }
251
+ }
220
252
  if (!permission.allowed) {
221
253
  return {
222
254
  error: true,
@@ -225,7 +257,6 @@ export class CodingToolExecutor {
225
257
  blocked: true
226
258
  };
227
259
  }
228
- const p = this.parseInput(input);
229
260
  // Check if it's an MCP tool (format: serverName::toolName)
230
261
  if (this.mcpClientManager && toolName.includes('::')) {
231
262
  try {
@@ -402,6 +433,16 @@ export class CodingToolExecutor {
402
433
  case 'get_git_changed_files': {
403
434
  return this.getGitChangedFiles(p.target);
404
435
  }
436
+ case 'git_commit': {
437
+ if (!p.message || typeof p.message !== 'string')
438
+ return { error: true, success: false, message: 'Missing message' };
439
+ return this.gitCommit(p.message, p.agent_name);
440
+ }
441
+ case 'git_blame_ai': {
442
+ if (!p.file_path || typeof p.file_path !== 'string')
443
+ return { error: true, success: false, message: 'Missing file_path' };
444
+ return this.gitBlameAi(p.file_path);
445
+ }
405
446
  case 'create_git_checkpoint': {
406
447
  if (!p.message || typeof p.message !== 'string') {
407
448
  return { error: true, success: false, message: 'Missing required parameter: message (string)' };
@@ -535,14 +576,122 @@ export class CodingToolExecutor {
535
576
  maxTestsPerFunction: p.max_tests_per_function,
536
577
  }, p.write_file);
537
578
  }
579
+ case 'preview_app': {
580
+ if (!p.url || typeof p.url !== 'string') {
581
+ return { error: true, success: false, message: 'Missing required parameter: url (string)' };
582
+ }
583
+ return this.visualFeedback.capture(p.url, { fullPage: p.full_page });
584
+ }
585
+ case 'mine_project_patterns': {
586
+ const patterns = await this.patternMiner.mine();
587
+ if (patterns.length === 0) {
588
+ return { success: true, message: 'No significant repeated patterns found in the project.' };
589
+ }
590
+ // Format for AI consumption
591
+ const summary = patterns.map(p => `Pattern: ${p.description}\n` +
592
+ `- Occurrences: ${p.frequency}\n` +
593
+ `- Locations: ${p.chunks.map(c => `${path.relative(this.workingDir, c.filePath)}:${c.startLine}`).join(', ')}\n` +
594
+ `- Example Code:\n\`\`\`typescript\n${p.chunks[0].content}\n\`\`\`\n`).join('\n---\n\n');
595
+ return {
596
+ success: true,
597
+ message: `Found ${patterns.length} pattern clusters.`,
598
+ patterns: summary
599
+ };
600
+ }
601
+ case 'start_background_task': {
602
+ if (!p.prompt || typeof p.prompt !== 'string') {
603
+ return { error: true, success: false, message: 'Missing required parameter: prompt (string)' };
604
+ }
605
+ const taskId = await this.backgroundAgent.startTask(p.prompt);
606
+ return { success: true, message: `Background task started with ID: ${taskId}`, task_id: taskId };
607
+ }
608
+ case 'list_background_tasks': {
609
+ const tasks = await this.backgroundAgent.listTasks();
610
+ const summary = tasks.map(t => `ID: ${t.id} | Status: ${t.status} | Started: ${new Date(t.startTime).toISOString()} | Prompt: "${t.prompt.substring(0, 50)}..."`).join('\n');
611
+ return { success: true, message: `Active Tasks:\n${summary || 'No active tasks.'}` };
612
+ }
613
+ case 'check_background_task': {
614
+ if (!p.task_id || typeof p.task_id !== 'string') {
615
+ return { error: true, success: false, message: 'Missing required parameter: task_id (string)' };
616
+ }
617
+ const logs = await this.backgroundAgent.getTaskLogs(p.task_id);
618
+ return { success: true, logs };
619
+ }
620
+ case 'start_background_task': {
621
+ if (!p.prompt || typeof p.prompt !== 'string') {
622
+ return { error: true, success: false, message: 'Missing required parameter: prompt (string)' };
623
+ }
624
+ const taskId = await this.backgroundAgent.startTask(p.prompt);
625
+ return { success: true, message: `Background task started with ID: ${taskId}`, task_id: taskId };
626
+ }
627
+ case 'list_background_tasks': {
628
+ const tasks = await this.backgroundAgent.listTasks();
629
+ const summary = tasks.map(t => `ID: ${t.id} | Status: ${t.status} | Started: ${new Date(t.startTime).toISOString()} | Prompt: "${t.prompt.substring(0, 50)}..."`).join('\n');
630
+ return { success: true, message: `Active Tasks:\n${summary || 'No active tasks.'}` };
631
+ }
632
+ case 'check_background_task': {
633
+ if (!p.task_id || typeof p.task_id !== 'string') {
634
+ return { error: true, success: false, message: 'Missing required parameter: task_id (string)' };
635
+ }
636
+ const logs = await this.backgroundAgent.getTaskLogs(p.task_id);
637
+ return { success: true, logs };
638
+ }
639
+ case 'search_code_graph': {
640
+ if (!p.query || typeof p.query !== 'string') {
641
+ return { error: true, success: false, message: 'Missing required parameter: query (symbol name)' };
642
+ }
643
+ const results = await this.codeGraph.findReferences(p.query);
644
+ return { success: true, message: results };
645
+ }
538
646
  case 'analyze_code_for_tests': {
539
647
  if (!p.file_path || typeof p.file_path !== 'string') {
540
648
  return { error: true, success: false, message: 'Missing required parameter: file_path (string)' };
541
649
  }
542
650
  return this.analyzeCodeForTests(p.file_path);
543
651
  }
652
+ case 'resolve_merge_conflicts': {
653
+ const files = await this.conflictSolver.findConflictingFiles();
654
+ if (files.length === 0) {
655
+ return { success: true, message: 'No merge conflicts found in the project.' };
656
+ }
657
+ // If specific file requested, use it; otherwise default to first
658
+ const targetFile = (p.file_path && typeof p.file_path === 'string') ? p.file_path : files[0];
659
+ // Ensure target is in the list or we try to parse it anyway
660
+ const conflictData = await this.conflictSolver.parseConflicts(targetFile);
661
+ if (!conflictData) {
662
+ return { success: false, message: `Could not parse conflicts in ${targetFile}. Markers might be missing or malformed.`, other_files: files };
663
+ }
664
+ return {
665
+ success: true,
666
+ message: `Found ${files.length} conflicting files. Showing conflicts for: ${targetFile}`,
667
+ conflicts: conflictData.conflicts.map(c => ({
668
+ id: c.index,
669
+ lines: `${c.startLine}-${c.endLine}`,
670
+ ours: c.ours,
671
+ theirs: c.theirs,
672
+ base: c.base
673
+ })),
674
+ other_conflicting_files: files.filter(f => f !== targetFile)
675
+ };
676
+ }
677
+ case 'delegate_subtask': {
678
+ if (!p.task || typeof p.task !== 'string')
679
+ return { error: true, success: false, message: 'Missing task' };
680
+ if (!p.worker_type || typeof p.worker_type !== 'string')
681
+ return { error: true, success: false, message: 'Missing worker_type (agent mode)' };
682
+ if (!isValidMode(p.worker_type)) {
683
+ return { error: true, success: false, message: `Invalid worker_type: ${p.worker_type}. Must be a valid AgentMode.` };
684
+ }
685
+ const result = await this.swarmOrchestrator.delegateSubtask(p.worker_type, p.task);
686
+ return {
687
+ success: result.success,
688
+ result: result.result,
689
+ status: result.status,
690
+ worker: p.worker_type
691
+ };
692
+ }
544
693
  default:
545
- return { error: true, success: false, message: `Unknown tool: ${toolName}. Available tools: read_file, read_multiple_files, write_file, edit_file, edit_lines, insert_at_line, verified_edit, list_directory, search_files, run_command, create_directory, delete_file, move_file, get_context, revert_file, run_tests, get_test_status, get_git_status, get_git_diff_summary, get_git_changed_files, create_git_checkpoint, revert_to_git_checkpoint, git_show_diff, get_mcp_status, grep_code, web_search, fetch_url, remember_lesson, take_screenshot, get_console_logs, run_visual_test, check_accessibility, measure_performance, test_responsive, capture_network, run_playwright_test, search_skills_sh, install_skill_from_skills_sh` };
694
+ return { error: true, success: false, message: `Unknown tool: ${toolName}. Available tools: read_file, read_multiple_files, write_file, edit_file, edit_lines, insert_at_line, verified_edit, list_directory, search_files, run_command, create_directory, delete_file, move_file, get_context, revert_file, run_tests, get_test_status, get_git_status, get_git_diff_summary, get_git_changed_files, create_git_checkpoint, revert_to_git_checkpoint, git_show_diff, get_mcp_status, grep_code, web_search, fetch_url, remember_lesson, take_screenshot, get_console_logs, run_visual_test, check_accessibility, measure_performance, test_responsive, capture_network, run_playwright_test, search_skills_sh, install_skill_from_skills_sh, preview_app, delegate_subtask` };
546
695
  }
547
696
  }
548
697
  /**
@@ -726,20 +875,93 @@ export class CodingToolExecutor {
726
875
  },
727
876
  end_line: {
728
877
  type: 'number',
729
- description: 'End line number (1-indexed, inclusive) of the content to replace',
878
+ description: 'End line number (inclusive)',
730
879
  },
731
880
  old_content: {
732
881
  type: 'string',
733
- description: 'The exact content currently at lines start_line through end_line. This MUST match the actual file content or the edit will be rejected. Copy this directly from read_file output.',
882
+ description: 'The content currently at those lines (for verification)',
734
883
  },
735
884
  new_content: {
736
885
  type: 'string',
737
- description: 'The new content to replace the old content with',
886
+ description: 'New content to replace those lines',
738
887
  },
739
888
  },
740
889
  required: ['path', 'start_line', 'end_line', 'old_content', 'new_content'],
741
890
  },
742
891
  },
892
+ {
893
+ name: 'mine_project_patterns',
894
+ description: 'Analyze the project codebase to find repeated code patterns, structural duplication, and similar logic. Returns a list of pattern clusters that can be used to synthesize new skills.',
895
+ input_schema: {
896
+ type: 'object',
897
+ properties: {},
898
+ },
899
+ },
900
+ {
901
+ name: 'preview_app',
902
+ description: 'Capture a visual preview of a web application. Returns a screenshot path and a simplified semantic representation of the DOM. Useful for validating UI changes and layouts.',
903
+ input_schema: {
904
+ type: 'object',
905
+ properties: {
906
+ url: {
907
+ type: 'string',
908
+ description: 'URL of the application to preview',
909
+ },
910
+ full_page: {
911
+ type: 'boolean',
912
+ description: 'Capture full page screenshot instead of just viewport (default: false)',
913
+ },
914
+ },
915
+ required: ['url'],
916
+ },
917
+ },
918
+ {
919
+ name: 'start_background_task',
920
+ description: 'Start a long-running task in the background. The agent will run in a detached process.',
921
+ input_schema: {
922
+ type: 'object',
923
+ properties: {
924
+ prompt: {
925
+ type: 'string',
926
+ description: 'The task instructions for the background agent',
927
+ },
928
+ },
929
+ required: ['prompt'],
930
+ },
931
+ },
932
+ {
933
+ name: 'list_background_tasks',
934
+ description: 'List all running and completed background tasks.',
935
+ input_schema: {
936
+ type: 'object',
937
+ properties: {},
938
+ },
939
+ },
940
+ {
941
+ name: 'check_background_task',
942
+ description: 'Get the logs and status of a specific background task.',
943
+ input_schema: {
944
+ type: 'object',
945
+ properties: {
946
+ task_id: {
947
+ type: 'string',
948
+ description: 'The ID of the task to check',
949
+ },
950
+ },
951
+ required: ['task_id'],
952
+ },
953
+ },
954
+ {
955
+ name: 'search_code_graph',
956
+ description: 'Semantic code search using ts-morph. Finds where a symbol (class, function, variable) is defined and referenced in the project. More powerful than text search for code understanding.',
957
+ input_schema: {
958
+ type: 'object',
959
+ properties: {
960
+ query: { type: 'string', description: 'The symbol name to search for (e.g. "User", "authService")' }
961
+ },
962
+ required: ['query']
963
+ }
964
+ },
743
965
  {
744
966
  name: 'list_directory',
745
967
  description: 'List files and directories in a path with metadata.',
@@ -935,6 +1157,29 @@ export class CodingToolExecutor {
935
1157
  },
936
1158
  },
937
1159
  },
1160
+ {
1161
+ name: 'git_commit',
1162
+ description: 'Commit staged changes with optional AI attribution trailer (X-AI-Agent). Use this instead of run_command("git commit") to ensure proper credit.',
1163
+ input_schema: {
1164
+ type: 'object',
1165
+ properties: {
1166
+ message: { type: 'string', description: 'Commit message' },
1167
+ agent_name: { type: 'string', description: 'Name of the AI agent/persona (e.g. "Arya", "Coder")' }
1168
+ },
1169
+ required: ['message']
1170
+ }
1171
+ },
1172
+ {
1173
+ name: 'git_blame_ai',
1174
+ description: 'Get git blame output with AI attribution. Shows who (Human or AI Agent) wrote each line.',
1175
+ input_schema: {
1176
+ type: 'object',
1177
+ properties: {
1178
+ file_path: { type: 'string', description: 'Path to file' }
1179
+ },
1180
+ required: ['file_path']
1181
+ }
1182
+ },
938
1183
  {
939
1184
  name: 'create_git_checkpoint',
940
1185
  description: 'Create a safe restore point before making risky changes. Can use git stash or commit strategy.',
@@ -1002,6 +1247,32 @@ export class CodingToolExecutor {
1002
1247
  properties: {},
1003
1248
  },
1004
1249
  },
1250
+ {
1251
+ name: 'resolve_merge_conflicts',
1252
+ description: 'Scan for git merge conflicts and get details for resolution. Returns the conflict blocks (ours/theirs) so the agent can fix them.',
1253
+ input_schema: {
1254
+ type: 'object',
1255
+ properties: {
1256
+ file_path: { type: 'string', description: 'Optional: Specific file to resolve. If omitted, picks the first conflicting file.' }
1257
+ }
1258
+ }
1259
+ },
1260
+ {
1261
+ name: 'delegate_subtask',
1262
+ description: 'Delegate a task to a specialized sub-agent (swarm worker). The main agent waits for the result. Useful for parallelizing or isolating complex tasks.',
1263
+ input_schema: {
1264
+ type: 'object',
1265
+ properties: {
1266
+ task: { type: 'string', description: 'Task description for the worker.' },
1267
+ worker_type: {
1268
+ type: 'string',
1269
+ description: 'Agent mode/persona to use (e.g. "engineer", "reviewer", "planner")',
1270
+ enum: ['plan', 'agent', 'tester', 'debugger', 'security', 'review', 'team_leader', 'seo', 'product', 'architect', 'engineer', 'data', 'researcher']
1271
+ }
1272
+ },
1273
+ required: ['task', 'worker_type']
1274
+ }
1275
+ },
1005
1276
  {
1006
1277
  name: 'grep_code',
1007
1278
  description: 'Search for a text pattern across your codebase using ripgrep (or grep fallback). Returns matching file paths, line numbers, and line content. Use this to find function usages, variable references, imports, error messages, etc. Much faster than reading files one by one.',
@@ -2019,6 +2290,16 @@ export class CodingToolExecutor {
2019
2290
  };
2020
2291
  }
2021
2292
  }
2293
+ async gitCommit(message, agentName) {
2294
+ if (this.dryRun) {
2295
+ return { success: true, dryRun: true, message: `[DRY RUN] Would commit: "${message}" (Agent: ${agentName})` };
2296
+ }
2297
+ return this.gitUtils.commit(message, agentName);
2298
+ }
2299
+ async gitBlameAi(filePath) {
2300
+ const result = await this.gitUtils.getBlame(filePath);
2301
+ return { success: true, blame: result };
2302
+ }
2022
2303
  async createGitCheckpoint(message, strategy) {
2023
2304
  if (this.dryRun) {
2024
2305
  return {