chainlesschain 0.162.177 → 0.162.178
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/package.json +1 -1
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-DT-VPWuN.js → AIOps-DRftcSue.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DyOreOVN.js → ActionButton-BFvUaMKR.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DslNsKux.js → Analytics-C0-Rru4P.js} +3 -3
- package/src/assets/web-panel/assets/AppLayout-bx-BCljj.js +9 -0
- package/src/assets/web-panel/assets/{Artifacts-DoaAtEcY.js → Artifacts-DAJ8B3Un.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DPG3WdJ9.js → Audit-hOk4L1lr.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-C_JO6R5G.js → BackgroundAgents-3pbDpM9z.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-Cv3BooyX.js → Backup-BtziGDn9.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-D2uQXWu-.js → BaseInput-kmshphJ3.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-B4Vczyf3.js → Chat-d7tGSosA.js} +5 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-p-_PBpX_.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-qTgk4VeP.js → Checkbox-C4Eh4Tz5.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DlLWcIzj.js → Codegen-r7gmhZyA.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DNO73qp7.js → Col-U7mDaGlL.js} +1 -1
- package/src/assets/web-panel/assets/{Community-vRDNpc4j.js → Community-Bpu8aH1T.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-CEWtIXni.js → Compact-CHb2XBJe.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-KgYC9Fxi.js → Compliance-Cn_r4dey.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-zj5wvkpT.js → Cowork-CdMWfDcz.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-BLDoCozU.js → Cron-BtnREHWy.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BYnff4VY.js → Crosschain-BKI9TSzr.js} +1 -1
- package/src/assets/web-panel/assets/{DID-C75VFsVm.js → DID-pkNubzzJ.js} +2 -2
- package/src/assets/web-panel/assets/Dashboard-1rrz1snN.js +3 -0
- package/src/assets/web-panel/assets/{Dropdown-B5dbO4Kx.js → Dropdown-DLyFVxDc.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BDipZtHJ.js → EmailListRenderer-CtUWfYVq.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-DmIzt8jj.js → FamilyGuardDashboard-B8eX2Qe4.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-D9QOS-uW.js → Federation-D8lsDGus.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-B47HRwAm.js → FormItemContext-CRYt_aIw.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-3R4mXmgV.js → GenericCardRenderer-ClKzY8_N.js} +1 -1
- package/src/assets/web-panel/assets/{Git-DrNXZf1C.js → Git-BXj5Dney.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-BGd7JR98.js → Governance-Cm-I8RMz.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-D-2he1ed.js → Inference-CPvbhvgt.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-C0sHIbK5.js → KnowledgeGraph-sYNDZaoi.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DiBQO-jL.js → Logs-BZY_3CRZ.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-DL_5eV2D.js → MarkdownRenderer-up0BW6pv.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-VR59OdrC.js → Marketplace-C5MEJ2Qe.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DrPzwSd3.js → McpTools-ihdrn43I.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-CBgKALwQ.js → Memory-Br8bPMlh.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-pQ9Tn-Mn.js → MobileBridge-BNntgrYW.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-mASB6jyj.js → MobileProjects-BdV915mw.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-DTMgE7HC.js → Mtc-A3wDmlqL.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-CwTnCtiL.js → MtcAudit-CF-mBLWM.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-ngm6WU8f.js → Multisig-Iy2k_MSo.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-4YO4Qww9.js → NLProgramming-kk0W7HUb.js} +1 -1
- package/src/assets/web-panel/assets/Notes-B5u5t_4S.js +7 -0
- package/src/assets/web-panel/assets/{NotificationSettings-r2H8yPKb.js → NotificationSettings-BN0POf6_.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-CHkSUrXB.js +1 -0
- package/src/assets/web-panel/assets/{Organization-DrO7jRWS.js → Organization-DwWQESuN.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Cnwu4i4t.js → Overflow-DG6klrcC.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-zi-cDwA_.js → P2P-BwJcKkgZ.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-DBEryDv7.js → PdhVaultBrowser-BwOHG0in.js} +5 -5
- package/src/assets/web-panel/assets/{Permissions-lqXK2C3x.js → Permissions-CGMXe4TX.js} +4 -4
- package/src/assets/web-panel/assets/PersonalDataHub-ziYqg7-A.js +8 -0
- package/src/assets/web-panel/assets/{Pipeline-Kep5KAGW.js → Pipeline-BzJfeoGt.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-CHdvOAh1.js → Privacy-DLh3Bblx.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-BhKfdwe9.js → ProjectInit-USVWW36c.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-Yavk9K8A.js → ProjectSettings-CiiOn62h.js} +2 -2
- package/src/assets/web-panel/assets/Projects-6V-PNmcA.js +1 -0
- package/src/assets/web-panel/assets/{Providers-Bfym6SQn.js → Providers-CBPWWzpu.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-CLSQcrlR.js → QrScannerModal-QVwoRUq3.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-VPa2WKQN.js → QuickAsk-CXnR-2Vn.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-CGXR8jVU.js → Recommend-ClaNzjmF.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-C_20YfMB.js → RemoteSession-C3rGw8vJ.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-awZh68UV.js → Reputation-Ci-OWAoP.js} +1 -1
- package/src/assets/web-panel/assets/{Row-Ctb4oiYN.js → Row-DRhAwXOS.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-D3sdjvUV.js → RssFeed-BQLJQ2_y.js} +3 -3
- package/src/assets/web-panel/assets/{Search-C-zfA4kT.js → Search-QQUpkfFd.js} +1 -1
- package/src/assets/web-panel/assets/{Security-D9XlmHA3.js → Security-DdXKzuKT.js} +4 -4
- package/src/assets/web-panel/assets/{Services-C3UKnr41.js → Services-x2Zh62Qd.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-BQxagZfF.js → Skeleton-GdY4KwRz.js} +1 -1
- package/src/assets/web-panel/assets/Skills-Bv4tY1Fd.js +1 -0
- package/src/assets/web-panel/assets/{Sla-DveENvek.js → Sla-C3QnM-11.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BFjXLNgF.js → SpeechSettings-Bl3ytvmI.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-BpHgbaP9.js → SyncSettings-Wp9IwTsP.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-CF3rIrDe.js +1 -0
- package/src/assets/web-panel/assets/{Templates-DEiaoyve.js → Templates-CGfvVVM9.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-ITg774nY.js → Tenant-CVXmwQ3U.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-D3ZBcvnb.js → Terminal-bvwrt03E.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-BsLU6JjU.js → TimelineRenderer-D0g74KhH.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-Cb5Pquc9.js → Tokens-BH4IwzlT.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-Dwfy-m9N.js → Trigger-DJOpM533.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-CnlSRGG0.js → Trust-B43EPRLr.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-Y4TlvKVo.js → UkeySign-BmBFG-em.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BpKLtTTO.js → VideoEditing-n9oJwB8k.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-LLBzIq8x.js → Wallet-D5QeivHp.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-BeSRiusP.js → WebAuthn-DcNy7igO.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-BK_l1tXO.js → WorkflowEditor-BVjc7-5-.js} +1 -1
- package/src/assets/web-panel/assets/{chat-DYd-X7Wg.js → chat-Dy5Tfj3m.js} +1 -1
- package/src/assets/web-panel/assets/{colors-C9uip71j.js → colors-C4c2CNZU.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-JBrfjUP6.js → compact-item-DPa3O5vN.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-D03fbuiq.js → createContext-TLcfNA6_.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BAwdDA_5.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DLQOR6l-.js → hasIn-D41LVFkp.js} +1 -1
- package/src/assets/web-panel/assets/{index-rIxxfdTN.js → index-0oevYjfT.js} +1 -1
- package/src/assets/web-panel/assets/{index-CChaISMb.js → index-388pLGJ1.js} +1 -1
- package/src/assets/web-panel/assets/{index-BfOs_bmg.js → index-B8nLBZbv.js} +3 -3
- package/src/assets/web-panel/assets/{index-D-1SqEpQ.js → index-BPTGAjee.js} +1 -1
- package/src/assets/web-panel/assets/{index-BYv-LWdy.js → index-BPtrOBmW.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cpn19c9k.js → index-BQiIxHBy.js} +1 -1
- package/src/assets/web-panel/assets/{index-BpYKLrUT.js → index-BSM1cHVK.js} +1 -1
- package/src/assets/web-panel/assets/{index-CS63r8h3.js → index-BYPr9fkz.js} +1 -1
- package/src/assets/web-panel/assets/{index-Q7mmL6w4.js → index-BsQ7Ev6i.js} +1 -1
- package/src/assets/web-panel/assets/{index-SO6lgMg0.js → index-Btk9qLL2.js} +1 -1
- package/src/assets/web-panel/assets/{index-iahNhZwm.js → index-BvmziZSG.js} +1 -1
- package/src/assets/web-panel/assets/{index-BnQgRjsm.js → index-BvopLC_T.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ba-Ps_AJ.js → index-C7xhTVyP.js} +1 -1
- package/src/assets/web-panel/assets/{index-BuNFCZCx.js → index-CNk_ZooP.js} +1 -1
- package/src/assets/web-panel/assets/{index-CL0ixCxk.js → index-CQrEHoOG.js} +1 -1
- package/src/assets/web-panel/assets/{index-CChQBM1d.js → index-CSxex23J.js} +1 -1
- package/src/assets/web-panel/assets/{index-5YN7F5bO.js → index-CVjgm992.js} +1 -1
- package/src/assets/web-panel/assets/{index-CwoDpKzW.js → index-CWK4zOPe.js} +1 -1
- package/src/assets/web-panel/assets/{index-BcBZwlnG.js → index-CX0VsoP4.js} +1 -1
- package/src/assets/web-panel/assets/{index-B46YcgsV.js → index-CXl0YPNG.js} +1 -1
- package/src/assets/web-panel/assets/{index-l08afIbV.js → index-Cip7LWml.js} +1 -1
- package/src/assets/web-panel/assets/{index-6GuLRpBQ.js → index-Cq_hlWNt.js} +1 -1
- package/src/assets/web-panel/assets/{index-DYLZY4uh.js → index-CzZ49YZL.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0X76LjX.js → index-D2Nkivlm.js} +1 -1
- package/src/assets/web-panel/assets/{index-BdH9l8wl.js → index-DBUgRs4D.js} +1 -1
- package/src/assets/web-panel/assets/index-DEjVkdzq.js +1 -0
- package/src/assets/web-panel/assets/{index-D4UY5Z60.js → index-DNsBj2Ob.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ce0Bf1YF.js → index-Di4X8cfI.js} +1 -1
- package/src/assets/web-panel/assets/{index-ByHO3SqZ.js → index-DljFsVGI.js} +1 -1
- package/src/assets/web-panel/assets/{index-C2zmOsyD.js → index-Korc3QIe.js} +1 -1
- package/src/assets/web-panel/assets/index-LMOc5xrS.js +1 -0
- package/src/assets/web-panel/assets/{index-BNCdRmWf.js → index-MKZDje0H.js} +1 -1
- package/src/assets/web-panel/assets/{index-D8KvuDz0.js → index-OHAfRu_3.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaokIHt3.js → index-WEJr8PL5.js} +1 -1
- package/src/assets/web-panel/assets/{index-CILVyK3b.js → index-WinCp6du.js} +1 -1
- package/src/assets/web-panel/assets/{index-CVZWiUE_.js → index-Yjr6cqSK.js} +1 -1
- package/src/assets/web-panel/assets/{index-CqWk1FLG.js → index-iQ6gtFih.js} +1 -1
- package/src/assets/web-panel/assets/{index-DNMAAUVk.js → index-pt3s7yvV.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ck17i0OD.js → index-tQ3igERQ.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-CG9z1c6w.js → initDefaultProps-BFZu87WZ.js} +1 -1
- package/src/assets/web-panel/assets/{motion-B1Ky7Zff.js → motion-DJIo7qvt.js} +1 -1
- package/src/assets/web-panel/assets/{move-DME8X2P1.js → move-Cfr5qknL.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-cuJYSWB7.js → mtc-parser-Bgc-OadH.js} +1 -1
- package/src/assets/web-panel/assets/{omit-UI_EE0uZ.js → omit-X3WI-TNp.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-BIoE_Z_V.js → pickAttrs-pJhU9IxK.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-B48-9HKN.js → placementArrow-BNg_Vj3T.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-D7x_GDgD.js → responsiveObserve-TeSEGQ5-.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DjzC5_7m.js → slide-D_t_P0bv.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-C6BIymhh.js → statusUtils-DrrIMwAT.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-B4dGrdD9.js → styleChecker-BjZCuFRm.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-Bken4aNE.js → useFlexGapSupport-rTFdlqdQ.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BMlqECqv.js → useFs-BidCpfLX.js} +1 -1
- package/src/assets/web-panel/assets/usePersonalDataHub-C5mHttA9.js +1 -0
- package/src/assets/web-panel/assets/{vnode-CKJQmxa0.js → vnode-BrbcRiHZ.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CaZunuau.js → zoom-PISX7AkR.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/__tests__/hub-wechat.test.js +45 -0
- package/src/commands/background-session.js +5 -2
- package/src/commands/context.js +33 -1
- package/src/commands/hub.js +473 -39
- package/src/commands/init.js +212 -110
- package/src/commands/llm.js +22 -6
- package/src/commands/skill.js +11 -1
- package/src/data/changelog.json +76 -270
- package/src/gateways/ws/personal-data-hub-protocol.js +22 -2
- package/src/harness/golden-transcript.js +3 -0
- package/src/index.js +18 -7
- package/src/lib/approval-authority-store.js +891 -0
- package/src/lib/background-interaction-resolver.js +399 -54
- package/src/lib/background-session-transport.js +3 -1
- package/src/lib/context-breakdown.js +82 -3
- package/src/lib/event-runtime-host.js +225 -0
- package/src/lib/event-runtime-store.js +102 -21
- package/src/lib/event-runtime-worker.js +70 -2
- package/src/lib/hooks-v2-producers.js +33 -8
- package/src/lib/hooks-v2-runtime.js +360 -40
- package/src/lib/interaction-adapter.js +66 -0
- package/src/lib/operation-fingerprint.js +107 -2
- package/src/lib/pdh-dedicated-batch-collectors.js +124 -0
- package/src/lib/personal-data-hub-wiring.js +327 -52
- package/src/lib/process-execution-broker/credential-agent.js +954 -111
- package/src/lib/process-execution-broker/index.js +369 -85
- package/src/lib/process-execution-broker/platform-sandbox.js +320 -140
- package/src/lib/provider-http-error.js +94 -0
- package/src/lib/remote-approval-bridge.js +222 -26
- package/src/lib/side-effect-ledger-store.js +65 -14
- package/src/lib/skill-loader.js +215 -12
- package/src/lib/skill-process-broker.js +15 -1
- package/src/lib/sub-agent-context.js +42 -0
- package/src/lib/turn-binding-store.js +64 -15
- package/src/lib/turn-binding.js +85 -16
- package/src/repl/agent-repl.js +40 -6
- package/src/repl/remote-approval.js +13 -13
- package/src/repl/repl-turn-binding.js +46 -16
- package/src/runtime/agent-core.js +286 -35
- package/src/runtime/coding-agent-contract-shared.cjs +16 -0
- package/src/runtime/headless-runner.js +147 -34
- package/src/runtime/headless-stream.js +147 -7
- package/src/workers/background-agent-worker.js +70 -38
- package/src/assets/web-panel/assets/AppLayout-BNJJAYME.js +0 -9
- package/src/assets/web-panel/assets/ChatBubbleRenderer-DE6reP99.js +0 -1
- package/src/assets/web-panel/assets/Dashboard-C4Gutni2.js +0 -3
- package/src/assets/web-panel/assets/Notes-DP1k45mF.js +0 -7
- package/src/assets/web-panel/assets/OrderTableRenderer-CoM_Zw0J.js +0 -1
- package/src/assets/web-panel/assets/PersonalDataHub-b63T3HJM.js +0 -9
- package/src/assets/web-panel/assets/Projects-CN8E_5Mq.js +0 -1
- package/src/assets/web-panel/assets/Skills-q6eb6KPZ.js +0 -1
- package/src/assets/web-panel/assets/Tasks-DvepRb8-.js +0 -1
- package/src/assets/web-panel/assets/devWarning-B8LQ8leS.js +0 -1
- package/src/assets/web-panel/assets/index-Bh8BPtqR.js +0 -1
- package/src/assets/web-panel/assets/index-CeVrHLzZ.js +0 -1
- package/src/assets/web-panel/assets/usePersonalDataHub-DLdrfmMa.js +0 -1
package/src/lib/turn-binding.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* -> toolCallIds[] (tool_use_ids this turn issued)
|
|
14
14
|
* -> permissionDecisionIds[] (approval decisions made this turn)
|
|
15
15
|
* -> childAgentIds[] (sub-agents spawned this turn)
|
|
16
|
+
* -> childBindings[] (child trace/checkpoint/worktree lineage)
|
|
16
17
|
* -> worktreeId (isolation worktree, if any)
|
|
17
18
|
* -> coverage: full | partial | none
|
|
18
19
|
*
|
|
@@ -90,6 +91,7 @@ function emptyRecord(turnId, conversationOffset) {
|
|
|
90
91
|
toolCallIds: [],
|
|
91
92
|
permissionDecisionIds: [],
|
|
92
93
|
childAgentIds: [],
|
|
94
|
+
childBindings: [],
|
|
93
95
|
worktreeId: null,
|
|
94
96
|
// side-effect flags → coverage (kept internal; surfaced via `coverage`)
|
|
95
97
|
_flags: {
|
|
@@ -160,6 +162,39 @@ export class TurnBindingLog {
|
|
|
160
162
|
return this;
|
|
161
163
|
}
|
|
162
164
|
|
|
165
|
+
recordChildBinding(turnId, binding) {
|
|
166
|
+
if (!binding || typeof binding !== "object") return this;
|
|
167
|
+
const childAgentId =
|
|
168
|
+
binding.childAgentId == null ? null : String(binding.childAgentId);
|
|
169
|
+
if (!childAgentId) return this;
|
|
170
|
+
const normalized = {
|
|
171
|
+
childAgentId,
|
|
172
|
+
parentAgentId:
|
|
173
|
+
binding.parentAgentId == null ? null : String(binding.parentAgentId),
|
|
174
|
+
traceId: binding.traceId == null ? null : String(binding.traceId),
|
|
175
|
+
parentTraceId:
|
|
176
|
+
binding.parentTraceId == null ? null : String(binding.parentTraceId),
|
|
177
|
+
checkpointIds: Array.isArray(binding.checkpointIds)
|
|
178
|
+
? [...new Set(binding.checkpointIds.map(String))]
|
|
179
|
+
: [],
|
|
180
|
+
toolUseIds: Array.isArray(binding.toolUseIds)
|
|
181
|
+
? [...new Set(binding.toolUseIds.map(String))]
|
|
182
|
+
: [],
|
|
183
|
+
worktreeId:
|
|
184
|
+
binding.worktreeId == null ? null : String(binding.worktreeId),
|
|
185
|
+
worktreePath:
|
|
186
|
+
binding.worktreePath == null ? null : String(binding.worktreePath),
|
|
187
|
+
};
|
|
188
|
+
const rec = this._rec(turnId);
|
|
189
|
+
const index = rec.childBindings.findIndex(
|
|
190
|
+
(item) => item.childAgentId === childAgentId,
|
|
191
|
+
);
|
|
192
|
+
if (index === -1) rec.childBindings.push(normalized);
|
|
193
|
+
else rec.childBindings[index] = normalized;
|
|
194
|
+
pushUnique(rec.childAgentIds, childAgentId);
|
|
195
|
+
return this;
|
|
196
|
+
}
|
|
197
|
+
|
|
163
198
|
/** Bind (or re-bind to the earliest) file checkpoint for this turn. */
|
|
164
199
|
bindCheckpoint(turnId, checkpointId) {
|
|
165
200
|
const rec = this._rec(turnId);
|
|
@@ -231,6 +266,11 @@ export class TurnBindingLog {
|
|
|
231
266
|
toolCallIds: [...rec.toolCallIds],
|
|
232
267
|
permissionDecisionIds: [...rec.permissionDecisionIds],
|
|
233
268
|
childAgentIds: [...rec.childAgentIds],
|
|
269
|
+
childBindings: rec.childBindings.map((binding) => ({
|
|
270
|
+
...binding,
|
|
271
|
+
checkpointIds: [...binding.checkpointIds],
|
|
272
|
+
toolUseIds: [...binding.toolUseIds],
|
|
273
|
+
})),
|
|
234
274
|
worktreeId: rec.worktreeId,
|
|
235
275
|
coverage: computeCoverage(rec._flags),
|
|
236
276
|
};
|
|
@@ -260,6 +300,22 @@ export class TurnBindingLog {
|
|
|
260
300
|
childAgentIds: Array.isArray(r.childAgentIds)
|
|
261
301
|
? [...r.childAgentIds]
|
|
262
302
|
: [],
|
|
303
|
+
childBindings: Array.isArray(r.childBindings)
|
|
304
|
+
? r.childBindings.map((binding) => ({
|
|
305
|
+
childAgentId: String(binding.childAgentId),
|
|
306
|
+
parentAgentId: binding.parentAgentId ?? null,
|
|
307
|
+
traceId: binding.traceId ?? null,
|
|
308
|
+
parentTraceId: binding.parentTraceId ?? null,
|
|
309
|
+
checkpointIds: Array.isArray(binding.checkpointIds)
|
|
310
|
+
? binding.checkpointIds.map(String)
|
|
311
|
+
: [],
|
|
312
|
+
toolUseIds: Array.isArray(binding.toolUseIds)
|
|
313
|
+
? binding.toolUseIds.map(String)
|
|
314
|
+
: [],
|
|
315
|
+
worktreeId: binding.worktreeId ?? null,
|
|
316
|
+
worktreePath: binding.worktreePath ?? null,
|
|
317
|
+
}))
|
|
318
|
+
: [],
|
|
263
319
|
worktreeId: r.worktreeId ?? null,
|
|
264
320
|
_flags: { ...emptyRecord(id)._flags, ...(r._flags || {}) },
|
|
265
321
|
});
|
|
@@ -428,16 +484,12 @@ export function buildTurnBindingFromMarks(turns = [], marks = []) {
|
|
|
428
484
|
/**
|
|
429
485
|
* Stateful feeder turning raw agent-loop events into TurnBindingLog records —
|
|
430
486
|
* the SHARED producer core for every runner (headless and the interactive
|
|
431
|
-
* REPL)
|
|
432
|
-
*
|
|
433
|
-
* tool-call ids are synthesized `<nonce>:c<seq>` and turn ids `<nonce>:t<seq>`
|
|
434
|
-
* (mirrors the side-effect ledger's op-id scheme — stable within a run, unique
|
|
435
|
-
* across resumes as long as `nonce` is per-run unique).
|
|
487
|
+
* REPL). Provider tool ids are consumed directly; ids are synthesized only for
|
|
488
|
+
* legacy/custom event sources that omit `tool_use_id`.
|
|
436
489
|
*
|
|
437
|
-
*
|
|
438
|
-
*
|
|
439
|
-
*
|
|
440
|
-
* prune) does.
|
|
490
|
+
* Every begun turn marks the table dirty. Tool-free turns still need an
|
|
491
|
+
* explicit `full` coverage record; otherwise restore/history consumers cannot
|
|
492
|
+
* distinguish "nothing happened" from "the producer failed to record".
|
|
441
493
|
*
|
|
442
494
|
* @param {{log?: TurnBindingLog, nonce?: string}} [opts]
|
|
443
495
|
*/
|
|
@@ -458,8 +510,7 @@ export function createTurnBindingFeed({
|
|
|
458
510
|
* contract `pickPersistedTurn` relies on). `supersede: true` first prunes
|
|
459
511
|
* records at/after that offset (live-REPL rewind/clear/compaction rule);
|
|
460
512
|
* append-only runners leave it off. `worktreeId` stamps the run's isolation
|
|
461
|
-
* worktree onto the record
|
|
462
|
-
* turn in a worktree still writes nothing).
|
|
513
|
+
* worktree onto the record.
|
|
463
514
|
*/
|
|
464
515
|
beginTurn(
|
|
465
516
|
conversationOffset,
|
|
@@ -471,6 +522,7 @@ export function createTurnBindingFeed({
|
|
|
471
522
|
currentTurnId = `${nonce}:t${turnSeq++}`;
|
|
472
523
|
log.startTurn(currentTurnId, { conversationOffset });
|
|
473
524
|
if (worktreeId != null) log.setWorktree(currentTurnId, worktreeId);
|
|
525
|
+
dirty = true;
|
|
474
526
|
return currentTurnId;
|
|
475
527
|
},
|
|
476
528
|
currentTurnId: () => currentTurnId,
|
|
@@ -486,27 +538,41 @@ export function createTurnBindingFeed({
|
|
|
486
538
|
}
|
|
487
539
|
break;
|
|
488
540
|
case "tool-executing": {
|
|
489
|
-
const callId =
|
|
541
|
+
const callId =
|
|
542
|
+
event.tool_use_id == null
|
|
543
|
+
? `${nonce}:c${callSeq++}`
|
|
544
|
+
: String(event.tool_use_id);
|
|
490
545
|
currentCallId = callId;
|
|
491
546
|
log.recordToolCall(turnId, callId, { name: event.tool });
|
|
492
547
|
dirty = true;
|
|
493
548
|
break;
|
|
494
549
|
}
|
|
495
550
|
case "tool-result": {
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
551
|
+
const callId =
|
|
552
|
+
event.tool_use_id == null
|
|
553
|
+
? currentCallId
|
|
554
|
+
: String(event.tool_use_id);
|
|
555
|
+
// New core events expose the exact decision id. Legacy/custom event
|
|
556
|
+
// sources retain the deterministic compatibility derivation.
|
|
499
557
|
const policy = event.result?.policy;
|
|
500
558
|
if (policy && (policy.via || policy.decision)) {
|
|
501
559
|
log.recordPermissionDecision(
|
|
502
560
|
turnId,
|
|
503
|
-
|
|
561
|
+
event.permission_decision_id ||
|
|
562
|
+
`${callId || "call"}:perm:${policy.via || policy.decision}`,
|
|
504
563
|
);
|
|
505
564
|
dirty = true;
|
|
506
565
|
}
|
|
566
|
+
if (event.result?.userEdited === true) {
|
|
567
|
+
log.markUserEdit(turnId);
|
|
568
|
+
dirty = true;
|
|
569
|
+
}
|
|
507
570
|
// Foreground spawn_sub_agent reports its child id on the result.
|
|
508
571
|
if (event.result?.subAgentId) {
|
|
509
572
|
log.recordChildAgent(turnId, event.result.subAgentId);
|
|
573
|
+
if (event.result.childBinding) {
|
|
574
|
+
log.recordChildBinding(turnId, event.result.childBinding);
|
|
575
|
+
}
|
|
510
576
|
dirty = true;
|
|
511
577
|
}
|
|
512
578
|
currentCallId = null;
|
|
@@ -515,6 +581,9 @@ export function createTurnBindingFeed({
|
|
|
515
581
|
case "background-sub-agent-result":
|
|
516
582
|
if (event.subAgentId) {
|
|
517
583
|
log.recordChildAgent(turnId, event.subAgentId);
|
|
584
|
+
if (event.childBinding) {
|
|
585
|
+
log.recordChildBinding(turnId, event.childBinding);
|
|
586
|
+
}
|
|
518
587
|
dirty = true;
|
|
519
588
|
}
|
|
520
589
|
break;
|
package/src/repl/agent-repl.js
CHANGED
|
@@ -1123,8 +1123,10 @@ export async function startAgentRepl(options = {}) {
|
|
|
1123
1123
|
// P1 explicit turn→checkpoint binding — the REPL as PRODUCER (mirrors the
|
|
1124
1124
|
// headless runner's feed via the shared feeder core): one record per
|
|
1125
1125
|
// interactive turn, persisted dirty-gated at each settle. Lazily created on
|
|
1126
|
-
// the first prompt turn of a persistable (JSONL) session
|
|
1126
|
+
// the first prompt turn of a persistable (JSONL) session. This is Critical
|
|
1127
|
+
// recovery state: a failure blocks subsequent model/tool turns.
|
|
1127
1128
|
let _turnBindingProducer = null;
|
|
1129
|
+
let _turnBindingCriticalError = null;
|
|
1128
1130
|
// Apply --output-style or the settings.json `outputStyle` default at startup.
|
|
1129
1131
|
try {
|
|
1130
1132
|
const { resolveOutputStyle } = await import("../lib/output-styles.js");
|
|
@@ -3650,6 +3652,11 @@ export async function startAgentRepl(options = {}) {
|
|
|
3650
3652
|
_sanitizeRolesNextTurn =
|
|
3651
3653
|
messages[messages.length - 1]?.role === "user";
|
|
3652
3654
|
sessionId = resumeId;
|
|
3655
|
+
// The producer owns one immutable session id. Recreate it lazily
|
|
3656
|
+
// on the next turn so bindings from the resumed conversation can
|
|
3657
|
+
// never be appended to the previously active session.
|
|
3658
|
+
_turnBindingProducer = null;
|
|
3659
|
+
_turnBindingCriticalError = null;
|
|
3653
3660
|
// The prior session's checkpoint marks (turn-index → checkpoint id)
|
|
3654
3661
|
// no longer map to this swapped-in history; keeping them would make
|
|
3655
3662
|
// a later /rewind restore files from the WRONG session's snapshot.
|
|
@@ -3671,6 +3678,8 @@ export async function startAgentRepl(options = {}) {
|
|
|
3671
3678
|
_sanitizeRolesNextTurn =
|
|
3672
3679
|
messages[messages.length - 1]?.role === "user";
|
|
3673
3680
|
sessionId = existing.id;
|
|
3681
|
+
_turnBindingProducer = null;
|
|
3682
|
+
_turnBindingCriticalError = null;
|
|
3674
3683
|
// Drop the prior session's checkpoint marks (see JSONL branch).
|
|
3675
3684
|
_checkpointMarks.length = 0;
|
|
3676
3685
|
_clearedConversation = null; // stash belongs to the swapped-out session
|
|
@@ -5267,6 +5276,15 @@ export async function startAgentRepl(options = {}) {
|
|
|
5267
5276
|
}
|
|
5268
5277
|
}
|
|
5269
5278
|
|
|
5279
|
+
if (_turnBindingCriticalError) {
|
|
5280
|
+
logger.error(
|
|
5281
|
+
`[recovery] critical turn-binding state is unavailable: ${_turnBindingCriticalError.message}. ` +
|
|
5282
|
+
"Resume or start a healthy session before running another model/tool turn.",
|
|
5283
|
+
);
|
|
5284
|
+
prompt();
|
|
5285
|
+
return;
|
|
5286
|
+
}
|
|
5287
|
+
|
|
5270
5288
|
// Add user message (keep the object ref so a /btw aside can be injected for
|
|
5271
5289
|
// this turn's model call and then stripped before persistence).
|
|
5272
5290
|
const _userMsg = { role: "user", content: _userMessageContent };
|
|
@@ -5283,11 +5301,26 @@ export async function startAgentRepl(options = {}) {
|
|
|
5283
5301
|
if (!_turnBindingProducer) {
|
|
5284
5302
|
const { createReplTurnBindingProducer } =
|
|
5285
5303
|
await import("./repl-turn-binding.js");
|
|
5286
|
-
_turnBindingProducer = createReplTurnBindingProducer({
|
|
5304
|
+
_turnBindingProducer = createReplTurnBindingProducer({
|
|
5305
|
+
sessionId,
|
|
5306
|
+
onError: (error, phase) => {
|
|
5307
|
+
_turnBindingCriticalError = error;
|
|
5308
|
+
logger.warn(
|
|
5309
|
+
`[recovery] turn binding ${phase} failed for ${sessionId}: ${error.message}`,
|
|
5310
|
+
);
|
|
5311
|
+
},
|
|
5312
|
+
});
|
|
5287
5313
|
}
|
|
5288
5314
|
_turnBindingProducer?.beginTurn(messages.length);
|
|
5289
|
-
} catch {
|
|
5290
|
-
|
|
5315
|
+
} catch (error) {
|
|
5316
|
+
_turnBindingCriticalError =
|
|
5317
|
+
error instanceof Error ? error : new Error(String(error));
|
|
5318
|
+
if (messages[messages.length - 1] === _userMsg) messages.pop();
|
|
5319
|
+
logger.error(
|
|
5320
|
+
`[recovery] refusing the turn because binding state is unavailable: ${_turnBindingCriticalError.message}`,
|
|
5321
|
+
);
|
|
5322
|
+
prompt();
|
|
5323
|
+
return;
|
|
5291
5324
|
}
|
|
5292
5325
|
}
|
|
5293
5326
|
|
|
@@ -5722,8 +5755,9 @@ export async function startAgentRepl(options = {}) {
|
|
|
5722
5755
|
// Non-critical
|
|
5723
5756
|
}
|
|
5724
5757
|
}
|
|
5725
|
-
// Persist the explicit turn-binding table for this settled turn
|
|
5726
|
-
//
|
|
5758
|
+
// Persist the explicit turn-binding table for this settled turn,
|
|
5759
|
+
// including tool-free turns. A failure is Critical: the producer throws,
|
|
5760
|
+
// this turn reports an error, and the guard above blocks later turns.
|
|
5727
5761
|
_turnBindingProducer?.persistIfDirty();
|
|
5728
5762
|
// Auto-compact when context grows too large
|
|
5729
5763
|
if (
|
|
@@ -8,10 +8,9 @@
|
|
|
8
8
|
* publishes permission.resolved so the phone/web UI clears it)
|
|
9
9
|
* - remote answer first → cancel the local readline prompt and print
|
|
10
10
|
* the outcome
|
|
11
|
-
* - remote leg times out or the bridge closes mid-ask → NOT a
|
|
12
|
-
* keep waiting on the terminal. A
|
|
13
|
-
*
|
|
14
|
-
* semantics only.
|
|
11
|
+
* - remote leg times out or the bridge closes mid-ask → NOT a remote human
|
|
12
|
+
* decision, so keep waiting on the terminal. A later local answer still
|
|
13
|
+
* needs the bridge's durable CAS; an expired/closed card cannot be revived.
|
|
15
14
|
*
|
|
16
15
|
* Pure over an injected bridge + local prompt handle ({promise, cancel}),
|
|
17
16
|
* so the race is unit-testable without a WS server or readline.
|
|
@@ -46,8 +45,9 @@ export function describeAskContext({
|
|
|
46
45
|
};
|
|
47
46
|
}
|
|
48
47
|
|
|
49
|
-
//
|
|
50
|
-
//
|
|
48
|
+
// These outcomes are not a remote human decision. The terminal may still
|
|
49
|
+
// answer, but its result is accepted only if resolveLocally can durably settle
|
|
50
|
+
// the same live card.
|
|
51
51
|
const NON_DECISIVE_REMOTE = new Set(["timeout", "closed"]);
|
|
52
52
|
|
|
53
53
|
/**
|
|
@@ -90,14 +90,14 @@ export async function raceLocalAndRemote({
|
|
|
90
90
|
winner = await localLeg;
|
|
91
91
|
}
|
|
92
92
|
if (winner.src === "local") {
|
|
93
|
-
if (requestId)
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
93
|
+
if (!requestId) return false;
|
|
94
|
+
try {
|
|
95
|
+
const persisted = bridge.resolveLocally(requestId, winner.approved);
|
|
96
|
+
return persisted === true && winner.approved === true;
|
|
97
|
+
} catch {
|
|
98
|
+
// A local "yes" without a durable CAS is not an approval.
|
|
99
|
+
return false;
|
|
99
100
|
}
|
|
100
|
-
return winner.approved;
|
|
101
101
|
}
|
|
102
102
|
try {
|
|
103
103
|
local.cancel?.();
|
|
@@ -14,10 +14,9 @@
|
|
|
14
14
|
* anchored at/after its own offset — under `pickPersistedTurn`'s
|
|
15
15
|
* exact-offset matching a stale record from the discarded timeline would
|
|
16
16
|
* otherwise shadow the new turn and could offer the wrong checkpoint.
|
|
17
|
-
* 3. Per-settle persistence:
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* swallows its own failures.
|
|
17
|
+
* 3. Per-settle persistence: `persistTurnBinding` after each turn, including
|
|
18
|
+
* tool-free turns. Failures are reported through `onError` and fail closed
|
|
19
|
+
* by default; tests/diagnostics may explicitly request advisory mode.
|
|
21
20
|
*
|
|
22
21
|
* I/O goes through `_deps` so tests drive the producer hermetically.
|
|
23
22
|
*/
|
|
@@ -37,15 +36,35 @@ export const _deps = {
|
|
|
37
36
|
};
|
|
38
37
|
|
|
39
38
|
/**
|
|
40
|
-
* @param {{sessionId?: string, nonce?: string
|
|
39
|
+
* @param {{sessionId?: string, nonce?: string, failClosed?:boolean,
|
|
40
|
+
* onError?:(error:Error, phase:string)=>void}} [opts]
|
|
41
41
|
* @returns {object|null} null when the session cannot persist (no sessionId)
|
|
42
42
|
*/
|
|
43
|
-
export function createReplTurnBindingProducer({
|
|
43
|
+
export function createReplTurnBindingProducer({
|
|
44
|
+
sessionId,
|
|
45
|
+
nonce,
|
|
46
|
+
onError,
|
|
47
|
+
failClosed = true,
|
|
48
|
+
} = {}) {
|
|
44
49
|
if (!sessionId) return null;
|
|
45
50
|
// Per-process nonce (mirrors the headless runner's per-run nonce): restored
|
|
46
51
|
// turn ids keep their original nonce, new ids can't collide across resumes.
|
|
47
52
|
const runNonce = nonce || String(_deps.now());
|
|
48
53
|
let feed = null;
|
|
54
|
+
let lastError = null;
|
|
55
|
+
const report = (error, phase) => {
|
|
56
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
57
|
+
try {
|
|
58
|
+
onError?.(lastError, phase);
|
|
59
|
+
} catch {
|
|
60
|
+
// Reporting must not replace the underlying recovery warning.
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const rejectOr = (error, phase, fallback) => {
|
|
64
|
+
report(error, phase);
|
|
65
|
+
if (failClosed) throw lastError;
|
|
66
|
+
return fallback;
|
|
67
|
+
};
|
|
49
68
|
return {
|
|
50
69
|
/**
|
|
51
70
|
* Anchor a new interactive turn. Call just AFTER the user message was
|
|
@@ -61,8 +80,8 @@ export function createReplTurnBindingProducer({ sessionId, nonce } = {}) {
|
|
|
61
80
|
});
|
|
62
81
|
}
|
|
63
82
|
return feed.beginTurn(conversationOffset, { supersede: true });
|
|
64
|
-
} catch {
|
|
65
|
-
return null;
|
|
83
|
+
} catch (error) {
|
|
84
|
+
return rejectOr(error, "load", null);
|
|
66
85
|
}
|
|
67
86
|
},
|
|
68
87
|
/** Fold one agent-loop event into the current turn (fed by agentLoop). */
|
|
@@ -70,21 +89,32 @@ export function createReplTurnBindingProducer({ sessionId, nonce } = {}) {
|
|
|
70
89
|
if (!feed) return false;
|
|
71
90
|
try {
|
|
72
91
|
return feed.handleEvent(event);
|
|
73
|
-
} catch {
|
|
74
|
-
return false;
|
|
92
|
+
} catch (error) {
|
|
93
|
+
return rejectOr(error, "event", false);
|
|
75
94
|
}
|
|
76
95
|
},
|
|
77
|
-
/** Persist the table after a settled turn (dirty-gated,
|
|
96
|
+
/** Persist the table after a settled turn (dirty-gated, fail-closed). */
|
|
78
97
|
persistIfDirty() {
|
|
79
98
|
if (!feed || !feed.isDirty()) return false;
|
|
99
|
+
let ok = false;
|
|
80
100
|
try {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
return
|
|
84
|
-
}
|
|
85
|
-
|
|
101
|
+
ok = _deps.persistTurnBinding(sessionId, feed.log);
|
|
102
|
+
} catch (error) {
|
|
103
|
+
return rejectOr(error, "persist", false);
|
|
104
|
+
}
|
|
105
|
+
if (!ok) {
|
|
106
|
+
return rejectOr(
|
|
107
|
+
new Error("turn-binding snapshot was not persisted"),
|
|
108
|
+
"persist",
|
|
109
|
+
false,
|
|
110
|
+
);
|
|
86
111
|
}
|
|
112
|
+
feed.clearDirty();
|
|
113
|
+
lastError = null;
|
|
114
|
+
return true;
|
|
87
115
|
},
|
|
116
|
+
lastError: () => lastError,
|
|
117
|
+
sessionId: () => sessionId,
|
|
88
118
|
/** The live table (for tests / future in-process consumers). */
|
|
89
119
|
log: () => (feed ? feed.log : null),
|
|
90
120
|
};
|