very-happy-cli 0.2.182 → 0.2.183

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 (200) hide show
  1. package/dist/{AcpBackend-DLk3gMYH.mjs → AcpBackend-9c-Jeaxd.mjs} +3 -3
  2. package/dist/{AcpBackend-JA5eu8Y0.cjs → AcpBackend-B-aMuEzO.cjs} +3 -3
  3. package/dist/{AcpSessionManager-DjYidq4C.cjs → AcpSessionManager-BxXe24AV.cjs} +10 -3
  4. package/dist/{AcpSessionManager-OrCww-Qv.mjs → AcpSessionManager-CS0FOSQk.mjs} +10 -3
  5. package/dist/{BasePermissionHandler-u-neo-iN.mjs → BasePermissionHandler-BJ1ID_Br.mjs} +1 -1
  6. package/dist/{BasePermissionHandler-D3PMKLBS.cjs → BasePermissionHandler-BREjppjP.cjs} +1 -1
  7. package/dist/{acpSessionResume-u2TwX5Jd.mjs → acpSessionResume-BKtI9Jq_.mjs} +1 -1
  8. package/dist/{acpSessionResume-Dxo8222T.cjs → acpSessionResume-mVoJ75vI.cjs} +1 -1
  9. package/dist/{agentHome-D3hNrnoA.mjs → agentHome-B8Ctr_Nu.mjs} +4 -4
  10. package/dist/{agentHome-CP1tCBXz.cjs → agentHome-rzjm56o4.cjs} +4 -4
  11. package/dist/{api-C_YSQnsi.mjs → api-C29WLYkW.mjs} +79 -12
  12. package/dist/{api-CZWcG7uh.cjs → api-xZiqVynF.cjs} +81 -11
  13. package/dist/{apiMachine-DPGrED5C.cjs → apiMachine-B-FNBIYG.cjs} +14 -14
  14. package/dist/{apiMachine-C_GA5Bm-.mjs → apiMachine-Dz6Yfk0m.mjs} +14 -14
  15. package/dist/{attachmentContent-I_dJIevE.cjs → attachmentContent-COV4LF8k.cjs} +2 -2
  16. package/dist/{attachmentContent-Ckzyb1Uy.mjs → attachmentContent-DwY0uIg6.mjs} +2 -2
  17. package/dist/{auth-Lw_utSMV.cjs → auth-CYtk9_ga.cjs} +5 -5
  18. package/dist/{auth-BKnE7uv7.cjs → auth-D_qsnVr3.cjs} +8 -8
  19. package/dist/{auth-DOXMI-xp.mjs → auth-DvbSDalm.mjs} +8 -8
  20. package/dist/{auth-CGgpiJ5-.mjs → auth-xT70IYMx.mjs} +5 -5
  21. package/dist/{auto-CIgFHIyQ.cjs → auto-DT_PfpCx.cjs} +32 -25
  22. package/dist/{auto-Z56mMZnH.mjs → auto-IiPqvIsN.mjs} +32 -26
  23. package/dist/{bootstrap-DsXp74wv.cjs → bootstrap-C50NkfPx.cjs} +2 -2
  24. package/dist/{bootstrap-D3vlOROj.mjs → bootstrap-DS8Acdhm.mjs} +2 -2
  25. package/dist/{browser-CUxGoATV.mjs → browser-1j9gdZoD.mjs} +1 -1
  26. package/dist/{browser-CZlA9AkO.cjs → browser-CxKZLd2T.cjs} +1 -1
  27. package/dist/{claudeLocal-oELvwiZL.cjs → claudeLocal-CgNWpepB.cjs} +5 -5
  28. package/dist/{claudeLocal-FnTUgwCi.mjs → claudeLocal-U1Fa9sJo.mjs} +5 -5
  29. package/dist/{claudeLocalLauncher-CO5YHCzi.mjs → claudeLocalLauncher-BjCsfZUE.mjs} +10 -10
  30. package/dist/{claudeLocalLauncher-QsVXEVdE.cjs → claudeLocalLauncher-IyFm0D6a.cjs} +10 -10
  31. package/dist/{claudeSessionFork-Cspr6QW0.mjs → claudeSessionFork-6-1vKISn.mjs} +1 -1
  32. package/dist/{claudeSessionFork-BA4GE5AL.cjs → claudeSessionFork-BUO1XdSm.cjs} +1 -1
  33. package/dist/{client-xnWiHqdb.cjs → client--vZueZYF.cjs} +4 -4
  34. package/dist/{client-o-meK7-a.mjs → client-5_zDNdOh.mjs} +2 -2
  35. package/dist/{client-Ctbw05Xj.mjs → client-BgHvK7lo.mjs} +15 -7
  36. package/dist/{client-CDuW4MS9.cjs → client-DYGDBD0M.cjs} +15 -7
  37. package/dist/{client-DK8CzUry.cjs → client-DcKJ0ul_.cjs} +2 -2
  38. package/dist/{client-BGfmSbWc.mjs → client-DfDyE322.mjs} +4 -4
  39. package/dist/codex/happyMcpStdioBridge.cjs +16 -16
  40. package/dist/codex/happyMcpStdioBridge.mjs +16 -16
  41. package/dist/{codexAppServerClient-DhNDTU_i.cjs → codexAppServerClient-C3nrTfwY.cjs} +3 -3
  42. package/dist/{codexAppServerClient-BlsOZLul.mjs → codexAppServerClient-DvBg4hGc.mjs} +3 -3
  43. package/dist/{codexCommand-BGx5NMQR.mjs → codexCommand-Bqp2--g_.mjs} +94 -60
  44. package/dist/{codexCommand-DJDPfpIs.cjs → codexCommand-DSiU6MNt.cjs} +94 -60
  45. package/dist/{codexTermination-CqPMuokw.cjs → codexTermination-D9TRTglF.cjs} +1 -1
  46. package/dist/{codexTermination-CVhhwHZU.mjs → codexTermination-DsliWl_s.mjs} +1 -1
  47. package/dist/{config-CHpxzXBL.cjs → config-CRhWiOwi.cjs} +3 -3
  48. package/dist/{config-CWAe08-Q.mjs → config-DeaqRn3o.mjs} +3 -3
  49. package/dist/{configuration-B-CugKJ3.cjs → configuration-K3I6yOjZ.cjs} +1 -1
  50. package/dist/{configuration-YXw_Dcsb.mjs → configuration-elzht62L.mjs} +1 -1
  51. package/dist/{connect-BmHvMXH2.cjs → connect-B5UbfmO3.cjs} +13 -13
  52. package/dist/{connect-CPeJXHha.mjs → connect-CT5cOlnC.mjs} +13 -13
  53. package/dist/{context-Drzs_Z38.mjs → context-CLj1_RYF.mjs} +1 -1
  54. package/dist/{context-BtIVqHI5.cjs → context-DNKNF8Yh.cjs} +1 -1
  55. package/dist/{controlClient-D0kGwKYx.cjs → controlClient-ChqmxgbB.cjs} +3 -3
  56. package/dist/{controlClient-BL4hb4l3.mjs → controlClient-CuYQs2aZ.mjs} +3 -3
  57. package/dist/{createSessionMetadata-DvGDsnsn.mjs → createSessionMetadata-C1MbLQnh.mjs} +2 -2
  58. package/dist/{createSessionMetadata-L499emJn.cjs → createSessionMetadata-QfiRx4Tf.cjs} +2 -2
  59. package/dist/daemonSupervisor-57JYYzMf.cjs +268 -0
  60. package/dist/daemonSupervisor-DfzrtNhM.mjs +245 -0
  61. package/dist/{defaultPermissionMode-MXpZlXud.cjs → defaultPermissionMode-DQmdZZIg.cjs} +2 -2
  62. package/dist/{defaultPermissionMode-BLfxu-Yz.mjs → defaultPermissionMode-U9LuUeQh.mjs} +2 -2
  63. package/dist/{deterministicJson-CfLkBRvU.cjs → deterministicJson-BBRUcB8i.cjs} +569 -17
  64. package/dist/{deterministicJson-B_UAbmQ4.mjs → deterministicJson-BixlyPWV.mjs} +572 -21
  65. package/dist/{doctor-DMvlzmnE.cjs → doctor-CKgHUV4W.cjs} +7 -7
  66. package/dist/{doctor-bKScPtZu.mjs → doctor-Dban2oE2.mjs} +7 -7
  67. package/dist/{downloadTarget-D33BFvew.cjs → downloadTarget-CmC11Y7E.cjs} +6 -6
  68. package/dist/{downloadTarget-J9j37eFG.mjs → downloadTarget-VUTd9lEO.mjs} +6 -6
  69. package/dist/{ensureDaemonRunning-2IqWROJp.cjs → ensureDaemonRunning-L0fl0cLE.cjs} +5 -5
  70. package/dist/{ensureDaemonRunning-DLvwhpNg.mjs → ensureDaemonRunning-khb8Nr1n.mjs} +5 -5
  71. package/dist/{handleResumeCommand-CjtjQ_I7.mjs → handleResumeCommand-CLDGWpTJ.mjs} +5 -5
  72. package/dist/{handleResumeCommand-Dp2Y-p6V.cjs → handleResumeCommand-D9myBN2N.cjs} +5 -5
  73. package/dist/{index-BOT0Tg5E.mjs → index-BMZx-699.mjs} +4 -4
  74. package/dist/{index-CZC7egJA.cjs → index-BdJs0465.cjs} +3 -3
  75. package/dist/{index-BI0h2Zks.mjs → index-BptfFoXM.mjs} +268 -77
  76. package/dist/{index-DymOv3kK.cjs → index-COSjJPIv.cjs} +4 -4
  77. package/dist/{index-D_LvOWUN.mjs → index-CtwqBeH6.mjs} +3 -3
  78. package/dist/{index-DYVIbhAJ.cjs → index-DgA79dVw.cjs} +40 -40
  79. package/dist/{index-oh8XEozJ.cjs → index-Fq-jxjsB.cjs} +277 -76
  80. package/dist/{index-Cllzqoes.mjs → index-GkkbUZX-.mjs} +4 -4
  81. package/dist/{index-kA46KMxN.mjs → index-IRI8s8kz.mjs} +41 -41
  82. package/dist/{index-B_aNaW9w.cjs → index-y4JNyz9H.cjs} +4 -4
  83. package/dist/index.cjs +2 -2
  84. package/dist/index.mjs +2 -2
  85. package/dist/{install-D2NCbeJ-.cjs → install-BATFlr_l.cjs} +2 -2
  86. package/dist/{install-D0inLCv-.mjs → install-F3rP8tBU.mjs} +2 -2
  87. package/dist/{install-C46mkr9a.mjs → install-JvCk2PJV.mjs} +3 -3
  88. package/dist/{install-BAa_Xmof.cjs → install-cn98bTCs.cjs} +3 -3
  89. package/dist/lib.cjs +12 -12
  90. package/dist/lib.d.cts +1 -1
  91. package/dist/lib.d.mts +1 -1
  92. package/dist/lib.mjs +12 -12
  93. package/dist/{lidState-DcPvwniz.cjs → lidState-Bcs5kRHi.cjs} +1 -1
  94. package/dist/{lidState-D8Iuvjgl.mjs → lidState-DXeYTsrm.mjs} +1 -1
  95. package/dist/{localHappyAgentAuth-D3rQDRd9.mjs → localHappyAgentAuth-C1A4ChCR.mjs} +1 -1
  96. package/dist/{localHappyAgentAuth-SD6GM97y.cjs → localHappyAgentAuth-CypTSe42.cjs} +1 -1
  97. package/dist/{logger-DK1ytCz6.cjs → logger-Cgwz30rK.cjs} +2 -2
  98. package/dist/{logger-DpqihN1f.mjs → logger-RMPh5aqe.mjs} +2 -2
  99. package/dist/{machineMetadata-IJc6_iyx.cjs → machineMetadata-BSOGMNRi.cjs} +3 -3
  100. package/dist/{machineMetadata-D4E3qoIG.mjs → machineMetadata-BTUtPRth.mjs} +3 -3
  101. package/dist/{main-DUXh2rgW.cjs → main-4iiwYpCR.cjs} +61 -56
  102. package/dist/{main-CpUmw7hm.mjs → main-DNDL6t8z.mjs} +61 -56
  103. package/dist/{mcp-D5f3Vd-z.cjs → mcp-C7eEoGhz.cjs} +15 -15
  104. package/dist/{mcp-66g1TJ8P.mjs → mcp-DXYDPOpJ.mjs} +15 -15
  105. package/dist/{mirrorProtocol-bsCUcaCY.mjs → mirrorProtocol-DQRy5PaT.mjs} +3 -3
  106. package/dist/{mirrorProtocol-DkWOcZh9.cjs → mirrorProtocol-c5g5MgNc.cjs} +3 -3
  107. package/dist/{package-BfeqAzyJ.cjs → package-3aPiSpZj.cjs} +7 -7
  108. package/dist/{package-CKj8zndE.mjs → package-CTrz6U3C.mjs} +7 -7
  109. package/dist/{panels-r8LmaBs6.mjs → panels-B5sZ84vA.mjs} +5 -5
  110. package/dist/{panels-2PXsw9-d.cjs → panels-BmsmKHbw.cjs} +5 -5
  111. package/dist/{peerTools-D_id4d41.mjs → peerTools-DIPOX033.mjs} +5 -5
  112. package/dist/{peerTools-BVp1z0T_.cjs → peerTools-Dxe7iCi_.cjs} +5 -5
  113. package/dist/{persistence-BdpwWXKh.cjs → persistence-DZRMUZZS.cjs} +2 -2
  114. package/dist/{persistence-jOEuAFTS.mjs → persistence-zJo4r7YI.mjs} +2 -2
  115. package/dist/{piRunnerArgs-vxCHKnSA.cjs → piRunnerArgs-BSPiS6tZ.cjs} +1 -1
  116. package/dist/{piRunnerArgs-68I5F_M1.mjs → piRunnerArgs-IVdoHUB6.mjs} +1 -1
  117. package/dist/{piRuntime-C3Dg5uni.cjs → piRuntime-BJzjlMcN.cjs} +2 -2
  118. package/dist/{piRuntime-DgLIard1.mjs → piRuntime-BvHO3vgO.mjs} +2 -2
  119. package/dist/{piTerminal-C135BcLP.cjs → piTerminal-Cz4pW55d.cjs} +18 -18
  120. package/dist/{piTerminal-DJL0w-uA.mjs → piTerminal-D7vBOpkE.mjs} +18 -18
  121. package/dist/{pushNotifications-CMmRsbKv.mjs → pushNotifications-C4R9-1hU.mjs} +3 -3
  122. package/dist/{pushNotifications-CyQVDThC.cjs → pushNotifications-CgIrYml3.cjs} +3 -3
  123. package/dist/{query-CK--1fbL.cjs → query-CZQG1PdU.cjs} +1 -1
  124. package/dist/{query-CPXnDURZ.mjs → query-DKPmDsHS.mjs} +1 -1
  125. package/dist/{rateLimitWindows-DJxnNw-X.cjs → rateLimitWindows-CPV0nLeq.cjs} +1 -1
  126. package/dist/{rateLimitWindows-Cqa4AGaB.mjs → rateLimitWindows-HlHATOQ0.mjs} +1 -1
  127. package/dist/{registerCommonHandlers-DbNoM39q.cjs → registerCommonHandlers-D1pC83Op.cjs} +2 -2
  128. package/dist/{registerCommonHandlers-K8dICQO2.mjs → registerCommonHandlers-a9lHojSV.mjs} +2 -2
  129. package/dist/{registerKillSessionHandler-O1iriOMO.mjs → registerKillSessionHandler-Bp-fuH-w.mjs} +6 -6
  130. package/dist/{registerKillSessionHandler-DiS_go8d.cjs → registerKillSessionHandler-nTi2vVJy.cjs} +6 -6
  131. package/dist/{remoteSessionClient-BlURPulk.mjs → remoteSessionClient-Cwrddscy.mjs} +5 -5
  132. package/dist/{remoteSessionClient-CtV9mDko.cjs → remoteSessionClient-HQAKAvVd.cjs} +5 -5
  133. package/dist/{reportProgressTool-DlD_xjzU.cjs → reportProgressTool-Be-8ADI4.cjs} +4 -4
  134. package/dist/{reportProgressTool-nCExrHZH.mjs → reportProgressTool-CcZ32nrd.mjs} +4 -4
  135. package/dist/{resources-CH1iP6Cv.mjs → resources-CLdQfe3b.mjs} +1 -1
  136. package/dist/{resources-BPyN59Iv.cjs → resources-CqwHPhdK.cjs} +1 -1
  137. package/dist/{run-drtwHYkO.mjs → run-BBU8GyxE.mjs} +59 -243
  138. package/dist/{run-BBNrcCfI.cjs → run-CxRJk9qq.cjs} +69 -254
  139. package/dist/{runClaude-CFp27Tyi.mjs → runClaude-DR6pEQwd.mjs} +22 -22
  140. package/dist/{runClaude-B3KSeby4.cjs → runClaude-Dd5zJaUZ.cjs} +22 -22
  141. package/dist/{runClaudeDeps-DMcv93lA.mjs → runClaudeDeps-COgZaUZm.mjs} +50 -45
  142. package/dist/{runClaudeDeps-C_C9TCI0.cjs → runClaudeDeps-CTtZ_1mC.cjs} +45 -40
  143. package/dist/{runGemini-Bc6SY-hd.mjs → runGemini-DVoVUfPp.mjs} +37 -35
  144. package/dist/{runGemini-DzdSBAr9.cjs → runGemini-DX72qB92.cjs} +37 -35
  145. package/dist/{runOpenClaw-DI0qMlgF.mjs → runOpenClaw-BHjzmzeC.mjs} +18 -18
  146. package/dist/{runOpenClaw-DN6rEVqC.cjs → runOpenClaw-BSg4hFVt.cjs} +18 -18
  147. package/dist/{sandbox-v-ffe8LR.mjs → sandbox-CWR9EqoN.mjs} +4 -4
  148. package/dist/{sandbox-DtttPBMA.cjs → sandbox-D1T_hmgZ.cjs} +4 -4
  149. package/dist/{selfCheck-B-yy6bW3.cjs → selfCheck-CE7vlnNS.cjs} +36 -36
  150. package/dist/selfCheck-ZGgBtxFQ.mjs +85 -0
  151. package/dist/{send-DpBwSZuj.mjs → send-BDF0Zvxo.mjs} +8 -8
  152. package/dist/{send-ShzXYPRu.cjs → send-BxZqRCcG.cjs} +8 -8
  153. package/dist/{server-DScgJXxa.mjs → server-B4JtnDLF.mjs} +4 -4
  154. package/dist/{server-CEzKrfKj.cjs → server-DB7_70Mi.cjs} +6 -6
  155. package/dist/{sessionLock-Dc0fadGG.cjs → sessionLock-BXvFN6uw.cjs} +3 -3
  156. package/dist/{sessionLock-B6K4SBZD.mjs → sessionLock-CXOOX-VD.mjs} +3 -3
  157. package/dist/{sessionOps-Dx7wARjI.cjs → sessionOps-BWlDlFYP.cjs} +4 -4
  158. package/dist/{sessionOps-D0BPWPoh.mjs → sessionOps-ByVggB_q.mjs} +4 -4
  159. package/dist/{sessionScanner-BJ35TVG6.cjs → sessionScanner-DkxPB5VA.cjs} +3 -3
  160. package/dist/{sessionScanner-9Fpgaxtf.mjs → sessionScanner-r66RtF95.mjs} +3 -3
  161. package/dist/{sessions-TZGGAry1.cjs → sessions-BiJTxFy9.cjs} +10 -10
  162. package/dist/{sessions-CFtDlyZd.mjs → sessions-C1lLK_a9.mjs} +10 -10
  163. package/dist/{setupOfflineReconnection-Biaus-0T.mjs → setupOfflineReconnection-Bl3DuakT.mjs} +2 -2
  164. package/dist/{setupOfflineReconnection-B1GsVA8P.cjs → setupOfflineReconnection-CecTiFZ-.cjs} +2 -2
  165. package/dist/{spawn-CsoQ-Ecz.mjs → spawn-D-8MlEM6.mjs} +14 -14
  166. package/dist/{spawn-BRTuypQ2.cjs → spawn-D79mVa3h.cjs} +14 -14
  167. package/dist/{spawnAgents-Co-SLcx-.mjs → spawnAgents-DJHjq01u.mjs} +1 -1
  168. package/dist/{spawnAgents-CG211IW7.cjs → spawnAgents-Sfnf-4pN.cjs} +1 -1
  169. package/dist/{spawnHappyCLI-D47kX6jg.cjs → spawnHappyCLI-CQwQs9G5.cjs} +1 -1
  170. package/dist/{spawnHappyCLI-D1doCjkZ.mjs → spawnHappyCLI-v_bJwZ4Z.mjs} +1 -1
  171. package/dist/{specialCommands-Ch-Gvy-i.cjs → specialCommands-CWMVfT5s.cjs} +3 -3
  172. package/dist/{specialCommands-xSmqT_Fu.mjs → specialCommands-yMnFvS-W.mjs} +3 -3
  173. package/dist/{startFileWatcher-CCl2fFxT.mjs → startFileWatcher-BCDkT_tr.mjs} +1 -1
  174. package/dist/{startFileWatcher-gKQTstR6.cjs → startFileWatcher-GW4_E7dV.cjs} +1 -1
  175. package/dist/{startupSessionCreate-DlZc8yPl.mjs → startupSessionCreate-BcAGYo51.mjs} +1 -1
  176. package/dist/{startupSessionCreate-BXqoUX30.cjs → startupSessionCreate-tBRa_ze8.cjs} +1 -1
  177. package/dist/{streamRelay-DnJXsi36.mjs → streamRelay-BEDiy6_b.mjs} +1 -1
  178. package/dist/{streamRelay-B-J-4St1.cjs → streamRelay-BZ8drtof.cjs} +1 -1
  179. package/dist/{sync-BbjMC3sR.mjs → sync--QUIOuf8.mjs} +1 -1
  180. package/dist/{sync-BxMdnZzz.cjs → sync-BMDkyo75.cjs} +1 -1
  181. package/dist/{systemPrompt-C2KojRmK.cjs → systemPrompt-DoHSXrH0.cjs} +2 -2
  182. package/dist/{systemPrompt-CmSDAoIx.mjs → systemPrompt-O0Kd6vbA.mjs} +2 -2
  183. package/dist/{teams-DESdalox.cjs → teams-BkZop-sP.cjs} +9 -9
  184. package/dist/{teams-lRy1MS0Z.mjs → teams-CTF1gT48.mjs} +9 -9
  185. package/dist/{template-BaHAmH2K.cjs → template-CeC1dYe-.cjs} +32 -2
  186. package/dist/{template-CiOPa2rd.mjs → template-D1fm22em.mjs} +31 -3
  187. package/dist/{time-Cfknl7xG.mjs → time-B2KKdAym.mjs} +1 -1
  188. package/dist/{time-DNLeIRgR.cjs → time-CdCotzKU.cjs} +1 -1
  189. package/dist/{titleGenerator-ClnMSzwC.mjs → titleGenerator-BFDczskR.mjs} +1 -1
  190. package/dist/{titleGenerator-YNutaU88.cjs → titleGenerator-DZH1XqAf.cjs} +2 -2
  191. package/dist/{todo-DZbK5POc.mjs → todo-C2gyOUom.mjs} +6 -6
  192. package/dist/{todo-DS75Mboz.cjs → todo-DnTFTHmV.cjs} +6 -6
  193. package/dist/{tools-ClYcb1YQ.cjs → tools-C8rpwyIl.cjs} +1 -1
  194. package/dist/{tools-BgdU0dWp.mjs → tools-DUjkqSQL.mjs} +1 -1
  195. package/dist/{uninstall-bXenFevR.mjs → uninstall-B5Ew50mZ.mjs} +3 -3
  196. package/dist/{uninstall-Di1vPBLV.cjs → uninstall-CKMPWTMv.cjs} +3 -3
  197. package/package.json +7 -7
  198. package/dist/daemonSupervisor-B-SPSqhs.cjs +0 -13
  199. package/dist/daemonSupervisor-C6urv3_8.mjs +0 -10
  200. package/dist/selfCheck-BDfTwxqB.mjs +0 -85
