deepdebug-local-agent 1.0.22 → 1.1.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 (188) hide show
  1. package/.claude/context.md +76 -0
  2. package/.claude/skills/README.md +25 -0
  3. package/.claude/skills/tdd-debugging/SKILL.md +53 -0
  4. package/.claude/skills/tdd-debugging/references/anti-patterns.md +43 -0
  5. package/.claude/skills/tdd-debugging/references/command-reference.md +46 -0
  6. package/.claude/standards/README.md +51 -0
  7. package/.claude/standards/clean-code.md +75 -0
  8. package/.claude/standards/code-review-checklist.md +61 -0
  9. package/.claude/standards/layered-architecture.md +163 -0
  10. package/.claude/standards/node.md +45 -0
  11. package/.claude/standards/security-owasp.md +114 -0
  12. package/.claude/standards/simplicity.md +42 -0
  13. package/.claude/standards/solid.md +64 -0
  14. package/.claude/standards/testing.md +59 -0
  15. package/.cursor/rules/standards.mdc +17 -0
  16. package/.github/workflows/build-byoc-image.yml +315 -0
  17. package/.github/workflows/deploy-gcp.yml +102 -0
  18. package/.github/workflows/npm-publish.yml +69 -8
  19. package/AGENTS.md +21 -0
  20. package/CHANGELOG.md +69 -0
  21. package/CLAUDE.md +13 -0
  22. package/CLAUDE_CODE_AGENT_INFINITE.md +5 -3
  23. package/Dockerfile +4 -0
  24. package/Dockerfile.full +55 -3
  25. package/README.md +81 -0
  26. package/bin/install.js +16 -5
  27. package/cloudbuild-full.yaml +57 -0
  28. package/docker-compose.yml +5 -3
  29. package/docs/OBSERVABILITY.md +164 -0
  30. package/docs/byoc-agent-image.md +70 -0
  31. package/docs/graphify-packaging-plan.md +133 -0
  32. package/docs/graphify-validation-run-2026-10-28.md +243 -0
  33. package/docs/legacy-connectors.md +268 -0
  34. package/docs/releasing.md +43 -0
  35. package/docs/signed-commands.md +163 -0
  36. package/env.example +30 -0
  37. package/helm/Chart.yaml +2 -2
  38. package/helm/templates/deployment.yaml +13 -3
  39. package/helm/templates/networkpolicy.yaml +22 -0
  40. package/helm/templates/secret.yaml +1 -0
  41. package/helm/values.yaml +13 -14
  42. package/mcp-server.js +4 -1
  43. package/package.json +12 -4
  44. package/scripts/sync-fixtures.mjs +246 -0
  45. package/scripts/upgrade-observability-push.sh +227 -0
  46. package/src/adapters/as400/as400-parser.js +12 -0
  47. package/src/adapters/as400/index.js +134 -0
  48. package/src/adapters/cobol/cobol-parser.js +37 -0
  49. package/src/adapters/cobol/index.js +151 -0
  50. package/src/adapters/ibmmq/ibmmq-parser.js +23 -0
  51. package/src/adapters/ibmmq/index.js +137 -0
  52. package/src/adapters/index.js +79 -0
  53. package/src/adapters/oracle-forms/index.js +145 -0
  54. package/src/adapters/oracle-forms/oracle-forms-parser.js +11 -0
  55. package/src/adapters/sap/index.js +146 -0
  56. package/src/adapters/sap/sap-parser.js +41 -0
  57. package/src/ai-engine.js +22 -22
  58. package/src/config/trusted-signing-keys.json +3 -0
  59. package/src/detectors/build-tool-detector.js +50 -0
  60. package/src/detectors/multi-project-detector.js +22 -22
  61. package/src/detectors/service-detector.js +24 -24
  62. package/src/exec-utils.js +26 -4
  63. package/src/git/base-git-provider.js +117 -117
  64. package/src/git/bitbucket-provider.js +2 -2
  65. package/src/git/git-provider-registry.js +18 -18
  66. package/src/git/github-provider.js +13 -13
  67. package/src/git/multi-repo-pr.js +161 -0
  68. package/src/mcp-http-server.js +32 -16
  69. package/src/observability/bundle-files.js +418 -0
  70. package/src/observability/detect.js +151 -0
  71. package/src/observability/provision.js +212 -0
  72. package/src/observability/render-cli.js +59 -0
  73. package/src/observability/routes.js +88 -0
  74. package/src/patch/patch-engine.js +28 -28
  75. package/src/patch-manager.js +85 -85
  76. package/src/patch_bkp.js +14 -14
  77. package/src/ports.js +4 -4
  78. package/src/routes/workspace.route.js +47 -16
  79. package/src/runtimes/base-runtime.js +75 -75
  80. package/src/runtimes/java/gradle-runtime.js +17 -17
  81. package/src/runtimes/java/java-integrations.js +25 -25
  82. package/src/runtimes/java/maven-runtime.js +34 -34
  83. package/src/runtimes/node/node-integrations.js +1 -1
  84. package/src/runtimes/node/npm-runtime.js +14 -14
  85. package/src/runtimes/node/yarn-runtime.js +4 -4
  86. package/src/runtimes/runtime-registry.js +25 -25
  87. package/src/server-local.js +4 -4
  88. package/src/server.js +1412 -335
  89. package/src/siblings/burst-suppressor.js +89 -0
  90. package/src/siblings/capabilities.js +273 -0
  91. package/src/siblings/env-compat.cjs +58 -0
  92. package/src/siblings/incident-forwarder.js +320 -0
  93. package/src/siblings/logger.js +15 -0
  94. package/src/siblings/metrics.js +94 -0
  95. package/src/utils/agent-auth.js +184 -0
  96. package/src/utils/approval-token.js +56 -0
  97. package/src/utils/bind-host.js +29 -0
  98. package/src/utils/branch-refspec.js +98 -0
  99. package/src/utils/child-env.js +34 -0
  100. package/src/utils/environment-diagnostics.js +55 -55
  101. package/src/utils/exec-policy.js +962 -0
  102. package/src/utils/exec-utils.js +15 -15
  103. package/src/utils/file-count.js +46 -0
  104. package/src/utils/fs-utils.js +10 -10
  105. package/src/utils/multi-repo-open.js +132 -0
  106. package/src/utils/open-gate.js +183 -0
  107. package/src/utils/ranged-read.js +65 -0
  108. package/src/utils/request-guards.js +77 -0
  109. package/src/utils/request-signing.js +342 -0
  110. package/src/utils/root-recovery.js +244 -0
  111. package/src/utils/safe-exec-args.js +58 -0
  112. package/src/utils/sandbox.js +182 -0
  113. package/src/utils/search-outcome.js +56 -0
  114. package/src/utils/workspace-root.js +80 -0
  115. package/src/validators/syntax-validator.js +149 -0
  116. package/src/workspace/detect-port.js +16 -16
  117. package/src/workspace/file-reader.js +1 -1
  118. package/src/workspace/process-manager.js +46 -46
  119. package/src/workspace-manager.js +86 -24
  120. package/test/adapters/as400/as400.test.js +121 -0
  121. package/test/adapters/cobol/cobol.test.js +217 -0
  122. package/test/adapters/ibmmq/ibmmq.test.js +122 -0
  123. package/test/adapters/oracle-forms/oracle-forms.test.js +180 -0
  124. package/test/adapters/registry.test.js +108 -0
  125. package/test/adapters/sap/sap.test.js +142 -0
  126. package/test/agent-auth.test.js +194 -0
  127. package/test/bind-host.test.js +26 -0
  128. package/test/branch-refspec.test.js +224 -0
  129. package/test/burst-suppressor.test.js +60 -0
  130. package/test/capabilities-access.test.js +47 -0
  131. package/test/capabilities.test.js +87 -0
  132. package/test/child-env.test.js +23 -0
  133. package/test/env-compat.test.js +71 -0
  134. package/test/exec-policy.test.js +463 -0
  135. package/test/file-count.test.js +64 -0
  136. package/test/incident-forwarder.test.js +231 -0
  137. package/test/multi-repo-open.test.js +180 -0
  138. package/test/multi-repo-pr.test.js +129 -0
  139. package/test/observability-detect.test.js +199 -0
  140. package/test/open-gate.test.js +341 -0
  141. package/test/ranged-read.test.js +60 -0
  142. package/test/request-guards.test.js +91 -0
  143. package/test/request-signing.test.js +284 -0
  144. package/test/root-recovery-sidecar.test.js +171 -0
  145. package/test/root-recovery.test.js +274 -0
  146. package/test/safe-exec-args.test.js +58 -0
  147. package/test/sandbox.test.js +98 -0
  148. package/test/search-outcome.test.js +50 -0
  149. package/test/workspace-root.test.js +64 -0
  150. package/tools/graphify-validation/README.md +92 -0
  151. package/tools/graphify-validation/config/questions.json +31 -0
  152. package/tools/graphify-validation/config/repos.json +9 -0
  153. package/tools/graphify-validation/config/symbols.json +6 -0
  154. package/tools/graphify-validation/fixtures/spring/expected.json +34 -0
  155. package/tools/graphify-validation/fixtures/spring/src/main/java/com/example/fx/AppConfig.java +29 -0
  156. package/tools/graphify-validation/fixtures/spring/src/main/java/com/example/fx/AuditLogger.java +15 -0
  157. package/tools/graphify-validation/fixtures/spring/src/main/java/com/example/fx/Cache.java +7 -0
  158. package/tools/graphify-validation/fixtures/spring/src/main/java/com/example/fx/CheckoutService.java +25 -0
  159. package/tools/graphify-validation/fixtures/spring/src/main/java/com/example/fx/InMemoryCache.java +18 -0
  160. package/tools/graphify-validation/fixtures/spring/src/main/java/com/example/fx/OrderController.java +22 -0
  161. package/tools/graphify-validation/fixtures/spring/src/main/java/com/example/fx/PaymentGateway.java +5 -0
  162. package/tools/graphify-validation/fixtures/spring/src/main/java/com/example/fx/PaypalGateway.java +11 -0
  163. package/tools/graphify-validation/fixtures/spring/src/main/java/com/example/fx/RefundService.java +14 -0
  164. package/tools/graphify-validation/fixtures/spring/src/main/java/com/example/fx/StripeGateway.java +11 -0
  165. package/tools/graphify-validation/lib/affected_vs_rg.py +81 -0
  166. package/tools/graphify-validation/lib/audit_hook/sitecustomize.py +22 -0
  167. package/tools/graphify-validation/lib/graph_metrics.py +96 -0
  168. package/tools/graphify-validation/lib/gv_common.py +130 -0
  169. package/tools/graphify-validation/lib/licenses.py +47 -0
  170. package/tools/graphify-validation/lib/pip_audit_summary.py +18 -0
  171. package/tools/graphify-validation/lib/recall.py +115 -0
  172. package/tools/graphify-validation/lib/report.py +226 -0
  173. package/tools/graphify-validation/lib/run_all.py +237 -0
  174. package/tools/graphify-validation/lib/run_graphify.py +144 -0
  175. package/tools/graphify-validation/lib/rusage_helper.py +17 -0
  176. package/tools/graphify-validation/lib/sample_edges.py +246 -0
  177. package/tools/graphify-validation/lib/spring_fixture.py +81 -0
  178. package/tools/graphify-validation/requirements-py311.lock +508 -0
  179. package/tools/graphify-validation/requirements-tools.in +1 -0
  180. package/tools/graphify-validation/requirements-tools.lock +371 -0
  181. package/tools/graphify-validation/requirements.in +1 -0
  182. package/tools/graphify-validation/requirements.lock +502 -0
  183. package/tools/graphify-validation/run.sh +43 -0
  184. package/tools/graphify-validation/tests/test_harness.py +151 -0
  185. package/cloudbuild-agent-qa.yaml +0 -43
  186. package/cloudbuild-agent-staging.yaml +0 -40
  187. package/cloudbuild.yaml.deprecated +0 -42
  188. package/src/local-agent-source.tar.gz +0 -0
