chainlesschain 0.163.4 → 0.163.6
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/completions/_cc +1 -1
- package/completions/cc.bash +1 -1
- package/completions/cc.fish +1 -1
- package/completions/cc.ps1 +1 -1
- package/package.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-DB5X7qqV.js → AIOps-DDIUofA8.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DxHRtKLk.js → ActionButton-Bm-5xYRn.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DIH5QrxT.js → Analytics-D5UH4ljI.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-uu0oxVz7.js → AppLayout-D_ifjOOP.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-BNSMiW9Y.js → Artifacts-BY1mXdC7.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DcAzB4_x.js → Audit-Bujr4Ml3.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-ClSsvjIc.js → BackgroundAgents-sioKSTcC.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BMciY0js.js → Backup-DDOAK8RK.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-Hn3b57Sh.js → BaseInput-CtCsVVke.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CoSlC53V.js → Chat-DpNj0vnd.js} +4 -4
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-CFevJ3So.js → ChatBubbleRenderer-CZta3Ftr.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-B4L4Eu4w.js → Checkbox-DoHVNSXq.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-C77FgRxF.js → Codegen-DlVl7Qmv.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BrLtJLH3.js → Col-GIqoPYty.js} +1 -1
- package/src/assets/web-panel/assets/{Community-Be7pXXhA.js → Community-CIAPEVji.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DuGPecjo.js → Compact-BN7JiI_h.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CzS66mjP.js → Compliance-CqUWCM9B.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CEhjCoyK.js → Cowork-A4iPp7A4.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-D7ir8Vja.js → Cron-B2zeXXWb.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BcXmuLxf.js → Crosschain-BR2xmWr8.js} +1 -1
- package/src/assets/web-panel/assets/{DID-Cto1dtBy.js → DID-BzFDjrIv.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-B7KjgwOX.js → Dashboard-DKtDo3yA.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-COMqxijg.js → Dropdown-RNx43_YG.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BZrya-nf.js → EmailListRenderer-SwMt4Rcy.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-AmVeMq0J.js → FamilyGuardDashboard-CsYebZ4X.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-kZU8c-27.js → Federation-BmRKvBTy.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-sOV22v2-.js → FormItemContext-CVxGTA-0.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-BUuLtGCz.js → GenericCardRenderer-x2iXpyB7.js} +1 -1
- package/src/assets/web-panel/assets/{Git-K-ZxsLsH.js → Git-DfqbkiOP.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-D3OEnawI.js → Governance-RuHyyj5O.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-Bll0gRmP.js → Inference-Bn7uZ7rI.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DBXwjr53.js → KnowledgeGraph-DlP7XefZ.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-CEzPwEfP.js → Logs-BYNdOiCd.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-aMtgN-R6.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-BYyRyOPz.js → Marketplace-JQYmDqM8.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DVu8w_rM.js → McpTools-Cyx4yZ-9.js} +4 -4
- package/src/assets/web-panel/assets/{Memory-tenuZ_hO.js → Memory-VDuGZTN2.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-Bxgy4ozS.js → MobileBridge-_yKo97gi.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-Dgx1D6sc.js → MobileProjects-CXRXW3q7.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-CRfJ8r8j.js → Mtc-acTGtfLH.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-BBJq4Aiz.js → MtcAudit-ClpjXfkY.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-B3ii9lai.js → Multisig-_6Tn3o96.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-FIi-Cubv.js → NLProgramming-CK7pbZzP.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-DIq8MPf1.js → Notes-Czy6V_P8.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-BFOD9eGd.js → NotificationSettings-Cqx-UVv3.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer--41u7vre.js → OrderTableRenderer-C69WDxGy.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-B_0AWztW.js → Organization-DFnA9vLQ.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-B6I7TuXv.js → Overflow-ReZkk2yT.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-Cdf6qens.js → P2P-DzjSI0aI.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-B_0FcQJY.js → PdhVaultBrowser-DKTf5xIP.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-6nFBjsQp.js → Permissions-DhQ5klhR.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-nQYV7xpn.js → PersonalDataHub-CUL1iHrW.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-CBVod5jm.js → Pipeline-DU88iu4N.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-D52jW1Nt.js → Privacy-Bw-sYfyK.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Bdx3BYhf.js → ProjectInit-Bq3Q5y0z.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-b7xr4DUa.js → ProjectSettings-C8spzpho.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-DhfifCKx.js → Projects-Dd-xuPIc.js} +1 -1
- package/src/assets/web-panel/assets/Providers-Bf4eTP9W.js +1 -0
- package/src/assets/web-panel/assets/{QrScannerModal-FQKSmc3e.js → QrScannerModal-Dme9BDU1.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-CSTrhzcF.js → QuickAsk-CIXfv1rE.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-CxMABOUh.js → Recommend-CIxvdeZ-.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-Cv2T8yRa.js → RemoteSession-C6k7MExI.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-CE1k4Vvu.js → Reputation-CISDz2bl.js} +1 -1
- package/src/assets/web-panel/assets/{Row-BNgNcAV_.js → Row-CdnDxXyf.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-5ZiBZ3ph.js → RssFeed-C-QpRHsl.js} +3 -3
- package/src/assets/web-panel/assets/{Search-mDOIF1UV.js → Search-DBjaGzSn.js} +1 -1
- package/src/assets/web-panel/assets/{Security-CtuCTC-e.js → Security-CQKukOeE.js} +3 -3
- package/src/assets/web-panel/assets/{Services-DxFO2Zg7.js → Services-DZz86jWb.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CKmKkH9y.js → Skeleton-jb8RMK0d.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-Bmzl9qkk.js → Skills-CdY76fZG.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-9RqaWHOC.js → Sla-C_CSiZX9.js} +1 -1
- package/src/assets/web-panel/assets/SpeechSettings-C7tT9iad.js +1 -0
- package/src/assets/web-panel/assets/{SyncSettings-CvNuCeBT.js → SyncSettings-qvimGO0O.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-B_sLdcnw.js → Tasks-Dng5LPJC.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-D9_YijdK.js → Templates-Bwqq5Wll.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-Cuc7BUSP.js → Tenant-DNWuwP7Z.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-6VYRnJgd.js → Terminal-B-6Othpp.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-GtK8xd8Y.js → TimelineRenderer-DKpKZfzx.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BZ94Lt5W.js → Tokens-DzfGMd2J.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DEcZgDaX.js → Trigger-BXwUi74J.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-CC3z9THe.js → Trust-BNzUq4ui.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-Cvtw8cV3.js → UkeySign-BYugxww4.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-CL4e6Bn3.js → VideoEditing-DdauhtSJ.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-ycEemP27.js → Wallet-CSC9bCe_.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DgZ4X_aw.js → WebAuthn-Q8AN3bTO.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-D0qMhSv7.js → WorkflowEditor-d-LBGCuA.js} +1 -1
- package/src/assets/web-panel/assets/{chat-DsAg01Zn.js → chat-BLVDCgsZ.js} +1 -1
- package/src/assets/web-panel/assets/{colors-B0oqAhrQ.js → colors-BZlPSEHl.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-CmX0Rabz.js → compact-item-IWseP6R6.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-Be4cn1Ub.js → createContext-DnVRV3Ao.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-Jzu62CLC.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-D5v12kVq.js → hasIn-DLQZA_Wn.js} +1 -1
- package/src/assets/web-panel/assets/{index-BA4oulaP.js → index-1jeAudHd.js} +1 -1
- package/src/assets/web-panel/assets/{index-DM724NgU.js → index-BEu2lMBy.js} +1 -1
- package/src/assets/web-panel/assets/{index-5LGY0JbG.js → index-BOZJBTWZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DikJ0Qqe.js → index-BSjilZ9L.js} +1 -1
- package/src/assets/web-panel/assets/{index-BqltWojQ.js → index-BZs5bBnk.js} +1 -1
- package/src/assets/web-panel/assets/{index-7VKDn-t1.js → index-B_N4-Gq9.js} +1 -1
- package/src/assets/web-panel/assets/{index-BXGSbelg.js → index-Bbj2NS_I.js} +3 -3
- package/src/assets/web-panel/assets/{index-CGiIyTZw.js → index-BhA3QEni.js} +1 -1
- package/src/assets/web-panel/assets/{index-BKmsS2jj.js → index-Bxp7uDD8.js} +1 -1
- package/src/assets/web-panel/assets/{index-B3mUHuVc.js → index-C1ifZtXo.js} +1 -1
- package/src/assets/web-panel/assets/{index-BBvyHguy.js → index-C2FqfMvU.js} +1 -1
- package/src/assets/web-panel/assets/{index-q_fQ94SE.js → index-C5dgnilC.js} +1 -1
- package/src/assets/web-panel/assets/{index-D5YVopyr.js → index-CINJQEj6.js} +1 -1
- package/src/assets/web-panel/assets/{index-0eWLkQKT.js → index-COev0W2g.js} +1 -1
- package/src/assets/web-panel/assets/{index-BoAIAZ5C.js → index-CT9vVN-X.js} +1 -1
- package/src/assets/web-panel/assets/{index-CqoCZ5vR.js → index-CZDekj7T.js} +1 -1
- package/src/assets/web-panel/assets/{index-301ogenv.js → index-CarMTIyQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dn2dSdXx.js → index-CbQNL0ue.js} +1 -1
- package/src/assets/web-panel/assets/{index-DKUBj36_.js → index-CpBaJ3TD.js} +1 -1
- package/src/assets/web-panel/assets/{index-BBREnn1V.js → index-DB0MJgF_.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRIqLy1m.js → index-DOoQpuQY.js} +1 -1
- package/src/assets/web-panel/assets/{index-jK3ax6Z6.js → index-DTbxp4UH.js} +1 -1
- package/src/assets/web-panel/assets/{index-B1YGjOWC.js → index-DUq0c7gq.js} +1 -1
- package/src/assets/web-panel/assets/{index-CyyGTMKd.js → index-DZpYeqrh.js} +1 -1
- package/src/assets/web-panel/assets/{index-_JjRLSD0.js → index-D_LQodeJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DyUaFWEk.js → index-DalA0TKC.js} +1 -1
- package/src/assets/web-panel/assets/{index-BaE0Ui07.js → index-DjWnONdy.js} +1 -1
- package/src/assets/web-panel/assets/{index-CyWBir7N.js → index-Dkwsi1Kn.js} +1 -1
- package/src/assets/web-panel/assets/{index-qMuZ-NRR.js → index-DocEhinm.js} +1 -1
- package/src/assets/web-panel/assets/{index-Ckrk3pIV.js → index-DpVrK6fr.js} +1 -1
- package/src/assets/web-panel/assets/{index-DQRsQen0.js → index-Dy0R5ZED.js} +1 -1
- package/src/assets/web-panel/assets/{index-frSojpHj.js → index-M7wxfAbm.js} +1 -1
- package/src/assets/web-panel/assets/{index-D0BSkxYQ.js → index-N_GoWZX4.js} +1 -1
- package/src/assets/web-panel/assets/{index-8WvYGnON.js → index-YSw_gxlZ.js} +1 -1
- package/src/assets/web-panel/assets/index-Zb2MeDSy.js +1 -0
- package/src/assets/web-panel/assets/index-fikqml4k.js +1 -0
- package/src/assets/web-panel/assets/{index-Hfe_dEGx.js → index-gt8bNefW.js} +1 -1
- package/src/assets/web-panel/assets/{index-CZ2wUEgr.js → index-hwVDeoC0.js} +1 -1
- package/src/assets/web-panel/assets/{index-CZpfzcuy.js → index-jWb70ZgZ.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-D4VdhJ9_.js → initDefaultProps-Co67Kqmb.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CZJA0MQW.js → motion-BMOxQSF_.js} +1 -1
- package/src/assets/web-panel/assets/{move-BqEs7Sb1.js → move-C5fWDw-N.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-BpHEtsu1.js → mtc-parser-BJevpL0e.js} +1 -1
- package/src/assets/web-panel/assets/{omit-BW94tY9W.js → omit-BCzNU8s6.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-BnBjPWP9.js → pickAttrs-CybWvDPk.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-uUkjQ_hu.js → placementArrow-BMWS9HnW.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-B-klUqXK.js → responsiveObserve-BoL2UnGY.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CvY1cNAs.js → slide-DWNfXraU.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-Ix5sEDT2.js → statusUtils-BquTM3tX.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-C8qcXOne.js → styleChecker-BEkCleim.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-KNF6Kj8f.js → useFlexGapSupport-Oecnq7EA.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DGJr345n.js → useFs-CkDffJ4F.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BboN99rI.js → usePersonalDataHub-qbvKXesB.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-Bgt8Vgte.js → vnode-C6v8n6mA.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-BhJtErgt.js → zoom-4CTeFILV.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +3 -3
- package/src/command-manifest.json +1 -1
- package/src/commands/agenda.js +125 -7
- package/src/commands/automation.js +462 -3
- package/src/commands/background-session.js +102 -1
- package/src/commands/cowork.js +30 -13
- package/src/commands/loop.js +167 -36
- package/src/commands/routine.js +50 -13
- package/src/commands/scheduler-daemon.js +450 -0
- package/src/data/changelog.json +27 -1
- package/src/lib/agent-schedule-store.js +509 -36
- package/src/lib/automation-center-routines.js +363 -0
- package/src/lib/automation-center.js +435 -0
- package/src/lib/automation-engine.js +74 -19
- package/src/lib/automation-execution-authority.js +736 -0
- package/src/lib/background-agent-supervisor.js +78 -0
- package/src/lib/background-needs-input-incident.js +221 -0
- package/src/lib/cowork-cron.js +555 -39
- package/src/lib/cowork-observe.js +5 -1
- package/src/lib/loop.js +37 -2
- package/src/lib/micro-compact.js +11 -5
- package/src/lib/permission-engine.js +14 -7
- package/src/lib/process-execution-broker/index.js +14 -3
- package/src/lib/public-ide-capability-manifest.js +2 -0
- package/src/lib/routine-store.js +242 -68
- package/src/lib/scheduler-kernel/agenda-adapter.js +812 -0
- package/src/lib/scheduler-kernel/authority-resolver.js +163 -0
- package/src/lib/scheduler-kernel/automation-adapter.js +592 -0
- package/src/lib/scheduler-kernel/automation-event-adapter.js +721 -0
- package/src/lib/scheduler-kernel/contract.js +11 -3
- package/src/lib/scheduler-kernel/cowork-cron-adapter.js +820 -0
- package/src/lib/scheduler-kernel/loop-adapter.js +378 -0
- package/src/lib/scheduler-kernel/routine-adapter.js +812 -0
- package/src/lib/scheduler-kernel/runtime.js +527 -0
- package/src/lib/scheduler-kernel/service.js +328 -0
- package/src/lib/scheduler-kernel/store.js +940 -98
- package/src/lib/session-message-provenance.js +4 -1
- package/src/repl/agent-repl.js +24 -5
- package/src/runtime/agent-core.js +38 -17
- package/src/runtime/coding-agent-contract-shared.cjs +5 -0
- package/src/workers/background-agent-worker.js +91 -28
- package/src/assets/web-panel/assets/MarkdownRenderer-CLmCbHx6.js +0 -1
- package/src/assets/web-panel/assets/Providers-Dy_PgDMr.js +0 -1
- package/src/assets/web-panel/assets/SpeechSettings-CGdzFIYw.js +0 -1
- package/src/assets/web-panel/assets/devWarning-CP2qzG6D.js +0 -1
- package/src/assets/web-panel/assets/index-CKB0vbJU.js +0 -1
- package/src/assets/web-panel/assets/index-DgoXmwqB.js +0 -1
|
@@ -28,6 +28,12 @@ import {
|
|
|
28
28
|
stripFirstTurnPromptArgv,
|
|
29
29
|
} from "./background-command-argv.js";
|
|
30
30
|
import { terminateOwnedProcessTree } from "./process-tree-termination.js";
|
|
31
|
+
import { sendAgentNotification } from "./agent-notify.js";
|
|
32
|
+
import {
|
|
33
|
+
buildNeedsInputNotification,
|
|
34
|
+
claimNeedsInputNotification,
|
|
35
|
+
settleNeedsInputNotification,
|
|
36
|
+
} from "./background-needs-input-incident.js";
|
|
31
37
|
import {
|
|
32
38
|
assessBackgroundLaunchProfileCompatibility,
|
|
33
39
|
buildArgvFromBackgroundLaunchProfile,
|
|
@@ -631,6 +637,78 @@ export function writeBackgroundAgentState(state, options = {}) {
|
|
|
631
637
|
}).state;
|
|
632
638
|
}
|
|
633
639
|
|
|
640
|
+
/**
|
|
641
|
+
* Claim and deliver the durable notification for one pending human question.
|
|
642
|
+
*
|
|
643
|
+
* The delivery claim is persisted before any notifier runs. A thrown notifier
|
|
644
|
+
* is therefore recorded as outcome_unknown and is never replayed implicitly;
|
|
645
|
+
* an operator must use force after accepting the possible duplicate. Known
|
|
646
|
+
* failures and an unconfigured notifier remain explicitly retryable.
|
|
647
|
+
*/
|
|
648
|
+
export async function deliverBackgroundNeedsInputNotification(
|
|
649
|
+
id,
|
|
650
|
+
options = {},
|
|
651
|
+
) {
|
|
652
|
+
const now = typeof options.now === "function" ? options.now : Date.now;
|
|
653
|
+
let claim = null;
|
|
654
|
+
const claimed = mutateBackgroundAgentState(id, (current) => {
|
|
655
|
+
claim = claimNeedsInputNotification(current?.needsInputIncident, {
|
|
656
|
+
retry: options.retry === true,
|
|
657
|
+
force: options.force === true,
|
|
658
|
+
now: now(),
|
|
659
|
+
});
|
|
660
|
+
if (!claim.applied) return null;
|
|
661
|
+
return { ...current, needsInputIncident: claim.incident };
|
|
662
|
+
});
|
|
663
|
+
if (!claim?.applied) {
|
|
664
|
+
return {
|
|
665
|
+
applied: false,
|
|
666
|
+
reason: claim?.reason || "incident_not_pending",
|
|
667
|
+
incident: claimed.state?.needsInputIncident || null,
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
const notify = options.notify || sendAgentNotification;
|
|
672
|
+
let result = null;
|
|
673
|
+
let deliveryError = null;
|
|
674
|
+
try {
|
|
675
|
+
result = await notify(buildNeedsInputNotification(claim.incident));
|
|
676
|
+
} catch (error) {
|
|
677
|
+
deliveryError = error;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
let settlement = null;
|
|
681
|
+
const settled = mutateBackgroundAgentState(id, (current) => {
|
|
682
|
+
if (current?.needsInputIncident?.incidentId !== claim.incident.incidentId) {
|
|
683
|
+
settlement = {
|
|
684
|
+
applied: false,
|
|
685
|
+
reason: "incident_changed",
|
|
686
|
+
incident: current?.needsInputIncident || null,
|
|
687
|
+
};
|
|
688
|
+
return null;
|
|
689
|
+
}
|
|
690
|
+
settlement = settleNeedsInputNotification(current.needsInputIncident, {
|
|
691
|
+
attempt: claim.attempt,
|
|
692
|
+
result,
|
|
693
|
+
error: deliveryError,
|
|
694
|
+
now: now(),
|
|
695
|
+
});
|
|
696
|
+
if (!settlement.applied) return null;
|
|
697
|
+
return { ...current, needsInputIncident: settlement.incident };
|
|
698
|
+
});
|
|
699
|
+
|
|
700
|
+
return {
|
|
701
|
+
applied: true,
|
|
702
|
+
attempt: claim.attempt,
|
|
703
|
+
settlementApplied: settlement?.applied === true,
|
|
704
|
+
reason: settlement?.reason || null,
|
|
705
|
+
incident:
|
|
706
|
+
settled.state?.needsInputIncident ||
|
|
707
|
+
settlement?.incident ||
|
|
708
|
+
claim.incident,
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
|
|
634
712
|
/**
|
|
635
713
|
* Atomically claim/refresh a worker heartbeat. The returned `applied` bit is
|
|
636
714
|
* the only authority to start or continue a turn: a terminal, deleted,
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
|
|
3
|
+
export const NEEDS_INPUT_INCIDENT_SCHEMA_VERSION = 1;
|
|
4
|
+
export const DEFAULT_NEEDS_INPUT_NOTIFICATION_STALE_MS = 60_000;
|
|
5
|
+
export const NEEDS_INPUT_NOTIFICATION_STATUS = Object.freeze({
|
|
6
|
+
PENDING: "pending",
|
|
7
|
+
DELIVERING: "delivering",
|
|
8
|
+
DELIVERED: "delivered",
|
|
9
|
+
PARTIAL: "partial",
|
|
10
|
+
UNCONFIGURED: "unconfigured",
|
|
11
|
+
FAILED: "failed",
|
|
12
|
+
OUTCOME_UNKNOWN: "outcome_unknown",
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
function boundedText(value, maxLength) {
|
|
16
|
+
return String(value ?? "")
|
|
17
|
+
.trim()
|
|
18
|
+
.slice(0, maxLength);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function requiredId(value, field) {
|
|
22
|
+
const normalized = boundedText(value, 256);
|
|
23
|
+
if (!normalized) throw new Error(`${field} is required`);
|
|
24
|
+
if ([...normalized].some((character) => character.codePointAt(0) < 32)) {
|
|
25
|
+
throw new Error(`${field} contains a control character`);
|
|
26
|
+
}
|
|
27
|
+
return normalized;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function epochMs(value, field) {
|
|
31
|
+
const normalized = Number(value);
|
|
32
|
+
if (!Number.isSafeInteger(normalized) || normalized < 0) {
|
|
33
|
+
throw new Error(`${field} must be a non-negative epoch millisecond`);
|
|
34
|
+
}
|
|
35
|
+
return normalized;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function incidentDigest(runId, requestId) {
|
|
39
|
+
return createHash("sha256")
|
|
40
|
+
.update(`chainlesschain.background-needs-input.v1\0${runId}\0${requestId}`)
|
|
41
|
+
.digest("hex");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function createNeedsInputIncident({
|
|
45
|
+
runId,
|
|
46
|
+
sessionId = null,
|
|
47
|
+
requestId,
|
|
48
|
+
now = Date.now(),
|
|
49
|
+
} = {}) {
|
|
50
|
+
const normalizedRunId = requiredId(runId, "runId");
|
|
51
|
+
const normalizedRequestId = requiredId(requestId, "requestId");
|
|
52
|
+
const createdAt = epochMs(now, "now");
|
|
53
|
+
return {
|
|
54
|
+
schemaVersion: NEEDS_INPUT_INCIDENT_SCHEMA_VERSION,
|
|
55
|
+
incidentId: incidentDigest(normalizedRunId, normalizedRequestId),
|
|
56
|
+
runId: normalizedRunId,
|
|
57
|
+
sessionId: sessionId == null ? null : requiredId(sessionId, "sessionId"),
|
|
58
|
+
requestId: normalizedRequestId,
|
|
59
|
+
status: "needs_input",
|
|
60
|
+
createdAt,
|
|
61
|
+
updatedAt: createdAt,
|
|
62
|
+
notification: {
|
|
63
|
+
status: NEEDS_INPUT_NOTIFICATION_STATUS.PENDING,
|
|
64
|
+
attempts: 0,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function buildNeedsInputNotification(incident) {
|
|
70
|
+
const runId = requiredId(incident?.runId, "incident.runId");
|
|
71
|
+
const incidentId = requiredId(incident?.incidentId, "incident.incidentId");
|
|
72
|
+
return {
|
|
73
|
+
title: "Background agent needs input",
|
|
74
|
+
body: `Run ${runId} is waiting for human input. Resume with: cc attach ${runId}\nIncident: ${incidentId}`,
|
|
75
|
+
level: "info",
|
|
76
|
+
taskId: runId,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function claimNeedsInputNotification(
|
|
81
|
+
incident,
|
|
82
|
+
{
|
|
83
|
+
retry = false,
|
|
84
|
+
force = false,
|
|
85
|
+
now = Date.now(),
|
|
86
|
+
staleAfterMs = DEFAULT_NEEDS_INPUT_NOTIFICATION_STALE_MS,
|
|
87
|
+
} = {},
|
|
88
|
+
) {
|
|
89
|
+
if (!incident || incident.status !== "needs_input") {
|
|
90
|
+
return { applied: false, reason: "incident_not_pending", incident };
|
|
91
|
+
}
|
|
92
|
+
const status = incident.notification?.status;
|
|
93
|
+
const retryable = new Set([
|
|
94
|
+
NEEDS_INPUT_NOTIFICATION_STATUS.FAILED,
|
|
95
|
+
NEEDS_INPUT_NOTIFICATION_STATUS.UNCONFIGURED,
|
|
96
|
+
]);
|
|
97
|
+
const claimAt = epochMs(now, "now");
|
|
98
|
+
const normalizedStaleAfterMs = epochMs(staleAfterMs, "staleAfterMs");
|
|
99
|
+
const deliveryStartedAt = Number(incident.notification?.startedAt);
|
|
100
|
+
const deliveryIsStale =
|
|
101
|
+
status === NEEDS_INPUT_NOTIFICATION_STATUS.DELIVERING &&
|
|
102
|
+
(!Number.isSafeInteger(deliveryStartedAt) ||
|
|
103
|
+
deliveryStartedAt < 0 ||
|
|
104
|
+
claimAt - deliveryStartedAt >= normalizedStaleAfterMs);
|
|
105
|
+
const canClaim =
|
|
106
|
+
status === NEEDS_INPUT_NOTIFICATION_STATUS.PENDING ||
|
|
107
|
+
(retry && retryable.has(status)) ||
|
|
108
|
+
(force &&
|
|
109
|
+
(status !== NEEDS_INPUT_NOTIFICATION_STATUS.DELIVERING ||
|
|
110
|
+
deliveryIsStale));
|
|
111
|
+
if (!canClaim) {
|
|
112
|
+
return {
|
|
113
|
+
applied: false,
|
|
114
|
+
reason:
|
|
115
|
+
status === NEEDS_INPUT_NOTIFICATION_STATUS.DELIVERING
|
|
116
|
+
? "delivery_in_progress"
|
|
117
|
+
: "delivery_not_retryable",
|
|
118
|
+
incident,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
const startedAt = claimAt;
|
|
122
|
+
const attempt = Number(incident.notification?.attempts || 0) + 1;
|
|
123
|
+
return {
|
|
124
|
+
applied: true,
|
|
125
|
+
reason: null,
|
|
126
|
+
attempt,
|
|
127
|
+
incident: {
|
|
128
|
+
...incident,
|
|
129
|
+
updatedAt: startedAt,
|
|
130
|
+
notification: {
|
|
131
|
+
status: NEEDS_INPUT_NOTIFICATION_STATUS.DELIVERING,
|
|
132
|
+
attempts: attempt,
|
|
133
|
+
startedAt,
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function safeError(error) {
|
|
140
|
+
return {
|
|
141
|
+
code: boundedText(error?.code, 128) || "NOTIFICATION_OUTCOME_UNKNOWN",
|
|
142
|
+
message:
|
|
143
|
+
boundedText(error?.message || error, 1_000) ||
|
|
144
|
+
"Notification delivery outcome is unknown",
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function channelNames(value) {
|
|
149
|
+
if (!Array.isArray(value)) return [];
|
|
150
|
+
return [
|
|
151
|
+
...new Set(value.map((entry) => boundedText(entry, 64)).filter(Boolean)),
|
|
152
|
+
]
|
|
153
|
+
.sort()
|
|
154
|
+
.slice(0, 32);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export function settleNeedsInputNotification(
|
|
158
|
+
incident,
|
|
159
|
+
{ attempt, result = null, error = null, now = Date.now() } = {},
|
|
160
|
+
) {
|
|
161
|
+
if (
|
|
162
|
+
!incident ||
|
|
163
|
+
incident.notification?.status !==
|
|
164
|
+
NEEDS_INPUT_NOTIFICATION_STATUS.DELIVERING ||
|
|
165
|
+
incident.notification?.attempts !== attempt
|
|
166
|
+
) {
|
|
167
|
+
return { applied: false, reason: "delivery_claim_changed", incident };
|
|
168
|
+
}
|
|
169
|
+
const settledAt = epochMs(now, "now");
|
|
170
|
+
const delivered = channelNames(result?.delivered);
|
|
171
|
+
const failed = channelNames(result?.failed);
|
|
172
|
+
const channels = Math.max(0, Number(result?.channels) || 0);
|
|
173
|
+
let status;
|
|
174
|
+
if (error) status = NEEDS_INPUT_NOTIFICATION_STATUS.OUTCOME_UNKNOWN;
|
|
175
|
+
else if (channels === 0)
|
|
176
|
+
status = NEEDS_INPUT_NOTIFICATION_STATUS.UNCONFIGURED;
|
|
177
|
+
else if (delivered.length > 0 && failed.length > 0) {
|
|
178
|
+
status = NEEDS_INPUT_NOTIFICATION_STATUS.PARTIAL;
|
|
179
|
+
} else if (delivered.length > 0) {
|
|
180
|
+
status = NEEDS_INPUT_NOTIFICATION_STATUS.DELIVERED;
|
|
181
|
+
} else {
|
|
182
|
+
status = NEEDS_INPUT_NOTIFICATION_STATUS.FAILED;
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
applied: true,
|
|
186
|
+
reason: null,
|
|
187
|
+
incident: {
|
|
188
|
+
...incident,
|
|
189
|
+
updatedAt: settledAt,
|
|
190
|
+
notification: {
|
|
191
|
+
status,
|
|
192
|
+
attempts: attempt,
|
|
193
|
+
startedAt: incident.notification.startedAt,
|
|
194
|
+
settledAt,
|
|
195
|
+
channels,
|
|
196
|
+
delivered,
|
|
197
|
+
failed,
|
|
198
|
+
...(error ? { error: safeError(error) } : {}),
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export function closeNeedsInputIncident(
|
|
205
|
+
incident,
|
|
206
|
+
{ status = "resolved", now = Date.now() } = {},
|
|
207
|
+
) {
|
|
208
|
+
if (!incident || incident.status !== "needs_input") return incident;
|
|
209
|
+
if (status !== "resolved" && status !== "cancelled") {
|
|
210
|
+
throw new Error(
|
|
211
|
+
"needs-input incident close status must be resolved or cancelled",
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
const closedAt = epochMs(now, "now");
|
|
215
|
+
return {
|
|
216
|
+
...incident,
|
|
217
|
+
status,
|
|
218
|
+
updatedAt: closedAt,
|
|
219
|
+
closedAt,
|
|
220
|
+
};
|
|
221
|
+
}
|