crewly 1.13.0 → 1.13.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 (597) hide show
  1. package/config/skills/_common/complete-body-shape.test.sh +113 -0
  2. package/config/skills/_common/no-dangling-symlinks.test.sh +63 -0
  3. package/config/skills/_common/task-pool-body-shape.test.sh +471 -0
  4. package/config/skills/agent/core/accept-task/execute.sh +30 -5
  5. package/config/skills/agent/core/block-task/execute.sh +59 -6
  6. package/config/skills/agent/core/complete-task/SKILL.md +37 -5
  7. package/config/skills/agent/core/complete-task/execute.sh +40 -9
  8. package/config/skills/agent/core/complete-task/execute.test.sh +213 -0
  9. package/config/skills/agent/core/create-task/SKILL.md +33 -0
  10. package/config/skills/agent/core/create-task/execute.sh +82 -23
  11. package/config/skills/agent/core/delegate-task/execute.sh +46 -0
  12. package/config/skills/agent/core/get-team-norms/SKILL.md +1 -1
  13. package/config/skills/agent/core/get-team-norms/execute.sh +73 -2
  14. package/config/skills/agent/core/handoff-task/execute.sh +8 -1
  15. package/config/skills/agent/core/report-status/SKILL.md +26 -0
  16. package/config/skills/agent/core/report-status/execute.sh +40 -5
  17. package/config/skills/orchestrator/delegate-task/SKILL.md +1 -1
  18. package/config/skills/orchestrator/delegate-task/execute.sh +45 -11
  19. package/config/skills/orchestrator/delegate-task/execute.test.sh +153 -1
  20. package/config/skills/team-leader/aggregate-results/SKILL.md +1 -1
  21. package/config/skills/team-leader/decompose-goal/execute.sh +11 -16
  22. package/config/skills/team-leader/delegate-task/SKILL.md +14 -1
  23. package/config/skills/team-leader/delegate-task/execute.sh +132 -43
  24. package/config/skills/team-leader/delegate-task/execute.test.sh +180 -27
  25. package/config/vitest-exclude.constants.ts +56 -0
  26. package/dist/backend/backend/src/controllers/monitoring/terminal.controller.d.ts.map +1 -1
  27. package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js +18 -3
  28. package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js.map +1 -1
  29. package/dist/backend/backend/src/controllers/slack/slack.controller.d.ts.map +1 -1
  30. package/dist/backend/backend/src/controllers/slack/slack.controller.js +18 -15
  31. package/dist/backend/backend/src/controllers/slack/slack.controller.js.map +1 -1
  32. package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.d.ts +6 -1
  33. package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.d.ts.map +1 -1
  34. package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js +19 -10
  35. package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js.map +1 -1
  36. package/dist/backend/backend/src/index.d.ts.map +1 -1
  37. package/dist/backend/backend/src/index.js +20 -0
  38. package/dist/backend/backend/src/index.js.map +1 -1
  39. package/dist/backend/backend/src/scripts/stamp-build.d.ts +25 -0
  40. package/dist/backend/backend/src/scripts/stamp-build.d.ts.map +1 -0
  41. package/dist/backend/backend/src/scripts/stamp-build.js +48 -0
  42. package/dist/backend/backend/src/scripts/stamp-build.js.map +1 -0
  43. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  44. package/dist/backend/backend/src/services/agent/agent-registration.service.js +25 -0
  45. package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
  46. package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.d.ts.map +1 -1
  47. package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.js +9 -1
  48. package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.js.map +1 -1
  49. package/dist/backend/backend/src/services/agent/crewly-agent/types.d.ts +42 -3
  50. package/dist/backend/backend/src/services/agent/crewly-agent/types.d.ts.map +1 -1
  51. package/dist/backend/backend/src/services/agent/crewly-agent/types.js +22 -1
  52. package/dist/backend/backend/src/services/agent/crewly-agent/types.js.map +1 -1
  53. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.d.ts +15 -0
  54. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.d.ts.map +1 -1
  55. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js +40 -0
  56. package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js.map +1 -1
  57. package/dist/backend/backend/src/services/orchestrator/orchestrator-status.service.d.ts +28 -3
  58. package/dist/backend/backend/src/services/orchestrator/orchestrator-status.service.d.ts.map +1 -1
  59. package/dist/backend/backend/src/services/orchestrator/orchestrator-status.service.js +65 -8
  60. package/dist/backend/backend/src/services/orchestrator/orchestrator-status.service.js.map +1 -1
  61. package/dist/backend/backend/src/services/reconciler/reconcile-rules.d.ts +214 -4
  62. package/dist/backend/backend/src/services/reconciler/reconcile-rules.d.ts.map +1 -1
  63. package/dist/backend/backend/src/services/reconciler/reconcile-rules.js +330 -48
  64. package/dist/backend/backend/src/services/reconciler/reconcile-rules.js.map +1 -1
  65. package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.d.ts +13 -1
  66. package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.d.ts.map +1 -1
  67. package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.js +84 -5
  68. package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.js.map +1 -1
  69. package/dist/backend/backend/src/services/reconciler/reconciler.service.d.ts +14 -0
  70. package/dist/backend/backend/src/services/reconciler/reconciler.service.d.ts.map +1 -1
  71. package/dist/backend/backend/src/services/reconciler/reconciler.service.js +77 -3
  72. package/dist/backend/backend/src/services/reconciler/reconciler.service.js.map +1 -1
  73. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +152 -7
  74. package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
  75. package/dist/backend/backend/src/services/task-pool/task-pool.service.js +268 -36
  76. package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
  77. package/dist/backend/backend/src/services/v3/escalation-router.service.js +2 -2
  78. package/dist/backend/backend/src/services/v3/escalation-router.service.js.map +1 -1
  79. package/dist/backend/backend/src/services/v3/request-sla.subscriber.d.ts.map +1 -1
  80. package/dist/backend/backend/src/services/v3/request-sla.subscriber.js +39 -2
  81. package/dist/backend/backend/src/services/v3/request-sla.subscriber.js.map +1 -1
  82. package/dist/backend/backend/src/types/v2/index.d.ts +1 -1
  83. package/dist/backend/backend/src/types/v2/index.d.ts.map +1 -1
  84. package/dist/backend/backend/src/types/v2/index.js +1 -1
  85. package/dist/backend/backend/src/types/v2/index.js.map +1 -1
  86. package/dist/backend/backend/src/types/v2/work-item.types.d.ts +181 -1
  87. package/dist/backend/backend/src/types/v2/work-item.types.d.ts.map +1 -1
  88. package/dist/backend/backend/src/types/v2/work-item.types.js +104 -17
  89. package/dist/backend/backend/src/types/v2/work-item.types.js.map +1 -1
  90. package/dist/backend/backend/src/utils/build-provenance.d.ts +150 -0
  91. package/dist/backend/backend/src/utils/build-provenance.d.ts.map +1 -0
  92. package/dist/backend/backend/src/utils/build-provenance.js +211 -0
  93. package/dist/backend/backend/src/utils/build-provenance.js.map +1 -0
  94. package/dist/backend/build-info.json +4 -0
  95. package/dist/backend/config/vitest-exclude.constants.d.ts +53 -0
  96. package/dist/backend/config/vitest-exclude.constants.d.ts.map +1 -0
  97. package/dist/backend/config/vitest-exclude.constants.js +55 -0
  98. package/dist/backend/config/vitest-exclude.constants.js.map +1 -0
  99. package/dist/cli/backend/src/services/agent/active-work-briefing.service.d.ts +538 -0
  100. package/dist/cli/backend/src/services/agent/active-work-briefing.service.d.ts.map +1 -0
  101. package/dist/cli/backend/src/services/agent/active-work-briefing.service.js +802 -0
  102. package/dist/cli/backend/src/services/agent/active-work-briefing.service.js.map +1 -0
  103. package/dist/cli/backend/src/services/agent/agent-heartbeat.service.d.ts +240 -0
  104. package/dist/cli/backend/src/services/agent/agent-heartbeat.service.d.ts.map +1 -0
  105. package/dist/cli/backend/src/services/agent/agent-heartbeat.service.js +524 -0
  106. package/dist/cli/backend/src/services/agent/agent-heartbeat.service.js.map +1 -0
  107. package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts +629 -0
  108. package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts.map +1 -0
  109. package/dist/cli/backend/src/services/agent/agent-registration.service.js +4548 -0
  110. package/dist/cli/backend/src/services/agent/agent-registration.service.js.map +1 -0
  111. package/dist/cli/backend/src/services/agent/agent-suspend.service.d.ts +118 -0
  112. package/dist/cli/backend/src/services/agent/agent-suspend.service.d.ts.map +1 -0
  113. package/dist/cli/backend/src/services/agent/agent-suspend.service.js +304 -0
  114. package/dist/cli/backend/src/services/agent/agent-suspend.service.js.map +1 -0
  115. package/dist/cli/backend/src/services/agent/auditor-scheduler.service.d.ts +196 -0
  116. package/dist/cli/backend/src/services/agent/auditor-scheduler.service.d.ts.map +1 -0
  117. package/dist/cli/backend/src/services/agent/auditor-scheduler.service.js +504 -0
  118. package/dist/cli/backend/src/services/agent/auditor-scheduler.service.js.map +1 -0
  119. package/dist/cli/backend/src/services/agent/claude-runtime.service.d.ts +97 -0
  120. package/dist/cli/backend/src/services/agent/claude-runtime.service.d.ts.map +1 -0
  121. package/dist/cli/backend/src/services/agent/claude-runtime.service.js +334 -0
  122. package/dist/cli/backend/src/services/agent/claude-runtime.service.js.map +1 -0
  123. package/dist/cli/backend/src/services/agent/codex-runtime.service.d.ts +47 -0
  124. package/dist/cli/backend/src/services/agent/codex-runtime.service.d.ts.map +1 -0
  125. package/dist/cli/backend/src/services/agent/codex-runtime.service.js +112 -0
  126. package/dist/cli/backend/src/services/agent/codex-runtime.service.js.map +1 -0
  127. package/dist/cli/backend/src/services/agent/context-window-monitor.service.d.ts +323 -0
  128. package/dist/cli/backend/src/services/agent/context-window-monitor.service.d.ts.map +1 -0
  129. package/dist/cli/backend/src/services/agent/context-window-monitor.service.js +1056 -0
  130. package/dist/cli/backend/src/services/agent/context-window-monitor.service.js.map +1 -0
  131. package/dist/cli/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.d.ts +198 -0
  132. package/dist/cli/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.d.ts.map +1 -0
  133. package/dist/cli/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.js +816 -0
  134. package/dist/cli/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.js.map +1 -0
  135. package/dist/cli/backend/src/services/agent/crewly-agent/in-process-log-buffer.d.ts +155 -0
  136. package/dist/cli/backend/src/services/agent/crewly-agent/in-process-log-buffer.d.ts.map +1 -0
  137. package/dist/cli/backend/src/services/agent/crewly-agent/in-process-log-buffer.js +272 -0
  138. package/dist/cli/backend/src/services/agent/crewly-agent/in-process-log-buffer.js.map +1 -0
  139. package/dist/cli/backend/src/services/agent/crewly-agent/in-process-runtime-registry.d.ts +91 -0
  140. package/dist/cli/backend/src/services/agent/crewly-agent/in-process-runtime-registry.d.ts.map +1 -0
  141. package/dist/cli/backend/src/services/agent/crewly-agent/in-process-runtime-registry.js +120 -0
  142. package/dist/cli/backend/src/services/agent/crewly-agent/in-process-runtime-registry.js.map +1 -0
  143. package/dist/cli/backend/src/services/agent/crewly-agent/types.d.ts +536 -0
  144. package/dist/cli/backend/src/services/agent/crewly-agent/types.d.ts.map +1 -0
  145. package/dist/cli/backend/src/services/agent/crewly-agent/types.js +282 -0
  146. package/dist/cli/backend/src/services/agent/crewly-agent/types.js.map +1 -0
  147. package/dist/cli/backend/src/services/agent/disk-cleanup.service.d.ts +100 -0
  148. package/dist/cli/backend/src/services/agent/disk-cleanup.service.d.ts.map +1 -0
  149. package/dist/cli/backend/src/services/agent/disk-cleanup.service.js +149 -0
  150. package/dist/cli/backend/src/services/agent/disk-cleanup.service.js.map +1 -0
  151. package/dist/cli/backend/src/services/agent/gemini-runtime.service.d.ts +130 -0
  152. package/dist/cli/backend/src/services/agent/gemini-runtime.service.d.ts.map +1 -0
  153. package/dist/cli/backend/src/services/agent/gemini-runtime.service.js +758 -0
  154. package/dist/cli/backend/src/services/agent/gemini-runtime.service.js.map +1 -0
  155. package/dist/cli/backend/src/services/agent/oauth-relogin-monitor.service.d.ts +216 -0
  156. package/dist/cli/backend/src/services/agent/oauth-relogin-monitor.service.d.ts.map +1 -0
  157. package/dist/cli/backend/src/services/agent/oauth-relogin-monitor.service.js +508 -0
  158. package/dist/cli/backend/src/services/agent/oauth-relogin-monitor.service.js.map +1 -0
  159. package/dist/cli/backend/src/services/agent/pty-activity-tracker.service.d.ts +113 -0
  160. package/dist/cli/backend/src/services/agent/pty-activity-tracker.service.d.ts.map +1 -0
  161. package/dist/cli/backend/src/services/agent/pty-activity-tracker.service.js +161 -0
  162. package/dist/cli/backend/src/services/agent/pty-activity-tracker.service.js.map +1 -0
  163. package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.d.ts +156 -0
  164. package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.d.ts.map +1 -0
  165. package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.js +641 -0
  166. package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.js.map +1 -0
  167. package/dist/cli/backend/src/services/agent/runtime-exit-monitor.service.d.ts +295 -0
  168. package/dist/cli/backend/src/services/agent/runtime-exit-monitor.service.d.ts.map +1 -0
  169. package/dist/cli/backend/src/services/agent/runtime-exit-monitor.service.js +1166 -0
  170. package/dist/cli/backend/src/services/agent/runtime-exit-monitor.service.js.map +1 -0
  171. package/dist/cli/backend/src/services/agent/runtime-service.factory.d.ts +71 -0
  172. package/dist/cli/backend/src/services/agent/runtime-service.factory.d.ts.map +1 -0
  173. package/dist/cli/backend/src/services/agent/runtime-service.factory.js +174 -0
  174. package/dist/cli/backend/src/services/agent/runtime-service.factory.js.map +1 -0
  175. package/dist/cli/backend/src/services/ai/prompt-builder.service.d.ts +435 -0
  176. package/dist/cli/backend/src/services/ai/prompt-builder.service.d.ts.map +1 -0
  177. package/dist/cli/backend/src/services/ai/prompt-builder.service.js +1331 -0
  178. package/dist/cli/backend/src/services/ai/prompt-builder.service.js.map +1 -0
  179. package/dist/cli/backend/src/services/ai/prompt-modules/capability-overlay.module.d.ts +33 -0
  180. package/dist/cli/backend/src/services/ai/prompt-modules/capability-overlay.module.d.ts.map +1 -0
  181. package/dist/cli/backend/src/services/ai/prompt-modules/capability-overlay.module.js +70 -0
  182. package/dist/cli/backend/src/services/ai/prompt-modules/capability-overlay.module.js.map +1 -0
  183. package/dist/cli/backend/src/services/ai/prompt-modules/communication.module.d.ts +100 -0
  184. package/dist/cli/backend/src/services/ai/prompt-modules/communication.module.d.ts.map +1 -0
  185. package/dist/cli/backend/src/services/ai/prompt-modules/communication.module.js +296 -0
  186. package/dist/cli/backend/src/services/ai/prompt-modules/communication.module.js.map +1 -0
  187. package/dist/cli/backend/src/services/ai/prompt-modules/decision-rights.module.d.ts +59 -0
  188. package/dist/cli/backend/src/services/ai/prompt-modules/decision-rights.module.d.ts.map +1 -0
  189. package/dist/cli/backend/src/services/ai/prompt-modules/decision-rights.module.js +87 -0
  190. package/dist/cli/backend/src/services/ai/prompt-modules/decision-rights.module.js.map +1 -0
  191. package/dist/cli/backend/src/services/ai/prompt-modules/default-execution-loop.module.d.ts +67 -0
  192. package/dist/cli/backend/src/services/ai/prompt-modules/default-execution-loop.module.d.ts.map +1 -0
  193. package/dist/cli/backend/src/services/ai/prompt-modules/default-execution-loop.module.js +84 -0
  194. package/dist/cli/backend/src/services/ai/prompt-modules/default-execution-loop.module.js.map +1 -0
  195. package/dist/cli/backend/src/services/ai/prompt-modules/domain-sop.module.d.ts +35 -0
  196. package/dist/cli/backend/src/services/ai/prompt-modules/domain-sop.module.d.ts.map +1 -0
  197. package/dist/cli/backend/src/services/ai/prompt-modules/domain-sop.module.js +50 -0
  198. package/dist/cli/backend/src/services/ai/prompt-modules/domain-sop.module.js.map +1 -0
  199. package/dist/cli/backend/src/services/ai/prompt-modules/expert-profile.module.d.ts +41 -0
  200. package/dist/cli/backend/src/services/ai/prompt-modules/expert-profile.module.d.ts.map +1 -0
  201. package/dist/cli/backend/src/services/ai/prompt-modules/expert-profile.module.js +95 -0
  202. package/dist/cli/backend/src/services/ai/prompt-modules/expert-profile.module.js.map +1 -0
  203. package/dist/cli/backend/src/services/ai/prompt-modules/identity.module.d.ts +28 -0
  204. package/dist/cli/backend/src/services/ai/prompt-modules/identity.module.d.ts.map +1 -0
  205. package/dist/cli/backend/src/services/ai/prompt-modules/identity.module.js +47 -0
  206. package/dist/cli/backend/src/services/ai/prompt-modules/identity.module.js.map +1 -0
  207. package/dist/cli/backend/src/services/ai/prompt-modules/lazy-anti-patterns.module.d.ts +65 -0
  208. package/dist/cli/backend/src/services/ai/prompt-modules/lazy-anti-patterns.module.d.ts.map +1 -0
  209. package/dist/cli/backend/src/services/ai/prompt-modules/lazy-anti-patterns.module.js +79 -0
  210. package/dist/cli/backend/src/services/ai/prompt-modules/lazy-anti-patterns.module.js.map +1 -0
  211. package/dist/cli/backend/src/services/ai/prompt-modules/learning-reference.module.d.ts +28 -0
  212. package/dist/cli/backend/src/services/ai/prompt-modules/learning-reference.module.d.ts.map +1 -0
  213. package/dist/cli/backend/src/services/ai/prompt-modules/learning-reference.module.js +55 -0
  214. package/dist/cli/backend/src/services/ai/prompt-modules/learning-reference.module.js.map +1 -0
  215. package/dist/cli/backend/src/services/ai/prompt-modules/lifecycle.module.d.ts +44 -0
  216. package/dist/cli/backend/src/services/ai/prompt-modules/lifecycle.module.d.ts.map +1 -0
  217. package/dist/cli/backend/src/services/ai/prompt-modules/lifecycle.module.js +120 -0
  218. package/dist/cli/backend/src/services/ai/prompt-modules/lifecycle.module.js.map +1 -0
  219. package/dist/cli/backend/src/services/ai/prompt-modules/markdown-file-module.d.ts +46 -0
  220. package/dist/cli/backend/src/services/ai/prompt-modules/markdown-file-module.d.ts.map +1 -0
  221. package/dist/cli/backend/src/services/ai/prompt-modules/markdown-file-module.js +44 -0
  222. package/dist/cli/backend/src/services/ai/prompt-modules/markdown-file-module.js.map +1 -0
  223. package/dist/cli/backend/src/services/ai/prompt-modules/memory-reference.module.d.ts +28 -0
  224. package/dist/cli/backend/src/services/ai/prompt-modules/memory-reference.module.d.ts.map +1 -0
  225. package/dist/cli/backend/src/services/ai/prompt-modules/memory-reference.module.js +46 -0
  226. package/dist/cli/backend/src/services/ai/prompt-modules/memory-reference.module.js.map +1 -0
  227. package/dist/cli/backend/src/services/ai/prompt-modules/mission-context.module.d.ts +60 -0
  228. package/dist/cli/backend/src/services/ai/prompt-modules/mission-context.module.d.ts.map +1 -0
  229. package/dist/cli/backend/src/services/ai/prompt-modules/mission-context.module.js +104 -0
  230. package/dist/cli/backend/src/services/ai/prompt-modules/mission-context.module.js.map +1 -0
  231. package/dist/cli/backend/src/services/ai/prompt-modules/project-reference.module.d.ts +29 -0
  232. package/dist/cli/backend/src/services/ai/prompt-modules/project-reference.module.d.ts.map +1 -0
  233. package/dist/cli/backend/src/services/ai/prompt-modules/project-reference.module.js +50 -0
  234. package/dist/cli/backend/src/services/ai/prompt-modules/project-reference.module.js.map +1 -0
  235. package/dist/cli/backend/src/services/ai/prompt-modules/prompt-assembly.service.d.ts +103 -0
  236. package/dist/cli/backend/src/services/ai/prompt-modules/prompt-assembly.service.d.ts.map +1 -0
  237. package/dist/cli/backend/src/services/ai/prompt-modules/prompt-assembly.service.js +383 -0
  238. package/dist/cli/backend/src/services/ai/prompt-modules/prompt-assembly.service.js.map +1 -0
  239. package/dist/cli/backend/src/services/ai/prompt-modules/recovery.module.d.ts +34 -0
  240. package/dist/cli/backend/src/services/ai/prompt-modules/recovery.module.d.ts.map +1 -0
  241. package/dist/cli/backend/src/services/ai/prompt-modules/recovery.module.js +96 -0
  242. package/dist/cli/backend/src/services/ai/prompt-modules/recovery.module.js.map +1 -0
  243. package/dist/cli/backend/src/services/ai/prompt-modules/request-contract.module.d.ts +106 -0
  244. package/dist/cli/backend/src/services/ai/prompt-modules/request-contract.module.d.ts.map +1 -0
  245. package/dist/cli/backend/src/services/ai/prompt-modules/request-contract.module.js +167 -0
  246. package/dist/cli/backend/src/services/ai/prompt-modules/request-contract.module.js.map +1 -0
  247. package/dist/cli/backend/src/services/ai/prompt-modules/risk-policy.module.d.ts +35 -0
  248. package/dist/cli/backend/src/services/ai/prompt-modules/risk-policy.module.d.ts.map +1 -0
  249. package/dist/cli/backend/src/services/ai/prompt-modules/risk-policy.module.js +50 -0
  250. package/dist/cli/backend/src/services/ai/prompt-modules/risk-policy.module.js.map +1 -0
  251. package/dist/cli/backend/src/services/ai/prompt-modules/role-boundary.module.d.ts +91 -0
  252. package/dist/cli/backend/src/services/ai/prompt-modules/role-boundary.module.d.ts.map +1 -0
  253. package/dist/cli/backend/src/services/ai/prompt-modules/role-boundary.module.js +411 -0
  254. package/dist/cli/backend/src/services/ai/prompt-modules/role-boundary.module.js.map +1 -0
  255. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts +62 -0
  256. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -0
  257. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js +199 -0
  258. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -0
  259. package/dist/cli/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.d.ts +79 -0
  260. package/dist/cli/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.d.ts.map +1 -0
  261. package/dist/cli/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.js +118 -0
  262. package/dist/cli/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.js.map +1 -0
  263. package/dist/cli/backend/src/services/ai/prompt-modules/soul.module.d.ts +102 -0
  264. package/dist/cli/backend/src/services/ai/prompt-modules/soul.module.d.ts.map +1 -0
  265. package/dist/cli/backend/src/services/ai/prompt-modules/soul.module.js +229 -0
  266. package/dist/cli/backend/src/services/ai/prompt-modules/soul.module.js.map +1 -0
  267. package/dist/cli/backend/src/services/ai/prompt-modules/team-norms.module.d.ts +61 -0
  268. package/dist/cli/backend/src/services/ai/prompt-modules/team-norms.module.d.ts.map +1 -0
  269. package/dist/cli/backend/src/services/ai/prompt-modules/team-norms.module.js +197 -0
  270. package/dist/cli/backend/src/services/ai/prompt-modules/team-norms.module.js.map +1 -0
  271. package/dist/cli/backend/src/services/ai/prompt-modules/team-reference.module.d.ts +54 -0
  272. package/dist/cli/backend/src/services/ai/prompt-modules/team-reference.module.d.ts.map +1 -0
  273. package/dist/cli/backend/src/services/ai/prompt-modules/team-reference.module.js +149 -0
  274. package/dist/cli/backend/src/services/ai/prompt-modules/team-reference.module.js.map +1 -0
  275. package/dist/cli/backend/src/services/ai/prompt-modules/user-profile-reference.module.d.ts +32 -0
  276. package/dist/cli/backend/src/services/ai/prompt-modules/user-profile-reference.module.d.ts.map +1 -0
  277. package/dist/cli/backend/src/services/ai/prompt-modules/user-profile-reference.module.js +69 -0
  278. package/dist/cli/backend/src/services/ai/prompt-modules/user-profile-reference.module.js.map +1 -0
  279. package/dist/cli/backend/src/services/ai/prompt-modules/working-memory.module.d.ts +91 -0
  280. package/dist/cli/backend/src/services/ai/prompt-modules/working-memory.module.d.ts.map +1 -0
  281. package/dist/cli/backend/src/services/ai/prompt-modules/working-memory.module.js +136 -0
  282. package/dist/cli/backend/src/services/ai/prompt-modules/working-memory.module.js.map +1 -0
  283. package/dist/cli/backend/src/services/ai/self-improvement/growth-areas.service.d.ts +81 -0
  284. package/dist/cli/backend/src/services/ai/self-improvement/growth-areas.service.d.ts.map +1 -0
  285. package/dist/cli/backend/src/services/ai/self-improvement/growth-areas.service.js +135 -0
  286. package/dist/cli/backend/src/services/ai/self-improvement/growth-areas.service.js.map +1 -0
  287. package/dist/cli/backend/src/services/chat-v2/chat-v2.service.d.ts +737 -0
  288. package/dist/cli/backend/src/services/chat-v2/chat-v2.service.d.ts.map +1 -0
  289. package/dist/cli/backend/src/services/chat-v2/chat-v2.service.js +1213 -0
  290. package/dist/cli/backend/src/services/chat-v2/chat-v2.service.js.map +1 -0
  291. package/dist/cli/backend/src/services/chat-v2/chat-v2.singleton.d.ts +27 -0
  292. package/dist/cli/backend/src/services/chat-v2/chat-v2.singleton.d.ts.map +1 -0
  293. package/dist/cli/backend/src/services/chat-v2/chat-v2.singleton.js +57 -0
  294. package/dist/cli/backend/src/services/chat-v2/chat-v2.singleton.js.map +1 -0
  295. package/dist/cli/backend/src/services/chat-v2/config.d.ts +100 -0
  296. package/dist/cli/backend/src/services/chat-v2/config.d.ts.map +1 -0
  297. package/dist/cli/backend/src/services/chat-v2/config.js +174 -0
  298. package/dist/cli/backend/src/services/chat-v2/config.js.map +1 -0
  299. package/dist/cli/backend/src/services/chat-v2/legacy-dto.utils.d.ts +118 -0
  300. package/dist/cli/backend/src/services/chat-v2/legacy-dto.utils.d.ts.map +1 -0
  301. package/dist/cli/backend/src/services/chat-v2/legacy-dto.utils.js +171 -0
  302. package/dist/cli/backend/src/services/chat-v2/legacy-dto.utils.js.map +1 -0
  303. package/dist/cli/backend/src/services/chat-v2/sqlite/channel.store.d.ts +188 -0
  304. package/dist/cli/backend/src/services/chat-v2/sqlite/channel.store.d.ts.map +1 -0
  305. package/dist/cli/backend/src/services/chat-v2/sqlite/channel.store.js +317 -0
  306. package/dist/cli/backend/src/services/chat-v2/sqlite/channel.store.js.map +1 -0
  307. package/dist/cli/backend/src/services/chat-v2/sqlite/chat-db.d.ts +119 -0
  308. package/dist/cli/backend/src/services/chat-v2/sqlite/chat-db.d.ts.map +1 -0
  309. package/dist/cli/backend/src/services/chat-v2/sqlite/chat-db.js +551 -0
  310. package/dist/cli/backend/src/services/chat-v2/sqlite/chat-db.js.map +1 -0
  311. package/dist/cli/backend/src/services/chat-v2/sqlite/message.store.d.ts +208 -0
  312. package/dist/cli/backend/src/services/chat-v2/sqlite/message.store.d.ts.map +1 -0
  313. package/dist/cli/backend/src/services/chat-v2/sqlite/message.store.js +405 -0
  314. package/dist/cli/backend/src/services/chat-v2/sqlite/message.store.js.map +1 -0
  315. package/dist/cli/backend/src/services/chat-v2/types.d.ts +341 -0
  316. package/dist/cli/backend/src/services/chat-v2/types.d.ts.map +1 -0
  317. package/dist/cli/backend/src/services/chat-v2/types.js +61 -0
  318. package/dist/cli/backend/src/services/chat-v2/types.js.map +1 -0
  319. package/dist/cli/backend/src/services/continuation/patterns/idle-patterns.d.ts +37 -0
  320. package/dist/cli/backend/src/services/continuation/patterns/idle-patterns.d.ts.map +1 -0
  321. package/dist/cli/backend/src/services/continuation/patterns/idle-patterns.js +63 -0
  322. package/dist/cli/backend/src/services/continuation/patterns/idle-patterns.js.map +1 -0
  323. package/dist/cli/backend/src/services/intent-task/intent-classifier.rules.d.ts +335 -0
  324. package/dist/cli/backend/src/services/intent-task/intent-classifier.rules.d.ts.map +1 -0
  325. package/dist/cli/backend/src/services/intent-task/intent-classifier.rules.js +421 -0
  326. package/dist/cli/backend/src/services/intent-task/intent-classifier.rules.js.map +1 -0
  327. package/dist/cli/backend/src/services/mcp-client.d.ts +233 -0
  328. package/dist/cli/backend/src/services/mcp-client.d.ts.map +1 -0
  329. package/dist/cli/backend/src/services/mcp-client.js +302 -0
  330. package/dist/cli/backend/src/services/mcp-client.js.map +1 -0
  331. package/dist/cli/backend/src/services/memory/mission-context.service.d.ts +168 -0
  332. package/dist/cli/backend/src/services/memory/mission-context.service.d.ts.map +1 -0
  333. package/dist/cli/backend/src/services/memory/mission-context.service.js +365 -0
  334. package/dist/cli/backend/src/services/memory/mission-context.service.js.map +1 -0
  335. package/dist/cli/backend/src/services/memory/session-memory.service.d.ts +197 -0
  336. package/dist/cli/backend/src/services/memory/session-memory.service.d.ts.map +1 -0
  337. package/dist/cli/backend/src/services/memory/session-memory.service.js +369 -0
  338. package/dist/cli/backend/src/services/memory/session-memory.service.js.map +1 -0
  339. package/dist/cli/backend/src/services/memory/user-profile.service.d.ts +77 -0
  340. package/dist/cli/backend/src/services/memory/user-profile.service.d.ts.map +1 -0
  341. package/dist/cli/backend/src/services/memory/user-profile.service.js +171 -0
  342. package/dist/cli/backend/src/services/memory/user-profile.service.js.map +1 -0
  343. package/dist/cli/backend/src/services/memory/working-memory.service.d.ts +232 -0
  344. package/dist/cli/backend/src/services/memory/working-memory.service.d.ts.map +1 -0
  345. package/dist/cli/backend/src/services/memory/working-memory.service.js +417 -0
  346. package/dist/cli/backend/src/services/memory/working-memory.service.js.map +1 -0
  347. package/dist/cli/backend/src/services/messaging/sub-agent-message-queue.service.d.ts +84 -0
  348. package/dist/cli/backend/src/services/messaging/sub-agent-message-queue.service.d.ts.map +1 -0
  349. package/dist/cli/backend/src/services/messaging/sub-agent-message-queue.service.js +136 -0
  350. package/dist/cli/backend/src/services/messaging/sub-agent-message-queue.service.js.map +1 -0
  351. package/dist/cli/backend/src/services/messaging/thread-status-queue.service.d.ts +358 -0
  352. package/dist/cli/backend/src/services/messaging/thread-status-queue.service.d.ts.map +1 -0
  353. package/dist/cli/backend/src/services/messaging/thread-status-queue.service.js +755 -0
  354. package/dist/cli/backend/src/services/messaging/thread-status-queue.service.js.map +1 -0
  355. package/dist/cli/backend/src/services/monitoring/token-usage.service.d.ts +269 -0
  356. package/dist/cli/backend/src/services/monitoring/token-usage.service.d.ts.map +1 -0
  357. package/dist/cli/backend/src/services/monitoring/token-usage.service.js +391 -0
  358. package/dist/cli/backend/src/services/monitoring/token-usage.service.js.map +1 -0
  359. package/dist/cli/backend/src/services/observability/agent-behavior-log.service.d.ts +132 -0
  360. package/dist/cli/backend/src/services/observability/agent-behavior-log.service.d.ts.map +1 -0
  361. package/dist/cli/backend/src/services/observability/agent-behavior-log.service.js +284 -0
  362. package/dist/cli/backend/src/services/observability/agent-behavior-log.service.js.map +1 -0
  363. package/dist/cli/backend/src/services/observability/agent-behavior-log.singleton.d.ts +70 -0
  364. package/dist/cli/backend/src/services/observability/agent-behavior-log.singleton.d.ts.map +1 -0
  365. package/dist/cli/backend/src/services/observability/agent-behavior-log.singleton.js +121 -0
  366. package/dist/cli/backend/src/services/observability/agent-behavior-log.singleton.js.map +1 -0
  367. package/dist/cli/backend/src/services/observability/agent-behavior-log.types.d.ts +130 -0
  368. package/dist/cli/backend/src/services/observability/agent-behavior-log.types.d.ts.map +1 -0
  369. package/dist/cli/backend/src/services/observability/agent-behavior-log.types.js +48 -0
  370. package/dist/cli/backend/src/services/observability/agent-behavior-log.types.js.map +1 -0
  371. package/dist/cli/backend/src/services/observability/observability-db.d.ts +84 -0
  372. package/dist/cli/backend/src/services/observability/observability-db.d.ts.map +1 -0
  373. package/dist/cli/backend/src/services/observability/observability-db.js +165 -0
  374. package/dist/cli/backend/src/services/observability/observability-db.js.map +1 -0
  375. package/dist/cli/backend/src/services/onboarding/content-approval.service.d.ts +124 -0
  376. package/dist/cli/backend/src/services/onboarding/content-approval.service.d.ts.map +1 -0
  377. package/dist/cli/backend/src/services/onboarding/content-approval.service.js +256 -0
  378. package/dist/cli/backend/src/services/onboarding/content-approval.service.js.map +1 -0
  379. package/dist/cli/backend/src/services/onboarding/content-approval.types.d.ts +80 -0
  380. package/dist/cli/backend/src/services/onboarding/content-approval.types.d.ts.map +1 -0
  381. package/dist/cli/backend/src/services/onboarding/content-approval.types.js +16 -0
  382. package/dist/cli/backend/src/services/onboarding/content-approval.types.js.map +1 -0
  383. package/dist/cli/backend/src/services/orc/orc-delivery-enforcer.service.d.ts +142 -0
  384. package/dist/cli/backend/src/services/orc/orc-delivery-enforcer.service.d.ts.map +1 -0
  385. package/dist/cli/backend/src/services/orc/orc-delivery-enforcer.service.js +265 -0
  386. package/dist/cli/backend/src/services/orc/orc-delivery-enforcer.service.js.map +1 -0
  387. package/dist/cli/backend/src/services/orchestrator/improvement-marker.service.d.ts +231 -0
  388. package/dist/cli/backend/src/services/orchestrator/improvement-marker.service.d.ts.map +1 -0
  389. package/dist/cli/backend/src/services/orchestrator/improvement-marker.service.js +353 -0
  390. package/dist/cli/backend/src/services/orchestrator/improvement-marker.service.js.map +1 -0
  391. package/dist/cli/backend/src/services/orchestrator/improvement-startup.service.d.ts +157 -0
  392. package/dist/cli/backend/src/services/orchestrator/improvement-startup.service.d.ts.map +1 -0
  393. package/dist/cli/backend/src/services/orchestrator/improvement-startup.service.js +483 -0
  394. package/dist/cli/backend/src/services/orchestrator/improvement-startup.service.js.map +1 -0
  395. package/dist/cli/backend/src/services/orchestrator/index.d.ts +16 -0
  396. package/dist/cli/backend/src/services/orchestrator/index.d.ts.map +1 -0
  397. package/dist/cli/backend/src/services/orchestrator/index.js +16 -0
  398. package/dist/cli/backend/src/services/orchestrator/index.js.map +1 -0
  399. package/dist/cli/backend/src/services/orchestrator/orchestrator-restart.service.d.ts +117 -0
  400. package/dist/cli/backend/src/services/orchestrator/orchestrator-restart.service.d.ts.map +1 -0
  401. package/dist/cli/backend/src/services/orchestrator/orchestrator-restart.service.js +300 -0
  402. package/dist/cli/backend/src/services/orchestrator/orchestrator-restart.service.js.map +1 -0
  403. package/dist/cli/backend/src/services/orchestrator/orchestrator-setup.service.d.ts +114 -0
  404. package/dist/cli/backend/src/services/orchestrator/orchestrator-setup.service.d.ts.map +1 -0
  405. package/dist/cli/backend/src/services/orchestrator/orchestrator-setup.service.js +195 -0
  406. package/dist/cli/backend/src/services/orchestrator/orchestrator-setup.service.js.map +1 -0
  407. package/dist/cli/backend/src/services/orchestrator/orchestrator-status.service.d.ts +94 -0
  408. package/dist/cli/backend/src/services/orchestrator/orchestrator-status.service.d.ts.map +1 -0
  409. package/dist/cli/backend/src/services/orchestrator/orchestrator-status.service.js +279 -0
  410. package/dist/cli/backend/src/services/orchestrator/orchestrator-status.service.js.map +1 -0
  411. package/dist/cli/backend/src/services/orchestrator/safe-restart.service.d.ts +192 -0
  412. package/dist/cli/backend/src/services/orchestrator/safe-restart.service.d.ts.map +1 -0
  413. package/dist/cli/backend/src/services/orchestrator/safe-restart.service.js +395 -0
  414. package/dist/cli/backend/src/services/orchestrator/safe-restart.service.js.map +1 -0
  415. package/dist/cli/backend/src/services/orchestrator/self-improvement.service.d.ts +201 -0
  416. package/dist/cli/backend/src/services/orchestrator/self-improvement.service.d.ts.map +1 -0
  417. package/dist/cli/backend/src/services/orchestrator/self-improvement.service.js +396 -0
  418. package/dist/cli/backend/src/services/orchestrator/self-improvement.service.js.map +1 -0
  419. package/dist/cli/backend/src/services/orchestrator/slack-bridge-lazy.d.ts +17 -0
  420. package/dist/cli/backend/src/services/orchestrator/slack-bridge-lazy.d.ts.map +1 -0
  421. package/dist/cli/backend/src/services/orchestrator/slack-bridge-lazy.js +30 -0
  422. package/dist/cli/backend/src/services/orchestrator/slack-bridge-lazy.js.map +1 -0
  423. package/dist/cli/backend/src/services/orchestrator/state-persistence.service.d.ts +249 -0
  424. package/dist/cli/backend/src/services/orchestrator/state-persistence.service.d.ts.map +1 -0
  425. package/dist/cli/backend/src/services/orchestrator/state-persistence.service.js +569 -0
  426. package/dist/cli/backend/src/services/orchestrator/state-persistence.service.js.map +1 -0
  427. package/dist/cli/backend/src/services/session/index.d.ts +47 -0
  428. package/dist/cli/backend/src/services/session/index.d.ts.map +1 -0
  429. package/dist/cli/backend/src/services/session/index.js +50 -0
  430. package/dist/cli/backend/src/services/session/index.js.map +1 -0
  431. package/dist/cli/backend/src/services/session/log-rotation.service.d.ts +163 -0
  432. package/dist/cli/backend/src/services/session/log-rotation.service.d.ts.map +1 -0
  433. package/dist/cli/backend/src/services/session/log-rotation.service.js +362 -0
  434. package/dist/cli/backend/src/services/session/log-rotation.service.js.map +1 -0
  435. package/dist/cli/backend/src/services/session/pty/index.d.ts +11 -0
  436. package/dist/cli/backend/src/services/session/pty/index.d.ts.map +1 -0
  437. package/dist/cli/backend/src/services/session/pty/index.js +11 -0
  438. package/dist/cli/backend/src/services/session/pty/index.js.map +1 -0
  439. package/dist/cli/backend/src/services/session/pty/pty-session-backend.d.ts +445 -0
  440. package/dist/cli/backend/src/services/session/pty/pty-session-backend.d.ts.map +1 -0
  441. package/dist/cli/backend/src/services/session/pty/pty-session-backend.js +804 -0
  442. package/dist/cli/backend/src/services/session/pty/pty-session-backend.js.map +1 -0
  443. package/dist/cli/backend/src/services/session/pty/pty-session.d.ts +252 -0
  444. package/dist/cli/backend/src/services/session/pty/pty-session.d.ts.map +1 -0
  445. package/dist/cli/backend/src/services/session/pty/pty-session.js +611 -0
  446. package/dist/cli/backend/src/services/session/pty/pty-session.js.map +1 -0
  447. package/dist/cli/backend/src/services/session/pty/pty-terminal-buffer.d.ts +275 -0
  448. package/dist/cli/backend/src/services/session/pty/pty-terminal-buffer.d.ts.map +1 -0
  449. package/dist/cli/backend/src/services/session/pty/pty-terminal-buffer.js +403 -0
  450. package/dist/cli/backend/src/services/session/pty/pty-terminal-buffer.js.map +1 -0
  451. package/dist/cli/backend/src/services/session/runtime-pid-registry.service.d.ts +86 -0
  452. package/dist/cli/backend/src/services/session/runtime-pid-registry.service.d.ts.map +1 -0
  453. package/dist/cli/backend/src/services/session/runtime-pid-registry.service.js +214 -0
  454. package/dist/cli/backend/src/services/session/runtime-pid-registry.service.js.map +1 -0
  455. package/dist/cli/backend/src/services/session/session-backend.factory.d.ts +127 -0
  456. package/dist/cli/backend/src/services/session/session-backend.factory.d.ts.map +1 -0
  457. package/dist/cli/backend/src/services/session/session-backend.factory.js +226 -0
  458. package/dist/cli/backend/src/services/session/session-backend.factory.js.map +1 -0
  459. package/dist/cli/backend/src/services/session/session-backend.interface.d.ts +390 -0
  460. package/dist/cli/backend/src/services/session/session-backend.interface.d.ts.map +1 -0
  461. package/dist/cli/backend/src/services/session/session-backend.interface.js +19 -0
  462. package/dist/cli/backend/src/services/session/session-backend.interface.js.map +1 -0
  463. package/dist/cli/backend/src/services/session/session-command-helper.d.ts +350 -0
  464. package/dist/cli/backend/src/services/session/session-command-helper.d.ts.map +1 -0
  465. package/dist/cli/backend/src/services/session/session-command-helper.js +810 -0
  466. package/dist/cli/backend/src/services/session/session-command-helper.js.map +1 -0
  467. package/dist/cli/backend/src/services/session/session-handoff.service.d.ts +307 -0
  468. package/dist/cli/backend/src/services/session/session-handoff.service.d.ts.map +1 -0
  469. package/dist/cli/backend/src/services/session/session-handoff.service.js +742 -0
  470. package/dist/cli/backend/src/services/session/session-handoff.service.js.map +1 -0
  471. package/dist/cli/backend/src/services/session/session-state-persistence.d.ts +231 -0
  472. package/dist/cli/backend/src/services/session/session-state-persistence.d.ts.map +1 -0
  473. package/dist/cli/backend/src/services/session/session-state-persistence.js +407 -0
  474. package/dist/cli/backend/src/services/session/session-state-persistence.js.map +1 -0
  475. package/dist/cli/backend/src/services/settings/role.service.d.ts +277 -0
  476. package/dist/cli/backend/src/services/settings/role.service.d.ts.map +1 -0
  477. package/dist/cli/backend/src/services/settings/role.service.js +728 -0
  478. package/dist/cli/backend/src/services/settings/role.service.js.map +1 -0
  479. package/dist/cli/backend/src/services/slack/cross-machine-message.service.d.ts +152 -0
  480. package/dist/cli/backend/src/services/slack/cross-machine-message.service.d.ts.map +1 -0
  481. package/dist/cli/backend/src/services/slack/cross-machine-message.service.js +354 -0
  482. package/dist/cli/backend/src/services/slack/cross-machine-message.service.js.map +1 -0
  483. package/dist/cli/backend/src/services/slack/slack-image.service.d.ts +114 -0
  484. package/dist/cli/backend/src/services/slack/slack-image.service.d.ts.map +1 -0
  485. package/dist/cli/backend/src/services/slack/slack-image.service.js +331 -0
  486. package/dist/cli/backend/src/services/slack/slack-image.service.js.map +1 -0
  487. package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.d.ts +499 -0
  488. package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -0
  489. package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.js +1928 -0
  490. package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -0
  491. package/dist/cli/backend/src/services/slack/slack.service.d.ts +315 -0
  492. package/dist/cli/backend/src/services/slack/slack.service.d.ts.map +1 -0
  493. package/dist/cli/backend/src/services/slack/slack.service.js +1094 -0
  494. package/dist/cli/backend/src/services/slack/slack.service.js.map +1 -0
  495. package/dist/cli/backend/src/services/sop/sop.service.d.ts +364 -0
  496. package/dist/cli/backend/src/services/sop/sop.service.d.ts.map +1 -0
  497. package/dist/cli/backend/src/services/sop/sop.service.js +734 -0
  498. package/dist/cli/backend/src/services/sop/sop.service.js.map +1 -0
  499. package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts +152 -7
  500. package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
  501. package/dist/cli/backend/src/services/task-pool/task-pool.service.js +268 -36
  502. package/dist/cli/backend/src/services/task-pool/task-pool.service.js.map +1 -1
  503. package/dist/cli/backend/src/services/v3/escalation-router.service.d.ts +178 -0
  504. package/dist/cli/backend/src/services/v3/escalation-router.service.d.ts.map +1 -0
  505. package/dist/cli/backend/src/services/v3/escalation-router.service.js +692 -0
  506. package/dist/cli/backend/src/services/v3/escalation-router.service.js.map +1 -0
  507. package/dist/cli/backend/src/services/v3/kr-tracking.service.d.ts +200 -0
  508. package/dist/cli/backend/src/services/v3/kr-tracking.service.d.ts.map +1 -0
  509. package/dist/cli/backend/src/services/v3/kr-tracking.service.js +482 -0
  510. package/dist/cli/backend/src/services/v3/kr-tracking.service.js.map +1 -0
  511. package/dist/cli/backend/src/services/v3/mission-executor.service.d.ts +117 -0
  512. package/dist/cli/backend/src/services/v3/mission-executor.service.d.ts.map +1 -0
  513. package/dist/cli/backend/src/services/v3/mission-executor.service.js +321 -0
  514. package/dist/cli/backend/src/services/v3/mission-executor.service.js.map +1 -0
  515. package/dist/cli/backend/src/services/v3/request-sla.subscriber.d.ts +610 -0
  516. package/dist/cli/backend/src/services/v3/request-sla.subscriber.d.ts.map +1 -0
  517. package/dist/cli/backend/src/services/v3/request-sla.subscriber.js +1529 -0
  518. package/dist/cli/backend/src/services/v3/request-sla.subscriber.js.map +1 -0
  519. package/dist/cli/backend/src/services/v3/request-tracker.service.d.ts +78 -0
  520. package/dist/cli/backend/src/services/v3/request-tracker.service.d.ts.map +1 -0
  521. package/dist/cli/backend/src/services/v3/request-tracker.service.js +108 -0
  522. package/dist/cli/backend/src/services/v3/request-tracker.service.js.map +1 -0
  523. package/dist/cli/backend/src/services/v3/request.service.d.ts +295 -0
  524. package/dist/cli/backend/src/services/v3/request.service.d.ts.map +1 -0
  525. package/dist/cli/backend/src/services/v3/request.service.js +534 -0
  526. package/dist/cli/backend/src/services/v3/request.service.js.map +1 -0
  527. package/dist/cli/backend/src/services/v3/v3-data.service.d.ts +340 -0
  528. package/dist/cli/backend/src/services/v3/v3-data.service.d.ts.map +1 -0
  529. package/dist/cli/backend/src/services/v3/v3-data.service.js +1113 -0
  530. package/dist/cli/backend/src/services/v3/v3-data.service.js.map +1 -0
  531. package/dist/cli/backend/src/types/cross-machine.types.d.ts +103 -0
  532. package/dist/cli/backend/src/types/cross-machine.types.d.ts.map +1 -0
  533. package/dist/cli/backend/src/types/cross-machine.types.js +47 -0
  534. package/dist/cli/backend/src/types/cross-machine.types.js.map +1 -0
  535. package/dist/cli/backend/src/types/intent-task.types.d.ts +402 -0
  536. package/dist/cli/backend/src/types/intent-task.types.d.ts.map +1 -0
  537. package/dist/cli/backend/src/types/intent-task.types.js +403 -0
  538. package/dist/cli/backend/src/types/intent-task.types.js.map +1 -0
  539. package/dist/cli/backend/src/types/orchestrator-state.types.d.ts +531 -0
  540. package/dist/cli/backend/src/types/orchestrator-state.types.d.ts.map +1 -0
  541. package/dist/cli/backend/src/types/orchestrator-state.types.js +110 -0
  542. package/dist/cli/backend/src/types/orchestrator-state.types.js.map +1 -0
  543. package/dist/cli/backend/src/types/v2/index.d.ts +30 -0
  544. package/dist/cli/backend/src/types/v2/index.d.ts.map +1 -0
  545. package/dist/cli/backend/src/types/v2/index.js +22 -0
  546. package/dist/cli/backend/src/types/v2/index.js.map +1 -0
  547. package/dist/cli/backend/src/types/v2/key-result.types.d.ts +279 -0
  548. package/dist/cli/backend/src/types/v2/key-result.types.d.ts.map +1 -0
  549. package/dist/cli/backend/src/types/v2/key-result.types.js +264 -0
  550. package/dist/cli/backend/src/types/v2/key-result.types.js.map +1 -0
  551. package/dist/cli/backend/src/types/v2/mission.types.d.ts +661 -0
  552. package/dist/cli/backend/src/types/v2/mission.types.d.ts.map +1 -0
  553. package/dist/cli/backend/src/types/v2/mission.types.js +713 -0
  554. package/dist/cli/backend/src/types/v2/mission.types.js.map +1 -0
  555. package/dist/cli/backend/src/types/v2/reconcile.types.d.ts +204 -0
  556. package/dist/cli/backend/src/types/v2/reconcile.types.d.ts.map +1 -0
  557. package/dist/cli/backend/src/types/v2/reconcile.types.js +121 -0
  558. package/dist/cli/backend/src/types/v2/reconcile.types.js.map +1 -0
  559. package/dist/cli/backend/src/types/v2/request.types.d.ts +192 -0
  560. package/dist/cli/backend/src/types/v2/request.types.d.ts.map +1 -0
  561. package/dist/cli/backend/src/types/v2/request.types.js +179 -0
  562. package/dist/cli/backend/src/types/v2/request.types.js.map +1 -0
  563. package/dist/cli/backend/src/types/v2/work-item.types.d.ts +181 -1
  564. package/dist/cli/backend/src/types/v2/work-item.types.d.ts.map +1 -1
  565. package/dist/cli/backend/src/types/v2/work-item.types.js +104 -17
  566. package/dist/cli/backend/src/types/v2/work-item.types.js.map +1 -1
  567. package/dist/cli/backend/src/types/v2/workspace.types.d.ts +157 -0
  568. package/dist/cli/backend/src/types/v2/workspace.types.d.ts.map +1 -0
  569. package/dist/cli/backend/src/types/v2/workspace.types.js +173 -0
  570. package/dist/cli/backend/src/types/v2/workspace.types.js.map +1 -0
  571. package/dist/cli/backend/src/utils/async.utils.d.ts +68 -0
  572. package/dist/cli/backend/src/utils/async.utils.d.ts.map +1 -0
  573. package/dist/cli/backend/src/utils/async.utils.js +80 -0
  574. package/dist/cli/backend/src/utils/async.utils.js.map +1 -0
  575. package/dist/cli/backend/src/utils/native-binding.utils.d.ts +128 -0
  576. package/dist/cli/backend/src/utils/native-binding.utils.d.ts.map +1 -0
  577. package/dist/cli/backend/src/utils/native-binding.utils.js +206 -0
  578. package/dist/cli/backend/src/utils/native-binding.utils.js.map +1 -0
  579. package/dist/cli/backend/src/websocket/chat.gateway.d.ts +142 -0
  580. package/dist/cli/backend/src/websocket/chat.gateway.d.ts.map +1 -0
  581. package/dist/cli/backend/src/websocket/chat.gateway.js +327 -0
  582. package/dist/cli/backend/src/websocket/chat.gateway.js.map +1 -0
  583. package/dist/cli/backend/src/websocket/terminal.gateway.d.ts +341 -0
  584. package/dist/cli/backend/src/websocket/terminal.gateway.d.ts.map +1 -0
  585. package/dist/cli/backend/src/websocket/terminal.gateway.js +933 -0
  586. package/dist/cli/backend/src/websocket/terminal.gateway.js.map +1 -0
  587. package/dist/cli/config/vitest-exclude.constants.d.ts +53 -0
  588. package/dist/cli/config/vitest-exclude.constants.d.ts.map +1 -0
  589. package/dist/cli/config/vitest-exclude.constants.js +55 -0
  590. package/dist/cli/config/vitest-exclude.constants.js.map +1 -0
  591. package/frontend/dist/assets/index-890d3f9d.js +4961 -0
  592. package/frontend/dist/index.html +1 -1
  593. package/package.json +2 -2
  594. package/packages/crewly-agent/src/runtime/agent-runner.service.test.ts +174 -30
  595. package/packages/crewly-agent/src/runtime/agent-runner.service.ts +121 -6
  596. package/packages/crewly-agent/src/runtime/types.ts +56 -5
  597. package/frontend/dist/assets/index-aa737fd3.js +0 -5254
