agentengine-sdk-python 0.8.2__py3-none-any.whl → 0.8.3__py3-none-any.whl
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.
- {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/METADATA +18 -25
- {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/RECORD +224 -169
- ksadk/_build_provenance.json +1 -0
- ksadk/agui/_agent_helpers.py +4 -0
- ksadk/api/client.py +3 -0
- ksadk/builders/managed_runtime_builder.py +3 -0
- ksadk/cli/__init__.py +6 -0
- ksadk/cli/cmd_plugin.py +657 -0
- ksadk/codex/runtime.py +50 -8
- ksadk/configs/env_registry.py +31 -3
- ksadk/configs/settings.py +9 -0
- ksadk/context_engine/contributors.py +73 -8
- ksadk/conversations/__init__.py +19 -0
- ksadk/conversations/context.py +104 -24
- ksadk/conversations/contracts.py +266 -0
- ksadk/conversations/message_projection.py +19 -1
- ksadk/conversations/projector.py +616 -0
- ksadk/conversations/reducer.py +98 -0
- ksadk/events/_v1_compat/projection.py +2 -0
- ksadk/events/adapters/codex.py +190 -0
- ksadk/harness/__init__.py +45 -35
- ksadk/harness/runtime.py +60 -1
- ksadk/kernel/contract_fingerprints.py +5 -4
- ksadk/kernel/contracts.py +8 -0
- ksadk/kernel/control.py +1 -0
- ksadk/kernel/ingress.py +21 -0
- ksadk/kernel/memory_store.py +1 -0
- ksadk/kernel/postgres_store.py +1 -0
- ksadk/kernel/sqlite_store.py +1 -0
- ksadk/kernel/worker.py +11 -0
- ksadk/memory/providers/local_sqlite.py +7 -0
- ksadk/plugins/__init__.py +167 -0
- ksadk/plugins/bridges/__init__.py +45 -0
- ksadk/plugins/bridges/codex.py +552 -0
- ksadk/plugins/bridges/dsh.py +1116 -0
- ksadk/plugins/builtins.py +747 -0
- ksadk/plugins/bundle.py +246 -0
- ksadk/plugins/bundle_security.py +167 -0
- ksadk/plugins/composition.py +529 -0
- ksadk/plugins/context_contributor.py +437 -0
- ksadk/plugins/contracts.py +451 -0
- ksadk/plugins/dsh_toolchain.py +935 -0
- ksadk/plugins/ecosystem_bridge.py +1105 -0
- ksadk/plugins/ecosystem_probe.py +191 -0
- ksadk/plugins/host.py +724 -0
- ksadk/plugins/providers/__init__.py +85 -0
- ksadk/plugins/providers/bundles/ksadk-codex/cordis.patch.yml +3 -0
- ksadk/plugins/providers/bundles/ksadk-codex/index.mjs +18 -0
- ksadk/plugins/providers/bundles/ksadk-codex/package.json +19 -0
- ksadk/plugins/providers/bundles/ksadk-harness/cordis.patch.yml +3 -0
- ksadk/plugins/providers/bundles/ksadk-harness/index.mjs +19 -0
- ksadk/plugins/providers/bundles/ksadk-harness/package.json +19 -0
- ksadk/plugins/providers/codex.py +722 -0
- ksadk/plugins/providers/codex_dsh.py +83 -0
- ksadk/plugins/providers/dsh.py +951 -0
- ksadk/plugins/providers/dsh_descriptor_host.py +226 -0
- ksadk/plugins/providers/harness.py +627 -0
- ksadk/plugins/providers/harness_dsh.py +91 -0
- ksadk/plugins/providers/legacy.py +215 -0
- ksadk/plugins/providers/legacy_catalog.py +100 -0
- ksadk/plugins/providers/shipped_dsh.py +370 -0
- ksadk/plugins/resolver.py +331 -0
- ksadk/plugins/subagent_providers/__init__.py +12 -0
- ksadk/plugins/subagent_providers/codex.py +443 -0
- ksadk/plugins/subagents.py +333 -0
- ksadk/runtime/_runner_adapter/stream_mapping.py +51 -42
- ksadk/runtime/adapter.py +1 -0
- ksadk/runtime/factory.py +76 -2
- ksadk/runtime/framework_adapters.py +18 -0
- ksadk/runtime/runner_adapter.py +5 -0
- ksadk/sandbox/__init__.py +2 -1
- ksadk/sandbox/factory.py +72 -0
- ksadk/scheduler/__init__.py +18 -0
- ksadk/scheduler/calendar.py +102 -0
- ksadk/scheduler/contracts.py +254 -0
- ksadk/scheduler/dispatcher.py +129 -0
- ksadk/scheduler/engine.py +416 -0
- ksadk/scheduler/sqlite_store.py +563 -0
- ksadk/server/static/assets/{ArtifactsPanel-DSU1sWD_.js → ArtifactsPanel-10GPXIJ6.js} +1 -1
- ksadk/server/static/assets/{CodeBlock-DOH6MVcn.js → CodeBlock-BXk1l-G1.js} +1 -1
- ksadk/server/static/assets/{MathMessageMarkdown-BL8my1R2.js → MathMessageMarkdown-D9uB55Oh.js} +1 -1
- ksadk/server/static/assets/{MermaidBlock-Dz4IP-Tx.js → MermaidBlock--OEYoXIJ.js} +6 -6
- ksadk/server/static/assets/{NativeTerminalPanel-DUrK0JpZ.js → NativeTerminalPanel-DrEe1syq.js} +1 -1
- ksadk/server/static/assets/{abnfDiagram-VCTEODGH-g20pFzNV.js → abnfDiagram-VCTEODGH-eeTFJLvo.js} +1 -1
- ksadk/server/static/assets/{arc-C4FzinUA.js → arc-S3ZNbIAd.js} +1 -1
- ksadk/server/static/assets/architecture-7GRP2DOG-Dk9nRQ6-.js +1 -0
- ksadk/server/static/assets/{architectureDiagram-5GKGNRK7-DpIqL5h4.js → architectureDiagram-5GKGNRK7-CRjgEJDX.js} +1 -1
- ksadk/server/static/assets/{blockDiagram-NRAW4CY4-BjkljTNz.js → blockDiagram-NRAW4CY4-C7bsBoNH.js} +1 -1
- ksadk/server/static/assets/{c4Diagram-UCG6FXSJ-Dk_ieq2X.js → c4Diagram-UCG6FXSJ-BX3c33Ob.js} +1 -1
- ksadk/server/static/assets/channel-s354Yo6o.js +1 -0
- ksadk/server/static/assets/chunk-2Q5K7J3B-CDpPpKR5.js +1 -0
- ksadk/server/static/assets/{chunk-5VM5RSS4-BVHAchFb.js → chunk-5VM5RSS4-bZ7ws-8m.js} +1 -1
- ksadk/server/static/assets/{chunk-F27PBJKO-C-ipQzuS.js → chunk-F27PBJKO-D2r0pvhY.js} +1 -1
- ksadk/server/static/assets/{chunk-G27WJ6UU-C2EyJbIK.js → chunk-G27WJ6UU-CZwF3oUP.js} +1 -1
- ksadk/server/static/assets/{chunk-JWPE2WC7-vYvVJb_M.js → chunk-JWPE2WC7-DigFYCML.js} +1 -1
- ksadk/server/static/assets/{chunk-LCL6LL3I-BcI6ysPT.js → chunk-LCL6LL3I-CnorGV5q.js} +1 -1
- ksadk/server/static/assets/{chunk-POPQ4Y6H-C030x_Z1.js → chunk-POPQ4Y6H-CexntQA-.js} +1 -1
- ksadk/server/static/assets/{chunk-RHFEMEQ7-yyGpsz4n.js → chunk-RHFEMEQ7-CHTC7UxA.js} +1 -1
- ksadk/server/static/assets/{chunk-SVP7TREG-BLTlmMU7.js → chunk-SVP7TREG-BC1EWt_-.js} +1 -1
- ksadk/server/static/assets/{chunk-XXDRQBXY-C_32ArgP.js → chunk-XXDRQBXY-BTG24xN0.js} +1 -1
- ksadk/server/static/assets/classDiagram-DTDB5LWJ-Dd0nucl9.js +1 -0
- ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-Dd0nucl9.js +1 -0
- ksadk/server/static/assets/{cose-bilkent-JH36ORCC-9YQYwdl0.js → cose-bilkent-JH36ORCC-CkonRdAS.js} +1 -1
- ksadk/server/static/assets/cynefin-OW5HDTMX-BBlT4uMf.js +1 -0
- ksadk/server/static/assets/{cynefinDiagram-5FMLGOSQ-ErLF5N13.js → cynefinDiagram-5FMLGOSQ-DEOCBe15.js} +1 -1
- ksadk/server/static/assets/{dagre-3AP2YEHR-DFiQF-6f.js → dagre-3AP2YEHR-DBThPuLa.js} +1 -1
- ksadk/server/static/assets/{dagre-BuhGnRI1.js → dagre-ClTPrTht.js} +1 -1
- ksadk/server/static/assets/{diagram-S7CK7UJ4-Bt1v8-GC.js → diagram-S7CK7UJ4-DsZHrnpJ.js} +1 -1
- ksadk/server/static/assets/{diagram-UQ7AKVKN-DSCxJdBK.js → diagram-UQ7AKVKN-BJR4nhVr.js} +1 -1
- ksadk/server/static/assets/{diagram-VSXAHHWV-DHfYwp_9.js → diagram-VSXAHHWV-xzcERX0a.js} +1 -1
- ksadk/server/static/assets/{diagram-VX7I27RA-DdzD-4Le.js → diagram-VX7I27RA-tn2xM1xu.js} +1 -1
- ksadk/server/static/assets/{diagram-Z3DM3KII-Du-nAJ9F.js → diagram-Z3DM3KII-BZPGBkw5.js} +1 -1
- ksadk/server/static/assets/{dist-ClxGviKw.js → dist-4zN1_tq5.js} +1 -1
- ksadk/server/static/assets/{dist-BE7bu-DL.js → dist-8VWI-2bZ.js} +1 -1
- ksadk/server/static/assets/{dist-BX8z72IC.js → dist-B-46q3Hk.js} +1 -1
- ksadk/server/static/assets/{dist-BjU6y-A2.js → dist-B0gdk4rl.js} +1 -1
- ksadk/server/static/assets/{dist-C_wsv-Qd.js → dist-B1oWRmrH.js} +1 -1
- ksadk/server/static/assets/{dist-ngtN0DJB.js → dist-BI1qQH4n.js} +1 -1
- ksadk/server/static/assets/{dist-dydu68Fl.js → dist-BJLUwH6W.js} +1 -1
- ksadk/server/static/assets/{dist-Dq9gLD7L.js → dist-Bbwqa8TG.js} +1 -1
- ksadk/server/static/assets/{dist-CttYUqzS.js → dist-Btyo4vX4.js} +1 -1
- ksadk/server/static/assets/{dist-CXYYBw3_.js → dist-C71CsujO.js} +1 -1
- ksadk/server/static/assets/{dist-dDdADKFA.js → dist-CXpH_Rdd.js} +1 -1
- ksadk/server/static/assets/{dist-CSh_DE14.js → dist-Cq4OL6nO.js} +1 -1
- ksadk/server/static/assets/{dist-8hqcx0sU.js → dist-D1V3f1B4.js} +1 -1
- ksadk/server/static/assets/{dist-BVDffZ0U.js → dist-DJmCPRVB.js} +1 -1
- ksadk/server/static/assets/{dist-DnfXs8Vn.js → dist-DQAB0qn_.js} +1 -1
- ksadk/server/static/assets/{dist-DNp6rLRA.js → dist-DUwKa_l6.js} +1 -1
- ksadk/server/static/assets/{dist-B7seoj3d.js → dist-DdRBIceA.js} +1 -1
- ksadk/server/static/assets/{dist-BytlxIDT.js → dist-DfGFrb0v.js} +1 -1
- ksadk/server/static/assets/{dist-Bf2M8m3N.js → dist-DjhwGUgZ.js} +1 -1
- ksadk/server/static/assets/{dist-W-TIVntx.js → dist-DyqV4fL4.js} +1 -1
- ksadk/server/static/assets/{dist-DUX-id_F.js → dist-M67Hwu0n.js} +1 -1
- ksadk/server/static/assets/{dist-DmldrHd_.js → dist-u8tVH5Ak.js} +1 -1
- ksadk/server/static/assets/{ebnfDiagram-PWID7BFC-Da9C9NO1.js → ebnfDiagram-PWID7BFC-DVfMsLge.js} +1 -1
- ksadk/server/static/assets/{erDiagram-SSCWMZ5O-EAGqqR79.js → erDiagram-SSCWMZ5O-CWEZSYaw.js} +1 -1
- ksadk/server/static/assets/eventmodeling-NTZA5JFV-Dr5okd8V.js +1 -0
- ksadk/server/static/assets/flowDiagram-A5DVABFB-VEO-cVcO.js +1 -0
- ksadk/server/static/assets/{ganttDiagram-EL5Y4UJY-DqJsKb59.js → ganttDiagram-EL5Y4UJY-TWIxoyYL.js} +1 -1
- ksadk/server/static/assets/gitGraph-4MIJSDKK-CKiKY9Cf.js +1 -0
- ksadk/server/static/assets/{gitGraphDiagram-WWUBYQGX-B6g4dtDi.js → gitGraphDiagram-WWUBYQGX-DDh2hd2S.js} +1 -1
- ksadk/server/static/assets/index-B2k_urY8.js +241 -0
- ksadk/server/static/assets/index-ILPt6IWF.css +2 -0
- ksadk/server/static/assets/info-A6RAGUB7-ubA4Nm_p.js +1 -0
- ksadk/server/static/assets/{infoDiagram-RXCK75RN-Djm_nbd5.js → infoDiagram-RXCK75RN-CgoyWiDR.js} +1 -1
- ksadk/server/static/assets/{ishikawaDiagram-5VMMS53U-DWya9SG2.js → ishikawaDiagram-5VMMS53U-CyRIu_om.js} +1 -1
- ksadk/server/static/assets/{journeyDiagram-EYS64GPL-DutxhSNI.js → journeyDiagram-EYS64GPL-DN5JXHzN.js} +1 -1
- ksadk/server/static/assets/{kanban-definition-3QL26DDD-DJdOF8Fm.js → kanban-definition-3QL26DDD-CNP3ui66.js} +1 -1
- ksadk/server/static/assets/{katex-vFWytM5c.js → katex-DWEzQy1d.js} +1 -1
- ksadk/server/static/assets/{linear-BHjG8b-J.js → linear-C-qHp7d2.js} +1 -1
- ksadk/server/static/assets/{mermaid-parser.core-KGSy4jWT.js → mermaid-parser.core-Cl-K943T.js} +2 -2
- ksadk/server/static/assets/{mindmap-definition-FBJOCRG2-9-HC88D4.js → mindmap-definition-FBJOCRG2-D5DB5mYm.js} +1 -1
- ksadk/server/static/assets/packet-AYTQ26CC-C7R3NUlK.js +1 -0
- ksadk/server/static/assets/{pegDiagram-XKGWAZYB-DrEZd4fD.js → pegDiagram-XKGWAZYB-BQVc9ia_.js} +1 -1
- ksadk/server/static/assets/pie-WAS4IAKB-BIT6qjr3.js +1 -0
- ksadk/server/static/assets/{pieDiagram-E7YTZNPT-DpjqOFFp.js → pieDiagram-E7YTZNPT-B6UCAvtY.js} +1 -1
- ksadk/server/static/assets/{quadrantDiagram-AXDQQJYC-BiNhgOXX.js → quadrantDiagram-AXDQQJYC-mIr2d3eb.js} +1 -1
- ksadk/server/static/assets/radar-RG4KPBEZ-l5noef9X.js +1 -0
- ksadk/server/static/assets/railroad-74A4TZTK-Baea6ZvM.js +1 -0
- ksadk/server/static/assets/railroad-abnf-HS5TGJTU-OKn8zZnU.js +1 -0
- ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-DdKAKC4l.js +1 -0
- ksadk/server/static/assets/railroad-peg-WCYAUIDC-Bds8udlG.js +1 -0
- ksadk/server/static/assets/{railroadDiagram-O6MQD6OU-_Y3Ojg6G.js → railroadDiagram-O6MQD6OU-Dt3FFDmK.js} +1 -1
- ksadk/server/static/assets/{requirementDiagram-EFPCY7ZU-DeCFdg9K.js → requirementDiagram-EFPCY7ZU-Cz_vQtgF.js} +1 -1
- ksadk/server/static/assets/{sankeyDiagram-P5KCCOFB-CPH75rhw.js → sankeyDiagram-P5KCCOFB-wlO1TsH5.js} +1 -1
- ksadk/server/static/assets/{sequenceDiagram-WJ2MYXX4-OEpQQdr4.js → sequenceDiagram-WJ2MYXX4-CHRbElYq.js} +1 -1
- ksadk/server/static/assets/{sizeCapture-X5ZJPWSS-heUErzhI.js → sizeCapture-X5ZJPWSS-DXX54iyO.js} +1 -1
- ksadk/server/static/assets/{stateDiagram-HBIQ2CUA-DvA3jSMB.js → stateDiagram-HBIQ2CUA-Dp_lw9II.js} +1 -1
- ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-5b-8o2iS.js +1 -0
- ksadk/server/static/assets/{swimlanes-XN3QIQJK-CR-dfN_t.js → swimlanes-XN3QIQJK-D8O5UlLG.js} +1 -1
- ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-uf6WPRA4.js +8 -0
- ksadk/server/static/assets/{timeline-definition-24CTP7MA-DAVJf1TX.js → timeline-definition-24CTP7MA-8mfKcxvG.js} +1 -1
- ksadk/server/static/assets/treeView-Q6P3EWNA-CK5CSrSO.js +1 -0
- ksadk/server/static/assets/treemap-WGGIJYW6-Ch2BKgAM.js +1 -0
- ksadk/server/static/assets/{vennDiagram-4TSXK5OY-DwM8eDkh.js → vennDiagram-4TSXK5OY-EnNl0DE7.js} +1 -1
- ksadk/server/static/assets/wardley-WFR3VGLG-YW3Q0ml_.js +1 -0
- ksadk/server/static/assets/{wardleyDiagram-VM6X3IG4-DZL-Zz2t.js → wardleyDiagram-VM6X3IG4-DBu5fbYr.js} +1 -1
- ksadk/server/static/assets/{xychartDiagram-S5SC5T6Z-Dy6Yh_hu.js → xychartDiagram-S5SC5T6Z-BSVXs4IY.js} +1 -1
- ksadk/server/static/index.html +2 -2
- ksadk/skills/service_client.py +48 -0
- ksadk/studio/agent_lifecycle.py +26 -20
- ksadk/studio/api.py +513 -71
- ksadk/studio/api_catalog_routes.py +5 -0
- ksadk/studio/api_contracts.py +34 -1
- ksadk/studio/api_plugin_routes.py +480 -0
- ksadk/studio/attachment_store.py +187 -0
- ksadk/studio/authoring.py +10 -4
- ksadk/studio/authoring_coordinator.py +12 -2
- ksadk/studio/builder.py +123 -43
- ksadk/studio/cloud.py +4 -0
- ksadk/studio/codex_agent_service.py +12 -1
- ksadk/studio/codex_builder.py +54 -15
- ksadk/studio/codex_manifest.py +21 -1
- ksadk/studio/codex_run.py +16 -4
- ksadk/studio/compatibility_report.py +445 -0
- ksadk/studio/compiler.py +6 -1
- ksadk/studio/contracts.py +123 -4
- ksadk/studio/dsh_provider_registration.py +768 -0
- ksadk/studio/event_store.py +54 -6
- ksadk/studio/framework_run.py +37 -4
- ksadk/studio/hosted_kernel.py +1 -1
- ksadk/studio/operations.py +12 -2
- ksadk/studio/plugin_composition.py +301 -0
- ksadk/studio/plugin_kernel_adapter.py +128 -0
- ksadk/studio/plugin_runtime.py +652 -0
- ksadk/studio/resource_catalog.py +6 -1
- ksadk/studio/run_service.py +713 -75
- ksadk/studio/runtime_source.py +9 -1
- ksadk/studio/scheduler_runtime.py +374 -0
- ksadk/studio/scheduler_service.py +211 -0
- ksadk/studio/service.py +672 -82
- ksadk/studio/shared_web.py +167 -28
- ksadk/studio/soul.py +52 -0
- ksadk/studio/static/assets/index-DXs1Eq4M.css +1 -0
- ksadk/studio/static/assets/index-DeDqwTsD.js +283 -0
- ksadk/studio/static/index.html +2 -2
- ksadk/studio/validator.py +1 -1
- ksadk/studio/workspace.py +1 -0
- ksadk/version.py +1 -1
- ksadk_runtime_common/workspace_files/path_utils.py +41 -0
- ksadk/server/static/assets/architecture-7GRP2DOG-DjKratdf.js +0 -1
- ksadk/server/static/assets/channel-4cQHKtx1.js +0 -1
- ksadk/server/static/assets/chunk-2Q5K7J3B-DmgWkESh.js +0 -1
- ksadk/server/static/assets/classDiagram-DTDB5LWJ-DLFd9Xi0.js +0 -1
- ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-DLFd9Xi0.js +0 -1
- ksadk/server/static/assets/cynefin-OW5HDTMX-DjEM48Qp.js +0 -1
- ksadk/server/static/assets/eventmodeling-NTZA5JFV-CMgMaJrC.js +0 -1
- ksadk/server/static/assets/flowDiagram-A5DVABFB-BBKL0x3P.js +0 -1
- ksadk/server/static/assets/gitGraph-4MIJSDKK-Dw63mrhw.js +0 -1
- ksadk/server/static/assets/index-8ipRcQ-M.js +0 -240
- ksadk/server/static/assets/index-ByFCqjlh.css +0 -2
- ksadk/server/static/assets/info-A6RAGUB7-B6iAblII.js +0 -1
- ksadk/server/static/assets/packet-AYTQ26CC-BOYAipuq.js +0 -1
- ksadk/server/static/assets/pie-WAS4IAKB-Ctq0Kbku.js +0 -1
- ksadk/server/static/assets/radar-RG4KPBEZ-DN0-ul_0.js +0 -1
- ksadk/server/static/assets/railroad-74A4TZTK-C6cC_to0.js +0 -1
- ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BimjIuRc.js +0 -1
- ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-CvY65ABq.js +0 -1
- ksadk/server/static/assets/railroad-peg-WCYAUIDC-D72Iq_Tv.js +0 -1
- ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BgQY03nz.js +0 -1
- ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-DLVw3q5Q.js +0 -8
- ksadk/server/static/assets/treeView-Q6P3EWNA-BMpO0wsB.js +0 -1
- ksadk/server/static/assets/treemap-WGGIJYW6-Et0aqzU3.js +0 -1
- ksadk/server/static/assets/wardley-WFR3VGLG-CbY0mhpl.js +0 -1
- ksadk/studio/static/assets/index-BLpcdrgW.css +0 -1
- ksadk/studio/static/assets/index-CYekR2Xv.js +0 -260
- {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/WHEEL +0 -0
- {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/entry_points.txt +0 -0
- {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/licenses/LICENSE +0 -0
- {agentengine_sdk_python-0.8.2.dist-info → agentengine_sdk_python-0.8.3.dist-info}/top_level.txt +0 -0
ksadk/cli/cmd_plugin.py
ADDED
|
@@ -0,0 +1,657 @@
|
|
|
1
|
+
"""``agentengine plugin`` - DSH-native and Codex-compatible plugin management.
|
|
2
|
+
|
|
3
|
+
The stable CLI deliberately exposes only two ecosystems. Top-level lifecycle
|
|
4
|
+
commands manage the active DeepSeek Harness Profile; ``plugin dsh`` remains a
|
|
5
|
+
compatibility alias for scripts that adopted the earlier explicit namespace.
|
|
6
|
+
Codex plugins stay under ``plugin codex`` because their lifecycle is owned by
|
|
7
|
+
Codex App Server.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import asyncio
|
|
13
|
+
import os
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Any
|
|
16
|
+
|
|
17
|
+
import click
|
|
18
|
+
|
|
19
|
+
from ksadk.cli.error_utils import (
|
|
20
|
+
EXIT_CODE_RESOLUTION,
|
|
21
|
+
EXIT_CODE_VALIDATION,
|
|
22
|
+
CLIError,
|
|
23
|
+
abort_with_cli_error,
|
|
24
|
+
)
|
|
25
|
+
from ksadk.cli.resource_common import CONTEXT_SETTINGS
|
|
26
|
+
from ksadk.cli.ui import emit_json, is_json_output, print_info, print_kv, print_success
|
|
27
|
+
|
|
28
|
+
CODEX_HOME_ENV = "KSADK_CODEX_HOME"
|
|
29
|
+
DSH_HOME_ENV = "KSADK_DSH_HOME"
|
|
30
|
+
DSH_BIN_ENV = "KSADK_DSH_BIN"
|
|
31
|
+
DSH_PROFILE_ENV = "KSADK_DSH_PROFILE"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _codex_home() -> Path:
|
|
35
|
+
"""Use the same workspace-isolated Codex home as the local Runtime."""
|
|
36
|
+
|
|
37
|
+
configured = os.environ.get(CODEX_HOME_ENV, "").strip()
|
|
38
|
+
if configured:
|
|
39
|
+
return Path(configured).expanduser()
|
|
40
|
+
return Path.cwd() / ".agentkit" / "codex-home"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _dsh_home() -> Path:
|
|
44
|
+
configured = os.environ.get(DSH_HOME_ENV, "").strip()
|
|
45
|
+
if configured:
|
|
46
|
+
return Path(configured).expanduser()
|
|
47
|
+
return Path.cwd() / ".agentkit" / "dsh-home"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _dsh_command() -> tuple[str, ...] | None:
|
|
51
|
+
configured = os.environ.get(DSH_BIN_ENV, "").strip()
|
|
52
|
+
from ksadk.plugins.dsh_toolchain import DshToolchainManager
|
|
53
|
+
|
|
54
|
+
return DshToolchainManager().require_command(configured or None)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _dsh_profile() -> str:
|
|
58
|
+
return os.environ.get(DSH_PROFILE_ENV, "").strip() or "ksadk"
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _codex_inventory_payload(value: Any) -> dict[str, Any]:
|
|
62
|
+
"""Project Codex host inventory without leaking marketplace filesystem paths."""
|
|
63
|
+
|
|
64
|
+
raw = value.model_dump(mode="json", by_alias=True, exclude_none=True)
|
|
65
|
+
return {
|
|
66
|
+
"ecosystem": "codex",
|
|
67
|
+
"integrationMode": "bridged",
|
|
68
|
+
"pluginId": raw["pluginId"],
|
|
69
|
+
"name": raw["name"],
|
|
70
|
+
"marketplaceName": raw["marketplaceName"],
|
|
71
|
+
"version": raw.get("version"),
|
|
72
|
+
"installed": raw["installed"],
|
|
73
|
+
"enabled": raw["enabled"],
|
|
74
|
+
"availability": raw["availability"],
|
|
75
|
+
"permissionsDeclared": False,
|
|
76
|
+
"riskDisclosures": raw.get("riskDisclosures", []),
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _dsh_inventory_payload(value: Any) -> dict[str, Any]:
|
|
81
|
+
return value.model_dump(mode="json", by_alias=True, exclude_none=True)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
async def _with_codex_bridge(operation):
|
|
85
|
+
from ksadk.plugins.bridges.codex import CodexAppServerPluginBridge
|
|
86
|
+
|
|
87
|
+
async with CodexAppServerPluginBridge(codex_home=_codex_home()) as bridge:
|
|
88
|
+
return bridge.host, await operation(bridge)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _call_codex(operation):
|
|
92
|
+
"""Run one bounded App Server lifecycle request from the synchronous CLI."""
|
|
93
|
+
|
|
94
|
+
try:
|
|
95
|
+
return asyncio.run(_with_codex_bridge(operation))
|
|
96
|
+
except (KeyboardInterrupt, SystemExit):
|
|
97
|
+
raise
|
|
98
|
+
except Exception as err:
|
|
99
|
+
code = (
|
|
100
|
+
"codex_plugin_not_found"
|
|
101
|
+
if type(err).__name__ == "CodexPluginNotFoundError"
|
|
102
|
+
else (
|
|
103
|
+
"codex_plugin_permission_confirmation_required"
|
|
104
|
+
if type(err).__name__ == "CodexPluginApprovalRequired"
|
|
105
|
+
else "codex_plugin_host_unavailable"
|
|
106
|
+
)
|
|
107
|
+
)
|
|
108
|
+
abort_with_cli_error(
|
|
109
|
+
CLIError(
|
|
110
|
+
code=code,
|
|
111
|
+
message=(
|
|
112
|
+
"Codex 插件不存在或来源不唯一"
|
|
113
|
+
if code == "codex_plugin_not_found"
|
|
114
|
+
else "安装前必须确认 Codex App Server 宿主权限风险"
|
|
115
|
+
if code == "codex_plugin_permission_confirmation_required"
|
|
116
|
+
else "Codex 插件宿主当前不可用"
|
|
117
|
+
),
|
|
118
|
+
exit_code=(
|
|
119
|
+
EXIT_CODE_RESOLUTION
|
|
120
|
+
if code == "codex_plugin_not_found"
|
|
121
|
+
else EXIT_CODE_VALIDATION
|
|
122
|
+
),
|
|
123
|
+
),
|
|
124
|
+
context="Plugin",
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _call_dsh(operation):
|
|
129
|
+
"""Run one bounded DSH Profile lifecycle request from the synchronous CLI."""
|
|
130
|
+
|
|
131
|
+
from ksadk.plugins.bridges.dsh import DshProfilePluginBridge
|
|
132
|
+
|
|
133
|
+
try:
|
|
134
|
+
with DshProfilePluginBridge(
|
|
135
|
+
dsh_home=_dsh_home(),
|
|
136
|
+
profile=_dsh_profile(),
|
|
137
|
+
dsh_command=_dsh_command(),
|
|
138
|
+
) as bridge:
|
|
139
|
+
return bridge.host, operation(bridge)
|
|
140
|
+
except (KeyboardInterrupt, SystemExit):
|
|
141
|
+
raise
|
|
142
|
+
except Exception as err:
|
|
143
|
+
name = type(err).__name__
|
|
144
|
+
code = (
|
|
145
|
+
"dsh_plugin_not_found"
|
|
146
|
+
if name == "DshPluginNotFoundError"
|
|
147
|
+
else "dsh_plugin_permission_confirmation_required"
|
|
148
|
+
if name == "DshPluginApprovalRequired"
|
|
149
|
+
else "dsh_plugin_operation_failed"
|
|
150
|
+
if name in {"DshPluginMutationError", "ValueError"}
|
|
151
|
+
else "dsh_plugin_host_unavailable"
|
|
152
|
+
)
|
|
153
|
+
messages = {
|
|
154
|
+
"dsh_plugin_not_found": "DSH 插件未安装",
|
|
155
|
+
"dsh_plugin_permission_confirmation_required": (
|
|
156
|
+
"安装或升级前必须确认 DSH 宿主权限风险"
|
|
157
|
+
),
|
|
158
|
+
"dsh_plugin_operation_failed": "DSH 插件操作失败,原 Profile 已保留",
|
|
159
|
+
"dsh_plugin_host_unavailable": "DSH 插件宿主当前不可用",
|
|
160
|
+
}
|
|
161
|
+
abort_with_cli_error(
|
|
162
|
+
CLIError(
|
|
163
|
+
code=code,
|
|
164
|
+
message=messages[code],
|
|
165
|
+
exit_code=(
|
|
166
|
+
EXIT_CODE_RESOLUTION if code == "dsh_plugin_not_found" else EXIT_CODE_VALIDATION
|
|
167
|
+
),
|
|
168
|
+
),
|
|
169
|
+
context="Plugin",
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def _call_dsh_developer(operation):
|
|
174
|
+
"""Run one bounded standard DSH bundle development operation."""
|
|
175
|
+
|
|
176
|
+
from ksadk.plugins.dsh_toolchain import (
|
|
177
|
+
DshPluginPackError,
|
|
178
|
+
DshPluginSourceError,
|
|
179
|
+
DshPluginValidationError,
|
|
180
|
+
DshToolchainInstallError,
|
|
181
|
+
DshToolchainUnavailableError,
|
|
182
|
+
DshToolchainVersionMismatchError,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
try:
|
|
186
|
+
return operation()
|
|
187
|
+
except (KeyboardInterrupt, SystemExit):
|
|
188
|
+
raise
|
|
189
|
+
except Exception as err:
|
|
190
|
+
if isinstance(err, DshToolchainVersionMismatchError):
|
|
191
|
+
code = "dsh_toolchain_version_mismatch"
|
|
192
|
+
message = "DSH 或 pnpm 版本与受支持工具链不一致"
|
|
193
|
+
elif isinstance(err, DshToolchainUnavailableError):
|
|
194
|
+
code = "dsh_toolchain_unavailable"
|
|
195
|
+
message = "DSH 插件开发工具链不可用"
|
|
196
|
+
elif isinstance(err, DshToolchainInstallError):
|
|
197
|
+
code = "dsh_toolchain_install_failed"
|
|
198
|
+
message = "DSH 插件开发工具链安装失败"
|
|
199
|
+
elif isinstance(err, DshPluginSourceError):
|
|
200
|
+
code = "dsh_plugin_source_invalid"
|
|
201
|
+
message = "DSH 插件源码不是有效的标准 Bundle"
|
|
202
|
+
elif isinstance(err, DshPluginValidationError):
|
|
203
|
+
code = "dsh_plugin_validation_failed"
|
|
204
|
+
message = "DSH 插件生命周期校验失败"
|
|
205
|
+
elif isinstance(err, DshPluginPackError):
|
|
206
|
+
code = "dsh_plugin_pack_failed"
|
|
207
|
+
message = "DSH 插件 npm 打包失败"
|
|
208
|
+
else:
|
|
209
|
+
raise
|
|
210
|
+
details = {}
|
|
211
|
+
stage = getattr(err, "stage", None)
|
|
212
|
+
if isinstance(stage, str) and stage:
|
|
213
|
+
details["stage"] = stage
|
|
214
|
+
abort_with_cli_error(
|
|
215
|
+
CLIError(
|
|
216
|
+
code=code,
|
|
217
|
+
message=message,
|
|
218
|
+
exit_code=EXIT_CODE_VALIDATION,
|
|
219
|
+
details=details,
|
|
220
|
+
),
|
|
221
|
+
context="Plugin",
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
@click.group("plugin", context_settings=CONTEXT_SETTINGS)
|
|
226
|
+
def plugin() -> None:
|
|
227
|
+
"""管理 DSH 插件,并兼容 Codex App Server 插件。"""
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
@plugin.group("toolchain", context_settings=CONTEXT_SETTINGS)
|
|
231
|
+
def plugin_toolchain() -> None:
|
|
232
|
+
"""管理固定版本、隔离安装的 DSH 插件开发工具链。"""
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
@plugin_toolchain.command("status", context_settings=CONTEXT_SETTINGS)
|
|
236
|
+
def plugin_toolchain_status() -> None:
|
|
237
|
+
"""检查受管理 DSH CLI、实际版本、pnpm 和锁文件。"""
|
|
238
|
+
|
|
239
|
+
from ksadk.plugins.dsh_toolchain import DshToolchainManager
|
|
240
|
+
|
|
241
|
+
state = DshToolchainManager().status()
|
|
242
|
+
payload = state.model_dump(mode="json", by_alias=True, exclude_none=True)
|
|
243
|
+
if is_json_output():
|
|
244
|
+
emit_json(payload)
|
|
245
|
+
return
|
|
246
|
+
print_kv("DSH", state.actual_version or state.expected_version)
|
|
247
|
+
print_kv("状态", "可用" if state.usable else "未安装或不完整")
|
|
248
|
+
print_kv("目录", state.root)
|
|
249
|
+
if state.problem:
|
|
250
|
+
print_kv("问题", state.problem)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
@plugin_toolchain.command("install", context_settings=CONTEXT_SETTINGS)
|
|
254
|
+
def install_plugin_toolchain() -> None:
|
|
255
|
+
"""从 npm 安装受支持的 DSH CLI;不需要 DSH 源码仓。"""
|
|
256
|
+
|
|
257
|
+
from ksadk.plugins.dsh_toolchain import DshToolchainManager
|
|
258
|
+
|
|
259
|
+
state = _call_dsh_developer(lambda: DshToolchainManager().install())
|
|
260
|
+
payload = state.model_dump(mode="json", by_alias=True, exclude_none=True)
|
|
261
|
+
if is_json_output():
|
|
262
|
+
emit_json(payload)
|
|
263
|
+
else:
|
|
264
|
+
print_success(f"DSH 插件开发工具链已就绪: {state.actual_version}")
|
|
265
|
+
print_kv("目录", state.root)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
@plugin.command("create", context_settings=CONTEXT_SETTINGS)
|
|
269
|
+
@click.argument("target", type=click.Path(path_type=Path))
|
|
270
|
+
@click.option("--name", "package_name", default=None, help="标准 npm 包名。")
|
|
271
|
+
def create_dsh_plugin(target: Path, package_name: str | None) -> None:
|
|
272
|
+
"""创建标准 DSH Bundle;不会生成 KsADK 私有 manifest。"""
|
|
273
|
+
|
|
274
|
+
from ksadk.plugins.dsh_toolchain import DshPluginDeveloper
|
|
275
|
+
|
|
276
|
+
result = _call_dsh_developer(
|
|
277
|
+
lambda: DshPluginDeveloper().create(target, package_name=package_name)
|
|
278
|
+
)
|
|
279
|
+
payload = result.model_dump(mode="json", by_alias=True)
|
|
280
|
+
if is_json_output():
|
|
281
|
+
emit_json(payload)
|
|
282
|
+
else:
|
|
283
|
+
print_success(f"DSH 插件已创建: {result.package_name}")
|
|
284
|
+
print_kv("目录", result.target)
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
@plugin.command("validate", context_settings=CONTEXT_SETTINGS)
|
|
288
|
+
@click.argument("source")
|
|
289
|
+
def validate_dsh_plugin(source: str) -> None:
|
|
290
|
+
"""在临时 Profile 验证安装、投射、启停与卸载生命周期。"""
|
|
291
|
+
|
|
292
|
+
from ksadk.plugins.dsh_toolchain import DshPluginDeveloper
|
|
293
|
+
|
|
294
|
+
configured = os.environ.get(DSH_BIN_ENV, "").strip() or None
|
|
295
|
+
result = _call_dsh_developer(
|
|
296
|
+
lambda: DshPluginDeveloper(explicit_dsh=configured).validate(source)
|
|
297
|
+
)
|
|
298
|
+
payload = result.model_dump(mode="json", by_alias=True)
|
|
299
|
+
if is_json_output():
|
|
300
|
+
emit_json(payload)
|
|
301
|
+
else:
|
|
302
|
+
print_success(f"DSH 插件生命周期已通过: {result.package_name}")
|
|
303
|
+
print_kv("DSH", result.host_version)
|
|
304
|
+
print_kv("Profile 摘要", result.profile_digest)
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
@plugin.command("test", context_settings=CONTEXT_SETTINGS)
|
|
308
|
+
@click.argument("source")
|
|
309
|
+
def test_dsh_plugin(source: str) -> None:
|
|
310
|
+
"""运行真实 DSH 生命周期 smoke;不冒充 Provider conformance。"""
|
|
311
|
+
|
|
312
|
+
validate_dsh_plugin.callback(source) # type: ignore[attr-defined]
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
@plugin.command("pack", context_settings=CONTEXT_SETTINGS)
|
|
316
|
+
@click.argument("source", type=click.Path(path_type=Path))
|
|
317
|
+
@click.option(
|
|
318
|
+
"--output-dir",
|
|
319
|
+
type=click.Path(path_type=Path),
|
|
320
|
+
default=None,
|
|
321
|
+
help="npm tarball 输出目录,默认 SOURCE/dist。",
|
|
322
|
+
)
|
|
323
|
+
def pack_dsh_plugin(source: Path, output_dir: Path | None) -> None:
|
|
324
|
+
"""委托固定 pnpm 将标准 DSH Bundle 打包成 npm tgz。"""
|
|
325
|
+
|
|
326
|
+
from ksadk.plugins.dsh_toolchain import DshPluginDeveloper
|
|
327
|
+
|
|
328
|
+
result = _call_dsh_developer(
|
|
329
|
+
lambda: DshPluginDeveloper().pack(source, output_dir=output_dir)
|
|
330
|
+
)
|
|
331
|
+
payload = result.model_dump(mode="json", by_alias=True)
|
|
332
|
+
if is_json_output():
|
|
333
|
+
emit_json(payload)
|
|
334
|
+
else:
|
|
335
|
+
print_success(f"DSH 插件已打包: {result.package_name}@{result.package_version}")
|
|
336
|
+
print_kv("产物", result.artifact)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
@plugin.group("codex", context_settings=CONTEXT_SETTINGS)
|
|
340
|
+
def codex_plugins() -> None:
|
|
341
|
+
"""通过 Codex App Server 管理 Codex 官方插件。"""
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
@codex_plugins.command("list", context_settings=CONTEXT_SETTINGS)
|
|
345
|
+
@click.option("--installed-only", is_flag=True, help="只显示已安装插件。")
|
|
346
|
+
@click.option("--force-refetch", is_flag=True, help="请求宿主刷新插件目录。")
|
|
347
|
+
def list_codex_plugins(installed_only: bool, force_refetch: bool) -> None:
|
|
348
|
+
"""列出 Codex 宿主可见的官方插件。"""
|
|
349
|
+
|
|
350
|
+
async def operation(bridge):
|
|
351
|
+
return await bridge.list_plugins(force_refetch=force_refetch)
|
|
352
|
+
|
|
353
|
+
host, items = _call_codex(operation)
|
|
354
|
+
visible = [item for item in items if item.installed or not installed_only]
|
|
355
|
+
payload = {
|
|
356
|
+
"ecosystem": "codex",
|
|
357
|
+
"integrationMode": "bridged",
|
|
358
|
+
"host": {"id": "codex-app-server", "version": host.version, "available": True},
|
|
359
|
+
"items": [_codex_inventory_payload(item) for item in visible],
|
|
360
|
+
}
|
|
361
|
+
if is_json_output():
|
|
362
|
+
emit_json(payload)
|
|
363
|
+
return
|
|
364
|
+
print_info(f"Codex App Server {host.version} · {len(visible)} 个插件")
|
|
365
|
+
for item in payload["items"]:
|
|
366
|
+
state = "已安装" if item["installed"] else "可安装"
|
|
367
|
+
click.echo(f"{item['pluginId']} {item.get('version') or '-'} {state}")
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
@codex_plugins.command("info", context_settings=CONTEXT_SETTINGS)
|
|
371
|
+
@click.argument("plugin_id")
|
|
372
|
+
@click.option("--marketplace", "marketplace_name", default=None)
|
|
373
|
+
def codex_plugin_info(plugin_id: str, marketplace_name: str | None) -> None:
|
|
374
|
+
"""显示一个 Codex 插件的宿主 inventory 和能力。"""
|
|
375
|
+
|
|
376
|
+
async def operation(bridge):
|
|
377
|
+
return await bridge.read_plugin(plugin_id, marketplace_name=marketplace_name)
|
|
378
|
+
|
|
379
|
+
host, detail = _call_codex(operation)
|
|
380
|
+
payload = {
|
|
381
|
+
"item": _codex_inventory_payload(detail.inventory),
|
|
382
|
+
"host": {"id": "codex-app-server", "version": host.version, "available": True},
|
|
383
|
+
"description": detail.description,
|
|
384
|
+
"capabilities": {
|
|
385
|
+
"skills": list(detail.skills),
|
|
386
|
+
"mcpServers": list(detail.mcp_servers),
|
|
387
|
+
"hooks": list(detail.hooks),
|
|
388
|
+
"apps": list(detail.apps),
|
|
389
|
+
"scheduledTasks": list(detail.scheduled_tasks),
|
|
390
|
+
},
|
|
391
|
+
}
|
|
392
|
+
if is_json_output():
|
|
393
|
+
emit_json(payload)
|
|
394
|
+
else:
|
|
395
|
+
print_success(f"Codex 插件: {plugin_id}")
|
|
396
|
+
print_kv("宿主", f"Codex App Server {host.version}")
|
|
397
|
+
print_kv("状态", "已安装" if detail.inventory.installed else "可安装")
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
@codex_plugins.command("install", context_settings=CONTEXT_SETTINGS)
|
|
401
|
+
@click.argument("plugin_id")
|
|
402
|
+
@click.option("--marketplace", "marketplace_name", default=None)
|
|
403
|
+
@click.option(
|
|
404
|
+
"--accept-host-permissions",
|
|
405
|
+
is_flag=True,
|
|
406
|
+
help="确认插件权限由 Codex 宿主管理并以当前系统用户权限运行。",
|
|
407
|
+
)
|
|
408
|
+
def install_codex_plugin(
|
|
409
|
+
plugin_id: str,
|
|
410
|
+
marketplace_name: str | None,
|
|
411
|
+
accept_host_permissions: bool,
|
|
412
|
+
) -> None:
|
|
413
|
+
"""安装一个 Codex 官方插件;必须显式确认宿主权限风险。"""
|
|
414
|
+
|
|
415
|
+
if not accept_host_permissions:
|
|
416
|
+
abort_with_cli_error(
|
|
417
|
+
CLIError(
|
|
418
|
+
code="codex_plugin_permission_confirmation_required",
|
|
419
|
+
message="安装前必须传入 --accept-host-permissions 确认宿主权限风险",
|
|
420
|
+
exit_code=EXIT_CODE_VALIDATION,
|
|
421
|
+
),
|
|
422
|
+
context="Plugin",
|
|
423
|
+
)
|
|
424
|
+
|
|
425
|
+
async def operation(bridge):
|
|
426
|
+
return await bridge.install_plugin(
|
|
427
|
+
plugin_id,
|
|
428
|
+
marketplace_name=marketplace_name,
|
|
429
|
+
accept_undeclared_permissions=True,
|
|
430
|
+
)
|
|
431
|
+
|
|
432
|
+
host, result = _call_codex(operation)
|
|
433
|
+
payload = {
|
|
434
|
+
"item": _codex_inventory_payload(result.inventory),
|
|
435
|
+
"host": {"id": "codex-app-server", "version": host.version, "available": True},
|
|
436
|
+
"authPolicy": result.auth_policy,
|
|
437
|
+
"appsNeedingAuth": list(result.apps_needing_auth),
|
|
438
|
+
}
|
|
439
|
+
if is_json_output():
|
|
440
|
+
emit_json(payload)
|
|
441
|
+
else:
|
|
442
|
+
print_success(f"Codex 插件已安装: {result.inventory.plugin_id}")
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
@codex_plugins.command("uninstall", context_settings=CONTEXT_SETTINGS)
|
|
446
|
+
@click.argument("plugin_id")
|
|
447
|
+
def uninstall_codex_plugin(plugin_id: str) -> None:
|
|
448
|
+
"""请求 Codex App Server 卸载插件。"""
|
|
449
|
+
|
|
450
|
+
async def operation(bridge):
|
|
451
|
+
return await bridge.uninstall_plugin(plugin_id)
|
|
452
|
+
|
|
453
|
+
host, result = _call_codex(operation)
|
|
454
|
+
payload = {
|
|
455
|
+
"ecosystem": "codex",
|
|
456
|
+
"integrationMode": "bridged",
|
|
457
|
+
"pluginId": result.plugin_id,
|
|
458
|
+
"installed": False,
|
|
459
|
+
"enabled": False,
|
|
460
|
+
"host": {"id": "codex-app-server", "version": host.version, "available": True},
|
|
461
|
+
}
|
|
462
|
+
if is_json_output():
|
|
463
|
+
emit_json(payload)
|
|
464
|
+
else:
|
|
465
|
+
print_success(f"Codex 插件已卸载: {plugin_id}")
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
@plugin.group("dsh", context_settings=CONTEXT_SETTINGS)
|
|
469
|
+
def dsh_plugins() -> None:
|
|
470
|
+
"""通过原生 DeepSeek Harness Profile 管理 DSH 插件。"""
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
@dsh_plugins.command("list", context_settings=CONTEXT_SETTINGS)
|
|
474
|
+
def list_dsh_plugins() -> None:
|
|
475
|
+
"""列出当前隔离 Profile 中的 DSH bundle。"""
|
|
476
|
+
|
|
477
|
+
host, items = _call_dsh(lambda bridge: bridge.list_plugins())
|
|
478
|
+
payload = {
|
|
479
|
+
"ecosystem": "dsh",
|
|
480
|
+
"integrationMode": "bridged",
|
|
481
|
+
"profile": _dsh_profile(),
|
|
482
|
+
"host": {"id": host.host_id, "version": host.version, "available": True},
|
|
483
|
+
"items": [_dsh_inventory_payload(item) for item in items],
|
|
484
|
+
}
|
|
485
|
+
if is_json_output():
|
|
486
|
+
emit_json(payload)
|
|
487
|
+
return
|
|
488
|
+
print_info(f"DeepSeek Harness {host.version} · {len(items)} 个 Profile 插件")
|
|
489
|
+
for item in payload["items"]:
|
|
490
|
+
state = "已启用" if item["enabled"] else "已停用"
|
|
491
|
+
click.echo(f"{item['name']} {item.get('version') or '-'} {state}")
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
@dsh_plugins.command("info", context_settings=CONTEXT_SETTINGS)
|
|
495
|
+
@click.argument("plugin_name")
|
|
496
|
+
def dsh_plugin_info(plugin_name: str) -> None:
|
|
497
|
+
"""显示一个 DSH 插件的原生 Profile inventory。"""
|
|
498
|
+
|
|
499
|
+
host, item = _call_dsh(lambda bridge: bridge.get_plugin(plugin_name))
|
|
500
|
+
payload = {
|
|
501
|
+
"item": _dsh_inventory_payload(item),
|
|
502
|
+
"host": {"id": host.host_id, "version": host.version, "available": True},
|
|
503
|
+
}
|
|
504
|
+
if is_json_output():
|
|
505
|
+
emit_json(payload)
|
|
506
|
+
else:
|
|
507
|
+
print_success(f"DSH 插件: {plugin_name}")
|
|
508
|
+
print_kv("状态", "已启用" if item.enabled else "已停用")
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
@dsh_plugins.command("install", context_settings=CONTEXT_SETTINGS)
|
|
512
|
+
@click.argument("source")
|
|
513
|
+
@click.option(
|
|
514
|
+
"--accept-host-permissions",
|
|
515
|
+
is_flag=True,
|
|
516
|
+
help="确认 DSH 包与安装脚本会以当前宿主用户权限运行。",
|
|
517
|
+
)
|
|
518
|
+
def install_dsh_plugin(source: str, accept_host_permissions: bool) -> None:
|
|
519
|
+
"""把一个 DSH bundle 安装到隔离 Profile;安装后默认停用。"""
|
|
520
|
+
|
|
521
|
+
if not accept_host_permissions:
|
|
522
|
+
abort_with_cli_error(
|
|
523
|
+
CLIError(
|
|
524
|
+
code="dsh_plugin_permission_confirmation_required",
|
|
525
|
+
message="安装前必须传入 --accept-host-permissions 确认宿主权限风险",
|
|
526
|
+
exit_code=EXIT_CODE_VALIDATION,
|
|
527
|
+
),
|
|
528
|
+
context="Plugin",
|
|
529
|
+
)
|
|
530
|
+
host, item = _call_dsh(
|
|
531
|
+
lambda bridge: bridge.install_plugin(source, accept_host_permissions=True)
|
|
532
|
+
)
|
|
533
|
+
payload = {
|
|
534
|
+
"item": _dsh_inventory_payload(item),
|
|
535
|
+
"host": {"id": host.host_id, "version": host.version, "available": True},
|
|
536
|
+
}
|
|
537
|
+
if is_json_output():
|
|
538
|
+
emit_json(payload)
|
|
539
|
+
else:
|
|
540
|
+
print_success(f"DSH 插件已安装并保持停用: {item.name};请显式执行 enable")
|
|
541
|
+
|
|
542
|
+
|
|
543
|
+
@dsh_plugins.command("enable", context_settings=CONTEXT_SETTINGS)
|
|
544
|
+
@click.argument("plugin_name")
|
|
545
|
+
def enable_dsh_plugin(plugin_name: str) -> None:
|
|
546
|
+
"""在 DSH Profile 中启用已安装的 bundle。"""
|
|
547
|
+
|
|
548
|
+
host, item = _call_dsh(lambda bridge: bridge.set_enabled(plugin_name, enabled=True))
|
|
549
|
+
payload = {
|
|
550
|
+
"item": _dsh_inventory_payload(item),
|
|
551
|
+
"host": {"id": host.host_id, "version": host.version, "available": True},
|
|
552
|
+
}
|
|
553
|
+
if is_json_output():
|
|
554
|
+
emit_json(payload)
|
|
555
|
+
else:
|
|
556
|
+
print_success(f"DSH 插件已启用: {plugin_name}")
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
@dsh_plugins.command("disable", context_settings=CONTEXT_SETTINGS)
|
|
560
|
+
@click.argument("plugin_name")
|
|
561
|
+
def disable_dsh_plugin(plugin_name: str) -> None:
|
|
562
|
+
"""从 DSH Profile 组合中停用 bundle,但保留已安装包。"""
|
|
563
|
+
|
|
564
|
+
host, item = _call_dsh(lambda bridge: bridge.set_enabled(plugin_name, enabled=False))
|
|
565
|
+
payload = {
|
|
566
|
+
"item": _dsh_inventory_payload(item),
|
|
567
|
+
"host": {"id": host.host_id, "version": host.version, "available": True},
|
|
568
|
+
}
|
|
569
|
+
if is_json_output():
|
|
570
|
+
emit_json(payload)
|
|
571
|
+
else:
|
|
572
|
+
print_success(f"DSH 插件已停用: {plugin_name}")
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
@dsh_plugins.command("update", context_settings=CONTEXT_SETTINGS)
|
|
576
|
+
@click.argument("plugin_name")
|
|
577
|
+
@click.option(
|
|
578
|
+
"--accept-host-permissions",
|
|
579
|
+
is_flag=True,
|
|
580
|
+
help="确认升级后的包与安装脚本会以当前宿主用户权限运行。",
|
|
581
|
+
)
|
|
582
|
+
def update_dsh_plugin(plugin_name: str, accept_host_permissions: bool) -> None:
|
|
583
|
+
"""由 DSH/pnpm 更新一个插件;失败时恢复旧 Profile。"""
|
|
584
|
+
|
|
585
|
+
if not accept_host_permissions:
|
|
586
|
+
abort_with_cli_error(
|
|
587
|
+
CLIError(
|
|
588
|
+
code="dsh_plugin_permission_confirmation_required",
|
|
589
|
+
message="升级前必须传入 --accept-host-permissions 确认宿主权限风险",
|
|
590
|
+
exit_code=EXIT_CODE_VALIDATION,
|
|
591
|
+
),
|
|
592
|
+
context="Plugin",
|
|
593
|
+
)
|
|
594
|
+
host, item = _call_dsh(
|
|
595
|
+
lambda bridge: bridge.update_plugin(plugin_name, accept_host_permissions=True)
|
|
596
|
+
)
|
|
597
|
+
payload = {
|
|
598
|
+
"item": _dsh_inventory_payload(item),
|
|
599
|
+
"host": {"id": host.host_id, "version": host.version, "available": True},
|
|
600
|
+
}
|
|
601
|
+
if is_json_output():
|
|
602
|
+
emit_json(payload)
|
|
603
|
+
else:
|
|
604
|
+
print_success(f"DSH 插件已更新: {plugin_name}")
|
|
605
|
+
|
|
606
|
+
|
|
607
|
+
@dsh_plugins.command("uninstall", context_settings=CONTEXT_SETTINGS)
|
|
608
|
+
@click.argument("plugin_name")
|
|
609
|
+
def uninstall_dsh_plugin(plugin_name: str) -> None:
|
|
610
|
+
"""从 DSH Profile 卸载一个 bundle。"""
|
|
611
|
+
|
|
612
|
+
host, _ = _call_dsh(lambda bridge: bridge.uninstall_plugin(plugin_name))
|
|
613
|
+
payload = {
|
|
614
|
+
"ecosystem": "dsh",
|
|
615
|
+
"integrationMode": "bridged",
|
|
616
|
+
"profile": _dsh_profile(),
|
|
617
|
+
"name": plugin_name,
|
|
618
|
+
"installed": False,
|
|
619
|
+
"enabled": False,
|
|
620
|
+
"host": {"id": host.host_id, "version": host.version, "available": True},
|
|
621
|
+
}
|
|
622
|
+
if is_json_output():
|
|
623
|
+
emit_json(payload)
|
|
624
|
+
else:
|
|
625
|
+
print_success(f"DSH 插件已卸载: {plugin_name}")
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
@dsh_plugins.command("profile", context_settings=CONTEXT_SETTINGS)
|
|
629
|
+
def dsh_profile_info() -> None:
|
|
630
|
+
"""预检并显示当前 DSH Profile 的无 Secret 配置摘要。"""
|
|
631
|
+
|
|
632
|
+
host, projection = _call_dsh(lambda bridge: bridge.project_profile())
|
|
633
|
+
payload = {
|
|
634
|
+
"profile": projection.model_dump(mode="json", by_alias=True),
|
|
635
|
+
"host": {"id": host.host_id, "version": host.version, "available": True},
|
|
636
|
+
}
|
|
637
|
+
if is_json_output():
|
|
638
|
+
emit_json(payload)
|
|
639
|
+
else:
|
|
640
|
+
print_success(f"DSH Profile 已通过预检: {projection.profile}")
|
|
641
|
+
print_kv("配置摘要", projection.config_digest)
|
|
642
|
+
|
|
643
|
+
|
|
644
|
+
# DSH is the canonical plugin ecosystem. Reuse the exact same Click command
|
|
645
|
+
# objects at the top level so output, validation and typed errors cannot drift
|
|
646
|
+
# between ``plugin list`` and the compatibility alias ``plugin dsh list``.
|
|
647
|
+
for _dsh_command_alias in (
|
|
648
|
+
list_dsh_plugins,
|
|
649
|
+
dsh_plugin_info,
|
|
650
|
+
install_dsh_plugin,
|
|
651
|
+
enable_dsh_plugin,
|
|
652
|
+
disable_dsh_plugin,
|
|
653
|
+
update_dsh_plugin,
|
|
654
|
+
uninstall_dsh_plugin,
|
|
655
|
+
dsh_profile_info,
|
|
656
|
+
):
|
|
657
|
+
plugin.add_command(_dsh_command_alias)
|