crewly 1.20.356 → 1.20.359

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 (277) hide show
  1. package/config/constants.ts +11 -0
  2. package/dist/backend/backend/src/constants.d.ts +313 -17
  3. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  4. package/dist/backend/backend/src/constants.js +316 -17
  5. package/dist/backend/backend/src/constants.js.map +1 -1
  6. package/dist/backend/backend/src/index.d.ts +21 -0
  7. package/dist/backend/backend/src/index.d.ts.map +1 -1
  8. package/dist/backend/backend/src/index.js +232 -15
  9. package/dist/backend/backend/src/index.js.map +1 -1
  10. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts +10 -2
  11. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  12. package/dist/backend/backend/src/services/agent/agent-registration.service.js +27 -2
  13. package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
  14. package/dist/backend/backend/src/services/agent/fresh-task-conversation.service.d.ts +34 -1
  15. package/dist/backend/backend/src/services/agent/fresh-task-conversation.service.d.ts.map +1 -1
  16. package/dist/backend/backend/src/services/agent/fresh-task-conversation.service.js +69 -13
  17. package/dist/backend/backend/src/services/agent/fresh-task-conversation.service.js.map +1 -1
  18. package/dist/backend/backend/src/services/agent/idle-detection.service.d.ts +8 -0
  19. package/dist/backend/backend/src/services/agent/idle-detection.service.d.ts.map +1 -1
  20. package/dist/backend/backend/src/services/agent/idle-detection.service.js +26 -2
  21. package/dist/backend/backend/src/services/agent/idle-detection.service.js.map +1 -1
  22. package/dist/backend/backend/src/services/agent/resource-mode.service.d.ts +9 -0
  23. package/dist/backend/backend/src/services/agent/resource-mode.service.d.ts.map +1 -1
  24. package/dist/backend/backend/src/services/agent/resource-mode.service.js +16 -0
  25. package/dist/backend/backend/src/services/agent/resource-mode.service.js.map +1 -1
  26. package/dist/backend/backend/src/services/agent/runtime-session-recovery.d.ts +44 -3
  27. package/dist/backend/backend/src/services/agent/runtime-session-recovery.d.ts.map +1 -1
  28. package/dist/backend/backend/src/services/agent/runtime-session-recovery.js +126 -11
  29. package/dist/backend/backend/src/services/agent/runtime-session-recovery.js.map +1 -1
  30. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts +2 -0
  31. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -1
  32. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +9 -1
  33. package/dist/backend/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
  34. package/dist/backend/backend/src/services/memory/agent-memory-refresh.service.d.ts +150 -0
  35. package/dist/backend/backend/src/services/memory/agent-memory-refresh.service.d.ts.map +1 -0
  36. package/dist/backend/backend/src/services/memory/agent-memory-refresh.service.js +324 -0
  37. package/dist/backend/backend/src/services/memory/agent-memory-refresh.service.js.map +1 -0
  38. package/dist/backend/backend/src/services/memory/auto-learning.subscriber.d.ts +9 -7
  39. package/dist/backend/backend/src/services/memory/auto-learning.subscriber.d.ts.map +1 -1
  40. package/dist/backend/backend/src/services/memory/auto-learning.subscriber.js +19 -17
  41. package/dist/backend/backend/src/services/memory/auto-learning.subscriber.js.map +1 -1
  42. package/dist/backend/backend/src/services/memory/memory.service.d.ts.map +1 -1
  43. package/dist/backend/backend/src/services/memory/memory.service.js +11 -0
  44. package/dist/backend/backend/src/services/memory/memory.service.js.map +1 -1
  45. package/dist/backend/backend/src/services/memory/startup-briefing.service.d.ts +114 -0
  46. package/dist/backend/backend/src/services/memory/startup-briefing.service.d.ts.map +1 -0
  47. package/dist/backend/backend/src/services/memory/startup-briefing.service.js +345 -0
  48. package/dist/backend/backend/src/services/memory/startup-briefing.service.js.map +1 -0
  49. package/dist/backend/backend/src/services/messaging/owner-thread-sentinel.service.d.ts +33 -1
  50. package/dist/backend/backend/src/services/messaging/owner-thread-sentinel.service.d.ts.map +1 -1
  51. package/dist/backend/backend/src/services/messaging/owner-thread-sentinel.service.js +69 -4
  52. package/dist/backend/backend/src/services/messaging/owner-thread-sentinel.service.js.map +1 -1
  53. package/dist/backend/backend/src/services/messaging/owner-thread-sentinel.wiring.d.ts +24 -1
  54. package/dist/backend/backend/src/services/messaging/owner-thread-sentinel.wiring.d.ts.map +1 -1
  55. package/dist/backend/backend/src/services/messaging/owner-thread-sentinel.wiring.js +54 -3
  56. package/dist/backend/backend/src/services/messaging/owner-thread-sentinel.wiring.js.map +1 -1
  57. package/dist/backend/backend/src/services/orc/owner-completion-report.service.d.ts +9 -0
  58. package/dist/backend/backend/src/services/orc/owner-completion-report.service.d.ts.map +1 -1
  59. package/dist/backend/backend/src/services/orc/owner-completion-report.service.js +16 -2
  60. package/dist/backend/backend/src/services/orc/owner-completion-report.service.js.map +1 -1
  61. package/dist/backend/backend/src/services/project-tickets/ticket-prefixes.d.ts +30 -0
  62. package/dist/backend/backend/src/services/project-tickets/ticket-prefixes.d.ts.map +1 -0
  63. package/dist/backend/backend/src/services/project-tickets/ticket-prefixes.js +48 -0
  64. package/dist/backend/backend/src/services/project-tickets/ticket-prefixes.js.map +1 -0
  65. package/dist/backend/backend/src/services/reconciler/reconciler.service.d.ts +8 -0
  66. package/dist/backend/backend/src/services/reconciler/reconciler.service.d.ts.map +1 -1
  67. package/dist/backend/backend/src/services/reconciler/reconciler.service.js +29 -8
  68. package/dist/backend/backend/src/services/reconciler/reconciler.service.js.map +1 -1
  69. package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.service.d.ts +27 -0
  70. package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.service.d.ts.map +1 -1
  71. package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.service.js +78 -24
  72. package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.service.js.map +1 -1
  73. package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.wiring.d.ts +23 -0
  74. package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.wiring.d.ts.map +1 -1
  75. package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.wiring.js +38 -1
  76. package/dist/backend/backend/src/services/runtime-fallback/runtime-fallback.wiring.js.map +1 -1
  77. package/dist/backend/backend/src/services/session/session-binding.d.ts +25 -2
  78. package/dist/backend/backend/src/services/session/session-binding.d.ts.map +1 -1
  79. package/dist/backend/backend/src/services/session/session-binding.js +32 -4
  80. package/dist/backend/backend/src/services/session/session-binding.js.map +1 -1
  81. package/dist/backend/backend/src/services/slack/agent-coordination.d.ts +119 -0
  82. package/dist/backend/backend/src/services/slack/agent-coordination.d.ts.map +1 -0
  83. package/dist/backend/backend/src/services/slack/agent-coordination.js +174 -0
  84. package/dist/backend/backend/src/services/slack/agent-coordination.js.map +1 -0
  85. package/dist/backend/backend/src/services/slack/slack-initializer.d.ts.map +1 -1
  86. package/dist/backend/backend/src/services/slack/slack-initializer.js +7 -0
  87. package/dist/backend/backend/src/services/slack/slack-initializer.js.map +1 -1
  88. package/dist/backend/backend/src/services/slack/slack-team-channel.service.d.ts +167 -0
  89. package/dist/backend/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
  90. package/dist/backend/backend/src/services/slack/slack-team-channel.service.js +619 -9
  91. package/dist/backend/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
  92. package/dist/backend/backend/src/services/slack/slack-thread-context.service.d.ts +22 -0
  93. package/dist/backend/backend/src/services/slack/slack-thread-context.service.d.ts.map +1 -1
  94. package/dist/backend/backend/src/services/slack/slack-thread-context.service.js +49 -12
  95. package/dist/backend/backend/src/services/slack/slack-thread-context.service.js.map +1 -1
  96. package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.d.ts +7 -0
  97. package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.d.ts.map +1 -1
  98. package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.js +25 -4
  99. package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.js.map +1 -1
  100. package/dist/backend/backend/src/services/team-move/team-move-chat.d.ts +21 -1
  101. package/dist/backend/backend/src/services/team-move/team-move-chat.d.ts.map +1 -1
  102. package/dist/backend/backend/src/services/team-move/team-move-chat.js +54 -2
  103. package/dist/backend/backend/src/services/team-move/team-move-chat.js.map +1 -1
  104. package/dist/backend/backend/src/services/team-move/team-move-exporter.d.ts +9 -4
  105. package/dist/backend/backend/src/services/team-move/team-move-exporter.d.ts.map +1 -1
  106. package/dist/backend/backend/src/services/team-move/team-move-exporter.js +32 -10
  107. package/dist/backend/backend/src/services/team-move/team-move-exporter.js.map +1 -1
  108. package/dist/backend/backend/src/services/team-move/team-move-importer.d.ts +19 -0
  109. package/dist/backend/backend/src/services/team-move/team-move-importer.d.ts.map +1 -1
  110. package/dist/backend/backend/src/services/team-move/team-move-importer.js +78 -3
  111. package/dist/backend/backend/src/services/team-move/team-move-importer.js.map +1 -1
  112. package/dist/backend/backend/src/services/team-move/team-move-runtime.d.ts.map +1 -1
  113. package/dist/backend/backend/src/services/team-move/team-move-runtime.js +8 -0
  114. package/dist/backend/backend/src/services/team-move/team-move-runtime.js.map +1 -1
  115. package/dist/backend/backend/src/services/team-move/team-move-transcripts.d.ts +106 -0
  116. package/dist/backend/backend/src/services/team-move/team-move-transcripts.d.ts.map +1 -0
  117. package/dist/backend/backend/src/services/team-move/team-move-transcripts.js +212 -0
  118. package/dist/backend/backend/src/services/team-move/team-move-transcripts.js.map +1 -0
  119. package/dist/backend/backend/src/services/team-move/team-move.types.d.ts +20 -0
  120. package/dist/backend/backend/src/services/team-move/team-move.types.d.ts.map +1 -1
  121. package/dist/backend/backend/src/services/team-move/team-move.types.js.map +1 -1
  122. package/dist/backend/backend/src/services/v3/agent-auto-claim.service.d.ts +2 -2
  123. package/dist/backend/backend/src/services/v3/agent-auto-claim.service.d.ts.map +1 -1
  124. package/dist/backend/backend/src/services/v3/agent-auto-claim.service.js +11 -4
  125. package/dist/backend/backend/src/services/v3/agent-auto-claim.service.js.map +1 -1
  126. package/dist/backend/backend/src/services/wiki/wiki-backlinks.service.d.ts.map +1 -1
  127. package/dist/backend/backend/src/services/wiki/wiki-backlinks.service.js +3 -0
  128. package/dist/backend/backend/src/services/wiki/wiki-backlinks.service.js.map +1 -1
  129. package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.d.ts.map +1 -1
  130. package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.js +4 -1
  131. package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.js.map +1 -1
  132. package/dist/backend/backend/src/services/wiki/wiki-cleanup.service.d.ts.map +1 -1
  133. package/dist/backend/backend/src/services/wiki/wiki-cleanup.service.js +4 -0
  134. package/dist/backend/backend/src/services/wiki/wiki-cleanup.service.js.map +1 -1
  135. package/dist/backend/backend/src/services/wiki/wiki-ingest.service.d.ts +36 -5
  136. package/dist/backend/backend/src/services/wiki/wiki-ingest.service.d.ts.map +1 -1
  137. package/dist/backend/backend/src/services/wiki/wiki-ingest.service.js +75 -7
  138. package/dist/backend/backend/src/services/wiki/wiki-ingest.service.js.map +1 -1
  139. package/dist/backend/backend/src/services/wiki/wiki-lint.service.d.ts.map +1 -1
  140. package/dist/backend/backend/src/services/wiki/wiki-lint.service.js +3 -1
  141. package/dist/backend/backend/src/services/wiki/wiki-lint.service.js.map +1 -1
  142. package/dist/backend/backend/src/services/wiki/wiki-log-compile.service.d.ts +141 -0
  143. package/dist/backend/backend/src/services/wiki/wiki-log-compile.service.d.ts.map +1 -0
  144. package/dist/backend/backend/src/services/wiki/wiki-log-compile.service.js +324 -0
  145. package/dist/backend/backend/src/services/wiki/wiki-log-compile.service.js.map +1 -0
  146. package/dist/backend/backend/src/services/wiki/wiki-log-entries.d.ts +142 -0
  147. package/dist/backend/backend/src/services/wiki/wiki-log-entries.d.ts.map +1 -0
  148. package/dist/backend/backend/src/services/wiki/wiki-log-entries.js +222 -0
  149. package/dist/backend/backend/src/services/wiki/wiki-log-entries.js.map +1 -0
  150. package/dist/backend/backend/src/services/wiki/wiki-log-rotation.service.d.ts +93 -0
  151. package/dist/backend/backend/src/services/wiki/wiki-log-rotation.service.d.ts.map +1 -0
  152. package/dist/backend/backend/src/services/wiki/wiki-log-rotation.service.js +142 -0
  153. package/dist/backend/backend/src/services/wiki/wiki-log-rotation.service.js.map +1 -0
  154. package/dist/backend/backend/src/services/wiki/wiki-maintenance.service.d.ts +104 -0
  155. package/dist/backend/backend/src/services/wiki/wiki-maintenance.service.d.ts.map +1 -0
  156. package/dist/backend/backend/src/services/wiki/wiki-maintenance.service.js +192 -0
  157. package/dist/backend/backend/src/services/wiki/wiki-maintenance.service.js.map +1 -0
  158. package/dist/backend/backend/src/services/wiki/wiki-query.service.d.ts +3 -2
  159. package/dist/backend/backend/src/services/wiki/wiki-query.service.d.ts.map +1 -1
  160. package/dist/backend/backend/src/services/wiki/wiki-query.service.js +23 -39
  161. package/dist/backend/backend/src/services/wiki/wiki-query.service.js.map +1 -1
  162. package/dist/backend/backend/src/services/wiki/wiki-queue-drain.service.d.ts +105 -0
  163. package/dist/backend/backend/src/services/wiki/wiki-queue-drain.service.d.ts.map +1 -0
  164. package/dist/backend/backend/src/services/wiki/wiki-queue-drain.service.js +195 -0
  165. package/dist/backend/backend/src/services/wiki/wiki-queue-drain.service.js.map +1 -0
  166. package/dist/backend/backend/src/services/wiki/wiki-recent.service.d.ts.map +1 -1
  167. package/dist/backend/backend/src/services/wiki/wiki-recent.service.js +3 -0
  168. package/dist/backend/backend/src/services/wiki/wiki-recent.service.js.map +1 -1
  169. package/dist/backend/backend/src/services/wiki/wiki-search.service.d.ts +28 -5
  170. package/dist/backend/backend/src/services/wiki/wiki-search.service.d.ts.map +1 -1
  171. package/dist/backend/backend/src/services/wiki/wiki-search.service.js +96 -25
  172. package/dist/backend/backend/src/services/wiki/wiki-search.service.js.map +1 -1
  173. package/dist/backend/backend/src/services/wiki/wiki-vault-walk.d.ts +11 -0
  174. package/dist/backend/backend/src/services/wiki/wiki-vault-walk.d.ts.map +1 -1
  175. package/dist/backend/backend/src/services/wiki/wiki-vault-walk.js +17 -1
  176. package/dist/backend/backend/src/services/wiki/wiki-vault-walk.js.map +1 -1
  177. package/dist/backend/backend/src/services/wiki/work-record-transcript.d.ts +64 -0
  178. package/dist/backend/backend/src/services/wiki/work-record-transcript.d.ts.map +1 -0
  179. package/dist/backend/backend/src/services/wiki/work-record-transcript.js +194 -0
  180. package/dist/backend/backend/src/services/wiki/work-record-transcript.js.map +1 -0
  181. package/dist/backend/backend/src/services/wiki/work-record.d.ts +239 -0
  182. package/dist/backend/backend/src/services/wiki/work-record.d.ts.map +1 -0
  183. package/dist/backend/backend/src/services/wiki/work-record.js +631 -0
  184. package/dist/backend/backend/src/services/wiki/work-record.js.map +1 -0
  185. package/dist/backend/backend/src/services/wiki/work-record.service.d.ts +209 -0
  186. package/dist/backend/backend/src/services/wiki/work-record.service.d.ts.map +1 -0
  187. package/dist/backend/backend/src/services/wiki/work-record.service.js +514 -0
  188. package/dist/backend/backend/src/services/wiki/work-record.service.js.map +1 -0
  189. package/dist/backend/build-info.json +2 -2
  190. package/dist/backend/config/constants.d.ts +11 -0
  191. package/dist/backend/config/constants.d.ts.map +1 -1
  192. package/dist/backend/config/constants.js +11 -0
  193. package/dist/backend/config/constants.js.map +1 -1
  194. package/dist/cli/backend/src/constants.d.ts +313 -17
  195. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  196. package/dist/cli/backend/src/constants.js +316 -17
  197. package/dist/cli/backend/src/constants.js.map +1 -1
  198. package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts +10 -2
  199. package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  200. package/dist/cli/backend/src/services/agent/agent-registration.service.js +27 -2
  201. package/dist/cli/backend/src/services/agent/agent-registration.service.js.map +1 -1
  202. package/dist/cli/backend/src/services/agent/fresh-task-conversation.service.d.ts +34 -1
  203. package/dist/cli/backend/src/services/agent/fresh-task-conversation.service.d.ts.map +1 -1
  204. package/dist/cli/backend/src/services/agent/fresh-task-conversation.service.js +69 -13
  205. package/dist/cli/backend/src/services/agent/fresh-task-conversation.service.js.map +1 -1
  206. package/dist/cli/backend/src/services/agent/resource-mode.service.d.ts +9 -0
  207. package/dist/cli/backend/src/services/agent/resource-mode.service.d.ts.map +1 -1
  208. package/dist/cli/backend/src/services/agent/resource-mode.service.js +16 -0
  209. package/dist/cli/backend/src/services/agent/resource-mode.service.js.map +1 -1
  210. package/dist/cli/backend/src/services/agent/runtime-session-recovery.d.ts +44 -3
  211. package/dist/cli/backend/src/services/agent/runtime-session-recovery.d.ts.map +1 -1
  212. package/dist/cli/backend/src/services/agent/runtime-session-recovery.js +126 -11
  213. package/dist/cli/backend/src/services/agent/runtime-session-recovery.js.map +1 -1
  214. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts +2 -0
  215. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.d.ts.map +1 -1
  216. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.js +9 -1
  217. package/dist/cli/backend/src/services/chat-v2/chat-v2.dispatcher.service.js.map +1 -1
  218. package/dist/cli/backend/src/services/memory/memory.service.d.ts.map +1 -1
  219. package/dist/cli/backend/src/services/memory/memory.service.js +11 -0
  220. package/dist/cli/backend/src/services/memory/memory.service.js.map +1 -1
  221. package/dist/cli/backend/src/services/memory/startup-briefing.service.d.ts +114 -0
  222. package/dist/cli/backend/src/services/memory/startup-briefing.service.d.ts.map +1 -0
  223. package/dist/cli/backend/src/services/memory/startup-briefing.service.js +345 -0
  224. package/dist/cli/backend/src/services/memory/startup-briefing.service.js.map +1 -0
  225. package/dist/cli/backend/src/services/messaging/owner-thread-sentinel.service.d.ts +33 -1
  226. package/dist/cli/backend/src/services/messaging/owner-thread-sentinel.service.d.ts.map +1 -1
  227. package/dist/cli/backend/src/services/messaging/owner-thread-sentinel.service.js +69 -4
  228. package/dist/cli/backend/src/services/messaging/owner-thread-sentinel.service.js.map +1 -1
  229. package/dist/cli/backend/src/services/slack/agent-coordination.d.ts +119 -0
  230. package/dist/cli/backend/src/services/slack/agent-coordination.d.ts.map +1 -0
  231. package/dist/cli/backend/src/services/slack/agent-coordination.js +174 -0
  232. package/dist/cli/backend/src/services/slack/agent-coordination.js.map +1 -0
  233. package/dist/cli/backend/src/services/slack/slack-team-channel.service.d.ts +167 -0
  234. package/dist/cli/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
  235. package/dist/cli/backend/src/services/slack/slack-team-channel.service.js +619 -9
  236. package/dist/cli/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
  237. package/dist/cli/backend/src/services/slack/slack-thread-context.service.d.ts +22 -0
  238. package/dist/cli/backend/src/services/slack/slack-thread-context.service.d.ts.map +1 -1
  239. package/dist/cli/backend/src/services/slack/slack-thread-context.service.js +49 -12
  240. package/dist/cli/backend/src/services/slack/slack-thread-context.service.js.map +1 -1
  241. package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.d.ts +7 -0
  242. package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.d.ts.map +1 -1
  243. package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.js +25 -4
  244. package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.js.map +1 -1
  245. package/dist/cli/backend/src/services/wiki/wiki-ingest.service.d.ts +36 -5
  246. package/dist/cli/backend/src/services/wiki/wiki-ingest.service.d.ts.map +1 -1
  247. package/dist/cli/backend/src/services/wiki/wiki-ingest.service.js +75 -7
  248. package/dist/cli/backend/src/services/wiki/wiki-ingest.service.js.map +1 -1
  249. package/dist/cli/backend/src/services/wiki/wiki-log-entries.d.ts +142 -0
  250. package/dist/cli/backend/src/services/wiki/wiki-log-entries.d.ts.map +1 -0
  251. package/dist/cli/backend/src/services/wiki/wiki-log-entries.js +222 -0
  252. package/dist/cli/backend/src/services/wiki/wiki-log-entries.js.map +1 -0
  253. package/dist/cli/backend/src/services/wiki/wiki-recent.service.d.ts +51 -0
  254. package/dist/cli/backend/src/services/wiki/wiki-recent.service.d.ts.map +1 -0
  255. package/dist/cli/backend/src/services/wiki/wiki-recent.service.js +105 -0
  256. package/dist/cli/backend/src/services/wiki/wiki-recent.service.js.map +1 -0
  257. package/dist/cli/backend/src/services/wiki/wiki-search.service.d.ts +28 -5
  258. package/dist/cli/backend/src/services/wiki/wiki-search.service.d.ts.map +1 -1
  259. package/dist/cli/backend/src/services/wiki/wiki-search.service.js +96 -25
  260. package/dist/cli/backend/src/services/wiki/wiki-search.service.js.map +1 -1
  261. package/dist/cli/backend/src/services/wiki/wiki-vault-walk.d.ts +11 -0
  262. package/dist/cli/backend/src/services/wiki/wiki-vault-walk.d.ts.map +1 -1
  263. package/dist/cli/backend/src/services/wiki/wiki-vault-walk.js +17 -1
  264. package/dist/cli/backend/src/services/wiki/wiki-vault-walk.js.map +1 -1
  265. package/dist/cli/backend/src/services/wiki/work-record-transcript.d.ts +64 -0
  266. package/dist/cli/backend/src/services/wiki/work-record-transcript.d.ts.map +1 -0
  267. package/dist/cli/backend/src/services/wiki/work-record-transcript.js +194 -0
  268. package/dist/cli/backend/src/services/wiki/work-record-transcript.js.map +1 -0
  269. package/dist/cli/backend/src/services/wiki/work-record.d.ts +239 -0
  270. package/dist/cli/backend/src/services/wiki/work-record.d.ts.map +1 -0
  271. package/dist/cli/backend/src/services/wiki/work-record.js +631 -0
  272. package/dist/cli/backend/src/services/wiki/work-record.js.map +1 -0
  273. package/dist/cli/config/constants.d.ts +11 -0
  274. package/dist/cli/config/constants.d.ts.map +1 -1
  275. package/dist/cli/config/constants.js +11 -0
  276. package/dist/cli/config/constants.js.map +1 -1
  277. package/package.json +1 -1
