chainlesschain 0.162.176 → 0.162.178
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.
- package/README.md +10 -0
- package/package.json +1 -1
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-BDLu5Elz.js → AIOps-DRftcSue.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DH5us-CK.js → ActionButton-BFvUaMKR.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-BZ0u8IFG.js → Analytics-C0-Rru4P.js} +3 -3
- package/src/assets/web-panel/assets/AppLayout-bx-BCljj.js +9 -0
- package/src/assets/web-panel/assets/{Artifacts-Br2YBbh_.js → Artifacts-DAJ8B3Un.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-C3C6a482.js → Audit-hOk4L1lr.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-CzHvebcj.js → BackgroundAgents-3pbDpM9z.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DZNHYDFd.js → Backup-BtziGDn9.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-VRiC4fIx.js → BaseInput-kmshphJ3.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-Cm08WWAD.js → Chat-d7tGSosA.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-CGHYrugQ.js → ChatBubbleRenderer-p-_PBpX_.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-DtByk7d7.js → Checkbox-C4Eh4Tz5.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-CphXXOfD.js → Codegen-r7gmhZyA.js} +1 -1
- package/src/assets/web-panel/assets/{Col-Hz86TnLR.js → Col-U7mDaGlL.js} +1 -1
- package/src/assets/web-panel/assets/{Community-HP03ltpD.js → Community-Bpu8aH1T.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-B_N1mqQz.js → Compact-CHb2XBJe.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CVztRpi8.js → Compliance-Cn_r4dey.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-wUVOyZih.js → Cowork-CdMWfDcz.js} +4 -4
- package/src/assets/web-panel/assets/{Cron-DW5TLJKw.js → Cron-BtnREHWy.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CrAFGhWH.js → Crosschain-BKI9TSzr.js} +1 -1
- package/src/assets/web-panel/assets/{DID-pA-oD8ke.js → DID-pkNubzzJ.js} +2 -2
- package/src/assets/web-panel/assets/Dashboard-1rrz1snN.js +3 -0
- package/src/assets/web-panel/assets/{Dropdown-EweJcsek.js → Dropdown-DLyFVxDc.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-C9xVLPG4.js → EmailListRenderer-CtUWfYVq.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-CDcEEqlu.js → FamilyGuardDashboard-B8eX2Qe4.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DtZda9A_.js → Federation-D8lsDGus.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-CiYdcVz3.js → FormItemContext-CRYt_aIw.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DA13uwA0.js → GenericCardRenderer-ClKzY8_N.js} +1 -1
- package/src/assets/web-panel/assets/{Git-DzRhZD1O.js → Git-BXj5Dney.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-D5RMgOSb.js → Governance-Cm-I8RMz.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-BgrPfSNk.js → Inference-CPvbhvgt.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DzjnD571.js → KnowledgeGraph-sYNDZaoi.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BhWzVDtN.js → Logs-BZY_3CRZ.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-BDape9cx.js → MarkdownRenderer-up0BW6pv.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-DJtL5GV7.js → Marketplace-C5MEJ2Qe.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-CZcQygI7.js → McpTools-ihdrn43I.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-DUWSDUUu.js → Memory-Br8bPMlh.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BTwq2WKY.js → MobileBridge-BNntgrYW.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-BdV915mw.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-BiGugEQm.js → Mtc-A3wDmlqL.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-DY7a6gUe.js → MtcAudit-CF-mBLWM.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-BQbDu_w7.js → Multisig-Iy2k_MSo.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CM2wXTLv.js → NLProgramming-kk0W7HUb.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-DI6gGs1v.js → Notes-B5u5t_4S.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-BsZOLWAB.js → NotificationSettings-BN0POf6_.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-CHkSUrXB.js +1 -0
- package/src/assets/web-panel/assets/{Organization-Cds0_tXr.js → Organization-DwWQESuN.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-WunYMD87.js → Overflow-DG6klrcC.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-Bo6j4DDv.js → P2P-BwJcKkgZ.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-Bh2XPD5f.js → PdhVaultBrowser-BwOHG0in.js} +5 -5
- package/src/assets/web-panel/assets/{Permissions-EMvMMC8N.js → Permissions-CGMXe4TX.js} +4 -4
- package/src/assets/web-panel/assets/PersonalDataHub-ziYqg7-A.js +8 -0
- package/src/assets/web-panel/assets/{Pipeline-BOx8HOgL.js → Pipeline-BzJfeoGt.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-tBeTVQVM.js → Privacy-DLh3Bblx.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CVYg1W4M.js → ProjectInit-USVWW36c.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-Dvt5I7y1.js → ProjectSettings-CiiOn62h.js} +2 -2
- package/src/assets/web-panel/assets/Projects-6V-PNmcA.js +1 -0
- package/src/assets/web-panel/assets/{Providers-Ct8xqY-E.js → Providers-CBPWWzpu.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-Cni8Ooja.js → QrScannerModal-QVwoRUq3.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BJVLKdxr.js → QuickAsk-CXnR-2Vn.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DPG8Rbbm.js → Recommend-ClaNzjmF.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-DsdR7dCt.js → RemoteSession-C3rGw8vJ.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-Csg1YM-b.js → Reputation-Ci-OWAoP.js} +1 -1
- package/src/assets/web-panel/assets/{Row-D9DoFoEf.js → Row-DRhAwXOS.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BsvKrXMS.js → RssFeed-BQLJQ2_y.js} +3 -3
- package/src/assets/web-panel/assets/{Search-DFUStfgQ.js → Search-QQUpkfFd.js} +1 -1
- package/src/assets/web-panel/assets/{Security-ILg1zxdK.js → Security-DdXKzuKT.js} +4 -4
- package/src/assets/web-panel/assets/{Services-Dd41PCaY.js → Services-x2Zh62Qd.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-Bzo1cN80.js → Skeleton-GdY4KwRz.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-BDHh17P0.js → Skills-Bv4tY1Fd.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-jl7UTiRY.js → Sla-C3QnM-11.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BePa-RF6.js → SpeechSettings-Bl3ytvmI.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-DiqqDKGZ.js → SyncSettings-Wp9IwTsP.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-DYQ_6lxj.js → Tasks-CF3rIrDe.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-JiDeI06L.js → Templates-CGfvVVM9.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-hhgI6zwS.js → Tenant-CVXmwQ3U.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-bvwrt03E.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-B8uB5Llk.js → TimelineRenderer-D0g74KhH.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-C3b_6r2z.js → Tokens-BH4IwzlT.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-tIP7HKVe.js → Trigger-DJOpM533.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-vjoc11vJ.js → Trust-B43EPRLr.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-DUPBnGuH.js → UkeySign-BmBFG-em.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-CBvhUY5T.js → VideoEditing-n9oJwB8k.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-DUaQ0uA5.js → Wallet-D5QeivHp.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DllSivjE.js → WebAuthn-DcNy7igO.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-xc8D3uO6.js → WorkflowEditor-BVjc7-5-.js} +1 -1
- package/src/assets/web-panel/assets/{chat-BVicU7oA.js → chat-Dy5Tfj3m.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DJzLmhLm.js → colors-C4c2CNZU.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BvYRfThE.js → compact-item-DPa3O5vN.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DGXxCBKR.js → createContext-TLcfNA6_.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BAwdDA_5.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-SBDJB1y4.js → hasIn-D41LVFkp.js} +1 -1
- package/src/assets/web-panel/assets/{index-D7HimK0M.js → index-0oevYjfT.js} +1 -1
- package/src/assets/web-panel/assets/{index-DCdRAgjy.js → index-388pLGJ1.js} +1 -1
- package/src/assets/web-panel/assets/{index-BO1itZaY.js → index-B8nLBZbv.js} +3 -3
- package/src/assets/web-panel/assets/{index-DvUTDYXX.js → index-BPTGAjee.js} +1 -1
- package/src/assets/web-panel/assets/{index-hxTODbM1.js → index-BPtrOBmW.js} +1 -1
- package/src/assets/web-panel/assets/{index-wcCL-miV.js → index-BQiIxHBy.js} +1 -1
- package/src/assets/web-panel/assets/{index-CKyEivf8.js → index-BSM1cHVK.js} +1 -1
- package/src/assets/web-panel/assets/{index-BJZf9DhV.js → index-BYPr9fkz.js} +1 -1
- package/src/assets/web-panel/assets/{index-DHVLJ8q0.js → index-BsQ7Ev6i.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cs2rmLFt.js → index-Btk9qLL2.js} +1 -1
- package/src/assets/web-panel/assets/{index-z1ZylsLq.js → index-BvmziZSG.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cf-O_g_8.js → index-BvopLC_T.js} +1 -1
- package/src/assets/web-panel/assets/{index-DMarmfrv.js → index-C7xhTVyP.js} +1 -1
- package/src/assets/web-panel/assets/{index-CoJAO1Lm.js → index-CNk_ZooP.js} +1 -1
- package/src/assets/web-panel/assets/{index-9gdI7uUW.js → index-CQrEHoOG.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bf-ctERC.js → index-CSxex23J.js} +1 -1
- package/src/assets/web-panel/assets/{index-MjC4G09d.js → index-CVjgm992.js} +1 -1
- package/src/assets/web-panel/assets/{index-e4fXH_WO.js → index-CWK4zOPe.js} +1 -1
- package/src/assets/web-panel/assets/{index-xfluRkCT.js → index-CX0VsoP4.js} +1 -1
- package/src/assets/web-panel/assets/{index-DRfiXB_p.js → index-CXl0YPNG.js} +1 -1
- package/src/assets/web-panel/assets/{index-d5BVd-cL.js → index-Cip7LWml.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dm_77jgR.js → index-Cq_hlWNt.js} +1 -1
- package/src/assets/web-panel/assets/{index-YJkzy8ZF.js → index-CzZ49YZL.js} +1 -1
- package/src/assets/web-panel/assets/{index-CtwqO5qo.js → index-D2Nkivlm.js} +1 -1
- package/src/assets/web-panel/assets/{index-BYqz4Wrr.js → index-DBUgRs4D.js} +1 -1
- package/src/assets/web-panel/assets/index-DEjVkdzq.js +1 -0
- package/src/assets/web-panel/assets/{index-CdGY9P8a.js → index-DNsBj2Ob.js} +1 -1
- package/src/assets/web-panel/assets/{index-DonCnfMr.js → index-Di4X8cfI.js} +1 -1
- package/src/assets/web-panel/assets/{index-1SdDS6lR.js → index-DljFsVGI.js} +1 -1
- package/src/assets/web-panel/assets/{index-DnjPdvR6.js → index-Korc3QIe.js} +1 -1
- package/src/assets/web-panel/assets/index-LMOc5xrS.js +1 -0
- package/src/assets/web-panel/assets/{index-VMfwIH5G.js → index-MKZDje0H.js} +1 -1
- package/src/assets/web-panel/assets/{index-DKrvvWm4.js → index-OHAfRu_3.js} +1 -1
- package/src/assets/web-panel/assets/{index-FxZzRyE1.js → index-WEJr8PL5.js} +1 -1
- package/src/assets/web-panel/assets/{index-Crk5NTb0.js → index-WinCp6du.js} +1 -1
- package/src/assets/web-panel/assets/{index-DCqRS6da.js → index-Yjr6cqSK.js} +1 -1
- package/src/assets/web-panel/assets/{index-BTrBGBJs.js → index-iQ6gtFih.js} +1 -1
- package/src/assets/web-panel/assets/{index-lpaGoTH3.js → index-pt3s7yvV.js} +1 -1
- package/src/assets/web-panel/assets/{index-CloCgBUR.js → index-tQ3igERQ.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-C1zO1KnY.js → initDefaultProps-BFZu87WZ.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CWLtEGmC.js → motion-DJIo7qvt.js} +1 -1
- package/src/assets/web-panel/assets/{move-DzD_C3Vm.js → move-Cfr5qknL.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-D880PYJl.js → mtc-parser-Bgc-OadH.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CFR_z2ov.js → omit-X3WI-TNp.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-srIhgrSC.js → pickAttrs-pJhU9IxK.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-C1rXpibP.js → placementArrow-BNg_Vj3T.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-C30gRcSS.js → responsiveObserve-TeSEGQ5-.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CvtKiMfV.js → slide-D_t_P0bv.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DNHO7ITG.js → statusUtils-DrrIMwAT.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-Dt_Sl-g4.js → styleChecker-BjZCuFRm.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-Cjev42Gh.js → useFlexGapSupport-rTFdlqdQ.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-Baxglj2V.js → useFs-BidCpfLX.js} +1 -1
- package/src/assets/web-panel/assets/usePersonalDataHub-C5mHttA9.js +1 -0
- package/src/assets/web-panel/assets/{vnode-mIRkdT7o.js → vnode-BrbcRiHZ.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-HzI5DlH_.js → zoom-PISX7AkR.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/__tests__/hub-wechat.test.js +45 -0
- package/src/commands/agenda.js +22 -6
- package/src/commands/agent.js +3 -3
- package/src/commands/background-session.js +16 -6
- package/src/commands/batch.js +79 -27
- package/src/commands/changelog.js +15 -4
- package/src/commands/context.js +33 -1
- package/src/commands/eval.js +21 -6
- package/src/commands/hook.js +2 -2
- package/src/commands/hub.js +473 -39
- package/src/commands/init.js +212 -110
- package/src/commands/llm.js +22 -6
- package/src/commands/loop.js +9 -2
- package/src/commands/skill.js +13 -1
- package/src/commands/statusline.js +3 -3
- package/src/data/changelog.json +53 -5
- package/src/gateways/ws/personal-data-hub-protocol.js +22 -2
- package/src/harness/background-task-manager.js +18 -6
- package/src/harness/background-task-worker.js +11 -18
- package/src/harness/golden-transcript.js +3 -0
- package/src/harness/mcp-client.js +9 -15
- package/src/harness/worktree-isolator.js +18 -21
- package/src/index.js +18 -7
- package/src/lib/agent-core.js +5 -0
- package/src/lib/agent-ipc-bus.js +12 -3
- package/src/lib/agent-team/team-worktree.js +28 -6
- package/src/lib/agent-worktree.js +20 -19
- package/src/lib/approval-authority-store.js +891 -0
- package/src/lib/async-hook-supervisor.cjs +134 -24
- package/src/lib/async-hook-supervisor.js +47 -0
- package/src/lib/background-agent-supervisor.js +35 -12
- package/src/lib/background-interaction-resolver.js +399 -54
- package/src/lib/background-session-transport.js +3 -1
- package/src/lib/background-task-manager.js +5 -1
- package/src/lib/changelog.js +57 -0
- package/src/lib/chrome-connector.js +6 -2
- package/src/lib/claude-code-bridge.js +24 -8
- package/src/lib/cli-anything-bridge.js +82 -25
- package/src/lib/context-breakdown.js +82 -3
- package/src/lib/doctor-checkup.js +18 -6
- package/src/lib/eval/tasks.js +25 -31
- package/src/lib/event-runtime-host.js +225 -0
- package/src/lib/event-runtime-store.js +102 -21
- package/src/lib/event-runtime-worker.js +70 -2
- package/src/lib/hook-runner.cjs +71 -36
- package/src/lib/hook-runner.js +55 -0
- package/src/lib/hooks-v2-producers.js +33 -8
- package/src/lib/hooks-v2-runtime.js +360 -40
- package/src/lib/host-adb-bridge.js +18 -3
- package/src/lib/interaction-adapter.js +66 -0
- package/src/lib/lsp/__tests__/benchmark.test.js +61 -0
- package/src/lib/lsp/__tests__/lsp-client.test.js +6 -1
- package/src/lib/lsp/benchmark.js +20 -4
- package/src/lib/lsp/lsp-client.js +6 -4
- package/src/lib/lsp/lsp-server-registry.js +0 -2
- package/src/lib/operation-fingerprint.js +107 -2
- package/src/lib/orchestrator.js +8 -2
- package/src/lib/packer/pack-update-applier.js +14 -2
- package/src/lib/packer/smoke-runner.js +18 -5
- package/src/lib/paths.js +1 -1
- package/src/lib/pdh-dedicated-batch-collectors.js +124 -0
- package/src/lib/personal-data-hub-wiring.js +327 -52
- package/src/lib/plugin-monitor-supervisor.js +20 -13
- package/src/lib/plugin-runtime/install.js +10 -3
- package/src/lib/process-execution-broker/credential-agent.js +954 -111
- package/src/lib/process-execution-broker/index.js +369 -85
- package/src/lib/process-execution-broker/platform-sandbox.js +320 -140
- package/src/lib/provider-http-error.js +94 -0
- package/src/lib/remote-approval-bridge.js +222 -26
- package/src/lib/repl-bang-memorize.js +10 -2
- package/src/lib/repl-goal.js +19 -2
- package/src/lib/settings-hook-events.cjs +13 -8
- package/src/lib/settings-hook-events.js +20 -0
- package/src/lib/side-effect-ledger-store.js +65 -14
- package/src/lib/skill-loader.js +215 -12
- package/src/lib/skill-packs/generator.js +18 -9
- package/src/lib/skill-process-broker.js +85 -0
- package/src/lib/slash-commands.js +10 -2
- package/src/lib/status-line.cjs +28 -7
- package/src/lib/status-line.js +33 -0
- package/src/lib/sub-agent-context.js +42 -0
- package/src/lib/turn-binding-store.js +64 -15
- package/src/lib/turn-binding.js +85 -16
- package/src/repl/agent-repl.js +88 -49
- package/src/repl/remote-approval.js +13 -13
- package/src/repl/repl-turn-binding.js +46 -16
- package/src/runtime/agent-core.js +419 -84
- package/src/runtime/coding-agent-contract-shared.cjs +16 -0
- package/src/runtime/headless-runner.js +172 -44
- package/src/runtime/headless-stream.js +221 -11
- package/src/runtime/session-slash-commands.js +506 -0
- package/src/skills/video-editing/extractors/audio-extractor.js +13 -5
- package/src/skills/video-editing/extractors/video-extractor.js +13 -3
- package/src/skills/video-editing/media-process.js +20 -0
- package/src/skills/video-editing/render/audio-mix.js +13 -3
- package/src/skills/video-editing/render/ffmpeg-concat.js +7 -2
- package/src/skills/video-editing/render/ffmpeg-extract.js +7 -2
- package/src/workers/background-agent-worker.js +76 -40
- package/src/assets/web-panel/assets/AppLayout-Duu8xR14.js +0 -9
- package/src/assets/web-panel/assets/Dashboard-CXrd5gAw.js +0 -3
- package/src/assets/web-panel/assets/MobileProjects-NZvvfDME.js +0 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-C48mu09U.js +0 -1
- package/src/assets/web-panel/assets/PersonalDataHub-AX3ypUDV.js +0 -9
- package/src/assets/web-panel/assets/Projects-Cc7FC9-e.js +0 -1
- package/src/assets/web-panel/assets/Terminal-CjTZPa37.js +0 -3
- package/src/assets/web-panel/assets/devWarning-BT46Y_QI.js +0 -1
- package/src/assets/web-panel/assets/index-B7nuIywP.js +0 -1
- package/src/assets/web-panel/assets/index-ycwAfC-i.js +0 -1
- package/src/assets/web-panel/assets/usePersonalDataHub-B4NkcLaP.js +0 -1
|
@@ -25,15 +25,17 @@ import fs from "node:fs/promises";
|
|
|
25
25
|
import path from "node:path";
|
|
26
26
|
import broker from "./process-execution-broker/index.js";
|
|
27
27
|
import { EventRuntimeStore } from "./event-runtime-store.js";
|
|
28
|
+
import { getDefaultEventRuntimeHost } from "./event-runtime-host.js";
|
|
28
29
|
|
|
29
30
|
const VALID_HOOK_EVENTS = new Set([
|
|
31
|
+
"Setup",
|
|
30
32
|
// Session
|
|
31
33
|
"PreToolUse", "PostToolUse", "Notification", "Stop", "SubagentStart", "SubagentStop",
|
|
32
|
-
"SessionResume", "SessionPause", "PostCompact",
|
|
34
|
+
"SessionResume", "SessionPause", "PostCompact", "StopFailure",
|
|
33
35
|
// Auth
|
|
34
36
|
"PreCommit", "PostCommit",
|
|
35
37
|
// Skill
|
|
36
|
-
"UserPromptSubmit", "SessionStart", "SessionEnd",
|
|
38
|
+
"UserPromptSubmit", "UserPromptExpansion", "SessionStart", "SessionEnd",
|
|
37
39
|
// Model
|
|
38
40
|
"PreCompact", "ModelSelection",
|
|
39
41
|
// Config
|
|
@@ -41,19 +43,178 @@ const VALID_HOOK_EVENTS = new Set([
|
|
|
41
43
|
// Timeline
|
|
42
44
|
"TimelineEntry",
|
|
43
45
|
// MCP
|
|
44
|
-
"McpRequest", "McpResponse", "MCPElicitation",
|
|
46
|
+
"McpRequest", "McpResponse", "MCPElicitation", "Elicitation", "ElicitationResult",
|
|
45
47
|
// Task / workspace lifecycle
|
|
46
48
|
"TaskCreated", "TaskCompleted", "InstructionsLoaded", "CwdChanged",
|
|
47
|
-
"WorktreeCreate", "WorktreeRemove",
|
|
49
|
+
"WorktreeCreate", "WorktreeRemove", "TeammateIdle",
|
|
50
|
+
// Tool aggregate / failure / filesystem lifecycle
|
|
51
|
+
"PostToolUseFailure", "PostToolBatch", "FileChanged",
|
|
48
52
|
]);
|
|
49
53
|
|
|
50
|
-
const VALID_EXECUTOR_TYPES = new Set([
|
|
54
|
+
const VALID_EXECUTOR_TYPES = new Set([
|
|
55
|
+
"command",
|
|
56
|
+
"http",
|
|
57
|
+
"mcp_tool",
|
|
58
|
+
"prompt",
|
|
59
|
+
"agent",
|
|
60
|
+
// Trusted programmatic compatibility executor. Config-loaded source text is
|
|
61
|
+
// not executed in-process.
|
|
62
|
+
"js",
|
|
63
|
+
]);
|
|
64
|
+
|
|
65
|
+
export const HOOK_EVENT_SCHEMA_VERSION = 1;
|
|
66
|
+
const DECISION_EVENTS = new Set([
|
|
67
|
+
"Setup",
|
|
68
|
+
"PreToolUse",
|
|
69
|
+
"UserPromptSubmit",
|
|
70
|
+
"UserPromptExpansion",
|
|
71
|
+
"PermissionRequest",
|
|
72
|
+
"ModelSelection",
|
|
73
|
+
"PreCompact",
|
|
74
|
+
]);
|
|
75
|
+
const CONTEXT_EVENTS = new Set([
|
|
76
|
+
"Setup",
|
|
77
|
+
"UserPromptSubmit",
|
|
78
|
+
"UserPromptExpansion",
|
|
79
|
+
"SessionStart",
|
|
80
|
+
"PostCompact",
|
|
81
|
+
]);
|
|
82
|
+
const DEFAULT_ALLOWED_EXECUTORS = Object.freeze([
|
|
83
|
+
"command",
|
|
84
|
+
"http",
|
|
85
|
+
"mcp_tool",
|
|
86
|
+
"prompt",
|
|
87
|
+
"agent",
|
|
88
|
+
"js",
|
|
89
|
+
]);
|
|
90
|
+
|
|
91
|
+
export const HOOK_EVENT_CONTRACTS = Object.freeze(
|
|
92
|
+
Object.fromEntries(
|
|
93
|
+
[...VALID_HOOK_EVENTS].map((event) => [
|
|
94
|
+
event,
|
|
95
|
+
Object.freeze({
|
|
96
|
+
schemaVersion: HOOK_EVENT_SCHEMA_VERSION,
|
|
97
|
+
event,
|
|
98
|
+
allowedExecutors: DEFAULT_ALLOWED_EXECUTORS,
|
|
99
|
+
decisionCapable: DECISION_EVENTS.has(event),
|
|
100
|
+
contextCapable: CONTEXT_EVENTS.has(event),
|
|
101
|
+
blockingSemantics: DECISION_EVENTS.has(event)
|
|
102
|
+
? "strictest:block>ask>allow>continue"
|
|
103
|
+
: "observe-only",
|
|
104
|
+
}),
|
|
105
|
+
]),
|
|
106
|
+
),
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
const SAFE_ENV_KEYS = Object.freeze([
|
|
110
|
+
"PATH",
|
|
111
|
+
"PATHEXT",
|
|
112
|
+
"SystemRoot",
|
|
113
|
+
"WINDIR",
|
|
114
|
+
"COMSPEC",
|
|
115
|
+
"TMP",
|
|
116
|
+
"TEMP",
|
|
117
|
+
"TMPDIR",
|
|
118
|
+
"LANG",
|
|
119
|
+
"LC_ALL",
|
|
120
|
+
"HOME",
|
|
121
|
+
"USERPROFILE",
|
|
122
|
+
]);
|
|
123
|
+
const DECISION_RANK = Object.freeze({
|
|
124
|
+
continue: 0,
|
|
125
|
+
allow: 1,
|
|
126
|
+
ask: 2,
|
|
127
|
+
block: 3,
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
function normalizeDecision(value) {
|
|
131
|
+
const decision = String(value || "continue").toLowerCase();
|
|
132
|
+
return Object.hasOwn(DECISION_RANK, decision) ? decision : "continue";
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function strictestDecision(results) {
|
|
136
|
+
let decision = "continue";
|
|
137
|
+
for (const record of results) {
|
|
138
|
+
const candidate = normalizeDecision(record?.decision);
|
|
139
|
+
if (DECISION_RANK[candidate] > DECISION_RANK[decision]) {
|
|
140
|
+
decision = candidate;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return decision;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function hostnameMatches(hostname, pattern) {
|
|
147
|
+
const host = String(hostname || "").toLowerCase();
|
|
148
|
+
const rule = String(pattern || "").trim().toLowerCase();
|
|
149
|
+
if (!host || !rule) return false;
|
|
150
|
+
if (rule.startsWith("*.")) {
|
|
151
|
+
const suffix = rule.slice(1);
|
|
152
|
+
return host.endsWith(suffix) && host.length > suffix.length;
|
|
153
|
+
}
|
|
154
|
+
return host === rule;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function buildHookEnvironment(hook, policy) {
|
|
158
|
+
const env = {};
|
|
159
|
+
for (const key of SAFE_ENV_KEYS) {
|
|
160
|
+
if (process.env[key] != null) env[key] = process.env[key];
|
|
161
|
+
}
|
|
162
|
+
const managed = new Set(
|
|
163
|
+
(policy.environmentAllowlist || []).map((key) => String(key)),
|
|
164
|
+
);
|
|
165
|
+
const requested = new Set(
|
|
166
|
+
(hook.environmentAllowlist || hook.envAllowlist || []).map((key) =>
|
|
167
|
+
String(key),
|
|
168
|
+
),
|
|
169
|
+
);
|
|
170
|
+
for (const key of requested) {
|
|
171
|
+
if (!managed.has(key) || process.env[key] == null) continue;
|
|
172
|
+
env[key] = process.env[key];
|
|
173
|
+
}
|
|
174
|
+
env.CC_HOOK_EVENT = hook.event;
|
|
175
|
+
env.CC_HOOK_SCHEMA_VERSION = String(HOOK_EVENT_SCHEMA_VERSION);
|
|
176
|
+
return env;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function hookBudget(hook) {
|
|
180
|
+
return Object.freeze({
|
|
181
|
+
maxTurns: Math.min(10, Math.max(1, Number(hook.maxTurns) || 1)),
|
|
182
|
+
maxTokens: Math.min(
|
|
183
|
+
32768,
|
|
184
|
+
Math.max(1, Number(hook.maxTokens || hook.tokenBudget) || 4096),
|
|
185
|
+
),
|
|
186
|
+
timeoutMs: Math.min(
|
|
187
|
+
10 * 60 * 1000,
|
|
188
|
+
Math.max(1, Number(hook.timeoutMs) || 30000),
|
|
189
|
+
),
|
|
190
|
+
});
|
|
191
|
+
}
|
|
51
192
|
|
|
52
193
|
class HooksV2Runtime extends EventEmitter {
|
|
53
194
|
constructor(configDir, options = {}) {
|
|
54
195
|
super();
|
|
55
196
|
this.configDir = configDir;
|
|
56
197
|
this.durableStore = options.durableStore || null;
|
|
198
|
+
this.durableOwner =
|
|
199
|
+
options.durableOwner ||
|
|
200
|
+
`hooks-inline:${process.pid}:${crypto.randomUUID()}`;
|
|
201
|
+
this.durableRecoveryBufferMs = Math.max(
|
|
202
|
+
1000,
|
|
203
|
+
Number(options.durableRecoveryBufferMs) || 5000,
|
|
204
|
+
);
|
|
205
|
+
this.executionBroker = options.broker || broker;
|
|
206
|
+
this.fetchImpl = options.fetch || globalThis.fetch;
|
|
207
|
+
this.executors = {
|
|
208
|
+
...(options.executors || {}),
|
|
209
|
+
...(options.mcpExecutor ? { mcp_tool: options.mcpExecutor } : {}),
|
|
210
|
+
...(options.promptExecutor ? { prompt: options.promptExecutor } : {}),
|
|
211
|
+
...(options.agentExecutor ? { agent: options.agentExecutor } : {}),
|
|
212
|
+
};
|
|
213
|
+
this.managedPolicy = {
|
|
214
|
+
httpAllowlist: [],
|
|
215
|
+
environmentAllowlist: [],
|
|
216
|
+
...(options.managedPolicy || {}),
|
|
217
|
+
};
|
|
57
218
|
this.hooks = new Map(); // eventName -> HookDefinition[]
|
|
58
219
|
this.executionLog = [];
|
|
59
220
|
this._loaded = false;
|
|
@@ -119,6 +280,12 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
119
280
|
registerHook(def) {
|
|
120
281
|
if (!VALID_HOOK_EVENTS.has(def.event)) throw new Error(`Invalid event: ${def.event}`);
|
|
121
282
|
if (!VALID_EXECUTOR_TYPES.has(def.type)) throw new Error(`Invalid executor type: ${def.type}`);
|
|
283
|
+
const contract = HOOK_EVENT_CONTRACTS[def.event];
|
|
284
|
+
if (!contract.allowedExecutors.includes(def.type)) {
|
|
285
|
+
throw new Error(
|
|
286
|
+
`Executor ${def.type} is not allowed for event ${def.event}`,
|
|
287
|
+
);
|
|
288
|
+
}
|
|
122
289
|
const id = def.id || crypto.randomUUID();
|
|
123
290
|
const full = { id, blocking: false, timeoutMs: 30000, ...def };
|
|
124
291
|
if (!this.hooks.has(def.event)) this.hooks.set(def.event, []);
|
|
@@ -149,12 +316,45 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
149
316
|
}
|
|
150
317
|
|
|
151
318
|
const hooks = this.hooks.get(eventName) || [];
|
|
152
|
-
|
|
319
|
+
// Reserve the durable record for the inline producer before executing any
|
|
320
|
+
// hook. A process-level EventRuntimeHost may observe the same store, but it
|
|
321
|
+
// cannot reclaim this record until the longest declared hook timeout plus
|
|
322
|
+
// a recovery buffer has elapsed. If this process dies, the expired lease
|
|
323
|
+
// becomes claimable and the host replays the event exactly once.
|
|
324
|
+
const longestHookTimeout = hooks.reduce(
|
|
325
|
+
(max, hook) => Math.max(max, Number(hook?.timeoutMs) || 30000),
|
|
326
|
+
0,
|
|
327
|
+
);
|
|
328
|
+
const durableRecord =
|
|
329
|
+
this.durableStore && options.skipDurable !== true
|
|
153
330
|
? this.durableStore.enqueueInbox(
|
|
154
|
-
{
|
|
155
|
-
|
|
331
|
+
{
|
|
332
|
+
runtime_type: "hooks.v2",
|
|
333
|
+
requiresHandler: true,
|
|
334
|
+
event: eventName,
|
|
335
|
+
context,
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
id: context.event_id || context.eventId || null,
|
|
339
|
+
claimOwner: this.durableOwner,
|
|
340
|
+
leaseMs: longestHookTimeout + this.durableRecoveryBufferMs,
|
|
341
|
+
},
|
|
156
342
|
)
|
|
157
343
|
: null;
|
|
344
|
+
if (durableRecord?.duplicate) {
|
|
345
|
+
if (durableRecord.status === "done" && durableRecord.result) {
|
|
346
|
+
return { ...durableRecord.result, duplicate: true };
|
|
347
|
+
}
|
|
348
|
+
return {
|
|
349
|
+
success: false,
|
|
350
|
+
results: [],
|
|
351
|
+
blocked: true,
|
|
352
|
+
blockingResult: null,
|
|
353
|
+
decision: "block",
|
|
354
|
+
duplicate: true,
|
|
355
|
+
pending: true,
|
|
356
|
+
};
|
|
357
|
+
}
|
|
158
358
|
// Hooks are parallel by default. De-duplicate by id so a reload or layered
|
|
159
359
|
// config cannot execute the same handler twice. `parallel:false` remains a
|
|
160
360
|
// deterministic compatibility mode for callers that require ordering.
|
|
@@ -179,6 +379,9 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
179
379
|
case "http":
|
|
180
380
|
result = await this._execHttp(hook, context);
|
|
181
381
|
break;
|
|
382
|
+
case "mcp_tool":
|
|
383
|
+
result = await this._execMcpTool(hook, context);
|
|
384
|
+
break;
|
|
182
385
|
case "prompt":
|
|
183
386
|
result = await this._execPrompt(hook, context);
|
|
184
387
|
break;
|
|
@@ -193,13 +396,18 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
193
396
|
record.durationMs = Date.now() - start;
|
|
194
397
|
record.status = "success";
|
|
195
398
|
record.result = result;
|
|
196
|
-
|
|
399
|
+
record.decision = normalizeDecision(result?.decision);
|
|
197
400
|
|
|
198
401
|
this.emit("hook:success", record);
|
|
199
402
|
} catch (err) {
|
|
200
403
|
record.durationMs = Date.now() - start;
|
|
201
404
|
record.status = "error";
|
|
202
405
|
record.error = err.message;
|
|
406
|
+
record.decision =
|
|
407
|
+
HOOK_EVENT_CONTRACTS[eventName].decisionCapable &&
|
|
408
|
+
hook.failureMode !== "ignore"
|
|
409
|
+
? "block"
|
|
410
|
+
: "continue";
|
|
203
411
|
this.emit("hook:error", record);
|
|
204
412
|
}
|
|
205
413
|
|
|
@@ -212,17 +420,42 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
212
420
|
if (options.parallel === false) {
|
|
213
421
|
for (const hook of uniqueHooks) results.push(await runOne(hook));
|
|
214
422
|
}
|
|
215
|
-
const
|
|
216
|
-
const
|
|
423
|
+
const contract = HOOK_EVENT_CONTRACTS[eventName];
|
|
424
|
+
const decision = contract.decisionCapable
|
|
425
|
+
? strictestDecision(results)
|
|
426
|
+
: "continue";
|
|
427
|
+
const blocking = results.filter((record) => record.decision === "block");
|
|
428
|
+
const blocked = decision === "block";
|
|
217
429
|
const blockingResult = blocking[0]?.result || null;
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
430
|
+
const outcome = {
|
|
431
|
+
success:
|
|
432
|
+
!blocked && results.every((record) => record.status !== "error"),
|
|
433
|
+
results,
|
|
434
|
+
blocked,
|
|
435
|
+
requiresApproval: decision === "ask",
|
|
436
|
+
decision,
|
|
437
|
+
blockingResult,
|
|
438
|
+
schemaVersion: HOOK_EVENT_SCHEMA_VERSION,
|
|
439
|
+
};
|
|
440
|
+
if (durableRecord) {
|
|
441
|
+
const settled = this.durableStore.acknowledgeInbox(
|
|
442
|
+
durableRecord.id,
|
|
443
|
+
outcome,
|
|
444
|
+
{
|
|
445
|
+
owner: durableRecord.lease?.owner,
|
|
446
|
+
fence: durableRecord.lease?.fence,
|
|
447
|
+
},
|
|
448
|
+
);
|
|
449
|
+
if (settled == null) {
|
|
450
|
+
return {
|
|
451
|
+
success: false,
|
|
452
|
+
results,
|
|
453
|
+
blocked: true,
|
|
454
|
+
blockingResult: null,
|
|
455
|
+
decision: "block",
|
|
456
|
+
leaseLost: true,
|
|
457
|
+
};
|
|
458
|
+
}
|
|
226
459
|
this.durableStore.enqueueOutbox(
|
|
227
460
|
{ event: eventName, outcome },
|
|
228
461
|
{ id: `${durableRecord.id}:result` },
|
|
@@ -237,19 +470,36 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
237
470
|
}
|
|
238
471
|
|
|
239
472
|
async _execCommand(hook, context) {
|
|
240
|
-
|
|
241
|
-
|
|
473
|
+
if (!hook.command || typeof hook.command !== "string") {
|
|
474
|
+
throw new Error("command hook requires a command");
|
|
475
|
+
}
|
|
476
|
+
const budget = hookBudget(hook);
|
|
477
|
+
const child = await this.executionBroker.spawn(
|
|
478
|
+
hook.command,
|
|
479
|
+
hook.args || [],
|
|
242
480
|
{
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
481
|
+
cwd: hook.cwd || this.configDir || process.cwd(),
|
|
482
|
+
env: buildHookEnvironment(hook, this.managedPolicy),
|
|
483
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
484
|
+
timeout: budget.timeoutMs,
|
|
485
|
+
shell: hook.shell === true,
|
|
486
|
+
origin: "hook",
|
|
487
|
+
scope: "hook",
|
|
488
|
+
policy: "allow",
|
|
489
|
+
hookName: hook.id,
|
|
246
490
|
},
|
|
247
|
-
{ origin: "hook", hookName: hook.id, timeout: hook.timeoutMs },
|
|
248
491
|
);
|
|
492
|
+
const payload = JSON.stringify({
|
|
493
|
+
schema_version: HOOK_EVENT_SCHEMA_VERSION,
|
|
494
|
+
hook_event_name: hook.event,
|
|
495
|
+
context,
|
|
496
|
+
});
|
|
497
|
+
child.stdin?.end(payload);
|
|
249
498
|
return new Promise((resolve, reject) => {
|
|
250
499
|
let stdout = "", stderr = "";
|
|
251
|
-
child.stdout
|
|
252
|
-
child.stderr
|
|
500
|
+
child.stdout?.on("data", d => stdout += d);
|
|
501
|
+
child.stderr?.on("data", d => stderr += d);
|
|
502
|
+
child.on("error", reject);
|
|
253
503
|
child.on("exit", (code) => {
|
|
254
504
|
if (code === 0) {
|
|
255
505
|
let parsed = {};
|
|
@@ -263,14 +513,36 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
263
513
|
}
|
|
264
514
|
|
|
265
515
|
async _execHttp(hook, context) {
|
|
266
|
-
|
|
516
|
+
if (typeof this.fetchImpl !== "function") {
|
|
517
|
+
throw new Error("HTTP hook executor is unavailable");
|
|
518
|
+
}
|
|
519
|
+
const target = new URL(hook.url);
|
|
520
|
+
const allowlist = this.managedPolicy.httpAllowlist || [];
|
|
521
|
+
if (
|
|
522
|
+
target.protocol !== "https:" ||
|
|
523
|
+
!allowlist.some((pattern) => hostnameMatches(target.hostname, pattern))
|
|
524
|
+
) {
|
|
525
|
+
const error = new Error(
|
|
526
|
+
`HTTP hook target is outside the managed HTTPS allowlist: ${target.hostname}`,
|
|
527
|
+
);
|
|
528
|
+
error.code = "CC_HOOK_HTTP_TARGET_DENIED";
|
|
529
|
+
throw error;
|
|
530
|
+
}
|
|
267
531
|
const method = hook.method || "POST";
|
|
268
532
|
const controller = new AbortController();
|
|
269
|
-
const timer = setTimeout(
|
|
533
|
+
const timer = setTimeout(
|
|
534
|
+
() => controller.abort(),
|
|
535
|
+
hookBudget(hook).timeoutMs,
|
|
536
|
+
);
|
|
537
|
+
const headers = { "Content-Type": "application/json" };
|
|
538
|
+
for (const [key, value] of Object.entries(hook.headers || {})) {
|
|
539
|
+
if (/^(authorization|cookie|proxy-authorization)$/i.test(key)) continue;
|
|
540
|
+
headers[key] = String(value);
|
|
541
|
+
}
|
|
270
542
|
try {
|
|
271
|
-
const res = await
|
|
543
|
+
const res = await this.fetchImpl(target, {
|
|
272
544
|
method,
|
|
273
|
-
headers
|
|
545
|
+
headers,
|
|
274
546
|
body: method !== "GET" ? JSON.stringify({ event: hook.event, context }) : undefined,
|
|
275
547
|
signal: controller.signal,
|
|
276
548
|
});
|
|
@@ -282,23 +554,58 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
282
554
|
}
|
|
283
555
|
|
|
284
556
|
async _execPrompt(hook, context) {
|
|
285
|
-
// Prompt template execution - returns expanded prompt for agent prepend
|
|
286
557
|
const vars = { ...context };
|
|
287
558
|
let expanded = hook.template || "";
|
|
288
559
|
expanded = expanded.replace(/\$\{(\w+)\}/g, (_, k) => vars[k] ?? "");
|
|
289
|
-
|
|
560
|
+
const executor = this.executors.prompt;
|
|
561
|
+
if (typeof executor !== "function") {
|
|
562
|
+
throw new Error("prompt hook executor is not configured");
|
|
563
|
+
}
|
|
564
|
+
return executor({
|
|
565
|
+
hook,
|
|
566
|
+
prompt: expanded,
|
|
567
|
+
context,
|
|
568
|
+
budget: hookBudget(hook),
|
|
569
|
+
});
|
|
290
570
|
}
|
|
291
571
|
|
|
292
572
|
async _execAgent(hook, context) {
|
|
293
|
-
|
|
294
|
-
|
|
573
|
+
const executor = this.executors.agent;
|
|
574
|
+
if (typeof executor !== "function") {
|
|
575
|
+
throw new Error("agent hook executor is not configured");
|
|
576
|
+
}
|
|
577
|
+
return executor({
|
|
578
|
+
hook,
|
|
579
|
+
agentName: hook.agentName || null,
|
|
580
|
+
skillName: hook.skillName || null,
|
|
581
|
+
context,
|
|
582
|
+
budget: hookBudget(hook),
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
async _execMcpTool(hook, context) {
|
|
587
|
+
const executor = this.executors.mcp_tool;
|
|
588
|
+
if (typeof executor !== "function") {
|
|
589
|
+
throw new Error("MCP hook executor is not configured");
|
|
590
|
+
}
|
|
591
|
+
if (!hook.server || !hook.tool) {
|
|
592
|
+
throw new Error("mcp_tool hook requires server and tool");
|
|
593
|
+
}
|
|
594
|
+
return executor({
|
|
595
|
+
server: hook.server,
|
|
596
|
+
tool: hook.tool,
|
|
597
|
+
arguments: hook.arguments || context,
|
|
598
|
+
context,
|
|
599
|
+
hook,
|
|
600
|
+
budget: hookBudget(hook),
|
|
601
|
+
});
|
|
295
602
|
}
|
|
296
603
|
|
|
297
604
|
async _execJs(hook, context) {
|
|
298
605
|
if (typeof hook.handler === "function") return hook.handler(context);
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
606
|
+
throw new Error(
|
|
607
|
+
"Config-loaded JavaScript is disabled; register a trusted function handler",
|
|
608
|
+
);
|
|
302
609
|
}
|
|
303
610
|
|
|
304
611
|
/** Get all registered hooks */
|
|
@@ -317,11 +624,24 @@ class HooksV2Runtime extends EventEmitter {
|
|
|
317
624
|
}
|
|
318
625
|
|
|
319
626
|
// Singleton instance
|
|
627
|
+
const defaultEventRuntimeHost =
|
|
628
|
+
process.env.CC_EVENT_RUNTIME_DURABLE === "1"
|
|
629
|
+
? getDefaultEventRuntimeHost()
|
|
630
|
+
: null;
|
|
320
631
|
const hooksRuntime = new HooksV2Runtime(undefined, {
|
|
321
632
|
durableStore:
|
|
322
|
-
|
|
633
|
+
defaultEventRuntimeHost?.store ||
|
|
634
|
+
(process.env.CC_EVENT_RUNTIME_DURABLE === "1"
|
|
323
635
|
? new EventRuntimeStore()
|
|
324
|
-
: null,
|
|
636
|
+
: null),
|
|
325
637
|
});
|
|
638
|
+
defaultEventRuntimeHost?.registerHandler(
|
|
639
|
+
(event) =>
|
|
640
|
+
hooksRuntime.executeHooks(event.event, event.context || {}, {
|
|
641
|
+
skipDurable: true,
|
|
642
|
+
recovered: true,
|
|
643
|
+
}),
|
|
644
|
+
{ queue: "inbox", type: "hooks.v2" },
|
|
645
|
+
);
|
|
326
646
|
export default hooksRuntime;
|
|
327
647
|
export { HooksV2Runtime, VALID_HOOK_EVENTS, VALID_EXECUTOR_TYPES };
|
|
@@ -31,10 +31,20 @@
|
|
|
31
31
|
* `\n` / EOS — every parse routine strips `\r+$` first.
|
|
32
32
|
*/
|
|
33
33
|
|
|
34
|
-
import
|
|
35
|
-
import { promisify } from "node:util";
|
|
34
|
+
import executionBroker from "./process-execution-broker/index.js";
|
|
36
35
|
|
|
37
|
-
const
|
|
36
|
+
export const _deps = {
|
|
37
|
+
execFile: (...args) => executionBroker.execFile(...args),
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
function execFileP(file, args, options) {
|
|
41
|
+
return new Promise((resolve, reject) => {
|
|
42
|
+
_deps.execFile(file, args, options, (error, stdout, stderr) => {
|
|
43
|
+
if (error) reject(error);
|
|
44
|
+
else resolve({ stdout, stderr });
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
}
|
|
38
48
|
|
|
39
49
|
export class HostAdbBridgeUnavailableError extends Error {
|
|
40
50
|
constructor(reason) {
|
|
@@ -52,6 +62,10 @@ async function adb(args, opts = {}) {
|
|
|
52
62
|
timeout: opts.timeoutMs || 30_000,
|
|
53
63
|
maxBuffer: 32 * 1024 * 1024,
|
|
54
64
|
encoding: "utf8",
|
|
65
|
+
origin: "host-adb:command",
|
|
66
|
+
policy: "allow",
|
|
67
|
+
scope: "host-adb",
|
|
68
|
+
shell: false,
|
|
55
69
|
});
|
|
56
70
|
if (stderr && /error:|failed:|protocol fault/i.test(stderr)) {
|
|
57
71
|
throw new HostAdbBridgeUnavailableError(stderr.trim().split("\n")[0]);
|
|
@@ -585,6 +599,7 @@ export function createHostAdbBridge(opts = {}) {
|
|
|
585
599
|
|
|
586
600
|
// Exposed for unit testing without spawning real adb.
|
|
587
601
|
export const _internals = {
|
|
602
|
+
adb,
|
|
588
603
|
parseContentQueryRows,
|
|
589
604
|
mergeContactRows,
|
|
590
605
|
listDevices,
|
|
@@ -179,6 +179,7 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
|
|
|
179
179
|
|
|
180
180
|
this._sendWs({
|
|
181
181
|
...message,
|
|
182
|
+
...(message.type === "question_request" ? { id: requestId } : {}),
|
|
182
183
|
sessionId: this.sessionId,
|
|
183
184
|
requestId,
|
|
184
185
|
// Ride the binding out so the remote UI/bridge can echo it back on the
|
|
@@ -238,6 +239,71 @@ export class WebSocketInteractionAdapter extends InteractionAdapter {
|
|
|
238
239
|
return answer === "true" || answer === "yes" || answer === "y";
|
|
239
240
|
}
|
|
240
241
|
|
|
242
|
+
/**
|
|
243
|
+
* Agent-core AskUserQuestion transport for Desktop/WebSocket consumers.
|
|
244
|
+
* It uses the same pending map and `session-answer` resolver as MCP
|
|
245
|
+
* elicitation, while exposing the stream protocol's `question_request`
|
|
246
|
+
* shape so capable UIs can render options natively.
|
|
247
|
+
*/
|
|
248
|
+
async askUser({
|
|
249
|
+
question,
|
|
250
|
+
options = null,
|
|
251
|
+
multiSelect = false,
|
|
252
|
+
timeoutMs,
|
|
253
|
+
defaultValue,
|
|
254
|
+
onTimeout,
|
|
255
|
+
onReject,
|
|
256
|
+
turnId,
|
|
257
|
+
toolUseId,
|
|
258
|
+
metadata = null,
|
|
259
|
+
} = {}) {
|
|
260
|
+
const normalizedTurnId =
|
|
261
|
+
turnId === undefined || turnId === null ? null : String(turnId);
|
|
262
|
+
const normalizedToolUseId =
|
|
263
|
+
toolUseId === undefined || toolUseId === null ? null : String(toolUseId);
|
|
264
|
+
const questionMetadata = {
|
|
265
|
+
...(metadata && typeof metadata === "object" ? metadata : {}),
|
|
266
|
+
kind: "ask_user_question",
|
|
267
|
+
...(normalizedTurnId
|
|
268
|
+
? { turnId: normalizedTurnId, turn_id: normalizedTurnId }
|
|
269
|
+
: {}),
|
|
270
|
+
...(normalizedToolUseId
|
|
271
|
+
? {
|
|
272
|
+
toolUseId: normalizedToolUseId,
|
|
273
|
+
tool_use_id: normalizedToolUseId,
|
|
274
|
+
}
|
|
275
|
+
: {}),
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
return this._request(
|
|
279
|
+
{
|
|
280
|
+
type: "question_request",
|
|
281
|
+
questionType: "ask_user_question",
|
|
282
|
+
question: typeof question === "string" ? question : "",
|
|
283
|
+
options: Array.isArray(options) ? options : null,
|
|
284
|
+
multiSelect: multiSelect === true,
|
|
285
|
+
...(defaultValue !== undefined ? { defaultValue } : {}),
|
|
286
|
+
...(onTimeout ? { onTimeout } : {}),
|
|
287
|
+
...(onReject ? { onReject } : {}),
|
|
288
|
+
...(Number(timeoutMs) > 0 ? { timeoutMs: Number(timeoutMs) } : {}),
|
|
289
|
+
...(normalizedTurnId
|
|
290
|
+
? { turnId: normalizedTurnId, turn_id: normalizedTurnId }
|
|
291
|
+
: {}),
|
|
292
|
+
...(normalizedToolUseId
|
|
293
|
+
? {
|
|
294
|
+
toolUseId: normalizedToolUseId,
|
|
295
|
+
tool_use_id: normalizedToolUseId,
|
|
296
|
+
}
|
|
297
|
+
: {}),
|
|
298
|
+
metadata: questionMetadata,
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
kind: "question",
|
|
302
|
+
...(Number(timeoutMs) > 0 ? { timeoutMs: Number(timeoutMs) } : {}),
|
|
303
|
+
},
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
|
|
241
307
|
/**
|
|
242
308
|
* Called by ws-server when a session-answer message arrives.
|
|
243
309
|
* Resolves the corresponding pending promise.
|