chainlesschain 0.162.124 → 0.162.126
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/package.json +1 -1
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/AIOps-BrTOcqIJ.js +1 -0
- package/src/assets/web-panel/assets/{ActionButton-COjZZKWG.js → ActionButton-na9cocmf.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-4ZDZE7lc.js → Analytics-BtDygkpt.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-CYH5k2Rp.js → AppLayout-D_t5CS18.js} +5 -5
- package/src/assets/web-panel/assets/Audit-BYMZccCy.js +1 -0
- package/src/assets/web-panel/assets/{Backup-CiX61Qc2.js → Backup-D2qDfAdL.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-CDxIQokd.js → BaseInput-kj456Ju9.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CaKgdRab.js → Chat-BY0A0ZLE.js} +4 -4
- package/src/assets/web-panel/assets/ChatBubbleRenderer-D1VvrOPQ.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-CjiWfu4s.js → Checkbox-DiBhtXsh.js} +1 -1
- package/src/assets/web-panel/assets/Codegen-B1ER0L0j.js +1 -0
- package/src/assets/web-panel/assets/{Col-ZKWREyNs.js → Col-CjLmza7D.js} +1 -1
- package/src/assets/web-panel/assets/Community-BNId05U7.js +1 -0
- package/src/assets/web-panel/assets/{Compact-DqknM98n.js → Compact-BuuMj7K1.js} +1 -1
- package/src/assets/web-panel/assets/Compliance-DUuDycaJ.js +1 -0
- package/src/assets/web-panel/assets/{Cowork-Dp29kHsC.js → Cowork-BKHiF6uL.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-zmEJAetz.js → Cron-C7p-lHnC.js} +2 -2
- package/src/assets/web-panel/assets/Crosschain-BvSOx8a6.js +1 -0
- package/src/assets/web-panel/assets/{DID-D_UFNzJ5.js → DID-D1k9jgHv.js} +2 -2
- package/src/assets/web-panel/assets/Dashboard-B9mCCnqY.js +3 -0
- package/src/assets/web-panel/assets/{Dropdown-CH7l3KCs.js → Dropdown-ge9UHSXF.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-Bud2M3XX.js → EmailListRenderer-TZO7ppXi.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-Bd2_8uME.js → FamilyGuardDashboard-DkhLJmzx.js} +1 -1
- package/src/assets/web-panel/assets/Federation-JLuA_8zp.js +1 -0
- package/src/assets/web-panel/assets/{FormItemContext-CpSH464Y.js → FormItemContext-C4w-rzNg.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-CANo8O-y.js → GenericCardRenderer-Btns4sV9.js} +1 -1
- package/src/assets/web-panel/assets/{Git-hvuZVoD3.js → Git-BheXMjzC.js} +2 -2
- package/src/assets/web-panel/assets/Governance-D9rLlatH.js +1 -0
- package/src/assets/web-panel/assets/Inference-DiklIMcd.js +1 -0
- package/src/assets/web-panel/assets/KnowledgeGraph-C70EWL03.js +1 -0
- package/src/assets/web-panel/assets/{Logs-DDkTnedu.js → Logs-Zt_MLI10.js} +2 -2
- package/src/assets/web-panel/assets/Marketplace-suQxES99.js +1 -0
- package/src/assets/web-panel/assets/{McpTools-Qx78XyOT.js → McpTools-CclpCDpY.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-CXYDO1oT.js → Memory-B2lHOUwF.js} +2 -2
- package/src/assets/web-panel/assets/MobileBridge-BMXKoDAD.js +1 -0
- package/src/assets/web-panel/assets/{MobileProjects-DEDbWNIk.js → MobileProjects-a6mWVdBV.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-Dwa_vlR8.js → Mtc-BFpM4Fkj.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-DAVkxhJv.js → MtcAudit-DDQkxkbS.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-C3upmgPN.js → Multisig-Crkd_zKQ.js} +3 -3
- package/src/assets/web-panel/assets/NLProgramming-Dpk5An7B.js +1 -0
- package/src/assets/web-panel/assets/{Notes-B1Oy3FbC.js → Notes-BrFnOMNz.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-Bs4-Fc6b.js → NotificationSettings-CM0iApFM.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-CEy1pIeq.js → OrderTableRenderer-XXjeqkdz.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-D4cJ1UNo.js → Organization-CHFW_38T.js} +2 -2
- package/src/assets/web-panel/assets/{Overflow-fdzvlF7x.js → Overflow-C-vl3EjV.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-Y13PwXBA.js → P2P-BT7Slavq.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-Ck1zCLe6.js → PdhVaultBrowser-DRUaULap.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-CvEXP6LC.js → Permissions-DkhOAvMz.js} +2 -2
- package/src/assets/web-panel/assets/{PersonalDataHub-JeP7IWMW.js → PersonalDataHub-Dl7dSOvV.js} +3 -3
- package/src/assets/web-panel/assets/Pipeline-B3nVI4p6.js +1 -0
- package/src/assets/web-panel/assets/Privacy-Dv1SXx1Q.js +1 -0
- package/src/assets/web-panel/assets/{ProjectInit-DeWd9UcS.js → ProjectInit-DrAhVi5p.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-DUpVuU9F.js → ProjectSettings-h-ggCYN_.js} +2 -2
- package/src/assets/web-panel/assets/Projects-CM91hYdr.js +1 -0
- package/src/assets/web-panel/assets/{Providers-DECW00ek.js → Providers-rfkZel3N.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-Dl-pK9Io.js → QuickAsk-XepZB7h_.js} +1 -1
- package/src/assets/web-panel/assets/Recommend-DzQWsh1a.js +1 -0
- package/src/assets/web-panel/assets/Reputation-CDeaal0j.js +1 -0
- package/src/assets/web-panel/assets/Row-BN4aKhFH.js +1 -0
- package/src/assets/web-panel/assets/{RssFeed-iyQT5q9l.js → RssFeed-INP6VYAA.js} +3 -3
- package/src/assets/web-panel/assets/Search-ChPbwatu.js +1 -0
- package/src/assets/web-panel/assets/{Security-c4Jxf5Ih.js → Security-C97ZCY8N.js} +4 -4
- package/src/assets/web-panel/assets/{Services-CRuisolj.js → Services-Cbtl2Ajs.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CCnzJkb-.js → Skeleton-B13sFxBQ.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CZURCwZg.js → Skills-vI9zSIKX.js} +1 -1
- package/src/assets/web-panel/assets/Sla-Cr3oBH39.js +1 -0
- package/src/assets/web-panel/assets/SpeechSettings-BwemqPPV.js +1 -0
- package/src/assets/web-panel/assets/{SyncSettings-CJWVtd87.js → SyncSettings-CLA78P-Z.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-61lrQ_lS.js → Tasks-DBjQ_DOM.js} +1 -1
- package/src/assets/web-panel/assets/Templates-BkSLDkBs.js +1 -0
- package/src/assets/web-panel/assets/Tenant-Dn0nSlib.js +1 -0
- package/src/assets/web-panel/assets/{Terminal-CP15hcNS.js → Terminal-C8f4boru.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-Sl5uXrkN.js → TimelineRenderer-DW_rMtJR.js} +1 -1
- package/src/assets/web-panel/assets/Tokens-BdffrKYV.js +1 -0
- package/src/assets/web-panel/assets/{Trigger-BLCQEOF2.js → Trigger-CX4CUg-Q.js} +1 -1
- package/src/assets/web-panel/assets/Trust-Cq9Bl7Od.js +1 -0
- package/src/assets/web-panel/assets/{UkeySign-Dwp0zXQ6.js → UkeySign-BQy18_VY.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-CIHA55Sx.js → VideoEditing-h5hzK7Vw.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Hjajvnto.js → Wallet-BLotT3gw.js} +3 -3
- package/src/assets/web-panel/assets/{WebAuthn-DqSURUvI.js → WebAuthn-8cCANYLE.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-B5bHRwUG.js → WorkflowEditor-Db6NwtAv.js} +1 -1
- package/src/assets/web-panel/assets/{chat-DsheLKkG.js → chat-BPk1LbpL.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CST2UkgL.js → colors-BnNal71p.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-yqEoy1L7.js → compact-item-W2VC0tcy.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-Jwp78HFY.js → createContext-DceVsgnZ.js} +1 -1
- package/src/assets/web-panel/assets/devWarning--rwFDBhx.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CVS5mFEP.js → hasIn-BEq6EDcp.js} +1 -1
- package/src/assets/web-panel/assets/{index-BLTUVd0V.js → index-5gIBUFBn.js} +2 -2
- package/src/assets/web-panel/assets/index-APCHxOkM.js +3 -0
- package/src/assets/web-panel/assets/index-B2dMhwZi.js +1 -0
- package/src/assets/web-panel/assets/{index-C0FZScMe.js → index-B8cPjrEH.js} +4 -4
- package/src/assets/web-panel/assets/{index-CjfN2CpJ.js → index-BDC5HsxZ.js} +1 -1
- package/src/assets/web-panel/assets/index-BPFuPGKi.js +1 -0
- package/src/assets/web-panel/assets/{index-SjxCCf5h.js → index-BUkDcIwJ.js} +2 -2
- package/src/assets/web-panel/assets/{index-Cjig5i3a.js → index-BWcCyH6-.js} +28 -26
- package/src/assets/web-panel/assets/{index-AnW25bEq.js → index-BgZikQoh.js} +1 -1
- package/src/assets/web-panel/assets/index-Bwjus13Y.js +1 -0
- package/src/assets/web-panel/assets/index-BzSzRWsw.js +55 -0
- package/src/assets/web-panel/assets/index-C1K9CsGr.js +1 -0
- package/src/assets/web-panel/assets/{index-DDAigsel.js → index-CBZVISK6.js} +2 -2
- package/src/assets/web-panel/assets/index-CEJN-R2L.js +1 -0
- package/src/assets/web-panel/assets/index-CG5dGC9E.js +1 -0
- package/src/assets/web-panel/assets/{index-DxaU_lza.js → index-CMGLpstm.js} +1 -1
- package/src/assets/web-panel/assets/index-CWrGCndd.js +1 -0
- package/src/assets/web-panel/assets/index-CbcvfpCV.js +1 -0
- package/src/assets/web-panel/assets/{index-De600Jjm.js → index-Ceqv4lI2.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cy0dNzkp.js → index-CsT6frT8.js} +1 -1
- package/src/assets/web-panel/assets/{index-CDAPnZUs.js → index-D8PQKsDT.js} +1 -1
- package/src/assets/web-panel/assets/{index-Crk4KWLW.js → index-DGncdA-j.js} +1 -1
- package/src/assets/web-panel/assets/{index-R-VGFpi6.js → index-DHanQHO0.js} +3 -3
- package/src/assets/web-panel/assets/index-DaUBk28E.js +12 -0
- package/src/assets/web-panel/assets/{index-BzetOasL.js → index-Di2J4b4V.js} +1 -1
- package/src/assets/web-panel/assets/index-DtuLvWZN.js +21 -0
- package/src/assets/web-panel/assets/{index-Dgyn8-wN.js → index-DvS1J8xc.js} +2 -2
- package/src/assets/web-panel/assets/{index-CtyEOGuj.js → index-DxePJdwP.js} +1 -1
- package/src/assets/web-panel/assets/{index-CzsKK0tQ.js → index-Et4XvL49.js} +2 -2
- package/src/assets/web-panel/assets/{index-BuI27WSx.js → index-GlFxgcj4.js} +2 -2
- package/src/assets/web-panel/assets/index-HV119Oui.js +1 -0
- package/src/assets/web-panel/assets/index-InGW87pj.js +13 -0
- package/src/assets/web-panel/assets/{index-Dxljh9Fu.js → index-P1-s8JR7.js} +2 -2
- package/src/assets/web-panel/assets/{index-CSBPc-sI.js → index-SdABCNoi.js} +2 -2
- package/src/assets/web-panel/assets/{index-BCHAUdel.js → index-WTAZbN-c.js} +1 -1
- package/src/assets/web-panel/assets/index-_2I-KzOj.js +1 -0
- package/src/assets/web-panel/assets/index-m1sVaWVU.js +1 -0
- package/src/assets/web-panel/assets/index-s37wwyeN.js +1 -0
- package/src/assets/web-panel/assets/{index-CRBbVS43.js → index-tyWABqp9.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-ClAjrsQ-.js → initDefaultProps-DzrCDb3j.js} +1 -1
- package/src/assets/web-panel/assets/motion-BQERVnE3.js +11 -0
- package/src/assets/web-panel/assets/{move-DMelzIW-.js → move-I9ACA5XJ.js} +1 -1
- package/src/assets/web-panel/assets/mtc-parser-Dd2Pw-tr.js +1 -0
- package/src/assets/web-panel/assets/{omit-oxecfU3b.js → omit-DwzYRzWV.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DJ5F5M6x.js → pickAttrs-BSGULyIL.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-DdbKsant.js → placementArrow-tSYYjAts.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BUuM5cmS.js → responsiveObserve-Dy2lqikT.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DSV0ccvR.js → slide-RaB4Uq0c.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-B-6oLAXf.js → statusUtils-CBpC_wZg.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-DdCAHtsZ.js → styleChecker-BEKwPWt5.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-ZORkcoZd.js → useFlexGapSupport-C4CnYJH1.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BFp46LoP.js → useFs-n24jutw5.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-H7rxgbdW.js → usePersonalDataHub-DMgS8F6G.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-eIq4Tk0J.js → vnode-BSp2KYcj.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CTNrv8-H.js → zoom-7UfQtTPh.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +51 -2
- package/src/commands/compliance.js +3 -1
- package/src/commands/ide.js +60 -5
- package/src/commands/incentive.js +22 -22
- package/src/commands/mtc.js +5 -1
- package/src/commands/review.js +47 -17
- package/src/commands/session.js +11 -2
- package/src/gateways/ws/message-dispatcher.js +149 -166
- package/src/gateways/ws/ws-session-gateway.js +95 -9
- package/src/harness/background-task-manager.js +5 -1
- package/src/harness/jsonl-session-store.js +90 -12
- package/src/harness/mcp-client.js +62 -21
- package/src/harness/prompt-compressor.js +24 -5
- package/src/harness/worktree-isolator.js +10 -1
- package/src/lib/agent-core.js +2 -0
- package/src/lib/audit-logger.js +3 -1
- package/src/lib/autonomous-agent.js +29 -0
- package/src/lib/chat-core.js +5 -2
- package/src/lib/chat-intent-service.js +82 -23
- package/src/lib/checkpoint-store.js +31 -4
- package/src/lib/claude-code-bridge.js +48 -3
- package/src/lib/config-manager.js +25 -1
- package/src/lib/cost-budget.js +13 -2
- package/src/lib/credential-guard.js +81 -1
- package/src/lib/git-integration.js +16 -2
- package/src/lib/goal-store.js +11 -0
- package/src/lib/hook-manager.js +4 -0
- package/src/lib/interaction-adapter.js +32 -11
- package/src/lib/jetbrains-bridge.js +147 -0
- package/src/lib/jsonl-session-store.js +2 -0
- package/src/lib/llm-config-defaults.js +37 -0
- package/src/lib/llm-pricing.js +11 -4
- package/src/lib/llm-providers.js +11 -1
- package/src/lib/mcp-oauth.js +88 -10
- package/src/lib/mcp-serve.js +29 -0
- package/src/lib/orchestrator.js +38 -2
- package/src/lib/permission-engine.js +4 -1
- package/src/lib/pipeline-orchestrator.js +20 -2
- package/src/lib/project-instructions.js +13 -0
- package/src/lib/repl-bang-memorize.js +9 -1
- package/src/lib/repl-denials.js +137 -0
- package/src/lib/runnable-provider.js +7 -1
- package/src/lib/safe-json.js +22 -0
- package/src/lib/sandbox-v2.js +7 -6
- package/src/lib/search-command.js +65 -0
- package/src/lib/session-insights.js +13 -6
- package/src/lib/session-usage.js +21 -3
- package/src/lib/settings-hooks.cjs +133 -0
- package/src/lib/settings-loader.cjs +16 -7
- package/src/lib/social-graph.js +3 -1
- package/src/lib/status-line.cjs +4 -1
- package/src/lib/stream-retry.js +27 -0
- package/src/lib/sub-agent-context.js +9 -0
- package/src/lib/turn-context.js +15 -5
- package/src/repl/agent-repl.js +110 -8
- package/src/runtime/__tests__/message-roles.test.js +36 -3
- package/src/runtime/agent-core.js +179 -52
- package/src/runtime/coding-agent-contract-shared.cjs +9 -2
- package/src/runtime/coding-agent-shell-policy.cjs +23 -2
- package/src/runtime/file-ref-expander.js +51 -7
- package/src/runtime/headless-runner.js +96 -2
- package/src/runtime/headless-stream.js +78 -3
- package/src/runtime/mcp-config.js +114 -4
- package/src/runtime/message-roles.js +14 -1
- package/src/runtime/pipe-safety.js +51 -0
- package/src/runtime/policies/agent-policy.js +3 -0
- package/src/assets/web-panel/assets/AIOps-BsDJlD_l.js +0 -1
- package/src/assets/web-panel/assets/Audit-BKlFbLdl.js +0 -1
- package/src/assets/web-panel/assets/ChatBubbleRenderer-DgvpwU5o.js +0 -1
- package/src/assets/web-panel/assets/Codegen-tKWGzajw.js +0 -1
- package/src/assets/web-panel/assets/Community-CmLuPBUU.js +0 -1
- package/src/assets/web-panel/assets/Compliance-PZw0aBLI.js +0 -1
- package/src/assets/web-panel/assets/Crosschain-Sb-uM7Ty.js +0 -1
- package/src/assets/web-panel/assets/Dashboard-Btag698v.js +0 -3
- package/src/assets/web-panel/assets/Federation-1jhstF5P.js +0 -1
- package/src/assets/web-panel/assets/Governance-BQrWksKt.js +0 -1
- package/src/assets/web-panel/assets/Inference-jEBTp12v.js +0 -1
- package/src/assets/web-panel/assets/KnowledgeGraph-tDiV2taf.js +0 -1
- package/src/assets/web-panel/assets/Marketplace-9Yi32avt.js +0 -1
- package/src/assets/web-panel/assets/MobileBridge-MfUfkHA0.js +0 -1
- package/src/assets/web-panel/assets/NLProgramming-DO3CZ0_z.js +0 -1
- package/src/assets/web-panel/assets/Pipeline-BZ7wRzG1.js +0 -1
- package/src/assets/web-panel/assets/Privacy-BJ6qj9Hv.js +0 -1
- package/src/assets/web-panel/assets/Projects-y1WbI337.js +0 -1
- package/src/assets/web-panel/assets/Recommend-Bju04wTd.js +0 -1
- package/src/assets/web-panel/assets/Reputation-BUPa3nEk.js +0 -1
- package/src/assets/web-panel/assets/Row-WYqqaq_5.js +0 -1
- package/src/assets/web-panel/assets/Search-CrfwJF0R.js +0 -1
- package/src/assets/web-panel/assets/Sla-CrMzaEi2.js +0 -1
- package/src/assets/web-panel/assets/SpeechSettings-jTDOM5eY.js +0 -1
- package/src/assets/web-panel/assets/Templates-Cg-iF2g1.js +0 -1
- package/src/assets/web-panel/assets/Tenant-DrDv1FFc.js +0 -1
- package/src/assets/web-panel/assets/Tokens-yRIZTVsR.js +0 -1
- package/src/assets/web-panel/assets/Trust-D5xq8z6s.js +0 -1
- package/src/assets/web-panel/assets/community-parser-Cuyslaku.js +0 -3
- package/src/assets/web-panel/assets/devWarning-C8to6gQk.js +0 -1
- package/src/assets/web-panel/assets/index-BeblNJDH.js +0 -1
- package/src/assets/web-panel/assets/index-C130LLPq.js +0 -1
- package/src/assets/web-panel/assets/index-C8rq85gu.js +0 -1
- package/src/assets/web-panel/assets/index-CIE2n8k_.js +0 -1
- package/src/assets/web-panel/assets/index-CTd3lDxp.js +0 -13
- package/src/assets/web-panel/assets/index-CUWj5L2s.js +0 -1
- package/src/assets/web-panel/assets/index-ChRL6rgA.js +0 -3
- package/src/assets/web-panel/assets/index-CrlRa054.js +0 -1
- package/src/assets/web-panel/assets/index-Cu6Ql64n.js +0 -1
- package/src/assets/web-panel/assets/index-Cx_t5rWw.js +0 -12
- package/src/assets/web-panel/assets/index-DZfnYE6e.js +0 -1
- package/src/assets/web-panel/assets/index-D_1b7uh6.js +0 -55
- package/src/assets/web-panel/assets/index-D_e9gwfn.js +0 -1
- package/src/assets/web-panel/assets/index-DbxAlpPC.js +0 -21
- package/src/assets/web-panel/assets/index-DiK4vSZa.js +0 -1
- package/src/assets/web-panel/assets/index-DpYn5v2k.js +0 -1
- package/src/assets/web-panel/assets/index-diWkx2Wq.js +0 -1
- package/src/assets/web-panel/assets/motion-BalXv_60.js +0 -11
- package/src/assets/web-panel/assets/mtc-parser-CEQffxds.js +0 -1
|
@@ -23,7 +23,10 @@ export function createWsMessageDispatcher(server) {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
const client = server.clients.get(clientId);
|
|
26
|
-
|
|
26
|
+
// client may be undefined if it was removed mid-dispatch (heartbeat sweep
|
|
27
|
+
// / disconnect); treat a missing client as unauthenticated rather than
|
|
28
|
+
// throwing a TypeError (every sibling call site null-checks the client).
|
|
29
|
+
if (server.token && !client?.authenticated && type !== "auth") {
|
|
27
30
|
server._send(ws, {
|
|
28
31
|
id,
|
|
29
32
|
type: "error",
|
|
@@ -103,199 +106,179 @@ export function createWsMessageDispatcher(server) {
|
|
|
103
106
|
"llm.chat": () => server._handleLlmChat(id, ws, message),
|
|
104
107
|
};
|
|
105
108
|
|
|
106
|
-
//
|
|
107
|
-
//
|
|
108
|
-
//
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
109
|
+
// Static core routes take precedence and are dispatched directly. The
|
|
110
|
+
// feature handler maps below are consulted ONLY when no static route
|
|
111
|
+
// matches — so a feature topic can never shadow a core protocol route
|
|
112
|
+
// (auth/cancel/ping/execute), and we no longer allocate a closure for all
|
|
113
|
+
// ~79 feature keys on every message (the old per-message Object.keys loops
|
|
114
|
+
// built the entire route table each dispatch). Only the matched handler
|
|
115
|
+
// runs.
|
|
116
|
+
const staticHandler = routes[type];
|
|
117
|
+
if (staticHandler) {
|
|
118
|
+
return staticHandler();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Phase I — Hosted Session API streaming routes (stream.run). Each
|
|
122
|
+
// intermediate event goes out as { id, type:"stream.event", event } and
|
|
123
|
+
// the final response is sent by the normal ok/err wrapper.
|
|
124
|
+
if (SESSION_CORE_STREAMING_HANDLERS[type]) {
|
|
125
|
+
const controller = new AbortController();
|
|
126
|
+
const client = server.clients.get(clientId);
|
|
127
|
+
if (client) {
|
|
128
|
+
client._streamAborts = client._streamAborts || new Map();
|
|
129
|
+
client._streamAborts.set(id, controller);
|
|
130
|
+
}
|
|
131
|
+
const sender = (payload) => server._send(ws, { id, ...payload });
|
|
132
|
+
const context = { server, ws, clientId };
|
|
133
|
+
try {
|
|
134
|
+
const result = await SESSION_CORE_STREAMING_HANDLERS[type](
|
|
135
|
+
message,
|
|
136
|
+
sender,
|
|
137
|
+
controller.signal,
|
|
138
|
+
context,
|
|
139
|
+
);
|
|
140
|
+
server._send(ws, { id, type: `${type}.end`, ...result });
|
|
141
|
+
} catch (err) {
|
|
142
|
+
server._send(ws, {
|
|
143
|
+
id,
|
|
144
|
+
type: "error",
|
|
145
|
+
code: "STREAM_RUN_ERROR",
|
|
146
|
+
message: err?.message || String(err),
|
|
147
|
+
});
|
|
148
|
+
} finally {
|
|
149
|
+
if (client?._streamAborts) client._streamAborts.delete(id);
|
|
150
|
+
}
|
|
151
|
+
return;
|
|
144
152
|
}
|
|
145
153
|
|
|
146
154
|
// Video Editing streaming routes
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
});
|
|
174
|
-
} finally {
|
|
175
|
-
if (client?._streamAborts) client._streamAborts.delete(id);
|
|
176
|
-
}
|
|
177
|
-
};
|
|
155
|
+
if (VIDEO_STREAMING_HANDLERS[type]) {
|
|
156
|
+
const controller = new AbortController();
|
|
157
|
+
const client = server.clients.get(clientId);
|
|
158
|
+
if (client) {
|
|
159
|
+
client._streamAborts = client._streamAborts || new Map();
|
|
160
|
+
client._streamAborts.set(id, controller);
|
|
161
|
+
}
|
|
162
|
+
const sender = (payload) => server._send(ws, { id, ...payload });
|
|
163
|
+
try {
|
|
164
|
+
const result = await VIDEO_STREAMING_HANDLERS[type](
|
|
165
|
+
message,
|
|
166
|
+
sender,
|
|
167
|
+
controller.signal,
|
|
168
|
+
);
|
|
169
|
+
server._send(ws, { id, type: `${type}.end`, ...result });
|
|
170
|
+
} catch (err) {
|
|
171
|
+
server._send(ws, {
|
|
172
|
+
id,
|
|
173
|
+
type: "error",
|
|
174
|
+
code: "VIDEO_STREAM_ERROR",
|
|
175
|
+
message: err?.message || String(err),
|
|
176
|
+
});
|
|
177
|
+
} finally {
|
|
178
|
+
if (client?._streamAborts) client._streamAborts.delete(id);
|
|
179
|
+
}
|
|
180
|
+
return;
|
|
178
181
|
}
|
|
179
182
|
|
|
180
183
|
// Video Editing request/response routes
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
code: "VIDEO_ERROR",
|
|
195
|
-
message: err?.message || String(err),
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
};
|
|
184
|
+
if (VIDEO_HANDLERS[type]) {
|
|
185
|
+
try {
|
|
186
|
+
const result = await VIDEO_HANDLERS[type](message);
|
|
187
|
+
server._send(ws, { id, type: `${type}.response`, ...result });
|
|
188
|
+
} catch (err) {
|
|
189
|
+
server._send(ws, {
|
|
190
|
+
id,
|
|
191
|
+
type: "error",
|
|
192
|
+
code: "VIDEO_ERROR",
|
|
193
|
+
message: err?.message || String(err),
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
return;
|
|
199
197
|
}
|
|
200
198
|
|
|
201
199
|
// Personal Data Hub topics — same 10 surfaces as the Electron IPC
|
|
202
200
|
// (see desktop-app-vue/src/main/ipc/personal-data-hub-ipc.js). Each
|
|
203
201
|
// handler returns { result } or { error }; we wrap with the standard
|
|
204
202
|
// response envelope so renderer code is shell-agnostic.
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
if (out && out.error) {
|
|
210
|
-
server._send(ws, {
|
|
211
|
-
id,
|
|
212
|
-
type: "error",
|
|
213
|
-
code: "PERSONAL_DATA_HUB_ERROR",
|
|
214
|
-
message: out.error,
|
|
215
|
-
});
|
|
216
|
-
} else {
|
|
217
|
-
server._send(ws, {
|
|
218
|
-
id,
|
|
219
|
-
type: `${hubType}.response`,
|
|
220
|
-
result: out && out.result !== undefined ? out.result : out,
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
} catch (err) {
|
|
203
|
+
if (PERSONAL_DATA_HUB_HANDLERS[type]) {
|
|
204
|
+
try {
|
|
205
|
+
const out = await PERSONAL_DATA_HUB_HANDLERS[type](message);
|
|
206
|
+
if (out && out.error) {
|
|
224
207
|
server._send(ws, {
|
|
225
208
|
id,
|
|
226
209
|
type: "error",
|
|
227
210
|
code: "PERSONAL_DATA_HUB_ERROR",
|
|
228
|
-
message:
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// Phase 5.7 — streaming sync routes. Adapter progress events are
|
|
235
|
-
// pushed as `<topic>.event` messages tagged with the request id;
|
|
236
|
-
// the final report comes as `<topic>.end`.
|
|
237
|
-
for (const streamType of Object.keys(
|
|
238
|
-
PERSONAL_DATA_HUB_STREAMING_HANDLERS,
|
|
239
|
-
)) {
|
|
240
|
-
routes[streamType] = async () => {
|
|
241
|
-
const sender = (payload) => server._send(ws, { id, ...payload });
|
|
242
|
-
try {
|
|
243
|
-
const out = await PERSONAL_DATA_HUB_STREAMING_HANDLERS[streamType](
|
|
244
|
-
message,
|
|
245
|
-
sender,
|
|
246
|
-
);
|
|
247
|
-
server._send(ws, {
|
|
248
|
-
id,
|
|
249
|
-
type: `${streamType}.end`,
|
|
250
|
-
...(out && out.result !== undefined
|
|
251
|
-
? { result: out.result }
|
|
252
|
-
: out || {}),
|
|
211
|
+
message: out.error,
|
|
253
212
|
});
|
|
254
|
-
}
|
|
213
|
+
} else {
|
|
255
214
|
server._send(ws, {
|
|
256
215
|
id,
|
|
257
|
-
type:
|
|
258
|
-
|
|
259
|
-
message: err?.message || String(err),
|
|
216
|
+
type: `${type}.response`,
|
|
217
|
+
result: out && out.result !== undefined ? out.result : out,
|
|
260
218
|
});
|
|
261
219
|
}
|
|
262
|
-
}
|
|
220
|
+
} catch (err) {
|
|
221
|
+
server._send(ws, {
|
|
222
|
+
id,
|
|
223
|
+
type: "error",
|
|
224
|
+
code: "PERSONAL_DATA_HUB_ERROR",
|
|
225
|
+
message: err?.message || String(err),
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
return;
|
|
263
229
|
}
|
|
264
230
|
|
|
265
|
-
// Phase
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
231
|
+
// Phase 5.7 — streaming sync routes. Adapter progress events are pushed
|
|
232
|
+
// as `<topic>.event` messages tagged with the request id; the final
|
|
233
|
+
// report comes as `<topic>.end`.
|
|
234
|
+
if (PERSONAL_DATA_HUB_STREAMING_HANDLERS[type]) {
|
|
235
|
+
const sender = (payload) => server._send(ws, { id, ...payload });
|
|
236
|
+
try {
|
|
237
|
+
const out = await PERSONAL_DATA_HUB_STREAMING_HANDLERS[type](
|
|
238
|
+
message,
|
|
239
|
+
sender,
|
|
240
|
+
);
|
|
241
|
+
server._send(ws, {
|
|
242
|
+
id,
|
|
243
|
+
type: `${type}.end`,
|
|
244
|
+
...(out && out.result !== undefined
|
|
245
|
+
? { result: out.result }
|
|
246
|
+
: out || {}),
|
|
247
|
+
});
|
|
248
|
+
} catch (err) {
|
|
249
|
+
server._send(ws, {
|
|
250
|
+
id,
|
|
251
|
+
type: "error",
|
|
252
|
+
code: "PERSONAL_DATA_HUB_STREAM_ERROR",
|
|
253
|
+
message: err?.message || String(err),
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
return;
|
|
285
257
|
}
|
|
286
258
|
|
|
287
|
-
|
|
288
|
-
if (
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
type:
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
259
|
+
// Phase I — Hosted Session API (session-core, memory, beta, usage)
|
|
260
|
+
if (SESSION_CORE_HANDLERS[type]) {
|
|
261
|
+
try {
|
|
262
|
+
const result = await SESSION_CORE_HANDLERS[type](message);
|
|
263
|
+
server._send(ws, { id, type: `${type}.response`, ...result });
|
|
264
|
+
} catch (err) {
|
|
265
|
+
server._send(ws, {
|
|
266
|
+
id,
|
|
267
|
+
type: "error",
|
|
268
|
+
code: "SESSION_CORE_ERROR",
|
|
269
|
+
message: err?.message || String(err),
|
|
270
|
+
});
|
|
271
|
+
}
|
|
295
272
|
return;
|
|
296
273
|
}
|
|
297
274
|
|
|
298
|
-
|
|
275
|
+
server._send(ws, {
|
|
276
|
+
id,
|
|
277
|
+
type: "error",
|
|
278
|
+
code: "UNKNOWN_TYPE",
|
|
279
|
+
message: `Unknown message type: ${type}`,
|
|
280
|
+
});
|
|
281
|
+
return;
|
|
299
282
|
},
|
|
300
283
|
};
|
|
301
284
|
}
|
|
@@ -109,6 +109,47 @@ export class WSSessionManager {
|
|
|
109
109
|
this.maxSessions = Number.isFinite(options.maxSessions)
|
|
110
110
|
? options.maxSessions
|
|
111
111
|
: 100;
|
|
112
|
+
|
|
113
|
+
// Cap patch bookkeeping per session. `patchHistory` is append-only (every
|
|
114
|
+
// applyPatch/rejectPatch pushes, nothing trims) and `pendingPatches` grows
|
|
115
|
+
// with each proposePatch — both are serialized in full by
|
|
116
|
+
// _persistSessionState on every session op, so unbounded growth means
|
|
117
|
+
// O(n) memory AND an O(n²) rewrite cost over a long session (and a tool
|
|
118
|
+
// proposing many large before/after/diff blobs amplifies it). Keep a
|
|
119
|
+
// recent window; oldest entries fall off (FIFO).
|
|
120
|
+
this.maxPatchHistory = Number.isFinite(options.maxPatchHistory)
|
|
121
|
+
? options.maxPatchHistory
|
|
122
|
+
: 200;
|
|
123
|
+
this.maxPendingPatches = Number.isFinite(options.maxPendingPatches)
|
|
124
|
+
? options.maxPendingPatches
|
|
125
|
+
: 50;
|
|
126
|
+
// The entry-count caps above bound how MANY patches are kept, but a SINGLE
|
|
127
|
+
// proposed patch (a client-reachable `patch-propose`) could still carry an
|
|
128
|
+
// unbounded number of files, each with unbounded before/after/diff content
|
|
129
|
+
// — all held in memory AND serialized to disk by _persistSessionState. One
|
|
130
|
+
// file with a multi-GB diff string is enough to OOM. Bound a single patch's
|
|
131
|
+
// payload: cap the file count and truncate each content field.
|
|
132
|
+
this.maxPatchFiles = Number.isFinite(options.maxPatchFiles)
|
|
133
|
+
? options.maxPatchFiles
|
|
134
|
+
: 200;
|
|
135
|
+
this.maxPatchContentChars = Number.isFinite(options.maxPatchContentChars)
|
|
136
|
+
? options.maxPatchContentChars
|
|
137
|
+
: 512 * 1024; // 512 KB per before/after/diff field
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Truncate a patch content field (before/after/diff) to maxPatchContentChars,
|
|
142
|
+
* appending a visible marker. Preserves the null-vs-string distinction (a null
|
|
143
|
+
* field stays null — it signals create/delete ops). Pure.
|
|
144
|
+
*/
|
|
145
|
+
_capPatchContent(value) {
|
|
146
|
+
if (value == null) return null;
|
|
147
|
+
const s = String(value);
|
|
148
|
+
if (s.length <= this.maxPatchContentChars) return s;
|
|
149
|
+
return (
|
|
150
|
+
s.slice(0, this.maxPatchContentChars) +
|
|
151
|
+
`\n…[truncated for storage: field was ${s.length} chars]`
|
|
152
|
+
);
|
|
112
153
|
}
|
|
113
154
|
|
|
114
155
|
_normalizeEnabledToolNames(enabledToolNames) {
|
|
@@ -499,9 +540,7 @@ export class WSSessionManager {
|
|
|
499
540
|
permanentMemory,
|
|
500
541
|
reviewState: metadata.reviewState || null,
|
|
501
542
|
pendingPatches: this._hydratePendingPatches(metadata.pendingPatches),
|
|
502
|
-
patchHistory:
|
|
503
|
-
? metadata.patchHistory
|
|
504
|
-
: [],
|
|
543
|
+
patchHistory: this._boundPatchHistory(metadata.patchHistory),
|
|
505
544
|
taskGraph: this._hydrateTaskGraph(metadata.taskGraph),
|
|
506
545
|
interaction: null,
|
|
507
546
|
createdAt: dbSession.created_at,
|
|
@@ -842,8 +881,13 @@ export class WSSessionManager {
|
|
|
842
881
|
const session = this.sessions.get(sessionId);
|
|
843
882
|
if (!session) return null;
|
|
844
883
|
|
|
845
|
-
const
|
|
846
|
-
if (
|
|
884
|
+
const rawFiles = Array.isArray(payload.files) ? payload.files : [];
|
|
885
|
+
if (rawFiles.length === 0) return null;
|
|
886
|
+
// Cap the per-patch file count; a proposal touching more than this is
|
|
887
|
+
// pathological for review. Excess files are dropped (count recorded below)
|
|
888
|
+
// so one message can't pin unbounded memory / disk.
|
|
889
|
+
const files = rawFiles.slice(0, this.maxPatchFiles);
|
|
890
|
+
const droppedFiles = rawFiles.length - files.length;
|
|
847
891
|
|
|
848
892
|
const patchId = `patch-${this._generateId()}`;
|
|
849
893
|
const now = new Date().toISOString();
|
|
@@ -854,9 +898,9 @@ export class WSSessionManager {
|
|
|
854
898
|
index,
|
|
855
899
|
path: file.path || `unknown-${index}`,
|
|
856
900
|
op,
|
|
857
|
-
before:
|
|
858
|
-
after:
|
|
859
|
-
diff:
|
|
901
|
+
before: this._capPatchContent(file.before),
|
|
902
|
+
after: this._capPatchContent(file.after),
|
|
903
|
+
diff: this._capPatchContent(file.diff),
|
|
860
904
|
stats,
|
|
861
905
|
};
|
|
862
906
|
});
|
|
@@ -883,12 +927,23 @@ export class WSSessionManager {
|
|
|
883
927
|
fileCount: normalizedFiles.length,
|
|
884
928
|
added: totalStats.added,
|
|
885
929
|
removed: totalStats.removed,
|
|
930
|
+
// Surfaced so the reviewer/UI knows the proposal was capped for storage.
|
|
931
|
+
...(droppedFiles > 0 ? { droppedFiles } : {}),
|
|
886
932
|
},
|
|
887
933
|
};
|
|
888
934
|
|
|
889
935
|
if (!(session.pendingPatches instanceof Map)) {
|
|
890
936
|
session.pendingPatches = new Map();
|
|
891
937
|
}
|
|
938
|
+
// Bound un-reviewed proposals: evict the oldest pending (Map preserves
|
|
939
|
+
// insertion order) once at cap. 50 unresolved patches is already
|
|
940
|
+
// pathological; dropping the stalest keeps memory + persisted state bounded
|
|
941
|
+
// without blocking a legitimate new proposal.
|
|
942
|
+
while (session.pendingPatches.size >= this.maxPendingPatches) {
|
|
943
|
+
const oldestKey = session.pendingPatches.keys().next().value;
|
|
944
|
+
if (oldestKey === undefined) break;
|
|
945
|
+
session.pendingPatches.delete(oldestKey);
|
|
946
|
+
}
|
|
892
947
|
session.pendingPatches.set(patchId, patch);
|
|
893
948
|
session.lastActivity = now;
|
|
894
949
|
this._persistSessionState(sessionId);
|
|
@@ -917,11 +972,35 @@ export class WSSessionManager {
|
|
|
917
972
|
session.patchHistory = [];
|
|
918
973
|
}
|
|
919
974
|
session.patchHistory.push(patch);
|
|
975
|
+
this._trimPatchHistory(session);
|
|
920
976
|
session.lastActivity = patch.resolvedAt;
|
|
921
977
|
this._persistSessionState(sessionId);
|
|
922
978
|
return patch;
|
|
923
979
|
}
|
|
924
980
|
|
|
981
|
+
/**
|
|
982
|
+
* Keep `patchHistory` bounded to the most recent maxPatchHistory entries.
|
|
983
|
+
* Oldest fall off the front (FIFO) so memory + persisted JSON stay bounded.
|
|
984
|
+
*/
|
|
985
|
+
_trimPatchHistory(session) {
|
|
986
|
+
if (!Array.isArray(session.patchHistory)) return;
|
|
987
|
+
const overflow = session.patchHistory.length - this.maxPatchHistory;
|
|
988
|
+
if (overflow > 0) {
|
|
989
|
+
session.patchHistory.splice(0, overflow);
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
/**
|
|
994
|
+
* Bound a (possibly persisted/tampered) patchHistory array on load, keeping
|
|
995
|
+
* the most recent entries. Returns a fresh array (never the input).
|
|
996
|
+
*/
|
|
997
|
+
_boundPatchHistory(list) {
|
|
998
|
+
if (!Array.isArray(list)) return [];
|
|
999
|
+
return list.length > this.maxPatchHistory
|
|
1000
|
+
? list.slice(list.length - this.maxPatchHistory)
|
|
1001
|
+
: list.slice();
|
|
1002
|
+
}
|
|
1003
|
+
|
|
925
1004
|
/**
|
|
926
1005
|
* Discard a pending patch. Same bookkeeping as applyPatch but records a
|
|
927
1006
|
* "rejected" decision instead.
|
|
@@ -944,6 +1023,7 @@ export class WSSessionManager {
|
|
|
944
1023
|
session.patchHistory = [];
|
|
945
1024
|
}
|
|
946
1025
|
session.patchHistory.push(patch);
|
|
1026
|
+
this._trimPatchHistory(session);
|
|
947
1027
|
session.lastActivity = patch.resolvedAt;
|
|
948
1028
|
this._persistSessionState(sessionId);
|
|
949
1029
|
return patch;
|
|
@@ -1339,7 +1419,13 @@ export class WSSessionManager {
|
|
|
1339
1419
|
_hydratePendingPatches(list) {
|
|
1340
1420
|
const map = new Map();
|
|
1341
1421
|
if (Array.isArray(list)) {
|
|
1342
|
-
|
|
1422
|
+
// Trim from the front so the most recent proposals survive a reload even
|
|
1423
|
+
// if a prior (or tampered) persisted state exceeded the cap.
|
|
1424
|
+
const bounded =
|
|
1425
|
+
list.length > this.maxPendingPatches
|
|
1426
|
+
? list.slice(list.length - this.maxPendingPatches)
|
|
1427
|
+
: list;
|
|
1428
|
+
for (const patch of bounded) {
|
|
1343
1429
|
if (patch && patch.patchId) {
|
|
1344
1430
|
map.set(patch.patchId, patch);
|
|
1345
1431
|
}
|
|
@@ -194,7 +194,11 @@ export class BackgroundTaskManager extends EventEmitter {
|
|
|
194
194
|
return history;
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
-
|
|
197
|
+
// offset + null === offset, so an offset-only page (no limit) used to
|
|
198
|
+
// slice(offset, offset) === [] and lose every item past the offset. Use
|
|
199
|
+
// history.length as the end when limit is null.
|
|
200
|
+
const end = limit === null ? history.length : offset + limit;
|
|
201
|
+
const items = history.slice(offset, end);
|
|
198
202
|
return {
|
|
199
203
|
items,
|
|
200
204
|
total: history.length,
|