chainlesschain 0.165.6 → 0.165.9
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 +2 -1
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-vfoDb6HZ.js → AIOps-DxwjrnEA.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-Cm5f7p93.js → ActionButton-JdbYowzn.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-yRuvgWxa.js → Analytics-C06GCahv.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-BROsC4h1.js → AppLayout-BUVEEyi1.js} +4 -4
- package/src/assets/web-panel/assets/{Artifacts-CimHApb1.js → Artifacts-D_ORzkJd.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DI8kr8zI.js → Audit-8o_Y5ejG.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-DSLzKy-n.js → BackgroundAgents-DrkHd5VU.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DkH_n2r1.js → Backup-CKBZCX11.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-CKSrUoRA.js → BaseInput-C8HkI399.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-ClwfMXUS.js → Chat-zb2H2Wux.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-CjMaqfL7.js → ChatBubbleRenderer-BDcNpU_F.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-BYTehcQG.js → Checkbox-MwPtQmNz.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-B8AMcp6J.js → Codegen-3p5QCkFK.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BNSogPo3.js → Col-BPLlhn52.js} +1 -1
- package/src/assets/web-panel/assets/{Community-JxPvGb8O.js → Community-C-3dBNOM.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DF7bFAgE.js → Compact-BUcy-F_b.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-Bvhqnwrq.js → Compliance-CI8NxT8m.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BDS0CJvM.js → Cowork-DaDEBS-Q.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-DqvRfxoQ.js → Cron-BSv9HXu5.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CDcIvnqS.js → Crosschain-yuiKlJmv.js} +1 -1
- package/src/assets/web-panel/assets/{DID-D7jaUxU3.js → DID-D6LfldB0.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-B5A18wEV.js → Dashboard-CBhLqG61.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-_6IVkGag.js → Dropdown-BG8pIl3O.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-C9PeiKCG.js → EmailListRenderer-CY92VIE6.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-DXjuEHrX.js → FamilyGuardDashboard-1Q_ehauM.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-B4IAR9zv.js → Federation-D3XirJIU.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-CxQeSNx1.js → FormItemContext-DfI9UuGZ.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-B8GS-Y3N.js → GenericCardRenderer-IeCZk2m7.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BS8SouUX.js → Git-DzK4IJAZ.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-Dq9aYb5Q.js → Governance-BHf5KfmQ.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-BrCEe9AJ.js → Inference-BmaxSALS.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DybOpiY2.js → KnowledgeGraph-BgePFLA9.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DBpzbRfx.js → Logs-nqgxpOc4.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-xkX6izBt.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-Cc7CCSCu.js → Marketplace-Bu8to-86.js} +1 -1
- package/src/assets/web-panel/assets/McpTools-BFWTzEk0.js +4 -0
- package/src/assets/web-panel/assets/{Memory-KCqlp9ol.js → Memory-B026G2GA.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-Bys84ySN.js → MobileBridge-CM2Eeg6I.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-B-6qU-je.js → MobileProjects-B79Ob3hy.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BgY-fvCq.js → Mtc-CxevSZuV.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-B8pCmqQJ.js → MtcAudit-X396cPEX.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-BbOmYutA.js → Multisig-HWIB_aZ1.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-BocLQz_M.js → NLProgramming-gnYD1Xwy.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-CSwbxEop.js → Notes-Dn2Gf_J1.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-CqFNSYG3.js → NotificationSettings-BRKBQ5rq.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-C6gMfAk7.js → OrderTableRenderer-Dy___Cgo.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-QrDXVdMJ.js → Organization-cqfccxnt.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Cxntotjt.js → Overflow-CSX4FHN3.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CIdBOwNq.js → P2P-Bwa4aghp.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-CT5aP8rD.js → PdhVaultBrowser-Dhszyjig.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-DH7OM8XU.js → Permissions-CXzTyk6e.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-CnJqbWce.js → PersonalDataHub-CFCAAJbb.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-5C3HG1kH.js → Pipeline-BPJbx6xt.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-B4yIp7xK.js → Privacy-BbiXvEHz.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-BMvt-2M0.js → ProjectInit-B-s7-wSD.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CvSTEMRG.js → ProjectSettings-Dyug206y.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-BKBJxEek.js → Projects-BtAI5Fwo.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-BdwUqFWN.js → Providers-JpIPmz6N.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-DtnCKlTm.js → QrScannerModal-CZdoN64A.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-sTbgwyNr.js → QuickAsk-BwvnoRIT.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-Bzr14gSb.js → Recommend-ASMlMQrD.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-C_TF5IaJ.js → RemoteSession-BiJzKFKi.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-GCAM4H2K.js → Reputation-C80TWLIO.js} +1 -1
- package/src/assets/web-panel/assets/{Row-Dir0r6OQ.js → Row-C1VNmjmX.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CpGnlecX.js → RssFeed-T2MyGUlG.js} +3 -3
- package/src/assets/web-panel/assets/{Search-DMMamC6u.js → Search-DXM6O83L.js} +1 -1
- package/src/assets/web-panel/assets/{Security-yqay5yG-.js → Security-nv69kU7W.js} +3 -3
- package/src/assets/web-panel/assets/{Services-C5i2wh9G.js → Services-AyHWe7Qj.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-vUqk35yj.js → Skeleton-D6PWLxFI.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DzcSkhot.js → Skills-BqVeOmNQ.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CB6qbYNr.js → Sla-BegIPl9M.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BHUI7cox.js → SpeechSettings-CKJn3xk-.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-D-RrsxTJ.js → SyncSettings-Th4cnAMl.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-DFxdOJiq.js → Tasks-BuKfBroh.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-SKAob_Aq.js → Templates-CMuWN8Ac.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-BPfsfHQ-.js → Tenant-C4je8E8Q.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-8iw7FpUf.js → Terminal-agJESOcO.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-C4Gjj5Su.js → TimelineRenderer-D2qDuVZ_.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-COYhN18e.js → Tokens-Cvmn99rH.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-B-JzXcf6.js → Trigger-D_QYIHH8.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BJ5bg0nI.js → Trust-BmzvQLnX.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-BG_ByRMf.js → UkeySign-D_LopHwH.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-B3kOnSiU.js → VideoEditing-DoWl3PhQ.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-CcoGFnK7.js → Wallet-5NYcAkxe.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DdT8vRC_.js → WebAuthn-B-_Q3ewp.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-CZu3M9N8.js → WorkflowEditor-CHET-gi2.js} +1 -1
- package/src/assets/web-panel/assets/{chat-DxJt3Qba.js → chat-C6nvb-n6.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DdYfwJaB.js → colors-CTDE9LTX.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BG3SUzwj.js → compact-item-KnemdF8D.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-By51z2-1.js → createContext-DUJR3Uek.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-1DqLH1KX.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-B0apZ3KJ.js → hasIn-CFNTaby8.js} +1 -1
- package/src/assets/web-panel/assets/{index-ZxtP8jG7.js → index-65HO56Bv.js} +1 -1
- package/src/assets/web-panel/assets/{index-Da_WBdLX.js → index-B8RtbSkV.js} +1 -1
- package/src/assets/web-panel/assets/{index-BBPf3TpM.js → index-BHqSqnW7.js} +1 -1
- package/src/assets/web-panel/assets/{index-BP94CrBV.js → index-BTetEUWd.js} +1 -1
- package/src/assets/web-panel/assets/{index-p1_8SbI1.js → index-BXWg1crv.js} +1 -1
- package/src/assets/web-panel/assets/{index-BWF8_mkx.js → index-BdiC4LOs.js} +1 -1
- package/src/assets/web-panel/assets/index-BhJtcPWo.js +1 -0
- package/src/assets/web-panel/assets/{index-SQqOlR3d.js → index-BuizJo2E.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpjZhgNd.js → index-BwZM1rod.js} +1 -1
- package/src/assets/web-panel/assets/{index-CzmQElZy.js → index-C96N9xeL.js} +1 -1
- package/src/assets/web-panel/assets/{index-bP_VlDb4.js → index-CHfUdnJH.js} +1 -1
- package/src/assets/web-panel/assets/{index-ZFbps9po.js → index-CKvBF3Ov.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaIz0NAW.js → index-CSD9_I2_.js} +1 -1
- package/src/assets/web-panel/assets/{index-BewKYrX9.js → index-Cc7dbl_p.js} +1 -1
- package/src/assets/web-panel/assets/{index-CNIxXMmN.js → index-CcF0D7UZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Q2SCX-MI.js → index-Ceu92a8D.js} +1 -1
- package/src/assets/web-panel/assets/{index-DE76D-kA.js → index-CnLpuTAU.js} +1 -1
- package/src/assets/web-panel/assets/index-Cq8MWPDT.js +1 -0
- package/src/assets/web-panel/assets/{index-BkvcEo4p.js → index-CquKnw5r.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cp6e-hGw.js → index-CyEtHvEE.js} +1 -1
- package/src/assets/web-panel/assets/{index-BLIbGOLX.js → index-DF-fcTvQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DCn8IcxV.js → index-DF1Y0Vuw.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bissefox.js → index-DJyPeBBk.js} +3 -3
- package/src/assets/web-panel/assets/{index-BZ_0qm4g.js → index-DP-PbO11.js} +1 -1
- package/src/assets/web-panel/assets/{index-kf57LJ93.js → index-DZgCRMxk.js} +1 -1
- package/src/assets/web-panel/assets/{index-BYINoRLK.js → index-DfJzS3Qa.js} +1 -1
- package/src/assets/web-panel/assets/{index-3jWkIu5j.js → index-DqPpJkte.js} +1 -1
- package/src/assets/web-panel/assets/{index-B5rLiEo0.js → index-DzReoLyh.js} +1 -1
- package/src/assets/web-panel/assets/{index-CW93tZDv.js → index-JGTiDeOW.js} +1 -1
- package/src/assets/web-panel/assets/{index-C1C9i79A.js → index-NUR0If7O.js} +1 -1
- package/src/assets/web-panel/assets/{index-CAhHirVH.js → index-NtAcnJYW.js} +1 -1
- package/src/assets/web-panel/assets/{index-RD6O-0C6.js → index-OmuhFYKE.js} +1 -1
- package/src/assets/web-panel/assets/{index-oxRrmFO9.js → index-Wlc7o_C8.js} +1 -1
- package/src/assets/web-panel/assets/{index-B3rWuPMW.js → index-bxTPfdri.js} +1 -1
- package/src/assets/web-panel/assets/{index-BIrJfqO4.js → index-k6uorYmf.js} +1 -1
- package/src/assets/web-panel/assets/{index-BfWYsB9t.js → index-ox6mIwE2.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bos5_aMV.js → index-rVDD7AAR.js} +1 -1
- package/src/assets/web-panel/assets/{index-CWEuZWCK.js → index-u0h6QqVV.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dz49VOyQ.js → index-v-mtxmWH.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BWJktcg8.js → initDefaultProps-qEt8dI-t.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BEXBzUFV.js → motion-DetKPWy-.js} +1 -1
- package/src/assets/web-panel/assets/{move-BUKwn2sx.js → move-BeNYeDV2.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-FTI7btqQ.js → mtc-parser-C0q0MK_T.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CsLtSPH3.js → omit-DLKkrKpE.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DWZxsT_S.js → pickAttrs-Bw1tWsY8.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-Bcfs43CX.js → placementArrow-DeesBLbd.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-a9bcC1p-.js → responsiveObserve-bqLhxHhn.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BDTzgOXN.js → slide-DGCXRoQm.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-Iq1j_HUg.js → statusUtils-H-re3Egl.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-DAZEYxeh.js → styleChecker-BXg4qGX_.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DVkjyDrh.js → useFlexGapSupport-CKLb2KA6.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-wXTpNTHt.js → useFs-CTAhHeyw.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-CtQM_aZr.js → usePersonalDataHub-BQ4pDh5g.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-hjEoG85v.js → vnode-jrSK6j4j.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-BHVpyKg_.js → zoom-fOQE24pw.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +3 -3
- package/src/commands/agent.js +91 -60
- package/src/commands/git.js +39 -0
- package/src/commands/plugin.js +17 -2
- package/src/commands/session-group.js +131 -0
- package/src/commands/session-location.js +48 -0
- package/src/commands/session.js +11 -0
- package/src/commands/sync-providers.js +4 -1
- package/src/commands/update.js +1 -0
- package/src/data/changelog.json +40 -1
- package/src/gateways/ws/mcp-topic-handlers.js +167 -0
- package/src/gateways/ws/ws-agent-handler.js +20 -12
- package/src/harness/jsonl-session-store.js +279 -37
- package/src/harness/mcp-client.js +701 -91
- package/src/harness/session-index.js +15 -4
- package/src/lib/agent-network.js +166 -29
- package/src/lib/agent-router.js +62 -6
- package/src/lib/agent-sandbox.js +7 -1
- package/src/lib/agent-worktree.js +8 -1
- package/src/lib/auto-mode-safety-classifier.js +3 -17
- package/src/lib/background-agent-keeper-protocol.js +26 -6
- package/src/lib/background-agent-supervisor.js +17 -1
- package/src/lib/browser-evidence.js +1405 -0
- package/src/lib/chrome-connector.js +465 -79
- package/src/lib/claude-code-bridge.js +159 -54
- package/src/lib/claude-project-auto-memory.js +481 -0
- package/src/lib/claude-project-storage-layout.js +104 -0
- package/src/lib/cloud/cloud-client.js +40 -0
- package/src/lib/cowork-workflow.js +69 -6
- package/src/lib/execution-location-local-supervisor.mjs +226 -0
- package/src/lib/execution-location-runner-lifecycle.js +991 -0
- package/src/lib/execution-location-target-preflight.js +333 -0
- package/src/lib/execution-location-target.js +783 -13
- package/src/lib/external-agent-adapters.js +269 -0
- package/src/lib/file-lines.js +6 -1
- package/src/lib/gateway-client-resilience.js +571 -0
- package/src/lib/gitlab-mr-worktree.js +176 -0
- package/src/lib/hooks-v2-producers.js +119 -15
- package/src/lib/hooks-v2-workspace-context.js +44 -1
- package/src/lib/host-resource-budget.js +295 -0
- package/src/lib/ide-context.js +15 -2
- package/src/lib/ipfs-storage.js +127 -25
- package/src/lib/llm-config-defaults.js +43 -0
- package/src/lib/mcp-lifecycle-authority.js +887 -0
- package/src/lib/mcp-oauth.js +101 -20
- package/src/lib/mcp-tls.js +103 -3
- package/src/lib/orchestrator.js +47 -0
- package/src/lib/paths.js +260 -32
- package/src/lib/permission-request.js +48 -0
- package/src/lib/plugin-runtime/bin.js +3 -1
- package/src/lib/plugin-runtime/hooks.js +3 -1
- package/src/lib/plugin-runtime/install.js +117 -1
- package/src/lib/plugin-runtime/lsp.js +4 -4
- package/src/lib/plugin-runtime/marketplace-archive-source.js +40 -5
- package/src/lib/plugin-runtime/marketplace-catalog.js +13 -2
- package/src/lib/plugin-runtime/marketplace-command-descriptor.js +343 -0
- package/src/lib/plugin-runtime/marketplace-command-source.js +580 -0
- package/src/lib/plugin-runtime/marketplace-source-adapter.js +33 -8
- package/src/lib/plugin-runtime/mcp.js +3 -1
- package/src/lib/plugin-runtime/monitors.js +3 -1
- package/src/lib/plugin-runtime/remote-source.js +151 -6
- package/src/lib/plugin-runtime/settings.js +3 -1
- package/src/lib/plugin-runtime/trust.js +274 -13
- package/src/lib/process-execution-broker/credential-agent.js +210 -41
- package/src/lib/process-execution-broker/index.js +15 -1
- package/src/lib/process-execution-broker/linux-cgroup-v2.js +391 -0
- package/src/lib/process-execution-broker/platform-sandbox.js +50 -28
- package/src/lib/project-mcp-trust.js +165 -10
- package/src/lib/resume-session.js +9 -6
- package/src/lib/session-core-singletons.js +26 -11
- package/src/lib/session-host-lease.js +52 -16
- package/src/lib/session-lifecycle-scope.js +153 -0
- package/src/lib/session-message-fabric.js +168 -21
- package/src/lib/session-projection.js +244 -4
- package/src/lib/session-store-guard.js +3 -1
- package/src/lib/session-workbench-store.js +466 -0
- package/src/lib/shell-approval.js +7 -5
- package/src/lib/spellcheck.js +211 -0
- package/src/lib/sub-agent-context.js +9 -9
- package/src/lib/sync-cli-db.js +485 -129
- package/src/lib/sync-credentials.js +31 -20
- package/src/lib/web-fetch.js +112 -40
- package/src/lib/web-search.js +127 -61
- package/src/lib/workflow-engine.js +42 -11
- package/src/lib/workspace-trust.js +793 -0
- package/src/repl/agent-repl.js +124 -5
- package/src/repl/permission-prompt.js +10 -12
- package/src/runtime/agent-core.js +311 -18
- package/src/runtime/agent-runtime.js +12 -1
- package/src/runtime/bootstrap.js +37 -13
- package/src/runtime/coding-agent-contract-shared.cjs +11 -4
- package/src/runtime/headless-runner.js +234 -36
- package/src/runtime/headless-stream.js +181 -6
- package/src/runtime/mcp-config.js +298 -8
- package/src/runtime/policies/agent-policy.js +8 -0
- package/src/runtime/status-diagnostics-lite.js +9 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-CFyt8iUd.js +0 -1
- package/src/assets/web-panel/assets/McpTools-DFaIhOfu.js +0 -7
- package/src/assets/web-panel/assets/devWarning-DorRZcI9.js +0 -1
- package/src/assets/web-panel/assets/index-BETiL0a3.js +0 -1
- package/src/assets/web-panel/assets/index-BhAVHuW8.js +0 -1
|
@@ -12,7 +12,12 @@
|
|
|
12
12
|
import fs from "node:fs";
|
|
13
13
|
import path from "node:path";
|
|
14
14
|
import { createHash, randomUUID } from "node:crypto";
|
|
15
|
-
import { ensureDir
|
|
15
|
+
import { ensureDir } from "./paths.js";
|
|
16
|
+
import {
|
|
17
|
+
ensureTrustedSessionLifecycleScope,
|
|
18
|
+
resolveTrustedSessionLifecycleScope,
|
|
19
|
+
sessionLifecycleFabricDirectory,
|
|
20
|
+
} from "./session-lifecycle-scope.js";
|
|
16
21
|
import { withFileLock } from "./with-file-lock.js";
|
|
17
22
|
|
|
18
23
|
export const SESSION_MESSAGE_FABRIC_SCHEMA =
|
|
@@ -31,6 +36,7 @@ export const SESSION_MESSAGE_RECEIPT_STATUSES = Object.freeze([
|
|
|
31
36
|
"held",
|
|
32
37
|
"refused",
|
|
33
38
|
"full",
|
|
39
|
+
"rate_limited",
|
|
34
40
|
"expired",
|
|
35
41
|
]);
|
|
36
42
|
|
|
@@ -38,6 +44,8 @@ export const SESSION_MESSAGE_FABRIC_LIMITS = Object.freeze({
|
|
|
38
44
|
maxMessageBytes: 256 * 1024,
|
|
39
45
|
maxPendingPerRecipient: 100,
|
|
40
46
|
maxReceiptHistory: 5_000,
|
|
47
|
+
maxMessagesPerSenderWindow: 120,
|
|
48
|
+
senderRateWindowMs: 60_000,
|
|
41
49
|
defaultTtlMs: 24 * 60 * 60 * 1000,
|
|
42
50
|
maxTtlMs: 7 * 24 * 60 * 60 * 1000,
|
|
43
51
|
});
|
|
@@ -153,6 +161,9 @@ function emptyState(now) {
|
|
|
153
161
|
channels: [],
|
|
154
162
|
messages: [],
|
|
155
163
|
receipts: [],
|
|
164
|
+
// Per-sender fixed windows are durable so a new CLI process cannot evade
|
|
165
|
+
// the same-host admission limit by reopening the fabric state file.
|
|
166
|
+
rateBuckets: [],
|
|
156
167
|
};
|
|
157
168
|
return { ...state, digest: digestValue(state) };
|
|
158
169
|
}
|
|
@@ -326,6 +337,41 @@ function updateReceipt(state, message, status, reason, now) {
|
|
|
326
337
|
return receipt;
|
|
327
338
|
}
|
|
328
339
|
|
|
340
|
+
function pruneRateBuckets(state, now, windowMs) {
|
|
341
|
+
if (!Array.isArray(state.rateBuckets) || state.rateBuckets.length === 0) {
|
|
342
|
+
return false;
|
|
343
|
+
}
|
|
344
|
+
const before = state.rateBuckets.length;
|
|
345
|
+
state.rateBuckets = state.rateBuckets.filter(
|
|
346
|
+
(bucket) => now < bucket.windowStartedAt + windowMs,
|
|
347
|
+
);
|
|
348
|
+
return state.rateBuckets.length !== before;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function consumeSenderRate(state, senderAuthority, now, limit, windowMs) {
|
|
352
|
+
state.rateBuckets ??= [];
|
|
353
|
+
let bucket = state.rateBuckets.find(
|
|
354
|
+
(entry) => entry.senderAuthority === senderAuthority,
|
|
355
|
+
);
|
|
356
|
+
if (!bucket || now >= bucket.windowStartedAt + windowMs) {
|
|
357
|
+
if (!bucket) {
|
|
358
|
+
bucket = { senderAuthority, windowStartedAt: now, count: 0 };
|
|
359
|
+
state.rateBuckets.push(bucket);
|
|
360
|
+
} else {
|
|
361
|
+
bucket.windowStartedAt = now;
|
|
362
|
+
bucket.count = 0;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
if (bucket.count >= limit) {
|
|
366
|
+
return {
|
|
367
|
+
allowed: false,
|
|
368
|
+
retryAfterMs: Math.max(1, bucket.windowStartedAt + windowMs - now),
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
bucket.count += 1;
|
|
372
|
+
return { allowed: true, retryAfterMs: 0 };
|
|
373
|
+
}
|
|
374
|
+
|
|
329
375
|
function trimReceiptHistory(state, limit) {
|
|
330
376
|
if (state.receipts.length <= limit) return false;
|
|
331
377
|
const protectedIds = new Set(
|
|
@@ -368,12 +414,18 @@ function compactSettledMessages(state) {
|
|
|
368
414
|
}
|
|
369
415
|
|
|
370
416
|
function applyExpectedMessage(state, channel, message, recipient, now) {
|
|
371
|
-
if (recipient.policy === "hold") {
|
|
372
|
-
updateReceipt(state, message, "held", "policy_hold", now);
|
|
373
|
-
return false;
|
|
374
|
-
}
|
|
375
417
|
if (recipient.policy === "refuse") {
|
|
376
418
|
updateReceipt(state, message, "refused", "policy_refuse", now);
|
|
419
|
+
} else if (recipient.policy === "hold") {
|
|
420
|
+
updateReceipt(state, message, "held", "policy_hold", now);
|
|
421
|
+
return false;
|
|
422
|
+
} else if (recipient.online !== true) {
|
|
423
|
+
// Durable admission is not delivery. In particular, an offline target
|
|
424
|
+
// must never produce a success-looking `delivered` receipt merely because
|
|
425
|
+
// this host appended the payload to its local queue. Reconnect promotes
|
|
426
|
+
// the exact retained sequence through the same policy gate.
|
|
427
|
+
updateReceipt(state, message, "held", "recipient_offline", now);
|
|
428
|
+
return false;
|
|
377
429
|
} else {
|
|
378
430
|
const receipt = updateReceipt(state, message, "delivered", null, now);
|
|
379
431
|
message.deliveredAt = now;
|
|
@@ -455,6 +507,7 @@ function validateState(state) {
|
|
|
455
507
|
!Array.isArray(state.channels) ||
|
|
456
508
|
!Array.isArray(state.messages) ||
|
|
457
509
|
!Array.isArray(state.receipts) ||
|
|
510
|
+
(state.rateBuckets != null && !Array.isArray(state.rateBuckets)) ||
|
|
458
511
|
typeof state.digest !== "string"
|
|
459
512
|
) {
|
|
460
513
|
fail("invalid envelope");
|
|
@@ -520,29 +573,56 @@ function validateState(state) {
|
|
|
520
573
|
fail("invalid receipt");
|
|
521
574
|
}
|
|
522
575
|
}
|
|
576
|
+
const bucketAuthorities = new Set();
|
|
577
|
+
for (const bucket of state.rateBuckets || []) {
|
|
578
|
+
if (
|
|
579
|
+
typeof bucket?.senderAuthority !== "string" ||
|
|
580
|
+
bucketAuthorities.has(bucket.senderAuthority) ||
|
|
581
|
+
!Number.isSafeInteger(bucket.windowStartedAt) ||
|
|
582
|
+
bucket.windowStartedAt < 0 ||
|
|
583
|
+
!Number.isSafeInteger(bucket.count) ||
|
|
584
|
+
bucket.count < 1
|
|
585
|
+
) {
|
|
586
|
+
fail("invalid rate bucket");
|
|
587
|
+
}
|
|
588
|
+
bucketAuthorities.add(bucket.senderAuthority);
|
|
589
|
+
}
|
|
523
590
|
return state;
|
|
524
591
|
}
|
|
525
592
|
|
|
526
|
-
export function defaultSessionMessageFabricPath() {
|
|
527
|
-
return
|
|
593
|
+
export function defaultSessionMessageFabricPath(options = {}) {
|
|
594
|
+
return resolveTrustedSessionLifecycleScope(options).messageFabricStatePath;
|
|
528
595
|
}
|
|
529
596
|
|
|
530
597
|
export class SessionMessageFabric {
|
|
531
|
-
constructor({
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
598
|
+
constructor(options = {}) {
|
|
599
|
+
const {
|
|
600
|
+
statePath: configuredStatePath,
|
|
601
|
+
launchEnv,
|
|
602
|
+
cwd,
|
|
603
|
+
now = () => Date.now(),
|
|
604
|
+
createId = randomUUID,
|
|
605
|
+
lock = withFileLock,
|
|
606
|
+
lockTimeoutMs = 10_000,
|
|
607
|
+
maxMessageBytes = SESSION_MESSAGE_FABRIC_LIMITS.maxMessageBytes,
|
|
608
|
+
maxPendingPerRecipient = SESSION_MESSAGE_FABRIC_LIMITS.maxPendingPerRecipient,
|
|
609
|
+
maxReceiptHistory = SESSION_MESSAGE_FABRIC_LIMITS.maxReceiptHistory,
|
|
610
|
+
maxMessagesPerSenderWindow = SESSION_MESSAGE_FABRIC_LIMITS.maxMessagesPerSenderWindow,
|
|
611
|
+
senderRateWindowMs = SESSION_MESSAGE_FABRIC_LIMITS.senderRateWindowMs,
|
|
612
|
+
defaultTtlMs = SESSION_MESSAGE_FABRIC_LIMITS.defaultTtlMs,
|
|
613
|
+
maxTtlMs = SESSION_MESSAGE_FABRIC_LIMITS.maxTtlMs,
|
|
614
|
+
} = options;
|
|
615
|
+
const usesDefaultStatePath = configuredStatePath === undefined;
|
|
616
|
+
const lifecycleScope = usesDefaultStatePath
|
|
617
|
+
? resolveTrustedSessionLifecycleScope({ launchEnv, cwd })
|
|
618
|
+
: null;
|
|
619
|
+
const statePath = usesDefaultStatePath
|
|
620
|
+
? lifecycleScope.messageFabricStatePath
|
|
621
|
+
: configuredStatePath;
|
|
543
622
|
this.statePath = path.resolve(statePath);
|
|
623
|
+
this._lifecycleScope = lifecycleScope;
|
|
544
624
|
this._secureDefaultDirectory =
|
|
545
|
-
|
|
625
|
+
usesDefaultStatePath && lifecycleScope.kind === "legacy";
|
|
546
626
|
this._now = now;
|
|
547
627
|
this._createId = createId;
|
|
548
628
|
this._lock = lock;
|
|
@@ -560,6 +640,14 @@ export class SessionMessageFabric {
|
|
|
560
640
|
maxReceiptHistory,
|
|
561
641
|
SESSION_MESSAGE_FABRIC_LIMITS.maxReceiptHistory,
|
|
562
642
|
),
|
|
643
|
+
maxMessagesPerSenderWindow: positiveInteger(
|
|
644
|
+
maxMessagesPerSenderWindow,
|
|
645
|
+
SESSION_MESSAGE_FABRIC_LIMITS.maxMessagesPerSenderWindow,
|
|
646
|
+
),
|
|
647
|
+
senderRateWindowMs: positiveInteger(
|
|
648
|
+
senderRateWindowMs,
|
|
649
|
+
SESSION_MESSAGE_FABRIC_LIMITS.senderRateWindowMs,
|
|
650
|
+
),
|
|
563
651
|
defaultTtlMs: positiveInteger(
|
|
564
652
|
defaultTtlMs,
|
|
565
653
|
SESSION_MESSAGE_FABRIC_LIMITS.defaultTtlMs,
|
|
@@ -573,6 +661,14 @@ export class SessionMessageFabric {
|
|
|
573
661
|
|
|
574
662
|
_ensureDirectory() {
|
|
575
663
|
const directory = path.dirname(this.statePath);
|
|
664
|
+
if (this._lifecycleScope?.kind === "project") {
|
|
665
|
+
ensureTrustedSessionLifecycleScope(this._lifecycleScope, {
|
|
666
|
+
extraDirectories: [
|
|
667
|
+
sessionLifecycleFabricDirectory(this._lifecycleScope),
|
|
668
|
+
],
|
|
669
|
+
});
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
576
672
|
if (this._secureDefaultDirectory) {
|
|
577
673
|
ensureDir(directory);
|
|
578
674
|
return;
|
|
@@ -667,13 +763,24 @@ export class SessionMessageFabric {
|
|
|
667
763
|
}
|
|
668
764
|
const now = this._now();
|
|
669
765
|
const swept = sweepExpired(state, now);
|
|
766
|
+
const prunedRateBuckets = pruneRateBuckets(
|
|
767
|
+
state,
|
|
768
|
+
now,
|
|
769
|
+
this._limits.senderRateWindowMs,
|
|
770
|
+
);
|
|
670
771
|
const outcome = mutator(state, now) || { value: undefined };
|
|
671
772
|
const compacted = compactSettledMessages(state);
|
|
672
773
|
const trimmed = trimReceiptHistory(
|
|
673
774
|
state,
|
|
674
775
|
this._limits.maxReceiptHistory,
|
|
675
776
|
);
|
|
676
|
-
if (
|
|
777
|
+
if (
|
|
778
|
+
swept ||
|
|
779
|
+
prunedRateBuckets ||
|
|
780
|
+
compacted ||
|
|
781
|
+
trimmed ||
|
|
782
|
+
outcome.changed === true
|
|
783
|
+
) {
|
|
677
784
|
state.revision += 1;
|
|
678
785
|
state.updatedAt = now;
|
|
679
786
|
state.digest = digestValue(stateWithoutDigest(state));
|
|
@@ -757,6 +864,13 @@ export class SessionMessageFabric {
|
|
|
757
864
|
};
|
|
758
865
|
state.endpoints.push(endpoint);
|
|
759
866
|
}
|
|
867
|
+
for (const channel of state.channels.filter(
|
|
868
|
+
(entry) =>
|
|
869
|
+
entry.recipientAuthority === endpoint.authorityId &&
|
|
870
|
+
entry.recipientEpoch === endpoint.epoch,
|
|
871
|
+
)) {
|
|
872
|
+
promoteChannel(state, channel, now);
|
|
873
|
+
}
|
|
760
874
|
return {
|
|
761
875
|
changed: true,
|
|
762
876
|
value: { ...clone(endpoint), address: endpointAddress(endpoint) },
|
|
@@ -783,6 +897,13 @@ export class SessionMessageFabric {
|
|
|
783
897
|
const endpoint = requireEndpoint(state, selector);
|
|
784
898
|
endpoint.online = true;
|
|
785
899
|
endpoint.updatedAt = now;
|
|
900
|
+
for (const channel of state.channels.filter(
|
|
901
|
+
(entry) =>
|
|
902
|
+
entry.recipientAuthority === endpoint.authorityId &&
|
|
903
|
+
entry.recipientEpoch === endpoint.epoch,
|
|
904
|
+
)) {
|
|
905
|
+
promoteChannel(state, channel, now);
|
|
906
|
+
}
|
|
786
907
|
return {
|
|
787
908
|
changed: true,
|
|
788
909
|
value: { ...clone(endpoint), address: endpointAddress(endpoint) },
|
|
@@ -913,6 +1034,32 @@ export class SessionMessageFabric {
|
|
|
913
1034
|
}
|
|
914
1035
|
return { value: clone(duplicate) };
|
|
915
1036
|
}
|
|
1037
|
+
const rate = consumeSenderRate(
|
|
1038
|
+
state,
|
|
1039
|
+
sender.authorityId,
|
|
1040
|
+
now,
|
|
1041
|
+
this._limits.maxMessagesPerSenderWindow,
|
|
1042
|
+
this._limits.senderRateWindowMs,
|
|
1043
|
+
);
|
|
1044
|
+
if (!rate.allowed) {
|
|
1045
|
+
const receipt = {
|
|
1046
|
+
messageId: id,
|
|
1047
|
+
senderAuthority: sender.authorityId,
|
|
1048
|
+
recipientAuthority: recipient?.authorityId || null,
|
|
1049
|
+
recipientEpoch: recipient?.epoch || null,
|
|
1050
|
+
sequence: requestedSequence,
|
|
1051
|
+
payloadDigest,
|
|
1052
|
+
status: "rate_limited",
|
|
1053
|
+
reason: "sender_rate_limit",
|
|
1054
|
+
retryAfterMs: rate.retryAfterMs,
|
|
1055
|
+
createdAt: now,
|
|
1056
|
+
updatedAt: now,
|
|
1057
|
+
idleNotifiedAt: null,
|
|
1058
|
+
readAt: null,
|
|
1059
|
+
};
|
|
1060
|
+
state.receipts.push(receipt);
|
|
1061
|
+
return { changed: true, value: clone(receipt) };
|
|
1062
|
+
}
|
|
916
1063
|
if (!recipient) {
|
|
917
1064
|
const receipt = {
|
|
918
1065
|
messageId: id,
|
|
@@ -84,6 +84,29 @@ function asText(value) {
|
|
|
84
84
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
function boundedText(value, maxChars = 240) {
|
|
88
|
+
let text = null;
|
|
89
|
+
if (typeof value === "string") text = value;
|
|
90
|
+
else if (value && typeof value === "object") {
|
|
91
|
+
text =
|
|
92
|
+
value.summary ||
|
|
93
|
+
value.title ||
|
|
94
|
+
value.question ||
|
|
95
|
+
value.text ||
|
|
96
|
+
value.answer ||
|
|
97
|
+
null;
|
|
98
|
+
}
|
|
99
|
+
if (typeof text !== "string") return null;
|
|
100
|
+
const normalized = text
|
|
101
|
+
.replace(/[\u0000-\u001f\u007f]+/gu, " ")
|
|
102
|
+
.replace(/\s+/gu, " ")
|
|
103
|
+
.trim();
|
|
104
|
+
if (!normalized) return null;
|
|
105
|
+
return normalized.length <= maxChars
|
|
106
|
+
? normalized
|
|
107
|
+
: `${normalized.slice(0, Math.max(0, maxChars - 1))}…`;
|
|
108
|
+
}
|
|
109
|
+
|
|
87
110
|
function asCount(value) {
|
|
88
111
|
const number = Number(value);
|
|
89
112
|
return Number.isFinite(number) && number > 0 ? Math.floor(number) : 0;
|
|
@@ -646,6 +669,178 @@ function messagingSummary(sessionIds, fabric) {
|
|
|
646
669
|
};
|
|
647
670
|
}
|
|
648
671
|
|
|
672
|
+
function pendingInteractionCount(source) {
|
|
673
|
+
if (Array.isArray(source?.pendingInteractions)) {
|
|
674
|
+
return Math.min(1_000, source.pendingInteractions.length);
|
|
675
|
+
}
|
|
676
|
+
return Math.min(1_000, asCount(source?.pendingInteractions));
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
function liveToolSummary(source) {
|
|
680
|
+
const candidate =
|
|
681
|
+
source?.liveTool || source?.currentTool || source?.recent?.call || null;
|
|
682
|
+
const name = boundedText(candidate?.name || candidate?.tool || candidate, 96);
|
|
683
|
+
if (!name) return null;
|
|
684
|
+
return {
|
|
685
|
+
name,
|
|
686
|
+
status: boundedText(candidate?.status || source?.toolStatus, 48),
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
function focusSummary(source, state) {
|
|
691
|
+
const pendingQuestion = boundedText(source?.pendingQuestion, 240);
|
|
692
|
+
const todos = Array.isArray(source?.todos) ? source.todos : [];
|
|
693
|
+
const latestTodo = boundedText(
|
|
694
|
+
source?.latestTodo || source?.todo?.latest || todos.at(-1),
|
|
695
|
+
240,
|
|
696
|
+
);
|
|
697
|
+
const settledAnswer = boundedText(
|
|
698
|
+
source?.settledAnswer || source?.lastAnswer || source?.answerSummary,
|
|
699
|
+
240,
|
|
700
|
+
);
|
|
701
|
+
const liveTool = liveToolSummary(source);
|
|
702
|
+
return {
|
|
703
|
+
active: ["working", "needs_input", "blocked"].includes(state),
|
|
704
|
+
liveTool,
|
|
705
|
+
latestTodo,
|
|
706
|
+
pendingQuestion,
|
|
707
|
+
settledAnswer,
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
function locationSummary(source, kind) {
|
|
712
|
+
const hint = String(
|
|
713
|
+
source?.executionLocation?.kind ||
|
|
714
|
+
source?.executionLocation ||
|
|
715
|
+
source?.location?.kind ||
|
|
716
|
+
source?.location ||
|
|
717
|
+
source?.origin ||
|
|
718
|
+
"",
|
|
719
|
+
)
|
|
720
|
+
.trim()
|
|
721
|
+
.toLowerCase();
|
|
722
|
+
const locationKind =
|
|
723
|
+
source?.cloud === true || hint === "cloud"
|
|
724
|
+
? "cloud"
|
|
725
|
+
: kind === "remote"
|
|
726
|
+
? "remote"
|
|
727
|
+
: "local";
|
|
728
|
+
const connection = String(source?.connection || source?.connectivity || "")
|
|
729
|
+
.trim()
|
|
730
|
+
.toLowerCase();
|
|
731
|
+
const offline =
|
|
732
|
+
source?.offline === true ||
|
|
733
|
+
source?.online === false ||
|
|
734
|
+
["offline", "disconnected", "unreachable"].includes(connection) ||
|
|
735
|
+
(kind === "remote" && source?.alive !== true);
|
|
736
|
+
const online =
|
|
737
|
+
!offline &&
|
|
738
|
+
(source?.online === true ||
|
|
739
|
+
["online", "connected"].includes(connection) ||
|
|
740
|
+
(kind === "remote" && source?.alive === true) ||
|
|
741
|
+
locationKind === "cloud");
|
|
742
|
+
return {
|
|
743
|
+
kind: locationKind,
|
|
744
|
+
status: offline ? "offline" : online ? "online" : "local",
|
|
745
|
+
};
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
function groupingSummary(workbench, error) {
|
|
749
|
+
if (error) {
|
|
750
|
+
return {
|
|
751
|
+
authority: "cli",
|
|
752
|
+
connected: false,
|
|
753
|
+
revision: null,
|
|
754
|
+
generation: 0,
|
|
755
|
+
reason: String(error).slice(0, 240),
|
|
756
|
+
items: [],
|
|
757
|
+
assignments: [],
|
|
758
|
+
};
|
|
759
|
+
}
|
|
760
|
+
if (workbench == null) {
|
|
761
|
+
const items = [];
|
|
762
|
+
const assignments = [];
|
|
763
|
+
return {
|
|
764
|
+
authority: "cli",
|
|
765
|
+
connected: true,
|
|
766
|
+
revision: projectionRevision({
|
|
767
|
+
schema: "chainlesschain.session-workbench-state/v1",
|
|
768
|
+
generation: 0,
|
|
769
|
+
groups: [],
|
|
770
|
+
memberships: {},
|
|
771
|
+
}),
|
|
772
|
+
generation: 0,
|
|
773
|
+
items,
|
|
774
|
+
assignments,
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
if (
|
|
778
|
+
typeof workbench !== "object" ||
|
|
779
|
+
workbench.authority !== "cli" ||
|
|
780
|
+
workbench.connected !== true ||
|
|
781
|
+
typeof workbench.revision !== "string" ||
|
|
782
|
+
!Number.isSafeInteger(workbench.generation) ||
|
|
783
|
+
workbench.generation < 0 ||
|
|
784
|
+
!Array.isArray(workbench.items) ||
|
|
785
|
+
workbench.items.length > 128 ||
|
|
786
|
+
!Array.isArray(workbench.assignments) ||
|
|
787
|
+
workbench.assignments.length > 4096
|
|
788
|
+
) {
|
|
789
|
+
return groupingSummary(null, "session group projection is malformed");
|
|
790
|
+
}
|
|
791
|
+
const ids = new Set();
|
|
792
|
+
const items = [];
|
|
793
|
+
for (const raw of workbench.items) {
|
|
794
|
+
const id = asText(raw?.id);
|
|
795
|
+
const name = boundedText(raw?.name, 80);
|
|
796
|
+
const order = Number(raw?.order);
|
|
797
|
+
if (
|
|
798
|
+
!id ||
|
|
799
|
+
!/^group-[a-zA-Z0-9_-]+$/u.test(id) ||
|
|
800
|
+
!name ||
|
|
801
|
+
!Number.isSafeInteger(order) ||
|
|
802
|
+
order < 0 ||
|
|
803
|
+
ids.has(id)
|
|
804
|
+
) {
|
|
805
|
+
return groupingSummary(null, "session group projection is malformed");
|
|
806
|
+
}
|
|
807
|
+
ids.add(id);
|
|
808
|
+
items.push({ id, name, order });
|
|
809
|
+
}
|
|
810
|
+
items.sort(
|
|
811
|
+
(left, right) =>
|
|
812
|
+
left.order - right.order || left.name.localeCompare(right.name),
|
|
813
|
+
);
|
|
814
|
+
const assignments = [];
|
|
815
|
+
const seenSessions = new Set();
|
|
816
|
+
for (const raw of workbench.assignments) {
|
|
817
|
+
const sessionId = asText(raw?.sessionId);
|
|
818
|
+
const groupId = asText(raw?.groupId);
|
|
819
|
+
if (
|
|
820
|
+
!sessionId ||
|
|
821
|
+
sessionId.length > 512 ||
|
|
822
|
+
!groupId ||
|
|
823
|
+
!ids.has(groupId) ||
|
|
824
|
+
seenSessions.has(sessionId)
|
|
825
|
+
) {
|
|
826
|
+
return groupingSummary(null, "session group projection is malformed");
|
|
827
|
+
}
|
|
828
|
+
seenSessions.add(sessionId);
|
|
829
|
+
assignments.push({ sessionId, groupId });
|
|
830
|
+
}
|
|
831
|
+
assignments.sort((left, right) =>
|
|
832
|
+
left.sessionId.localeCompare(right.sessionId),
|
|
833
|
+
);
|
|
834
|
+
return {
|
|
835
|
+
authority: "cli",
|
|
836
|
+
connected: true,
|
|
837
|
+
revision: workbench.revision,
|
|
838
|
+
generation: workbench.generation,
|
|
839
|
+
items,
|
|
840
|
+
assignments,
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
|
|
649
844
|
function lastEventFor(source, state) {
|
|
650
845
|
const at =
|
|
651
846
|
toIso(source?.lastEvent?.at) ||
|
|
@@ -663,7 +858,7 @@ function lastEventFor(source, state) {
|
|
|
663
858
|
function projectOne(
|
|
664
859
|
kind,
|
|
665
860
|
source,
|
|
666
|
-
{ artifacts, prLinks, sessionMessageFabric },
|
|
861
|
+
{ artifacts, prLinks, sessionMessageFabric, groupAssignments },
|
|
667
862
|
) {
|
|
668
863
|
let sourceId;
|
|
669
864
|
if (kind === "remote") {
|
|
@@ -707,6 +902,11 @@ function projectOne(
|
|
|
707
902
|
sourceId,
|
|
708
903
|
linkedSessionId,
|
|
709
904
|
);
|
|
905
|
+
const approval = approvalSummary(source, state);
|
|
906
|
+
const messaging = messagingSummary(linkedSessionIds, sessionMessageFabric);
|
|
907
|
+
const focus = focusSummary(source, state);
|
|
908
|
+
const groupId =
|
|
909
|
+
groupAssignments.get(canonicalSessionId(kind, sourceId)) || null;
|
|
710
910
|
const projected = {
|
|
711
911
|
id: canonicalSessionId(kind, sourceId),
|
|
712
912
|
sourceId,
|
|
@@ -735,8 +935,19 @@ function projectOne(
|
|
|
735
935
|
kind === "dynamic_workflow"
|
|
736
936
|
? { count: asCount(source?.artifacts?.count), latest: null }
|
|
737
937
|
: artifactSummary(linkedSessionIds, artifacts),
|
|
738
|
-
approval
|
|
739
|
-
messaging
|
|
938
|
+
approval,
|
|
939
|
+
messaging,
|
|
940
|
+
groupId,
|
|
941
|
+
attention: {
|
|
942
|
+
unread: messaging.unread,
|
|
943
|
+
needsApproval: approval.pending,
|
|
944
|
+
pendingInteractions: Math.min(
|
|
945
|
+
1_000,
|
|
946
|
+
pendingInteractionCount(source) + (focus.pendingQuestion ? 1 : 0),
|
|
947
|
+
),
|
|
948
|
+
},
|
|
949
|
+
focus,
|
|
950
|
+
location: locationSummary(source, kind),
|
|
740
951
|
pr: prSummary(linkedSessionIds, prLinks),
|
|
741
952
|
workflow: dynamicWorkflowSummary(source),
|
|
742
953
|
lastEvent: lastEventFor(source, state),
|
|
@@ -763,10 +974,23 @@ export function buildSessionProjection({
|
|
|
763
974
|
artifacts = [],
|
|
764
975
|
prLinks = {},
|
|
765
976
|
sessionMessageFabric = null,
|
|
977
|
+
sessionWorkbench = null,
|
|
766
978
|
sourceErrors = {},
|
|
767
979
|
generatedAt = new Date().toISOString(),
|
|
768
980
|
} = {}) {
|
|
769
|
-
const
|
|
981
|
+
const groups = groupingSummary(
|
|
982
|
+
sessionWorkbench,
|
|
983
|
+
sourceErrors.sessionWorkbench,
|
|
984
|
+
);
|
|
985
|
+
const groupAssignments = new Map(
|
|
986
|
+
groups.assignments.map((entry) => [entry.sessionId, entry.groupId]),
|
|
987
|
+
);
|
|
988
|
+
const context = {
|
|
989
|
+
artifacts,
|
|
990
|
+
prLinks,
|
|
991
|
+
sessionMessageFabric,
|
|
992
|
+
groupAssignments,
|
|
993
|
+
};
|
|
770
994
|
const sessions = [
|
|
771
995
|
...(Array.isArray(local) ? local : []).map((source) =>
|
|
772
996
|
projectOne("local", source, context),
|
|
@@ -828,6 +1052,11 @@ export function buildSessionProjection({
|
|
|
828
1052
|
: 0,
|
|
829
1053
|
sourceErrors.sessionMessageFabric,
|
|
830
1054
|
),
|
|
1055
|
+
sessionWorkbench: sourceStatus(
|
|
1056
|
+
groups.connected ? groups.items.length : 0,
|
|
1057
|
+
sourceErrors.sessionWorkbench ||
|
|
1058
|
+
(groups.connected ? null : groups.reason),
|
|
1059
|
+
),
|
|
831
1060
|
};
|
|
832
1061
|
const revision = projectionRevision({
|
|
833
1062
|
schema: SESSION_PROJECTION_SCHEMA,
|
|
@@ -836,6 +1065,7 @@ export function buildSessionProjection({
|
|
|
836
1065
|
id: session.id,
|
|
837
1066
|
revision: session.revision,
|
|
838
1067
|
})),
|
|
1068
|
+
groupRevision: groups.revision,
|
|
839
1069
|
});
|
|
840
1070
|
return {
|
|
841
1071
|
schema: SESSION_PROJECTION_SCHEMA,
|
|
@@ -845,6 +1075,7 @@ export function buildSessionProjection({
|
|
|
845
1075
|
generatedAt: toIso(generatedAt) || new Date().toISOString(),
|
|
846
1076
|
revision,
|
|
847
1077
|
sources,
|
|
1078
|
+
groups,
|
|
848
1079
|
sessions,
|
|
849
1080
|
};
|
|
850
1081
|
}
|
|
@@ -962,6 +1193,15 @@ export function disconnectedSessionProjection(reasonText = "CLI unavailable") {
|
|
|
962
1193
|
revision: projectionRevision({ connected: false, reason }),
|
|
963
1194
|
reason,
|
|
964
1195
|
sources: {},
|
|
1196
|
+
groups: {
|
|
1197
|
+
authority: "cli",
|
|
1198
|
+
connected: false,
|
|
1199
|
+
revision: null,
|
|
1200
|
+
generation: 0,
|
|
1201
|
+
reason,
|
|
1202
|
+
items: [],
|
|
1203
|
+
assignments: [],
|
|
1204
|
+
},
|
|
965
1205
|
sessions: [],
|
|
966
1206
|
};
|
|
967
1207
|
}
|
|
@@ -11,9 +11,11 @@
|
|
|
11
11
|
|
|
12
12
|
import { resolve, relative, isAbsolute, join } from "node:path";
|
|
13
13
|
import { getHomeDir } from "./paths.js";
|
|
14
|
+
import { resolveClaudeProjectStorageDir } from "./claude-project-storage-layout.js";
|
|
14
15
|
|
|
15
16
|
export function sessionStoreDir() {
|
|
16
|
-
|
|
17
|
+
const homeDir = getHomeDir();
|
|
18
|
+
return resolveClaudeProjectStorageDir(homeDir) || join(homeDir, "sessions");
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
/**
|