@@ -1,31 +1,33 @@
1
- import { l as logger } from './logger-DpqihN1f.mjs';
1
+ import { l as logger } from './logger-RMPh5aqe.mjs';
2
2
  import { p as prependToMessage, b as buildDigestLine, a as buildFirstTurnPrefix } from './prompt-QHuFx9j6.mjs';
3
- import { P as ProjectsUnsupportedError } from './client-o-meK7-a.mjs';
4
- import { c as createSelfReportState, A as AUTOMATION_TOOL_NAMES, P as PROJECT_TOOL_NAMES, r as registerAutomationTools, a as registerProjectTools, d as createProjectToolExecutor, b as registerReportProgressTool, n as normalizeAttention, e as normalizePhase, f as normalizeProgress, s as shouldAcceptSelfReport } from './reportProgressTool-nCExrHZH.mjs';
3
+ import { P as ProjectsUnsupportedError } from './client-5_zDNdOh.mjs';
4
+ import { c as createSelfReportState, A as AUTOMATION_TOOL_NAMES, P as PROJECT_TOOL_NAMES, r as registerAutomationTools, a as registerProjectTools, d as createProjectToolExecutor, b as registerReportProgressTool, n as normalizeAttention, e as normalizePhase, f as normalizeProgress, s as shouldAcceptSelfReport } from './reportProgressTool-CcZ32nrd.mjs';
5
5
  import { readFileSync, constants } from 'node:fs';
