chainlesschain 0.163.2 → 0.163.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/package.json +3 -2
- package/scripts/command-lifecycle-report.mjs +330 -38
- package/src/assets/web-panel/assets/{AIOps-DnGsmsqJ.js → AIOps-DB5X7qqV.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CrO6fcQ7.js → ActionButton-DxHRtKLk.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DsBdOaP2.js → Analytics-DIH5QrxT.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DmQslKUB.js → AppLayout-uu0oxVz7.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-BvyrT_QQ.js → Artifacts-BNSMiW9Y.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-prndoLiC.js → Audit-DcAzB4_x.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-DOTFyA55.js → BackgroundAgents-ClSsvjIc.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-9zOnPp_8.js → Backup-BMciY0js.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-C4PC6sAG.js → BaseInput-Hn3b57Sh.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-BBAF-W9v.js → Chat-CoSlC53V.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-CWhvvloO.js → ChatBubbleRenderer-CFevJ3So.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-BI9iculd.js → Checkbox-B4L4Eu4w.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-3DP9BCKb.js → Codegen-C77FgRxF.js} +1 -1
- package/src/assets/web-panel/assets/{Col-df-2TnJX.js → Col-BrLtJLH3.js} +1 -1
- package/src/assets/web-panel/assets/{Community-CHs8gG_A.js → Community-Be7pXXhA.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-CDfF6q7V.js → Compact-DuGPecjo.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CthrDnO7.js → Compliance-CzS66mjP.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-HjIqsWJw.js → Cowork-CEhjCoyK.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-BKc196fb.js → Cron-D7ir8Vja.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CJnjdc8W.js → Crosschain-BcXmuLxf.js} +1 -1
- package/src/assets/web-panel/assets/{DID-BHUy-8Q2.js → DID-Cto1dtBy.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-QDB7sKeY.js → Dashboard-B7KjgwOX.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-DStcVK11.js → Dropdown-COMqxijg.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BwSUskMJ.js → EmailListRenderer-BZrya-nf.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-DgF_kurT.js → FamilyGuardDashboard-AmVeMq0J.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-k8wvv-wN.js → Federation-kZU8c-27.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-C11qoq2r.js → FormItemContext-sOV22v2-.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-BIIpr9kg.js → GenericCardRenderer-BUuLtGCz.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BlA1exTe.js → Git-K-ZxsLsH.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-CYa1ZYM4.js → Governance-D3OEnawI.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-6_kKVIt6.js → Inference-Bll0gRmP.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-CB4AwxYy.js → KnowledgeGraph-DBXwjr53.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-xf7nHFAe.js → Logs-CEzPwEfP.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-Bf3DEqP6.js → MarkdownRenderer-CLmCbHx6.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-aPg8e4Jt.js → Marketplace-BYyRyOPz.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-C-TNlVUf.js → McpTools-DVu8w_rM.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-DMTPIpGa.js → Memory-tenuZ_hO.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BxyvveRq.js → MobileBridge-Bxgy4ozS.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-DyPCrAyQ.js → MobileProjects-Dgx1D6sc.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BdhqNXp6.js → Mtc-CRfJ8r8j.js} +5 -5
- package/src/assets/web-panel/assets/{MtcAudit-Cz-HFxzW.js → MtcAudit-BBJq4Aiz.js} +5 -5
- package/src/assets/web-panel/assets/{Multisig-CIUaFNsx.js → Multisig-B3ii9lai.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-CWe6-J17.js → NLProgramming-FIi-Cubv.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-vYAKeviU.js → Notes-DIq8MPf1.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-DQL9-2d7.js → NotificationSettings-BFOD9eGd.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DnXj1jBn.js → OrderTableRenderer--41u7vre.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-B3spU8AN.js → Organization-B_0AWztW.js} +2 -2
- package/src/assets/web-panel/assets/{Overflow-DgEwo7vm.js → Overflow-B6I7TuXv.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-hujMRH8X.js → P2P-Cdf6qens.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-C_qhdg9h.js → PdhVaultBrowser-B_0FcQJY.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-vp7LMcSf.js → Permissions-6nFBjsQp.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-Dxr5Hgnq.js → PersonalDataHub-nQYV7xpn.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-DEPZqqH4.js → Pipeline-CBVod5jm.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-DTpDiKPe.js → Privacy-D52jW1Nt.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-jDJsRWmF.js → ProjectInit-Bdx3BYhf.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-Dhor5RWH.js → ProjectSettings-b7xr4DUa.js} +2 -2
- package/src/assets/web-panel/assets/Projects-DhfifCKx.js +1 -0
- package/src/assets/web-panel/assets/Providers-Dy_PgDMr.js +1 -0
- package/src/assets/web-panel/assets/{QrScannerModal-CjIw-wIb.js → QrScannerModal-FQKSmc3e.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-DX6jcqoi.js → QuickAsk-CSTrhzcF.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DopXkhar.js → Recommend-CxMABOUh.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-BLvqJE9c.js → RemoteSession-Cv2T8yRa.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-DhRj2Me7.js → Reputation-CE1k4Vvu.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DQ53vuPq.js → Row-BNgNcAV_.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BslvwiBD.js → RssFeed-5ZiBZ3ph.js} +3 -3
- package/src/assets/web-panel/assets/{Search-DJKBDNKZ.js → Search-mDOIF1UV.js} +1 -1
- package/src/assets/web-panel/assets/{Security-COhpxHER.js → Security-CtuCTC-e.js} +3 -3
- package/src/assets/web-panel/assets/{Services-dbulD6cI.js → Services-DxFO2Zg7.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-ciIVNfhC.js → Skeleton-CKmKkH9y.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-AiRTkTCk.js → Skills-Bmzl9qkk.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-DDMcWYBc.js → Sla-9RqaWHOC.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BPxWbpXO.js → SpeechSettings-CGdzFIYw.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-BoEOXCyg.js → SyncSettings-CvNuCeBT.js} +2 -2
- package/src/assets/web-panel/assets/Tasks-B_sLdcnw.js +1 -0
- package/src/assets/web-panel/assets/{Templates-UowY8Ixe.js → Templates-D9_YijdK.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DauSLQXN.js → Tenant-Cuc7BUSP.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DBj7Jneq.js → Terminal-6VYRnJgd.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-UMrPwoZC.js → TimelineRenderer-GtK8xd8Y.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-4ea96-bn.js → Tokens-BZ94Lt5W.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger--ISCqt4b.js → Trigger-DEcZgDaX.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-D4GVimRJ.js → Trust-CC3z9THe.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-Ci-nXRQc.js → UkeySign-Cvtw8cV3.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-Cjk7mKPw.js → VideoEditing-CL4e6Bn3.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BgOLOO3Z.js → Wallet-ycEemP27.js} +2 -2
- package/src/assets/web-panel/assets/{WebAuthn-CCX0K29i.js → WebAuthn-DgZ4X_aw.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-Ch3zgIsE.js → WorkflowEditor-D0qMhSv7.js} +1 -1
- package/src/assets/web-panel/assets/{chat-DKOU_2Vb.js → chat-DsAg01Zn.js} +1 -1
- package/src/assets/web-panel/assets/{colors-6OVo4u3C.js → colors-B0oqAhrQ.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BH78Hlsq.js → compact-item-CmX0Rabz.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CFRpSbbC.js → createContext-Be4cn1Ub.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-CP2qzG6D.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DNQhgcVi.js → hasIn-D5v12kVq.js} +1 -1
- package/src/assets/web-panel/assets/{index-BkN3iTTp.js → index-0eWLkQKT.js} +1 -1
- package/src/assets/web-panel/assets/{index-CkNEMANR.js → index-301ogenv.js} +1 -1
- package/src/assets/web-panel/assets/{index-D3RtTT4K.js → index-5LGY0JbG.js} +1 -1
- package/src/assets/web-panel/assets/{index-dDkoL4Pe.js → index-7VKDn-t1.js} +1 -1
- package/src/assets/web-panel/assets/{index-BHa4WyTZ.js → index-8WvYGnON.js} +1 -1
- package/src/assets/web-panel/assets/{index-CaYqY35Z.js → index-B1YGjOWC.js} +1 -1
- package/src/assets/web-panel/assets/{index-bKm3TUDp.js → index-B3mUHuVc.js} +1 -1
- package/src/assets/web-panel/assets/{index--rq90rL9.js → index-BA4oulaP.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaDgdJYj.js → index-BBREnn1V.js} +1 -1
- package/src/assets/web-panel/assets/{index-B_Z-YoxX.js → index-BBvyHguy.js} +1 -1
- package/src/assets/web-panel/assets/{index-CkqHgG-b.js → index-BKmsS2jj.js} +1 -1
- package/src/assets/web-panel/assets/{index-CrcLHN2F.js → index-BRIqLy1m.js} +1 -1
- package/src/assets/web-panel/assets/{index-BaVE6E8y.js → index-BXGSbelg.js} +3 -3
- package/src/assets/web-panel/assets/{index-BYrnm5Ob.js → index-BaE0Ui07.js} +1 -1
- package/src/assets/web-panel/assets/{index-BDSR7ecX.js → index-BoAIAZ5C.js} +1 -1
- package/src/assets/web-panel/assets/{index-CNuCHHQT.js → index-BqltWojQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Eag8e_mA.js → index-CGiIyTZw.js} +1 -1
- package/src/assets/web-panel/assets/index-CKB0vbJU.js +1 -0
- package/src/assets/web-panel/assets/{index-BepBTpa8.js → index-CZ2wUEgr.js} +1 -1
- package/src/assets/web-panel/assets/{index-HNGGVF6o.js → index-CZpfzcuy.js} +1 -1
- package/src/assets/web-panel/assets/{index-AuBhLqOm.js → index-Ckrk3pIV.js} +1 -1
- package/src/assets/web-panel/assets/{index-7TC3S8SN.js → index-CqoCZ5vR.js} +1 -1
- package/src/assets/web-panel/assets/{index-CFPJ8yzF.js → index-CyWBir7N.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bb6kDrUx.js → index-CyyGTMKd.js} +1 -1
- package/src/assets/web-panel/assets/{index-DKN2noIF.js → index-D0BSkxYQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Du0rnksC.js → index-D5YVopyr.js} +1 -1
- package/src/assets/web-panel/assets/{index-BxRy5LPR.js → index-DKUBj36_.js} +1 -1
- package/src/assets/web-panel/assets/{index-sm7W8AXy.js → index-DM724NgU.js} +1 -1
- package/src/assets/web-panel/assets/{index-BujsOZfc.js → index-DQRsQen0.js} +1 -1
- package/src/assets/web-panel/assets/index-DgoXmwqB.js +1 -0
- package/src/assets/web-panel/assets/{index-Y9MJv28e.js → index-DikJ0Qqe.js} +1 -1
- package/src/assets/web-panel/assets/{index-caye7AOE.js → index-Dn2dSdXx.js} +1 -1
- package/src/assets/web-panel/assets/{index-cdf7fd7d.js → index-DyUaFWEk.js} +1 -1
- package/src/assets/web-panel/assets/{index-BnnXQot_.js → index-Hfe_dEGx.js} +1 -1
- package/src/assets/web-panel/assets/{index-DvHGtNnF.js → index-_JjRLSD0.js} +1 -1
- package/src/assets/web-panel/assets/{index-nbfHl1oV.js → index-frSojpHj.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cu3L4r5l.js → index-jK3ax6Z6.js} +1 -1
- package/src/assets/web-panel/assets/{index-D84id2Y4.js → index-qMuZ-NRR.js} +1 -1
- package/src/assets/web-panel/assets/{index-hPY0fFrd.js → index-q_fQ94SE.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BZ9w6jPL.js → initDefaultProps-D4VdhJ9_.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BnwUiOho.js → motion-CZJA0MQW.js} +1 -1
- package/src/assets/web-panel/assets/{move-ByUKJnNm.js → move-BqEs7Sb1.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-V7yK1KEl.js → mtc-parser-BpHEtsu1.js} +1 -1
- package/src/assets/web-panel/assets/{omit-BEXBBt4j.js → omit-BW94tY9W.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-qDm_46Gi.js → pickAttrs-BnBjPWP9.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BIbhEo_0.js → placementArrow-uUkjQ_hu.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-NbPbDgA_.js → responsiveObserve-B-klUqXK.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BnUWglZ0.js → slide-CvY1cNAs.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BX8_wZI5.js → statusUtils-Ix5sEDT2.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BV4OycQX.js → styleChecker-C8qcXOne.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-Od_H5llY.js → useFlexGapSupport-KNF6Kj8f.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BWI-PyiX.js → useFs-DGJr345n.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BqMuhG3g.js → usePersonalDataHub-BboN99rI.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-DNd23z6f.js → vnode-Bgt8Vgte.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-Cjaxnm7l.js → zoom-BhJtErgt.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +2 -2
- package/src/commands/agenda.js +6 -5
- package/src/commands/agent.js +237 -75
- package/src/commands/agents.js +6 -0
- package/src/commands/artifacts.js +98 -0
- package/src/commands/background-session.js +11 -1
- package/src/commands/mcp.js +218 -31
- package/src/commands/review.js +221 -22
- package/src/commands/session-mcp-recovery.js +5 -5
- package/src/data/changelog.json +27 -1
- package/src/gateways/ws/ws-agent-handler.js +492 -14
- package/src/harness/jsonl-session-store.js +39 -1
- package/src/harness/mcp-client.js +414 -71
- package/src/harness/prompt-compressor.js +24 -0
- package/src/harness/provider-backed-compaction.js +205 -0
- package/src/harness/worktree-isolator.js +26 -3
- package/src/lib/agent-worktree.js +41 -2
- package/src/lib/app-preview.js +3 -0
- package/src/lib/background-agent-supervisor.js +790 -186
- package/src/lib/background-command-argv.js +318 -0
- package/src/lib/background-launch-profile.js +1 -0
- package/src/lib/background-phase-reporter.js +22 -2
- package/src/lib/background-worktree-policy.js +109 -0
- package/src/lib/command-lifecycle-report.js +1340 -145
- package/src/lib/cowork-mcp-tools.js +51 -6
- package/src/lib/cowork-task-runner.js +1 -0
- package/src/lib/delivery-coordinator.js +30 -5
- package/src/lib/delivery-production-adapter.js +1777 -0
- package/src/lib/delivery-production-runner.js +240 -0
- package/src/lib/durable-security-store.js +29 -17
- package/src/lib/execution-trace/trace-context.cjs +179 -0
- package/src/lib/execution-trace/trace-context.js +8 -175
- package/src/lib/mcp-call-ledger-store.js +58 -6
- package/src/lib/mcp-headers-helper.js +76 -8
- package/src/lib/mcp-host-recovery-runtime.js +2 -0
- package/src/lib/mcp-ledger-recovery-admission.js +39 -3
- package/src/lib/mcp-recovery-adjudication.js +256 -19
- package/src/lib/mcp-sandbox-policy.js +184 -0
- package/src/lib/mcp-stdio-capsule-builder-worker.cjs +495 -0
- package/src/lib/mcp-stdio-executable-identity.js +33 -2
- package/src/lib/mcp-stdio-execution-authority.js +163 -0
- package/src/lib/mcp-stdio-immutable-vfs-resolver.cjs +830 -0
- package/src/lib/mcp-stdio-package-materialization.js +721 -333
- package/src/lib/mcp-stdio-workspace-authority.js +252 -0
- package/src/lib/observability/index.js +2 -0
- package/src/lib/observability/otlp-exporter.js +2 -2
- package/src/lib/packer/pack-update-applier.js +8 -1
- package/src/lib/packer/pkg-config-generator.js +34 -0
- package/src/lib/plugin-runtime/sandbox-policy.js +42 -2
- package/src/lib/process-execution-broker/index.js +213 -109
- package/src/lib/process-execution-broker/platform-sandbox.js +1024 -169
- package/src/lib/process-tree-termination.js +17 -1
- package/src/lib/scheduler-kernel/contract.js +315 -0
- package/src/lib/scheduler-kernel/store.js +1345 -0
- package/src/lib/session-host-lease.js +403 -30
- package/src/lib/session-persistence-failure.js +4 -1
- package/src/lib/skill-mcp.js +65 -4
- package/src/lib/sub-agent-context.js +8 -0
- package/src/lib/web-fetch.js +4 -4
- package/src/repl/agent-repl.js +285 -38
- package/src/runtime/agent-core.js +1044 -90
- package/src/runtime/agent-runtime.js +61 -8
- package/src/runtime/headless-runner.js +260 -166
- package/src/runtime/headless-stream.js +254 -25
- package/src/runtime/mcp-config.js +235 -28
- package/src/workers/background-agent-worker.js +492 -71
- package/src/assets/web-panel/assets/Projects-08xUDZGt.js +0 -1
- package/src/assets/web-panel/assets/Providers-BGs47s1a.js +0 -1
- package/src/assets/web-panel/assets/Tasks-CEYFJwmr.js +0 -1
- package/src/assets/web-panel/assets/devWarning-DEMblAIm.js +0 -1
- package/src/assets/web-panel/assets/index-BTvq-36D.js +0 -1
- package/src/assets/web-panel/assets/index-hUpvk6Jl.js +0 -1
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capture the Commander option grammar needed to safely transform a parsed
|
|
3
|
+
* command's original argv. Keeping option arity is important: an option value
|
|
4
|
+
* can be byte-for-byte identical to a prompt token or another option name.
|
|
5
|
+
*/
|
|
6
|
+
/** Keep untrusted prompt text inside one argv token, even when it starts `-`. */
|
|
7
|
+
export function agentPrintArgument(prompt) {
|
|
8
|
+
return `--print=${String(prompt)}`;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function captureCommandArgvGrammar(command) {
|
|
12
|
+
const hierarchy = [];
|
|
13
|
+
for (let cursor = command; cursor; cursor = cursor.parent) {
|
|
14
|
+
hierarchy.unshift(cursor);
|
|
15
|
+
}
|
|
16
|
+
const optionSpecs = hierarchy.flatMap((owner) =>
|
|
17
|
+
(owner?.options || []).map((option) => ({
|
|
18
|
+
short: option.short || null,
|
|
19
|
+
long: option.long || null,
|
|
20
|
+
required: option.required === true,
|
|
21
|
+
optional: option.optional === true,
|
|
22
|
+
variadic: option.variadic === true,
|
|
23
|
+
})),
|
|
24
|
+
);
|
|
25
|
+
const commandNames = [
|
|
26
|
+
command?.name?.(),
|
|
27
|
+
...(command?.aliases?.() || []),
|
|
28
|
+
].filter(Boolean);
|
|
29
|
+
return { optionSpecs, commandNames };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function captureCommandOptionSpecs(command) {
|
|
33
|
+
return captureCommandArgvGrammar(command).optionSpecs;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function normalizedOptionSpecs(optionSpecs) {
|
|
37
|
+
return (optionSpecs || [])
|
|
38
|
+
.map((spec) => ({
|
|
39
|
+
short: spec?.short || null,
|
|
40
|
+
long: spec?.long || null,
|
|
41
|
+
required: spec?.required === true,
|
|
42
|
+
optional: spec?.optional === true,
|
|
43
|
+
variadic: spec?.variadic === true,
|
|
44
|
+
}))
|
|
45
|
+
.filter((spec) => spec.short || spec.long);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function consumesValue(spec) {
|
|
49
|
+
return spec?.required === true || spec?.optional === true;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function looksLikeOption(value) {
|
|
53
|
+
return typeof value === "string" && value.length > 1 && value[0] === "-";
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function consumedValueCount(argv, start, spec) {
|
|
57
|
+
if (!consumesValue(spec) || start >= argv.length || argv[start] === "--") {
|
|
58
|
+
return 0;
|
|
59
|
+
}
|
|
60
|
+
if (spec.optional && looksLikeOption(argv[start])) return 0;
|
|
61
|
+
if (!spec.variadic) return 1;
|
|
62
|
+
let count = 0;
|
|
63
|
+
for (let index = start; index < argv.length; index++) {
|
|
64
|
+
if (argv[index] === "--" || looksLikeOption(argv[index])) break;
|
|
65
|
+
count += 1;
|
|
66
|
+
}
|
|
67
|
+
return count;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function optionGrammar(optionSpecs) {
|
|
71
|
+
const specs = normalizedOptionSpecs(optionSpecs);
|
|
72
|
+
const aliases = new Map();
|
|
73
|
+
for (const spec of specs) {
|
|
74
|
+
if (spec.short) aliases.set(spec.short, spec);
|
|
75
|
+
if (spec.long) aliases.set(spec.long, spec);
|
|
76
|
+
}
|
|
77
|
+
return { specs, aliases };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function parseShortCluster(token, aliases, argv, index) {
|
|
81
|
+
if (!/^-[^-].+/.test(token)) return null;
|
|
82
|
+
const body = token.slice(1);
|
|
83
|
+
const parts = [];
|
|
84
|
+
for (let offset = 0; offset < body.length; offset++) {
|
|
85
|
+
const alias = `-${body[offset]}`;
|
|
86
|
+
const spec = aliases.get(alias);
|
|
87
|
+
if (!spec) return null;
|
|
88
|
+
if (!consumesValue(spec)) {
|
|
89
|
+
parts.push({ alias, spec, attachedValue: null });
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const attachedValue = body.slice(offset + 1);
|
|
93
|
+
parts.push({
|
|
94
|
+
alias,
|
|
95
|
+
spec,
|
|
96
|
+
attachedValue: attachedValue || null,
|
|
97
|
+
});
|
|
98
|
+
const valueCount = attachedValue
|
|
99
|
+
? 0
|
|
100
|
+
: consumedValueCount(argv, index + 1, spec);
|
|
101
|
+
return {
|
|
102
|
+
kind: "short-cluster",
|
|
103
|
+
parts,
|
|
104
|
+
values: argv.slice(index + 1, index + 1 + valueCount),
|
|
105
|
+
consumed: 1 + valueCount,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
kind: "short-cluster",
|
|
110
|
+
parts,
|
|
111
|
+
values: [],
|
|
112
|
+
consumed: 1,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function parseOption(argv, index, aliases) {
|
|
117
|
+
const token = argv[index];
|
|
118
|
+
const equalsIndex = token.startsWith("--") ? token.indexOf("=") : -1;
|
|
119
|
+
const name = equalsIndex > 0 ? token.slice(0, equalsIndex) : token;
|
|
120
|
+
const spec = aliases.get(name);
|
|
121
|
+
if (spec) {
|
|
122
|
+
const inlineValue = equalsIndex > 0 ? token.slice(equalsIndex + 1) : null;
|
|
123
|
+
const valueCount =
|
|
124
|
+
inlineValue !== null ? 0 : consumedValueCount(argv, index + 1, spec);
|
|
125
|
+
return {
|
|
126
|
+
kind: "option",
|
|
127
|
+
spec,
|
|
128
|
+
token,
|
|
129
|
+
inlineValue,
|
|
130
|
+
values: argv.slice(index + 1, index + 1 + valueCount),
|
|
131
|
+
consumed: 1 + valueCount,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
return parseShortCluster(token, aliases, argv, index);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function parseCommandArgv(argv, optionSpecs, commandNames) {
|
|
138
|
+
const source = [...(argv || [])];
|
|
139
|
+
const { aliases } = optionGrammar(optionSpecs);
|
|
140
|
+
const segments = [];
|
|
141
|
+
let index = 0;
|
|
142
|
+
const names = new Set(commandNames || []);
|
|
143
|
+
let foundCommand = names.size === 0;
|
|
144
|
+
if (foundCommand && source.length > 0) {
|
|
145
|
+
// The background launcher always receives process.argv.slice(2), whose
|
|
146
|
+
// first token is the command name (`agent`/`a`). It is not an operand.
|
|
147
|
+
segments.push({ kind: "command", tokens: [source[0]] });
|
|
148
|
+
index = 1;
|
|
149
|
+
}
|
|
150
|
+
while (index < source.length) {
|
|
151
|
+
if (foundCommand && source[index] === "--") {
|
|
152
|
+
segments.push({ kind: "terminator", tokens: source.slice(index) });
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
const option = parseOption(source, index, aliases);
|
|
156
|
+
if (option) {
|
|
157
|
+
segments.push(option);
|
|
158
|
+
index += option.consumed;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (!foundCommand && names.has(source[index])) {
|
|
162
|
+
foundCommand = true;
|
|
163
|
+
segments.push({ kind: "command", tokens: [source[index]] });
|
|
164
|
+
} else {
|
|
165
|
+
// Unknown pre-command tokens are preserved fail-closed. A successfully
|
|
166
|
+
// parsed Commander invocation should only reach this for the command
|
|
167
|
+
// token itself, but retaining an unexpected prefix is safer than
|
|
168
|
+
// silently launching a different command.
|
|
169
|
+
segments.push({
|
|
170
|
+
kind: foundCommand ? "operand" : "prefix",
|
|
171
|
+
tokens: [source[index]],
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
index += 1;
|
|
175
|
+
}
|
|
176
|
+
return segments;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function renderShortCluster(segment, keepPart) {
|
|
180
|
+
const kept = segment.parts.filter(keepPart);
|
|
181
|
+
if (kept.length === 0) return [];
|
|
182
|
+
let token = "-";
|
|
183
|
+
let keepValues = false;
|
|
184
|
+
for (const part of kept) {
|
|
185
|
+
token += part.alias.slice(1);
|
|
186
|
+
if (consumesValue(part.spec)) {
|
|
187
|
+
if (part.attachedValue !== null) token += part.attachedValue;
|
|
188
|
+
else keepValues = true;
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return [token, ...(keepValues ? segment.values : [])];
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const BACKGROUND_PARENT_OPTIONS = new Set([
|
|
196
|
+
"--background",
|
|
197
|
+
"--worktree",
|
|
198
|
+
"--no-worktree",
|
|
199
|
+
]);
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Remove parent-only background/worktree decisions and replace every parsed
|
|
203
|
+
* --add-dir occurrence with the already validated canonical roots. A token is
|
|
204
|
+
* changed only when the command grammar identifies it as that option; equal
|
|
205
|
+
* values belonging to another option stay byte-for-byte intact.
|
|
206
|
+
*/
|
|
207
|
+
export function transformBackgroundLaunchArgv(
|
|
208
|
+
argv,
|
|
209
|
+
{ directories = [], optionSpecs, commandNames } = {},
|
|
210
|
+
) {
|
|
211
|
+
const out = [];
|
|
212
|
+
let positionalTail = [];
|
|
213
|
+
for (const segment of parseCommandArgv(argv, optionSpecs, commandNames)) {
|
|
214
|
+
if (segment.kind === "option") {
|
|
215
|
+
if (
|
|
216
|
+
segment.spec?.long !== "--add-dir" &&
|
|
217
|
+
!BACKGROUND_PARENT_OPTIONS.has(segment.spec?.long)
|
|
218
|
+
) {
|
|
219
|
+
out.push(segment.token, ...segment.values);
|
|
220
|
+
}
|
|
221
|
+
} else if (segment.kind === "short-cluster") {
|
|
222
|
+
out.push(
|
|
223
|
+
...renderShortCluster(
|
|
224
|
+
segment,
|
|
225
|
+
(part) =>
|
|
226
|
+
part.spec?.long !== "--add-dir" &&
|
|
227
|
+
!BACKGROUND_PARENT_OPTIONS.has(part.spec?.long),
|
|
228
|
+
),
|
|
229
|
+
);
|
|
230
|
+
} else if (segment.kind === "terminator") {
|
|
231
|
+
positionalTail = segment.tokens;
|
|
232
|
+
} else {
|
|
233
|
+
out.push(...segment.tokens);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
for (const directory of directories || []) {
|
|
237
|
+
out.push("--add-dir", directory);
|
|
238
|
+
}
|
|
239
|
+
return [...out, ...positionalTail];
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const SESSION_PARENT_OPTIONS = new Set([
|
|
243
|
+
"--session",
|
|
244
|
+
"--continue",
|
|
245
|
+
"--resume",
|
|
246
|
+
"--fork-session",
|
|
247
|
+
"--fork-request-id",
|
|
248
|
+
]);
|
|
249
|
+
|
|
250
|
+
function isParentSessionOption(spec) {
|
|
251
|
+
return SESSION_PARENT_OPTIONS.has(spec?.long);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Remove every parent-owned resume/fork spelling and insert one resolved
|
|
256
|
+
* session id. Literal prompt tokens after `--`, and values belonging to other
|
|
257
|
+
* options, are preserved exactly.
|
|
258
|
+
*/
|
|
259
|
+
export function canonicalizeBackgroundSessionArgv(
|
|
260
|
+
argv,
|
|
261
|
+
{ sessionId, optionSpecs, commandNames } = {},
|
|
262
|
+
) {
|
|
263
|
+
if (!sessionId) {
|
|
264
|
+
throw new Error("Cannot launch background agent without a session id");
|
|
265
|
+
}
|
|
266
|
+
const out = [];
|
|
267
|
+
let positionalTail = [];
|
|
268
|
+
for (const segment of parseCommandArgv(argv, optionSpecs, commandNames)) {
|
|
269
|
+
if (segment.kind === "option") {
|
|
270
|
+
if (!isParentSessionOption(segment.spec)) {
|
|
271
|
+
out.push(segment.token, ...segment.values);
|
|
272
|
+
}
|
|
273
|
+
} else if (segment.kind === "short-cluster") {
|
|
274
|
+
out.push(
|
|
275
|
+
...renderShortCluster(
|
|
276
|
+
segment,
|
|
277
|
+
(part) => !isParentSessionOption(part.spec),
|
|
278
|
+
),
|
|
279
|
+
);
|
|
280
|
+
} else if (segment.kind === "terminator") {
|
|
281
|
+
positionalTail = segment.tokens;
|
|
282
|
+
} else {
|
|
283
|
+
out.push(...segment.tokens);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return [...out, "--session", String(sessionId), ...positionalTail];
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function isPrintOption(spec) {
|
|
290
|
+
return spec?.long === "--print";
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Build the reusable argv for an attached follow-up turn. Option grammar, not
|
|
295
|
+
* token equality, distinguishes option values from first-turn operands.
|
|
296
|
+
*/
|
|
297
|
+
export function stripFirstTurnPromptArgv(
|
|
298
|
+
argv,
|
|
299
|
+
{ optionSpecs, commandNames } = {},
|
|
300
|
+
) {
|
|
301
|
+
const out = [];
|
|
302
|
+
for (const segment of parseCommandArgv(argv, optionSpecs, commandNames)) {
|
|
303
|
+
if (segment.kind === "command" || segment.kind === "prefix") {
|
|
304
|
+
out.push(...segment.tokens);
|
|
305
|
+
} else if (segment.kind === "option") {
|
|
306
|
+
if (!isPrintOption(segment.spec)) {
|
|
307
|
+
out.push(segment.token, ...segment.values);
|
|
308
|
+
}
|
|
309
|
+
} else if (segment.kind === "short-cluster") {
|
|
310
|
+
out.push(
|
|
311
|
+
...renderShortCluster(segment, (part) => !isPrintOption(part.spec)),
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
// All operands, the option terminator, and its literal tail belong to the
|
|
315
|
+
// first turn and are intentionally omitted.
|
|
316
|
+
}
|
|
317
|
+
return out;
|
|
318
|
+
}
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
*/
|
|
32
32
|
|
|
33
33
|
import {
|
|
34
|
+
mutateBackgroundAgentState,
|
|
34
35
|
readBackgroundAgentState,
|
|
35
36
|
writeBackgroundAgentState,
|
|
36
37
|
} from "./background-agent-supervisor.js";
|
|
@@ -43,6 +44,8 @@ import {
|
|
|
43
44
|
* `process.env.CC_BACKGROUND_AGENT_ID`. Falsy → disabled no-op reporter.
|
|
44
45
|
* @param {(id:string)=>object|null} [opts.readState] injectable state reader
|
|
45
46
|
* @param {(state:object)=>void} [opts.writeState] injectable state writer
|
|
47
|
+
* @param {(id:string, updater:Function)=>object} [opts.mutateState] injectable
|
|
48
|
+
* atomic mutator; production defaults to the strict supervisor transaction
|
|
46
49
|
*/
|
|
47
50
|
export function createBackgroundPhaseReporter(opts = {}) {
|
|
48
51
|
const agentId =
|
|
@@ -51,16 +54,33 @@ export function createBackgroundPhaseReporter(opts = {}) {
|
|
|
51
54
|
: process.env.CC_BACKGROUND_AGENT_ID;
|
|
52
55
|
const readState = opts.readState || readBackgroundAgentState;
|
|
53
56
|
const writeState = opts.writeState || writeBackgroundAgentState;
|
|
57
|
+
const mutateState =
|
|
58
|
+
opts.mutateState ||
|
|
59
|
+
(opts.readState || opts.writeState ? null : mutateBackgroundAgentState);
|
|
54
60
|
const enabled = typeof agentId === "string" && agentId.trim() !== "";
|
|
55
61
|
let pending = 0;
|
|
56
62
|
|
|
57
63
|
function patch(fields) {
|
|
58
64
|
if (!enabled) return false;
|
|
59
65
|
try {
|
|
60
|
-
|
|
66
|
+
if (mutateState) {
|
|
67
|
+
return mutateState(agentId, (current) => {
|
|
68
|
+
if (
|
|
69
|
+
!current ||
|
|
70
|
+
current.status !== "running" ||
|
|
71
|
+
current.stopRequestedAt
|
|
72
|
+
) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
return { ...current, id: agentId, ...fields };
|
|
76
|
+
}).applied;
|
|
77
|
+
}
|
|
78
|
+
const current = readState(agentId);
|
|
61
79
|
// Terminal states are owned by the worker/stopper — never write a
|
|
62
80
|
// "waiting" phase over a completed/failed/stopped record.
|
|
63
|
-
if (current
|
|
81
|
+
if (!current || current.status !== "running" || current.stopRequestedAt) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
64
84
|
writeState({ ...current, id: agentId, ...fields });
|
|
65
85
|
return true;
|
|
66
86
|
} catch {
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { lstatSync, realpathSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Locate a Git marker without `existsSync()`'s fail-open error swallowing.
|
|
6
|
+
* ENOENT/ENOTDIR means "keep walking"; access, I/O, and indeterminate marker
|
|
7
|
+
* failures propagate so a mutation-capable background task never silently
|
|
8
|
+
* falls back to the shared checkout.
|
|
9
|
+
*/
|
|
10
|
+
export function findGitRepositoryRootStrict(
|
|
11
|
+
cwd = process.cwd(),
|
|
12
|
+
{
|
|
13
|
+
stat = lstatSync,
|
|
14
|
+
realpath = realpathSync.native || realpathSync,
|
|
15
|
+
pathApi = path,
|
|
16
|
+
} = {},
|
|
17
|
+
) {
|
|
18
|
+
// Resolve the starting directory before walking ancestors. A lexical cwd
|
|
19
|
+
// reached through a symlink/junction may sit outside the repository even
|
|
20
|
+
// though its canonical target is inside it; walking the alias would
|
|
21
|
+
// otherwise classify a real Git checkout as non-Git and share it.
|
|
22
|
+
let dir = realpath(pathApi.resolve(cwd));
|
|
23
|
+
for (;;) {
|
|
24
|
+
try {
|
|
25
|
+
stat(pathApi.join(dir, ".git"));
|
|
26
|
+
return dir;
|
|
27
|
+
} catch (error) {
|
|
28
|
+
if (error?.code !== "ENOENT" && error?.code !== "ENOTDIR") throw error;
|
|
29
|
+
}
|
|
30
|
+
const parent = pathApi.dirname(dir);
|
|
31
|
+
if (parent === dir) return null;
|
|
32
|
+
dir = parent;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Decide whether an agent session must use an isolated git worktree.
|
|
38
|
+
*
|
|
39
|
+
* Background prompts and tool declarations are deliberately not inspected.
|
|
40
|
+
* An unqualified detached agent is treated as mutation-capable and isolated
|
|
41
|
+
* whenever it starts in a git repository. `--no-worktree` is the only explicit
|
|
42
|
+
* escape hatch: a nominally read-only permission mode is not enough because
|
|
43
|
+
* host/MCP extension tools may widen the effective tool surface.
|
|
44
|
+
*/
|
|
45
|
+
export function resolveBackgroundWorktreePolicy({
|
|
46
|
+
background = false,
|
|
47
|
+
worktree,
|
|
48
|
+
inputFormat = "text",
|
|
49
|
+
cwd = process.cwd(),
|
|
50
|
+
findProjectRoot = findGitRepositoryRootStrict,
|
|
51
|
+
} = {}) {
|
|
52
|
+
if (worktree === true) {
|
|
53
|
+
const repoRoot = findProjectRoot(cwd);
|
|
54
|
+
if (!repoRoot) {
|
|
55
|
+
throw new Error("--worktree requires a Git repository");
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
enabled: true,
|
|
59
|
+
source: "explicit",
|
|
60
|
+
reason: "worktree explicitly requested",
|
|
61
|
+
repoRoot,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (worktree === false) {
|
|
65
|
+
return {
|
|
66
|
+
enabled: false,
|
|
67
|
+
source: "explicit-disable",
|
|
68
|
+
reason: "worktree explicitly disabled",
|
|
69
|
+
repoRoot: null,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (!background) {
|
|
73
|
+
return {
|
|
74
|
+
enabled: false,
|
|
75
|
+
source: "foreground-default",
|
|
76
|
+
reason: "foreground sessions preserve the existing default",
|
|
77
|
+
repoRoot: null,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
// stream-json is a foreground, long-lived stdin protocol in the current
|
|
81
|
+
// command contract even if callers also pass --background. Do not silently
|
|
82
|
+
// change that established dispatch path in the worktree policy layer.
|
|
83
|
+
if (String(inputFormat || "text").toLowerCase() === "stream-json") {
|
|
84
|
+
return {
|
|
85
|
+
enabled: false,
|
|
86
|
+
source: "stream-json-foreground",
|
|
87
|
+
reason: "stream-json uses the foreground stream driver",
|
|
88
|
+
repoRoot: null,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
// Detection errors propagate: once a caller asks for mutation-capable
|
|
92
|
+
// background isolation, an indeterminate repository state must not silently
|
|
93
|
+
// fall back to sharing the main checkout.
|
|
94
|
+
const repoRoot = findProjectRoot(cwd);
|
|
95
|
+
if (!repoRoot) {
|
|
96
|
+
return {
|
|
97
|
+
enabled: false,
|
|
98
|
+
source: "non-git-default",
|
|
99
|
+
reason: "current directory is not inside a git repository",
|
|
100
|
+
repoRoot: null,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
enabled: true,
|
|
105
|
+
source: "background-git-default",
|
|
106
|
+
reason: "mutation-capable background agent in a git repository",
|
|
107
|
+
repoRoot,
|
|
108
|
+
};
|
|
109
|
+
}
|