@overdeck/core 0.45.10 → 0.45.11

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 (219) hide show
  1. package/dist/{agent-state-KVbJEG5f.js → agent-state-RLhS7ckO.js} +1 -1
  2. package/dist/{agents-pp8FO7Uj.js → agents-By3u_fQ8.js} +1 -1
  3. package/dist/{agents-CQHK0CSA.js → agents-CgVr77Qq.js} +12 -12
  4. package/dist/{agents-CQHK0CSA.js.map → agents-CgVr77Qq.js.map} +1 -1
  5. package/dist/{backlog-auto-trigger-CyuoS0nl.js → backlog-auto-trigger-B_-1tk4e.js} +5 -5
  6. package/dist/{backlog-auto-trigger-CyuoS0nl.js.map → backlog-auto-trigger-B_-1tk4e.js.map} +1 -1
  7. package/dist/cli/index.js +45 -45
  8. package/dist/{cli-Cewlu3yU.js → cli-DGeSW85B.js} +2 -2
  9. package/dist/{cli-Cewlu3yU.js.map → cli-DGeSW85B.js.map} +1 -1
  10. package/dist/cli-MTB9IOoR.js +3 -0
  11. package/dist/{close-issue-BJGX9_z7.js → close-issue-Djajb6Sv.js} +2 -2
  12. package/dist/{close-issue-BJGX9_z7.js.map → close-issue-Djajb6Sv.js.map} +1 -1
  13. package/dist/{concurrency-Ca-fC7tA.js → concurrency-4rzjHAQA.js} +1 -1
  14. package/dist/{conversation-compaction-B_6s9EvM.js → conversation-compaction-BQvZh09I.js} +4 -4
  15. package/dist/{conversation-compaction-B_6s9EvM.js.map → conversation-compaction-BQvZh09I.js.map} +1 -1
  16. package/dist/dashboard/{advancing-selfheal-CMlGznKv.js → advancing-selfheal-BezNfM3P.js} +3 -3
  17. package/dist/dashboard/{advancing-selfheal-CMlGznKv.js.map → advancing-selfheal-BezNfM3P.js.map} +1 -1
  18. package/dist/dashboard/{agent-state-xk_G8t90.js → agent-state-BUANcaA7.js} +1 -1
  19. package/dist/dashboard/{agent-state-service-C1iUF9Ft.js → agent-state-service-DmFpIMbP.js} +1 -1
  20. package/dist/dashboard/{agent-state-service-5ge9xxhx.js → agent-state-service-tXUdp6UF.js} +2 -2
  21. package/dist/dashboard/{agent-state-service-5ge9xxhx.js.map → agent-state-service-tXUdp6UF.js.map} +1 -1
  22. package/dist/dashboard/{agents-BIggLvi_.js → agents-C-vqmKDi.js} +1 -1
  23. package/dist/dashboard/{agents-DHvsjsuP.js → agents-C7V4odQ6.js} +11 -11
  24. package/dist/dashboard/{agents-DHvsjsuP.js.map → agents-C7V4odQ6.js.map} +1 -1
  25. package/dist/dashboard/{backlog-auto-trigger-COm_R96V.js → backlog-auto-trigger-Cb8PR-5w.js} +2 -2
  26. package/dist/dashboard/{backlog-auto-trigger-COm_R96V.js.map → backlog-auto-trigger-Cb8PR-5w.js.map} +1 -1
  27. package/dist/dashboard/{cli-CvK9xuSS.js → cli-BgzbB6h3.js} +2 -2
  28. package/dist/dashboard/{cli-CvK9xuSS.js.map → cli-BgzbB6h3.js.map} +1 -1
  29. package/dist/dashboard/cli-DCqy_wFa.js +3 -0
  30. package/dist/dashboard/{close-issue-BnpErnD1.js → close-issue-BWf3pxn4.js} +2 -2
  31. package/dist/dashboard/{close-issue-BnpErnD1.js.map → close-issue-BWf3pxn4.js.map} +1 -1
  32. package/dist/dashboard/{closed-issue-reaper-DRqK5k39.js → closed-issue-reaper-D7XPq5pY.js} +4 -4
  33. package/dist/dashboard/{closed-issue-reaper-DRqK5k39.js.map → closed-issue-reaper-D7XPq5pY.js.map} +1 -1
  34. package/dist/dashboard/{closed-issue-reaper-BLCQwTpF.js → closed-issue-reaper-VSTSTROK.js} +1 -1
  35. package/dist/dashboard/{conflict-gate-JdFuhKuF.js → conflict-gate-DwOslTij.js} +1 -1
  36. package/dist/dashboard/{conflict-gate-BhKvrPxn.js → conflict-gate-FFEvTDVA.js} +3 -3
  37. package/dist/dashboard/{conflict-gate-BhKvrPxn.js.map → conflict-gate-FFEvTDVA.js.map} +1 -1
  38. package/dist/dashboard/{conversation-compaction-C5o_eKEm.js → conversation-compaction-CCqN4hWk.js} +4 -4
  39. package/dist/dashboard/{conversation-compaction-C5o_eKEm.js.map → conversation-compaction-CCqN4hWk.js.map} +1 -1
  40. package/dist/dashboard/{conversation-compaction-Ba5aZdrb.js → conversation-compaction-CL5Ti4j4.js} +1 -1
  41. package/dist/dashboard/{deacon-j3qSZ7--.js → deacon-CGHl90eC.js} +107 -50
  42. package/dist/dashboard/{deacon-j3qSZ7--.js.map → deacon-CGHl90eC.js.map} +1 -1
  43. package/dist/dashboard/{deacon-Cv2RMfHs.js → deacon-DMPh40Im.js} +2 -2
  44. package/dist/dashboard/deacon-swarm-CVTiNL0N.js +2 -0
  45. package/dist/dashboard/{deacon-swarm-DadWNi5J.js → deacon-swarm-aMMJTq6t.js} +4 -4
  46. package/dist/dashboard/{deacon-swarm-DadWNi5J.js.map → deacon-swarm-aMMJTq6t.js.map} +1 -1
  47. package/dist/dashboard/deacon.js +4 -4
  48. package/dist/dashboard/{feedback-target-oE4-Esxl.js → feedback-target-dJjFfITP.js} +4 -4
  49. package/dist/dashboard/{feedback-target-oE4-Esxl.js.map → feedback-target-dJjFfITP.js.map} +1 -1
  50. package/dist/dashboard/{feedback-target-C4DaDSZ8.js → feedback-target-nQSM6ygL.js} +1 -1
  51. package/dist/dashboard/{flywheel-ClMjGW_u.js → flywheel-BLoVNtJV.js} +6 -6
  52. package/dist/dashboard/{flywheel-ClMjGW_u.js.map → flywheel-BLoVNtJV.js.map} +1 -1
  53. package/dist/dashboard/{flywheel-DefHRzY4.js → flywheel-Cqf8vu7N.js} +6 -6
  54. package/dist/dashboard/{flywheel-DefHRzY4.js.map → flywheel-Cqf8vu7N.js.map} +1 -1
  55. package/dist/dashboard/{flywheel-BqDdGvrQ.js → flywheel-PJsbrXNY.js} +1 -1
  56. package/dist/dashboard/{flywheel-merge-order-CuDcqTRJ.js → flywheel-merge-order-B7BH8mZ3.js} +2 -2
  57. package/dist/dashboard/{flywheel-merge-order-CuDcqTRJ.js.map → flywheel-merge-order-B7BH8mZ3.js.map} +1 -1
  58. package/dist/dashboard/{flywheel-merge-order-B6YDSElh.js → flywheel-merge-order-CCwF60b-.js} +1 -1
  59. package/dist/dashboard/{harness-resolve-DKeSVsJL.js → harness-resolve-B3f9G1Kp.js} +2 -2
  60. package/dist/dashboard/{harness-resolve-DKeSVsJL.js.map → harness-resolve-B3f9G1Kp.js.map} +1 -1
  61. package/dist/dashboard/{inspect-agent-BKKc0XnB.js → inspect-agent-CKF5-SJr.js} +3 -3
  62. package/dist/dashboard/{inspect-agent-BKKc0XnB.js.map → inspect-agent-CKF5-SJr.js.map} +1 -1
  63. package/dist/dashboard/inspect-agent-CqpEWGWy.js +2 -0
  64. package/dist/dashboard/{issue-lifecycle-DnhQgddB.js → issue-lifecycle-5LbOcATP.js} +7 -7
  65. package/dist/dashboard/{issue-lifecycle-DnhQgddB.js.map → issue-lifecycle-5LbOcATP.js.map} +1 -1
  66. package/dist/dashboard/{issue-lifecycle-nY4esZn8.js → issue-lifecycle-CjYqQ669.js} +1 -1
  67. package/dist/dashboard/{issue-service-singleton-Bnqv1uaa.js → issue-service-singleton-B8iu_TKV.js} +1 -1
  68. package/dist/dashboard/{issue-service-singleton-_AquSBTl.js → issue-service-singleton-CDGt__oQ.js} +2 -2
  69. package/dist/dashboard/{issue-service-singleton-_AquSBTl.js.map → issue-service-singleton-CDGt__oQ.js.map} +1 -1
  70. package/dist/dashboard/{lifecycle-CGKm7doE.js → lifecycle-CEg4sHZH.js} +4 -4
  71. package/dist/dashboard/{lifecycle-CGKm7doE.js.map → lifecycle-CEg4sHZH.js.map} +1 -1
  72. package/dist/dashboard/{merge-agent-Dh8Y9PDO.js → merge-agent-7nBiCytp.js} +1 -1
  73. package/dist/dashboard/{merge-agent-BcgAYStl.js → merge-agent-C81xPIGd.js} +6 -6
  74. package/dist/dashboard/{merge-agent-BcgAYStl.js.map → merge-agent-C81xPIGd.js.map} +1 -1
  75. package/dist/dashboard/merge-ops-DE_6CnmZ.js +2 -0
  76. package/dist/dashboard/{merge-train-DmxlYbEo.js → merge-train-D3qzRccL.js} +2 -2
  77. package/dist/dashboard/{merge-train-DmxlYbEo.js.map → merge-train-D3qzRccL.js.map} +1 -1
  78. package/dist/dashboard/{merge-train-deps-DBHsOWt9.js → merge-train-deps-Be5ElC_P.js} +2 -2
  79. package/dist/dashboard/{merge-train-deps-DBHsOWt9.js.map → merge-train-deps-Be5ElC_P.js.map} +1 -1
  80. package/dist/dashboard/{orphan-proposed-reconciler-Db8tUhce.js → orphan-proposed-reconciler-Boq_XaRe.js} +3 -3
  81. package/dist/dashboard/{orphan-proposed-reconciler-Db8tUhce.js.map → orphan-proposed-reconciler-Boq_XaRe.js.map} +1 -1
  82. package/dist/dashboard/{orphan-proposed-reconciler-mXV--tcB.js → orphan-proposed-reconciler-C0sPnDq_.js} +1 -1
  83. package/dist/dashboard/{reconstruct-cache-_tDZ2D72.js → reconstruct-cache-C2pCltOq.js} +3 -3
  84. package/dist/dashboard/{reconstruct-cache-_tDZ2D72.js.map → reconstruct-cache-C2pCltOq.js.map} +1 -1
  85. package/dist/dashboard/{remote-completion-Bklh6loJ.js → remote-completion-BmxD5UMQ.js} +3 -3
  86. package/dist/dashboard/{remote-completion-Bklh6loJ.js.map → remote-completion-BmxD5UMQ.js.map} +1 -1
  87. package/dist/dashboard/resume-C-nxu9Y4.js +3 -0
  88. package/dist/dashboard/{review-agent-phzqNqIs.js → review-agent-D6P6d3pz.js} +26 -17
  89. package/dist/dashboard/review-agent-D6P6d3pz.js.map +1 -0
  90. package/dist/dashboard/review-agent-DTINEffB.js +3 -0
  91. package/dist/dashboard/{review-context-CCq56O_Y.js → review-context-Dyo0tsBa.js} +2 -2
  92. package/dist/dashboard/{review-context-CCq56O_Y.js.map → review-context-Dyo0tsBa.js.map} +1 -1
  93. package/dist/dashboard/{review-status-BQjqQXZG.js → review-status-B5ZASOo4.js} +18 -5
  94. package/dist/dashboard/review-status-B5ZASOo4.js.map +1 -0
  95. package/dist/dashboard/{review-status-bBkqUj5i.js → review-status-h7BXIA4z.js} +1 -1
  96. package/dist/dashboard/{review-verdict-feedback-wqnikhMK.js → review-verdict-feedback-B70VbfRL.js} +4 -4
  97. package/dist/dashboard/{review-verdict-feedback-wqnikhMK.js.map → review-verdict-feedback-B70VbfRL.js.map} +1 -1
  98. package/dist/dashboard/{review-verdict-feedback-cZh9Wi9G.js → review-verdict-feedback-CorgH49f.js} +1 -1
  99. package/dist/dashboard/{sequence-io-B2GmilSI.js → sequence-io-6YP8fVpH.js} +2 -2
  100. package/dist/dashboard/{sequence-io-B2GmilSI.js.map → sequence-io-6YP8fVpH.js.map} +1 -1
  101. package/dist/dashboard/{sequencer-agent-D8pW2aU_.js → sequencer-agent-ja-nkEc1.js} +5 -5
  102. package/dist/dashboard/{sequencer-agent-D8pW2aU_.js.map → sequencer-agent-ja-nkEc1.js.map} +1 -1
  103. package/dist/dashboard/server.js +66 -55
  104. package/dist/dashboard/server.js.map +1 -1
  105. package/dist/dashboard/{service-CILd-uOt.js → service-HKDrIy0h.js} +24 -24
  106. package/dist/dashboard/{service-CILd-uOt.js.map → service-HKDrIy0h.js.map} +1 -1
  107. package/dist/dashboard/{smart-compaction-Bgp_gwcA.js → smart-compaction-L0LSnF0_.js} +1 -1
  108. package/dist/dashboard/{smart-compaction-CrP90OFE.js → smart-compaction-uke1npUz.js} +2 -2
  109. package/dist/dashboard/{smart-compaction-CrP90OFE.js.map → smart-compaction-uke1npUz.js.map} +1 -1
  110. package/dist/dashboard/{spawn-planning-session-D15KbPOy.js → spawn-planning-session-CSMWco8B.js} +1 -1
  111. package/dist/dashboard/{spawn-planning-session-BmJWHSCu.js → spawn-planning-session-CXc0NkwV.js} +3 -3
  112. package/dist/dashboard/{spawn-planning-session-BmJWHSCu.js.map → spawn-planning-session-CXc0NkwV.js.map} +1 -1
  113. package/dist/dashboard/{specialist-context-CwKkcXL9.js → specialist-context-BGCJ24LH.js} +3 -3
  114. package/dist/dashboard/{specialist-context-CwKkcXL9.js.map → specialist-context-BGCJ24LH.js.map} +1 -1
  115. package/dist/dashboard/{specialist-logs-CvDxquV_.js → specialist-logs--Uz-r8ia.js} +2 -2
  116. package/dist/dashboard/{specialist-logs-CvDxquV_.js.map → specialist-logs--Uz-r8ia.js.map} +1 -1
  117. package/dist/dashboard/{specialists-BCjcG4uE.js → specialists-Ca9XSBCS.js} +1 -1
  118. package/dist/dashboard/{specialists-D07ybnam.js → specialists-DEfrAbWs.js} +36 -36
  119. package/dist/dashboard/{specialists-D07ybnam.js.map → specialists-DEfrAbWs.js.map} +1 -1
  120. package/dist/dashboard/{specialists-F2uMO4QS.js → specialists-DeZx9xom.js} +1 -1
  121. package/dist/dashboard/{specialists-BYi0k8CZ.js → specialists-nZ0mRwpZ.js} +12 -12
  122. package/dist/dashboard/{specialists-BYi0k8CZ.js.map → specialists-nZ0mRwpZ.js.map} +1 -1
  123. package/dist/dashboard/{summary-fork-DedqguZb.js → summary-fork-2a1L2DIU.js} +2 -2
  124. package/dist/dashboard/{summary-fork-EjvOkEPl.js → summary-fork-Xn0QUNmb.js} +3 -3
  125. package/dist/dashboard/{summary-fork-EjvOkEPl.js.map → summary-fork-Xn0QUNmb.js.map} +1 -1
  126. package/dist/dashboard/{teardown-workspace-5LCVbjfq.js → teardown-workspace-DhA6oAIK.js} +2 -2
  127. package/dist/dashboard/{teardown-workspace-5LCVbjfq.js.map → teardown-workspace-DhA6oAIK.js.map} +1 -1
  128. package/dist/dashboard/{test-agent-queue-qfsq6uaC.js → test-agent-queue-B_ukPyIK.js} +3 -3
  129. package/dist/dashboard/{test-agent-queue-qfsq6uaC.js.map → test-agent-queue-B_ukPyIK.js.map} +1 -1
  130. package/dist/dashboard/{uat-train-CtNGgXxj.js → uat-train-BLBAbJ8Y.js} +10 -10
  131. package/dist/dashboard/{uat-train-CtNGgXxj.js.map → uat-train-BLBAbJ8Y.js.map} +1 -1
  132. package/dist/dashboard/{uat-train-C3hWXtip.js → uat-train-DPfGR9_I.js} +1 -1
  133. package/dist/dashboard/{verification-runner-DuZRHjPU.js → verification-runner-KTGTNugM.js} +1 -1
  134. package/dist/dashboard/{verification-runner-BPAhPWR7.js → verification-runner-R2-4XgMO.js} +4 -4
  135. package/dist/dashboard/{verification-runner-BPAhPWR7.js.map → verification-runner-R2-4XgMO.js.map} +1 -1
  136. package/dist/dashboard/{workflows-H-COJ84X.js → workflows-CSKX5MhC.js} +7 -7
  137. package/dist/dashboard/{workflows-H-COJ84X.js.map → workflows-CSKX5MhC.js.map} +1 -1
  138. package/dist/dashboard/workflows-DVwXauef.js +2 -0
  139. package/dist/dashboard/{workspaces-CRU9_vRn.js → workspaces-DXLDgXo2.js} +32 -32
  140. package/dist/dashboard/{workspaces-CRU9_vRn.js.map → workspaces-DXLDgXo2.js.map} +1 -1
  141. package/dist/docs-index.sqlite +0 -0
  142. package/dist/{feedback-target-DTGAhFkM.js → feedback-target-BsKN4Tr_.js} +4 -4
  143. package/dist/{feedback-target-DTGAhFkM.js.map → feedback-target-BsKN4Tr_.js.map} +1 -1
  144. package/dist/{feedback-target-DutF088V.js → feedback-target-DM1WzOKy.js} +1 -1
  145. package/dist/{harness-resolve-Bz1prk6B.js → harness-resolve-B-YDNwNW.js} +2 -2
  146. package/dist/{harness-resolve-Bz1prk6B.js.map → harness-resolve-B-YDNwNW.js.map} +1 -1
  147. package/dist/{issue-lifecycle-fVqvCdKM.js → issue-lifecycle-Bc1l3U9f.js} +7 -7
  148. package/dist/{issue-lifecycle-fVqvCdKM.js.map → issue-lifecycle-Bc1l3U9f.js.map} +1 -1
  149. package/dist/{issue-service-singleton-CZm8p6Rj.js → issue-service-singleton-D-8Q6tdT.js} +1 -1
  150. package/dist/{issue-service-singleton-Cr73JAaR.js → issue-service-singleton-D1433I7n.js} +2 -2
  151. package/dist/{issue-service-singleton-Cr73JAaR.js.map → issue-service-singleton-D1433I7n.js.map} +1 -1
  152. package/dist/{lifecycle-CR6tZfl1.js → lifecycle-SmrqysDf.js} +7 -7
  153. package/dist/{lifecycle-CR6tZfl1.js.map → lifecycle-SmrqysDf.js.map} +1 -1
  154. package/dist/{lifecycle-D_EWiUjk.js → lifecycle-mRMyiIXs.js} +2 -2
  155. package/dist/{merge-agent-LM4avOtA.js → merge-agent-B9hIZ6Z0.js} +6 -6
  156. package/dist/{merge-agent-LM4avOtA.js.map → merge-agent-B9hIZ6Z0.js.map} +1 -1
  157. package/dist/{merge-agent-Bj046HE1.js → merge-agent-DUj22cXL.js} +1 -1
  158. package/dist/{merge-fulfillment-DrnC1Kmg.js → merge-fulfillment-__P4WE-T.js} +3 -3
  159. package/dist/{merge-fulfillment-DrnC1Kmg.js.map → merge-fulfillment-__P4WE-T.js.map} +1 -1
  160. package/dist/{reconstruct-cache-NPqoAUg-.js → reconstruct-cache-9SWp82SQ.js} +3 -3
  161. package/dist/{reconstruct-cache-NPqoAUg-.js.map → reconstruct-cache-9SWp82SQ.js.map} +1 -1
  162. package/dist/{records-BIkN1LQ4.js → records-CTmvuRzz.js} +14 -1
  163. package/dist/{records-BIkN1LQ4.js.map → records-CTmvuRzz.js.map} +1 -1
  164. package/dist/records-backfill-BQcmTmwF.js +2 -0
  165. package/dist/{records-backfill-HM0Pln6N.js → records-backfill-BrNsv_zT.js} +2 -2
  166. package/dist/{records-backfill-HM0Pln6N.js.map → records-backfill-BrNsv_zT.js.map} +1 -1
  167. package/dist/resume-Bn4kDk9x.js +3 -0
  168. package/dist/{review-agent-DFosQzCG.js → review-agent-PhqOhpx3.js} +24 -16
  169. package/dist/{review-agent-DFosQzCG.js.map → review-agent-PhqOhpx3.js.map} +1 -1
  170. package/dist/review-agent-hLbRRxZF.js +3 -0
  171. package/dist/{review-status-iJwfEoNX.js → review-status-B_XXomV0.js} +6 -6
  172. package/dist/{review-status-iJwfEoNX.js.map → review-status-B_XXomV0.js.map} +1 -1
  173. package/dist/{review-status-BbNVlXh1.js → review-status-Bo-EFVKh.js} +1 -1
  174. package/dist/{review-verdict-feedback-BGPw3z1X.js → review-verdict-feedback-CXHkoiKZ.js} +1 -1
  175. package/dist/{review-verdict-feedback-CCZ05atV.js → review-verdict-feedback-DGV13LDb.js} +4 -4
  176. package/dist/{review-verdict-feedback-CCZ05atV.js.map → review-verdict-feedback-DGV13LDb.js.map} +1 -1
  177. package/dist/{sequence-io-CcxZNHcD.js → sequence-io-Cg4NHAco.js} +1 -1
  178. package/dist/{sequence-io-Cx1usxG3.js → sequence-io-CyxvNHfA.js} +2 -2
  179. package/dist/{sequence-io-Cx1usxG3.js.map → sequence-io-CyxvNHfA.js.map} +1 -1
  180. package/dist/{smart-compaction-ByUEgQkF.js → smart-compaction-ByKXTQNy.js} +2 -2
  181. package/dist/{smart-compaction-ByUEgQkF.js.map → smart-compaction-ByKXTQNy.js.map} +1 -1
  182. package/dist/{smart-compaction-DfLe_CtH.js → smart-compaction-U6e_uB1E.js} +1 -1
  183. package/dist/{specialist-context-McuGkaeR.js → specialist-context-BUTadO-U.js} +3 -3
  184. package/dist/{specialist-context-McuGkaeR.js.map → specialist-context-BUTadO-U.js.map} +1 -1
  185. package/dist/{specialist-logs-CUUJ4eiB.js → specialist-logs-pEMCTtGZ.js} +2 -2
  186. package/dist/{specialist-logs-CUUJ4eiB.js.map → specialist-logs-pEMCTtGZ.js.map} +1 -1
  187. package/dist/{specialists-BSrylD1S.js → specialists-BGFnrQ8n.js} +1 -1
  188. package/dist/{specialists-B0elgInc.js → specialists-DeTkkp8b.js} +12 -12
  189. package/dist/{specialists-B0elgInc.js.map → specialists-DeTkkp8b.js.map} +1 -1
  190. package/dist/{summary-fork-DskMRnyb.js → summary-fork-CgzThE2-.js} +2 -2
  191. package/dist/{summary-fork-CPUTKcAT.js → summary-fork-Dx1RMuvU.js} +3 -3
  192. package/dist/{summary-fork-CPUTKcAT.js.map → summary-fork-Dx1RMuvU.js.map} +1 -1
  193. package/dist/{sync-BiNVQHBf.js → sync-Bsww9tuj.js} +2 -2
  194. package/dist/{sync-BiNVQHBf.js.map → sync-Bsww9tuj.js.map} +1 -1
  195. package/dist/sync-CylE_SjB.js +2 -0
  196. package/dist/{verdict-restore-DQiV7_fe.js → verdict-restore-DGpX0ZOJ.js} +5 -5
  197. package/dist/{verdict-restore-DQiV7_fe.js.map → verdict-restore-DGpX0ZOJ.js.map} +1 -1
  198. package/dist/{webhook-handlers-DHBSEDEm.js → webhook-handlers-BjsfIL7u.js} +3 -3
  199. package/dist/{webhook-handlers-DHBSEDEm.js.map → webhook-handlers-BjsfIL7u.js.map} +1 -1
  200. package/dist/{workspace-migrate-duUsWNpd.js → workspace-migrate-BBQ8nAnP.js} +2 -2
  201. package/dist/{workspace-migrate-duUsWNpd.js.map → workspace-migrate-BBQ8nAnP.js.map} +1 -1
  202. package/dist/{workspace-reap-DLCIoJmn.js → workspace-reap-12O9354k.js} +2 -2
  203. package/dist/{workspace-reap-DLCIoJmn.js.map → workspace-reap-12O9354k.js.map} +1 -1
  204. package/package.json +1 -1
  205. package/scripts/file-size-baseline.txt +1 -1
  206. package/dist/cli-DBWG12XK.js +0 -3
  207. package/dist/dashboard/cli-CJDWXE_Y.js +0 -3
  208. package/dist/dashboard/deacon-swarm-D1iAUX-P.js +0 -2
  209. package/dist/dashboard/inspect-agent-vm88mLYr.js +0 -2
  210. package/dist/dashboard/merge-ops-QdBiQ8XB.js +0 -2
  211. package/dist/dashboard/resume-DnIsmIgC.js +0 -3
  212. package/dist/dashboard/review-agent-DgySDb-G.js +0 -3
  213. package/dist/dashboard/review-agent-phzqNqIs.js.map +0 -1
  214. package/dist/dashboard/review-status-BQjqQXZG.js.map +0 -1
  215. package/dist/dashboard/workflows-Cz8OtiB4.js +0 -2
  216. package/dist/records-backfill-DEgtRyKL.js +0 -2
  217. package/dist/resume-DGymuXZM.js +0 -3
  218. package/dist/review-agent-DjVadURa.js +0 -3
  219. package/dist/sync-4jqukkxz.js +0 -2
