devchain-cli 0.21.0 → 0.22.1

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 (379) hide show
  1. package/README.md +1 -0
  2. package/dist/drizzle/0073_integration_storage.sql +27 -0
  3. package/dist/drizzle/0074_black_drax.sql +7 -0
  4. package/dist/drizzle/0075_misty_franklin_richards.sql +37 -0
  5. package/dist/drizzle/0076_epic_time_accounting.sql +48 -0
  6. package/dist/drizzle/meta/0073_snapshot.json +6247 -0
  7. package/dist/drizzle/meta/0074_snapshot.json +6299 -0
  8. package/dist/drizzle/meta/0075_snapshot.json +6563 -0
  9. package/dist/drizzle/meta/0076_snapshot.json +6913 -0
  10. package/dist/drizzle/meta/_journal.json +28 -0
  11. package/dist/node_modules/@devchain/shared/mobile-rpc-contract/index.d.ts +27 -1
  12. package/dist/node_modules/@devchain/shared/mobile-rpc-contract/index.d.ts.map +1 -1
  13. package/dist/node_modules/@devchain/shared/mobile-rpc-contract/index.js +15 -0
  14. package/dist/node_modules/@devchain/shared/mobile-rpc-contract/index.js.map +1 -1
  15. package/dist/node_modules/@devchain/shared/schemas/export-schema.d.ts +52 -52
  16. package/dist/node_modules/@devchain/shared/tsconfig.tsbuildinfo +1 -1
  17. package/dist/server/app.main.module.js +4 -0
  18. package/dist/server/app.main.module.js.map +1 -1
  19. package/dist/server/app.normal.module.js +2 -0
  20. package/dist/server/app.normal.module.js.map +1 -1
  21. package/dist/server/common/config/container-scope.d.ts +11 -0
  22. package/dist/server/common/config/container-scope.js +37 -0
  23. package/dist/server/common/config/container-scope.js.map +1 -1
  24. package/dist/server/common/constants/terminal.d.ts +1 -0
  25. package/dist/server/common/constants/terminal.js +2 -1
  26. package/dist/server/common/constants/terminal.js.map +1 -1
  27. package/dist/server/common/filters/http-exception.filter.js +3 -4
  28. package/dist/server/common/filters/http-exception.filter.js.map +1 -1
  29. package/dist/server/common/guards/integration-admission.guard.d.ts +4 -0
  30. package/dist/server/common/guards/integration-admission.guard.js +22 -0
  31. package/dist/server/common/guards/integration-admission.guard.js.map +1 -0
  32. package/dist/server/common/test/app-bootstrap.helper.js +1 -1
  33. package/dist/server/common/test/app-bootstrap.helper.js.map +1 -1
  34. package/dist/server/modules/agent-message-delivery/agent-message-delivery.service.js +4 -0
  35. package/dist/server/modules/agent-message-delivery/agent-message-delivery.service.js.map +1 -1
  36. package/dist/server/modules/cloud/cloud.module.js +5 -1
  37. package/dist/server/modules/cloud/cloud.module.js.map +1 -1
  38. package/dist/server/modules/cloud/services/cloud-egress-bridge.service.d.ts +3 -1
  39. package/dist/server/modules/cloud/services/cloud-egress-bridge.service.js +19 -3
  40. package/dist/server/modules/cloud/services/cloud-egress-bridge.service.js.map +1 -1
  41. package/dist/server/modules/cloud/services/egress-queue.service.d.ts +2 -0
  42. package/dist/server/modules/cloud/services/egress-queue.service.js +35 -17
  43. package/dist/server/modules/cloud/services/egress-queue.service.js.map +1 -1
  44. package/dist/server/modules/cloud/services/event-mapper.service.d.ts +1 -0
  45. package/dist/server/modules/cloud/services/event-mapper.service.js.map +1 -1
  46. package/dist/server/modules/cloud/services/notification-recipient-resolver.service.d.ts +10 -0
  47. package/dist/server/modules/cloud/services/notification-recipient-resolver.service.js +55 -0
  48. package/dist/server/modules/cloud/services/notification-recipient-resolver.service.js.map +1 -0
  49. package/dist/server/modules/cloud-tunnel/services/mobile-rpc-contract.generated.d.ts +31 -5
  50. package/dist/server/modules/cloud-tunnel/services/mobile-rpc-contract.generated.js +15 -0
  51. package/dist/server/modules/cloud-tunnel/services/mobile-rpc-contract.generated.js.map +1 -1
  52. package/dist/server/modules/cloud-tunnel/services/mobile-rpc-workspace-access.service.js +5 -2
  53. package/dist/server/modules/cloud-tunnel/services/mobile-rpc-workspace-access.service.js.map +1 -1
  54. package/dist/server/modules/cloud-tunnel/services/tunnel-handler.service.d.ts +1 -0
  55. package/dist/server/modules/cloud-tunnel/services/tunnel-handler.service.js +8 -0
  56. package/dist/server/modules/cloud-tunnel/services/tunnel-handler.service.js.map +1 -1
  57. package/dist/server/modules/core/controllers/runtime.controller.d.ts +1 -0
  58. package/dist/server/modules/core/controllers/runtime.controller.js +2 -0
  59. package/dist/server/modules/core/controllers/runtime.controller.js.map +1 -1
  60. package/dist/server/modules/e2ee/services/e2ee-device-store.service.d.ts +2 -0
  61. package/dist/server/modules/e2ee/services/e2ee-device-store.service.js +26 -0
  62. package/dist/server/modules/e2ee/services/e2ee-device-store.service.js.map +1 -1
  63. package/dist/server/modules/e2ee/services/e2ee-trust.service.d.ts +5 -0
  64. package/dist/server/modules/e2ee/services/e2ee-trust.service.js +11 -0
  65. package/dist/server/modules/e2ee/services/e2ee-trust.service.js.map +1 -1
  66. package/dist/server/modules/e2ee/services/paired-device-workspace-access.service.d.ts +1 -0
  67. package/dist/server/modules/e2ee/services/paired-device-workspace-access.service.js +4 -0
  68. package/dist/server/modules/e2ee/services/paired-device-workspace-access.service.js.map +1 -1
  69. package/dist/server/modules/epic-time/controllers/epic-time.controller.d.ts +8 -0
  70. package/dist/server/modules/epic-time/controllers/epic-time.controller.js +70 -0
  71. package/dist/server/modules/epic-time/controllers/epic-time.controller.js.map +1 -0
  72. package/dist/server/modules/epic-time/epic-time.module.d.ts +2 -0
  73. package/dist/server/modules/epic-time/epic-time.module.js +28 -0
  74. package/dist/server/modules/epic-time/epic-time.module.js.map +1 -0
  75. package/dist/server/modules/epic-time/models/epic-time.models.d.ts +26 -0
  76. package/dist/server/modules/epic-time/models/epic-time.models.js +3 -0
  77. package/dist/server/modules/epic-time/models/epic-time.models.js.map +1 -0
  78. package/dist/server/modules/epic-time/services/agent-time-accounting.service.d.ts +32 -0
  79. package/dist/server/modules/epic-time/services/agent-time-accounting.service.js +159 -0
  80. package/dist/server/modules/epic-time/services/agent-time-accounting.service.js.map +1 -0
  81. package/dist/server/modules/epic-time/services/epic-time.service.d.ts +15 -0
  82. package/dist/server/modules/epic-time/services/epic-time.service.js +224 -0
  83. package/dist/server/modules/epic-time/services/epic-time.service.js.map +1 -0
  84. package/dist/server/modules/epic-time/services/epic-time.store.d.ts +75 -0
  85. package/dist/server/modules/epic-time/services/epic-time.store.js +453 -0
  86. package/dist/server/modules/epic-time/services/epic-time.store.js.map +1 -0
  87. package/dist/server/modules/epics/controllers/epics.controller.d.ts +10 -0
  88. package/dist/server/modules/epics/controllers/epics.controller.js +92 -0
  89. package/dist/server/modules/epics/controllers/epics.controller.js.map +1 -1
  90. package/dist/server/modules/epics/services/epics.service.d.ts +32 -2
  91. package/dist/server/modules/epics/services/epics.service.js +243 -96
  92. package/dist/server/modules/epics/services/epics.service.js.map +1 -1
  93. package/dist/server/modules/events/catalog/agent.created.d.ts +4 -4
  94. package/dist/server/modules/events/catalog/agent.deleted.d.ts +2 -2
  95. package/dist/server/modules/events/catalog/agent.message.sent.d.ts +40 -40
  96. package/dist/server/modules/events/catalog/broadcast-registry.js +1 -0
  97. package/dist/server/modules/events/catalog/broadcast-registry.js.map +1 -1
  98. package/dist/server/modules/events/catalog/claude.hooks.ask_user_question.pending.d.ts +4 -4
  99. package/dist/server/modules/events/catalog/claude.hooks.session.started.d.ts +10 -10
  100. package/dist/server/modules/events/catalog/epic.comment.created.d.ts +6 -6
  101. package/dist/server/modules/events/catalog/epic.created.d.ts +8 -8
  102. package/dist/server/modules/events/catalog/epic.deleted.d.ts +4 -4
  103. package/dist/server/modules/events/catalog/epic.updated.d.ts +68 -42
  104. package/dist/server/modules/events/catalog/epic.updated.js +5 -0
  105. package/dist/server/modules/events/catalog/epic.updated.js.map +1 -1
  106. package/dist/server/modules/events/catalog/guest.registered.d.ts +2 -2
  107. package/dist/server/modules/events/catalog/guest.unregistered.d.ts +4 -4
  108. package/dist/server/modules/events/catalog/index.d.ts +370 -228
  109. package/dist/server/modules/events/catalog/index.js +11 -1
  110. package/dist/server/modules/events/catalog/index.js.map +1 -1
  111. package/dist/server/modules/events/catalog/integration.connection.created.d.ts +30 -0
  112. package/dist/server/modules/events/catalog/integration.connection.created.js +17 -0
  113. package/dist/server/modules/events/catalog/integration.connection.created.js.map +1 -0
  114. package/dist/server/modules/events/catalog/integration.connection.deleted.d.ts +27 -0
  115. package/dist/server/modules/events/catalog/integration.connection.deleted.js +16 -0
  116. package/dist/server/modules/events/catalog/integration.connection.deleted.js.map +1 -0
  117. package/dist/server/modules/events/catalog/integration.connection.updated.d.ts +39 -0
  118. package/dist/server/modules/events/catalog/integration.connection.updated.js +20 -0
  119. package/dist/server/modules/events/catalog/integration.connection.updated.js.map +1 -0
  120. package/dist/server/modules/events/catalog/review.comment.created.d.ts +16 -16
  121. package/dist/server/modules/events/catalog/review.comment.deleted.d.ts +2 -2
  122. package/dist/server/modules/events/catalog/review.comment.resolved.d.ts +2 -2
  123. package/dist/server/modules/events/catalog/review.comment.updated.d.ts +4 -4
  124. package/dist/server/modules/events/catalog/review.created.d.ts +12 -12
  125. package/dist/server/modules/events/catalog/review.updated.d.ts +22 -22
  126. package/dist/server/modules/events/catalog/scheduled-epic.executed.d.ts +12 -12
  127. package/dist/server/modules/events/catalog/session.human-prompt-state-changed.d.ts +77 -0
  128. package/dist/server/modules/events/catalog/session.human-prompt-state-changed.js +25 -0
  129. package/dist/server/modules/events/catalog/session.human-prompt-state-changed.js.map +1 -0
  130. package/dist/server/modules/events/catalog/session.provider-session-id.discovered.d.ts +2 -2
  131. package/dist/server/modules/events/catalog/session.recommendation.d.ts +4 -4
  132. package/dist/server/modules/events/catalog/session.restored.d.ts +2 -2
  133. package/dist/server/modules/events/catalog/session.started.d.ts +2 -2
  134. package/dist/server/modules/events/catalog/session.starting.d.ts +2 -2
  135. package/dist/server/modules/events/catalog/session.stopped.d.ts +2 -2
  136. package/dist/server/modules/events/catalog/session.transcript.discovered.d.ts +4 -4
  137. package/dist/server/modules/events/catalog/team.config.updated.d.ts +6 -6
  138. package/dist/server/modules/events/catalog/team.member.added.d.ts +2 -2
  139. package/dist/server/modules/events/catalog/team.member.removed.d.ts +2 -2
  140. package/dist/server/modules/events/catalog/terminal.watcher.triggered.d.ts +4 -4
  141. package/dist/server/modules/events/events-core.module.js +8 -1
  142. package/dist/server/modules/events/events-core.module.js.map +1 -1
  143. package/dist/server/modules/events/events-infra.module.js +6 -1
  144. package/dist/server/modules/events/events-infra.module.js.map +1 -1
  145. package/dist/server/modules/events/services/committed-event.store.d.ts +23 -0
  146. package/dist/server/modules/events/services/committed-event.store.js +169 -0
  147. package/dist/server/modules/events/services/committed-event.store.js.map +1 -0
  148. package/dist/server/modules/events/services/durable-event-dispatcher.service.d.ts +16 -0
  149. package/dist/server/modules/events/services/durable-event-dispatcher.service.js +97 -0
  150. package/dist/server/modules/events/services/durable-event-dispatcher.service.js.map +1 -0
  151. package/dist/server/modules/events/services/durable-event-registry.service.d.ts +25 -0
  152. package/dist/server/modules/events/services/durable-event-registry.service.js +59 -0
  153. package/dist/server/modules/events/services/durable-event-registry.service.js.map +1 -0
  154. package/dist/server/modules/events/services/event-log.service.d.ts +6 -1
  155. package/dist/server/modules/events/services/event-log.service.js +32 -18
  156. package/dist/server/modules/events/services/event-log.service.js.map +1 -1
  157. package/dist/server/modules/events/services/events.service.d.ts +11 -1
  158. package/dist/server/modules/events/services/events.service.js +50 -7
  159. package/dist/server/modules/events/services/events.service.js.map +1 -1
  160. package/dist/server/modules/external-integrations/adapters/clickup-external-task.provider.d.ts +97 -0
  161. package/dist/server/modules/external-integrations/adapters/clickup-external-task.provider.js +1404 -0
  162. package/dist/server/modules/external-integrations/adapters/clickup-external-task.provider.js.map +1 -0
  163. package/dist/server/modules/external-integrations/adapters/jira-external-task.provider.d.ts +113 -0
  164. package/dist/server/modules/external-integrations/adapters/jira-external-task.provider.js +1790 -0
  165. package/dist/server/modules/external-integrations/adapters/jira-external-task.provider.js.map +1 -0
  166. package/dist/server/modules/external-integrations/adapters/rich/clickup-comment-converter.d.ts +10 -0
  167. package/dist/server/modules/external-integrations/adapters/rich/clickup-comment-converter.js +97 -0
  168. package/dist/server/modules/external-integrations/adapters/rich/clickup-comment-converter.js.map +1 -0
  169. package/dist/server/modules/external-integrations/adapters/rich/clickup-markdown-converter.d.ts +16 -0
  170. package/dist/server/modules/external-integrations/adapters/rich/clickup-markdown-converter.js +386 -0
  171. package/dist/server/modules/external-integrations/adapters/rich/clickup-markdown-converter.js.map +1 -0
  172. package/dist/server/modules/external-integrations/adapters/rich/jira-adf-converter.d.ts +5 -0
  173. package/dist/server/modules/external-integrations/adapters/rich/jira-adf-converter.js +229 -0
  174. package/dist/server/modules/external-integrations/adapters/rich/jira-adf-converter.js.map +1 -0
  175. package/dist/server/modules/external-integrations/adapters/vendor-shared.d.ts +42 -0
  176. package/dist/server/modules/external-integrations/adapters/vendor-shared.js +182 -0
  177. package/dist/server/modules/external-integrations/adapters/vendor-shared.js.map +1 -0
  178. package/dist/server/modules/external-integrations/connections/integration-connections.controller.d.ts +11 -0
  179. package/dist/server/modules/external-integrations/connections/integration-connections.controller.js +121 -0
  180. package/dist/server/modules/external-integrations/connections/integration-connections.controller.js.map +1 -0
  181. package/dist/server/modules/external-integrations/connections/integration-connections.service.d.ts +46 -0
  182. package/dist/server/modules/external-integrations/connections/integration-connections.service.js +193 -0
  183. package/dist/server/modules/external-integrations/connections/integration-connections.service.js.map +1 -0
  184. package/dist/server/modules/external-integrations/connections/managed-subtask-sync.controller.d.ts +8 -0
  185. package/dist/server/modules/external-integrations/connections/managed-subtask-sync.controller.js +73 -0
  186. package/dist/server/modules/external-integrations/connections/managed-subtask-sync.controller.js.map +1 -0
  187. package/dist/server/modules/external-integrations/errors/external-provider.errors.d.ts +23 -0
  188. package/dist/server/modules/external-integrations/errors/external-provider.errors.js +105 -0
  189. package/dist/server/modules/external-integrations/errors/external-provider.errors.js.map +1 -0
  190. package/dist/server/modules/external-integrations/external-integrations.module.d.ts +2 -0
  191. package/dist/server/modules/external-integrations/external-integrations.module.js +72 -0
  192. package/dist/server/modules/external-integrations/external-integrations.module.js.map +1 -0
  193. package/dist/server/modules/external-integrations/external-task-provider.registry.d.ts +12 -0
  194. package/dist/server/modules/external-integrations/external-task-provider.registry.js +65 -0
  195. package/dist/server/modules/external-integrations/external-task-provider.registry.js.map +1 -0
  196. package/dist/server/modules/external-integrations/models/external-comment-lookup-token.d.ts +12 -0
  197. package/dist/server/modules/external-integrations/models/external-comment-lookup-token.js +49 -0
  198. package/dist/server/modules/external-integrations/models/external-comment-lookup-token.js.map +1 -0
  199. package/dist/server/modules/external-integrations/models/external-edit-session.models.d.ts +94 -0
  200. package/dist/server/modules/external-integrations/models/external-edit-session.models.js +10 -0
  201. package/dist/server/modules/external-integrations/models/external-edit-session.models.js.map +1 -0
  202. package/dist/server/modules/external-integrations/models/external-provider.models.d.ts +341 -0
  203. package/dist/server/modules/external-integrations/models/external-provider.models.js +21 -0
  204. package/dist/server/modules/external-integrations/models/external-provider.models.js.map +1 -0
  205. package/dist/server/modules/external-integrations/models/external-rich-capabilities.d.ts +6 -0
  206. package/dist/server/modules/external-integrations/models/external-rich-capabilities.js +9 -0
  207. package/dist/server/modules/external-integrations/models/external-rich-capabilities.js.map +1 -0
  208. package/dist/server/modules/external-integrations/models/external-rich-document.d.ts +59 -0
  209. package/dist/server/modules/external-integrations/models/external-rich-document.js +233 -0
  210. package/dist/server/modules/external-integrations/models/external-rich-document.js.map +1 -0
  211. package/dist/server/modules/external-integrations/models/external-task-source.d.ts +4 -0
  212. package/dist/server/modules/external-integrations/models/external-task-source.js +71 -0
  213. package/dist/server/modules/external-integrations/models/external-task-source.js.map +1 -0
  214. package/dist/server/modules/external-integrations/models/external-time-mutation.models.d.ts +74 -0
  215. package/dist/server/modules/external-integrations/models/external-time-mutation.models.js +19 -0
  216. package/dist/server/modules/external-integrations/models/external-time-mutation.models.js.map +1 -0
  217. package/dist/server/modules/external-integrations/my-work/external-edit-session.service.d.ts +57 -0
  218. package/dist/server/modules/external-integrations/my-work/external-edit-session.service.js +776 -0
  219. package/dist/server/modules/external-integrations/my-work/external-edit-session.service.js.map +1 -0
  220. package/dist/server/modules/external-integrations/my-work/external-my-work.controller.d.ts +37 -0
  221. package/dist/server/modules/external-integrations/my-work/external-my-work.controller.js +626 -0
  222. package/dist/server/modules/external-integrations/my-work/external-my-work.controller.js.map +1 -0
  223. package/dist/server/modules/external-integrations/my-work/external-my-work.openapi.d.ts +29 -0
  224. package/dist/server/modules/external-integrations/my-work/external-my-work.openapi.js +847 -0
  225. package/dist/server/modules/external-integrations/my-work/external-my-work.openapi.js.map +1 -0
  226. package/dist/server/modules/external-integrations/my-work/external-my-work.service.d.ts +34 -0
  227. package/dist/server/modules/external-integrations/my-work/external-my-work.service.js +330 -0
  228. package/dist/server/modules/external-integrations/my-work/external-my-work.service.js.map +1 -0
  229. package/dist/server/modules/external-integrations/my-work/external-time-mutation.service.d.ts +27 -0
  230. package/dist/server/modules/external-integrations/my-work/external-time-mutation.service.js +412 -0
  231. package/dist/server/modules/external-integrations/my-work/external-time-mutation.service.js.map +1 -0
  232. package/dist/server/modules/external-integrations/ports/external-task-provider.d.ts +13 -0
  233. package/dist/server/modules/external-integrations/ports/external-task-provider.js +5 -0
  234. package/dist/server/modules/external-integrations/ports/external-task-provider.js.map +1 -0
  235. package/dist/server/modules/external-integrations/request-validation.d.ts +2 -0
  236. package/dist/server/modules/external-integrations/request-validation.js +14 -0
  237. package/dist/server/modules/external-integrations/request-validation.js.map +1 -0
  238. package/dist/server/modules/external-integrations/sessions/external-edit-session.store.d.ts +59 -0
  239. package/dist/server/modules/external-integrations/sessions/external-edit-session.store.js +329 -0
  240. package/dist/server/modules/external-integrations/sessions/external-edit-session.store.js.map +1 -0
  241. package/dist/server/modules/external-integrations/sessions/external-time-mutation.store.d.ts +44 -0
  242. package/dist/server/modules/external-integrations/sessions/external-time-mutation.store.js +171 -0
  243. package/dist/server/modules/external-integrations/sessions/external-time-mutation.store.js.map +1 -0
  244. package/dist/server/modules/external-integrations/sessions/provider-operation-gate.d.ts +7 -0
  245. package/dist/server/modules/external-integrations/sessions/provider-operation-gate.js +33 -0
  246. package/dist/server/modules/external-integrations/sessions/provider-operation-gate.js.map +1 -0
  247. package/dist/server/modules/external-integrations/subscribers/external-subtask-sync.subscriber.d.ts +69 -0
  248. package/dist/server/modules/external-integrations/subscribers/external-subtask-sync.subscriber.js +1092 -0
  249. package/dist/server/modules/external-integrations/subscribers/external-subtask-sync.subscriber.js.map +1 -0
  250. package/dist/server/modules/external-integrations/subscribers/managed-subtask-content.d.ts +8 -0
  251. package/dist/server/modules/external-integrations/subscribers/managed-subtask-content.js +23 -0
  252. package/dist/server/modules/external-integrations/subscribers/managed-subtask-content.js.map +1 -0
  253. package/dist/server/modules/external-integrations/subscribers/managed-subtask-recovery-policy.d.ts +7 -0
  254. package/dist/server/modules/external-integrations/subscribers/managed-subtask-recovery-policy.js +30 -0
  255. package/dist/server/modules/external-integrations/subscribers/managed-subtask-recovery-policy.js.map +1 -0
  256. package/dist/server/modules/external-integrations/subscribers/managed-subtask-sync-health.service.d.ts +44 -0
  257. package/dist/server/modules/external-integrations/subscribers/managed-subtask-sync-health.service.js +135 -0
  258. package/dist/server/modules/external-integrations/subscribers/managed-subtask-sync-health.service.js.map +1 -0
  259. package/dist/server/modules/external-integrations/transport/safe-vendor-http-client.d.ts +47 -0
  260. package/dist/server/modules/external-integrations/transport/safe-vendor-http-client.js +294 -0
  261. package/dist/server/modules/external-integrations/transport/safe-vendor-http-client.js.map +1 -0
  262. package/dist/server/modules/hooks/dtos/hook-event.dto.d.ts +64 -64
  263. package/dist/server/modules/mcp/dtos/mcp.dto.d.ts +36 -36
  264. package/dist/server/modules/orchestrator/docker/services/seed-preparation.service.d.ts +5 -0
  265. package/dist/server/modules/orchestrator/docker/services/seed-preparation.service.js +51 -1
  266. package/dist/server/modules/orchestrator/docker/services/seed-preparation.service.js.map +1 -1
  267. package/dist/server/modules/orchestrator/sync/services/task-merge.service.d.ts +0 -2
  268. package/dist/server/modules/orchestrator/sync/services/task-merge.service.js +9 -48
  269. package/dist/server/modules/orchestrator/sync/services/task-merge.service.js.map +1 -1
  270. package/dist/server/modules/profiles/dto.d.ts +11 -11
  271. package/dist/server/modules/projects/controllers/projects.controller.d.ts +2 -2
  272. package/dist/server/modules/projects/dtos/export.dto.d.ts +6 -6
  273. package/dist/server/modules/projects/helpers/project-export.d.ts +1 -1
  274. package/dist/server/modules/projects/services/projects.service.d.ts +1 -1
  275. package/dist/server/modules/projects/template-codec/codecs/watchers.codec.d.ts +1 -1
  276. package/dist/server/modules/registry/controllers/templates.controller.d.ts +7 -7
  277. package/dist/server/modules/reviews/dtos/review.dto.d.ts +10 -10
  278. package/dist/server/modules/scheduled-epics/dtos/scheduled-epic.dto.d.ts +1 -1
  279. package/dist/server/modules/session-reader/adapters/antigravity-session-reader.adapter.d.ts +1 -1
  280. package/dist/server/modules/session-reader/adapters/opencode-session-reader.adapter.d.ts +1 -1
  281. package/dist/server/modules/session-reader/data/pricing.json +128 -39
  282. package/dist/server/modules/session-terminal-runtime/session-terminal-runtime.service.d.ts +2 -0
  283. package/dist/server/modules/session-terminal-runtime/session-terminal-runtime.service.js +18 -12
  284. package/dist/server/modules/session-terminal-runtime/session-terminal-runtime.service.js.map +1 -1
  285. package/dist/server/modules/sessions/controllers/sessions.controller.d.ts +3 -0
  286. package/dist/server/modules/sessions/controllers/sessions.controller.js +30 -0
  287. package/dist/server/modules/sessions/controllers/sessions.controller.js.map +1 -1
  288. package/dist/server/modules/sessions/dtos/sessions.dto.d.ts +2 -2
  289. package/dist/server/modules/sessions/services/message-enqueue.service.d.ts +2 -0
  290. package/dist/server/modules/sessions/services/message-enqueue.service.js +2 -0
  291. package/dist/server/modules/sessions/services/message-enqueue.service.js.map +1 -1
  292. package/dist/server/modules/sessions/services/message-pool.types.d.ts +8 -1
  293. package/dist/server/modules/sessions/services/sessions-message-pool.service.d.ts +50 -6
  294. package/dist/server/modules/sessions/services/sessions-message-pool.service.js +828 -190
  295. package/dist/server/modules/sessions/services/sessions-message-pool.service.js.map +1 -1
  296. package/dist/server/modules/settings/dtos/settings.dto.d.ts +8 -0
  297. package/dist/server/modules/settings/dtos/settings.dto.js +1 -0
  298. package/dist/server/modules/settings/dtos/settings.dto.js.map +1 -1
  299. package/dist/server/modules/settings/local/delegates/core-settings.delegate.js +12 -0
  300. package/dist/server/modules/settings/local/delegates/core-settings.delegate.js.map +1 -1
  301. package/dist/server/modules/settings/services/settings.constants.d.ts +1 -1
  302. package/dist/server/modules/settings/services/settings.constants.js +2 -1
  303. package/dist/server/modules/settings/services/settings.constants.js.map +1 -1
  304. package/dist/server/modules/settings/services/settings.service.d.ts +1 -1
  305. package/dist/server/modules/settings/services/settings.service.js +2 -1
  306. package/dist/server/modules/settings/services/settings.service.js.map +1 -1
  307. package/dist/server/modules/skills/dtos/skill.dto.d.ts +2 -2
  308. package/dist/server/modules/storage/db/schema.d.ts +2420 -958
  309. package/dist/server/modules/storage/db/schema.js +144 -2
  310. package/dist/server/modules/storage/db/schema.js.map +1 -1
  311. package/dist/server/modules/storage/interfaces/storage.interface.d.ts +34 -6
  312. package/dist/server/modules/storage/interfaces/storage.interface.js.map +1 -1
  313. package/dist/server/modules/storage/local/delegates/epic.delegate.d.ts +9 -5
  314. package/dist/server/modules/storage/local/delegates/epic.delegate.js +67 -30
  315. package/dist/server/modules/storage/local/delegates/epic.delegate.js.map +1 -1
  316. package/dist/server/modules/storage/local/delegates/external-managed-subtask.delegate.d.ts +18 -0
  317. package/dist/server/modules/storage/local/delegates/external-managed-subtask.delegate.js +320 -0
  318. package/dist/server/modules/storage/local/delegates/external-managed-subtask.delegate.js.map +1 -0
  319. package/dist/server/modules/storage/local/delegates/integration.delegate.d.ts +37 -0
  320. package/dist/server/modules/storage/local/delegates/integration.delegate.js +308 -0
  321. package/dist/server/modules/storage/local/delegates/integration.delegate.js.map +1 -0
  322. package/dist/server/modules/storage/local/integration-credential-cipher.d.ts +18 -0
  323. package/dist/server/modules/storage/local/integration-credential-cipher.js +138 -0
  324. package/dist/server/modules/storage/local/integration-credential-cipher.js.map +1 -0
  325. package/dist/server/modules/storage/local/local-storage.service.d.ts +36 -7
  326. package/dist/server/modules/storage/local/local-storage.service.js +93 -10
  327. package/dist/server/modules/storage/local/local-storage.service.js.map +1 -1
  328. package/dist/server/modules/storage/models/domain.models.d.ts +127 -0
  329. package/dist/server/modules/storage/models/domain.models.js +15 -0
  330. package/dist/server/modules/storage/models/domain.models.js.map +1 -1
  331. package/dist/server/modules/storage/storage.module.js +2 -1
  332. package/dist/server/modules/storage/storage.module.js.map +1 -1
  333. package/dist/server/modules/subscribers/dtos/subscriber.dto.d.ts +1 -1
  334. package/dist/server/modules/terminal/dtos/ws-envelope.dto.d.ts +2 -2
  335. package/dist/server/modules/terminal/gateways/terminal.gateway.d.ts +9 -1
  336. package/dist/server/modules/terminal/gateways/terminal.gateway.js +79 -3
  337. package/dist/server/modules/terminal/gateways/terminal.gateway.js.map +1 -1
  338. package/dist/server/modules/terminal/services/human-prompt-state.service.d.ts +58 -0
  339. package/dist/server/modules/terminal/services/human-prompt-state.service.js +206 -0
  340. package/dist/server/modules/terminal/services/human-prompt-state.service.js.map +1 -0
  341. package/dist/server/modules/terminal/services/terminal-activity.service.js +7 -18
  342. package/dist/server/modules/terminal/services/terminal-activity.service.js.map +1 -1
  343. package/dist/server/modules/terminal/services/terminal-io/delivery.d.ts +2 -1
  344. package/dist/server/modules/terminal/services/terminal-io/delivery.js +77 -33
  345. package/dist/server/modules/terminal/services/terminal-io/delivery.js.map +1 -1
  346. package/dist/server/modules/terminal/services/terminal-io/terminal-io.service.d.ts +14 -5
  347. package/dist/server/modules/terminal/services/terminal-io/terminal-io.service.js +64 -8
  348. package/dist/server/modules/terminal/services/terminal-io/terminal-io.service.js.map +1 -1
  349. package/dist/server/modules/terminal/services/terminal-io/types.d.ts +8 -0
  350. package/dist/server/modules/terminal/services/terminal-key-input/terminal-key-input.facade.d.ts +5 -1
  351. package/dist/server/modules/terminal/services/terminal-key-input/terminal-key-input.facade.js +39 -2
  352. package/dist/server/modules/terminal/services/terminal-key-input/terminal-key-input.facade.js.map +1 -1
  353. package/dist/server/modules/terminal/services/terminal-session/terminal-session-registry.d.ts +3 -1
  354. package/dist/server/modules/terminal/services/terminal-session/terminal-session-registry.js +7 -2
  355. package/dist/server/modules/terminal/services/terminal-session/terminal-session-registry.js.map +1 -1
  356. package/dist/server/modules/terminal/services/terminal-session/terminal-session.d.ts +4 -0
  357. package/dist/server/modules/terminal/services/terminal-session/terminal-session.js +8 -0
  358. package/dist/server/modules/terminal/services/terminal-session/terminal-session.js.map +1 -1
  359. package/dist/server/modules/terminal/terminal-delivery.module.js +13 -2
  360. package/dist/server/modules/terminal/terminal-delivery.module.js.map +1 -1
  361. package/dist/server/modules/terminal/terminal.module.js +4 -3
  362. package/dist/server/modules/terminal/terminal.module.js.map +1 -1
  363. package/dist/server/modules/terminal/utils/terminal-activity.d.ts +4 -0
  364. package/dist/server/modules/terminal/utils/terminal-activity.js +86 -0
  365. package/dist/server/modules/terminal/utils/terminal-activity.js.map +1 -0
  366. package/dist/server/modules/watchers/dtos/watcher.dto.d.ts +8 -8
  367. package/dist/server/templates/teams-dev.json +9 -9
  368. package/dist/server/tsconfig.tsbuildinfo +1 -1
  369. package/dist/server/ui/assets/ExternalRichEditor-DMtnZIMZ.js +113 -0
  370. package/dist/server/ui/assets/{ReviewDetailPage-CNffXKv8.js → ReviewDetailPage-BmyiM5IR.js} +1 -1
  371. package/dist/server/ui/assets/{ReviewsPage-DAcufZ3r.js → ReviewsPage-CQ87BMwT.js} +1 -1
  372. package/dist/server/ui/assets/index-BX6Yze-A.js +1177 -0
  373. package/dist/server/ui/assets/index-qoQEv_u4.css +32 -0
  374. package/dist/server/ui/assets/{useReviewSubscription-DD29I7uU.js → useReviewSubscription-DjbEUzt4.js} +1 -1
  375. package/dist/server/ui/index.html +2 -2
  376. package/dist/templates/teams-dev.json +9 -9
  377. package/package.json +15 -4
  378. package/dist/server/ui/assets/index-7iCs8Dxj.js +0 -1153
  379. package/dist/server/ui/assets/index-CLXZjL_B.css +0 -32