@@ -3,14 +3,14 @@ import path from 'path';
3
3
  import crypto from 'crypto';
4
4
 
5
5
  /**
6
- * PatchManager - Sistema robusto de aplicação de patches
6
+ * PatchManager - Robust patch application system
7
7
  *
8
8
  * Features:
9
- * - Validação rigorosa de unified diff
10
- * - Sistema de backup com rollback
11
- * - Mensagens de erro detalhadas
12
- * - Suporte a múltiplos arquivos
13
- * - Cleanup automático de backups antigos
9
+ * - Strict unified diff validation
10
+ * - Backup system with rollback
11
+ * - Detailed error messages
12
+ * - Multi-file support
13
+ * - Automatic cleanup of old backups
14
14
  */
15
15
  export class PatchManager {
16
16
  constructor(workspaceRoot) {
@@ -24,8 +24,8 @@ export class PatchManager {
24
24
  // ============================================
25
25
 
26
26
  /**
27
- * Valida se o diff está no formato unified diff correto
28
- * @param {string} diffText - Texto do diff
27
+ * Validates whether the diff is in the correct unified diff format
28
+ * @param {string} diffText - Diff text
29
29
  * @returns {ValidationResult} - { valid: boolean, errors: string[] }
30
30
  */
31
31
  validateDiff(diffText) {
@@ -37,7 +37,7 @@ export class PatchManager {
37
37
 
38
38
  const lines = diffText.split('\n');
39
39
 
40
- // Verificar se tem pelo menos os headers básicos
40
+ // Check that it has at least the basic headers
41
41
  const hasOldFileHeader = lines.some(l => l.startsWith('--- '));
42
42
  const hasNewFileHeader = lines.some(l => l.startsWith('+++ '));
43
43
  const hasHunkHeader = lines.some(l => /^@@ -\d+,?\d* \+\d+,?\d* @@/.test(l));
@@ -52,7 +52,7 @@ export class PatchManager {
52
52
  errors.push('Missing hunk header (@@ -line,count +line,count @@)');
53
53
  }
54
54
 
55
- // Validar estrutura dos hunks
55
+ // Validate the structure of the hunks
56
56
  const hunkErrors = this._validateHunks(lines);
57
57
  errors.push(...hunkErrors);
58
58
 
@@ -63,9 +63,9 @@ export class PatchManager {
63
63
  }
64
64
 
65
65
  /**
66
- * Faz parse do diff em estrutura manipulável
67
- * @param {string} diffText - Texto do diff
68
- * @returns {ParsedPatch} - Estrutura parseada do patch
66
+ * Parses the diff into a manipulable structure
67
+ * @param {string} diffText - Diff text
68
+ * @returns {ParsedPatch} - Parsed patch structure
69
69
  */
70
70
  parseDiff(diffText) {
71
71
  const validation = this.validateDiff(diffText);
@@ -81,7 +81,7 @@ export class PatchManager {
81
81
  for (let i = 0; i < lines.length; i++) {
82
82
  const line = lines[i];
83
83
 
84
- // Detectar início de novo arquivo
84
+ // Detect the start of a new file
85
85
  if (line.startsWith('--- ')) {
86
86
  if (currentPatch) {
87
87
  if (currentHunk) {
@@ -104,7 +104,7 @@ export class PatchManager {
104
104
  continue;
105
105
  }
106
106
 
107
- // Detectar início de hunk
107
+ // Detect the start of a hunk
108
108
  const hunkMatch = line.match(/^@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@(.*)$/);
109
109
  if (hunkMatch && currentPatch) {
110
110
  if (currentHunk) {
@@ -122,18 +122,18 @@ export class PatchManager {
122
122
  continue;
123
123
  }
124
124
 
125
- // Coletar linhas do hunk
125
+ // Collect the hunk lines
126
126
  if (currentHunk && (line.startsWith(' ') || line.startsWith('+') || line.startsWith('-') || line === '')) {
127
127
  const type = line.startsWith('+') ? 'add' :
128
128
  line.startsWith('-') ? 'remove' : 'context';
129
129
  currentHunk.lines.push({
130
130
  type,
131
- content: line.substring(1) // Remove o prefixo
131
+ content: line.substring(1) // Remove the prefix
132
132
  });
133
133
  }
134
134
  }
135
135
 
136
- // Adicionar último patch/hunk
136
+ // Add the last patch/hunk
137
137
  if (currentPatch) {
138
138
  if (currentHunk) {
139
139
  currentPatch.hunks.push(currentHunk);
@@ -153,40 +153,40 @@ export class PatchManager {
153
153
  }
154
154
 
155
155
  /**
156
- * Cria backup de um arquivo
157
- * @param {string} filePath - Caminho relativo do arquivo
156
+ * Creates a backup of a file
157
+ * @param {string} filePath - Relative path of the file
158
158
  * @returns {Promise<BackupResult>}
159
159
  */
160
160
  async backupFile(filePath) {
161
161
  const fullPath = path.join(this.workspaceRoot, filePath);
162
162
 
163
- // Verificar se arquivo existe
163
+ // Check whether the file exists
164
164
  try {
165
165
  await fs.access(fullPath);
166
166
  } catch {
167
167
  throw new PatchError('FILE_NOT_FOUND', `File not found: ${filePath}`);
168
168
  }
169
169
 
170
- // Criar diretório de backup
170
+ // Create the backup directory
171
171
  await this._ensureBackupDir();
172
172
 
173
- // Ler conteúdo original
173
+ // Read the original content
174
174
  const originalContent = await fs.readFile(fullPath, 'utf8');
175
175
 
176
- // Gerar ID único para o backup
176
+ // Generate a unique ID for the backup
177
177
  const timestamp = Date.now();
178
178
  const hash = crypto.createHash('md5').update(filePath + timestamp).digest('hex').substring(0, 8);
179
179
  const backupId = `${timestamp}-${hash}`;
180
180
 
181
- // Criar nome do arquivo de backup
181
+ // Build the backup file name
182
182
  const safeFileName = filePath.replace(/[\/\\]/g, '_');
183
183
  const backupFileName = `${backupId}_${safeFileName}`;
184
184
  const backupPath = path.join(this.backupDir, backupFileName);
185
185
 
186
- // Salvar backup
186
+ // Save the backup
187
187
  await fs.writeFile(backupPath, originalContent, 'utf8');
188
188
 
189
- // Salvar metadados
189
+ // Save the metadata
190
190
  const metadataPath = path.join(this.backupDir, `${backupId}.meta.json`);
191
191
  const metadata = {
192
192
  backupId,
@@ -199,10 +199,10 @@ export class PatchManager {
199
199
  };
200
200
  await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2), 'utf8');
201
201
 
202
- // Cleanup de backups antigos
202
+ // Cleanup of old backups
203
203
  await this._cleanupOldBackups(filePath);
204
204
 
205
- console.log(`📦 Backup created: ${backupId} for ${filePath}`);
205
+ console.log(`📦 Backup created: ${backupId} for ${filePath}`);
206
206
 
207
207
  return {
208
208
  backupId,
@@ -214,9 +214,9 @@ export class PatchManager {
214
214
  }
215
215
 
216
216
  /**
217
- * Aplica um patch parseado ao workspace
218
- * @param {ParsedPatch} parsedPatch - Resultado do parseDiff
219
- * @param {object} options - Opções { createBackup: boolean, dryRun: boolean }
217
+ * Applies a parsed patch to the workspace
218
+ * @param {ParsedPatch} parsedPatch - Result of parseDiff
219
+ * @param {object} options - Options { createBackup: boolean, dryRun: boolean }
220
220
  * @returns {Promise<ApplyResult>}
221
221
  */
222
222
  async applyPatch(parsedPatch, options = {}) {
@@ -237,20 +237,20 @@ export class PatchManager {
237
237
  }
238
238
 
239
239
  try {
240
- // Criar backup se solicitado
240
+ // Create a backup if requested
241
241
  if (createBackup && !dryRun) {
242
242
  const backup = await this.backupFile(targetPath);
243
243
  backups.push(backup);
244
244
  }
245
245
 
246
- // Ler arquivo original
246
+ // Read the original file
247
247
  const fullPath = path.join(this.workspaceRoot, targetPath);
248
248
  let originalContent;
249
249
 
250
250
  try {
251
251
  originalContent = await fs.readFile(fullPath, 'utf8');
252
252
  } catch (err) {
253
- // Arquivo novo sendo criado
253
+ // A new file is being created
254
254
  if (patch.oldFile === '/dev/null' || patch.oldFile.endsWith('/dev/null')) {
255
255
  originalContent = '';
256
256
  } else {
@@ -258,10 +258,10 @@ export class PatchManager {
258
258
  }
259
259
  }
260
260
 
261
- // Aplicar cada hunk
261
+ // Apply each hunk
262
262
  const originalLines = originalContent.split('\n');
263
263
  let modifiedLines = [...originalLines];
264
- let offset = 0; // Offset causado por adições/remoções anteriores
264
+ let offset = 0; // Offset caused by previous additions/removals
265
265
 
266
266
  for (let hunkIndex = 0; hunkIndex < patch.hunks.length; hunkIndex++) {
267
267
  const hunk = patch.hunks[hunkIndex];
@@ -275,11 +275,11 @@ export class PatchManager {
275
275
  offset = hunkResult.newOffset;
276
276
  }
277
277
 
278
- // Salvar arquivo modificado (se não for dry run)
278
+ // Save the modified file (unless it is a dry run)
279
279
  if (!dryRun) {
280
280
  const newContent = modifiedLines.join('\n');
281
281
  await fs.writeFile(fullPath, newContent, 'utf8');
282
- console.log(`✅ Patched: ${targetPath}`);
282
+ console.log(`✅ Patched: ${targetPath}`);
283
283
  }
284
284
 
285
285
  results.push({
@@ -290,14 +290,14 @@ export class PatchManager {
290
290
  });
291
291
 
292
292
  } catch (err) {
293
- // Rollback dos backups já criados nesta operação
293
+ // Roll back the backups already created in this operation
294
294
  if (!dryRun && backups.length > 0) {
295
- console.log(`⚠️ Rolling back ${backups.length} backups due to error...`);
295
+ console.log(`⚠️ Rolling back ${backups.length} backups due to error...`);
296
296
  for (const backup of backups) {
297
297
  try {
298
298
  await this.rollback(backup.backupId);
299
299
  } catch (rollbackErr) {
300
- console.error(`❌ Rollback failed for ${backup.backupId}: ${rollbackErr.message}`);
300
+ console.error(`❌ Rollback failed for ${backup.backupId}: ${rollbackErr.message}`);
301
301
  }
302
302
  }
303
303
  }
@@ -308,7 +308,7 @@ export class PatchManager {
308
308
  error: err instanceof PatchError ? err.message : err.toString()
309
309
  });
310
310
 
311
- // Parar no primeiro erro
311
+ // Stop at the first error
312
312
  break;
313
313
  }
314
314
  }
@@ -326,14 +326,14 @@ export class PatchManager {
326
326
  }
327
327
 
328
328
  /**
329
- * Restaura um arquivo do backup
330
- * @param {string} backupId - ID do backup
329
+ * Restores a file from a backup
330
+ * @param {string} backupId - Backup ID
331
331
  * @returns {Promise<boolean>}
332
332
  */
333
333
  async rollback(backupId) {
334
334
  const metadataPath = path.join(this.backupDir, `${backupId}.meta.json`);
335
335
 
336
- // Ler metadados
336
+ // Read the metadata
337
337
  let metadata;
338
338
  try {
339
339
  const metadataContent = await fs.readFile(metadataPath, 'utf8');
@@ -342,7 +342,7 @@ export class PatchManager {
342
342
  throw new PatchError('BACKUP_NOT_FOUND', `Backup not found: ${backupId}`);
343
343
  }
344
344
 
345
- // Ler conteúdo do backup
345
+ // Read the backup content
346
346
  const backupFullPath = path.join(this.backupDir, path.basename(metadata.backupPath));
347
347
  let backupContent;
348
348
  try {
@@ -351,22 +351,22 @@ export class PatchManager {
351
351
  throw new PatchError('BACKUP_CORRUPTED', `Backup file corrupted or missing: ${backupId}`);
352
352
  }
353
353
 
354
- // Verificar checksum
354
+ // Verify the checksum
355
355
  const currentChecksum = crypto.createHash('md5').update(backupContent).digest('hex');
356
356
  if (currentChecksum !== metadata.checksum) {
357
357
  throw new PatchError('CHECKSUM_MISMATCH', `Backup checksum mismatch for ${backupId}`);
358
358
  }
359
359
 
360
- // Restaurar arquivo original
360
+ // Restore the original file
361
361
  await fs.writeFile(metadata.fullPath, backupContent, 'utf8');
362
362
 
363
- console.log(`🔄 Rolled back: ${metadata.originalPath} from backup ${backupId}`);
363
+ console.log(`🔄 Rolled back: ${metadata.originalPath} from backup ${backupId}`);
364
364
 
365
365
  return true;
366
366
  }
367
367
 
368
368
  /**
369
- * Lista todos os backups disponíveis
369
+ * Lists all available backups
370
370
  * @returns {Promise<BackupInfo[]>}
371
371
  */
372
372
  async listBackups() {
@@ -391,18 +391,18 @@ export class PatchManager {
391
391
  size: metadata.size
392
392
  });
393
393
  } catch {
394
- // Ignorar arquivos de metadados corrompidos
394
+ // Ignore corrupted metadata files
395
395
  }
396
396
  }
397
397
 
398
- // Ordenar por timestamp (mais recente primeiro)
398
+ // Sort by timestamp (most recent first)
399
399
  backups.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp));
400
400
 
401
401
  return backups;
402
402
  }
403
403
 
404
404
  /**
405
- * Aplica patch de forma segura com backup automático e rollback em falha
405
+ * Applies a patch safely with automatic backup and rollback on failure
406
406
  * @param {string} diffText - Texto do diff
407
407
  * @param {string} incidentId - ID do incident (para logging)
408
408
  * @returns {Promise<SafePatchResult>}
@@ -410,10 +410,10 @@ export class PatchManager {
410
410
  async safePatch(diffText, incidentId = null) {
411
411
  const startTime = Date.now();
412
412
 
413
- console.log(`🔧 SafePatch starting${incidentId ? ` for incident ${incidentId}` : ''}...`);
414
- console.log(`📝 Diff size: ${diffText.length} characters`);
413
+ console.log(`🔧 SafePatch starting${incidentId ? ` for incident ${incidentId}` : ''}...`);
414
+ console.log(`📝 Diff size: ${diffText.length} characters`);
415
415
 
416
- // 1. Validar diff
416
+ // 1. Validate the diff
417
417
  const validation = this.validateDiff(diffText);
418
418
  if (!validation.valid) {
419
419
  return {
@@ -424,11 +424,11 @@ export class PatchManager {
424
424
  };
425
425
  }
426
426
 
427
- // 2. Parsear diff
427
+ // 2. Parse the diff
428
428
  let parsed;
429
429
  try {
430
430
  parsed = this.parseDiff(diffText);
431
- console.log(`📊 Parsed: ${parsed.totalFiles} file(s), ${parsed.totalHunks} hunk(s)`);
431
+ console.log(`📊 Parsed: ${parsed.totalFiles} file(s), ${parsed.totalHunks} hunk(s)`);
432
432
  } catch (err) {
433
433
  return {
434
434
  success: false,
@@ -438,7 +438,7 @@ export class PatchManager {
438
438
  };
439
439
  }
440
440
 
441
- // 3. Aplicar com backup
441
+ // 3. Apply with backup
442
442
  let result;
443
443
  try {
444
444
  result = await this.applyPatch(parsed, { createBackup: true, dryRun: false });
@@ -454,7 +454,7 @@ export class PatchManager {
454
454
  const duration = Date.now() - startTime;
455
455
 
456
456
  if (result.success) {
457
- console.log(`✅ SafePatch completed in ${duration}ms`);
457
+ console.log(`✅ SafePatch completed in ${duration}ms`);
458
458
  return {
459
459
  success: true,
460
460
  filesModified: result.filesModified,
@@ -464,7 +464,7 @@ export class PatchManager {
464
464
  duration
465
465
  };
466
466
  } else {
467
- console.log(`❌ SafePatch failed: ${result.results.find(r => !r.success)?.error}`);
467
+ console.log(`❌ SafePatch failed: ${result.results.find(r => !r.success)?.error}`);
468
468
  return {
469
469
  success: false,
470
470
  error: result.results.find(r => !r.success)?.error || 'Unknown error',
@@ -479,7 +479,7 @@ export class PatchManager {
479
479
  // ============================================
480
480
 
481
481
  /**
482
- * Valida a estrutura dos hunks
482
+ * Validates the structure of the hunks
483
483
  */
484
484
  _validateHunks(lines) {
485
485
  const errors = [];
@@ -493,10 +493,10 @@ export class PatchManager {
493
493
  for (let i = 0; i < lines.length; i++) {
494
494
  const line = lines[i];
495
495
 
496
- // Detectar início de hunk
496
+ // Detect the start of a hunk
497
497
  const hunkMatch = line.match(/^@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@/);
498
498
  if (hunkMatch) {
499
- // Verificar hunk anterior
499
+ // Check the previous hunk
500
500
  if (inHunk) {
501
501
  if (actualOldLines !== expectedOldLines) {
502
502
  errors.push(`Hunk #${hunkNumber}: expected ${expectedOldLines} old lines, got ${actualOldLines}`);
@@ -515,7 +515,7 @@ export class PatchManager {
515
515
  continue;
516
516
  }
517
517
 
518
- // Contar linhas dentro do hunk
518
+ // Count lines inside the hunk
519
519
  if (inHunk) {
520
520
  if (line.startsWith(' ')) {
521
521
  actualOldLines++;
@@ -525,16 +525,16 @@ export class PatchManager {
525
525
  } else if (line.startsWith('+')) {
526
526
  actualNewLines++;
527
527
  } else if (line.startsWith('\\')) {
528
- // "" - ignorar
528
+ // "" - ignore
529
529
  } else if (line.startsWith('diff ') || line.startsWith('index ') ||
530
530
  line.startsWith('--- ') || line.startsWith('+++ ')) {
531
- // Novo arquivo, resetar
531
+ // New file, reset
532
532
  inHunk = false;
533
533
  }
534
534
  }
535
535
  }
536
536
 
537
- // Verificar último hunk
537
+ // Check the last hunk
538
538
  if (inHunk) {
539
539
  if (actualOldLines !== expectedOldLines && expectedOldLines > 0) {
540
540
  errors.push(`Hunk #${hunkNumber}: expected ${expectedOldLines} old lines, got ${actualOldLines}`);
@@ -548,17 +548,17 @@ export class PatchManager {
548
548
  }
549
549
 
550
550
  /**
551
- * Extrai o caminho do arquivo do header
551
+ * Extracts the file path from the header
552
552
  */
553
553
  _extractFilePath(line, prefix) {
554
554
  let filePath = line.substring(prefix.length).trim();
555
555
 
556
- // Remover prefixo a/ ou b/
556
+ // Remove the a/ or b/ prefix
557
557
  if (filePath.startsWith('a/') || filePath.startsWith('b/')) {
558
558
  filePath = filePath.substring(2);
559
559
  }
560
560
 
561
- // Remover timestamp se presente (git diff format)
561
+ // Remove the timestamp if present (git diff format)
562
562
  const tabIndex = filePath.indexOf('\t');
563
563
  if (tabIndex > 0) {
564
564
  filePath = filePath.substring(0, tabIndex);
@@ -568,7 +568,7 @@ export class PatchManager {
568
568
  }
569
569
 
570
570
  /**
571
- * Aplica um único hunk ao array de linhas
571
+ * Applies a single hunk to the array of lines
572
572
  */
573
573
  _applyHunk(lines, hunk, offset, hunkNumber) {
574
574
  let startLine = hunk.oldStart - 1 + offset; // 0-indexed
@@ -609,24 +609,24 @@ export class PatchManager {
609
609
  // Context verified (exact or fuzzy match) - apply the changes
610
610
  const newLines = [...lines];
611
611
 
612
- // Calcular quantas linhas remover e quais linhas adicionar
612
+ // Calculate how many lines to remove and which lines to add
613
613
  const linesToAdd = hunk.lines.filter(l => l.type === 'add').map(l => l.content);
614
614
  const removeCount = hunk.lines.filter(l => l.type === 'remove').length;
615
615
  const contextAndRemoveCount = originalLines.length;
616
616
 
617
- // Construir o novo conteúdo para esta seção
617
+ // Build the new content for this section
618
618
  const newSectionLines = [];
619
619
  for (const hunkLine of hunk.lines) {
620
620
  if (hunkLine.type === 'context' || hunkLine.type === 'add') {
621
621
  newSectionLines.push(hunkLine.content);
622
622
  }
623
- // 'remove' lines são ignoradas (não vão para o novo conteúdo)
623
+ // 'remove' lines are ignored (they do not go into the new content)
624
624
  }
625
625
 
626
- // Substituir a seção antiga pela nova
626
+ // Replace the old section with the new one
627
627
  newLines.splice(startLine, contextAndRemoveCount, ...newSectionLines);
628
628
 
629
- // Calcular novo offset
629
+ // Calculate the new offset
630
630
  const addedCount = linesToAdd.length;
631
631
  const newOffset = offset + addedCount - removeCount;
632
632
 
@@ -640,7 +640,7 @@ export class PatchManager {
640
640
  }
641
641
 
642
642
  /**
643
- * Trunca string para exibição
643
+ * Truncates a string for display
644
644
  */
645
645
  /**
646
646
  * Check if context lines match at a given position in the file.
@@ -682,19 +682,19 @@ export class PatchManager {
682
682
  }
683
683
 
684
684
  /**
685
- * Garante que o diretório de backup existe
685
+ * Ensures the backup directory exists
686
686
  */
687
687
  async _ensureBackupDir() {
688
688
  try {
689
689
  await fs.access(this.backupDir);
690
690
  } catch {
691
691
  await fs.mkdir(this.backupDir, { recursive: true });
692
- console.log(`📁 Created backup directory: ${this.backupDir}`);
692
+ console.log(`📁 Created backup directory: ${this.backupDir}`);
693
693
  }
694
694
  }
695
695
 
696
696
  /**
697
- * Remove backups antigos para um arquivo específico
697
+ * Removes old backups for a specific file
698
698
  */
699
699
  async _cleanupOldBackups(originalPath) {
700
700
  const backups = await this.listBackups();
@@ -704,7 +704,7 @@ export class PatchManager {
704
704
  return;
705
705
  }
706
706
 
707
- // Remover backups mais antigos
707
+ // Remove the oldest backups
708
708
  const toRemove = fileBackups.slice(this.maxBackupsPerFile);
709
709
 
710
710
  for (const backup of toRemove) {
@@ -715,9 +715,9 @@ export class PatchManager {
715
715
  await fs.unlink(path.join(this.backupDir, backupFileName));
716
716
  await fs.unlink(path.join(this.backupDir, `${backup.backupId}.meta.json`));
717
717
 
718
- console.log(`🗑️ Removed old backup: ${backup.backupId}`);
718
+ console.log(`🗑️ Removed old backup: ${backup.backupId}`);
719
719
  } catch (err) {
720
- console.warn(`⚠️ Failed to remove old backup ${backup.backupId}: ${err.message}`);
720
+ console.warn(`⚠️ Failed to remove old backup ${backup.backupId}: ${err.message}`);
721
721
  }
722
722
  }
723
723
  }
package/src/patch_bkp.js CHANGED
@@ -5,8 +5,8 @@ import pkg from "unidiff";
5
5
  const { parsePatch, applyPatch } = pkg;
6
6
 
7
7
  /**
8
- * Aplica um unified diff ao arquivo alvo.
9
- * VERSION 2: Melhor logging e fallback para replace direto.
8
+ * Applies a unified diff to the target file.
9
+ * VERSION 2: Better logging and fallback to direct replace.
10
10
  */
11
11
  export async function applyUnifiedDiff(root, diffText) {
12
12
  console.log("🔧 [patch_bkp.js] Applying unified diff...");
@@ -17,14 +17,14 @@ export async function applyUnifiedDiff(root, diffText) {
17
17
  throw new Error("Empty diff text provided");
18
18
  }
19
19
 
20
- // Log primeiras linhas do diff para debug
20
+ // Log the first lines of the diff for debugging
21
21
  const diffLines = diffText.split("\n");
22
22
  console.log("📋 Diff preview:");
23
23
  for (let i = 0; i < Math.min(10, diffLines.length); i++) {
24
24
  console.log(` ${i + 1}: ${diffLines[i]}`);
25
25
  }
26
26
 
27
- // Parse o diff
27
+ // Parse the diff
28
28
  let patches;
29
29
  try {
30
30
  patches = parsePatch(diffText);
@@ -45,7 +45,7 @@ export async function applyUnifiedDiff(root, diffText) {
45
45
  hunks: p?.hunks?.length || 0
46
46
  });
47
47
 
48
- // Descobre path alvo a partir do patch
48
+ // Determine the target path from the patch
49
49
  const targetRel =
50
50
  p?.newFileName?.replace(/^b\//, "") ||
51
51
  p?.oldFileName?.replace(/^a\//, "");
@@ -59,12 +59,12 @@ export async function applyUnifiedDiff(root, diffText) {
59
59
  const full = path.join(root, targetRel);
60
60
  console.log("📄 Full path:", full);
61
61
 
62
- // Verificar se arquivo existe
62
+ // Check whether the file exists
63
63
  if (!(await exists(full))) {
64
64
  throw new Error(`Target file not found: ${full}`);
65
65
  }
66
66
 
67
- // Ler arquivo original
67
+ // Read the original file
68
68
  let original;
69
69
  try {
70
70
  original = await readFile(full, "utf8");
@@ -73,7 +73,7 @@ export async function applyUnifiedDiff(root, diffText) {
73
73
  throw new Error(`Failed to read target file: ${readErr.message}`);
74
74
  }
75
75
 
76
- // Tentar aplicar o patch
76
+ // Try to apply the patch
77
77
  let result;
78
78
  try {
79
79
  result = applyPatch(original, p);
@@ -84,13 +84,13 @@ export async function applyUnifiedDiff(root, diffText) {
84
84
  }
85
85
 
86
86
  if (result === false) {
87
- // Log mais detalhes sobre por que falhou
87
+ // Log more details about why it failed
88
88
  console.error("❌ Patch failed to apply. Possible reasons:");
89
89
  console.error(" - Line numbers don't match current file");
90
90
  console.error(" - Context lines don't match");
91
91
  console.error(" - File was modified since diff was generated");
92
92
 
93
- // Log hunks para debug
93
+ // Log hunks for debugging
94
94
  if (p.hunks) {
95
95
  for (const hunk of p.hunks) {
96
96
  console.error(` Hunk: @@ -${hunk.oldStart},${hunk.oldLines} +${hunk.newStart},${hunk.newLines} @@`);
@@ -100,7 +100,7 @@ export async function applyUnifiedDiff(root, diffText) {
100
100
  throw new Error("Patch failed to apply - context mismatch");
101
101
  }
102
102
 
103
- // Escrever resultado
103
+ // Write the result
104
104
  try {
105
105
  await writeFile(full, result, "utf8");
106
106
  console.log("✅ Patch applied successfully!");
@@ -118,7 +118,7 @@ export async function applyUnifiedDiff(root, diffText) {
118
118
  }
119
119
 
120
120
  /**
121
- * Conta quantas linhas foram alteradas
121
+ * Counts how many lines were changed
122
122
  */
123
123
  function countChangedLines(patch) {
124
124
  if (!patch.hunks) return 0;
@@ -132,8 +132,8 @@ function countChangedLines(patch) {
132
132
  }
133
133
 
134
134
  /**
135
- * Fallback: aplica substituição direta do arquivo
136
- * Usado quando o patch unidiff falha mas temos o conteúdo completo
135
+ * Fallback: applies a direct file replacement
136
+ * Used when the unidiff patch fails but we have the full content
137
137
  */
138
138
  export async function applyDirectReplace(root, targetRel, newContent) {
139
139
  console.log("🔄 [patch_bkp.js] Applying direct replace...");