6
6
  import { homedir } from 'node:os';
7
7
  import { join, dirname } from 'node:path';
8
8
  import { z } from 'zod';
9
9
  import { p as piAgentDir } from './pi-CqyoZMjI.mjs';
10
10
  import { unlink, mkdir, open, rename } from 'node:fs/promises';
11
- import { randomUUID } from 'node:crypto';
12
- import { T as TeamConnectionPreflightError, S as SessionInOtherTeamError, c as createTeamsClient } from './client-BGfmSbWc.mjs';
13
- import { t as teamScopePath } from './context-Drzs_Z38.mjs';
14
- import { g as waitForSessionKey, e as sendUserMessage } from './sessionOps-D0BPWPoh.mjs';
15
- import { T as TEAM_SKILL, a as TEAM_LEAD_PLAYBOOK } from './resources-CH1iP6Cv.mjs';
16
- import { T as TEAM_TOOL_NAMES, r as registerTeamsTools } from './tools-BgdU0dWp.mjs';
17
- import { S as SESSION_PEER_TOOL_NAMES, r as registerSessionPeerTools, a as createSessionPeerToolExecutor } from './peerTools-D_id4d41.mjs';
11
+ import { randomUUID, createHash } from 'node:crypto';
12
+ import { T as TeamConnectionPreflightError, S as SessionInOtherTeamError, c as createTeamsClient, t as teamRequest } from './client-DfDyE322.mjs';
13
+ import { t as teamScopePath, r as readTeamScope } from './context-CLj1_RYF.mjs';
14
+ import { g as waitForSessionKey, e as sendUserMessage } from './sessionOps-ByVggB_q.mjs';
15
+ import { T as TEAM_SKILL, a as TEAM_LEAD_PLAYBOOK } from './resources-CLdQfe3b.mjs';
16
+ import { T as TEAM_TOOL_NAMES, r as registerTeamsTools } from './tools-DUjkqSQL.mjs';
17
+ import { S as SESSION_PEER_TOOL_NAMES, r as registerSessionPeerTools, a as createSessionPeerToolExecutor } from './peerTools-DIPOX033.mjs';
18
18
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
19
19
  import { createServer } from 'node:http';
