chainlesschain 0.165.2 → 0.165.4
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 +151 -29
- package/package.json +2 -2
- package/src/assets/web-panel/assets/{AIOps-lS1R0Cza.js → AIOps-C__nnraW.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-BmlgBPsj.js → ActionButton-CsKWHEZ-.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-CNKczv1S.js → Analytics-BhIjfjWO.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-BuZGJARQ.js → AppLayout-BjuXFzWZ.js} +4 -4
- package/src/assets/web-panel/assets/{Artifacts-Dm73Sl-O.js → Artifacts-k6whDkZJ.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-BGMW7A5e.js → Audit-C4FBMYRh.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BQ6M54JR.js → BackgroundAgents-C_vRrSXk.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-DBzGP0bR.js → Backup-CngFZeVp.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-D1mLCoOV.js → BaseInput-B_H9EBRm.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-BUfcN7p8.js → Chat-DLEC5kt7.js} +4 -4
- package/src/assets/web-panel/assets/ChatBubbleRenderer-xijcWkJe.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-Du0Yg5Pi.js → Checkbox-m3ClR4xh.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-B2RXziHW.js → Codegen-CmLSFrgp.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DWhekOrR.js → Col-DFGQteHN.js} +1 -1
- package/src/assets/web-panel/assets/{Community-HQhrkon4.js → Community-EUUVORHE.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-izHNb4uz.js → Compact-2PSg0Yr7.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-BDwLy41-.js → Compliance-CcKur7gB.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DFJhLa7K.js → Cowork-DK_Fezfa.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-DYY9RG7-.js → Cron-Dbw89xl7.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-rr7tJTtv.js → Crosschain-CH66h_Ec.js} +1 -1
- package/src/assets/web-panel/assets/{DID-D2sfHRLi.js → DID-D1igRb17.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-q_eGdhha.js → Dashboard-DVAsrobk.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-Cufrh2Bz.js → Dropdown-Dl7W8AQs.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-B-kdv10f.js → EmailListRenderer-D5tpaEQC.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-D21XjgfG.js → FamilyGuardDashboard-O_VQf8gq.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-CAwRTLZH.js → Federation-BTVcgS9n.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-vx3daNDF.js → FormItemContext-BRnkJAIz.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-CRWY2wU4.js → GenericCardRenderer-8OWSCkDj.js} +1 -1
- package/src/assets/web-panel/assets/{Git-Q6SwauyD.js → Git-WXLYTQj2.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-BJ1q4IQZ.js → Governance-BezaUhtc.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CSWjROgD.js → Inference-CuRay3Gu.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-fzuQsWuY.js → KnowledgeGraph-DfWLDW1m.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DVF8Mnns.js → Logs-C55y2pPY.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-hDpWdiBc.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-BQP7LOA4.js → Marketplace-Dk08Uycg.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-BNlJCmNc.js → McpTools-C11fSB5V.js} +4 -4
- package/src/assets/web-panel/assets/{Memory-DLLg5WQ4.js → Memory-mr0eZc97.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-CR2skNAF.js → MobileBridge-C0iCSRbb.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-BxVavObl.js → MobileProjects-CY-xMG8Z.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-B17pgqMI.js → Mtc-Bplqc_Wc.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-4UmV5cIL.js → MtcAudit-BlzwsoSM.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-DoMEXEcU.js → Multisig-BBLmTty6.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-h9DMXFX4.js → NLProgramming-DtT1uf1W.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-Cihn-xX8.js → Notes-DcqQAxTK.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-BE6ZGa3R.js → NotificationSettings-cb0kWoZe.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-CnwojoSI.js → OrderTableRenderer-kw9HZQNN.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-B2vpwmjb.js → Organization-DlTlbkUN.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-C4z28R0-.js → Overflow-pp1qs-oY.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BVlFkwhW.js → P2P-BESLnyYz.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-BXbEdL5B.js → PdhVaultBrowser-B-J1mGuf.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-C28xs4lp.js → Permissions-B36PeT1_.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-Dgl_rBjM.js → PersonalDataHub-CTK2ad-3.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-3QUIhrKI.js → Pipeline-zJNGXsac.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-8Gh33OZ5.js → Privacy-b9fz0Qf0.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-BNmg4tZi.js → ProjectInit-DjZbZgiB.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-vgMfeCf9.js → ProjectSettings-C-hHJXlD.js} +2 -2
- package/src/assets/web-panel/assets/Projects-BC9KSDM6.js +1 -0
- package/src/assets/web-panel/assets/{Providers-CXoOa8eX.js → Providers-Dz-CAYYU.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-BhfTF0oS.js → QrScannerModal-A0yoQ3-3.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-C746HEAj.js → QuickAsk-DrFgFJNC.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BSej8Eo0.js → Recommend-KC8hF1g4.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-f3gmnlG3.js → RemoteSession-DGTPIk6u.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-CyvybpkN.js → Reputation-QmbwM7Yk.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DwV2PeYn.js → Row-BxjJylia.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-11GrzjZy.js → RssFeed-B7Wda1J6.js} +3 -3
- package/src/assets/web-panel/assets/{Search-BjKXkrAY.js → Search-_plQ_YSA.js} +1 -1
- package/src/assets/web-panel/assets/{Security-eWiFb9Yk.js → Security-CD2YJZfx.js} +2 -2
- package/src/assets/web-panel/assets/{Services-CdCsMAtt.js → Services-qQE7NmwE.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-4Q2UTKQ5.js → Skeleton-DgQqkFf7.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-v4rtYrRj.js → Skills-C4C0oFFt.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CRhsFvd_.js → Sla-Px2N2B5c.js} +1 -1
- package/src/assets/web-panel/assets/SpeechSettings-DN6C3lQd.js +1 -0
- package/src/assets/web-panel/assets/{SyncSettings-D16zonl7.js → SyncSettings-jm5aH_m7.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-Xxozz0i_.js → Tasks-DlkJcv67.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-CXJpPtCT.js → Templates-DyrTHUBs.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-XRV0L1ZF.js → Tenant-mC434PtL.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-CYuO1i_w.js → Terminal-o0_s3NgK.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-BXqitWsu.js → TimelineRenderer-DAGlAXOw.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BvPrDHIy.js → Tokens-BnulS_bs.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DhCrSTf5.js → Trigger-suQbVXYM.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DmsuZD6K.js → Trust-DbIJAPo5.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-D_yrts5C.js → UkeySign-CQNpbIHi.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-B01ihPrm.js → VideoEditing-D8aWCERk.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-DpUjKa-N.js → Wallet-CuLpYfZc.js} +2 -2
- package/src/assets/web-panel/assets/{WebAuthn-CL07yON6.js → WebAuthn-CsfG8ZMc.js} +2 -2
- package/src/assets/web-panel/assets/{WorkflowEditor-CLMflnRr.js → WorkflowEditor-BYsEAZbd.js} +1 -1
- package/src/assets/web-panel/assets/{chat-DtUqe8h_.js → chat-FT4Um3-I.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DPKrgVfy.js → colors-CKbS_Wlt.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BTt2GtOm.js → compact-item-CFJtzuJM.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-D_VeUc1J.js → createContext-B9kSRW6K.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DJZ0gAMu.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-1kndiylj.js → hasIn-DR-x0Xpi.js} +1 -1
- package/src/assets/web-panel/assets/{index-dVc-CXY4.js → index-7jHr_A_k.js} +1 -1
- package/src/assets/web-panel/assets/{index-DFIZ_1Sf.js → index-B3ZX81mK.js} +1 -1
- package/src/assets/web-panel/assets/{index-fk2Rjacw.js → index-B7osrXqy.js} +3 -3
- package/src/assets/web-panel/assets/{index-CHG-KcS4.js → index-BGbPnC5x.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dbbymxpj.js → index-BI5hP_qy.js} +1 -1
- package/src/assets/web-panel/assets/{index-BaZAbw9A.js → index-BK3TiKVq.js} +1 -1
- package/src/assets/web-panel/assets/{index-CzjkKUmR.js → index-BVPU43b1.js} +1 -1
- package/src/assets/web-panel/assets/{index-BAXfRKfG.js → index-BW-t9n-q.js} +1 -1
- package/src/assets/web-panel/assets/{index-8nz_fmlj.js → index-BfFCQHL3.js} +1 -1
- package/src/assets/web-panel/assets/index-Bizb4hkw.js +1 -0
- package/src/assets/web-panel/assets/{index-DdkplL9R.js → index-Bt4fS2eL.js} +1 -1
- package/src/assets/web-panel/assets/{index-DG2MZQ3f.js → index-BwR7yc2h.js} +1 -1
- package/src/assets/web-panel/assets/{index-DfKBRdSS.js → index-Bzz0C1BZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-GsoUQ2M7.js → index-C2JvmYRc.js} +1 -1
- package/src/assets/web-panel/assets/{index-l1BETrDb.js → index-CGaXUsIs.js} +1 -1
- package/src/assets/web-panel/assets/{index-4bna2_SR.js → index-CJmIQ9XR.js} +1 -1
- package/src/assets/web-panel/assets/{index-DfGl8CqG.js → index-C_enk9I_.js} +1 -1
- package/src/assets/web-panel/assets/{index-D95OFht7.js → index-Cr2FLUsD.js} +1 -1
- package/src/assets/web-panel/assets/{index-DsJCDUJG.js → index-CvrCCqJt.js} +1 -1
- package/src/assets/web-panel/assets/{index-sDoMHTNA.js → index-D4LfPvWA.js} +1 -1
- package/src/assets/web-panel/assets/{index-By5n8up9.js → index-DMGmg497.js} +1 -1
- package/src/assets/web-panel/assets/{index-ocf06EVQ.js → index-DShSkww-.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bhudc_Ez.js → index-DTxNy0ZU.js} +1 -1
- package/src/assets/web-panel/assets/{index-CX81qSM4.js → index-DW4BWjTk.js} +1 -1
- package/src/assets/web-panel/assets/{index-BlDNVgBt.js → index-DWdqx7zI.js} +1 -1
- package/src/assets/web-panel/assets/{index-CcO04eDn.js → index-Dap9c3eD.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dwqmtk65.js → index-DcfxhKXR.js} +1 -1
- package/src/assets/web-panel/assets/{index-2eyAXE3d.js → index-DdkIhfi-.js} +1 -1
- package/src/assets/web-panel/assets/{index-brCInrzq.js → index-DeSgw-WV.js} +1 -1
- package/src/assets/web-panel/assets/{index-DJ8vXGOa.js → index-DiNUEpSQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BHpBMWCh.js → index-DjEP7WkH.js} +1 -1
- package/src/assets/web-panel/assets/{index-m31Ka8hZ.js → index-DtkFqPVA.js} +1 -1
- package/src/assets/web-panel/assets/{index-CtF7EN49.js → index-KqDaCApw.js} +1 -1
- package/src/assets/web-panel/assets/index-OHSl-xCh.js +1 -0
- package/src/assets/web-panel/assets/{index-B9KvcS7R.js → index-OSzjTzGM.js} +1 -1
- package/src/assets/web-panel/assets/{index-CauoBQkH.js → index-QBSeNVO3.js} +1 -1
- package/src/assets/web-panel/assets/{index-FzdwcSy2.js → index-WE08gMJP.js} +1 -1
- package/src/assets/web-panel/assets/{index-DxdTdBix.js → index-r2VI1Ikk.js} +1 -1
- package/src/assets/web-panel/assets/{index-BepLZwgB.js → index-tqSEHPRT.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-CvyYJd7z.js → initDefaultProps-Dd7n7VgI.js} +1 -1
- package/src/assets/web-panel/assets/{motion-DYZkhUdz.js → motion-BwxouRw1.js} +1 -1
- package/src/assets/web-panel/assets/{move-slnJRVT1.js → move-DObN0PG9.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DVc0CKmy.js → mtc-parser-B3nOUQc7.js} +1 -1
- package/src/assets/web-panel/assets/{omit-BCXAtHCq.js → omit-o9WU2Nbl.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DBsemz_K.js → pickAttrs-CL_vvfQ_.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BRtkJ-nv.js → placementArrow-CYrM2tyK.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-Cebq7EZn.js → responsiveObserve-k_06cQ96.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DT7qvId2.js → slide-CPKG0pxS.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-pQiITLkG.js → statusUtils-BDDEeLTw.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-c-19BVKQ.js → styleChecker-Cmb7RTh7.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DsS5-0bE.js → useFlexGapSupport-e2IedC4N.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-CxGiMe5n.js → useFs-CE_gxVnm.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-D9btVID5.js → usePersonalDataHub-BkMIIKMz.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CUYFsFEN.js → vnode-DW886XV1.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CXmn_35j.js → zoom-Dwo_adaf.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +3 -3
- package/src/commands/agent.js +105 -35
- package/src/commands/artifacts.js +363 -33
- package/src/commands/cowork.js +202 -36
- package/src/commands/session-budget.js +155 -0
- package/src/commands/session-location.js +948 -0
- package/src/commands/session.js +72 -46
- package/src/data/changelog.json +26 -0
- package/src/gateways/ws/artifact-protocol.js +77 -13
- package/src/gateways/ws/session-protocol.js +391 -24
- package/src/gateways/ws/ws-agent-handler.js +191 -14
- package/src/gateways/ws/ws-server.js +14 -3
- package/src/gateways/ws/ws-session-gateway.js +101 -5
- package/src/harness/jsonl-session-store.js +1210 -0
- package/src/lib/agent-team/team-runner.js +43 -13
- package/src/lib/artifact-access-ledger.js +461 -0
- package/src/lib/artifact-cleanup-ledger.js +861 -0
- package/src/lib/artifact-deletion-ledger.js +677 -0
- package/src/lib/artifact-store.js +256 -51
- package/src/lib/background-agent-keeper-protocol.js +75 -4
- package/src/lib/background-agent-launch-barrier.js +74 -0
- package/src/lib/background-agent-supervisor.js +149 -5
- package/src/lib/background-turn-bootstrap-protocol.js +4 -0
- package/src/lib/command-lifecycle-report.js +8 -4
- package/src/lib/cowork-adapter.js +9 -5
- package/src/lib/cowork-task-runner.js +20 -0
- package/src/lib/cowork-workflow.js +178 -20
- package/src/lib/direct-model-usage.js +62 -22
- package/src/lib/dynamic-workflow-runtime.js +3184 -111
- package/src/lib/execution-location-result-apply.js +339 -0
- package/src/lib/execution-location-result-artifact.js +271 -0
- package/src/lib/execution-location-result-review.js +253 -0
- package/src/lib/execution-location-result-store.js +331 -0
- package/src/lib/execution-location-result.js +617 -0
- package/src/lib/execution-location-target.js +236 -1
- package/src/lib/managed-tool-checkpoint.js +47 -4
- package/src/lib/process-execution-broker/workspace-transaction.js +3 -0
- package/src/lib/session-budget-production-root.js +376 -0
- package/src/lib/session-budget-runtime.js +109 -18
- package/src/lib/session-budget-usage.js +63 -0
- package/src/lib/session-host-snapshot.js +19 -2
- package/src/lib/session-resource-budget.js +766 -105
- package/src/lib/sub-agent-context.js +69 -22
- package/src/lib/web-ui-server.js +12 -1
- package/src/lib/with-file-lock.js +175 -26
- package/src/repl/agent-repl.js +237 -16
- package/src/runtime/agent-core.js +123 -0
- package/src/runtime/headless-runner.js +135 -46
- package/src/runtime/headless-stream.js +133 -25
- package/src/runtime/policies/agent-policy.js +10 -0
- package/src/workers/background-agent-keeper.js +112 -19
- package/src/workers/background-agent-worker.js +383 -134
- package/src/workers/background-turn-bootstrap.js +13 -8
- package/src/assets/web-panel/assets/ChatBubbleRenderer-CY5m8ZHg.js +0 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-BLif4QSg.js +0 -1
- package/src/assets/web-panel/assets/Projects-BhtAVilc.js +0 -1
- package/src/assets/web-panel/assets/SpeechSettings-DLjKsDVu.js +0 -1
- package/src/assets/web-panel/assets/devWarning-Bj5nUW2v.js +0 -1
- package/src/assets/web-panel/assets/index-CPcM-eqo.js +0 -1
- package/src/assets/web-panel/assets/index-xeSyVoRe.js +0 -1
|
@@ -79,6 +79,110 @@ export const PID_IDENTITY_TOLERANCE_MS = 60000;
|
|
|
79
79
|
export const PROCESS_START_TIME_CACHE_TTL_MS = 10_000;
|
|
80
80
|
export const PROCESS_START_TIME_CACHE_MAX_ENTRIES = 4_096;
|
|
81
81
|
|
|
82
|
+
// Linux exposes these fields directly through procfs. `/proc/<pid>/stat`
|
|
83
|
+
// reports starttime in USER_HZ units, which Linux defines as 100 ticks/second
|
|
84
|
+
// for this userspace ABI independently of the kernel scheduler frequency.
|
|
85
|
+
const LINUX_PROC_CLOCK_TICKS_PER_SECOND = 100;
|
|
86
|
+
let linuxBootTimeMsCache;
|
|
87
|
+
|
|
88
|
+
export function parseLinuxProcStat(text, bootTimeMs = null) {
|
|
89
|
+
const value = String(text || "").trim();
|
|
90
|
+
const open = value.indexOf("(");
|
|
91
|
+
const close = value.lastIndexOf(")");
|
|
92
|
+
if (open <= 0 || close <= open || value.charAt(close + 1) !== " ") {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
const pid = Number(value.slice(0, open).trim());
|
|
96
|
+
const fields = value
|
|
97
|
+
.slice(close + 2)
|
|
98
|
+
.trim()
|
|
99
|
+
.split(/\s+/u);
|
|
100
|
+
const state = fields[0];
|
|
101
|
+
const processGroupId = Number(fields[2]);
|
|
102
|
+
const startTimeTicks = Number(fields[19]);
|
|
103
|
+
if (
|
|
104
|
+
!Number.isSafeInteger(pid) ||
|
|
105
|
+
pid <= 0 ||
|
|
106
|
+
!/^[A-Z]$/iu.test(state || "") ||
|
|
107
|
+
!Number.isSafeInteger(processGroupId) ||
|
|
108
|
+
processGroupId <= 0 ||
|
|
109
|
+
!Number.isFinite(startTimeTicks) ||
|
|
110
|
+
startTimeTicks < 0
|
|
111
|
+
) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
const boot = Number(bootTimeMs);
|
|
115
|
+
return {
|
|
116
|
+
pid,
|
|
117
|
+
state: state.toUpperCase(),
|
|
118
|
+
processGroupId,
|
|
119
|
+
startTimeTicks,
|
|
120
|
+
startedAtMs:
|
|
121
|
+
Number.isFinite(boot) && boot > 0
|
|
122
|
+
? boot + (startTimeTicks * 1000) / LINUX_PROC_CLOCK_TICKS_PER_SECOND
|
|
123
|
+
: null,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function linuxBootTimeMs() {
|
|
128
|
+
if (linuxBootTimeMsCache !== undefined) return linuxBootTimeMsCache;
|
|
129
|
+
try {
|
|
130
|
+
const match = /^btime\s+(\d+)\s*$/mu.exec(
|
|
131
|
+
readFileSync("/proc/stat", "utf8"),
|
|
132
|
+
);
|
|
133
|
+
const seconds = match ? Number(match[1]) : null;
|
|
134
|
+
linuxBootTimeMsCache =
|
|
135
|
+
Number.isFinite(seconds) && seconds > 0 ? seconds * 1000 : null;
|
|
136
|
+
} catch {
|
|
137
|
+
linuxBootTimeMsCache = null;
|
|
138
|
+
}
|
|
139
|
+
return linuxBootTimeMsCache;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function readLinuxProcProcess(pid) {
|
|
143
|
+
const target = Number(pid);
|
|
144
|
+
if (!Number.isSafeInteger(target) || target <= 0) {
|
|
145
|
+
return { status: "unknown", process: null };
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
148
|
+
const parsed = parseLinuxProcStat(
|
|
149
|
+
readFileSync(`/proc/${target}/stat`, "utf8"),
|
|
150
|
+
linuxBootTimeMs(),
|
|
151
|
+
);
|
|
152
|
+
return parsed
|
|
153
|
+
? { status: "present", process: parsed }
|
|
154
|
+
: { status: "unknown", process: null };
|
|
155
|
+
} catch (error) {
|
|
156
|
+
return ["ENOENT", "ESRCH"].includes(error?.code)
|
|
157
|
+
? { status: "absent", process: null }
|
|
158
|
+
: { status: "unknown", process: null };
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function readLinuxProcProcessGroupStates(pgid) {
|
|
163
|
+
const target = Number(pgid);
|
|
164
|
+
if (!Number.isSafeInteger(target) || target <= 0) return null;
|
|
165
|
+
let entries;
|
|
166
|
+
try {
|
|
167
|
+
entries = readdirSync("/proc");
|
|
168
|
+
} catch {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
const states = [];
|
|
172
|
+
for (const entry of entries) {
|
|
173
|
+
if (!/^\d+$/u.test(entry)) continue;
|
|
174
|
+
const observed = readLinuxProcProcess(Number(entry));
|
|
175
|
+
if (observed.status === "unknown") return null;
|
|
176
|
+
if (
|
|
177
|
+
observed.status === "present" &&
|
|
178
|
+
observed.process.processGroupId === target
|
|
179
|
+
) {
|
|
180
|
+
states.push(observed.process.state);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return states;
|
|
184
|
+
}
|
|
185
|
+
|
|
82
186
|
/**
|
|
83
187
|
* A bounded FIFO/TTL cache for process creation-time probes.
|
|
84
188
|
*
|
|
@@ -263,6 +367,13 @@ function defaultReadProcessStartTimeMs(pid) {
|
|
|
263
367
|
}
|
|
264
368
|
return null;
|
|
265
369
|
}
|
|
370
|
+
if (process.platform === "linux") {
|
|
371
|
+
const observed = readLinuxProcProcess(target);
|
|
372
|
+
if (observed.status === "absent") return { status: "absent" };
|
|
373
|
+
if (Number.isFinite(observed.process?.startedAtMs)) {
|
|
374
|
+
return observed.process.startedAtMs;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
266
377
|
// POSIX: `ps -o lstart=` gives an absolute start timestamp on Linux + macOS
|
|
267
378
|
// (procps and BSD ps both support it; busybox ps does not → null → open).
|
|
268
379
|
try {
|
|
@@ -300,6 +411,12 @@ function defaultReadProcessState(pid) {
|
|
|
300
411
|
) {
|
|
301
412
|
return null;
|
|
302
413
|
}
|
|
414
|
+
if (process.platform === "linux") {
|
|
415
|
+
const observed = readLinuxProcProcess(target);
|
|
416
|
+
if (observed.status !== "unknown") {
|
|
417
|
+
return observed.process?.state || null;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
303
420
|
try {
|
|
304
421
|
const result = runSupervisorCommand(
|
|
305
422
|
"ps",
|
|
@@ -335,6 +452,10 @@ function defaultReadProcessGroupStates(pgid) {
|
|
|
335
452
|
) {
|
|
336
453
|
return null;
|
|
337
454
|
}
|
|
455
|
+
if (process.platform === "linux") {
|
|
456
|
+
const states = readLinuxProcProcessGroupStates(target);
|
|
457
|
+
if (Array.isArray(states)) return states;
|
|
458
|
+
}
|
|
338
459
|
try {
|
|
339
460
|
const result = runSupervisorCommand(
|
|
340
461
|
"ps",
|
|
@@ -1128,7 +1249,7 @@ function mergeBackgroundAgentState(current, requested) {
|
|
|
1128
1249
|
return next;
|
|
1129
1250
|
}
|
|
1130
1251
|
|
|
1131
|
-
function persistBackgroundAgentState(target, next) {
|
|
1252
|
+
function persistBackgroundAgentState(target, next, options = {}) {
|
|
1132
1253
|
// Multiple async state writers can run in one process; a pid-only temporary
|
|
1133
1254
|
// name lets them overwrite each other's staging file. A unique suffix keeps
|
|
1134
1255
|
// each atomic replacement independent. Windows scanners/readers can also
|
|
@@ -1136,6 +1257,21 @@ function persistBackgroundAgentState(target, next) {
|
|
|
1136
1257
|
// transient class rather than surfacing a spurious EPERM background failure.
|
|
1137
1258
|
const tmp = `${target}.${process.pid}.${randomBytes(4).toString("hex")}.tmp`;
|
|
1138
1259
|
writeFileSync(tmp, JSON.stringify(next, null, 2), { mode: 0o600 });
|
|
1260
|
+
try {
|
|
1261
|
+
if (
|
|
1262
|
+
typeof options.publishReleaseAfterPathRemoved === "function" &&
|
|
1263
|
+
options.publishReleaseAfterPathRemoved(tmp) !== true
|
|
1264
|
+
) {
|
|
1265
|
+
const error = new Error(
|
|
1266
|
+
`Could not publish state-lock release handoff: ${target}`,
|
|
1267
|
+
);
|
|
1268
|
+
error.code = "STATE_LOCK_RELEASE_HANDOFF_FAILED";
|
|
1269
|
+
throw error;
|
|
1270
|
+
}
|
|
1271
|
+
} catch (error) {
|
|
1272
|
+
rmSync(tmp, { force: true });
|
|
1273
|
+
throw error;
|
|
1274
|
+
}
|
|
1139
1275
|
for (let attempt = 0; ; attempt++) {
|
|
1140
1276
|
try {
|
|
1141
1277
|
renameSync(tmp, target);
|
|
@@ -1179,7 +1315,7 @@ export function mutateBackgroundAgentState(id, updater, options = {}) {
|
|
|
1179
1315
|
const target = statePath(safe);
|
|
1180
1316
|
return withFileLock(
|
|
1181
1317
|
target,
|
|
1182
|
-
() => {
|
|
1318
|
+
({ publishReleaseAfterPathRemoved }) => {
|
|
1183
1319
|
const read = readBackgroundAgentStateResult(safe);
|
|
1184
1320
|
if (read.error) throw read.error;
|
|
1185
1321
|
if (read.missing && options.createIfMissing !== true) {
|
|
@@ -1193,7 +1329,9 @@ export function mutateBackgroundAgentState(id, updater, options = {}) {
|
|
|
1193
1329
|
...requested,
|
|
1194
1330
|
id: safe,
|
|
1195
1331
|
});
|
|
1196
|
-
persistBackgroundAgentState(target, next
|
|
1332
|
+
persistBackgroundAgentState(target, next, {
|
|
1333
|
+
publishReleaseAfterPathRemoved,
|
|
1334
|
+
});
|
|
1197
1335
|
return { applied: true, state: next, previous: read.state };
|
|
1198
1336
|
},
|
|
1199
1337
|
{
|
|
@@ -2976,8 +3114,14 @@ function recordedBackgroundProcessesAlive(state) {
|
|
|
2976
3114
|
);
|
|
2977
3115
|
}
|
|
2978
3116
|
|
|
2979
|
-
export function isBackgroundProcessTreeExecutionAlive(
|
|
2980
|
-
|
|
3117
|
+
export function isBackgroundProcessTreeExecutionAlive(
|
|
3118
|
+
pid,
|
|
3119
|
+
startedAt,
|
|
3120
|
+
options = {},
|
|
3121
|
+
) {
|
|
3122
|
+
const identity = inspectDestructiveProcessIdentity(pid, startedAt, {
|
|
3123
|
+
processGroup: options.processGroup !== false,
|
|
3124
|
+
});
|
|
2981
3125
|
// `unverifiable` includes a vanished/zombie POSIX leader whose process group
|
|
2982
3126
|
// is still executable or whose group snapshot failed. Both must block
|
|
2983
3127
|
// worktree deletion just as a verified live leader does.
|
|
@@ -11,6 +11,10 @@ export const BACKGROUND_TURN_BOOTSTRAP_READY =
|
|
|
11
11
|
"background-turn-bootstrap-ready";
|
|
12
12
|
export const BACKGROUND_TURN_BOOTSTRAP_RELEASE =
|
|
13
13
|
"background-turn-bootstrap-release";
|
|
14
|
+
// The formal launch gate permits 120 seconds for a 20-worker hosted runner to
|
|
15
|
+
// become ready. Keep the pre-main barrier alive for that same bounded window;
|
|
16
|
+
// worker/IPC death still fails immediately through the disconnect listener.
|
|
17
|
+
export const BACKGROUND_TURN_BOOTSTRAP_RELEASE_TIMEOUT_MS = 120_000;
|
|
14
18
|
|
|
15
19
|
export const BACKGROUND_TURN_BOOTSTRAP_ENV = Object.freeze({
|
|
16
20
|
nonce: "CC_BACKGROUND_TURN_BOOTSTRAP_NONCE",
|
|
@@ -38,12 +38,16 @@ export const COMMAND_ALIAS_DECISION_POLICY = Object.freeze({
|
|
|
38
38
|
requiredPlatforms: Object.freeze(["linux", "macos", "windows"]),
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
//
|
|
41
|
+
// Repository-owned anchor for the first public release containing the complete
|
|
42
|
+
// DELTA lifecycle exporter and repository-probe hardening. Coverage must begin
|
|
43
|
+
// at this exact npm publication boundary; report input cannot override it.
|
|
44
44
|
export const COMMAND_LIFECYCLE_DELTA_RELEASE_POLICY = Object.freeze({
|
|
45
45
|
schema: "chainlesschain.command-lifecycle-delta-release-policy.v1",
|
|
46
|
-
firstPublicRelease:
|
|
46
|
+
firstPublicRelease: Object.freeze({
|
|
47
|
+
version: "0.163.4",
|
|
48
|
+
commitSha: "27ed0ac2005e16ce5ddff53990e85b1d13ea0b1d",
|
|
49
|
+
npmPublishedAt: "2026-08-10T19:42:11.053Z",
|
|
50
|
+
}),
|
|
47
51
|
incompatibleReleases: Object.freeze(["0.162.198", "0.163.3"]),
|
|
48
52
|
});
|
|
49
53
|
|
|
@@ -108,8 +108,9 @@ async function invokeChatCall(callWrapper, provider, model, call) {
|
|
|
108
108
|
* @param {string} [options.apiKey] - API key override
|
|
109
109
|
* @param {(request: {call: function, provider: string, model: string}) => Promise<object>} [options.callWrapper]
|
|
110
110
|
* Optional host boundary around each real provider call. The callback
|
|
111
|
-
*
|
|
112
|
-
* receive only the
|
|
111
|
+
* may invoke `call({ signal })` to bind cancellation and resolves to a
|
|
112
|
+
* private `{content, usage?}` envelope; callers still receive only the
|
|
113
|
+
* response string.
|
|
113
114
|
* @returns {(messages: object[], opts?: object) => Promise<string>}
|
|
114
115
|
*/
|
|
115
116
|
export function createChatFn(options = {}) {
|
|
@@ -145,9 +146,10 @@ export function createChatFn(options = {}) {
|
|
|
145
146
|
callWrapper,
|
|
146
147
|
provider,
|
|
147
148
|
currentModel,
|
|
148
|
-
async () => {
|
|
149
|
+
async ({ signal = opts.signal || resolved.signal } = {}) => {
|
|
149
150
|
const res = await fetch(`${baseUrl}/api/chat`, {
|
|
150
151
|
method: "POST",
|
|
152
|
+
signal,
|
|
151
153
|
headers: { "Content-Type": "application/json" },
|
|
152
154
|
body: JSON.stringify({
|
|
153
155
|
model: currentModel,
|
|
@@ -185,9 +187,10 @@ export function createChatFn(options = {}) {
|
|
|
185
187
|
callWrapper,
|
|
186
188
|
provider,
|
|
187
189
|
currentModel,
|
|
188
|
-
async () => {
|
|
190
|
+
async ({ signal = opts.signal || resolved.signal } = {}) => {
|
|
189
191
|
const res = await fetch(`${baseUrl}/messages`, {
|
|
190
192
|
method: "POST",
|
|
193
|
+
signal,
|
|
191
194
|
headers: {
|
|
192
195
|
"Content-Type": "application/json",
|
|
193
196
|
"x-api-key": key,
|
|
@@ -214,9 +217,10 @@ export function createChatFn(options = {}) {
|
|
|
214
217
|
callWrapper,
|
|
215
218
|
provider,
|
|
216
219
|
currentModel,
|
|
217
|
-
async () => {
|
|
220
|
+
async ({ signal = opts.signal || resolved.signal } = {}) => {
|
|
218
221
|
const res = await fetch(`${baseUrl}/chat/completions`, {
|
|
219
222
|
method: "POST",
|
|
223
|
+
signal,
|
|
220
224
|
headers: {
|
|
221
225
|
"Content-Type": "application/json",
|
|
222
226
|
Authorization: `Bearer ${key}`,
|
|
@@ -518,8 +518,12 @@ export function prepareCoworkMcpRuntime(mcp, options = {}) {
|
|
|
518
518
|
* @param {string} [options.mcpSessionId] - Stable MCP ledger session for resume
|
|
519
519
|
* @param {string} [options.workflowEffectId] - Canonical durable workflow effect
|
|
520
520
|
* @param {boolean} [options.strictUsageTelemetry] - Require synchronous durable call observers
|
|
521
|
+
* @param {boolean} [options.managedCheckpoint] - Wrap mutating child tools in workspace transactions
|
|
522
|
+
* @param {string|null} [options.managedCheckpointStateDir] - Optional transaction state root
|
|
523
|
+
* @param {string[]} [options.managedCheckpointExclusions] - Explicit uncovered workspace paths
|
|
521
524
|
* @param {function} [options.onUsageBoundary] - Provider-call durable start observer
|
|
522
525
|
* @param {function} [options.onUsageSettlement] - Provider-call durable settlement observer
|
|
526
|
+
* @param {function} [options.onProviderReceipt] - Provider receipt durable prewrite observer
|
|
523
527
|
* @param {function} [options.onToolCallBoundary] - Tool-call durable start observer
|
|
524
528
|
* @param {function} [options.onToolCallSettlement] - Tool-call durable settlement observer
|
|
525
529
|
* @param {(request: object) => boolean|Promise<boolean>} [options.approveMcpLocalCodeExecution]
|
|
@@ -540,8 +544,12 @@ export async function runCoworkTask(options = {}) {
|
|
|
540
544
|
mcpSessionId = null,
|
|
541
545
|
workflowEffectId = null,
|
|
542
546
|
strictUsageTelemetry = false,
|
|
547
|
+
managedCheckpoint = false,
|
|
548
|
+
managedCheckpointStateDir = null,
|
|
549
|
+
managedCheckpointExclusions = [],
|
|
543
550
|
onUsageBoundary = null,
|
|
544
551
|
onUsageSettlement = null,
|
|
552
|
+
onProviderReceipt = null,
|
|
545
553
|
onToolCallBoundary = null,
|
|
546
554
|
onToolCallSettlement = null,
|
|
547
555
|
approveMcpLocalCodeExecution = null,
|
|
@@ -640,6 +648,7 @@ export async function runCoworkTask(options = {}) {
|
|
|
640
648
|
strictUsageTelemetry: true,
|
|
641
649
|
onUsageBoundary,
|
|
642
650
|
onUsageSettlement,
|
|
651
|
+
onProviderReceipt,
|
|
643
652
|
onToolCallBoundary,
|
|
644
653
|
onToolCallSettlement,
|
|
645
654
|
}
|
|
@@ -678,6 +687,17 @@ export async function runCoworkTask(options = {}) {
|
|
|
678
687
|
mcpRuntime.sessionId && mcpRuntime.bindingAllowed
|
|
679
688
|
? { sessionId: mcpRuntime.sessionId }
|
|
680
689
|
: {};
|
|
690
|
+
if (managedCheckpoint === true) {
|
|
691
|
+
loopOptions.managedCheckpoint = true;
|
|
692
|
+
if (managedCheckpointStateDir) {
|
|
693
|
+
loopOptions.managedCheckpointStateDir = managedCheckpointStateDir;
|
|
694
|
+
}
|
|
695
|
+
if (Array.isArray(managedCheckpointExclusions)) {
|
|
696
|
+
loopOptions.managedCheckpointExclusions = [
|
|
697
|
+
...managedCheckpointExclusions,
|
|
698
|
+
];
|
|
699
|
+
}
|
|
700
|
+
}
|
|
681
701
|
if (
|
|
682
702
|
Array.isArray(template.shellPolicyOverrides) &&
|
|
683
703
|
template.shellPolicyOverrides.length
|
|
@@ -59,6 +59,9 @@ import { canonicalJson } from "./scheduler-kernel/contract.js";
|
|
|
59
59
|
/** Maximum number of items a single forEach step can expand into. */
|
|
60
60
|
export const MAX_FAN_OUT = 500;
|
|
61
61
|
|
|
62
|
+
/** Maximum declarative choices accepted by one durable stage input gate. */
|
|
63
|
+
export const MAX_STAGE_INPUT_OPTIONS = 32;
|
|
64
|
+
|
|
62
65
|
/** Absolute ceiling on a single loop step's iterations (infinite-loop guard). */
|
|
63
66
|
export const MAX_LOOP_ITERATIONS = 100;
|
|
64
67
|
export const COWORK_WORKFLOW_RUN_RECORD_SCHEMA = "cc-cowork-workflow-run/v1";
|
|
@@ -832,6 +835,53 @@ export function validateWorkflow(wf) {
|
|
|
832
835
|
if (s.when !== undefined && typeof s.when !== "string") {
|
|
833
836
|
errors.push(`steps[${i}].when must be a string expression`);
|
|
834
837
|
}
|
|
838
|
+
if (s.needsInput !== undefined) {
|
|
839
|
+
const input = s.needsInput;
|
|
840
|
+
const inputKeys =
|
|
841
|
+
input && typeof input === "object" && !Array.isArray(input)
|
|
842
|
+
? Object.keys(input)
|
|
843
|
+
: [];
|
|
844
|
+
if (
|
|
845
|
+
!input ||
|
|
846
|
+
typeof input !== "object" ||
|
|
847
|
+
Array.isArray(input) ||
|
|
848
|
+
inputKeys.some(
|
|
849
|
+
(key) => !["prompt", "options", "multiSelect"].includes(key),
|
|
850
|
+
) ||
|
|
851
|
+
typeof input.prompt !== "string" ||
|
|
852
|
+
input.prompt.trim() !== input.prompt ||
|
|
853
|
+
input.prompt.length === 0 ||
|
|
854
|
+
input.prompt.length > 4096
|
|
855
|
+
) {
|
|
856
|
+
errors.push(`steps[${i}].needsInput has an invalid prompt schema`);
|
|
857
|
+
} else {
|
|
858
|
+
if (
|
|
859
|
+
input.options !== undefined &&
|
|
860
|
+
(!Array.isArray(input.options) ||
|
|
861
|
+
input.options.length === 0 ||
|
|
862
|
+
input.options.length > MAX_STAGE_INPUT_OPTIONS ||
|
|
863
|
+
input.options.some(
|
|
864
|
+
(option) =>
|
|
865
|
+
typeof option !== "string" ||
|
|
866
|
+
option.trim() !== option ||
|
|
867
|
+
option.length === 0 ||
|
|
868
|
+
option.length > 512,
|
|
869
|
+
) ||
|
|
870
|
+
new Set(input.options).size !== input.options.length)
|
|
871
|
+
) {
|
|
872
|
+
errors.push(`steps[${i}].needsInput.options is invalid`);
|
|
873
|
+
}
|
|
874
|
+
if (
|
|
875
|
+
input.multiSelect !== undefined &&
|
|
876
|
+
typeof input.multiSelect !== "boolean"
|
|
877
|
+
) {
|
|
878
|
+
errors.push(`steps[${i}].needsInput.multiSelect must be boolean`);
|
|
879
|
+
}
|
|
880
|
+
if (input.multiSelect === true && !Array.isArray(input.options)) {
|
|
881
|
+
errors.push(`steps[${i}].needsInput.multiSelect requires options`);
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
}
|
|
835
885
|
if (s.forEach !== undefined) {
|
|
836
886
|
const f = s.forEach;
|
|
837
887
|
const ok =
|
|
@@ -1076,6 +1126,69 @@ export function substitutePlaceholders(template, resultsById) {
|
|
|
1076
1126
|
);
|
|
1077
1127
|
}
|
|
1078
1128
|
|
|
1129
|
+
function normalizeResolvedStageInput(value, spec) {
|
|
1130
|
+
const answer = snapshotAdmittedCanonicalValue(
|
|
1131
|
+
value,
|
|
1132
|
+
"workflow stage input answer",
|
|
1133
|
+
{ maxNodes: 256, maxBytes: 64 * 1024 },
|
|
1134
|
+
);
|
|
1135
|
+
const options = Array.isArray(spec.options) ? spec.options : null;
|
|
1136
|
+
if (spec.multiSelect === true) {
|
|
1137
|
+
if (
|
|
1138
|
+
!Array.isArray(answer) ||
|
|
1139
|
+
answer.length === 0 ||
|
|
1140
|
+
answer.length > MAX_STAGE_INPUT_OPTIONS ||
|
|
1141
|
+
answer.some((item) => typeof item !== "string") ||
|
|
1142
|
+
new Set(answer).size !== answer.length ||
|
|
1143
|
+
answer.some((item) => !options.includes(item))
|
|
1144
|
+
) {
|
|
1145
|
+
throw runResultError("workflow stage input answer is invalid");
|
|
1146
|
+
}
|
|
1147
|
+
return answer;
|
|
1148
|
+
}
|
|
1149
|
+
if (
|
|
1150
|
+
typeof answer !== "string" ||
|
|
1151
|
+
answer.length === 0 ||
|
|
1152
|
+
answer.length > 64 * 1024 ||
|
|
1153
|
+
(options && !options.includes(answer))
|
|
1154
|
+
) {
|
|
1155
|
+
throw runResultError("workflow stage input answer is invalid");
|
|
1156
|
+
}
|
|
1157
|
+
return answer;
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
async function resolveStageInputMessage(
|
|
1161
|
+
step,
|
|
1162
|
+
message,
|
|
1163
|
+
resultsById,
|
|
1164
|
+
resolveInput,
|
|
1165
|
+
) {
|
|
1166
|
+
if (step.needsInput === undefined) return message;
|
|
1167
|
+
if (typeof resolveInput !== "function") {
|
|
1168
|
+
const error = new Error(
|
|
1169
|
+
`workflow step '${step.id}' requires a durable input resolver`,
|
|
1170
|
+
);
|
|
1171
|
+
error.code = "COWORK_WORKFLOW_INPUT_RESOLVER_REQUIRED";
|
|
1172
|
+
throw error;
|
|
1173
|
+
}
|
|
1174
|
+
const spec = step.needsInput;
|
|
1175
|
+
const prompt = substitutePlaceholders(spec.prompt, resultsById);
|
|
1176
|
+
const answer = normalizeResolvedStageInput(
|
|
1177
|
+
await resolveInput(
|
|
1178
|
+
Object.freeze({
|
|
1179
|
+
stepId: step.id,
|
|
1180
|
+
prompt,
|
|
1181
|
+
options: Array.isArray(spec.options)
|
|
1182
|
+
? Object.freeze([...spec.options])
|
|
1183
|
+
: null,
|
|
1184
|
+
multiSelect: spec.multiSelect === true,
|
|
1185
|
+
}),
|
|
1186
|
+
),
|
|
1187
|
+
spec,
|
|
1188
|
+
);
|
|
1189
|
+
return `${message}\n\n## Bound user input for stage ${step.id}\n${canonicalJson(answer, "workflowStageInput")}`;
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1079
1192
|
// ─── Persistence ─────────────────────────────────────────────────────────────
|
|
1080
1193
|
|
|
1081
1194
|
function _storedWorkflowError(message) {
|
|
@@ -1600,6 +1713,7 @@ export async function runStepNode(step, ctx) {
|
|
|
1600
1713
|
onStepComplete,
|
|
1601
1714
|
taskSemaphore,
|
|
1602
1715
|
runTask,
|
|
1716
|
+
resolveInput,
|
|
1603
1717
|
admitted = false,
|
|
1604
1718
|
} = ctx;
|
|
1605
1719
|
const recordId = step.id;
|
|
@@ -1620,9 +1734,20 @@ export async function runStepNode(step, ctx) {
|
|
|
1620
1734
|
}
|
|
1621
1735
|
if (!runThis) return single("skipped", "when-condition false");
|
|
1622
1736
|
|
|
1623
|
-
|
|
1737
|
+
const resolvedMessage = await resolveStageInputMessage(
|
|
1738
|
+
step,
|
|
1739
|
+
step.message,
|
|
1740
|
+
resultsById,
|
|
1741
|
+
resolveInput,
|
|
1742
|
+
);
|
|
1743
|
+
const activeStep =
|
|
1744
|
+
resolvedMessage === step.message
|
|
1745
|
+
? step
|
|
1746
|
+
: { ...step, message: resolvedMessage };
|
|
1747
|
+
|
|
1748
|
+
if (isLoopStep(activeStep)) {
|
|
1624
1749
|
const o = await runLoopStep({
|
|
1625
|
-
step,
|
|
1750
|
+
step: activeStep,
|
|
1626
1751
|
recordId,
|
|
1627
1752
|
cwd,
|
|
1628
1753
|
llmOptions,
|
|
@@ -1640,10 +1765,10 @@ export async function runStepNode(step, ctx) {
|
|
|
1640
1765
|
};
|
|
1641
1766
|
}
|
|
1642
1767
|
|
|
1643
|
-
if (
|
|
1768
|
+
if (activeStep.forEach !== undefined) {
|
|
1644
1769
|
let items;
|
|
1645
1770
|
try {
|
|
1646
|
-
items = resolveForEachItems(
|
|
1771
|
+
items = resolveForEachItems(activeStep.forEach, resultsById);
|
|
1647
1772
|
} catch (err) {
|
|
1648
1773
|
return single("failed", err.message);
|
|
1649
1774
|
}
|
|
@@ -1651,10 +1776,10 @@ export async function runStepNode(step, ctx) {
|
|
|
1651
1776
|
const children = await Promise.all(
|
|
1652
1777
|
items.map(async (item, k) => {
|
|
1653
1778
|
const childId = `${recordId}[${k}]`;
|
|
1654
|
-
const withItem = substituteItem(
|
|
1779
|
+
const withItem = substituteItem(activeStep.message, item);
|
|
1655
1780
|
const msg = substitutePlaceholders(withItem, resultsById);
|
|
1656
1781
|
const r = await runStepWithRetry({
|
|
1657
|
-
step,
|
|
1782
|
+
step: activeStep,
|
|
1658
1783
|
message: msg,
|
|
1659
1784
|
cwd,
|
|
1660
1785
|
llmOptions,
|
|
@@ -1687,9 +1812,9 @@ export async function runStepNode(step, ctx) {
|
|
|
1687
1812
|
};
|
|
1688
1813
|
}
|
|
1689
1814
|
|
|
1690
|
-
const message = substitutePlaceholders(
|
|
1815
|
+
const message = substitutePlaceholders(activeStep.message, resultsById);
|
|
1691
1816
|
const r = await runStepWithRetry({
|
|
1692
|
-
step,
|
|
1817
|
+
step: activeStep,
|
|
1693
1818
|
message,
|
|
1694
1819
|
cwd,
|
|
1695
1820
|
llmOptions,
|
|
@@ -1724,6 +1849,7 @@ export async function runPipeline({
|
|
|
1724
1849
|
onStepComplete,
|
|
1725
1850
|
taskSemaphore,
|
|
1726
1851
|
runTask = _deps.runTask,
|
|
1852
|
+
resolveInput,
|
|
1727
1853
|
admitted = false,
|
|
1728
1854
|
}) {
|
|
1729
1855
|
const limit = Math.max(1, Math.floor(maxParallel) || 1);
|
|
@@ -1787,6 +1913,7 @@ export async function runPipeline({
|
|
|
1787
1913
|
onStepComplete,
|
|
1788
1914
|
taskSemaphore,
|
|
1789
1915
|
runTask,
|
|
1916
|
+
resolveInput,
|
|
1790
1917
|
admitted,
|
|
1791
1918
|
});
|
|
1792
1919
|
} catch (err) {
|
|
@@ -1950,6 +2077,7 @@ function normalizeAdmittedRunRecord(
|
|
|
1950
2077
|
* @param {object} [options.llmOptions] - Forwarded to each task
|
|
1951
2078
|
* @param {function} [options.onStepStart]
|
|
1952
2079
|
* @param {function} [options.onStepComplete]
|
|
2080
|
+
* @param {function} [options.resolveInput] - Durable stage input resolver
|
|
1953
2081
|
* @param {object} [options.runAdmission] - Secret-free, digest-bound dynamic
|
|
1954
2082
|
* workflow admission. Production entry points require this even though the
|
|
1955
2083
|
* low-level executor keeps it optional for existing library callers.
|
|
@@ -1973,6 +2101,7 @@ export async function executeWorkflow(options = {}) {
|
|
|
1973
2101
|
onStepComplete,
|
|
1974
2102
|
pipeline,
|
|
1975
2103
|
runAdmission,
|
|
2104
|
+
resolveInput,
|
|
1976
2105
|
runTask: requestedRunTask,
|
|
1977
2106
|
} = options;
|
|
1978
2107
|
|
|
@@ -2019,6 +2148,16 @@ export async function executeWorkflow(options = {}) {
|
|
|
2019
2148
|
"cowork-workflow: runTask is not available (wire runCoworkTask before executing)",
|
|
2020
2149
|
);
|
|
2021
2150
|
}
|
|
2151
|
+
if (
|
|
2152
|
+
runtimeWorkflow.steps.some((step) => step.needsInput !== undefined) &&
|
|
2153
|
+
typeof resolveInput !== "function"
|
|
2154
|
+
) {
|
|
2155
|
+
const error = new Error(
|
|
2156
|
+
"workflow contains needsInput stages but no durable input resolver was provided",
|
|
2157
|
+
);
|
|
2158
|
+
error.code = "COWORK_WORKFLOW_INPUT_RESOLVER_REQUIRED";
|
|
2159
|
+
throw error;
|
|
2160
|
+
}
|
|
2022
2161
|
|
|
2023
2162
|
const taskSemaphore = createWorkflowTaskSemaphore(concurrencyLimit);
|
|
2024
2163
|
const resultsById = new Map();
|
|
@@ -2038,6 +2177,7 @@ export async function executeWorkflow(options = {}) {
|
|
|
2038
2177
|
onStepComplete,
|
|
2039
2178
|
taskSemaphore,
|
|
2040
2179
|
runTask: runtimeRunTask,
|
|
2180
|
+
resolveInput,
|
|
2041
2181
|
admitted: verifiedRunAdmission != null,
|
|
2042
2182
|
}));
|
|
2043
2183
|
} else {
|
|
@@ -2094,23 +2234,33 @@ export async function executeWorkflow(options = {}) {
|
|
|
2094
2234
|
preOutcomes.push(outcome);
|
|
2095
2235
|
continue;
|
|
2096
2236
|
}
|
|
2237
|
+
const resolvedMessage = await resolveStageInputMessage(
|
|
2238
|
+
step,
|
|
2239
|
+
step.message,
|
|
2240
|
+
resultsById,
|
|
2241
|
+
resolveInput,
|
|
2242
|
+
);
|
|
2243
|
+
const activeStep =
|
|
2244
|
+
resolvedMessage === step.message
|
|
2245
|
+
? step
|
|
2246
|
+
: { ...step, message: resolvedMessage };
|
|
2097
2247
|
// loop node — runs its body repeatedly; per-iteration substitution
|
|
2098
2248
|
// happens inside runLoopStep, so push the raw template.
|
|
2099
|
-
if (isLoopStep(
|
|
2249
|
+
if (isLoopStep(activeStep)) {
|
|
2100
2250
|
runnable.push({
|
|
2101
|
-
step,
|
|
2102
|
-
message:
|
|
2103
|
-
recordId:
|
|
2251
|
+
step: activeStep,
|
|
2252
|
+
message: activeStep.message,
|
|
2253
|
+
recordId: activeStep.id,
|
|
2104
2254
|
parentId: null,
|
|
2105
2255
|
isLoop: true,
|
|
2106
2256
|
});
|
|
2107
2257
|
continue;
|
|
2108
2258
|
}
|
|
2109
2259
|
// forEach-expansion
|
|
2110
|
-
if (
|
|
2260
|
+
if (activeStep.forEach !== undefined) {
|
|
2111
2261
|
let items;
|
|
2112
2262
|
try {
|
|
2113
|
-
items = resolveForEachItems(
|
|
2263
|
+
items = resolveForEachItems(activeStep.forEach, resultsById);
|
|
2114
2264
|
} catch (err) {
|
|
2115
2265
|
anyFailure = true;
|
|
2116
2266
|
const outcome = {
|
|
@@ -2135,20 +2285,28 @@ export async function executeWorkflow(options = {}) {
|
|
|
2135
2285
|
continue;
|
|
2136
2286
|
}
|
|
2137
2287
|
for (let k = 0; k < items.length; k++) {
|
|
2138
|
-
const childId = `${
|
|
2139
|
-
const withItem = substituteItem(
|
|
2288
|
+
const childId = `${activeStep.id}[${k}]`;
|
|
2289
|
+
const withItem = substituteItem(activeStep.message, items[k]);
|
|
2140
2290
|
const msg = substitutePlaceholders(withItem, resultsById);
|
|
2141
2291
|
runnable.push({
|
|
2142
|
-
step,
|
|
2292
|
+
step: activeStep,
|
|
2143
2293
|
message: msg,
|
|
2144
2294
|
recordId: childId,
|
|
2145
|
-
parentId:
|
|
2295
|
+
parentId: activeStep.id,
|
|
2146
2296
|
});
|
|
2147
2297
|
}
|
|
2148
2298
|
continue;
|
|
2149
2299
|
}
|
|
2150
|
-
const message = substitutePlaceholders(
|
|
2151
|
-
|
|
2300
|
+
const message = substitutePlaceholders(
|
|
2301
|
+
activeStep.message,
|
|
2302
|
+
resultsById,
|
|
2303
|
+
);
|
|
2304
|
+
runnable.push({
|
|
2305
|
+
step: activeStep,
|
|
2306
|
+
message,
|
|
2307
|
+
recordId: activeStep.id,
|
|
2308
|
+
parentId: null,
|
|
2309
|
+
});
|
|
2152
2310
|
}
|
|
2153
2311
|
|
|
2154
2312
|
const promises = runnable.map(
|