@resolveio/server-lib 22.3.221 → 22.3.222

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 (745) hide show
  1. package/ai/assistant-core-heuristics.d.ts +11 -0
  2. package/ai/assistant-core-heuristics.js +356 -0
  3. package/ai/assistant-core-heuristics.js.map +1 -0
  4. package/ai/resolveio-platform-intelligence-memory-corpus.d.ts +3 -0
  5. package/ai/resolveio-platform-intelligence-memory-corpus.js +214 -0
  6. package/ai/resolveio-platform-intelligence-memory-corpus.js.map +1 -0
  7. package/ai/resolveio-platform-intelligence-memory.d.ts +20 -0
  8. package/ai/resolveio-platform-intelligence-memory.js +341 -0
  9. package/ai/resolveio-platform-intelligence-memory.js.map +1 -0
  10. package/{src/ai/resolveio-platform-intelligence-types.ts → ai/resolveio-platform-intelligence-types.d.ts} +15 -20
  11. package/ai/resolveio-platform-intelligence-types.js +4 -0
  12. package/ai/resolveio-platform-intelligence-types.js.map +1 -0
  13. package/ai/resolveio-platform-intelligence.d.ts +6 -0
  14. package/ai/resolveio-platform-intelligence.js +463 -0
  15. package/ai/resolveio-platform-intelligence.js.map +1 -0
  16. package/client-server-app.d.ts +1 -0
  17. package/client-server-app.js +68 -0
  18. package/client-server-app.js.map +1 -0
  19. package/collections/ai-run.collection.d.ts +3 -0
  20. package/collections/ai-run.collection.js +170 -0
  21. package/collections/ai-run.collection.js.map +1 -0
  22. package/collections/ai-terminal-conversation.collection.d.ts +2 -0
  23. package/collections/ai-terminal-conversation.collection.js +140 -0
  24. package/collections/ai-terminal-conversation.collection.js.map +1 -0
  25. package/collections/ai-terminal-issue-report.collection.d.ts +2 -0
  26. package/collections/ai-terminal-issue-report.collection.js +148 -0
  27. package/collections/ai-terminal-issue-report.collection.js.map +1 -0
  28. package/collections/ai-terminal-message.collection.d.ts +2 -0
  29. package/collections/ai-terminal-message.collection.js +121 -0
  30. package/collections/ai-terminal-message.collection.js.map +1 -0
  31. package/collections/app-setting.collection.d.ts +3 -0
  32. package/collections/app-setting.collection.js +103 -0
  33. package/collections/app-setting.collection.js.map +1 -0
  34. package/collections/app-status.collection.d.ts +3 -0
  35. package/collections/app-status.collection.js +57 -0
  36. package/collections/app-status.collection.js.map +1 -0
  37. package/collections/communication-metric.collection.d.ts +2 -0
  38. package/collections/communication-metric.collection.js +133 -0
  39. package/collections/communication-metric.collection.js.map +1 -0
  40. package/collections/counter.collection.d.ts +3 -0
  41. package/collections/counter.collection.js +56 -0
  42. package/collections/counter.collection.js.map +1 -0
  43. package/collections/cron-job-history.collection.d.ts +3 -0
  44. package/collections/cron-job-history.collection.js +137 -0
  45. package/collections/cron-job-history.collection.js.map +1 -0
  46. package/collections/cron-job.collection.d.ts +3 -0
  47. package/collections/cron-job.collection.js +92 -0
  48. package/collections/cron-job.collection.js.map +1 -0
  49. package/collections/customer-notification.collection.d.ts +3 -0
  50. package/collections/customer-notification.collection.js +130 -0
  51. package/collections/customer-notification.collection.js.map +1 -0
  52. package/collections/customer-portal-password.collection.d.ts +3 -0
  53. package/collections/customer-portal-password.collection.js +75 -0
  54. package/collections/customer-portal-password.collection.js.map +1 -0
  55. package/collections/email-history.collection.d.ts +3 -0
  56. package/collections/email-history.collection.js +134 -0
  57. package/collections/email-history.collection.js.map +1 -0
  58. package/collections/email-verified.collection.d.ts +3 -0
  59. package/collections/email-verified.collection.js +62 -0
  60. package/collections/email-verified.collection.js.map +1 -0
  61. package/collections/file.collection.d.ts +3 -0
  62. package/collections/file.collection.js +74 -0
  63. package/collections/file.collection.js.map +1 -0
  64. package/collections/flag-update.collection.d.ts +3 -0
  65. package/collections/flag-update.collection.js +57 -0
  66. package/collections/flag-update.collection.js.map +1 -0
  67. package/collections/flag.collection.d.ts +3 -0
  68. package/collections/flag.collection.js +57 -0
  69. package/collections/flag.collection.js.map +1 -0
  70. package/collections/log-method-latency.collection.d.ts +3 -0
  71. package/collections/log-method-latency.collection.js +77 -0
  72. package/collections/log-method-latency.collection.js.map +1 -0
  73. package/collections/log-subscription.collection.d.ts +3 -0
  74. package/collections/log-subscription.collection.js +80 -0
  75. package/collections/log-subscription.collection.js.map +1 -0
  76. package/collections/log.collection.d.ts +3 -0
  77. package/collections/log.collection.js +93 -0
  78. package/collections/log.collection.js.map +1 -0
  79. package/collections/logged-in-users.collection.d.ts +3 -0
  80. package/collections/logged-in-users.collection.js +67 -0
  81. package/collections/logged-in-users.collection.js.map +1 -0
  82. package/collections/monitor-cpu.collection.d.ts +3 -0
  83. package/collections/monitor-cpu.collection.js +65 -0
  84. package/collections/monitor-cpu.collection.js.map +1 -0
  85. package/collections/monitor-function.collection.d.ts +3 -0
  86. package/collections/monitor-function.collection.js +74 -0
  87. package/collections/monitor-function.collection.js.map +1 -0
  88. package/collections/monitor-memory.collection.d.ts +3 -0
  89. package/collections/monitor-memory.collection.js +77 -0
  90. package/collections/monitor-memory.collection.js.map +1 -0
  91. package/collections/monitor-mongo.collection.d.ts +3 -0
  92. package/collections/monitor-mongo.collection.js +71 -0
  93. package/collections/monitor-mongo.collection.js.map +1 -0
  94. package/collections/notification.collection.d.ts +3 -0
  95. package/collections/notification.collection.js +57 -0
  96. package/collections/notification.collection.js.map +1 -0
  97. package/collections/openai-usage-ledger.collection.d.ts +2 -0
  98. package/collections/openai-usage-ledger.collection.js +188 -0
  99. package/collections/openai-usage-ledger.collection.js.map +1 -0
  100. package/collections/report-builder-dashboard-builder.collection.d.ts +3 -0
  101. package/collections/report-builder-dashboard-builder.collection.js +109 -0
  102. package/collections/report-builder-dashboard-builder.collection.js.map +1 -0
  103. package/collections/report-builder-library.collection.d.ts +3 -0
  104. package/collections/report-builder-library.collection.js +87 -0
  105. package/collections/report-builder-library.collection.js.map +1 -0
  106. package/collections/report-builder-report.collection.d.ts +4 -0
  107. package/collections/report-builder-report.collection.js +184 -0
  108. package/collections/report-builder-report.collection.js.map +1 -0
  109. package/collections/user-group.collection.d.ts +4 -0
  110. package/collections/user-group.collection.js +89 -0
  111. package/collections/user-group.collection.js.map +1 -0
  112. package/collections/user-guide.collection.d.ts +3 -0
  113. package/collections/user-guide.collection.js +57 -0
  114. package/collections/user-guide.collection.js.map +1 -0
  115. package/collections/user.collection.d.ts +4 -0
  116. package/collections/user.collection.js +180 -0
  117. package/collections/user.collection.js.map +1 -0
  118. package/cron/cron.d.ts +14 -0
  119. package/cron/cron.js +216 -0
  120. package/cron/cron.js.map +1 -0
  121. package/fixtures/cron-jobs.d.ts +1 -0
  122. package/fixtures/cron-jobs.js +150 -0
  123. package/fixtures/cron-jobs.js.map +1 -0
  124. package/fixtures/init.d.ts +1 -0
  125. package/fixtures/init.js +91 -0
  126. package/fixtures/init.js.map +1 -0
  127. package/http/auth.d.ts +2 -0
  128. package/http/auth.js +951 -0
  129. package/http/auth.js.map +1 -0
  130. package/http/health.d.ts +1 -0
  131. package/http/health.js +11 -0
  132. package/http/health.js.map +1 -0
  133. package/http/home.d.ts +1 -0
  134. package/http/home.js +134 -0
  135. package/http/home.js.map +1 -0
  136. package/http/slow-query-publication.d.ts +2 -0
  137. package/http/slow-query-publication.js +99 -0
  138. package/http/slow-query-publication.js.map +1 -0
  139. package/index.d.ts +1 -0
  140. package/index.js +19 -0
  141. package/index.js.map +1 -0
  142. package/managers/ai-assistant-codex-manager.manager.d.ts +67 -0
  143. package/managers/ai-assistant-codex-manager.manager.js +1113 -0
  144. package/managers/ai-assistant-codex-manager.manager.js.map +1 -0
  145. package/managers/ai-run-evidence.manager.d.ts +36 -0
  146. package/managers/ai-run-evidence.manager.js +377 -0
  147. package/managers/ai-run-evidence.manager.js.map +1 -0
  148. package/managers/communication-metric.manager.d.ts +16 -0
  149. package/managers/communication-metric.manager.js +134 -0
  150. package/managers/communication-metric.manager.js.map +1 -0
  151. package/managers/cron.manager.d.ts +20 -0
  152. package/managers/cron.manager.js +534 -0
  153. package/managers/cron.manager.js.map +1 -0
  154. package/managers/customer-notification-content.manager.d.ts +55 -0
  155. package/managers/customer-notification-content.manager.js +158 -0
  156. package/managers/customer-notification-content.manager.js.map +1 -0
  157. package/managers/diagnostic-manager-bootstrap.d.ts +9 -0
  158. package/managers/diagnostic-manager-bootstrap.js +260 -0
  159. package/managers/diagnostic-manager-bootstrap.js.map +1 -0
  160. package/managers/error-auto-fix.manager.d.ts +149 -0
  161. package/managers/error-auto-fix.manager.js +3064 -0
  162. package/managers/error-auto-fix.manager.js.map +1 -0
  163. package/managers/local-log.manager.d.ts +18 -0
  164. package/managers/local-log.manager.js +88 -0
  165. package/managers/local-log.manager.js.map +1 -0
  166. package/managers/method.manager.d.ts +84 -0
  167. package/managers/method.manager.js +1964 -0
  168. package/managers/method.manager.js.map +1 -0
  169. package/managers/mongo.manager.d.ts +224 -0
  170. package/managers/mongo.manager.js +5000 -0
  171. package/managers/mongo.manager.js.map +1 -0
  172. package/managers/monitor.manager.d.ts +70 -0
  173. package/managers/monitor.manager.js +550 -0
  174. package/managers/monitor.manager.js.map +1 -0
  175. package/managers/openai-usage-ledger.manager.d.ts +30 -0
  176. package/managers/openai-usage-ledger.manager.js +142 -0
  177. package/managers/openai-usage-ledger.manager.js.map +1 -0
  178. package/managers/slow-query-verifier.manager.d.ts +144 -0
  179. package/managers/slow-query-verifier.manager.js +3857 -0
  180. package/managers/slow-query-verifier.manager.js.map +1 -0
  181. package/managers/slow-query.manager.d.ts +28 -0
  182. package/managers/slow-query.manager.js +468 -0
  183. package/managers/slow-query.manager.js.map +1 -0
  184. package/managers/subscription.manager.d.ts +169 -0
  185. package/managers/subscription.manager.js +3434 -0
  186. package/managers/subscription.manager.js.map +1 -0
  187. package/managers/websocket.manager.d.ts +73 -0
  188. package/managers/websocket.manager.js +673 -0
  189. package/managers/websocket.manager.js.map +1 -0
  190. package/managers/worker-dispatcher.manager.d.ts +120 -0
  191. package/managers/worker-dispatcher.manager.js +1266 -0
  192. package/managers/worker-dispatcher.manager.js.map +1 -0
  193. package/managers/worker-server.manager.d.ts +35 -0
  194. package/managers/worker-server.manager.js +582 -0
  195. package/managers/worker-server.manager.js.map +1 -0
  196. package/methods/accounts.d.ts +2 -0
  197. package/methods/accounts.js +624 -0
  198. package/methods/accounts.js.map +1 -0
  199. package/methods/ai-terminal.d.ts +458 -0
  200. package/methods/ai-terminal.js +27991 -0
  201. package/methods/ai-terminal.js.map +1 -0
  202. package/methods/app-settings.d.ts +2 -0
  203. package/methods/app-settings.js +169 -0
  204. package/methods/app-settings.js.map +1 -0
  205. package/methods/aws.d.ts +2 -0
  206. package/methods/aws.js +877 -0
  207. package/methods/aws.js.map +1 -0
  208. package/methods/collections.d.ts +2 -0
  209. package/methods/collections.js +719 -0
  210. package/methods/collections.js.map +1 -0
  211. package/methods/counters.d.ts +2 -0
  212. package/methods/counters.js +113 -0
  213. package/methods/counters.js.map +1 -0
  214. package/methods/cron-jobs.d.ts +2 -0
  215. package/methods/cron-jobs.js +2475 -0
  216. package/methods/cron-jobs.js.map +1 -0
  217. package/methods/customer-notifications.d.ts +2 -0
  218. package/methods/customer-notifications.js +528 -0
  219. package/methods/customer-notifications.js.map +1 -0
  220. package/methods/diagnostics.d.ts +2 -0
  221. package/methods/diagnostics.js +703 -0
  222. package/methods/diagnostics.js.map +1 -0
  223. package/methods/flag-updates.d.ts +2 -0
  224. package/methods/flag-updates.js +8 -0
  225. package/methods/flag-updates.js.map +1 -0
  226. package/methods/flags.d.ts +2 -0
  227. package/methods/flags.js +8 -0
  228. package/methods/flags.js.map +1 -0
  229. package/methods/logs.d.ts +2 -0
  230. package/methods/logs.js +751 -0
  231. package/methods/logs.js.map +1 -0
  232. package/methods/mongo-explorer.d.ts +2 -0
  233. package/methods/mongo-explorer.js +1808 -0
  234. package/methods/mongo-explorer.js.map +1 -0
  235. package/methods/monitor.d.ts +2 -0
  236. package/methods/monitor.js +543 -0
  237. package/methods/monitor.js.map +1 -0
  238. package/methods/pdf.d.ts +2 -0
  239. package/methods/pdf.js +1216 -0
  240. package/methods/pdf.js.map +1 -0
  241. package/methods/publications.d.ts +1 -0
  242. package/methods/publications.js +183 -0
  243. package/methods/publications.js.map +1 -0
  244. package/methods/report-builder.d.ts +2 -0
  245. package/methods/report-builder.js +3094 -0
  246. package/methods/report-builder.js.map +1 -0
  247. package/methods/support.d.ts +2 -0
  248. package/methods/support.js +430 -0
  249. package/methods/support.js.map +1 -0
  250. package/models/ai-run.model.d.ts +19 -0
  251. package/models/ai-run.model.js +4 -0
  252. package/models/ai-run.model.js.map +1 -0
  253. package/models/ai-terminal-conversation.model.d.ts +17 -0
  254. package/models/ai-terminal-conversation.model.js +4 -0
  255. package/models/ai-terminal-conversation.model.js.map +1 -0
  256. package/models/ai-terminal-issue-report.model.d.ts +19 -0
  257. package/models/ai-terminal-issue-report.model.js +4 -0
  258. package/models/ai-terminal-issue-report.model.js.map +1 -0
  259. package/models/ai-terminal-message.model.d.ts +22 -0
  260. package/models/ai-terminal-message.model.js +4 -0
  261. package/models/ai-terminal-message.model.js.map +1 -0
  262. package/models/app-setting.model.d.ts +16 -0
  263. package/models/app-setting.model.js +4 -0
  264. package/models/app-setting.model.js.map +1 -0
  265. package/{src/models/app-status.model.ts → models/app-status.model.d.ts} +2 -3
  266. package/models/app-status.model.js +4 -0
  267. package/models/app-status.model.js.map +1 -0
  268. package/{src/models/billing-logged-in-users.model.ts → models/billing-logged-in-users.model.d.ts} +4 -5
  269. package/models/billing-logged-in-users.model.js +4 -0
  270. package/models/billing-logged-in-users.model.js.map +1 -0
  271. package/models/collection-document.model.d.ts +21 -0
  272. package/models/collection-document.model.js +4 -0
  273. package/models/collection-document.model.js.map +1 -0
  274. package/models/communication-metric.model.d.ts +20 -0
  275. package/models/communication-metric.model.js +4 -0
  276. package/models/communication-metric.model.js.map +1 -0
  277. package/{src/models/counter.model.ts → models/counter.model.d.ts} +3 -4
  278. package/models/counter.model.js +4 -0
  279. package/models/counter.model.js.map +1 -0
  280. package/models/cron-job-history.model.d.ts +15 -0
  281. package/models/cron-job-history.model.js +4 -0
  282. package/models/cron-job-history.model.js.map +1 -0
  283. package/models/cron-job.model.d.ts +14 -0
  284. package/models/cron-job.model.js +4 -0
  285. package/models/cron-job.model.js.map +1 -0
  286. package/models/customer-notification.model.d.ts +26 -0
  287. package/models/customer-notification.model.js +4 -0
  288. package/models/customer-notification.model.js.map +1 -0
  289. package/models/customer-portal-password.model.d.ts +11 -0
  290. package/models/customer-portal-password.model.js +4 -0
  291. package/models/customer-portal-password.model.js.map +1 -0
  292. package/models/dialog.model.d.ts +23 -0
  293. package/models/dialog.model.js +4 -0
  294. package/models/dialog.model.js.map +1 -0
  295. package/models/email-history.model.d.ts +32 -0
  296. package/{src/models/email-history.model.ts → models/email-history.model.js} +4 -36
  297. package/models/email-history.model.js.map +1 -0
  298. package/{src/models/email-verified.model.ts → models/email-verified.model.d.ts} +5 -6
  299. package/models/email-verified.model.js +4 -0
  300. package/models/email-verified.model.js.map +1 -0
  301. package/{src/models/file.model.ts → models/file.model.d.ts} +7 -8
  302. package/models/file.model.js +4 -0
  303. package/models/file.model.js.map +1 -0
  304. package/{src/models/flag-update.model.ts → models/flag-update.model.d.ts} +3 -4
  305. package/models/flag-update.model.js +4 -0
  306. package/models/flag-update.model.js.map +1 -0
  307. package/{src/models/flag.model.ts → models/flag.model.d.ts} +3 -4
  308. package/models/flag.model.js +4 -0
  309. package/models/flag.model.js.map +1 -0
  310. package/models/log-method-latency.model.d.ts +10 -0
  311. package/models/log-method-latency.model.js +4 -0
  312. package/models/log-method-latency.model.js.map +1 -0
  313. package/{src/models/log-subscription.model.ts → models/log-subscription.model.d.ts} +9 -11
  314. package/models/log-subscription.model.js +4 -0
  315. package/models/log-subscription.model.js.map +1 -0
  316. package/models/log.model.d.ts +17 -0
  317. package/models/log.model.js +4 -0
  318. package/models/log.model.js.map +1 -0
  319. package/{src/models/logged-in-users.model.ts → models/logged-in-users.model.d.ts} +5 -6
  320. package/models/logged-in-users.model.js +4 -0
  321. package/models/logged-in-users.model.js.map +1 -0
  322. package/{src/models/method-response.model.ts → models/method-response.model.d.ts} +6 -7
  323. package/models/method-response.model.js +4 -0
  324. package/models/method-response.model.js.map +1 -0
  325. package/models/method.model.d.ts +26 -0
  326. package/models/method.model.js +4 -0
  327. package/models/method.model.js.map +1 -0
  328. package/{src/models/monitor-cpu.model.ts → models/monitor-cpu.model.d.ts} +7 -9
  329. package/models/monitor-cpu.model.js +4 -0
  330. package/models/monitor-cpu.model.js.map +1 -0
  331. package/models/monitor-function.model.d.ts +14 -0
  332. package/models/monitor-function.model.js +4 -0
  333. package/models/monitor-function.model.js.map +1 -0
  334. package/models/monitor-memory.model.d.ts +15 -0
  335. package/models/monitor-memory.model.js +4 -0
  336. package/models/monitor-memory.model.js.map +1 -0
  337. package/models/monitor-mongo.model.d.ts +13 -0
  338. package/models/monitor-mongo.model.js +4 -0
  339. package/models/monitor-mongo.model.js.map +1 -0
  340. package/{src/models/notification.model.ts → models/notification.model.d.ts} +4 -6
  341. package/models/notification.model.js +4 -0
  342. package/models/notification.model.js.map +1 -0
  343. package/models/openai-usage-ledger.model.d.ts +30 -0
  344. package/models/openai-usage-ledger.model.js +4 -0
  345. package/models/openai-usage-ledger.model.js.map +1 -0
  346. package/models/pagination.model.d.ts +11 -0
  347. package/models/pagination.model.js +28 -0
  348. package/models/pagination.model.js.map +1 -0
  349. package/models/permission.model.d.ts +12 -0
  350. package/models/permission.model.js +4 -0
  351. package/models/permission.model.js.map +1 -0
  352. package/models/report-builder-dashboard-builder.model.d.ts +25 -0
  353. package/models/report-builder-dashboard-builder.model.js +4 -0
  354. package/models/report-builder-dashboard-builder.model.js.map +1 -0
  355. package/models/report-builder-library.model.d.ts +17 -0
  356. package/models/report-builder-library.model.js +4 -0
  357. package/models/report-builder-library.model.js.map +1 -0
  358. package/models/report-builder-report.model.d.ts +121 -0
  359. package/models/report-builder-report.model.js +4 -0
  360. package/models/report-builder-report.model.js.map +1 -0
  361. package/models/report-builder.model.d.ts +61 -0
  362. package/models/report-builder.model.js +4 -0
  363. package/models/report-builder.model.js.map +1 -0
  364. package/models/select-data-label.model.d.ts +9 -0
  365. package/models/select-data-label.model.js +4 -0
  366. package/models/select-data-label.model.js.map +1 -0
  367. package/models/server-message.model.d.ts +32 -0
  368. package/models/server-message.model.js +4 -0
  369. package/models/server-message.model.js.map +1 -0
  370. package/models/slow-query-report.model.d.ts +23 -0
  371. package/models/slow-query-report.model.js +4 -0
  372. package/models/slow-query-report.model.js.map +1 -0
  373. package/models/subscription.model.d.ts +31 -0
  374. package/models/subscription.model.js +4 -0
  375. package/models/subscription.model.js.map +1 -0
  376. package/models/support-ticket.model.d.ts +87 -0
  377. package/models/support-ticket.model.js +4 -0
  378. package/models/support-ticket.model.js.map +1 -0
  379. package/models/user-group.model.d.ts +20 -0
  380. package/models/user-group.model.js +4 -0
  381. package/models/user-group.model.js.map +1 -0
  382. package/{src/models/user-guide.model.ts → models/user-guide.model.d.ts} +4 -5
  383. package/models/user-guide.model.js +4 -0
  384. package/models/user-guide.model.js.map +1 -0
  385. package/models/user.model.d.ts +84 -0
  386. package/models/user.model.js +4 -0
  387. package/models/user.model.js.map +1 -0
  388. package/package.json +1 -1
  389. package/private/images/ResolveIO.png +0 -0
  390. package/public_api.js +127 -0
  391. package/public_api.js.map +1 -0
  392. package/publications/ai-terminal.d.ts +1 -0
  393. package/publications/ai-terminal.js +122 -0
  394. package/publications/ai-terminal.js.map +1 -0
  395. package/publications/app-settings.d.ts +2 -0
  396. package/publications/app-settings.js +28 -0
  397. package/publications/app-settings.js.map +1 -0
  398. package/publications/app-status.d.ts +2 -0
  399. package/publications/app-status.js +16 -0
  400. package/publications/app-status.js.map +1 -0
  401. package/publications/cron-jobs.d.ts +2 -0
  402. package/publications/cron-jobs.js +88 -0
  403. package/publications/cron-jobs.js.map +1 -0
  404. package/publications/customer-notifications.d.ts +2 -0
  405. package/publications/customer-notifications.js +161 -0
  406. package/publications/customer-notifications.js.map +1 -0
  407. package/publications/files.d.ts +2 -0
  408. package/publications/files.js +36 -0
  409. package/publications/files.js.map +1 -0
  410. package/publications/flags-update.d.ts +2 -0
  411. package/publications/flags-update.js +22 -0
  412. package/publications/flags-update.js.map +1 -0
  413. package/publications/flags.d.ts +2 -0
  414. package/publications/flags.js +22 -0
  415. package/publications/flags.js.map +1 -0
  416. package/publications/logs.d.ts +2 -0
  417. package/publications/logs.js +164 -0
  418. package/publications/logs.js.map +1 -0
  419. package/publications/notifications.d.ts +2 -0
  420. package/publications/notifications.js +16 -0
  421. package/publications/notifications.js.map +1 -0
  422. package/publications/report-builder-dashboard-builders.d.ts +2 -0
  423. package/publications/report-builder-dashboard-builders.js +42 -0
  424. package/publications/report-builder-dashboard-builders.js.map +1 -0
  425. package/publications/report-builder-libraries.d.ts +2 -0
  426. package/publications/report-builder-libraries.js +90 -0
  427. package/publications/report-builder-libraries.js.map +1 -0
  428. package/publications/report-builder-reports.d.ts +2 -0
  429. package/publications/report-builder-reports.js +50 -0
  430. package/publications/report-builder-reports.js.map +1 -0
  431. package/publications/super-admin.d.ts +2 -0
  432. package/publications/super-admin.js +16 -0
  433. package/publications/super-admin.js.map +1 -0
  434. package/publications/user-groups.d.ts +1 -0
  435. package/publications/user-groups.js +16 -0
  436. package/publications/user-groups.js.map +1 -0
  437. package/publications/user-guides.d.ts +1 -0
  438. package/publications/user-guides.js +16 -0
  439. package/publications/user-guides.js.map +1 -0
  440. package/resolveio-server-app.d.ts +70 -0
  441. package/resolveio-server-app.js +801 -0
  442. package/resolveio-server-app.js.map +1 -0
  443. package/server-app.d.ts +228 -0
  444. package/server-app.js +3566 -0
  445. package/server-app.js.map +1 -0
  446. package/services/codex-client.d.ts +128 -0
  447. package/services/codex-client.js +1629 -0
  448. package/services/codex-client.js.map +1 -0
  449. package/services/openai-client.d.ts +46 -0
  450. package/services/openai-client.js +318 -0
  451. package/services/openai-client.js.map +1 -0
  452. package/types/error-report.d.ts +25 -0
  453. package/types/error-report.js +4 -0
  454. package/types/error-report.js.map +1 -0
  455. package/types/slow-query-report.d.ts +27 -0
  456. package/types/slow-query-report.js +6 -0
  457. package/types/slow-query-report.js.map +1 -0
  458. package/util/ai-qa-policy.d.ts +124 -0
  459. package/util/ai-qa-policy.js +736 -0
  460. package/util/ai-qa-policy.js.map +1 -0
  461. package/util/ai-run-evidence-adapters.d.ts +109 -0
  462. package/util/ai-run-evidence-adapters.js +7234 -0
  463. package/util/ai-run-evidence-adapters.js.map +1 -0
  464. package/util/ai-run-evidence-dashboard.d.ts +88 -0
  465. package/util/ai-run-evidence-dashboard.js +343 -0
  466. package/util/ai-run-evidence-dashboard.js.map +1 -0
  467. package/util/ai-run-evidence-eval.d.ts +86 -0
  468. package/util/ai-run-evidence-eval.js +1018 -0
  469. package/util/ai-run-evidence-eval.js.map +1 -0
  470. package/util/ai-run-evidence.d.ts +244 -0
  471. package/util/ai-run-evidence.js +1096 -0
  472. package/util/ai-run-evidence.js.map +1 -0
  473. package/util/ai-runner-artifacts.d.ts +82 -0
  474. package/util/ai-runner-artifacts.js +713 -0
  475. package/util/ai-runner-artifacts.js.map +1 -0
  476. package/util/ai-runner-manager-autopilot.d.ts +210 -0
  477. package/util/ai-runner-manager-autopilot.js +642 -0
  478. package/util/ai-runner-manager-autopilot.js.map +1 -0
  479. package/util/ai-runner-manager-policy.d.ts +807 -0
  480. package/util/ai-runner-manager-policy.js +3501 -0
  481. package/util/ai-runner-manager-policy.js.map +1 -0
  482. package/util/ai-runner-qa-auth.d.ts +5 -0
  483. package/util/ai-runner-qa-auth.js +839 -0
  484. package/util/ai-runner-qa-auth.js.map +1 -0
  485. package/util/ai-runner-qa-tools.d.ts +26 -0
  486. package/util/ai-runner-qa-tools.js +3520 -0
  487. package/util/ai-runner-qa-tools.js.map +1 -0
  488. package/util/aicoder-runner-v6.d.ts +426 -0
  489. package/util/aicoder-runner-v6.js +2464 -0
  490. package/util/aicoder-runner-v6.js.map +1 -0
  491. package/util/common.d.ts +31 -0
  492. package/util/common.js +683 -0
  493. package/util/common.js.map +1 -0
  494. package/util/customer-portal-password.d.ts +13 -0
  495. package/util/customer-portal-password.js +209 -0
  496. package/util/customer-portal-password.js.map +1 -0
  497. package/util/error-reporter.d.ts +52 -0
  498. package/util/error-reporter.js +326 -0
  499. package/util/error-reporter.js.map +1 -0
  500. package/util/error-tracking.d.ts +13 -0
  501. package/util/error-tracking.js +120 -0
  502. package/util/error-tracking.js.map +1 -0
  503. package/util/openai-usage-cost.d.ts +6 -0
  504. package/util/openai-usage-cost.js +103 -0
  505. package/util/openai-usage-cost.js.map +1 -0
  506. package/util/report-builder-unwinds.d.ts +15 -0
  507. package/util/report-builder-unwinds.js +156 -0
  508. package/util/report-builder-unwinds.js.map +1 -0
  509. package/util/runner-process-janitor.d.ts +27 -0
  510. package/util/runner-process-janitor.js +208 -0
  511. package/util/runner-process-janitor.js.map +1 -0
  512. package/util/schema-report-builder.d.ts +6 -0
  513. package/util/schema-report-builder.js +481 -0
  514. package/util/schema-report-builder.js.map +1 -0
  515. package/util/slow-query-reporter.d.ts +28 -0
  516. package/util/slow-query-reporter.js +226 -0
  517. package/util/slow-query-reporter.js.map +1 -0
  518. package/util/subscription-dependency-context.d.ts +34 -0
  519. package/util/subscription-dependency-context.js +1283 -0
  520. package/util/subscription-dependency-context.js.map +1 -0
  521. package/util/support-runner-v5.d.ts +1426 -0
  522. package/util/support-runner-v5.js +7643 -0
  523. package/util/support-runner-v5.js.map +1 -0
  524. package/util/tokenizer.d.ts +5 -0
  525. package/util/tokenizer.js +41 -0
  526. package/util/tokenizer.js.map +1 -0
  527. package/workers/codex-runner.worker.d.ts +1 -0
  528. package/workers/codex-runner.worker.js +192 -0
  529. package/workers/codex-runner.worker.js.map +1 -0
  530. package/.nodemon.json +0 -5
  531. package/.vscode/settings.json +0 -21
  532. package/AGENTS.md +0 -195
  533. package/README.md +0 -22
  534. package/build_package.sh +0 -5
  535. package/compileDTS.pl +0 -64
  536. package/docs/ai-assistant-nightly-eval.md +0 -65
  537. package/docs/ai-assistant-preflight-checklist.md +0 -23
  538. package/docs/ai-assistant-report-builder-bridge-playbook.md +0 -115
  539. package/eslint-plugin-custom/index.js +0 -7
  540. package/eslint-plugin-custom/rules/no-filter-zero-index.js +0 -44
  541. package/eslint.config.js +0 -103
  542. package/gulpfile.js +0 -216
  543. package/methodAndPublicationListGenerator.py +0 -375
  544. package/mongodbensurers.js +0 -2
  545. package/mongostop.js +0 -3
  546. package/scripts/cleanup-bypassed-callmethod-logs.js +0 -616
  547. package/settings.development.json +0 -25
  548. package/settings.development.redacted.json +0 -25
  549. package/src/.env +0 -12
  550. package/src/ai/assistant-core-heuristics.ts +0 -379
  551. package/src/ai/resolveio-platform-intelligence-memory-corpus.ts +0 -185
  552. package/src/ai/resolveio-platform-intelligence-memory.ts +0 -325
  553. package/src/ai/resolveio-platform-intelligence.ts +0 -462
  554. package/src/client-server-app.ts +0 -12
  555. package/src/collections/ai-run.collection.ts +0 -117
  556. package/src/collections/ai-terminal-conversation.collection.ts +0 -91
  557. package/src/collections/ai-terminal-issue-report.collection.ts +0 -99
  558. package/src/collections/ai-terminal-message.collection.ts +0 -77
  559. package/src/collections/app-setting.collection.ts +0 -104
  560. package/src/collections/app-status.collection.ts +0 -58
  561. package/src/collections/communication-metric.collection.ts +0 -84
  562. package/src/collections/counter.collection.ts +0 -56
  563. package/src/collections/cron-job-history.collection.ts +0 -94
  564. package/src/collections/cron-job.collection.ts +0 -92
  565. package/src/collections/customer-notification.collection.ts +0 -131
  566. package/src/collections/customer-portal-password.collection.ts +0 -76
  567. package/src/collections/email-history.collection.ts +0 -134
  568. package/src/collections/email-verified.collection.ts +0 -62
  569. package/src/collections/file.collection.ts +0 -74
  570. package/src/collections/flag-update.collection.ts +0 -57
  571. package/src/collections/flag.collection.ts +0 -57
  572. package/src/collections/log-method-latency.collection.ts +0 -77
  573. package/src/collections/log-subscription.collection.ts +0 -80
  574. package/src/collections/log.collection.ts +0 -93
  575. package/src/collections/logged-in-users.collection.ts +0 -67
  576. package/src/collections/monitor-cpu.collection.ts +0 -65
  577. package/src/collections/monitor-function.collection.ts +0 -74
  578. package/src/collections/monitor-memory.collection.ts +0 -77
  579. package/src/collections/monitor-mongo.collection.ts +0 -71
  580. package/src/collections/notification.collection.ts +0 -57
  581. package/src/collections/openai-usage-ledger.collection.ts +0 -131
  582. package/src/collections/report-builder-dashboard-builder.collection.ts +0 -109
  583. package/src/collections/report-builder-library.collection.ts +0 -89
  584. package/src/collections/report-builder-report.collection.ts +0 -184
  585. package/src/collections/user-group.collection.ts +0 -89
  586. package/src/collections/user-guide.collection.ts +0 -57
  587. package/src/collections/user.collection.ts +0 -181
  588. package/src/cron/cron.ts +0 -117
  589. package/src/fixtures/cron-jobs.ts +0 -95
  590. package/src/fixtures/init.ts +0 -35
  591. package/src/http/auth.ts +0 -818
  592. package/src/http/health.ts +0 -7
  593. package/src/http/home.ts +0 -90
  594. package/src/http/slow-query-publication.ts +0 -49
  595. package/src/index.ts +0 -1
  596. package/src/managers/ai-assistant-codex-manager.manager.ts +0 -1131
  597. package/src/managers/ai-run-evidence.manager.ts +0 -264
  598. package/src/managers/communication-metric.manager.ts +0 -82
  599. package/src/managers/cron.manager.ts +0 -333
  600. package/src/managers/customer-notification-content.manager.ts +0 -236
  601. package/src/managers/diagnostic-manager-bootstrap.ts +0 -165
  602. package/src/managers/error-auto-fix.manager.ts +0 -2767
  603. package/src/managers/local-log.manager.ts +0 -113
  604. package/src/managers/method.manager.ts +0 -1857
  605. package/src/managers/mongo.manager.ts +0 -4575
  606. package/src/managers/monitor.manager.ts +0 -507
  607. package/src/managers/openai-usage-ledger.manager.ts +0 -112
  608. package/src/managers/slow-query-verifier.manager.ts +0 -3590
  609. package/src/managers/slow-query.manager.ts +0 -519
  610. package/src/managers/subscription.manager.ts +0 -3128
  611. package/src/managers/websocket.manager.ts +0 -746
  612. package/src/managers/worker-dispatcher.manager.ts +0 -1360
  613. package/src/managers/worker-server.manager.ts +0 -536
  614. package/src/methods/accounts.ts +0 -532
  615. package/src/methods/ai-terminal.ts +0 -29070
  616. package/src/methods/app-settings.ts +0 -114
  617. package/src/methods/aws.ts +0 -649
  618. package/src/methods/collections.ts +0 -641
  619. package/src/methods/counters.ts +0 -69
  620. package/src/methods/cron-jobs.ts +0 -2614
  621. package/src/methods/customer-notifications.ts +0 -458
  622. package/src/methods/diagnostics.ts +0 -616
  623. package/src/methods/flag-updates.ts +0 -7
  624. package/src/methods/flags.ts +0 -7
  625. package/src/methods/logs.ts +0 -657
  626. package/src/methods/mongo-explorer.ts +0 -1880
  627. package/src/methods/monitor.ts +0 -540
  628. package/src/methods/pdf.ts +0 -1236
  629. package/src/methods/publications.ts +0 -129
  630. package/src/methods/report-builder.ts +0 -3300
  631. package/src/methods/support.ts +0 -335
  632. package/src/models/ai-run.model.ts +0 -27
  633. package/src/models/ai-terminal-conversation.model.ts +0 -19
  634. package/src/models/ai-terminal-issue-report.model.ts +0 -21
  635. package/src/models/ai-terminal-message.model.ts +0 -24
  636. package/src/models/app-setting.model.ts +0 -17
  637. package/src/models/collection-document.model.ts +0 -24
  638. package/src/models/communication-metric.model.ts +0 -23
  639. package/src/models/cron-job-history.model.ts +0 -16
  640. package/src/models/cron-job.model.ts +0 -15
  641. package/src/models/customer-notification.model.ts +0 -28
  642. package/src/models/customer-portal-password.model.ts +0 -12
  643. package/src/models/dialog.model.ts +0 -25
  644. package/src/models/log-method-latency.model.ts +0 -11
  645. package/src/models/log.model.ts +0 -19
  646. package/src/models/method.model.ts +0 -25
  647. package/src/models/monitor-function.model.ts +0 -16
  648. package/src/models/monitor-memory.model.ts +0 -17
  649. package/src/models/monitor-mongo.model.ts +0 -15
  650. package/src/models/openai-usage-ledger.model.ts +0 -56
  651. package/src/models/pagination.model.ts +0 -35
  652. package/src/models/permission.model.ts +0 -14
  653. package/src/models/report-builder-dashboard-builder.model.ts +0 -29
  654. package/src/models/report-builder-library.model.ts +0 -20
  655. package/src/models/report-builder-report.model.ts +0 -136
  656. package/src/models/report-builder.model.ts +0 -68
  657. package/src/models/select-data-label.model.ts +0 -9
  658. package/src/models/server-message.model.ts +0 -31
  659. package/src/models/slow-query-report.model.ts +0 -23
  660. package/src/models/subscription.model.ts +0 -73
  661. package/src/models/support-ticket.model.ts +0 -104
  662. package/src/models/user-group.model.ts +0 -24
  663. package/src/models/user.model.ts +0 -96
  664. package/src/private/images/ResolveIO.png +0 -0
  665. package/src/publications/ai-terminal.ts +0 -73
  666. package/src/publications/app-settings.ts +0 -25
  667. package/src/publications/app-status.ts +0 -13
  668. package/src/publications/cron-jobs.ts +0 -40
  669. package/src/publications/customer-notifications.ts +0 -101
  670. package/src/publications/files.ts +0 -33
  671. package/src/publications/flags-update.ts +0 -19
  672. package/src/publications/flags.ts +0 -19
  673. package/src/publications/logs.ts +0 -163
  674. package/src/publications/notifications.ts +0 -13
  675. package/src/publications/report-builder-dashboard-builders.ts +0 -39
  676. package/src/publications/report-builder-libraries.ts +0 -41
  677. package/src/publications/report-builder-reports.ts +0 -47
  678. package/src/publications/super-admin.ts +0 -13
  679. package/src/publications/user-groups.ts +0 -12
  680. package/src/publications/user-guides.ts +0 -12
  681. package/src/resolveio-server-app.ts +0 -617
  682. package/src/server-app.ts +0 -3354
  683. package/src/services/codex-client.ts +0 -1231
  684. package/src/services/openai-client.ts +0 -265
  685. package/src/types/error-report.ts +0 -26
  686. package/src/types/js-tiktoken.d.ts +0 -11
  687. package/src/types/slow-query-report.ts +0 -28
  688. package/src/util/ai-qa-policy.ts +0 -925
  689. package/src/util/ai-run-evidence-adapters.ts +0 -8347
  690. package/src/util/ai-run-evidence-dashboard.ts +0 -323
  691. package/src/util/ai-run-evidence-eval.ts +0 -1057
  692. package/src/util/ai-run-evidence.ts +0 -1430
  693. package/src/util/ai-runner-artifacts.ts +0 -586
  694. package/src/util/ai-runner-manager-autopilot.ts +0 -961
  695. package/src/util/ai-runner-manager-policy.ts +0 -5011
  696. package/src/util/ai-runner-qa-auth.ts +0 -838
  697. package/src/util/ai-runner-qa-tools.ts +0 -3536
  698. package/src/util/aicoder-runner-v6.ts +0 -3121
  699. package/src/util/common.ts +0 -649
  700. package/src/util/customer-portal-password.ts +0 -183
  701. package/src/util/error-reporter.ts +0 -332
  702. package/src/util/error-tracking.ts +0 -79
  703. package/src/util/openai-usage-cost.ts +0 -114
  704. package/src/util/report-builder-unwinds.ts +0 -180
  705. package/src/util/runner-process-janitor.ts +0 -219
  706. package/src/util/schema-report-builder.ts +0 -448
  707. package/src/util/slow-query-reporter.ts +0 -216
  708. package/src/util/subscription-dependency-context.ts +0 -1096
  709. package/src/util/support-runner-v5.ts +0 -10040
  710. package/src/util/tokenizer.ts +0 -38
  711. package/src/workers/codex-runner.worker.ts +0 -142
  712. package/start_server.sh +0 -5
  713. package/tests/ai-assistant-corpus-build.ts +0 -484
  714. package/tests/ai-assistant-corpus-replay-e2e.ts +0 -774
  715. package/tests/ai-assistant-data-parity-e2e.ts +0 -1989
  716. package/tests/ai-assistant-eval-triage.ts +0 -831
  717. package/tests/ai-assistant-openai-e2e.ts +0 -1061
  718. package/tests/ai-assistant-openai-git-e2e.ts +0 -155
  719. package/tests/ai-assistant-preflight-matrix.ts +0 -215
  720. package/tests/ai-assistant-routing-eval.test.ts +0 -585
  721. package/tests/ai-assistant-snf-live-eval.ts +0 -975
  722. package/tests/ai-assistant-utils.test.ts +0 -4834
  723. package/tests/ai-manager-autopilot-snapshot.test.ts +0 -193
  724. package/tests/ai-manager-recovery-checkpoint.test.ts +0 -1383
  725. package/tests/ai-run-eval.test.ts +0 -132
  726. package/tests/ai-run-evidence.test.ts +0 -3773
  727. package/tests/ai-runner-contract.test.ts +0 -515
  728. package/tests/aicoder-runner-v6.test.ts +0 -822
  729. package/tests/error-reporter.test.ts +0 -145
  730. package/tests/method-publication-generator.test.ts +0 -46
  731. package/tests/report-builder-linking.test.ts +0 -79
  732. package/tests/resolveio-platform-intelligence.test.ts +0 -352
  733. package/tests/server-app-cron-owner.test.ts +0 -127
  734. package/tests/subscription-connect-race.test.ts +0 -158
  735. package/tests/subscription-dependency-context.test.ts +0 -324
  736. package/tests/subscription-manager-collection-tracking.test.ts +0 -86
  737. package/tests/subscription-manager-invalidation.test.ts +0 -86
  738. package/tests/support-runner-v5.test.ts +0 -3201
  739. package/tsconfig.json +0 -34
  740. /package/{src/private → private}/email-templates/enrollment.html +0 -0
  741. /package/{src/private → private}/email-templates/forgot-password.html +0 -0
  742. /package/{src/private → private}/email-templates/support-ticket-deleted.html +0 -0
  743. /package/{src/private → private}/email-templates/support-ticket-modified.html +0 -0
  744. /package/{src/private → private}/email-templates/support-ticket.html +0 -0
  745. /package/{src/public_api.ts → public_api.d.ts} +0 -0
