chainlesschain 0.163.7 → 0.164.0
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 +5 -1
- package/scripts/macos-mcp-launcher-build.mjs +317 -0
- package/scripts/macos-mcp-launcher-postinstall.sh +54 -0
- package/scripts/macos-mcp-launcher-preinstall.sh +61 -0
- package/src/assets/web-panel/assets/{AIOps-axqQfwv8.js → AIOps-D2MEn7fI.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DV-Ro0By.js → ActionButton-lCW_4Gf0.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-Bt72WEVu.js → Analytics-Bs7i-nsS.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-BtepG55E.js → AppLayout-CK7B6S_j.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-B7KaJ7S_.js → Artifacts-C8ILjpyo.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-FNFaUg7A.js → Audit-Bb9cNaWc.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-DFb6J2wQ.js → BackgroundAgents-sC9ooXIf.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CC7YBhyj.js → Backup-D-DrsplT.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-RkgTNVtj.js → BaseInput-uCNZpwSK.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-hHEmGZy-.js → Chat-CsDK1uE9.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-CAP9YhHv.js → ChatBubbleRenderer-OqSDt50w.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-z5wXOQP1.js → Checkbox-JhTXM1-K.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DVaDJnxy.js → Codegen-BbzZLnyD.js} +1 -1
- package/src/assets/web-panel/assets/{Col-CJmaRDR5.js → Col-D4VW4m4j.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DF29_2bI.js → Community-BXrYawxV.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DtkQkBzn.js → Compact-DCihGy1u.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-xoHDxp7I.js → Compliance-DlyZ-lk8.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BUm-R7ht.js → Cowork-DvGZrhbO.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-Cgl14ZkB.js → Cron-DUncZi8h.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BNcbmoqh.js → Crosschain-C_hLuUcm.js} +1 -1
- package/src/assets/web-panel/assets/{DID-Bwja0Zo9.js → DID-b6YSUqxr.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-Bk5XjEdJ.js → Dashboard-uvM15Cfb.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-Ci36Oitq.js → Dropdown-D1-Nd4qY.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer--U04ZN4q.js → EmailListRenderer-8ApvL6Zc.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-B2gNPR2s.js → FamilyGuardDashboard-LYJt8811.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-C4KghYn7.js → Federation-BbI3HGpv.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-QL7x_Q_0.js → FormItemContext-DSoEKuFu.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-F3Ryltwm.js → GenericCardRenderer-B0S9OWd5.js} +1 -1
- package/src/assets/web-panel/assets/{Git-2HassK5k.js → Git-DIs9Zhf3.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-DoBIp7oe.js → Governance-jzZXrxcl.js} +1 -1
- package/src/assets/web-panel/assets/{Inference--W01QhZ-.js → Inference-JUPjf2ZI.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DmvwqGpT.js → KnowledgeGraph-DxnfJvlP.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BBJ4yAel.js → Logs-iXiz8BEE.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-BLCZMzhJ.js → MarkdownRenderer-GmB6DOr6.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-D5lNngSI.js → Marketplace-Y3Xch312.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-CkEVOMKH.js → McpTools-D7kGGbO7.js} +4 -4
- package/src/assets/web-panel/assets/{Memory-B1Ow1xVE.js → Memory-Do_hVxzh.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-SgYbUfb6.js → MobileBridge-CtrR0Tas.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-BL0Czcoj.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-DcTXSSma.js → Mtc-qo5QCTGd.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-Dt3WG4oj.js → MtcAudit-cq5mnjYj.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-B9B38UZx.js → Multisig-Bq0MAQHw.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-B0S4GGvG.js → NLProgramming-DdWE6Vi2.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-DZ5U58Ng.js → Notes-BxMBFcIp.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-PjL5ZW34.js → NotificationSettings-RTrAcbUe.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DrAX2ESt.js → OrderTableRenderer-DJbpGqzT.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-Cv1GYs-c.js → Organization-SQzIPdqC.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Bbkp_PL3.js → Overflow-02yECh22.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BD8QUgoZ.js → P2P-BNg4pNCM.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-BO-2PeaB.js → PdhVaultBrowser-BxPJZsD3.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-D_OPVa02.js → Permissions-CLnDnPAz.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-mh-pEmaB.js → PersonalDataHub-C5m0AjGf.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-6JC2EDdb.js → Pipeline-VwOf5Dhv.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-CUshzUAG.js → Privacy-CC0W2hZd.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Cs2Aalri.js → ProjectInit-Dz893Bob.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-1ak49tcj.js → ProjectSettings-CxQkvl0k.js} +2 -2
- package/src/assets/web-panel/assets/Projects-DDAjkUkT.js +1 -0
- package/src/assets/web-panel/assets/{Providers-CXXxvafH.js → Providers-DeB9IkxK.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-PTcDsF58.js → QrScannerModal-OCeoaswn.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-CDwucrJw.js → QuickAsk-DenotaAj.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-CJlLVRXR.js → Recommend-Cies_jjI.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-DlN-ETsO.js → RemoteSession-Dxzl5n2T.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-DI23LR6m.js → Reputation-CW0mvxgZ.js} +1 -1
- package/src/assets/web-panel/assets/{Row-Cl7UQMrM.js → Row-SEd32qZU.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CexHNfh8.js → RssFeed-BSwnJ3Lm.js} +3 -3
- package/src/assets/web-panel/assets/{Search-BneBWvRN.js → Search-xe2m8bkC.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DX7Phgrp.js → Security-Mq2F9Nro.js} +4 -4
- package/src/assets/web-panel/assets/{Services-BWXO8Mte.js → Services-BKGw2V3P.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DCyOjKPJ.js → Skeleton-DW95-Rxf.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CXqERsTB.js → Skills-CHgChCv_.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-bhbrbz8E.js → Sla-tKh6k3R7.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-3IPU0HBZ.js → SpeechSettings-D6UL3dA5.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-DBNTQLbM.js → SyncSettings-D0Fw8fVL.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-quP0bkN-.js → Tasks-20x1GB3D.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-BouWmgho.js → Templates-DJ-lts-a.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-qv0D9s7z.js → Tenant-BFdGpbs7.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-BxvbE8BB.js → Terminal-Xpx61vHL.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-D-IeLnJ2.js → TimelineRenderer-C6UIvyZQ.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-CFMKKyVG.js → Tokens-Dellq08f.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-L8as3UuJ.js → Trigger-VKw8d0J-.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-MxmA4VZG.js → Trust-DNftdKT5.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-C0VvJYRi.js → UkeySign-DX9VAKJI.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-Bf5QZj8N.js → VideoEditing-B2h3jO8q.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BIJ9riRz.js → Wallet-CjGkof7f.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-B8p9Mhkw.js → WebAuthn-2Zfcu55P.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-BVsuaPen.js → WorkflowEditor-B9eZ8UxZ.js} +1 -1
- package/src/assets/web-panel/assets/{chat-BfkjoKpV.js → chat-CQNfD-YO.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DeAlsWK8.js → colors-D4usyFT2.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-Cs97bz5j.js → compact-item-s4TpjvjX.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BqbG60LH.js → createContext-BRCSvYxj.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DKJjSWRn.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-i_RY0b1X.js → hasIn-AdkUbkV-.js} +1 -1
- package/src/assets/web-panel/assets/{index-BOVkf1K3.js → index--00U6vXZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-B-3tEpTc.js → index-B2V-eKfK.js} +1 -1
- package/src/assets/web-panel/assets/{index-D2B4VPyP.js → index-B4JJCfQ2.js} +1 -1
- package/src/assets/web-panel/assets/{index-BkBi5TmC.js → index-BIoG5yYf.js} +1 -1
- package/src/assets/web-panel/assets/{index-79V_zv1s.js → index-BMcimU-2.js} +1 -1
- package/src/assets/web-panel/assets/{index-U4f5izHz.js → index-BPhkFZ1I.js} +1 -1
- package/src/assets/web-panel/assets/{index-DiSkx4UB.js → index-BQ3DXBtD.js} +3 -3
- package/src/assets/web-panel/assets/{index-dIHr4B_u.js → index-Bad4VNvz.js} +1 -1
- package/src/assets/web-panel/assets/{index-CIG8fQ2_.js → index-BgiXR_-_.js} +1 -1
- package/src/assets/web-panel/assets/{index-DqBgBpgp.js → index-BtobShro.js} +1 -1
- package/src/assets/web-panel/assets/{index-ZxO_-E8a.js → index-Bw2MEnUk.js} +1 -1
- package/src/assets/web-panel/assets/{index-DUUrv141.js → index-C1mJtE6q.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bm7lLR4c.js → index-C484EJiS.js} +1 -1
- package/src/assets/web-panel/assets/{index-COdGA-8n.js → index-C5KAQFPQ.js} +1 -1
- package/src/assets/web-panel/assets/index-C61cnl3K.js +1 -0
- package/src/assets/web-panel/assets/{index-CED2PL_y.js → index-C7Y8Aluc.js} +1 -1
- package/src/assets/web-panel/assets/{index-YXgLng0K.js → index-CCsM_Ybx.js} +1 -1
- package/src/assets/web-panel/assets/{index-0-agYlWL.js → index-CJCFe2Qf.js} +1 -1
- package/src/assets/web-panel/assets/{index-B5UkyA3c.js → index-CJVEOa4i.js} +1 -1
- package/src/assets/web-panel/assets/{index-B1CbOH1i.js → index-CJdQrZth.js} +1 -1
- package/src/assets/web-panel/assets/{index-s1opAL-M.js → index-CKC1t3Ic.js} +1 -1
- package/src/assets/web-panel/assets/{index-yObj1O4n.js → index-CQhAVU5t.js} +1 -1
- package/src/assets/web-panel/assets/{index-CgsqdnRV.js → index-CYdoQsa1.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dk7-v4hP.js → index-Cduu2Hhr.js} +1 -1
- package/src/assets/web-panel/assets/{index-B-JVTrpr.js → index-CkwiSLhU.js} +1 -1
- package/src/assets/web-panel/assets/{index-CeWoNHau.js → index-Cvyt-zhm.js} +1 -1
- package/src/assets/web-panel/assets/{index-CE2VtTlp.js → index-D2GjI2oe.js} +1 -1
- package/src/assets/web-panel/assets/index-D4XFHxBr.js +1 -0
- package/src/assets/web-panel/assets/{index-DmbfhJUP.js → index-DARsAyUp.js} +1 -1
- package/src/assets/web-panel/assets/{index-BESLFt4q.js → index-DVKfQ0Ux.js} +1 -1
- package/src/assets/web-panel/assets/{index-PT_5sBMA.js → index-DZT36ZYq.js} +1 -1
- package/src/assets/web-panel/assets/{index-gyFpvL7l.js → index-D_XBHopw.js} +1 -1
- package/src/assets/web-panel/assets/{index-BYUVuwKt.js → index-DdCB70SS.js} +1 -1
- package/src/assets/web-panel/assets/{index-BcUXAB2s.js → index-DzRjHxEv.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dk2qouAz.js → index-MMN9V6JF.js} +1 -1
- package/src/assets/web-panel/assets/{index-D9evtvg2.js → index-RfMr79MW.js} +1 -1
- package/src/assets/web-panel/assets/{index-BuLQobzW.js → index-_IRVsV9X.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cf3WCLmy.js → index-nXyk8GZ9.js} +1 -1
- package/src/assets/web-panel/assets/{index-CG3PRyAL.js → index-s_buFMEG.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-C9h9yKL3.js → initDefaultProps-Blmpk7HL.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BvmLsPdu.js → motion-DPBJMv1n.js} +1 -1
- package/src/assets/web-panel/assets/{move-CoL4ekU1.js → move-ButdzCM7.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-C4pMy6xV.js → mtc-parser-cyRC_QCe.js} +1 -1
- package/src/assets/web-panel/assets/{omit-DPuJfNxx.js → omit-1epSV7hz.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-D0KEeaK2.js → pickAttrs-DuPY8xJs.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BpkyINxt.js → placementArrow-6XZqarhe.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-DQI_wOq8.js → responsiveObserve-B40pXBWM.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DYfdDiRg.js → slide-jbZ9Wu4n.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-B5dtvb0D.js → statusUtils-BKQQcVy4.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-CF310mSj.js → styleChecker-NiKfWjUT.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-D1Qp4BLp.js → useFlexGapSupport-bQUCvPeb.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-C7_iyvJK.js → useFs-CUGji7ph.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-DZUt_fIm.js → usePersonalDataHub-4veyN2N2.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-D3dsi0lZ.js → vnode-1-nLug-Z.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-WdbOlvdQ.js → zoom-dhCeRDMo.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +6 -6
- package/src/commands/automation.js +103 -1
- package/src/commands/cowork.js +174 -19
- package/src/commands/permissions.js +240 -16
- package/src/commands/plugin.js +1293 -56
- package/src/commands/session-location.js +276 -0
- package/src/commands/session.js +2 -0
- package/src/commands/team-merge-review.js +937 -0
- package/src/commands/team.js +2 -0
- package/src/data/changelog.json +27 -1
- package/src/gateways/ws/action-protocol.js +35 -10
- package/src/gateways/ws/remote-session-protocol.js +24 -1
- package/src/gateways/ws/ws-agent-handler.js +12 -0
- package/src/gateways/ws/ws-server.js +48 -12
- package/src/harness/jsonl-session-store.js +341 -24
- package/src/harness/mcp-client.js +8 -1
- package/src/harness/remote-session-audit.js +1 -0
- package/src/harness/remote-session-crypto.js +210 -2
- package/src/harness/remote-session-registry.js +159 -6
- package/src/harness/session-list-index.js +233 -14
- package/src/lib/agent-authority.js +6 -0
- package/src/lib/agent-schedule-store.js +139 -28
- package/src/lib/agent-team/team-merge-review-store.js +765 -0
- package/src/lib/agent-team/team-merge-review-transaction.js +1223 -0
- package/src/lib/agent-team/team-merge-review.js +1847 -0
- package/src/lib/automation-center-incidents.js +314 -0
- package/src/lib/automation-center-runtime.js +448 -0
- package/src/lib/automation-center.js +182 -38
- package/src/lib/automation-engine.js +41 -0
- package/src/lib/automation-execution-authority.js +241 -12
- package/src/lib/automation-execution-incident.js +737 -0
- package/src/lib/background-agent-keeper-client.js +248 -0
- package/src/lib/background-agent-keeper-protocol.js +147 -0
- package/src/lib/background-agent-supervisor.js +520 -40
- package/src/lib/background-interaction-resolver.js +12 -0
- package/src/lib/background-turn-bootstrap-protocol.js +126 -0
- package/src/lib/cowork-cron.js +85 -14
- package/src/lib/cowork-workflow.js +336 -16
- package/src/lib/dynamic-workflow-facade.js +648 -0
- package/src/lib/execution-location-contract.js +551 -0
- package/src/lib/execution-location-runtime.js +130 -0
- package/src/lib/ide-context.js +94 -6
- package/src/lib/mcp-stdio-package-materialization.js +166 -14
- package/src/lib/packer/pkg-config-generator.js +2 -0
- package/src/lib/permission-authority.js +77 -0
- package/src/lib/permission-side-effect-center.js +495 -0
- package/src/lib/plugin-runtime/install.js +514 -13
- package/src/lib/plugin-runtime/marketplace-artifact-readback.js +900 -0
- package/src/lib/plugin-runtime/marketplace-catalog.js +1181 -0
- package/src/lib/plugin-runtime/marketplace-impact.js +408 -0
- package/src/lib/plugin-runtime/marketplace-remote-artifacts.js +1567 -0
- package/src/lib/plugin-security.js +60 -3
- package/src/lib/process-execution-broker/index.js +1095 -57
- package/src/lib/process-execution-broker/linux-bwrap-descriptor-launch.js +375 -0
- package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +90 -16
- package/src/lib/process-execution-broker/linux-generic-bwrap.js +159 -18
- package/src/lib/process-execution-broker/macos-mcp-launcher-contract.js +278 -0
- package/src/lib/process-execution-broker/macos-mcp-launcher-protocol.json +23 -0
- package/src/lib/process-execution-broker/macos-mcp-launcher.c +1497 -0
- package/src/lib/process-execution-broker/mcp-fd-entry-bootstrap.js +37 -0
- package/src/lib/process-execution-broker/platform-sandbox.js +2330 -279
- package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
- package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
- package/src/lib/process-execution-broker/windows-sandbox.cs +50 -4
- package/src/lib/public-ide-capability-manifest.js +3 -0
- package/src/lib/remote-approval-bridge.js +123 -17
- package/src/lib/remote-membership-authority.js +632 -0
- package/src/lib/remote-membership-coordinator.js +2409 -0
- package/src/lib/remote-membership-host-store.js +1750 -0
- package/src/lib/scheduler-kernel/agenda-adapter.js +17 -7
- package/src/lib/scheduler-kernel/automation-adapter.js +105 -11
- package/src/lib/scheduler-kernel/automation-event-adapter.js +87 -11
- package/src/lib/scheduler-kernel/contract.js +91 -0
- package/src/lib/scheduler-kernel/cowork-cron-adapter.js +12 -1
- package/src/lib/scheduler-kernel/loop-adapter.js +7 -1
- package/src/lib/scheduler-kernel/routine-adapter.js +7 -1
- package/src/lib/scheduler-kernel/runtime-control-capabilities.js +31 -0
- package/src/lib/scheduler-kernel/runtime.js +176 -3
- package/src/lib/scheduler-kernel/store.js +1253 -45
- package/src/lib/scoped-permission-store.js +369 -0
- package/src/lib/session-anti-rollback-anchor.js +262 -5
- package/src/lib/sub-agent-context.js +4 -0
- package/src/lib/workflow-definition-contract.js +149 -0
- package/src/repl/agent-repl.js +41 -7
- package/src/repl/chat-repl.js +2 -0
- package/src/repl/clipboard-image.js +735 -16
- package/src/repl/ide-status.js +1 -1
- package/src/repl/prompt-interactions.js +59 -6
- package/src/runtime/agent-core.js +93 -3
- package/src/runtime/headless-runner.js +30 -25
- package/src/runtime/headless-stream.js +32 -25
- package/src/runtime/mcp-config.js +81 -10
- package/src/workers/background-agent-keeper.js +498 -0
- package/src/workers/background-agent-worker.js +358 -13
- package/src/workers/background-turn-bootstrap.js +143 -0
- package/src/assets/web-panel/assets/MobileProjects-BWdOvQAj.js +0 -1
- package/src/assets/web-panel/assets/Projects-BV4oApsm.js +0 -1
- package/src/assets/web-panel/assets/devWarning-DPty0mGN.js +0 -1
- package/src/assets/web-panel/assets/index-Bt7g0Vq_.js +0 -1
- package/src/assets/web-panel/assets/index-ChVT0p9u.js +0 -1
|
@@ -1,11 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Clipboard-image capability boundary for terminal REPL hosts.
|
|
3
3
|
*
|
|
4
|
-
* Plain Node readline receives pasted text only
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* a truthful path-attachment fallback instead of a fake "paste succeeded".
|
|
4
|
+
* Plain Node readline receives pasted text only, so standard terminals need a
|
|
5
|
+
* guarded OS adapter to obtain image bytes. Embedded hosts may still inject the
|
|
6
|
+
* same narrow `readImage()` binding used by the production adapter.
|
|
8
7
|
*/
|
|
8
|
+
import {
|
|
9
|
+
accessSync,
|
|
10
|
+
constants as fsConstants,
|
|
11
|
+
lstatSync,
|
|
12
|
+
mkdtempSync,
|
|
13
|
+
readFileSync,
|
|
14
|
+
rmSync,
|
|
15
|
+
statSync,
|
|
16
|
+
writeFileSync,
|
|
17
|
+
} from "node:fs";
|
|
18
|
+
import { tmpdir } from "node:os";
|
|
19
|
+
import { join, posix as posixPath, win32 as win32Path } from "node:path";
|
|
20
|
+
import { executionBroker } from "../lib/process-execution-broker/index.js";
|
|
21
|
+
import {
|
|
22
|
+
ensurePrivateDirectory,
|
|
23
|
+
ensurePrivateFile,
|
|
24
|
+
PRIVATE_FILE_MODE,
|
|
25
|
+
} from "../lib/secure-fs.js";
|
|
9
26
|
|
|
10
27
|
export const CLIPBOARD_IMAGE_MEDIA_TYPES = Object.freeze([
|
|
11
28
|
"image/png",
|
|
@@ -14,16 +31,706 @@ export const CLIPBOARD_IMAGE_MEDIA_TYPES = Object.freeze([
|
|
|
14
31
|
"image/webp",
|
|
15
32
|
]);
|
|
16
33
|
export const MAX_CLIPBOARD_IMAGE_BYTES = 20 * 1024 * 1024;
|
|
34
|
+
export const MAX_CLIPBOARD_IMAGE_ATTACHMENTS = 4;
|
|
35
|
+
export const MAX_CLIPBOARD_IMAGE_TOTAL_BYTES = 40 * 1024 * 1024;
|
|
36
|
+
export const CLIPBOARD_IMAGE_READ_TIMEOUT_MS = 10_000;
|
|
37
|
+
|
|
38
|
+
const MAX_MACOS_SOURCE_BYTES = 80 * 1024 * 1024;
|
|
39
|
+
const MAX_MACOS_IMAGE_PIXELS = 25_000_000;
|
|
40
|
+
const MAX_MACOS_IMAGE_DIMENSION = 16_384;
|
|
41
|
+
const MAX_MACOS_DECODED_IMAGE_BYTES = 256 * 1024 * 1024;
|
|
42
|
+
const MACOS_CLIPBOARD_HELPER_ERROR_STAGES = new Set([
|
|
43
|
+
"arguments",
|
|
44
|
+
"pasteboard",
|
|
45
|
+
"png-read",
|
|
46
|
+
"png-check",
|
|
47
|
+
"tiff-read",
|
|
48
|
+
"tiff-check",
|
|
49
|
+
"tiff-length",
|
|
50
|
+
"tiff-source",
|
|
51
|
+
"tiff-count",
|
|
52
|
+
"tiff-image-create",
|
|
53
|
+
"tiff-image-layout",
|
|
54
|
+
"tiff-color-space",
|
|
55
|
+
"tiff-color-model",
|
|
56
|
+
"tiff-bitmap",
|
|
57
|
+
"tiff-encode",
|
|
58
|
+
"image-length",
|
|
59
|
+
"image-write",
|
|
60
|
+
]);
|
|
61
|
+
|
|
62
|
+
const WINDOWS_CLIPBOARD_IMAGE_SCRIPT = [
|
|
63
|
+
"$ErrorActionPreference='Stop'",
|
|
64
|
+
"Add-Type -AssemblyName System.Windows.Forms",
|
|
65
|
+
"Add-Type -AssemblyName System.Drawing",
|
|
66
|
+
"$image=$null",
|
|
67
|
+
"for ($attempt=0; $attempt -lt 3; $attempt+=1) {",
|
|
68
|
+
" try { $image=[System.Windows.Forms.Clipboard]::GetImage(); break }",
|
|
69
|
+
" catch [System.Runtime.InteropServices.ExternalException] {",
|
|
70
|
+
" if ($attempt -eq 2) { throw }",
|
|
71
|
+
" Start-Sleep -Milliseconds 50",
|
|
72
|
+
" }",
|
|
73
|
+
"}",
|
|
74
|
+
"if ($null -eq $image) { exit 3 }",
|
|
75
|
+
"$stream=New-Object System.IO.MemoryStream",
|
|
76
|
+
"try {",
|
|
77
|
+
" $image.Save($stream,[System.Drawing.Imaging.ImageFormat]::Png)",
|
|
78
|
+
" $bytes=$stream.ToArray()",
|
|
79
|
+
" [Console]::OpenStandardOutput().Write($bytes,0,$bytes.Length)",
|
|
80
|
+
"} finally {",
|
|
81
|
+
" $stream.Dispose()",
|
|
82
|
+
" $image.Dispose()",
|
|
83
|
+
"}",
|
|
84
|
+
].join("\n");
|
|
85
|
+
|
|
86
|
+
const MACOS_CLIPBOARD_IMAGE_SCRIPT = String.raw`
|
|
87
|
+
ObjC.import("AppKit");
|
|
88
|
+
ObjC.import("CoreGraphics");
|
|
89
|
+
ObjC.import("Foundation");
|
|
90
|
+
ObjC.import("ImageIO");
|
|
91
|
+
|
|
92
|
+
function isObjCNil(value) {
|
|
93
|
+
return value == null ||
|
|
94
|
+
(typeof value.isNil === "function" && value.isNil());
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function run(argv) {
|
|
98
|
+
let stage = "arguments";
|
|
99
|
+
try {
|
|
100
|
+
const outputPath = String(argv[0]);
|
|
101
|
+
const maximumBytes = Number(argv[1]);
|
|
102
|
+
const maximumSourceBytes = Number(argv[2]);
|
|
103
|
+
const maximumPixels = Number(argv[3]);
|
|
104
|
+
const maximumDimension = Number(argv[4]);
|
|
105
|
+
const maximumDecodedBytes = Number(argv[5]);
|
|
106
|
+
if (
|
|
107
|
+
outputPath.length < 1 ||
|
|
108
|
+
!Number.isSafeInteger(maximumBytes) ||
|
|
109
|
+
!Number.isSafeInteger(maximumSourceBytes) ||
|
|
110
|
+
!Number.isSafeInteger(maximumPixels) ||
|
|
111
|
+
!Number.isSafeInteger(maximumDimension) ||
|
|
112
|
+
!Number.isSafeInteger(maximumDecodedBytes) ||
|
|
113
|
+
maximumBytes <= 0 ||
|
|
114
|
+
maximumSourceBytes <= 0 ||
|
|
115
|
+
maximumPixels <= 0 ||
|
|
116
|
+
maximumDimension <= 0 ||
|
|
117
|
+
maximumDecodedBytes <= 0
|
|
118
|
+
) {
|
|
119
|
+
return "invalid:arguments";
|
|
120
|
+
}
|
|
121
|
+
stage = "pasteboard";
|
|
122
|
+
const pasteboard = $.NSPasteboard.generalPasteboard;
|
|
123
|
+
stage = "png-read";
|
|
124
|
+
let imageData = pasteboard.dataForType($.NSPasteboardTypePNG);
|
|
125
|
+
let imageKind = "png";
|
|
126
|
+
stage = "png-check";
|
|
127
|
+
if (isObjCNil(imageData)) {
|
|
128
|
+
stage = "tiff-read";
|
|
129
|
+
const tiffData = pasteboard.dataForType($.NSPasteboardTypeTIFF);
|
|
130
|
+
stage = "tiff-check";
|
|
131
|
+
if (isObjCNil(tiffData)) return "none";
|
|
132
|
+
stage = "tiff-length";
|
|
133
|
+
const tiffBytes = Number(tiffData.length);
|
|
134
|
+
if (!Number.isSafeInteger(tiffBytes) || tiffBytes <= 0) {
|
|
135
|
+
return "invalid:tiff-length";
|
|
136
|
+
}
|
|
137
|
+
if (tiffBytes > maximumSourceBytes) return "too-large:tiff-source";
|
|
138
|
+
stage = "tiff-source";
|
|
139
|
+
const imageSource = $.CGImageSourceCreateWithData(tiffData, $());
|
|
140
|
+
stage = "tiff-count";
|
|
141
|
+
const imageCount = isObjCNil(imageSource)
|
|
142
|
+
? 0
|
|
143
|
+
: Number($.CGImageSourceGetCount(imageSource));
|
|
144
|
+
if (
|
|
145
|
+
isObjCNil(imageSource) ||
|
|
146
|
+
!Number.isSafeInteger(imageCount) ||
|
|
147
|
+
imageCount < 1
|
|
148
|
+
) {
|
|
149
|
+
return "invalid:tiff-source";
|
|
150
|
+
}
|
|
151
|
+
// ImageIO defaults immediate caching to false, so the CGImage remains
|
|
152
|
+
// lazy through the scalar getters. Rendering/encoding is reached only
|
|
153
|
+
// after every layout bound below passes.
|
|
154
|
+
stage = "tiff-image-create";
|
|
155
|
+
const cgImage = $.CGImageSourceCreateImageAtIndex(imageSource, 0, $());
|
|
156
|
+
if (isObjCNil(cgImage)) return "invalid:tiff-image-create";
|
|
157
|
+
stage = "tiff-image-layout";
|
|
158
|
+
const imageIsMask = Number($.CGImageIsMask(cgImage));
|
|
159
|
+
if (
|
|
160
|
+
!Number.isSafeInteger(imageIsMask) ||
|
|
161
|
+
(imageIsMask !== 0 && imageIsMask !== 1)
|
|
162
|
+
) {
|
|
163
|
+
return "invalid:tiff-image-layout";
|
|
164
|
+
}
|
|
165
|
+
if (imageIsMask === 1) {
|
|
166
|
+
return "invalid:tiff-image-mask";
|
|
167
|
+
}
|
|
168
|
+
const width = Number($.CGImageGetWidth(cgImage));
|
|
169
|
+
const height = Number($.CGImageGetHeight(cgImage));
|
|
170
|
+
const bitsPerComponent = Number($.CGImageGetBitsPerComponent(cgImage));
|
|
171
|
+
const bitsPerPixel = Number($.CGImageGetBitsPerPixel(cgImage));
|
|
172
|
+
const bytesPerRow = Number($.CGImageGetBytesPerRow(cgImage));
|
|
173
|
+
if (
|
|
174
|
+
!Number.isSafeInteger(width) ||
|
|
175
|
+
!Number.isSafeInteger(height) ||
|
|
176
|
+
!Number.isSafeInteger(bitsPerComponent) ||
|
|
177
|
+
!Number.isSafeInteger(bitsPerPixel) ||
|
|
178
|
+
!Number.isSafeInteger(bytesPerRow) ||
|
|
179
|
+
width <= 0 ||
|
|
180
|
+
height <= 0 ||
|
|
181
|
+
bitsPerComponent <= 0 ||
|
|
182
|
+
bitsPerPixel <= 0 ||
|
|
183
|
+
bytesPerRow <= 0
|
|
184
|
+
) {
|
|
185
|
+
return "invalid:tiff-image-layout";
|
|
186
|
+
}
|
|
187
|
+
if (
|
|
188
|
+
width > maximumDimension ||
|
|
189
|
+
height > maximumDimension ||
|
|
190
|
+
width > Math.floor(maximumPixels / height) ||
|
|
191
|
+
bitsPerComponent > 16 ||
|
|
192
|
+
bitsPerPixel > 64 ||
|
|
193
|
+
bytesPerRow > Math.floor(maximumDecodedBytes / height)
|
|
194
|
+
) {
|
|
195
|
+
return "too-large:tiff-image-layout";
|
|
196
|
+
}
|
|
197
|
+
if (bytesPerRow < Math.ceil((width * bitsPerPixel) / 8)) {
|
|
198
|
+
return "invalid:tiff-image-layout";
|
|
199
|
+
}
|
|
200
|
+
stage = "tiff-color-space";
|
|
201
|
+
const colorSpace = $.CGImageGetColorSpace(cgImage);
|
|
202
|
+
if (isObjCNil(colorSpace)) return "invalid:tiff-color-space";
|
|
203
|
+
stage = "tiff-color-model";
|
|
204
|
+
const colorModel = Number($.CGColorSpaceGetModel(colorSpace));
|
|
205
|
+
const isRgb = colorModel === Number($.kCGColorSpaceModelRGB);
|
|
206
|
+
const isMonochrome =
|
|
207
|
+
colorModel === Number($.kCGColorSpaceModelMonochrome);
|
|
208
|
+
if (!isRgb && !isMonochrome) {
|
|
209
|
+
return "invalid:unsupported-color-model";
|
|
210
|
+
}
|
|
211
|
+
if (bitsPerPixel < (isRgb ? 3 : 1) * bitsPerComponent) {
|
|
212
|
+
return "invalid:tiff-image-layout";
|
|
213
|
+
}
|
|
214
|
+
const normalizedBytesPerPixel =
|
|
215
|
+
(isRgb ? 4 : 2) * Math.ceil(bitsPerComponent / 8);
|
|
216
|
+
if (
|
|
217
|
+
width >
|
|
218
|
+
Math.floor(
|
|
219
|
+
maximumDecodedBytes / (height * normalizedBytesPerPixel),
|
|
220
|
+
)
|
|
221
|
+
) {
|
|
222
|
+
return "too-large:tiff-image-layout";
|
|
223
|
+
}
|
|
224
|
+
stage = "tiff-bitmap";
|
|
225
|
+
const bitmap = $.NSBitmapImageRep.alloc.initWithCGImage(cgImage);
|
|
226
|
+
if (isObjCNil(bitmap)) return "invalid:tiff-bitmap";
|
|
227
|
+
stage = "tiff-encode";
|
|
228
|
+
imageData = bitmap.representationUsingTypeProperties(4, $({}));
|
|
229
|
+
if (isObjCNil(imageData)) return "invalid:tiff-encode";
|
|
230
|
+
imageKind = "tiff-png";
|
|
231
|
+
}
|
|
232
|
+
stage = "image-length";
|
|
233
|
+
const imageBytes = Number(imageData.length);
|
|
234
|
+
if (!Number.isSafeInteger(imageBytes) || imageBytes <= 0) {
|
|
235
|
+
return "invalid:image-length";
|
|
236
|
+
}
|
|
237
|
+
if (imageBytes > maximumBytes) return "too-large:image-bytes";
|
|
238
|
+
stage = "image-write";
|
|
239
|
+
if (!imageData.writeToFileAtomically($(outputPath), true)) {
|
|
240
|
+
return "invalid:image-write";
|
|
241
|
+
}
|
|
242
|
+
return imageKind;
|
|
243
|
+
} catch (error) {
|
|
244
|
+
return "error:" + stage;
|
|
245
|
+
}
|
|
246
|
+
}`;
|
|
247
|
+
|
|
248
|
+
const defaultSystemDeps = {
|
|
249
|
+
accessSync,
|
|
250
|
+
ensurePrivateDirectory,
|
|
251
|
+
ensurePrivateFile,
|
|
252
|
+
lstatSync,
|
|
253
|
+
mkdtempSync,
|
|
254
|
+
readFileSync,
|
|
255
|
+
rmSync,
|
|
256
|
+
spawnSync: (...args) => executionBroker.spawnSync(...args),
|
|
257
|
+
statSync,
|
|
258
|
+
tmpdir,
|
|
259
|
+
writeFileSync,
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
function canExecute(filePath, deps) {
|
|
263
|
+
if (!filePath) return false;
|
|
264
|
+
try {
|
|
265
|
+
deps.accessSync(filePath, fsConstants.X_OK);
|
|
266
|
+
return true;
|
|
267
|
+
} catch {
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function executableFromPath(name, { env, platform, deps }) {
|
|
273
|
+
const pathValue = String(env.PATH || env.Path || "");
|
|
274
|
+
if (!pathValue) return null;
|
|
275
|
+
const separator = platform === "win32" ? ";" : ":";
|
|
276
|
+
const pathJoin = platform === "win32" ? win32Path.join : posixPath.join;
|
|
277
|
+
const extensions =
|
|
278
|
+
platform === "win32"
|
|
279
|
+
? String(env.PATHEXT || ".EXE;.CMD;.BAT")
|
|
280
|
+
.split(";")
|
|
281
|
+
.filter(Boolean)
|
|
282
|
+
: [""];
|
|
283
|
+
for (const rawDirectory of pathValue.split(separator)) {
|
|
284
|
+
const directory = rawDirectory.trim().replace(/^"|"$/gu, "");
|
|
285
|
+
if (!directory) continue;
|
|
286
|
+
for (const extension of extensions) {
|
|
287
|
+
const candidate = pathJoin(directory, `${name}${extension}`);
|
|
288
|
+
if (canExecute(candidate, deps)) return candidate;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return null;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/** Resolve the guarded native tools without spawning an untrusted probe. */
|
|
295
|
+
export function resolveSystemClipboardImageTools(options = {}) {
|
|
296
|
+
const platform = options.platform || process.platform;
|
|
297
|
+
const env = options.env || process.env;
|
|
298
|
+
const deps = { ...defaultSystemDeps, ...(options.deps || {}) };
|
|
299
|
+
if (platform === "darwin") {
|
|
300
|
+
const osascript = "/usr/bin/osascript";
|
|
301
|
+
return canExecute(osascript, deps)
|
|
302
|
+
? { supported: true, executables: { osascript } }
|
|
303
|
+
: {
|
|
304
|
+
supported: false,
|
|
305
|
+
reason: "macOS clipboard image helper is unavailable.",
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
if (platform === "win32") {
|
|
309
|
+
const systemRootValue = String(env.SystemRoot || env.WINDIR || "");
|
|
310
|
+
const systemRoot = /^[A-Za-z]:\\[^\r\n<>"|?*]+$/u.test(systemRootValue)
|
|
311
|
+
? systemRootValue
|
|
312
|
+
: "C:\\Windows";
|
|
313
|
+
const windowsPowerShell = win32Path.join(
|
|
314
|
+
systemRoot,
|
|
315
|
+
"System32",
|
|
316
|
+
"WindowsPowerShell",
|
|
317
|
+
"v1.0",
|
|
318
|
+
"powershell.exe",
|
|
319
|
+
);
|
|
320
|
+
const powershell = canExecute(windowsPowerShell, deps)
|
|
321
|
+
? windowsPowerShell
|
|
322
|
+
: executableFromPath("pwsh", { env, platform, deps });
|
|
323
|
+
return powershell
|
|
324
|
+
? { supported: true, executables: { powershell } }
|
|
325
|
+
: {
|
|
326
|
+
supported: false,
|
|
327
|
+
reason: "Windows PowerShell clipboard image support is unavailable.",
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
if (platform === "linux") {
|
|
331
|
+
if (!env.WAYLAND_DISPLAY && !env.DISPLAY) {
|
|
332
|
+
return {
|
|
333
|
+
supported: false,
|
|
334
|
+
reason: "No Wayland or X11 clipboard display is available.",
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
const wlPaste = env.WAYLAND_DISPLAY
|
|
338
|
+
? executableFromPath("wl-paste", { env, platform, deps })
|
|
339
|
+
: null;
|
|
340
|
+
const xclip = env.DISPLAY
|
|
341
|
+
? executableFromPath("xclip", { env, platform, deps })
|
|
342
|
+
: null;
|
|
343
|
+
return wlPaste || xclip
|
|
344
|
+
? { supported: true, executables: { wlPaste, xclip } }
|
|
345
|
+
: {
|
|
346
|
+
supported: false,
|
|
347
|
+
reason: "No Wayland or X11 clipboard image reader is available.",
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
return {
|
|
351
|
+
supported: false,
|
|
352
|
+
reason: `System clipboard image reading is unsupported on ${platform}.`,
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function boundedPositiveInteger(
|
|
357
|
+
value,
|
|
358
|
+
fallback,
|
|
359
|
+
maximum = Number.MAX_SAFE_INTEGER,
|
|
360
|
+
) {
|
|
361
|
+
const parsed = Number(value);
|
|
362
|
+
if (!Number.isSafeInteger(parsed) || parsed <= 0) return fallback;
|
|
363
|
+
return Math.min(parsed, maximum);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function commandFailure(result, tool) {
|
|
367
|
+
if (result?.error?.code === "ENOENT") return `${tool} is unavailable.`;
|
|
368
|
+
if (result?.error?.code === "ETIMEDOUT") {
|
|
369
|
+
return "System clipboard image read timed out.";
|
|
370
|
+
}
|
|
371
|
+
if (result?.signal) return `${tool} clipboard image helper was terminated.`;
|
|
372
|
+
return `${tool} clipboard image helper exited with status ${String(result?.status)}.`;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function isOutputLimitError(error) {
|
|
376
|
+
return (
|
|
377
|
+
error?.code === "ENOBUFS" ||
|
|
378
|
+
/maxbuffer/iu.test(String(error?.message || ""))
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function normalizeStdout(value) {
|
|
383
|
+
if (Buffer.isBuffer(value)) return value;
|
|
384
|
+
if (value instanceof Uint8Array) return Buffer.from(value);
|
|
385
|
+
if (typeof value === "string") return Buffer.from(value, "binary");
|
|
386
|
+
return Buffer.alloc(0);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/** Return the media type identified by image magic bytes, or `null`. */
|
|
390
|
+
export function detectClipboardImageMediaType(value) {
|
|
391
|
+
const data = Buffer.isBuffer(value) ? value : Buffer.from(value || []);
|
|
392
|
+
if (
|
|
393
|
+
data.length >= 8 &&
|
|
394
|
+
data
|
|
395
|
+
.subarray(0, 8)
|
|
396
|
+
.equals(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]))
|
|
397
|
+
) {
|
|
398
|
+
return "image/png";
|
|
399
|
+
}
|
|
400
|
+
if (
|
|
401
|
+
data.length >= 3 &&
|
|
402
|
+
data[0] === 0xff &&
|
|
403
|
+
data[1] === 0xd8 &&
|
|
404
|
+
data[2] === 0xff
|
|
405
|
+
) {
|
|
406
|
+
return "image/jpeg";
|
|
407
|
+
}
|
|
408
|
+
if (
|
|
409
|
+
data.length >= 6 &&
|
|
410
|
+
(data.subarray(0, 6).equals(Buffer.from("GIF87a", "ascii")) ||
|
|
411
|
+
data.subarray(0, 6).equals(Buffer.from("GIF89a", "ascii")))
|
|
412
|
+
) {
|
|
413
|
+
return "image/gif";
|
|
414
|
+
}
|
|
415
|
+
if (
|
|
416
|
+
data.length >= 12 &&
|
|
417
|
+
data.subarray(0, 4).equals(Buffer.from("RIFF", "ascii")) &&
|
|
418
|
+
data.subarray(8, 12).equals(Buffer.from("WEBP", "ascii"))
|
|
419
|
+
) {
|
|
420
|
+
return "image/webp";
|
|
421
|
+
}
|
|
422
|
+
return null;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/** Ordered binary clipboard readers for platforms that expose stdout bytes. */
|
|
426
|
+
export function systemClipboardImageCommands(
|
|
427
|
+
platform = process.platform,
|
|
428
|
+
executables = {},
|
|
429
|
+
) {
|
|
430
|
+
if (platform === "win32") {
|
|
431
|
+
return executables.powershell
|
|
432
|
+
? [
|
|
433
|
+
{
|
|
434
|
+
cmd: executables.powershell,
|
|
435
|
+
args: [
|
|
436
|
+
"-NoLogo",
|
|
437
|
+
"-NoProfile",
|
|
438
|
+
"-NonInteractive",
|
|
439
|
+
"-Sta",
|
|
440
|
+
"-Command",
|
|
441
|
+
WINDOWS_CLIPBOARD_IMAGE_SCRIPT,
|
|
442
|
+
],
|
|
443
|
+
mediaType: "image/png",
|
|
444
|
+
noImageStatus: 3,
|
|
445
|
+
},
|
|
446
|
+
]
|
|
447
|
+
: [];
|
|
448
|
+
}
|
|
449
|
+
if (platform === "linux") {
|
|
450
|
+
const requestedTypes = [
|
|
451
|
+
["image/png", "image/png"],
|
|
452
|
+
["image/jpeg", "image/jpeg"],
|
|
453
|
+
["image/jpg", "image/jpeg"],
|
|
454
|
+
["image/gif", "image/gif"],
|
|
455
|
+
["image/webp", "image/webp"],
|
|
456
|
+
];
|
|
457
|
+
const readers = [];
|
|
458
|
+
if (executables.wlPaste) {
|
|
459
|
+
readers.push(
|
|
460
|
+
...requestedTypes.map(([requestedType, mediaType]) => ({
|
|
461
|
+
cmd: executables.wlPaste,
|
|
462
|
+
args: ["--no-newline", "--type", requestedType],
|
|
463
|
+
mediaType,
|
|
464
|
+
})),
|
|
465
|
+
);
|
|
466
|
+
}
|
|
467
|
+
if (executables.xclip) {
|
|
468
|
+
readers.push(
|
|
469
|
+
...requestedTypes.map(([requestedType, mediaType]) => ({
|
|
470
|
+
cmd: executables.xclip,
|
|
471
|
+
args: ["-selection", "clipboard", "-t", requestedType, "-o"],
|
|
472
|
+
mediaType,
|
|
473
|
+
})),
|
|
474
|
+
);
|
|
475
|
+
}
|
|
476
|
+
return readers;
|
|
477
|
+
}
|
|
478
|
+
return [];
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function spawnClipboardReader(deps, candidate, { maxBytes, timeoutMs }) {
|
|
482
|
+
return deps.spawnSync(candidate.cmd, candidate.args, {
|
|
483
|
+
encoding: null,
|
|
484
|
+
maxBuffer: maxBytes + 64 * 1024,
|
|
485
|
+
timeout: timeoutMs,
|
|
486
|
+
windowsHide: true,
|
|
487
|
+
origin: "repl:clipboard-image",
|
|
488
|
+
policy: "allow",
|
|
489
|
+
scope: "clipboard",
|
|
490
|
+
shell: false,
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function readCommandClipboardImage(platform, deps, options) {
|
|
495
|
+
const candidates = systemClipboardImageCommands(
|
|
496
|
+
platform,
|
|
497
|
+
options.executables,
|
|
498
|
+
);
|
|
499
|
+
let commandStarted = false;
|
|
500
|
+
let lastFailure = "No supported system clipboard image tool is available.";
|
|
501
|
+
const deadline = Date.now() + options.timeoutMs;
|
|
502
|
+
for (const candidate of candidates) {
|
|
503
|
+
const remainingMs = deadline - Date.now();
|
|
504
|
+
if (remainingMs <= 0) {
|
|
505
|
+
throw new Error("System clipboard image read timed out.");
|
|
506
|
+
}
|
|
507
|
+
let result;
|
|
508
|
+
try {
|
|
509
|
+
result = spawnClipboardReader(deps, candidate, {
|
|
510
|
+
...options,
|
|
511
|
+
timeoutMs: remainingMs,
|
|
512
|
+
});
|
|
513
|
+
} catch (error) {
|
|
514
|
+
if (isOutputLimitError(error)) {
|
|
515
|
+
throw new Error(`Clipboard image exceeds ${options.maxBytes} bytes.`);
|
|
516
|
+
}
|
|
517
|
+
if (error?.code === "ETIMEDOUT") {
|
|
518
|
+
throw new Error("System clipboard image read timed out.");
|
|
519
|
+
}
|
|
520
|
+
lastFailure = `${candidate.cmd} clipboard image helper could not start.`;
|
|
521
|
+
continue;
|
|
522
|
+
}
|
|
523
|
+
if (result?.error) {
|
|
524
|
+
if (isOutputLimitError(result.error)) {
|
|
525
|
+
throw new Error(`Clipboard image exceeds ${options.maxBytes} bytes.`);
|
|
526
|
+
}
|
|
527
|
+
if (result.error.code !== "ENOENT") commandStarted = true;
|
|
528
|
+
lastFailure = commandFailure(result, candidate.cmd);
|
|
529
|
+
if (result.error.code === "ETIMEDOUT") throw new Error(lastFailure);
|
|
530
|
+
continue;
|
|
531
|
+
}
|
|
532
|
+
commandStarted = true;
|
|
533
|
+
if (result?.status === candidate.noImageStatus) return null;
|
|
534
|
+
if (result?.status !== 0 || result?.signal) {
|
|
535
|
+
lastFailure = commandFailure(result, candidate.cmd);
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
const data = normalizeStdout(result.stdout);
|
|
539
|
+
if (!data.length) continue;
|
|
540
|
+
if (data.length > options.maxBytes) {
|
|
541
|
+
throw new Error(`Clipboard image exceeds ${options.maxBytes} bytes.`);
|
|
542
|
+
}
|
|
543
|
+
return { mediaType: candidate.mediaType, data, tool: candidate.cmd };
|
|
544
|
+
}
|
|
545
|
+
if (!commandStarted) throw new Error(lastFailure);
|
|
546
|
+
if (platform === "win32") throw new Error(lastFailure);
|
|
547
|
+
return null;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
function requirePrivateRegularFile(filePath, deps) {
|
|
551
|
+
const fileStat = deps.lstatSync(filePath);
|
|
552
|
+
if (!fileStat.isFile() || fileStat.isSymbolicLink()) {
|
|
553
|
+
throw new Error("Clipboard helper did not produce a regular private file.");
|
|
554
|
+
}
|
|
555
|
+
deps.ensurePrivateFile(filePath, {
|
|
556
|
+
applyWindowsAcl: false,
|
|
557
|
+
failIfUnavailable: true,
|
|
558
|
+
});
|
|
559
|
+
return deps.statSync(filePath);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
function readMacosClipboardImage(deps, options) {
|
|
563
|
+
let directory = null;
|
|
564
|
+
try {
|
|
565
|
+
directory = deps.mkdtempSync(join(deps.tmpdir(), "cc-clipboard-image-"));
|
|
566
|
+
deps.ensurePrivateDirectory(directory, {
|
|
567
|
+
applyWindowsAcl: false,
|
|
568
|
+
failIfUnavailable: true,
|
|
569
|
+
});
|
|
570
|
+
const pngPath = join(directory, "clipboard.png");
|
|
571
|
+
deps.writeFileSync(pngPath, Buffer.alloc(0), {
|
|
572
|
+
mode: PRIVATE_FILE_MODE,
|
|
573
|
+
});
|
|
574
|
+
deps.ensurePrivateFile(pngPath, {
|
|
575
|
+
applyWindowsAcl: false,
|
|
576
|
+
failIfUnavailable: true,
|
|
577
|
+
});
|
|
578
|
+
|
|
579
|
+
const readResult = deps.spawnSync(
|
|
580
|
+
options.executables.osascript,
|
|
581
|
+
[
|
|
582
|
+
"-l",
|
|
583
|
+
"JavaScript",
|
|
584
|
+
"-e",
|
|
585
|
+
MACOS_CLIPBOARD_IMAGE_SCRIPT,
|
|
586
|
+
"--",
|
|
587
|
+
pngPath,
|
|
588
|
+
String(options.maxBytes),
|
|
589
|
+
String(MAX_MACOS_SOURCE_BYTES),
|
|
590
|
+
String(MAX_MACOS_IMAGE_PIXELS),
|
|
591
|
+
String(MAX_MACOS_IMAGE_DIMENSION),
|
|
592
|
+
String(MAX_MACOS_DECODED_IMAGE_BYTES),
|
|
593
|
+
],
|
|
594
|
+
{
|
|
595
|
+
encoding: "utf8",
|
|
596
|
+
maxBuffer: 64 * 1024,
|
|
597
|
+
timeout: options.timeoutMs,
|
|
598
|
+
windowsHide: true,
|
|
599
|
+
origin: "repl:clipboard-image",
|
|
600
|
+
policy: "allow",
|
|
601
|
+
scope: "clipboard",
|
|
602
|
+
shell: false,
|
|
603
|
+
},
|
|
604
|
+
);
|
|
605
|
+
if (readResult?.error || readResult?.signal || readResult?.status !== 0) {
|
|
606
|
+
throw new Error(commandFailure(readResult, "osascript"));
|
|
607
|
+
}
|
|
608
|
+
const imageKind = String(readResult.stdout || "")
|
|
609
|
+
.trim()
|
|
610
|
+
.toLowerCase();
|
|
611
|
+
if (imageKind === "none") return null;
|
|
612
|
+
if (imageKind === "too-large" || imageKind.startsWith("too-large:")) {
|
|
613
|
+
throw new Error(`Clipboard image exceeds ${options.maxBytes} bytes.`);
|
|
614
|
+
}
|
|
615
|
+
if (imageKind === "invalid" || imageKind.startsWith("invalid:")) {
|
|
616
|
+
const stageValue = imageKind.includes(":")
|
|
617
|
+
? imageKind.slice(imageKind.indexOf(":") + 1)
|
|
618
|
+
: "";
|
|
619
|
+
const stage = /^[a-z][a-z-]{0,63}$/u.test(stageValue)
|
|
620
|
+
? ` (${stageValue})`
|
|
621
|
+
: "";
|
|
622
|
+
throw new Error(
|
|
623
|
+
`macOS clipboard helper returned invalid image data${stage}.`,
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
if (imageKind.startsWith("error:")) {
|
|
627
|
+
const stageValue = imageKind.slice("error:".length);
|
|
628
|
+
const stage = MACOS_CLIPBOARD_HELPER_ERROR_STAGES.has(stageValue)
|
|
629
|
+
? ` (${stageValue})`
|
|
630
|
+
: "";
|
|
631
|
+
throw new Error(`macOS clipboard helper failed${stage}.`);
|
|
632
|
+
}
|
|
633
|
+
if (imageKind !== "png" && imageKind !== "tiff-png") {
|
|
634
|
+
throw new Error("macOS clipboard helper returned an invalid image kind.");
|
|
635
|
+
}
|
|
636
|
+
const finalStat = requirePrivateRegularFile(pngPath, deps);
|
|
637
|
+
if (finalStat.size <= 0)
|
|
638
|
+
throw new Error("The clipboard image payload is empty.");
|
|
639
|
+
if (finalStat.size > options.maxBytes) {
|
|
640
|
+
throw new Error(`Clipboard image exceeds ${options.maxBytes} bytes.`);
|
|
641
|
+
}
|
|
642
|
+
return {
|
|
643
|
+
mediaType: "image/png",
|
|
644
|
+
data: deps.readFileSync(pngPath),
|
|
645
|
+
tool: imageKind === "png" ? "osascript" : "osascript+jxa-tiff",
|
|
646
|
+
};
|
|
647
|
+
} finally {
|
|
648
|
+
if (directory) {
|
|
649
|
+
try {
|
|
650
|
+
deps.rmSync(directory, { recursive: true, force: true });
|
|
651
|
+
} catch {
|
|
652
|
+
// The directory is owner-private; cleanup remains best effort.
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/** Read one bounded image from the current user's system clipboard. */
|
|
659
|
+
export function readSystemClipboardImage(options = {}) {
|
|
660
|
+
const platform = options.platform || process.platform;
|
|
661
|
+
const maxBytes = boundedPositiveInteger(
|
|
662
|
+
options.maxBytes,
|
|
663
|
+
MAX_CLIPBOARD_IMAGE_BYTES,
|
|
664
|
+
MAX_CLIPBOARD_IMAGE_BYTES,
|
|
665
|
+
);
|
|
666
|
+
const timeoutMs = boundedPositiveInteger(
|
|
667
|
+
options.timeoutMs,
|
|
668
|
+
CLIPBOARD_IMAGE_READ_TIMEOUT_MS,
|
|
669
|
+
30_000,
|
|
670
|
+
);
|
|
671
|
+
const deps = { ...defaultSystemDeps, ...(options.deps || {}) };
|
|
672
|
+
const resolution = options.executables
|
|
673
|
+
? { supported: true, executables: options.executables }
|
|
674
|
+
: resolveSystemClipboardImageTools({
|
|
675
|
+
platform,
|
|
676
|
+
env: options.env || process.env,
|
|
677
|
+
deps,
|
|
678
|
+
});
|
|
679
|
+
if (!resolution.supported) {
|
|
680
|
+
throw new Error(resolution.reason);
|
|
681
|
+
}
|
|
682
|
+
const executionOptions = {
|
|
683
|
+
maxBytes,
|
|
684
|
+
timeoutMs,
|
|
685
|
+
executables: resolution.executables,
|
|
686
|
+
};
|
|
687
|
+
if (platform === "darwin") {
|
|
688
|
+
return readMacosClipboardImage(deps, executionOptions);
|
|
689
|
+
}
|
|
690
|
+
if (platform === "win32" || platform === "linux") {
|
|
691
|
+
return readCommandClipboardImage(platform, deps, executionOptions);
|
|
692
|
+
}
|
|
693
|
+
throw new Error(
|
|
694
|
+
`System clipboard image reading is unsupported on ${platform}.`,
|
|
695
|
+
);
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/** Create the production binding injected into a standard terminal REPL. */
|
|
699
|
+
export function createSystemClipboardImageBinding(options = {}) {
|
|
700
|
+
const platform = options.platform || process.platform;
|
|
701
|
+
const deps = { ...defaultSystemDeps, ...(options.deps || {}) };
|
|
702
|
+
const resolution = resolveSystemClipboardImageTools({
|
|
703
|
+
platform,
|
|
704
|
+
env: options.env || process.env,
|
|
705
|
+
deps,
|
|
706
|
+
});
|
|
707
|
+
if (!resolution.supported) return null;
|
|
708
|
+
return Object.freeze({
|
|
709
|
+
supportsImagePaste: true,
|
|
710
|
+
mode: "system-clipboard",
|
|
711
|
+
platform,
|
|
712
|
+
readImage: async () =>
|
|
713
|
+
readSystemClipboardImage({
|
|
714
|
+
...options,
|
|
715
|
+
platform,
|
|
716
|
+
deps,
|
|
717
|
+
executables: resolution.executables,
|
|
718
|
+
}),
|
|
719
|
+
});
|
|
720
|
+
}
|
|
17
721
|
|
|
18
722
|
export function detectClipboardImageCapability(binding) {
|
|
19
723
|
if (
|
|
20
724
|
binding?.supportsImagePaste === true &&
|
|
21
725
|
typeof binding.readImage === "function"
|
|
22
726
|
) {
|
|
727
|
+
const systemClipboard = binding.mode === "system-clipboard";
|
|
23
728
|
return {
|
|
24
729
|
supported: true,
|
|
25
|
-
mode: "host-binding",
|
|
26
|
-
reason:
|
|
730
|
+
mode: systemClipboard ? "system-clipboard" : "host-binding",
|
|
731
|
+
reason: systemClipboard
|
|
732
|
+
? "The CLI can read clipboard image bytes through guarded platform tools."
|
|
733
|
+
: "The terminal host exposes clipboard image bytes.",
|
|
27
734
|
};
|
|
28
735
|
}
|
|
29
736
|
return {
|
|
@@ -61,15 +768,15 @@ export async function readClipboardImageChip(binding, options = {}) {
|
|
|
61
768
|
return {
|
|
62
769
|
ok: false,
|
|
63
770
|
supported: true,
|
|
64
|
-
mode:
|
|
65
|
-
reason: `Clipboard image read failed: ${error
|
|
771
|
+
mode: capability.mode,
|
|
772
|
+
reason: `Clipboard image read failed: ${error?.message || String(error)}`,
|
|
66
773
|
};
|
|
67
774
|
}
|
|
68
775
|
if (!image) {
|
|
69
776
|
return {
|
|
70
777
|
ok: false,
|
|
71
778
|
supported: true,
|
|
72
|
-
mode:
|
|
779
|
+
mode: capability.mode,
|
|
73
780
|
reason: "The clipboard does not currently contain an image.",
|
|
74
781
|
};
|
|
75
782
|
}
|
|
@@ -78,7 +785,7 @@ export async function readClipboardImageChip(binding, options = {}) {
|
|
|
78
785
|
return {
|
|
79
786
|
ok: false,
|
|
80
787
|
supported: true,
|
|
81
|
-
mode:
|
|
788
|
+
mode: capability.mode,
|
|
82
789
|
reason: `Unsupported clipboard image type: ${mediaType || "unknown"}.`,
|
|
83
790
|
};
|
|
84
791
|
}
|
|
@@ -87,26 +794,38 @@ export async function readClipboardImageChip(binding, options = {}) {
|
|
|
87
794
|
return {
|
|
88
795
|
ok: false,
|
|
89
796
|
supported: true,
|
|
90
|
-
mode:
|
|
797
|
+
mode: capability.mode,
|
|
91
798
|
reason: "The clipboard image payload is empty or invalid.",
|
|
92
799
|
};
|
|
93
800
|
}
|
|
94
|
-
const maxBytes =
|
|
95
|
-
|
|
96
|
-
|
|
801
|
+
const maxBytes = boundedPositiveInteger(
|
|
802
|
+
options.maxBytes,
|
|
803
|
+
MAX_CLIPBOARD_IMAGE_BYTES,
|
|
804
|
+
MAX_CLIPBOARD_IMAGE_BYTES,
|
|
97
805
|
);
|
|
98
806
|
if (data.length > maxBytes) {
|
|
99
807
|
return {
|
|
100
808
|
ok: false,
|
|
101
809
|
supported: true,
|
|
102
|
-
mode:
|
|
810
|
+
mode: capability.mode,
|
|
103
811
|
reason: `Clipboard image exceeds ${maxBytes} bytes.`,
|
|
104
812
|
};
|
|
105
813
|
}
|
|
814
|
+
const detectedMediaType = detectClipboardImageMediaType(data);
|
|
815
|
+
if (detectedMediaType !== mediaType) {
|
|
816
|
+
return {
|
|
817
|
+
ok: false,
|
|
818
|
+
supported: true,
|
|
819
|
+
mode: capability.mode,
|
|
820
|
+
reason: detectedMediaType
|
|
821
|
+
? `Clipboard image signature is ${detectedMediaType}, not ${mediaType}.`
|
|
822
|
+
: "Clipboard image signature is invalid or unsupported.",
|
|
823
|
+
};
|
|
824
|
+
}
|
|
106
825
|
return {
|
|
107
826
|
ok: true,
|
|
108
827
|
supported: true,
|
|
109
|
-
mode:
|
|
828
|
+
mode: capability.mode,
|
|
110
829
|
bytes: data.length,
|
|
111
830
|
mediaType,
|
|
112
831
|
chip: {
|