chainlesschain 0.162.188 → 0.162.193
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 +61 -11
- package/bin/chainlesschain.js +7 -52
- package/completions/_cc +209 -0
- package/completions/cc.bash +18 -0
- package/completions/cc.fish +13 -0
- package/completions/cc.ps1 +226 -0
- package/package.json +10 -2
- package/src/assets/web-panel/assets/{AIOps-Brr1LVcE.js → AIOps-DBLkaTje.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DQU74DKG.js → ActionButton-BAy-Qebo.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-CYp9178y.js → Analytics-Dfb1Mlau.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DW4SCYsW.js → AppLayout-BbFkN8m0.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-CYlD_ed1.js → Artifacts-kM4-cEEH.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CWl1rZOi.js → Audit-BSQfYWf3.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BOR-LPsa.js → BackgroundAgents-CWDbI_fG.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DLpG7j1X.js → Backup-BxLPbq_Q.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-B35K9wdr.js → BaseInput-DuIbdrp6.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CwUJb9gB.js → Chat-NEmjGahU.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-1v6aMS1m.js → ChatBubbleRenderer-DfJEo-5_.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-pi3-tPNW.js → Checkbox-CaoeG3Ns.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-FyNF35eL.js → Codegen-BFf_g3xY.js} +1 -1
- package/src/assets/web-panel/assets/{Col-tGt_JDEr.js → Col-CNOd8mdQ.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CC7LonQX.js → Community-BhpDqz-i.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BGXrHHjE.js → Compact-CQ42T7Z6.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-DSW0TBZ8.js → Compliance-DI5PcLMN.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-Bhk7rbvE.js → Cowork-wYYZe0wR.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-DxyiQ2NZ.js → Cron-Dlq03DD_.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-B2ZkxHok.js → Crosschain-BzqS8PP3.js} +1 -1
- package/src/assets/web-panel/assets/{DID-yOJV99eJ.js → DID-It55Yem7.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CKsttz7D.js → Dashboard-9HkH6oxn.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-CVFldXSL.js → Dropdown-00e2YWRB.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-Bufv638J.js → EmailListRenderer-By-ugRDL.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-4ncjoIjL.js → FamilyGuardDashboard-C396yu5m.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DsknEDoX.js → Federation-BME5sbZY.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-Cqe5jWXA.js → FormItemContext-B4TEZCr-.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-NAJaFKxc.js → GenericCardRenderer-_9CX9ieY.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CszKQpnl.js → Git-BrS6WVSr.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-BXGodXi6.js → Governance-BMdCWnKF.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CkoYuG2c.js → Inference-Bcp3vzcA.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DFlEr_T0.js → KnowledgeGraph-DlLuqGY5.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-CVaENddA.js → Logs-D-W_6x09.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-DElGPxCZ.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-CDlLT0fw.js → Marketplace-Dzn2guvI.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DdwOyszN.js → McpTools-uPict-KL.js} +6 -6
- package/src/assets/web-panel/assets/{Memory-DKQnkKuG.js → Memory-BCw43kOb.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DGseqlzJ.js → MobileBridge-DmV8Wv7F.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-COBbEOlj.js → MobileProjects-C-HaCmSM.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-O61Vwyli.js → Mtc-C6jxJ34Y.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-Dw2SyasS.js → MtcAudit-Za8ExwhQ.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-hSu_l8kf.js → Multisig-KKDbuEgb.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CX1Epurr.js → NLProgramming-Dj97zbCk.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-R9xX8o8_.js → Notes-DBXvMraU.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-jtSNLCuK.js → NotificationSettings-DOxITLYl.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-7DVjZwMM.js +1 -0
- package/src/assets/web-panel/assets/{Organization-Pu2WO-U3.js → Organization-D1i73mjb.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-BjnqUyFp.js → Overflow-kW6Q3rvg.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-jjkvz44c.js → P2P-C-v_8p2v.js} +2 -2
- package/src/assets/web-panel/assets/PdhVaultBrowser-tUbbY64W.js +7 -0
- package/src/assets/web-panel/assets/{Permissions-D4yDpivd.js → Permissions-DkHxEZ58.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-0qsL6iH1.js → PersonalDataHub-DWuMPGrK.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-Cx7Ybrk2.js → Pipeline-30IYXWWm.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-PbfR_M_V.js → Privacy-DZNQ4RrH.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CyV6Gsub.js → ProjectInit-De2MCElf.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-C7KZ2Wdk.js → ProjectSettings-5uHk9wsC.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-DQDjO-yK.js → Projects-XjDfrFLb.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DyFVBBMX.js → Providers-Bgwj6gcE.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-CzB1BC9_.js → QrScannerModal-gKql9umv.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-Bk636mC1.js → QuickAsk-BWvmwkh7.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DoWxHIT3.js → Recommend-Uok4hZPd.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-oOVIv9wq.js → RemoteSession-DLJzTk9a.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-BucoReGG.js → Reputation-ZVwIPMSO.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DzmOdJU7.js → Row-CN04HxWR.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-C1tK7KGU.js → RssFeed-BdSrEG4g.js} +3 -3
- package/src/assets/web-panel/assets/{Search-CSnInOqk.js → Search-5PwVd0IR.js} +1 -1
- package/src/assets/web-panel/assets/{Security-dlejr15l.js → Security-DdBo4zjN.js} +3 -3
- package/src/assets/web-panel/assets/{Services-BioPZuNh.js → Services-D3letU7M.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DWMibwpC.js → Skeleton--Jb83f1v.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-BAAnx1B2.js → Skills-Bg-CulHX.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-jWNp4hNO.js → Sla-7QOa7S-X.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-y5kqKha-.js → SpeechSettings-DQwppjRw.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-B9GNsc3e.js → SyncSettings-dNPQGL-s.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-BDBYKRen.js → Tasks-Ggs-Z48q.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-DRiE5eaN.js → Templates-78TYHgRO.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-BGlAvExF.js → Tenant-xHwwv9vO.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-B8uzrbNY.js → Terminal-BJXSJfm4.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-Df48iveY.js → TimelineRenderer-fLbjRhJw.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-CcmHndN6.js → Tokens-oMSBSBmB.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DPkWxmQ2.js → Trigger-CfnY_wX_.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DTb5a5AV.js → Trust-AdyTgYKO.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-CBmg5vch.js → UkeySign-C5K_81dS.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-B0mZrz4O.js → VideoEditing-vcGVDqki.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Bxs7_mpd.js → Wallet-hhOc3hlY.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-C8x3cMxU.js → WebAuthn-CVloC11s.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-DPrNznrP.js → WorkflowEditor-CYeE32R5.js} +1 -1
- package/src/assets/web-panel/assets/{chat-D3bYWu7S.js → chat-CNROR5bN.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DY-PwMu4.js → colors-Cjx-cnwU.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-LDk10Kw6.js → compact-item-DOIfelvD.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-C-2MZnFq.js → createContext-DfA7UZ8u.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-ChcCBGs7.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BQIBjcnB.js → hasIn-BMSCzcfM.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQVb2dWp.js → index-5-HXgOX5.js} +1 -1
- package/src/assets/web-panel/assets/{index-BdXnYMCZ.js → index-AWg-0M1S.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cx6D_dx2.js → index-B4iYzpkL.js} +1 -1
- package/src/assets/web-panel/assets/{index-_HRO_cIu.js → index-B5Udeb_6.js} +1 -1
- package/src/assets/web-panel/assets/{index-DlRYqt3S.js → index-B7gf77CJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BrnRO9yE.js → index-BEMwBBHk.js} +1 -1
- package/src/assets/web-panel/assets/{index-VCh5zNJo.js → index-BM1y_9hM.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRI3ngNg.js → index-BUonmKSE.js} +1 -1
- package/src/assets/web-panel/assets/{index-C3GNvExG.js → index-BbQ2eQ8H.js} +1 -1
- package/src/assets/web-panel/assets/{index-DSvo_bp0.js → index-BemJ2u_E.js} +1 -1
- package/src/assets/web-panel/assets/{index-L6qixyLc.js → index-BolaOQxx.js} +1 -1
- package/src/assets/web-panel/assets/{index-BI4KgcYC.js → index-BxOk9vkG.js} +1 -1
- package/src/assets/web-panel/assets/{index-CY4KnaO9.js → index-By61ojUx.js} +1 -1
- package/src/assets/web-panel/assets/{index-L3smcoQX.js → index-C2K9SNVX.js} +1 -1
- package/src/assets/web-panel/assets/{index-BX2b9Orc.js → index-C3L5gdiD.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cz4b6Z_7.js → index-C7xn0Nub.js} +1 -1
- package/src/assets/web-panel/assets/{index-COG61sRv.js → index-CAnvhwg6.js} +1 -1
- package/src/assets/web-panel/assets/{index-C7FC8cP2.js → index-CEKMcOyU.js} +1 -1
- package/src/assets/web-panel/assets/{index-BN-xdSWZ.js → index-CNC5onm4.js} +1 -1
- package/src/assets/web-panel/assets/{index-DY2FIrmz.js → index-CVL27kXC.js} +1 -1
- package/src/assets/web-panel/assets/{index-CiTvBAr-.js → index-CVm1_i3t.js} +1 -1
- package/src/assets/web-panel/assets/{index-DhRt9cYJ.js → index-CdYBye8B.js} +1 -1
- package/src/assets/web-panel/assets/{index-B5pgtZnY.js → index-ClNMrqEY.js} +1 -1
- package/src/assets/web-panel/assets/{index-7xKu7Fns.js → index-Cs6l7uRu.js} +1 -1
- package/src/assets/web-panel/assets/{index-D4K1weKc.js → index-CshQbilz.js} +1 -1
- package/src/assets/web-panel/assets/{index-k7C_oDCO.js → index-Cyweh0Hy.js} +1 -1
- package/src/assets/web-panel/assets/{index-D3Oq-DLL.js → index-DBpWXFed.js} +3 -3
- package/src/assets/web-panel/assets/{index-DYyLJPlF.js → index-DHtpHZAQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dh-tkpKQ.js → index-DLmn0BoK.js} +1 -1
- package/src/assets/web-panel/assets/{index-8JC9BJa1.js → index-DPAWBrMf.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dd2Km97U.js → index-DjEsxO5h.js} +1 -1
- package/src/assets/web-panel/assets/{index-KFZO_lcx.js → index-FBc_CJBd.js} +1 -1
- package/src/assets/web-panel/assets/{index-DTIZpPtG.js → index-Icdoqmzt.js} +1 -1
- package/src/assets/web-panel/assets/index-Q2IajL54.js +1 -0
- package/src/assets/web-panel/assets/index-bRkHgOMc.js +1 -0
- package/src/assets/web-panel/assets/{index-lmm9p-jm.js → index-dCd8cSUq.js} +1 -1
- package/src/assets/web-panel/assets/{index-HasPt4-h.js → index-m2vG9gG_.js} +1 -1
- package/src/assets/web-panel/assets/{index-CaslYch6.js → index-mTpHoEzr.js} +1 -1
- package/src/assets/web-panel/assets/{index-CbR6ROOa.js → index-ti_lnTWl.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-zQPSHf2C.js → initDefaultProps-Bu8k7H1Y.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CKCStGVk.js → motion-s3iVK41k.js} +1 -1
- package/src/assets/web-panel/assets/{move-BufVDGYF.js → move-B6B-E5Jz.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DcaFxy5D.js → mtc-parser-BiYgTidA.js} +1 -1
- package/src/assets/web-panel/assets/{omit-EScpkGdo.js → omit-pU1RdUDA.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-72hG_qfT.js → pickAttrs-Cdoq_SeM.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-CMFWiH20.js → placementArrow-DIuvAn2K.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-DKQHS41p.js → responsiveObserve-8w16YR2D.js} +1 -1
- package/src/assets/web-panel/assets/{slide-QVAFHTIQ.js → slide-VZ01cZe3.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DIz38e2G.js → statusUtils-lh8YMN8Z.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-zK5cyLby.js → styleChecker-CmDyreec.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DhZngk62.js → useFlexGapSupport-hiJWMU5y.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BvV2cvkg.js → useFs-Thnu-Iaj.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-CRmxb9l3.js → usePersonalDataHub-LBdOxjwY.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CgQIbobP.js → vnode-Cg6lFY_X.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-D4XrrO0R.js → zoom-DVfsR1YO.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/cli-help.js +181 -0
- package/src/command-help-index.json +181 -0
- package/src/command-manifest.json +1107 -175
- package/src/command-surface-policy.js +197 -0
- package/src/commands/agent.js +98 -33
- package/src/commands/artifacts.js +400 -2
- package/src/commands/background-session.js +41 -3
- package/src/commands/checkpoint-managed.js +1059 -0
- package/src/commands/checkpoint-restore-recovery.js +1476 -0
- package/src/commands/checkpoint.js +950 -22
- package/src/commands/compact.js +101 -25
- package/src/commands/config.js +506 -20
- package/src/commands/doctor.js +4 -1
- package/src/commands/hub.js +1 -1
- package/src/commands/mcp.js +688 -24
- package/src/commands/pack.js +16 -2
- package/src/commands/plugin.js +20 -12
- package/src/commands/session-mcp-recovery.js +218 -0
- package/src/commands/session.js +470 -110
- package/src/commands/setup.js +36 -10
- package/src/commands/skill.js +181 -110
- package/src/commands/status.js +21 -5
- package/src/commands/team-distributed.js +3324 -0
- package/src/commands/team.js +1130 -74
- package/src/commands/update.js +68 -6
- package/src/constants.js +11 -0
- package/src/data/changelog.json +26 -0
- package/src/gateways/ws/action-protocol.js +10 -0
- package/src/gateways/ws/session-protocol.js +555 -27
- package/src/gateways/ws/ws-agent-handler.js +541 -14
- package/src/gateways/ws/ws-session-gateway.js +129 -22
- package/src/gateways/ws/ws-session-state.js +431 -0
- package/src/harness/background-task-manager.js +233 -36
- package/src/harness/jsonl-session-store.js +2551 -167
- package/src/harness/mcp-client.js +802 -61
- package/src/harness/prompt-compressor.js +227 -27
- package/src/harness/session-index.js +89 -38
- package/src/harness/session-list-index.js +254 -0
- package/src/harness/structured-handoff.js +410 -0
- package/src/lazy-dispatch.js +747 -84
- package/src/lib/__tests__/logger.test.js +50 -2
- package/src/lib/advisor-runtime.js +1047 -0
- package/src/lib/agent-core.js +2 -0
- package/src/lib/agent-sandbox.js +120 -26
- package/src/lib/agent-session-export.js +20 -0
- package/src/lib/agent-team/task-lease.js +271 -3
- package/src/lib/agent-team/team-adjudication.js +1501 -0
- package/src/lib/agent-team/team-budget.js +4 -1
- package/src/lib/agent-team/team-control-store.js +582 -0
- package/src/lib/agent-team/team-distributed-queue.js +5246 -0
- package/src/lib/agent-team/team-process-checkpoint.js +211 -0
- package/src/lib/agent-team/team-runner.js +543 -24
- package/src/lib/agent-team/team-worktree.js +1403 -95
- package/src/lib/artifact-store.js +131 -8
- package/src/lib/background-agent-supervisor.js +185 -13
- package/src/lib/background-interaction-journal.js +37 -9
- package/src/lib/background-launch-profile.js +1058 -0
- package/src/lib/checkpoint-restore-already-completed-controller.js +902 -0
- package/src/lib/checkpoint-restore-orchestrator.js +987 -0
- package/src/lib/checkpoint-restore-partial-rollback-controller.js +1953 -0
- package/src/lib/checkpoint-restore-recovery-controller.js +689 -0
- package/src/lib/checkpoint-restore-recovery.js +884 -0
- package/src/lib/checkpoint-restore-retention.js +126 -0
- package/src/lib/checkpoint-restore-saga.js +5079 -0
- package/src/lib/checkpoint-restore-session-recovery.js +1178 -0
- package/src/lib/checkpoint-restore-workspace-target-verifier.js +270 -0
- package/src/lib/checkpoint-store.js +1688 -97
- package/src/lib/checkpoint-timeline-authority.js +522 -0
- package/src/lib/checkpoint-timeline.js +642 -0
- package/src/lib/config-keys.js +18 -119
- package/src/lib/config-manager.js +446 -27
- package/src/lib/config-redaction.js +57 -0
- package/src/lib/config-schema.js +853 -0
- package/src/lib/cowork-mcp-tools.js +5 -0
- package/src/lib/cowork-task-runner.js +458 -63
- package/src/lib/delivery-coordinator.js +1234 -0
- package/src/lib/delivery-evidence.js +450 -0
- package/src/lib/doctor-checkup.js +199 -14
- package/src/lib/executable-path.js +34 -0
- package/src/lib/fatal-handler.js +16 -0
- package/src/lib/file-checkpoint.js +4909 -186
- package/src/lib/file-lines.js +125 -0
- package/src/lib/headless-config-command.js +16 -5
- package/src/lib/hook-runner.cjs +139 -38
- package/src/lib/hooks-v2-workspace-context.js +10 -0
- package/src/lib/impacted-gate-selector.js +424 -0
- package/src/lib/interaction-adapter.js +62 -0
- package/src/lib/jsonl-session-store.js +1 -35
- package/src/lib/logger.js +66 -14
- package/src/lib/managed-checkpoint-render.js +60 -0
- package/src/lib/managed-tool-checkpoint.js +194 -0
- package/src/lib/mcp-call-ledger-store.js +1069 -0
- package/src/lib/mcp-call-ledger.js +747 -0
- package/src/lib/mcp-client.js +5 -0
- package/src/lib/mcp-conflict-scheduler.js +468 -0
- package/src/lib/mcp-effect-contract.js +102 -0
- package/src/lib/mcp-headers-helper-trust.js +145 -0
- package/src/lib/mcp-headers-helper.js +616 -0
- package/src/lib/mcp-host-recovery-runtime.js +131 -0
- package/src/lib/mcp-ledger-recovery-admission.js +1065 -0
- package/src/lib/mcp-recovery-adjudication.js +443 -0
- package/src/lib/output-context.js +86 -0
- package/src/lib/packer/file-identity.js +170 -0
- package/src/lib/packer/index.js +3 -0
- package/src/lib/packer/native-update-state.js +277 -0
- package/src/lib/packer/pack-update-applier.js +1983 -136
- package/src/lib/packer/pack-update-checker.js +34 -0
- package/src/lib/packer/pack-update-downloader.js +875 -86
- package/src/lib/packer/pack-update-signature.js +86 -0
- package/src/lib/packer/pkg-config-generator.js +6 -0
- package/src/lib/paths.js +65 -10
- package/src/lib/plan-mode.js +831 -14
- package/src/lib/plan-persistence.js +540 -0
- package/src/lib/plugin-runtime/hooks.js +227 -69
- package/src/lib/plugin-runtime/plugin-options.js +189 -44
- package/src/lib/pr-automation-policy.js +146 -8
- package/src/lib/process-execution-broker/credential-agent.js +7 -0
- package/src/lib/process-execution-broker/index.js +491 -13
- package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +28 -1
- package/src/lib/process-execution-broker/linux-generic-bwrap.js +28 -4
- package/src/lib/process-execution-broker/platform-sandbox.js +92 -70
- package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
- package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
- package/src/lib/process-execution-broker/windows-sandbox.cs +284 -19
- package/src/lib/process-execution-broker/workspace-transaction.js +4459 -0
- package/src/lib/project-instructions.js +165 -29
- package/src/lib/project-mcp-trust.js +67 -0
- package/src/lib/public-ide-capability-manifest.js +272 -0
- package/src/lib/public-ide-capability-validation.js +351 -0
- package/src/lib/secret-store.js +267 -43
- package/src/lib/secure-file-identity.js +433 -0
- package/src/lib/secure-fs.js +1089 -0
- package/src/lib/security-audit.js +58 -0
- package/src/lib/service-manager.js +34 -13
- package/src/lib/session-budget-runtime.js +1452 -0
- package/src/lib/session-host-snapshot.js +388 -0
- package/src/lib/session-message-provenance.js +429 -0
- package/src/lib/session-projection.js +804 -0
- package/src/lib/session-resource-budget.js +1495 -0
- package/src/lib/settings-hooks.cjs +138 -22
- package/src/lib/settings-loader.cjs +25 -2
- package/src/lib/side-effect-ledger-store.js +45 -23
- package/src/lib/skill-execution-identity.js +217 -0
- package/src/lib/skill-loader.js +299 -18
- package/src/lib/sub-agent-context.js +236 -28
- package/src/lib/sub-agent-registry.js +5 -0
- package/src/lib/subagent-contract.js +94 -0
- package/src/lib/todo-manager.js +185 -18
- package/src/lib/todo-persistence.js +417 -0
- package/src/lib/turn-binding-store.js +41 -23
- package/src/lib/turn-binding.js +160 -2
- package/src/lib/with-file-lock.js +165 -24
- package/src/lib/ws-chat-handler.js +21 -0
- package/src/program-base.js +18 -0
- package/src/repl/advisor-command.js +103 -0
- package/src/repl/agent-repl.js +2175 -146
- package/src/repl/btw-command.js +93 -10
- package/src/repl/clipboard-image.js +119 -0
- package/src/repl/config-summary.js +64 -108
- package/src/repl/prompt-editor.js +233 -0
- package/src/repl/prompt-interactions.js +344 -0
- package/src/repl/prompt-stash.js +354 -0
- package/src/repl/prompt-suggestions.js +312 -0
- package/src/repl/repl-keybindings.js +227 -0
- package/src/repl/session-recap.js +217 -0
- package/src/repl/slash-command-registry.js +22 -0
- package/src/repl/terminal-layout.js +88 -0
- package/src/runtime/agent-core.js +1630 -447
- package/src/runtime/coding-agent-contract-shared.cjs +13 -1
- package/src/runtime/coding-agent-managed-tool-policy.cjs +7 -2
- package/src/runtime/diagnostics.js +32 -13
- package/src/runtime/headless-runner.js +310 -118
- package/src/runtime/headless-stream.js +356 -95
- package/src/runtime/mcp-config.js +148 -14
- package/src/runtime/policies/agent-policy.js +14 -0
- package/src/runtime/status-diagnostics-lite.js +137 -0
- package/src/assets/web-panel/assets/MarkdownRenderer-7iWGwZ-r.js +0 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-BU2Yqq5H.js +0 -1
- package/src/assets/web-panel/assets/PdhVaultBrowser-69ca_WeR.js +0 -7
- package/src/assets/web-panel/assets/devWarning-B4dXIJqD.js +0 -1
- package/src/assets/web-panel/assets/index-C-C7DaG6.js +0 -1
- package/src/assets/web-panel/assets/index-DkfWzWtd.js +0 -1
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rebuildable metadata index for append-only JSONL sessions.
|
|
3
|
+
*
|
|
4
|
+
* Each transcript owns a tiny `<id>.meta.json` snapshot. A global reverse-read
|
|
5
|
+
* activity journal points at the newest snapshots, so `session list --limit N`
|
|
6
|
+
* reads O(N recent sessions) instead of every transcript body. The transcript
|
|
7
|
+
* remains the content authority; both index layers may be deleted and rebuilt.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
appendFileSync,
|
|
12
|
+
existsSync,
|
|
13
|
+
readFileSync,
|
|
14
|
+
writeFileSync,
|
|
15
|
+
} from "node:fs";
|
|
16
|
+
import { join } from "node:path";
|
|
17
|
+
import { iterateFileLinesReverseSync } from "../lib/file-lines.js";
|
|
18
|
+
import { ensurePrivateFile } from "../lib/secure-fs.js";
|
|
19
|
+
|
|
20
|
+
export const SESSION_INDEX_SCHEMA = 2;
|
|
21
|
+
export const SESSION_INDEX_FILE = ".sessions-index-v2.ndjson";
|
|
22
|
+
|
|
23
|
+
// Used only by an opted-in child in the independent session-scale crash gate.
|
|
24
|
+
// Keeping the injection immediately around the production sidecar/journal
|
|
25
|
+
// boundary makes that gate deterministic without replacing either write.
|
|
26
|
+
export const _sessionScaleFaultHooks = Object.seal({
|
|
27
|
+
afterMetaSnapshot: null,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
function runSessionScaleFaultHook(name, payload) {
|
|
31
|
+
if (process.env.CC_SESSION_SCALE_FAULT_INJECTION !== "1") return;
|
|
32
|
+
const hook = _sessionScaleFaultHooks[name];
|
|
33
|
+
if (typeof hook === "function") hook(payload);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function sessionMetaPath(dir, sessionId) {
|
|
37
|
+
return join(dir, `${sessionId}.meta.json`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function sessionIndexPath(dir) {
|
|
41
|
+
return join(dir, SESSION_INDEX_FILE);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function emptySessionMeta(sessionId) {
|
|
45
|
+
return {
|
|
46
|
+
schema: SESSION_INDEX_SCHEMA,
|
|
47
|
+
id: sessionId,
|
|
48
|
+
title: "Untitled",
|
|
49
|
+
provider: "",
|
|
50
|
+
model: "",
|
|
51
|
+
message_count: 0,
|
|
52
|
+
event_count: 0,
|
|
53
|
+
created_at_ms: 0,
|
|
54
|
+
updated_at_ms: 0,
|
|
55
|
+
last_hash: null,
|
|
56
|
+
deleted: false,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function readSessionMeta(dir, sessionId) {
|
|
61
|
+
const filePath = sessionMetaPath(dir, sessionId);
|
|
62
|
+
if (!existsSync(filePath)) return null;
|
|
63
|
+
try {
|
|
64
|
+
const value = JSON.parse(readFileSync(filePath, "utf8"));
|
|
65
|
+
return value?.schema === SESSION_INDEX_SCHEMA && value?.id === sessionId
|
|
66
|
+
? value
|
|
67
|
+
: null;
|
|
68
|
+
} catch {
|
|
69
|
+
// A sidecar interrupted mid-write is discarded and streamed from the
|
|
70
|
+
// authoritative transcript on the next list/search operation.
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function applyEventToSessionMeta(meta, event, lastHash) {
|
|
76
|
+
const next = { ...(meta || emptySessionMeta("")) };
|
|
77
|
+
next.schema = SESSION_INDEX_SCHEMA;
|
|
78
|
+
next.deleted = false;
|
|
79
|
+
next.event_count = Math.max(0, Number(next.event_count) || 0) + 1;
|
|
80
|
+
const timestamp = Number(event?.timestamp);
|
|
81
|
+
if (Number.isFinite(timestamp)) {
|
|
82
|
+
if (!next.created_at_ms) next.created_at_ms = timestamp;
|
|
83
|
+
next.updated_at_ms = Math.max(next.updated_at_ms || 0, timestamp);
|
|
84
|
+
}
|
|
85
|
+
if (event?.type === "session_start") {
|
|
86
|
+
next.title = event.data?.title || next.title || "Untitled";
|
|
87
|
+
next.provider = event.data?.provider || "";
|
|
88
|
+
next.model = event.data?.model || "";
|
|
89
|
+
} else if (event?.type === "session_rename" && event.data?.title) {
|
|
90
|
+
next.title = String(event.data.title);
|
|
91
|
+
} else if (
|
|
92
|
+
event?.type === "user_message" ||
|
|
93
|
+
event?.type === "assistant_message"
|
|
94
|
+
) {
|
|
95
|
+
next.message_count = Math.max(0, Number(next.message_count) || 0) + 1;
|
|
96
|
+
} else if (
|
|
97
|
+
event?.type === "ws_turn" &&
|
|
98
|
+
event.data?.schemaVersion === 1 &&
|
|
99
|
+
event.data?.outcome === "completed" &&
|
|
100
|
+
event.data?.user?.role === "user" &&
|
|
101
|
+
event.data?.assistant?.role === "assistant"
|
|
102
|
+
) {
|
|
103
|
+
next.message_count = Math.max(0, Number(next.message_count) || 0) + 2;
|
|
104
|
+
}
|
|
105
|
+
next.last_hash = typeof lastHash === "string" ? lastHash : null;
|
|
106
|
+
return next;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function writeMetaSnapshot(dir, meta) {
|
|
110
|
+
const filePath = sessionMetaPath(dir, meta.id);
|
|
111
|
+
// The owning transcript lock serializes this derived snapshot. It need not
|
|
112
|
+
// use a second temp+rename protocol: interruption can only corrupt a cache,
|
|
113
|
+
// which readSessionMeta rejects and rebuildSessionMeta regenerates.
|
|
114
|
+
writeFileSync(filePath, `${JSON.stringify(meta)}\n`, {
|
|
115
|
+
encoding: "utf8",
|
|
116
|
+
mode: 0o600,
|
|
117
|
+
});
|
|
118
|
+
ensurePrivateFile(filePath);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function appendActivity(dir, meta) {
|
|
122
|
+
const filePath = sessionIndexPath(dir);
|
|
123
|
+
// One compact line is emitted through one O_APPEND write. The journal is a
|
|
124
|
+
// disposable ordering hint (the per-session sidecar and transcript remain
|
|
125
|
+
// authoritative). Prefixing the record with a newline isolates any
|
|
126
|
+
// crash-partial physical tail before publishing the next valid snapshot;
|
|
127
|
+
// reverse readers already skip the resulting empty lines. Avoiding a second
|
|
128
|
+
// global directory lock keeps concurrent transcript appends from serializing
|
|
129
|
+
// on derived metadata.
|
|
130
|
+
appendFileSync(filePath, `\n${JSON.stringify(meta)}\n`, {
|
|
131
|
+
encoding: "utf8",
|
|
132
|
+
mode: 0o600,
|
|
133
|
+
});
|
|
134
|
+
ensurePrivateFile(filePath);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** Called while the owning transcript lock is held. */
|
|
138
|
+
export function recordSessionEvent(dir, sessionId, event, lastHash) {
|
|
139
|
+
const current =
|
|
140
|
+
readSessionMeta(dir, sessionId) || emptySessionMeta(sessionId);
|
|
141
|
+
current.id = sessionId;
|
|
142
|
+
const next = applyEventToSessionMeta(current, event, lastHash);
|
|
143
|
+
writeMetaSnapshot(dir, next);
|
|
144
|
+
runSessionScaleFaultHook("afterMetaSnapshot", {
|
|
145
|
+
dir,
|
|
146
|
+
sessionId,
|
|
147
|
+
event,
|
|
148
|
+
meta: next,
|
|
149
|
+
});
|
|
150
|
+
appendActivity(dir, next);
|
|
151
|
+
return next;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function replaceSessionMeta(dir, meta) {
|
|
155
|
+
const normalized = { ...emptySessionMeta(meta.id), ...meta };
|
|
156
|
+
writeMetaSnapshot(dir, normalized);
|
|
157
|
+
appendActivity(dir, normalized);
|
|
158
|
+
return normalized;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/** Re-emit an existing snapshot only to the global activity order. */
|
|
162
|
+
export function recordSessionActivity(dir, meta) {
|
|
163
|
+
const normalized = { ...emptySessionMeta(meta.id), ...meta };
|
|
164
|
+
appendActivity(dir, normalized);
|
|
165
|
+
return normalized;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function recordSessionDeleted(dir, sessionId, timestamp = Date.now()) {
|
|
169
|
+
const current =
|
|
170
|
+
readSessionMeta(dir, sessionId) || emptySessionMeta(sessionId);
|
|
171
|
+
const tombstone = {
|
|
172
|
+
...current,
|
|
173
|
+
updated_at_ms: timestamp,
|
|
174
|
+
deleted: true,
|
|
175
|
+
};
|
|
176
|
+
writeMetaSnapshot(dir, tombstone);
|
|
177
|
+
appendActivity(dir, tombstone);
|
|
178
|
+
return tombstone;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** Newest journal snapshot for one session, or null if none survived. */
|
|
182
|
+
export function readLatestSessionActivity(dir, sessionId) {
|
|
183
|
+
const filePath = sessionIndexPath(dir);
|
|
184
|
+
if (!existsSync(filePath) || typeof sessionId !== "string") return null;
|
|
185
|
+
for (const { line } of iterateFileLinesReverseSync(filePath)) {
|
|
186
|
+
try {
|
|
187
|
+
const meta = JSON.parse(line);
|
|
188
|
+
if (meta?.schema === SESSION_INDEX_SCHEMA && meta.id === sessionId) {
|
|
189
|
+
return meta;
|
|
190
|
+
}
|
|
191
|
+
} catch {
|
|
192
|
+
// A crash-partial tail is not an activity snapshot.
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function iso(value) {
|
|
199
|
+
const number = Number(value);
|
|
200
|
+
if (!Number.isFinite(number) || number <= 0) return "";
|
|
201
|
+
try {
|
|
202
|
+
return new Date(number).toISOString();
|
|
203
|
+
} catch {
|
|
204
|
+
return "";
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export function publicSessionMeta(meta) {
|
|
209
|
+
return {
|
|
210
|
+
id: meta.id,
|
|
211
|
+
title: meta.title || "Untitled",
|
|
212
|
+
provider: meta.provider || "",
|
|
213
|
+
model: meta.model || "",
|
|
214
|
+
message_count: Math.max(0, Number(meta.message_count) || 0),
|
|
215
|
+
created_at: iso(meta.created_at_ms),
|
|
216
|
+
updated_at: iso(meta.updated_at_ms),
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Read the activity journal newest-first and return the first record seen for
|
|
222
|
+
* each session. This is the latest snapshot because every metadata mutation
|
|
223
|
+
* appends after its sidecar commit.
|
|
224
|
+
*/
|
|
225
|
+
export function listIndexedSessions(
|
|
226
|
+
dir,
|
|
227
|
+
{ limit = 20, hasSession = () => true } = {},
|
|
228
|
+
) {
|
|
229
|
+
const filePath = sessionIndexPath(dir);
|
|
230
|
+
if (!existsSync(filePath)) return [];
|
|
231
|
+
const wanted = Math.max(0, Number(limit) || 0);
|
|
232
|
+
const seen = new Set();
|
|
233
|
+
const result = [];
|
|
234
|
+
for (const { line } of iterateFileLinesReverseSync(filePath)) {
|
|
235
|
+
let meta;
|
|
236
|
+
try {
|
|
237
|
+
meta = JSON.parse(line);
|
|
238
|
+
} catch {
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
if (
|
|
242
|
+
meta?.schema !== SESSION_INDEX_SCHEMA ||
|
|
243
|
+
typeof meta.id !== "string" ||
|
|
244
|
+
seen.has(meta.id)
|
|
245
|
+
) {
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
seen.add(meta.id);
|
|
249
|
+
if (meta.deleted || !hasSession(meta.id)) continue;
|
|
250
|
+
result.push(publicSessionMeta(meta));
|
|
251
|
+
if (wanted > 0 && result.length >= wanted) break;
|
|
252
|
+
}
|
|
253
|
+
return result;
|
|
254
|
+
}
|
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical, bounded handoff shared by compaction, checkpoint summaries, and
|
|
3
|
+
* parent-to-child agent context. The field order is part of the wire format.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { projectCanonicalResumeMessages } from "../lib/session-message-provenance.js";
|
|
7
|
+
|
|
8
|
+
export const STRUCTURED_HANDOFF_FIELDS = Object.freeze([
|
|
9
|
+
"objective",
|
|
10
|
+
"constraints",
|
|
11
|
+
"keyDecisions",
|
|
12
|
+
"changedFiles",
|
|
13
|
+
"tests",
|
|
14
|
+
"unresolvedSideEffects",
|
|
15
|
+
"checkpoints",
|
|
16
|
+
"blockers",
|
|
17
|
+
"nextSteps",
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
const ARRAY_FIELDS = STRUCTURED_HANDOFF_FIELDS.slice(1);
|
|
21
|
+
const DEFAULT_MAX_CONTENT_CHARS = 32_000;
|
|
22
|
+
const DEFAULT_MAX_ITEMS_PER_FIELD = 12;
|
|
23
|
+
const DEFAULT_MAX_ITEM_CHARS = 1_000;
|
|
24
|
+
const DEFAULT_MAX_FALLBACK_SOURCE_CHARS = 24_000;
|
|
25
|
+
|
|
26
|
+
export class StructuredHandoffValidationError extends Error {
|
|
27
|
+
constructor(code, message) {
|
|
28
|
+
super(message);
|
|
29
|
+
this.name = "StructuredHandoffValidationError";
|
|
30
|
+
this.code = code;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function boundedInteger(value, fallback, minimum, maximum) {
|
|
35
|
+
const number = Math.floor(Number(value));
|
|
36
|
+
if (!Number.isFinite(number) || number <= 0) return fallback;
|
|
37
|
+
return Math.min(Math.max(number, minimum), maximum);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function normalizeText(value) {
|
|
41
|
+
return String(value ?? "")
|
|
42
|
+
.replace(/\r\n?/g, "\n")
|
|
43
|
+
.replace(/[ \t]+/g, " ")
|
|
44
|
+
.replace(/ *\n */g, "\n")
|
|
45
|
+
.trim();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function truncateText(value, maxChars) {
|
|
49
|
+
const text = normalizeText(value);
|
|
50
|
+
if (text.length <= maxChars) return text;
|
|
51
|
+
if (maxChars <= 1) return text.slice(0, maxChars);
|
|
52
|
+
return `${text.slice(0, maxChars - 1).trimEnd()}…`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function contentText(message) {
|
|
56
|
+
if (typeof message?.content === "string") return message.content;
|
|
57
|
+
if (message?.content == null) return "";
|
|
58
|
+
try {
|
|
59
|
+
return JSON.stringify(message.content);
|
|
60
|
+
} catch {
|
|
61
|
+
return String(message.content);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function validationError(code, message) {
|
|
66
|
+
throw new StructuredHandoffValidationError(code, message);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function validateHandoffObject(value, maxContentChars) {
|
|
70
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
71
|
+
validationError("invalid_shape", "structured handoff must be an object");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const keys = Object.keys(value);
|
|
75
|
+
if (
|
|
76
|
+
keys.length !== STRUCTURED_HANDOFF_FIELDS.length ||
|
|
77
|
+
keys.some((key, index) => key !== STRUCTURED_HANDOFF_FIELDS[index])
|
|
78
|
+
) {
|
|
79
|
+
validationError(
|
|
80
|
+
"invalid_fields",
|
|
81
|
+
"structured handoff fields are missing, extra, or out of order",
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
if (typeof value.objective !== "string") {
|
|
85
|
+
validationError("invalid_objective", "objective must be a string");
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const normalized = { objective: normalizeText(value.objective) };
|
|
89
|
+
for (const field of ARRAY_FIELDS) {
|
|
90
|
+
if (!Array.isArray(value[field])) {
|
|
91
|
+
validationError(`invalid_${field}`, `${field} must be an array`);
|
|
92
|
+
}
|
|
93
|
+
normalized[field] = value[field].map((item) => {
|
|
94
|
+
if (typeof item !== "string") {
|
|
95
|
+
validationError(`invalid_${field}`, `${field} must contain strings`);
|
|
96
|
+
}
|
|
97
|
+
return normalizeText(item);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (JSON.stringify(normalized).length > maxContentChars) {
|
|
102
|
+
validationError(
|
|
103
|
+
"content_too_large",
|
|
104
|
+
`structured handoff exceeds ${maxContentChars} characters`,
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
return normalized;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Parse one strict JSON object. Markdown fences and surrounding prose fail. */
|
|
111
|
+
export function parseStructuredHandoff(raw, options = {}) {
|
|
112
|
+
const maxContentChars = boundedInteger(
|
|
113
|
+
options.maxContentChars,
|
|
114
|
+
DEFAULT_MAX_CONTENT_CHARS,
|
|
115
|
+
512,
|
|
116
|
+
1_000_000,
|
|
117
|
+
);
|
|
118
|
+
let value = raw;
|
|
119
|
+
if (typeof raw === "string") {
|
|
120
|
+
const text = raw.trim();
|
|
121
|
+
if (!text) validationError("invalid_json", "structured handoff is empty");
|
|
122
|
+
if (text.length > maxContentChars) {
|
|
123
|
+
validationError(
|
|
124
|
+
"content_too_large",
|
|
125
|
+
`structured handoff exceeds ${maxContentChars} characters`,
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
value = JSON.parse(text);
|
|
130
|
+
} catch {
|
|
131
|
+
validationError("invalid_json", "structured handoff is not strict JSON");
|
|
132
|
+
}
|
|
133
|
+
} else if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
134
|
+
validationError(
|
|
135
|
+
"invalid_type",
|
|
136
|
+
"structured handoff must be JSON text or an object",
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
return validateHandoffObject(value, maxContentChars);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** Format with stable field order so persisted summaries are reproducible. */
|
|
143
|
+
export function formatStructuredHandoff(value) {
|
|
144
|
+
return JSON.stringify(
|
|
145
|
+
validateHandoffObject(value, DEFAULT_MAX_CONTENT_CHARS),
|
|
146
|
+
null,
|
|
147
|
+
2,
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function selectBoundedSources(messages, maxChars) {
|
|
152
|
+
// A structured handoff can later become durable system context. Never let a
|
|
153
|
+
// merely verified (or wire-tag-forged) system message gain that authority by
|
|
154
|
+
// being quoted into a new handoff. Only the runtime WeakMap capability is
|
|
155
|
+
// admitted; ordinary user/assistant/tool conversation remains eligible.
|
|
156
|
+
const canonicalSources = projectCanonicalResumeMessages(messages);
|
|
157
|
+
const entries = canonicalSources
|
|
158
|
+
.map((message, index) => ({
|
|
159
|
+
index,
|
|
160
|
+
role: typeof message?.role === "string" ? message.role : "unknown",
|
|
161
|
+
text: normalizeText(contentText(message)),
|
|
162
|
+
}))
|
|
163
|
+
.filter((entry) => entry.text);
|
|
164
|
+
const firstUser = entries.find((entry) => entry.role === "user");
|
|
165
|
+
const selected = new Map();
|
|
166
|
+
let remaining = maxChars;
|
|
167
|
+
|
|
168
|
+
if (firstUser) {
|
|
169
|
+
const allowance = Math.min(
|
|
170
|
+
firstUser.text.length,
|
|
171
|
+
Math.max(1, Math.floor(maxChars / 3)),
|
|
172
|
+
);
|
|
173
|
+
selected.set(firstUser.index, {
|
|
174
|
+
...firstUser,
|
|
175
|
+
text: firstUser.text.slice(0, allowance),
|
|
176
|
+
});
|
|
177
|
+
remaining -= allowance;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
for (let index = entries.length - 1; index >= 0 && remaining > 0; index--) {
|
|
181
|
+
const entry = entries[index];
|
|
182
|
+
if (selected.has(entry.index)) continue;
|
|
183
|
+
const allowance = Math.min(entry.text.length, remaining);
|
|
184
|
+
if (allowance <= 0) break;
|
|
185
|
+
selected.set(entry.index, {
|
|
186
|
+
...entry,
|
|
187
|
+
text: entry.text.slice(0, allowance),
|
|
188
|
+
});
|
|
189
|
+
remaining -= allowance;
|
|
190
|
+
}
|
|
191
|
+
return [...selected.values()].sort((left, right) => left.index - right.index);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function fragments(text) {
|
|
195
|
+
return text
|
|
196
|
+
.split(/\n+|(?<=[.!?。!?])\s+/u)
|
|
197
|
+
.map((part) => normalizeText(part).replace(/^(?:[-*+]\s+|\d+[.)]\s+)/, ""))
|
|
198
|
+
.filter(Boolean);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function stripLabel(value, labels) {
|
|
202
|
+
return normalizeText(value).replace(
|
|
203
|
+
new RegExp(`^(?:${labels})\\s*(?::|:|-)?\\s*`, "iu"),
|
|
204
|
+
"",
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function uniqueBounded(values, maxItems, maxItemChars) {
|
|
209
|
+
const seen = new Set();
|
|
210
|
+
const result = [];
|
|
211
|
+
for (const value of values) {
|
|
212
|
+
const item = truncateText(value, maxItemChars);
|
|
213
|
+
const key = item.toLocaleLowerCase();
|
|
214
|
+
if (!item || seen.has(key)) continue;
|
|
215
|
+
seen.add(key);
|
|
216
|
+
result.push(item);
|
|
217
|
+
if (result.length >= maxItems) break;
|
|
218
|
+
}
|
|
219
|
+
return result;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function pathsFrom(text) {
|
|
223
|
+
const matches = text.match(
|
|
224
|
+
/(?:[A-Za-z]:[\\/]|\.{0,2}[\\/])?(?:[A-Za-z0-9_@.-]+[\\/])+(?:[A-Za-z0-9_@.-]+)/g,
|
|
225
|
+
);
|
|
226
|
+
return (matches || [])
|
|
227
|
+
.map((value) => value.replace(/[),;:.]+$/g, ""))
|
|
228
|
+
.filter((value) => value && !value.includes("://"));
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function emptyHandoff(objective = "") {
|
|
232
|
+
return {
|
|
233
|
+
objective,
|
|
234
|
+
constraints: [],
|
|
235
|
+
keyDecisions: [],
|
|
236
|
+
changedFiles: [],
|
|
237
|
+
tests: [],
|
|
238
|
+
unresolvedSideEffects: [],
|
|
239
|
+
checkpoints: [],
|
|
240
|
+
blockers: [],
|
|
241
|
+
nextSteps: [],
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function serializedLength(value) {
|
|
246
|
+
return JSON.stringify(value, null, 2).length;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function fitToContentLimit(handoff, maxContentChars) {
|
|
250
|
+
const value = structuredClone(handoff);
|
|
251
|
+
while (serializedLength(value) > maxContentChars) {
|
|
252
|
+
const strings = [
|
|
253
|
+
{ field: "objective", index: null, value: value.objective },
|
|
254
|
+
...ARRAY_FIELDS.flatMap((field) =>
|
|
255
|
+
value[field].map((item, index) => ({ field, index, value: item })),
|
|
256
|
+
),
|
|
257
|
+
].sort((left, right) => right.value.length - left.value.length);
|
|
258
|
+
const longest = strings[0];
|
|
259
|
+
if (!longest) break;
|
|
260
|
+
if (longest.value.length > 80) {
|
|
261
|
+
const excess = serializedLength(value) - maxContentChars;
|
|
262
|
+
const nextLength = Math.max(80, longest.value.length - excess - 1);
|
|
263
|
+
const next = truncateText(longest.value, nextLength);
|
|
264
|
+
if (longest.index == null) value.objective = next;
|
|
265
|
+
else value[longest.field][longest.index] = next;
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
const removable = [...ARRAY_FIELDS]
|
|
269
|
+
.reverse()
|
|
270
|
+
.find((field) => value[field].length > 0);
|
|
271
|
+
if (removable) {
|
|
272
|
+
value[removable].pop();
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
value.objective = truncateText(
|
|
276
|
+
value.objective,
|
|
277
|
+
Math.max(0, value.objective.length - 1),
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
return value;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Deterministic fallback that retains labelled facts and exact file paths.
|
|
285
|
+
* The first user objective and the most recent history receive source-budget
|
|
286
|
+
* priority, preventing a large middle tool result from crowding out either.
|
|
287
|
+
*/
|
|
288
|
+
export function buildExtractiveHandoff(messages, options = {}) {
|
|
289
|
+
const maxContentChars = boundedInteger(
|
|
290
|
+
options.maxContentChars,
|
|
291
|
+
DEFAULT_MAX_CONTENT_CHARS,
|
|
292
|
+
512,
|
|
293
|
+
1_000_000,
|
|
294
|
+
);
|
|
295
|
+
const maxItemsPerField = boundedInteger(
|
|
296
|
+
options.maxItemsPerField,
|
|
297
|
+
DEFAULT_MAX_ITEMS_PER_FIELD,
|
|
298
|
+
1,
|
|
299
|
+
256,
|
|
300
|
+
);
|
|
301
|
+
const maxItemChars = boundedInteger(
|
|
302
|
+
options.maxItemChars,
|
|
303
|
+
DEFAULT_MAX_ITEM_CHARS,
|
|
304
|
+
32,
|
|
305
|
+
16_000,
|
|
306
|
+
);
|
|
307
|
+
const maxFallbackSourceChars = boundedInteger(
|
|
308
|
+
options.maxFallbackSourceChars,
|
|
309
|
+
DEFAULT_MAX_FALLBACK_SOURCE_CHARS,
|
|
310
|
+
512,
|
|
311
|
+
1_000_000,
|
|
312
|
+
);
|
|
313
|
+
const sources = selectBoundedSources(messages, maxFallbackSourceChars);
|
|
314
|
+
const firstUser = sources.find((entry) => entry.role === "user");
|
|
315
|
+
const candidates = emptyHandoff(
|
|
316
|
+
truncateText(firstUser?.text || "", maxItemChars),
|
|
317
|
+
);
|
|
318
|
+
|
|
319
|
+
for (const source of sources) {
|
|
320
|
+
for (const fragment of fragments(source.text)) {
|
|
321
|
+
candidates.changedFiles.push(...pathsFrom(fragment));
|
|
322
|
+
if (
|
|
323
|
+
/^(?:constraint|constraints|requirement|requirements|must|must not|do not|don't|only|约束|必须|不要|只能|仅限)\b/iu.test(
|
|
324
|
+
fragment,
|
|
325
|
+
) ||
|
|
326
|
+
/\bwithout\s+(?:widening|changing|removing|losing)\b/iu.test(fragment)
|
|
327
|
+
) {
|
|
328
|
+
candidates.constraints.push(
|
|
329
|
+
stripLabel(
|
|
330
|
+
fragment,
|
|
331
|
+
"constraint(?:s)?|requirement(?:s)?|must(?: not)?|do not|don't|only|约束|必须|不要|只能|仅限",
|
|
332
|
+
),
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
if (
|
|
336
|
+
/^(?:key decision|decision|decided|approach|we will|选择|决定|方案)\b/iu.test(
|
|
337
|
+
fragment,
|
|
338
|
+
)
|
|
339
|
+
) {
|
|
340
|
+
candidates.keyDecisions.push(
|
|
341
|
+
stripLabel(
|
|
342
|
+
fragment,
|
|
343
|
+
"key decision|decision|decided|approach|we will|选择|决定|方案",
|
|
344
|
+
),
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
if (
|
|
348
|
+
/\b(?:test|tests|vitest|jest|pytest|playwright|lint|typecheck|build)\b/iu.test(
|
|
349
|
+
fragment,
|
|
350
|
+
) &&
|
|
351
|
+
/\b(?:passed|failed|run|ran|green|verified|success|succeeded|通过|失败|运行|验证)\b/iu.test(
|
|
352
|
+
fragment,
|
|
353
|
+
)
|
|
354
|
+
) {
|
|
355
|
+
candidates.tests.push(stripLabel(fragment, "test(?:s)?|测试|验证"));
|
|
356
|
+
}
|
|
357
|
+
if (
|
|
358
|
+
/\b(?:unresolved (?:external )?side effects?|external action|not (?:yet )?(?:published|deployed|merged|sent)|pending (?:publish|deploy|merge)|未发布|未部署|未合并|外部副作用)\b/iu.test(
|
|
359
|
+
fragment,
|
|
360
|
+
)
|
|
361
|
+
) {
|
|
362
|
+
candidates.unresolvedSideEffects.push(
|
|
363
|
+
stripLabel(
|
|
364
|
+
fragment,
|
|
365
|
+
"unresolved (?:external )?side effects?|external action|外部副作用",
|
|
366
|
+
),
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
if (
|
|
370
|
+
/\b(?:checkpoint|commit\s+[0-9a-f]{7,40}|implemented|completed|done|verified|checkpoint|检查点|已完成|已实现)\b/iu.test(
|
|
371
|
+
fragment,
|
|
372
|
+
)
|
|
373
|
+
) {
|
|
374
|
+
candidates.checkpoints.push(
|
|
375
|
+
stripLabel(fragment, "checkpoint|status|检查点|状态"),
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
if (
|
|
379
|
+
/\b(?:blocker|blocked|blocking|cannot|can't|missing|required external|阻塞|受阻|缺失)\b/iu.test(
|
|
380
|
+
fragment,
|
|
381
|
+
)
|
|
382
|
+
) {
|
|
383
|
+
candidates.blockers.push(
|
|
384
|
+
stripLabel(fragment, "blocker(?:s)?|blocked|阻塞"),
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
if (
|
|
388
|
+
/^(?:next steps?|next|todo|remaining|then|下一步|待办|后续)\b/iu.test(
|
|
389
|
+
fragment,
|
|
390
|
+
)
|
|
391
|
+
) {
|
|
392
|
+
candidates.nextSteps.push(
|
|
393
|
+
stripLabel(
|
|
394
|
+
fragment,
|
|
395
|
+
"next steps?|next|todo|remaining|then|下一步|待办|后续",
|
|
396
|
+
),
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
for (const field of ARRAY_FIELDS) {
|
|
403
|
+
candidates[field] = uniqueBounded(
|
|
404
|
+
candidates[field],
|
|
405
|
+
maxItemsPerField,
|
|
406
|
+
maxItemChars,
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
return fitToContentLimit(candidates, maxContentChars);
|
|
410
|
+
}
|