@@ -0,0 +1,631 @@
1
+ /**
2
+ * Work records (#1349) — the pure half.
3
+ *
4
+ * A work record is one structured `(record)` entry in a vault's activity log
5
+ * describing a finished (or long-blocked) task: who asked for it, who did it,
6
+ * what came out, what went wrong on the way and how it was resolved, who was
7
+ * pulled in, and how it ended. This module knows the shape, assembles a
8
+ * record from already-loaded inputs (no I/O, so fixtures can drive it),
9
+ * renders it as a log body, and parses a body back for the digest and the
10
+ * startup briefing.
11
+ *
12
+ * Owner-facing lines never carry ticket ids or WorkItem ids; those live on
13
+ * the `meta:` line, which the digest reads but never renders.
14
+ *
15
+ * Body layout (one field per line, parse-friendly):
16
+ *
17
+ * (record) **<title>** — <outcome phrase>
18
+ * asked by: <who> — "<quote>"
19
+ * done by: <name>
20
+ * did: <summary>
21
+ * outputs: <a>; <b>
22
+ * errors: <what> (fixed); <what> (unresolved)
23
+ * helpers: delegated to Leo: "<title>" → done; asked Ella → answered; reviewed by Owen
24
+ * outcome: <phrase>
25
+ * meta: wi=<id> phase=final status=verified asked_by=owen:lead done_by=nova …
26
+ *
27
+ * @module services/wiki/work-record
28
+ */
29
+ import { WORK_RECORD_CONSTANTS } from '../../constants.js';
30
+ import { TICKET_CONSTANTS } from '../../constants.js';
31
+ import { stripTicketIds } from '../slack/agent-coordination.js';
32
+ const C = WORK_RECORD_CONSTANTS;
33
+ const UUID_RE = /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}(?::[A-Za-z]+:[0-9a-f-]+)*\b/gi;
34
+ const WORK_ITEM_WORD_RE = /\b(?:WorkItem|work item)\s+(?=\[?[0-9a-f]{8}-)/gi;
35
+ const URL_RE = /https?:\/\/[^\s)"'<>]+/g;
36
+ /**
37
+ * `work-record:<workItemId>#<phase>` — the entry's `ref:` and its dedupe key.
38
+ *
39
+ * @param workItemId - WorkItem id
40
+ * @param phase - Record phase
41
+ * @returns Stable ref
42
+ */
43
+ export function workRecordRef(workItemId, phase) {
44
+ return `${C.REF_PREFIX}${workItemId}#${phase}`;
45
+ }
46
+ /**
47
+ * Parse a record ref back into its parts.
48
+ *
49
+ * @param ref - `ref:` value
50
+ * @returns Parts, or null when it is not a record ref
51
+ */
52
+ export function parseWorkRecordRef(ref) {
53
+ if (!ref.startsWith(C.REF_PREFIX))
54
+ return null;
55
+ const rest = ref.slice(C.REF_PREFIX.length);
56
+ const hash = rest.lastIndexOf('#');
57
+ if (hash <= 0)
58
+ return null;
59
+ const phase = rest.slice(hash + 1);
60
+ if (phase !== 'final' && phase !== 'blocked')
61
+ return null;
62
+ return { workItemId: rest.slice(0, hash), phase };
63
+ }
64
+ /**
65
+ * Whether a log entry is a work record.
66
+ *
67
+ * @param entry - Parsed log entry
68
+ * @returns True for `work_record` entries (by source type or ref)
69
+ */
70
+ export function isWorkRecordEntry(entry) {
71
+ return entry.sourceType === C.SOURCE_TYPE || entry.ref.startsWith(C.REF_PREFIX);
72
+ }
73
+ /**
74
+ * Whether a WorkItem is the verify item of another (`<id>:verify:<id>` or
75
+ * `metadata.verifyOf`). Verify items are folded into the parent's record.
76
+ *
77
+ * @param wi - WorkItem
78
+ * @returns True for a verify item
79
+ */
80
+ export function isVerifyWorkItem(wi) {
81
+ return wi.id.includes(':verify:') || typeof wi.metadata?.verifyOf === 'string';
82
+ }
83
+ /**
84
+ * Whether a WorkItem gets a record at all: real work, not a verify item or a
85
+ * bookkeeping type.
86
+ *
87
+ * @param wi - WorkItem
88
+ * @returns True when the item is recordable
89
+ */
90
+ export function isRecordableWorkItem(wi) {
91
+ if (isVerifyWorkItem(wi))
92
+ return false;
93
+ return !C.SKIPPED_TYPES.includes(wi.type);
94
+ }
95
+ /**
96
+ * The moment an item stopped: `completedAt`, else `statusChangedAt`, else
97
+ * `createdAt`.
98
+ *
99
+ * @param wi - WorkItem
100
+ * @returns ISO time
101
+ */
102
+ export function workItemEndedAt(wi) {
103
+ return wi.completedAt ?? wi.statusChangedAt ?? wi.createdAt;
104
+ }
105
+ /**
106
+ * Owner-facing text: ticket ids, WorkItem ids and uuids removed, whitespace
107
+ * collapsed, clipped.
108
+ *
109
+ * @param text - Raw text
110
+ * @param prefixes - Ticket prefixes to strip
111
+ * @param max - Character cap
112
+ * @returns Clean one-line text
113
+ */
114
+ export function cleanOwnerText(text, prefixes = [], max = Number.MAX_SAFE_INTEGER) {
115
+ if (!text)
116
+ return '';
117
+ let out = text.replace(/\r?\n+/g, ' ');
118
+ out = out.replace(WORK_ITEM_WORD_RE, '').replace(UUID_RE, '');
119
+ out = stripTicketIds(out, prefixes);
120
+ out = out
121
+ .replace(/\s+/g, ' ')
122
+ .replace(/\(\s*\)/g, '')
123
+ .replace(/\s+([.,;:!?)])/g, '$1')
124
+ .replace(/^[\s—–:-]+/, '')
125
+ .trim();
126
+ return clip(out, max);
127
+ }
128
+ /**
129
+ * Clip to `max` characters with an ellipsis.
130
+ *
131
+ * @param text - Text
132
+ * @param max - Cap
133
+ * @returns Clipped text
134
+ */
135
+ export function clip(text, max) {
136
+ return text.length > max ? `${text.slice(0, Math.max(1, max - 1))}…` : text;
137
+ }
138
+ /**
139
+ * Assemble a record from loaded inputs. Pure.
140
+ *
141
+ * @param inputs - WorkItem, links, trace, transcript facts and name resolvers
142
+ * @returns The record
143
+ *
144
+ * @example
145
+ * ```typescript
146
+ * const record = assembleWorkRecord({ workItem, phase: 'final', ticket, children, trace, nameOf, kindOf });
147
+ * const body = renderWorkRecordBody(record);
148
+ * ```
149
+ */
150
+ export function assembleWorkRecord(inputs) {
151
+ const wi = inputs.workItem;
152
+ const prefixes = collectPrefixes(inputs);
153
+ const clean = (t, max) => cleanOwnerText(t, prefixes, max);
154
+ const doerSession = wi.target ?? '';
155
+ const doneBy = doerSession
156
+ ? { kind: inputs.kindOf(doerSession), name: inputs.nameOf(doerSession), session: doerSession }
157
+ : { kind: 'system', name: 'nobody (unassigned)' };
158
+ const origin = (wi.metadata?.origin ?? undefined);
159
+ const { askedBy, askedWhere, forOwner } = resolveAsker(wi, origin, inputs, prefixes);
160
+ const askQuote = clean(firstLine(inputs.ticket?.description) || firstLine(wi.description) || firstLine(inputs.request?.description) || firstLine(wi.briefMarkdown) || wi.title, C.QUOTE_MAX_CHARS);
161
+ const bag = { ...(wi.output ?? {}), ...(wi.result ?? {}) };
162
+ const did = clean(summaryOf(bag) || (wi.status === 'cancelled' ? wi.cancelReason : wi.status === 'blocked' ? wi.blockedReason : wi.error) || '', C.DID_MAX_CHARS);
163
+ const outputs = collectOutputs(wi, bag, inputs, prefixes);
164
+ const errors = collectErrors(wi, inputs, prefixes);
165
+ const helpers = collectHelpers(wi, inputs, prefixes);
166
+ const { outcome, outcomeBy, outcomeNote } = resolveOutcome(wi, inputs, prefixes);
167
+ const endedAt = inputs.phase === 'blocked' ? (wi.statusChangedAt ?? workItemEndedAt(wi)) : workItemEndedAt(wi);
168
+ const startMs = Date.parse(wi.startedAt ?? wi.createdAt);
169
+ const endMs = Date.parse(endedAt);
170
+ const durationMs = Number.isFinite(startMs) && Number.isFinite(endMs) && endMs > startMs ? endMs - startMs : undefined;
171
+ const meta = {
172
+ wi: wi.id,
173
+ phase: inputs.phase,
174
+ status: wi.status,
175
+ asked_by: `${metaToken(askedBy.session ?? askedBy.kind)}:${askedBy.kind}`,
176
+ done_by: metaToken(doneBy.session ?? doneBy.kind),
177
+ outcome,
178
+ };
179
+ if (inputs.ticket)
180
+ meta.ticket = inputs.ticket.id;
181
+ if (wi.requestId)
182
+ meta.request = wi.requestId;
183
+ if (wi.traceId)
184
+ meta.trace = wi.traceId;
185
+ if (typeof wi.metadata?.teamId === 'string')
186
+ meta.team = wi.metadata.teamId;
187
+ if (helpers.length)
188
+ meta.helpers = helpers.map((h) => `${metaToken(h.session ?? h.name)}:${h.how}`).join(',');
189
+ if (outcomeBy)
190
+ meta.outcome_by = metaToken(outcomeBy);
191
+ return {
192
+ workItemId: wi.id,
193
+ phase: inputs.phase,
194
+ title: clean(wi.title, 120) || 'Untitled task',
195
+ askedBy,
196
+ askedWhere,
197
+ forOwner,
198
+ askQuote,
199
+ doneBy,
200
+ did,
201
+ outputs,
202
+ errors,
203
+ helpers,
204
+ outcome,
205
+ outcomeBy,
206
+ outcomeNote,
207
+ endedAt,
208
+ durationMs,
209
+ meta,
210
+ };
211
+ }
212
+ /**
213
+ * Render a record as the log body. Always fits `MAX_CHARS`; the `meta:` line
214
+ * is never cut.
215
+ *
216
+ * @param record - Assembled record
217
+ * @returns Markdown body
218
+ */
219
+ export function renderWorkRecordBody(record) {
220
+ const asked = [
221
+ `${record.askedBy.name}${partySuffix(record.askedBy)}`,
222
+ record.forOwner ? 'for the owner' : '',
223
+ record.askedWhere ? `(${record.askedWhere})` : '',
224
+ ].filter(Boolean).join(' ');
225
+ const lines = [
226
+ `(record) **${record.title}** — ${outcomePhrase(record)}`,
227
+ `asked by: ${asked}${record.askQuote ? ` — "${record.askQuote}"` : ''}`,
228
+ `done by: ${record.doneBy.name}`,
229
+ ];
230
+ if (record.did)
231
+ lines.push(`did: ${record.did}`);
232
+ if (record.outputs.length)
233
+ lines.push(`outputs: ${record.outputs.join('; ')}`);
234
+ if (record.errors.length)
235
+ lines.push(`errors: ${record.errors.map((e) => `${e.what} (${e.resolved})`).join('; ')}`);
236
+ if (record.helpers.length)
237
+ lines.push(`helpers: ${record.helpers.map(renderHelper).join('; ')}`);
238
+ lines.push(`outcome: ${outcomePhrase(record)}${record.outcomeNote ? ` — ${record.outcomeNote}` : ''}${record.durationMs ? `, ${humanDuration(record.durationMs)}` : ''}`);
239
+ const metaLine = `meta: ${Object.entries(record.meta).map(([k, v]) => `${k}=${v}`).join(' ')}`;
240
+ let body = lines.join('\n');
241
+ const budget = C.MAX_CHARS - metaLine.length - 1;
242
+ if (body.length > budget)
243
+ body = `${body.slice(0, Math.max(0, budget - 1)).replace(/\n[^\n]*$/, '')}\n…`;
244
+ return `${body}\n${metaLine}`;
245
+ }
246
+ /**
247
+ * Parse a record body written by {@link renderWorkRecordBody}.
248
+ *
249
+ * @param body - Log entry body
250
+ * @returns The fields, or null when the body is not a record
251
+ */
252
+ export function parseWorkRecordBody(body) {
253
+ const lines = body.split('\n');
254
+ const head = lines[0]?.match(/^\s*\(record\)\s+\*\*(.+?)\*\*(?:\s+—\s+(.*))?$/);
255
+ if (!head)
256
+ return null;
257
+ const fields = new Map();
258
+ for (const line of lines.slice(1)) {
259
+ const m = line.match(/^([a-z ]+):\s?(.*)$/);
260
+ if (m)
261
+ fields.set(m[1], m[2]);
262
+ }
263
+ const meta = {};
264
+ for (const token of (fields.get('meta') ?? '').split(/\s+/)) {
265
+ const eq = token.indexOf('=');
266
+ if (eq > 0)
267
+ meta[token.slice(0, eq)] = token.slice(eq + 1);
268
+ }
269
+ const helpers = [];
270
+ for (const part of splitList(fields.get('helpers'))) {
271
+ const h = part.match(/^(delegated to|asked|reviewed by)\s+(.+?)(?::\s|\s→\s|$)(.*)$/);
272
+ if (!h)
273
+ continue;
274
+ helpers.push({ how: h[1] === 'delegated to' ? 'delegated' : h[1] === 'asked' ? 'asked' : 'reviewed', name: h[2].trim(), rest: h[3].trim() });
275
+ }
276
+ const asked = fields.get('asked by') ?? '';
277
+ return {
278
+ title: head[1].trim(),
279
+ askedBy: asked.split(' — "')[0].trim(),
280
+ doneBy: (fields.get('done by') ?? '').trim(),
281
+ did: (fields.get('did') ?? '').trim(),
282
+ outputs: splitList(fields.get('outputs')),
283
+ errors: splitList(fields.get('errors')),
284
+ helpers,
285
+ outcome: (fields.get('outcome') ?? head[2] ?? '').trim(),
286
+ meta,
287
+ };
288
+ }
289
+ /**
290
+ * One-line form of a record for the startup briefing and the digest.
291
+ *
292
+ * @param parsed - Parsed record
293
+ * @param max - Character cap
294
+ * @returns `**Title** — asked by X, done by Y → outcome`
295
+ */
296
+ export function shortWorkRecordLine(parsed, max = C.BRIEFING_LINE_MAX_CHARS) {
297
+ const parts = [`**${clip(parsed.title, 80)}**`, `asked by ${parsed.askedBy || 'unknown'}`, `done by ${parsed.doneBy || 'unknown'}`];
298
+ if (parsed.outputs.length)
299
+ parts.push(`outputs: ${parsed.outputs.slice(0, 2).map((o) => clip(o, 60)).join('; ')}`);
300
+ const tail = ` → ${clip(parsed.outcome, 60)}`;
301
+ return `${clip(parts.join(' — '), Math.max(40, max - tail.length))}${tail}`;
302
+ }
303
+ // ---------------------------------------------------------------------------
304
+ // Assembly internals
305
+ // ---------------------------------------------------------------------------
306
+ function collectPrefixes(inputs) {
307
+ const out = new Set(inputs.ticketPrefixes ?? []);
308
+ const ticketId = inputs.ticket?.id ?? inputs.workItem.metadata?.projectTicket?.id;
309
+ if (typeof ticketId === 'string') {
310
+ const dash = ticketId.indexOf('-');
311
+ if (dash > 0)
312
+ out.add(ticketId.slice(0, dash));
313
+ }
314
+ out.add(TICKET_CONSTANTS.NUMBER_PREFIX.replace(/-$/, ''));
315
+ return [...out];
316
+ }
317
+ function firstLine(text) {
318
+ if (!text)
319
+ return '';
320
+ for (const raw of text.split('\n')) {
321
+ const line = raw.replace(/^#+\s*/, '').replace(/^\*\*[^*]+\*\*\s*/, '').trim();
322
+ if (line.length > 0)
323
+ return line;
324
+ }
325
+ return '';
326
+ }
327
+ function summaryOf(bag) {
328
+ for (const k of ['summary', 'message', 'text', 'verdict', 'reason']) {
329
+ const v = bag[k];
330
+ if (typeof v === 'string' && v.trim())
331
+ return v;
332
+ }
333
+ return '';
334
+ }
335
+ function resolveAsker(wi, origin, inputs, prefixes) {
336
+ const delegatedBy = typeof wi.metadata?.delegatedBy === 'string' ? wi.metadata.delegatedBy : undefined;
337
+ const forOwner = origin?.kind === 'owner';
338
+ const askedWhere = origin?.kind === 'owner' ? ownerPlace(origin) : undefined;
339
+ if (delegatedBy && delegatedBy !== wi.target) {
340
+ return { askedBy: { kind: inputs.kindOf(delegatedBy), name: inputs.nameOf(delegatedBy), session: delegatedBy }, askedWhere, forOwner };
341
+ }
342
+ if (origin?.kind === 'owner') {
343
+ return { askedBy: { kind: 'owner', name: 'the owner' }, askedWhere, forOwner: false };
344
+ }
345
+ if (origin?.kind === 'trigger') {
346
+ return { askedBy: { kind: 'schedule', name: `schedule "${cleanOwnerText(origin.topic, prefixes, 60)}"` }, forOwner: false };
347
+ }
348
+ const source = inputs.ticket?.source ?? inputs.request?.origin?.author;
349
+ if (typeof source === 'string') {
350
+ const session = source.replace(/^agent:/, '');
351
+ if (source === 'owner' || inputs.request?.origin?.channel === 'slack-dm' || inputs.request?.origin?.channel === 'portal') {
352
+ return { askedBy: { kind: 'owner', name: 'the owner' }, askedWhere: inputs.request?.origin?.channel, forOwner: false };
353
+ }
354
+ if (session && session !== wi.target && /^[a-z0-9][a-z0-9-]*$/i.test(session)) {
355
+ return { askedBy: { kind: inputs.kindOf(session), name: inputs.nameOf(session), session }, forOwner };
356
+ }
357
+ }
358
+ if (wi.owner === 'orchestrator')
359
+ return { askedBy: { kind: 'orchestrator', name: 'the orchestrator' }, forOwner };
360
+ if (wi.owner === 'team_lead')
361
+ return { askedBy: { kind: 'lead', name: 'the team lead' }, forOwner };
362
+ return { askedBy: { kind: 'system', name: 'Crewly (system)' }, forOwner };
363
+ }
364
+ function ownerPlace(origin) {
365
+ if (origin.appComment)
366
+ return 'app comment';
367
+ if (origin.slackChannelId && origin.threadTs)
368
+ return 'Slack thread';
369
+ if (origin.slackChannelId)
370
+ return 'Slack DM';
371
+ if (origin.conversationId)
372
+ return 'chat';
373
+ return 'owner message';
374
+ }
375
+ function collectOutputs(wi, bag, inputs, prefixes) {
376
+ const out = [];
377
+ const seen = new Set();
378
+ const push = (s) => {
379
+ const t = cleanOwnerText(s, prefixes, C.OUTPUT_MAX_CHARS);
380
+ if (!t || seen.has(t.toLowerCase()))
381
+ return;
382
+ seen.add(t.toLowerCase());
383
+ out.push(t);
384
+ };
385
+ const summary = summaryOf(bag);
386
+ for (const url of summary.match(URL_RE) ?? [])
387
+ push(url.replace(/[.,;:]+$/, ''));
388
+ const evidence = bag.evidence;
389
+ let checks = 0;
390
+ if (Array.isArray(evidence)) {
391
+ for (const e of evidence) {
392
+ if (e?.type === 'artifact' && typeof e.path === 'string')
393
+ push(e.path);
394
+ else if (e?.type === 'command' && typeof e.exitCode === 'number' && e.exitCode === 0)
395
+ checks++;
396
+ }
397
+ }
398
+ if (checks > 0)
399
+ push(`${checks} check${checks === 1 ? '' : 's'} passed`);
400
+ for (const k of ['files', 'artifacts', 'paths', 'evidencePaths', 'outputPaths', 'prUrl', 'pr', 'url']) {
401
+ const v = bag[k];
402
+ if (Array.isArray(v))
403
+ v.forEach((x) => typeof x === 'string' && push(x));
404
+ else if (typeof v === 'string')
405
+ push(v);
406
+ }
407
+ const t = inputs.transcript;
408
+ if (t) {
409
+ for (const u of t.urls)
410
+ push(u);
411
+ for (const c of t.commits)
412
+ push(`commit ${c}`);
413
+ for (const f of t.filesWritten)
414
+ push(f);
415
+ }
416
+ const posts = new Map();
417
+ for (const ev of inputs.trace ?? []) {
418
+ if (ev.type !== 'message.outbound' || ev.outcome !== 'ok' || ev.actor.session !== wi.target)
419
+ continue;
420
+ const place = placeFromSummary(ev.summary) ?? String(ev.data?.destination ?? ev.data?.source ?? 'message');
421
+ posts.set(place, (posts.get(place) ?? 0) + 1);
422
+ }
423
+ for (const [place, n] of posts)
424
+ push(`${n} message${n === 1 ? '' : 's'} posted (${place})`);
425
+ if (t && t.posts > 0 && posts.size === 0)
426
+ push(`${t.posts} message${t.posts === 1 ? '' : 's'} posted`);
427
+ return out.slice(0, C.MAX_OUTPUTS);
428
+ }
429
+ function placeFromSummary(summary) {
430
+ const m = summary.match(/→\s+(Slack|chat|app|WhatsApp)\b/i);
431
+ return m ? m[1] : null;
432
+ }
433
+ function collectErrors(wi, inputs, prefixes) {
434
+ const out = [];
435
+ const seen = new Set();
436
+ const push = (what, resolved) => {
437
+ const t = cleanOwnerText(what, prefixes, C.ERROR_MAX_CHARS);
438
+ if (!t)
439
+ return;
440
+ const key = t.toLowerCase();
441
+ if (seen.has(key))
442
+ return;
443
+ seen.add(key);
444
+ out.push({ what: t, resolved });
445
+ };
446
+ for (const e of inputs.transcript?.errors ?? [])
447
+ push(e.what, e.resolved);
448
+ for (const ev of inputs.trace ?? []) {
449
+ const mine = ev.actor.session === wi.target || ev.refs.workItemId === wi.id;
450
+ if (!mine)
451
+ continue;
452
+ if (ev.type === 'turn.error' || ev.type === 'error' || ev.type === 'guard.block')
453
+ push(ev.summary, finishedOk(wi) ? 'fixed' : 'unknown');
454
+ else if (ev.type === 'skill.call' && ev.outcome === 'failed')
455
+ push(`${String(ev.refs.skill ?? 'a skill call')} failed`, finishedOk(wi) ? 'fixed' : 'unknown');
456
+ else if (ev.type === 'message.outbound' && ev.outcome === 'failed')
457
+ push(ev.summary, 'unknown');
458
+ }
459
+ if (wi.retryCount > 0)
460
+ push(`retried ${wi.retryCount} time${wi.retryCount === 1 ? '' : 's'}${typeof wi.metadata?.lastFailureReason === 'string' ? `: ${wi.metadata.lastFailureReason}` : ''}`, finishedOk(wi) ? 'fixed' : 'unresolved');
461
+ if (wi.status === 'failed' && wi.error)
462
+ push(wi.error, 'unresolved');
463
+ return out.slice(0, C.MAX_ERRORS);
464
+ }
465
+ function finishedOk(wi) {
466
+ return wi.status === 'done' || wi.status === 'verified';
467
+ }
468
+ function collectHelpers(wi, inputs, prefixes) {
469
+ const out = [];
470
+ const doer = wi.target;
471
+ const startMs = Date.parse(wi.startedAt ?? wi.createdAt);
472
+ const endMs = Date.parse(workItemEndedAt(wi));
473
+ const verify = (inputs.children ?? []).find((c) => isVerifyWorkItem(c) && (c.metadata?.verifyOf === wi.id || c.id.startsWith(`${wi.id}:verify:`)));
474
+ for (const child of inputs.children ?? []) {
475
+ if (isVerifyWorkItem(child) || child.id === wi.id)
476
+ continue;
477
+ const byParent = child.parentWorkItemId === wi.id;
478
+ const createdMs = Date.parse(child.createdAt);
479
+ const byDoer = !!doer && child.metadata?.delegatedBy === doer && Number.isFinite(createdMs) && createdMs >= startMs - C.TRANSCRIPT_WINDOW_SLACK_MS && (!Number.isFinite(endMs) || createdMs <= endMs + C.TRANSCRIPT_WINDOW_SLACK_MS);
480
+ if (!byParent && !byDoer)
481
+ continue;
482
+ if (!child.target || child.target === doer)
483
+ continue;
484
+ out.push({ how: 'delegated', name: inputs.nameOf(child.target), session: child.target, what: cleanOwnerText(child.title, prefixes, 60), back: child.status });
485
+ }
486
+ const asked = new Map();
487
+ const dispatchers = new Set(['WorkItemDispatch']);
488
+ for (const ev of inputs.trace ?? []) {
489
+ if (ev.type !== 'message.agent' || !doer)
490
+ continue;
491
+ const from = ev.actor.session;
492
+ const to = ev.refs.session;
493
+ if (!from || !to || dispatchers.has(from))
494
+ continue;
495
+ if (from === doer && to !== doer && !out.some((h) => h.session === to)) {
496
+ if (!asked.has(to))
497
+ asked.set(to, { how: 'asked', name: inputs.nameOf(to), session: to, back: 'no answer' });
498
+ }
499
+ else if (to === doer && asked.has(from)) {
500
+ const h = asked.get(from);
501
+ if (h)
502
+ h.back = 'answered';
503
+ }
504
+ }
505
+ for (const ev of inputs.trace ?? []) {
506
+ if (ev.type !== 'turn.delivered' || !doer)
507
+ continue;
508
+ const sender = typeof ev.data?.sender === 'string' ? ev.data.sender : null;
509
+ if (sender && asked.has(sender) && ev.summary.includes(`delivered to ${doer}`)) {
510
+ const h = asked.get(sender);
511
+ if (h)
512
+ h.back = 'answered';
513
+ }
514
+ }
515
+ out.push(...asked.values());
516
+ const reviewer = verify?.target ?? (typeof wi.metadata?.reviewedBy === 'string' ? wi.metadata.reviewedBy : undefined);
517
+ if (reviewer && reviewer !== doer)
518
+ out.push({ how: 'reviewed', name: inputs.nameOf(reviewer), session: reviewer });
519
+ return out.slice(0, C.MAX_HELPERS);
520
+ }
521
+ function resolveOutcome(wi, inputs, prefixes) {
522
+ const reviewer = reviewerOf(wi, inputs);
523
+ const reviewerName = reviewer ? inputs.nameOf(reviewer) : undefined;
524
+ if (inputs.phase === 'blocked' || wi.status === 'blocked') {
525
+ return { outcome: 'blocked', outcomeNote: cleanOwnerText(wi.blockedReason, prefixes, 160) || undefined };
526
+ }
527
+ switch (wi.status) {
528
+ case 'cancelled':
529
+ return { outcome: 'cancelled', outcomeNote: cleanOwnerText(wi.cancelReason, prefixes, 160) || undefined };
530
+ case 'failed':
531
+ return { outcome: 'failed', outcomeNote: cleanOwnerText(wi.error, prefixes, 160) || undefined };
532
+ case 'rejected': {
533
+ const bag = { ...(wi.output ?? {}), ...(wi.result ?? {}) };
534
+ const note = typeof bag.rejectionReason === 'string' ? bag.rejectionReason : typeof bag.verdict === 'string' ? bag.verdict : undefined;
535
+ return { outcome: 'rejected', outcomeBy: reviewerName, outcomeNote: cleanOwnerText(note, prefixes, 160) || undefined };
536
+ }
537
+ default:
538
+ break;
539
+ }
540
+ // done / verified: the linked ticket decides whether the owner had a say.
541
+ const ticket = inputs.ticket;
542
+ const request = inputs.request;
543
+ if (request?.acceptedBy === 'silence' || request?.tags?.includes(TICKET_CONSTANTS.REVIEW.AUTO_ACCEPTED_TAG))
544
+ return { outcome: 'silence_accepted' };
545
+ if (request?.acceptedBy === 'owner')
546
+ return { outcome: 'owner_verified', outcomeBy: 'the owner' };
547
+ if (ticket?.ownerReview) {
548
+ if (ticket.status === 'done') {
549
+ if (ticket.labels.includes(TICKET_CONSTANTS.REVIEW.AUTO_ACCEPTED_TAG) || ticketLogSaysSilence(ticket))
550
+ return { outcome: 'silence_accepted' };
551
+ return { outcome: 'owner_verified', outcomeBy: 'the owner' };
552
+ }
553
+ if (ticket.status === 'review')
554
+ return { outcome: 'waiting_owner', outcomeBy: reviewerName };
555
+ }
556
+ if (wi.status === 'verified')
557
+ return { outcome: 'lead_verified', outcomeBy: reviewerName };
558
+ return { outcome: 'done' };
559
+ }
560
+ function reviewerOf(wi, inputs) {
561
+ const verify = (inputs.children ?? []).find((c) => isVerifyWorkItem(c) && (c.metadata?.verifyOf === wi.id || c.id.startsWith(`${wi.id}:verify:`)));
562
+ const r = verify?.target ?? (typeof wi.metadata?.reviewedBy === 'string' ? wi.metadata.reviewedBy : undefined);
563
+ return r && r !== wi.target ? r : undefined;
564
+ }
565
+ function ticketLogSaysSilence(ticket) {
566
+ const last = ticket.log[ticket.log.length - 1] ?? '';
567
+ return /auto[- ]accept|silence|no objection/i.test(last);
568
+ }
569
+ /**
570
+ * The outcome phrase used in the headline and the `outcome:` line.
571
+ *
572
+ * @param record - Record
573
+ * @returns Owner-facing phrase
574
+ */
575
+ export function outcomePhrase(record) {
576
+ switch (record.outcome) {
577
+ case 'owner_verified':
578
+ return 'verified by the owner';
579
+ case 'lead_verified':
580
+ return record.outcomeBy ? `verified by ${record.outcomeBy}` : 'verified';
581
+ case 'silence_accepted':
582
+ return 'accepted (no objection from the owner)';
583
+ case 'done':
584
+ return 'done (no review)';
585
+ case 'rejected':
586
+ return record.outcomeBy ? `rejected by ${record.outcomeBy}` : 'rejected';
587
+ case 'cancelled':
588
+ return 'cancelled';
589
+ case 'failed':
590
+ return 'failed';
591
+ case 'blocked':
592
+ return 'blocked';
593
+ case 'waiting_owner':
594
+ return "finished, waiting for the owner's OK";
595
+ default:
596
+ return String(record.outcome);
597
+ }
598
+ }
599
+ function partySuffix(party) {
600
+ if (party.kind === 'lead')
601
+ return ' (team lead)';
602
+ if (party.kind === 'orchestrator' && party.session)
603
+ return ' (orchestrator)';
604
+ return '';
605
+ }
606
+ function renderHelper(h) {
607
+ const line = h.how === 'delegated'
608
+ ? `delegated to ${h.name}: "${h.what ?? ''}" → ${h.back ?? 'open'}`
609
+ : h.how === 'asked'
610
+ ? `asked ${h.name} → ${h.back ?? 'no answer'}`
611
+ : `reviewed by ${h.name}`;
612
+ return clip(line, C.HELPER_MAX_CHARS);
613
+ }
614
+ function humanDuration(ms) {
615
+ const minutes = Math.round(ms / 60_000);
616
+ if (minutes < 1)
617
+ return 'under a minute';
618
+ if (minutes < 60)
619
+ return `${minutes} min`;
620
+ const hours = Math.round(minutes / 6) / 10;
621
+ if (hours < 48)
622
+ return `${hours} h`;
623
+ return `${Math.round(hours / 24)} d`;
624
+ }
625
+ function metaToken(value) {
626
+ return value.replace(/\s+/g, '_').replace(/[^A-Za-z0-9_.:-]/g, '');
627
+ }
628
+ function splitList(value) {
629
+ return (value ?? '').split(/;\s+/).map((s) => s.trim()).filter(Boolean);
630
+ }
631
+ //# sourceMappingURL=work-record.js.map