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
|
@@ -8,13 +8,27 @@
|
|
|
8
8
|
* that the existing 4-layer skill-loader picks up automatically.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { execSync } from "child_process";
|
|
12
11
|
import fs from "fs";
|
|
13
12
|
import path from "path";
|
|
14
13
|
import { getElectronUserDataDir } from "./paths.js";
|
|
14
|
+
import executionBroker from "./process-execution-broker/index.js";
|
|
15
15
|
|
|
16
16
|
/* ---------- _deps injection (Vitest CJS mock pattern) ---------- */
|
|
17
|
-
export const _deps = {
|
|
17
|
+
export const _deps = {
|
|
18
|
+
execFileSync: executionBroker.execFileSync.bind(executionBroker),
|
|
19
|
+
fs,
|
|
20
|
+
path,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
function execCliAnything(file, args, options, origin) {
|
|
24
|
+
return _deps.execFileSync(file, args, {
|
|
25
|
+
...options,
|
|
26
|
+
origin,
|
|
27
|
+
policy: "allow",
|
|
28
|
+
scope: "cli-anything",
|
|
29
|
+
shell: false,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
18
32
|
|
|
19
33
|
/* ----------------------------------------------------------------
|
|
20
34
|
* Database helpers
|
|
@@ -55,13 +69,16 @@ export function detectPython() {
|
|
|
55
69
|
|
|
56
70
|
for (const cmd of candidates) {
|
|
57
71
|
try {
|
|
58
|
-
const ver =
|
|
59
|
-
|
|
72
|
+
const ver = execCliAnything(
|
|
73
|
+
cmd,
|
|
74
|
+
["--version"],
|
|
75
|
+
{
|
|
60
76
|
encoding: "utf-8",
|
|
61
77
|
timeout: 10000,
|
|
62
78
|
stdio: ["pipe", "pipe", "pipe"],
|
|
63
|
-
}
|
|
64
|
-
|
|
79
|
+
},
|
|
80
|
+
"cli-anything:detect-python",
|
|
81
|
+
).trim();
|
|
65
82
|
const match = ver.match(/Python\s+([\d.]+)/i);
|
|
66
83
|
if (match) {
|
|
67
84
|
return { found: true, command: cmd, version: match[1] };
|
|
@@ -82,11 +99,16 @@ export function detectCliAnything() {
|
|
|
82
99
|
if (!py.found) return { installed: false };
|
|
83
100
|
|
|
84
101
|
try {
|
|
85
|
-
const out =
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
102
|
+
const out = execCliAnything(
|
|
103
|
+
py.command,
|
|
104
|
+
["-m", "pip", "show", "cli-anything"],
|
|
105
|
+
{
|
|
106
|
+
encoding: "utf-8",
|
|
107
|
+
timeout: 15000,
|
|
108
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
109
|
+
},
|
|
110
|
+
"cli-anything:detect-package",
|
|
111
|
+
);
|
|
90
112
|
const verMatch = out.match(/Version:\s*([\d.]+)/i);
|
|
91
113
|
return {
|
|
92
114
|
installed: true,
|
|
@@ -102,11 +124,16 @@ export function detectCliAnything() {
|
|
|
102
124
|
* Install CLI-Anything via pip.
|
|
103
125
|
*/
|
|
104
126
|
export function installCliAnything(pythonCmd) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
127
|
+
execCliAnything(
|
|
128
|
+
pythonCmd,
|
|
129
|
+
["-m", "pip", "install", "cli-anything"],
|
|
130
|
+
{
|
|
131
|
+
encoding: "utf-8",
|
|
132
|
+
timeout: 120000,
|
|
133
|
+
stdio: "inherit",
|
|
134
|
+
},
|
|
135
|
+
"cli-anything:install",
|
|
136
|
+
);
|
|
110
137
|
}
|
|
111
138
|
|
|
112
139
|
/* ----------------------------------------------------------------
|
|
@@ -152,11 +179,16 @@ export function scanPathForTools() {
|
|
|
152
179
|
export function parseToolHelp(command) {
|
|
153
180
|
let helpText;
|
|
154
181
|
try {
|
|
155
|
-
helpText =
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
182
|
+
helpText = execCliAnything(
|
|
183
|
+
command,
|
|
184
|
+
["--help"],
|
|
185
|
+
{
|
|
186
|
+
encoding: "utf-8",
|
|
187
|
+
timeout: 15000,
|
|
188
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
189
|
+
},
|
|
190
|
+
"cli-anything:tool-help",
|
|
191
|
+
);
|
|
160
192
|
} catch (err) {
|
|
161
193
|
const raw = err.stdout || err.stderr || "";
|
|
162
194
|
helpText = typeof raw === "string" ? raw : raw.toString("utf-8");
|
|
@@ -252,19 +284,44 @@ Pass the subcommand and arguments as plain text input:
|
|
|
252
284
|
*/
|
|
253
285
|
export function _generateHandlerJs(name, command) {
|
|
254
286
|
return `"use strict";
|
|
255
|
-
const
|
|
287
|
+
const CLI_COMMAND = ${JSON.stringify(command)};
|
|
288
|
+
|
|
289
|
+
function parseArgs(input) {
|
|
290
|
+
const args = [];
|
|
291
|
+
let current = "";
|
|
292
|
+
let inSingle = false;
|
|
293
|
+
let inDouble = false;
|
|
294
|
+
for (const ch of input.trim()) {
|
|
295
|
+
if (ch === "'" && !inDouble) { inSingle = !inSingle; continue; }
|
|
296
|
+
if (ch === '"' && !inSingle) { inDouble = !inDouble; continue; }
|
|
297
|
+
if (/\\s/.test(ch) && !inSingle && !inDouble) {
|
|
298
|
+
if (current) { args.push(current); current = ""; }
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
current += ch;
|
|
302
|
+
}
|
|
303
|
+
if (inSingle || inDouble) return null;
|
|
304
|
+
if (current) args.push(current);
|
|
305
|
+
return args;
|
|
306
|
+
}
|
|
256
307
|
|
|
257
308
|
module.exports = {
|
|
258
309
|
async execute(task, context) {
|
|
259
310
|
const input = (task?.params?.input || task?.action || "").trim();
|
|
260
311
|
if (!input) return { success: false, error: "No input provided" };
|
|
261
|
-
//
|
|
262
|
-
//
|
|
312
|
+
// Keep the historical shell-character guard for generated-handler
|
|
313
|
+
// compatibility even though the Broker now receives literal argv.
|
|
263
314
|
if (/[;&|\`$<>()\\n\\r]/.test(input)) {
|
|
264
315
|
return { success: false, error: "Input contains unsafe shell characters; refused." };
|
|
265
316
|
}
|
|
317
|
+
const args = parseArgs(input);
|
|
318
|
+
if (!args) return { success: false, error: "Input contains an unmatched quote; refused." };
|
|
319
|
+
const processBroker = context?.processBroker;
|
|
320
|
+
if (!processBroker || typeof processBroker.runFileSync !== "function") {
|
|
321
|
+
return { success: false, error: "Process Broker unavailable for skill execution." };
|
|
322
|
+
}
|
|
266
323
|
try {
|
|
267
|
-
const output =
|
|
324
|
+
const output = processBroker.runFileSync(CLI_COMMAND, args, {
|
|
268
325
|
encoding: "utf-8",
|
|
269
326
|
timeout: 60000,
|
|
270
327
|
cwd: context?.projectRoot || process.cwd(),
|
|
@@ -84,14 +84,93 @@ export function breakdownSkillSources(skills, estimateTokens) {
|
|
|
84
84
|
.map((skill) => ({
|
|
85
85
|
source: skill?.source || "skill",
|
|
86
86
|
skill: String(skill?.id || skill?.displayName || "skill"),
|
|
87
|
-
tokens:
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
tokens: Number.isFinite(skill?.tokens)
|
|
88
|
+
? Math.max(0, skill.tokens)
|
|
89
|
+
: est(
|
|
90
|
+
`## Persona: ${skill?.displayName || skill?.id || "skill"}\n${skill?.body || ""}`,
|
|
91
|
+
),
|
|
90
92
|
}))
|
|
91
93
|
.filter((row) => row.tokens > 0);
|
|
92
94
|
return { sources, total: sources.reduce((sum, row) => sum + row.tokens, 0) };
|
|
93
95
|
}
|
|
94
96
|
|
|
97
|
+
/** Normalize the content-free two-tier Skill cache snapshot. */
|
|
98
|
+
export function breakdownSkillCache(cache) {
|
|
99
|
+
const descriptors = cache?.descriptors || {};
|
|
100
|
+
const bodies = cache?.bodies || {};
|
|
101
|
+
const savings = cache?.savings || {};
|
|
102
|
+
return {
|
|
103
|
+
descriptors: {
|
|
104
|
+
resident: Number(descriptors.resident) || 0,
|
|
105
|
+
scans: Number(descriptors.scans) || 0,
|
|
106
|
+
cacheHits: Number(descriptors.cacheHits) || 0,
|
|
107
|
+
estimatedTokens: Number(descriptors.estimatedTokens) || 0,
|
|
108
|
+
},
|
|
109
|
+
bodies: {
|
|
110
|
+
resident: Number(bodies.resident) || 0,
|
|
111
|
+
cacheHits: Number(bodies.cacheHits) || 0,
|
|
112
|
+
cacheMisses: Number(bodies.cacheMisses) || 0,
|
|
113
|
+
entries: Array.isArray(bodies.entries)
|
|
114
|
+
? bodies.entries.map((entry) => ({
|
|
115
|
+
id: String(entry?.id || "skill"),
|
|
116
|
+
source: String(entry?.source || "skill"),
|
|
117
|
+
estimatedTokens: Number(entry?.estimatedTokens) || 0,
|
|
118
|
+
loads: Number(entry?.loads) || 0,
|
|
119
|
+
cacheHits: Number(entry?.cacheHits) || 0,
|
|
120
|
+
loadedBecause: Array.isArray(entry?.loadedBecause)
|
|
121
|
+
? entry.loadedBecause.map(String)
|
|
122
|
+
: [],
|
|
123
|
+
}))
|
|
124
|
+
: [],
|
|
125
|
+
},
|
|
126
|
+
savings: {
|
|
127
|
+
lazyFileBytes: Number(savings.lazyFileBytes) || 0,
|
|
128
|
+
estimatedTokensAvoided: Number(savings.estimatedTokensAvoided) || 0,
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Actionable, content-free suggestions derived from the measured sources. */
|
|
134
|
+
export function buildContextOptimizations({
|
|
135
|
+
instructions = [],
|
|
136
|
+
mcpSchemas = [],
|
|
137
|
+
skillCache = null,
|
|
138
|
+
} = {}) {
|
|
139
|
+
const suggestions = [];
|
|
140
|
+
if (skillCache?.savings?.estimatedTokensAvoided > 0) {
|
|
141
|
+
suggestions.push({
|
|
142
|
+
kind: "skill_lazy_loading",
|
|
143
|
+
estimatedTokens: skillCache.savings.estimatedTokensAvoided,
|
|
144
|
+
message:
|
|
145
|
+
`${skillCache.descriptors.resident} Skill descriptors stayed discoverable while ` +
|
|
146
|
+
`${skillCache.savings.estimatedTokensAvoided} estimated body tokens remained lazy.`,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
const largestMcp = [...(mcpSchemas || [])].sort(
|
|
150
|
+
(a, b) => (b.tokens || 0) - (a.tokens || 0),
|
|
151
|
+
)[0];
|
|
152
|
+
if (largestMcp?.tokens > 0) {
|
|
153
|
+
suggestions.push({
|
|
154
|
+
kind: "mcp_tool_search",
|
|
155
|
+
estimatedTokens: largestMcp.tokens,
|
|
156
|
+
source: largestMcp.tool || largestMcp.source,
|
|
157
|
+
message: `Consider Tool Search or a narrower MCP allow-list for ${largestMcp.tool || largestMcp.source}.`,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
const largestInstruction = [...(instructions || [])].sort(
|
|
161
|
+
(a, b) => (b.tokens || 0) - (a.tokens || 0),
|
|
162
|
+
)[0];
|
|
163
|
+
if (largestInstruction?.tokens > 0) {
|
|
164
|
+
suggestions.push({
|
|
165
|
+
kind: "instruction_scope",
|
|
166
|
+
estimatedTokens: largestInstruction.tokens,
|
|
167
|
+
source: largestInstruction.source,
|
|
168
|
+
message: `Scope or split ${largestInstruction.source} if it is not needed for every turn.`,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
return suggestions.slice(0, 5);
|
|
172
|
+
}
|
|
173
|
+
|
|
95
174
|
// role bucket key → { label, kind } for the ranked source list.
|
|
96
175
|
const MESSAGE_SOURCE_ROWS = [
|
|
97
176
|
["system", "system messages", "message"],
|
|
@@ -23,9 +23,9 @@ import {
|
|
|
23
23
|
statSync,
|
|
24
24
|
rmSync,
|
|
25
25
|
} from "node:fs";
|
|
26
|
-
import { execSync, spawnSync } from "node:child_process";
|
|
27
26
|
import { join, basename } from "node:path";
|
|
28
27
|
import { getHomeDir, getConfigPath } from "./paths.js";
|
|
28
|
+
import executionBroker from "./process-execution-broker/index.js";
|
|
29
29
|
import {
|
|
30
30
|
languageIdForFile,
|
|
31
31
|
resolveServer,
|
|
@@ -59,8 +59,8 @@ export const _deps = {
|
|
|
59
59
|
readFileSync,
|
|
60
60
|
statSync,
|
|
61
61
|
rmSync,
|
|
62
|
-
|
|
63
|
-
spawnSync,
|
|
62
|
+
execFileSync: (...args) => executionBroker.execFileSync(...args),
|
|
63
|
+
spawnSync: (...args) => executionBroker.spawnSync(...args),
|
|
64
64
|
now: () => Date.now(),
|
|
65
65
|
};
|
|
66
66
|
|
|
@@ -549,10 +549,14 @@ async function worktreeSection(opts, deps) {
|
|
|
549
549
|
try {
|
|
550
550
|
const inRepo = (() => {
|
|
551
551
|
try {
|
|
552
|
-
deps.
|
|
552
|
+
deps.execFileSync("git", ["rev-parse", "--is-inside-work-tree"], {
|
|
553
553
|
cwd,
|
|
554
554
|
encoding: "utf-8",
|
|
555
555
|
stdio: ["ignore", "pipe", "ignore"],
|
|
556
|
+
origin: "doctor:git-worktree",
|
|
557
|
+
policy: "allow",
|
|
558
|
+
scope: "diagnostics",
|
|
559
|
+
shell: false,
|
|
556
560
|
});
|
|
557
561
|
return true;
|
|
558
562
|
} catch {
|
|
@@ -570,10 +574,14 @@ async function worktreeSection(opts, deps) {
|
|
|
570
574
|
);
|
|
571
575
|
} else {
|
|
572
576
|
const out =
|
|
573
|
-
deps.
|
|
577
|
+
deps.execFileSync("git", ["worktree", "prune", "--dry-run", "-v"], {
|
|
574
578
|
cwd,
|
|
575
579
|
encoding: "utf-8",
|
|
576
580
|
stdio: ["ignore", "pipe", "ignore"],
|
|
581
|
+
origin: "doctor:git-worktree",
|
|
582
|
+
policy: "allow",
|
|
583
|
+
scope: "diagnostics",
|
|
584
|
+
shell: false,
|
|
577
585
|
}) || "";
|
|
578
586
|
const prunable = out.split("\n").filter((l) => l.trim()).length;
|
|
579
587
|
if (prunable > 0) {
|
|
@@ -1138,10 +1146,14 @@ export async function runCheckupFixes(sections, opts = {}) {
|
|
|
1138
1146
|
detail: `removed ${removed} file(s)`,
|
|
1139
1147
|
});
|
|
1140
1148
|
} else if (fix.id === "git-worktree-prune") {
|
|
1141
|
-
deps.
|
|
1149
|
+
deps.execFileSync("git", ["worktree", "prune"], {
|
|
1142
1150
|
cwd: opts.cwd || process.cwd(),
|
|
1143
1151
|
encoding: "utf-8",
|
|
1144
1152
|
stdio: ["ignore", "pipe", "ignore"],
|
|
1153
|
+
origin: "doctor:git-worktree-fix",
|
|
1154
|
+
policy: "allow",
|
|
1155
|
+
scope: "diagnostics",
|
|
1156
|
+
shell: false,
|
|
1145
1157
|
});
|
|
1146
1158
|
results.push({
|
|
1147
1159
|
id: fix.id,
|
package/src/lib/eval/tasks.js
CHANGED
|
@@ -11,7 +11,24 @@
|
|
|
11
11
|
|
|
12
12
|
import fs from "fs";
|
|
13
13
|
import path from "path";
|
|
14
|
-
import
|
|
14
|
+
import executionBroker from "../process-execution-broker/index.js";
|
|
15
|
+
|
|
16
|
+
export const _deps = {
|
|
17
|
+
execFileSync: (...args) => executionBroker.execFileSync(...args),
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function runTaskCheck(dir, script, options = {}) {
|
|
21
|
+
return _deps.execFileSync(process.execPath, [script], {
|
|
22
|
+
cwd: dir,
|
|
23
|
+
timeout: 10000,
|
|
24
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
25
|
+
...options,
|
|
26
|
+
origin: "eval:task-check",
|
|
27
|
+
policy: "allow",
|
|
28
|
+
scope: "eval",
|
|
29
|
+
shell: false,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
15
32
|
|
|
16
33
|
function read(dir, rel) {
|
|
17
34
|
try {
|
|
@@ -97,11 +114,8 @@ export const BUILTIN_TASKS = [
|
|
|
97
114
|
// Objective check: it must parse AND print OK. Re-run in a child so we
|
|
98
115
|
// score the actual behavior, not a heuristic on the source.
|
|
99
116
|
try {
|
|
100
|
-
const out =
|
|
101
|
-
cwd: dir,
|
|
117
|
+
const out = runTaskCheck(dir, "bug.js", {
|
|
102
118
|
encoding: "utf8",
|
|
103
|
-
timeout: 10000,
|
|
104
|
-
stdio: ["ignore", "pipe", "pipe"], // capture stderr, don't inherit
|
|
105
119
|
});
|
|
106
120
|
return out.trim() === "OK"
|
|
107
121
|
? { pass: true, detail: "node bug.js prints OK" }
|
|
@@ -186,11 +200,8 @@ export const BUILTIN_TASKS = [
|
|
|
186
200
|
};
|
|
187
201
|
}
|
|
188
202
|
try {
|
|
189
|
-
const out =
|
|
190
|
-
cwd: dir,
|
|
203
|
+
const out = runTaskCheck(dir, "run-checks.mjs", {
|
|
191
204
|
encoding: "utf8",
|
|
192
|
-
timeout: 10000,
|
|
193
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
194
205
|
});
|
|
195
206
|
return out.includes("ALL OK")
|
|
196
207
|
? { pass: true, detail: "test suite passes" }
|
|
@@ -243,11 +254,8 @@ export const BUILTIN_TASKS = [
|
|
|
243
254
|
}
|
|
244
255
|
// Behavior must be preserved: run main.js and check the output.
|
|
245
256
|
try {
|
|
246
|
-
const out =
|
|
247
|
-
cwd: dir,
|
|
257
|
+
const out = runTaskCheck(dir, "main.js", {
|
|
248
258
|
encoding: "utf8",
|
|
249
|
-
timeout: 10000,
|
|
250
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
251
259
|
});
|
|
252
260
|
return out.trim() === "6"
|
|
253
261
|
? { pass: true, detail: "renamed + behavior preserved" }
|
|
@@ -290,12 +298,7 @@ export const BUILTIN_TASKS = [
|
|
|
290
298
|
if (read(dir, "verify.mjs") == null) {
|
|
291
299
|
return { pass: false, detail: "verify.mjs not created" };
|
|
292
300
|
}
|
|
293
|
-
const run = () =>
|
|
294
|
-
execFileSync(process.execPath, ["verify.mjs"], {
|
|
295
|
-
cwd: dir,
|
|
296
|
-
timeout: 10000,
|
|
297
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
298
|
-
});
|
|
301
|
+
const run = () => runTaskCheck(dir, "verify.mjs");
|
|
299
302
|
// 1) The verifier must PASS against the correct implementation.
|
|
300
303
|
try {
|
|
301
304
|
run();
|
|
@@ -383,11 +386,8 @@ export const BUILTIN_TASKS = [
|
|
|
383
386
|
};
|
|
384
387
|
}
|
|
385
388
|
try {
|
|
386
|
-
const out =
|
|
387
|
-
cwd: dir,
|
|
389
|
+
const out = runTaskCheck(dir, "app.mjs", {
|
|
388
390
|
encoding: "utf8",
|
|
389
|
-
timeout: 10000,
|
|
390
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
391
391
|
}).trim();
|
|
392
392
|
return out === "Hello, Ada!\nHello, Bob!!!"
|
|
393
393
|
? { pass: true, detail: "signature migrated + callers updated" }
|
|
@@ -525,11 +525,8 @@ export const BUILTIN_TASKS = [
|
|
|
525
525
|
};
|
|
526
526
|
}
|
|
527
527
|
try {
|
|
528
|
-
const out =
|
|
529
|
-
cwd: dir,
|
|
528
|
+
const out = runTaskCheck(dir, "build.mjs", {
|
|
530
529
|
encoding: "utf8",
|
|
531
|
-
timeout: 10000,
|
|
532
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
533
530
|
});
|
|
534
531
|
return out.includes("BUILD OK")
|
|
535
532
|
? { pass: true, detail: "build links + passes" }
|
|
@@ -620,11 +617,8 @@ export const BUILTIN_TASKS = [
|
|
|
620
617
|
return { pass: false, detail: "app.mjs does not use the new toTitle" };
|
|
621
618
|
}
|
|
622
619
|
try {
|
|
623
|
-
const out =
|
|
624
|
-
cwd: dir,
|
|
620
|
+
const out = runTaskCheck(dir, "run.mjs", {
|
|
625
621
|
encoding: "utf8",
|
|
626
|
-
timeout: 10000,
|
|
627
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
628
622
|
});
|
|
629
623
|
return out.trim() === "OK"
|
|
630
624
|
? { pass: true, detail: "adapted to new API + manifest bumped" }
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process-level lifecycle owner for the durable Event Runtime.
|
|
3
|
+
*
|
|
4
|
+
* Producers only append records. This host owns the single non-overlapping
|
|
5
|
+
* drain loop, dispatches records to registered handlers, and exposes a
|
|
6
|
+
* stoppable lifecycle shared by short CLI commands and resident daemons.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { EventEmitter } from "node:events";
|
|
10
|
+
import { EventRuntimeStore } from "./event-runtime-store.js";
|
|
11
|
+
import { EventRuntimeWorker } from "./event-runtime-worker.js";
|
|
12
|
+
|
|
13
|
+
function routeType(event) {
|
|
14
|
+
return String(
|
|
15
|
+
event?.runtime_type ||
|
|
16
|
+
event?.runtimeType ||
|
|
17
|
+
event?.event ||
|
|
18
|
+
event?.type ||
|
|
19
|
+
"*",
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function routeOrigin(event) {
|
|
24
|
+
return String(event?.origin || "*");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function routeKey(queue, type = "*", origin = "*") {
|
|
28
|
+
return `${queue}:${String(type || "*")}:${String(origin || "*")}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export class EventRuntimeHost extends EventEmitter {
|
|
32
|
+
constructor({
|
|
33
|
+
store = new EventRuntimeStore(),
|
|
34
|
+
intervalMs = 1000,
|
|
35
|
+
worker = null,
|
|
36
|
+
setTimeoutFn = setTimeout,
|
|
37
|
+
clearTimeoutFn = clearTimeout,
|
|
38
|
+
} = {}) {
|
|
39
|
+
super();
|
|
40
|
+
this.store = store;
|
|
41
|
+
this.intervalMs = Math.max(1, Number(intervalMs) || 1000);
|
|
42
|
+
this.setTimeoutFn = setTimeoutFn;
|
|
43
|
+
this.clearTimeoutFn = clearTimeoutFn;
|
|
44
|
+
this.handlers = new Map();
|
|
45
|
+
this.running = false;
|
|
46
|
+
this.timer = null;
|
|
47
|
+
this.inFlight = null;
|
|
48
|
+
this.lastStats = null;
|
|
49
|
+
this.lastError = null;
|
|
50
|
+
this.worker =
|
|
51
|
+
worker ||
|
|
52
|
+
new EventRuntimeWorker({
|
|
53
|
+
store,
|
|
54
|
+
onInbox: (event, record) =>
|
|
55
|
+
this._dispatch("inbox", event, record),
|
|
56
|
+
onOutbox: (event, record) =>
|
|
57
|
+
this._dispatch("outbox", event, record),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
registerHandler(
|
|
62
|
+
handler,
|
|
63
|
+
{ queue = "inbox", type = "*", origin = "*" } = {},
|
|
64
|
+
) {
|
|
65
|
+
if (typeof handler !== "function") {
|
|
66
|
+
throw new TypeError("Event Runtime handler must be a function");
|
|
67
|
+
}
|
|
68
|
+
if (queue !== "inbox" && queue !== "outbox") {
|
|
69
|
+
throw new Error(`unsupported event queue: ${queue}`);
|
|
70
|
+
}
|
|
71
|
+
const key = routeKey(queue, type, origin);
|
|
72
|
+
const handlers = this.handlers.get(key) || new Set();
|
|
73
|
+
handlers.add(handler);
|
|
74
|
+
this.handlers.set(key, handlers);
|
|
75
|
+
return () => {
|
|
76
|
+
handlers.delete(handler);
|
|
77
|
+
if (handlers.size === 0) this.handlers.delete(key);
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async _dispatch(queue, event, record) {
|
|
82
|
+
const type = routeType(event);
|
|
83
|
+
const origin = routeOrigin(event);
|
|
84
|
+
const candidates = [
|
|
85
|
+
routeKey(queue, type, origin),
|
|
86
|
+
routeKey(queue, type, "*"),
|
|
87
|
+
routeKey(queue, "*", origin),
|
|
88
|
+
routeKey(queue, "*", "*"),
|
|
89
|
+
];
|
|
90
|
+
const handlers = [];
|
|
91
|
+
const seen = new Set();
|
|
92
|
+
for (const key of candidates) {
|
|
93
|
+
for (const handler of this.handlers.get(key) || []) {
|
|
94
|
+
if (seen.has(handler)) continue;
|
|
95
|
+
seen.add(handler);
|
|
96
|
+
handlers.push(handler);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (handlers.length === 0 && event?.requiresHandler === true) {
|
|
100
|
+
const error = new Error(
|
|
101
|
+
`No Event Runtime handler for ${queue}:${type}:${origin}`,
|
|
102
|
+
);
|
|
103
|
+
error.code = "CC_EVENT_RUNTIME_HANDLER_UNAVAILABLE";
|
|
104
|
+
throw error;
|
|
105
|
+
}
|
|
106
|
+
const results = await Promise.all(
|
|
107
|
+
handlers.map((handler) => handler(event, record)),
|
|
108
|
+
);
|
|
109
|
+
const delivery = {
|
|
110
|
+
queue,
|
|
111
|
+
type,
|
|
112
|
+
origin,
|
|
113
|
+
handlerCount: handlers.length,
|
|
114
|
+
results,
|
|
115
|
+
};
|
|
116
|
+
this.emit("delivered", delivery, event, record);
|
|
117
|
+
this.emit(`${queue}:${type}`, event, record, delivery);
|
|
118
|
+
return delivery;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async runOnce() {
|
|
122
|
+
if (this.inFlight) return this.inFlight;
|
|
123
|
+
this.inFlight = Promise.resolve()
|
|
124
|
+
.then(() => this.worker.runOnce())
|
|
125
|
+
.then((stats) => {
|
|
126
|
+
this.lastStats = stats;
|
|
127
|
+
this.lastError = null;
|
|
128
|
+
this.emit("tick", stats);
|
|
129
|
+
return stats;
|
|
130
|
+
})
|
|
131
|
+
.catch((error) => {
|
|
132
|
+
this.lastError = error;
|
|
133
|
+
this.emit("runtime-error", error);
|
|
134
|
+
throw error;
|
|
135
|
+
})
|
|
136
|
+
.finally(() => {
|
|
137
|
+
this.inFlight = null;
|
|
138
|
+
});
|
|
139
|
+
return this.inFlight;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
_schedule() {
|
|
143
|
+
if (!this.running || this.timer != null) return;
|
|
144
|
+
this.timer = this.setTimeoutFn(async () => {
|
|
145
|
+
this.timer = null;
|
|
146
|
+
try {
|
|
147
|
+
await this.runOnce();
|
|
148
|
+
} catch {
|
|
149
|
+
// The durable records remain pending/retriable. The host keeps running
|
|
150
|
+
// so a transient lock or filesystem failure does not kill the daemon.
|
|
151
|
+
} finally {
|
|
152
|
+
this._schedule();
|
|
153
|
+
}
|
|
154
|
+
}, this.intervalMs);
|
|
155
|
+
this.timer?.unref?.();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
start({ immediate = true } = {}) {
|
|
159
|
+
if (this.running) return false;
|
|
160
|
+
this.running = true;
|
|
161
|
+
if (immediate) {
|
|
162
|
+
void this.runOnce()
|
|
163
|
+
.catch(() => {})
|
|
164
|
+
.finally(() => this._schedule());
|
|
165
|
+
} else {
|
|
166
|
+
this._schedule();
|
|
167
|
+
}
|
|
168
|
+
this.emit("started");
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async stop({ drain = true } = {}) {
|
|
173
|
+
const wasRunning = this.running;
|
|
174
|
+
this.running = false;
|
|
175
|
+
if (this.timer != null) {
|
|
176
|
+
this.clearTimeoutFn(this.timer);
|
|
177
|
+
this.timer = null;
|
|
178
|
+
}
|
|
179
|
+
if (drain && this.inFlight) {
|
|
180
|
+
try {
|
|
181
|
+
await this.inFlight;
|
|
182
|
+
} catch {
|
|
183
|
+
// Error already exposed through runtime-error/lastError.
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (wasRunning) this.emit("stopped");
|
|
187
|
+
return wasRunning;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
status() {
|
|
191
|
+
return {
|
|
192
|
+
running: this.running,
|
|
193
|
+
inFlight: this.inFlight != null,
|
|
194
|
+
handlerRoutes: this.handlers.size,
|
|
195
|
+
lastStats: this.lastStats,
|
|
196
|
+
lastError: this.lastError?.message || null,
|
|
197
|
+
health: this.store.getHealthSnapshot(),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
let defaultHost = null;
|
|
203
|
+
|
|
204
|
+
export function getDefaultEventRuntimeHost(options = {}) {
|
|
205
|
+
if (!defaultHost) defaultHost = new EventRuntimeHost(options);
|
|
206
|
+
return defaultHost;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export function startDefaultEventRuntimeHost(options = {}) {
|
|
210
|
+
if (process.env.CC_EVENT_RUNTIME_DURABLE !== "1" && options.force !== true) {
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
const host = getDefaultEventRuntimeHost(options);
|
|
214
|
+
host.start({ immediate: options.immediate !== false });
|
|
215
|
+
return host;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export async function stopDefaultEventRuntimeHost(options) {
|
|
219
|
+
return defaultHost ? defaultHost.stop(options) : false;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export function _resetDefaultEventRuntimeHostForTests() {
|
|
223
|
+
defaultHost = null;
|
|
224
|
+
}
|
|
225
|
+
|