chainlesschain 0.162.197 → 0.162.200
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/bin/chainlesschain.js +14 -6
- package/package.json +4 -1
- package/scripts/command-lifecycle-report.mjs +94 -0
- package/src/assets/web-panel/assets/{AIOps-D3Gu1a5d.js → AIOps-DcQ0bWKy.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DrwAoKaz.js → ActionButton-GecwfFPt.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-C7Q-gd_3.js → Analytics-CD6iSt9v.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DgBtae-n.js → AppLayout-CDEtuEYf.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-pQ6LcA-W.js → Artifacts-DS3jAjeW.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-DK61tocB.js → Audit-CcSJA048.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BOKgDFRh.js → BackgroundAgents-DRo9Morb.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-Bo9G4vTP.js → Backup-Vw5MrWft.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-Do_dE9_v.js → BaseInput-DNHIu823.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-COVvZzOL.js → Chat-DvAsO8-b.js} +4 -4
- package/src/assets/web-panel/assets/ChatBubbleRenderer-9aDuObay.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-Z9MJMolt.js → Checkbox-CKCa7tvn.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BVzWKVbf.js → Codegen-CIFvZdaT.js} +1 -1
- package/src/assets/web-panel/assets/{Col-C8MnYcbT.js → Col-C79yz7bK.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DQxqw15l.js → Community-DVvZskLJ.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BAUmrh3y.js → Compact-oaew61hV.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-jPAkQ3zK.js → Compliance-DqA7wmRx.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BBQyxbh8.js → Cowork-B-qGadxa.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-W5koq8Z5.js → Cron-CUlCl4sS.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BQhnu5hS.js → Crosschain-CNOlr9DU.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DD7PlI18.js → DID-DJqFCT_3.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-w_ILuwKI.js → Dashboard-CznGpphf.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-qiDUAyAo.js → Dropdown-_cJw218E.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-PDeBcI5H.js → EmailListRenderer-Dr-1BZ9C.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-SuArscRM.js → FamilyGuardDashboard-Dxf4xtSk.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BCovZaUn.js → Federation-DOiG3i_1.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DjlFdVFk.js → FormItemContext-BzbMcFB9.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DoEZ7fcS.js → GenericCardRenderer-VbBrYttP.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CV0-6GPI.js → Git-CLG8E6ED.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-B_SFN50w.js → Governance-LGJQfk_q.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-heI0Eo6k.js → Inference-DlQKx9lF.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-Cz5INS5p.js → KnowledgeGraph-DU8vEouV.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BSFxiHkg.js → Logs-FZIQOdln.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-BJNWIrbw.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-0TWTpE7k.js → Marketplace-C_xd-zZI.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-CV4-wBLm.js → McpTools-q-YktphS.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-x5bH5rw5.js → Memory-Cq9OhDin.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DaBmUu9G.js → MobileBridge-B03_R98T.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-DZrk-qmF.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-B_zKEBif.js → Mtc-BidCKW28.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-BCfKD2yg.js → MtcAudit-r-iaMVM7.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-DgYfj6c_.js → Multisig-CgTUFvff.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-Dz09lFUm.js → NLProgramming-B7NvzfAV.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-Cuj6ugBE.js → Notes-80CWNqJI.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-DK2WXjhg.js → NotificationSettings-0H6xdiY3.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-D1IAOQoo.js → OrderTableRenderer-CKP4AFWy.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-9fqnPvTw.js → Organization-B8sxCV_h.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-n5xHkhow.js → Overflow-CW9JBBhQ.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-B5AUWwH-.js → P2P-bdSQV7oZ.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-CoUDV6dy.js → PdhVaultBrowser-DQad42nW.js} +4 -4
- package/src/assets/web-panel/assets/{Permissions-DPRmQf_H.js → Permissions-CueexxTR.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-B37bsbEN.js → PersonalDataHub-fqxflhR8.js} +6 -6
- package/src/assets/web-panel/assets/{Pipeline-CCAuPqu9.js → Pipeline-KFwwnIMC.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-B81msZdv.js → Privacy-ClnD9buY.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-B-Py2NbF.js → ProjectInit-CZEz6sm3.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CYsneiRB.js → ProjectSettings-B6NzpmOI.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-Y975Mh6R.js → Projects-DYyuwPCs.js} +1 -1
- package/src/assets/web-panel/assets/Providers-C3tz_jdh.js +1 -0
- package/src/assets/web-panel/assets/{QrScannerModal-Bj_6gJ0l.js → QrScannerModal-BzuOBbqB.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BgpBCMPE.js → QuickAsk-CmNO9qSj.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DhUW3YUA.js → Recommend-VJNj3_NF.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-DdeyfbkA.js → RemoteSession-CrbdbSBF.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-fxW421xd.js → Reputation-DTyMd45j.js} +1 -1
- package/src/assets/web-panel/assets/{Row-De73w1og.js → Row-DHrQ-Icz.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-3US_Q_lj.js → RssFeed-DqWxY9c5.js} +2 -2
- package/src/assets/web-panel/assets/{Search-DbZ_DU74.js → Search-ctF1Ks3J.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DoIU1vMF.js → Security-BrQz8uo5.js} +4 -4
- package/src/assets/web-panel/assets/{Services-DB_RGqpc.js → Services-D4scVFar.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DnzLaayC.js → Skeleton-oUScaOjv.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-VzVXHENF.js → Skills-CL-y0eLt.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-DMfvjCAI.js → Sla-DQExhwXj.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-DQQOYWbF.js → SpeechSettings-iNp_I7kN.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-Bmx3FG1P.js → SyncSettings-CTDlMo0A.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-DOQyfb-2.js → Tasks-4kb8l3sc.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-D6hTRT7c.js → Templates-BXcL9oXW.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CTPQZAzs.js → Tenant-DLE8eS0D.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-B7vII3oH.js → Terminal-DGpUZPPK.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-BkiFJeXV.js → TimelineRenderer-C1pWXGPC.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-BPPdQMNo.js → Tokens-BYfbfqhZ.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BxG8JAEI.js → Trigger-K9YfLOCw.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-DHD7nMpM.js → Trust-Ctkq77Hy.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-B4BJpU47.js → UkeySign-C6_CSe9J.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-CRiGpFx2.js → VideoEditing-Be3rpOWs.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BSDSNiem.js → Wallet-D0UIplxk.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DLTUh5Zv.js → WebAuthn-CF9bM9I3.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-tW2MwjhD.js → WorkflowEditor-D0H1XVPY.js} +1 -1
- package/src/assets/web-panel/assets/{chat-SgsLQ3FC.js → chat-Cgzzbe0o.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BHjjLIKO.js → colors-BwNxEVS0.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-VceErdKq.js → compact-item-D60Z4Hhs.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BZ332MYl.js → createContext-MFk58XB0.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BJiw369i.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CBTjJOjn.js → hasIn-CRj2SvGO.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaCCy6lq.js → index--s45_1cb.js} +1 -1
- package/src/assets/web-panel/assets/{index-CMVvxIS8.js → index--tquQ2ZG.js} +1 -1
- package/src/assets/web-panel/assets/{index-BhXZEUAc.js → index-1T1rhokn.js} +1 -1
- package/src/assets/web-panel/assets/{index-BQSmZGgs.js → index-B-M82_rx.js} +1 -1
- package/src/assets/web-panel/assets/{index-BeiqkxJG.js → index-BE_el1Zs.js} +1 -1
- package/src/assets/web-panel/assets/{index-29wVzi-k.js → index-BhRkR7IO.js} +1 -1
- package/src/assets/web-panel/assets/{index-iYQNU9za.js → index-Bo0y96-K.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRWhLbWF.js → index-CJgu5JUK.js} +1 -1
- package/src/assets/web-panel/assets/{index-BPXFLYdW.js → index-CLWwdebO.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cr4rjlW5.js → index-CNAK5QG_.js} +1 -1
- package/src/assets/web-panel/assets/{index-CaIS_TNX.js → index-CQjJjPRD.js} +1 -1
- package/src/assets/web-panel/assets/{index-1n7xjKDU.js → index-CTDbAfae.js} +1 -1
- package/src/assets/web-panel/assets/{index-BETEjuNr.js → index-CVI_9sRK.js} +1 -1
- package/src/assets/web-panel/assets/{index-By5jBtkV.js → index-CY14oMQK.js} +1 -1
- package/src/assets/web-panel/assets/{index-DgPvuIn2.js → index-CbiTJkZf.js} +1 -1
- package/src/assets/web-panel/assets/index-CiMouosn.js +1 -0
- package/src/assets/web-panel/assets/{index-CawpdGTW.js → index-CqWpxMqx.js} +1 -1
- package/src/assets/web-panel/assets/{index-_PHrIO4O.js → index-CvB8lYUR.js} +1 -1
- package/src/assets/web-panel/assets/{index-BOtvPdHt.js → index-D51XwtCY.js} +1 -1
- package/src/assets/web-panel/assets/{index-CrUgDQkf.js → index-D6HvK_1O.js} +1 -1
- package/src/assets/web-panel/assets/{index-BY1wexYG.js → index-D9jVIwLJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-C_B9rFQE.js → index-DA4tE98u.js} +1 -1
- package/src/assets/web-panel/assets/{index-B5KAGxNo.js → index-DBwOtXw0.js} +1 -1
- package/src/assets/web-panel/assets/{index-BC1xuQgX.js → index-DKdNzTIb.js} +1 -1
- package/src/assets/web-panel/assets/{index-B2u26AS3.js → index-DRySdmvN.js} +1 -1
- package/src/assets/web-panel/assets/{index-DePOeMDM.js → index-DWzyTev7.js} +1 -1
- package/src/assets/web-panel/assets/index-DXcKlwy7.js +1 -0
- package/src/assets/web-panel/assets/{index-BTlc-Bve.js → index-DYjs7jAP.js} +1 -1
- package/src/assets/web-panel/assets/{index-CLc19alH.js → index-DbROzMBp.js} +1 -1
- package/src/assets/web-panel/assets/{index-fU7wNHDB.js → index-DhFtk5PR.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_SePDWj.js → index-Di2AbMLg.js} +1 -1
- package/src/assets/web-panel/assets/{index-vIXOpcjD.js → index-DvmocQsM.js} +1 -1
- package/src/assets/web-panel/assets/{index-BcUenmCX.js → index-Dw-o0zEF.js} +1 -1
- package/src/assets/web-panel/assets/{index-DUkVN794.js → index-DysPoP38.js} +1 -1
- package/src/assets/web-panel/assets/{index-CtjLcCNU.js → index-LX9pJxm_.js} +1 -1
- package/src/assets/web-panel/assets/{index-B40dQn0G.js → index-OI_fXWx0.js} +3 -3
- package/src/assets/web-panel/assets/{index-FJ3zC9LK.js → index-eDTOX8Xj.js} +1 -1
- package/src/assets/web-panel/assets/{index-DdefYBSw.js → index-gWKDsTzF.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpumS98o.js → index-q_GDUVAA.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-D1oZNz0D.js → initDefaultProps-C61kZqEd.js} +1 -1
- package/src/assets/web-panel/assets/{motion-C8k6doMO.js → motion-DZnT5U1L.js} +1 -1
- package/src/assets/web-panel/assets/{move-DJ4qSbYt.js → move-L8wzwbel.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-CdpJD85j.js → mtc-parser-DLdYSejc.js} +1 -1
- package/src/assets/web-panel/assets/{omit-B0V4slKA.js → omit-D53cbS59.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-Di5NiW1F.js → pickAttrs-Bbc5HPtu.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-B5OMHgEM.js → placementArrow-BkvmO860.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-C6U9IWql.js → responsiveObserve-u2y1ryS1.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BMyTH3rN.js → slide-BBqj7svU.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-C7d6BG7Z.js → statusUtils-GN0mqu2d.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-CR50QnQy.js → styleChecker-BvwPKoBT.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DBEeoMb8.js → useFlexGapSupport-CCt8tnfY.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-3r099cjv.js → useFs-DXAxl2SV.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-C5IYNdTK.js → usePersonalDataHub-DihlR2dj.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-DmEOLRHf.js → vnode-D7BOX2gi.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DnpUiVCB.js → zoom-CVbO-nL7.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +4 -4
- package/src/commands/agent.js +3 -3
- package/src/commands/background-session.js +145 -0
- package/src/commands/mcp.js +244 -7
- package/src/commands/serve.js +1 -1
- package/src/commands/session-show.js +129 -0
- package/src/commands/session.js +97 -145
- package/src/commands/skill.js +87 -50
- package/src/data/changelog.json +40 -1
- package/src/gateways/ws/session-protocol.js +14 -4
- package/src/gateways/ws/ws-agent-handler.js +39 -1
- package/src/harness/jsonl-session-store.js +1547 -127
- package/src/harness/mcp-client.js +2690 -409
- package/src/harness/session-index.js +80 -80
- package/src/harness/session-list-index.js +210 -7
- package/src/lazy-dispatch.js +76 -8
- package/src/lib/abort-utils.js +68 -0
- package/src/lib/agent-core.js +1 -59
- package/src/lib/background-interaction-journal.js +2 -2
- package/src/lib/chat-core.js +24 -6
- package/src/lib/command-lifecycle-report.js +516 -0
- package/src/lib/cowork-mcp-tools.js +47 -2
- package/src/lib/cowork-task-runner.js +11 -3
- package/src/lib/doctor-checkup.js +9 -7
- package/src/lib/learning/skill-improver.js +21 -2
- package/src/lib/mcp-call-ledger-store.js +116 -3
- package/src/lib/mcp-call-ledger.js +59 -14
- package/src/lib/mcp-client.js +1 -0
- package/src/lib/mcp-stdio-environment.js +48 -0
- package/src/lib/mcp-stdio-executable-identity.js +1133 -0
- package/src/lib/mcp-stdio-execution-authority.js +363 -0
- package/src/lib/mcp-stdio-package-materialization.js +1424 -0
- package/src/lib/mcp-tool-metadata.js +436 -0
- package/src/lib/mcp-tool-result.js +367 -0
- package/src/lib/observability/index.js +71 -0
- package/src/lib/packer/native-update-state.js +979 -1
- package/src/lib/packer/pack-update-applier.js +1050 -125
- package/src/lib/packer/pkg-config-generator.js +1 -0
- package/src/lib/paths.js +53 -0
- package/src/lib/pr-link-ledger.js +8 -27
- package/src/lib/pr-link-store.js +26 -0
- package/src/lib/process-execution-broker/index.js +192 -35
- package/src/lib/process-execution-broker/platform-sandbox.js +291 -24
- package/src/lib/process-tree-termination.js +253 -0
- package/src/lib/recent-session.js +17 -17
- package/src/lib/secure-file-identity.js +47 -0
- package/src/lib/secure-fs.js +21 -2
- package/src/lib/session-anti-rollback-anchor.js +766 -0
- package/src/lib/session-host-lease.js +492 -0
- package/src/lib/session-host-snapshot.js +9 -5
- package/src/lib/session-persistence-failure.js +109 -0
- package/src/lib/session-picker.js +26 -3
- package/src/lib/session-projection.js +5 -1
- package/src/lib/session-search.js +25 -11
- package/src/lib/session-tail.js +31 -1
- package/src/lib/side-effect-ledger-store.js +2 -2
- package/src/lib/skill-budget.js +222 -0
- package/src/lib/skill-execution-authority.js +385 -0
- package/src/lib/skill-execution-identity.js +39 -2
- package/src/lib/skill-loader.js +322 -86
- package/src/lib/skill-mcp.js +43 -1
- package/src/lib/turn-binding-store.js +2 -2
- package/src/repl/agent-repl.js +483 -77
- package/src/repl/bg-dashboard.js +81 -28
- package/src/repl/chat-repl.js +77 -12
- package/src/runtime/agent-core.js +428 -113
- package/src/runtime/agent-runtime.js +26 -3
- package/src/runtime/cleanup-deadline.js +143 -0
- package/src/runtime/headless-runner.js +494 -149
- package/src/runtime/headless-stream.js +504 -75
- package/src/runtime/mcp-config.js +157 -10
- package/src/runtime/mcp-tool-search.js +0 -0
- package/src/runtime/output-backpressure.js +419 -0
- package/src/runtime/pipe-safety.js +56 -21
- package/src/assets/web-panel/assets/ChatBubbleRenderer-BUUyJ5QO.js +0 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-1mNozZ8v.js +0 -1
- package/src/assets/web-panel/assets/MobileProjects-DqnoFPgR.js +0 -1
- package/src/assets/web-panel/assets/Providers-uO-10aP1.js +0 -1
- package/src/assets/web-panel/assets/devWarning-DosMaL-k.js +0 -1
- package/src/assets/web-panel/assets/index-0O5ePnUq.js +0 -1
- package/src/assets/web-panel/assets/index-ChAzPigF.js +0 -1
- package/src/lib/skill-process-broker.js +0 -85
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
import { executionBroker } from "./process-execution-broker/index.js";
|
|
2
|
+
|
|
3
|
+
export const PROCESS_TREE_CLEANUP_MAX_MS = 2_000;
|
|
4
|
+
export const PROCESS_TREE_GRACE_MAX_MS = 500;
|
|
5
|
+
const TREE_MODES = new Set(["sandbox", "posix-group", "windows-tree"]);
|
|
6
|
+
|
|
7
|
+
function boundedMilliseconds(value, fallback, maximum) {
|
|
8
|
+
const parsed = Number(value);
|
|
9
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return fallback;
|
|
10
|
+
return Math.max(1, Math.min(maximum, Math.floor(parsed)));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function validChildPid(child) {
|
|
14
|
+
const pid = Number(child?.pid);
|
|
15
|
+
return Number.isInteger(pid) && pid > 0 && pid !== process.pid ? pid : null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function childHasClosed(child, observedClose) {
|
|
19
|
+
return (
|
|
20
|
+
observedClose() ||
|
|
21
|
+
(child?.exitCode !== null && child?.exitCode !== undefined) ||
|
|
22
|
+
(child?.signalCode !== null && child?.signalCode !== undefined)
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function posixGroupIsGone(pid, kill) {
|
|
27
|
+
try {
|
|
28
|
+
kill(-pid, 0);
|
|
29
|
+
return false;
|
|
30
|
+
} catch (error) {
|
|
31
|
+
return error?.code === "ESRCH";
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function requestDirectSignal(child, signal) {
|
|
36
|
+
try {
|
|
37
|
+
return child?.kill?.(signal) !== false;
|
|
38
|
+
} catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function requestPosixGroupSignal(child, pid, signal, kill) {
|
|
44
|
+
try {
|
|
45
|
+
kill(-pid, signal);
|
|
46
|
+
return { requested: true, treeRequested: true };
|
|
47
|
+
} catch {
|
|
48
|
+
return {
|
|
49
|
+
requested: requestDirectSignal(child, signal),
|
|
50
|
+
treeRequested: false,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function requestWindowsTreeSignal(child, pid, force, spawnSync, timeoutMs) {
|
|
56
|
+
try {
|
|
57
|
+
const args = ["/PID", String(pid), "/T"];
|
|
58
|
+
if (force) args.push("/F");
|
|
59
|
+
const result = spawnSync("taskkill", args, {
|
|
60
|
+
shell: false,
|
|
61
|
+
windowsHide: true,
|
|
62
|
+
encoding: "utf8",
|
|
63
|
+
timeout: Math.max(1, timeoutMs),
|
|
64
|
+
origin: "process-tree:taskkill",
|
|
65
|
+
policy: "allow",
|
|
66
|
+
scope: "process-tree",
|
|
67
|
+
});
|
|
68
|
+
if (!result?.error && result?.status === 0) {
|
|
69
|
+
return { requested: true, treeRequested: true };
|
|
70
|
+
}
|
|
71
|
+
} catch {
|
|
72
|
+
// Fall through to the hard-phase fallback below.
|
|
73
|
+
}
|
|
74
|
+
// Never kill only the Windows root during the soft phase: doing so can
|
|
75
|
+
// orphan its descendants and make the later `/T /F` walk impossible.
|
|
76
|
+
if (!force) return { requested: false, treeRequested: false };
|
|
77
|
+
return {
|
|
78
|
+
requested: requestDirectSignal(child, "SIGKILL"),
|
|
79
|
+
treeRequested: false,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Retire one Broker-owned child tree inside a host-capped deadline.
|
|
85
|
+
*
|
|
86
|
+
* `treeMode` describes the ownership established at spawn time:
|
|
87
|
+
* - `sandbox`: a PID namespace / Windows Job close fence owns descendants;
|
|
88
|
+
* - `posix-group`: the child is the leader of a detached process group;
|
|
89
|
+
* - `windows-tree`: taskkill walks the live root's descendant tree.
|
|
90
|
+
*
|
|
91
|
+
* The function never throws and never treats a direct-child fallback as proof
|
|
92
|
+
* that descendants are gone. Callers can preserve their primary error while
|
|
93
|
+
* attaching the structured result, or fail closed on an unconfirmed explicit
|
|
94
|
+
* disconnect.
|
|
95
|
+
*/
|
|
96
|
+
export async function terminateOwnedProcessTree(child, options = {}) {
|
|
97
|
+
const platform = options.platform || process.platform;
|
|
98
|
+
const cleanupTimeoutMs = boundedMilliseconds(
|
|
99
|
+
options.cleanupTimeoutMs,
|
|
100
|
+
PROCESS_TREE_CLEANUP_MAX_MS,
|
|
101
|
+
PROCESS_TREE_CLEANUP_MAX_MS,
|
|
102
|
+
);
|
|
103
|
+
const graceMs = Math.min(
|
|
104
|
+
cleanupTimeoutMs,
|
|
105
|
+
boundedMilliseconds(options.graceMs, 250, PROCESS_TREE_GRACE_MAX_MS),
|
|
106
|
+
);
|
|
107
|
+
const now = options.now || Date.now;
|
|
108
|
+
const sleep =
|
|
109
|
+
options.sleep ||
|
|
110
|
+
((milliseconds) =>
|
|
111
|
+
new Promise((resolve) => setTimeout(resolve, milliseconds)));
|
|
112
|
+
const kill = options.kill || process.kill.bind(process);
|
|
113
|
+
const spawnSync =
|
|
114
|
+
options.spawnSync || executionBroker.spawnSync.bind(executionBroker);
|
|
115
|
+
const pid = validChildPid(child);
|
|
116
|
+
const inferredTreeMode =
|
|
117
|
+
options.treeMode ||
|
|
118
|
+
(options.sandboxManagedTree === true
|
|
119
|
+
? "sandbox"
|
|
120
|
+
: platform === "win32"
|
|
121
|
+
? "windows-tree"
|
|
122
|
+
: "posix-group");
|
|
123
|
+
const treeMode = TREE_MODES.has(inferredTreeMode)
|
|
124
|
+
? inferredTreeMode
|
|
125
|
+
: platform === "win32"
|
|
126
|
+
? "windows-tree"
|
|
127
|
+
: "posix-group";
|
|
128
|
+
const startedAt = now();
|
|
129
|
+
const deadline = startedAt + cleanupTimeoutMs;
|
|
130
|
+
let closeObserved = options.alreadyClosed === true;
|
|
131
|
+
let softRequested = false;
|
|
132
|
+
let hardRequested = false;
|
|
133
|
+
let treeRequested = false;
|
|
134
|
+
let escalated = false;
|
|
135
|
+
|
|
136
|
+
const onClose = () => {
|
|
137
|
+
closeObserved = true;
|
|
138
|
+
};
|
|
139
|
+
child?.once?.("close", onClose);
|
|
140
|
+
|
|
141
|
+
const remaining = () => Math.max(0, deadline - now());
|
|
142
|
+
const closed = () => childHasClosed(child, () => closeObserved);
|
|
143
|
+
const treeGone = () => {
|
|
144
|
+
if (!pid) return false;
|
|
145
|
+
if (treeMode === "sandbox") return closed();
|
|
146
|
+
if (treeMode === "posix-group") return posixGroupIsGone(pid, kill);
|
|
147
|
+
return treeRequested;
|
|
148
|
+
};
|
|
149
|
+
const confirmed = () => closed() && treeGone();
|
|
150
|
+
const waitForConfirmation = async (maximumMs) => {
|
|
151
|
+
const phaseDeadline = Math.min(deadline, now() + Math.max(0, maximumMs));
|
|
152
|
+
while (!confirmed() && now() < phaseDeadline) {
|
|
153
|
+
await sleep(Math.max(1, Math.min(10, phaseDeadline - now())));
|
|
154
|
+
}
|
|
155
|
+
return confirmed();
|
|
156
|
+
};
|
|
157
|
+
const request = (force) => {
|
|
158
|
+
if (!pid) {
|
|
159
|
+
return {
|
|
160
|
+
requested: requestDirectSignal(child, force ? "SIGKILL" : "SIGTERM"),
|
|
161
|
+
treeRequested: false,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
if (treeMode === "sandbox") {
|
|
165
|
+
return {
|
|
166
|
+
requested: requestDirectSignal(child, force ? "SIGKILL" : "SIGTERM"),
|
|
167
|
+
treeRequested: true,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
if (treeMode === "windows-tree") {
|
|
171
|
+
return requestWindowsTreeSignal(
|
|
172
|
+
child,
|
|
173
|
+
pid,
|
|
174
|
+
force,
|
|
175
|
+
spawnSync,
|
|
176
|
+
remaining(),
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
return requestPosixGroupSignal(
|
|
180
|
+
child,
|
|
181
|
+
pid,
|
|
182
|
+
force ? "SIGKILL" : "SIGTERM",
|
|
183
|
+
kill,
|
|
184
|
+
);
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
if (!pid) {
|
|
189
|
+
// Test doubles and partial spawn failures have no verifiable tree
|
|
190
|
+
// identity. Preserve legacy best-effort direct-child cleanup without
|
|
191
|
+
// upgrading it to a whole-tree claim.
|
|
192
|
+
const attempt = request(true);
|
|
193
|
+
hardRequested = attempt.requested;
|
|
194
|
+
return {
|
|
195
|
+
pid: null,
|
|
196
|
+
treeMode,
|
|
197
|
+
verifiable: false,
|
|
198
|
+
softRequested,
|
|
199
|
+
hardRequested,
|
|
200
|
+
treeRequested: false,
|
|
201
|
+
escalated: true,
|
|
202
|
+
closed: closed(),
|
|
203
|
+
treeTerminated: false,
|
|
204
|
+
confirmed: false,
|
|
205
|
+
deadlineExceeded: false,
|
|
206
|
+
elapsedMs: Math.max(0, now() - startedAt),
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// A managed sandbox close fence already proves its namespace/job is empty.
|
|
211
|
+
// A closed unmanaged POSIX root does not: descendants in the owned group
|
|
212
|
+
// must still be signalled and probed.
|
|
213
|
+
if (treeMode === "sandbox" && closed()) {
|
|
214
|
+
treeRequested = true;
|
|
215
|
+
} else if (!closed()) {
|
|
216
|
+
try {
|
|
217
|
+
child?.stdin?.end?.();
|
|
218
|
+
} catch {
|
|
219
|
+
// EOF is only an additional graceful hint; SIGTERM remains authoritative.
|
|
220
|
+
}
|
|
221
|
+
const attempt = request(false);
|
|
222
|
+
softRequested = attempt.requested;
|
|
223
|
+
treeRequested ||= attempt.treeRequested;
|
|
224
|
+
await waitForConfirmation(graceMs);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (!confirmed()) {
|
|
228
|
+
escalated = true;
|
|
229
|
+
const attempt = request(true);
|
|
230
|
+
hardRequested = attempt.requested;
|
|
231
|
+
treeRequested ||= attempt.treeRequested;
|
|
232
|
+
if (remaining() > 0) await waitForConfirmation(remaining());
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const didConfirm = confirmed();
|
|
236
|
+
return {
|
|
237
|
+
pid,
|
|
238
|
+
treeMode,
|
|
239
|
+
verifiable: true,
|
|
240
|
+
softRequested,
|
|
241
|
+
hardRequested,
|
|
242
|
+
treeRequested,
|
|
243
|
+
escalated,
|
|
244
|
+
closed: closed(),
|
|
245
|
+
treeTerminated: treeGone(),
|
|
246
|
+
confirmed: didConfirm,
|
|
247
|
+
deadlineExceeded: !didConfirm && remaining() === 0,
|
|
248
|
+
elapsedMs: Math.max(0, now() - startedAt),
|
|
249
|
+
};
|
|
250
|
+
} finally {
|
|
251
|
+
child?.removeListener?.("close", onClose);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
@@ -7,8 +7,10 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { listSessions } from "./session-manager.js";
|
|
10
|
-
import {
|
|
11
|
-
|
|
10
|
+
import {
|
|
11
|
+
listSessionAuthoritySummaries,
|
|
12
|
+
listSessionEvidenceIds,
|
|
13
|
+
} from "../harness/jsonl-session-store.js";
|
|
12
14
|
|
|
13
15
|
/**
|
|
14
16
|
* Merge both stores into a single newest-first, id-deduped list.
|
|
@@ -21,15 +23,18 @@ import { feature } from "./feature-flags.js";
|
|
|
21
23
|
export function listRecentSessions(ctx, opts = {}) {
|
|
22
24
|
const scan = Math.max(1, opts.scan || 20);
|
|
23
25
|
const sessions = [];
|
|
26
|
+
const canonicalIds = new Set(listSessionEvidenceIds());
|
|
24
27
|
|
|
25
28
|
if (ctx && ctx.db) {
|
|
26
29
|
try {
|
|
27
30
|
const db = ctx.db.getDatabase();
|
|
28
31
|
sessions.push(
|
|
29
|
-
...listSessions(db, { limit: scan })
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
...listSessions(db, { limit: scan })
|
|
33
|
+
.filter((s) => !canonicalIds.has(s?.id))
|
|
34
|
+
.map((s) => ({
|
|
35
|
+
...s,
|
|
36
|
+
_store: "db",
|
|
37
|
+
})),
|
|
33
38
|
);
|
|
34
39
|
} catch (err) {
|
|
35
40
|
/* db unavailable — fall through to JSONL */
|
|
@@ -37,17 +42,12 @@ export function listRecentSessions(ctx, opts = {}) {
|
|
|
37
42
|
}
|
|
38
43
|
}
|
|
39
44
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
})),
|
|
47
|
-
);
|
|
48
|
-
} catch (err) {
|
|
49
|
-
void err;
|
|
50
|
-
}
|
|
45
|
+
try {
|
|
46
|
+
// Existing canonical history remains authoritative even when the feature
|
|
47
|
+
// flag that controls new JSONL adoption is disabled.
|
|
48
|
+
sessions.push(...listSessionAuthoritySummaries({ limit: scan }));
|
|
49
|
+
} catch (err) {
|
|
50
|
+
void err;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
// Dedup by id (JSONL precedence via sort+seen), newest updated_at first.
|
|
@@ -33,6 +33,10 @@ const IDENTITY_FIELDS = Object.freeze([
|
|
|
33
33
|
const IDENTITY_FIELDS_EXCEPT_DEVICE = Object.freeze(
|
|
34
34
|
IDENTITY_FIELDS.filter((field) => field !== "dev"),
|
|
35
35
|
);
|
|
36
|
+
const STABLE_FILE_IDENTITY_FIELDS = Object.freeze(["dev", "ino", "mode"]);
|
|
37
|
+
const STABLE_FILE_IDENTITY_FIELDS_EXCEPT_DEVICE = Object.freeze(
|
|
38
|
+
STABLE_FILE_IDENTITY_FIELDS.filter((field) => field !== "dev"),
|
|
39
|
+
);
|
|
36
40
|
const DIRECTORY_IDENTITY_FIELDS = Object.freeze(["dev", "ino", "mode"]);
|
|
37
41
|
const DIRECTORY_IDENTITY_FIELDS_EXCEPT_DEVICE = Object.freeze(
|
|
38
42
|
DIRECTORY_IDENTITY_FIELDS.filter((field) => field !== "dev"),
|
|
@@ -184,6 +188,49 @@ export function samePathHandleFileIdentity(
|
|
|
184
188
|
);
|
|
185
189
|
}
|
|
186
190
|
|
|
191
|
+
/**
|
|
192
|
+
* Compare only the immutable/type portion of a path/handle file identity.
|
|
193
|
+
*
|
|
194
|
+
* This is for appenders: size and timestamps are expected to change while the
|
|
195
|
+
* descriptor is held, but the published name must continue to designate that
|
|
196
|
+
* exact regular file. The independently opened parent/volume device keeps the
|
|
197
|
+
* narrow Node 22.12 Windows device-projection bridge fail-closed.
|
|
198
|
+
*/
|
|
199
|
+
export function samePathHandleStableFileIdentity(
|
|
200
|
+
pathStat,
|
|
201
|
+
handleStat,
|
|
202
|
+
expectedDevice,
|
|
203
|
+
runtime = undefined,
|
|
204
|
+
) {
|
|
205
|
+
const pathIdentity = fileStatIdentity(pathStat);
|
|
206
|
+
const handleIdentity = fileStatIdentity(handleStat);
|
|
207
|
+
const trustedDevice =
|
|
208
|
+
expectedDevice === undefined || expectedDevice === null
|
|
209
|
+
? null
|
|
210
|
+
: String(expectedDevice);
|
|
211
|
+
if (
|
|
212
|
+
!hasFields(pathIdentity, STABLE_FILE_IDENTITY_FIELDS) ||
|
|
213
|
+
!hasFields(handleIdentity, STABLE_FILE_IDENTITY_FIELDS) ||
|
|
214
|
+
trustedDevice === null ||
|
|
215
|
+
handleIdentity.dev !== trustedDevice
|
|
216
|
+
) {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
if (sameFields(pathIdentity, handleIdentity, STABLE_FILE_IDENTITY_FIELDS)) {
|
|
220
|
+
return true;
|
|
221
|
+
}
|
|
222
|
+
return (
|
|
223
|
+
isAffectedWindowsZeroDeviceStatRuntime(runtime) &&
|
|
224
|
+
pathIdentity.dev !== handleIdentity.dev &&
|
|
225
|
+
handleIdentity.dev !== "0" &&
|
|
226
|
+
sameFields(
|
|
227
|
+
pathIdentity,
|
|
228
|
+
handleIdentity,
|
|
229
|
+
STABLE_FILE_IDENTITY_FIELDS_EXCEPT_DEVICE,
|
|
230
|
+
)
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
187
234
|
/**
|
|
188
235
|
* Directory contents can legitimately change while a child is written, so a
|
|
189
236
|
* parent recheck excludes content-derived metadata and the directory link
|
package/src/lib/secure-fs.js
CHANGED
|
@@ -1004,6 +1004,7 @@ export function ensurePrivateDirectory(target, options = {}) {
|
|
|
1004
1004
|
platform,
|
|
1005
1005
|
);
|
|
1006
1006
|
let existed = deps.fs.existsSync(target);
|
|
1007
|
+
let existingMode = null;
|
|
1007
1008
|
if (existed) {
|
|
1008
1009
|
const pathEntry = readPrivatePathEntry(
|
|
1009
1010
|
target,
|
|
@@ -1013,6 +1014,7 @@ export function ensurePrivateDirectory(target, options = {}) {
|
|
|
1013
1014
|
);
|
|
1014
1015
|
existed = pathEntry.exists;
|
|
1015
1016
|
const existing = pathEntry.entry;
|
|
1017
|
+
existingMode = existing ? Number(existing.mode) : null;
|
|
1016
1018
|
if (existed && existing.isSymbolicLink()) {
|
|
1017
1019
|
throw new Error(
|
|
1018
1020
|
`Refusing owner-only directory through a symbolic link: ${target}`,
|
|
@@ -1031,7 +1033,16 @@ export function ensurePrivateDirectory(target, options = {}) {
|
|
|
1031
1033
|
mode: PRIVATE_DIRECTORY_MODE,
|
|
1032
1034
|
});
|
|
1033
1035
|
if ((options.platform || deps.platform()) !== "win32") {
|
|
1034
|
-
|
|
1036
|
+
// chmod updates ctime even when the mode is already correct. Session and
|
|
1037
|
+
// security stores use ctime as part of their physical witness, so avoid
|
|
1038
|
+
// invalidating an otherwise unchanged owner-only directory.
|
|
1039
|
+
if (
|
|
1040
|
+
!existed ||
|
|
1041
|
+
!Number.isFinite(existingMode) ||
|
|
1042
|
+
(existingMode & 0o7777) !== PRIVATE_DIRECTORY_MODE
|
|
1043
|
+
) {
|
|
1044
|
+
deps.fs.chmodSync(target, PRIVATE_DIRECTORY_MODE);
|
|
1045
|
+
}
|
|
1035
1046
|
} else if (
|
|
1036
1047
|
options.applyWindowsAcl === true ||
|
|
1037
1048
|
(!existed && options.applyWindowsAcl !== false)
|
|
@@ -1071,7 +1082,15 @@ export function ensurePrivateFile(target, options = {}) {
|
|
|
1071
1082
|
throw new Error(`Expected a file for owner-only storage: ${target}`);
|
|
1072
1083
|
}
|
|
1073
1084
|
if (platform !== "win32") {
|
|
1074
|
-
|
|
1085
|
+
// Preserve ctime for an already-secure file. Rejected CAS writes and
|
|
1086
|
+
// read-only preflights must not make a persisted physical witness stale.
|
|
1087
|
+
const existingMode = Number(existing.mode);
|
|
1088
|
+
if (
|
|
1089
|
+
!Number.isFinite(existingMode) ||
|
|
1090
|
+
(existingMode & 0o7777) !== PRIVATE_FILE_MODE
|
|
1091
|
+
) {
|
|
1092
|
+
deps.fs.chmodSync(target, PRIVATE_FILE_MODE);
|
|
1093
|
+
}
|
|
1075
1094
|
} else if (
|
|
1076
1095
|
options.applyWindowsAcl === true &&
|
|
1077
1096
|
(options.deps || !securedWindowsPaths.has(target))
|