@@ -1 +1 @@
1
- {"version":3,"file":"specialist-logs-CUUJ4eiB.js","names":[],"sources":["../src/lib/cloister/specialist-logs.ts"],"sourcesContent":["/**\n * Specialist Log Management\n *\n * Manages persistent log files for specialist agent runs.\n * Each run produces a structured log file with metadata, context, and full transcript.\n *\n * Directory structure:\n * ~/.overdeck/specialists/{projectKey}/{specialistType}/runs/{timestamp}-{issueId}.log\n */\n\nimport { existsSync, mkdirSync, writeFileSync, appendFileSync, readFileSync, readdirSync, statSync, unlinkSync } from 'fs';\nimport { join, basename } from 'path';\nimport { Data, Effect } from 'effect';\nimport { getOverdeckHome } from '../paths.js';\n\n/** Get specialists directory (lazy to support test env overrides) */\nfunction getSpecialistsDir(): string {\n return join(getOverdeckHome(), 'specialists');\n}\n\n/**\n * Log file metadata\n */\nexport interface RunLogMetadata {\n runId: string;\n project: string;\n specialistType: string;\n issueId: string;\n startedAt: string;\n finishedAt?: string;\n status?: 'passed' | 'failed' | 'blocked' | 'incomplete';\n duration?: number; // in milliseconds\n notes?: string;\n}\n\n/**\n * Run log entry for listing\n */\nexport interface RunLogEntry {\n runId: string;\n filePath: string;\n metadata: RunLogMetadata;\n fileSize: number;\n createdAt: Date;\n}\n\n/**\n * Get the runs directory for a project's specialist\n */\nexport function getRunsDirectory(projectKey: string, specialistType: string): string {\n return join(getSpecialistsDir(), projectKey, specialistType, 'runs');\n}\n\n/**\n * Generate a run ID from timestamp and issue ID\n */\nexport function generateRunId(issueId: string): string {\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-').substring(0, 19);\n return `${timestamp}-${issueId}`;\n}\n\n/**\n * Get the log file path for a run\n */\nexport function getRunLogPath(projectKey: string, specialistType: string, runId: string): string {\n const runsDir = getRunsDirectory(projectKey, specialistType);\n return join(runsDir, `${runId}.log`);\n}\n\n/**\n * Ensure runs directory exists for a project's specialist\n */\nfunction ensureRunsDirectory(projectKey: string, specialistType: string): void {\n const runsDir = getRunsDirectory(projectKey, specialistType);\n if (!existsSync(runsDir)) {\n mkdirSync(runsDir, { recursive: true });\n }\n}\n\n/**\n * Create a new run log file\n *\n * Initializes a log file with metadata header.\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type (review-agent, test-agent, merge-agent)\n * @param issueId - Issue ID being worked on\n * @param contextSeed - Optional context digest that was provided to the specialist\n * @returns Run ID and file path\n */\nexport function createRunLogSync(\n projectKey: string,\n specialistType: string,\n issueId: string,\n contextSeed?: string\n): { runId: string; filePath: string } {\n ensureRunsDirectory(projectKey, specialistType);\n\n const runId = generateRunId(issueId);\n const filePath = getRunLogPath(projectKey, specialistType, runId);\n const startedAt = new Date().toISOString();\n\n // Create log header\n const header = `# ${specialistType} Run - ${issueId}\nProject: ${projectKey}\nStarted: ${startedAt}\nIssue: ${issueId}\nRun ID: ${runId}\n\n## Context Seed\n${contextSeed ? contextSeed : '[No context digest available]'}\n\n## Session Transcript\n`;\n\n writeFileSync(filePath, header, 'utf-8');\n\n return { runId, filePath };\n}\n\n/**\n * Append content to a run log\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param runId - Run identifier\n * @param content - Content to append\n */\nexport function appendToRunLogSync(\n projectKey: string,\n specialistType: string,\n runId: string,\n content: string\n): void {\n const filePath = getRunLogPath(projectKey, specialistType, runId);\n\n if (!existsSync(filePath)) {\n throw new Error(`Run log not found: ${filePath}`);\n }\n\n appendFileSync(filePath, content, 'utf-8');\n}\n\n/**\n * Finalize a run log with result metadata\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param runId - Run identifier\n * @param result - Run result\n */\nexport function finalizeRunLogSync(\n projectKey: string,\n specialistType: string,\n runId: string,\n result: {\n status: 'passed' | 'failed' | 'blocked' | 'incomplete';\n notes?: string;\n }\n): void {\n const filePath = getRunLogPath(projectKey, specialistType, runId);\n\n if (!existsSync(filePath)) {\n throw new Error(`Run log not found: ${filePath}`);\n }\n\n // Read the log to extract start time\n const content = readFileSync(filePath, 'utf-8');\n const startMatch = content.match(/^Started: (.+)$/m);\n const startedAt = startMatch ? new Date(startMatch[1]) : new Date();\n const finishedAt = new Date();\n const duration = finishedAt.getTime() - startedAt.getTime();\n\n // Format duration\n const durationSeconds = Math.floor(duration / 1000);\n const minutes = Math.floor(durationSeconds / 60);\n const seconds = durationSeconds % 60;\n const durationStr = `${minutes}m ${seconds}s`;\n\n // Append result section\n const resultSection = `\n\n## Result\nStatus: ${result.status}\n${result.notes ? `Notes: ${result.notes}` : ''}\nDuration: ${durationStr}\nFinished: ${finishedAt.toISOString()}\n`;\n\n appendFileSync(filePath, resultSection, 'utf-8');\n}\n\n/**\n * Read a run log file\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param runId - Run identifier\n * @returns Log content or null if not found\n */\nexport function getRunLogSync(\n projectKey: string,\n specialistType: string,\n runId: string\n): string | null {\n const filePath = getRunLogPath(projectKey, specialistType, runId);\n\n if (!existsSync(filePath)) {\n return null;\n }\n\n try {\n return readFileSync(filePath, 'utf-8');\n } catch (error) {\n console.error(`Failed to read run log ${runId}:`, error);\n return null;\n }\n}\n\n/**\n * Parse metadata from a log file\n *\n * @param logContent - Log file content\n * @returns Parsed metadata\n */\nexport function parseLogMetadata(logContent: string): Partial<RunLogMetadata> {\n const metadata: Partial<RunLogMetadata> = {};\n\n // Extract metadata from header\n const projectMatch = logContent.match(/^Project: (.+)$/m);\n const startedMatch = logContent.match(/^Started: (.+)$/m);\n const issueMatch = logContent.match(/^Issue: (.+)$/m);\n const runIdMatch = logContent.match(/^Run ID: (.+)$/m);\n const statusMatch = logContent.match(/^Status: (.+)$/m);\n const notesMatch = logContent.match(/^Notes: (.+)$/m);\n const finishedMatch = logContent.match(/^Finished: (.+)$/m);\n const durationMatch = logContent.match(/^Duration: (.+)$/m);\n\n if (projectMatch) metadata.project = projectMatch[1].trim();\n if (startedMatch) metadata.startedAt = startedMatch[1].trim();\n if (issueMatch) metadata.issueId = issueMatch[1].trim();\n if (runIdMatch) metadata.runId = runIdMatch[1].trim();\n if (statusMatch) metadata.status = statusMatch[1].trim() as RunLogMetadata['status'];\n if (notesMatch) metadata.notes = notesMatch[1].trim();\n if (finishedMatch) metadata.finishedAt = finishedMatch[1].trim();\n\n // Parse duration if available\n if (durationMatch) {\n const durationStr = durationMatch[1].trim();\n const minutesMatch = durationStr.match(/(\\d+)m/);\n const secondsMatch = durationStr.match(/(\\d+)s/);\n const minutes = minutesMatch ? parseInt(minutesMatch[1], 10) : 0;\n const seconds = secondsMatch ? parseInt(secondsMatch[1], 10) : 0;\n metadata.duration = (minutes * 60 + seconds) * 1000;\n }\n\n return metadata;\n}\n\n/**\n * List all run logs for a project's specialist\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param options - Listing options\n * @returns Array of run log entries, sorted by most recent first\n */\nexport function listRunLogsSync(\n projectKey: string,\n specialistType: string,\n options: {\n limit?: number;\n offset?: number;\n } = {}\n): RunLogEntry[] {\n const runsDir = getRunsDirectory(projectKey, specialistType);\n\n if (!existsSync(runsDir)) {\n return [];\n }\n\n try {\n const files = readdirSync(runsDir)\n .filter(f => f.endsWith('.log'))\n .map(f => {\n const filePath = join(runsDir, f);\n const stats = statSync(filePath);\n const runId = basename(f, '.log');\n\n // Read file to extract metadata\n const content = readFileSync(filePath, 'utf-8');\n const metadata = parseLogMetadata(content);\n\n return {\n runId,\n filePath,\n metadata: {\n runId,\n project: projectKey,\n specialistType,\n issueId: metadata.issueId || 'unknown',\n startedAt: metadata.startedAt || stats.birthtime.toISOString(),\n finishedAt: metadata.finishedAt,\n status: metadata.status,\n duration: metadata.duration,\n notes: metadata.notes,\n },\n fileSize: stats.size,\n createdAt: stats.birthtime,\n };\n });\n\n // Sort by most recent first, with runId as tiebreaker for stable ordering\n files.sort((a, b) => {\n const timeDiff = b.createdAt.getTime() - a.createdAt.getTime();\n if (timeDiff !== 0) return timeDiff;\n return b.runId.localeCompare(a.runId);\n });\n\n // Apply pagination\n const { limit, offset = 0 } = options;\n if (limit !== undefined) {\n return files.slice(offset, offset + limit);\n }\n\n return files.slice(offset);\n } catch (error) {\n console.error(`Failed to list run logs for ${projectKey}/${specialistType}:`, error);\n return [];\n }\n}\n\n/**\n * Get the most recent N run logs\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param count - Number of recent runs to retrieve\n * @returns Array of recent run log entries\n */\nexport function getRecentRunLogs(\n projectKey: string,\n specialistType: string,\n count: number\n): RunLogEntry[] {\n return listRunLogsSync(projectKey, specialistType, { limit: count });\n}\n\n/**\n * Clean up old run logs based on retention policy\n *\n * Keeps logs that match either criteria (whichever is more permissive):\n * - Within maxDays\n * - Within the last maxRuns count\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param retention - Retention policy\n * @returns Number of logs deleted\n */\nexport function cleanupOldLogsSync(\n projectKey: string,\n specialistType: string,\n retention: { maxDays: number; maxRuns: number }\n): number {\n const { maxDays, maxRuns } = retention;\n\n // Compute cutoff BEFORE reading file stats. This ensures all files that existed\n // when cleanup was invoked have birthtimes <= cutoffDate when maxDays=0, avoiding\n // a race where a file created in the same millisecond as cutoffDate would be\n // incorrectly retained by a >= comparison.\n const now = new Date();\n const cutoffDate = new Date(now.getTime() - maxDays * 24 * 60 * 60 * 1000);\n\n const allLogs = listRunLogsSync(projectKey, specialistType);\n\n if (allLogs.length === 0) {\n return 0;\n }\n\n let deletedCount = 0;\n\n allLogs.forEach((log, index) => {\n // Keep if within maxRuns (most recent N runs)\n if (index < maxRuns) {\n return;\n }\n\n // Keep if within maxDays. Skip the age check entirely when maxDays=0, because\n // \"within 0 days\" means no age-based protection — only maxRuns applies.\n // This avoids a timing/rounding issue: Node.js converts nanosecond birthtime\n // to milliseconds using standard rounding, so a file created at 431.6ms gets\n // birthtime 432ms. If cutoff is 431ms (same wall-clock millisecond), the file\n // incorrectly appears newer than the cutoff and gets retained.\n if (maxDays > 0 && log.createdAt >= cutoffDate) {\n return;\n }\n\n // Delete this log\n try {\n unlinkSync(log.filePath);\n deletedCount++;\n console.log(`[specialist-logs] Deleted old log: ${log.runId}`);\n } catch (error) {\n console.error(`[specialist-logs] Failed to delete ${log.runId}:`, error);\n }\n });\n\n return deletedCount;\n}\n\n/**\n * Check if a run log is still active (not finalized)\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param runId - Run identifier\n * @returns True if log exists but has no result section yet\n */\nexport function isRunLogActive(\n projectKey: string,\n specialistType: string,\n runId: string\n): boolean {\n const content = getRunLogSync(projectKey, specialistType, runId);\n\n if (!content) {\n return false;\n }\n\n // Check if Result section exists\n return !content.includes('## Result');\n}\n\n/**\n * Get file size of a run log (useful for truncation check)\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param runId - Run identifier\n * @returns File size in bytes or null if not found\n */\nexport function getRunLogSize(\n projectKey: string,\n specialistType: string,\n runId: string\n): number | null {\n const filePath = getRunLogPath(projectKey, specialistType, runId);\n\n if (!existsSync(filePath)) {\n return null;\n }\n\n try {\n const stats = statSync(filePath);\n return stats.size;\n } catch (error) {\n return null;\n }\n}\n\n/**\n * Maximum log file size (10MB) before truncation warning\n */\nexport const MAX_LOG_SIZE = 10 * 1024 * 1024;\n\n/**\n * Check if a log file is approaching or exceeding size limits\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param runId - Run identifier\n * @returns Warning info or null if size is OK\n */\nexport function checkLogSizeLimit(\n projectKey: string,\n specialistType: string,\n runId: string\n): { exceeded: boolean; size: number; limit: number } | null {\n const size = getRunLogSize(projectKey, specialistType, runId);\n\n if (size === null) {\n return null;\n }\n\n if (size >= MAX_LOG_SIZE) {\n return {\n exceeded: true,\n size,\n limit: MAX_LOG_SIZE,\n };\n }\n\n return null;\n}\n\n/**\n * Clean up old logs for all projects and specialists\n *\n * Runs cleanup based on retention policies configured in projects.yaml.\n * This should be called periodically (e.g., daily cron job).\n *\n * @returns Summary of cleanup results\n */\nexport function cleanupAllLogsSync(): {\n totalDeleted: number;\n byProject: Record<string, Record<string, number>>;\n} {\n const { listProjectsWithSpecialists } = require('./specialists.js');\n const { getSpecialistRetention } = require('../projects.js');\n\n const results = {\n totalDeleted: 0,\n byProject: {} as Record<string, Record<string, number>>,\n };\n\n const projects = listProjectsWithSpecialists();\n\n for (const projectKey of projects) {\n results.byProject[projectKey] = {};\n\n // Get retention policy for this project\n const retention = getSpecialistRetention(projectKey);\n\n // Clean up each specialist type\n const specialistTypes = ['review-agent', 'test-agent', 'merge-agent'];\n\n for (const specialistType of specialistTypes) {\n const deleted = cleanupOldLogsSync(projectKey, specialistType, retention);\n\n if (deleted > 0) {\n results.byProject[projectKey][specialistType] = deleted;\n results.totalDeleted += deleted;\n }\n }\n }\n\n console.log(`[specialist-logs] Cleanup complete: deleted ${results.totalDeleted} old logs`);\n\n return results;\n}\n\n// ─── Effect variants (PAN-1249) ───────────────────────────────────────────────\n//\n// Additive Effect wrappers around the existing sync APIs. The underlying file\n// I/O is sync (CLI-callable); these variants lift thrown exceptions into a\n// typed error channel so callers can compose specialist-log operations with\n// other Effect-native code. Migrate callers individually.\n\n/** Tagged error for specialist-log Effect variants. */\nexport class SpecialistLogError extends Data.TaggedError('SpecialistLogError')<{\n readonly projectKey: string;\n readonly specialistType: string;\n readonly operation: string;\n readonly message: string;\n readonly cause?: unknown;\n}> {}\n\nconst liftLogError = (\n projectKey: string,\n specialistType: string,\n operation: string,\n cause: unknown,\n): SpecialistLogError =>\n new SpecialistLogError({\n projectKey,\n specialistType,\n operation,\n message: cause instanceof Error ? cause.message : String(cause),\n cause,\n });\n\n/** Effect variant of `createRunLog`. */\nexport const createRunLog = (\n projectKey: string,\n specialistType: string,\n issueId: string,\n contextSeed?: string,\n): Effect.Effect<{ runId: string; filePath: string }, SpecialistLogError> =>\n Effect.try({\n try: () => createRunLogSync(projectKey, specialistType, issueId, contextSeed),\n catch: (cause) => liftLogError(projectKey, specialistType, 'createRunLog', cause),\n });\n\n/** Effect variant of `appendToRunLog`. */\nexport const appendToRunLog = (\n projectKey: string,\n specialistType: string,\n runId: string,\n content: string,\n): Effect.Effect<void, SpecialistLogError> =>\n Effect.try({\n try: () => appendToRunLogSync(projectKey, specialistType, runId, content),\n catch: (cause) => liftLogError(projectKey, specialistType, 'appendToRunLog', cause),\n });\n\n/** Effect variant of `finalizeRunLog`. */\nexport const finalizeRunLog = (\n projectKey: string,\n specialistType: string,\n runId: string,\n result: { status: 'passed' | 'failed' | 'blocked' | 'incomplete'; notes?: string },\n): Effect.Effect<void, SpecialistLogError> =>\n Effect.try({\n try: () => finalizeRunLogSync(projectKey, specialistType, runId, result),\n catch: (cause) => liftLogError(projectKey, specialistType, 'finalizeRunLog', cause),\n });\n\n/** Effect variant of `getRunLog`. */\nexport const getRunLog = (\n projectKey: string,\n specialistType: string,\n runId: string,\n): Effect.Effect<string | null, SpecialistLogError> =>\n Effect.try({\n try: () => getRunLogSync(projectKey, specialistType, runId),\n catch: (cause) => liftLogError(projectKey, specialistType, 'getRunLog', cause),\n });\n\n/** Effect variant of `listRunLogs`. */\nexport const listRunLogs = (\n projectKey: string,\n specialistType: string,\n options: { limit?: number; offset?: number } = {},\n): Effect.Effect<RunLogEntry[], SpecialistLogError> =>\n Effect.try({\n try: () => listRunLogsSync(projectKey, specialistType, options),\n catch: (cause) => liftLogError(projectKey, specialistType, 'listRunLogs', cause),\n });\n\n/** Effect variant of `cleanupOldLogs`. */\nexport const cleanupOldLogs = (\n projectKey: string,\n specialistType: string,\n retention: { maxDays: number; maxRuns: number },\n): Effect.Effect<number, SpecialistLogError> =>\n Effect.try({\n try: () => cleanupOldLogsSync(projectKey, specialistType, retention),\n catch: (cause) => liftLogError(projectKey, specialistType, 'cleanupOldLogs', cause),\n });\n\n/** Effect variant of `cleanupAllLogs`. */\nexport const cleanupAllLogs = (): Effect.Effect<\n { totalDeleted: number; byProject: Record<string, Record<string, number>> },\n SpecialistLogError\n> =>\n Effect.try({\n try: () => cleanupAllLogsSync(),\n catch: (cause) => liftLogError('*', '*', 'cleanupAllLogs', cause),\n });\n"],"mappings":"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"}
1
+ {"version":3,"file":"specialist-logs-pEMCTtGZ.js","names":[],"sources":["../src/lib/cloister/specialist-logs.ts"],"sourcesContent":["/**\n * Specialist Log Management\n *\n * Manages persistent log files for specialist agent runs.\n * Each run produces a structured log file with metadata, context, and full transcript.\n *\n * Directory structure:\n * ~/.overdeck/specialists/{projectKey}/{specialistType}/runs/{timestamp}-{issueId}.log\n */\n\nimport { existsSync, mkdirSync, writeFileSync, appendFileSync, readFileSync, readdirSync, statSync, unlinkSync } from 'fs';\nimport { join, basename } from 'path';\nimport { Data, Effect } from 'effect';\nimport { getOverdeckHome } from '../paths.js';\n\n/** Get specialists directory (lazy to support test env overrides) */\nfunction getSpecialistsDir(): string {\n return join(getOverdeckHome(), 'specialists');\n}\n\n/**\n * Log file metadata\n */\nexport interface RunLogMetadata {\n runId: string;\n project: string;\n specialistType: string;\n issueId: string;\n startedAt: string;\n finishedAt?: string;\n status?: 'passed' | 'failed' | 'blocked' | 'incomplete';\n duration?: number; // in milliseconds\n notes?: string;\n}\n\n/**\n * Run log entry for listing\n */\nexport interface RunLogEntry {\n runId: string;\n filePath: string;\n metadata: RunLogMetadata;\n fileSize: number;\n createdAt: Date;\n}\n\n/**\n * Get the runs directory for a project's specialist\n */\nexport function getRunsDirectory(projectKey: string, specialistType: string): string {\n return join(getSpecialistsDir(), projectKey, specialistType, 'runs');\n}\n\n/**\n * Generate a run ID from timestamp and issue ID\n */\nexport function generateRunId(issueId: string): string {\n const timestamp = new Date().toISOString().replace(/[:.]/g, '-').substring(0, 19);\n return `${timestamp}-${issueId}`;\n}\n\n/**\n * Get the log file path for a run\n */\nexport function getRunLogPath(projectKey: string, specialistType: string, runId: string): string {\n const runsDir = getRunsDirectory(projectKey, specialistType);\n return join(runsDir, `${runId}.log`);\n}\n\n/**\n * Ensure runs directory exists for a project's specialist\n */\nfunction ensureRunsDirectory(projectKey: string, specialistType: string): void {\n const runsDir = getRunsDirectory(projectKey, specialistType);\n if (!existsSync(runsDir)) {\n mkdirSync(runsDir, { recursive: true });\n }\n}\n\n/**\n * Create a new run log file\n *\n * Initializes a log file with metadata header.\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type (review-agent, test-agent, merge-agent)\n * @param issueId - Issue ID being worked on\n * @param contextSeed - Optional context digest that was provided to the specialist\n * @returns Run ID and file path\n */\nexport function createRunLogSync(\n projectKey: string,\n specialistType: string,\n issueId: string,\n contextSeed?: string\n): { runId: string; filePath: string } {\n ensureRunsDirectory(projectKey, specialistType);\n\n const runId = generateRunId(issueId);\n const filePath = getRunLogPath(projectKey, specialistType, runId);\n const startedAt = new Date().toISOString();\n\n // Create log header\n const header = `# ${specialistType} Run - ${issueId}\nProject: ${projectKey}\nStarted: ${startedAt}\nIssue: ${issueId}\nRun ID: ${runId}\n\n## Context Seed\n${contextSeed ? contextSeed : '[No context digest available]'}\n\n## Session Transcript\n`;\n\n writeFileSync(filePath, header, 'utf-8');\n\n return { runId, filePath };\n}\n\n/**\n * Append content to a run log\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param runId - Run identifier\n * @param content - Content to append\n */\nexport function appendToRunLogSync(\n projectKey: string,\n specialistType: string,\n runId: string,\n content: string\n): void {\n const filePath = getRunLogPath(projectKey, specialistType, runId);\n\n if (!existsSync(filePath)) {\n throw new Error(`Run log not found: ${filePath}`);\n }\n\n appendFileSync(filePath, content, 'utf-8');\n}\n\n/**\n * Finalize a run log with result metadata\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param runId - Run identifier\n * @param result - Run result\n */\nexport function finalizeRunLogSync(\n projectKey: string,\n specialistType: string,\n runId: string,\n result: {\n status: 'passed' | 'failed' | 'blocked' | 'incomplete';\n notes?: string;\n }\n): void {\n const filePath = getRunLogPath(projectKey, specialistType, runId);\n\n if (!existsSync(filePath)) {\n throw new Error(`Run log not found: ${filePath}`);\n }\n\n // Read the log to extract start time\n const content = readFileSync(filePath, 'utf-8');\n const startMatch = content.match(/^Started: (.+)$/m);\n const startedAt = startMatch ? new Date(startMatch[1]) : new Date();\n const finishedAt = new Date();\n const duration = finishedAt.getTime() - startedAt.getTime();\n\n // Format duration\n const durationSeconds = Math.floor(duration / 1000);\n const minutes = Math.floor(durationSeconds / 60);\n const seconds = durationSeconds % 60;\n const durationStr = `${minutes}m ${seconds}s`;\n\n // Append result section\n const resultSection = `\n\n## Result\nStatus: ${result.status}\n${result.notes ? `Notes: ${result.notes}` : ''}\nDuration: ${durationStr}\nFinished: ${finishedAt.toISOString()}\n`;\n\n appendFileSync(filePath, resultSection, 'utf-8');\n}\n\n/**\n * Read a run log file\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param runId - Run identifier\n * @returns Log content or null if not found\n */\nexport function getRunLogSync(\n projectKey: string,\n specialistType: string,\n runId: string\n): string | null {\n const filePath = getRunLogPath(projectKey, specialistType, runId);\n\n if (!existsSync(filePath)) {\n return null;\n }\n\n try {\n return readFileSync(filePath, 'utf-8');\n } catch (error) {\n console.error(`Failed to read run log ${runId}:`, error);\n return null;\n }\n}\n\n/**\n * Parse metadata from a log file\n *\n * @param logContent - Log file content\n * @returns Parsed metadata\n */\nexport function parseLogMetadata(logContent: string): Partial<RunLogMetadata> {\n const metadata: Partial<RunLogMetadata> = {};\n\n // Extract metadata from header\n const projectMatch = logContent.match(/^Project: (.+)$/m);\n const startedMatch = logContent.match(/^Started: (.+)$/m);\n const issueMatch = logContent.match(/^Issue: (.+)$/m);\n const runIdMatch = logContent.match(/^Run ID: (.+)$/m);\n const statusMatch = logContent.match(/^Status: (.+)$/m);\n const notesMatch = logContent.match(/^Notes: (.+)$/m);\n const finishedMatch = logContent.match(/^Finished: (.+)$/m);\n const durationMatch = logContent.match(/^Duration: (.+)$/m);\n\n if (projectMatch) metadata.project = projectMatch[1].trim();\n if (startedMatch) metadata.startedAt = startedMatch[1].trim();\n if (issueMatch) metadata.issueId = issueMatch[1].trim();\n if (runIdMatch) metadata.runId = runIdMatch[1].trim();\n if (statusMatch) metadata.status = statusMatch[1].trim() as RunLogMetadata['status'];\n if (notesMatch) metadata.notes = notesMatch[1].trim();\n if (finishedMatch) metadata.finishedAt = finishedMatch[1].trim();\n\n // Parse duration if available\n if (durationMatch) {\n const durationStr = durationMatch[1].trim();\n const minutesMatch = durationStr.match(/(\\d+)m/);\n const secondsMatch = durationStr.match(/(\\d+)s/);\n const minutes = minutesMatch ? parseInt(minutesMatch[1], 10) : 0;\n const seconds = secondsMatch ? parseInt(secondsMatch[1], 10) : 0;\n metadata.duration = (minutes * 60 + seconds) * 1000;\n }\n\n return metadata;\n}\n\n/**\n * List all run logs for a project's specialist\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param options - Listing options\n * @returns Array of run log entries, sorted by most recent first\n */\nexport function listRunLogsSync(\n projectKey: string,\n specialistType: string,\n options: {\n limit?: number;\n offset?: number;\n } = {}\n): RunLogEntry[] {\n const runsDir = getRunsDirectory(projectKey, specialistType);\n\n if (!existsSync(runsDir)) {\n return [];\n }\n\n try {\n const files = readdirSync(runsDir)\n .filter(f => f.endsWith('.log'))\n .map(f => {\n const filePath = join(runsDir, f);\n const stats = statSync(filePath);\n const runId = basename(f, '.log');\n\n // Read file to extract metadata\n const content = readFileSync(filePath, 'utf-8');\n const metadata = parseLogMetadata(content);\n\n return {\n runId,\n filePath,\n metadata: {\n runId,\n project: projectKey,\n specialistType,\n issueId: metadata.issueId || 'unknown',\n startedAt: metadata.startedAt || stats.birthtime.toISOString(),\n finishedAt: metadata.finishedAt,\n status: metadata.status,\n duration: metadata.duration,\n notes: metadata.notes,\n },\n fileSize: stats.size,\n createdAt: stats.birthtime,\n };\n });\n\n // Sort by most recent first, with runId as tiebreaker for stable ordering\n files.sort((a, b) => {\n const timeDiff = b.createdAt.getTime() - a.createdAt.getTime();\n if (timeDiff !== 0) return timeDiff;\n return b.runId.localeCompare(a.runId);\n });\n\n // Apply pagination\n const { limit, offset = 0 } = options;\n if (limit !== undefined) {\n return files.slice(offset, offset + limit);\n }\n\n return files.slice(offset);\n } catch (error) {\n console.error(`Failed to list run logs for ${projectKey}/${specialistType}:`, error);\n return [];\n }\n}\n\n/**\n * Get the most recent N run logs\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param count - Number of recent runs to retrieve\n * @returns Array of recent run log entries\n */\nexport function getRecentRunLogs(\n projectKey: string,\n specialistType: string,\n count: number\n): RunLogEntry[] {\n return listRunLogsSync(projectKey, specialistType, { limit: count });\n}\n\n/**\n * Clean up old run logs based on retention policy\n *\n * Keeps logs that match either criteria (whichever is more permissive):\n * - Within maxDays\n * - Within the last maxRuns count\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param retention - Retention policy\n * @returns Number of logs deleted\n */\nexport function cleanupOldLogsSync(\n projectKey: string,\n specialistType: string,\n retention: { maxDays: number; maxRuns: number }\n): number {\n const { maxDays, maxRuns } = retention;\n\n // Compute cutoff BEFORE reading file stats. This ensures all files that existed\n // when cleanup was invoked have birthtimes <= cutoffDate when maxDays=0, avoiding\n // a race where a file created in the same millisecond as cutoffDate would be\n // incorrectly retained by a >= comparison.\n const now = new Date();\n const cutoffDate = new Date(now.getTime() - maxDays * 24 * 60 * 60 * 1000);\n\n const allLogs = listRunLogsSync(projectKey, specialistType);\n\n if (allLogs.length === 0) {\n return 0;\n }\n\n let deletedCount = 0;\n\n allLogs.forEach((log, index) => {\n // Keep if within maxRuns (most recent N runs)\n if (index < maxRuns) {\n return;\n }\n\n // Keep if within maxDays. Skip the age check entirely when maxDays=0, because\n // \"within 0 days\" means no age-based protection — only maxRuns applies.\n // This avoids a timing/rounding issue: Node.js converts nanosecond birthtime\n // to milliseconds using standard rounding, so a file created at 431.6ms gets\n // birthtime 432ms. If cutoff is 431ms (same wall-clock millisecond), the file\n // incorrectly appears newer than the cutoff and gets retained.\n if (maxDays > 0 && log.createdAt >= cutoffDate) {\n return;\n }\n\n // Delete this log\n try {\n unlinkSync(log.filePath);\n deletedCount++;\n console.log(`[specialist-logs] Deleted old log: ${log.runId}`);\n } catch (error) {\n console.error(`[specialist-logs] Failed to delete ${log.runId}:`, error);\n }\n });\n\n return deletedCount;\n}\n\n/**\n * Check if a run log is still active (not finalized)\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param runId - Run identifier\n * @returns True if log exists but has no result section yet\n */\nexport function isRunLogActive(\n projectKey: string,\n specialistType: string,\n runId: string\n): boolean {\n const content = getRunLogSync(projectKey, specialistType, runId);\n\n if (!content) {\n return false;\n }\n\n // Check if Result section exists\n return !content.includes('## Result');\n}\n\n/**\n * Get file size of a run log (useful for truncation check)\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param runId - Run identifier\n * @returns File size in bytes or null if not found\n */\nexport function getRunLogSize(\n projectKey: string,\n specialistType: string,\n runId: string\n): number | null {\n const filePath = getRunLogPath(projectKey, specialistType, runId);\n\n if (!existsSync(filePath)) {\n return null;\n }\n\n try {\n const stats = statSync(filePath);\n return stats.size;\n } catch (error) {\n return null;\n }\n}\n\n/**\n * Maximum log file size (10MB) before truncation warning\n */\nexport const MAX_LOG_SIZE = 10 * 1024 * 1024;\n\n/**\n * Check if a log file is approaching or exceeding size limits\n *\n * @param projectKey - Project identifier\n * @param specialistType - Specialist type\n * @param runId - Run identifier\n * @returns Warning info or null if size is OK\n */\nexport function checkLogSizeLimit(\n projectKey: string,\n specialistType: string,\n runId: string\n): { exceeded: boolean; size: number; limit: number } | null {\n const size = getRunLogSize(projectKey, specialistType, runId);\n\n if (size === null) {\n return null;\n }\n\n if (size >= MAX_LOG_SIZE) {\n return {\n exceeded: true,\n size,\n limit: MAX_LOG_SIZE,\n };\n }\n\n return null;\n}\n\n/**\n * Clean up old logs for all projects and specialists\n *\n * Runs cleanup based on retention policies configured in projects.yaml.\n * This should be called periodically (e.g., daily cron job).\n *\n * @returns Summary of cleanup results\n */\nexport function cleanupAllLogsSync(): {\n totalDeleted: number;\n byProject: Record<string, Record<string, number>>;\n} {\n const { listProjectsWithSpecialists } = require('./specialists.js');\n const { getSpecialistRetention } = require('../projects.js');\n\n const results = {\n totalDeleted: 0,\n byProject: {} as Record<string, Record<string, number>>,\n };\n\n const projects = listProjectsWithSpecialists();\n\n for (const projectKey of projects) {\n results.byProject[projectKey] = {};\n\n // Get retention policy for this project\n const retention = getSpecialistRetention(projectKey);\n\n // Clean up each specialist type\n const specialistTypes = ['review-agent', 'test-agent', 'merge-agent'];\n\n for (const specialistType of specialistTypes) {\n const deleted = cleanupOldLogsSync(projectKey, specialistType, retention);\n\n if (deleted > 0) {\n results.byProject[projectKey][specialistType] = deleted;\n results.totalDeleted += deleted;\n }\n }\n }\n\n console.log(`[specialist-logs] Cleanup complete: deleted ${results.totalDeleted} old logs`);\n\n return results;\n}\n\n// ─── Effect variants (PAN-1249) ───────────────────────────────────────────────\n//\n// Additive Effect wrappers around the existing sync APIs. The underlying file\n// I/O is sync (CLI-callable); these variants lift thrown exceptions into a\n// typed error channel so callers can compose specialist-log operations with\n// other Effect-native code. Migrate callers individually.\n\n/** Tagged error for specialist-log Effect variants. */\nexport class SpecialistLogError extends Data.TaggedError('SpecialistLogError')<{\n readonly projectKey: string;\n readonly specialistType: string;\n readonly operation: string;\n readonly message: string;\n readonly cause?: unknown;\n}> {}\n\nconst liftLogError = (\n projectKey: string,\n specialistType: string,\n operation: string,\n cause: unknown,\n): SpecialistLogError =>\n new SpecialistLogError({\n projectKey,\n specialistType,\n operation,\n message: cause instanceof Error ? cause.message : String(cause),\n cause,\n });\n\n/** Effect variant of `createRunLog`. */\nexport const createRunLog = (\n projectKey: string,\n specialistType: string,\n issueId: string,\n contextSeed?: string,\n): Effect.Effect<{ runId: string; filePath: string }, SpecialistLogError> =>\n Effect.try({\n try: () => createRunLogSync(projectKey, specialistType, issueId, contextSeed),\n catch: (cause) => liftLogError(projectKey, specialistType, 'createRunLog', cause),\n });\n\n/** Effect variant of `appendToRunLog`. */\nexport const appendToRunLog = (\n projectKey: string,\n specialistType: string,\n runId: string,\n content: string,\n): Effect.Effect<void, SpecialistLogError> =>\n Effect.try({\n try: () => appendToRunLogSync(projectKey, specialistType, runId, content),\n catch: (cause) => liftLogError(projectKey, specialistType, 'appendToRunLog', cause),\n });\n\n/** Effect variant of `finalizeRunLog`. */\nexport const finalizeRunLog = (\n projectKey: string,\n specialistType: string,\n runId: string,\n result: { status: 'passed' | 'failed' | 'blocked' | 'incomplete'; notes?: string },\n): Effect.Effect<void, SpecialistLogError> =>\n Effect.try({\n try: () => finalizeRunLogSync(projectKey, specialistType, runId, result),\n catch: (cause) => liftLogError(projectKey, specialistType, 'finalizeRunLog', cause),\n });\n\n/** Effect variant of `getRunLog`. */\nexport const getRunLog = (\n projectKey: string,\n specialistType: string,\n runId: string,\n): Effect.Effect<string | null, SpecialistLogError> =>\n Effect.try({\n try: () => getRunLogSync(projectKey, specialistType, runId),\n catch: (cause) => liftLogError(projectKey, specialistType, 'getRunLog', cause),\n });\n\n/** Effect variant of `listRunLogs`. */\nexport const listRunLogs = (\n projectKey: string,\n specialistType: string,\n options: { limit?: number; offset?: number } = {},\n): Effect.Effect<RunLogEntry[], SpecialistLogError> =>\n Effect.try({\n try: () => listRunLogsSync(projectKey, specialistType, options),\n catch: (cause) => liftLogError(projectKey, specialistType, 'listRunLogs', cause),\n });\n\n/** Effect variant of `cleanupOldLogs`. */\nexport const cleanupOldLogs = (\n projectKey: string,\n specialistType: string,\n retention: { maxDays: number; maxRuns: number },\n): Effect.Effect<number, SpecialistLogError> =>\n Effect.try({\n try: () => cleanupOldLogsSync(projectKey, specialistType, retention),\n catch: (cause) => liftLogError(projectKey, specialistType, 'cleanupOldLogs', cause),\n });\n\n/** Effect variant of `cleanupAllLogs`. */\nexport const cleanupAllLogs = (): Effect.Effect<\n { totalDeleted: number; byProject: Record<string, Record<string, number>> },\n SpecialistLogError\n> =>\n Effect.try({\n try: () => cleanupAllLogsSync(),\n catch: (cause) => liftLogError('*', '*', 'cleanupAllLogs', cause),\n });\n"],"mappings":"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"}
@@ -1,3 +1,3 @@
1
- import { O as init_specialists, V as pruneSpecialistRegistryEntriesForIssue, y as getProjectSpecialistMetadata } from "./specialists-B0elgInc.js";
1
+ import { O as init_specialists, V as pruneSpecialistRegistryEntriesForIssue, y as getProjectSpecialistMetadata } from "./specialists-DeTkkp8b.js";
2
2
  init_specialists();