@@ -0,0 +1,1092 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.ExternalSubtaskSyncSubscriber = exports.MANAGED_SUBTASK_DELIVERY_KEY = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const node_crypto_1 = require("node:crypto");
18
+ const error_types_1 = require("../../../common/errors/error-types");
19
+ const logger_1 = require("../../../common/logging/logger");
20
+ const events_service_1 = require("../../events/services/events.service");
21
+ const storage_interface_1 = require("../../storage/interfaces/storage.interface");
22
+ const external_provider_errors_1 = require("../errors/external-provider.errors");
23
+ const external_task_provider_registry_1 = require("../external-task-provider.registry");
24
+ const external_task_source_1 = require("../models/external-task-source");
25
+ const provider_operation_gate_1 = require("../sessions/provider-operation-gate");
26
+ const managed_subtask_recovery_policy_1 = require("./managed-subtask-recovery-policy");
27
+ const managed_subtask_content_1 = require("./managed-subtask-content");
28
+ const logger = (0, logger_1.createLogger)('ExternalSubtaskSyncSubscriber');
29
+ exports.MANAGED_SUBTASK_DELIVERY_KEY = 'managed-subtask-sync';
30
+ const RETRY_DELAY_MS = 30_000;
31
+ let ExternalSubtaskSyncSubscriber = class ExternalSubtaskSyncSubscriber {
32
+ storage;
33
+ events;
34
+ providers;
35
+ providerGate;
36
+ unregister;
37
+ projectionTails = new Map();
38
+ constructor(storage, events, providers, providerGate) {
39
+ this.storage = storage;
40
+ this.events = events;
41
+ this.providers = providers;
42
+ this.providerGate = providerGate;
43
+ }
44
+ onModuleInit() {
45
+ this.unregister = this.events.registerDurableSubscriber({
46
+ deliveryKey: exports.MANAGED_SUBTASK_DELIVERY_KEY,
47
+ ordered: false,
48
+ eventNames: [
49
+ 'epic.created',
50
+ 'epic.updated',
51
+ 'epic.deleted',
52
+ 'integration.connection.created',
53
+ 'integration.connection.updated',
54
+ 'integration.connection.deleted',
55
+ ],
56
+ handle: (event) => this.handleCommittedEvent(event),
57
+ });
58
+ }
59
+ onModuleDestroy() {
60
+ this.unregister?.();
61
+ this.unregister = undefined;
62
+ }
63
+ async handleCommittedEvent(event) {
64
+ let results = [];
65
+ if (event.name === 'epic.created' ||
66
+ event.name === 'epic.updated' ||
67
+ event.name === 'epic.deleted') {
68
+ const epicId = event.payload.epicId;
69
+ results = await this.reconcileEpic(epicId);
70
+ }
71
+ else if (event.name === 'integration.connection.created' ||
72
+ event.name === 'integration.connection.updated') {
73
+ const provider = event.payload.provider;
74
+ results = await this.reconcileProvider(provider);
75
+ }
76
+ else if (event.name === 'integration.connection.deleted') {
77
+ const provider = event.payload.provider;
78
+ results = await this.projectDisconnected(provider);
79
+ }
80
+ const retryCount = results.filter((result) => result.outcome === 'retry').length;
81
+ if (retryCount > 0) {
82
+ throw new Error(`Managed subtask reconciliation has ${retryCount} retryable projection(s).`);
83
+ }
84
+ }
85
+ async reconcileEpic(epicId, providerFilter) {
86
+ const allExisting = await this.storage.listExternalManagedSubtaskLinksForEpicSnapshot(epicId);
87
+ const existing = allExisting.filter((row) => !providerFilter || row.provider === providerFilter);
88
+ const epic = await this.loadEpicOrNull(epicId);
89
+ const desired = epic?.parentId
90
+ ? await this.desiredProjections(epic, providerFilter)
91
+ : new Map();
92
+ const results = [];
93
+ const obsolete = existing.filter((row) => !desired.has(row.parentSourceLinkIdSnapshot));
94
+ const current = existing.filter((row) => desired.has(row.parentSourceLinkIdSnapshot));
95
+ const obsoleteIds = new Set(obsolete.map((row) => row.id));
96
+ const replacementBlockedProviders = new Set();
97
+ for (const row of [...obsolete, ...current]) {
98
+ const result = await this.withProjectionLock(row.id, () => this.reconcileExisting(row, epic, desired.get(row.parentSourceLinkIdSnapshot) ?? null));
99
+ results.push(result);
100
+ if (obsoleteIds.has(row.id) &&
101
+ (result.outcome === 'retry' || result.outcome === 'needs_attention')) {
102
+ replacementBlockedProviders.add(row.provider);
103
+ }
104
+ }
105
+ if (!epic?.parentId) {
106
+ return results;
107
+ }
108
+ const ordinaryLinks = await this.storage.listExternalTaskLinksForEpic(epic.id);
109
+ for (const link of ordinaryLinks) {
110
+ const belongsToExistingManagedProjection = allExisting.some((row) => row.epicIdSnapshot === epic.id &&
111
+ row.provider === link.provider &&
112
+ row.remoteScopeKey === link.remoteScopeKey &&
113
+ row.remoteTaskId === link.remoteTaskId);
114
+ if (belongsToExistingManagedProjection) {
115
+ continue;
116
+ }
117
+ const result = {
118
+ epicId: epic.id,
119
+ provider: link.provider,
120
+ managedLinkId: null,
121
+ outcome: 'already_remote_unmanaged',
122
+ reason: 'ordinary_link_is_not_managed',
123
+ };
124
+ logger.info(result, 'Skipped managed projection for an imported remote task');
125
+ results.push(result);
126
+ return results;
127
+ }
128
+ const existingSourceIds = new Set(existing.map((row) => row.parentSourceLinkIdSnapshot));
129
+ for (const projection of desired.values()) {
130
+ if (existingSourceIds.has(projection.parentSource.id)) {
131
+ continue;
132
+ }
133
+ if (replacementBlockedProviders.has(projection.parentSource.provider)) {
134
+ continue;
135
+ }
136
+ const created = await this.createManagedProjection(projection);
137
+ results.push(await this.withProjectionLock(created.id, () => this.reconcileExisting(created, epic, projection)));
138
+ }
139
+ return results;
140
+ }
141
+ async reconcileProvider(provider) {
142
+ const results = [];
143
+ const existing = await this.storage.listExternalManagedSubtaskLinksByProvider(provider);
144
+ const processedEpicIds = new Set();
145
+ for (const row of existing) {
146
+ if (processedEpicIds.has(row.epicIdSnapshot)) {
147
+ continue;
148
+ }
149
+ processedEpicIds.add(row.epicIdSnapshot);
150
+ results.push(...(await this.reconcileEpic(row.epicIdSnapshot, provider)));
151
+ }
152
+ let projectOffset = 0;
153
+ while (true) {
154
+ const projects = await this.storage.listProjects({ limit: 500, offset: projectOffset });
155
+ for (const project of projects.items) {
156
+ if (project.isTemplate) {
157
+ continue;
158
+ }
159
+ let offset = 0;
160
+ while (true) {
161
+ const page = await this.storage.listProjectEpics(project.id, {
162
+ type: 'all',
163
+ limit: 500,
164
+ offset,
165
+ });
166
+ for (const epic of page.items) {
167
+ if (epic.parentId && !processedEpicIds.has(epic.id)) {
168
+ processedEpicIds.add(epic.id);
169
+ results.push(...(await this.reconcileEpic(epic.id, provider)));
170
+ }
171
+ }
172
+ offset += page.items.length;
173
+ if (page.items.length === 0 || offset >= page.total) {
174
+ break;
175
+ }
176
+ }
177
+ }
178
+ projectOffset += projects.items.length;
179
+ if (projects.items.length === 0 || projectOffset >= projects.total) {
180
+ break;
181
+ }
182
+ }
183
+ return results;
184
+ }
185
+ async reconcileManagedLink(id) {
186
+ return this.withProjectionLock(id, async () => {
187
+ const row = await this.storage.getExternalManagedSubtaskLink(id);
188
+ const epic = await this.loadEpicOrNull(row.epicIdSnapshot);
189
+ const desired = epic?.parentId
190
+ ? await this.desiredProjections(epic, row.provider)
191
+ : new Map();
192
+ return this.reconcileExisting(row, epic, desired.get(row.parentSourceLinkIdSnapshot) ?? null);
193
+ });
194
+ }
195
+ async verifyManagedLink(id) {
196
+ const row = await this.storage.getExternalManagedSubtaskLink(id);
197
+ if (row.operationPhase === 'dispatch_admitted' ||
198
+ row.operationPhase === 'outcome_unknown' ||
199
+ row.operationPhase === 'needs_attention') {
200
+ await this.storage.updateExternalManagedSubtaskLink(id, {
201
+ operationPhase: 'outcome_unknown',
202
+ retryAt: null,
203
+ });
204
+ }
205
+ return this.reconcileManagedLink(id);
206
+ }
207
+ async retryManagedLink(id) {
208
+ const row = await this.storage.getExternalManagedSubtaskLink(id);
209
+ const decision = (0, managed_subtask_recovery_policy_1.managedSubtaskRetryDecision)(row);
210
+ if (!decision.allowed) {
211
+ throw new error_types_1.ConflictError(decision.reason === 'verification_required'
212
+ ? 'Unknown managed-subtask outcomes must be verified before retry.'
213
+ : 'Managed-subtask state does not allow Retry.', {
214
+ managedLinkId: id,
215
+ reason: decision.reason,
216
+ });
217
+ }
218
+ await this.storage.updateExternalManagedSubtaskLink(id, {
219
+ operationPhase: 'pre_dispatch',
220
+ safeErrorCode: null,
221
+ retryAt: null,
222
+ });
223
+ return this.reconcileManagedLink(id);
224
+ }
225
+ async reconcileExisting(original, epic, desired) {
226
+ let row = await this.storage.getExternalManagedSubtaskLink(original.id);
227
+ const connection = await this.storage.getIntegrationConnection(row.provider);
228
+ if (!connection?.subtaskSyncEnabled) {
229
+ return this.result(row, 'paused', connection ? 'sync_disabled' : 'connection_missing');
230
+ }
231
+ row = await this.refreshConnectionFence(row, connection);
232
+ const safeAbsentProjection = !row.remoteTaskId &&
233
+ (row.operationPhase === 'pre_dispatch' ||
234
+ (row.operationPhase === 'needs_attention' &&
235
+ row.safeErrorCode?.startsWith('provider_') === true));
236
+ if ((!epic || !desired) && safeAbsentProjection) {
237
+ await this.storage.removeExternalManagedSubtaskLink(row.id);
238
+ return this.result(row, 'deleted');
239
+ }
240
+ if (row.operationPhase === 'needs_attention' || row.tombstoneState === 'orphan_risk') {
241
+ return this.result(row, 'needs_attention', row.safeErrorCode ?? 'needs_attention');
242
+ }
243
+ if (this.retryIsInFuture(row.retryAt)) {
244
+ return this.result(row, 'retry', row.safeErrorCode ?? 'retry_scheduled');
245
+ }
246
+ if (row.operationPhase === 'dispatch_admitted') {
247
+ row = await this.storage.updateExternalManagedSubtaskLink(row.id, {
248
+ operationPhase: 'outcome_unknown',
249
+ safeErrorCode: 'recovered_dispatched_operation',
250
+ });
251
+ }
252
+ if (!epic || !desired) {
253
+ const tombstoneState = epic ? 'move_out' : 'local_deleted';
254
+ if (row.operationPhase === 'outcome_unknown' && !row.remoteTaskId) {
255
+ return this.resolveUnknownCreateForRemoval(row, tombstoneState);
256
+ }
257
+ row = await this.storage.updateExternalManagedSubtaskLink(row.id, {
258
+ tombstoneState,
259
+ tombstonedAt: row.tombstonedAt ?? new Date().toISOString(),
260
+ });
261
+ return this.deleteProjection(row);
262
+ }
263
+ const versionOnlyChange = row.operationPhase === 'confirmed' &&
264
+ row.remoteTaskId !== null &&
265
+ row.confirmedFingerprint === desired.desiredFingerprint &&
266
+ row.desiredFingerprint === desired.desiredFingerprint;
267
+ let confirmationUpdate = {};
268
+ if (versionOnlyChange) {
269
+ confirmationUpdate = {
270
+ confirmedVersion: epic.version,
271
+ confirmedFingerprint: desired.desiredFingerprint,
272
+ };
273
+ }
274
+ else if (row.operationPhase === 'confirmed') {
275
+ confirmationUpdate = { operationPhase: 'pre_dispatch' };
276
+ }
277
+ const desiredChanged = row.desiredVersion !== epic.version ||
278
+ row.desiredFingerprint !== desired.desiredFingerprint ||
279
+ row.connectionIdSnapshot !== connection.id ||
280
+ row.connectionGeneration !== connection.generation ||
281
+ row.syncSettingRevision !== connection.syncSettingRevision;
282
+ if (desiredChanged) {
283
+ row = await this.storage.updateExternalManagedSubtaskLink(row.id, {
284
+ connectionIdSnapshot: connection.id,
285
+ connectionGeneration: connection.generation,
286
+ syncSettingRevision: connection.syncSettingRevision,
287
+ desiredVersion: epic.version,
288
+ desiredFingerprint: desired.desiredFingerprint,
289
+ ...confirmationUpdate,
290
+ safeErrorCode: null,
291
+ retryAt: null,
292
+ });
293
+ }
294
+ if (row.operationPhase === 'outcome_unknown') {
295
+ return this.resolveUnknown(row, epic, desired);
296
+ }
297
+ if (!row.remoteTaskId) {
298
+ return this.createProjection(row, epic, desired);
299
+ }
300
+ if (row.operationPhase === 'confirmed' &&
301
+ row.confirmedVersion === row.desiredVersion &&
302
+ row.confirmedFingerprint === row.desiredFingerprint) {
303
+ const recognized = await this.storage.findRecognizedManagedSubtask(row.epicIdSnapshot, row.provider, row.remoteScopeKey, row.remoteTaskId);
304
+ if (recognized) {
305
+ return this.result(row, 'unchanged');
306
+ }
307
+ return this.repairRecognition(row, epic, desired);
308
+ }
309
+ return this.updateProjection(row, epic, desired);
310
+ }
311
+ async createProjection(row, epic, desired) {
312
+ const admission = await this.admitMutation(row);
313
+ if (!admission) {
314
+ return this.result(row, 'retry', 'admission_changed');
315
+ }
316
+ try {
317
+ const snapshot = await admission.capability.create(admission.credentials, admission.context, {
318
+ parentRemoteTaskId: row.parentRemoteTaskId,
319
+ ownershipToken: row.ownershipToken,
320
+ title: epic.title,
321
+ description: epic.description,
322
+ });
323
+ if (!(await this.fenceStillCurrent(admission.connection))) {
324
+ await this.markUnknown(row, 'connection_changed_after_dispatch');
325
+ return this.result(row, 'retry', 'connection_changed_after_dispatch');
326
+ }
327
+ this.assertOwnedSnapshot(row, snapshot);
328
+ const confirmed = await this.storage.confirmExternalManagedSubtaskLink({
329
+ managedLinkId: row.id,
330
+ remoteTaskId: snapshot.remoteTaskId,
331
+ remoteKey: snapshot.remoteKey,
332
+ confirmedVersion: row.desiredVersion,
333
+ confirmedFingerprint: row.desiredFingerprint,
334
+ sourceSnapshot: this.sourceSnapshot(row, desired, snapshot, admission.credentials),
335
+ });
336
+ return this.result(confirmed.managedLink, 'confirmed');
337
+ }
338
+ catch (error) {
339
+ return this.persistPostAdmissionFailure(row, error);
340
+ }
341
+ }
342
+ async updateProjection(row, epic, desired) {
343
+ if (!row.remoteTaskId) {
344
+ return this.createProjection(row, epic, desired);
345
+ }
346
+ const ownershipFailure = await this.verifyOwnershipBeforeMutation(row);
347
+ if (ownershipFailure) {
348
+ return ownershipFailure;
349
+ }
350
+ const admission = await this.admitMutation(row);
351
+ if (!admission) {
352
+ return this.result(row, 'retry', 'admission_changed');
353
+ }
354
+ try {
355
+ await admission.capability.update(admission.credentials, admission.context, {
356
+ remoteTaskId: row.remoteTaskId,
357
+ expectedParentRemoteTaskId: row.parentRemoteTaskId,
358
+ ownershipToken: row.ownershipToken,
359
+ title: epic.title,
360
+ description: epic.description,
361
+ });
362
+ const snapshot = await admission.capability.readExact(admission.credentials, admission.context, row.remoteTaskId);
363
+ if (!(await this.fenceStillCurrent(admission.connection))) {
364
+ await this.markUnknown(row, 'connection_changed_after_dispatch');
365
+ return this.result(row, 'retry', 'connection_changed_after_dispatch');
366
+ }
367
+ if (!snapshot) {
368
+ return this.keepUnknownForRetry(row, 'remote_task_missing_after_update');
369
+ }
370
+ this.assertOwnedSnapshot(row, snapshot);
371
+ if (!(0, managed_subtask_content_1.managedSubtaskContentMatches)(row.provider, snapshot, epic)) {
372
+ return this.keepUnknownForRetry(row, 'remote_verification_mismatch');
373
+ }
374
+ const confirmed = await this.storage.confirmExternalManagedSubtaskLink({
375
+ managedLinkId: row.id,
376
+ remoteTaskId: snapshot.remoteTaskId,
377
+ remoteKey: snapshot.remoteKey,
378
+ confirmedVersion: row.desiredVersion,
379
+ confirmedFingerprint: row.desiredFingerprint,
380
+ sourceSnapshot: this.sourceSnapshot(row, desired, snapshot, admission.credentials),
381
+ });
382
+ return this.result(confirmed.managedLink, 'confirmed');
383
+ }
384
+ catch (error) {
385
+ return this.persistPostAdmissionFailure(row, error);
386
+ }
387
+ }
388
+ async deleteProjection(row) {
389
+ if (!row.remoteTaskId) {
390
+ await this.storage.removeExternalManagedSubtaskLink(row.id);
391
+ return this.result(row, 'deleted');
392
+ }
393
+ const remoteTaskId = row.remoteTaskId;
394
+ if (row.operationPhase === 'dispatch_admitted') {
395
+ row = await this.storage.updateExternalManagedSubtaskLink(row.id, {
396
+ operationPhase: 'outcome_unknown',
397
+ safeErrorCode: 'recovered_dispatched_operation',
398
+ });
399
+ }
400
+ if (row.operationPhase === 'outcome_unknown') {
401
+ return this.resolveUnknownDelete(row);
402
+ }
403
+ const ownershipFailure = await this.verifyOwnershipBeforeMutation(row);
404
+ if (ownershipFailure) {
405
+ return ownershipFailure;
406
+ }
407
+ const admission = await this.admitMutation(row);
408
+ if (!admission) {
409
+ return this.result(row, 'retry', 'admission_changed');
410
+ }
411
+ try {
412
+ await admission.capability.delete(admission.credentials, admission.context, {
413
+ remoteTaskId,
414
+ expectedParentRemoteTaskId: row.parentRemoteTaskId,
415
+ ownershipToken: row.ownershipToken,
416
+ });
417
+ if (!(await this.fenceStillCurrent(admission.connection))) {
418
+ await this.markUnknown(row, 'connection_changed_after_dispatch');
419
+ return this.result(row, 'retry', 'connection_changed_after_dispatch');
420
+ }
421
+ await this.storage.removeExternalManagedSubtaskLink(row.id);
422
+ return this.result(row, 'deleted');
423
+ }
424
+ catch (error) {
425
+ return this.persistPostAdmissionFailure(row, error);
426
+ }
427
+ }
428
+ async resolveUnknown(row, epic, desired) {
429
+ if (!row.remoteTaskId) {
430
+ return this.resolveUnknownCreate(row, epic, desired);
431
+ }
432
+ const access = await this.captureReadAccess(row.provider);
433
+ if (!access) {
434
+ return this.result(row, 'retry', 'verification_unavailable');
435
+ }
436
+ try {
437
+ const snapshot = await access.capability.readExact(access.credentials, access.context, row.remoteTaskId);
438
+ if (!(await this.fenceStillCurrent(access.connection))) {
439
+ return this.keepUnknownForRetry(row, 'connection_changed_during_verification');
440
+ }
441
+ if (!snapshot) {
442
+ return this.markNeedsAttention(row, 'remote_task_missing_after_unknown_update');
443
+ }
444
+ this.assertOwnedSnapshot(row, snapshot);
445
+ if ((0, managed_subtask_content_1.managedSubtaskContentMatches)(row.provider, snapshot, epic)) {
446
+ const confirmed = await this.storage.confirmExternalManagedSubtaskLink({
447
+ managedLinkId: row.id,
448
+ remoteTaskId: snapshot.remoteTaskId,
449
+ remoteKey: snapshot.remoteKey,
450
+ confirmedVersion: row.desiredVersion,
451
+ confirmedFingerprint: row.desiredFingerprint,
452
+ sourceSnapshot: this.sourceSnapshot(row, desired, snapshot, access.credentials),
453
+ });
454
+ return this.result(confirmed.managedLink, 'confirmed');
455
+ }
456
+ const retryable = await this.storage.updateExternalManagedSubtaskLink(row.id, {
457
+ operationPhase: 'pre_dispatch',
458
+ safeErrorCode: null,
459
+ retryAt: null,
460
+ });
461
+ return this.updateProjection(retryable, epic, desired);
462
+ }
463
+ catch (error) {
464
+ if (this.isOwnershipFailure(error)) {
465
+ return this.markNeedsAttention(row, this.ownershipFailureCode(error));
466
+ }
467
+ return this.persistVerificationFailure(row, error);
468
+ }
469
+ }
470
+ async resolveUnknownCreate(row, epic, desired) {
471
+ const access = await this.captureReadAccess(row.provider);
472
+ if (!access) {
473
+ return this.result(row, 'retry', 'verification_unavailable');
474
+ }
475
+ let adopted = null;
476
+ let adoptedFingerprint = null;
477
+ let adoptedMatchesDesired = false;
478
+ try {
479
+ const children = await access.capability.listOwnedDirectChildren(access.credentials, access.context, row.parentRemoteTaskId, row.ownershipToken);
480
+ if (!(await this.fenceStillCurrent(access.connection))) {
481
+ return this.keepUnknownForRetry(row, 'connection_changed_during_verification');
482
+ }
483
+ const matches = children.items.filter((item) => item.ownershipToken === row.ownershipToken &&
484
+ item.parentRemoteTaskId === row.parentRemoteTaskId);
485
+ if (matches.length === 1) {
486
+ const snapshot = matches[0];
487
+ this.assertOwnedSnapshot(row, snapshot);
488
+ adoptedMatchesDesired = (0, managed_subtask_content_1.managedSubtaskContentMatches)(row.provider, snapshot, epic);
489
+ adoptedFingerprint = adoptedMatchesDesired
490
+ ? row.desiredFingerprint
491
+ : this.projectionFingerprint(snapshot.title, snapshot.description, row.parentSourceLinkIdSnapshot, row.parentRemoteTaskId);
492
+ const confirmed = await this.storage.confirmExternalManagedSubtaskLink({
493
+ managedLinkId: row.id,
494
+ remoteTaskId: snapshot.remoteTaskId,
495
+ remoteKey: snapshot.remoteKey,
496
+ confirmedVersion: row.desiredVersion,
497
+ confirmedFingerprint: adoptedFingerprint,
498
+ sourceSnapshot: this.sourceSnapshot(row, desired, snapshot, access.credentials),
499
+ });
500
+ adopted = confirmed.managedLink;
501
+ }
502
+ if (!adopted && matches.length === 0 && children.complete) {
503
+ const retryable = await this.storage.updateExternalManagedSubtaskLink(row.id, {
504
+ operationPhase: 'pre_dispatch',
505
+ safeErrorCode: null,
506
+ retryAt: null,
507
+ });
508
+ return this.createProjection(retryable, epic, desired);
509
+ }
510
+ if (!adopted) {
511
+ return this.markNeedsAttention(row, matches.length > 1 ? 'multiple_owned_children' : 'ownership_scan_incomplete');
512
+ }
513
+ }
514
+ catch (error) {
515
+ return this.persistVerificationFailure(row, error);
516
+ }
517
+ if (adoptedMatchesDesired) {
518
+ return this.result(adopted, 'confirmed');
519
+ }
520
+ return this.updateProjection(adopted, epic, desired);
521
+ }
522
+ async resolveUnknownCreateForRemoval(row, tombstoneState) {
523
+ const access = await this.captureReadAccess(row.provider);
524
+ if (!access) {
525
+ return this.result(row, 'retry', 'verification_unavailable');
526
+ }
527
+ try {
528
+ const children = await access.capability.listOwnedDirectChildren(access.credentials, access.context, row.parentRemoteTaskId, row.ownershipToken);
529
+ if (!(await this.fenceStillCurrent(access.connection))) {
530
+ return this.keepUnknownForRetry(row, 'connection_changed_during_verification');
531
+ }
532
+ const matches = children.items.filter((item) => item.ownershipToken === row.ownershipToken &&
533
+ item.parentRemoteTaskId === row.parentRemoteTaskId);
534
+ if (matches.length === 0 && children.complete) {
535
+ await this.storage.removeExternalManagedSubtaskLink(row.id);
536
+ return this.result(row, 'deleted');
537
+ }
538
+ if (matches.length !== 1) {
539
+ return this.markNeedsAttention(row, matches.length > 1 ? 'multiple_owned_children' : 'ownership_scan_incomplete');
540
+ }
541
+ const snapshot = matches[0];
542
+ this.assertOwnedSnapshot(row, snapshot);
543
+ const adopted = await this.storage.updateExternalManagedSubtaskLink(row.id, {
544
+ remoteTaskId: snapshot.remoteTaskId,
545
+ remoteKey: snapshot.remoteKey,
546
+ operationPhase: 'pre_dispatch',
547
+ safeErrorCode: null,
548
+ retryAt: null,
549
+ tombstoneState,
550
+ tombstonedAt: row.tombstonedAt ?? new Date().toISOString(),
551
+ });
552
+ return this.deleteProjection(adopted);
553
+ }
554
+ catch (error) {
555
+ if (this.isOwnershipFailure(error)) {
556
+ return this.markNeedsAttention(row, this.ownershipFailureCode(error));
557
+ }
558
+ return this.persistVerificationFailure(row, error);
559
+ }
560
+ }
561
+ async resolveUnknownDelete(row) {
562
+ if (!row.remoteTaskId) {
563
+ await this.storage.removeExternalManagedSubtaskLink(row.id);
564
+ return this.result(row, 'deleted');
565
+ }
566
+ const access = await this.captureReadAccess(row.provider);
567
+ if (!access) {
568
+ return this.result(row, 'retry', 'verification_unavailable');
569
+ }
570
+ try {
571
+ const snapshot = await access.capability.readExact(access.credentials, access.context, row.remoteTaskId);
572
+ if (!(await this.fenceStillCurrent(access.connection))) {
573
+ return this.keepUnknownForRetry(row, 'connection_changed_during_verification');
574
+ }
575
+ if (!snapshot) {
576
+ await this.storage.removeExternalManagedSubtaskLink(row.id);
577
+ return this.result(row, 'deleted');
578
+ }
579
+ this.assertOwnedSnapshot(row, snapshot);
580
+ const retryable = await this.storage.updateExternalManagedSubtaskLink(row.id, {
581
+ operationPhase: 'pre_dispatch',
582
+ safeErrorCode: null,
583
+ retryAt: null,
584
+ });
585
+ return this.deleteProjection(retryable);
586
+ }
587
+ catch (error) {
588
+ if (this.isOwnershipFailure(error)) {
589
+ return this.markNeedsAttention(row, this.ownershipFailureCode(error));
590
+ }
591
+ return this.persistVerificationFailure(row, error);
592
+ }
593
+ }
594
+ async repairRecognition(row, epic, desired) {
595
+ if (!row.remoteTaskId) {
596
+ return this.createProjection(row, epic, desired);
597
+ }
598
+ const access = await this.captureReadAccess(row.provider);
599
+ if (!access) {
600
+ return this.result(row, 'retry', 'verification_unavailable');
601
+ }
602
+ try {
603
+ const snapshot = await access.capability.readExact(access.credentials, access.context, row.remoteTaskId);
604
+ if (!(await this.fenceStillCurrent(access.connection))) {
605
+ return this.keepUnknownForRetry(row, 'connection_changed_during_verification');
606
+ }
607
+ if (!snapshot) {
608
+ return this.markNeedsAttention(row, 'remote_task_missing');
609
+ }
610
+ this.assertOwnedSnapshot(row, snapshot);
611
+ const repaired = await this.storage.confirmExternalManagedSubtaskLink({
612
+ managedLinkId: row.id,
613
+ remoteTaskId: snapshot.remoteTaskId,
614
+ remoteKey: snapshot.remoteKey,
615
+ confirmedVersion: row.desiredVersion,
616
+ confirmedFingerprint: row.desiredFingerprint,
617
+ sourceSnapshot: this.sourceSnapshot(row, desired, snapshot, access.credentials),
618
+ });
619
+ return this.result(repaired.managedLink, 'confirmed', 'recognition_repaired');
620
+ }
621
+ catch (error) {
622
+ if (this.isOwnershipFailure(error)) {
623
+ return this.markNeedsAttention(row, this.ownershipFailureCode(error));
624
+ }
625
+ return this.persistVerificationFailure(row, error);
626
+ }
627
+ }
628
+ async verifyOwnershipBeforeMutation(row) {
629
+ if (!row.remoteTaskId) {
630
+ return this.markNeedsAttention(row, 'remote_identity_missing');
631
+ }
632
+ const access = await this.captureReadAccess(row.provider);
633
+ if (!access) {
634
+ return this.result(row, 'retry', 'ownership_verification_unavailable');
635
+ }
636
+ try {
637
+ const snapshot = await access.capability.readExact(access.credentials, access.context, row.remoteTaskId);
638
+ if (!(await this.fenceStillCurrent(access.connection))) {
639
+ return this.keepUnknownForRetry(row, 'connection_changed_during_verification');
640
+ }
641
+ if (!snapshot) {
642
+ return this.markNeedsAttention(row, 'remote_task_missing');
643
+ }
644
+ this.assertOwnedSnapshot(row, snapshot);
645
+ return null;
646
+ }
647
+ catch (error) {
648
+ if (this.isOwnershipFailure(error)) {
649
+ return this.markNeedsAttention(row, this.ownershipFailureCode(error));
650
+ }
651
+ return this.persistVerificationFailure(row, error);
652
+ }
653
+ }
654
+ async admitMutation(row) {
655
+ try {
656
+ return await this.providerGate.run(row.provider, async () => {
657
+ const connection = await this.storage.getIntegrationConnection(row.provider);
658
+ if (!connection?.subtaskSyncEnabled ||
659
+ connection.id !== row.connectionIdSnapshot ||
660
+ connection.generation !== row.connectionGeneration ||
661
+ connection.syncSettingRevision !== row.syncSettingRevision) {
662
+ return null;
663
+ }
664
+ const adapter = this.providers.get(row.provider);
665
+ const credentials = await this.storage.getIntegrationConnectionCredentials(row.provider);
666
+ const rechecked = await this.storage.getIntegrationConnection(row.provider);
667
+ if (!adapter.subtaskSync ||
668
+ !credentials ||
669
+ credentials.provider !== row.provider ||
670
+ !rechecked?.subtaskSyncEnabled ||
671
+ rechecked.id !== connection.id ||
672
+ rechecked.generation !== connection.generation ||
673
+ rechecked.syncSettingRevision !== connection.syncSettingRevision) {
674
+ return null;
675
+ }
676
+ await this.storage.updateExternalManagedSubtaskLink(row.id, {
677
+ operationPhase: 'dispatch_admitted',
678
+ safeErrorCode: null,
679
+ retryAt: null,
680
+ });
681
+ return {
682
+ connection,
683
+ credentials,
684
+ capability: adapter.subtaskSync,
685
+ context: this.context(connection),
686
+ };
687
+ });
688
+ }
689
+ catch (error) {
690
+ if (error instanceof error_types_1.BusyError) {
691
+ await this.storage.updateExternalManagedSubtaskLink(row.id, {
692
+ operationPhase: 'pre_dispatch',
693
+ safeErrorCode: 'provider_operation_busy',
694
+ retryAt: new Date(Date.now() + RETRY_DELAY_MS).toISOString(),
695
+ });
696
+ return null;
697
+ }
698
+ throw error;
699
+ }
700
+ }
701
+ async captureReadAccess(provider) {
702
+ try {
703
+ return await this.providerGate.run(provider, async () => {
704
+ const connection = await this.storage.getIntegrationConnection(provider);
705
+ const adapter = this.providers.get(provider);
706
+ const credentials = await this.storage.getIntegrationConnectionCredentials(provider);
707
+ const rechecked = await this.storage.getIntegrationConnection(provider);
708
+ if (!connection?.subtaskSyncEnabled ||
709
+ !adapter.subtaskSync ||
710
+ !credentials ||
711
+ credentials.provider !== provider ||
712
+ !rechecked?.subtaskSyncEnabled ||
713
+ rechecked.id !== connection.id ||
714
+ rechecked.generation !== connection.generation ||
715
+ rechecked.syncSettingRevision !== connection.syncSettingRevision) {
716
+ return null;
717
+ }
718
+ return {
719
+ connection,
720
+ credentials,
721
+ capability: adapter.subtaskSync,
722
+ context: this.context(connection),
723
+ };
724
+ });
725
+ }
726
+ catch (error) {
727
+ if (error instanceof error_types_1.BusyError) {
728
+ return null;
729
+ }
730
+ throw error;
731
+ }
732
+ }
733
+ async refreshConnectionFence(row, connection) {
734
+ if (row.connectionIdSnapshot === connection.id &&
735
+ row.connectionGeneration === connection.generation &&
736
+ row.syncSettingRevision === connection.syncSettingRevision) {
737
+ return row;
738
+ }
739
+ if (!row.remoteTaskId) {
740
+ return this.storage.updateExternalManagedSubtaskLink(row.id, {
741
+ connectionIdSnapshot: connection.id,
742
+ connectionGeneration: connection.generation,
743
+ syncSettingRevision: connection.syncSettingRevision,
744
+ });
745
+ }
746
+ const access = await this.captureReadAccess(row.provider);
747
+ if (!access) {
748
+ return this.storage.updateExternalManagedSubtaskLink(row.id, {
749
+ operationPhase: 'pre_dispatch',
750
+ safeErrorCode: 'connection_fence_verification_pending',
751
+ retryAt: new Date(Date.now() + RETRY_DELAY_MS).toISOString(),
752
+ });
753
+ }
754
+ try {
755
+ const snapshot = await access.capability.readExact(access.credentials, access.context, row.remoteTaskId);
756
+ if (!(await this.fenceStillCurrent(access.connection))) {
757
+ return this.storage.updateExternalManagedSubtaskLink(row.id, {
758
+ operationPhase: 'pre_dispatch',
759
+ safeErrorCode: 'connection_fence_verification_pending',
760
+ retryAt: new Date(Date.now() + RETRY_DELAY_MS).toISOString(),
761
+ });
762
+ }
763
+ if (!snapshot) {
764
+ return this.storage.updateExternalManagedSubtaskLink(row.id, {
765
+ operationPhase: 'needs_attention',
766
+ safeErrorCode: 'connection_generation_changed',
767
+ retryAt: null,
768
+ });
769
+ }
770
+ this.assertOwnedSnapshot(row, snapshot);
771
+ return this.storage.updateExternalManagedSubtaskLink(row.id, {
772
+ connectionIdSnapshot: connection.id,
773
+ connectionGeneration: connection.generation,
774
+ syncSettingRevision: connection.syncSettingRevision,
775
+ safeErrorCode: null,
776
+ retryAt: null,
777
+ });
778
+ }
779
+ catch (error) {
780
+ if (this.isOwnershipFailure(error)) {
781
+ return this.storage.updateExternalManagedSubtaskLink(row.id, {
782
+ operationPhase: 'needs_attention',
783
+ safeErrorCode: this.ownershipFailureCode(error),
784
+ retryAt: null,
785
+ });
786
+ }
787
+ const failure = this.classifyFailure(error);
788
+ return this.storage.updateExternalManagedSubtaskLink(row.id, {
789
+ operationPhase: failure.retry ? 'pre_dispatch' : 'needs_attention',
790
+ safeErrorCode: failure.safeErrorCode,
791
+ retryAt: failure.retryAt,
792
+ });
793
+ }
794
+ }
795
+ async desiredProjections(epic, providerFilter) {
796
+ const result = new Map();
797
+ if (!epic.parentId) {
798
+ return result;
799
+ }
800
+ const sources = await this.storage.listExternalTaskLinksForEpic(epic.parentId);
801
+ for (const source of sources) {
802
+ if (providerFilter && source.provider !== providerFilter) {
803
+ continue;
804
+ }
805
+ const connection = await this.storage.getIntegrationConnection(source.provider);
806
+ if (!connection?.subtaskSyncEnabled ||
807
+ source.connectionId !== connection.id ||
808
+ !this.providers.get(source.provider).subtaskSync) {
809
+ continue;
810
+ }
811
+ const workAreaRemoteId = this.sourceText(source.sourceSnapshot, 'workAreaId');
812
+ if (!workAreaRemoteId) {
813
+ continue;
814
+ }
815
+ result.set(source.id, {
816
+ epic,
817
+ parentSource: source,
818
+ connection,
819
+ workAreaRemoteId,
820
+ desiredFingerprint: this.desiredFingerprint(epic, source),
821
+ });
822
+ }
823
+ return result;
824
+ }
825
+ async createManagedProjection(desired) {
826
+ try {
827
+ return await this.storage.createExternalManagedSubtaskLink({
828
+ epicId: desired.epic.id,
829
+ epicIdSnapshot: desired.epic.id,
830
+ parentEpicIdSnapshot: desired.parentSource.epicId,
831
+ parentSourceLinkIdSnapshot: desired.parentSource.id,
832
+ connectionIdSnapshot: desired.connection.id,
833
+ provider: desired.parentSource.provider,
834
+ remoteScopeKey: desired.parentSource.remoteScopeKey,
835
+ workAreaRemoteId: desired.workAreaRemoteId,
836
+ parentRemoteTaskId: desired.parentSource.remoteTaskId,
837
+ connectionGeneration: desired.connection.generation,
838
+ syncSettingRevision: desired.connection.syncSettingRevision,
839
+ ownershipToken: (0, node_crypto_1.randomUUID)(),
840
+ desiredVersion: desired.epic.version,
841
+ desiredFingerprint: desired.desiredFingerprint,
842
+ });
843
+ }
844
+ catch (error) {
845
+ const existing = (await this.storage.listExternalManagedSubtaskLinksForEpicSnapshot(desired.epic.id)).find((row) => row.parentSourceLinkIdSnapshot === desired.parentSource.id);
846
+ if (existing) {
847
+ return existing;
848
+ }
849
+ throw error;
850
+ }
851
+ }
852
+ async projectDisconnected(provider) {
853
+ const rows = await this.storage.listExternalManagedSubtaskLinksByProvider(provider);
854
+ return Promise.all(rows.map(async (row) => {
855
+ const updated = await this.storage.updateExternalManagedSubtaskLink(row.id, {
856
+ safeErrorCode: 'connection_missing',
857
+ retryAt: null,
858
+ });
859
+ return this.result(updated, 'paused', 'connection_missing');
860
+ }));
861
+ }
862
+ async persistPostAdmissionFailure(row, error) {
863
+ const failure = this.classifyFailure(error);
864
+ const safeErrorCode = this.isOwnershipFailure(error)
865
+ ? this.ownershipFailureCode(error)
866
+ : failure.safeErrorCode === 'unexpected_provider_failure'
867
+ ? 'post_dispatch_local_failure'
868
+ : failure.safeErrorCode;
869
+ const updated = await this.storage.updateExternalManagedSubtaskLink(row.id, {
870
+ operationPhase: 'outcome_unknown',
871
+ safeErrorCode,
872
+ retryAt: failure.retryAt ?? new Date(Date.now() + RETRY_DELAY_MS).toISOString(),
873
+ });
874
+ return this.result(updated, 'retry', safeErrorCode);
875
+ }
876
+ async persistVerificationFailure(row, error) {
877
+ const failure = this.classifyFailure(error);
878
+ if (!failure.retry) {
879
+ return this.markNeedsAttention(row, failure.safeErrorCode);
880
+ }
881
+ const updated = await this.storage.updateExternalManagedSubtaskLink(row.id, {
882
+ operationPhase: 'outcome_unknown',
883
+ safeErrorCode: failure.safeErrorCode,
884
+ retryAt: failure.retryAt,
885
+ });
886
+ return this.result(updated, 'retry', failure.safeErrorCode);
887
+ }
888
+ classifyFailure(error) {
889
+ if (error instanceof external_provider_errors_1.ExternalProviderError) {
890
+ const reason = typeof error.details?.reason === 'string' ? error.details.reason : 'provider_error';
891
+ const retryAt = typeof error.details?.retryAt === 'string'
892
+ ? error.details.retryAt
893
+ : new Date(Date.now() + RETRY_DELAY_MS).toISOString();
894
+ if (error.details?.dispatched === true) {
895
+ return {
896
+ phase: 'outcome_unknown',
897
+ safeErrorCode: `provider_${reason}`,
898
+ retryAt,
899
+ retry: true,
900
+ };
901
+ }
902
+ if (error.details?.retryable === true) {
903
+ return {
904
+ phase: 'pre_dispatch',
905
+ safeErrorCode: `provider_${reason}`,
906
+ retryAt,
907
+ retry: true,
908
+ };
909
+ }
910
+ return {
911
+ phase: 'needs_attention',
912
+ safeErrorCode: `provider_${reason}`,
913
+ retryAt: null,
914
+ retry: false,
915
+ };
916
+ }
917
+ return {
918
+ phase: 'needs_attention',
919
+ safeErrorCode: 'unexpected_provider_failure',
920
+ retryAt: null,
921
+ retry: false,
922
+ };
923
+ }
924
+ async markNeedsAttention(row, reason) {
925
+ const updated = await this.storage.updateExternalManagedSubtaskLink(row.id, {
926
+ operationPhase: 'needs_attention',
927
+ safeErrorCode: reason,
928
+ retryAt: null,
929
+ });
930
+ return this.result(updated, 'needs_attention', reason);
931
+ }
932
+ async markUnknown(row, reason) {
933
+ await this.storage.updateExternalManagedSubtaskLink(row.id, {
934
+ operationPhase: 'outcome_unknown',
935
+ safeErrorCode: reason,
936
+ retryAt: new Date(Date.now() + RETRY_DELAY_MS).toISOString(),
937
+ });
938
+ }
939
+ async keepUnknownForRetry(row, reason) {
940
+ const updated = await this.storage.updateExternalManagedSubtaskLink(row.id, {
941
+ operationPhase: 'outcome_unknown',
942
+ safeErrorCode: reason,
943
+ retryAt: new Date(Date.now() + RETRY_DELAY_MS).toISOString(),
944
+ });
945
+ return this.result(updated, 'retry', reason);
946
+ }
947
+ assertOwnedSnapshot(row, snapshot) {
948
+ if (!snapshot.ownershipToken) {
949
+ throw new Error('ownership_marker_missing');
950
+ }
951
+ if (snapshot.ownershipToken !== row.ownershipToken) {
952
+ throw new Error('ownership_mismatch');
953
+ }
954
+ if (snapshot.parentRemoteTaskId !== row.parentRemoteTaskId) {
955
+ throw new Error('parent_mismatch');
956
+ }
957
+ if (snapshot.workAreaRemoteId !== row.workAreaRemoteId) {
958
+ throw new Error('work_area_mismatch');
959
+ }
960
+ }
961
+ isOwnershipFailure(error) {
962
+ if (error instanceof external_provider_errors_1.ExternalProviderError &&
963
+ (error.details?.reason === 'ownership_mismatch' ||
964
+ error.details?.reason === 'parent_mismatch')) {
965
+ return true;
966
+ }
967
+ return (error instanceof Error &&
968
+ [
969
+ 'ownership_marker_missing',
970
+ 'ownership_mismatch',
971
+ 'parent_mismatch',
972
+ 'work_area_mismatch',
973
+ ].includes(error.message));
974
+ }
975
+ ownershipFailureCode(error) {
976
+ if (error instanceof external_provider_errors_1.ExternalProviderError &&
977
+ (error.details?.reason === 'ownership_mismatch' ||
978
+ error.details?.reason === 'parent_mismatch')) {
979
+ return error.details.reason;
980
+ }
981
+ return error instanceof Error && this.isOwnershipFailure(error)
982
+ ? error.message
983
+ : 'ownership_mismatch';
984
+ }
985
+ async fenceStillCurrent(expected) {
986
+ const current = await this.storage.getIntegrationConnection(expected.provider);
987
+ return (current?.subtaskSyncEnabled === true &&
988
+ current.id === expected.id &&
989
+ current.generation === expected.generation &&
990
+ current.syncSettingRevision === expected.syncSettingRevision);
991
+ }
992
+ sourceSnapshot(row, desired, snapshot, credentials) {
993
+ const parentSnapshot = desired.parentSource.sourceSnapshot;
994
+ return {
995
+ remoteKey: snapshot.remoteKey,
996
+ title: snapshot.title,
997
+ description: snapshot.description,
998
+ webUrl: this.remoteWebUrl(row.provider, snapshot, credentials),
999
+ workAreaId: row.workAreaRemoteId,
1000
+ workAreaName: this.sourceText(parentSnapshot, 'workAreaName') ?? row.workAreaRemoteId,
1001
+ statusName: 'Managed by DevChain',
1002
+ ownershipToken: row.ownershipToken,
1003
+ parentRemoteTaskId: row.parentRemoteTaskId,
1004
+ workAreaRemoteId: row.workAreaRemoteId,
1005
+ };
1006
+ }
1007
+ remoteWebUrl(provider, snapshot, credentials) {
1008
+ if (provider === 'clickup') {
1009
+ const candidate = `https://app.clickup.com/t/${encodeURIComponent(snapshot.remoteTaskId)}`;
1010
+ return (0, external_task_source_1.normalizeExternalTaskSourceUrl)(provider, candidate);
1011
+ }
1012
+ if (credentials.provider !== 'jira') {
1013
+ return null;
1014
+ }
1015
+ const candidate = `${new URL(credentials.siteUrl).origin}/browse/${encodeURIComponent(snapshot.remoteKey)}`;
1016
+ return (0, external_task_source_1.normalizeExternalTaskSourceUrl)(provider, candidate);
1017
+ }
1018
+ desiredFingerprint(epic, parentSource) {
1019
+ return this.projectionFingerprint(epic.title, epic.description, parentSource.id, parentSource.remoteTaskId);
1020
+ }
1021
+ projectionFingerprint(title, description, parentSourceLinkId, parentRemoteTaskId) {
1022
+ return (0, node_crypto_1.createHash)('sha256')
1023
+ .update(JSON.stringify({
1024
+ title,
1025
+ description,
1026
+ parentSourceLinkId,
1027
+ parentRemoteTaskId,
1028
+ }))
1029
+ .digest('hex');
1030
+ }
1031
+ sourceText(snapshot, key) {
1032
+ const value = snapshot[key];
1033
+ return typeof value === 'string' && value.trim() ? value.trim() : null;
1034
+ }
1035
+ context(connection) {
1036
+ return {
1037
+ connectionId: connection.id,
1038
+ connectionGeneration: connection.generation,
1039
+ };
1040
+ }
1041
+ retryIsInFuture(retryAt) {
1042
+ return Boolean(retryAt && Date.parse(retryAt) > Date.now());
1043
+ }
1044
+ async loadEpicOrNull(id) {
1045
+ try {
1046
+ return await this.storage.getEpic(id);
1047
+ }
1048
+ catch (error) {
1049
+ if (error instanceof error_types_1.NotFoundError) {
1050
+ return null;
1051
+ }
1052
+ throw error;
1053
+ }
1054
+ }
1055
+ result(row, outcome, reason) {
1056
+ return {
1057
+ epicId: row.epicIdSnapshot,
1058
+ provider: row.provider,
1059
+ managedLinkId: row.id,
1060
+ outcome,
1061
+ ...(reason ? { reason } : {}),
1062
+ };
1063
+ }
1064
+ async withProjectionLock(id, operation) {
1065
+ const previous = this.projectionTails.get(id) ?? Promise.resolve();
1066
+ let release;
1067
+ const tail = new Promise((resolve) => {
1068
+ release = resolve;
1069
+ });
1070
+ const queued = previous.then(() => tail);
1071
+ this.projectionTails.set(id, queued);
1072
+ await previous;
1073
+ try {
1074
+ return await operation();
1075
+ }
1076
+ finally {
1077
+ release();
1078
+ if (this.projectionTails.get(id) === queued) {
1079
+ this.projectionTails.delete(id);
1080
+ }
1081
+ }
1082
+ }
1083
+ };
1084
+ exports.ExternalSubtaskSyncSubscriber = ExternalSubtaskSyncSubscriber;
1085
+ exports.ExternalSubtaskSyncSubscriber = ExternalSubtaskSyncSubscriber = __decorate([
1086
+ (0, common_1.Injectable)(),
1087
+ __param(0, (0, common_1.Inject)(storage_interface_1.STORAGE_SERVICE)),
1088
+ __metadata("design:paramtypes", [Object, events_service_1.EventsService,
1089
+ external_task_provider_registry_1.ExternalTaskProviderRegistry,
1090
+ provider_operation_gate_1.ProviderOperationGate])
1091
+ ], ExternalSubtaskSyncSubscriber);
1092
+ //# sourceMappingURL=external-subtask-sync.subscriber.js.map