chainlesschain 0.162.174 → 0.162.176

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 (281) hide show
  1. package/package.json +10 -10
  2. package/src/assets/web-panel/assets/{AIOps-Dcl-X1Hw.js → AIOps-BDLu5Elz.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-ClMh9HzT.js → ActionButton-DH5us-CK.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-DPj0rSQ5.js → Analytics-BZ0u8IFG.js} +3 -3
  5. package/src/assets/web-panel/assets/AppLayout-Duu8xR14.js +9 -0
  6. package/src/assets/web-panel/assets/{Artifacts-L8781rE8.js → Artifacts-Br2YBbh_.js} +1 -1
  7. package/src/assets/web-panel/assets/{Audit-CffB6WIP.js → Audit-C3C6a482.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-BkLhayyY.js → BackgroundAgents-CzHvebcj.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-BQnwFI78.js → Backup-DZNHYDFd.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-xuUGHQch.js → BaseInput-VRiC4fIx.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-feQXwWrg.js → Chat-Cm08WWAD.js} +5 -5
  12. package/src/assets/web-panel/assets/ChatBubbleRenderer-CGHYrugQ.js +1 -0
  13. package/src/assets/web-panel/assets/{Checkbox-DVaIiUGW.js → Checkbox-DtByk7d7.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-D2kEnzeU.js → Codegen-CphXXOfD.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-azDoyusS.js → Col-Hz86TnLR.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-OZdnPWM5.js → Community-HP03ltpD.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-VDMvBN-C.js → Compact-B_N1mqQz.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-CPJ_zgQ1.js → Compliance-CVztRpi8.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-iRBwcsOA.js → Cowork-wUVOyZih.js} +4 -4
  20. package/src/assets/web-panel/assets/{Cron-DrxrspUz.js → Cron-DW5TLJKw.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-D-rkAZXF.js → Crosschain-CrAFGhWH.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-5Pp1Xnmr.js → DID-pA-oD8ke.js} +2 -2
  23. package/src/assets/web-panel/assets/Dashboard-CXrd5gAw.js +3 -0
  24. package/src/assets/web-panel/assets/{Dropdown-BWj_E0Ie.js → Dropdown-EweJcsek.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-BT-wgSEh.js → EmailListRenderer-C9xVLPG4.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-1PzH23pa.js → FamilyGuardDashboard-CDcEEqlu.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-BxMIXGC6.js → Federation-DtZda9A_.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-CyJobBln.js → FormItemContext-CiYdcVz3.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-YkjFuQTN.js → GenericCardRenderer-DA13uwA0.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-C2a98Wp_.js → Git-DzRhZD1O.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-DKL3Fl84.js → Governance-D5RMgOSb.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-BJ2cQC_3.js → Inference-BgrPfSNk.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-DBAsOngt.js → KnowledgeGraph-DzjnD571.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-COt8g9LO.js → Logs-BhWzVDtN.js} +2 -2
  35. package/src/assets/web-panel/assets/{MarkdownRenderer-3Lfht1Fd.js → MarkdownRenderer-BDape9cx.js} +1 -1
  36. package/src/assets/web-panel/assets/{Marketplace-C9Zk9Pb2.js → Marketplace-DJtL5GV7.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-DDWDFWPO.js → McpTools-CZcQygI7.js} +5 -5
  38. package/src/assets/web-panel/assets/{Memory-BRmVye_o.js → Memory-DUWSDUUu.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-CppBbWpD.js → MobileBridge-BTwq2WKY.js} +1 -1
  40. package/src/assets/web-panel/assets/MobileProjects-NZvvfDME.js +1 -0
  41. package/src/assets/web-panel/assets/{Mtc-CcWpeGa6.js → Mtc-BiGugEQm.js} +6 -6
  42. package/src/assets/web-panel/assets/{MtcAudit-BcllEq0K.js → MtcAudit-DY7a6gUe.js} +4 -4
  43. package/src/assets/web-panel/assets/{Multisig-BFD1CarL.js → Multisig-BQbDu_w7.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-QNXXYvjz.js → NLProgramming-CM2wXTLv.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-07YwgQVy.js → Notes-DI6gGs1v.js} +4 -4
  46. package/src/assets/web-panel/assets/{NotificationSettings-bOccEInE.js → NotificationSettings-BsZOLWAB.js} +1 -1
  47. package/src/assets/web-panel/assets/{OrderTableRenderer-DlRi29WL.js → OrderTableRenderer-C48mu09U.js} +1 -1
  48. package/src/assets/web-panel/assets/{Organization-CBaezzEr.js → Organization-Cds0_tXr.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-Bl5NohFO.js → Overflow-WunYMD87.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-CLMal9Aw.js → P2P-Bo6j4DDv.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-CGO0NITk.js → PdhVaultBrowser-Bh2XPD5f.js} +3 -3
  52. package/src/assets/web-panel/assets/{Permissions-CPSw48E2.js → Permissions-EMvMMC8N.js} +3 -3
  53. package/src/assets/web-panel/assets/{PersonalDataHub-CDM5n134.js → PersonalDataHub-AX3ypUDV.js} +2 -2
  54. package/src/assets/web-panel/assets/{Pipeline-BdsqG7WV.js → Pipeline-BOx8HOgL.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-B6L4E-M7.js → Privacy-tBeTVQVM.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-DXPyZKRs.js → ProjectInit-CVYg1W4M.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-BrCC3xYT.js → ProjectSettings-Dvt5I7y1.js} +2 -2
  58. package/src/assets/web-panel/assets/{Projects-BYmuHC2q.js → Projects-Cc7FC9-e.js} +1 -1
  59. package/src/assets/web-panel/assets/{Providers-CbCe2eUl.js → Providers-Ct8xqY-E.js} +1 -1
  60. package/src/assets/web-panel/assets/{QrScannerModal-DkukgCrR.js → QrScannerModal-Cni8Ooja.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-D-htOrV8.js → QuickAsk-BJVLKdxr.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-Bm7SIfzu.js → Recommend-DPG8Rbbm.js} +1 -1
  63. package/src/assets/web-panel/assets/{RemoteSession-C9rP-iMc.js → RemoteSession-DsdR7dCt.js} +2 -2
  64. package/src/assets/web-panel/assets/{Reputation-kGlUgbsl.js → Reputation-Csg1YM-b.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-PBupbbUA.js → Row-D9DoFoEf.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-njlwKUGK.js → RssFeed-BsvKrXMS.js} +2 -2
  67. package/src/assets/web-panel/assets/{Search-DLdEmgBw.js → Search-DFUStfgQ.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-SXGPSHdu.js → Security-ILg1zxdK.js} +4 -4
  69. package/src/assets/web-panel/assets/{Services-CuFGnNsb.js → Services-Dd41PCaY.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-CtUC0mDa.js → Skeleton-Bzo1cN80.js} +1 -1
  71. package/src/assets/web-panel/assets/{Skills-P1qgOVFn.js → Skills-BDHh17P0.js} +1 -1
  72. package/src/assets/web-panel/assets/{Sla-CsppE8YV.js → Sla-jl7UTiRY.js} +1 -1
  73. package/src/assets/web-panel/assets/{SpeechSettings-Cq1oG56m.js → SpeechSettings-BePa-RF6.js} +1 -1
  74. package/src/assets/web-panel/assets/{SyncSettings-DdKW6V-C.js → SyncSettings-DiqqDKGZ.js} +2 -2
  75. package/src/assets/web-panel/assets/{Tasks-BCc9san5.js → Tasks-DYQ_6lxj.js} +1 -1
  76. package/src/assets/web-panel/assets/{Templates-CcHC1dMA.js → Templates-JiDeI06L.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-CA4PqU22.js → Tenant-hhgI6zwS.js} +1 -1
  78. package/src/assets/web-panel/assets/Terminal-CjTZPa37.js +3 -0
  79. package/src/assets/web-panel/assets/{TimelineRenderer-DHWTSvOy.js → TimelineRenderer-B8uB5Llk.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tokens-Ddz-P_yh.js → Tokens-C3b_6r2z.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger-ePmrmLZ1.js → Trigger-tIP7HKVe.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-DmuK1CCE.js → Trust-vjoc11vJ.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-CqqBuRrT.js → UkeySign-DUPBnGuH.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-BGlR3uWM.js → VideoEditing-CBvhUY5T.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-Ba_Qx6Ga.js → Wallet-DUaQ0uA5.js} +4 -4
  86. package/src/assets/web-panel/assets/{WebAuthn-29neXKt2.js → WebAuthn-DllSivjE.js} +5 -5
  87. package/src/assets/web-panel/assets/{WorkflowEditor-lD0lR0UQ.js → WorkflowEditor-xc8D3uO6.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-B3stH01u.js → chat-BVicU7oA.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-Czly56MN.js → colors-DJzLmhLm.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-C0TkbkAJ.js → compact-item-BvYRfThE.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-BJmpSlf1.js → createContext-DGXxCBKR.js} +1 -1
  92. package/src/assets/web-panel/assets/devWarning-BT46Y_QI.js +1 -0
  93. package/src/assets/web-panel/assets/{hasIn-D1q-zw7u.js → hasIn-SBDJB1y4.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-DV-twjNO.js → index-1SdDS6lR.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-B-kTvMq7.js → index-9gdI7uUW.js} +1 -1
  96. package/src/assets/web-panel/assets/index-B7nuIywP.js +1 -0
  97. package/src/assets/web-panel/assets/{index-Bm_-RKal.js → index-BJZf9DhV.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CQftlZn-.js → index-BO1itZaY.js} +3 -3
  99. package/src/assets/web-panel/assets/{index-Dw3L_smW.js → index-BTrBGBJs.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-C7sFKQ53.js → index-BYqz4Wrr.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-DlvsSuBC.js → index-Bf-ctERC.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-ChESIe5r.js → index-CKyEivf8.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DaqEHaCg.js → index-CdGY9P8a.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-DZeoKL6t.js → index-Cf-O_g_8.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-XWV8JWMc.js → index-CloCgBUR.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-CpMIdPJ0.js → index-CoJAO1Lm.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-CgS8XUBU.js → index-Crk5NTb0.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-DmUta2lw.js → index-Cs2rmLFt.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Dpz_7sf-.js → index-CtwqO5qo.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-DRcQsPez.js → index-D7HimK0M.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-BEt2-3x5.js → index-DCdRAgjy.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-CHvPlzWJ.js → index-DCqRS6da.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-BDHXx65P.js → index-DHVLJ8q0.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-K4YaPDOn.js → index-DKrvvWm4.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-C1pOqU7D.js → index-DMarmfrv.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-DAhrn9EJ.js → index-DRfiXB_p.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-cPjWjvmW.js → index-Dm_77jgR.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-C27TnOoT.js → index-DnjPdvR6.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-upY9rkGZ.js → index-DonCnfMr.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-CbvNJUwu.js → index-DvUTDYXX.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-BVwJ3jht.js → index-FxZzRyE1.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-DIF6XHIi.js → index-MjC4G09d.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-B8KqsomG.js → index-VMfwIH5G.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-8GKykbS4.js → index-YJkzy8ZF.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DpGs96FC.js → index-d5BVd-cL.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-DO8xOwxi.js → index-e4fXH_WO.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-Cu_4HaUS.js → index-hxTODbM1.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-Cf7Gr3NG.js → index-lpaGoTH3.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-DBqAm8es.js → index-wcCL-miV.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-ZDUhX41Z.js → index-xfluRkCT.js} +1 -1
  131. package/src/assets/web-panel/assets/index-ycwAfC-i.js +1 -0
  132. package/src/assets/web-panel/assets/{index-z8ATo2aQ.js → index-z1ZylsLq.js} +1 -1
  133. package/src/assets/web-panel/assets/{initDefaultProps-QWEXi6-t.js → initDefaultProps-C1zO1KnY.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-BfrQwvV1.js → motion-CWLtEGmC.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-Dn7x0H9t.js → move-DzD_C3Vm.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-F61D_TgE.js → mtc-parser-D880PYJl.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-4SQZ39PF.js → omit-CFR_z2ov.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-C7DTe126.js → pickAttrs-srIhgrSC.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-40NeyzDK.js → placementArrow-C1rXpibP.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-BiUJ6qWs.js → responsiveObserve-C30gRcSS.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-CacJTM3f.js → slide-CvtKiMfV.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-K812HB-k.js → statusUtils-DNHO7ITG.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-CKeHA2eM.js → styleChecker-Dt_Sl-g4.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-CKl4FqXF.js → useFlexGapSupport-Cjev42Gh.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-DPoiJjSZ.js → useFs-Baxglj2V.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-aHwBspmt.js → usePersonalDataHub-B4NkcLaP.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-DrA-GuCT.js → vnode-mIRkdT7o.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-G3LMswgy.js → zoom-HzI5DlH_.js} +1 -1
  149. package/src/assets/web-panel/index.html +1 -1
  150. package/src/auth/npm-auth.js +30 -5
  151. package/src/commands/agenda.js +64 -2
  152. package/src/commands/agent.js +45 -3
  153. package/src/commands/background-session.js +103 -0
  154. package/src/commands/config.js +70 -5
  155. package/src/commands/context.js +36 -2
  156. package/src/commands/hub.js +19 -1
  157. package/src/commands/memory.js +21 -6
  158. package/src/commands/permissions.js +57 -1
  159. package/src/commands/plugin.js +2 -0
  160. package/src/commands/review.js +23 -11
  161. package/src/commands/routine.js +31 -8
  162. package/src/commands/session.js +11 -3
  163. package/src/commands/team.js +20 -7
  164. package/src/commands/update.js +65 -10
  165. package/src/esm-bridge.js +3 -0
  166. package/src/gateways/terminal/PtyManager.js +8 -1
  167. package/src/gateways/ws/message-dispatcher.js +3 -0
  168. package/src/gateways/ws/session-protocol.js +26 -0
  169. package/src/gateways/ws/ws-agent-handler.js +107 -69
  170. package/src/gateways/ws/ws-server.js +92 -4
  171. package/src/harness/jsonl-session-store.js +13 -6
  172. package/src/harness/mcp-client.js +200 -1
  173. package/src/index.js +123 -55
  174. package/src/lazy-dispatch.js +86 -85
  175. package/src/lib/__tests__/personal-data-hub-aichat-wizard.test.js +15 -0
  176. package/src/lib/agent-coordinator.js +4 -0
  177. package/src/lib/agent-ipc-bus.js +32 -2
  178. package/src/lib/agent-sandbox.js +16 -2
  179. package/src/lib/agent-schedule-store.js +55 -0
  180. package/src/lib/agent-tool-admission.js +104 -0
  181. package/src/lib/api-key-helper.js +10 -2
  182. package/src/lib/async-hook-supervisor.cjs +26 -4
  183. package/src/lib/background-interaction-resolver.js +71 -0
  184. package/src/lib/background-session-transport.js +59 -1
  185. package/src/lib/changelog.js +19 -11
  186. package/src/lib/channels/channel-manager.js +6 -0
  187. package/src/lib/channels/telegram-channel.js +11 -1
  188. package/src/lib/channels/webhook-channel.js +15 -3
  189. package/src/lib/checkpoint-store.js +10 -2
  190. package/src/lib/cloud/bundle.js +12 -2
  191. package/src/lib/code-review.js +32 -8
  192. package/src/lib/computer-use/control-backend.js +18 -3
  193. package/src/lib/context-breakdown.js +46 -0
  194. package/src/lib/context-source-ledger.js +43 -0
  195. package/src/lib/crash-reporter.js +6 -0
  196. package/src/lib/diff-review-follow-up.js +154 -0
  197. package/src/lib/downloader.js +17 -3
  198. package/src/lib/ensure-utf8.js +11 -3
  199. package/src/lib/event-runtime-producer.js +58 -0
  200. package/src/lib/event-runtime-store.js +354 -0
  201. package/src/lib/event-runtime-worker.js +109 -0
  202. package/src/lib/execution-backend.js +72 -21
  203. package/src/lib/git-integration.js +19 -4
  204. package/src/lib/hook-manager.js +34 -15
  205. package/src/lib/hook-runner.cjs +48 -3
  206. package/src/lib/hooks-v2-producers.js +15 -0
  207. package/src/lib/hooks-v2-runtime.js +70 -21
  208. package/src/lib/host-adb-bridge.js +111 -21
  209. package/src/lib/ide-context.js +128 -1
  210. package/src/lib/interaction-adapter.js +39 -0
  211. package/src/lib/ipc-attach-protocol.js +98 -0
  212. package/src/lib/json-schema-validate.js +190 -36
  213. package/src/lib/lan-pairing-preflight.js +13 -2
  214. package/src/lib/lsp/__tests__/lsp-server-registry.test.js +18 -0
  215. package/src/lib/lsp/lsp-client.js +18 -1
  216. package/src/lib/lsp/lsp-manager.js +4 -0
  217. package/src/lib/lsp/lsp-server-registry.js +11 -0
  218. package/src/lib/mcp-oauth.js +8 -2
  219. package/src/lib/npm-invocation.js +29 -0
  220. package/src/lib/packer/pkg-runner.js +13 -2
  221. package/src/lib/packer/precheck.js +33 -16
  222. package/src/lib/packer/web-panel-builder.js +16 -2
  223. package/src/lib/permission-rules.cjs +5 -1
  224. package/src/lib/personal-data-hub-aichat-wizard.js +22 -6
  225. package/src/lib/personal-data-hub-wiring.js +27 -3
  226. package/src/lib/plan-mode.js +204 -11
  227. package/src/lib/plugin-monitor-supervisor.js +39 -4
  228. package/src/lib/plugin-runtime/bin.js +45 -0
  229. package/src/lib/plugin-runtime/hooks.js +14 -1
  230. package/src/lib/plugin-runtime/install.js +2 -1
  231. package/src/lib/plugin-runtime/lsp.js +3 -0
  232. package/src/lib/plugin-runtime/mcp.js +8 -1
  233. package/src/lib/plugin-runtime/monitors.js +4 -0
  234. package/src/lib/plugin-runtime/plugin-options.js +74 -7
  235. package/src/lib/plugin-runtime/signature.js +45 -0
  236. package/src/lib/pr-create.js +21 -8
  237. package/src/lib/pr-link-ledger.js +15 -3
  238. package/src/lib/process-execution-broker/credential-agent.js +295 -0
  239. package/src/lib/process-execution-broker/index.js +440 -14
  240. package/src/lib/process-execution-broker/patch-child-process.js +2 -3
  241. package/src/lib/process-execution-broker/platform-sandbox.js +351 -0
  242. package/src/lib/process-manager.js +18 -3
  243. package/src/lib/provenance-api.js +6 -0
  244. package/src/lib/proxy-bootstrap.js +19 -0
  245. package/src/lib/publish-workspace.js +14 -6
  246. package/src/lib/repl-rewind.js +9 -4
  247. package/src/lib/secret-store.js +159 -0
  248. package/src/lib/service-manager.js +64 -29
  249. package/src/lib/session-hooks.js +328 -473
  250. package/src/lib/session-telemetry-middleware.js +6 -0
  251. package/src/lib/settings-hook-events.cjs +61 -1
  252. package/src/lib/settings-hooks.cjs +4 -0
  253. package/src/lib/side-effect-ledger.js +22 -0
  254. package/src/lib/sub-agent-context.js +5 -0
  255. package/src/lib/sub-agent-profiles.js +4 -0
  256. package/src/lib/trace-api.js +6 -0
  257. package/src/lib/turn-context.js +14 -8
  258. package/src/lib/unattended-action-policy.js +83 -0
  259. package/src/lib/update-notice.js +9 -45
  260. package/src/lib/with-file-lock.js +7 -0
  261. package/src/lib/ws-server.js +1 -0
  262. package/src/repl/agent-repl.js +71 -13
  263. package/src/repl/clipboard-copy.js +8 -2
  264. package/src/repl/pr-comments.js +30 -7
  265. package/src/runtime/agent-core.js +439 -87
  266. package/src/runtime/agent-runtime.js +1 -0
  267. package/src/runtime/coding-agent-contract-shared.cjs +52 -0
  268. package/src/runtime/coding-agent-policy.cjs +20 -0
  269. package/src/runtime/diagnostics.js +73 -8
  270. package/src/runtime/headless-runner.js +63 -0
  271. package/src/runtime/headless-stream.js +269 -17
  272. package/src/runtime/mcp-config.js +16 -1
  273. package/src/workers/background-agent-worker.js +80 -1
  274. package/src/assets/web-panel/assets/AppLayout-7iSKDmlI.js +0 -9
  275. package/src/assets/web-panel/assets/ChatBubbleRenderer-DcbUHeGW.js +0 -1
  276. package/src/assets/web-panel/assets/Dashboard-BAKYNavw.js +0 -3
  277. package/src/assets/web-panel/assets/MobileProjects-C4GKn1dH.js +0 -1
  278. package/src/assets/web-panel/assets/Terminal-Fj7ea0In.js +0 -3
  279. package/src/assets/web-panel/assets/devWarning-CDI8Sbaj.js +0 -1
  280. package/src/assets/web-panel/assets/index-96LBR96V.js +0 -1
  281. package/src/assets/web-panel/assets/index-DyQkiW24.js +0 -1