20
20
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
21
21
  import { C as CLIPBOARD_TOOL_NAME, a as CLIPBOARD_TOOL_TITLE, b as CLIPBOARD_TOOL_DESCRIPTION, c as CLIPBOARD_MAX_BYTES } from './limits-DIo7rEBR.mjs';
22
- import { A as ASSISTANT_TOOL_NAMES, a as registerAssistantTools, c as checkDownloadTarget } from './downloadTarget-J9j37eFG.mjs';
22
+ import { A as ASSISTANT_TOOL_NAMES, a as registerAssistantTools, c as checkDownloadTarget } from './downloadTarget-VUTd9lEO.mjs';
23
23
  import { P as PREVIEW_TOOL_NAME, R as REPORT_PROGRESS_TOOL_NAME, a as PREVIEW_TOOL_TITLE, b as PREVIEW_TOOL_DESCRIPTION, c as PREVIEW_DOWNLOAD_PARAM_DESCRIPTION } from './agentGuidance-BDYt2Qy2.mjs';
24
24
  import { n as normalizeWebPanels, w as webPanelPath } from './webPanels-B2_C2-3g.mjs';
25
- import { r as readSettings } from './persistence-jOEuAFTS.mjs';
26
- import { g as getSessionNotificationBody } from './pushNotifications-CMmRsbKv.mjs';
25
+ import { b as readCredentialsForConfiguredRelay, r as readSettings } from './persistence-zJo4r7YI.mjs';
26
+ import { g as getSessionNotificationBody } from './pushNotifications-C4R9-1hU.mjs';
27
27
  import { c as checkPreviewPath } from './previewPath-CXN4Vag0.mjs';
28
- import { createHash } from 'crypto';
28
+ import { x as ATTENTION_DISABLED_ERROR, y as ATTENTION_LIMITS, z as ownerBoardPostToRest, C as isAttentionBoardLocalId, O as OwnerBoardPostInputSchema, D as OwnerBoardUpdateInputSchema, E as OwnerBoardResolveInputSchema, F as OwnerBoardListInputSchema, G as ATTENTION_SESSION_CAPABILITY } from './index-BptfFoXM.mjs';
29
+ import { c as configuration } from './configuration-elzht62L.mjs';
30
+ import { createHash as createHash$1 } from 'crypto';
29
31
 