3
3
  export { getProjectSpecialistMetadata, pruneSpecialistRegistryEntriesForIssue };
@@ -4,7 +4,7 @@ import { m as init_errors } from "./errors-DyEDJ7xB.js";
4
4
  import { A as sessionExists, C as listPaneValues, x as killSession, y as init_tmux } from "./tmux-Ceg1ulra.js";
5
5
  import { f as init_cost, t as calculateCostSync, u as getPricingSync } from "./cost-6uWF3Bnw.js";
6
6
  import { a as readCavemanVariant, n as init_workspace } from "./workspace-P0whzIO3.js";
7
- import { n as resolveHarness, t as init_harness_resolve } from "./harness-resolve-Bz1prk6B.js";
7
+ import { n as resolveHarness, t as init_harness_resolve } from "./harness-resolve-B-YDNwNW.js";
8
8
  import { Effect } from "effect";
9
9
  import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
10
10
  import { basename, join } from "path";
@@ -295,7 +295,7 @@ function roleForSpecialistModel(specialistType) {
295
295
  return { role: "work" };
296
296
  }
297
297
  async function buildSpecialistBaseCommand(specialistType, model, sessionName) {
298
- const { getAgentRuntimeBaseCommand } = await import("./agents-pp8FO7Uj.js");
298
+ const { getAgentRuntimeBaseCommand } = await import("./agents-By3u_fQ8.js");
299
299
  const role = roleForSpecialistModel(specialistType).role;
300
300
  const harness = await resolveHarness({
301
301
  model,
@@ -694,7 +694,7 @@ async function signalSpecialistCompletion(projectKey, specialistType, result, is
694
694
  const resolvedTmuxSession = metadata.tmuxSession ?? getTmuxSessionName(specialistType, projectKey, issueId);
695
695
  updateRunStatus(projectKey, registryKey, result.status);
696
696
  if (metadata.currentRun) try {
697
- const { finalizeRunLogSync } = await import("./specialist-logs-CUUJ4eiB.js");
697
+ const { finalizeRunLogSync } = await import("./specialist-logs-pEMCTtGZ.js");
698
698
  finalizeRunLogSync(projectKey, specialistType, metadata.currentRun, {
699
699
  status: result.status,
700
700
  notes: result.notes
@@ -704,7 +704,7 @@ async function signalSpecialistCompletion(projectKey, specialistType, result, is
704
704
  }
705
705
  setCurrentRun(projectKey, registryKey, null);
706
706
  updateRunMetadata(projectKey, registryKey, { currentActivity: null });
707
- import("./agents-pp8FO7Uj.js").then(({ saveAgentRuntimeState }) => {
707
+ import("./agents-By3u_fQ8.js").then(({ saveAgentRuntimeState }) => {
708
708
  saveAgentRuntimeState(resolvedTmuxSession, {
709
709
  state: "idle",
710
710
  lastActivity: (/* @__PURE__ */ new Date()).toISOString(),
@@ -735,7 +735,7 @@ async function terminateSpecialist(projectKey, specialistType, issueId) {
735
735
  console.error(`[specialist] Failed to kill tmux session ${tmuxSession}:`, error);
736
736
  }
737
737
  if (metadata.currentRun) {
738
- const { finalizeRunLogSync } = await import("./specialist-logs-CUUJ4eiB.js");
738
+ const { finalizeRunLogSync } = await import("./specialist-logs-pEMCTtGZ.js");
739
739
  try {
740
740
  finalizeRunLogSync(projectKey, specialistType, metadata.currentRun, {
741
741
  status: metadata.lastRunStatus || "incomplete",
@@ -749,12 +749,12 @@ async function terminateSpecialist(projectKey, specialistType, issueId) {
749
749
  updateRunMetadata(projectKey, registryKey, { currentActivity: null });
750
750
  const key = `${projectKey}-${specialistType}`;
751
751
  gracePeriodStates.delete(key);
752
- const { saveAgentRuntimeState } = await import("./agents-pp8FO7Uj.js");
752
+ const { saveAgentRuntimeState } = await import("./agents-By3u_fQ8.js");
753
753
  saveAgentRuntimeState(tmuxSession, {
754
754
  state: "suspended",
755
755
  lastActivity: (/* @__PURE__ */ new Date()).toISOString()
756
756
  });
757
- const { scheduleDigestGeneration } = await import("./specialist-context-McuGkaeR.js");
757
+ const { scheduleDigestGeneration } = await import("./specialist-context-BUTadO-U.js");
758
758
  scheduleDigestGeneration(projectKey, specialistType);
759
759
  scheduleLogCleanup(projectKey, specialistType);
760
760
  }
@@ -767,7 +767,7 @@ async function terminateSpecialist(projectKey, specialistType, issueId) {
767
767
  function scheduleLogCleanup(projectKey, specialistType) {
768
768
  Promise.resolve().then(async () => {
769
769
  try {
770
- const { cleanupOldLogsSync } = await import("./specialist-logs-CUUJ4eiB.js");
770
+ const { cleanupOldLogsSync } = await import("./specialist-logs-pEMCTtGZ.js");
771
771
  const { getSpecialistRetention } = await import("./projects-DbssjAtz.js");
772
772
  const retention = getSpecialistRetention(projectKey);
773
773
  const deleted = cleanupOldLogsSync(projectKey, specialistType, {
@@ -922,7 +922,7 @@ function listSpecialistsForProject(projectKey) {
922
922
  */
923
923
  async function getAllProjectSpecialistStatuses() {
924
924
  const registry = loadRegistry();
925
- const { getAgentRuntimeStateSync } = await import("./agents-pp8FO7Uj.js");
925
+ const { getAgentRuntimeStateSync } = await import("./agents-By3u_fQ8.js");
926
926
  const results = [];
927
927
  for (const [projectKey, specialists] of Object.entries(registry.projects)) for (const [registryKey, metadata] of Object.entries(specialists)) {
928
928
  const { specialistType, issueId, role } = parseSpecialistRegistryKey(registryKey);
@@ -1059,7 +1059,7 @@ async function getSpecialistStatus(name, projectKey) {
1059
1059
  const sessionId = readRecordedClaudeSessionId(getTmuxSessionName(name, projectKey));
1060
1060
  const running = await isRunning(name, projectKey);
1061
1061
  const contextTokens = countContextTokens(name);
1062
- const { getAgentRuntimeStateSync } = await import("./agents-pp8FO7Uj.js");
1062
+ const { getAgentRuntimeStateSync } = await import("./agents-By3u_fQ8.js");
1063
1063
  const runtimeState = getAgentRuntimeStateSync(getTmuxSessionName(name, projectKey));
1064
1064
  let state;
1065
1065
  if (runtimeState) switch (runtimeState.state) {
@@ -1158,7 +1158,7 @@ async function sendFeedbackToAgent(feedback) {
1158
1158
  return false;
1159
1159
  }
1160
1160
  try {
1161
- const { messageAgent } = await import("./agents-pp8FO7Uj.js");
1161
+ const { messageAgent } = await import("./agents-By3u_fQ8.js");
1162
1162
  await messageAgent(agentSession, `SPECIALIST FEEDBACK: ${fromSpecialist} reported ${feedback.feedbackType.toUpperCase()} for ${toIssueId}.\n\nMUST READ: ${fileResult.filePath}\n\nUse your Read tool to open this file, read every line, then address the feedback and continue working. Do NOT stop at the prompt.`);
1163
1163
  console.log(`[specialist] Sent feedback from ${fromSpecialist} to ${agentSession} (file: ${fileResult.filePath})`);
1164
1164
  return true;
@@ -1277,4 +1277,4 @@ var init_specialists = __esmMin((() => {
1277
1277
  //#endregion
1278
1278
  export { updateRunMetadata as $, isEnabled as A, pauseGracePeriod as B, getSpecialistState as C, initSpecialistsDirectory as D, incrementProjectRunCount as E, listSpecialistsForProject as F, sendFeedbackToAgent as G, recordWake as H, loadRegistry as I, specialists_exports as J, setCurrentRun as K, makeSpecialistRegistryKey as L, isProjectSpecialistActivelyRunning as M, isRunning as N, init_specialists as O, listProjectsWithSpecialists as P, updateProjectSpecialistMetadata as Q, parseReviewerSessionName as R, getSpecialistMetadata as S, getTmuxSessionName as T, resumeGracePeriod as U, pruneSpecialistRegistryEntriesForIssue as V, saveRegistry as W, terminateSpecialist as X, startGracePeriod as Y, updateContextTokens as Z, getPendingFeedback as _, disableSpecialist as a, getReviewerSessionName as b, exitGracePeriod as c, getAllProjectSpecialistStatuses as d, updateRunStatus as et, getAllSpecialistStatus as f, getGracePeriodState as g, getFeedbackStats as h, countContextTokens as i, isInitialized as j, initializeEnabledSpecialists as k, findActiveRegistryKey as l, getEnabledSpecialists as m, buildSpecialistBaseCommand as n, enableSpecialist as o, getAllSpecialists as p, signalSpecialistCompletion as q, buildSpecialistCavemanExports as r, ensureProjectSpecialistDir as s, REVIEWER_ROLES as t, updateSpecialistMetadata as tt, findSessionFile as u, getProjectSpecialistDir as v, getSpecialistStatus as w, getRunMetadata as x, getProjectSpecialistMetadata as y, parseSpecialistRegistryKey as z };
1279
1279
 
1280
- //# sourceMappingURL=specialists-B0elgInc.js.map
1280
+ //# sourceMappingURL=specialists-DeTkkp8b.js.map