@@ -1,236 +1,219 @@
1
1
  /**
2
- * Session-level hook firing helpers — the "三件套 +1" that complements
3
- * the tool-level PreToolUse/PostToolUse hooks already wired in
4
- * `runtime/agent-core.js`.
2
+ * Session hooks - 会话级钩子触发工具
5
3
  *
6
- * Four session-level events are fired from `repl/agent-repl.js`:
7
- *
8
- * - SessionStart — once, after sessionId is established
9
- * - UserPromptSubmit — per user line, before agentLoop()
10
- * - AssistantResponse — per agent reply, after agentLoop() returns
11
- * - SessionEnd — once, on rl.close() before shutdown
12
- *
13
- * Semantics (matches existing PreToolUse convention):
14
- * - Fire-and-forget by default: hook failures NEVER break the host flow
15
- * - `fireUserPromptSubmit` / `fireAssistantResponse` are opt-in helpers
16
- * that parse stdout JSON directives ({rewrittenPrompt,abort} /
17
- * {rewrittenResponse,suppress}) for callers that want control flow
18
- * - No-op when hookDb is null (REPL without DB)
19
- * - Helper-side timeout protects against runaway hooks even if
20
- * hook-manager's per-hook timeout is misconfigured
21
- * - Swallowed errors are persisted to hook_execution_log when possible
4
+ * 用于 agent-repl 的三件套会话级钩子:
5
+ * - SessionStart
6
+ * - UserPromptSubmit
7
+ * - AssistantResponse
8
+ * - SessionEnd
9
+ * - Notification
22
10
  */