@@ -0,0 +1,1094 @@
1
+ /**
2
+ * Slack Service
3
+ *
4
+ * Manages Slack bot connection and messaging using Bolt SDK.
5
+ * Enables bidirectional communication between Slack and Crewly.
6
+ *
7
+ * @module services/slack
8
+ */
9
+ import { EventEmitter } from 'events';
10
+ import { createReadStream } from 'fs';
11
+ import { basename } from 'path';
12
+ import { isUserAllowed } from '../../types/slack.types.js';
13
+ import { CROSS_MACHINE_PREFIX } from '../../types/cross-machine.types.js';
14
+ import { SLACK_IMAGE_CONSTANTS, SLACK_FILE_UPLOAD_CONSTANTS, SLACK_DEDUP_CONSTANTS, SLACK_RECONNECT_CONSTANTS, ORCHESTRATOR_SESSION_NAME } from '../../constants.js';
15
+ import { LoggerService } from '../core/logger.service.js';
16
+ import { ContentApprovalService } from '../onboarding/content-approval.service.js';
17
+ import { getAgentBehaviorLogService } from '../observability/agent-behavior-log.singleton.js';
18
+ /**
19
+ * Slack Service singleton instance
20
+ */
21
+ let slackServiceInstance = null;
22
+ /**
23
+ * SlackService class for managing Slack bot operations
24
+ */
25
+ export class SlackService extends EventEmitter {
26
+ logger = LoggerService.getInstance().createComponentLogger('SlackService');
27
+ app = null;
28
+ client = null;
29
+ config = null;
30
+ status = {
31
+ connected: false,
32
+ socketMode: false,
33
+ messagesSent: 0,
34
+ messagesReceived: 0,
35
+ };
36
+ conversationContexts = new Map();
37
+ /** Cached Bolt App constructor from the first successful dynamic import */
38
+ cachedAppConstructor = null;
39
+ /** Cached Bolt LogLevel enum from the first successful dynamic import */
40
+ cachedLogLevelEnum = null;
41
+ /**
42
+ * Message deduplication tracker.
43
+ * Maps a fingerprint (channelId:threadTs:textHash) to the timestamp it was sent.
44
+ * Prevents identical messages from being sent to the same thread within a time window.
45
+ */
46
+ recentMessageFingerprints = new Map();
47
+ /** Whether a reconnection attempt is currently in progress */
48
+ reconnecting = false;
49
+ /** Timer handle for the reconnection grace period */
50
+ reconnectGraceTimer = null;
51
+ /** Timer handle for the periodic health check */
52
+ healthCheckTimer = null;
53
+ /** Current consecutive reconnection attempt count */
54
+ reconnectAttempts = 0;
55
+ /** Whether the service has been intentionally shut down (skip auto-reconnect) */
56
+ intentionalDisconnect = false;
57
+ /** Timestamp of the last successful Slack API ping */
58
+ lastPingAt = 0;
59
+ /** Number of consecutive health-check ping failures */
60
+ consecutivePingFailures = 0;
61
+ /**
62
+ * Initialize the Slack service with configuration
63
+ *
64
+ * @param config - Slack bot configuration
65
+ * @returns Promise that resolves when connected
66
+ */
67
+ async initialize(config) {
68
+ this.config = config;
69
+ this.intentionalDisconnect = false;
70
+ this.reconnectAttempts = 0;
71
+ try {
72
+ // Dynamic import of @slack/bolt (CJS module requires default import handling).
73
+ // Cache the constructor and LogLevel on first import for reuse in reconnect.
74
+ const boltModule = await import('@slack/bolt');
75
+ const defaultExport = boltModule.default;
76
+ const App = (boltModule.App ?? defaultExport?.App);
77
+ const LogLevel = (boltModule.LogLevel ?? defaultExport?.LogLevel);
78
+ this.cachedAppConstructor = App;
79
+ this.cachedLogLevelEnum = LogLevel ?? null;
80
+ this.app = new App({
81
+ token: config.botToken,
82
+ appToken: config.appToken,
83
+ signingSecret: config.signingSecret,
84
+ socketMode: config.socketMode,
85
+ logLevel: LogLevel?.INFO ?? 'info',
86
+ });
87
+ this.client = this.app.client;
88
+ // Set up event handlers
89
+ this.setupEventHandlers();
90
+ // Start the app
91
+ if (config.socketMode) {
92
+ await this.app.start();
93
+ this.status.connected = true;
94
+ this.status.socketMode = true;
95
+ // Monitor SocketModeClient connection state for logging and status tracking
96
+ this.setupConnectionMonitoring();
97
+ this.emit('connected');
98
+ this.logger.info('Connected in Socket Mode');
99
+ }
100
+ }
101
+ catch (error) {
102
+ // Ensure partially initialized Bolt app is torn down to avoid
103
+ // lingering socket retries/background tasks after failed startup.
104
+ if (this.app) {
105
+ try {
106
+ await this.app.stop();
107
+ }
108
+ catch {
109
+ // Ignore shutdown errors during failed initialization
110
+ }
111
+ }
112
+ this.app = null;
113
+ this.client = null;
114
+ this.status.connected = false;
115
+ this.status.socketMode = false;
116
+ this.status.lastError = error.message;
117
+ this.status.lastErrorAt = new Date().toISOString();
118
+ this.emit('error', error);
119
+ throw error;
120
+ }
121
+ }
122
+ /**
123
+ * Set up Slack event handlers
124
+ */
125
+ setupEventHandlers() {
126
+ if (!this.app || !this.config)
127
+ return;
128
+ const config = this.config;
129
+ // Handle direct messages
130
+ this.app.message(async ({ message }) => {
131
+ // Allow messages with text or files (or both)
132
+ if (!message.text && (!message.files || message.files.length === 0))
133
+ return;
134
+ if (!message.user)
135
+ return;
136
+ // Bypass user permission check for cross-machine messages —
137
+ // these come from other bots and are authenticated by device ID,
138
+ // not Slack user ID. The CrossMachineMessageService handles its
139
+ // own security (device identity, target filtering, deduplication).
140
+ const isCrossMachine = message.text && message.text.startsWith(CROSS_MACHINE_PREFIX);
141
+ // Check user permissions (skip for cross-machine messages)
142
+ if (!isCrossMachine && !isUserAllowed(message.user, config)) {
143
+ this.logger.info('Unauthorized user', { userId: message.user });
144
+ return;
145
+ }
146
+ // Pass ALL files through; downstream services handle image vs non-image distinction
147
+ const allFiles = (message.files || []);
148
+ const imageFiles = allFiles.filter(f => f.mimetype?.startsWith('image/'));
149
+ const incomingMessage = {
150
+ id: message.ts || '',
151
+ type: 'message',
152
+ text: message.text || '',
153
+ userId: message.user,
154
+ channelId: message.channel,
155
+ threadTs: message.thread_ts,
156
+ ts: message.ts || '',
157
+ teamId: message.team || '',
158
+ eventTs: message.ts || '',
159
+ files: allFiles.length > 0 ? allFiles : undefined,
160
+ hasImages: imageFiles.length > 0,
161
+ hasFiles: allFiles.length > 0,
162
+ };
163
+ this.status.messagesReceived++;
164
+ this.status.lastEventAt = new Date().toISOString();
165
+ this.emit('message', incomingMessage);
166
+ });
167
+ // Handle @mentions
168
+ this.app.event('app_mention', async ({ event }) => {
169
+ if (!isUserAllowed(event.user, config)) {
170
+ this.logger.info('Unauthorized user mention', { userId: event.user });
171
+ return;
172
+ }
173
+ const incomingMessage = {
174
+ id: event.ts,
175
+ type: 'app_mention',
176
+ text: event.text,
177
+ userId: event.user,
178
+ channelId: event.channel,
179
+ threadTs: event.thread_ts,
180
+ ts: event.ts,
181
+ teamId: event.team || '',
182
+ eventTs: event.event_ts,
183
+ };
184
+ this.status.messagesReceived++;
185
+ this.status.lastEventAt = new Date().toISOString();
186
+ this.emit('message', incomingMessage);
187
+ });
188
+ // Handle content approval button clicks (Block Kit interactive actions)
189
+ this.app.action(/content_approval_(approve|reject)/, async ({ action, body, ack, respond }) => {
190
+ await ack();
191
+ const approvalId = action.value;
192
+ const actionType = action.action_id;
193
+ const slackUserName = body.user.name || body.user.username || body.user.id;
194
+ const channelId = body.channel?.id || body.container?.channel_id;
195
+ const messageTs = body.message?.ts || body.container?.message_ts;
196
+ if (!approvalId) {
197
+ await respond({ text: 'Error: Missing approval ID.', replace_original: false, response_type: 'ephemeral' });
198
+ return;
199
+ }
200
+ try {
201
+ const service = ContentApprovalService.getInstance();
202
+ const existing = service.get(approvalId);
203
+ if (!existing) {
204
+ await respond({ text: `Approval \`${approvalId.slice(0, 8)}\` not found.`, replace_original: false, response_type: 'ephemeral' });
205
+ return;
206
+ }
207
+ if (existing.status !== 'pending') {
208
+ await respond({
209
+ text: `This approval has already been ${existing.status} by ${existing.resolvedBy ?? 'someone'}.`,
210
+ replace_original: false,
211
+ response_type: 'ephemeral',
212
+ });
213
+ return;
214
+ }
215
+ const isApprove = actionType === 'content_approval_approve';
216
+ const result = isApprove
217
+ ? service.approve(approvalId, slackUserName)
218
+ : service.reject(approvalId, slackUserName);
219
+ if (!result) {
220
+ await respond({ text: 'Failed to resolve approval.', replace_original: false, response_type: 'ephemeral' });
221
+ return;
222
+ }
223
+ // Update the original message to replace buttons with status
224
+ const statusEmoji = isApprove ? '\u2705' : '\u274c';
225
+ const statusText = isApprove ? 'Approved' : 'Rejected';
226
+ const updatedText = `${statusEmoji} ${statusText} by @${slackUserName}`;
227
+ if (channelId && messageTs) {
228
+ const updatedBlocks = [
229
+ {
230
+ type: 'section',
231
+ text: { type: 'mrkdwn', text: `~${existing.content.slice(0, 200)}~` },
232
+ },
233
+ {
234
+ type: 'context',
235
+ elements: [
236
+ { type: 'mrkdwn', text: `${updatedText} \u2022 ${new Date().toLocaleString()}` },
237
+ ],
238
+ },
239
+ ];
240
+ await this.updateMessage(channelId, messageTs, updatedText, updatedBlocks);
241
+ }
242
+ this.emit('content_approval_resolved', {
243
+ approvalId,
244
+ action: isApprove ? 'approved' : 'rejected',
245
+ resolvedBy: slackUserName,
246
+ });
247
+ this.logger.info('Content approval resolved via Slack button', {
248
+ approvalId: approvalId.slice(0, 8),
249
+ action: statusText.toLowerCase(),
250
+ resolvedBy: slackUserName,
251
+ });
252
+ }
253
+ catch (err) {
254
+ this.logger.error('Content approval action handler error', {
255
+ approvalId: approvalId?.slice(0, 8),
256
+ error: err instanceof Error ? err.message : String(err),
257
+ });
258
+ await respond({
259
+ text: `Error processing approval: ${err instanceof Error ? err.message : 'Unknown error'}`,
260
+ replace_original: false,
261
+ response_type: 'ephemeral',
262
+ });
263
+ }
264
+ });
265
+ // Handle errors
266
+ this.app.error(async (error) => {
267
+ this.logger.error('Error', { error: error.message });
268
+ this.status.lastError = error.message;
269
+ this.status.lastErrorAt = new Date().toISOString();
270
+ this.emit('error', error);
271
+ });
272
+ }
273
+ /**
274
+ * Attach listeners to the underlying SocketModeClient to track
275
+ * connection lifecycle (disconnected, reconnecting, connected).
276
+ * Updates `status.connected` so health checks reflect actual state.
277
+ *
278
+ * The Bolt App stores the receiver at `app.receiver`, and the
279
+ * SocketModeReceiver exposes `client` (SocketModeClient), which
280
+ * is an EventEmitter emitting: connected, reconnecting, disconnected, close.
281
+ */
282
+ setupConnectionMonitoring() {
283
+ // Access the SocketModeClient from Bolt's internal receiver.
284
+ // This relies on Bolt's internal structure, so we guard with try/catch.
285
+ try {
286
+ const receiver = this.app?.receiver;
287
+ const socketClient = receiver?.client;
288
+ if (!socketClient) {
289
+ this.logger.warn('Could not access SocketModeClient for connection monitoring');
290
+ return;
291
+ }
292
+ // Issue #548 — `@slack/socket-mode`'s finity state machine throws
293
+ // `Unhandled event 'server explicit disconnect' in state 'connecting'`
294
+ // when Slack sends a disconnect signal during the reconnect
295
+ // handshake window. The throw is SYNCHRONOUS inside the WebSocket
296
+ // message callback (WebSocket.onMessage → SocketModeClient.
297
+ // onWebSocketMessage → finity.handle → throw) so it surfaces as
298
+ // an uncaughtException that takes the process down on v1 hosts
299
+ // (no pm2/systemd to restart). CrewlyNode1 went dark for ~21
300
+ // hours on 2026-05-14 from exactly this.
301
+ //
302
+ // Wrap `onWebSocketMessage` with a synchronous try/catch that
303
+ // swallows the unhandled-event throw, logs it as a recoverable
304
+ // event, and triggers the reconnect path. Other throws still
305
+ // surface normally — we only suppress the specific finity
306
+ // "Unhandled event" signature.
307
+ const wrappedClient = socketClient;
308
+ const originalOnMessage = wrappedClient.onWebSocketMessage;
309
+ if (typeof originalOnMessage === 'function') {
310
+ wrappedClient.onWebSocketMessage = (...args) => {
311
+ try {
312
+ return originalOnMessage.apply(socketClient, args);
313
+ }
314
+ catch (err) {
315
+ const msg = err instanceof Error ? err.message : String(err);
316
+ if (/Unhandled event/.test(msg)) {
317
+ this.logger.warn('Suppressed finity unhandled-event from SocketModeClient (issue #548) — triggering reconnect', {
318
+ error: msg,
319
+ });
320
+ this.status.connected = false;
321
+ this.status.lastError = `SocketMode finity throw: ${msg}`;
322
+ this.status.lastErrorAt = new Date().toISOString();
323
+ this.scheduleReconnect();
324
+ return undefined;
325
+ }
326
+ throw err;
327
+ }
328
+ };
329
+ this.logger.info('SocketModeClient.onWebSocketMessage wrapped for #548 finity-throw recovery');
330
+ }
331
+ else {
332
+ this.logger.warn('SocketModeClient.onWebSocketMessage not found — #548 finity-throw guard NOT installed');
333
+ }
334
+ socketClient.on('disconnected', () => {
335
+ this.status.connected = false;
336
+ this.status.lastError = 'Socket Mode connection lost';
337
+ this.status.lastErrorAt = new Date().toISOString();
338
+ this.logger.warn('Socket Mode disconnected');
339
+ this.emit('disconnected');
340
+ this.scheduleReconnect();
341
+ });
342
+ socketClient.on('reconnecting', () => {
343
+ this.status.connected = false;
344
+ this.logger.info('Socket Mode reconnecting (Bolt built-in)...');
345
+ });
346
+ socketClient.on('connected', () => {
347
+ this.status.connected = true;
348
+ this.reconnectAttempts = 0;
349
+ this.consecutivePingFailures = 0;
350
+ this.lastPingAt = Date.now();
351
+ this.cancelReconnectGrace();
352
+ this.logger.info('Socket Mode reconnected');
353
+ this.emit('connected');
354
+ });
355
+ socketClient.on('close', () => {
356
+ // 'close' fires on WebSocket close before reconnection kicks in
357
+ if (this.status.connected) {
358
+ this.status.connected = false;
359
+ this.logger.warn('Socket Mode WebSocket closed, awaiting reconnect...');
360
+ this.scheduleReconnect();
361
+ }
362
+ });
363
+ }
364
+ catch (err) {
365
+ this.logger.warn('Failed to set up connection monitoring', {
366
+ error: err instanceof Error ? err.message : String(err),
367
+ });
368
+ }
369
+ // Start periodic health check
370
+ this.startHealthCheck();
371
+ }
372
+ /**
373
+ * Start a periodic health check that verifies the Socket Mode connection
374
+ * is alive and triggers reconnection if it has silently died.
375
+ *
376
+ * Uses an active Slack API ping (auth.test) to detect half-open sockets
377
+ * that appear connected but are actually dead after WiFi/network drops.
378
+ */
379
+ startHealthCheck() {
380
+ this.stopHealthCheck();
381
+ this.lastPingAt = Date.now();
382
+ this.consecutivePingFailures = 0;
383
+ this.healthCheckTimer = setInterval(async () => {
384
+ if (this.intentionalDisconnect)
385
+ return;
386
+ // Case 1: Already known to be disconnected — trigger reconnect
387
+ if (!this.status.connected && !this.reconnecting) {
388
+ this.logger.warn('Health check: Socket Mode not connected and no reconnect in progress — triggering reconnect');
389
+ this.attemptReconnect();
390
+ return;
391
+ }
392
+ // Case 2: Status says connected — verify with an active API ping
393
+ if (this.status.connected && this.client && !this.reconnecting) {
394
+ try {
395
+ const pingPromise = this.client.auth.test();
396
+ const timeoutMs = SLACK_RECONNECT_CONSTANTS.PING_TIMEOUT_MS;
397
+ const timeoutPromise = new Promise((_, reject) => {
398
+ const timer = setTimeout(() => reject(new Error('Ping timeout')), timeoutMs);
399
+ // Clear timer if ping resolves first to prevent leak
400
+ pingPromise.then(() => clearTimeout(timer), () => clearTimeout(timer));
401
+ });
402
+ await Promise.race([pingPromise, timeoutPromise]);
403
+ // Ping succeeded — connection is truly alive
404
+ this.lastPingAt = Date.now();
405
+ this.consecutivePingFailures = 0;
406
+ }
407
+ catch (err) {
408
+ this.consecutivePingFailures++;
409
+ this.logger.warn('Health check ping failed', {
410
+ consecutiveFailures: this.consecutivePingFailures,
411
+ error: err instanceof Error ? err.message : String(err),
412
+ });
413
+ // After consecutive failures, declare connection dead and reconnect
414
+ if (this.consecutivePingFailures >= SLACK_RECONNECT_CONSTANTS.PING_FAILURES_BEFORE_RECONNECT) {
415
+ this.logger.warn('Health check: connection appears dead after consecutive ping failures — forcing reconnect', {
416
+ consecutiveFailures: this.consecutivePingFailures,
417
+ lastPingAt: new Date(this.lastPingAt).toISOString(),
418
+ });
419
+ this.status.connected = false;
420
+ this.consecutivePingFailures = 0;
421
+ this.attemptReconnect();
422
+ }
423
+ }
424
+ }
425
+ }, SLACK_RECONNECT_CONSTANTS.HEALTH_CHECK_INTERVAL_MS);
426
+ // Allow Node to exit even if health check timer is still active
427
+ if (this.healthCheckTimer && typeof this.healthCheckTimer === 'object' && 'unref' in this.healthCheckTimer) {
428
+ this.healthCheckTimer.unref();
429
+ }
430
+ }
431
+ /**
432
+ * Stop the periodic health check timer.
433
+ */
434
+ stopHealthCheck() {
435
+ if (this.healthCheckTimer) {
436
+ clearInterval(this.healthCheckTimer);
437
+ this.healthCheckTimer = null;
438
+ }
439
+ }
440
+ /**
441
+ * Schedule a reconnection attempt after a grace period.
442
+ * The grace period gives Bolt's built-in reconnect a chance to recover first.
443
+ * If the connection comes back within the grace period, the reconnect is cancelled.
444
+ */
445
+ scheduleReconnect() {
446
+ if (this.intentionalDisconnect || this.reconnecting || this.reconnectGraceTimer)
447
+ return;
448
+ this.logger.info('Scheduling reconnect after grace period', {
449
+ gracePeriodMs: SLACK_RECONNECT_CONSTANTS.GRACE_PERIOD_MS,
450
+ });
451
+ this.reconnectGraceTimer = setTimeout(() => {
452
+ this.reconnectGraceTimer = null;
453
+ if (!this.status.connected && !this.intentionalDisconnect) {
454
+ this.logger.warn('Grace period expired, Bolt reconnect did not recover — starting manual reconnect');
455
+ this.attemptReconnect();
456
+ }
457
+ }, SLACK_RECONNECT_CONSTANTS.GRACE_PERIOD_MS);
458
+ }
459
+ /**
460
+ * Cancel the reconnection grace period timer.
461
+ */
462
+ cancelReconnectGrace() {
463
+ if (this.reconnectGraceTimer) {
464
+ clearTimeout(this.reconnectGraceTimer);
465
+ this.reconnectGraceTimer = null;
466
+ }
467
+ }
468
+ /**
469
+ * Attempt to reconnect by tearing down the current Bolt app and
470
+ * re-initializing from scratch with the saved config.
471
+ * Uses exponential backoff between attempts.
472
+ */
473
+ async attemptReconnect() {
474
+ if (this.reconnecting || this.intentionalDisconnect || !this.config)
475
+ return;
476
+ const maxAttempts = SLACK_RECONNECT_CONSTANTS.MAX_ATTEMPTS;
477
+ if (maxAttempts > 0 && this.reconnectAttempts >= maxAttempts) {
478
+ this.logger.error('Max reconnection attempts reached, giving up', {
479
+ attempts: this.reconnectAttempts,
480
+ maxAttempts,
481
+ });
482
+ return;
483
+ }
484
+ this.reconnecting = true;
485
+ this.reconnectAttempts++;
486
+ const delay = Math.min(SLACK_RECONNECT_CONSTANTS.INITIAL_DELAY_MS * Math.pow(SLACK_RECONNECT_CONSTANTS.BACKOFF_MULTIPLIER, this.reconnectAttempts - 1), SLACK_RECONNECT_CONSTANTS.MAX_DELAY_MS);
487
+ this.logger.info('Reconnecting to Slack Socket Mode', {
488
+ attempt: this.reconnectAttempts,
489
+ delayMs: delay,
490
+ });
491
+ await new Promise(resolve => setTimeout(resolve, delay));
492
+ // Bail out if we reconnected or intentionally disconnected while waiting
493
+ if (this.status.connected || this.intentionalDisconnect) {
494
+ this.reconnecting = false;
495
+ return;
496
+ }
497
+ try {
498
+ // Guard: cached App constructor must be available from initialize()
499
+ if (!this.cachedAppConstructor) {
500
+ throw new Error('App constructor not cached — initialize() must be called before reconnect');
501
+ }
502
+ // Tear down existing app
503
+ if (this.app) {
504
+ try {
505
+ await this.app.stop();
506
+ }
507
+ catch {
508
+ // Ignore teardown errors
509
+ }
510
+ this.app = null;
511
+ this.client = null;
512
+ }
513
+ // Re-initialize using cached constructor (avoids stale dynamic import issues)
514
+ const App = this.cachedAppConstructor;
515
+ const LogLevel = this.cachedLogLevelEnum;
516
+ this.app = new App({
517
+ token: this.config.botToken,
518
+ appToken: this.config.appToken,
519
+ signingSecret: this.config.signingSecret,
520
+ socketMode: this.config.socketMode,
521
+ logLevel: LogLevel?.INFO ?? 'info',
522
+ });
523
+ this.client = this.app.client;
524
+ this.setupEventHandlers();
525
+ await this.app.start();
526
+ this.status.connected = true;
527
+ this.status.socketMode = true;
528
+ this.reconnectAttempts = 0;
529
+ this.reconnecting = false;
530
+ this.consecutivePingFailures = 0;
531
+ this.lastPingAt = Date.now();
532
+ this.setupConnectionMonitoring();
533
+ this.emit('connected');
534
+ this.logger.info('Successfully reconnected to Slack Socket Mode');
535
+ }
536
+ catch (error) {
537
+ this.reconnecting = false;
538
+ const errorMessage = error instanceof Error ? error.message : String(error);
539
+ this.status.lastError = `Reconnect failed: ${errorMessage}`;
540
+ this.status.lastErrorAt = new Date().toISOString();
541
+ // Classify error: fatal errors stop the loop, transient errors retry
542
+ if (this.isFatalReconnectError(error)) {
543
+ this.logger.error('Fatal reconnection error — stopping retry loop', {
544
+ attempt: this.reconnectAttempts,
545
+ error: errorMessage,
546
+ });
547
+ this.emit('error', error instanceof Error ? error : new Error(errorMessage));
548
+ return;
549
+ }
550
+ this.logger.error('Transient reconnection error — will retry', {
551
+ attempt: this.reconnectAttempts,
552
+ error: errorMessage,
553
+ });
554
+ // Schedule next attempt — the health check will also retry if this doesn't fire
555
+ if (!this.intentionalDisconnect) {
556
+ this.scheduleReconnect();
557
+ }
558
+ }
559
+ }
560
+ /**
561
+ * Classify whether a reconnection error is fatal (non-recoverable)
562
+ * or transient (may succeed on retry).
563
+ *
564
+ * Fatal errors: missing constructor, invalid config, auth errors.
565
+ * Transient errors: network timeouts, temporary server errors.
566
+ *
567
+ * @param error - The error caught during reconnection
568
+ * @returns True if the error is fatal and retrying would be futile
569
+ */
570
+ isFatalReconnectError(error) {
571
+ const message = error instanceof Error ? error.message : String(error);
572
+ const lowerMessage = message.toLowerCase();
573
+ /** Patterns that indicate a non-recoverable configuration or code error */
574
+ const fatalPatterns = [
575
+ 'not a constructor',
576
+ 'is not a function',
577
+ 'constructor not cached',
578
+ 'invalid_auth',
579
+ 'token_revoked',
580
+ 'account_inactive',
581
+ 'missing required',
582
+ 'config',
583
+ ];
584
+ return fatalPatterns.some(pattern => lowerMessage.includes(pattern));
585
+ }
586
+ /**
587
+ * Send a message to Slack with content-based deduplication.
588
+ *
589
+ * Generates a fingerprint from (channelId, threadTs, text) and suppresses
590
+ * duplicate sends within a configurable time window (default 30s).
591
+ * This is the single chokepoint for all Slack message sends — skill delivery,
592
+ * bridge fallback, and direct API calls all converge here.
593
+ *
594
+ * @param message - Message to send
595
+ * @returns Promise with message timestamp (empty string if deduplicated)
596
+ */
597
+ async sendMessage(message) {
598
+ if (!this.client) {
599
+ throw new Error('Slack client not initialized');
600
+ }
601
+ // Content-based deduplication: suppress identical messages within time window
602
+ const fingerprint = this.buildMessageFingerprint(message);
603
+ const now = Date.now();
604
+ const lastSentAt = this.recentMessageFingerprints.get(fingerprint);
605
+ if (lastSentAt !== undefined && (now - lastSentAt) < SLACK_DEDUP_CONSTANTS.DEDUP_WINDOW_MS) {
606
+ this.logger.info('Slack message deduplicated — identical message sent recently', {
607
+ channelId: message.channelId,
608
+ threadTs: message.threadTs,
609
+ ageMs: now - lastSentAt,
610
+ });
611
+ return '';
612
+ }
613
+ try {
614
+ const result = await this.client.chat.postMessage({
615
+ channel: message.channelId,
616
+ text: message.text,
617
+ thread_ts: message.threadTs,
618
+ blocks: message.blocks,
619
+ attachments: message.attachments,
620
+ unfurl_links: message.unfurlLinks,
621
+ unfurl_media: message.unfurlMedia,
622
+ });
623
+ this.status.messagesSent++;
624
+ // Track this fingerprint for future dedup
625
+ this.trackMessageFingerprint(fingerprint, now);
626
+ // Mirror the outbound reply into chat-v2 so the Slack thread shows both
627
+ // sides ("收和发") in the consolidated chat. Best-effort, thread-only.
628
+ if (message.threadTs) {
629
+ void this.recordOutboundToChatV2(message);
630
+ }
631
+ return result.ts || '';
632
+ }
633
+ catch (error) {
634
+ this.logger.error('Send message error', { error: error instanceof Error ? error.message : String(error) });
635
+ // F14: record slack.delivery.failed event (best-effort — never
636
+ // changes retry semantics or throws). The wrapper swallows
637
+ // construction errors and `record()` itself swallows DB errors.
638
+ try {
639
+ const errMessage = error instanceof Error ? error.message : String(error);
640
+ getAgentBehaviorLogService()?.record({
641
+ type: 'slack.delivery.failed',
642
+ agent: '',
643
+ thread: `${message.channelId}:${message.threadTs ?? ''}`,
644
+ reason: 'api_error',
645
+ details: {
646
+ errorMessage: errMessage,
647
+ textLength: (message.text ?? '').length,
648
+ hasBlocks: Array.isArray(message.blocks) && message.blocks.length > 0,
649
+ },
650
+ });
651
+ }
652
+ catch {
653
+ /* observability is best-effort — never block the original throw */
654
+ }
655
+ throw error;
656
+ }
657
+ }
658
+ /**
659
+ * Mirror an outbound Slack reply into the canonical chat-v2 store so the
660
+ * Slack thread shows both inbound (user) and outbound (agent) messages in
661
+ * the consolidated /team-chat surface. Records against the SAME channel the
662
+ * inbound persisted to — `synthesizeSlackConversationId(channelId, threadTs)`.
663
+ *
664
+ * Best-effort: dynamic imports + try/catch so a chat-v2 failure never
665
+ * affects Slack delivery. Only called for threaded replies (threadTs set).
666
+ *
667
+ * @param message - The outbound Slack message that was just sent.
668
+ */
669
+ async recordOutboundToChatV2(message) {
670
+ try {
671
+ if (!message.channelId || !message.threadTs || !(message.text ?? '').trim())
672
+ return;
673
+ const [{ getChatV2Service }, { synthesizeSlackConversationId, slackOutboundClientMessageId }] = await Promise.all([
674
+ import('../chat-v2/chat-v2.singleton.js'),
675
+ import('../chat-v2/legacy-dto.utils.js'),
676
+ ]);
677
+ const chatV2 = getChatV2Service();
678
+ const conversationId = synthesizeSlackConversationId(message.channelId, message.threadTs);
679
+ const channel = chatV2.ensureChannelForLegacyConversation({
680
+ conversationId,
681
+ agentSession: ORCHESTRATOR_SESSION_NAME,
682
+ });
683
+ chatV2.recordTurn({
684
+ channelId: channel.id,
685
+ senderType: 'agent',
686
+ senderId: channel.agentSession || ORCHESTRATOR_SESSION_NAME,
687
+ content: message.text,
688
+ // Shared idempotency key with the /slack/send bookkeeping path so the
689
+ // same reply isn't persisted twice (duplicate bubbles in the merged
690
+ // Orchestrator timeline).
691
+ clientMessageId: slackOutboundClientMessageId(message.channelId, message.threadTs, message.text),
692
+ metadata: {
693
+ source: 'slack',
694
+ slackChannelId: message.channelId,
695
+ slackThreadTs: message.threadTs,
696
+ },
697
+ });
698
+ }
699
+ catch (err) {
700
+ this.logger.warn('Failed to mirror outbound Slack message to chat-v2', {
701
+ error: err instanceof Error ? err.message : String(err),
702
+ });
703
+ }
704
+ }
705
+ /**
706
+ * Build a deduplication fingerprint for a Slack message.
707
+ * Combines channelId, threadTs, and a simple hash of the message text.
708
+ *
709
+ * @param message - Outgoing Slack message
710
+ * @returns Fingerprint string
711
+ */
712
+ buildMessageFingerprint(message) {
713
+ // Simple string hash (djb2) — fast and sufficient for dedup
714
+ let hash = 5381;
715
+ const text = message.text || '';
716
+ for (let i = 0; i < text.length; i++) {
717
+ hash = ((hash << 5) + hash + text.charCodeAt(i)) | 0;
718
+ }
719
+ return `${message.channelId}:${message.threadTs || ''}:${hash}`;
720
+ }
721
+ /**
722
+ * Track a message fingerprint and evict stale entries.
723
+ *
724
+ * @param fingerprint - Message fingerprint to track
725
+ * @param timestamp - Current timestamp in ms
726
+ */
727
+ trackMessageFingerprint(fingerprint, timestamp) {
728
+ this.recentMessageFingerprints.set(fingerprint, timestamp);
729
+ // Evict expired entries and enforce size limit
730
+ if (this.recentMessageFingerprints.size > SLACK_DEDUP_CONSTANTS.MAX_TRACKED_MESSAGES) {
731
+ const windowMs = SLACK_DEDUP_CONSTANTS.DEDUP_WINDOW_MS;
732
+ for (const [key, ts] of this.recentMessageFingerprints) {
733
+ if (timestamp - ts > windowMs) {
734
+ this.recentMessageFingerprints.delete(key);
735
+ }
736
+ }
737
+ // If still over limit after expiry cleanup, drop oldest
738
+ if (this.recentMessageFingerprints.size > SLACK_DEDUP_CONSTANTS.MAX_TRACKED_MESSAGES) {
739
+ const firstKey = this.recentMessageFingerprints.keys().next().value;
740
+ if (firstKey !== undefined) {
741
+ this.recentMessageFingerprints.delete(firstKey);
742
+ }
743
+ }
744
+ }
745
+ }
746
+ /**
747
+ * Send a notification to the default channel
748
+ *
749
+ * @param notification - Notification to send
750
+ */
751
+ async sendNotification(notification) {
752
+ const targetChannelId = notification.channelId || this.config?.defaultChannelId;
753
+ if (!targetChannelId) {
754
+ this.logger.warn('No channel configured for notification');
755
+ return;
756
+ }
757
+ const blocks = this.formatNotificationBlocks(notification);
758
+ await this.sendMessage({
759
+ channelId: targetChannelId,
760
+ text: `${notification.title}: ${notification.message}`,
761
+ blocks,
762
+ threadTs: notification.threadTs,
763
+ });
764
+ }
765
+ /**
766
+ * Format notification as Slack blocks
767
+ *
768
+ * @param notification - Notification to format
769
+ * @returns Slack blocks for the notification
770
+ */
771
+ formatNotificationBlocks(notification) {
772
+ const urgencyEmoji = {
773
+ low: ':white_circle:',
774
+ normal: ':large_blue_circle:',
775
+ high: ':large_orange_circle:',
776
+ critical: ':red_circle:',
777
+ };
778
+ const blocks = [
779
+ {
780
+ type: 'header',
781
+ text: {
782
+ type: 'plain_text',
783
+ text: `${urgencyEmoji[notification.urgency]} ${notification.title}`,
784
+ emoji: true,
785
+ },
786
+ },
787
+ {
788
+ type: 'section',
789
+ text: {
790
+ type: 'mrkdwn',
791
+ text: notification.message,
792
+ },
793
+ },
794
+ ];
795
+ // Context block elements are text objects where `text` is a plain string.
796
+ // Using type assertion because SlackElement.text is typed as SlackTextObject
797
+ // but Slack API context elements use text objects directly as elements.
798
+ blocks.push({
799
+ type: 'context',
800
+ elements: [
801
+ {
802
+ type: 'mrkdwn',
803
+ text: `Sent at ${new Date(notification.timestamp).toLocaleString()}`,
804
+ },
805
+ ],
806
+ });
807
+ return blocks;
808
+ }
809
+ /**
810
+ * Update a message
811
+ *
812
+ * @param channelId - Channel ID
813
+ * @param messageTs - Message timestamp
814
+ * @param text - New text
815
+ * @param blocks - Optional new blocks
816
+ */
817
+ async updateMessage(channelId, messageTs, text, blocks) {
818
+ if (!this.client) {
819
+ throw new Error('Slack client not initialized');
820
+ }
821
+ await this.client.chat.update({
822
+ channel: channelId,
823
+ ts: messageTs,
824
+ text,
825
+ blocks,
826
+ });
827
+ }
828
+ /**
829
+ * Add a reaction to a message
830
+ *
831
+ * @param channelId - Channel ID
832
+ * @param messageTs - Message timestamp
833
+ * @param emoji - Emoji name (without colons)
834
+ */
835
+ async addReaction(channelId, messageTs, emoji) {
836
+ if (!this.client) {
837
+ throw new Error('Slack client not initialized');
838
+ }
839
+ await this.client.reactions.add({
840
+ channel: channelId,
841
+ timestamp: messageTs,
842
+ name: emoji,
843
+ });
844
+ }
845
+ /**
846
+ * Get or create conversation context for a thread
847
+ *
848
+ * @param threadTs - Thread timestamp
849
+ * @param channelId - Channel ID
850
+ * @param userId - User ID
851
+ * @returns Conversation context
852
+ */
853
+ getConversationContext(threadTs, channelId, userId) {
854
+ const key = `${channelId}:${threadTs}`;
855
+ // NOTE: This is intentionally NOT `synthesizeSlackConversationId`
856
+ // (chat-v2/legacy-dto.utils.ts). That helper produces the chat-v2
857
+ // channel id by replacing the single dot in the Slack ts. The id
858
+ // built here is for an in-memory `SlackConversationContext` map keyed
859
+ // by a broader sanitized form (any non-alphanumeric → `-`) and may
860
+ // diverge from the chat-v2 channel id by design. Do not "unify" —
861
+ // see the 2026-05-15 review of PR #547 for the discussion.
862
+ const conversationId = `slack-${channelId}-${threadTs}`.replace(/[^A-Za-z0-9_-]/g, '-');
863
+ let context = this.conversationContexts.get(key);
864
+ if (!context) {
865
+ context = {
866
+ threadTs,
867
+ channelId,
868
+ userId,
869
+ conversationId,
870
+ startedAt: new Date().toISOString(),
871
+ lastActivityAt: new Date().toISOString(),
872
+ messageCount: 0,
873
+ };
874
+ this.conversationContexts.set(key, context);
875
+ }
876
+ else if (context.conversationId !== conversationId) {
877
+ context.conversationId = conversationId;
878
+ }
879
+ context.lastActivityAt = new Date().toISOString();
880
+ context.messageCount++;
881
+ return context;
882
+ }
883
+ /**
884
+ * Get service status
885
+ *
886
+ * @returns Current service status
887
+ */
888
+ getStatus() {
889
+ return { ...this.status };
890
+ }
891
+ /**
892
+ * Check if service is connected
893
+ *
894
+ * @returns True if connected
895
+ */
896
+ isConnected() {
897
+ return this.status.connected;
898
+ }
899
+ /**
900
+ * Get the bot token used to initialize the Slack client.
901
+ * Required for downloading private files from Slack.
902
+ *
903
+ * @returns The bot token string, or null if not initialized
904
+ */
905
+ getBotToken() {
906
+ return this.config?.botToken || null;
907
+ }
908
+ /**
909
+ * Upload an image file to a Slack channel.
910
+ *
911
+ * Delegates to the shared upload-with-retry logic.
912
+ * Kept as a separate public method for backward compatibility
913
+ * with callers that use the image-specific endpoint.
914
+ *
915
+ * @param options - Upload configuration
916
+ * @returns Object with the uploaded file ID
917
+ * @throws Error if the client is not initialized or upload fails
918
+ */
919
+ async uploadImage(options) {
920
+ return this.uploadWithRetry(options, SLACK_IMAGE_CONSTANTS);
921
+ }
922
+ /**
923
+ * Upload any supported file to a Slack channel.
924
+ *
925
+ * Delegates to the shared upload-with-retry logic.
926
+ * Works for PDFs, images, documents, and other file types supported by Slack.
927
+ *
928
+ * @param options - Upload configuration
929
+ * @returns Object with the uploaded file ID
930
+ * @throws Error if the client is not initialized or upload fails
931
+ */
932
+ async uploadFile(options) {
933
+ return this.uploadWithRetry(options, SLACK_FILE_UPLOAD_CONSTANTS);
934
+ }
935
+ /**
936
+ * Shared upload logic with retry/backoff for Slack rate limits.
937
+ *
938
+ * Reads the file from disk and uploads via files.uploadV2.
939
+ * Retries on 429 responses with exponential backoff capped at 60s.
940
+ *
941
+ * @param options - Upload configuration (channel, path, filename, etc.)
942
+ * @param constants - Constants object providing UPLOAD_MAX_RETRIES and UPLOAD_DEFAULT_BACKOFF_MS
943
+ * @returns Object with the uploaded file ID
944
+ * @throws Error if the client is not initialized, retries exhausted, or a non-rate-limit error occurs
945
+ */
946
+ async uploadWithRetry(options, constants) {
947
+ if (!this.client) {
948
+ throw new Error('Slack client not initialized');
949
+ }
950
+ const filename = options.filename || basename(options.filePath);
951
+ const maxRetries = constants.UPLOAD_MAX_RETRIES;
952
+ const MAX_BACKOFF_MS = 60_000;
953
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
954
+ const fileStream = createReadStream(options.filePath);
955
+ try {
956
+ const result = await this.client.files.uploadV2({
957
+ channel_id: options.channelId,
958
+ file: fileStream,
959
+ filename,
960
+ title: options.title,
961
+ initial_comment: options.initialComment,
962
+ thread_ts: options.threadTs,
963
+ });
964
+ this.status.messagesSent++;
965
+ return { fileId: result.files?.[0]?.id };
966
+ }
967
+ catch (error) {
968
+ fileStream.destroy();
969
+ const isRateLimit = this.isRateLimitError(error);
970
+ if (isRateLimit && attempt < maxRetries) {
971
+ const rawMs = this.extractRetryAfterMs(error) || constants.UPLOAD_DEFAULT_BACKOFF_MS;
972
+ const retryAfterMs = Math.min(rawMs, MAX_BACKOFF_MS);
973
+ this.logger.warn('Upload rate-limited (429), retrying', { retryAfterMs, attempt: attempt + 1, maxRetries });
974
+ await new Promise(resolve => setTimeout(resolve, retryAfterMs));
975
+ continue;
976
+ }
977
+ this.logger.error('Upload error', { error: error instanceof Error ? error.message : String(error) });
978
+ throw error;
979
+ }
980
+ }
981
+ throw new Error('Upload failed after maximum retries');
982
+ }
983
+ /**
984
+ * Check if an error is a Slack 429 rate limit error.
985
+ *
986
+ * @param error - The caught error
987
+ * @returns True if the error represents a 429 rate limit response
988
+ */
989
+ isRateLimitError(error) {
990
+ if (error && typeof error === 'object') {
991
+ const err = error;
992
+ // @slack/web-api throws errors with code 'slack_webapi_rate_limited_error'
993
+ if (err.code === 'slack_webapi_rate_limited_error')
994
+ return true;
995
+ // Also check for status 429 in case of raw HTTP errors
996
+ if (err.statusCode === 429 || err.status === 429)
997
+ return true;
998
+ }
999
+ return false;
1000
+ }
1001
+ /**
1002
+ * Extract the retry-after delay from a Slack rate limit error.
1003
+ *
1004
+ * @param error - The caught error
1005
+ * @returns Retry delay in milliseconds, or null if not found
1006
+ */
1007
+ extractRetryAfterMs(error) {
1008
+ if (error && typeof error === 'object') {
1009
+ const err = error;
1010
+ // @slack/web-api attaches retryAfter (seconds) to the error
1011
+ if (typeof err.retryAfter === 'number') {
1012
+ return err.retryAfter * 1000;
1013
+ }
1014
+ // Check headers in case of raw response
1015
+ const headers = err.headers;
1016
+ if (headers?.['retry-after']) {
1017
+ const seconds = parseInt(headers['retry-after'], 10);
1018
+ if (!isNaN(seconds))
1019
+ return seconds * 1000;
1020
+ }
1021
+ }
1022
+ return null;
1023
+ }
1024
+ /**
1025
+ * Disconnect from Slack
1026
+ */
1027
+ async disconnect() {
1028
+ this.intentionalDisconnect = true;
1029
+ this.cancelReconnectGrace();
1030
+ this.stopHealthCheck();
1031
+ if (this.app) {
1032
+ await this.app.stop();
1033
+ this.status.connected = false;
1034
+ this.emit('disconnected');
1035
+ this.logger.info('Disconnected');
1036
+ }
1037
+ }
1038
+ /**
1039
+ * Get file info from Slack via the files.info API.
1040
+ * Requires the bot token to have `files:read` scope.
1041
+ *
1042
+ * @param fileId - Slack file ID (e.g., F0123ABC456)
1043
+ * @returns Object with private download URLs
1044
+ * @throws Error if the client is not initialized or API call fails
1045
+ */
1046
+ async getFileInfo(fileId) {
1047
+ if (!this.client) {
1048
+ throw new Error('Slack client not initialized');
1049
+ }
1050
+ const result = await this.client.files.info({ file: fileId });
1051
+ return {
1052
+ url_private: result.file?.url_private || '',
1053
+ url_private_download: result.file?.url_private_download || '',
1054
+ };
1055
+ }
1056
+ /**
1057
+ * Get user info from Slack
1058
+ *
1059
+ * @param userId - Slack user ID
1060
+ * @returns User info object
1061
+ */
1062
+ async getUserInfo(userId) {
1063
+ if (!this.client) {
1064
+ throw new Error('Slack client not initialized');
1065
+ }
1066
+ const result = await this.client.users.info({ user: userId });
1067
+ return {
1068
+ name: result.user?.name || userId,
1069
+ realName: result.user?.real_name || userId,
1070
+ email: result.user?.profile?.email,
1071
+ };
1072
+ }
1073
+ }
1074
+ /**
1075
+ * Get the SlackService singleton instance
1076
+ *
1077
+ * @returns SlackService instance
1078
+ */
1079
+ export function getSlackService() {
1080
+ if (!slackServiceInstance) {
1081
+ slackServiceInstance = new SlackService();
1082
+ }
1083
+ return slackServiceInstance;
1084
+ }
1085
+ /**
1086
+ * Reset the SlackService instance (for testing)
1087
+ */
1088
+ export function resetSlackService() {
1089
+ if (slackServiceInstance) {
1090
+ slackServiceInstance.disconnect().catch(() => { });
1091
+ slackServiceInstance = null;
1092
+ }
1093
+ }
1094
+ //# sourceMappingURL=slack.service.js.map