@@ -1,2767 +0,0 @@
1
- import { ResolveIOServer } from '../resolveio-server-app';
2
- import { objectIdHexString, pad } from '../util/common';
3
- import axios, { AxiosRequestConfig } from 'axios';
4
- import { createHash } from 'crypto';
5
- import { URL } from 'url';
6
- import { Users } from '../collections/user.collection';
7
- import { AppSettings } from '../collections/app-setting.collection';
8
- import { buildGeneratedAppAutoFixSummary, buildResolveIOProjectAutoFixDetails } from './customer-notification-content.manager';
9
- import { ErrorReportAttachment, ErrorReportPayload } from '../types/error-report';
10
-
11
- type AICoderAppModel = Record<string, any>;
12
- type AIDashboardJob = Record<string, any>;
13
- type ClientModel = Record<string, any>;
14
- type ErrorAutoFixLogModel = Record<string, any>;
15
-
16
- export interface ErrorAutoFixManagerDependencies {
17
- Clients?: any;
18
- ErrorAutoFixLogs: any;
19
- AICoderApps?: any;
20
- AIDashboardJobs?: any;
21
- }
22
-
23
- const OPTIONAL_COLLECTION = {
24
- findOne: () => Promise.resolve(null),
25
- findById: () => Promise.resolve(null),
26
- find: () => Promise.resolve([])
27
- };
28
-
29
- let AICoderApps: any = OPTIONAL_COLLECTION;
30
- let AIDashboardJobs: any = OPTIONAL_COLLECTION;
31
- let Clients: any = OPTIONAL_COLLECTION;
32
- let ErrorAutoFixLogs: any = null;
33
- let configuredErrorAutoFixDependencies: ErrorAutoFixManagerDependencies | null = null;
34
-
35
- function resolveErrorAutoFixManagerDependencies(
36
- overrides?: Partial<ErrorAutoFixManagerDependencies>
37
- ): ErrorAutoFixManagerDependencies {
38
- const resolved: ErrorAutoFixManagerDependencies = {
39
- ...(configuredErrorAutoFixDependencies || {} as ErrorAutoFixManagerDependencies),
40
- ...(overrides || {})
41
- };
42
-
43
- if (!resolved.ErrorAutoFixLogs) {
44
- throw new Error('ErrorAutoFixManager dependencies are not configured.');
45
- }
46
-
47
- return resolved;
48
- }
49
-
50
- function applyErrorAutoFixDependencies(dependencies: ErrorAutoFixManagerDependencies): void {
51
- configuredErrorAutoFixDependencies = dependencies;
52
- Clients = dependencies.Clients || OPTIONAL_COLLECTION;
53
- ErrorAutoFixLogs = dependencies.ErrorAutoFixLogs;
54
- AICoderApps = dependencies.AICoderApps || OPTIONAL_COLLECTION;
55
- AIDashboardJobs = dependencies.AIDashboardJobs || OPTIONAL_COLLECTION;
56
- }
57
-
58
- export function registerErrorAutoFixManagerDependencies(dependencies: ErrorAutoFixManagerDependencies): void {
59
- applyErrorAutoFixDependencies(dependencies);
60
- ensureErrorAutoFixManager();
61
- }
62
-
63
- interface AutoFixConfig {
64
- enabled: boolean;
65
- repoRoot: string;
66
- baseBranch: string;
67
- branchPrefix: string;
68
- githubToken?: string;
69
- githubOwner: string;
70
- githubRepo: string;
71
- commandTimeoutMs: number;
72
- notifyEmails: string[];
73
- debugLogging: boolean;
74
- configSource: string;
75
- openaiEnvironment?: string;
76
- openaiProjectId?: string;
77
- autoOptimizeEnabled: boolean;
78
- ingestKeys: string[];
79
- dashboardWorkflowEnabled: boolean;
80
- dashboardFallbackToGithub: boolean;
81
- dashboardWaitTimeoutMs: number;
82
- dashboardPublishRequired: boolean;
83
- maxAutoRunAttemptsPerIssue: number;
84
- escalationEmails: string[];
85
- }
86
-
87
- interface ErrorEmail {
88
- key: string;
89
- subject: string;
90
- body: string;
91
- from?: string;
92
- messageId?: string;
93
- hash?: string;
94
- rawHash?: string;
95
- issueHash?: string;
96
- logId?: string;
97
- raw: string;
98
- fromAddress?: string;
99
- id_client?: string;
100
- client_name?: string;
101
- source_type?: 'app' | 'infrastructure' | 'noise';
102
- classification_reason?: string;
103
- openai_environment?: string;
104
- sourceApp?: string;
105
- sourceEnvironment?: string;
106
- severity?: string;
107
- reportedBy?: string;
108
- reportMetadata?: Record<string, any>;
109
- reportContext?: Record<string, any>;
110
- attachments?: ErrorReportAttachment[];
111
- reportedAt?: Date;
112
- }
113
-
114
- interface AutoFixResult {
115
- status: 'skipped' | 'failed' | 'success' | 'in_progress';
116
- email: ErrorEmail;
117
- error?: string;
118
- branchName?: string;
119
- prUrl?: string;
120
- log?: ErrorAutoFixLogModel;
121
- reason?: string;
122
- summary?: string;
123
- notes?: string;
124
- }
125
-
126
- interface LogReservation {
127
- proceed: boolean;
128
- log?: ErrorAutoFixLogModel;
129
- reason?: string;
130
- }
131
-
132
- interface EmailClassification {
133
- source: 'app' | 'infrastructure' | 'noise';
134
- skip: boolean;
135
- reason?: string;
136
- notify?: boolean;
137
- markIgnored?: boolean;
138
- }
139
-
140
- interface LibraryIssueGateDecision {
141
- blocked: boolean;
142
- reason?: string;
143
- evidence: string[];
144
- }
145
-
146
- const INFRA_SUBJECT_KEYWORDS = [
147
- 'failed snapshot',
148
- 'replica set',
149
- 'data size used',
150
- 'oplog',
151
- 'lock during backup',
152
- 'backup',
153
- 'no primary',
154
- 'no secondary',
155
- 'preferred primary',
156
- 'exceeding memory',
157
- 'exceeding storage',
158
- 'unhealthy status',
159
- 'disconnected status',
160
- 'replication lag',
161
- 'database storage size',
162
- 'compacting collections',
163
- 'failed connection',
164
- 'heartbeat',
165
- 'high cpu usage',
166
- 'high ram usage'
167
- ];
168
- const MONGO_SOURCE_KEYWORDS = [
169
- 'mongo-explorer',
170
- 'mongo explorer',
171
- 'mongo-manager',
172
- 'mongo manager',
173
- 'mongomanager',
174
- 'mongodb'
175
- ];
176
- const MONGO_TEXT_PATTERNS: RegExp[] = [
177
- /\[mongo\]/i,
178
- /\bmongo(?:db)?\s+(?:server\s+)?error\b/i,
179
- /\bmongoservererror\b/i,
180
- /\bmongonetwork(?:timeout)?error\b/i,
181
- /\bmongonetworktimeouterror\b/i
182
- ];
183
- const DEFAULT_ERROR_ALERT_EMAIL = 'dev@resolveio.com';
184
- const MAX_LOCAL_NOTIFICATION_USERS = 5000;
185
- const LIBRARY_MARKER_PATTERNS: Array<{label: string; pattern: RegExp}> = [
186
- {label: 'node_modules stack', pattern: /(?:^|[\/\\])node_modules(?:[\/\\]|$)/i},
187
- {label: '@resolveio/client-lib', pattern: /@resolveio\/client-lib(?:-[a-z0-9-]+)?/i},
188
- {label: '@resolveio/server-lib', pattern: /@resolveio\/server-lib/i},
189
- {label: 'resolveio-client-lib path', pattern: /(?:^|[\/\\])resolveio-client-lib(?:[\/\\]|$)/i},
190
- {label: 'resolveio-server-lib path', pattern: /(?:^|[\/\\])resolveio-server-lib(?:[\/\\]|$)/i},
191
- {label: 'base template path', pattern: /(?:^|[\/\\])aicoder[\/\\]templates[\/\\]base_(?:small|medium|large|tool)(?:[\/\\]|$)/i}
192
- ];
193
- const APP_OWNED_PATH_PATTERN = /(?:^|[\/\\])(angular[\/\\]app|server[\/\\]src)(?:[\/\\]|$)/i;
194
- const FILE_PATH_PATTERN = /(?:webpack:\/\/\/?|\/|\.\/|[A-Za-z]:\\)[^\s'"`]+?\.(?:ts|tsx|js|jsx|mjs|cjs|html|scss|css)/g;
195
-
196
- interface RepoTarget {
197
- owner: string;
198
- repo: string;
199
- }
200
-
201
- interface GithubPullRequest {
202
- number: number;
203
- html_url: string;
204
- }
205
-
206
- interface ErrorReportIngestResult {
207
- status: 'queued' | 'skipped' | 'duplicate' | 'ignored' | 'success' | 'failed' | 'in_progress';
208
- reason?: string;
209
- log?: ErrorAutoFixLogModel;
210
- }
211
-
212
- export interface DevErrorReportOptions {
213
- subject: string;
214
- body?: string;
215
- sourceApp?: string;
216
- environment?: string;
217
- severity?: string;
218
- fingerprint?: string;
219
- idempotencyKey?: string;
220
- metadata?: Record<string, any>;
221
- clientId?: string;
222
- clientName?: string;
223
- clientSlug?: string;
224
- }
225
-
226
- export class ErrorAutoFixManager {
227
- private config: AutoFixConfig;
228
- private _serverConfig = null;
229
- private readonly githubApiBase = 'https://api.github.com';
230
- private readonly dashboardMonitors = new Map<string, Promise<void>>();
231
- private static readonly APP_SETTINGS_CACHE_TTL_MS = 10000;
232
- private appSettingsAutoOptimizeCacheExpiresAt = 0;
233
- private appSettingsAutoOptimizeCacheValue: boolean | null = null;
234
- private ready = false;
235
-
236
- constructor(serverConfig, dependencies?: Partial<ErrorAutoFixManagerDependencies>) {
237
- const resolvedDependencies = resolveErrorAutoFixManagerDependencies(dependencies);
238
- applyErrorAutoFixDependencies(resolvedDependencies);
239
-
240
- this._serverConfig = serverConfig || {};
241
- this.config = this.resolveConfig();
242
-
243
- if (!resolvedDependencies.AICoderApps || !resolvedDependencies.AIDashboardJobs) {
244
- this.config.dashboardWorkflowEnabled = false;
245
- }
246
-
247
- if (!this.config.enabled) {
248
- return;
249
- }
250
-
251
- if (!this.config.dashboardWorkflowEnabled && (!this.config.repoRoot || !this.config.githubOwner || !this.config.githubRepo)) {
252
- console.warn('ErrorAutoFixManager auto-optimize unavailable - missing repository configuration. Ingest and manual runs remain available.');
253
- }
254
-
255
- this.ready = true;
256
-
257
- // console.log('ErrorAutoFixManager initialized (HTTP intake mode).');
258
- // console.log('ErrorAutoFixManager config source:', this.config.configSource);
259
- // if (this.config.debugLogging) {
260
- // console.log('ErrorAutoFixManager debug logging enabled.');
261
- // }
262
- // if (!this.config.autoOptimizeEnabled) {
263
- // console.log('ErrorAutoFixManager auto-run disabled. Manual OpenAI runs required.');
264
- // }
265
- }
266
-
267
- public isReady(): boolean {
268
- return !!(this.ready && this.config?.enabled);
269
- }
270
-
271
- public validateIngestKey(candidate?: string): boolean {
272
- const keys = Array.isArray(this.config?.ingestKeys) ? this.config.ingestKeys.filter(Boolean) : [];
273
-
274
- if (!keys.length) {
275
- return true;
276
- }
277
-
278
- if (!candidate) {
279
- return false;
280
- }
281
-
282
- return keys.includes(candidate.trim());
283
- }
284
-
285
- private debugLog(message: string, details?: any): void {
286
- if (!this.config?.debugLogging) {
287
- return;
288
- }
289
-
290
- return;
291
-
292
- if (typeof details === 'undefined') {
293
- console.log(`[ErrorAutoFixManager][debug] ${message}`);
294
- }
295
- else {
296
- console.log(`[ErrorAutoFixManager][debug] ${message}`, details);
297
- }
298
- }
299
-
300
- private resolveConfig(): AutoFixConfig {
301
- const scAutofix = (this._serverConfig && (this._serverConfig.autofix || this._serverConfig.AUTOFIX)) || {};
302
- let notifyEmails: string[] = [];
303
- let escalationEmails: string[] = [];
304
-
305
- if (process.env.AUTOFIX_NOTIFY_EMAILS) {
306
- notifyEmails = process.env.AUTOFIX_NOTIFY_EMAILS.split(',').map(a => a.trim()).filter(Boolean);
307
- }
308
- else if (Array.isArray(scAutofix.notifyEmails)) {
309
- notifyEmails = scAutofix.notifyEmails.map(a => (a || '').trim()).filter(Boolean);
310
- }
311
- else if (typeof scAutofix.notifyEmails === 'string') {
312
- notifyEmails = scAutofix.notifyEmails.split(',').map(a => a.trim()).filter(Boolean);
313
- }
314
-
315
- if (process.env.AUTOFIX_ESCALATION_EMAILS) {
316
- escalationEmails = process.env.AUTOFIX_ESCALATION_EMAILS.split(',').map(a => a.trim()).filter(Boolean);
317
- }
318
- else if (Array.isArray(scAutofix.escalationEmails)) {
319
- escalationEmails = scAutofix.escalationEmails.map(a => (a || '').trim()).filter(Boolean);
320
- }
321
- else if (typeof scAutofix.escalationEmails === 'string') {
322
- escalationEmails = scAutofix.escalationEmails.split(',').map(a => a.trim()).filter(Boolean);
323
- }
324
-
325
- const getString = (envKey: string, scKey: string, fallback = ''): string => {
326
- return process.env[envKey] || scAutofix[scKey] || fallback;
327
- };
328
-
329
- const getNumber = (envKey: string, scKey: string, fallback: number) => {
330
- const envVal = Number(process.env[envKey]);
331
- if (!Number.isNaN(envVal) && process.env[envKey] !== undefined) {
332
- return envVal;
333
- }
334
- const scVal = Number(scAutofix[scKey]);
335
- if (!Number.isNaN(scVal) && scAutofix[scKey] !== undefined) {
336
- return scVal;
337
- }
338
- return fallback;
339
- };
340
-
341
- const getBoolean = (envKey: string, scKey: string, fallback = false) => {
342
- if (typeof process.env[envKey] !== 'undefined') {
343
- return process.env[envKey] === 'true';
344
- }
345
- if (typeof scAutofix[scKey] !== 'undefined') {
346
- return !!scAutofix[scKey];
347
- }
348
- return fallback;
349
- };
350
-
351
- const parseKeyList = (value: any): string[] => {
352
- if (Array.isArray(value)) {
353
- return value.map(val => `${val || ''}`.trim()).filter(Boolean);
354
- }
355
-
356
- if (typeof value === 'string') {
357
- return value.split(',').map(val => val.trim()).filter(Boolean);
358
- }
359
-
360
- return [];
361
- };
362
-
363
- const normalizePositiveInt = (value: number, fallback: number): number => {
364
- if (!Number.isFinite(value) || value <= 0) {
365
- return fallback;
366
- }
367
- return Math.floor(value);
368
- };
369
-
370
- const openaiProjectId = getString('OPENAI_PROJECT_ID', 'openaiProjectId');
371
- const openaiEnvironment = getString('OPENAI_ENVIRONMENT', 'openaiEnvironment', openaiProjectId);
372
- const ingestSource = typeof process.env.AUTOFIX_INGEST_KEYS !== 'undefined'
373
- ? process.env.AUTOFIX_INGEST_KEYS
374
- : scAutofix.ingestKeys;
375
- const hasAutoOptimizeEnv = typeof process.env.AUTOFIX_AUTO_OPTIMIZE_ENABLED !== 'undefined';
376
- const autoOptimizeEnabled = getBoolean('AUTOFIX_AUTO_OPTIMIZE_ENABLED', 'autoOptimizeEnabled', false);
377
-
378
- return {
379
- enabled: true,
380
- repoRoot: getString('AUTOFIX_REPO_ROOT', 'repoRoot', ''),
381
- baseBranch: getString('AUTOFIX_BASE_BRANCH', 'baseBranch', 'main'),
382
- branchPrefix: getString('AUTOFIX_BRANCH_PREFIX', 'branchPrefix', 'openai/auto'),
383
- githubToken: getString('GITHUB_TOKEN', 'githubToken', getString('AUTOFIX_GITHUB_TOKEN', 'githubToken')),
384
- githubOwner: getString('AUTOFIX_GITHUB_OWNER', 'githubOwner', 'resolveio'),
385
- githubRepo: getString('AUTOFIX_GITHUB_REPO', 'githubRepo', 'resolveio-all'),
386
- commandTimeoutMs: getNumber('AUTOFIX_COMMAND_TIMEOUT_MS', 'commandTimeoutMs', 600000),
387
- notifyEmails,
388
- debugLogging: getBoolean('AUTOFIX_DEBUG_LOGS', 'debugLogging', false),
389
- configSource: hasAutoOptimizeEnv ? 'environment' : (Object.keys(scAutofix).length ? 'serverConfig' : 'defaults'),
390
- openaiEnvironment,
391
- openaiProjectId,
392
- autoOptimizeEnabled: autoOptimizeEnabled,
393
- ingestKeys: parseKeyList(ingestSource),
394
- dashboardWorkflowEnabled: getBoolean('AUTOFIX_DASHBOARD_WORKFLOW_ENABLED', 'dashboardWorkflowEnabled', true),
395
- dashboardFallbackToGithub: getBoolean('AUTOFIX_DASHBOARD_FALLBACK_TO_GITHUB', 'dashboardFallbackToGithub', true),
396
- dashboardWaitTimeoutMs: getNumber('AUTOFIX_DASHBOARD_WAIT_TIMEOUT_MS', 'dashboardWaitTimeoutMs', 45 * 60 * 1000),
397
- dashboardPublishRequired: getBoolean('AUTOFIX_DASHBOARD_PUBLISH_REQUIRED', 'dashboardPublishRequired', true),
398
- maxAutoRunAttemptsPerIssue: normalizePositiveInt(
399
- getNumber('AUTOFIX_MAX_AUTORUN_ATTEMPTS_PER_ISSUE', 'maxAutoRunAttemptsPerIssue', 3),
400
- 3
401
- ),
402
- escalationEmails
403
- };
404
- }
405
-
406
- private extractEmailAddress(value: string): string {
407
- if (!value) {
408
- return '';
409
- }
410
-
411
- let email = value;
412
- const angleMatch = value.match(/<([^>]+)>/);
413
-
414
- if (angleMatch && angleMatch[1]) {
415
- email = angleMatch[1];
416
- }
417
-
418
- email = email.split(';')[0].split(',')[0];
419
- return email.trim().toLowerCase();
420
- }
421
-
422
- private escapeRegex(value: string): string {
423
- return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
424
- }
425
-
426
- private async resolveClientForEnvironment(environment?: string): Promise<ClientModel> {
427
- const host = this.extractHostFromUrl(environment);
428
- if (!host) {
429
- return null;
430
- }
431
-
432
- try {
433
- const escaped = this.escapeRegex(host);
434
- const query = {
435
- website: {
436
- $regex: escaped,
437
- $options: 'i'
438
- }
439
- };
440
-
441
- return await Clients.findOne(query);
442
- }
443
- catch (err) {
444
- console.error('ErrorAutoFixManager resolveClientForEnvironment error:', err);
445
- return null;
446
- }
447
- }
448
-
449
- private extractHostFromUrl(value?: string): string | null {
450
- if (!value) {
451
- return null;
452
- }
453
-
454
- const trimmed = value.trim();
455
- if (!trimmed) {
456
- return null;
457
- }
458
-
459
- try {
460
- const parsed = new URL(trimmed);
461
- return parsed.hostname.toLowerCase();
462
- }
463
- catch {
464
- return trimmed.toLowerCase();
465
- }
466
- }
467
-
468
- private async resolveClientForReport(report: ErrorReportPayload): Promise<ClientModel> {
469
- if (!report) {
470
- return null;
471
- }
472
-
473
- try {
474
- if (report.clientId) {
475
- const byId = await Clients.findById(report.clientId);
476
- if (byId) {
477
- return byId;
478
- }
479
- }
480
-
481
- const tryField = async (field: string, value?: string): Promise<ClientModel> => {
482
- if (!value) {
483
- return null;
484
- }
485
-
486
- const escaped = this.escapeRegex(value);
487
- const query: {[key: string]: any} = {};
488
- query[field] = {$regex: `^${escaped}$`, $options: 'i'};
489
- return await Clients.findOne(query);
490
- };
491
-
492
- return (
493
- (await tryField('name', report.clientName)) ||
494
- (await tryField('demo_name', report.clientSlug)) ||
495
- (await tryField('repo', report.clientRepo)) ||
496
- (await this.resolveClientForEnvironment(report.environment))
497
- );
498
- }
499
- catch (err) {
500
- console.error('ErrorAutoFixManager resolveClientForReport error:', err);
501
- return null;
502
- }
503
- }
504
-
505
- private determineOpenAIEnvironment(client?: ClientModel): string {
506
- const repoCandidate = (client?.repo || '').trim();
507
-
508
- if (repoCandidate) {
509
- return repoCandidate;
510
- }
511
-
512
- const configEnv = (this.config.openaiEnvironment || '').trim();
513
-
514
- if (configEnv) {
515
- return configEnv;
516
- }
517
-
518
- if ((this.config.githubOwner || '').trim() && (this.config.githubRepo || '').trim()) {
519
- return `${this.config.githubOwner}/${this.config.githubRepo}`.trim();
520
- }
521
-
522
- return '';
523
- }
524
-
525
- private resolveEnvironmentForTask(email: ErrorEmail, log: ErrorAutoFixLogModel): string {
526
- if (email && email.openai_environment && email.openai_environment.trim()) {
527
- return email.openai_environment.trim();
528
- }
529
-
530
- if (log && log.openai_environment && log.openai_environment.trim()) {
531
- return log.openai_environment.trim();
532
- }
533
-
534
- return this.determineOpenAIEnvironment();
535
- }
536
-
537
-
538
- private buildEmailFromReport(report: ErrorReportPayload): ErrorEmail {
539
- const timestamp = report.reportedAt instanceof Date && !Number.isNaN(report.reportedAt.getTime())
540
- ? report.reportedAt
541
- : new Date();
542
- const safeMessage = (report.message || '').toString().trim() || 'Unknown error';
543
- const subjectBase = `[AppError] ${report.sourceApp || 'application'}${report.environment ? ` (${report.environment})` : ''}`;
544
- const subject = `${subjectBase} - ${safeMessage.slice(0, 120)}`;
545
- const lines: string[] = [
546
- `Source App:\t${report.sourceApp}`,
547
- `Environment:\t${report.environment || 'n/a'}`,
548
- `Severity:\t${report.severity || 'error'}`,
549
- `Client Hint:\t${report.clientName || report.clientSlug || report.clientRepo || report.clientId || 'n/a'}`,
550
- `Reported By:\t${report.reportedBy || report.clientEmail || 'n/a'}`,
551
- `Reported At:\t${timestamp.toISOString()}`,
552
- `Message:\t${safeMessage}`
553
- ];
554
-
555
- if (report.stack) {
556
- lines.push('', 'Stack Trace:', report.stack);
557
- }
558
-
559
- if (report.context && typeof report.context === 'object' && Object.keys(report.context).length) {
560
- lines.push('', 'Context JSON:', JSON.stringify(report.context, null, 2));
561
- }
562
-
563
- if (report.metadata && typeof report.metadata === 'object' && Object.keys(report.metadata).length) {
564
- lines.push('', 'Metadata JSON:', JSON.stringify(report.metadata, null, 2));
565
- }
566
-
567
- if (Array.isArray(report.attachments) && report.attachments.length) {
568
- lines.push('', 'Attachments:');
569
- report.attachments.forEach((att: ErrorReportAttachment) => {
570
- const desc: string[] = [];
571
- if (att.name) {
572
- desc.push(att.name);
573
- }
574
- if (att.contentType) {
575
- desc.push(att.contentType);
576
- }
577
- if (typeof att.size === 'number') {
578
- desc.push(`${att.size}b`);
579
- }
580
-
581
- const summary = desc.length ? desc.join(' | ') : 'attachment';
582
- lines.push(`- ${summary}${att.url ? ` -> ${att.url}` : ''}`);
583
- });
584
- }
585
-
586
- if (report.fingerprint) {
587
- lines.push('', `Fingerprint:\t${report.fingerprint}`);
588
- }
589
-
590
- if (report.idempotencyKey) {
591
- lines.push(`Idempotency Key:\t${report.idempotencyKey}`);
592
- }
593
-
594
- const body = lines.join('\n');
595
-
596
- return {
597
- key: `report:${timestamp.getTime().toString(36)}:${Math.random().toString(36).slice(2, 10)}`,
598
- subject,
599
- body,
600
- raw: body,
601
- from: report.reportedBy || report.clientEmail || 'errors@resolveio.com',
602
- sourceApp: report.sourceApp,
603
- sourceEnvironment: report.environment,
604
- severity: report.severity,
605
- reportedBy: report.reportedBy,
606
- reportMetadata: report.metadata,
607
- reportContext: report.context,
608
- attachments: Array.isArray(report.attachments) ? report.attachments : [],
609
- openai_environment: report.clientRepo,
610
- reportedAt: timestamp
611
- };
612
- }
613
-
614
- private classifyEmail(email: ErrorEmail): EmailClassification {
615
- const subject = (email.subject || '').toLowerCase();
616
- const body = email.body || '';
617
- const normalizedBody = body.toLowerCase();
618
-
619
- if (
620
- subject.includes('autofix') &&
621
- (normalizedBody.includes('auto-fix workflow') || normalizedBody.includes('autofix workflow'))
622
- ) {
623
- return {source: 'noise', skip: true, reason: 'AutoFix status notification'};
624
- }
625
-
626
- if (this.isMongoOriginError(email)) {
627
- return {
628
- source: 'infrastructure',
629
- skip: true,
630
- reason: 'Mongo-origin error ignored for auto-fix',
631
- markIgnored: true
632
- };
633
- }
634
-
635
- if (subject.includes('[database]') || subject.includes('[server]')) {
636
- return {source: 'infrastructure', skip: true, reason: 'Infrastructure alert (subject tag)'};
637
- }
638
-
639
- const infraKeyword = INFRA_SUBJECT_KEYWORDS.find(keyword => subject.includes(keyword));
640
- if (infraKeyword) {
641
- return {source: 'infrastructure', skip: true, reason: `Infrastructure alert (${infraKeyword})`};
642
- }
643
-
644
- if (!body.trim()) {
645
- return {source: 'noise', skip: true, reason: 'Empty error payload'};
646
- }
647
-
648
- const emptyErrorsRegex = /errors\s*[\r\n]+(\{\s*\}|\[\s*\])/i;
649
- if (emptyErrorsRegex.test(body)) {
650
- return {source: 'noise', skip: true, reason: 'Empty error details'};
651
- }
652
-
653
- if (subject.includes('database is down') || normalizedBody.includes('database is down')) {
654
- return {source: 'infrastructure', skip: true, reason: 'Database outage alert'};
655
- }
656
-
657
- return {source: 'app', skip: false};
658
- }
659
-
660
- private isMongoOriginError(email: ErrorEmail): boolean {
661
- const sourceApp = String(email?.sourceApp || '').toLowerCase();
662
- const sourceEnvironment = String(email?.sourceEnvironment || '').toLowerCase();
663
- const subject = String(email?.subject || '').toLowerCase();
664
- const body = String(email?.body || '');
665
-
666
- const sourceMatches = MONGO_SOURCE_KEYWORDS.some(keyword =>
667
- sourceApp.includes(keyword) || sourceEnvironment.includes(keyword)
668
- );
669
- if (sourceMatches) {
670
- return true;
671
- }
672
-
673
- const text = `${subject}\n${body}`;
674
- return MONGO_TEXT_PATTERNS.some(pattern => pattern.test(text));
675
- }
676
-
677
- private generateRawEmailHash(email: ErrorEmail): string {
678
- return createHash('sha256').update(`${email.subject || ''}\n${email.body || ''}`, 'utf8').digest('hex');
679
- }
680
-
681
- private generateIssueHash(email: ErrorEmail): string {
682
- const subject = this.normalizeTextForHash(email.subject || '');
683
- const body = this.normalizeBodyForHash(email.body || '');
684
- return createHash('sha256').update(`${subject}\n${body}`, 'utf8').digest('hex');
685
- }
686
-
687
- private normalizeTextForHash(value: string): string {
688
- if (!value) {
689
- return '';
690
- }
691
-
692
- const normalized = value
693
- .replace(/\r/g, '\n')
694
- .toLowerCase()
695
- .replace(/0x[0-9a-f]+/gi, '0x#')
696
- .replace(/\b[0-9a-f]{7,64}\b/gi, '#')
697
- .replace(/\b[0-9]{4}[-/][0-9]{2}[-/][0-9]{2}(?:[ t][0-9]{2}:[0-9]{2}:[0-9]{2}(?:\.[0-9]{1,6})?)?\b/g, '#datetime#')
698
- .replace(/\b[0-9]{2}:[0-9]{2}:[0-9]{2}\b/g, '#time#')
699
- .replace(/[0-9]+/g, '#')
700
- .replace(/[^\S\n]+/g, ' ')
701
- .split('\n')
702
- .map(line => line.trim())
703
- .filter(Boolean)
704
- .slice(0, 60)
705
- .join('\n');
706
-
707
- return normalized.length > 4000 ? normalized.slice(0, 4000) : normalized;
708
- }
709
-
710
- private normalizeBodyForHash(body: string): string {
711
- if (!body) {
712
- return '';
713
- }
714
-
715
- const withoutStackNoise = body
716
- .replace(/=+\s*stack trace\s*=+/gi, 'stack trace')
717
- .replace(/-{3,}/g, '-')
718
- .replace(/\[[^\]]*request id[^\]]*\]/gi, '[request id]')
719
- .replace(/guid:[^\s]+/gi, 'guid:#')
720
- .replace(/request id:[^\s]+/gi, 'request id:#')
721
- .replace(/correlation id:[^\s]+/gi, 'correlation id:#');
722
-
723
- return this.normalizeTextForHash(withoutStackNoise);
724
- }
725
-
726
- private parseRepoTarget(env: string): RepoTarget {
727
- const trimmed = (env || '').trim();
728
- if (!trimmed) {
729
- return null;
730
- }
731
-
732
- const [owner, repo] = trimmed.split('/', 2);
733
- if (!owner || !repo) {
734
- return null;
735
- }
736
-
737
- return {
738
- owner: owner.trim(),
739
- repo: repo.trim()
740
- };
741
- }
742
-
743
- private buildWorkBranch(hash: string): string {
744
- const shortHash = (hash || '').toLowerCase().replace(/[^a-z0-9]/g, '').slice(0, 12) || 'autofix';
745
- const prefix = (this.config.branchPrefix || 'openai/auto').trim();
746
- if (!prefix) {
747
- return shortHash;
748
- }
749
-
750
- const segments = prefix.split('/').map(segment => segment.trim()).filter(Boolean);
751
- const sanitized = segments.map(segment => segment.replace(/[^a-zA-Z0-9._-]/g, '-'));
752
- return `${sanitized.join('/')}/${shortHash}`;
753
- }
754
-
755
- private normalizeEmailText(value: string, limit = 20000): string {
756
- if (!value) {
757
- return '';
758
- }
759
-
760
- const cleaned = value.replace(/\r/g, '');
761
- if (cleaned.length <= limit) {
762
- return cleaned;
763
- }
764
-
765
- return `${cleaned.slice(0, limit)}\n... (truncated)`;
766
- }
767
-
768
- private buildContextMarkdown(email: ErrorEmail, identifier: string, normalizedBody: string): string {
769
- const lines: string[] = [
770
- `# OpenAI Error Context: ${identifier}`,
771
- '',
772
- `**Subject**: ${email.subject || '(no subject)'}`,
773
- email.fromAddress ? `**From**: ${email.fromAddress}` : undefined,
774
- email.client_name ? `**Client**: ${email.client_name}` : undefined,
775
- email.source_type ? `**Classification**: ${email.source_type}${email.classification_reason ? ` (${email.classification_reason})` : ''}` : undefined,
776
- email.id_client ? `**Client Id**: ${email.id_client}` : undefined,
777
- '',
778
- '## Body',
779
- '```',
780
- normalizedBody || '(empty body)',
781
- '```',
782
- '',
783
- '_Generated by ErrorAutoFixManager_'
784
- ];
785
-
786
- return lines.filter(line => typeof line !== 'undefined').join('\n');
787
- }
788
-
789
- private buildOpenAIComment(email: ErrorEmail, contextPath: string, normalizedBody: string): string {
790
- const lines: string[] = [
791
- '@openai review',
792
- '',
793
- `**Email Subject**: ${email.subject || '(no subject)'}`,
794
- email.fromAddress ? `**From**: ${email.fromAddress}` : undefined,
795
- email.client_name ? `**Client**: ${email.client_name}` : undefined,
796
- contextPath ? `Context file: \`${contextPath}\`` : undefined,
797
- '',
798
- '```',
799
- normalizedBody || '(empty body)',
800
- '```',
801
- '',
802
- 'Please investigate this error and propose a minimal, safe fix.'
803
- ];
804
-
805
- return lines.filter(line => typeof line !== 'undefined').join('\n');
806
- }
807
-
808
- private formatGithubError(error: any): string {
809
- if (!error) {
810
- return 'GitHub request failed.';
811
- }
812
-
813
- const status = error?.response?.status;
814
- const message = error?.response?.data?.message || error?.message || 'GitHub request failed.';
815
-
816
- if (status) {
817
- return `GitHub API error (${status}): ${message}`;
818
- }
819
-
820
- return `GitHub API error: ${message}`;
821
- }
822
-
823
- private buildGithubAuthHeader(token?: string): string {
824
- const trimmed = (token || '').trim();
825
- if (!trimmed) {
826
- return '';
827
- }
828
-
829
- if (/^(token|Bearer)\s+/i.test(trimmed)) {
830
- return trimmed;
831
- }
832
-
833
- if (trimmed.includes('.') && !trimmed.startsWith('gh')) {
834
- return `Bearer ${trimmed}`;
835
- }
836
-
837
- return `token ${trimmed}`;
838
- }
839
-
840
- private async githubRequest<T>(config: AxiosRequestConfig, allow404 = false): Promise<T> {
841
- const authHeader = this.buildGithubAuthHeader(this.config.githubToken);
842
- const headers = {
843
- ...(authHeader ? {Authorization: authHeader} : {}),
844
- Accept: 'application/vnd.github+json',
845
- 'User-Agent': 'ResolveIO-AutoFix',
846
- 'X-GitHub-Api-Version': '2022-11-28'
847
- };
848
-
849
- const finalConfig: AxiosRequestConfig = {
850
- ...config,
851
- baseURL: this.githubApiBase,
852
- headers: {
853
- ...headers,
854
- ...(config.headers || {})
855
- },
856
- timeout: Math.min(Math.max(this.config.commandTimeoutMs || 600000, 1000), 120000)
857
- };
858
-
859
- try {
860
- const response = await axios.request<T>(finalConfig);
861
- return response.data;
862
- }
863
- catch (err) {
864
- const status = err?.response?.status;
865
- if (allow404 && status === 404) {
866
- return null as unknown as T;
867
- }
868
- throw new Error(this.formatGithubError(err));
869
- }
870
- }
871
-
872
- private async resolveBaseBranch(target: RepoTarget): Promise<string> {
873
- const fallback = (this.config.baseBranch || 'main').trim();
874
- try {
875
- const repo = await this.githubRequest<{default_branch?: string}>(
876
- {method: 'GET', url: `/repos/${target.owner}/${target.repo}`}
877
- );
878
- const defaultBranch = (repo?.default_branch || '').trim();
879
- return defaultBranch || fallback;
880
- }
881
- catch (err) {
882
- this.debugLog('Failed to fetch default branch. Falling back to configured branch.', {
883
- target,
884
- error: err?.message
885
- });
886
- return fallback;
887
- }
888
- }
889
-
890
- private async getBranchSha(target: RepoTarget, branch: string): Promise<string> {
891
- const ref = await this.githubRequest<{object?: {sha?: string}}>(
892
- {method: 'GET', url: `/repos/${target.owner}/${target.repo}/git/ref/heads/${branch}`}
893
- );
894
- const sha = ref?.object?.sha;
895
- if (!sha) {
896
- throw new Error(`Base branch ${branch} not found.`);
897
- }
898
- return sha;
899
- }
900
-
901
- private async ensureBranch(target: RepoTarget, newBranch: string, baseBranch: string, baseSha: string): Promise<void> {
902
- const existing = await this.githubRequest<any>(
903
- {method: 'GET', url: `/repos/${target.owner}/${target.repo}/git/ref/heads/${newBranch}`},
904
- true
905
- );
906
- if (existing) {
907
- return;
908
- }
909
-
910
- await this.githubRequest(
911
- {
912
- method: 'POST',
913
- url: `/repos/${target.owner}/${target.repo}/git/refs`,
914
- data: {
915
- ref: `refs/heads/${newBranch}`,
916
- sha: baseSha
917
- }
918
- }
919
- );
920
- }
921
-
922
- private async upsertContextFile(target: RepoTarget, branch: string, contextPath: string, content: string): Promise<void> {
923
- const encodedPath = encodeURIComponent(contextPath).replace(/%2F/g, '/');
924
- const existing = await this.githubRequest<any>(
925
- {
926
- method: 'GET',
927
- url: `/repos/${target.owner}/${target.repo}/contents/${encodedPath}`,
928
- params: {ref: branch}
929
- },
930
- true
931
- );
932
- const sha = existing && existing.sha ? existing.sha : undefined;
933
- const commitMessage = `chore(openai): update error context ${contextPath}`;
934
-
935
- await this.githubRequest(
936
- {
937
- method: 'PUT',
938
- url: `/repos/${target.owner}/${target.repo}/contents/${encodedPath}`,
939
- data: {
940
- message: commitMessage.slice(0, 200),
941
- content: Buffer.from(content, 'utf8').toString('base64'),
942
- branch,
943
- sha
944
- }
945
- }
946
- );
947
- }
948
-
949
- private async findOpenPullRequest(target: RepoTarget, branch: string, base: string): Promise<GithubPullRequest> {
950
- const prs = await this.githubRequest<GithubPullRequest[]>(
951
- {
952
- method: 'GET',
953
- url: `/repos/${target.owner}/${target.repo}/pulls`,
954
- params: {
955
- state: 'open',
956
- head: `${target.owner}:${branch}`,
957
- base,
958
- per_page: 1
959
- }
960
- }
961
- );
962
- if (prs && prs.length) {
963
- return prs[0];
964
- }
965
- return null;
966
- }
967
-
968
- private async createPullRequest(target: RepoTarget, branch: string, base: string, title: string, body: string): Promise<GithubPullRequest> {
969
- const pr = await this.githubRequest<GithubPullRequest>(
970
- {
971
- method: 'POST',
972
- url: `/repos/${target.owner}/${target.repo}/pulls`,
973
- data: {
974
- title,
975
- head: branch,
976
- base,
977
- body
978
- }
979
- }
980
- );
981
- return pr;
982
- }
983
-
984
- private async commentOnPullRequest(target: RepoTarget, prNumber: number, body: string): Promise<void> {
985
- await this.githubRequest(
986
- {
987
- method: 'POST',
988
- url: `/repos/${target.owner}/${target.repo}/issues/${prNumber}/comments`,
989
- data: {
990
- body
991
- }
992
- }
993
- );
994
- }
995
-
996
- private parseBooleanEnv(envKey: string): boolean | null {
997
- if (typeof process.env[envKey] === 'undefined') {
998
- return null;
999
- }
1000
-
1001
- return process.env[envKey] === 'true';
1002
- }
1003
-
1004
- private async resolveAutoOptimizeEnabled(): Promise<boolean> {
1005
- const now = Date.now();
1006
- if (this.appSettingsAutoOptimizeCacheValue !== null && now < this.appSettingsAutoOptimizeCacheExpiresAt) {
1007
- return this.appSettingsAutoOptimizeCacheValue;
1008
- }
1009
-
1010
- const envValue = this.parseBooleanEnv('AUTOFIX_AUTO_OPTIMIZE_ENABLED');
1011
- let enabled = envValue !== null ? envValue : !!this.config.autoOptimizeEnabled;
1012
- try {
1013
- if (AppSettings && typeof AppSettings.findOne === 'function') {
1014
- const activeSetting = await AppSettings.findOne({
1015
- is_active: {
1016
- $ne: false
1017
- }
1018
- }, {
1019
- sort: {
1020
- updatedAt: -1,
1021
- createdAt: -1
1022
- }
1023
- }) || await AppSettings.findOne({}, {
1024
- sort: {
1025
- updatedAt: -1,
1026
- createdAt: -1
1027
- }
1028
- });
1029
-
1030
- if (activeSetting && typeof activeSetting.enable_auto_fix === 'boolean') {
1031
- enabled = !!activeSetting.enable_auto_fix;
1032
- }
1033
- }
1034
- }
1035
- catch (error) {
1036
- if (this.config?.debugLogging) {
1037
- console.warn('ErrorAutoFixManager failed to read app settings auto-fix toggle', error);
1038
- }
1039
- }
1040
-
1041
- this.appSettingsAutoOptimizeCacheValue = enabled;
1042
- this.appSettingsAutoOptimizeCacheExpiresAt = now + ErrorAutoFixManager.APP_SETTINGS_CACHE_TTL_MS;
1043
- return enabled;
1044
- }
1045
-
1046
- private async reserveLog(email: ErrorEmail, client?: ClientModel, autoOptimizeEnabled = false): Promise<LogReservation> {
1047
- const hash = email.hash;
1048
- const rawHash = email.rawHash || hash;
1049
- const now = email.reportedAt || new Date();
1050
-
1051
- let existing: ErrorAutoFixLogModel = null;
1052
-
1053
- if (hash) {
1054
- existing = await ErrorAutoFixLogs.findOne({issue_hash: hash});
1055
- }
1056
-
1057
- if (!existing && rawHash) {
1058
- existing = await ErrorAutoFixLogs.findOne({email_hash: rawHash});
1059
- }
1060
-
1061
- if (!existing && hash && hash !== rawHash) {
1062
- existing = await ErrorAutoFixLogs.findOne({email_hash: hash});
1063
- }
1064
-
1065
- if (existing) {
1066
- await this.markDuplicate(existing._id, now);
1067
- const updatedExisting = await ErrorAutoFixLogs.findOne({_id: existing._id}) || existing;
1068
-
1069
- const metaUpdate: Partial<ErrorAutoFixLogModel> = {};
1070
-
1071
- if (hash && (!updatedExisting.issue_hash || updatedExisting.issue_hash !== hash)) {
1072
- metaUpdate.issue_hash = hash;
1073
- }
1074
-
1075
- if (rawHash && (!updatedExisting.email_hash || updatedExisting.email_hash !== rawHash)) {
1076
- metaUpdate.email_hash = rawHash;
1077
- }
1078
-
1079
- if (email.fromAddress && email.fromAddress !== updatedExisting.from_email) {
1080
- metaUpdate.from_email = email.fromAddress;
1081
- }
1082
-
1083
- if (client) {
1084
- if (!updatedExisting.id_client || updatedExisting.id_client !== client._id) {
1085
- metaUpdate.id_client = client._id;
1086
- }
1087
-
1088
- if (!updatedExisting.client_name || updatedExisting.client_name !== client.name) {
1089
- metaUpdate.client_name = client.name;
1090
- }
1091
- }
1092
-
1093
- if (email.openai_environment && email.openai_environment !== updatedExisting.openai_environment) {
1094
- metaUpdate.openai_environment = email.openai_environment;
1095
- }
1096
-
1097
- if (email.sourceApp && email.sourceApp !== updatedExisting.source_app) {
1098
- metaUpdate.source_app = email.sourceApp;
1099
- }
1100
-
1101
- if (email.sourceEnvironment && email.sourceEnvironment !== updatedExisting.source_environment) {
1102
- metaUpdate.source_environment = email.sourceEnvironment;
1103
- }
1104
-
1105
- if (email.severity && email.severity !== updatedExisting.severity) {
1106
- metaUpdate.severity = email.severity;
1107
- }
1108
-
1109
- if (email.reportedBy && email.reportedBy !== updatedExisting.reported_by) {
1110
- metaUpdate.reported_by = email.reportedBy;
1111
- }
1112
-
1113
- if (typeof email.reportMetadata !== 'undefined') {
1114
- metaUpdate.report_metadata = email.reportMetadata;
1115
- }
1116
-
1117
- if (typeof email.reportContext !== 'undefined') {
1118
- metaUpdate.report_context = email.reportContext;
1119
- }
1120
-
1121
- if (typeof email.attachments !== 'undefined') {
1122
- metaUpdate.attachments = email.attachments;
1123
- }
1124
-
1125
- metaUpdate.last_reported_at = now;
1126
-
1127
- if (Object.keys(metaUpdate).length) {
1128
- await this.updateLog(updatedExisting._id, metaUpdate);
1129
- }
1130
-
1131
- if (updatedExisting.status === 'completed') {
1132
- const reactivated = (await ErrorAutoFixLogs.findOneAndUpdate({_id: updatedExisting._id}, {
1133
- $set: {
1134
- status: 'pending',
1135
- ignored: false,
1136
- last_error: '',
1137
- openai_task_id: '',
1138
- branch_name: '',
1139
- pr_url: ''
1140
- }
1141
- }, {
1142
- returnDocument: 'after'
1143
- })) || updatedExisting;
1144
-
1145
- return {
1146
- proceed: true,
1147
- log: reactivated
1148
- };
1149
- }
1150
-
1151
- if (updatedExisting.ignored) {
1152
- return {
1153
- proceed: false,
1154
- log: updatedExisting,
1155
- reason: 'ignored'
1156
- };
1157
- }
1158
-
1159
- if (autoOptimizeEnabled && (updatedExisting.status === 'failed' || updatedExisting.status === 'skipped') && !updatedExisting.ignored) {
1160
- const attemptsUsed = Number.isFinite(Number(updatedExisting.attempt_count))
1161
- ? Number(updatedExisting.attempt_count)
1162
- : 0;
1163
- const maxAttempts = Number.isFinite(Number(this.config.maxAutoRunAttemptsPerIssue))
1164
- ? Number(this.config.maxAutoRunAttemptsPerIssue)
1165
- : 0;
1166
- if (maxAttempts > 0 && attemptsUsed >= maxAttempts) {
1167
- const reason = `Auto-fix attempt budget reached (${attemptsUsed}/${maxAttempts}).`;
1168
- const exhausted = (await ErrorAutoFixLogs.findOneAndUpdate({_id: updatedExisting._id}, {
1169
- $set: {
1170
- status: 'skipped',
1171
- ignored: true,
1172
- last_error: `${reason} Marked ignored pending manual intervention.`,
1173
- last_result_at: now,
1174
- updatedAt: now
1175
- }
1176
- }, {
1177
- returnDocument: 'after'
1178
- })) || updatedExisting;
1179
-
1180
- await this.sendEscalationNotice(exhausted, reason);
1181
- return {
1182
- proceed: false,
1183
- log: exhausted,
1184
- reason: 'budget_exhausted'
1185
- };
1186
- }
1187
-
1188
- const resumed = await ErrorAutoFixLogs.findOneAndUpdate({_id: updatedExisting._id}, {
1189
- $inc: {
1190
- attempt_count: 1
1191
- },
1192
- $set: {
1193
- status: 'in_progress',
1194
- last_attempt_at: now,
1195
- openai_task_id: '',
1196
- branch_name: '',
1197
- pr_url: '',
1198
- last_error: ''
1199
- }
1200
- }, {
1201
- returnDocument: 'after'
1202
- });
1203
-
1204
- return {
1205
- proceed: true,
1206
- log: resumed || updatedExisting
1207
- };
1208
- }
1209
-
1210
- if (updatedExisting.status === 'in_progress') {
1211
- return {
1212
- proceed: false,
1213
- log: updatedExisting,
1214
- reason: 'in_progress'
1215
- };
1216
- }
1217
-
1218
- if (updatedExisting.status === 'success') {
1219
- return {
1220
- proceed: false,
1221
- log: updatedExisting,
1222
- reason: 'success'
1223
- };
1224
- }
1225
-
1226
- return {
1227
- proceed: false,
1228
- log: updatedExisting,
1229
- reason: 'duplicate'
1230
- };
1231
- }
1232
-
1233
- const counterValue = await ResolveIOServer.getMainServer().getMethodManager().callMethod('incCounter', 'autofix_error');
1234
- const counterString = pad(counterValue, 6);
1235
-
1236
- const doc: ErrorAutoFixLogModel = {
1237
- _id: objectIdHexString(),
1238
- email_hash: rawHash,
1239
- issue_hash: hash,
1240
- subject: email.subject,
1241
- message_id: email.messageId,
1242
- body: email.body,
1243
- status: autoOptimizeEnabled ? 'in_progress' : 'pending',
1244
- ignored: false,
1245
- attempt_count: autoOptimizeEnabled ? 1 : 0,
1246
- duplicate_count: 0,
1247
- autofix_error_count: counterValue,
1248
- autofix_error_count_string: counterString,
1249
- first_seen_at: now,
1250
- last_attempt_at: autoOptimizeEnabled ? now : undefined,
1251
- from_email: email.fromAddress || '',
1252
- id_client: client?._id,
1253
- client_name: client?.name,
1254
- openai_environment: email.openai_environment || this.determineOpenAIEnvironment(client),
1255
- source_app: email.sourceApp,
1256
- source_environment: email.sourceEnvironment,
1257
- severity: email.severity,
1258
- reported_by: email.reportedBy || email.fromAddress || '',
1259
- last_reported_at: now,
1260
- report_metadata: email.reportMetadata,
1261
- report_context: email.reportContext,
1262
- attachments: email.attachments
1263
- };
1264
-
1265
- await ErrorAutoFixLogs.insertOne(doc as any);
1266
-
1267
- return {
1268
- proceed: true,
1269
- log: doc
1270
- };
1271
- }
1272
-
1273
- private async markDuplicate(logId: string, timestamp: Date): Promise<void> {
1274
- await ErrorAutoFixLogs.updateOne({_id: logId}, {
1275
- $inc: {
1276
- duplicate_count: 1
1277
- },
1278
- $set: {
1279
- last_duplicate_at: timestamp,
1280
- last_reported_at: timestamp,
1281
- updatedAt: timestamp
1282
- }
1283
- });
1284
- }
1285
-
1286
- private async updateLog(logId: string, set: Partial<ErrorAutoFixLogModel>, inc?: {[key: string]: number}): Promise<ErrorAutoFixLogModel> {
1287
- const cleanedSet: {[key: string]: any} = {};
1288
- const rawSet: {[key: string]: any} = set ? {...set} : {};
1289
-
1290
- Object.keys(rawSet).forEach(key => {
1291
- if (typeof rawSet[key] !== 'undefined') {
1292
- cleanedSet[key] = rawSet[key];
1293
- }
1294
- });
1295
-
1296
- cleanedSet.updatedAt = new Date();
1297
-
1298
- const update: any = {
1299
- $set: cleanedSet
1300
- };
1301
-
1302
- if (inc) {
1303
- update.$inc = inc;
1304
- }
1305
-
1306
- const result = await ErrorAutoFixLogs.findOneAndUpdate({_id: logId}, update, {
1307
- returnDocument: 'after'
1308
- });
1309
-
1310
- return result;
1311
- }
1312
-
1313
- private getEscalationRecipients(): string[] {
1314
- const unique = new Set<string>();
1315
- const add = (value: string) => {
1316
- const normalized = String(value || '').trim().toLowerCase();
1317
- if (!normalized) {
1318
- return;
1319
- }
1320
- unique.add(normalized);
1321
- };
1322
-
1323
- (this.config.escalationEmails || []).forEach(add);
1324
- (this.config.notifyEmails || []).forEach(add);
1325
- if (!unique.size) {
1326
- add(DEFAULT_ERROR_ALERT_EMAIL);
1327
- }
1328
- return Array.from(unique);
1329
- }
1330
-
1331
- private async sendEscalationNotice(log: ErrorAutoFixLogModel, reason: string): Promise<void> {
1332
- const recipients = this.getEscalationRecipients();
1333
- if (!recipients.length || !log?._id) {
1334
- return;
1335
- }
1336
-
1337
- const identifier = log.autofix_error_count_string || log._id;
1338
- const subject = `ResolveIO AutoFix Escalation: ${identifier}`;
1339
- const body = [
1340
- 'Auto-fix retry budget was exhausted for this recurring issue and further autonomous attempts were stopped.',
1341
- '',
1342
- `Reason: ${reason}`,
1343
- `Issue Log ID: ${log._id}`,
1344
- `Issue Counter: ${log.autofix_error_count_string || 'n/a'}`,
1345
- `Client: ${log.client_name || log.id_client || 'unknown'}`,
1346
- `Source App: ${log.source_app || 'unknown'}`,
1347
- `Environment: ${log.source_environment || log.openai_environment || 'unknown'}`,
1348
- `Attempts: ${log.attempt_count || 0}/${this.config.maxAutoRunAttemptsPerIssue}`,
1349
- `Issue Hash: ${log.issue_hash || log.email_hash || 'n/a'}`,
1350
- '',
1351
- 'The issue is now marked ignored for auto-fix to protect customer token usage. Manual intervention is required.'
1352
- ].join('\n');
1353
-
1354
- const methodManager = ResolveIOServer.getMainServer().getMethodManager();
1355
- for (const recipient of recipients) {
1356
- try {
1357
- await methodManager.sendEmail(recipient, subject, body);
1358
- }
1359
- catch (error) {
1360
- console.error('Failed sending auto-fix escalation email', {recipient, logId: log._id, error});
1361
- }
1362
- }
1363
- }
1364
-
1365
- private collectLibraryIssueSignalText(email: ErrorEmail, log: ErrorAutoFixLogModel): string {
1366
- const attachments = Array.isArray(log?.attachments) ? log.attachments : [];
1367
- const attachmentSignals = attachments.map((attachment) => {
1368
- return [
1369
- attachment?.name || '',
1370
- attachment?.url || '',
1371
- attachment?.contentType || ''
1372
- ].filter(Boolean).join(' ');
1373
- });
1374
- const metadata = log?.report_metadata && Object.keys(log.report_metadata).length
1375
- ? JSON.stringify(log.report_metadata)
1376
- : '';
1377
- const context = log?.report_context && Object.keys(log.report_context).length
1378
- ? JSON.stringify(log.report_context)
1379
- : '';
1380
- return [
1381
- email?.subject || '',
1382
- email?.body || '',
1383
- log?.body || '',
1384
- metadata,
1385
- context,
1386
- attachmentSignals.join('\n')
1387
- ].filter(Boolean).join('\n');
1388
- }
1389
-
1390
- private evaluateLibraryIssueGate(email: ErrorEmail, log: ErrorAutoFixLogModel): LibraryIssueGateDecision {
1391
- const signalText = this.collectLibraryIssueSignalText(email, log);
1392
- if (!signalText) {
1393
- return {blocked: false, evidence: []};
1394
- }
1395
-
1396
- const evidence: string[] = [];
1397
- let markerHits = 0;
1398
- for (const marker of LIBRARY_MARKER_PATTERNS) {
1399
- if (!marker.pattern.test(signalText)) {
1400
- continue;
1401
- }
1402
- markerHits += 1;
1403
- evidence.push(marker.label);
1404
- }
1405
-
1406
- const rawPaths = signalText.match(FILE_PATH_PATTERN) || [];
1407
- const normalizedPaths = rawPaths
1408
- .map((value) => String(value || '').trim())
1409
- .filter(Boolean)
1410
- .map((value) => value.replace(/\\/g, '/').toLowerCase());
1411
- const appOwnedPathCount = normalizedPaths.filter((value) => APP_OWNED_PATH_PATTERN.test(value)).length;
1412
- const libraryPathCount = normalizedPaths.filter((value) => {
1413
- return value.includes('/node_modules/')
1414
- || value.includes('@resolveio/client-lib')
1415
- || value.includes('@resolveio/server-lib')
1416
- || value.includes('/resolveio-client-lib/')
1417
- || value.includes('/resolveio-server-lib/')
1418
- || value.includes('/aicoder/templates/base_');
1419
- }).length;
1420
-
1421
- const shouldBlock = (libraryPathCount > 0 && appOwnedPathCount === 0)
1422
- || (markerHits >= 2 && appOwnedPathCount === 0)
1423
- || (markerHits >= 1 && libraryPathCount >= 2);
1424
- if (!shouldBlock) {
1425
- return {blocked: false, evidence};
1426
- }
1427
-
1428
- const compactEvidence = Array.from(new Set([
1429
- ...evidence,
1430
- ...(libraryPathCount ? [`library_paths=${libraryPathCount}`] : []),
1431
- ...(appOwnedPathCount ? [`app_paths=${appOwnedPathCount}`] : [])
1432
- ])).slice(0, 8);
1433
- return {
1434
- blocked: true,
1435
- reason: 'Root cause appears to be in shared ResolveIO libraries/templates; app-level auto-fix was blocked.',
1436
- evidence: compactEvidence
1437
- };
1438
- }
1439
-
1440
- private async sendLibraryIssueNotice(log: ErrorAutoFixLogModel, reason: string, evidence: string[]): Promise<void> {
1441
- const recipients = this.getEscalationRecipients();
1442
- if (!recipients.length || !log?._id) {
1443
- return;
1444
- }
1445
-
1446
- const identifier = log.autofix_error_count_string || log._id;
1447
- const subject = `ResolveIO AutoFix Blocked (Library): ${identifier}`;
1448
- const body = [
1449
- 'Auto-fix was blocked because the issue appears library-owned, so no autonomous patch was attempted.',
1450
- '',
1451
- `Reason: ${reason}`,
1452
- evidence.length ? `Evidence: ${evidence.join(', ')}` : '',
1453
- `Issue Log ID: ${log._id}`,
1454
- `Issue Counter: ${log.autofix_error_count_string || 'n/a'}`,
1455
- `Client: ${log.client_name || log.id_client || 'unknown'}`,
1456
- `Source App: ${log.source_app || 'unknown'}`,
1457
- `Environment: ${log.source_environment || log.openai_environment || 'unknown'}`,
1458
- `Issue Hash: ${log.issue_hash || log.email_hash || 'n/a'}`,
1459
- '',
1460
- 'Manual library release/fix is required. App-level auto-fix remains blocked for this issue to protect credits.'
1461
- ].filter(Boolean).join('\n');
1462
-
1463
- const methodManager = ResolveIOServer.getMainServer().getMethodManager();
1464
- for (const recipient of recipients) {
1465
- try {
1466
- await methodManager.sendEmail(recipient, subject, body);
1467
- }
1468
- catch (error) {
1469
- console.error('Failed sending library-issue auto-fix email', {recipient, logId: log._id, error});
1470
- }
1471
- }
1472
- }
1473
-
1474
- private async blockLibraryOwnedIssue(email: ErrorEmail, log: ErrorAutoFixLogModel, gate: LibraryIssueGateDecision): Promise<AutoFixResult> {
1475
- const reason = gate.reason || 'Library-owned issue detected.';
1476
- const details = gate.evidence.length ? `Signals: ${gate.evidence.join(', ')}` : '';
1477
- const message = [reason, details].filter(Boolean).join(' ');
1478
- const updated = (await this.updateLog(log._id, {
1479
- status: 'skipped',
1480
- ignored: true,
1481
- last_error: message,
1482
- last_result_at: new Date()
1483
- })) || log;
1484
- await this.notifyCustomerWorkflowStatus('blocked_library_issue', email, updated, {
1485
- error: reason,
1486
- notes: details
1487
- });
1488
- await this.sendLibraryIssueNotice(updated, reason, gate.evidence);
1489
- return {
1490
- status: 'skipped',
1491
- email,
1492
- error: message,
1493
- log: updated,
1494
- reason: 'library_issue_blocked',
1495
- summary: updated.plan_summary || email.subject,
1496
- notes: details
1497
- };
1498
- }
1499
-
1500
- private shouldNotifySkip(reason: string): boolean {
1501
- return ['in_progress', 'success', 'ignored', 'duplicate', 'pending'].indexOf(reason) === -1;
1502
- }
1503
-
1504
- private async isGeneratedAICoderClient(idClient: string): Promise<boolean> {
1505
- const normalizedClientId = String(idClient || '').trim();
1506
- if (!normalizedClientId) {
1507
- return false;
1508
- }
1509
-
1510
- const match = await AICoderApps.findOne({
1511
- client_id: normalizedClientId
1512
- }, {
1513
- projection: {
1514
- _id: 1
1515
- }
1516
- });
1517
-
1518
- return !!match?._id;
1519
- }
1520
-
1521
- private buildAICoderWorkflowSummary(
1522
- stage: 'detected_autofix_enabled' | 'detected_autofix_disabled' | 'completed_success' | 'completed_failed' | 'blocked_library_issue',
1523
- email: ErrorEmail,
1524
- log: ErrorAutoFixLogModel,
1525
- extra?: { error?: string; notes?: string }
1526
- ): string {
1527
- return buildGeneratedAppAutoFixSummary(stage, {
1528
- source_app: String(log?.source_app || email?.sourceApp || '').trim(),
1529
- environment: String(log?.source_environment || email?.sourceEnvironment || '').trim(),
1530
- severity: String(log?.severity || email?.severity || '').trim(),
1531
- error: extra?.error
1532
- }, extra);
1533
- }
1534
-
1535
- private buildResolveIOProjectWorkflowDetails(
1536
- email: ErrorEmail,
1537
- log: ErrorAutoFixLogModel,
1538
- extra?: { error?: string; notes?: string }
1539
- ): string {
1540
- return buildResolveIOProjectAutoFixDetails({
1541
- client_name: log?.client_name || email?.client_name || '',
1542
- issue_counter: log?.autofix_error_count_string || '',
1543
- source_app: log?.source_app || email?.sourceApp || '',
1544
- environment: log?.source_environment || email?.sourceEnvironment || log?.openai_environment || '',
1545
- severity: log?.severity || email?.severity || '',
1546
- issue_hash: log?.issue_hash || email?.issueHash || log?.email_hash || '',
1547
- log_id: log?._id || '',
1548
- notes: extra?.notes,
1549
- error: extra?.error
1550
- });
1551
- }
1552
-
1553
- private buildLocalInternalUserCriteria(): Record<string, any> {
1554
- return {
1555
- $and: [
1556
- {
1557
- is_customer: {
1558
- $ne: true
1559
- }
1560
- },
1561
- {
1562
- $nor: [
1563
- {
1564
- 'other.id_customer': {
1565
- $exists: true,
1566
- $nin: ['', null]
1567
- }
1568
- },
1569
- {
1570
- id_customer: {
1571
- $exists: true,
1572
- $nin: ['', null]
1573
- }
1574
- }
1575
- ]
1576
- }
1577
- ]
1578
- };
1579
- }
1580
-
1581
- private buildLocalAdminUserCriteria(): Record<string, any> {
1582
- return {
1583
- $or: [
1584
- {
1585
- 'roles.super_admin': true
1586
- },
1587
- {
1588
- 'roles.groups.name': {
1589
- $regex: 'admin',
1590
- $options: 'i'
1591
- }
1592
- },
1593
- {
1594
- 'roles.groups.views': {
1595
- $regex: '^/manage'
1596
- }
1597
- },
1598
- {
1599
- 'roles.groups.views': '/manage'
1600
- }
1601
- ]
1602
- };
1603
- }
1604
-
1605
- private async resolveLocalNotificationUserIds(isGeneratedApp: boolean): Promise<string[]> {
1606
- const andClauses: Record<string, any>[] = [
1607
- {
1608
- active: true
1609
- },
1610
- {
1611
- username: {
1612
- $exists: true
1613
- }
1614
- }
1615
- ];
1616
-
1617
- if (isGeneratedApp) {
1618
- andClauses.push(this.buildLocalInternalUserCriteria());
1619
- }
1620
- else {
1621
- andClauses.push(this.buildLocalAdminUserCriteria());
1622
- }
1623
-
1624
- const users = await Users.find({
1625
- $and: andClauses
1626
- }, {
1627
- projection: {
1628
- _id: 1
1629
- },
1630
- limit: MAX_LOCAL_NOTIFICATION_USERS
1631
- });
1632
-
1633
- if (!Array.isArray(users) || !users.length) {
1634
- return [];
1635
- }
1636
-
1637
- const unique = new Set<string>();
1638
- for (const user of users) {
1639
- const idUser = String(user?._id || '').trim();
1640
- if (idUser) {
1641
- unique.add(idUser);
1642
- }
1643
- if (unique.size >= MAX_LOCAL_NOTIFICATION_USERS) {
1644
- break;
1645
- }
1646
- }
1647
- return Array.from(unique);
1648
- }
1649
-
1650
- private async notifyCustomerWorkflowStatus(
1651
- stage: 'detected_autofix_enabled' | 'detected_autofix_disabled' | 'completed_success' | 'completed_failed' | 'blocked_library_issue',
1652
- email: ErrorEmail,
1653
- log: ErrorAutoFixLogModel,
1654
- extra?: { error?: string; notes?: string }
1655
- ): Promise<void> {
1656
- const idClient = String(log?.id_client || email?.id_client || '').trim();
1657
- let isGeneratedApp = false;
1658
- if (idClient) {
1659
- isGeneratedApp = await this.isGeneratedAICoderClient(idClient);
1660
- }
1661
- else {
1662
- const resolvedEnvironment = this.resolveEnvironmentForTask(email, log);
1663
- const app = await this.resolveAutoFixApp(email, log, resolvedEnvironment);
1664
- isGeneratedApp = !!app;
1665
- }
1666
-
1667
- if (!isGeneratedApp && stage !== 'completed_success') {
1668
- return;
1669
- }
1670
-
1671
- const issueKey = String(log?.issue_hash || log?.email_hash || email?.issueHash || email?.hash || log?._id || '').trim();
1672
- const clientName = String(log?.client_name || email?.client_name || '').trim();
1673
- const targetPayload: Record<string, any> = {};
1674
- if (idClient) {
1675
- targetPayload.target_type = isGeneratedApp ? 'client_internal' : 'client_admins';
1676
- targetPayload.id_client = idClient;
1677
- targetPayload.client_name = clientName || undefined;
1678
- }
1679
- else {
1680
- const idUsers = await this.resolveLocalNotificationUserIds(isGeneratedApp);
1681
- if (!idUsers.length) {
1682
- return;
1683
- }
1684
- targetPayload.target_type = 'users';
1685
- targetPayload.id_users = idUsers;
1686
- targetPayload.client_name = clientName || undefined;
1687
- }
1688
-
1689
- const basePayload: Record<string, any> = {
1690
- ...targetPayload,
1691
- category: 'autofix',
1692
- source: 'error-auto-fix',
1693
- source_id: String(log?._id || '').trim() || undefined,
1694
- dedupe_key: issueKey ? `autofix:${issueKey}:${stage}` : `autofix:${String(log?._id || '').trim()}:${stage}`,
1695
- metadata: {
1696
- issue_hash: log?.issue_hash || email?.issueHash || '',
1697
- log_id: log?._id || '',
1698
- severity: log?.severity || email?.severity || '',
1699
- source_app: log?.source_app || email?.sourceApp || '',
1700
- source_environment: log?.source_environment || email?.sourceEnvironment || '',
1701
- error: extra?.error || '',
1702
- notes: extra?.notes || ''
1703
- }
1704
- };
1705
-
1706
- let payload: Record<string, any> = {};
1707
- if (isGeneratedApp) {
1708
- if (stage === 'detected_autofix_enabled') {
1709
- payload = {
1710
- title: 'Issue detected. Auto-fix is in progress.',
1711
- message: 'We detected an issue in your app and started an automatic fix workflow. We will notify you when it is complete.',
1712
- severity: 'info',
1713
- details: this.buildAICoderWorkflowSummary(stage, email, log, extra)
1714
- };
1715
- }
1716
- else if (stage === 'detected_autofix_disabled') {
1717
- payload = {
1718
- title: 'Issue detected. Auto-fix is disabled.',
1719
- message: 'We detected an issue, but automatic fixing is not enabled. Please ask the AI assistant to investigate this issue.',
1720
- severity: 'warning',
1721
- details: this.buildAICoderWorkflowSummary(stage, email, log, extra)
1722
- };
1723
- }
1724
- else if (stage === 'completed_success') {
1725
- payload = {
1726
- title: 'Auto-fix completed successfully.',
1727
- message: 'Your issue was fixed automatically and the update was published.',
1728
- severity: 'success',
1729
- details: this.buildAICoderWorkflowSummary(stage, email, log, extra)
1730
- };
1731
- }
1732
- else if (stage === 'blocked_library_issue') {
1733
- payload = {
1734
- title: 'Issue requires a platform library update.',
1735
- message: 'We detected this issue in shared platform libraries, so app auto-fix was stopped. Our engineering team has been notified to ship a library-level fix.',
1736
- severity: 'warning',
1737
- details: this.buildAICoderWorkflowSummary(stage, email, log, extra)
1738
- };
1739
- }
1740
- else {
1741
- payload = {
1742
- title: 'Auto-fix needs manual review.',
1743
- message: 'We could not complete an automatic fix for this issue. Manual follow-up is required.',
1744
- severity: 'warning',
1745
- details: this.buildAICoderWorkflowSummary(stage, email, log, extra)
1746
- };
1747
- }
1748
- }
1749
- else {
1750
- payload = {
1751
- title: 'ResolveIO project auto-fix completed',
1752
- message: `A fix for ${String(log?.source_app || email?.sourceApp || 'the project').trim()} completed successfully.`,
1753
- severity: 'success',
1754
- details: this.buildResolveIOProjectWorkflowDetails(email, log, extra)
1755
- };
1756
- }
1757
-
1758
- try {
1759
- await ResolveIOServer.getMainServer().getMethodManager().callMethod('createCustomerNotification', {
1760
- ...basePayload,
1761
- ...payload
1762
- });
1763
- }
1764
- catch (error) {
1765
- this.debugLog('Failed to create customer auto-fix notification', {
1766
- logId: log?._id,
1767
- stage,
1768
- error: error?.message || error
1769
- });
1770
- }
1771
- }
1772
-
1773
- private async delay(ms: number): Promise<void> {
1774
- // eslint-disable-next-line no-restricted-syntax
1775
- await new Promise(resolve => setTimeout(resolve, ms));
1776
- }
1777
-
1778
- public async reportDevError(options: DevErrorReportOptions): Promise<void> {
1779
- const subject = (options?.subject || '').trim() || 'ResolveIO alert';
1780
- const body = options?.body || '';
1781
- const sourceApp = options?.sourceApp || ResolveIOServer.getClientName() || 'resolveio-server';
1782
- const environment = options?.environment || process.env.NODE_ENV || '';
1783
- const severity = options?.severity || 'infrastructure';
1784
- const fingerprint = (options?.fingerprint || createHash('sha256').update(`${sourceApp}:${environment || 'env'}:${subject}`).digest('hex')).trim();
1785
- const metadata = options?.metadata && Object.keys(options.metadata).length ? options.metadata : undefined;
1786
-
1787
- if (!this.isReady()) {
1788
- console.warn('AutoFix manager not ready for dev alert', {subject, environment});
1789
- return;
1790
- }
1791
-
1792
- try {
1793
- await this.ingestErrorReport({
1794
- sourceApp,
1795
- environment,
1796
- message: subject,
1797
- stack: body,
1798
- severity,
1799
- metadata,
1800
- fingerprint,
1801
- idempotencyKey: options?.idempotencyKey,
1802
- clientId: options?.clientId,
1803
- clientName: options?.clientName,
1804
- clientSlug: options?.clientSlug,
1805
- reportedBy: 'resolveio-server'
1806
- });
1807
- }
1808
- catch (err) {
1809
- console.error('Failed to log developer alert', subject, err);
1810
- }
1811
- }
1812
-
1813
- public async ingestErrorReport(report: ErrorReportPayload): Promise<ErrorReportIngestResult> {
1814
- if (!this.isReady()) {
1815
- throw new Error('ErrorAutoFixManager is not enabled.');
1816
- }
1817
-
1818
- if (!report || !report.sourceApp || !report.message) {
1819
- throw new Error('Invalid error report payload.');
1820
- }
1821
-
1822
- const normalizedReport: ErrorReportPayload = {
1823
- ...report,
1824
- message: (report.message || '').toString(),
1825
- stack: report.stack ? report.stack.toString() : undefined,
1826
- metadata: report.metadata || undefined,
1827
- context: report.context || undefined,
1828
- attachments: Array.isArray(report.attachments) ? report.attachments : undefined,
1829
- reportedAt: report.reportedAt instanceof Date && !Number.isNaN(report.reportedAt.getTime()) ? report.reportedAt : new Date()
1830
- };
1831
-
1832
- const email = this.buildEmailFromReport(normalizedReport);
1833
- email.reportedAt = normalizedReport.reportedAt;
1834
- email.openai_environment = normalizedReport.clientRepo || email.openai_environment;
1835
- email.fromAddress = this.extractEmailAddress(normalizedReport.clientEmail || normalizedReport.reportedBy || email.from || '');
1836
- if (!email.fromAddress && normalizedReport.clientSlug) {
1837
- email.fromAddress = `${normalizedReport.clientSlug}@errors.resolveio.com`;
1838
- }
1839
-
1840
- const rawHash = normalizedReport.idempotencyKey ? normalizedReport.idempotencyKey.trim() : '';
1841
- email.rawHash = rawHash || this.generateRawEmailHash(email);
1842
- const fingerprint = normalizedReport.fingerprint ? normalizedReport.fingerprint.trim() : '';
1843
- if (fingerprint) {
1844
- email.issueHash = fingerprint;
1845
- email.hash = fingerprint;
1846
- }
1847
- else {
1848
- email.issueHash = this.generateIssueHash(email);
1849
- email.hash = email.issueHash || email.rawHash;
1850
- }
1851
-
1852
- const client = await this.resolveClientForReport(normalizedReport);
1853
- const autoOptimizeEnabled = await this.resolveAutoOptimizeEnabled();
1854
- const reservation = await this.reserveLog(email, client, autoOptimizeEnabled);
1855
-
1856
- if (!reservation.proceed) {
1857
- if (reservation.reason && this.shouldNotifySkip(reservation.reason)) {
1858
- await this.notify({
1859
- status: 'skipped',
1860
- email,
1861
- reason: reservation.reason,
1862
- error: `Skipped auto-fix (${reservation.reason}).`,
1863
- log: reservation.log
1864
- });
1865
- }
1866
-
1867
- return {
1868
- status: reservation.reason === 'duplicate' ? 'duplicate' : (reservation.reason as any) || 'skipped',
1869
- reason: reservation.reason,
1870
- log: reservation.log
1871
- };
1872
- }
1873
-
1874
- email.logId = reservation.log._id;
1875
- const classification = this.classifyEmail(email);
1876
- await this.updateLog(email.logId, {
1877
- id_client: client?._id,
1878
- client_name: client?.name,
1879
- from_email: email.fromAddress,
1880
- source_type: classification.source,
1881
- classification_reason: classification.reason || '',
1882
- openai_environment: email.openai_environment || reservation.log.openai_environment || this.determineOpenAIEnvironment(client),
1883
- source_app: email.sourceApp,
1884
- source_environment: email.sourceEnvironment,
1885
- severity: email.severity,
1886
- reported_by: email.reportedBy || email.fromAddress,
1887
- report_metadata: email.reportMetadata,
1888
- report_context: email.reportContext,
1889
- attachments: email.attachments,
1890
- last_reported_at: email.reportedAt || new Date()
1891
- });
1892
-
1893
- if (classification.skip) {
1894
- const updated = await this.updateLog(email.logId, {
1895
- status: 'skipped',
1896
- ignored: !!classification.markIgnored,
1897
- last_error: classification.reason || 'Ignored non-app alert',
1898
- last_result_at: new Date()
1899
- });
1900
-
1901
- if (classification.notify) {
1902
- await this.notify({
1903
- status: 'skipped',
1904
- email,
1905
- error: classification.reason,
1906
- log: updated,
1907
- reason: 'classified'
1908
- });
1909
- }
1910
-
1911
- return {
1912
- status: 'skipped',
1913
- reason: classification.reason,
1914
- log: updated
1915
- };
1916
- }
1917
-
1918
- if (!autoOptimizeEnabled) {
1919
- const queued = await this.updateLog(email.logId, {
1920
- status: 'pending'
1921
- });
1922
- await this.notifyCustomerWorkflowStatus('detected_autofix_disabled', email, queued || reservation.log);
1923
-
1924
- return {
1925
- status: 'queued',
1926
- log: queued
1927
- };
1928
- }
1929
-
1930
- await this.notifyCustomerWorkflowStatus('detected_autofix_enabled', email, reservation.log);
1931
- const result = await this.processEmail(email, reservation.log);
1932
- await this.notify(result);
1933
- const finalLog = result.log || (await ErrorAutoFixLogs.findOne({_id: email.logId}));
1934
- return {
1935
- status: result.status,
1936
- reason: result.reason,
1937
- log: finalLog || result.log
1938
- };
1939
- }
1940
-
1941
- public async runLog(logId: string): Promise<AutoFixResult> {
1942
- if (!this.config.enabled) {
1943
- throw new Error('Auto-fix manager disabled.');
1944
- }
1945
-
1946
- const log = await ErrorAutoFixLogs.findOne({_id: logId});
1947
- if (!log) {
1948
- throw new Error('Auto-fix log not found.');
1949
- }
1950
-
1951
- if (log.ignored) {
1952
- throw new Error('Auto-fix log is ignored.');
1953
- }
1954
-
1955
- if (log.status === 'in_progress') {
1956
- throw new Error('Auto-fix workflow already running.');
1957
- }
1958
-
1959
- if (!log.body) {
1960
- throw new Error('Auto-fix log is missing email body.');
1961
- }
1962
-
1963
- const now = new Date();
1964
- const email = this.buildEmailFromLog(log);
1965
- const classification = this.classifyEmail(email);
1966
- if (classification.skip && classification.markIgnored) {
1967
- const ignoredLog = await this.updateLog(logId, {
1968
- status: 'skipped',
1969
- ignored: true,
1970
- last_error: classification.reason || 'Mongo-origin error ignored for auto-fix',
1971
- last_result_at: now
1972
- });
1973
- return {
1974
- status: 'skipped',
1975
- email,
1976
- reason: 'classified',
1977
- error: classification.reason || 'Mongo-origin error ignored for auto-fix',
1978
- log: ignoredLog
1979
- };
1980
- }
1981
-
1982
- const inProgressLog = (await ErrorAutoFixLogs.findOneAndUpdate({_id: logId}, {
1983
- $inc: {
1984
- attempt_count: 1
1985
- },
1986
- $set: {
1987
- status: 'in_progress',
1988
- last_attempt_at: now,
1989
- last_error: '',
1990
- ignored: false
1991
- }
1992
- }, {
1993
- returnDocument: 'after'
1994
- })) || log;
1995
-
1996
- const result = await this.processEmail(email, inProgressLog);
1997
- await this.notify(result);
1998
- return result;
1999
- }
2000
-
2001
- private buildEmailFromLog(log: ErrorAutoFixLogModel): ErrorEmail {
2002
- return {
2003
- key: log.message_id || log._id,
2004
- subject: log.subject,
2005
- body: log.body || '',
2006
- messageId: log.message_id,
2007
- hash: log.issue_hash || log.email_hash,
2008
- rawHash: log.email_hash,
2009
- issueHash: log.issue_hash,
2010
- raw: log.body || '',
2011
- id_client: log.id_client,
2012
- client_name: log.client_name,
2013
- fromAddress: log.from_email,
2014
- source_type: log.source_type || 'app',
2015
- classification_reason: log.classification_reason,
2016
- openai_environment: log.openai_environment,
2017
- sourceApp: log.source_app,
2018
- sourceEnvironment: log.source_environment,
2019
- severity: log.severity,
2020
- reportedBy: log.reported_by,
2021
- reportMetadata: log.report_metadata,
2022
- reportContext: log.report_context,
2023
- attachments: log.attachments,
2024
- reportedAt: log.last_reported_at
2025
- };
2026
- }
2027
-
2028
- private async processEmail(email: ErrorEmail, log: ErrorAutoFixLogModel): Promise<AutoFixResult> {
2029
- const libraryIssueGate = this.evaluateLibraryIssueGate(email, log);
2030
- if (libraryIssueGate.blocked) {
2031
- return await this.blockLibraryOwnedIssue(email, log, libraryIssueGate);
2032
- }
2033
-
2034
- if (this.config.dashboardWorkflowEnabled) {
2035
- const dashboardResult = await this.dispatchDashboardWorkflow(email, log);
2036
- if (dashboardResult.status === 'in_progress' || dashboardResult.status === 'success') {
2037
- return dashboardResult;
2038
- }
2039
- if (!this.config.dashboardFallbackToGithub) {
2040
- return dashboardResult;
2041
- }
2042
-
2043
- this.debugLog('Dashboard workflow unavailable; falling back to GitHub workflow.', {
2044
- logId: log?._id,
2045
- reason: dashboardResult.reason,
2046
- error: dashboardResult.error
2047
- });
2048
- }
2049
-
2050
- return await this.dispatchGithubWorkflow(email, log);
2051
- }
2052
-
2053
- private shouldFallbackDashboardMethod(error: any): boolean {
2054
- const message = `${error?.message || ''}`.toLowerCase();
2055
- return message.includes('not found')
2056
- || message.includes('worker dispatch unavailable')
2057
- || message.includes('no worker')
2058
- || message.includes('unavailable for aidashboard');
2059
- }
2060
-
2061
- private async createDashboardJob(payload: Record<string, any>): Promise<AIDashboardJob> {
2062
- const methodManager = ResolveIOServer.getMainServer().getMethodManager();
2063
- try {
2064
- return await methodManager.callMethod('aiDashboardCreateJob', payload);
2065
- }
2066
- catch (error) {
2067
- if (!this.shouldFallbackDashboardMethod(error)) {
2068
- throw error;
2069
- }
2070
- }
2071
-
2072
- const manager: any = ResolveIOServer['AIDashboardManager'];
2073
- if (manager && manager.isEnabled && manager.isEnabled()) {
2074
- return await manager.createJob(payload);
2075
- }
2076
-
2077
- throw new Error('AI Dashboard manager is not available.');
2078
- }
2079
-
2080
- private async waitForDashboardJobStop(jobId: string, timeoutMs: number): Promise<void> {
2081
- const methodManager = ResolveIOServer.getMainServer().getMethodManager();
2082
- try {
2083
- await methodManager.callMethod('aiDashboardWaitForJobStop', jobId, timeoutMs);
2084
- return;
2085
- }
2086
- catch (error) {
2087
- if (!this.shouldFallbackDashboardMethod(error)) {
2088
- throw error;
2089
- }
2090
- }
2091
-
2092
- const manager: any = ResolveIOServer['AIDashboardManager'];
2093
- if (manager && manager.isEnabled && manager.isEnabled()) {
2094
- await manager.waitForJobStop(jobId, timeoutMs);
2095
- return;
2096
- }
2097
-
2098
- throw new Error('AI Dashboard manager is not available.');
2099
- }
2100
-
2101
- private async isDashboardJobRunning(jobId: string): Promise<boolean> {
2102
- const methodManager = ResolveIOServer.getMainServer().getMethodManager();
2103
- try {
2104
- const running = await methodManager.callMethod('aiDashboardIsJobRunning', jobId);
2105
- return !!running;
2106
- }
2107
- catch (error) {
2108
- if (!this.shouldFallbackDashboardMethod(error)) {
2109
- throw error;
2110
- }
2111
- }
2112
-
2113
- const manager: any = ResolveIOServer['AIDashboardManager'];
2114
- if (manager && manager.isEnabled && manager.isEnabled()) {
2115
- return !!manager.isJobRunning(jobId);
2116
- }
2117
-
2118
- throw new Error('AI Dashboard manager is not available.');
2119
- }
2120
-
2121
- private async resolveAutoFixApp(email: ErrorEmail, log: ErrorAutoFixLogModel, resolvedEnvironment: string): Promise<AICoderAppModel | null> {
2122
- const clientId = (email.id_client || log.id_client || '').trim();
2123
- if (clientId) {
2124
- const byClientId = await AICoderApps.findOne({client_id: clientId}, {
2125
- sort: {
2126
- updatedAt: -1,
2127
- createdAt: -1
2128
- }
2129
- });
2130
- if (byClientId) {
2131
- return byClientId;
2132
- }
2133
- }
2134
-
2135
- const lookupClientCandidates = [
2136
- (email.client_name || '').trim(),
2137
- (log.client_name || '').trim()
2138
- ].filter(Boolean);
2139
- for (const candidate of lookupClientCandidates) {
2140
- const escaped = this.escapeRegex(candidate);
2141
- const clientDoc = await Clients.findOne({
2142
- $or: [
2143
- {name: {$regex: `^${escaped}$`, $options: 'i'}},
2144
- {demo_name: {$regex: `^${escaped}$`, $options: 'i'}},
2145
- {repo: {$regex: `^${escaped}$`, $options: 'i'}}
2146
- ]
2147
- });
2148
- if (!clientDoc?._id) {
2149
- continue;
2150
- }
2151
- const byClient = await AICoderApps.findOne({client_id: clientDoc._id}, {
2152
- sort: {
2153
- updatedAt: -1,
2154
- createdAt: -1
2155
- }
2156
- });
2157
- if (byClient) {
2158
- return byClient;
2159
- }
2160
- }
2161
-
2162
- const environmentRepo = (resolvedEnvironment || '').trim();
2163
- if (environmentRepo) {
2164
- const escapedRepo = this.escapeRegex(environmentRepo);
2165
- const byRepo = await AICoderApps.findOne({
2166
- repo: {
2167
- $regex: `^${escapedRepo}$`,
2168
- $options: 'i'
2169
- }
2170
- }, {
2171
- sort: {
2172
- updatedAt: -1,
2173
- createdAt: -1
2174
- }
2175
- });
2176
- if (byRepo) {
2177
- return byRepo;
2178
- }
2179
- }
2180
-
2181
- const appNameCandidates = [
2182
- (email.sourceApp || '').trim(),
2183
- (log.source_app || '').trim()
2184
- ].filter(Boolean);
2185
- for (const candidate of appNameCandidates) {
2186
- const escaped = this.escapeRegex(candidate);
2187
- const bySlugOrName = await AICoderApps.findOne({
2188
- $or: [
2189
- {slug: {$regex: `^${escaped}$`, $options: 'i'}},
2190
- {name: {$regex: `^${escaped}$`, $options: 'i'}}
2191
- ]
2192
- }, {
2193
- sort: {
2194
- updatedAt: -1,
2195
- createdAt: -1
2196
- }
2197
- });
2198
- if (bySlugOrName) {
2199
- return bySlugOrName;
2200
- }
2201
- }
2202
-
2203
- return null;
2204
- }
2205
-
2206
- private buildDashboardAutoFixTitle(email: ErrorEmail, log: ErrorAutoFixLogModel, app: AICoderAppModel): string {
2207
- const identifier = log.autofix_error_count_string || (log._id || '').slice(-6) || 'error';
2208
- const source = (email.sourceApp || log.source_app || app?.name || 'application').trim();
2209
- return `Auto-fix ${identifier}: ${source}`;
2210
- }
2211
-
2212
- private buildDashboardAutoFixDescription(email: ErrorEmail, log: ErrorAutoFixLogModel, app: AICoderAppModel): string {
2213
- const normalizedBody = this.normalizeEmailText(email.body || log.body || '', 15000);
2214
- const metadata = log.report_metadata && Object.keys(log.report_metadata).length
2215
- ? JSON.stringify(log.report_metadata, null, 2)
2216
- : '';
2217
- const context = log.report_context && Object.keys(log.report_context).length
2218
- ? JSON.stringify(log.report_context, null, 2)
2219
- : '';
2220
- const attachments = Array.isArray(log.attachments) ? log.attachments : [];
2221
- const attachmentLines = attachments.length
2222
- ? attachments.map(att => `- ${(att?.name || 'attachment').trim()} ${att?.url ? `(${att.url})` : ''}`.trim()).join('\n')
2223
- : '(none)';
2224
- const lines: string[] = [
2225
- 'Autonomous production error remediation request.',
2226
- '',
2227
- 'Hard requirements:',
2228
- '1. Before changing code, query the project MongoDB diagnostics logs for the latest context.',
2229
- '2. Query `error-autofix-logs` using `_id`, `issue_hash`, and `email_hash` from this task, then use the newest matching records.',
2230
- '3. If a previous dashboard job id is provided, query `ai-development-jobs` by that `_id` and review recent failure logs before retrying.',
2231
- '4. Treat `.dashboard-output/build-*.log` as primary build evidence, and `.build-output/build-*.log` as retained history when diagnosing failures.',
2232
- '5. Reproduce and fix the reported issue with the smallest safe code change.',
2233
- '6. Keep query/result behavior backward compatible unless explicitly required by the bug fix.',
2234
- '7. Run project build checks and continue iterating until the build is green.',
2235
- '8. Ensure there are no new lint/type/runtime regressions introduced by the fix.',
2236
- '9. Finish by publishing the passing fix to the default branch and deploying artifacts.',
2237
- '',
2238
- `App: ${app?.name || app?._id || 'unknown'}`,
2239
- `Repo: ${app?.repo || 'unknown'}`,
2240
- `Environment: ${email.sourceEnvironment || log.source_environment || 'unknown'}`,
2241
- `Severity: ${email.severity || log.severity || 'error'}`,
2242
- `Fingerprint: ${email.issueHash || log.issue_hash || log.email_hash || 'n/a'}`,
2243
- `Error Log Id: ${String(log?._id || '').trim() || 'n/a'}`,
2244
- `Previous Dashboard Job Id: ${String(log?.openai_task_id || '').trim() || 'n/a'}`,
2245
- '',
2246
- 'Reported error payload:',
2247
- '```',
2248
- normalizedBody || '(empty error body)',
2249
- '```',
2250
- '',
2251
- 'Attachments:',
2252
- attachmentLines
2253
- ];
2254
- if (metadata) {
2255
- lines.push('', 'Metadata JSON:', '```json', metadata, '```');
2256
- }
2257
- if (context) {
2258
- lines.push('', 'Context JSON:', '```json', context, '```');
2259
- }
2260
- return lines.join('\n');
2261
- }
2262
-
2263
- private evaluateDashboardPublishOutcome(job: AIDashboardJob): { success: boolean; branchName?: string; message: string } {
2264
- const logEntries = Array.isArray(job?.log) ? job.log : [];
2265
- const lastMatch = (predicate): string => {
2266
- for (let i = logEntries.length - 1; i >= 0; i -= 1) {
2267
- if (predicate(logEntries[i] || '')) {
2268
- return logEntries[i];
2269
- }
2270
- }
2271
- return '';
2272
- };
2273
-
2274
- const failureEntry = lastMatch(entry => /publish failed|artifact publish failed|deploy failed/i.test(entry || ''));
2275
- if (failureEntry) {
2276
- return {
2277
- success: false,
2278
- message: failureEntry
2279
- };
2280
- }
2281
-
2282
- const publishEntry = lastMatch(entry => /Published build to /i.test(entry || ''));
2283
- if (publishEntry) {
2284
- const branchMatch = publishEntry.match(/\(([^()]+)\)\.?$/);
2285
- return {
2286
- success: true,
2287
- branchName: (branchMatch && branchMatch[1]) ? branchMatch[1].trim() : undefined,
2288
- message: publishEntry
2289
- };
2290
- }
2291
-
2292
- const skippedEntry = lastMatch(entry => /Publish skipped/i.test(entry || ''));
2293
- if (skippedEntry) {
2294
- return {
2295
- success: !this.config.dashboardPublishRequired,
2296
- message: skippedEntry
2297
- };
2298
- }
2299
-
2300
- return {
2301
- success: !this.config.dashboardPublishRequired,
2302
- message: 'Dashboard job completed without a publish confirmation log entry.'
2303
- };
2304
- }
2305
-
2306
- private queueDashboardMonitor(log: ErrorAutoFixLogModel, email: ErrorEmail, jobId: string, effectiveEnvironment: string): void {
2307
- const logId = (log?._id || '').trim();
2308
- const normalizedJobId = (jobId || '').trim();
2309
- if (!logId || !normalizedJobId) {
2310
- return;
2311
- }
2312
- if (this.dashboardMonitors.has(logId)) {
2313
- return;
2314
- }
2315
-
2316
- const monitor = (async () => {
2317
- try {
2318
- await this.monitorDashboardAutoFixJob(log, email, normalizedJobId, effectiveEnvironment);
2319
- }
2320
- catch (error) {
2321
- console.error('Auto-fix dashboard monitor failed', {logId, jobId: normalizedJobId, error});
2322
- }
2323
- finally {
2324
- this.dashboardMonitors.delete(logId);
2325
- }
2326
- })();
2327
-
2328
- this.dashboardMonitors.set(logId, monitor);
2329
- }
2330
-
2331
- private async monitorDashboardAutoFixJob(log: ErrorAutoFixLogModel, email: ErrorEmail, jobId: string, effectiveEnvironment: string): Promise<void> {
2332
- const logId = (log?._id || '').trim();
2333
- if (!logId) {
2334
- return;
2335
- }
2336
-
2337
- const fail = async (message: string): Promise<void> => {
2338
- const failedLog = (await this.updateLog(logId, {
2339
- status: 'failed',
2340
- last_error: message,
2341
- last_result_at: new Date(),
2342
- openai_task_id: jobId,
2343
- openai_environment: effectiveEnvironment
2344
- })) || log;
2345
- await this.notifyCustomerWorkflowStatus('completed_failed', email, failedLog, {error: message});
2346
- await this.notify({
2347
- status: 'failed',
2348
- email,
2349
- error: message,
2350
- log: failedLog,
2351
- summary: failedLog.plan_summary || email.subject
2352
- });
2353
- };
2354
-
2355
- try {
2356
- await this.waitForDashboardJobStop(jobId, this.config.dashboardWaitTimeoutMs);
2357
- }
2358
- catch (error) {
2359
- const message = error?.message || 'Failed while waiting for dashboard job completion.';
2360
- await fail(message);
2361
- return;
2362
- }
2363
-
2364
- let isRunning = false;
2365
- try {
2366
- isRunning = await this.isDashboardJobRunning(jobId);
2367
- }
2368
- catch (error) {
2369
- const message = error?.message || 'Unable to confirm dashboard job completion state.';
2370
- await fail(message);
2371
- return;
2372
- }
2373
-
2374
- if (isRunning) {
2375
- await fail(`Dashboard job ${jobId} timed out before completion.`);
2376
- return;
2377
- }
2378
-
2379
- const job = await AIDashboardJobs.findOne({_id: jobId}) as AIDashboardJob | null;
2380
- if (!job) {
2381
- await fail(`Dashboard job ${jobId} not found.`);
2382
- return;
2383
- }
2384
-
2385
- if (job.phase !== 'COMPLETE' || job.paused) {
2386
- await fail(`Dashboard job ${jobId} ended in phase ${job.phase || 'unknown'}${job.paused ? ' (paused)' : ''}.`);
2387
- return;
2388
- }
2389
-
2390
- const publishOutcome = this.evaluateDashboardPublishOutcome(job);
2391
- if (!publishOutcome.success) {
2392
- await fail(publishOutcome.message);
2393
- return;
2394
- }
2395
-
2396
- const fallbackBranch = (String(this._serverConfig?.['GITHUB_DEFAULT_BRANCH'] || process.env.GITHUB_DEFAULT_BRANCH || 'main').trim() || 'main');
2397
- const branchName = publishOutcome.branchName || fallbackBranch;
2398
- const successLog = (await this.updateLog(logId, {
2399
- status: 'success',
2400
- branch_name: branchName,
2401
- pr_url: '',
2402
- last_error: '',
2403
- last_result_at: new Date(),
2404
- openai_task_id: jobId,
2405
- openai_environment: effectiveEnvironment
2406
- })) || log;
2407
- await this.notifyCustomerWorkflowStatus('completed_success', email, successLog, {notes: publishOutcome.message});
2408
-
2409
- await this.notify({
2410
- status: 'success',
2411
- email,
2412
- branchName,
2413
- log: successLog,
2414
- summary: successLog.plan_summary || email.subject,
2415
- notes: publishOutcome.message
2416
- });
2417
- }
2418
-
2419
- private async dispatchDashboardWorkflow(email: ErrorEmail, log: ErrorAutoFixLogModel): Promise<AutoFixResult> {
2420
- const fail = async (
2421
- status: 'failed' | 'skipped',
2422
- reason: string,
2423
- message: string
2424
- ): Promise<AutoFixResult> => {
2425
- const updated = (await this.updateLog(log._id, {
2426
- status,
2427
- last_error: message,
2428
- last_result_at: new Date()
2429
- })) || log;
2430
- return {
2431
- status,
2432
- email,
2433
- error: message,
2434
- log: updated,
2435
- reason
2436
- };
2437
- };
2438
-
2439
- const openaiEnvironment = this.resolveEnvironmentForTask(email, log);
2440
- const app = await this.resolveAutoFixApp(email, log, openaiEnvironment);
2441
- if (!app?._id) {
2442
- return await fail('skipped', 'dashboard_app_not_found', 'No AI Coder app found for this error log.');
2443
- }
2444
-
2445
- const repo = (app.repo || '').trim();
2446
- if (!repo) {
2447
- return await fail('skipped', 'dashboard_repo_missing', 'Resolved AI Coder app is missing repo configuration.');
2448
- }
2449
-
2450
- const effectiveEnvironment = repo;
2451
- const emailHash = email.issueHash || email.hash || this.generateIssueHash(email);
2452
- const rawHash = email.rawHash || this.generateRawEmailHash(email);
2453
- const title = this.buildDashboardAutoFixTitle(email, log, app);
2454
- const description = this.buildDashboardAutoFixDescription(email, log, app);
2455
-
2456
- let job: AIDashboardJob;
2457
- try {
2458
- job = await this.createDashboardJob({
2459
- project: app._id,
2460
- title,
2461
- description,
2462
- repo,
2463
- path: app.git_local_path || undefined,
2464
- projectRoot: app.project_root || undefined
2465
- });
2466
- }
2467
- catch (error) {
2468
- const message = error?.message || 'Unable to enqueue dashboard auto-fix job.';
2469
- return await fail('failed', 'dashboard_job_create_failed', message);
2470
- }
2471
-
2472
- const jobId = (job?._id || '').trim();
2473
- if (!jobId) {
2474
- return await fail('failed', 'dashboard_job_missing_id', 'Dashboard job created without an id.');
2475
- }
2476
-
2477
- const queuedLog = (await this.updateLog(log._id, {
2478
- status: 'in_progress',
2479
- last_attempt_at: new Date(),
2480
- branch_name: '',
2481
- pr_url: '',
2482
- last_error: '',
2483
- openai_environment: effectiveEnvironment,
2484
- issue_hash: emailHash,
2485
- email_hash: rawHash,
2486
- openai_task_id: jobId,
2487
- plan_summary: title,
2488
- plan_body: description
2489
- })) || log;
2490
- this.queueDashboardMonitor(queuedLog, email, jobId, effectiveEnvironment);
2491
-
2492
- return {
2493
- status: 'in_progress',
2494
- email,
2495
- log: queuedLog,
2496
- reason: 'dashboard_job_queued',
2497
- summary: title,
2498
- notes: `Dashboard job ${jobId} queued for autonomous build/fix/publish/deploy.`
2499
- };
2500
- }
2501
-
2502
- private async dispatchGithubWorkflow(email: ErrorEmail, log: ErrorAutoFixLogModel): Promise<AutoFixResult> {
2503
- const openaiEnvironment = this.resolveEnvironmentForTask(email, log);
2504
- const fallbackEnv = this.config.githubOwner && this.config.githubRepo ? `${this.config.githubOwner}/${this.config.githubRepo}` : '';
2505
- const resolvedEnvironment = (openaiEnvironment || fallbackEnv || '').trim();
2506
- const repoTarget = this.parseRepoTarget(resolvedEnvironment) || this.parseRepoTarget(fallbackEnv);
2507
-
2508
- this.debugLog('Starting GitHub PR workflow.', {
2509
- emailKey: email.key,
2510
- logId: log._id,
2511
- openaiEnvironment: resolvedEnvironment,
2512
- repoTarget
2513
- });
2514
-
2515
- if (!this.config.githubToken) {
2516
- const updated = (await this.updateLog(log._id, {
2517
- status: 'skipped',
2518
- last_error: 'GitHub token not configured',
2519
- last_result_at: new Date(),
2520
- id_client: email.id_client,
2521
- client_name: email.client_name,
2522
- from_email: email.fromAddress,
2523
- source_type: email.source_type,
2524
- classification_reason: email.classification_reason || '',
2525
- openai_environment: resolvedEnvironment
2526
- })) || log;
2527
-
2528
- return {
2529
- status: 'skipped',
2530
- email,
2531
- error: 'GitHub token not configured',
2532
- log: updated,
2533
- reason: 'missing_github_token'
2534
- };
2535
- }
2536
-
2537
- if (!repoTarget) {
2538
- const updated = (await this.updateLog(log._id, {
2539
- status: 'skipped',
2540
- last_error: 'GitHub repository not configured',
2541
- last_result_at: new Date(),
2542
- id_client: email.id_client,
2543
- client_name: email.client_name,
2544
- from_email: email.fromAddress,
2545
- source_type: email.source_type,
2546
- classification_reason: email.classification_reason || '',
2547
- openai_environment: resolvedEnvironment
2548
- })) || log;
2549
-
2550
- return {
2551
- status: 'skipped',
2552
- email,
2553
- error: 'GitHub repository not configured',
2554
- log: updated,
2555
- reason: 'missing_github_repo'
2556
- };
2557
- }
2558
-
2559
- const effectiveEnv = `${repoTarget.owner}/${repoTarget.repo}`;
2560
- const emailHash = email.issueHash || email.hash || this.generateIssueHash(email);
2561
- const rawHash = email.rawHash || this.generateRawEmailHash(email);
2562
- const workBranch = this.buildWorkBranch(emailHash);
2563
- const contextIdentifier = (emailHash || '').slice(0, 12) || 'autofix';
2564
- const contextPath = `.openai/error-context/${contextIdentifier}.md`;
2565
- const normalizedBody = this.normalizeEmailText(email.body || '');
2566
- const contextContent = this.buildContextMarkdown(email, contextIdentifier, normalizedBody);
2567
- const commentBody = this.buildOpenAIComment(email, contextPath, normalizedBody);
2568
-
2569
- await this.updateLog(log._id, {
2570
- status: 'in_progress',
2571
- last_attempt_at: new Date(),
2572
- branch_name: workBranch,
2573
- pr_url: '',
2574
- last_error: '',
2575
- openai_environment: effectiveEnv,
2576
- issue_hash: emailHash,
2577
- email_hash: rawHash
2578
- });
2579
-
2580
- try {
2581
- const baseBranch = await this.resolveBaseBranch(repoTarget);
2582
- const baseSha = await this.getBranchSha(repoTarget, baseBranch);
2583
- await this.ensureBranch(repoTarget, workBranch, baseBranch, baseSha);
2584
- await this.upsertContextFile(repoTarget, workBranch, contextPath, contextContent);
2585
-
2586
- let pr = await this.findOpenPullRequest(repoTarget, workBranch, baseBranch);
2587
- if (!pr) {
2588
- const title = `AI Autofix: ${(email.subject || 'ResolveIO Error').slice(0, 180)}`;
2589
- const bodyLines = [
2590
- 'This PR was opened automatically to let AI investigate the reported failure.',
2591
- '',
2592
- `Context file: \`${contextPath}\``
2593
- ];
2594
- pr = await this.createPullRequest(repoTarget, workBranch, baseBranch, title, bodyLines.join('\n'));
2595
- }
2596
-
2597
- await this.commentOnPullRequest(repoTarget, pr.number, commentBody);
2598
-
2599
- const updated = (await this.updateLog(log._id, {
2600
- status: 'success',
2601
- branch_name: workBranch,
2602
- pr_url: pr.html_url,
2603
- plan_summary: email.subject,
2604
- plan_body: commentBody,
2605
- last_result_at: new Date(),
2606
- id_client: email.id_client,
2607
- client_name: email.client_name,
2608
- from_email: email.fromAddress,
2609
- source_type: email.source_type,
2610
- classification_reason: email.classification_reason || '',
2611
- openai_environment: effectiveEnv,
2612
- issue_hash: emailHash,
2613
- email_hash: rawHash
2614
- })) || log;
2615
-
2616
- return {
2617
- status: 'success',
2618
- email,
2619
- branchName: workBranch,
2620
- prUrl: pr.html_url,
2621
- log: updated,
2622
- summary: email.subject,
2623
- notes: `Context file: ${contextPath}`
2624
- };
2625
- }
2626
- catch (err) {
2627
- const message = err?.message || 'GitHub workflow failed.';
2628
- const updated = (await this.updateLog(log._id, {
2629
- status: 'failed',
2630
- last_error: message,
2631
- last_result_at: new Date(),
2632
- id_client: email.id_client,
2633
- client_name: email.client_name,
2634
- from_email: email.fromAddress,
2635
- source_type: email.source_type,
2636
- classification_reason: email.classification_reason || '',
2637
- openai_environment: effectiveEnv,
2638
- issue_hash: emailHash,
2639
- email_hash: rawHash
2640
- })) || log;
2641
-
2642
- return {
2643
- status: 'failed',
2644
- email,
2645
- error: message,
2646
- log: updated
2647
- };
2648
- }
2649
- }
2650
-
2651
- private async notify(result: AutoFixResult): Promise<void> {
2652
- if (result.status === 'in_progress') {
2653
- return;
2654
- }
2655
-
2656
- if (result.status === 'skipped' && result.reason && !this.shouldNotifySkip(result.reason)) {
2657
- return;
2658
- }
2659
-
2660
- const recipients = this.config.notifyEmails.length
2661
- ? this.config.notifyEmails
2662
- : (result.status === 'failed' ? [DEFAULT_ERROR_ALERT_EMAIL] : []);
2663
- if (!recipients.length) {
2664
- return;
2665
- }
2666
-
2667
- let subject = '';
2668
- let bodyLines: string[] = [];
2669
- const logId = result.log?._id || '';
2670
- const summary = result.summary || result.log?.plan_summary || result.email.subject;
2671
-
2672
- if (result.status === 'success') {
2673
- subject = `ResolveIO AutoFix ✔ ${summary}`;
2674
- bodyLines = [
2675
- 'Auto-fix workflow completed successfully.',
2676
- `Client: ${result.log?.client_name || result.email.client_name || 'Unknown'}`,
2677
- `Source: ${result.log?.source_type || result.email.source_type || 'app'}`,
2678
- '',
2679
- `Branch: ${result.branchName || 'unknown'}`,
2680
- `PR: ${result.prUrl || 'pending'}`,
2681
- '',
2682
- 'Summary:',
2683
- summary || '(none)',
2684
- ''
2685
- ];
2686
-
2687
- if (result.notes) {
2688
- bodyLines.push(`Notes: ${result.notes}`, '');
2689
- }
2690
-
2691
- if (logId) {
2692
- bodyLines.push(`Log ID: ${logId}`);
2693
- }
2694
- }
2695
- else if (result.status === 'failed') {
2696
- subject = `ResolveIO AutoFix ✖ ${summary}`;
2697
- bodyLines = [
2698
- 'Auto-fix workflow failed.',
2699
- `Reason: ${result.error || result.log?.last_error || 'Unknown error'}`,
2700
- `Client: ${result.log?.client_name || result.email.client_name || 'Unknown'}`,
2701
- `Source: ${result.log?.source_type || result.email.source_type || 'app'}`,
2702
- '',
2703
- 'Email Subject:',
2704
- result.email.subject
2705
- ];
2706
-
2707
- if (logId) {
2708
- bodyLines.push('', `Log ID: ${logId}`);
2709
- }
2710
- }
2711
- else {
2712
- subject = `ResolveIO AutoFix ⚠ ${result.email.subject}`;
2713
- const reason = result.reason || 'skipped';
2714
-
2715
- bodyLines = [
2716
- `Auto-fix skipped. Reason: ${reason}.`,
2717
- result.error && result.error !== reason ? `Details: ${result.error}` : '',
2718
- `Client: ${result.log?.client_name || result.email.client_name || 'Unknown'}`,
2719
- `Source: ${result.log?.source_type || result.email.source_type || 'app'}`,
2720
- ''
2721
- ];
2722
-
2723
- if (logId) {
2724
- bodyLines.push(`Log ID: ${logId}`);
2725
- }
2726
-
2727
- bodyLines.push('Update or remove the log entry to retry processing.');
2728
- }
2729
-
2730
- const textBody = bodyLines.filter(line => line !== undefined && line !== null && line !== '').join('\n');
2731
-
2732
- for (let email of recipients) {
2733
- await ResolveIOServer.getMainServer().getMethodManager().sendEmail(email, subject, textBody);
2734
- }
2735
- }
2736
-
2737
- }
2738
-
2739
- export function ensureErrorAutoFixManager(serverConfig?: any): ErrorAutoFixManager | null {
2740
- const existing = ResolveIOServer['AutoFixManager'] as ErrorAutoFixManager | null;
2741
- if (existing) {
2742
- return existing;
2743
- }
2744
-
2745
- if (!configuredErrorAutoFixDependencies) {
2746
- return null;
2747
- }
2748
-
2749
- const resolvedServerConfig = serverConfig || ResolveIOServer.getServerConfig();
2750
- if (!resolvedServerConfig) {
2751
- return null;
2752
- }
2753
-
2754
- const manager = new ErrorAutoFixManager(resolvedServerConfig);
2755
- ResolveIOServer['AutoFixManager'] = manager;
2756
- return manager;
2757
- }
2758
-
2759
- export async function reportDevError(options: DevErrorReportOptions): Promise<void> {
2760
- const manager = ensureErrorAutoFixManager();
2761
- if (!manager) {
2762
- console.warn('AutoFix manager not initialized for dev alert', options?.subject);
2763
- return;
2764
- }
2765
-
2766
- await manager.reportDevError(options);
2767
- }