File size: 4,281 Bytes
494c89b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
"""
Test patches incrementally to find which one breaks the extension
"""

import sys
import re
from pathlib import Path

sys.path.insert(0, str(Path(__file__).parent.parent))

from services.kiro_patcher_service import KiroPatcherService
from core.process_utils import is_kiro_running


class IncrementalPatcher(KiroPatcherService):
    """Patcher that can apply patches incrementally"""
    
    def apply_patch_1_only(self, content: str) -> str:
        """Apply only PATCH 1: getMachineId() injection (v4.0 approach)"""
        patched = content
        
        # === PATCH 1: getMachineId() - добавить проверку файла в начало ===
        pattern = r'function getMachineId\(\) \{\s+try \{\s+return \(0, import_node_machine_id\.machineIdSync\)\(\);'
        
        if re.search(pattern, patched):
            patch_code = f'''function getMachineId() {{
  {self.PATCH_MARKER}{self.PATCH_VERSION}_PATCH1_ONLY
  try {{
    const fs = require('fs');
    const path = require('path');
    const customIdFile = path.join(process.env.USERPROFILE || process.env.HOME || '', '.kiro-manager-wb', 'machine-id.txt');
    if (fs.existsSync(customIdFile)) {{
      const customId = fs.readFileSync(customIdFile, 'utf8').trim();
      if (customId && customId.length >= 32) {{
        return customId;
      }}
    }}
  }} catch (_) {{}}
  // END_PATCH_v{self.PATCH_VERSION}
  try {{
    return (0, import_node_machine_id.machineIdSync)();'''
            
            patched = re.sub(pattern, patch_code, patched)
            return patched
        
        return content
    
    def apply_patch_1_and_2(self, content: str) -> str:
        """Apply PATCH 1 + PATCH 2: getMachineId() + userAttributes()"""
        patched = self.apply_patch_1_only(content)
        
        # Replace marker
        patched = patched.replace('_PATCH1_ONLY', '_PATCH1_AND_2')
        
        # === PATCH 2: userAttributes() - вызывать getMachineId() динамически ===
        ua_pattern = r'(function userAttributes\(\)\s*\{\s*return\s*\{[^}]*machineId:\s*)MACHINE_ID(\s*\})'
        ua_match = re.search(ua_pattern, patched)
        if ua_match:
            patched = re.sub(ua_pattern, r'\1getMachineId()\2', patched)
        
        return patched
    
    def patch_incremental(self, patch_level: int = 1, skip_running_check: bool = False):
        """
        Apply patches incrementally
        patch_level: 1 = only PATCH 1, 2 = PATCH 1+2, 3 = all patches
        """
        if not skip_running_check and is_kiro_running():
            return {'success': False, 'message': 'Kiro is running. Please close it first.'}
        
        js_path = self.extension_js_path
        if not js_path:
            return {'success': False, 'message': 'extension.js not found'}
        
        # Read original
        content = js_path.read_text(encoding='utf-8')
        
        # Create backup
        backup_path = self._create_backup(js_path, content)
        
        # Apply patches based on level
        if patch_level == 1:
            patched = self.apply_patch_1_only(content)
            msg = "Applied PATCH 1 only (getMachineId replacement)"
        elif patch_level == 2:
            patched = self.apply_patch_1_and_2(content)
            msg = "Applied PATCH 1 + PATCH 2 (getMachineId + userAttributes)"
        elif patch_level == 3:
            patched = self._apply_patch(content)
            msg = "Applied all patches (PATCH 1 + 2 + 3)"
        else:
            return {'success': False, 'message': f'Invalid patch level: {patch_level}'}
        
        if patched == content:
            return {'success': False, 'message': 'No patches were applied'}
        
        # Write patched file
        js_path.write_text(patched, encoding='utf-8')
        
        return {
            'success': True,
            'message': msg,
            'backup_path': str(backup_path),
            'patched_file': str(js_path)
        }


if __name__ == '__main__':
    import json
    
    patcher = IncrementalPatcher()
    
    # Get patch level from command line
    patch_level = int(sys.argv[1]) if len(sys.argv) > 1 else 1
    
    result = patcher.patch_incremental(patch_level, skip_running_check=True)
    print(json.dumps(result, indent=2))