30
32
  function createProjectInjector(deps) {
31
33
  const timeoutMs = deps.timeoutMs ?? 1500;
@@ -301,10 +303,6 @@ function createRequestHuman(deps) {
301
303
  const reason = rawReason.replace(/\s+/g, " ").trim().slice(0, REQUEST_HUMAN_REASON_MAX);
302
304
  if (!reason) return { notified: false, error: "reason must be a non-empty string" };
303
305
  await deps.reportBlocked(reason);
304
- const at = now();
305
- if (last && last.reason === reason && at - last.at < REQUEST_HUMAN_DEDUPE_MS) {
306
- return { notified: true, deduped: true };
307
- }
308
306
  let url = `/session/${encodeURIComponent(deps.sessionId)}`;
309
307
  let unknownPanel;
310
308
  if (panel) {
@@ -313,18 +311,534 @@ function createRequestHuman(deps) {
313
311
  if (machineId && panels.some((p) => p.id === panel)) url = webPanelPath(machineId, panel);
314
312
  else unknownPanel = panel;
315
313
  }
314
+ if (deps.postBlocked && await deps.postBlocked(reason, unknownPanel ? void 0 : panel).catch(() => false)) {
315
+ return { notified: true, board: true, ...unknownPanel ? { unknownPanel } : {} };
316
+ }
317
+ const at = now();
318
+ if (last && last.reason === reason && at - last.at < REQUEST_HUMAN_DEDUPE_MS) {
319
+ return { notified: true, deduped: true };
320
+ }
316
321
  const sent = await deps.sendAttention({ sessionId: deps.sessionId, reason, url });
317
322
  if (sent.sent) last = { reason, at };
318
323
  return { notified: sent.sent, url, ...unknownPanel ? { unknownPanel } : {}, ...sent.error ? { error: sent.error } : {} };
319
324
  };
320
325
  }
321
326
  function requestHumanResultText(r) {
327
+ if (r.board) {
328
+ const panelNote2 = r.unknownPanel ? ` (panel "${r.unknownPanel}" is not declared on this machine, so it is not linked)` : "";
329
+ return `Posted to the user's briefing board as blocked; the server notifies them once (asking again with the same reason only refreshes it)${panelNote2}. This does not mean they have seen it. Poll your own completion condition (URL changed, element gone) instead of waiting for a reply.`;
330
+ }
322
331
  if (r.deduped) return "Already asked for this in the last minute; the board still shows it. Keep polling your completion condition.";
323
332
  if (!r.notified) return `Could not notify the user: ${r.error ?? "unknown error"}. The task board is marked blocked.`;
324
333
  const panelNote = r.unknownPanel ? ` (panel "${r.unknownPanel}" is not declared on this machine, so the notification opens the session instead)` : "";
325
334
  return `Notified the user${panelNote}. This does not mean they have seen it. Poll your own completion condition (URL changed, element gone) instead of waiting for a reply.`;
326
335
  }
327
336
 
337
+ const UNSUPPORTED_BACKOFF_MS = 10 * 6e4;
338
+ class AttentionUnsupportedError extends Error {
339
+ constructor() {
340
+ super("This Very Happy server has no briefing board");
341
+ }
342
+ }
343
+ class AttentionRequestError extends Error {
344
+ constructor(status, code) {
345
+ super(code ? `Briefing board request failed: ${code}` : `Briefing board request failed (HTTP ${status})`);
346
+ this.status = status;
347
+ this.code = code;
348
+ }
349
+ }
350
+ function isItemErrorCode(code) {
351
+ return typeof code === "string" && code.startsWith("attention_") || code === "session_not_found";
352
+ }
353
+ function createAttentionClient(deps = {}) {
354
+ const now = deps.now ?? Date.now;
355
+ const doFetch = deps.fetch ?? fetch;
356
+ const token = deps.token ?? (async () => (await readCredentialsForConfiguredRelay())?.token ?? null);
357
+ let disabledUntil = 0;
358
+ async function request(path, method, body, timeoutMs = 1e4) {
359
+ if (now() < disabledUntil) throw new AttentionUnsupportedError();
360
+ const bearer = await token();
361
+ if (!bearer) throw new AttentionRequestError(401, "not_signed_in");
362
+ const response = await doFetch(`${deps.serverUrl ?? configuration.serverUrl}${path}`, {
363
+ method,
364
+ redirect: "error",
365
+ headers: { authorization: `Bearer ${bearer}`, ...body === void 0 ? {} : { "content-type": "application/json" } },
366
+ body: body === void 0 ? void 0 : JSON.stringify(body),
367
+ signal: AbortSignal.timeout(timeoutMs)
368
+ });
369
+ let json = null;
370
+ try {
371
+ json = await response.json();
372
+ } catch {
373
+ }
374
+ if (response.status === 404 && (json?.error === ATTENTION_DISABLED_ERROR || !isItemErrorCode(json?.error))) {
375
+ disabledUntil = now() + UNSUPPORTED_BACKOFF_MS;
376
+ throw new AttentionUnsupportedError();
377
+ }
378
+ if (!response.ok) throw new AttentionRequestError(response.status, typeof json?.error === "string" ? json.error : null);
379
+ return json;
380
+ }
381
+ const enc = encodeURIComponent;
382
+ return {
383
+ isDisabled: () => now() < disabledUntil,
384
+ /** True when this server serves the board for this account (feature flag on). Network errors throw. */
385
+ async probe(sessionId, timeoutMs = 5e3) {
386
+ try {
387
+ await request(`/v1/attention-items?sessionId=${enc(sessionId)}&limit=1`, "GET", void 0, timeoutMs);
388
+ return true;
389
+ } catch (error) {
390
+ if (error instanceof AttentionUnsupportedError) return false;
391
+ throw error;
392
+ }
393
+ },
394
+ post: (input) => request("/v1/attention-items", "POST", input),
395
+ patch: (id, patch) => request(`/v1/attention-items/${enc(id)}`, "PATCH", patch),
396
+ resolve: (id, input) => request(`/v1/attention-items/${enc(id)}/resolve`, "POST", input),
397
+ list: (query, timeoutMs) => {
398
+ const params = new URLSearchParams();
399
+ for (const [key, value] of Object.entries(query)) if (value !== void 0) params.set(key, String(value));
400
+ return request(`/v1/attention-items?${params.toString()}`, "GET", void 0, timeoutMs);
401
+ }
402
+ };
403
+ }
404
+ let shared = null;
405
+ function sharedAttentionClient() {
406
+ return shared ??= createAttentionClient();
407
+ }
408
+
409
+ const TRIGGERS = [
410
+ /需要你(?:来)?(?:决定|拍板|确认|选择|定夺|批准|授权|选)/,
411
+ /请你?(?:来)?(?:拍板|决定|定夺|确认一下|选择|选一个|选一下)/,
412
+ /(?:等你|由你|你来)(?:拍板|决定|定夺|确认|选)/,
413
+ /需要\s*owner\s*(?:决定|拍板|确认)/i,
414
+ /\b(?:need|needs|waiting for|awaiting)\s+(?:your|the owner'?s?)\s+(?:decision|call|approval|sign-?off|go-?ahead)\b/i,
415
+ /\b(?:i|we)\s+need\s+you\s+to\s+(?:decide|choose|pick|confirm|approve)\b/i,
416
+ /\bplease\s+(?:decide|choose|pick one|confirm which|approve)\b/i,
417
+ /<options>/i
418
+ ];
419
+ const OPTION_LINE = /^\s*(?:[-*+]\s+)?(?:\*\*)?(?:选项|option\s*)?([A-Da-d]|[1-4])(?:\*\*)?\s*[.)、::)]\s*(?:\*\*)?\s*(\S.*?)\s*$/i;
420
+ const TAGGED_OPTION = /<option(?:\s+id="([^"]{1,16})")?\s*>([\s\S]*?)<\/option>/gi;
421
+ const RECOMMENDED = /推荐|建议选|\brecommend(?:ed)?\b|\(rec\)/i;
422
+ function stripCode(text) {
423
+ return text.replace(/```[\s\S]*?(?:```|$)/g, "\n").replace(/`[^`\n]*`/g, " ");
424
+ }
425
+ function clean(text, max) {
426
+ const flat = text.replace(/\*\*|__|^#+\s*/g, "").replace(/\s+/g, " ").trim();
427
+ return flat.length > max ? `${flat.slice(0, max - 1)}\u2026` : flat;
428
+ }
429
+ function triggerSentence(text, match) {
430
+ const start = Math.max(text.lastIndexOf("\n", match.index), ...["\u3002", "\uFF01", "\uFF1F", ". ", "! ", "? "].map((p) => {
431
+ const at = text.lastIndexOf(p, match.index);
432
+ return at < 0 ? -1 : at + p.length - 1;
433
+ })) + 1;
434
+ const rest = text.slice(match.index);
435
+ const endRel = rest.search(/[。!?\n]|[.!?](?:\s|$)/);
436
+ const end = endRel < 0 ? text.length : match.index + endRel + 1;
437
+ return text.slice(start, end);
438
+ }
439
+ function optionLabel(raw) {
440
+ return clean(raw.replace(/<[^>]+>/g, ""), ATTENTION_LIMITS.optionLabelChars);
441
+ }
442
+ function parseOptions(text) {
443
+ const tagged = [...text.matchAll(TAGGED_OPTION)].slice(0, ATTENTION_LIMITS.options.max);
444
+ if (tagged.length >= ATTENTION_LIMITS.options.min) {
445
+ return tagged.map((m, i) => ({
446
+ id: (m[1] ?? String.fromCharCode(65 + i)).slice(0, ATTENTION_LIMITS.optionIdChars),
447
+ label: optionLabel(m[2]) || `Option ${i + 1}`,
448
+ ...RECOMMENDED.test(m[2]) ? { recommended: true } : {}
449
+ }));
450
+ }
451
+ const groups = [];
452
+ let current = null;
453
+ for (const line of text.split("\n")) {
454
+ if (!line.trim()) continue;
455
+ const m = OPTION_LINE.exec(line);
456
+ if (!m) {
457
+ current = null;
458
+ continue;
459
+ }
460
+ const id = m[1].toUpperCase();
461
+ const letter = /[A-D]/.test(id);
462
+ if (!current || current.letter !== letter || current.lines.some((l) => l.id === id)) {
463
+ current = { letter, lines: [] };
464
+ groups.push(current);
465
+ }
466
+ current.lines.push({ id, label: optionLabel(m[2]), recommended: RECOMMENDED.test(m[2]) });
467
+ }
468
+ const usable = groups.filter((g) => g.lines.length >= ATTENTION_LIMITS.options.min && g.lines.every((l) => l.label));
469
+ const pick = usable.find((g) => g.letter) ?? usable[0];
470
+ if (!pick) return [];
471
+ return pick.lines.slice(0, ATTENTION_LIMITS.options.max).map((l) => ({ id: l.id, label: l.label, ...l.recommended ? { recommended: true } : {} }));
472
+ }
473
+ function defaultOptions(cjk) {
474
+ return cjk ? [{ id: "yes", label: "\u540C\u610F" }, { id: "other", label: "\u53E6\u6709\u5B89\u6392\uFF08\u56DE\u590D\u8BF4\u660E\uFF09" }] : [{ id: "yes", label: "Approve" }, { id: "other", label: "Something else (reply)" }];
475
+ }
476
+ function inferOwnerDecision(text) {
477
+ const prose = stripCode(text);
478
+ let match = null;
479
+ for (const trigger of TRIGGERS) {
480
+ match = trigger.exec(prose);
481
+ if (match) break;
482
+ }
483
+ if (!match) return null;
484
+ const title = clean(triggerSentence(prose, match).replace(/<\/?options>/gi, ""), ATTENTION_LIMITS.titleChars);
485
+ if (!title) return null;
486
+ const parsed = parseOptions(text);
487
+ const options = parsed.length ? parsed : defaultOptions(/[㐀-鿿]/.test(title));
488
+ const digest = createHash("sha256").update(`${title}
489
+ ${options.map((o) => `${o.id}:${o.label}`).join("\n")}`).digest("hex").slice(0, 16);
490
+ const encoder = new TextEncoder();
491
+ let bodyMd = text.trim();
492
+ while (encoder.encode(bodyMd).length > ATTENTION_LIMITS.bodyBytes / 2) bodyMd = `${bodyMd.slice(0, Math.floor(bodyMd.length * 0.8))}\u2026`;
493
+ return { title, options, key: `inferred-${digest}`, bodyMd };
494
+ }
495
+
496
+ const OWNER_BOARD_DIGEST_TIMEOUT_MS = 1500;
497
+ const QUESTION_TITLE_CHARS = 60;
498
+ const DIGEST_TITLE_CHARS = 40;
499
+ const DIGEST_MAX_CHARS = 480;
500
+ const LEAD_RECHECK_MS = 6e4;
501
+ const OWNER_SENT_FROM = ["web", "mobile", "ios", "android"];
502
+ const AUTOMATED_LOCAL_ID_PREFIXES = ["automation-", "teams-", "remote-send-", "session-message-", "edit-conflict-"];
503
+ function isOwnerMessage(input) {
504
+ const localId = input.localId ?? "";
505
+ if (isAttentionBoardLocalId(localId)) return false;
506
+ if (AUTOMATED_LOCAL_ID_PREFIXES.some((prefix) => localId.startsWith(prefix))) return false;
507
+ return typeof input.sentFrom === "string" && OWNER_SENT_FROM.includes(input.sentFrom);
508
+ }
509
+ function clip(text, max) {
510
+ const flat = text.replace(/\s+/g, " ").trim();
511
+ return flat.length > max ? `${flat.slice(0, max - 1)}\u2026` : flat;
512
+ }
513
+ function ownerQuestionTitle(text) {
514
+ const trimmed = text.trim();
515
+ if (!trimmed || trimmed.startsWith("/")) return null;
516
+ const first = trimmed.split("\n").find((line) => line.trim()) ?? "";
517
+ return clip(first, QUESTION_TITLE_CHARS) || null;
518
+ }
519
+ function minutesAgo(ms, now) {
520
+ const m = Math.max(0, Math.round((now - ms) / 6e4));
521
+ return m < 60 ? `${m}m` : `${Math.round(m / 60)}h`;
522
+ }
523
+ function formatBoardDigest(items, now, opts) {
524
+ if (items.length === 0) return null;
525
+ const parts = [];
526
+ let used = 0;
527
+ let shown = 0;
528
+ for (const item of items) {
529
+ const handle = item.key && !item.key.startsWith("req:") ? `key=${item.key}` : `id=${item.id}`;
530
+ const part = `${item.source === "owner" ? "owner " : ""}${item.kind} \u300C${clip(item.title, DIGEST_TITLE_CHARS)}\u300D ${handle} ${minutesAgo(item.createdAt, now)}`;
531
+ if (shown > 0 && used + part.length > DIGEST_MAX_CHARS) break;
532
+ parts.push(part);
533
+ used += part.length + 2;
534
+ shown++;
535
+ }
536
+ const more = items.length - shown;
537
+ const line1 = `[Briefing board] ${items.length} open: ${parts.join("; ")}${more > 0 ? `; +${more} more` : ""}`;
538
+ const line2 = opts.tools ? "[Briefing board] Answer owner items in this turn or settle them with owner_board_update / owner_board_resolve (owner_board_list shows ids); do not repeat open decisions in chat." : null;
539
+ return line2 ? `${line1}
540
+ ${line2}` : line1;
541
+ }
542
+ function parseSince(since) {
543
+ if (since === void 0) return void 0;
544
+ if (/^\d+$/.test(since)) return Number(since);
545
+ const parsed = Date.parse(since);
546
+ if (Number.isNaN(parsed)) throw new Error("since must be ISO-8601 or epoch milliseconds");
547
+ return parsed;
548
+ }
549
+ async function resolveTeamLead(sessionId) {
550
+ try {
551
+ const scope = await readTeamScope(teamScopePath(sessionId));
552
+ if (!scope) return false;
553
+ const inspected = await teamRequest(`/v1/teams/${encodeURIComponent(scope.teamId)}/agent`, "GET", scope.scopeToken, true);
554
+ const bots = Array.isArray(inspected?.team?.bots) ? inspected.team.bots : [];
555
+ return bots.some((bot) => bot.id === scope.botId && bot.root === true);
556
+ } catch {
557
+ return false;
558
+ }
559
+ }
560
+ function createLeadBoard(deps) {
561
+ const now = deps.now ?? Date.now;
562
+ const log = deps.log ?? (() => {
563
+ });
564
+ let supported = false;
565
+ let lead = false;
566
+ let leadCheckedAt = 0;
567
+ let toolsFrozen = null;
568
+ let initPromise = null;
569
+ let initDone = false;
570
+ let lastLocalId = null;
571
+ let pending = [];
572
+ let turn = null;
573
+ let work = Promise.resolve();
574
+ const queue = (task) => {
575
+ work = work.then(task).catch((error) => log(`[ownerBoard] ${error instanceof Error ? error.message : String(error)}`));
576
+ return work;
577
+ };
578
+ async function refreshLead() {
579
+ if (lead || now() - leadCheckedAt < LEAD_RECHECK_MS) return lead;
580
+ leadCheckedAt = now();
581
+ lead = await deps.isLead().catch(() => false);
582
+ return lead;
583
+ }
584
+ function init() {
585
+ return initPromise ??= (async () => {
586
+ try {
587
+ supported = await deps.client.probe(deps.sessionId());
588
+ } catch (error) {
589
+ log(`[ownerBoard] probe failed: ${error instanceof Error ? error.message : String(error)}`);
590
+ supported = false;
591
+ }
592
+ if (supported) {
593
+ deps.onSupported?.();
594
+ await refreshLead();
595
+ }
596
+ initDone = true;
597
+ })();
598
+ }
599
+ async function active() {
600
+ await init();
601
+ return supported && !deps.client.isDisabled() && await refreshLead();
602
+ }
603
+ function thisTurnAnchor() {
604
+ const localId = turn?.promptLocalId ?? lastLocalId;
605
+ if (!localId) return void 0;
606
+ const text = turn?.texts.at(-1);
607
+ return { localId, ...text ? { snippet: clip(text, ATTENTION_LIMITS.snippetChars) } : {} };
608
+ }
609
+ const noteBoardTool = (name) => {
610
+ turn?.boardTools.add(name);
611
+ };
612
+ async function settleQuestions(questions, reply) {
613
+ for (const question of questions) {
614
+ const id = await question.itemId;
615
+ if (!id) continue;
616
+ const anchor = { localId: question.localId, snippet: clip(reply, ATTENTION_LIMITS.snippetChars) };
617
+ const { item } = await deps.client.patch(id, { firstReply: anchor, requestId: `first-reply-${question.localId}`.slice(0, 128) });
618
+ if (item.state === "open") {
619
+ await deps.client.resolve(id, { outcome: "answered", by: "auto-first-reply", requestId: `auto-answered-${question.localId}`.slice(0, 128) });
620
+ }
621
+ }
622
+ }
623
+ async function draftDecision(text, anchor) {
624
+ if (!await deps.autoDetect().catch(() => true)) return;
625
+ const draft = inferOwnerDecision(text);
626
+ if (!draft) return;
627
+ await deps.client.post({
628
+ sessionId: deps.sessionId(),
629
+ source: "lead",
630
+ kind: "decision",
631
+ inferred: true,
632
+ title: draft.title,
633
+ bodyMd: draft.bodyMd,
634
+ options: draft.options,
635
+ key: draft.key,
636
+ ...anchor ? { anchor } : {},
637
+ requestId: randomUUID()
638
+ });
639
+ }
640
+ return {
641
+ init,
642
+ /** Waits (bounded) for the first probe so the first `tools/list` sees the final tool set. */
643
+ async ready(timeoutMs) {
644
+ await Promise.race([init(), new Promise((resolve) => setTimeout(resolve, timeoutMs).unref?.())]);
645
+ },
646
+ /** Server serves the board (any session: request_human items, `owner-board-v1`). */
647
+ supported: () => supported && !deps.client.isDisabled(),
648
+ /**
649
+ * `owner_board_*` exposure, decided once per process: the tool list must
650
+ * not change under a running agent. A session adopted into a team later
651
+ * gets the tools on its next relaunch; the fallbacks start at once.
652
+ */
653
+ toolsExposed() {
654
+ if (toolsFrozen === null && initDone) toolsFrozen = supported && lead;
655
+ return toolsFrozen ?? false;
656
+ },
657
+ // ─── tools ──────────────────────────────────────────────────────────
658
+ async post(input) {
659
+ noteBoardTool("owner_board_post");
660
+ const anchor = input.anchor === void 0 || input.anchor === "this_turn" ? thisTurnAnchor() : { localId: input.anchor.localId };
661
+ const { item, created } = await deps.client.post(ownerBoardPostToRest(deps.sessionId(), input, anchor));
662
+ return { id: item.id, created };
663
+ },
664
+ async update(input) {
665
+ noteBoardTool("owner_board_update");
666
+ return deps.client.patch(input.id, {
667
+ ...input.title !== void 0 ? { title: input.title } : {},
668
+ ...input.body_md !== void 0 ? { bodyMd: input.body_md } : {},
669
+ ...input.append_md !== void 0 ? { appendMd: input.append_md } : {},
670
+ ...input.options !== void 0 ? { options: input.options } : {},
671
+ ...input.links !== void 0 ? { links: input.links } : {},
672
+ ...input.state !== void 0 ? { state: input.state } : {},
673
+ requestId: input.request_id
674
+ });
675
+ },
676
+ async resolve(input) {
677
+ noteBoardTool("owner_board_resolve");
678
+ return deps.client.resolve(input.id, { outcome: input.outcome, ...input.note !== void 0 ? { note: input.note } : {}, by: "lead", requestId: input.request_id });
679
+ },
680
+ async list(input) {
681
+ const since = parseSince(input.since);
682
+ return deps.client.list({ sessionId: deps.sessionId(), state: input.state === "all" ? "all" : "open", limit: 50, ...since !== void 0 ? { since } : {} });
683
+ },
684
+ /**
685
+ * `request_human` as a `blocked` item (server dedupes by key and pushes
686
+ * once). False when this server has no board: the caller keeps the old
687
+ * metadata + push path.
688
+ */
689
+ async postBlocked(reason, panel) {
690
+ noteBoardTool("request_human");
691
+ await init();
692
+ if (!supported || deps.client.isDisabled()) return false;
693
+ try {
694
+ await deps.client.post({
695
+ sessionId: deps.sessionId(),
696
+ source: "agent",
697
+ kind: "blocked",
698
+ title: clip(reason, ATTENTION_LIMITS.titleChars),
699
+ ...reason.length > ATTENTION_LIMITS.titleChars ? { bodyMd: reason } : {},
700
+ key: `request-human-${createHash("sha256").update(reason).digest("hex").slice(0, 16)}`,
701
+ ...panel ? { links: [{ type: "panel", ref: panel }] } : {},
702
+ ...thisTurnAnchor() ? { anchor: thisTurnAnchor() } : {},
703
+ requestId: randomUUID()
704
+ });
705
+ return true;
706
+ } catch (error) {
707
+ if (!(error instanceof AttentionUnsupportedError)) log(`[ownerBoard] request_human item failed: ${error instanceof Error ? error.message : String(error)}`);
708
+ return false;
709
+ }
710
+ },
711
+ // ─── message taps ───────────────────────────────────────────────────
712
+ /** Every routed user message (any runner). Owner messages in a lead session become `question` items. */
713
+ onUserMessage(message) {
714
+ if (message.localId) lastLocalId = message.localId;
715
+ if (!message.localId || !isOwnerMessage(message)) return;
716
+ const title = ownerQuestionTitle(message.text ?? "");
717
+ if (!title) return;
718
+ const localId = message.localId;
719
+ const itemId = (async () => {
720
+ if (!await active()) return null;
721
+ const { item } = await deps.client.post({
722
+ sessionId: deps.sessionId(),
723
+ source: "owner",
724
+ kind: "question",
725
+ title,
726
+ anchor: { localId, snippet: clip(message.text ?? "", ATTENTION_LIMITS.snippetChars) },
727
+ // No key: the server keys it by request id, so a replay after a restart is a no-op.
728
+ requestId: `owner-q-${localId}`.slice(0, 128)
729
+ });
730
+ return item.id;
731
+ })().catch((error) => {
732
+ log(`[ownerBoard] owner question not posted: ${error instanceof Error ? error.message : String(error)}`);
733
+ return null;
734
+ });
735
+ const question = { localId, itemId };
736
+ if (message.delivery === "steer" && turn) turn.questions.push(question);
737
+ else pending.push(question);
738
+ },
739
+ /**
740
+ * The agent takes queued input (Claude remote launcher, right before the
741
+ * prompt goes to the SDK). `sourceIds` = the batch's message localIds when
742
+ * known: only those questions belong to this turn. When none match (an
743
+ * id scheme we do not recognise) every waiting question does.
744
+ */
745
+ onTurnStart(sourceIds) {
746
+ const ids = new Set(sourceIds ?? []);
747
+ const mine = pending.filter((q) => ids.has(q.localId));
748
+ const questions = ids.size && mine.length ? mine : pending;
749
+ pending = pending.filter((q) => !questions.includes(q));
750
+ turn = { promptLocalId: sourceIds?.at(-1) ?? lastLocalId, questions, texts: [], boardTools: /* @__PURE__ */ new Set() };
751
+ },
752
+ onAssistantText(text) {
753
+ if (!turn || !text.trim() || turn.texts.at(-1) === text) return;
754
+ turn.texts.push(text);
755
+ },
756
+ onTurnEnd() {
757
+ const ended = turn;
758
+ turn = null;
759
+ if (!ended) return work;
760
+ const anchor = ended.promptLocalId ? { localId: ended.promptLocalId } : void 0;
761
+ return queue(async () => {
762
+ const reply = ended.texts.join("\n\n").trim();
763
+ if (!reply || !await active()) return;
764
+ if (ended.questions.length) await settleQuestions(ended.questions, ended.texts[0]);
765
+ if (!ended.boardTools.has("owner_board_post") && !ended.boardTools.has("request_human")) {
766
+ await draftDecision(reply, anchor ? { ...anchor, snippet: clip(ended.texts.at(-1) ?? reply, ATTENTION_LIMITS.snippetChars) } : void 0);
767
+ }
768
+ });
769
+ },
770
+ /** Prefix the turn's prompt with the open-items digest (lead sessions only; unchanged on any failure). */
771
+ async decorate(message) {
772
+ if (typeof message !== "string") return message;
773
+ try {
774
+ const result = await Promise.race([
775
+ (async () => {
776
+ if (!await active()) return null;
777
+ const fresh = new Set(turn?.questions.map((q) => q.localId) ?? []);
778
+ const { items } = await deps.client.list({ sessionId: deps.sessionId(), state: "open", limit: 20 }, OWNER_BOARD_DIGEST_TIMEOUT_MS);
779
+ return formatBoardDigest(items.filter((item) => !(item.anchor?.localId && fresh.has(item.anchor.localId) && item.source === "owner")), now(), { tools: toolsFrozen === true });
780
+ })(),
781
+ new Promise((resolve) => setTimeout(() => resolve(null), OWNER_BOARD_DIGEST_TIMEOUT_MS).unref?.())
782
+ ]);
783
+ return result ? `${result}
784
+ ${message}` : message;
785
+ } catch (error) {
786
+ log(`[ownerBoard] digest skipped: ${error instanceof Error ? error.message : String(error)}`);
787
+ return message;
788
+ }
789
+ },
790
+ /** Settles once queued turn-end follow-ups are done (tests, shutdown). */
791
+ idle: () => work
792
+ };
793
+ }
794
+ const boards = /* @__PURE__ */ new WeakMap();
795
+ function attachLeadBoard(client, board) {
796
+ boards.set(client, board);
797
+ }
798
+ function leadBoardFor(client) {
799
+ return boards.get(client);
800
+ }
801
+
802
+ const OWNER_BOARD_TOOL_NAMES = ["owner_board_post", "owner_board_update", "owner_board_resolve", "owner_board_list"];
803
+ const POST_DESCRIPTION = "Post to the owner's briefing board (\u6C47\u62A5\u677F / Briefing), the one place the user checks for what needs them. kind: decision (they must choose; 2-4 options, mark the recommended one), todo (something only they can do offline: log in, authorize, look at a device), report (a milestone: accepted, merged, released, incident conclusion), answer (reply_to = the owner question item id). Use a stable key per topic: posting the same key again updates that item instead of adding one. anchor defaults to this turn's reply. Do not also paste open decisions into chat or member replies.";
804
+ const UPDATE_DESCRIPTION = `Edit one of this session's briefing board items, or set state in_progress ("on it, the result will come to the board") / open. Use it to refresh a reminder instead of repeating it in chat; an owner question can be reclassified only by the board itself.`;
805
+ const RESOLVE_DESCRIPTION = "Close one of this session's briefing board items: done, answered, dropped or superseded (say why in note).";
806
+ const LIST_DESCRIPTION = "List this session's briefing board items with the owner's choice and note. state: open (default) or all; since: ISO-8601 or epoch ms.";
807
+ function errorText(error) {
808
+ if (error instanceof AttentionUnsupportedError) return "The briefing board is not available on this server right now.";
809
+ if (error instanceof AttentionRequestError) return error.message;
810
+ return error instanceof Error ? error.message : "Briefing board request failed";
811
+ }
812
+ function registerOwnerBoardTools(server, board) {
813
+ const register = (name, description, schema, execute, readOnly = false) => {
814
+ server.registerTool(name, {
815
+ description,
816
+ inputSchema: schema.shape,
817
+ annotations: { readOnlyHint: readOnly, idempotentHint: true, openWorldHint: false, destructiveHint: false }
818
+ }, async (args) => {
819
+ const parsed = schema.safeParse(args);
820
+ if (!parsed.success) {
821
+ return { content: [{ type: "text", text: `Invalid input: ${parsed.error.issues.map((i) => `${i.path.join(".") || "input"}: ${i.message}`).join("; ")}` }], isError: true };
822
+ }
823
+ try {
824
+ return { content: [{ type: "text", text: JSON.stringify(await execute(parsed.data)) }], isError: false };
825
+ } catch (error) {
826
+ return { content: [{ type: "text", text: errorText(error) }], isError: true };
827
+ }
828
+ });
829
+ };
830
+ register("owner_board_post", POST_DESCRIPTION, OwnerBoardPostInputSchema, (args) => board.post(args));
831
+ register("owner_board_update", UPDATE_DESCRIPTION, OwnerBoardUpdateInputSchema, (args) => board.update(args));
832
+ register("owner_board_resolve", RESOLVE_DESCRIPTION, OwnerBoardResolveInputSchema, (args) => board.resolve(args));
833
+ register("owner_board_list", LIST_DESCRIPTION, OwnerBoardListInputSchema, (args) => board.list(args), true);
834
+ }
835
+
836
+ const OWNER_BOARD_READY_MS = 3e3;
837
+ function assistantTexts(body) {
838
+ const line = body;
839
+ if (line?.type !== "assistant" || line.isSidechain || !Array.isArray(line.message?.content)) return [];
840
+ return line.message.content.filter((block) => block?.type === "text" && typeof block.text === "string" && block.text.trim()).map((block) => block.text);
841
+ }
328
842
  function createMcpServer(handlers, options, sessionId, client) {
329
843
  const mcp = new McpServer({
330
844
  name: "Very Happy Tools",
@@ -456,6 +970,32 @@ function withoutPhase(board) {
456
970
  async function startHappyServer(client, options) {
457
971
  logger.debug(`[happyMCP] server:start sessionId=${client.sessionId} assistant=${!!options?.assistant}`);
458
972
  const selfReportState = options?.selfReportState ?? createSelfReportState();
973
+ const leadBoard = createLeadBoard({
974
+ sessionId: () => client.sessionId,
975
+ client: sharedAttentionClient(),
976
+ isLead: () => resolveTeamLead(client.sessionId),
977
+ autoDetect: async () => (await readSettings()).ownerBoardAutoDetect !== false,
978
+ onSupported: () => client.updateMetadata((metadata) => ({ ...metadata, capabilities: [.../* @__PURE__ */ new Set([...metadata.capabilities ?? [], ATTENTION_SESSION_CAPABILITY])] })),
979
+ log: (message) => logger.debug(message)
980
+ });
981
+ attachLeadBoard(client, leadBoard);
982
+ void leadBoard.init();
983
+ const onRoutedUserMessage = (event) => {
984
+ const text = event.message?.content?.text;
985
+ leadBoard.onUserMessage({ localId: event.localId, text: typeof text === "string" ? text : null, sentFrom: event.message?.meta?.sentFrom, delivery: event.message?.meta?.delivery });
986
+ };
987
+ const onClaudeLine = (body) => {
988
+ for (const text of assistantTexts(body)) leadBoard.onAssistantText(text);
989
+ };
990
+ const onTurnEnded = () => {
991
+ void leadBoard.onTurnEnd();
992
+ };
993
+ const tapped = typeof client.on === "function";
994
+ if (tapped) {
995
+ client.on("user-message-routed", onRoutedUserMessage);
996
+ client.on("claude-session-message", onClaudeLine);
997
+ client.on("turn-ended", onTurnEnded);
998
+ }
459
999
  const handlers = {
460
1000
  openPreview: async (path, mode, download = false) => {
461
1001
  const verdict = checkPreviewPath(path);
@@ -536,7 +1076,8 @@ async function startHappyServer(client, options) {
536
1076
  readPanels: async () => (await readSettings()).webPanels,
537
1077
  // Same board write (and attention-change throttle bypass) as report_progress.
538
1078
  reportBlocked: (reason) => handlers.reportProgress(reason, "blocked"),
539
- sendAttention: (input) => options?.push ? options.push.sendAttention({ ...input, sessionTitle: getSessionNotificationBody(client.getMetadata()) }) : Promise.resolve({ sent: false, error: "push is not available in this runner" })
1079
+ sendAttention: (input) => options?.push ? options.push.sendAttention({ ...input, sessionTitle: getSessionNotificationBody(client.getMetadata()) }) : Promise.resolve({ sent: false, error: "push is not available in this runner" }),
1080
+ postBlocked: (reason, panel) => leadBoard.postBlocked(reason, panel)
540
1081
  })
541
1082
  };
542
1083
  const contextPath = "/runtime-context/" + randomUUID();
@@ -610,7 +1151,9 @@ async function startHappyServer(client, options) {
610
1151
  }
611
1152
  return;
612
1153
  }
1154
+ await leadBoard.ready(OWNER_BOARD_READY_MS);
613
1155
  const mcp = createMcpServer(handlers, options, client.sessionId, client);
1156
+ if (leadBoard.toolsExposed()) registerOwnerBoardTools(mcp, leadBoard);
614
1157
  try {
615
1158
  const transport = new StreamableHTTPServerTransport({
616
1159
  sessionIdGenerator: void 0
@@ -655,11 +1198,19 @@ async function startHappyServer(client, options) {
655
1198
  ...AUTOMATION_TOOL_NAMES,
656
1199
  ...SESSION_PEER_TOOL_NAMES,
657
1200
  ...PROJECT_TOOL_NAMES,
1201
+ // Auto-allow only; the tools themselves appear for a lead on a board server.
1202
+ ...OWNER_BOARD_TOOL_NAMES,
658
1203
  ...options?.assistant && !process.env.VH_TEAM_SCOPE_FILE ? ASSISTANT_TOOL_NAMES : []
659
1204
  ],
1205
+ leadBoard,
660
1206
  stop: () => {
661
1207
  logger.debug(`[happyMCP] server:stop sessionId=${client.sessionId}`);
662
1208
  if (adoptionEnabled) client.rpcHandlerManager.unregisterHandler("teams-adopt");
1209
+ if (tapped) {
1210
+ client.off("user-message-routed", onRoutedUserMessage);
1211
+ client.off("claude-session-message", onClaudeLine);
1212
+ client.off("turn-ended", onTurnEnded);
1213
+ }
663
1214
  server.close();
664
1215
  }
665
1216
  };
@@ -748,7 +1299,7 @@ function deterministicStringify(obj, options = {}) {
748
1299
  }
749
1300
  function hashObject(obj, options, encoding = "hex") {
750
1301
  const jsonString = deterministicStringify(obj, options);
751
- return createHash("sha256").update(jsonString).digest(encoding);
1302
+ return createHash$1("sha256").update(jsonString).digest(encoding);
752
1303
  }
753
1304
 
754
- export { resolvePiContextUsage as a, createProjectInjector as c, hashObject as h, readPiModelsJson as r, startHappyServer as s };
1305
+ export { resolvePiContextUsage as a, createProjectInjector as c, hashObject as h, leadBoardFor as l, readPiModelsJson as r, startHappyServer as s };