chainlesschain 0.166.6 → 0.166.7
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 +3 -1
- package/src/assets/web-panel/assets/{AIOps-CVnFjTfG.js → AIOps-BlrmQxa2.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-BxkwuuQC.js → ActionButton-zyRyLITg.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-C2670q6z.js → Analytics-DwGz7OGN.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-CU_rylW6.js → AppLayout-Dc-nj7Zd.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-DGJmYqnj.js → Artifacts-7Hu3O73p.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-BZOQbINJ.js → Audit-Bnoe3-fR.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-DghB4QwF.js → BackgroundAgents-BqYFrDKZ.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-l0mwPbta.js → Backup-B3hwW1nz.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-Bv3WSZOh.js → BaseInput-XFVxLA4w.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-s88nBdvt.js → Chat-CWRDNw7e.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-Z8CBuB1a.js → ChatBubbleRenderer-Bf30VM8G.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-B5icasEs.js → Checkbox-kFeeBgac.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-CsUFqNud.js → Codegen-CCxp8xoI.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DlBtClaW.js → Col-BLKZalle.js} +1 -1
- package/src/assets/web-panel/assets/{Community-xRn1IdLB.js → Community-DD0eWCez.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-naIr8a_o.js → Compact-CHqHWdy0.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-Dp9esfFE.js → Compliance-Bw54uPiK.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DQlMYJB-.js → Cowork-DZ13zKNJ.js} +4 -4
- package/src/assets/web-panel/assets/{Cron-Cd0oNLzJ.js → Cron-Dlj5Jevg.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BtDIx3XX.js → Crosschain-Nvz0aR0j.js} +1 -1
- package/src/assets/web-panel/assets/{DID-BOlpzEwg.js → DID-Ct89eUyY.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-DV15Axk1.js → Dashboard-BHUH5IAe.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-COXrewN1.js → Dropdown-BhZG-PO7.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-EjIt0Cm7.js → EmailListRenderer-ae4RVwwJ.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-DJlhwb-R.js → FamilyGuardDashboard-AOcxLfLr.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BMiFl82k.js → Federation-BK2PJQOF.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BUcDQyxn.js → FormItemContext-C2n3xO2_.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-C25uFxvK.js → GenericCardRenderer-DcyUVFZq.js} +1 -1
- package/src/assets/web-panel/assets/{Git-D20uaEUU.js → Git-tBae9Lt8.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-CQxYJjCX.js → Governance-DmNR3AP4.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-m-sczpS5.js → Inference-CoseEigi.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-CBsIlU0S.js → KnowledgeGraph-Bdjd1sxr.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-D0-5bqeu.js → Logs-CtlkKIcn.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-BwH414Ms.js → MarkdownRenderer-CZsTBEQE.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-CwDGFu2Q.js → Marketplace-BTYb7nEx.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-7FxJ3omT.js → McpTools-D0iUdW3P.js} +2 -2
- package/src/assets/web-panel/assets/{Memory-DOVyb59U.js → Memory--gwI7w4Y.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DZXl-Hje.js → MobileBridge-JmFBi24T.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-DlZ8tRXt.js → MobileProjects-BK01cQRx.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-D7Pjx1s_.js → Mtc-u7avzyoO.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-BND7lX8p.js → MtcAudit-gT3z5fo_.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-BknS7B-p.js → Multisig-BIqZTz5n.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-7C2-KPHt.js → NLProgramming-DdhVfXYq.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-DNWdTndN.js → Notes-CBlyUmY3.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-DCm4KcJZ.js → NotificationSettings-DSyI26N3.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DyVwwjJx.js → OrderTableRenderer-B7IEuNz4.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-Dl2O_qJ9.js → Organization-ozhi4kGS.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-BOFCvk9Q.js → Overflow-CBy57RVM.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-DgdVowY1.js → P2P-CA-ZRv77.js} +2 -2
- package/src/assets/web-panel/assets/PdhVaultBrowser-DOHc9zm8.js +7 -0
- package/src/assets/web-panel/assets/{Permissions-BHNEUUwa.js → Permissions-DiP632GP.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-CaZbrOdz.js → PersonalDataHub-AnU8O-SS.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-DJDnoXmE.js → Pipeline-DDibOUaP.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-CBQr2eX8.js → Privacy-D421t36T.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Yghqa06z.js → ProjectInit-DR879ZPJ.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-HBAtJi8U.js → ProjectSettings-Ded8o6aY.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-DiCGnMjz.js → Projects-BHPxiucB.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-uJTz77GI.js → Providers-Boivuu-E.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-k3M5ouTp.js → QrScannerModal-xKD_ntKp.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-CMji45PH.js → QuickAsk-D3y_A6FV.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DyoZYPls.js → Recommend-BjKM-YC2.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-s1gR38IO.js → RemoteSession-CgqKMXG4.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-D4hIs4vV.js → Reputation-Ci2GjH5p.js} +1 -1
- package/src/assets/web-panel/assets/{Row-mzE-ElTg.js → Row-B0-T2BSh.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-cg7J3hI6.js → RssFeed-Bet-ur-r.js} +3 -3
- package/src/assets/web-panel/assets/{Search-6M0TkGSZ.js → Search-DWtRAS2R.js} +1 -1
- package/src/assets/web-panel/assets/{Security-B1GQ67qh.js → Security-BDfu2Qn6.js} +4 -4
- package/src/assets/web-panel/assets/{Services-D_RwU_5S.js → Services-CvJmvSMM.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-TZjk-dsW.js → Skeleton-CEbrKpdC.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CG6FcaCV.js → Skills-CjVeiETf.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-BI190QDv.js → Sla-Dibypxum.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BWmxF2Wu.js → SpeechSettings-XflYXp7a.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CwPiGw6L.js → SyncSettings-ro1Ivx1E.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-BIXgCeSk.js → Tasks-CHq1qFbo.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-CQFgGCoK.js → Templates-CRnUZxtZ.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DAelEdkL.js → Tenant-jUX72JCA.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-BbqWK6qh.js → Terminal-BBhAs7pt.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-cmG3zvY5.js → TimelineRenderer-CD5M3RGp.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-C8444NKU.js → Tokens-sah3v0gu.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-C1Rpnz0I.js → Trigger-BNT3Uz3s.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-u4koPiFD.js → Trust-BytMGPMo.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-oPWKn80Z.js → UkeySign-BkYVMRQs.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-D0CUUY_5.js → VideoEditing-psvb5Q7Y.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-fu9pIAbt.js → Wallet-PFQTW0MH.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-Bc5ciuOx.js → WebAuthn-DgO-OwRT.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-BCin4_4N.js → WorkflowEditor-DL2l9VNl.js} +1 -1
- package/src/assets/web-panel/assets/{chat-B2jbM-XN.js → chat-C84akEzN.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CUVoUQ_2.js → colors-DzTWuQKP.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DgOGpkRH.js → compact-item-CR9LJQFv.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DIxU6eKI.js → createContext-CTTov5Kn.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BOhvmlpc.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DoKRKMav.js → hasIn-DALj523o.js} +1 -1
- package/src/assets/web-panel/assets/{index-i5MB455u.js → index-3-XJoYgX.js} +1 -1
- package/src/assets/web-panel/assets/{index-CLdpHe6w.js → index-7ux_XohH.js} +1 -1
- package/src/assets/web-panel/assets/{index-B3F_p8NA.js → index-AXnERsyV.js} +1 -1
- package/src/assets/web-panel/assets/{index-D2yo6ast.js → index-B2qpjU-D.js} +1 -1
- package/src/assets/web-panel/assets/{index-CWbL1-N0.js → index-B6QOJbSn.js} +1 -1
- package/src/assets/web-panel/assets/{index-DtyAuGOm.js → index-BDyt57zL.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpTFx8Xx.js → index-BHRXKiU1.js} +1 -1
- package/src/assets/web-panel/assets/{index-CF80xxPG.js → index-BKNIzw0U.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRMEO2Tl.js → index-BNaQt49r.js} +1 -1
- package/src/assets/web-panel/assets/{index-ByjrulIZ.js → index-Be6Os5S8.js} +1 -1
- package/src/assets/web-panel/assets/{index-BCLeNqIL.js → index-C5eeMl_2.js} +1 -1
- package/src/assets/web-panel/assets/{index-DJMHnbmu.js → index-CNmTDXmf.js} +1 -1
- package/src/assets/web-panel/assets/{index-2flsPFIX.js → index-CXTEpfGe.js} +1 -1
- package/src/assets/web-panel/assets/{index-BwYofQJg.js → index-CXaCRXN4.js} +1 -1
- package/src/assets/web-panel/assets/{index-B5ySiGYy.js → index-CZhhFQi9.js} +1 -1
- package/src/assets/web-panel/assets/{index-CeWSw-z5.js → index-Cef0n4k_.js} +1 -1
- package/src/assets/web-panel/assets/{index-C846lPGD.js → index-CjkPDSX4.js} +1 -1
- package/src/assets/web-panel/assets/{index-C9TsO9T9.js → index-CmELknPe.js} +1 -1
- package/src/assets/web-panel/assets/{index-CqlwIjJx.js → index-CnxjXIsK.js} +1 -1
- package/src/assets/web-panel/assets/{index-Co4lDEk-.js → index-CqUgXYIQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cj-us-D_.js → index-CunGDV0g.js} +1 -1
- package/src/assets/web-panel/assets/{index-BFUprhNd.js → index-D0MqUnKO.js} +1 -1
- package/src/assets/web-panel/assets/{index-DGTZdZOE.js → index-D9ScRFxz.js} +3 -3
- package/src/assets/web-panel/assets/{index-C88m9lsi.js → index-DBIPnoTj.js} +1 -1
- package/src/assets/web-panel/assets/index-DDyMJexx.js +1 -0
- package/src/assets/web-panel/assets/{index-BXb-Smmm.js → index-DH6OG-ci.js} +1 -1
- package/src/assets/web-panel/assets/{index-eTWPaeBI.js → index-DZER6Lj3.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cskz--fd.js → index-D_Bg0LdK.js} +1 -1
- package/src/assets/web-panel/assets/{index-D-ufbAJB.js → index-Dah8M4l2.js} +1 -1
- package/src/assets/web-panel/assets/{index-DHugFl3v.js → index-DjE_ew7U.js} +1 -1
- package/src/assets/web-panel/assets/{index-B9mSYovv.js → index-DtW6Zr_i.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ds8r3Fzb.js → index-DxdzSljS.js} +1 -1
- package/src/assets/web-panel/assets/{index-CPXdBnGi.js → index-QW0EXx14.js} +1 -1
- package/src/assets/web-panel/assets/{index-B-f6l4Vm.js → index-W9axN_Ce.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpvyOt5Z.js → index-_8vetPbU.js} +1 -1
- package/src/assets/web-panel/assets/index-btiojFYn.js +1 -0
- package/src/assets/web-panel/assets/{index-eYxUASSG.js → index-eJcFleIV.js} +1 -1
- package/src/assets/web-panel/assets/{index-be8SonCh.js → index-hzzTITR9.js} +1 -1
- package/src/assets/web-panel/assets/{index-BtSPhEyC.js → index-s4CFyn-n.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-B4chl7iR.js → initDefaultProps-JuW8mFj7.js} +1 -1
- package/src/assets/web-panel/assets/{motion-DruN9h96.js → motion-Cwb0HBve.js} +1 -1
- package/src/assets/web-panel/assets/{move-Cl0UtCgU.js → move-DHokzMgu.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-FX2ttw70.js → mtc-parser-DX31y6QS.js} +1 -1
- package/src/assets/web-panel/assets/{omit-BDCneY46.js → omit-BCIUYDA6.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DycsEg8b.js → pickAttrs-DMCj4EoZ.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-Bc-dBuMv.js → placementArrow-Dy5K-u1s.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve--Wwaf8lu.js → responsiveObserve-DkGeZu54.js} +1 -1
- package/src/assets/web-panel/assets/{slide-vDmHQqHH.js → slide-Dc5dyJdg.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-9c52yv3G.js → statusUtils-DIUBjOaC.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BT4BiO6_.js → styleChecker-DmyEOxm5.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-C7XxWPcP.js → useFlexGapSupport-FRhakk1e.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BHoMqh4i.js → useFs-clXyV1WQ.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BOLxvsAG.js → usePersonalDataHub-UF6DG41z.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CA7poeeP.js → vnode-CoCt95G7.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-B_sAn-co.js → zoom-yVWt-ENm.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/graph.js +215 -5
- package/src/commands/team-distributed.js +342 -2
- package/src/commands/team.js +169 -7
- package/src/data/changelog.json +13 -0
- package/src/generated/cc-agent-protocol.schema.json +6 -1
- package/src/lib/agent-team/task-lease.js +315 -0
- package/src/lib/agent-team/team-agent-stream.js +16 -0
- package/src/lib/agent-team/team-distributed-graph-bridge.js +257 -0
- package/src/lib/agent-team/team-distributed-graph-writer.js +523 -0
- package/src/lib/agent-team/team-distributed-queue.js +251 -0
- package/src/lib/agent-team/team-graph-runtime-adapter.js +1918 -0
- package/src/lib/agent-team/team-runner.js +225 -2
- package/src/lib/app-server/graph-runtime.js +754 -0
- package/src/lib/app-server/rollout-store.js +32 -0
- package/src/lib/app-server/server.js +140 -0
- package/src/lib/autonomous-agent.js +11 -0
- package/src/lib/cowork-graph-authority-adapter.js +455 -0
- package/src/lib/dynamic-workflow-facade.js +83 -16
- package/src/lib/graph-kernel/adapters.js +93 -20
- package/src/lib/graph-kernel/authority.js +324 -0
- package/src/lib/graph-kernel/compiler.js +1 -8
- package/src/lib/graph-kernel/cutover-authority-resolver.js +219 -0
- package/src/lib/graph-kernel/cutover-ledger.js +650 -0
- package/src/lib/graph-kernel/event-store.js +15 -1
- package/src/lib/graph-kernel/graph-runtime-surfaces.json +1427 -0
- package/src/lib/graph-kernel/index.js +4 -0
- package/src/lib/graph-kernel/migration-saga.js +309 -0
- package/src/lib/graph-kernel/runtime-surface-manifest.js +481 -0
- package/src/lib/graph-kernel/runtime.js +661 -24
- package/src/lib/graph-kernel/store-cutover-evidence.js +354 -0
- package/src/lib/graph-kernel/trace-reducer.js +6 -0
- package/src/lib/graph-kernel/trigger-adapter.js +60 -3
- package/src/lib/legacy-runtime-authority.js +160 -0
- package/src/lib/orchestrator.js +28 -0
- package/src/lib/scheduler-kernel/graph-authority-adapter.js +512 -0
- package/src/lib/scheduler-kernel/runtime.js +75 -2
- package/src/assets/web-panel/assets/PdhVaultBrowser-BiaZfQIM.js +0 -7
- package/src/assets/web-panel/assets/devWarning-DiSlgCC4.js +0 -1
- package/src/assets/web-panel/assets/index-9WIQEHvv.js +0 -1
- package/src/assets/web-panel/assets/index-B7mDobAl.js +0 -1
package/src/commands/team.js
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
import fs from "fs";
|
|
19
19
|
import path from "path";
|
|
20
|
-
import { randomUUID } from "node:crypto";
|
|
20
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
21
21
|
import { fileURLToPath } from "url";
|
|
22
22
|
import { TaskLeaseRegistry } from "../lib/agent-team/task-lease.js";
|
|
23
23
|
import { TeamRunner } from "../lib/agent-team/team-runner.js";
|
|
@@ -32,6 +32,8 @@ import {
|
|
|
32
32
|
computeTeamGraphRevisionDigest,
|
|
33
33
|
projectTeamGraphCollaboration,
|
|
34
34
|
} from "../lib/agent-team/team-graph-projection.js";
|
|
35
|
+
import { TeamGraphRuntimeAdapter } from "../lib/agent-team/team-graph-runtime-adapter.js";
|
|
36
|
+
import { createRuntimeGraphCutoverAuthorityResolver } from "../lib/graph-kernel/cutover-authority-resolver.js";
|
|
35
37
|
import { resolveTeamTaskContract } from "../lib/agent-team/team-task-contract.js";
|
|
36
38
|
import {
|
|
37
39
|
TeamScopeLock,
|
|
@@ -326,6 +328,41 @@ function teamExecutionMode(options) {
|
|
|
326
328
|
return "dry-run";
|
|
327
329
|
}
|
|
328
330
|
|
|
331
|
+
export function teamGraphAuthorityMode(
|
|
332
|
+
options,
|
|
333
|
+
env = process.env,
|
|
334
|
+
{ runKey = undefined, optIn = false, resolver = undefined } = {},
|
|
335
|
+
) {
|
|
336
|
+
const executionMode = teamExecutionMode(options);
|
|
337
|
+
const configured = String(env.CHAINLESSCHAIN_GRAPH_CLI_TEAM || "")
|
|
338
|
+
.trim()
|
|
339
|
+
.toLowerCase();
|
|
340
|
+
if (configured && !["legacy", "shadow", "canonical"].includes(configured)) {
|
|
341
|
+
throw new Error(
|
|
342
|
+
"CHAINLESSCHAIN_GRAPH_CLI_TEAM must be legacy, shadow, or canonical",
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
const fallbackMode =
|
|
346
|
+
executionMode === "dry-run" ? "shadow" : configured || "legacy";
|
|
347
|
+
const authorityResolver =
|
|
348
|
+
resolver ||
|
|
349
|
+
createRuntimeGraphCutoverAuthorityResolver({
|
|
350
|
+
env,
|
|
351
|
+
surface: "cli_team",
|
|
352
|
+
entryId: "cli-team-local",
|
|
353
|
+
fallbackMode,
|
|
354
|
+
});
|
|
355
|
+
const resolved =
|
|
356
|
+
typeof authorityResolver === "function"
|
|
357
|
+
? authorityResolver({ runKey, optIn })
|
|
358
|
+
: authorityResolver.resolve({ runKey, optIn, fallbackMode });
|
|
359
|
+
const mode = typeof resolved === "string" ? resolved : resolved?.mode;
|
|
360
|
+
if (!["legacy", "shadow", "canonical"].includes(mode)) {
|
|
361
|
+
throw new Error("Team Graph authority resolver returned an invalid mode");
|
|
362
|
+
}
|
|
363
|
+
return mode;
|
|
364
|
+
}
|
|
365
|
+
|
|
329
366
|
function optionWasProvided(command, name) {
|
|
330
367
|
const source = command?.getOptionValueSource?.(name);
|
|
331
368
|
return source != null && source !== "default";
|
|
@@ -1008,8 +1045,23 @@ export function makeShellRunTask() {
|
|
|
1008
1045
|
settle(terminationError);
|
|
1009
1046
|
return;
|
|
1010
1047
|
}
|
|
1011
|
-
if (code === 0)
|
|
1012
|
-
|
|
1048
|
+
if (code === 0) {
|
|
1049
|
+
settle(null, {
|
|
1050
|
+
code,
|
|
1051
|
+
terminalEvidence: {
|
|
1052
|
+
outputDigest: `sha256:${createHash("sha256")
|
|
1053
|
+
.update(
|
|
1054
|
+
JSON.stringify({
|
|
1055
|
+
command,
|
|
1056
|
+
cwd: process.cwd(),
|
|
1057
|
+
exitCode: code,
|
|
1058
|
+
}),
|
|
1059
|
+
"utf8",
|
|
1060
|
+
)
|
|
1061
|
+
.digest("hex")}`,
|
|
1062
|
+
},
|
|
1063
|
+
});
|
|
1064
|
+
} else {
|
|
1013
1065
|
const stderr = Buffer.concat(stderrChunks).toString("utf8");
|
|
1014
1066
|
settle(new Error(safeProcessError(stderr, `command exited ${code}`)));
|
|
1015
1067
|
}
|
|
@@ -1310,6 +1362,7 @@ function spawnAgentProcess(prompt, cwd, opts = {}) {
|
|
|
1310
1362
|
return;
|
|
1311
1363
|
}
|
|
1312
1364
|
const result = { code };
|
|
1365
|
+
result.terminalEvidence = parser.terminalEvidence();
|
|
1313
1366
|
if (sawStdout || summary.usage || summary.provider || summary.model) {
|
|
1314
1367
|
if (summary.usage) result.usage = summary.usage;
|
|
1315
1368
|
if (summary.provider) result.provider = summary.provider;
|
|
@@ -1994,6 +2047,10 @@ export function registerTeamCommand(program, { logger } = {}) {
|
|
|
1994
2047
|
"--resume",
|
|
1995
2048
|
"Restore progress from --state (completed tasks stay done; stale leases freed)",
|
|
1996
2049
|
)
|
|
2050
|
+
.option(
|
|
2051
|
+
"--graph-canary-opt-in",
|
|
2052
|
+
"Opt this new Team run into an entry-scoped Graph canary",
|
|
2053
|
+
)
|
|
1997
2054
|
.option("--json", "Emit the event stream as JSON lines")
|
|
1998
2055
|
.option(
|
|
1999
2056
|
"--otlp <file>",
|
|
@@ -2642,6 +2699,42 @@ export function registerTeamCommand(program, { logger } = {}) {
|
|
|
2642
2699
|
(_, index) => `teammate-${index + 1}`,
|
|
2643
2700
|
),
|
|
2644
2701
|
});
|
|
2702
|
+
const graphAuthorityMode =
|
|
2703
|
+
resumeSnapshot?.graphProjection?.authorityMode ||
|
|
2704
|
+
teamGraphAuthorityMode(options, process.env, {
|
|
2705
|
+
runKey: teamGraphRunId,
|
|
2706
|
+
optIn: options.graphCanaryOptIn === true,
|
|
2707
|
+
});
|
|
2708
|
+
let graphRuntime = null;
|
|
2709
|
+
const shadowDivergences = [];
|
|
2710
|
+
const recordShadowDivergence = (divergence) => {
|
|
2711
|
+
shadowDivergences.push(divergence);
|
|
2712
|
+
while (shadowDivergences.length > 256) shadowDivergences.shift();
|
|
2713
|
+
};
|
|
2714
|
+
if (["shadow", "canonical"].includes(graphAuthorityMode)) {
|
|
2715
|
+
graphRuntime = new TeamGraphRuntimeAdapter();
|
|
2716
|
+
graphRuntime.open({
|
|
2717
|
+
registry: reg,
|
|
2718
|
+
runId: teamGraphRunId,
|
|
2719
|
+
executionMode: executionContract.mode,
|
|
2720
|
+
worktree: options.worktree === true,
|
|
2721
|
+
teammates,
|
|
2722
|
+
budget: limits,
|
|
2723
|
+
authorityMode: graphAuthorityMode,
|
|
2724
|
+
dynamic: true,
|
|
2725
|
+
});
|
|
2726
|
+
if (graphAuthorityMode === "canonical") {
|
|
2727
|
+
reg = graphRuntime.bindRegistry(reg);
|
|
2728
|
+
mailbox = graphRuntime.bindMailbox(mailbox);
|
|
2729
|
+
} else {
|
|
2730
|
+
reg = graphRuntime.bindRegistry(reg, {
|
|
2731
|
+
onDivergence: recordShadowDivergence,
|
|
2732
|
+
});
|
|
2733
|
+
mailbox = graphRuntime.bindMailbox(mailbox, {
|
|
2734
|
+
onDivergence: recordShadowDivergence,
|
|
2735
|
+
});
|
|
2736
|
+
}
|
|
2737
|
+
}
|
|
2645
2738
|
const settleGovernance = (key, status, extra = {}) => {
|
|
2646
2739
|
const governanceKey = sessionTaskKeyFor(key);
|
|
2647
2740
|
const unit = collaborationUnits.get(governanceKey);
|
|
@@ -2704,6 +2797,9 @@ export function registerTeamCommand(program, { logger } = {}) {
|
|
|
2704
2797
|
revisionDigest: teamGraphRevisionDigest,
|
|
2705
2798
|
authorityDigest: teamGraphAuthorityDigest,
|
|
2706
2799
|
}),
|
|
2800
|
+
graphAuthorityMode,
|
|
2801
|
+
graphAuthority: graphRuntime?.status() || null,
|
|
2802
|
+
graphShadowDivergences: [...shadowDivergences],
|
|
2707
2803
|
});
|
|
2708
2804
|
};
|
|
2709
2805
|
|
|
@@ -2956,13 +3052,34 @@ export function registerTeamCommand(program, { logger } = {}) {
|
|
|
2956
3052
|
realtimeMessaging: options.agent === true,
|
|
2957
3053
|
scopeLock,
|
|
2958
3054
|
recorder,
|
|
2959
|
-
beforeTask: (
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
3055
|
+
beforeTask: (context) => {
|
|
3056
|
+
const { key } = context;
|
|
3057
|
+
if (graphAuthorityMode === "canonical") {
|
|
3058
|
+
graphRuntime?.beforeTask(context);
|
|
3059
|
+
} else if (graphAuthorityMode === "shadow") {
|
|
3060
|
+
try {
|
|
3061
|
+
graphRuntime?.beforeTask(context);
|
|
3062
|
+
} catch (error) {
|
|
3063
|
+
recordShadowDivergence({
|
|
3064
|
+
phase: "assignment",
|
|
3065
|
+
key,
|
|
3066
|
+
code: error?.code || "CC_TEAM_GRAPH_SHADOW_DIVERGED",
|
|
3067
|
+
error: error?.message || String(error),
|
|
3068
|
+
});
|
|
3069
|
+
}
|
|
3070
|
+
}
|
|
2963
3071
|
try {
|
|
3072
|
+
settleGovernance(key, "running", {
|
|
3073
|
+
startedAt: Date.now(),
|
|
3074
|
+
});
|
|
2964
3075
|
persist();
|
|
2965
3076
|
} catch (error) {
|
|
3077
|
+
try {
|
|
3078
|
+
graphRuntime?.abandonTask(key, error);
|
|
3079
|
+
} catch (canonicalError) {
|
|
3080
|
+
canonicalError.cause ||= error;
|
|
3081
|
+
throw canonicalError;
|
|
3082
|
+
}
|
|
2966
3083
|
try {
|
|
2967
3084
|
settleGovernance(key, "pending", {
|
|
2968
3085
|
startedAt: null,
|
|
@@ -2973,6 +3090,38 @@ export function registerTeamCommand(program, { logger } = {}) {
|
|
|
2973
3090
|
throw error;
|
|
2974
3091
|
}
|
|
2975
3092
|
},
|
|
3093
|
+
canonicalSettlement:
|
|
3094
|
+
graphAuthorityMode === "canonical" && graphRuntime
|
|
3095
|
+
? (settlement) => graphRuntime.settleTask(settlement)
|
|
3096
|
+
: null,
|
|
3097
|
+
canonicalReady:
|
|
3098
|
+
graphAuthorityMode === "canonical" && graphRuntime
|
|
3099
|
+
? ({ excludeKeys }) =>
|
|
3100
|
+
graphRuntime.nextReadyTaskKey({ excludeKeys })
|
|
3101
|
+
: null,
|
|
3102
|
+
shadowSettlement:
|
|
3103
|
+
graphAuthorityMode === "shadow" && graphRuntime
|
|
3104
|
+
? (settlement) => graphRuntime.settleTask(settlement)
|
|
3105
|
+
: null,
|
|
3106
|
+
canonicalCancellation:
|
|
3107
|
+
graphAuthorityMode === "canonical" && graphRuntime
|
|
3108
|
+
? ({ reason }) => graphRuntime.cancel(reason)
|
|
3109
|
+
: null,
|
|
3110
|
+
shadowCancellation:
|
|
3111
|
+
graphAuthorityMode === "shadow" && graphRuntime
|
|
3112
|
+
? async ({ reason }) => {
|
|
3113
|
+
try {
|
|
3114
|
+
return await graphRuntime.cancel(reason);
|
|
3115
|
+
} catch (error) {
|
|
3116
|
+
recordShadowDivergence({
|
|
3117
|
+
phase: "run-cancel",
|
|
3118
|
+
code: error?.code || "CC_TEAM_GRAPH_SHADOW_DIVERGED",
|
|
3119
|
+
error: error?.message || String(error),
|
|
3120
|
+
});
|
|
3121
|
+
return null;
|
|
3122
|
+
}
|
|
3123
|
+
}
|
|
3124
|
+
: null,
|
|
2976
3125
|
afterTask: ({ key, status, retry }) => {
|
|
2977
3126
|
const governanceStatus =
|
|
2978
3127
|
status === "completion-discarded" ||
|
|
@@ -3094,6 +3243,19 @@ export function registerTeamCommand(program, { logger } = {}) {
|
|
|
3094
3243
|
}
|
|
3095
3244
|
throw err;
|
|
3096
3245
|
}
|
|
3246
|
+
if (graphRuntime) {
|
|
3247
|
+
const graphStatus = graphRuntime.finalize();
|
|
3248
|
+
summary.graphAuthorityMode = graphAuthorityMode;
|
|
3249
|
+
summary.graphRuntime = graphStatus;
|
|
3250
|
+
summary.graphShadowDivergences = [...shadowDivergences];
|
|
3251
|
+
if (
|
|
3252
|
+
graphAuthorityMode === "canonical" &&
|
|
3253
|
+
graphStatus.status !== "succeeded"
|
|
3254
|
+
) {
|
|
3255
|
+
summary.success = false;
|
|
3256
|
+
summary.done = false;
|
|
3257
|
+
}
|
|
3258
|
+
}
|
|
3097
3259
|
if (controlStore) {
|
|
3098
3260
|
for (const request of controlStore.pending({
|
|
3099
3261
|
anchor: controlCursor,
|
package/src/data/changelog.json
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"source": "CHANGELOG.md",
|
|
3
3
|
"releases": [
|
|
4
|
+
{
|
|
5
|
+
"productVersion": null,
|
|
6
|
+
"cliVersion": "0.166.7",
|
|
7
|
+
"cliVersions": ["0.166.6", "0.166.7"],
|
|
8
|
+
"date": "2026-08-28",
|
|
9
|
+
"title": "",
|
|
10
|
+
"sections": [
|
|
11
|
+
{
|
|
12
|
+
"heading": "Added - cc CLI 0.166.7: authoritative Graph Kernel cutover",
|
|
13
|
+
"body": "> `chainlesschain` **0.166.6 -> 0.166.7** (release candidate,\n> 2026-08-28).\n\n- **Canonical execution authority**: CLI graph, Team, distributed-team,\n Cowork, Scheduler, and App Server entry points now resolve through the\n Graph Kernel cutover ledger instead of silently retaining parallel mutation\n paths.\n- **Durable fencing and recovery**: graph writers, leases, receipts, takeover,\n migration, and crash/resume flows are bound to persisted authority and\n checked-out source evidence so stale owners cannot resume mutations.\n- **Legacy containment**: retired runtimes retain explicitly read-only history\n access while unclassified or mutating legacy routes fail closed and report\n their canonical replacement targets.\n- **Release validation**: publication requires this exact candidate to pass\n Linux/Windows/macOS `CLI CI` and `CLI Strict Sandbox`, the Graph real-journey\n matrix, immutable package checks, and public-registry provenance readback."
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
},
|
|
4
17
|
{
|
|
5
18
|
"productVersion": null,
|
|
6
19
|
"cliVersion": "0.166.6",
|
|
@@ -325,6 +325,7 @@ export class TaskLeaseRegistry {
|
|
|
325
325
|
attempts: t.metadata?.attempts || 0,
|
|
326
326
|
lease: lease ? { ...lease } : null,
|
|
327
327
|
assignee: t.assignee,
|
|
328
|
+
createdBy: t.createdBy ?? null,
|
|
328
329
|
rev: t.rev,
|
|
329
330
|
// Full metadata is exposed so executors can read user payload
|
|
330
331
|
// (e.g. a task's shell `command` or agent `prompt`) — it carries the
|
|
@@ -1465,6 +1466,320 @@ export class TaskLeaseRegistry {
|
|
|
1465
1466
|
return { ok: true, priorStatus };
|
|
1466
1467
|
}
|
|
1467
1468
|
|
|
1469
|
+
/**
|
|
1470
|
+
* Repair the compatibility task view from a terminal canonical Graph node.
|
|
1471
|
+
* This exceptional path may correct a fail-closed recovery cancellation when
|
|
1472
|
+
* the immutable Graph ledger proves that the effect/attempt already settled.
|
|
1473
|
+
*/
|
|
1474
|
+
applyCanonicalTaskProjection(
|
|
1475
|
+
key,
|
|
1476
|
+
{
|
|
1477
|
+
runId,
|
|
1478
|
+
nodeId,
|
|
1479
|
+
graphStatus,
|
|
1480
|
+
authorityGeneration,
|
|
1481
|
+
eventHead,
|
|
1482
|
+
revisionDigest,
|
|
1483
|
+
evidence = null,
|
|
1484
|
+
now = this._now(),
|
|
1485
|
+
} = {},
|
|
1486
|
+
) {
|
|
1487
|
+
const terminalStatus =
|
|
1488
|
+
graphStatus === "succeeded"
|
|
1489
|
+
? TASK_STATUS.COMPLETED
|
|
1490
|
+
: ["failed", "blocked", "cancelled"].includes(graphStatus)
|
|
1491
|
+
? TASK_STATUS.CANCELLED
|
|
1492
|
+
: null;
|
|
1493
|
+
if (!terminalStatus) {
|
|
1494
|
+
return { ok: false, reason: "graph_not_terminal" };
|
|
1495
|
+
}
|
|
1496
|
+
if (
|
|
1497
|
+
!SAFE_HANDOFF_ID_PATTERN.test(String(runId || "")) ||
|
|
1498
|
+
!SAFE_HANDOFF_ID_PATTERN.test(String(nodeId || "")) ||
|
|
1499
|
+
!Number.isSafeInteger(Number(authorityGeneration)) ||
|
|
1500
|
+
Number(authorityGeneration) < 1 ||
|
|
1501
|
+
!SHA256_PATTERN.test(String(eventHead || "")) ||
|
|
1502
|
+
!SHA256_PATTERN.test(String(revisionDigest || ""))
|
|
1503
|
+
) {
|
|
1504
|
+
return { ok: false, reason: "invalid_graph_binding" };
|
|
1505
|
+
}
|
|
1506
|
+
let cleanEvidence;
|
|
1507
|
+
try {
|
|
1508
|
+
cleanEvidence = cloneValue(evidence);
|
|
1509
|
+
} catch {
|
|
1510
|
+
return { ok: false, reason: "invalid_graph_evidence" };
|
|
1511
|
+
}
|
|
1512
|
+
const binding = {
|
|
1513
|
+
schema: "chainlesschain.team-graph-task-projection/v1",
|
|
1514
|
+
runId: String(runId),
|
|
1515
|
+
nodeId: String(nodeId),
|
|
1516
|
+
graphStatus,
|
|
1517
|
+
authorityGeneration: Number(authorityGeneration),
|
|
1518
|
+
eventHead: String(eventHead),
|
|
1519
|
+
revisionDigest: String(revisionDigest),
|
|
1520
|
+
evidence: cleanEvidence,
|
|
1521
|
+
};
|
|
1522
|
+
const projectionDigest = digestValue(binding);
|
|
1523
|
+
const id = this._byKey.get(key);
|
|
1524
|
+
const task = id ? this._tasks.get(id) : null;
|
|
1525
|
+
if (!task) return { ok: false, reason: "not_found" };
|
|
1526
|
+
const prior = task.metadata?.canonicalGraphProjection || null;
|
|
1527
|
+
if (prior?.projectionDigest === projectionDigest) {
|
|
1528
|
+
return {
|
|
1529
|
+
ok: true,
|
|
1530
|
+
idempotent: true,
|
|
1531
|
+
status: task.status,
|
|
1532
|
+
projectionDigest,
|
|
1533
|
+
};
|
|
1534
|
+
}
|
|
1535
|
+
if (
|
|
1536
|
+
prior &&
|
|
1537
|
+
(prior.runId !== binding.runId ||
|
|
1538
|
+
prior.nodeId !== binding.nodeId ||
|
|
1539
|
+
prior.revisionDigest !== binding.revisionDigest ||
|
|
1540
|
+
prior.graphStatus !== binding.graphStatus)
|
|
1541
|
+
) {
|
|
1542
|
+
return { ok: false, reason: "graph_projection_conflict" };
|
|
1543
|
+
}
|
|
1544
|
+
const snapshot = this._tasks.snapshot();
|
|
1545
|
+
const stored = snapshot.tasks.find((candidate) => candidate.id === task.id);
|
|
1546
|
+
if (!stored || stored.rev !== task.rev) {
|
|
1547
|
+
return { ok: false, reason: "concurrent" };
|
|
1548
|
+
}
|
|
1549
|
+
const projectedAt = Number.isFinite(Number(now))
|
|
1550
|
+
? Number(now)
|
|
1551
|
+
: this._now();
|
|
1552
|
+
const metadata = {
|
|
1553
|
+
...stored.metadata,
|
|
1554
|
+
lease: null,
|
|
1555
|
+
canonicalGraphProjection: {
|
|
1556
|
+
...binding,
|
|
1557
|
+
projectionDigest,
|
|
1558
|
+
projectedAt,
|
|
1559
|
+
},
|
|
1560
|
+
};
|
|
1561
|
+
delete metadata.adjudication;
|
|
1562
|
+
if (terminalStatus === TASK_STATUS.COMPLETED) {
|
|
1563
|
+
metadata.result = {
|
|
1564
|
+
canonicalGraph: true,
|
|
1565
|
+
terminalEvidence: cleanEvidence,
|
|
1566
|
+
};
|
|
1567
|
+
delete metadata.lastError;
|
|
1568
|
+
} else {
|
|
1569
|
+
metadata.lastError = `canonical Graph node settled ${graphStatus}`;
|
|
1570
|
+
}
|
|
1571
|
+
stored.status = terminalStatus;
|
|
1572
|
+
stored.assignee = null;
|
|
1573
|
+
stored.updatedAt = projectedAt;
|
|
1574
|
+
stored.rev += 1;
|
|
1575
|
+
stored.metadata = metadata;
|
|
1576
|
+
stored.history = [
|
|
1577
|
+
...(stored.history || []),
|
|
1578
|
+
{
|
|
1579
|
+
ts: projectedAt,
|
|
1580
|
+
actor: "graph-kernel",
|
|
1581
|
+
action: "canonical-projection-repaired",
|
|
1582
|
+
changes: ["status", "assignee", "metadata"],
|
|
1583
|
+
graphStatus,
|
|
1584
|
+
projectionDigest,
|
|
1585
|
+
},
|
|
1586
|
+
];
|
|
1587
|
+
this._tasks = SharedTaskList.restore(snapshot, { now: this._now });
|
|
1588
|
+
this._rebuildIndexes();
|
|
1589
|
+
if (terminalStatus === TASK_STATUS.COMPLETED) {
|
|
1590
|
+
for (const dependent of this._dependentsByKey.get(key) || []) {
|
|
1591
|
+
this._enqueueIfReady(dependent, projectedAt);
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
return { ok: true, status: terminalStatus, projectionDigest };
|
|
1595
|
+
}
|
|
1596
|
+
|
|
1597
|
+
applyCanonicalHandoffProjection(
|
|
1598
|
+
key,
|
|
1599
|
+
{ handoff: source, targetLease = null, now = this._now() } = {},
|
|
1600
|
+
) {
|
|
1601
|
+
if (!source || typeof source !== "object") {
|
|
1602
|
+
return { ok: false, reason: "invalid_handoff_projection" };
|
|
1603
|
+
}
|
|
1604
|
+
const id = normalizedHandoffId(source.id, () => null);
|
|
1605
|
+
const fromHolder = normalizedHolder(source.fromHolder);
|
|
1606
|
+
const toHolder = normalizedHolder(source.toHolder);
|
|
1607
|
+
const revisionDigest = normalizedDigest(source.revisionDigest);
|
|
1608
|
+
const authorityDigest = normalizedDigest(source.authorityDigest);
|
|
1609
|
+
const artifactIds = normalizedArtifactIds(source.artifactIds);
|
|
1610
|
+
const status = String(source.status || "");
|
|
1611
|
+
const ttlMs = Number(source.ttlMs);
|
|
1612
|
+
if (
|
|
1613
|
+
!id ||
|
|
1614
|
+
!fromHolder ||
|
|
1615
|
+
!toHolder ||
|
|
1616
|
+
fromHolder === toHolder ||
|
|
1617
|
+
!revisionDigest ||
|
|
1618
|
+
!authorityDigest ||
|
|
1619
|
+
!artifactIds ||
|
|
1620
|
+
!TEAM_CUSTODY_HANDOFF_STATUSES.includes(status) ||
|
|
1621
|
+
!Number.isSafeInteger(ttlMs) ||
|
|
1622
|
+
ttlMs <= 0 ||
|
|
1623
|
+
ttlMs > MAX_HANDOFF_TTL_MS ||
|
|
1624
|
+
source.taskKey !== key ||
|
|
1625
|
+
typeof source.fromLeaseId !== "string" ||
|
|
1626
|
+
source.fromLeaseId.length === 0 ||
|
|
1627
|
+
!["string", "number"].includes(typeof source.fromFence)
|
|
1628
|
+
) {
|
|
1629
|
+
return { ok: false, reason: "invalid_handoff_projection" };
|
|
1630
|
+
}
|
|
1631
|
+
let preconditions;
|
|
1632
|
+
let summary;
|
|
1633
|
+
try {
|
|
1634
|
+
preconditions = cloneValue(source.preconditions);
|
|
1635
|
+
summary = cloneValue(source.summary);
|
|
1636
|
+
} catch {
|
|
1637
|
+
return { ok: false, reason: "invalid_handoff_projection" };
|
|
1638
|
+
}
|
|
1639
|
+
const idempotencyKey = normalizedHandoffId(
|
|
1640
|
+
source.idempotencyKey,
|
|
1641
|
+
() => null,
|
|
1642
|
+
);
|
|
1643
|
+
if (!idempotencyKey) {
|
|
1644
|
+
return { ok: false, reason: "invalid_handoff_projection" };
|
|
1645
|
+
}
|
|
1646
|
+
const binding = {
|
|
1647
|
+
schema: TEAM_CUSTODY_HANDOFF_SCHEMA,
|
|
1648
|
+
id,
|
|
1649
|
+
taskKey: key,
|
|
1650
|
+
fromHolder,
|
|
1651
|
+
fromLeaseId: source.fromLeaseId,
|
|
1652
|
+
fromFence: source.fromFence,
|
|
1653
|
+
toHolder,
|
|
1654
|
+
revisionDigest,
|
|
1655
|
+
authorityDigest,
|
|
1656
|
+
artifactIds,
|
|
1657
|
+
preconditions,
|
|
1658
|
+
summary,
|
|
1659
|
+
idempotencyKey,
|
|
1660
|
+
ttlMs,
|
|
1661
|
+
};
|
|
1662
|
+
const bindingDigest = digestValue(binding);
|
|
1663
|
+
if (source.bindingDigest && source.bindingDigest !== bindingDigest) {
|
|
1664
|
+
return { ok: false, reason: "handoff_binding_conflict" };
|
|
1665
|
+
}
|
|
1666
|
+
let cleanTargetLease = null;
|
|
1667
|
+
if (status === "committed") {
|
|
1668
|
+
try {
|
|
1669
|
+
cleanTargetLease = cloneValue(targetLease || source.targetLease);
|
|
1670
|
+
} catch {
|
|
1671
|
+
return { ok: false, reason: "invalid_target_lease" };
|
|
1672
|
+
}
|
|
1673
|
+
if (
|
|
1674
|
+
!cleanTargetLease ||
|
|
1675
|
+
cleanTargetLease.holder !== toHolder ||
|
|
1676
|
+
typeof cleanTargetLease.leaseId !== "string" ||
|
|
1677
|
+
cleanTargetLease.leaseId.length === 0 ||
|
|
1678
|
+
!Number.isFinite(Number(cleanTargetLease.expiresAt))
|
|
1679
|
+
) {
|
|
1680
|
+
return { ok: false, reason: "invalid_target_lease" };
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
const taskId = this._byKey.get(key);
|
|
1684
|
+
const task = taskId ? this._tasks.get(taskId) : null;
|
|
1685
|
+
if (!task) return { ok: false, reason: "not_found" };
|
|
1686
|
+
const history = handoffHistory(task);
|
|
1687
|
+
const existing = history.find((entry) => entry.id === id);
|
|
1688
|
+
if (existing && existing.bindingDigest !== bindingDigest) {
|
|
1689
|
+
return { ok: false, reason: "handoff_binding_conflict" };
|
|
1690
|
+
}
|
|
1691
|
+
if (existing && existing.status !== status) {
|
|
1692
|
+
const transitions = {
|
|
1693
|
+
offered: new Set([
|
|
1694
|
+
"accepted",
|
|
1695
|
+
"rejected",
|
|
1696
|
+
"committed",
|
|
1697
|
+
"revoked",
|
|
1698
|
+
"expired",
|
|
1699
|
+
]),
|
|
1700
|
+
accepted: new Set(["committed", "revoked", "expired"]),
|
|
1701
|
+
};
|
|
1702
|
+
if (!transitions[existing.status]?.has(status)) {
|
|
1703
|
+
return { ok: false, reason: "handoff_projection_regressed" };
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
if (existing?.status === status) {
|
|
1707
|
+
return { ok: true, idempotent: true, handoff: cloneValue(existing) };
|
|
1708
|
+
}
|
|
1709
|
+
const projectedAt = Number.isFinite(Number(now))
|
|
1710
|
+
? Number(now)
|
|
1711
|
+
: this._now();
|
|
1712
|
+
const projected = {
|
|
1713
|
+
...(existing || binding),
|
|
1714
|
+
...binding,
|
|
1715
|
+
bindingDigest,
|
|
1716
|
+
expiresAtMs: Number(source.expiresAtMs),
|
|
1717
|
+
status,
|
|
1718
|
+
offeredAt: Number(source.offeredAt),
|
|
1719
|
+
acceptedAt: source.acceptedAt == null ? null : Number(source.acceptedAt),
|
|
1720
|
+
rejectedAt: source.rejectedAt == null ? null : Number(source.rejectedAt),
|
|
1721
|
+
committedAt:
|
|
1722
|
+
source.committedAt == null ? null : Number(source.committedAt),
|
|
1723
|
+
revokedAt: source.revokedAt == null ? null : Number(source.revokedAt),
|
|
1724
|
+
expiredAt: source.expiredAt == null ? null : Number(source.expiredAt),
|
|
1725
|
+
targetStartedAt: existing?.targetStartedAt ?? null,
|
|
1726
|
+
targetSettledAt: existing?.targetSettledAt ?? null,
|
|
1727
|
+
targetSettlement: existing?.targetSettlement ?? null,
|
|
1728
|
+
reason:
|
|
1729
|
+
source.reason == null ? null : String(source.reason).slice(0, 1024),
|
|
1730
|
+
acceptedByAttempt: existing?.acceptedByAttempt ?? null,
|
|
1731
|
+
targetLease:
|
|
1732
|
+
status === "committed"
|
|
1733
|
+
? cloneValue(existing?.targetLease || cleanTargetLease)
|
|
1734
|
+
: null,
|
|
1735
|
+
canonicalProjectedAt: projectedAt,
|
|
1736
|
+
updatedAt: Number(source.updatedAt) || projectedAt,
|
|
1737
|
+
};
|
|
1738
|
+
if (existing) {
|
|
1739
|
+
history[history.indexOf(existing)] = projected;
|
|
1740
|
+
} else {
|
|
1741
|
+
history.push(projected);
|
|
1742
|
+
while (history.length > MAX_HANDOFF_HISTORY) history.shift();
|
|
1743
|
+
}
|
|
1744
|
+
const snapshot = this._tasks.snapshot();
|
|
1745
|
+
const stored = snapshot.tasks.find((candidate) => candidate.id === task.id);
|
|
1746
|
+
if (!stored || stored.rev !== task.rev) {
|
|
1747
|
+
return { ok: false, reason: "concurrent" };
|
|
1748
|
+
}
|
|
1749
|
+
stored.rev += 1;
|
|
1750
|
+
stored.updatedAt = projectedAt;
|
|
1751
|
+
stored.metadata = { ...stored.metadata, custodyHandoffs: history };
|
|
1752
|
+
if (
|
|
1753
|
+
status === "committed" &&
|
|
1754
|
+
![TASK_STATUS.COMPLETED, TASK_STATUS.CANCELLED].includes(stored.status)
|
|
1755
|
+
) {
|
|
1756
|
+
stored.status = TASK_STATUS.IN_PROGRESS;
|
|
1757
|
+
stored.assignee = toHolder;
|
|
1758
|
+
stored.metadata.lease = cloneValue(projected.targetLease);
|
|
1759
|
+
} else if (
|
|
1760
|
+
status === "expired" &&
|
|
1761
|
+
stored.metadata?.lease?.leaseId === binding.fromLeaseId
|
|
1762
|
+
) {
|
|
1763
|
+
stored.status = TASK_STATUS.PENDING;
|
|
1764
|
+
stored.assignee = null;
|
|
1765
|
+
stored.metadata.lease = null;
|
|
1766
|
+
}
|
|
1767
|
+
stored.history = [
|
|
1768
|
+
...(stored.history || []),
|
|
1769
|
+
{
|
|
1770
|
+
ts: projectedAt,
|
|
1771
|
+
actor: "graph-kernel",
|
|
1772
|
+
action: "canonical-handoff-projected",
|
|
1773
|
+
changes: ["status", "assignee", "metadata"],
|
|
1774
|
+
handoffId: id,
|
|
1775
|
+
handoffStatus: status,
|
|
1776
|
+
},
|
|
1777
|
+
];
|
|
1778
|
+
this._tasks = SharedTaskList.restore(snapshot, { now: this._now });
|
|
1779
|
+
this._rebuildIndexes();
|
|
1780
|
+
return { ok: true, handoff: cloneValue(projected) };
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1468
1783
|
/** Bind a pending adjudication to its immutable durable case evidence. */
|
|
1469
1784
|
bindAdjudicationCase(key, { caseId, registryDigest, sideEffectDigest } = {}) {
|
|
1470
1785
|
const id = this._byKey.get(key);
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* are never copied into parser state or returned to callers.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import { createHash } from "node:crypto";
|
|
10
11
|
import { TextDecoder } from "node:util";
|
|
11
12
|
|
|
12
13
|
export const DEFAULT_TEAM_AGENT_MAX_LINE_BYTES = 1024 * 1024;
|
|
@@ -96,6 +97,7 @@ export class TeamAgentStreamParser {
|
|
|
96
97
|
#tokenUsageEvents = 0;
|
|
97
98
|
#usageByIdentity = new Map();
|
|
98
99
|
#sawTerminalResult = false;
|
|
100
|
+
#terminalResultDigest = null;
|
|
99
101
|
#finished = false;
|
|
100
102
|
#failed = null;
|
|
101
103
|
#finalSummary = null;
|
|
@@ -204,6 +206,16 @@ export class TeamAgentStreamParser {
|
|
|
204
206
|
return this.#copyLiveSummary();
|
|
205
207
|
}
|
|
206
208
|
|
|
209
|
+
/**
|
|
210
|
+
* Return an immutable digest of the exact terminal result record without
|
|
211
|
+
* retaining or exposing its prompt/result body.
|
|
212
|
+
*/
|
|
213
|
+
terminalEvidence() {
|
|
214
|
+
return this.#terminalResultDigest
|
|
215
|
+
? Object.freeze({ outputDigest: this.#terminalResultDigest })
|
|
216
|
+
: null;
|
|
217
|
+
}
|
|
218
|
+
|
|
207
219
|
#copyLiveSummary() {
|
|
208
220
|
return {
|
|
209
221
|
provider: this.#provider,
|
|
@@ -291,6 +303,9 @@ export class TeamAgentStreamParser {
|
|
|
291
303
|
}
|
|
292
304
|
if (line.trim() === "") return;
|
|
293
305
|
|
|
306
|
+
const lineDigest = `sha256:${createHash("sha256")
|
|
307
|
+
.update(line, "utf8")
|
|
308
|
+
.digest("hex")}`;
|
|
294
309
|
let event;
|
|
295
310
|
try {
|
|
296
311
|
event = JSON.parse(line);
|
|
@@ -345,6 +360,7 @@ export class TeamAgentStreamParser {
|
|
|
345
360
|
|
|
346
361
|
if (event.type === "result") {
|
|
347
362
|
this.#sawTerminalResult = true;
|
|
363
|
+
this.#terminalResultDigest = lineDigest;
|
|
348
364
|
this.#lastResultProvider =
|
|
349
365
|
typeof event.provider === "string" ? event.provider : this.#provider;
|
|
350
366
|
this.#lastResultModel =
|