chainlesschain 0.163.8 → 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 +4 -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-CavM7W3k.js → AIOps-D2MEn7fI.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CUvZGabQ.js → ActionButton-lCW_4Gf0.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DeBnWnbe.js → Analytics-Bs7i-nsS.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DbI5kxvd.js → AppLayout-CK7B6S_j.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-D93bigKm.js → Artifacts-C8ILjpyo.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CBNvfUZa.js → Audit-Bb9cNaWc.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-CJLyh_YU.js → BackgroundAgents-sC9ooXIf.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-D_0yoehD.js → Backup-D-DrsplT.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-TJxmbObW.js → BaseInput-uCNZpwSK.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CE0dto1q.js → Chat-CsDK1uE9.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-CZ5-yYiD.js → ChatBubbleRenderer-OqSDt50w.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-Ck1RVIVo.js → Checkbox-JhTXM1-K.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-qpoyf6DK.js → Codegen-BbzZLnyD.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DUyPWjIE.js → Col-D4VW4m4j.js} +1 -1
- package/src/assets/web-panel/assets/{Community-D_S1BemS.js → Community-BXrYawxV.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BjxeK-Gc.js → Compact-DCihGy1u.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-Dd3CEJsu.js → Compliance-DlyZ-lk8.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-B4QG7-ad.js → Cowork-DvGZrhbO.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-BtZnids5.js → Cron-DUncZi8h.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CHPfCBFD.js → Crosschain-C_hLuUcm.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DT8DCEOK.js → DID-b6YSUqxr.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-COQab5_U.js → Dashboard-uvM15Cfb.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BY1PsQuU.js → Dropdown-D1-Nd4qY.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-CsuAuaq3.js → EmailListRenderer-8ApvL6Zc.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-BqpinD-j.js → FamilyGuardDashboard-LYJt8811.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-D0gkfQFv.js → Federation-BbI3HGpv.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BqgE-axK.js → FormItemContext-DSoEKuFu.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-D0hJ2KvC.js → GenericCardRenderer-B0S9OWd5.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CmMB0uPY.js → Git-DIs9Zhf3.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-BnVEI0Dk.js → Governance-jzZXrxcl.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-YTAMihRP.js → Inference-JUPjf2ZI.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-0ax7VHop.js → KnowledgeGraph-DxnfJvlP.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-B9TRcokL.js → Logs-iXiz8BEE.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-GmB6DOr6.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-B6CSuD_H.js → Marketplace-Y3Xch312.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-CjMXvOVU.js → McpTools-D7kGGbO7.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-CXRF71U3.js → Memory-Do_hVxzh.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DQgNp_oS.js → MobileBridge-CtrR0Tas.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-BL0Czcoj.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-6hDTRPe1.js → Mtc-qo5QCTGd.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-BlVHU1DS.js → MtcAudit-cq5mnjYj.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-DP9pzEbV.js → Multisig-Bq0MAQHw.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-Djorh8EV.js → NLProgramming-DdWE6Vi2.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-oLZ-JkUg.js → Notes-BxMBFcIp.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-Cg288VH3.js → NotificationSettings-RTrAcbUe.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-Bb1O3Ofr.js → OrderTableRenderer-DJbpGqzT.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-CBdo-bHs.js → Organization-SQzIPdqC.js} +2 -2
- package/src/assets/web-panel/assets/{Overflow-qZdnVumx.js → Overflow-02yECh22.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-D4kNfGNQ.js → P2P-BNg4pNCM.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-DnlMemM7.js → PdhVaultBrowser-BxPJZsD3.js} +5 -5
- package/src/assets/web-panel/assets/{Permissions-DHucHFBJ.js → Permissions-CLnDnPAz.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-BovlOIPR.js → PersonalDataHub-C5m0AjGf.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-Deru3CQY.js → Pipeline-VwOf5Dhv.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-Bq5oTTbU.js → Privacy-CC0W2hZd.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-BfzxVWAz.js → ProjectInit-Dz893Bob.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CKC6XBtH.js → ProjectSettings-CxQkvl0k.js} +2 -2
- package/src/assets/web-panel/assets/Projects-DDAjkUkT.js +1 -0
- package/src/assets/web-panel/assets/{Providers-C_jx4TWX.js → Providers-DeB9IkxK.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-BdIHeVGC.js → QrScannerModal-OCeoaswn.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BwZwAcPD.js → QuickAsk-DenotaAj.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BNTt0L-m.js → Recommend-Cies_jjI.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-Biyn2-Ro.js → RemoteSession-Dxzl5n2T.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-D6VpG32B.js → Reputation-CW0mvxgZ.js} +1 -1
- package/src/assets/web-panel/assets/{Row-D_74OvQQ.js → Row-SEd32qZU.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BTr0a-BQ.js → RssFeed-BSwnJ3Lm.js} +3 -3
- package/src/assets/web-panel/assets/{Search-C3MCFoNU.js → Search-xe2m8bkC.js} +1 -1
- package/src/assets/web-panel/assets/{Security-CqW9aJ6s.js → Security-Mq2F9Nro.js} +3 -3
- package/src/assets/web-panel/assets/{Services-Cw5GNaHF.js → Services-BKGw2V3P.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DZps5qeY.js → Skeleton-DW95-Rxf.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-C6NQ1znT.js → Skills-CHgChCv_.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-DFP8G2Sh.js → Sla-tKh6k3R7.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-ESt6MB6v.js → SpeechSettings-D6UL3dA5.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-BHnN98aM.js → SyncSettings-D0Fw8fVL.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-NiSCaOf-.js → Tasks-20x1GB3D.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-DsKFhW2C.js → Templates-DJ-lts-a.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CQ0E0ze5.js → Tenant-BFdGpbs7.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-D_rBu_by.js → Terminal-Xpx61vHL.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-D3Vm4Po4.js → TimelineRenderer-C6UIvyZQ.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DNTxRH6q.js → Tokens-Dellq08f.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-Dgprz1ms.js → Trigger-VKw8d0J-.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-B2rUnVBD.js → Trust-DNftdKT5.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-DEGQNc6_.js → UkeySign-DX9VAKJI.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-jlsAx3Eh.js → VideoEditing-B2h3jO8q.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-8jQih1ij.js → Wallet-CjGkof7f.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-XLeO6xIB.js → WebAuthn-2Zfcu55P.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-De_dgDAG.js → WorkflowEditor-B9eZ8UxZ.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CI19R_Sk.js → chat-CQNfD-YO.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DsYTOYN3.js → colors-D4usyFT2.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-CM3-t_Qr.js → compact-item-s4TpjvjX.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BjxlBRZv.js → createContext-BRCSvYxj.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DKJjSWRn.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-RDaWX_4i.js → hasIn-AdkUbkV-.js} +1 -1
- package/src/assets/web-panel/assets/{index-BN6UPD2E.js → index--00U6vXZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-CiECJi-Q.js → index-B2V-eKfK.js} +1 -1
- package/src/assets/web-panel/assets/{index-CnHH7bnD.js → index-B4JJCfQ2.js} +1 -1
- package/src/assets/web-panel/assets/{index-CjTrRt13.js → index-BIoG5yYf.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dxge-xWl.js → index-BMcimU-2.js} +1 -1
- package/src/assets/web-panel/assets/{index-9R6BxAr0.js → index-BPhkFZ1I.js} +1 -1
- package/src/assets/web-panel/assets/{index-BHNYPO0b.js → index-BQ3DXBtD.js} +3 -3
- package/src/assets/web-panel/assets/{index-Cpqm1qfU.js → index-Bad4VNvz.js} +1 -1
- package/src/assets/web-panel/assets/{index-B9O9YyWE.js → index-BgiXR_-_.js} +1 -1
- package/src/assets/web-panel/assets/{index-B5REnKt8.js → index-BtobShro.js} +1 -1
- package/src/assets/web-panel/assets/{index-D6sm5-Xq.js → index-Bw2MEnUk.js} +1 -1
- package/src/assets/web-panel/assets/{index-DcPFB8qJ.js → index-C1mJtE6q.js} +1 -1
- package/src/assets/web-panel/assets/{index-BKJr-TZp.js → index-C484EJiS.js} +1 -1
- package/src/assets/web-panel/assets/{index-Drlnwr8F.js → index-C5KAQFPQ.js} +1 -1
- package/src/assets/web-panel/assets/index-C61cnl3K.js +1 -0
- package/src/assets/web-panel/assets/{index-Dsij_KsN.js → index-C7Y8Aluc.js} +1 -1
- package/src/assets/web-panel/assets/{index-IeiL9RKc.js → index-CCsM_Ybx.js} +1 -1
- package/src/assets/web-panel/assets/{index-B-Z8eFUJ.js → index-CJCFe2Qf.js} +1 -1
- package/src/assets/web-panel/assets/{index-CyOGN6a5.js → index-CJVEOa4i.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0PMlbMs.js → index-CJdQrZth.js} +1 -1
- package/src/assets/web-panel/assets/{index-nAH87mQP.js → index-CKC1t3Ic.js} +1 -1
- package/src/assets/web-panel/assets/{index-BGqqJfL0.js → index-CQhAVU5t.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cd9OJhHG.js → index-CYdoQsa1.js} +1 -1
- package/src/assets/web-panel/assets/{index-D0zcy54x.js → index-Cduu2Hhr.js} +1 -1
- package/src/assets/web-panel/assets/{index-DIUnNOjG.js → index-CkwiSLhU.js} +1 -1
- package/src/assets/web-panel/assets/{index-CVQMeiwH.js → index-Cvyt-zhm.js} +1 -1
- package/src/assets/web-panel/assets/{index-BlT2VAEK.js → index-D2GjI2oe.js} +1 -1
- package/src/assets/web-panel/assets/index-D4XFHxBr.js +1 -0
- package/src/assets/web-panel/assets/{index-C0yx-jtQ.js → index-DARsAyUp.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bi46Xu4u.js → index-DVKfQ0Ux.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cd3euP_4.js → index-DZT36ZYq.js} +1 -1
- package/src/assets/web-panel/assets/{index-BCnZyIMA.js → index-D_XBHopw.js} +1 -1
- package/src/assets/web-panel/assets/{index-C4gkzxkw.js → index-DdCB70SS.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7WBt_4T.js → index-DzRjHxEv.js} +1 -1
- package/src/assets/web-panel/assets/{index-DX7tuWVJ.js → index-MMN9V6JF.js} +1 -1
- package/src/assets/web-panel/assets/{index-DoQA0-52.js → index-RfMr79MW.js} +1 -1
- package/src/assets/web-panel/assets/{index-DXXtGMUJ.js → index-_IRVsV9X.js} +1 -1
- package/src/assets/web-panel/assets/{index-pPL66J85.js → index-nXyk8GZ9.js} +1 -1
- package/src/assets/web-panel/assets/{index-DyIWssPC.js → index-s_buFMEG.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BTL88of4.js → initDefaultProps-Blmpk7HL.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BUB2pXwB.js → motion-DPBJMv1n.js} +1 -1
- package/src/assets/web-panel/assets/{move-egCkkOMm.js → move-ButdzCM7.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DAWhZC8c.js → mtc-parser-cyRC_QCe.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CvOxe_6d.js → omit-1epSV7hz.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DZUSLZ5Z.js → pickAttrs-DuPY8xJs.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BERxGNMY.js → placementArrow-6XZqarhe.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-DZuDfZ9n.js → responsiveObserve-B40pXBWM.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DO756sgI.js → slide-jbZ9Wu4n.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BRQlIz28.js → statusUtils-BKQQcVy4.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-DCSfdybl.js → styleChecker-NiKfWjUT.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-LD8dWVve.js → useFlexGapSupport-bQUCvPeb.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BX9uW2LK.js → useFs-CUGji7ph.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BPSlPuHU.js → usePersonalDataHub-4veyN2N2.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-BmOILC9V.js → vnode-1-nLug-Z.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-1iKowKGg.js → zoom-dhCeRDMo.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +3 -3
- 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/data/changelog.json +15 -2
- 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/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-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/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 +83 -3
- package/src/runtime/headless-runner.js +30 -25
- package/src/runtime/headless-stream.js +32 -25
- 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/MarkdownRenderer-yySN5YNM.js +0 -1
- package/src/assets/web-panel/assets/MobileProjects-DlPwcCbq.js +0 -1
- package/src/assets/web-panel/assets/Projects-CMolGhae.js +0 -1
- package/src/assets/web-panel/assets/devWarning-S1ld2LwU.js +0 -1
- package/src/assets/web-panel/assets/index-Drz6yq0m.js +0 -1
- package/src/assets/web-panel/assets/index-uWiUs7S_.js +0 -1
|
@@ -52,6 +52,22 @@ import {
|
|
|
52
52
|
withSessionHostDelegatedWriteAuthority,
|
|
53
53
|
withSessionHostRecoveryLease,
|
|
54
54
|
} from "../lib/session-host-lease.js";
|
|
55
|
+
import {
|
|
56
|
+
BACKGROUND_TURN_BOOTSTRAP_ENV,
|
|
57
|
+
BACKGROUND_TURN_BOOTSTRAP_READY,
|
|
58
|
+
BACKGROUND_TURN_BOOTSTRAP_RELEASE,
|
|
59
|
+
createBackgroundTurnBootstrapMessage,
|
|
60
|
+
matchesBackgroundTurnBootstrapMessage,
|
|
61
|
+
normalizeBackgroundTurnBootstrapAuthority,
|
|
62
|
+
normalizeBackgroundTurnBootstrapBinding,
|
|
63
|
+
} from "../lib/background-turn-bootstrap-protocol.js";
|
|
64
|
+
import { connectBackgroundAgentKeeper } from "../lib/background-agent-keeper-client.js";
|
|
65
|
+
|
|
66
|
+
const TURN_BOOTSTRAP_MODULE_URL = new URL(
|
|
67
|
+
"./background-turn-bootstrap.js",
|
|
68
|
+
import.meta.url,
|
|
69
|
+
).href;
|
|
70
|
+
const TURN_BOOTSTRAP_IMPORT_ARGUMENT = `--import=${TURN_BOOTSTRAP_MODULE_URL}`;
|
|
55
71
|
|
|
56
72
|
const jobFile = process.argv[2];
|
|
57
73
|
let job;
|
|
@@ -65,10 +81,14 @@ let turnCount = 0;
|
|
|
65
81
|
let lastExit = { code: 0, signal: null };
|
|
66
82
|
let transportState = null;
|
|
67
83
|
let detachInteractionHandler = null;
|
|
84
|
+
let detachTurnBootstrapHandler = null;
|
|
85
|
+
let keeperClient = null;
|
|
86
|
+
let activeKeeperTurn = null;
|
|
68
87
|
let interactionJournal = null;
|
|
69
88
|
let interactionFinalSweep = null;
|
|
70
89
|
let turnLaunchUncertainty = null;
|
|
71
90
|
let turnLaunchSettlement = null;
|
|
91
|
+
let initialTurnStarted = false;
|
|
72
92
|
const promptQueue = [];
|
|
73
93
|
// P0-2: 保存 pending 的交互请求,等 attach 客户端连接后转发
|
|
74
94
|
const pendingInteractions = new Map();
|
|
@@ -135,6 +155,109 @@ export function attachTurnChildTerminationSettlement(
|
|
|
135
155
|
};
|
|
136
156
|
}
|
|
137
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Release a pre-main turn child only after its actual runtime PID is durably
|
|
160
|
+
* committed and every worker listener needed to supervise it is installed.
|
|
161
|
+
* The ChildProcess PID may name a Windows sandbox helper, so the actual Node
|
|
162
|
+
* PID arrives over the nonce-bound private IPC channel instead of being
|
|
163
|
+
* inferred from `child.pid`.
|
|
164
|
+
*/
|
|
165
|
+
export function attachTurnChildBootstrapRelease(
|
|
166
|
+
childProcess,
|
|
167
|
+
authority,
|
|
168
|
+
commitReady,
|
|
169
|
+
onFailure = () => {},
|
|
170
|
+
) {
|
|
171
|
+
if (!childProcess || typeof childProcess.on !== "function") {
|
|
172
|
+
throw new TypeError("turn bootstrap child must expose message events");
|
|
173
|
+
}
|
|
174
|
+
if (typeof childProcess.send !== "function") {
|
|
175
|
+
throw new TypeError("turn bootstrap child must expose dedicated IPC");
|
|
176
|
+
}
|
|
177
|
+
if (typeof commitReady !== "function") {
|
|
178
|
+
throw new TypeError("turn bootstrap durable commit callback is required");
|
|
179
|
+
}
|
|
180
|
+
if (typeof onFailure !== "function") {
|
|
181
|
+
throw new TypeError("turn bootstrap failure callback must be a function");
|
|
182
|
+
}
|
|
183
|
+
const expected = normalizeBackgroundTurnBootstrapAuthority(authority);
|
|
184
|
+
let releasedBinding = null;
|
|
185
|
+
let pendingBinding = null;
|
|
186
|
+
let failed = false;
|
|
187
|
+
let detached = false;
|
|
188
|
+
|
|
189
|
+
const failOnce = (error) => {
|
|
190
|
+
if (failed || detached) return;
|
|
191
|
+
failed = true;
|
|
192
|
+
onFailure(error instanceof Error ? error : new Error(String(error)));
|
|
193
|
+
};
|
|
194
|
+
const onMessage = (message) => {
|
|
195
|
+
if (message?.type !== BACKGROUND_TURN_BOOTSTRAP_READY) return;
|
|
196
|
+
if (
|
|
197
|
+
!matchesBackgroundTurnBootstrapMessage(
|
|
198
|
+
message,
|
|
199
|
+
BACKGROUND_TURN_BOOTSTRAP_READY,
|
|
200
|
+
expected,
|
|
201
|
+
)
|
|
202
|
+
) {
|
|
203
|
+
failOnce(new Error("background turn bootstrap ready binding mismatch"));
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const readyBinding = normalizeBackgroundTurnBootstrapBinding(message);
|
|
207
|
+
if (releasedBinding) {
|
|
208
|
+
if (readyBinding.pid !== releasedBinding.pid) {
|
|
209
|
+
failOnce(new Error("background turn bootstrap runtime pid changed"));
|
|
210
|
+
}
|
|
211
|
+
// READY is retransmitted until the child observes RELEASE. Matching
|
|
212
|
+
// duplicates are idempotent; never answer with a second RELEASE.
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
if (pendingBinding) {
|
|
216
|
+
if (readyBinding.pid !== pendingBinding.pid) {
|
|
217
|
+
failOnce(new Error("background turn bootstrap runtime pid changed"));
|
|
218
|
+
}
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
pendingBinding = readyBinding;
|
|
222
|
+
Promise.resolve()
|
|
223
|
+
.then(() => commitReady(readyBinding))
|
|
224
|
+
.then((committed) => {
|
|
225
|
+
if (failed || detached) return;
|
|
226
|
+
if (committed !== true) {
|
|
227
|
+
failOnce(
|
|
228
|
+
new Error("background turn runtime pid commit was rejected"),
|
|
229
|
+
);
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
releasedBinding = readyBinding;
|
|
233
|
+
try {
|
|
234
|
+
childProcess.send(
|
|
235
|
+
createBackgroundTurnBootstrapMessage(
|
|
236
|
+
BACKGROUND_TURN_BOOTSTRAP_RELEASE,
|
|
237
|
+
readyBinding,
|
|
238
|
+
),
|
|
239
|
+
(error) => {
|
|
240
|
+
if (error) failOnce(error);
|
|
241
|
+
},
|
|
242
|
+
);
|
|
243
|
+
} catch (error) {
|
|
244
|
+
failOnce(error);
|
|
245
|
+
}
|
|
246
|
+
})
|
|
247
|
+
.catch(failOnce);
|
|
248
|
+
};
|
|
249
|
+
const detach = () => {
|
|
250
|
+
if (detached) return;
|
|
251
|
+
detached = true;
|
|
252
|
+
childProcess.off?.("message", onMessage);
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
childProcess.on("message", onMessage);
|
|
256
|
+
childProcess.once?.("exit", detach);
|
|
257
|
+
childProcess.once?.("disconnect", detach);
|
|
258
|
+
return detach;
|
|
259
|
+
}
|
|
260
|
+
|
|
138
261
|
/**
|
|
139
262
|
* Deliver an already-durable interaction outcome after best-effort cleanup of
|
|
140
263
|
* the worker-state projection.
|
|
@@ -398,6 +521,8 @@ function finalize(code, signal, errorMessage) {
|
|
|
398
521
|
}
|
|
399
522
|
}
|
|
400
523
|
const done = () => {
|
|
524
|
+
keeperClient?.close();
|
|
525
|
+
keeperClient = null;
|
|
401
526
|
try {
|
|
402
527
|
log?.close();
|
|
403
528
|
} catch {
|
|
@@ -650,7 +775,20 @@ function startTurn(argv, promptText) {
|
|
|
650
775
|
// Private spawn-generation binding for the dedicated child IPC channel.
|
|
651
776
|
// It is never persisted in state or exposed through attach transports.
|
|
652
777
|
const turnIpcToken = randomBytes(32).toString("hex");
|
|
778
|
+
const turnBootstrapNonce = randomBytes(32).toString("hex");
|
|
653
779
|
let turnLaunchAttempt = 0;
|
|
780
|
+
let turnTerminated = false;
|
|
781
|
+
let keeperBootstrapStarted = false;
|
|
782
|
+
let keeperBootstrapOutcome = null;
|
|
783
|
+
let resolveKeeperBootstrap;
|
|
784
|
+
const keeperBootstrapSettled = new Promise((resolvePromise) => {
|
|
785
|
+
resolveKeeperBootstrap = resolvePromise;
|
|
786
|
+
});
|
|
787
|
+
const settleKeeperBootstrap = (outcome) => {
|
|
788
|
+
if (keeperBootstrapOutcome) return;
|
|
789
|
+
keeperBootstrapOutcome = outcome;
|
|
790
|
+
resolveKeeperBootstrap(outcome);
|
|
791
|
+
};
|
|
654
792
|
let prepared;
|
|
655
793
|
try {
|
|
656
794
|
prepared = mutateBackgroundAgentState(job.id, (current) => {
|
|
@@ -723,13 +861,17 @@ function startTurn(argv, promptText) {
|
|
|
723
861
|
agentStartedAt = Date.now();
|
|
724
862
|
spawned = executionBroker.spawn(
|
|
725
863
|
process.execPath,
|
|
726
|
-
[job.cliEntry, ...argv],
|
|
864
|
+
[TURN_BOOTSTRAP_IMPORT_ARGUMENT, job.cliEntry, ...argv],
|
|
727
865
|
{
|
|
728
866
|
cwd: job.cwd,
|
|
729
867
|
env: {
|
|
730
868
|
...process.env,
|
|
731
869
|
CC_BACKGROUND_AGENT_ID: job.id,
|
|
732
870
|
CC_BACKGROUND_TURN_IPC_NONCE: turnIpcToken,
|
|
871
|
+
[BACKGROUND_TURN_BOOTSTRAP_ENV.nonce]: turnBootstrapNonce,
|
|
872
|
+
[BACKGROUND_TURN_BOOTSTRAP_ENV.workerGeneration]:
|
|
873
|
+
job.workerGeneration,
|
|
874
|
+
[BACKGROUND_TURN_BOOTSTRAP_ENV.attempt]: String(turnLaunchAttempt),
|
|
733
875
|
},
|
|
734
876
|
stdio: ["ignore", log.fd, log.fd, "ipc"],
|
|
735
877
|
windowsHide: true,
|
|
@@ -756,6 +898,17 @@ function startTurn(argv, promptText) {
|
|
|
756
898
|
},
|
|
757
899
|
agentPid: spawned.pid,
|
|
758
900
|
agentStartedAt,
|
|
901
|
+
agentRuntimePid: null,
|
|
902
|
+
agentRuntimeStartedAt: null,
|
|
903
|
+
turnBootstrapStatus: "awaiting-ready",
|
|
904
|
+
turnBootstrapCommittedAt: null,
|
|
905
|
+
turnKeeperStatus: "waiting-for-runtime",
|
|
906
|
+
turnKeeperPid: null,
|
|
907
|
+
turnKeeperArmedAt: null,
|
|
908
|
+
turnKeeperCleanupReason: null,
|
|
909
|
+
turnKeeperCleanupRequestedAt: null,
|
|
910
|
+
turnKeeperCleanupConfirmedAt: null,
|
|
911
|
+
turnKeeperCleanupError: null,
|
|
759
912
|
turnLaunchIntent: null,
|
|
760
913
|
turnLaunchResolution: {
|
|
761
914
|
token: turnLaunchToken,
|
|
@@ -982,38 +1135,190 @@ function startTurn(argv, promptText) {
|
|
|
982
1135
|
},
|
|
983
1136
|
);
|
|
984
1137
|
|
|
1138
|
+
detachTurnBootstrapHandler = attachTurnChildBootstrapRelease(
|
|
1139
|
+
child,
|
|
1140
|
+
{
|
|
1141
|
+
nonce: turnBootstrapNonce,
|
|
1142
|
+
workerGeneration: job.workerGeneration,
|
|
1143
|
+
attempt: turnLaunchAttempt,
|
|
1144
|
+
},
|
|
1145
|
+
async (readyBinding) => {
|
|
1146
|
+
keeperBootstrapStarted = true;
|
|
1147
|
+
const committedAt = Date.now();
|
|
1148
|
+
const commit = mutateBackgroundAgentState(job.id, (current) => {
|
|
1149
|
+
if (
|
|
1150
|
+
!current ||
|
|
1151
|
+
current.status !== "running" ||
|
|
1152
|
+
current.stopRequestedAt ||
|
|
1153
|
+
current.workerGeneration !== job.workerGeneration ||
|
|
1154
|
+
Number(current.workerClaimedPid) !== process.pid ||
|
|
1155
|
+
current.turnLaunchResolution?.token !== turnLaunchToken ||
|
|
1156
|
+
Number(current.turnLaunchResolution?.attempt) !== turnLaunchAttempt ||
|
|
1157
|
+
current.turnLaunchResolution?.outcome !== "spawned" ||
|
|
1158
|
+
Number(current.agentPid) !== Number(spawned.pid)
|
|
1159
|
+
) {
|
|
1160
|
+
return null;
|
|
1161
|
+
}
|
|
1162
|
+
return {
|
|
1163
|
+
...current,
|
|
1164
|
+
agentRuntimePid: readyBinding.pid,
|
|
1165
|
+
// The host timestamp immediately before native spawn is a positive
|
|
1166
|
+
// lower-bound anchor for the runtime creation window. Destructive
|
|
1167
|
+
// identity checks still require a fresh OS creation-time probe.
|
|
1168
|
+
agentRuntimeStartedAt: agentStartedAt,
|
|
1169
|
+
turnBootstrapStatus: "awaiting-keeper",
|
|
1170
|
+
turnBootstrapCommittedAt: null,
|
|
1171
|
+
turnKeeperStatus: "arming",
|
|
1172
|
+
};
|
|
1173
|
+
});
|
|
1174
|
+
if (!commit.applied || !keeperClient) {
|
|
1175
|
+
settleKeeperBootstrap("failed");
|
|
1176
|
+
return false;
|
|
1177
|
+
}
|
|
1178
|
+
if (turnTerminated || child !== spawned || turnLaunchSettlement) {
|
|
1179
|
+
settleKeeperBootstrap("retired");
|
|
1180
|
+
return false;
|
|
1181
|
+
}
|
|
1182
|
+
const keeperTurn = {
|
|
1183
|
+
id: job.id,
|
|
1184
|
+
workerGeneration: job.workerGeneration,
|
|
1185
|
+
turnLaunchToken,
|
|
1186
|
+
attempt: turnLaunchAttempt,
|
|
1187
|
+
agentPid: Number(spawned.pid),
|
|
1188
|
+
agentStartedAt,
|
|
1189
|
+
agentRuntimePid: readyBinding.pid,
|
|
1190
|
+
agentRuntimeStartedAt: agentStartedAt,
|
|
1191
|
+
};
|
|
1192
|
+
try {
|
|
1193
|
+
await keeperClient.arm(keeperTurn);
|
|
1194
|
+
} catch (error) {
|
|
1195
|
+
settleKeeperBootstrap("failed");
|
|
1196
|
+
throw error;
|
|
1197
|
+
}
|
|
1198
|
+
activeKeeperTurn = keeperTurn;
|
|
1199
|
+
if (turnTerminated || child !== spawned || turnLaunchSettlement) {
|
|
1200
|
+
await keeperClient.retire(keeperTurn);
|
|
1201
|
+
if (activeKeeperTurn === keeperTurn) activeKeeperTurn = null;
|
|
1202
|
+
settleKeeperBootstrap("retired");
|
|
1203
|
+
return false;
|
|
1204
|
+
}
|
|
1205
|
+
const released = mutateBackgroundAgentState(job.id, (current) => {
|
|
1206
|
+
if (
|
|
1207
|
+
!current ||
|
|
1208
|
+
current.status !== "running" ||
|
|
1209
|
+
current.stopRequestedAt ||
|
|
1210
|
+
current.workerGeneration !== job.workerGeneration ||
|
|
1211
|
+
Number(current.workerClaimedPid) !== process.pid ||
|
|
1212
|
+
current.turnLaunchResolution?.token !== turnLaunchToken ||
|
|
1213
|
+
Number(current.turnLaunchResolution?.attempt) !== turnLaunchAttempt ||
|
|
1214
|
+
current.turnLaunchResolution?.outcome !== "spawned" ||
|
|
1215
|
+
Number(current.agentPid) !== Number(spawned.pid) ||
|
|
1216
|
+
Number(current.agentRuntimePid) !== readyBinding.pid ||
|
|
1217
|
+
current.turnKeeperStatus !== "armed" ||
|
|
1218
|
+
Number(current.turnKeeperPid) !== Number(current.keeperPid)
|
|
1219
|
+
) {
|
|
1220
|
+
return null;
|
|
1221
|
+
}
|
|
1222
|
+
return {
|
|
1223
|
+
...current,
|
|
1224
|
+
turnBootstrapStatus: "released",
|
|
1225
|
+
turnBootstrapCommittedAt: committedAt,
|
|
1226
|
+
};
|
|
1227
|
+
});
|
|
1228
|
+
if (!released.applied) {
|
|
1229
|
+
await keeperClient.retire(keeperTurn);
|
|
1230
|
+
if (activeKeeperTurn === keeperTurn) activeKeeperTurn = null;
|
|
1231
|
+
settleKeeperBootstrap("failed");
|
|
1232
|
+
return false;
|
|
1233
|
+
}
|
|
1234
|
+
settleKeeperBootstrap("released");
|
|
1235
|
+
return true;
|
|
1236
|
+
},
|
|
1237
|
+
(error) => {
|
|
1238
|
+
settleKeeperBootstrap("failed");
|
|
1239
|
+
detachInteractionHandler?.();
|
|
1240
|
+
detachInteractionHandler = null;
|
|
1241
|
+
if (
|
|
1242
|
+
keeperBootstrapOutcome !== "retired" &&
|
|
1243
|
+
(child === spawned || turnTerminated) &&
|
|
1244
|
+
!turnLaunchSettlement
|
|
1245
|
+
) {
|
|
1246
|
+
beginTurnLaunchSettlement({
|
|
1247
|
+
owned: spawned,
|
|
1248
|
+
error,
|
|
1249
|
+
turnLaunchToken,
|
|
1250
|
+
turnLaunchAttempt,
|
|
1251
|
+
agentStartedAt,
|
|
1252
|
+
});
|
|
1253
|
+
}
|
|
1254
|
+
},
|
|
1255
|
+
);
|
|
1256
|
+
|
|
985
1257
|
attachTurnChildTerminationSettlement(
|
|
986
1258
|
child,
|
|
987
1259
|
({ code, signal, errorMessage }) => {
|
|
1260
|
+
turnTerminated = true;
|
|
988
1261
|
lastExit = {
|
|
989
1262
|
code,
|
|
990
1263
|
signal,
|
|
991
1264
|
...(errorMessage ? { errorMessage } : {}),
|
|
992
1265
|
};
|
|
993
1266
|
child = null;
|
|
1267
|
+
detachTurnBootstrapHandler?.();
|
|
1268
|
+
detachTurnBootstrapHandler = null;
|
|
994
1269
|
// 清理交互处理器
|
|
995
1270
|
detachInteractionHandler?.();
|
|
996
1271
|
detachInteractionHandler = null;
|
|
997
1272
|
// Reject any request that survived an abnormal child exit. Normal
|
|
998
1273
|
// responses remove themselves from this map before the turn continues.
|
|
999
|
-
for (const
|
|
1274
|
+
for (const pending of pendingInteractions.values()) {
|
|
1000
1275
|
const error = new Error("Agent exited");
|
|
1001
1276
|
error.code = "INTERACTION_CHILD_EXITED";
|
|
1002
1277
|
pending.deliverRejected?.(error);
|
|
1003
1278
|
}
|
|
1004
1279
|
pendingInteractions.clear();
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1280
|
+
const finishTurn = () =>
|
|
1281
|
+
beginFinalInteractionSweep(() => {
|
|
1282
|
+
server?.broadcast({
|
|
1283
|
+
type: "turn-ended",
|
|
1284
|
+
turn: turnCount,
|
|
1285
|
+
exitCode: code,
|
|
1286
|
+
});
|
|
1287
|
+
if (lastExit.errorMessage) {
|
|
1288
|
+
finalize(1, signal, lastExit.errorMessage);
|
|
1289
|
+
} else {
|
|
1290
|
+
maybeContinue();
|
|
1291
|
+
}
|
|
1010
1292
|
});
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1293
|
+
void (async () => {
|
|
1294
|
+
if (keeperBootstrapStarted) {
|
|
1295
|
+
const outcome = await keeperBootstrapSettled;
|
|
1296
|
+
// The bootstrap failure callback owns process-tree settlement and
|
|
1297
|
+
// must not race a normal continuation into the next queued turn.
|
|
1298
|
+
if (outcome === "failed") return;
|
|
1015
1299
|
}
|
|
1016
|
-
|
|
1300
|
+
if (turnLaunchSettlement) return;
|
|
1301
|
+
const keeperTurn = activeKeeperTurn;
|
|
1302
|
+
if (!keeperTurn || !keeperClient) {
|
|
1303
|
+
finishTurn();
|
|
1304
|
+
return;
|
|
1305
|
+
}
|
|
1306
|
+
try {
|
|
1307
|
+
await keeperClient.retire(keeperTurn);
|
|
1308
|
+
if (activeKeeperTurn === keeperTurn) activeKeeperTurn = null;
|
|
1309
|
+
finishTurn();
|
|
1310
|
+
} catch (error) {
|
|
1311
|
+
if (!turnLaunchSettlement) {
|
|
1312
|
+
beginTurnLaunchSettlement({
|
|
1313
|
+
owned: spawned,
|
|
1314
|
+
error,
|
|
1315
|
+
turnLaunchToken,
|
|
1316
|
+
turnLaunchAttempt,
|
|
1317
|
+
agentStartedAt,
|
|
1318
|
+
});
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1321
|
+
})();
|
|
1017
1322
|
},
|
|
1018
1323
|
);
|
|
1019
1324
|
return true;
|
|
@@ -1059,6 +1364,17 @@ function maybeContinue() {
|
|
|
1059
1364
|
uncertainSideEffects: 0,
|
|
1060
1365
|
agentPid: null,
|
|
1061
1366
|
agentStartedAt: null,
|
|
1367
|
+
agentRuntimePid: null,
|
|
1368
|
+
agentRuntimeStartedAt: null,
|
|
1369
|
+
turnBootstrapStatus: null,
|
|
1370
|
+
turnBootstrapCommittedAt: null,
|
|
1371
|
+
turnKeeperStatus: null,
|
|
1372
|
+
turnKeeperPid: null,
|
|
1373
|
+
turnKeeperArmedAt: null,
|
|
1374
|
+
turnKeeperCleanupReason: null,
|
|
1375
|
+
turnKeeperCleanupRequestedAt: null,
|
|
1376
|
+
turnKeeperCleanupConfirmedAt: null,
|
|
1377
|
+
turnKeeperCleanupError: null,
|
|
1062
1378
|
heartbeatAt: Date.now(),
|
|
1063
1379
|
});
|
|
1064
1380
|
server.broadcast({ type: "idle", turn: turnCount });
|
|
@@ -1147,7 +1463,11 @@ async function main() {
|
|
|
1147
1463
|
}
|
|
1148
1464
|
promptQueue.push(text);
|
|
1149
1465
|
const queued = promptQueue.length;
|
|
1150
|
-
|
|
1466
|
+
// The transport is intentionally published before keeper/bootstrap
|
|
1467
|
+
// readiness. Prompts arriving in that window belong behind turn 1;
|
|
1468
|
+
// consuming one immediately would skip the launch job and make the
|
|
1469
|
+
// queue cap timing-dependent.
|
|
1470
|
+
if (!child && initialTurnStarted) maybeContinue();
|
|
1151
1471
|
return { queued };
|
|
1152
1472
|
},
|
|
1153
1473
|
onStop: () => {
|
|
@@ -1265,12 +1585,37 @@ async function main() {
|
|
|
1265
1585
|
finalize(launchReadiness === "timeout" ? 1 : 0, null);
|
|
1266
1586
|
return;
|
|
1267
1587
|
}
|
|
1588
|
+
if (!job.keeper) {
|
|
1589
|
+
throw new Error("background agent keeper launch authority is missing");
|
|
1590
|
+
}
|
|
1591
|
+
keeperClient = await connectBackgroundAgentKeeper({
|
|
1592
|
+
id: job.id,
|
|
1593
|
+
workerGeneration: job.workerGeneration,
|
|
1594
|
+
workerPid: process.pid,
|
|
1595
|
+
pipePath: job.keeper.pipePath,
|
|
1596
|
+
token: job.keeper.token,
|
|
1597
|
+
onDisconnect(error, keeperTurn) {
|
|
1598
|
+
if (finalized || turnLaunchSettlement) return;
|
|
1599
|
+
if (child && keeperTurn) {
|
|
1600
|
+
beginTurnLaunchSettlement({
|
|
1601
|
+
owned: child,
|
|
1602
|
+
error,
|
|
1603
|
+
turnLaunchToken: keeperTurn.turnLaunchToken,
|
|
1604
|
+
turnLaunchAttempt: keeperTurn.attempt,
|
|
1605
|
+
agentStartedAt: keeperTurn.agentStartedAt,
|
|
1606
|
+
});
|
|
1607
|
+
return;
|
|
1608
|
+
}
|
|
1609
|
+
finalize(1, null, error?.message || "background keeper disconnected");
|
|
1610
|
+
},
|
|
1611
|
+
});
|
|
1268
1612
|
// Launch finalization can take long enough for an external stop/remove to
|
|
1269
1613
|
// win after bootstrap. Re-claim immediately before the first native turn.
|
|
1270
1614
|
if (!writeHeartbeat()) {
|
|
1271
1615
|
finalize(0, null);
|
|
1272
1616
|
return;
|
|
1273
1617
|
}
|
|
1618
|
+
initialTurnStarted = true;
|
|
1274
1619
|
if (!startTurn(job.argv, null)) finalize(0, null);
|
|
1275
1620
|
}
|
|
1276
1621
|
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pre-main barrier for one background-agent turn.
|
|
3
|
+
*
|
|
4
|
+
* Node loads this module through `--import` before executing the real CLI
|
|
5
|
+
* entrypoint. Top-level await keeps both ESM and CommonJS entry semantics
|
|
6
|
+
* intact while making execution contingent on the worker's durable PID
|
|
7
|
+
* commit and listener installation.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { writeSync } from "node:fs";
|
|
11
|
+
import {
|
|
12
|
+
BACKGROUND_TURN_BOOTSTRAP_ENV,
|
|
13
|
+
BACKGROUND_TURN_BOOTSTRAP_READY,
|
|
14
|
+
BACKGROUND_TURN_BOOTSTRAP_RELEASE,
|
|
15
|
+
backgroundTurnBootstrapBindingFromEnvironment,
|
|
16
|
+
clearBackgroundTurnBootstrapEnvironment,
|
|
17
|
+
createBackgroundTurnBootstrapMessage,
|
|
18
|
+
matchesBackgroundTurnBootstrapMessage,
|
|
19
|
+
removeBackgroundTurnBootstrapImport,
|
|
20
|
+
} from "../lib/background-turn-bootstrap-protocol.js";
|
|
21
|
+
|
|
22
|
+
const DEFAULT_RELEASE_TIMEOUT_MS = 30_000;
|
|
23
|
+
const TEST_RELEASE_TIMEOUT_MAX_MS = 2_000;
|
|
24
|
+
|
|
25
|
+
function releaseTimeoutMs() {
|
|
26
|
+
if (process.env.NODE_ENV !== "test") return DEFAULT_RELEASE_TIMEOUT_MS;
|
|
27
|
+
const requested = Number(
|
|
28
|
+
process.env[BACKGROUND_TURN_BOOTSTRAP_ENV.testTimeoutMs],
|
|
29
|
+
);
|
|
30
|
+
if (!Number.isFinite(requested)) return DEFAULT_RELEASE_TIMEOUT_MS;
|
|
31
|
+
return Math.max(10, Math.min(TEST_RELEASE_TIMEOUT_MAX_MS, requested));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function failClosed(message) {
|
|
35
|
+
try {
|
|
36
|
+
writeSync(2, `[background-turn-bootstrap] ${message}\n`);
|
|
37
|
+
} catch {
|
|
38
|
+
// The inherited diagnostic handle may already be closed.
|
|
39
|
+
}
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let binding;
|
|
44
|
+
try {
|
|
45
|
+
binding = backgroundTurnBootstrapBindingFromEnvironment(
|
|
46
|
+
process.env,
|
|
47
|
+
process.pid,
|
|
48
|
+
);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
failClosed(error?.message || String(error));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (typeof process.send !== "function" || process.connected === false) {
|
|
54
|
+
failClosed("dedicated worker IPC is unavailable");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
await new Promise((resolve) => {
|
|
58
|
+
let released = false;
|
|
59
|
+
let failed = false;
|
|
60
|
+
let timer = null;
|
|
61
|
+
let readyTimer = null;
|
|
62
|
+
|
|
63
|
+
const failOnce = (message) => {
|
|
64
|
+
if (failed) return;
|
|
65
|
+
failed = true;
|
|
66
|
+
if (timer) clearTimeout(timer);
|
|
67
|
+
if (readyTimer) clearInterval(readyTimer);
|
|
68
|
+
failClosed(message);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const onMessage = (message) => {
|
|
72
|
+
if (message?.type !== BACKGROUND_TURN_BOOTSTRAP_RELEASE) return;
|
|
73
|
+
if (released) {
|
|
74
|
+
failOnce("duplicate release rejected");
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (
|
|
78
|
+
!matchesBackgroundTurnBootstrapMessage(
|
|
79
|
+
message,
|
|
80
|
+
BACKGROUND_TURN_BOOTSTRAP_RELEASE,
|
|
81
|
+
binding,
|
|
82
|
+
)
|
|
83
|
+
) {
|
|
84
|
+
failOnce("release binding mismatch");
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
released = true;
|
|
88
|
+
if (timer) clearTimeout(timer);
|
|
89
|
+
if (readyTimer) clearInterval(readyTimer);
|
|
90
|
+
try {
|
|
91
|
+
process.execArgv = removeBackgroundTurnBootstrapImport(
|
|
92
|
+
process.execArgv,
|
|
93
|
+
import.meta.url,
|
|
94
|
+
);
|
|
95
|
+
clearBackgroundTurnBootstrapEnvironment(process.env);
|
|
96
|
+
// Keep the disconnect listener as a fail-closed worker-death signal,
|
|
97
|
+
// but do not make this private bootstrap channel keep an otherwise
|
|
98
|
+
// completed Agent process alive. Interaction requests explicitly ref
|
|
99
|
+
// the same channel for the duration of a pending same-turn answer.
|
|
100
|
+
process.channel?.unref?.();
|
|
101
|
+
} catch (error) {
|
|
102
|
+
failOnce(error?.message || String(error));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
resolve();
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// Keep both listeners after release. A repeated release or loss of the
|
|
109
|
+
// supervising worker remains fail-closed even after the real CLI starts.
|
|
110
|
+
process.on("message", onMessage);
|
|
111
|
+
process.once("disconnect", () =>
|
|
112
|
+
failOnce("worker IPC disconnected before turn completion"),
|
|
113
|
+
);
|
|
114
|
+
timer = setTimeout(
|
|
115
|
+
() => failOnce("timed out waiting for durable turn release"),
|
|
116
|
+
releaseTimeoutMs(),
|
|
117
|
+
);
|
|
118
|
+
timer.unref?.();
|
|
119
|
+
|
|
120
|
+
const sendReady = () => {
|
|
121
|
+
if (released || failed) return;
|
|
122
|
+
try {
|
|
123
|
+
process.send(
|
|
124
|
+
createBackgroundTurnBootstrapMessage(
|
|
125
|
+
BACKGROUND_TURN_BOOTSTRAP_READY,
|
|
126
|
+
binding,
|
|
127
|
+
),
|
|
128
|
+
(error) => {
|
|
129
|
+
if (error) failOnce(`ready delivery failed: ${error.message}`);
|
|
130
|
+
},
|
|
131
|
+
);
|
|
132
|
+
} catch (error) {
|
|
133
|
+
failOnce(`ready delivery failed: ${error?.message || String(error)}`);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
sendReady();
|
|
137
|
+
// A very fast preload can publish readiness while the worker is still
|
|
138
|
+
// fsyncing the PID commit. Repeat only READY (never RELEASE) until the
|
|
139
|
+
// post-commit listener answers, so an early unobserved event cannot strand
|
|
140
|
+
// the child. Matching duplicates are intentionally idempotent parent-side.
|
|
141
|
+
readyTimer = setInterval(sendReady, 100);
|
|
142
|
+
readyTimer.unref?.();
|
|
143
|
+
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{P as c,J as p,b as s}from"./vendor-Bn1JzzAn.js";import{r as a}from"./markdown-Yo_c6Krv.js";import{_ as d}from"./index-BHNYPO0b.js";const _={__name:"MarkdownRenderer",props:{content:{type:String,default:""}},setup(t,{expose:o}){o();const e=t,r=s(()=>a(e.content||"")),n={props:e,rendered:r,computed:s,get renderMarkdown(){return a}};return Object.defineProperty(n,"__isScriptSetup",{enumerable:!1,value:!0}),n}},i=["innerHTML"];function l(t,o,e,r,n,m){return c(),p("div",{class:"markdown-content",innerHTML:r.rendered},null,8,i)}const b=d(_,[["render",l],["__scopeId","data-v-0b0b9f63"],["__file","/tmp/cc-web-panel-blIgp5/repo/packages/web-panel/src/components/MarkdownRenderer.vue"]]);export{b as M};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{I as n,J as g,c as l,K as r,N as u,P as h,U as o,R as t,Q as b}from"./vendor-Bn1JzzAn.js";import{_ as v,b as m}from"./index-BHNYPO0b.js";import{a8 as y,M}from"./icons-DG5UD-6K.js";const B={__name:"MobileProjects",setup(p,{expose:i}){i();const c=u(),{t:e}=m();function a(){c.push("/projects")}function _(){c.push("/mobile-bridge")}const s={router:c,t:e,goToProjects:a,goToMobileBridge:_,get useRouter(){return u},get useI18n(){return m},get MobileOutlined(){return M},get FolderOutlined(){return y}};return Object.defineProperty(s,"__isScriptSetup",{enumerable:!1,value:!0}),s}},x={class:"mobile-projects-placeholder"},O={class:"title"},k={class:"subtitle"},w={class:"explainer"};function T(p,i,c,e,a,_){const s=n("a-alert"),d=n("a-button"),f=n("a-space"),P=n("a-empty"),j=n("a-card");return h(),g("div",x,[l(j,null,{default:r(()=>[l(P,{description:!1},{image:r(()=>[l(e.MobileOutlined,{style:{fontSize:"64px",color:"#bfbfbf"}})]),default:r(()=>[o("h2",O,t(e.t("mobileProjects.title")),1),o("p",k,t(e.t("mobileProjects.subtitle")),1),l(s,{message:e.t("mobileProjects.v02Banner"),type:"info","show-icon":"",class:"banner"},null,8,["message"]),o("div",w,[o("h3",null,t(e.t("mobileProjects.currentDirection")),1),o("p",null,t(e.t("mobileProjects.currentDirectionBody")),1),o("ul",null,[o("li",null,t(e.t("mobileProjects.stepPhone")),1),o("li",null,t(e.t("mobileProjects.stepTap")),1),o("li",null,t(e.t("mobileProjects.stepPull")),1)]),o("h3",null,t(e.t("mobileProjects.reverseDirection")),1),o("p",null,t(e.t("mobileProjects.reverseDirectionBody")),1)]),l(f,{class:"actions"},{default:r(()=>[l(d,{type:"primary",onClick:e.goToProjects},{default:r(()=>[l(e.FolderOutlined),b(" "+t(e.t("mobileProjects.viewLocalProjects")),1)]),_:1}),l(d,{onClick:e.goToMobileBridge},{default:r(()=>[l(e.MobileOutlined),b(" "+t(e.t("mobileProjects.checkBridge")),1)]),_:1})]),_:1})]),_:1})]),_:1})])}const N=v(B,[["render",T],["__scopeId","data-v-9262cc45"],["__file","/tmp/cc-web-panel-blIgp5/repo/packages/web-panel/src/views/MobileProjects.vue"]]);export{N as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{I as i,J as A,U,R as s,Q as r,c as t,K as a,V as _,S as x,o as oe,b as ee,r as u,P as p,F as ne,a2 as ge}from"./vendor-Bn1JzzAn.js";import{_ as we,b as re,u as ie,d}from"./index-BHNYPO0b.js";import{u as de}from"./useShellMode-CgR0wCYM.js";import{aN as ke,aO as be,aP as Fe,f as je,a5 as Ce,a8 as xe,at as Oe,R as Se}from"./icons-DG5UD-6K.js";const Pe={__name:"Projects",setup(se,{expose:l}){l();const{t:te}=re(),e=ie(),{isEmbedded:W}=de();async function w(o,f,ye,ae=8e3){if(W){const Z=await e.sendRaw({...f,type:o},ae);if(!Z?.ok){const $=Z?.error;throw new Error(typeof $=="string"?$:$?.message||`${o} failed`)}return Z.result}return e.executeJson(ye,ae)}const B=u(!1),y=u([]),O=u(""),S=u(""),P=u(!1),v=u(null),h=u([]),k=u(!1),E=u(!1),L=u(!1),b=u({name:"",description:"",type:"document",rootPath:""}),z=[{title:"ID",key:"id",width:110},{title:"名称",key:"name"},{title:"类型",key:"project_type",width:120},{title:"状态",key:"status",width:100},{title:"同步",key:"sync_status",width:100},{title:"更新",key:"updated_at",width:160},{title:"操作",key:"actions",width:180,fixed:"right"}],V=ee(()=>{const o={active:0,draft:0,completed:0,archived:0};for(const f of y.value)o[f.status]!==void 0&&(o[f.status]+=1);return o}),J=ee(()=>y.value.filter(o=>!(O.value&&o.status!==O.value||S.value&&!o.name.toLowerCase().includes(S.value.toLowerCase()))));function g(o){switch(o){case"active":return"green";case"draft":return"default";case"completed":return"cyan";case"archived":return"gold";default:return"default"}}function K(o){switch(o){case"synced":return"green";case"pending":return"orange";case"conflict":return"red";case"error":return"red";default:return"default"}}function Q(o){return!o&&o!==0?"-":new Date(typeof o=="number"?o:parseInt(o,10)).toLocaleString("zh-CN",{hour12:!1})}async function C(){B.value=!0;try{const o=await w("project.list",{limit:500},"project list --limit 500 --json",1e4);y.value=Array.isArray(o?.projects)?o.projects:Array.isArray(o)?o:[]}catch(o){d.error("加载失败: "+(o.message||o)),y.value=[]}finally{B.value=!1}}function G(o){return{onClick:()=>M(o)}}async function M(o){v.value=o,P.value=!0,k.value=!0,h.value=[];try{const f=await w("project.listFiles",{projectId:o.id,limit:200},`project list-files ${o.id} --json`,8e3);h.value=Array.isArray(f?.files)?f.files:[]}catch{h.value=[]}finally{k.value=!1}}async function H(o){try{(await w("project.delete",{id:o.id},`project delete ${o.id} --json`,8e3))?.ok?(d.success(`已删除项目 '${o.name}'`),P.value=!1,await C()):d.error("删除失败")}catch(f){d.error(f.message||String(f))}}function X(){b.value={name:"",description:"",type:"document",rootPath:""},E.value=!0}async function T(){if(!b.value.name.trim()){d.warning("请输入项目名称");return}L.value=!0;try{const o=await w("project.init",{name:b.value.name.trim(),description:b.value.description||null,projectType:b.value.type,rootPath:b.value.rootPath||null},`project init "${b.value.name.trim()}" --type ${b.value.type} --json`,8e3);o?.id?(d.success(`已创建项目 '${o.name}'`),E.value=!1,await C()):d.error("创建失败")}catch(o){d.error(o.message||String(o))}finally{L.value=!1}}const F=u(!1),D=u(!1),j=u({path:"",content:""}),I=u(!1),m=u(!1),R=u({path:""}),n=u(!1),c=u(null),q=u(""),Y=u(!1);function ue(){j.value={path:"",content:""},F.value=!0}function ce(){R.value={path:""},I.value=!0}async function N(){if(v.value){k.value=!0;try{const o=await w("project.listFiles",{projectId:v.value.id,limit:200},`project list-files ${v.value.id} --json`,8e3);h.value=Array.isArray(o?.files)?o.files:[]}catch(o){d.error("刷新文件失败: "+(o.message||o))}finally{k.value=!1}}}async function fe(){if(!j.value.path.trim()){d.warning("请输入文件路径");return}if(v.value){D.value=!0;try{const o=await w("project.createFile",{projectId:v.value.id,filePath:j.value.path.trim(),content:j.value.content||""},`project create-file ${v.value.id} "${j.value.path.trim()}" --json`,8e3);o?.id?(d.success(`已创建文件 '${o.file_name}'`),F.value=!1,await N(),await C()):d.error("创建文件失败")}catch(o){d.error(o.message||String(o))}finally{D.value=!1}}}async function pe(){if(!R.value.path.trim()){d.warning("请输入文件夹路径");return}if(v.value){m.value=!0;try{const o=await w("project.createFolder",{projectId:v.value.id,folderPath:R.value.path.trim()},`project create-folder ${v.value.id} "${R.value.path.trim()}" --json`,8e3);o?.id?(d.success(`已创建文件夹 '${o.file_name}'`),I.value=!1,await N(),await C()):d.error("创建文件夹失败")}catch(o){d.error(o.message||String(o))}finally{m.value=!1}}}async function ve(o){try{(await w("project.deleteFile",{fileId:o.id},`project delete-file ${o.id} --json`,8e3))?.deleted?(d.success(`已删除 '${o.file_name}'`),await N(),await C()):d.error("删除失败")}catch(f){d.error(f.message||String(f))}}async function me(o){if(o.is_folder){d.info("文件夹无内容可编辑");return}try{const f=await w("project.getFile",{fileId:o.id},`project get-file ${o.id} --json`,8e3);c.value=o,q.value=f?.content||"",n.value=!0}catch(f){d.error("读取文件失败: "+(f.message||f))}}async function _e(){if(c.value){Y.value=!0;try{(await w("project.writeFile",{fileId:c.value.id,content:q.value},`project write-file ${c.value.id} --json`,8e3))?.id?(d.success("已保存"),n.value=!1,await N()):d.error("保存失败")}catch(o){d.error(o.message||String(o))}finally{Y.value=!1}}}oe(()=>{C()});const le={t:te,ws:e,isEmbedded:W,callProjectTopic:w,loading:B,projects:y,statusFilter:O,nameFilter:S,detailOpen:P,detail:v,files:h,filesLoading:k,createOpen:E,creating:L,newProject:b,columns:z,countByStatus:V,filteredProjects:J,statusColor:g,syncColor:K,formatTime:Q,loadAll:C,onRowClick:G,openDetail:M,onDelete:H,onShowCreate:X,onCreate:T,createFileOpen:F,creatingFile:D,newFile:j,createFolderOpen:I,creatingFolder:m,newFolder:R,editFileOpen:n,editingFile:c,editFileContent:q,savingFile:Y,openCreateFile:ue,openCreateFolder:ce,refreshFiles:N,onCreateFile:fe,onCreateFolder:pe,onDeleteFile:ve,openEditFile:me,onSaveFile:_e,ref:u,computed:ee,onMounted:oe,get ReloadOutlined(){return Se},get PlusOutlined(){return Oe},get FolderOutlined(){return xe},get FileTextOutlined(){return Ce},get CheckCircleOutlined(){return je},get CheckSquareOutlined(){return Fe},get FileAddOutlined(){return be},get FolderAddOutlined(){return ke},get message(){return d},get useI18n(){return re},get useWsStore(){return ie},get useShellMode(){return de}};return Object.defineProperty(le,"__isScriptSetup",{enumerable:!1,value:!0}),le}},ze={style:{display:"flex","align-items":"center","justify-content":"space-between","margin-bottom":"24px"}},Ie={class:"page-title"},Ae={class:"page-sub"},Ue={class:"filter-bar",style:{"margin-bottom":"12px",display:"flex",gap:"12px","align-items":"center"}},he={key:0,style:{"font-size":"12px",color:"#888"}},De={key:0,style:{color:"#888","font-size":"12px"}},Re={key:0},Te={key:1,style:{color:"#888"}},Be=["onClick"],Ee={key:0,style:{color:"#888","font-size":"12px"}};function Le(se,l,te,e,W,w){const B=i("router-link"),y=i("a-button"),O=i("a-space"),S=i("a-statistic"),P=i("a-card"),v=i("a-col"),h=i("a-row"),k=i("a-radio-button"),E=i("a-radio-group"),L=i("a-input-search"),b=i("a-alert"),z=i("a-tag"),V=i("a-popconfirm"),J=i("a-table"),g=i("a-descriptions-item"),K=i("a-descriptions"),Q=i("a-divider"),C=i("a-empty"),G=i("a-list-item"),M=i("a-list"),H=i("a-spin"),X=i("a-drawer"),T=i("a-input"),F=i("a-form-item"),D=i("a-textarea"),j=i("a-form"),I=i("a-modal"),m=i("a-select-option"),R=i("a-select");return p(),A("div",null,[U("div",ze,[U("div",null,[U("h2",Ie,s(e.t("projects.title")),1),U("p",Ae,[l[17]||(l[17]=r("桌面 / CLI / 手机 三端共享同一份项目数据,Phase 3d sync 自动同步 (",-1)),t(B,{to:"/project-init"},{default:a(()=>[...l[16]||(l[16]=[r("项目初始化 / 环境设置",-1)])]),_:1}),l[18]||(l[18]=r(")",-1))])]),t(O,null,{default:a(()=>[t(y,{loading:e.loading,onClick:e.loadAll},{icon:a(()=>[t(e.ReloadOutlined)]),default:a(()=>[l[19]||(l[19]=r(" 刷新 ",-1))]),_:1},8,["loading"]),t(y,{type:"primary",onClick:e.onShowCreate},{icon:a(()=>[t(e.PlusOutlined)]),default:a(()=>[l[20]||(l[20]=r(" 新建项目 ",-1))]),_:1})]),_:1})]),_(" Stats "),t(h,{gutter:[16,16],style:{"margin-bottom":"20px"}},{default:a(()=>[t(v,{xs:12,sm:8,lg:6},{default:a(()=>[t(P,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:a(()=>[t(S,{title:"总项目",value:e.projects.length,"value-style":{color:"#1677ff",fontSize:"20px"}},{prefix:a(()=>[t(e.FolderOutlined)]),_:1},8,["value"])]),_:1})]),_:1}),t(v,{xs:12,sm:8,lg:6},{default:a(()=>[t(P,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:a(()=>[t(S,{title:"活跃",value:e.countByStatus.active,"value-style":{color:"#52c41a",fontSize:"20px"}},{prefix:a(()=>[t(e.CheckCircleOutlined)]),_:1},8,["value"])]),_:1})]),_:1}),t(v,{xs:12,sm:8,lg:6},{default:a(()=>[t(P,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:a(()=>[t(S,{title:"草稿",value:e.countByStatus.draft,"value-style":{color:"#8c8c8c",fontSize:"20px"}},{prefix:a(()=>[t(e.FileTextOutlined)]),_:1},8,["value"])]),_:1})]),_:1}),t(v,{xs:12,sm:8,lg:6},{default:a(()=>[t(P,{style:{background:"var(--bg-card)","border-color":"var(--border-color)"}},{default:a(()=>[t(S,{title:"已完成",value:e.countByStatus.completed,"value-style":{color:"#13c2c2",fontSize:"20px"}},{prefix:a(()=>[t(e.CheckSquareOutlined)]),_:1},8,["value"])]),_:1})]),_:1})]),_:1}),_(" Filter "),U("div",Ue,[t(E,{value:e.statusFilter,"onUpdate:value":l[0]||(l[0]=n=>e.statusFilter=n),size:"small","button-style":"solid"},{default:a(()=>[t(k,{value:""},{default:a(()=>[...l[21]||(l[21]=[r("全部",-1)])]),_:1}),t(k,{value:"active"},{default:a(()=>[...l[22]||(l[22]=[r("活跃",-1)])]),_:1}),t(k,{value:"draft"},{default:a(()=>[...l[23]||(l[23]=[r("草稿",-1)])]),_:1}),t(k,{value:"completed"},{default:a(()=>[...l[24]||(l[24]=[r("已完成",-1)])]),_:1}),t(k,{value:"archived"},{default:a(()=>[...l[25]||(l[25]=[r("已归档",-1)])]),_:1})]),_:1},8,["value"]),t(L,{value:e.nameFilter,"onUpdate:value":l[1]||(l[1]=n=>e.nameFilter=n),placeholder:"按名称过滤",style:{"max-width":"260px"},"allow-clear":""},null,8,["value"])]),!e.projects.length&&!e.loading?(p(),x(b,{key:0,type:"info",message:"还没有项目",description:'运行 `cc project init <name>` 或点击右上角"新建项目"按钮创建。桌面 / CLI / 手机三端共享同一份数据。',"show-icon":"",style:{"margin-bottom":"16px"}})):_("v-if",!0),e.projects.length||e.loading?(p(),x(J,{key:1,columns:e.columns,"data-source":e.filteredProjects,loading:e.loading,pagination:{pageSize:20,showSizeChanger:!0},"row-key":"id","custom-row":e.onRowClick},{bodyCell:a(({column:n,record:c})=>[n.key==="id"?(p(),A("code",he,s(c.id.slice(0,8))+"…",1)):n.key==="name"?(p(),A(ne,{key:1},[U("strong",null,s(c.name),1),c.description?(p(),A("div",De,s(c.description),1)):_("v-if",!0)],64)):n.key==="project_type"?(p(),x(z,{key:2},{default:a(()=>[r(s(c.project_type),1)]),_:2},1024)):n.key==="status"?(p(),x(z,{key:3,color:e.statusColor(c.status)},{default:a(()=>[r(s(c.status),1)]),_:2},1032,["color"])):n.key==="sync_status"?(p(),x(z,{key:4,color:e.syncColor(c.sync_status)},{default:a(()=>[r(s(c.sync_status||"unknown"),1)]),_:2},1032,["color"])):n.key==="updated_at"?(p(),A(ne,{key:5},[r(s(e.formatTime(c.updated_at)),1)],64)):n.key==="actions"?(p(),x(O,{key:6,onClick:l[2]||(l[2]=ge(()=>{},["stop"]))},{default:a(()=>[t(y,{size:"small",onClick:q=>e.openDetail(c)},{default:a(()=>[...l[26]||(l[26]=[r("详情",-1)])]),_:1},8,["onClick"]),t(V,{title:`删除项目 '${c.name}' ?`,"ok-text":"删除","ok-type":"danger","cancel-text":"取消",onConfirm:q=>e.onDelete(c)},{default:a(()=>[t(y,{size:"small",danger:""},{default:a(()=>[...l[27]||(l[27]=[r("删除",-1)])]),_:1})]),_:1},8,["title","onConfirm"])]),_:2},1024)):_("v-if",!0)]),_:1},8,["data-source","loading"])):_("v-if",!0),_(" Detail drawer "),t(X,{open:e.detailOpen,"onUpdate:open":l[3]||(l[3]=n=>e.detailOpen=n),title:e.detail?.name||"项目详情",width:"640",placement:"right"},{default:a(()=>[e.detail?(p(),x(K,{key:0,column:1,bordered:"",size:"small"},{default:a(()=>[t(g,{label:"ID"},{default:a(()=>[U("code",null,s(e.detail.id),1)]),_:1}),t(g,{label:"名称"},{default:a(()=>[r(s(e.detail.name),1)]),_:1}),t(g,{label:"描述"},{default:a(()=>[r(s(e.detail.description||"-"),1)]),_:1}),t(g,{label:"类型"},{default:a(()=>[t(z,null,{default:a(()=>[r(s(e.detail.project_type),1)]),_:1})]),_:1}),t(g,{label:"状态"},{default:a(()=>[t(z,{color:e.statusColor(e.detail.status)},{default:a(()=>[r(s(e.detail.status),1)]),_:1},8,["color"])]),_:1}),t(g,{label:"同步状态"},{default:a(()=>[t(z,{color:e.syncColor(e.detail.sync_status)},{default:a(()=>[r(s(e.detail.sync_status||"unknown"),1)]),_:1},8,["color"])]),_:1}),t(g,{label:"用户"},{default:a(()=>[r(s(e.detail.user_id),1)]),_:1}),t(g,{label:"根路径"},{default:a(()=>[e.detail.root_path?(p(),A("code",Re,s(e.detail.root_path),1)):(p(),A("span",Te,"(无)"))]),_:1}),t(g,{label:"文件数"},{default:a(()=>[r(s(e.detail.file_count||0),1)]),_:1}),t(g,{label:"创建"},{default:a(()=>[r(s(e.formatTime(e.detail.created_at)),1)]),_:1}),t(g,{label:"更新"},{default:a(()=>[r(s(e.formatTime(e.detail.updated_at)),1)]),_:1})]),_:1})):_("v-if",!0),t(Q,null,{default:a(()=>[...l[28]||(l[28]=[r("文件",-1)])]),_:1}),_(" Sub-phase 7.3 (2026-05-17): 文件 CRUD toolbar "),t(O,{style:{"margin-bottom":"12px"}},{default:a(()=>[t(y,{size:"small",type:"primary",disabled:!e.detail,onClick:e.openCreateFile},{default:a(()=>[t(e.FileAddOutlined),l[29]||(l[29]=r(" 新建文件 ",-1))]),_:1},8,["disabled"]),t(y,{size:"small",disabled:!e.detail,onClick:e.openCreateFolder},{default:a(()=>[t(e.FolderAddOutlined),l[30]||(l[30]=r(" 新建文件夹 ",-1))]),_:1},8,["disabled"])]),_:1}),t(H,{spinning:e.filesLoading},{default:a(()=>[!e.files.length&&!e.filesLoading?(p(),x(C,{key:0,description:"无文件 (点上方按钮新建)"})):(p(),x(M,{key:1,size:"small","data-source":e.files},{renderItem:a(({item:n})=>[t(G,null,{extra:a(()=>[t(O,null,{default:a(()=>[n.file_size?(p(),A("span",Ee,s(n.file_size)+" B",1)):_("v-if",!0),t(V,{title:`删除 ${n.is_folder?"文件夹":"文件"} '${n.file_name}' ?`,"ok-text":"删除","ok-type":"danger","cancel-text":"取消",onConfirm:c=>e.onDeleteFile(n)},{default:a(()=>[t(y,{size:"small",danger:""},{default:a(()=>[...l[31]||(l[31]=[r("×",-1)])]),_:1})]),_:1},8,["title","onConfirm"])]),_:2},1024)]),default:a(()=>[U("span",{style:{cursor:"pointer"},onClick:c=>e.openEditFile(n)},s(n.is_folder?"📁":"📄")+" "+s(n.file_path),9,Be)]),_:2},1024)]),_:1},8,["data-source"]))]),_:1},8,["spinning"])]),_:1},8,["open","title"]),_(" Sub-phase 7.3: Create file modal "),t(I,{open:e.createFileOpen,"onUpdate:open":l[6]||(l[6]=n=>e.createFileOpen=n),title:"新建文件","confirm-loading":e.creatingFile,"ok-text":"创建","cancel-text":"取消",onOk:e.onCreateFile},{default:a(()=>[t(j,{layout:"vertical"},{default:a(()=>[t(F,{label:"文件路径(项目内)",required:""},{default:a(()=>[t(T,{value:e.newFile.path,"onUpdate:value":l[4]||(l[4]=n=>e.newFile.path=n),placeholder:"例如 README.md 或 src/main.kt"},null,8,["value"])]),_:1}),t(F,{label:"初始内容(可选)"},{default:a(()=>[t(D,{value:e.newFile.content,"onUpdate:value":l[5]||(l[5]=n=>e.newFile.content=n),rows:6,placeholder:"留空创建空文件"},null,8,["value"])]),_:1})]),_:1})]),_:1},8,["open","confirm-loading"]),_(" Sub-phase 7.3: Create folder modal "),t(I,{open:e.createFolderOpen,"onUpdate:open":l[8]||(l[8]=n=>e.createFolderOpen=n),title:"新建文件夹","confirm-loading":e.creatingFolder,"ok-text":"创建","cancel-text":"取消",onOk:e.onCreateFolder},{default:a(()=>[t(j,{layout:"vertical"},{default:a(()=>[t(F,{label:"文件夹路径(项目内)",required:""},{default:a(()=>[t(T,{value:e.newFolder.path,"onUpdate:value":l[7]||(l[7]=n=>e.newFolder.path=n),placeholder:"例如 src/utils"},null,8,["value"])]),_:1})]),_:1})]),_:1},8,["open","confirm-loading"]),_(" Sub-phase 7.3: Edit file content modal "),t(I,{open:e.editFileOpen,"onUpdate:open":l[10]||(l[10]=n=>e.editFileOpen=n),title:`编辑 ${e.editingFile?.file_name||""}`,"confirm-loading":e.savingFile,"ok-text":"保存","cancel-text":"取消",onOk:e.onSaveFile,width:"720"},{default:a(()=>[t(D,{value:e.editFileContent,"onUpdate:value":l[9]||(l[9]=n=>e.editFileContent=n),rows:18,"auto-size":{minRows:12,maxRows:24},style:{"font-family":"monospace"}},null,8,["value"])]),_:1},8,["open","title","confirm-loading"]),_(" Create modal "),t(I,{open:e.createOpen,"onUpdate:open":l[15]||(l[15]=n=>e.createOpen=n),title:"新建项目","confirm-loading":e.creating,"ok-text":"创建","cancel-text":"取消",onOk:e.onCreate},{default:a(()=>[t(j,{layout:"vertical"},{default:a(()=>[t(F,{label:"项目名称",required:""},{default:a(()=>[t(T,{value:e.newProject.name,"onUpdate:value":l[11]||(l[11]=n=>e.newProject.name=n),placeholder:"例如:旅行计划-上海"},null,8,["value"])]),_:1}),t(F,{label:"描述"},{default:a(()=>[t(D,{value:e.newProject.description,"onUpdate:value":l[12]||(l[12]=n=>e.newProject.description=n),rows:2},null,8,["value"])]),_:1}),t(F,{label:"类型"},{default:a(()=>[t(R,{value:e.newProject.type,"onUpdate:value":l[13]||(l[13]=n=>e.newProject.type=n)},{default:a(()=>[t(m,{value:"document"},{default:a(()=>[...l[32]||(l[32]=[r("文档 (document)",-1)])]),_:1}),t(m,{value:"data"},{default:a(()=>[...l[33]||(l[33]=[r("数据 (data)",-1)])]),_:1}),t(m,{value:"web"},{default:a(()=>[...l[34]||(l[34]=[r("Web",-1)])]),_:1}),t(m,{value:"app"},{default:a(()=>[...l[35]||(l[35]=[r("应用 (app)",-1)])]),_:1}),t(m,{value:"presentation"},{default:a(()=>[...l[36]||(l[36]=[r("演示文稿",-1)])]),_:1}),t(m,{value:"spreadsheet"},{default:a(()=>[...l[37]||(l[37]=[r("表格",-1)])]),_:1}),t(m,{value:"design"},{default:a(()=>[...l[38]||(l[38]=[r("设计",-1)])]),_:1}),t(m,{value:"code"},{default:a(()=>[...l[39]||(l[39]=[r("代码",-1)])]),_:1}),t(m,{value:"workflow"},{default:a(()=>[...l[40]||(l[40]=[r("工作流",-1)])]),_:1}),t(m,{value:"knowledge"},{default:a(()=>[...l[41]||(l[41]=[r("知识库",-1)])]),_:1})]),_:1},8,["value"])]),_:1}),t(F,{label:"根路径 (可选)"},{default:a(()=>[t(T,{value:e.newProject.rootPath,"onUpdate:value":l[14]||(l[14]=n=>e.newProject.rootPath=n),placeholder:"留空则仅元数据"},null,8,["value"])]),_:1})]),_:1})]),_:1},8,["open","confirm-loading"])])}const We=we(Pe,[["render",Le],["__scopeId","data-v-019ac5aa"],["__file","/tmp/cc-web-panel-blIgp5/repo/packages/web-panel/src/views/Projects.vue"]]);export{We as default};
|