23
11
 
24
- import { executeHooks, HookEvents } from "./hook-manager.js";
12
+ import { HookEvents, executeHooks } from "./hook-manager.js";
25
13
 
26
- /**
27
- * Events this helper is allowed to fire. Guards against typos that
28
- * would otherwise silently no-op inside executeHooks' event filter.
29
- */
14
+ // 会话钩子白名单
30
15
  export const SESSION_HOOK_EVENTS = Object.freeze([
31
16
  HookEvents.SessionStart,
32
17
  HookEvents.UserPromptSubmit,
33
18
  HookEvents.AssistantResponse,
34
19
  HookEvents.SessionEnd,
20
+ HookEvents.Notification,
35
21
  ]);
36
22
 
37
- /**
38
- * Helper-side wall-clock cap. Per-hook timeout still lives in the
39
- * registered hook row; this is a belt-and-suspenders bound so a
40
- * misconfigured hook can never wedge the REPL.
41
- */
42
- const HELPER_TIMEOUT_MS = Number(
43
- process.env.CC_SESSION_HOOK_TIMEOUT_MS || 15000,
44
- );
45
-
46
- /**
47
- * Internal deps — exposed for tests via `_deps` injection.
48
- * Keeping this mutable lets vitest swap out timer/log writers without
49
- * resorting to vi.mock (which doesn't intercept inlined CJS).
50
- */
23
+ // 依赖注入点(用于测试)
51
24
  export const _deps = {
52
25
  executeHooks,
53
- now: () => Date.now(),
54
- logFailure: (hookDb, eventName, err) => {
55
- // Best-effort persistence to hook_execution_log; never throws.
56
- if (!hookDb || typeof hookDb.prepare !== "function") return;
57
- try {
58
- const stmt = hookDb.prepare(
59
- `INSERT INTO hook_execution_log
60
- (hook_id, event, success, error, executed_at)
61
- VALUES (?, ?, ?, ?, ?)`,
62
- );
63
- stmt.run(
64
- null,
65
- eventName,
66
- 0,
67
- String(err && err.message ? err.message : err),
68
- new Date().toISOString(),
69
- );
70
- } catch {
71
- /* table may not exist yet — silent */
72
- }
26
+ logFailure: (_db, event, error) => {
27
+ console.error(`[session-hooks] Failed to fire ${event}:`, error);
73
28
  },
74
29
  };
75
30
 
76
31
  /**
77
- * Fire a session-level hook. Returns the raw results from executeHooks
78
- * (array of {hookId, hookName, success, ...}) or an empty array if
79
- * hookDb is missing, event is not allowed, or execution throws.
80
- *
81
- * @param {object|null} hookDb better-sqlite3 handle, or null to no-op
82
- * @param {string} eventName one of SESSION_HOOK_EVENTS
83
- * @param {object} [context] forwarded to hook matcher + handler env
84
- * @returns {Promise<Array>}
32
+ * 通用会话钩子触发函数
33
+ * @param {object} db - 数据库实例
34
+ * @param {string} event - 钩子事件名
35
+ * @param {object} [context={}] - 钩子上下文
36
+ * @returns {Promise<Array>} 钩子执行结果数组
85
37
  */
86
- export async function fireSessionHook(hookDb, eventName, context = {}) {
87
- if (!hookDb) return [];
88
- if (!SESSION_HOOK_EVENTS.includes(eventName)) {
89
- throw new Error(
90
- `fireSessionHook: event "${eventName}" is not a session hook. ` +
91
- `Use one of: ${SESSION_HOOK_EVENTS.join(", ")}`,
92
- );
38
+ export async function fireSessionHook(db, event, context = {}) {
39
+ // 白名单验证
40
+ if (!SESSION_HOOK_EVENTS.includes(event)) {
41
+ throw new Error(`"${event}" is not a session hook event`);
42
+ }
43
+
44
+ // 如果没有数据库,空操作
45
+ if (!db) {
46
+ return [];
93
47
  }
94
48
 
95
49
  try {
96
- const enriched = {
50
+ // 注入时间戳
51
+ const ctxWithTimestamp = {
97
52
  timestamp: new Date().toISOString(),
98
53
  ...context,
99
54
  };
100
- return await withTimeout(
101
- _deps.executeHooks(hookDb, eventName, enriched),
102
- HELPER_TIMEOUT_MS,
103
- `${eventName} session hook`,
104
- );
105
- } catch (err) {
106
- // Hook failures must never break the REPL — but we record them
107
- _deps.logFailure(hookDb, eventName, err);
55
+
56
+ // 执行钩子
57
+ const results = await _deps.executeHooks(db, event, ctxWithTimestamp);
58
+ return Array.isArray(results) ? results : [];
59
+ } catch (error) {
60
+ _deps.logFailure(db, event, error);
108
61
  return [];
109
62
  }
110
63
  }
111
64
 
112
65
  /**
113
- * Fire UserPromptSubmit with rewrite/abort support.
114
- *
115
- * A hook may control the prompt by emitting a single JSON line to stdout:
116
- * {"rewrittenPrompt": "..."} — replace the user prompt
117
- * {"abort": true, "reason": "..."} — skip agentLoop entirely
118
- *
119
- * First matching directive wins (priority order from executeHooks).
120
- * Malformed JSON / no directive → no change (pure observation).
121
- *
66
+ * 触发用户提交提示词钩子
67
+ * @param {object} db - 数据库实例
68
+ * @param {string} prompt - 用户提示词
69
+ * @param {object} [context={}] - 上下文
122
70
  * @returns {Promise<{prompt: string, abort: boolean, reason?: string, results: Array}>}
123
71
  */
124
- export async function fireUserPromptSubmit(
125
- hookDb,
126
- originalPrompt,
127
- context = {},
128
- ) {
129
- const results = await fireSessionHook(hookDb, HookEvents.UserPromptSubmit, {
72
+ export async function fireUserPromptSubmit(db, prompt, context = {}) {
73
+ const results = await fireSessionHook(db, HookEvents.UserPromptSubmit, {
74
+ prompt,
130
75
  ...context,
131
- prompt: originalPrompt,
132
76
  });
133
77
 
134
- let prompt = originalPrompt;
78
+ let rewrittenPrompt = prompt;
135
79
  let abort = false;
136
- let reason;
80
+ let abortReason;
137
81
 
138
- for (const r of results) {
139
- if (!r || !r.success) continue;
140
- const directive = extractDirective(r);
141
- if (!directive) continue;
142
- if (directive.abort) {
143
- abort = true;
144
- reason = directive.reason;
145
- break;
146
- }
147
- if (
148
- typeof directive.rewrittenPrompt === "string" &&
149
- directive.rewrittenPrompt.trim()
150
- ) {
151
- prompt = directive.rewrittenPrompt;
152
- break;
82
+ // 处理钩子返回的指令
83
+ for (const result of results) {
84
+ if (!result.success) continue;
85
+ try {
86
+ const output = result.stdout ? JSON.parse(result.stdout) : {};
87
+ if (output.rewrittenPrompt) {
88
+ rewrittenPrompt = output.rewrittenPrompt;
89
+ }
90
+ if (output.abort) {
91
+ abort = true;
92
+ abortReason = output.reason || "aborted by hook";
93
+ }
94
+ } catch {
95
+ // 忽略解析错误
153
96
  }
154
97
  }
155
98
 
156
- return { prompt, abort, reason, results };
99
+ return {
100
+ prompt: rewrittenPrompt,
101
+ abort,
102
+ reason: abortReason,
103
+ results,
104
+ };
157
105
  }
158
106
 
159
107
  /**
160
- * Fire AssistantResponse with rewrite/suppress support.
161
- *
162
- * Symmetric to fireUserPromptSubmit but on the way out. A hook may emit:
163
- * {"rewrittenResponse": "..."} — replace the response shown to the user
164
- * {"suppress": true, "reason": "..."} — drop the response entirely
165
- *
166
- * Common use: PII / secret scrubbing, watermark injection, profanity
167
- * filter on the model's final string before it reaches the terminal.
168
- *
108
+ * 触发助手响应钩子(已存在,重写增强)
109
+ * @param {object} db - 数据库实例
110
+ * @param {string} response - 助手响应
111
+ * @param {object} [context={}] - 上下文
169
112
  * @returns {Promise<{response: string, suppress: boolean, reason?: string, results: Array}>}
170
113
  */
171
- export async function fireAssistantResponse(
172
- hookDb,
173
- originalResponse,
174
- context = {},
175
- ) {
176
- const results = await fireSessionHook(hookDb, HookEvents.AssistantResponse, {
114
+ export async function fireAssistantResponse(db, response, context = {}) {
115
+ const results = await fireSessionHook(db, HookEvents.AssistantResponse, {
116
+ response,
177
117
  ...context,
178
- response: originalResponse,
179
118
  });
180
119
 
181
- let response = originalResponse;
120
+ let rewrittenResponse = response;
182
121
  let suppress = false;
183
- let reason;
122
+ let suppressReason;
184
123
 
185
- for (const r of results) {
186
- if (!r || !r.success) continue;
187
- const directive = extractDirective(r);
188
- if (!directive) continue;
189
- if (directive.suppress) {
190
- suppress = true;
191
- reason = directive.reason;
192
- break;
193
- }
194
- if (
195
- typeof directive.rewrittenResponse === "string" &&
196
- directive.rewrittenResponse.length > 0
197
- ) {
198
- response = directive.rewrittenResponse;
199
- break;
124
+ for (const result of results) {
125
+ if (!result.success) continue;
126
+ try {
127
+ const output = result.stdout ? JSON.parse(result.stdout) : {};
128
+ if (output.rewrittenResponse) {
129
+ rewrittenResponse = output.rewrittenResponse;
130
+ }
131
+ if (output.suppress) {
132
+ suppress = true;
133
+ suppressReason = output.reason || "suppressed by hook";
134
+ }
135
+ } catch {
136
+ // 忽略解析错误
200
137
  }
201
138
  }
202
139
 
203
- return { response, suppress, reason, results };
140
+ return {
141
+ response: rewrittenResponse,
142
+ suppress,
143
+ reason: suppressReason,
144
+ results,
145
+ };
204
146
  }
205
147
 
206
- function extractDirective(result) {
207
- const raw = result.stdout ?? result.output ?? result.result;
208
- if (raw == null) return null;
209
- if (typeof raw === "object") return raw;
210
- if (typeof raw !== "string") return null;
211
- const trimmed = raw.trim();
212
- if (!trimmed.startsWith("{")) return null;
213
- try {
214
- return JSON.parse(trimmed);
215
- } catch {
216
- return null;
217
- }
148
+ /**
149
+ * 触发会话开始钩子
150
+ * @param {object} db - 数据库实例
151
+ * @param {object} [context={}] - 上下文
152
+ * @returns {Promise<Array>}
153
+ */
154
+ export async function fireSessionStart(db, context = {}) {
155
+ return fireSessionHook(db, HookEvents.SessionStart, context);
218
156
  }
219
157
 
220
- function withTimeout(promise, ms, label) {
221
- if (!ms || ms <= 0) return promise;
222
- let t;
223
- const timeout = new Promise((_, reject) => {
224
- t = setTimeout(
225
- () => reject(new Error(`${label} exceeded ${ms}ms helper timeout`)),
226
- ms,
227
- );
228
- if (typeof t.unref === "function") t.unref();
158
+ /**
159
+ * 触发会话结束钩子
160
+ * @param {object} db - 数据库实例
161
+ * @param {object} [context={}] - 上下文
162
+ * @returns {Promise<Array>}
163
+ */
164
+ export async function fireSessionEnd(db, context = {}) {
165
+ return fireSessionHook(db, HookEvents.SessionEnd, context);
166
+ }
167
+
168
+ // Historical callers use "Stop" for the terminal lifecycle event; retain the
169
+ // alias while the canonical hook event remains SessionEnd.
170
+ export const fireSessionStop = fireSessionEnd;
171
+
172
+ /**
173
+ * 获取钩子数据库实例
174
+ * @returns {null} 暂未实现
175
+ */
176
+ export function getHookDb() {
177
+ return null;
178
+ }
179
+
180
+ /**
181
+ * 触发设置钩子
182
+ * @param {object} db - 数据库实例
183
+ * @param {object} context - 上下文
184
+ * @returns {Promise<{abort: boolean}>}
185
+ */
186
+ export async function fireSetup(db, context) {
187
+ return { abort: false };
188
+ }
189
+
190
+ /** Fire Notification hooks. Notifications are best-effort and may return a
191
+ * suppress/message directive without ever breaking the host session. */
192
+ export async function fireNotification(db, message, context = {}) {
193
+ const results = await fireSessionHook(db, HookEvents.Notification, {
194
+ message,
195
+ ...context,
229
196
  });
230
- return Promise.race([promise, timeout]).finally(() => clearTimeout(t));
197
+ for (const result of results) {
198
+ if (!result?.success) continue;
199
+ const raw = result.stdout ?? result.output ?? result.result;
200
+ let directive = raw && typeof raw === "object" ? raw : null;
201
+ if (!directive && typeof raw === "string") {
202
+ try {
203
+ directive = JSON.parse(raw.trim());
204
+ } catch {
205
+ directive = null;
206
+ }
207
+ }
208
+ if (directive && typeof directive === "object") {
209
+ return { directive, results };
210
+ }
211
+ }
212
+ return { directive: null, results };
231
213
  }
232
214
 
233
- // ===== V2 Surface: Session Hooks governance overlay (CLI v0.142.0) =====
215
+ // Session Hooks V2 governance overlay. Kept in this module so the command and
216
+ // the library expose one stable surface to the CLI and its consumers.
234
217
  export const SHOK_PROFILE_MATURITY_V2 = Object.freeze({
235
218
  PENDING: "pending",
236
219
  ACTIVE: "active",
@@ -244,209 +227,150 @@ export const SHOK_INVOCATION_LIFECYCLE_V2 = Object.freeze({
244
227
  FAILED: "failed",
245
228
  CANCELLED: "cancelled",
246
229
  });
247
- const _shokPTrans = new Map([
248
- [
249
- SHOK_PROFILE_MATURITY_V2.PENDING,
250
- new Set([
251
- SHOK_PROFILE_MATURITY_V2.ACTIVE,
252
- SHOK_PROFILE_MATURITY_V2.RETIRED,
253
- ]),
254
- ],
255
- [
256
- SHOK_PROFILE_MATURITY_V2.ACTIVE,
257
- new Set([
258
- SHOK_PROFILE_MATURITY_V2.DISABLED,
259
- SHOK_PROFILE_MATURITY_V2.RETIRED,
260
- ]),
261
- ],
262
- [
263
- SHOK_PROFILE_MATURITY_V2.DISABLED,
264
- new Set([
265
- SHOK_PROFILE_MATURITY_V2.ACTIVE,
266
- SHOK_PROFILE_MATURITY_V2.RETIRED,
267
- ]),
268
- ],
269
- [SHOK_PROFILE_MATURITY_V2.RETIRED, new Set()],
270
- ]);
271
- const _shokPTerminal = new Set([SHOK_PROFILE_MATURITY_V2.RETIRED]);
272
- const _shokITrans = new Map([
273
- [
274
- SHOK_INVOCATION_LIFECYCLE_V2.QUEUED,
275
- new Set([
276
- SHOK_INVOCATION_LIFECYCLE_V2.RUNNING,
277
- SHOK_INVOCATION_LIFECYCLE_V2.CANCELLED,
278
- ]),
279
- ],
280
- [
281
- SHOK_INVOCATION_LIFECYCLE_V2.RUNNING,
282
- new Set([
283
- SHOK_INVOCATION_LIFECYCLE_V2.COMPLETED,
284
- SHOK_INVOCATION_LIFECYCLE_V2.FAILED,
285
- SHOK_INVOCATION_LIFECYCLE_V2.CANCELLED,
286
- ]),
287
- ],
288
- [SHOK_INVOCATION_LIFECYCLE_V2.COMPLETED, new Set()],
289
- [SHOK_INVOCATION_LIFECYCLE_V2.FAILED, new Set()],
290
- [SHOK_INVOCATION_LIFECYCLE_V2.CANCELLED, new Set()],
291
- ]);
292
- const _shokPsV2 = new Map();
293
- const _shokIsV2 = new Map();
294
- let _shokMaxActive = 12,
295
- _shokMaxPending = 25,
296
- _shokIdleMs = 30 * 24 * 60 * 60 * 1000,
297
- _shokStuckMs = 30 * 1000;
298
- function _shokPos(n, label) {
230
+ const _sp = new Map(),
231
+ _si = new Map();
232
+ let _maxActive = 12,
233
+ _maxPending = 25,
234
+ _idleMs = 30 * 24 * 60 * 60 * 1000,
235
+ _stuckMs = 30000;
236
+ const clone = (x) => ({ ...x, metadata: { ...(x.metadata || {}) } });
237
+ const pos = (n, name) => {
299
238
  const v = Math.floor(Number(n));
300
239
  if (!Number.isFinite(v) || v <= 0)
301
- throw new Error(`${label} must be positive integer`);
240
+ throw new Error(`${name} must be positive integer`);
302
241
  return v;
303
- }
304
- function _shokCheckP(from, to) {
305
- const a = _shokPTrans.get(from);
306
- if (!a || !a.has(to))
307
- throw new Error(`invalid shok profile transition ${from} → ${to}`);
308
- }
309
- function _shokCheckI(from, to) {
310
- const a = _shokITrans.get(from);
311
- if (!a || !a.has(to))
312
- throw new Error(`invalid shok invocation transition ${from} → ${to}`);
313
- }
314
- export function setMaxActiveShokProfilesPerOwnerV2(n) {
315
- _shokMaxActive = _shokPos(n, "maxActiveShokProfilesPerOwner");
316
- }
317
- export function getMaxActiveShokProfilesPerOwnerV2() {
318
- return _shokMaxActive;
319
- }
320
- export function setMaxPendingShokInvocationsPerProfileV2(n) {
321
- _shokMaxPending = _shokPos(n, "maxPendingShokInvocationsPerProfile");
322
- }
323
- export function getMaxPendingShokInvocationsPerProfileV2() {
324
- return _shokMaxPending;
325
- }
326
- export function setShokProfileIdleMsV2(n) {
327
- _shokIdleMs = _shokPos(n, "shokProfileIdleMs");
328
- }
329
- export function getShokProfileIdleMsV2() {
330
- return _shokIdleMs;
331
- }
332
- export function setShokInvocationStuckMsV2(n) {
333
- _shokStuckMs = _shokPos(n, "shokInvocationStuckMs");
334
- }
335
- export function getShokInvocationStuckMsV2() {
336
- return _shokStuckMs;
337
- }
242
+ };
243
+ const profile = (id) => {
244
+ const p = _sp.get(id);
245
+ if (!p) throw new Error(`shok profile ${id} not found`);
246
+ return p;
247
+ };
248
+ const invocation = (id) => {
249
+ const i = _si.get(id);
250
+ if (!i) throw new Error(`shok invocation ${id} not found`);
251
+ return i;
252
+ };
253
+ const transition = (map, from, to, label) => {
254
+ if (!map[from]?.includes(to))
255
+ throw new Error(`invalid ${label} transition ${from} → ${to}`);
256
+ };
257
+ const PT = {
258
+ pending: ["active", "retired"],
259
+ active: ["disabled", "retired"],
260
+ disabled: ["active", "retired"],
261
+ retired: [],
262
+ };
263
+ const IT = {
264
+ queued: ["running", "cancelled"],
265
+ running: ["completed", "failed", "cancelled"],
266
+ completed: [],
267
+ failed: [],
268
+ cancelled: [],
269
+ };
270
+ export const setMaxActiveShokProfilesPerOwnerV2 = (n) => {
271
+ _maxActive = pos(n, "maxActiveShokProfilesPerOwner");
272
+ };
273
+ export const getMaxActiveShokProfilesPerOwnerV2 = () => _maxActive;
274
+ export const setMaxPendingShokInvocationsPerProfileV2 = (n) => {
275
+ _maxPending = pos(n, "maxPendingShokInvocationsPerProfile");
276
+ };
277
+ export const getMaxPendingShokInvocationsPerProfileV2 = () => _maxPending;
278
+ export const setShokProfileIdleMsV2 = (n) => {
279
+ _idleMs = pos(n, "shokProfileIdleMs");
280
+ };
281
+ export const getShokProfileIdleMsV2 = () => _idleMs;
282
+ export const setShokInvocationStuckMsV2 = (n) => {
283
+ _stuckMs = pos(n, "shokInvocationStuckMs");
284
+ };
285
+ export const getShokInvocationStuckMsV2 = () => _stuckMs;
338
286
  export function _resetStateSessionHooksV2() {
339
- _shokPsV2.clear();
340
- _shokIsV2.clear();
341
- _shokMaxActive = 12;
342
- _shokMaxPending = 25;
343
- _shokIdleMs = 30 * 24 * 60 * 60 * 1000;
344
- _shokStuckMs = 30 * 1000;
345
- }
346
- export function registerShokProfileV2({ id, owner, event, metadata } = {}) {
347
- if (!id) throw new Error("shok profile id required");
348
- if (!owner) throw new Error("shok profile owner required");
349
- if (_shokPsV2.has(id))
350
- throw new Error(`shok profile ${id} already registered`);
287
+ _sp.clear();
288
+ _si.clear();
289
+ _maxActive = 12;
290
+ _maxPending = 25;
291
+ _idleMs = 30 * 24 * 60 * 60 * 1000;
292
+ _stuckMs = 30000;
293
+ }
294
+ export function registerShokProfileV2({
295
+ id,
296
+ owner,
297
+ event = "preTurn",
298
+ metadata = {},
299
+ } = {}) {
300
+ if (!id || !owner) throw new Error("shok profile id and owner required");
301
+ if (_sp.has(id)) throw new Error(`shok profile ${id} already registered`);
351
302
  const now = Date.now();
352
303
  const p = {
353
304
  id,
354
305
  owner,
355
- event: event || "preTurn",
356
- status: SHOK_PROFILE_MATURITY_V2.PENDING,
306
+ event,
307
+ status: "pending",
357
308
  createdAt: now,
358
309
  updatedAt: now,
359
310
  activatedAt: null,
360
311
  retiredAt: null,
361
312
  lastTouchedAt: now,
362
- metadata: { ...(metadata || {}) },
313
+ metadata: { ...metadata },
363
314
  };
364
- _shokPsV2.set(id, p);
365
- return { ...p, metadata: { ...p.metadata } };
366
- }
367
- function _shokCountActive(owner) {
368
- let n = 0;
369
- for (const p of _shokPsV2.values())
370
- if (p.owner === owner && p.status === SHOK_PROFILE_MATURITY_V2.ACTIVE) n++;
371
- return n;
315
+ _sp.set(id, p);
316
+ return clone(p);
372
317
  }
373
318
  export function activateShokProfileV2(id) {
374
- const p = _shokPsV2.get(id);
375
- if (!p) throw new Error(`shok profile ${id} not found`);
376
- _shokCheckP(p.status, SHOK_PROFILE_MATURITY_V2.ACTIVE);
377
- const recovery = p.status === SHOK_PROFILE_MATURITY_V2.DISABLED;
378
- if (!recovery && _shokCountActive(p.owner) >= _shokMaxActive)
319
+ const p = profile(id);
320
+ transition(PT, p.status, "active", "shok profile");
321
+ const active = [..._sp.values()].filter(
322
+ (x) => x.owner === p.owner && x.status === "active",
323
+ ).length;
324
+ if (p.status !== "disabled" && active >= _maxActive)
379
325
  throw new Error(`max active shok profiles for owner ${p.owner} reached`);
380
326
  const now = Date.now();
381
- p.status = SHOK_PROFILE_MATURITY_V2.ACTIVE;
327
+ p.status = "active";
382
328
  p.updatedAt = now;
383
329
  p.lastTouchedAt = now;
384
- if (!p.activatedAt) p.activatedAt = now;
385
- return { ...p, metadata: { ...p.metadata } };
330
+ p.activatedAt ||= now;
331
+ return clone(p);
386
332
  }
387
333
  export function disableShokProfileV2(id) {
388
- const p = _shokPsV2.get(id);
389
- if (!p) throw new Error(`shok profile ${id} not found`);
390
- _shokCheckP(p.status, SHOK_PROFILE_MATURITY_V2.DISABLED);
391
- p.status = SHOK_PROFILE_MATURITY_V2.DISABLED;
334
+ const p = profile(id);
335
+ transition(PT, p.status, "disabled", "shok profile");
336
+ p.status = "disabled";
392
337
  p.updatedAt = Date.now();
393
- return { ...p, metadata: { ...p.metadata } };
338
+ return clone(p);
394
339
  }
395
340
  export function retireShokProfileV2(id) {
396
- const p = _shokPsV2.get(id);
397
- if (!p) throw new Error(`shok profile ${id} not found`);
398
- _shokCheckP(p.status, SHOK_PROFILE_MATURITY_V2.RETIRED);
341
+ const p = profile(id);
342
+ transition(PT, p.status, "retired", "shok profile");
399
343
  const now = Date.now();
400
- p.status = SHOK_PROFILE_MATURITY_V2.RETIRED;
344
+ p.status = "retired";
401
345
  p.updatedAt = now;
402
- if (!p.retiredAt) p.retiredAt = now;
403
- return { ...p, metadata: { ...p.metadata } };
346
+ p.retiredAt ||= now;
347
+ return clone(p);
404
348
  }
405
349
  export function touchShokProfileV2(id) {
406
- const p = _shokPsV2.get(id);
407
- if (!p) throw new Error(`shok profile ${id} not found`);
408
- if (_shokPTerminal.has(p.status))
350
+ const p = profile(id);
351
+ if (p.status === "retired")
409
352
  throw new Error(`cannot touch terminal shok profile ${id}`);
410
- const now = Date.now();
411
- p.lastTouchedAt = now;
412
- p.updatedAt = now;
413
- return { ...p, metadata: { ...p.metadata } };
414
- }
415
- export function getShokProfileV2(id) {
416
- const p = _shokPsV2.get(id);
417
- if (!p) return null;
418
- return { ...p, metadata: { ...p.metadata } };
419
- }
420
- export function listShokProfilesV2() {
421
- return [..._shokPsV2.values()].map((p) => ({
422
- ...p,
423
- metadata: { ...p.metadata },
424
- }));
425
- }
426
- function _shokCountPending(profileId) {
427
- let n = 0;
428
- for (const i of _shokIsV2.values())
429
- if (
430
- i.profileId === profileId &&
431
- (i.status === SHOK_INVOCATION_LIFECYCLE_V2.QUEUED ||
432
- i.status === SHOK_INVOCATION_LIFECYCLE_V2.RUNNING)
433
- )
434
- n++;
435
- return n;
353
+ p.lastTouchedAt = p.updatedAt = Date.now();
354
+ return clone(p);
436
355
  }
356
+ export const getShokProfileV2 = (id) =>
357
+ _sp.has(id) ? clone(_sp.get(id)) : null;
358
+ export const listShokProfilesV2 = () => [..._sp.values()].map(clone);
437
359
  export function createShokInvocationV2({
438
360
  id,
439
361
  profileId,
440
- payload,
441
- metadata,
362
+ payload = "",
363
+ metadata = {},
442
364
  } = {}) {
443
- if (!id) throw new Error("shok invocation id required");
444
- if (!profileId) throw new Error("shok invocation profileId required");
445
- if (_shokIsV2.has(id))
446
- throw new Error(`shok invocation ${id} already exists`);
447
- if (!_shokPsV2.has(profileId))
448
- throw new Error(`shok profile ${profileId} not found`);
449
- if (_shokCountPending(profileId) >= _shokMaxPending)
365
+ if (!id || !profileId)
366
+ throw new Error("shok invocation id and profileId required");
367
+ if (_si.has(id) || !_sp.has(profileId))
368
+ throw new Error("invalid shok invocation");
369
+ const pending = [..._si.values()].filter(
370
+ (x) =>
371
+ x.profileId === profileId && ["queued", "running"].includes(x.status),
372
+ ).length;
373
+ if (pending >= _maxPending)
450
374
  throw new Error(
451
375
  `max pending shok invocations for profile ${profileId} reached`,
452
376
  );
@@ -454,159 +378,90 @@ export function createShokInvocationV2({
454
378
  const i = {
455
379
  id,
456
380
  profileId,
457
- payload: payload || "",
458
- status: SHOK_INVOCATION_LIFECYCLE_V2.QUEUED,
381
+ payload,
382
+ status: "queued",
459
383
  createdAt: now,
460
384
  updatedAt: now,
461
385
  startedAt: null,
462
386
  settledAt: null,
463
- metadata: { ...(metadata || {}) },
387
+ metadata: { ...metadata },
464
388
  };
465
- _shokIsV2.set(id, i);
466
- return { ...i, metadata: { ...i.metadata } };
467
- }
468
- export function runningShokInvocationV2(id) {
469
- const i = _shokIsV2.get(id);
470
- if (!i) throw new Error(`shok invocation ${id} not found`);
471
- _shokCheckI(i.status, SHOK_INVOCATION_LIFECYCLE_V2.RUNNING);
472
- const now = Date.now();
473
- i.status = SHOK_INVOCATION_LIFECYCLE_V2.RUNNING;
474
- i.updatedAt = now;
475
- if (!i.startedAt) i.startedAt = now;
476
- return { ...i, metadata: { ...i.metadata } };
477
- }
478
- export function completeShokInvocationV2(id) {
479
- const i = _shokIsV2.get(id);
480
- if (!i) throw new Error(`shok invocation ${id} not found`);
481
- _shokCheckI(i.status, SHOK_INVOCATION_LIFECYCLE_V2.COMPLETED);
482
- const now = Date.now();
483
- i.status = SHOK_INVOCATION_LIFECYCLE_V2.COMPLETED;
484
- i.updatedAt = now;
485
- if (!i.settledAt) i.settledAt = now;
486
- return { ...i, metadata: { ...i.metadata } };
487
- }
488
- export function failShokInvocationV2(id, reason) {
489
- const i = _shokIsV2.get(id);
490
- if (!i) throw new Error(`shok invocation ${id} not found`);
491
- _shokCheckI(i.status, SHOK_INVOCATION_LIFECYCLE_V2.FAILED);
492
- const now = Date.now();
493
- i.status = SHOK_INVOCATION_LIFECYCLE_V2.FAILED;
494
- i.updatedAt = now;
495
- if (!i.settledAt) i.settledAt = now;
496
- if (reason) i.metadata.failReason = String(reason);
497
- return { ...i, metadata: { ...i.metadata } };
389
+ _si.set(id, i);
390
+ return clone(i);
498
391
  }
499
- export function cancelShokInvocationV2(id, reason) {
500
- const i = _shokIsV2.get(id);
501
- if (!i) throw new Error(`shok invocation ${id} not found`);
502
- _shokCheckI(i.status, SHOK_INVOCATION_LIFECYCLE_V2.CANCELLED);
392
+ function setInvocation(id, to, extra = {}) {
393
+ const i = invocation(id);
394
+ transition(IT, i.status, to, "shok invocation");
503
395
  const now = Date.now();
504
- i.status = SHOK_INVOCATION_LIFECYCLE_V2.CANCELLED;
505
- i.updatedAt = now;
506
- if (!i.settledAt) i.settledAt = now;
507
- if (reason) i.metadata.cancelReason = String(reason);
508
- return { ...i, metadata: { ...i.metadata } };
509
- }
510
- export function getShokInvocationV2(id) {
511
- const i = _shokIsV2.get(id);
512
- if (!i) return null;
513
- return { ...i, metadata: { ...i.metadata } };
514
- }
515
- export function listShokInvocationsV2() {
516
- return [..._shokIsV2.values()].map((i) => ({
517
- ...i,
518
- metadata: { ...i.metadata },
519
- }));
520
- }
521
- export function autoDisableIdleShokProfilesV2({ now } = {}) {
522
- const t = now ?? Date.now();
396
+ Object.assign(i, extra, { status: to, updatedAt: now });
397
+ if (to === "running") i.startedAt ||= now;
398
+ if (["completed", "failed", "cancelled"].includes(to)) i.settledAt ||= now;
399
+ return clone(i);
400
+ }
401
+ export const runningShokInvocationV2 = (id) => setInvocation(id, "running");
402
+ export const completeShokInvocationV2 = (id) => setInvocation(id, "completed");
403
+ export const failShokInvocationV2 = (id, reason) =>
404
+ setInvocation(
405
+ id,
406
+ "failed",
407
+ reason
408
+ ? { metadata: { ...invocation(id).metadata, failReason: String(reason) } }
409
+ : {},
410
+ );
411
+ export const cancelShokInvocationV2 = (id, reason) =>
412
+ setInvocation(
413
+ id,
414
+ "cancelled",
415
+ reason
416
+ ? {
417
+ metadata: {
418
+ ...invocation(id).metadata,
419
+ cancelReason: String(reason),
420
+ },
421
+ }
422
+ : {},
423
+ );
424
+ export const getShokInvocationV2 = (id) =>
425
+ _si.has(id) ? clone(_si.get(id)) : null;
426
+ export const listShokInvocationsV2 = () => [..._si.values()].map(clone);
427
+ export function autoDisableIdleShokProfilesV2({ now = Date.now() } = {}) {
523
428
  const flipped = [];
524
- for (const p of _shokPsV2.values())
525
- if (
526
- p.status === SHOK_PROFILE_MATURITY_V2.ACTIVE &&
527
- t - p.lastTouchedAt >= _shokIdleMs
528
- ) {
529
- p.status = SHOK_PROFILE_MATURITY_V2.DISABLED;
530
- p.updatedAt = t;
429
+ for (const p of _sp.values())
430
+ if (p.status === "active" && now - p.lastTouchedAt >= _idleMs) {
431
+ p.status = "disabled";
432
+ p.updatedAt = now;
531
433
  flipped.push(p.id);
532
434
  }
533
435
  return { flipped, count: flipped.length };
534
436
  }
535
- export function autoFailStuckShokInvocationsV2({ now } = {}) {
536
- const t = now ?? Date.now();
437
+ export function autoFailStuckShokInvocationsV2({ now = Date.now() } = {}) {
537
438
  const flipped = [];
538
- for (const i of _shokIsV2.values())
539
- if (
540
- i.status === SHOK_INVOCATION_LIFECYCLE_V2.RUNNING &&
541
- i.startedAt != null &&
542
- t - i.startedAt >= _shokStuckMs
543
- ) {
544
- i.status = SHOK_INVOCATION_LIFECYCLE_V2.FAILED;
545
- i.updatedAt = t;
546
- if (!i.settledAt) i.settledAt = t;
439
+ for (const i of _si.values())
440
+ if (i.status === "running" && now - i.startedAt >= _stuckMs) {
441
+ i.status = "failed";
442
+ i.updatedAt = i.settledAt = now;
547
443
  i.metadata.failReason = "auto-fail-stuck";
548
444
  flipped.push(i.id);
549
445
  }
550
446
  return { flipped, count: flipped.length };
551
447
  }
552
448
  export function getSessionHooksGovStatsV2() {
553
- const profilesByStatus = {};
554
- for (const v of Object.values(SHOK_PROFILE_MATURITY_V2))
555
- profilesByStatus[v] = 0;
556
- for (const p of _shokPsV2.values()) profilesByStatus[p.status]++;
557
- const invocationsByStatus = {};
558
- for (const v of Object.values(SHOK_INVOCATION_LIFECYCLE_V2))
559
- invocationsByStatus[v] = 0;
560
- for (const i of _shokIsV2.values()) invocationsByStatus[i.status]++;
449
+ const profilesByStatus = Object.fromEntries(
450
+ Object.values(SHOK_PROFILE_MATURITY_V2).map((x) => [x, 0]),
451
+ );
452
+ const invocationsByStatus = Object.fromEntries(
453
+ Object.values(SHOK_INVOCATION_LIFECYCLE_V2).map((x) => [x, 0]),
454
+ );
455
+ for (const p of _sp.values()) profilesByStatus[p.status]++;
456
+ for (const i of _si.values()) invocationsByStatus[i.status]++;
561
457
  return {
562
- totalShokProfilesV2: _shokPsV2.size,
563
- totalShokInvocationsV2: _shokIsV2.size,
564
- maxActiveShokProfilesPerOwner: _shokMaxActive,
565
- maxPendingShokInvocationsPerProfile: _shokMaxPending,
566
- shokProfileIdleMs: _shokIdleMs,
567
- shokInvocationStuckMs: _shokStuckMs,
458
+ totalShokProfilesV2: _sp.size,
459
+ totalShokInvocationsV2: _si.size,
460
+ maxActiveShokProfilesPerOwner: _maxActive,
461
+ maxPendingShokInvocationsPerProfile: _maxPending,
462
+ shokProfileIdleMs: _idleMs,
463
+ shokInvocationStuckMs: _stuckMs,
568
464
  profilesByStatus,
569
465
  invocationsByStatus,
570
466
  };
571
467
  }
572
-
573
- /**
574
- * Fire settings.json Stop hooks (observe-only) — fires at the END of EVERY
575
- * agent turn/loop iteration, BEFORE waiting for the next user input.
576
- * Aligns with Claude Code hook spec.
577
- *
578
- * Fires regardless of outcome: normal completion, error, max iterations,
579
- * user interrupt, or tool stop. Does NOT fire on final process exit
580
- * (use SessionEnd/Shutdown hooks for that case).
581
- *
582
- * @param {Object} opts
583
- * @param {string} opts.sessionId - Current session ID
584
- * @param {string} opts.transcriptPath - Path to transcript file
585
- * @param {string} [opts.stopReason="end_turn"] - Reason the turn stopped:
586
- * "end_turn", "error", "max_iterations", "user_interrupt", "tool_stop"
587
- * @param {string} [opts.finalResponse=""] - Final assistant response text
588
- * @param {number} [opts.toolCount=0] - Number of tool calls made this turn
589
- * @param {number} [opts.durationMs=0] - Turn duration in milliseconds
590
- * @param {Error|string} [opts.error] - Error object if stopReason is "error"
591
- * @returns {Promise<Array>} Hook execution results
592
- */
593
- export async function fireSessionStop({
594
- sessionId,
595
- transcriptPath,
596
- stopReason = "end_turn",
597
- finalResponse = "",
598
- toolCount = 0,
599
- durationMs = 0,
600
- error = null,
601
- }) {
602
- return runSettingsHooks("Stop", {
603
- session_id: sessionId,
604
- transcript_path: transcriptPath,
605
- stop_reason: stopReason,
606
- final_response: finalResponse,
607
- tool_count: toolCount,
608
- duration_ms: durationMs,
609
- error: error ? String(error.message ?? error) : "",
610
- timestamp: new Date().toISOString(),
611
- });
612
- }