chainlesschain 0.165.3 → 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-BiHNUlbU.js → AIOps-C__nnraW.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-D-UFjDRQ.js → ActionButton-CsKWHEZ-.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DazVsDgW.js → Analytics-BhIjfjWO.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DXh9UfNJ.js → AppLayout-BjuXFzWZ.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-CZ6tsceY.js → Artifacts-k6whDkZJ.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-RyxnBr_h.js → Audit-C4FBMYRh.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BWS51Q6X.js → BackgroundAgents-C_vRrSXk.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BRtPcUul.js → Backup-CngFZeVp.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-CGd4vZYY.js → BaseInput-B_H9EBRm.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-h8ijVwCg.js → Chat-DLEC5kt7.js} +4 -4
- package/src/assets/web-panel/assets/ChatBubbleRenderer-xijcWkJe.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-NyF6dPl8.js → Checkbox-m3ClR4xh.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-Ci4OOxr5.js → Codegen-CmLSFrgp.js} +1 -1
- package/src/assets/web-panel/assets/{Col-CwTkc9BM.js → Col-DFGQteHN.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DW_tM82m.js → Community-EUUVORHE.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DEvHRV4S.js → Compact-2PSg0Yr7.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-BbjBEEfD.js → Compliance-CcKur7gB.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-10IXBaBa.js → Cowork-DK_Fezfa.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-BZkbpd5I.js → Cron-Dbw89xl7.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CFQ8L_6v.js → Crosschain-CH66h_Ec.js} +1 -1
- package/src/assets/web-panel/assets/{DID-BDF6AkXe.js → DID-D1igRb17.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-CoOdWMi4.js → Dashboard-DVAsrobk.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-DEsGmu8Y.js → Dropdown-Dl7W8AQs.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BS89SWlK.js → EmailListRenderer-D5tpaEQC.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-C1FpCHiI.js → FamilyGuardDashboard-O_VQf8gq.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BzvpVmLA.js → Federation-BTVcgS9n.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BeC259PQ.js → FormItemContext-BRnkJAIz.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-azgG3bmV.js → GenericCardRenderer-8OWSCkDj.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BmSSowc5.js → Git-WXLYTQj2.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-CTBCSyQZ.js → Governance-BezaUhtc.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-DA5xyk4a.js → Inference-CuRay3Gu.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-D1gPHNig.js → KnowledgeGraph-DfWLDW1m.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BPmLf1AR.js → Logs-C55y2pPY.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-hDpWdiBc.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-DtUFcR0E.js → Marketplace-Dk08Uycg.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DS_kqBv-.js → McpTools-C11fSB5V.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-Fvh7XL7V.js → Memory-mr0eZc97.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-C7itAP45.js → MobileBridge-C0iCSRbb.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-CY-xMG8Z.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-B57MiNLK.js → Mtc-Bplqc_Wc.js} +6 -6
- package/src/assets/web-panel/assets/{MtcAudit-BXfCUcM7.js → MtcAudit-BlzwsoSM.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-yaJ-ZcF6.js → Multisig-BBLmTty6.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CoaUCKrO.js → NLProgramming-DtT1uf1W.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-BKLM_65R.js → Notes-DcqQAxTK.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-DoDtK9uZ.js → NotificationSettings-cb0kWoZe.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-BJ28TGr-.js → OrderTableRenderer-kw9HZQNN.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-MuGsdoIb.js → Organization-DlTlbkUN.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-BLUN9J4R.js → Overflow-pp1qs-oY.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-DWuoBUPd.js → P2P-BESLnyYz.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-CUi37YPj.js → PdhVaultBrowser-B-J1mGuf.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-BYQg2pcr.js → Permissions-B36PeT1_.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-CAxoV2xu.js → PersonalDataHub-CTK2ad-3.js} +6 -6
- package/src/assets/web-panel/assets/{Pipeline-B33wGvIO.js → Pipeline-zJNGXsac.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-A8yXTORP.js → Privacy-b9fz0Qf0.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-D49I2I1O.js → ProjectInit-DjZbZgiB.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-Ci73jJDw.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-Dz-CAYYU.js +1 -0
- package/src/assets/web-panel/assets/{QrScannerModal-Brza0ykJ.js → QrScannerModal-A0yoQ3-3.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-DFydhjxL.js → QuickAsk-DrFgFJNC.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DLF8_NhA.js → Recommend-KC8hF1g4.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-dyuStW3x.js → RemoteSession-DGTPIk6u.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-5F3tA6yw.js → Reputation-QmbwM7Yk.js} +1 -1
- package/src/assets/web-panel/assets/{Row-Ca2A57S5.js → Row-BxjJylia.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-B0bxBkq_.js → RssFeed-B7Wda1J6.js} +3 -3
- package/src/assets/web-panel/assets/{Search-CFNvHalZ.js → Search-_plQ_YSA.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DSoH3Hav.js → Security-CD2YJZfx.js} +4 -4
- package/src/assets/web-panel/assets/{Services-BHpfEmBQ.js → Services-qQE7NmwE.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-Dsh-QNmn.js → Skeleton-DgQqkFf7.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-BhT1NkSU.js → Skills-C4C0oFFt.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-DY9snPeJ.js → Sla-Px2N2B5c.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-CWaX0_Cx.js → SpeechSettings-DN6C3lQd.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-B690y_TC.js → SyncSettings-jm5aH_m7.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-2N-w3zWd.js → Tasks-DlkJcv67.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-BjwQOQYC.js → Templates-DyrTHUBs.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CUqHErxY.js → Tenant-mC434PtL.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-C13rXvNy.js → Terminal-o0_s3NgK.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-CpbWcya_.js → TimelineRenderer-DAGlAXOw.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BXHLGXYC.js → Tokens-BnulS_bs.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-1e5i65o3.js → Trigger-suQbVXYM.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-FLGqNHs5.js → Trust-DbIJAPo5.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-BbaR_LJB.js → UkeySign-CQNpbIHi.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-NOp4RIov.js → VideoEditing-D8aWCERk.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-B7DW7bG4.js → Wallet-CuLpYfZc.js} +3 -3
- package/src/assets/web-panel/assets/{WebAuthn-BptSUWix.js → WebAuthn-CsfG8ZMc.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-CAJnDOXS.js → WorkflowEditor-BYsEAZbd.js} +1 -1
- package/src/assets/web-panel/assets/{chat-I8LgG1-Z.js → chat-FT4Um3-I.js} +1 -1
- package/src/assets/web-panel/assets/{colors-CWe7SOVD.js → colors-CKbS_Wlt.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-Cx3u3CA3.js → compact-item-CFJtzuJM.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CgD5ArwY.js → createContext-B9kSRW6K.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DJZ0gAMu.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BfQWiXN8.js → hasIn-DR-x0Xpi.js} +1 -1
- package/src/assets/web-panel/assets/{index-DAVy98u7.js → index-7jHr_A_k.js} +1 -1
- package/src/assets/web-panel/assets/{index-DlIyt1qF.js → index-B3ZX81mK.js} +1 -1
- package/src/assets/web-panel/assets/{index-CWZ3REg6.js → index-B7osrXqy.js} +3 -3
- package/src/assets/web-panel/assets/{index-DGMYTN5W.js → index-BGbPnC5x.js} +1 -1
- package/src/assets/web-panel/assets/{index-DFb-XIKy.js → index-BI5hP_qy.js} +1 -1
- package/src/assets/web-panel/assets/{index-CAUnl4Jv.js → index-BK3TiKVq.js} +1 -1
- package/src/assets/web-panel/assets/{index-BUAR7RY-.js → index-BVPU43b1.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cd79NQAx.js → index-BW-t9n-q.js} +1 -1
- package/src/assets/web-panel/assets/{index-BiI-xPRH.js → index-BfFCQHL3.js} +1 -1
- package/src/assets/web-panel/assets/index-Bizb4hkw.js +1 -0
- package/src/assets/web-panel/assets/{index-B6yChzt1.js → index-Bt4fS2eL.js} +1 -1
- package/src/assets/web-panel/assets/{index-e8BM1yY1.js → index-BwR7yc2h.js} +1 -1
- package/src/assets/web-panel/assets/{index-V-kIHzAV.js → index-Bzz0C1BZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bx7BNIRH.js → index-C2JvmYRc.js} +1 -1
- package/src/assets/web-panel/assets/{index-87gMxqhN.js → index-CGaXUsIs.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cy_cCJlr.js → index-CJmIQ9XR.js} +1 -1
- package/src/assets/web-panel/assets/{index-C1UjHdgZ.js → index-C_enk9I_.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bi24S7Dw.js → index-Cr2FLUsD.js} +1 -1
- package/src/assets/web-panel/assets/{index-CcX4FSPf.js → index-CvrCCqJt.js} +1 -1
- package/src/assets/web-panel/assets/{index-DmrdUwzU.js → index-D4LfPvWA.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dcdm_Z2c.js → index-DMGmg497.js} +1 -1
- package/src/assets/web-panel/assets/{index-DCJEY2T0.js → index-DShSkww-.js} +1 -1
- package/src/assets/web-panel/assets/{index-C0ztiqtB.js → index-DTxNy0ZU.js} +1 -1
- package/src/assets/web-panel/assets/{index-C-rIKccl.js → index-DW4BWjTk.js} +1 -1
- package/src/assets/web-panel/assets/{index-CdRkCwm4.js → index-DWdqx7zI.js} +1 -1
- package/src/assets/web-panel/assets/{index-C0nDKhWv.js → index-Dap9c3eD.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQDKYbnv.js → index-DcfxhKXR.js} +1 -1
- package/src/assets/web-panel/assets/{index-BuEQSorC.js → index-DdkIhfi-.js} +1 -1
- package/src/assets/web-panel/assets/{index-3iKP9OTJ.js → index-DeSgw-WV.js} +1 -1
- package/src/assets/web-panel/assets/{index-Doc0Ftpd.js → index-DiNUEpSQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BREnPKGo.js → index-DjEP7WkH.js} +1 -1
- package/src/assets/web-panel/assets/{index-CNYFQxAW.js → index-DtkFqPVA.js} +1 -1
- package/src/assets/web-panel/assets/{index-DslTuqro.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-CMu16vPC.js → index-OSzjTzGM.js} +1 -1
- package/src/assets/web-panel/assets/{index-DsQcURkA.js → index-QBSeNVO3.js} +1 -1
- package/src/assets/web-panel/assets/{index-DeizoQVZ.js → index-WE08gMJP.js} +1 -1
- package/src/assets/web-panel/assets/{index-B1cX4Rxu.js → index-r2VI1Ikk.js} +1 -1
- package/src/assets/web-panel/assets/{index-DmgtY58H.js → index-tqSEHPRT.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-DiBszVdG.js → initDefaultProps-Dd7n7VgI.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BGIFFozv.js → motion-BwxouRw1.js} +1 -1
- package/src/assets/web-panel/assets/{move-D5W7mp7B.js → move-DObN0PG9.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-JFIlxJ7F.js → mtc-parser-B3nOUQc7.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CQ3o6LIU.js → omit-o9WU2Nbl.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-R8MIlXo3.js → pickAttrs-CL_vvfQ_.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-sW7ylSky.js → placementArrow-CYrM2tyK.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-Cnl39Vbz.js → responsiveObserve-k_06cQ96.js} +1 -1
- package/src/assets/web-panel/assets/{slide-sn8tFd14.js → slide-CPKG0pxS.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-IKKY_QxZ.js → statusUtils-BDDEeLTw.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BNpV4Nqs.js → styleChecker-Cmb7RTh7.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-BWyT_eoU.js → useFlexGapSupport-e2IedC4N.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-D09p6_U9.js → useFs-CE_gxVnm.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-CzW3TkJZ.js → usePersonalDataHub-BkMIIKMz.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-3s3WoAKB.js → vnode-DW886XV1.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-Cjy_673s.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 +13 -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/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/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/assets/web-panel/assets/ChatBubbleRenderer-D7tcdDS9.js +0 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-SVLOg49H.js +0 -1
- package/src/assets/web-panel/assets/MobileProjects-DGbP36-3.js +0 -1
- package/src/assets/web-panel/assets/Projects-CF-yD6Cn.js +0 -1
- package/src/assets/web-panel/assets/Providers-D-etEhg5.js +0 -1
- package/src/assets/web-panel/assets/devWarning-DLv_872g.js +0 -1
- package/src/assets/web-panel/assets/index-CdiGCibe.js +0 -1
- package/src/assets/web-panel/assets/index-D_0z-gyz.js +0 -1
|
@@ -24,6 +24,7 @@ import fs from "fs";
|
|
|
24
24
|
import os from "os";
|
|
25
25
|
import path from "path";
|
|
26
26
|
import crypto from "crypto";
|
|
27
|
+
import { withFileLock } from "./with-file-lock.js";
|
|
27
28
|
|
|
28
29
|
export const ARTIFACT_KINDS = Object.freeze([
|
|
29
30
|
"report",
|
|
@@ -62,6 +63,7 @@ export function publicArtifactMetadata(entry) {
|
|
|
62
63
|
expiresAt,
|
|
63
64
|
immutable,
|
|
64
65
|
recordDigest,
|
|
66
|
+
lineage,
|
|
65
67
|
} = entry;
|
|
66
68
|
return {
|
|
67
69
|
id,
|
|
@@ -76,6 +78,7 @@ export function publicArtifactMetadata(entry) {
|
|
|
76
78
|
expiresAt,
|
|
77
79
|
immutable: immutable === true,
|
|
78
80
|
recordDigest: recordDigest || null,
|
|
81
|
+
...(lineage ? { lineage } : {}),
|
|
79
82
|
};
|
|
80
83
|
}
|
|
81
84
|
|
|
@@ -120,10 +123,36 @@ function normalizeKind(kind) {
|
|
|
120
123
|
return ARTIFACT_KINDS.includes(k) ? k : "other";
|
|
121
124
|
}
|
|
122
125
|
|
|
126
|
+
function normalizeLineage(lineage) {
|
|
127
|
+
if (lineage == null) return null;
|
|
128
|
+
if (typeof lineage !== "object" || Array.isArray(lineage)) {
|
|
129
|
+
throw new Error("artifact lineage must be an object");
|
|
130
|
+
}
|
|
131
|
+
let normalized;
|
|
132
|
+
try {
|
|
133
|
+
normalized = JSON.parse(JSON.stringify(lineage));
|
|
134
|
+
} catch {
|
|
135
|
+
throw new Error("artifact lineage must be JSON serializable");
|
|
136
|
+
}
|
|
137
|
+
if (
|
|
138
|
+
!normalized ||
|
|
139
|
+
typeof normalized !== "object" ||
|
|
140
|
+
Array.isArray(normalized)
|
|
141
|
+
) {
|
|
142
|
+
throw new Error("artifact lineage must be a JSON object");
|
|
143
|
+
}
|
|
144
|
+
return normalized;
|
|
145
|
+
}
|
|
146
|
+
|
|
123
147
|
export class ArtifactStore {
|
|
124
|
-
constructor({
|
|
148
|
+
constructor({
|
|
149
|
+
dir = null,
|
|
150
|
+
now = () => Date.now(),
|
|
151
|
+
indexLock = withFileLock,
|
|
152
|
+
} = {}) {
|
|
125
153
|
this.dir = dir || artifactsDir();
|
|
126
154
|
this._now = typeof now === "function" ? now : () => now;
|
|
155
|
+
this._indexLock = indexLock;
|
|
127
156
|
}
|
|
128
157
|
|
|
129
158
|
_indexFile() {
|
|
@@ -138,6 +167,31 @@ export class ArtifactStore {
|
|
|
138
167
|
fs.mkdirSync(this._filesDir(), { recursive: true });
|
|
139
168
|
}
|
|
140
169
|
|
|
170
|
+
_withIndexLock(callback) {
|
|
171
|
+
this._ensureDirs();
|
|
172
|
+
return this._indexLock(this._indexFile(), callback, {
|
|
173
|
+
failIfUnavailable: true,
|
|
174
|
+
timeoutMs: 30_000,
|
|
175
|
+
retryMs: 1,
|
|
176
|
+
maxRetryMs: 8,
|
|
177
|
+
retryJitterMs: 4,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Run a read-only callback against one locked index generation. The callback
|
|
183
|
+
* may inspect stored bytes before it returns; all ArtifactStore mutations use
|
|
184
|
+
* this same lock and therefore cannot replace that generation mid-read.
|
|
185
|
+
*/
|
|
186
|
+
withIndexSnapshot(callback) {
|
|
187
|
+
if (typeof callback !== "function") {
|
|
188
|
+
throw new TypeError("artifact index snapshot requires a callback");
|
|
189
|
+
}
|
|
190
|
+
return this._withIndexLock(() =>
|
|
191
|
+
callback(Object.freeze(this._readEntries())),
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
141
195
|
/**
|
|
142
196
|
* Publish a file as an artifact (copy + metadata row).
|
|
143
197
|
* @param {{ filePath: string, title?: string, kind?: string,
|
|
@@ -162,14 +216,16 @@ export class ArtifactStore {
|
|
|
162
216
|
);
|
|
163
217
|
}
|
|
164
218
|
const body = fs.readFileSync(abs);
|
|
165
|
-
return this.
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
219
|
+
return this._withIndexLock(() =>
|
|
220
|
+
this._publishDataUnlocked(body, {
|
|
221
|
+
fileName: path.basename(abs),
|
|
222
|
+
title,
|
|
223
|
+
kind,
|
|
224
|
+
sessionId,
|
|
225
|
+
ttlDays,
|
|
226
|
+
sourcePath: abs,
|
|
227
|
+
}),
|
|
228
|
+
);
|
|
173
229
|
}
|
|
174
230
|
|
|
175
231
|
/**
|
|
@@ -191,20 +247,78 @@ export class ArtifactStore {
|
|
|
191
247
|
if (typeof data !== "string" && !Buffer.isBuffer(data)) {
|
|
192
248
|
throw new Error("publishData requires string or Buffer data");
|
|
193
249
|
}
|
|
194
|
-
return this.
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
250
|
+
return this._withIndexLock(() =>
|
|
251
|
+
this._publishDataUnlocked(Buffer.from(data), {
|
|
252
|
+
fileName,
|
|
253
|
+
title,
|
|
254
|
+
kind,
|
|
255
|
+
mime,
|
|
256
|
+
sessionId,
|
|
257
|
+
ttlDays,
|
|
258
|
+
immutable,
|
|
259
|
+
recordDigest,
|
|
260
|
+
sourcePath: null,
|
|
261
|
+
}),
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Publish generated bytes once for a stable authority digest.
|
|
267
|
+
*
|
|
268
|
+
* The strict cross-process index lock makes response-loss retries return the
|
|
269
|
+
* same metadata row instead of creating duplicate managed artifacts. The
|
|
270
|
+
* caller still owns the semantic validation of the persisted lineage and
|
|
271
|
+
* must verifyIntegrity() before treating the returned entry as readable.
|
|
272
|
+
*/
|
|
273
|
+
publishDataOnce({
|
|
274
|
+
data,
|
|
275
|
+
fileName = "artifact.bin",
|
|
276
|
+
title,
|
|
277
|
+
kind,
|
|
278
|
+
mime,
|
|
279
|
+
sessionId = null,
|
|
280
|
+
ttlDays,
|
|
281
|
+
immutable = false,
|
|
282
|
+
recordDigest,
|
|
283
|
+
lineage,
|
|
284
|
+
} = {}) {
|
|
285
|
+
if (typeof data !== "string" && !Buffer.isBuffer(data)) {
|
|
286
|
+
throw new Error("publishDataOnce requires string or Buffer data");
|
|
287
|
+
}
|
|
288
|
+
const stableDigest = String(recordDigest || "");
|
|
289
|
+
if (!/^sha256:[a-f0-9]{64}$/u.test(stableDigest)) {
|
|
290
|
+
throw new Error("publishDataOnce requires a canonical recordDigest");
|
|
291
|
+
}
|
|
292
|
+
const normalizedLineage = normalizeLineage(lineage);
|
|
293
|
+
return this._withIndexLock(() => {
|
|
294
|
+
const matches = this._readEntries().filter(
|
|
295
|
+
(entry) => entry.recordDigest === stableDigest,
|
|
296
|
+
);
|
|
297
|
+
if (matches.length > 1) {
|
|
298
|
+
throw new Error(
|
|
299
|
+
`artifact authority ${stableDigest} has duplicate index rows`,
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
if (matches.length === 1) {
|
|
303
|
+
return Object.freeze({ entry: matches[0], published: false });
|
|
304
|
+
}
|
|
305
|
+
const entry = this._publishDataUnlocked(Buffer.from(data), {
|
|
306
|
+
fileName,
|
|
307
|
+
title,
|
|
308
|
+
kind,
|
|
309
|
+
mime,
|
|
310
|
+
sessionId,
|
|
311
|
+
ttlDays,
|
|
312
|
+
immutable,
|
|
313
|
+
recordDigest: stableDigest,
|
|
314
|
+
lineage: normalizedLineage,
|
|
315
|
+
sourcePath: null,
|
|
316
|
+
});
|
|
317
|
+
return Object.freeze({ entry, published: true });
|
|
204
318
|
});
|
|
205
319
|
}
|
|
206
320
|
|
|
207
|
-
|
|
321
|
+
_publishDataUnlocked(
|
|
208
322
|
body,
|
|
209
323
|
{
|
|
210
324
|
fileName,
|
|
@@ -215,6 +329,7 @@ export class ArtifactStore {
|
|
|
215
329
|
ttlDays,
|
|
216
330
|
immutable = false,
|
|
217
331
|
recordDigest = null,
|
|
332
|
+
lineage = null,
|
|
218
333
|
sourcePath = null,
|
|
219
334
|
},
|
|
220
335
|
) {
|
|
@@ -247,10 +362,15 @@ export class ArtifactStore {
|
|
|
247
362
|
expiresAt: new Date(createdAt + days * 24 * 60 * 60 * 1000).toISOString(),
|
|
248
363
|
immutable: immutable === true,
|
|
249
364
|
recordDigest: recordDigest ? String(recordDigest) : null,
|
|
365
|
+
...(lineage ? { lineage: normalizeLineage(lineage) } : {}),
|
|
250
366
|
};
|
|
251
367
|
this._ensureDirs();
|
|
252
368
|
const storedPath = path.join(this._filesDir(), entry.file);
|
|
253
|
-
fs.writeFileSync(storedPath, body, {
|
|
369
|
+
fs.writeFileSync(storedPath, body, {
|
|
370
|
+
flag: "wx",
|
|
371
|
+
mode: 0o600,
|
|
372
|
+
flush: true,
|
|
373
|
+
});
|
|
254
374
|
if (entry.immutable) {
|
|
255
375
|
try {
|
|
256
376
|
fs.chmodSync(storedPath, 0o444);
|
|
@@ -259,12 +379,37 @@ export class ArtifactStore {
|
|
|
259
379
|
// support; immutable here means append-only/no update API, not WORM.
|
|
260
380
|
}
|
|
261
381
|
}
|
|
262
|
-
|
|
382
|
+
let descriptor = null;
|
|
383
|
+
try {
|
|
384
|
+
descriptor = fs.openSync(
|
|
385
|
+
this._indexFile(),
|
|
386
|
+
fs.constants.O_WRONLY |
|
|
387
|
+
fs.constants.O_APPEND |
|
|
388
|
+
fs.constants.O_CREAT |
|
|
389
|
+
Number(fs.constants.O_NOFOLLOW || 0),
|
|
390
|
+
0o600,
|
|
391
|
+
);
|
|
392
|
+
const indexStat = fs.fstatSync(descriptor);
|
|
393
|
+
if (!indexStat.isFile() || Number(indexStat.nlink) !== 1) {
|
|
394
|
+
throw new Error("artifact index identity is invalid");
|
|
395
|
+
}
|
|
396
|
+
fs.writeFileSync(descriptor, `${JSON.stringify(entry)}\n`, "utf-8");
|
|
397
|
+
fs.fsyncSync(descriptor);
|
|
398
|
+
} catch (error) {
|
|
399
|
+
try {
|
|
400
|
+
this._deleteStoredFile(entry);
|
|
401
|
+
} catch {
|
|
402
|
+
/* best-effort rollback of an unpublished stored copy */
|
|
403
|
+
}
|
|
404
|
+
throw error;
|
|
405
|
+
} finally {
|
|
406
|
+
if (descriptor !== null) fs.closeSync(descriptor);
|
|
407
|
+
}
|
|
263
408
|
return entry;
|
|
264
409
|
}
|
|
265
410
|
|
|
266
411
|
/** All (non-corrupt) metadata rows, oldest first. */
|
|
267
|
-
|
|
412
|
+
_readEntries({ sessionId } = {}) {
|
|
268
413
|
let raw;
|
|
269
414
|
try {
|
|
270
415
|
raw = fs.readFileSync(this._indexFile(), "utf-8");
|
|
@@ -285,6 +430,10 @@ export class ArtifactStore {
|
|
|
285
430
|
return sessionId ? out.filter((e) => e.sessionId === sessionId) : out;
|
|
286
431
|
}
|
|
287
432
|
|
|
433
|
+
list(options = {}) {
|
|
434
|
+
return this._withIndexLock(() => this._readEntries(options));
|
|
435
|
+
}
|
|
436
|
+
|
|
288
437
|
/** One entry by id (or null). */
|
|
289
438
|
get(id) {
|
|
290
439
|
return this.list().find((e) => e.id === id) || null;
|
|
@@ -348,47 +497,103 @@ export class ArtifactStore {
|
|
|
348
497
|
|
|
349
498
|
/** Remove one artifact (file + index row). @returns {boolean} found */
|
|
350
499
|
remove(id) {
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
500
|
+
return this._withIndexLock(() => {
|
|
501
|
+
const entries = this._readEntries();
|
|
502
|
+
const matches = entries.filter((entry) => entry.id === id);
|
|
503
|
+
if (matches.length === 0) return false;
|
|
504
|
+
if (matches.length > 1) {
|
|
505
|
+
throw new Error(`artifact id ${id} has duplicate index rows`);
|
|
506
|
+
}
|
|
507
|
+
const target = matches[0];
|
|
508
|
+
this._rewriteUnlocked(entries.filter((entry) => entry.id !== id));
|
|
509
|
+
try {
|
|
510
|
+
this._deleteStoredFile(target);
|
|
511
|
+
} catch {
|
|
512
|
+
/* best-effort — the locked index generation is the source of truth */
|
|
513
|
+
}
|
|
514
|
+
return true;
|
|
515
|
+
});
|
|
361
516
|
}
|
|
362
517
|
|
|
363
518
|
/**
|
|
364
|
-
*
|
|
519
|
+
* Low-level legacy primitive for removing expired artifacts.
|
|
520
|
+
* Official CLI and WebSocket callers must use artifact cleanup settlement so
|
|
521
|
+
* retries preserve a frozen scope and leave content-free audit evidence.
|
|
365
522
|
* @returns {{ removed: number }}
|
|
366
523
|
*/
|
|
367
524
|
cleanupExpired() {
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
const
|
|
374
|
-
|
|
525
|
+
return this._withIndexLock(() => {
|
|
526
|
+
const entries = this._readEntries();
|
|
527
|
+
const now = this._now();
|
|
528
|
+
const keep = [];
|
|
529
|
+
const expired = [];
|
|
530
|
+
for (const entry of entries) {
|
|
531
|
+
const exp = Date.parse(entry.expiresAt || "");
|
|
532
|
+
if (Number.isFinite(exp) && exp <= now) {
|
|
533
|
+
expired.push(entry);
|
|
534
|
+
} else {
|
|
535
|
+
keep.push(entry);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
if (expired.length > 0) this._rewriteUnlocked(keep);
|
|
539
|
+
for (const entry of expired) {
|
|
375
540
|
try {
|
|
376
|
-
this._deleteStoredFile(
|
|
541
|
+
this._deleteStoredFile(entry);
|
|
377
542
|
} catch {
|
|
378
|
-
/* best-effort */
|
|
543
|
+
/* best-effort — the locked index generation is the source of truth */
|
|
379
544
|
}
|
|
380
|
-
removed += 1;
|
|
381
|
-
} else {
|
|
382
|
-
keep.push(e);
|
|
383
545
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
return { removed };
|
|
546
|
+
return { removed: expired.length };
|
|
547
|
+
});
|
|
387
548
|
}
|
|
388
549
|
|
|
389
|
-
|
|
550
|
+
_rewriteUnlocked(entries) {
|
|
390
551
|
this._ensureDirs();
|
|
391
552
|
const text = entries.map((e) => JSON.stringify(e)).join("\n");
|
|
392
|
-
|
|
553
|
+
const indexFile = this._indexFile();
|
|
554
|
+
const temporary = `${indexFile}.${process.pid}.${crypto
|
|
555
|
+
.randomBytes(8)
|
|
556
|
+
.toString("hex")}.tmp`;
|
|
557
|
+
let descriptor = null;
|
|
558
|
+
try {
|
|
559
|
+
descriptor = fs.openSync(
|
|
560
|
+
temporary,
|
|
561
|
+
fs.constants.O_WRONLY |
|
|
562
|
+
fs.constants.O_CREAT |
|
|
563
|
+
fs.constants.O_EXCL |
|
|
564
|
+
Number(fs.constants.O_NOFOLLOW || 0),
|
|
565
|
+
0o600,
|
|
566
|
+
);
|
|
567
|
+
fs.writeFileSync(descriptor, text ? `${text}\n` : "", "utf-8");
|
|
568
|
+
fs.fsyncSync(descriptor);
|
|
569
|
+
fs.closeSync(descriptor);
|
|
570
|
+
descriptor = null;
|
|
571
|
+
fs.renameSync(temporary, indexFile);
|
|
572
|
+
this._syncIndexDirectory();
|
|
573
|
+
} finally {
|
|
574
|
+
if (descriptor !== null) fs.closeSync(descriptor);
|
|
575
|
+
try {
|
|
576
|
+
fs.rmSync(temporary, { force: true });
|
|
577
|
+
} catch {
|
|
578
|
+
/* best-effort cleanup of an unpublished index generation */
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
_syncIndexDirectory() {
|
|
584
|
+
let descriptor = null;
|
|
585
|
+
try {
|
|
586
|
+
descriptor = fs.openSync(this.dir, "r");
|
|
587
|
+
fs.fsyncSync(descriptor);
|
|
588
|
+
} catch (error) {
|
|
589
|
+
if (
|
|
590
|
+
process.platform !== "win32" ||
|
|
591
|
+
!["EACCES", "EINVAL", "ENOTSUP", "EPERM"].includes(error?.code)
|
|
592
|
+
) {
|
|
593
|
+
throw error;
|
|
594
|
+
}
|
|
595
|
+
} finally {
|
|
596
|
+
if (descriptor !== null) fs.closeSync(descriptor);
|
|
597
|
+
}
|
|
393
598
|
}
|
|
394
599
|
}
|
|
@@ -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
|