agentengine-sdk-python 0.8.3__py3-none-any.whl → 0.8.5__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.
Files changed (819) hide show
  1. {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.5.dist-info}/METADATA +13 -9
  2. agentengine_sdk_python-0.8.5.dist-info/RECORD +1296 -0
  3. ksadk/_build_provenance.json +1 -1
  4. ksadk/_process.py +83 -0
  5. ksadk/_str_enum.py +17 -0
  6. ksadk/a2ui/core.py +3 -3
  7. ksadk/api/client.py +111 -91
  8. ksadk/builders/code_builder.py +74 -21
  9. ksadk/builders/framework_requirements.py +22 -3
  10. ksadk/builders/ks3_uploader.py +36 -7
  11. ksadk/builders/managed_runtime_builder.py +1 -0
  12. ksadk/cli/__init__.py +68 -3
  13. ksadk/cli/cmd_config.py +4 -4
  14. ksadk/cli/cmd_create.py +12 -12
  15. ksadk/cli/cmd_hermes.py +24 -2
  16. ksadk/cli/cmd_invoke.py +28 -5
  17. ksadk/cli/cmd_managed_runtime.py +13 -1
  18. ksadk/cli/cmd_openclaw.py +26 -1
  19. ksadk/cli/cmd_plugin.py +76 -13
  20. ksadk/cli/cmd_studio.py +64 -16
  21. ksadk/cli/cmd_web.py +2 -5
  22. ksadk/cli/openclaw_env.py +1 -1
  23. ksadk/cli/resource_common.py +26 -0
  24. ksadk/cli/runtime_bootstrap.py +23 -1
  25. ksadk/codex/client.py +425 -96
  26. ksadk/codex/projection.py +24 -0
  27. ksadk/codex/runtime.py +56 -298
  28. ksadk/common/auth.py +16 -10
  29. ksadk/configs/__init__.py +1 -1
  30. ksadk/configs/env_registry.py +153 -31
  31. ksadk/configs/env_registry_studio.py +86 -0
  32. ksadk/configs/global_config.py +1 -1
  33. ksadk/configs/settings.py +3 -3
  34. ksadk/connector/__init__.py +17 -0
  35. ksadk/connector/channel.py +477 -0
  36. ksadk/context_engine/capabilities.py +52 -4
  37. ksadk/conversations/attachment_storage.py +10 -3
  38. ksadk/conversations/attachments.py +16 -5
  39. ksadk/conversations/message_projection.py +133 -21
  40. ksadk/conversations/normalize.py +28 -10
  41. ksadk/conversations/projector.py +4 -6
  42. ksadk/conversations/runtime_baseline.py +37 -0
  43. ksadk/conversations/runtime_invocation.py +22 -4
  44. ksadk/conversations/runtime_observability.py +39 -10
  45. ksadk/conversations/runtime_payloads.py +9 -0
  46. ksadk/conversations/runtime_persistence.py +105 -9
  47. ksadk/conversations/runtime_preparation.py +42 -33
  48. ksadk/conversations/runtime_resume.py +50 -2
  49. ksadk/conversations/runtime_stream_events.py +34 -35
  50. ksadk/conversations/runtime_streaming.py +33 -7
  51. ksadk/deployment/env_forward.py +2 -2
  52. ksadk/deployment/providers/serverless.py +1 -1
  53. ksadk/events/adapters/_codex_items.py +16 -8
  54. ksadk/events/adapters/_codex_validators.py +18 -7
  55. ksadk/events/adapters/_langgraph_support.py +34 -0
  56. ksadk/events/adapters/langgraph.py +15 -1
  57. ksadk/events/canonical_store.py +3 -1
  58. ksadk/events/projections.py +1 -1
  59. ksadk/events/session_event.py +2 -2
  60. ksadk/harness/__init__.py +14 -0
  61. ksadk/harness/app.py +11 -0
  62. ksadk/harness/artifact_store.py +213 -0
  63. ksadk/harness/capabilities.py +115 -0
  64. ksadk/harness/capability_runtime.py +237 -0
  65. ksadk/harness/closure_contract.py +92 -0
  66. ksadk/harness/compaction_record.py +122 -0
  67. ksadk/harness/compiler.py +284 -0
  68. ksadk/harness/config.py +2 -2
  69. ksadk/harness/conformance/__init__.py +33 -0
  70. ksadk/harness/conformance/contract.py +506 -0
  71. ksadk/harness/conformance/fixtures.py +102 -0
  72. ksadk/harness/context_engine.py +403 -0
  73. ksadk/harness/context_maintenance.py +259 -0
  74. ksadk/harness/context_manifest.py +188 -0
  75. ksadk/harness/context_tuning.py +168 -0
  76. ksadk/harness/draft_runtime.py +322 -0
  77. ksadk/harness/engine/__init__.py +40 -0
  78. ksadk/harness/engine/base.py +122 -0
  79. ksadk/harness/engine/budgets.py +108 -0
  80. ksadk/harness/engine/capability_declarations.py +59 -0
  81. ksadk/harness/engine/completion_guard.py +42 -0
  82. ksadk/harness/engine/context_pipeline.py +579 -0
  83. ksadk/harness/engine/graph_builder.py +859 -0
  84. ksadk/harness/engine/langgraph.py +931 -0
  85. ksadk/harness/engine/mcp_disclosure.py +750 -0
  86. ksadk/harness/engine/policy_runtime.py +70 -0
  87. ksadk/harness/engine/postgres_checkpointer.py +63 -0
  88. ksadk/harness/engine/run_control_bridge.py +80 -0
  89. ksadk/harness/engine/run_types.py +88 -0
  90. ksadk/harness/engine/skill_disclosure.py +189 -0
  91. ksadk/harness/engine/spans.py +41 -0
  92. ksadk/harness/engine/subagents.py +343 -0
  93. ksadk/harness/engine/thread_ids.py +112 -0
  94. ksadk/harness/engine/tool_dispatch.py +144 -0
  95. ksadk/harness/event_tree.py +212 -0
  96. ksadk/harness/events.py +461 -0
  97. ksadk/harness/execution_policy.py +94 -0
  98. ksadk/harness/insights.py +210 -0
  99. ksadk/harness/lifecycle.py +578 -0
  100. ksadk/harness/lifecycle_conformance.py +233 -0
  101. ksadk/harness/lifecycle_local_plane.py +104 -0
  102. ksadk/harness/loop/__init__.py +44 -0
  103. ksadk/harness/loop/reason.py +454 -0
  104. ksadk/harness/loop/tools.py +762 -0
  105. ksadk/harness/managed_runtime.py +884 -0
  106. ksadk/harness/mcp_matrix.py +474 -0
  107. ksadk/harness/mcp_runtime.py +471 -0
  108. ksadk/harness/memory_consolidation.py +157 -0
  109. ksadk/harness/memory_loop.py +156 -0
  110. ksadk/harness/memory_runtime.py +541 -0
  111. ksadk/harness/metrics.py +90 -0
  112. ksadk/harness/model_capability.py +253 -0
  113. ksadk/harness/model_provider.py +220 -0
  114. ksadk/harness/observability/__init__.py +29 -0
  115. ksadk/harness/observability/inspection.py +528 -0
  116. ksadk/harness/observability/metrics.py +167 -0
  117. ksadk/harness/observability/otel_exporter.py +218 -0
  118. ksadk/harness/prompt_cache.py +70 -0
  119. ksadk/harness/public_activity.py +154 -0
  120. ksadk/harness/readiness.py +249 -0
  121. ksadk/harness/reasoner.py +466 -13
  122. ksadk/harness/release_readiness.py +140 -0
  123. ksadk/harness/resource_ref.py +69 -0
  124. ksadk/harness/run_control.py +668 -0
  125. ksadk/harness/runtime.py +171 -136
  126. ksadk/harness/runtime_capabilities.py +158 -0
  127. ksadk/harness/runtime_server.py +514 -0
  128. ksadk/harness/sandbox_adapters.py +739 -0
  129. ksadk/harness/sandbox_backend.py +530 -0
  130. ksadk/harness/sandbox_conformance.py +288 -0
  131. ksadk/harness/sandbox_lease.py +77 -0
  132. ksadk/harness/sandbox_lease_conformance.py +259 -0
  133. ksadk/harness/sandbox_matrix.py +170 -0
  134. ksadk/harness/sandbox_reconciliation.py +140 -0
  135. ksadk/harness/sandbox_recovery.py +586 -0
  136. ksadk/harness/sandbox_recovery_conformance.py +246 -0
  137. ksadk/harness/session_store.py +243 -0
  138. ksadk/harness/skill_composition.py +212 -0
  139. ksadk/harness/skill_feedback.py +123 -0
  140. ksadk/harness/skill_matrix.py +233 -0
  141. ksadk/harness/skill_runtime.py +259 -0
  142. ksadk/harness/spec.py +332 -0
  143. ksadk/harness/state.py +153 -0
  144. ksadk/harness/strategies.py +149 -0
  145. ksadk/harness/subagent.py +253 -0
  146. ksadk/harness/tool_policy.py +131 -0
  147. ksadk/harness/tool_receipts.py +96 -0
  148. ksadk/harness/tool_reliability.py +81 -0
  149. ksadk/harness/tools.py +38 -13
  150. ksadk/harness/user_errors.py +69 -0
  151. ksadk/harness/working_context.py +81 -0
  152. ksadk/harness/working_context_patch.py +99 -0
  153. ksadk/identity/resolver.py +18 -0
  154. ksadk/interaction/__init__.py +1 -1
  155. ksadk/interaction/ledger.py +1 -1
  156. ksadk/interaction/provider.py +2 -1
  157. ksadk/interaction/providers/__init__.py +3 -1
  158. ksadk/interaction/providers/adk.py +1 -1
  159. ksadk/interaction/providers/codex.py +1 -1
  160. ksadk/interaction/providers/harness.py +50 -0
  161. ksadk/interaction/providers/langgraph.py +2 -1
  162. ksadk/kernel/__init__.py +10 -0
  163. ksadk/kernel/approval_presentation.py +91 -0
  164. ksadk/kernel/authorization.py +1 -1
  165. ksadk/kernel/bootstrap.py +114 -106
  166. ksadk/kernel/contract_fingerprints.py +1 -1
  167. ksadk/kernel/contracts.py +5 -0
  168. ksadk/kernel/control.py +32 -1
  169. ksadk/kernel/execution_grants.py +221 -0
  170. ksadk/kernel/execution_grants_memory.py +133 -0
  171. ksadk/kernel/execution_grants_postgres.py +217 -0
  172. ksadk/kernel/execution_grants_sqlite.py +209 -0
  173. ksadk/kernel/ingress.py +42 -29
  174. ksadk/kernel/mapping.py +1 -1
  175. ksadk/kernel/memory_store.py +24 -11
  176. ksadk/kernel/postgres_store.py +63 -33
  177. ksadk/kernel/recovery.py +78 -14
  178. ksadk/kernel/sql/001_agent_kernel.sql +23 -0
  179. ksadk/kernel/sqlite_store.py +331 -25
  180. ksadk/kernel/state.py +2 -3
  181. ksadk/kernel/store.py +72 -2
  182. ksadk/kernel/worker.py +144 -51
  183. ksadk/kernel/worker_history.py +72 -0
  184. ksadk/kernel/worker_identity.py +47 -0
  185. ksadk/knowledge_base/client.py +57 -27
  186. ksadk/mcp_runtime/__init__.py +12 -4
  187. ksadk/memory/adk/backends/sdk_ltm_backend.py +161 -41
  188. ksadk/memory/adk/resilient_session_service.py +25 -17
  189. ksadk/memory/adk/short_term_memory.py +26 -9
  190. ksadk/memory/coordinator.py +22 -6
  191. ksadk/memory/extraction.py +40 -1
  192. ksadk/memory/models.py +84 -5
  193. ksadk/memory/provider_resolver.py +8 -0
  194. ksadk/memory/providers/local_postgres.py +200 -0
  195. ksadk/memory/providers/local_sqlite.py +42 -3
  196. ksadk/memory/retrieval.py +189 -0
  197. ksadk/memory/store_adapter.py +150 -0
  198. ksadk/model_policy.py +2 -2
  199. ksadk/model_proxy/detect.py +254 -0
  200. ksadk/model_proxy/server.py +14 -7
  201. ksadk/model_proxy/transform.py +40 -2
  202. ksadk/plugins/__init__.py +5 -1
  203. ksadk/plugins/artifacts.py +275 -0
  204. ksadk/plugins/bridges/__init__.py +4 -2
  205. ksadk/plugins/bridges/codex.py +120 -13
  206. ksadk/plugins/bridges/dsh.py +351 -156
  207. ksadk/plugins/builtins.py +72 -35
  208. ksadk/plugins/bundle_security.py +28 -4
  209. ksadk/plugins/codex_manifest.py +983 -0
  210. ksadk/plugins/companion_artifacts.py +83 -0
  211. ksadk/plugins/companions.py +368 -0
  212. ksadk/plugins/composition.py +8 -0
  213. ksadk/plugins/contracts.py +119 -1
  214. ksadk/plugins/delivery.py +153 -0
  215. ksadk/plugins/dsh_channels.py +156 -0
  216. ksadk/plugins/dsh_home.py +140 -0
  217. ksadk/plugins/dsh_installation_digest.py +71 -0
  218. ksadk/plugins/dsh_teams.py +105 -0
  219. ksadk/plugins/dsh_toolchain.py +203 -32
  220. ksadk/plugins/ecosystem_probe.py +6 -6
  221. ksadk/plugins/execution_host.py +99 -0
  222. ksadk/plugins/host.py +102 -39
  223. ksadk/plugins/kernel_adapter.py +205 -0
  224. ksadk/plugins/providers/__init__.py +23 -0
  225. ksadk/plugins/providers/bundles/dsh-channels-client/client.js +19 -0
  226. ksadk/plugins/providers/bundles/dsh-channels-client/cordis.patch.yml +3 -0
  227. ksadk/plugins/providers/bundles/dsh-channels-client/index.mjs +7 -0
  228. ksadk/plugins/providers/bundles/dsh-channels-client/package.json +12 -0
  229. ksadk/plugins/providers/bundles/dsh-knowledge/cordis.patch.yml +3 -0
  230. ksadk/plugins/providers/bundles/dsh-knowledge/index.mjs +53 -0
  231. ksadk/plugins/providers/bundles/dsh-knowledge/package.json +16 -0
  232. ksadk/plugins/providers/bundles/dsh-memory/cordis.patch.yml +3 -0
  233. ksadk/plugins/providers/bundles/dsh-memory/index.mjs +175 -0
  234. ksadk/plugins/providers/bundles/dsh-memory/package.json +16 -0
  235. ksadk/plugins/providers/bundles/dsh-platform-resources/client.mjs +166 -0
  236. ksadk/plugins/providers/bundles/dsh-platform-resources/cordis.patch.yml +3 -0
  237. ksadk/plugins/providers/bundles/dsh-platform-resources/index.mjs +9 -0
  238. ksadk/plugins/providers/bundles/dsh-platform-resources/package.json +12 -0
  239. ksadk/plugins/providers/bundles/dsh-skill-center/cordis.patch.yml +3 -0
  240. ksadk/plugins/providers/bundles/dsh-skill-center/index.mjs +125 -0
  241. ksadk/plugins/providers/bundles/dsh-skill-center/package.json +16 -0
  242. ksadk/plugins/providers/bundles/dsh-teams-client/client.js +29 -0
  243. ksadk/plugins/providers/bundles/dsh-teams-client/cordis.patch.yml +3 -0
  244. ksadk/plugins/providers/bundles/dsh-teams-client/index.mjs +11 -0
  245. ksadk/plugins/providers/bundles/dsh-teams-client/package.json +35 -0
  246. ksadk/plugins/providers/bundles/dsh-teams-leader-policy/cordis.patch.yml +3 -0
  247. ksadk/plugins/providers/bundles/dsh-teams-leader-policy/index.mjs +13 -0
  248. ksadk/plugins/providers/bundles/dsh-teams-leader-policy/package.json +27 -0
  249. ksadk/plugins/providers/bundles/dsh-teams-profile/cordis.patch.yml +3 -0
  250. ksadk/plugins/providers/bundles/dsh-teams-profile/index.mjs +12 -0
  251. ksadk/plugins/providers/bundles/dsh-teams-profile/package.json +26 -0
  252. ksadk/plugins/providers/bundles/dsh-teams-router/cordis.patch.yml +3 -0
  253. ksadk/plugins/providers/bundles/dsh-teams-router/index.mjs +16 -0
  254. ksadk/plugins/providers/bundles/dsh-teams-router/package.json +27 -0
  255. ksadk/plugins/providers/bundles/dsh-teams-tasks/cordis.patch.yml +3 -0
  256. ksadk/plugins/providers/bundles/dsh-teams-tasks/index.mjs +16 -0
  257. ksadk/plugins/providers/bundles/dsh-teams-tasks/package.json +27 -0
  258. ksadk/plugins/providers/bundles/dsh-teams-tools/cordis.patch.yml +3 -0
  259. ksadk/plugins/providers/bundles/dsh-teams-tools/index.mjs +25 -0
  260. ksadk/plugins/providers/bundles/dsh-teams-tools/package.json +29 -0
  261. ksadk/plugins/providers/bundles/dsh-teams-tools/tools.json +235 -0
  262. ksadk/plugins/providers/bundles/ksadk-codex/index.mjs +1 -1
  263. ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/cordis.patch.yml +3 -0
  264. ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/index.mjs +920 -0
  265. ksadk/plugins/providers/bundles/ksadk-dsh-capability-host/package.json +27 -0
  266. ksadk/plugins/providers/bundles/ksadk-dsh-companion-host/client.mjs +133 -0
  267. ksadk/plugins/providers/bundles/ksadk-dsh-companion-host/index.mjs +14 -0
  268. ksadk/plugins/providers/bundles/ksadk-dsh-studio/client.js +115 -0
  269. ksadk/plugins/providers/bundles/ksadk-dsh-studio/index.mjs +19 -0
  270. ksadk/plugins/providers/bundles/ksadk-dsh-studio/package.json +7 -0
  271. ksadk/plugins/providers/bundles/ksadk-harness/index.mjs +1 -1
  272. ksadk/plugins/providers/codex.py +344 -70
  273. ksadk/plugins/providers/codex_native.py +368 -0
  274. ksadk/plugins/providers/codex_turn.py +301 -0
  275. ksadk/plugins/providers/dsh_capabilities.py +1450 -0
  276. ksadk/plugins/providers/dsh_mcp.py +467 -0
  277. ksadk/plugins/providers/harness.py +294 -141
  278. ksadk/plugins/providers/harness_delegation.py +593 -0
  279. ksadk/plugins/providers/harness_managed.py +456 -0
  280. ksadk/plugins/providers/harness_tools.py +326 -0
  281. ksadk/plugins/providers/mcp_projection.py +150 -0
  282. ksadk/plugins/providers/platform_resources.py +657 -0
  283. ksadk/plugins/providers/shipped_dsh.py +4 -1
  284. ksadk/plugins/resolver.py +8 -1
  285. ksadk/plugins/subagent_providers/codex.py +28 -6
  286. ksadk/plugins/teams/__init__.py +5 -0
  287. ksadk/plugins/teams/api.py +405 -0
  288. ksadk/plugins/teams/application.py +680 -0
  289. ksadk/plugins/teams/artifacts.py +60 -0
  290. ksadk/plugins/teams/context.py +96 -0
  291. ksadk/plugins/teams/contracts.py +136 -0
  292. ksadk/plugins/teams/domain.py +1427 -0
  293. ksadk/plugins/teams/domain_values.py +24 -0
  294. ksadk/plugins/teams/errors.py +13 -0
  295. ksadk/plugins/teams/migration.py +311 -0
  296. ksadk/plugins/teams/migration_cli.py +322 -0
  297. ksadk/plugins/teams/postgres_store.py +138 -0
  298. ksadk/plugins/teams/runtime.py +777 -0
  299. ksadk/plugins/teams/source_projection.py +84 -0
  300. ksadk/plugins/teams/store.py +311 -0
  301. ksadk/plugins/teams/task_decisions.py +423 -0
  302. ksadk/plugins/teams/transport.py +91 -0
  303. ksadk/plugins/teams/workspaces.py +255 -0
  304. ksadk/resource_runtime/__init__.py +4 -0
  305. ksadk/resource_runtime/broker.py +616 -0
  306. ksadk/resource_runtime/build_artifacts.py +165 -0
  307. ksadk/resource_runtime/contracts.py +138 -0
  308. ksadk/resource_runtime/discovery_receipts.py +100 -0
  309. ksadk/resource_runtime/discovery_skills.py +172 -0
  310. ksadk/resource_runtime/errors.py +6 -0
  311. ksadk/resource_runtime/ipc.py +142 -0
  312. ksadk/resource_runtime/kernel_approval.py +165 -0
  313. ksadk/resource_runtime/knowledge.py +114 -0
  314. ksadk/resource_runtime/langgraph.py +94 -0
  315. ksadk/resource_runtime/leases.py +191 -0
  316. ksadk/resource_runtime/managed_projection.py +186 -0
  317. ksadk/resource_runtime/mcp_server.py +138 -0
  318. ksadk/resource_runtime/memory_provider.py +318 -0
  319. ksadk/resource_runtime/memory_receipts.py +34 -0
  320. ksadk/resource_runtime/operation_ledger.py +211 -0
  321. ksadk/resource_runtime/plugin_config.py +48 -0
  322. ksadk/resource_runtime/policy_authorization.py +54 -0
  323. ksadk/resource_runtime/process.py +110 -0
  324. ksadk/resource_runtime/skill_artifacts.py +153 -0
  325. ksadk/resource_runtime/skill_runtime.py +42 -0
  326. ksadk/resource_runtime/skill_workspace.py +118 -0
  327. ksadk/resource_runtime/skills.py +215 -0
  328. ksadk/resource_runtime/snapshots.py +180 -0
  329. ksadk/resource_runtime/socket_server.py +103 -0
  330. ksadk/resource_runtime/supervisor.py +380 -0
  331. ksadk/resource_runtime/worker.py +504 -0
  332. ksadk/runners/_langgraph_runner_streams.py +182 -38
  333. ksadk/runners/_langgraph_state_reader.py +106 -0
  334. ksadk/runners/_session_identity.py +285 -0
  335. ksadk/runners/adk_runner.py +166 -63
  336. ksadk/runners/base_runner.py +29 -1
  337. ksadk/runners/langgraph_runner.py +542 -195
  338. ksadk/runners/patch_langchain.py +47 -0
  339. ksadk/runners/usage_accumulator.py +11 -3
  340. ksadk/runtime/_runner_adapter/stream_mapping.py +194 -20
  341. ksadk/runtime/adapter.py +2 -0
  342. ksadk/runtime/conversation_execution.py +117 -17
  343. ksadk/runtime/executor.py +87 -3
  344. ksadk/runtime/factory.py +65 -274
  345. ksadk/runtime/framework_adapters.py +23 -0
  346. ksadk/runtime/preprocessing.py +21 -5
  347. ksadk/runtime/runner_adapter.py +106 -18
  348. ksadk/runtime/skill_eval_result.py +36 -0
  349. ksadk/runtime/timing.py +46 -0
  350. ksadk/runtime/usage.py +49 -18
  351. ksadk/runtime_context.py +142 -2
  352. ksadk/sandbox/backends/e2b.py +288 -25
  353. ksadk/sandbox/backends/local_process.py +72 -39
  354. ksadk/sandbox/base.py +64 -1
  355. ksadk/sandbox/diagnostics.py +82 -0
  356. ksadk/sandbox/e2b_connection.py +66 -0
  357. ksadk/sandbox/local_controls.py +746 -0
  358. ksadk/sandbox/local_launcher.py +90 -0
  359. ksadk/scheduler/dispatcher.py +1 -1
  360. ksadk/scheduler/sqlite_store.py +18 -0
  361. ksadk/server/composition.py +2 -0
  362. ksadk/server/factory.py +5 -0
  363. ksadk/server/invocation_identity.py +118 -0
  364. ksadk/server/persistence_capability.py +516 -0
  365. ksadk/server/routes/common.py +32 -3
  366. ksadk/server/routes/control.py +271 -52
  367. ksadk/server/routes/dependencies.py +16 -0
  368. ksadk/server/routes/kernel_ingress.py +9 -1
  369. ksadk/server/routes/misc.py +233 -25
  370. ksadk/server/routes/models.py +47 -4
  371. ksadk/server/routes/openai_compat.py +76 -13
  372. ksadk/server/routes/projection.py +252 -12
  373. ksadk/server/routes/run.py +106 -35
  374. ksadk/server/routes/sessions.py +491 -138
  375. ksadk/server/routes/streaming.py +43 -9
  376. ksadk/server/routes/workspace.py +130 -21
  377. ksadk/server/static/assets/{ArtifactsPanel-10GPXIJ6.js → ArtifactsPanel-C1YoaKhx.js} +1 -1
  378. ksadk/server/static/assets/{CodeBlock-BXk1l-G1.js → CodeBlock-DHuAWfr5.js} +10 -7
  379. ksadk/server/static/assets/MathMessageMarkdown-cvdrBwYr.js +8 -0
  380. ksadk/server/static/assets/{MermaidBlock--OEYoXIJ.js → MermaidBlock-DeBkbJvI.js} +9 -9
  381. ksadk/server/static/assets/{NativeTerminalPanel-DrEe1syq.js → NativeTerminalPanel-oJj44_sV.js} +1 -1
  382. ksadk/server/static/assets/{abnfDiagram-VCTEODGH-eeTFJLvo.js → abnfDiagram-VCTEODGH-Dhfv25o2.js} +1 -1
  383. ksadk/server/static/assets/{arc-S3ZNbIAd.js → arc-C35w-pn1.js} +1 -1
  384. ksadk/server/static/assets/architecture-7GRP2DOG-BCsa26zi.js +1 -0
  385. ksadk/server/static/assets/{architectureDiagram-5GKGNRK7-CRjgEJDX.js → architectureDiagram-5GKGNRK7-FoMY_u6D.js} +1 -1
  386. ksadk/server/static/assets/{blockDiagram-NRAW4CY4-C7bsBoNH.js → blockDiagram-NRAW4CY4-zD4Rt7oE.js} +1 -1
  387. ksadk/server/static/assets/{c4Diagram-UCG6FXSJ-BX3c33Ob.js → c4Diagram-UCG6FXSJ-BCtGGkhN.js} +1 -1
  388. ksadk/server/static/assets/channel-_KDifNys.js +1 -0
  389. ksadk/server/static/assets/chunk-2Q5K7J3B-HdVkJ9F0.js +1 -0
  390. ksadk/server/static/assets/{chunk-5VM5RSS4-bZ7ws-8m.js → chunk-5VM5RSS4-C2Ms13_k.js} +1 -1
  391. ksadk/server/static/assets/{chunk-F27PBJKO-D2r0pvhY.js → chunk-F27PBJKO-BoTj-qgx.js} +1 -1
  392. ksadk/server/static/assets/{chunk-G27WJ6UU-CZwF3oUP.js → chunk-G27WJ6UU-DOMyyjHH.js} +1 -1
  393. ksadk/server/static/assets/{chunk-JWPE2WC7-DigFYCML.js → chunk-JWPE2WC7-DbJJqDli.js} +1 -1
  394. ksadk/server/static/assets/{chunk-LCL6LL3I-CnorGV5q.js → chunk-LCL6LL3I-CLuRCt_W.js} +1 -1
  395. ksadk/server/static/assets/{chunk-POPQ4Y6H-CexntQA-.js → chunk-POPQ4Y6H-D0Dz847e.js} +1 -1
  396. ksadk/server/static/assets/{chunk-RHFEMEQ7-CHTC7UxA.js → chunk-RHFEMEQ7-BWSRzEcd.js} +1 -1
  397. ksadk/server/static/assets/{chunk-SVP7TREG-BC1EWt_-.js → chunk-SVP7TREG-CPoHqkCY.js} +1 -1
  398. ksadk/server/static/assets/{chunk-XXDRQBXY-BTG24xN0.js → chunk-XXDRQBXY-Bx1jS-X-.js} +1 -1
  399. ksadk/server/static/assets/classDiagram-DTDB5LWJ-BVCW3ZqZ.js +1 -0
  400. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-BVCW3ZqZ.js +1 -0
  401. ksadk/server/static/assets/{cose-bilkent-JH36ORCC-CkonRdAS.js → cose-bilkent-JH36ORCC-LzyWm4m0.js} +1 -1
  402. ksadk/server/static/assets/cynefin-OW5HDTMX-CNXjFctL.js +1 -0
  403. ksadk/server/static/assets/{cynefinDiagram-5FMLGOSQ-DEOCBe15.js → cynefinDiagram-5FMLGOSQ-BlW_bHED.js} +1 -1
  404. ksadk/server/static/assets/{dagre-3AP2YEHR-DBThPuLa.js → dagre-3AP2YEHR-Bu_S86_i.js} +1 -1
  405. ksadk/server/static/assets/{dagre-ClTPrTht.js → dagre-B7nCawed.js} +1 -1
  406. ksadk/server/static/assets/{diagram-S7CK7UJ4-DsZHrnpJ.js → diagram-S7CK7UJ4-W_Zow2Km.js} +1 -1
  407. ksadk/server/static/assets/{diagram-UQ7AKVKN-BJR4nhVr.js → diagram-UQ7AKVKN-CLIKAHON.js} +1 -1
  408. ksadk/server/static/assets/{diagram-VSXAHHWV-xzcERX0a.js → diagram-VSXAHHWV-Dv6_QAlN.js} +1 -1
  409. ksadk/server/static/assets/{diagram-VX7I27RA-tn2xM1xu.js → diagram-VX7I27RA-BWAWRDtZ.js} +1 -1
  410. ksadk/server/static/assets/{diagram-Z3DM3KII-BZPGBkw5.js → diagram-Z3DM3KII-XA_rWMss.js} +1 -1
  411. ksadk/server/static/assets/dist-0X_j2Rcc.js +1 -0
  412. ksadk/server/static/assets/{dist-4zN1_tq5.js → dist-1nXCdsej.js} +1 -1
  413. ksadk/server/static/assets/{dist-M67Hwu0n.js → dist-2vL2sAdF.js} +1 -1
  414. ksadk/server/static/assets/{dist-BJLUwH6W.js → dist-B3bA05-e.js} +1 -1
  415. ksadk/server/static/assets/{dist-8VWI-2bZ.js → dist-BLpRy_Yx.js} +1 -1
  416. ksadk/server/static/assets/{dist-D1V3f1B4.js → dist-BO_UwatH.js} +1 -1
  417. ksadk/server/static/assets/{dist-Cq4OL6nO.js → dist-BdNFAney.js} +1 -1
  418. ksadk/server/static/assets/{dist-DfGFrb0v.js → dist-C0J5_3qM.js} +1 -1
  419. ksadk/server/static/assets/{dist-DyqV4fL4.js → dist-CGt_UGeO.js} +1 -1
  420. ksadk/server/static/assets/{dist-DjhwGUgZ.js → dist-CIRMvUM4.js} +1 -1
  421. ksadk/server/static/assets/{dist-B1oWRmrH.js → dist-CIpWk_5f.js} +1 -1
  422. ksadk/server/static/assets/{dist-CXpH_Rdd.js → dist-CPyieXEf.js} +1 -1
  423. ksadk/server/static/assets/{dist-Btyo4vX4.js → dist-D-92S-Fd.js} +1 -1
  424. ksadk/server/static/assets/{dist-u8tVH5Ak.js → dist-DNKuMzWc.js} +1 -1
  425. ksadk/server/static/assets/{dist-DQAB0qn_.js → dist-DWfdmz9s.js} +2 -2
  426. ksadk/server/static/assets/{dist-B-46q3Hk.js → dist-DppE_r-D.js} +1 -1
  427. ksadk/server/static/assets/{dist-C71CsujO.js → dist-DyG6Ya-z.js} +1 -1
  428. ksadk/server/static/assets/{dist-DJmCPRVB.js → dist-M-SrdhhZ.js} +1 -1
  429. ksadk/server/static/assets/{dist-Bbwqa8TG.js → dist-mqD5TZup.js} +1 -1
  430. ksadk/server/static/assets/{dist-BI1qQH4n.js → dist-n3n6t_FO.js} +1 -1
  431. ksadk/server/static/assets/{dist-DUwKa_l6.js → dist-qe8xjesy.js} +1 -1
  432. ksadk/server/static/assets/{dist-B0gdk4rl.js → dist-t6MzE0jU.js} +1 -1
  433. ksadk/server/static/assets/{ebnfDiagram-PWID7BFC-DVfMsLge.js → ebnfDiagram-PWID7BFC-BfCzF1Xi.js} +1 -1
  434. ksadk/server/static/assets/{erDiagram-SSCWMZ5O-CWEZSYaw.js → erDiagram-SSCWMZ5O-Dpz9_0zn.js} +1 -1
  435. ksadk/server/static/assets/eventmodeling-NTZA5JFV-B5-8RH9c.js +1 -0
  436. ksadk/server/static/assets/flowDiagram-A5DVABFB-BppFxEKw.js +1 -0
  437. ksadk/server/static/assets/{ganttDiagram-EL5Y4UJY-TWIxoyYL.js → ganttDiagram-EL5Y4UJY-DDaG1f4_.js} +1 -1
  438. ksadk/server/static/assets/gitGraph-4MIJSDKK-B-AhYj4C.js +1 -0
  439. ksadk/server/static/assets/{gitGraphDiagram-WWUBYQGX-DDh2hd2S.js → gitGraphDiagram-WWUBYQGX-DcxzRwYC.js} +1 -1
  440. ksadk/server/static/assets/index-BMd2mucF.css +2 -0
  441. ksadk/server/static/assets/index-D5qyyhTH.js +244 -0
  442. ksadk/server/static/assets/info-A6RAGUB7-0uiKrC35.js +1 -0
  443. ksadk/server/static/assets/{infoDiagram-RXCK75RN-CgoyWiDR.js → infoDiagram-RXCK75RN-CYMdn6lQ.js} +1 -1
  444. ksadk/server/static/assets/{ishikawaDiagram-5VMMS53U-CyRIu_om.js → ishikawaDiagram-5VMMS53U-CLHFAD6c.js} +1 -1
  445. ksadk/server/static/assets/{journeyDiagram-EYS64GPL-DN5JXHzN.js → journeyDiagram-EYS64GPL-BHSKQGAl.js} +1 -1
  446. ksadk/server/static/assets/{kanban-definition-3QL26DDD-CNP3ui66.js → kanban-definition-3QL26DDD-D5W3tjTT.js} +1 -1
  447. ksadk/server/static/assets/{katex-DWEzQy1d.js → katex-mtjOi4KM.js} +1 -1
  448. ksadk/server/static/assets/{linear-C-qHp7d2.js → linear-BETqsxE_.js} +1 -1
  449. ksadk/server/static/assets/{mermaid-parser.core-Cl-K943T.js → mermaid-parser.core-DPWrvs90.js} +2 -2
  450. ksadk/server/static/assets/{mindmap-definition-FBJOCRG2-D5DB5mYm.js → mindmap-definition-FBJOCRG2-CJG2mfBP.js} +1 -1
  451. ksadk/server/static/assets/packet-AYTQ26CC-BVTmZ_cw.js +1 -0
  452. ksadk/server/static/assets/{pegDiagram-XKGWAZYB-BQVc9ia_.js → pegDiagram-XKGWAZYB-GjAPNaqn.js} +1 -1
  453. ksadk/server/static/assets/pie-WAS4IAKB-DyfxBU7V.js +1 -0
  454. ksadk/server/static/assets/{pieDiagram-E7YTZNPT-B6UCAvtY.js → pieDiagram-E7YTZNPT-ToIewrqr.js} +1 -1
  455. ksadk/server/static/assets/{quadrantDiagram-AXDQQJYC-mIr2d3eb.js → quadrantDiagram-AXDQQJYC-4d78KiEY.js} +1 -1
  456. ksadk/server/static/assets/radar-RG4KPBEZ-FFontjL2.js +1 -0
  457. ksadk/server/static/assets/railroad-74A4TZTK-D0Uidzen.js +1 -0
  458. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-BOo_9T2h.js +1 -0
  459. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-D6-BjW7Z.js +1 -0
  460. ksadk/server/static/assets/railroad-peg-WCYAUIDC-CXx__yMm.js +1 -0
  461. ksadk/server/static/assets/{railroadDiagram-O6MQD6OU-Dt3FFDmK.js → railroadDiagram-O6MQD6OU-DKzx4xfv.js} +1 -1
  462. ksadk/server/static/assets/{requirementDiagram-EFPCY7ZU-Cz_vQtgF.js → requirementDiagram-EFPCY7ZU-CJYljxQS.js} +1 -1
  463. ksadk/server/static/assets/{sankeyDiagram-P5KCCOFB-wlO1TsH5.js → sankeyDiagram-P5KCCOFB-DLU2fV1w.js} +1 -1
  464. ksadk/server/static/assets/{sequenceDiagram-WJ2MYXX4-CHRbElYq.js → sequenceDiagram-WJ2MYXX4-CVqysrA9.js} +1 -1
  465. ksadk/server/static/assets/{sizeCapture-X5ZJPWSS-DXX54iyO.js → sizeCapture-X5ZJPWSS-BUxfmTHc.js} +1 -1
  466. ksadk/server/static/assets/{stateDiagram-HBIQ2CUA-Dp_lw9II.js → stateDiagram-HBIQ2CUA-CNFgYI9E.js} +1 -1
  467. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-BXAFScz8.js +1 -0
  468. ksadk/server/static/assets/{swimlanes-XN3QIQJK-D8O5UlLG.js → swimlanes-XN3QIQJK-B6qCMe8N.js} +1 -1
  469. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-uIQ2lJKH.js +8 -0
  470. ksadk/server/static/assets/{timeline-definition-24CTP7MA-8mfKcxvG.js → timeline-definition-24CTP7MA-CMD3x_U_.js} +1 -1
  471. ksadk/server/static/assets/treeView-Q6P3EWNA-CK5GgucZ.js +1 -0
  472. ksadk/server/static/assets/treemap-WGGIJYW6-Bq1u1SpG.js +1 -0
  473. ksadk/server/static/assets/{vennDiagram-4TSXK5OY-EnNl0DE7.js → vennDiagram-4TSXK5OY-BqtUqvXM.js} +1 -1
  474. ksadk/server/static/assets/wardley-WFR3VGLG-QAt06uEz.js +1 -0
  475. ksadk/server/static/assets/{wardleyDiagram-VM6X3IG4-DBu5fbYr.js → wardleyDiagram-VM6X3IG4-B5KfDjI-.js} +1 -1
  476. ksadk/server/static/assets/{xychartDiagram-S5SC5T6Z-BSVXs4IY.js → xychartDiagram-S5SC5T6Z-BaUlSZrn.js} +1 -1
  477. ksadk/server/static/index.html +2 -2
  478. ksadk/server/terminal_sessions.py +34 -2
  479. ksadk/session_context.py +66 -0
  480. ksadk/sessions/__init__.py +11 -21
  481. ksadk/sessions/_local_service_sync.py +263 -1
  482. ksadk/sessions/base.py +176 -0
  483. ksadk/sessions/errors.py +4 -0
  484. ksadk/sessions/in_memory.py +309 -19
  485. ksadk/sessions/invocation_identity.py +235 -0
  486. ksadk/sessions/local_service.py +83 -1
  487. ksadk/sessions/persistence.py +275 -0
  488. ksadk/sessions/postgres_service.py +358 -0
  489. ksadk/sessions/resilience.py +8 -0
  490. ksadk/sessions/resilient.py +362 -4
  491. ksadk/sessions/topology.py +135 -0
  492. ksadk/skills/__init__.py +26 -0
  493. ksadk/skills/events.py +464 -0
  494. ksadk/skills/manifest_cache.py +263 -0
  495. ksadk/skills/mcp_server/__init__.py +0 -0
  496. ksadk/skills/mcp_server/_registry.py +33 -0
  497. ksadk/skills/mcp_server/_routing.py +26 -0
  498. ksadk/skills/mcp_server/_workspace_files.py +160 -0
  499. ksadk/skills/mcp_server/register.py +415 -0
  500. ksadk/skills/mcp_server/server.py +218 -0
  501. ksadk/skills/models.py +37 -4
  502. ksadk/skills/observability.py +132 -0
  503. ksadk/skills/package_store.py +261 -40
  504. ksadk/skills/runtime/agent.py +67 -9
  505. ksadk/skills/runtime/artifact_delivery.py +139 -0
  506. ksadk/skills/runtime/artifacts.py +87 -0
  507. ksadk/skills/runtime/backends/e2b.py +460 -27
  508. ksadk/skills/runtime/backends/local.py +629 -62
  509. ksadk/skills/runtime/base.py +81 -7
  510. ksadk/skills/runtime/executor.py +268 -1
  511. ksadk/skills/runtime/loader.py +118 -5
  512. ksadk/skills/runtime/pinned.py +114 -0
  513. ksadk/skills/runtime/request.py +49 -0
  514. ksadk/skills/service_client.py +167 -28
  515. ksadk/skills/tool_defs.py +108 -3
  516. ksadk/studio/api.py +810 -93
  517. ksadk/studio/api_catalog_routes.py +18 -0
  518. ksadk/studio/api_contracts.py +8 -2
  519. ksadk/studio/api_plugin_routes.py +562 -104
  520. ksadk/studio/api_resource_connections.py +221 -0
  521. ksadk/studio/authoring.py +12 -6
  522. ksadk/studio/authoring_coordinator.py +23 -16
  523. ksadk/studio/builder.py +88 -0
  524. ksadk/studio/capabilities.py +23 -6
  525. ksadk/studio/channel_connections.py +333 -0
  526. ksadk/studio/cloud.py +370 -112
  527. ksadk/studio/cloud_shared_web.py +638 -0
  528. ksadk/studio/codex_agent_service.py +130 -28
  529. ksadk/studio/codex_builder.py +242 -3
  530. ksadk/studio/codex_credentials.py +90 -0
  531. ksadk/studio/codex_manifest.py +31 -4
  532. ksadk/studio/codex_plugin_store.py +746 -0
  533. ksadk/studio/codex_provider_build.py +231 -0
  534. ksadk/studio/codex_run.py +190 -26
  535. ksadk/studio/compatibility_report.py +12 -1
  536. ksadk/studio/compiler.py +88 -14
  537. ksadk/studio/configuration.py +182 -0
  538. ksadk/studio/contracts.py +165 -11
  539. ksadk/studio/dsh_application.py +247 -0
  540. ksadk/studio/dsh_capability_service.py +1374 -0
  541. ksadk/studio/dsh_lifecycle.py +58 -0
  542. ksadk/studio/dsh_models.py +59 -0
  543. ksadk/studio/dsh_provider_registration.py +367 -21
  544. ksadk/studio/entry.py +53 -0
  545. ksadk/studio/event_store.py +36 -5
  546. ksadk/studio/execution_host.py +525 -0
  547. ksadk/studio/framework_run.py +32 -10
  548. ksadk/studio/hosted_kernel.py +89 -14
  549. ksadk/studio/kernel_registry.py +418 -0
  550. ksadk/studio/kernel_sqlite_migration.py +181 -0
  551. ksadk/studio/mcp_runtime.py +11 -3
  552. ksadk/studio/model_client.py +1180 -66
  553. ksadk/studio/model_profile_service.py +26 -11
  554. ksadk/studio/native_documents.py +172 -0
  555. ksadk/studio/plugin_composition.py +202 -24
  556. ksadk/studio/plugin_kernel_adapter.py +21 -106
  557. ksadk/studio/plugin_lifecycle.py +80 -0
  558. ksadk/studio/plugin_runtime.py +448 -56
  559. ksadk/studio/provider_recovery.py +59 -0
  560. ksadk/studio/recovery_page.py +70 -0
  561. ksadk/studio/resource_authority.py +664 -0
  562. ksadk/studio/resource_binding_validation.py +77 -0
  563. ksadk/studio/resource_build_admission.py +196 -0
  564. ksadk/studio/resource_build_materializer.py +149 -0
  565. ksadk/studio/resource_catalog.py +149 -2
  566. ksadk/studio/resource_connections.py +220 -0
  567. ksadk/studio/run_activity.py +895 -0
  568. ksadk/studio/run_documents.py +127 -0
  569. ksadk/studio/run_service.py +789 -83
  570. ksadk/studio/runtime_catalog.py +53 -10
  571. ksadk/studio/runtime_source.py +16 -8
  572. ksadk/studio/scheduler_assistant.py +317 -0
  573. ksadk/studio/scheduler_runtime.py +32 -280
  574. ksadk/studio/scheduler_service.py +3 -0
  575. ksadk/studio/service.py +861 -120
  576. ksadk/studio/shared_web.py +579 -82
  577. ksadk/studio/static/assets/ChannelsPage-D_PGmKVq.js +8 -0
  578. ksadk/studio/static/assets/CodeBlock-DMIf4h33-UIqo-BPW.js +44 -0
  579. ksadk/studio/static/assets/ExecutionTree-v3HexvPo-Bk8wzGSy.js +1 -0
  580. ksadk/studio/static/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  581. ksadk/studio/static/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  582. ksadk/studio/static/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  583. ksadk/studio/static/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  584. ksadk/studio/static/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  585. ksadk/studio/static/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  586. ksadk/studio/static/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  587. ksadk/studio/static/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  588. ksadk/studio/static/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  589. ksadk/studio/static/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  590. ksadk/studio/static/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  591. ksadk/studio/static/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  592. ksadk/studio/static/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  593. ksadk/studio/static/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  594. ksadk/studio/static/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  595. ksadk/studio/static/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  596. ksadk/studio/static/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  597. ksadk/studio/static/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  598. ksadk/studio/static/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  599. ksadk/studio/static/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  600. ksadk/studio/static/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  601. ksadk/studio/static/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  602. ksadk/studio/static/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  603. ksadk/studio/static/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  604. ksadk/studio/static/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  605. ksadk/studio/static/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  606. ksadk/studio/static/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  607. ksadk/studio/static/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  608. ksadk/studio/static/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  609. ksadk/studio/static/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  610. ksadk/studio/static/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  611. ksadk/studio/static/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  612. ksadk/studio/static/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  613. ksadk/studio/static/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  614. ksadk/studio/static/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  615. ksadk/studio/static/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  616. ksadk/studio/static/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  617. ksadk/studio/static/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  618. ksadk/studio/static/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  619. ksadk/studio/static/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  620. ksadk/studio/static/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  621. ksadk/studio/static/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  622. ksadk/studio/static/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  623. ksadk/studio/static/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  624. ksadk/studio/static/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  625. ksadk/studio/static/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  626. ksadk/studio/static/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  627. ksadk/studio/static/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  628. ksadk/studio/static/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  629. ksadk/studio/static/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  630. ksadk/studio/static/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  631. ksadk/studio/static/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  632. ksadk/studio/static/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  633. ksadk/studio/static/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  634. ksadk/studio/static/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  635. ksadk/studio/static/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  636. ksadk/studio/static/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  637. ksadk/studio/static/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  638. ksadk/studio/static/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  639. ksadk/studio/static/assets/MathMessageMarkdown-BesSeCYl-BEOyPC3w.css +1 -0
  640. ksadk/studio/static/assets/MathMessageMarkdown-BesSeCYl-OhNwH4K9.js +8 -0
  641. ksadk/studio/static/assets/MermaidBlock-H_0qzQDf-BdXtxug_.js +11 -0
  642. ksadk/studio/static/assets/MessageMarkdown-CwMTvgFj-g0I-I4dD.js +59 -0
  643. ksadk/studio/static/assets/PrismRenderer-5pK6tUdb.js +3 -0
  644. ksadk/studio/static/assets/TeamsPage-DqX4HWKQ.js +3 -0
  645. ksadk/studio/static/assets/abnfDiagram-VCTEODGH-Bnb1O3tA.js +1 -0
  646. ksadk/studio/static/assets/arc-Pry-7G1_.js +1 -0
  647. ksadk/studio/static/assets/architecture-7GRP2DOG-BMOPAkUC.js +1 -0
  648. ksadk/studio/static/assets/architectureDiagram-5GKGNRK7-5Zn1gqJv.js +36 -0
  649. ksadk/studio/static/assets/array-BifhSqXX.js +1 -0
  650. ksadk/studio/static/assets/blockDiagram-I7D4REHJ-CLB4L11u.js +129 -0
  651. ksadk/studio/static/assets/c4Diagram-7LVT6UL2-BOma_Z_F.js +38 -0
  652. ksadk/studio/static/assets/channel-r8itPEik.js +1 -0
  653. ksadk/studio/static/assets/chunk-2E4U76K2-BFf_huql.js +2 -0
  654. ksadk/studio/static/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
  655. ksadk/studio/static/assets/chunk-2ZTRR5NV-C2qZJila.js +2 -0
  656. ksadk/studio/static/assets/chunk-3Z5EZCMW-DMniOlPd.js +1 -0
  657. ksadk/studio/static/assets/chunk-4HAMMTFA-DVtDP4rm.js +62 -0
  658. ksadk/studio/static/assets/chunk-5V3GS4D5-i-ZDOEnP.js +1 -0
  659. ksadk/studio/static/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
  660. ksadk/studio/static/assets/chunk-6AZGARVD-BB6FqMl-.js +1 -0
  661. ksadk/studio/static/assets/chunk-6EIED4P4-DdUJkP0f.js +1 -0
  662. ksadk/studio/static/assets/chunk-6K3QC6MW-CqVsVn-y.js +1 -0
  663. ksadk/studio/static/assets/chunk-6TQVIW2G-DKlLbNIP.js +1 -0
  664. ksadk/studio/static/assets/chunk-747NJXEK-BFkZPlab.js +2 -0
  665. ksadk/studio/static/assets/chunk-75Z2AOVW-BZNhM4vB.js +2 -0
  666. ksadk/studio/static/assets/chunk-CLGD4ZFX-D-GTtyKs.js +1 -0
  667. ksadk/studio/static/assets/chunk-DU6HZSFF-CpEZCUgg.js +128 -0
  668. ksadk/studio/static/assets/chunk-F27PBJKO-D7pvKf0C.js +1 -0
  669. ksadk/studio/static/assets/chunk-FOHPRMQF-DHwB1DNv.js +161 -0
  670. ksadk/studio/static/assets/chunk-GMAD6QVW-DE_8H717.js +72 -0
  671. ksadk/studio/static/assets/chunk-GVQU2GXP-BfEB0lNv.js +1 -0
  672. ksadk/studio/static/assets/chunk-I5DQTOEV-Hm2LfiYI.js +1 -0
  673. ksadk/studio/static/assets/chunk-ICYGCRZG-749o-pGJ.js +1 -0
  674. ksadk/studio/static/assets/chunk-IH6LHLGP-CC6I9F3i.js +1 -0
  675. ksadk/studio/static/assets/chunk-IMKFNOWR-D38axYOR.js +231 -0
  676. ksadk/studio/static/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
  677. ksadk/studio/static/assets/chunk-KI3K4JFJ-Rma-0k_M.js +1 -0
  678. ksadk/studio/static/assets/chunk-L3NEJ4N5-Dq5xn7aL.js +1 -0
  679. ksadk/studio/static/assets/chunk-LNGE3PJU-DWpGwHrW.js +34 -0
  680. ksadk/studio/static/assets/chunk-OSK3NFVY-DiCQjx9b.js +10 -0
  681. ksadk/studio/static/assets/chunk-OUJLGHUK-D0j2JRSg.js +2 -0
  682. ksadk/studio/static/assets/chunk-P2QGCYS3-VdhKmfYq.js +1 -0
  683. ksadk/studio/static/assets/chunk-POPQ4Y6H-C1_rzO5M.js +1 -0
  684. ksadk/studio/static/assets/chunk-PWAF6VOD-B45HvflI.js +1 -0
  685. ksadk/studio/static/assets/chunk-SHT3W25Y-DsCFnRVE.js +168 -0
  686. ksadk/studio/static/assets/chunk-SVP7TREG-DljApgRX.js +88 -0
  687. ksadk/studio/static/assets/chunk-TICWLB2K-DWqRtyqa.js +206 -0
  688. ksadk/studio/static/assets/chunk-TLUHSLCS-DUeGgnD5.js +2 -0
  689. ksadk/studio/static/assets/chunk-UY3FDG6J-CnmaAkG5.js +1 -0
  690. ksadk/studio/static/assets/chunk-XHIXRSVI-BFQ6B8BE.js +1 -0
  691. ksadk/studio/static/assets/chunk-XXDRQBXY-DqAYeljN.js +1 -0
  692. ksadk/studio/static/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
  693. ksadk/studio/static/assets/classDiagram-ZZMXUADV-DjeMNJmu.js +1 -0
  694. ksadk/studio/static/assets/classDiagram-v2-VYDZK3BY-DjeMNJmu.js +1 -0
  695. ksadk/studio/static/assets/clsx-DB0hHKMi.js +1 -0
  696. ksadk/studio/static/assets/cose-bilkent-JH36ORCC-om8AY0Mc.js +1 -0
  697. ksadk/studio/static/assets/createLucideIcon-DR0LGTP5.js +1 -0
  698. ksadk/studio/static/assets/cynefin-OW5HDTMX-7tP7QfM3.js +1 -0
  699. ksadk/studio/static/assets/cynefinDiagram-5FMLGOSQ-6BrmK52S.js +62 -0
  700. ksadk/studio/static/assets/cytoscape.esm-CGd-uY3x.js +321 -0
  701. ksadk/studio/static/assets/dagre-GXQ25YYZ-buZBRlwz.js +4 -0
  702. ksadk/studio/static/assets/dagre-PrKaheQc.js +1 -0
  703. ksadk/studio/static/assets/defaultLocale-BFoDCU3G.js +1 -0
  704. ksadk/studio/static/assets/diagram-S7CK7UJ4-C6aH78c4.js +30 -0
  705. ksadk/studio/static/assets/diagram-UQ7AKVKN-DY_tQ6C_.js +41 -0
  706. ksadk/studio/static/assets/diagram-VSXAHHWV-DX9p5cQT.js +3 -0
  707. ksadk/studio/static/assets/diagram-VX7I27RA-DB2WSH8X.js +24 -0
  708. ksadk/studio/static/assets/diagram-Z3DM3KII-Ce1BJwHE.js +24 -0
  709. ksadk/studio/static/assets/dist-v5Q1xZ2K.js +1 -0
  710. ksadk/studio/static/assets/ebnfDiagram-PWID7BFC-Daukxwqf.js +1 -0
  711. ksadk/studio/static/assets/erDiagram-RLTQ6QDP-CGthTMmJ.js +99 -0
  712. ksadk/studio/static/assets/eventmodeling-NTZA5JFV-BR2FzK4R.js +1 -0
  713. ksadk/studio/static/assets/flowDiagram-HODETNUW-CZ1tEenp.js +1 -0
  714. ksadk/studio/static/assets/ganttDiagram-EL5Y4UJY-BfoAZW9X.js +292 -0
  715. ksadk/studio/static/assets/gitGraph-4MIJSDKK-DYlXv_yJ.js +1 -0
  716. ksadk/studio/static/assets/gitGraphDiagram-WWUBYQGX-S985OIJF.js +106 -0
  717. ksadk/studio/static/assets/graphlib-DS17s2tU.js +1 -0
  718. ksadk/studio/static/assets/iconfont-4HN3C9Pg.woff2 +0 -0
  719. ksadk/studio/static/assets/index-CfEnms6Y.css +2 -0
  720. ksadk/studio/static/assets/index-Dp61rOWZ.js +0 -0
  721. ksadk/studio/static/assets/index.dom-BQenBtFm.js +1 -0
  722. ksadk/studio/static/assets/info-A6RAGUB7-BlU-8_xu.js +1 -0
  723. ksadk/studio/static/assets/infoDiagram-27XIBGKW-CO3W8tFn.js +2 -0
  724. ksadk/studio/static/assets/init-C-OQMol4.js +1 -0
  725. ksadk/studio/static/assets/ishikawaDiagram-5VMMS53U-BUGEl8cO.js +70 -0
  726. ksadk/studio/static/assets/journeyDiagram-3NMN7TZE-Ch2ZYxvr.js +139 -0
  727. ksadk/studio/static/assets/kanban-definition-UXKFOSKX-Da-Fp4vC.js +89 -0
  728. ksadk/studio/static/assets/katex-DhON-x74.js +257 -0
  729. ksadk/studio/static/assets/kingsoft-cloud-BOcLiQ3e.ico +0 -0
  730. ksadk/studio/static/assets/line-BDaeq300.js +1 -0
  731. ksadk/studio/static/assets/linear-DmucvK78.js +1 -0
  732. ksadk/studio/static/assets/mermaid-parser.core-Cj5mYdBi.js +4 -0
  733. ksadk/studio/static/assets/mindmap-definition-YA3MSWOX-CvlsVQ38.js +96 -0
  734. ksadk/studio/static/assets/ordinal-BDEzSJ7C.js +1 -0
  735. ksadk/studio/static/assets/packet-AYTQ26CC-BSJEH9Lb.js +1 -0
  736. ksadk/studio/static/assets/path-fybaL0A-.js +1 -0
  737. ksadk/studio/static/assets/pegDiagram-XKGWAZYB-BuHuNgT5.js +1 -0
  738. ksadk/studio/static/assets/pie-WAS4IAKB-qxv01Y8W.js +1 -0
  739. ksadk/studio/static/assets/pieDiagram-E7YTZNPT-DlrWiSOv.js +39 -0
  740. ksadk/studio/static/assets/preload-helper-CO68xz6u.js +1 -0
  741. ksadk/studio/static/assets/presentation-yYw7xK60-BmcZriri.js +1 -0
  742. ksadk/studio/static/assets/quadrantDiagram-AXDQQJYC-BA3hpUZM.js +7 -0
  743. ksadk/studio/static/assets/radar-RG4KPBEZ-B6h6pWOs.js +1 -0
  744. ksadk/studio/static/assets/railroad-74A4TZTK-CGtTWdGc.js +1 -0
  745. ksadk/studio/static/assets/railroad-abnf-HS5TGJTU-Cq7y22IA.js +1 -0
  746. ksadk/studio/static/assets/railroad-ebnf-LZEXJU2U-V0aQVv9m.js +1 -0
  747. ksadk/studio/static/assets/railroad-peg-WCYAUIDC-BQiIsX_p.js +1 -0
  748. ksadk/studio/static/assets/railroadDiagram-O6MQD6OU-BxpAazym.js +1 -0
  749. ksadk/studio/static/assets/requirementDiagram-BXWQKSXE-E-Ge0FcV.js +84 -0
  750. ksadk/studio/static/assets/rolldown-runtime-Dy4uBu1J-DK3Fl9T5.js +1 -0
  751. ksadk/studio/static/assets/rough.esm-Dy-Kn_BL.js +1 -0
  752. ksadk/studio/static/assets/sankeyDiagram-P5KCCOFB-CA6YKhQ3.js +40 -0
  753. ksadk/studio/static/assets/sequenceDiagram-WJ2MYXX4-CcElXGg4.js +162 -0
  754. ksadk/studio/static/assets/sizeCapture-INFHLROL-B0uUizjq.js +1 -0
  755. ksadk/studio/static/assets/src-B6xuSHsQ.js +1 -0
  756. ksadk/studio/static/assets/stateDiagram-D77RDMKH-DdXZOFqY.js +1 -0
  757. ksadk/studio/static/assets/stateDiagram-v2-MP3YSRHH-CJbOM-QK.js +1 -0
  758. ksadk/studio/static/assets/swimlanes-42K2YHIH-NtgEEHLY.js +1 -0
  759. ksadk/studio/static/assets/swimlanesDiagram-VR7AAH4N-D-AVlW8B.js +8 -0
  760. ksadk/studio/static/assets/timeline-definition-24CTP7MA-CIuYhNy3.js +120 -0
  761. ksadk/studio/static/assets/treeView-Q6P3EWNA-BTTYcvrF.js +1 -0
  762. ksadk/studio/static/assets/treemap-WGGIJYW6-Cg7tyfH8.js +1 -0
  763. ksadk/studio/static/assets/vennDiagram-4TSXK5OY-7HbApbrv.js +34 -0
  764. ksadk/studio/static/assets/wardley-WFR3VGLG-C6N1rULY.js +1 -0
  765. ksadk/studio/static/assets/wardleyDiagram-VM6X3IG4-CMJiaedy.js +78 -0
  766. ksadk/studio/static/assets/xychartDiagram-S5SC5T6Z-BdgtMvW2.js +7 -0
  767. ksadk/studio/static/index.html +8 -2
  768. ksadk/studio/teams_catalog.py +133 -0
  769. ksadk/studio/teams_installation.py +214 -0
  770. ksadk/studio/teams_node.py +545 -0
  771. ksadk/studio/teams_node_runner.py +69 -0
  772. ksadk/studio/teams_remote.py +274 -0
  773. ksadk/studio/templates.py +40 -19
  774. ksadk/studio/validator.py +13 -0
  775. ksadk/studio/workspace.py +19 -4
  776. ksadk/studio/workspace_plugins.py +136 -0
  777. ksadk/studio/workspace_registry.py +286 -0
  778. ksadk/toolsets/__init__.py +11 -0
  779. ksadk/toolsets/skills.py +446 -378
  780. ksadk/toolsets/workspace.py +3 -3
  781. ksadk/toolsets/workspace_identity.py +15 -0
  782. ksadk/version.py +1 -1
  783. ksadk_runtime_common/memory_backend/providers/lancedb.py +56 -2
  784. ksadk_runtime_common/schemas/memory_backend_manifest.schema.json +148 -148
  785. ksadk_runtime_common/workspace_files/router.py +26 -13
  786. agentengine_sdk_python-0.8.3.dist-info/RECORD +0 -833
  787. ksadk/server/static/assets/MathMessageMarkdown-D9uB55Oh.js +0 -8
  788. ksadk/server/static/assets/architecture-7GRP2DOG-Dk9nRQ6-.js +0 -1
  789. ksadk/server/static/assets/channel-s354Yo6o.js +0 -1
  790. ksadk/server/static/assets/chunk-2Q5K7J3B-CDpPpKR5.js +0 -1
  791. ksadk/server/static/assets/classDiagram-DTDB5LWJ-Dd0nucl9.js +0 -1
  792. ksadk/server/static/assets/classDiagram-v2-JRS7N3AN-Dd0nucl9.js +0 -1
  793. ksadk/server/static/assets/cynefin-OW5HDTMX-BBlT4uMf.js +0 -1
  794. ksadk/server/static/assets/dist-DdRBIceA.js +0 -1
  795. ksadk/server/static/assets/eventmodeling-NTZA5JFV-Dr5okd8V.js +0 -1
  796. ksadk/server/static/assets/flowDiagram-A5DVABFB-VEO-cVcO.js +0 -1
  797. ksadk/server/static/assets/gitGraph-4MIJSDKK-CKiKY9Cf.js +0 -1
  798. ksadk/server/static/assets/index-B2k_urY8.js +0 -241
  799. ksadk/server/static/assets/index-ILPt6IWF.css +0 -2
  800. ksadk/server/static/assets/info-A6RAGUB7-ubA4Nm_p.js +0 -1
  801. ksadk/server/static/assets/packet-AYTQ26CC-C7R3NUlK.js +0 -1
  802. ksadk/server/static/assets/pie-WAS4IAKB-BIT6qjr3.js +0 -1
  803. ksadk/server/static/assets/radar-RG4KPBEZ-l5noef9X.js +0 -1
  804. ksadk/server/static/assets/railroad-74A4TZTK-Baea6ZvM.js +0 -1
  805. ksadk/server/static/assets/railroad-abnf-HS5TGJTU-OKn8zZnU.js +0 -1
  806. ksadk/server/static/assets/railroad-ebnf-LZEXJU2U-DdKAKC4l.js +0 -1
  807. ksadk/server/static/assets/railroad-peg-WCYAUIDC-Bds8udlG.js +0 -1
  808. ksadk/server/static/assets/stateDiagram-v2-4QOOHH4V-5b-8o2iS.js +0 -1
  809. ksadk/server/static/assets/swimlanesDiagram-VK2B7HYN-uf6WPRA4.js +0 -8
  810. ksadk/server/static/assets/treeView-Q6P3EWNA-CK5CSrSO.js +0 -1
  811. ksadk/server/static/assets/treemap-WGGIJYW6-Ch2BKgAM.js +0 -1
  812. ksadk/server/static/assets/wardley-WFR3VGLG-YW3Q0ml_.js +0 -1
  813. ksadk/studio/static/assets/PrismRenderer-IYN-ffww.js +0 -3
  814. ksadk/studio/static/assets/index-DXs1Eq4M.css +0 -1
  815. ksadk/studio/static/assets/index-DeDqwTsD.js +0 -283
  816. {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.5.dist-info}/WHEEL +0 -0
  817. {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.5.dist-info}/entry_points.txt +0 -0
  818. {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.5.dist-info}/licenses/LICENSE +0 -0
  819. {agentengine_sdk_python-0.8.3.dist-info → agentengine_sdk_python-0.8.5.dist-info}/top_level.txt +0 -0
@@ -3,11 +3,12 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import asyncio
6
- import hashlib
6
+ import base64
7
7
  import os
8
+ import re
8
9
  from pathlib import Path
9
10
  from typing import Any, Callable
10
- from urllib.parse import urlencode, urlparse
11
+ from urllib.parse import urlparse
11
12
  from uuid import uuid4
12
13
 
13
14
  from fastapi import FastAPI, Query, Response
@@ -29,8 +30,27 @@ from ksadk.plugins.bridges.dsh import (
29
30
  DshPluginMutationError,
30
31
  DshPluginNotFoundError,
31
32
  DshProfilePluginBridge,
33
+ DshProfileRecoveryError,
34
+ validate_dsh_registry_request,
35
+ )
36
+ from ksadk.plugins.codex_manifest import (
37
+ CodexInstalledPluginSnapshot,
38
+ CodexPluginSourceCoordinate,
39
+ snapshot_installed_codex_plugin,
40
+ )
41
+ from ksadk.plugins.dsh_home import (
42
+ DshHomeVersionError,
43
+ dsh_home_diagnostic,
44
+ prepare_studio_dsh_home,
45
+ studio_dsh_home,
32
46
  )
33
47
  from ksadk.plugins.dsh_toolchain import DshToolchainError, DshToolchainManager
48
+ from ksadk.plugins.host import PluginHostError
49
+ from ksadk.studio.codex_plugin_store import (
50
+ CodexWorkspacePluginSnapshot,
51
+ component_selector,
52
+ find_installed_codex_plugin_root,
53
+ )
34
54
  from ksadk.studio.errors import StudioError
35
55
  from ksadk.studio.service import StudioService
36
56
 
@@ -43,6 +63,13 @@ class CodexPluginInstallRequest(BaseModel):
43
63
  accept_undeclared_permissions: bool = Field(default=False, alias="acceptUndeclaredPermissions")
44
64
 
45
65
 
66
+ class CodexPluginSnapshotRequest(BaseModel):
67
+ model_config = ConfigDict(extra="forbid", populate_by_name=True)
68
+ marketplace_name: str | None = Field(
69
+ default=None, alias="marketplaceName", min_length=1, max_length=256
70
+ )
71
+
72
+
46
73
  class DshPluginInstallRequest(BaseModel):
47
74
  model_config = ConfigDict(extra="forbid", populate_by_name=True)
48
75
  source: str = Field(min_length=1, max_length=2048)
@@ -53,8 +80,16 @@ class DshPluginInstallRequest(BaseModel):
53
80
  def validate_source(cls, value: str) -> str:
54
81
  normalized = value.strip()
55
82
  if not normalized or any(character in value for character in ("\x00", "\r", "\n")):
56
- raise ValueError("source must be one package, Git URL, or absolute local path")
57
- return normalized
83
+ raise ValueError("source must be one exact registry package")
84
+ # The authenticated Studio API is a production-facing package install
85
+ # boundary. Local paths remain available to the CLI/developer bridge,
86
+ # where they are packed into the immutable store; exposing arbitrary
87
+ # host paths to a browser request would turn the API into a file reader.
88
+ if Path(normalized).expanduser().is_absolute():
89
+ raise ValueError(
90
+ "Studio only accepts registry packages; use the local CLI for development"
91
+ )
92
+ return validate_dsh_registry_request(normalized)
58
93
 
59
94
 
60
95
  class DshPluginUpdateRequest(BaseModel):
@@ -69,13 +104,14 @@ def _studio_codex_home(studio: StudioService) -> tuple[Path, str]:
69
104
  return studio.workspace.root / ".agentkit" / "codex-home", "workspace-isolated"
70
105
 
71
106
 
107
+ def _active_studio(studio):
108
+ """Resolve the active runtime while retaining compatibility with direct test fixtures."""
109
+ return getattr(studio, "active", studio)
110
+
111
+
72
112
  def _studio_dsh_options(studio: StudioService) -> tuple[Path, str, tuple[str, ...] | None, str]:
73
113
  configured_home = os.environ.get("KSADK_DSH_HOME", "").strip()
74
- home = (
75
- Path(configured_home).expanduser()
76
- if configured_home
77
- else studio.workspace.root / ".agentkit" / "dsh-home"
78
- )
114
+ home = studio_dsh_home(studio.workspace.root)
79
115
  configured_bin = os.environ.get("KSADK_DSH_BIN", "").strip()
80
116
  if configured_bin:
81
117
  command = (str(Path(configured_bin).expanduser()),)
@@ -86,7 +122,7 @@ def _studio_dsh_options(studio: StudioService) -> tuple[Path, str, tuple[str, ..
86
122
  # Keep the bridge's established PATH lookup when the optional
87
123
  # pinned toolchain has not been installed or is unusable.
88
124
  command = None
89
- profile = os.environ.get("KSADK_DSH_PROFILE", "").strip() or "studio"
125
+ profile = os.environ.get("KSADK_DSH_PROFILE", "").strip() or "web"
90
126
  return home, profile, command, "explicit" if configured_home else "workspace-isolated"
91
127
 
92
128
 
@@ -123,13 +159,20 @@ def _public_codex_source(source: BaseModel) -> dict[str, Any]:
123
159
  def _public_codex_inventory(
124
160
  inventory: CodexPluginInventory, *, host: CodexBridgeHost, home_mode: str
125
161
  ) -> dict[str, Any]:
162
+ presentation = _public_plugin_interface(inventory.interface)
163
+ if not presentation.get("logoUrl"):
164
+ artwork = _local_plugin_artwork(inventory)
165
+ if artwork:
166
+ presentation["logoUrl"] = artwork
126
167
  return {
127
168
  "ecosystem": "codex",
128
169
  "integrationMode": "bridged",
129
170
  "pluginId": inventory.plugin_id,
130
171
  "resolvedVersion": inventory.version,
131
172
  "distributionName": inventory.name,
132
- "displayName": inventory.name,
173
+ "displayName": inventory.interface.get("displayName") or inventory.name,
174
+ "description": inventory.interface.get("shortDescription"),
175
+ "interface": presentation,
133
176
  "marketplaceName": inventory.marketplace_name,
134
177
  "source": _public_codex_source(inventory.source),
135
178
  "installed": inventory.installed,
@@ -145,10 +188,81 @@ def _public_codex_inventory(
145
188
  }
146
189
 
147
190
 
191
+ def _local_plugin_artwork(inventory: CodexPluginInventory) -> str | None:
192
+ """Read only bounded image assets inside the host-reported local plugin.
193
+
194
+ Never expose host paths, accept browser-supplied filenames, or fetch URLs.
195
+ SVGs remain image data (not executable same-origin HTML documents).
196
+ """
197
+ if inventory.source.type != "local":
198
+ return None
199
+ root = Path(inventory.source.path)
200
+ if not root.is_absolute():
201
+ if not inventory.marketplace_path:
202
+ return None
203
+ root = Path(inventory.marketplace_path) / root
204
+ root = root.resolve()
205
+ if not (root / ".codex-plugin" / "plugin.json").is_file():
206
+ return None
207
+ for key in ("logo", "composerIcon"):
208
+ raw = inventory.interface.get(key)
209
+ if not isinstance(raw, str):
210
+ continue
211
+ path = Path(raw)
212
+ path = (path if path.is_absolute() else root / path).resolve()
213
+ if not path.is_relative_to(root):
214
+ continue
215
+ try:
216
+ with path.open("rb") as stream:
217
+ data = stream.read(256 * 1024 + 1)
218
+ except OSError:
219
+ continue
220
+ if len(data) > 256 * 1024:
221
+ continue
222
+ mime = None
223
+ if data.startswith(b"\x89PNG\r\n\x1a\n"):
224
+ mime = "image/png"
225
+ elif data.startswith(b"\xff\xd8\xff"):
226
+ mime = "image/jpeg"
227
+ elif data.startswith((b"GIF87a", b"GIF89a")):
228
+ mime = "image/gif"
229
+ elif data.startswith(b"RIFF") and data[8:12] == b"WEBP":
230
+ mime = "image/webp"
231
+ elif path.suffix.lower() == ".svg" and b"<svg" in data[:1024]:
232
+ mime = "image/svg+xml"
233
+ if mime:
234
+ return f"data:{mime};base64,{base64.b64encode(data).decode('ascii')}"
235
+ return None
236
+
237
+
238
+ def _public_plugin_interface(value: dict[str, Any]) -> dict[str, Any]:
239
+ """Project marketplace display data, never filesystem paths or host state."""
240
+ result = {
241
+ key: value[key] for key in (
242
+ "displayName", "shortDescription", "longDescription", "developerName", "category",
243
+ ) if isinstance(value.get(key), str)
244
+ }
245
+ for key in ("defaultPrompt", "capabilities"):
246
+ if isinstance(value.get(key), list):
247
+ result[key] = [item for item in value[key] if isinstance(item, str)]
248
+ for key in (
249
+ "logoUrl", "logoUrlDark", "composerIconUrl", "websiteUrl",
250
+ "privacyPolicyUrl", "termsOfServiceUrl",
251
+ ):
252
+ raw = value.get(key)
253
+ if isinstance(raw, str) and urlparse(raw).scheme == "https" and not urlparse(raw).username:
254
+ result[key] = raw
255
+ return result
256
+
257
+
148
258
  def _public_codex_detail(
149
- detail: CodexPluginDetail, *, host: CodexBridgeHost, home_mode: str
259
+ detail: CodexPluginDetail,
260
+ *,
261
+ host: CodexBridgeHost,
262
+ home_mode: str,
263
+ snapshot: CodexWorkspacePluginSnapshot | None = None,
150
264
  ) -> dict[str, Any]:
151
- return {
265
+ payload = {
152
266
  "item": _public_codex_inventory(detail.inventory, host=host, home_mode=home_mode),
153
267
  "description": detail.description,
154
268
  "capabilities": {
@@ -158,6 +272,189 @@ def _public_codex_detail(
158
272
  "apps": list(detail.apps),
159
273
  "scheduledTasks": list(detail.scheduled_tasks),
160
274
  },
275
+ "snapshot": None,
276
+ "snapshotRequired": detail.inventory.installed,
277
+ }
278
+ if snapshot is not None:
279
+ projection = _public_codex_snapshot(snapshot)
280
+ payload["snapshot"] = projection
281
+ payload["snapshotRequired"] = False
282
+ payload["item"].update(
283
+ snapshotDigest=projection["snapshotDigest"],
284
+ pluginRef=projection["pluginRef"],
285
+ components=projection["components"],
286
+ )
287
+ return payload
288
+
289
+
290
+ _EXACT_SEMVER = re.compile(
291
+ r"^(0|[1-9]\d*)\."
292
+ r"(0|[1-9]\d*)\."
293
+ r"(0|[1-9]\d*)"
294
+ r"(?:-(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\."
295
+ r"(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*)?"
296
+ r"(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$"
297
+ )
298
+ _FULL_GIT_COMMIT = re.compile(r"^(?:[0-9a-fA-F]{40}|[0-9a-fA-F]{64})$")
299
+
300
+
301
+ def _require_exact_codex_version(inventory: CodexPluginInventory) -> str:
302
+ version = str(inventory.version or "")
303
+ if _EXACT_SEMVER.fullmatch(version) is None:
304
+ raise StudioError(
305
+ "CODEX_PLUGIN_SOURCE_NOT_IMMUTABLE",
306
+ "Codex 插件缺少可锁定的精确语义版本",
307
+ status_code=422,
308
+ details={
309
+ "pluginId": inventory.plugin_id,
310
+ "sourceType": inventory.source.type,
311
+ "version": inventory.version,
312
+ },
313
+ )
314
+ return version
315
+
316
+
317
+ def _codex_source_coordinate(inventory: CodexPluginInventory) -> CodexPluginSourceCoordinate:
318
+ raw = inventory.source.model_dump(by_alias=True, exclude_none=True, mode="json")
319
+ source_type = str(raw.get("type") or "remote")
320
+ marketplace = inventory.marketplace_name
321
+ version = _require_exact_codex_version(inventory)
322
+ integrity: str | None = None
323
+ if source_type == "local":
324
+ requested = str(raw.get("path") or inventory.name)
325
+ resolved = f"codex-marketplace://{marketplace}/{inventory.name}@{version}"
326
+ elif source_type == "git":
327
+ requested = str(raw.get("url") or inventory.name)
328
+ revision = str(raw.get("sha") or "")
329
+ if _FULL_GIT_COMMIT.fullmatch(revision) is None:
330
+ raise StudioError(
331
+ "CODEX_PLUGIN_SOURCE_NOT_IMMUTABLE",
332
+ "Git Codex 插件必须由宿主解析为完整 commit SHA 后才能提交快照",
333
+ status_code=422,
334
+ details={
335
+ "pluginId": inventory.plugin_id,
336
+ "refName": raw.get("refName"),
337
+ "sha": raw.get("sha"),
338
+ },
339
+ )
340
+ resolved = f"{requested.rstrip('/')}@{revision.lower()}"
341
+ elif source_type == "npm":
342
+ package = str(raw.get("package") or inventory.name)
343
+ source_version = str(raw.get("version") or "")
344
+ if _EXACT_SEMVER.fullmatch(source_version) is None or source_version != version:
345
+ raise StudioError(
346
+ "CODEX_PLUGIN_SOURCE_NOT_IMMUTABLE",
347
+ "npm Codex 插件必须由宿主解析为一致的精确版本后才能提交快照",
348
+ status_code=422,
349
+ details={
350
+ "pluginId": inventory.plugin_id,
351
+ "requestedVersion": raw.get("version"),
352
+ "resolvedVersion": inventory.version,
353
+ },
354
+ )
355
+ requested = f"{package}@{source_version}"
356
+ resolved = requested
357
+ raw_integrity = raw.get("integrity")
358
+ integrity = str(raw_integrity) if raw_integrity else None
359
+ else:
360
+ requested = inventory.plugin_id
361
+ resolved = f"codex-marketplace://{marketplace}/{inventory.name}@{version}"
362
+ return CodexPluginSourceCoordinate(
363
+ type=source_type,
364
+ requested=requested,
365
+ resolved=resolved,
366
+ marketplace_name=marketplace,
367
+ registry=raw.get("registry"),
368
+ integrity=integrity,
369
+ )
370
+
371
+
372
+ def _observe_codex_snapshot(
373
+ codex_home: Path,
374
+ inventory: CodexPluginInventory,
375
+ ) -> CodexInstalledPluginSnapshot:
376
+ if not inventory.installed:
377
+ raise StudioError(
378
+ "CODEX_PLUGIN_NOT_INSTALLED",
379
+ "Codex 插件尚未安装,无法提交不可变快照",
380
+ status_code=409,
381
+ details={"pluginId": inventory.plugin_id},
382
+ )
383
+ installed_root = find_installed_codex_plugin_root(
384
+ codex_home,
385
+ marketplace_name=inventory.marketplace_name,
386
+ plugin_name=inventory.name,
387
+ version=inventory.version,
388
+ )
389
+ observed = snapshot_installed_codex_plugin(
390
+ installed_root,
391
+ source=_codex_source_coordinate(inventory),
392
+ )
393
+ if observed.manifest.version != inventory.version:
394
+ raise StudioError(
395
+ "CODEX_PLUGIN_VERSION_MISMATCH",
396
+ "Codex 宿主清单版本与已安装插件清单不一致",
397
+ status_code=409,
398
+ details={
399
+ "pluginId": inventory.plugin_id,
400
+ "hostVersion": inventory.version,
401
+ "manifestVersion": observed.manifest.version,
402
+ },
403
+ )
404
+ return observed
405
+
406
+
407
+ def _lookup_codex_snapshot(
408
+ studio: StudioService,
409
+ codex_home: Path,
410
+ inventory: CodexPluginInventory,
411
+ ) -> CodexWorkspacePluginSnapshot | None:
412
+ if not inventory.installed:
413
+ return None
414
+ try:
415
+ observed = _observe_codex_snapshot(codex_home, inventory)
416
+ except (StudioError, OSError, ValueError):
417
+ # GET is an inventory operation. Invalid/unpinned host bytes remain
418
+ # visible but require the explicit admission POST, which reports the
419
+ # actionable validation failure.
420
+ return None
421
+ return studio.codex_plugin_snapshots.lookup(observed)
422
+
423
+
424
+ def _commit_codex_snapshot(
425
+ studio: StudioService,
426
+ codex_home: Path,
427
+ inventory: CodexPluginInventory,
428
+ ) -> CodexWorkspacePluginSnapshot:
429
+ return studio.codex_plugin_snapshots.commit(_observe_codex_snapshot(codex_home, inventory))
430
+
431
+
432
+ def _snapshot_failure_details(error: Exception) -> dict[str, Any]:
433
+ if isinstance(error, StudioError):
434
+ return {
435
+ "code": error.code,
436
+ "message": error.message,
437
+ "details": error.details,
438
+ }
439
+ return {"code": type(error).__name__, "message": str(error)}
440
+
441
+
442
+ def _public_codex_snapshot(snapshot: CodexWorkspacePluginSnapshot) -> dict[str, Any]:
443
+ return {
444
+ "snapshotDigest": snapshot.snapshot_digest,
445
+ "pluginRef": snapshot.plugin_ref,
446
+ "artifactDigest": snapshot.artifact_digest,
447
+ "manifestDigest": snapshot.manifest_digest,
448
+ "components": [
449
+ {
450
+ "id": component_selector(component),
451
+ "kind": component.kind,
452
+ "name": component.name,
453
+ "path": component.path,
454
+ "digest": component.content_digest,
455
+ }
456
+ for component in snapshot.components
457
+ ],
161
458
  }
162
459
 
163
460
 
@@ -168,7 +465,20 @@ def _public_dsh_inventory(
168
465
  home_mode: str,
169
466
  runtime_state: dict[str, Any] | None = None,
170
467
  ) -> dict[str, Any]:
171
- client = inventory.client_bundle
468
+ if inventory.source_digest is not None:
469
+ source = {
470
+ "type": "local-immutable",
471
+ "name": inventory.name,
472
+ "kind": inventory.source_kind,
473
+ "integrity": inventory.source_digest,
474
+ }
475
+ else:
476
+ source = {
477
+ "type": "registry",
478
+ "package": inventory.name,
479
+ "requested": inventory.requested_spec,
480
+ "resolvedVersion": inventory.version,
481
+ }
172
482
  return {
173
483
  "ecosystem": "dsh",
174
484
  "integrationMode": "bridged",
@@ -177,8 +487,10 @@ def _public_dsh_inventory(
177
487
  "distributionName": inventory.name,
178
488
  "displayName": inventory.display_name,
179
489
  "description": inventory.description,
490
+ "clientExtension": inventory.client_extension,
491
+ "settingsIntegration": inventory.settings_integration,
180
492
  "profile": inventory.profile,
181
- "source": {"type": "host-profile", "name": inventory.name},
493
+ "source": source,
182
494
  "installed": True,
183
495
  "state": "enabled" if inventory.enabled else "disabled",
184
496
  "enabled": inventory.enabled,
@@ -187,42 +499,13 @@ def _public_dsh_inventory(
187
499
  "riskDisclosures": list(inventory.risk_disclosures),
188
500
  "isolation": "host-managed",
189
501
  "runtimeState": runtime_state,
190
- "clientBundle": (
191
- {
192
- "platform": client.platform,
193
- "digest": client.digest,
194
- "contentBytes": client.content_bytes,
195
- "external": list(client.external),
196
- "inject": list(client.inject),
197
- "compatible": client.compatible,
198
- "incompatibilityReason": client.incompatibility_reason or None,
199
- }
200
- if client is not None
201
- else None
202
- ),
203
502
  "host": _public_host("dsh", host, home_mode=home_mode),
204
503
  }
205
504
 
206
505
 
207
- def _public_dsh_client_bundle(inventory: DshPluginInventory) -> dict[str, Any] | None:
208
- client = inventory.client_bundle
209
- if client is None:
210
- return None
211
- query = urlencode({"pluginName": inventory.name, "digest": client.digest})
212
- return {
213
- "pluginId": inventory.name,
214
- "enabled": inventory.enabled,
215
- "compatible": client.compatible,
216
- "digest": client.digest,
217
- "contentBytes": client.content_bytes,
218
- "external": list(client.external),
219
- "inject": list(client.inject),
220
- "incompatibilityReason": client.incompatibility_reason or None,
221
- "url": f"/api/v1/plugin-ecosystems/dsh/client-bundle?{query}",
222
- }
223
-
224
-
225
506
  def _codex_error(error: Exception) -> StudioError:
507
+ if isinstance(error, StudioError):
508
+ return error
226
509
  if isinstance(error, CodexPluginNotFoundError):
227
510
  return StudioError(
228
511
  "CODEX_PLUGIN_NOT_FOUND", "Codex 插件不存在或来源不唯一", status_code=404
@@ -237,6 +520,11 @@ def _codex_error(error: Exception) -> StudioError:
237
520
 
238
521
 
239
522
  def _dsh_error(error: Exception) -> StudioError:
523
+ if isinstance(error, DshHomeVersionError):
524
+ return StudioError(
525
+ "DSH_HOME_VERSION_UNVERIFIED", str(error), status_code=409,
526
+ details=error.diagnostic,
527
+ )
240
528
  if isinstance(error, DshPluginNotFoundError):
241
529
  return StudioError("DSH_PLUGIN_NOT_FOUND", "DSH 插件未安装", status_code=404)
242
530
  if isinstance(error, DshPluginApprovalRequired):
@@ -245,6 +533,12 @@ def _dsh_error(error: Exception) -> StudioError:
245
533
  "安装或升级 DSH 插件前必须确认宿主权限风险",
246
534
  status_code=422,
247
535
  )
536
+ if isinstance(error, DshProfileRecoveryError):
537
+ return StudioError(
538
+ "DSH_PROFILE_RECOVERY_REQUIRED",
539
+ "Profile 迁移恢复失败,已保留恢复备份并暂停运行准入",
540
+ status_code=503,
541
+ )
248
542
  if isinstance(error, DshPluginMutationError):
249
543
  return StudioError(
250
544
  "DSH_PLUGIN_MUTATION_FAILED", "DSH 插件操作失败,原 Profile 已保留", status_code=409
@@ -257,10 +551,8 @@ def _dsh_error(error: Exception) -> StudioError:
257
551
  def register_plugin_routes(app: FastAPI, studio: StudioService) -> None:
258
552
  """Register only DSH Profile and Codex App Server lifecycle routes."""
259
553
 
260
- codex_home, codex_mode = _studio_codex_home(studio)
261
- dsh_home, dsh_profile, dsh_command, dsh_mode = _studio_dsh_options(studio)
262
-
263
554
  def public_dsh(item: DshPluginInventory, host: DshBridgeHost) -> dict[str, Any]:
555
+ _, _, _, dsh_mode = _studio_dsh_options(_active_studio(studio))
264
556
  return _public_dsh_inventory(
265
557
  item,
266
558
  host=host,
@@ -268,8 +560,14 @@ def register_plugin_routes(app: FastAPI, studio: StudioService) -> None:
268
560
  runtime_state=studio.dsh_provider_runtime_state(item.name),
269
561
  )
270
562
 
271
- def call_dsh(operation: Callable[[DshProfilePluginBridge], Any]) -> Any:
563
+ def call_dsh(operation: Callable[[DshProfilePluginBridge], Any], *, write: bool = False) -> Any:
564
+ dsh_home, dsh_profile, dsh_command, _ = _studio_dsh_options(_active_studio(studio))
272
565
  try:
566
+ # Even a read-only bridge creates its synchronization directory.
567
+ # Fence an empty home first so that lockfile cannot make our own
568
+ # fresh home look like an unversioned legacy installation later.
569
+ if write or dsh_home_diagnostic(dsh_home)["status"] == "new":
570
+ prepare_studio_dsh_home(dsh_home)
273
571
  with DshProfilePluginBridge(
274
572
  dsh_home=dsh_home, profile=dsh_profile, dsh_command=dsh_command
275
573
  ) as bridge:
@@ -277,10 +575,39 @@ def register_plugin_routes(app: FastAPI, studio: StudioService) -> None:
277
575
  except Exception as error:
278
576
  raise _dsh_error(error) from None
279
577
 
578
+ @app.post("/api/v1/plugin-ecosystems/dsh/core/session")
579
+ async def start_dsh_core_session(response: Response):
580
+ """Start the official full Core DSH Web profile on demand.
581
+
582
+ The token-bearing URL is returned only from this authenticated,
583
+ CSRF-protected local POST and must never be persisted in Studio state.
584
+ """
585
+
586
+ try:
587
+ lease = await studio.dsh_capabilities.connector_lease()
588
+ descriptor = await studio.dsh_capabilities.describe()
589
+ browser_url = lease.browser_url()
590
+ except PluginHostError as error:
591
+ raise StudioError(
592
+ "DSH_CORE_RUNTIME_UNAVAILABLE",
593
+ "完整 DSH Core 当前无法启动",
594
+ status_code=503,
595
+ details={"reason": error.code},
596
+ ) from error
597
+ response.headers["Cache-Control"] = "no-store"
598
+ return {
599
+ "protocolVersion": "ksadk.dsh-core-runtime/v1",
600
+ "version": descriptor.dsh_version,
601
+ "profile": descriptor.profile,
602
+ "endpoint": browser_url.split("?", 1)[0],
603
+ "browserUrl": browser_url,
604
+ }
605
+
280
606
  @app.get("/api/v1/plugin-ecosystems/codex/plugins")
281
607
  async def list_codex_plugins(
282
608
  installed_only: bool = Query(default=False), force_refetch: bool = Query(default=False)
283
609
  ):
610
+ codex_home, codex_mode = _studio_codex_home(_active_studio(studio))
284
611
  try:
285
612
  async with CodexAppServerPluginBridge(codex_home=codex_home) as bridge:
286
613
  items = await bridge.list_plugins(force_refetch=force_refetch)
@@ -310,29 +637,126 @@ def register_plugin_routes(app: FastAPI, studio: StudioService) -> None:
310
637
  async def get_codex_plugin(
311
638
  plugin_id: str, marketplace_name: str | None = Query(default=None, max_length=256)
312
639
  ):
640
+ codex_home, codex_mode = _studio_codex_home(_active_studio(studio))
313
641
  try:
314
642
  async with CodexAppServerPluginBridge(codex_home=codex_home) as bridge:
315
643
  detail = await bridge.read_plugin(plugin_id, marketplace_name=marketplace_name)
316
- return _public_codex_detail(detail, host=bridge.host, home_mode=codex_mode)
644
+ snapshot = _lookup_codex_snapshot(studio, codex_home, detail.inventory)
645
+ return _public_codex_detail(
646
+ detail,
647
+ host=bridge.host,
648
+ home_mode=codex_mode,
649
+ snapshot=snapshot,
650
+ )
651
+ except Exception as error:
652
+ raise _codex_error(error) from None
653
+
654
+ @app.post("/api/v1/plugin-ecosystems/codex/plugins/{plugin_id}:snapshot")
655
+ async def snapshot_codex_plugin(plugin_id: str, payload: CodexPluginSnapshotRequest):
656
+ codex_home, codex_mode = _studio_codex_home(_active_studio(studio))
657
+ """Explicitly admit already-installed host bytes into the workspace store."""
658
+
659
+ try:
660
+ async with CodexAppServerPluginBridge(codex_home=codex_home) as bridge:
661
+ detail = await bridge.read_plugin(
662
+ plugin_id,
663
+ marketplace_name=payload.marketplace_name,
664
+ )
665
+ snapshot = _commit_codex_snapshot(studio, codex_home, detail.inventory)
666
+ projection = _public_codex_snapshot(snapshot)
667
+ item = _public_codex_inventory(
668
+ detail.inventory,
669
+ host=bridge.host,
670
+ home_mode=codex_mode,
671
+ )
672
+ item.update(
673
+ snapshotDigest=projection["snapshotDigest"],
674
+ pluginRef=projection["pluginRef"],
675
+ components=projection["components"],
676
+ )
677
+ return {"item": item, "snapshot": projection, "snapshotRequired": False}
317
678
  except Exception as error:
318
679
  raise _codex_error(error) from None
319
680
 
320
681
  @app.post("/api/v1/plugin-ecosystems/codex/plugins/{plugin_id}:install")
321
682
  async def install_codex_plugin(plugin_id: str, payload: CodexPluginInstallRequest):
683
+ codex_home, codex_mode = _studio_codex_home(_active_studio(studio))
322
684
  if not payload.accept_undeclared_permissions:
323
685
  raise _codex_error(CodexPluginApprovalRequired("approval required"))
324
686
  try:
325
687
  async with CodexAppServerPluginBridge(codex_home=codex_home) as bridge:
688
+ before = await bridge.read_plugin(
689
+ plugin_id,
690
+ marketplace_name=payload.marketplace_name,
691
+ )
326
692
  result = await bridge.install_plugin(
327
693
  plugin_id,
328
694
  marketplace_name=payload.marketplace_name,
329
695
  accept_undeclared_permissions=True,
330
696
  install_attempt_id=f"studio-{uuid4().hex}",
331
697
  )
698
+ try:
699
+ snapshot = _commit_codex_snapshot(studio, codex_home, result.inventory)
700
+ except Exception as snapshot_error:
701
+ failure = _snapshot_failure_details(snapshot_error)
702
+ inventory = _public_codex_inventory(
703
+ result.inventory,
704
+ host=bridge.host,
705
+ home_mode=codex_mode,
706
+ )
707
+ if before.inventory.installed:
708
+ raise StudioError(
709
+ "CODEX_PLUGIN_INSTALLED_BUT_UNADMITTED",
710
+ "Codex 插件仍由宿主安装,但未能提交 KsADK 不可变快照",
711
+ status_code=409,
712
+ details={
713
+ "inventory": inventory,
714
+ "snapshotFailure": failure,
715
+ "compensation": "not-attempted-preexisting-install",
716
+ },
717
+ ) from snapshot_error
718
+ try:
719
+ await bridge.uninstall_plugin(result.inventory.plugin_id)
720
+ except Exception as rollback_error:
721
+ raise StudioError(
722
+ "CODEX_PLUGIN_INSTALL_RECONCILIATION_REQUIRED",
723
+ "Codex 插件快照提交失败,且宿主卸载补偿未能确认",
724
+ status_code=409,
725
+ details={
726
+ "inventory": inventory,
727
+ "snapshotFailure": failure,
728
+ "compensation": "uninstall-unconfirmed",
729
+ "compensationFailure": {
730
+ "type": type(rollback_error).__name__,
731
+ "message": str(rollback_error),
732
+ },
733
+ },
734
+ ) from rollback_error
735
+ raise StudioError(
736
+ "CODEX_PLUGIN_SNAPSHOT_FAILED_ROLLED_BACK",
737
+ "Codex 插件快照提交失败;本次新安装已由宿主卸载补偿",
738
+ status_code=409,
739
+ details={
740
+ "pluginId": result.inventory.plugin_id,
741
+ "marketplaceName": result.inventory.marketplace_name,
742
+ "snapshotFailure": failure,
743
+ "compensation": "uninstalled",
744
+ },
745
+ ) from snapshot_error
746
+ snapshot_projection = _public_codex_snapshot(snapshot)
747
+ item = _public_codex_inventory(
748
+ result.inventory, host=bridge.host, home_mode=codex_mode
749
+ )
750
+ if snapshot_projection is not None:
751
+ item.update(
752
+ snapshotDigest=snapshot_projection["snapshotDigest"],
753
+ pluginRef=snapshot_projection["pluginRef"],
754
+ components=snapshot_projection["components"],
755
+ )
332
756
  return {
333
- "item": _public_codex_inventory(
334
- result.inventory, host=bridge.host, home_mode=codex_mode
335
- ),
757
+ "item": item,
758
+ "snapshot": snapshot_projection,
759
+ "snapshotRequired": False,
336
760
  "authPolicy": result.auth_policy,
337
761
  "appsNeedingAuth": list(result.apps_needing_auth),
338
762
  }
@@ -341,6 +765,7 @@ def register_plugin_routes(app: FastAPI, studio: StudioService) -> None:
341
765
 
342
766
  @app.delete("/api/v1/plugin-ecosystems/codex/plugins/{plugin_id}", status_code=204)
343
767
  async def uninstall_codex_plugin(plugin_id: str):
768
+ codex_home, codex_mode = _studio_codex_home(_active_studio(studio))
344
769
  try:
345
770
  async with CodexAppServerPluginBridge(codex_home=codex_home) as bridge:
346
771
  await bridge.uninstall_plugin(plugin_id)
@@ -350,6 +775,7 @@ def register_plugin_routes(app: FastAPI, studio: StudioService) -> None:
350
775
 
351
776
  @app.get("/api/v1/plugin-ecosystems/dsh/plugins")
352
777
  async def list_dsh_plugins():
778
+ dsh_home, dsh_profile, _, dsh_mode = _studio_dsh_options(_active_studio(studio))
353
779
  try:
354
780
  host, items = await asyncio.to_thread(call_dsh, lambda bridge: bridge.list_plugins())
355
781
  return {
@@ -358,6 +784,7 @@ def register_plugin_routes(app: FastAPI, studio: StudioService) -> None:
358
784
  "profile": dsh_profile,
359
785
  "host": _public_host("dsh", host, home_mode=dsh_mode),
360
786
  "items": [public_dsh(item, host) for item in items],
787
+ "homeCompatibility": dsh_home_diagnostic(dsh_home, workspace=studio.workspace.root),
361
788
  }
362
789
  except StudioError as error:
363
790
  return {
@@ -367,62 +794,85 @@ def register_plugin_routes(app: FastAPI, studio: StudioService) -> None:
367
794
  "host": _public_host("dsh", None, home_mode=dsh_mode),
368
795
  "items": [],
369
796
  "error": {"code": error.code, "message": error.message},
797
+ "homeCompatibility": dsh_home_diagnostic(dsh_home, workspace=studio.workspace.root),
370
798
  }
371
799
 
372
800
  @app.get("/api/v1/plugin-ecosystems/dsh/profile")
373
801
  async def get_dsh_profile_projection():
374
- host, result = await asyncio.to_thread(
375
- call_dsh, lambda bridge: (bridge.project_profile(), bridge.list_plugins())
802
+ _, dsh_profile, _, dsh_mode = _studio_dsh_options(_active_studio(studio))
803
+ host, projection = await asyncio.to_thread(
804
+ call_dsh, lambda bridge: bridge.project_profile(), write=True,
376
805
  )
377
- projection, items = result
378
- bundles = [
379
- projected
380
- for item in items
381
- if item.enabled
382
- for projected in [_public_dsh_client_bundle(item)]
383
- if projected is not None
384
- ]
385
- graph_hash = hashlib.sha256(projection.config_digest.encode("utf-8"))
386
- for bundle in bundles:
387
- for value in (str(bundle["pluginId"]), str(bundle["digest"])):
388
- encoded = value.encode("utf-8")
389
- graph_hash.update(f"{len(encoded)}:".encode("ascii"))
390
- graph_hash.update(encoded)
391
806
  return {
392
807
  "host": _public_host("dsh", host, home_mode=dsh_mode),
393
808
  "profile": projection.model_dump(mode="json", by_alias=True),
394
- "clientGraphDigest": f"sha256:{graph_hash.hexdigest()}",
395
- "clientBundles": bundles,
396
809
  }
397
810
 
398
- @app.get("/api/v1/plugin-ecosystems/dsh/client-bundle")
399
- async def get_dsh_client_bundle(
400
- plugin_name: str = Query(alias="pluginName", min_length=1, max_length=256),
401
- digest: str = Query(pattern=r"^sha256:[0-9a-f]{64}$"),
402
- ):
403
- _, content = await asyncio.to_thread(
404
- call_dsh,
405
- lambda bridge: bridge.read_client_bundle(plugin_name, expected_digest=digest),
406
- )
407
- return Response(
408
- content=content,
409
- media_type="application/javascript; charset=utf-8",
410
- headers={
411
- "Cache-Control": "private, max-age=31536000, immutable",
412
- "ETag": f'"{digest}"',
413
- "X-Content-Type-Options": "nosniff",
414
- },
415
- )
811
+ @app.get("/api/v1/plugin-ecosystems/dsh/capabilities")
812
+ async def get_dsh_capabilities():
813
+ snapshot, resource = await studio.dsh_capability_catalog_snapshot()
814
+ descriptor = snapshot.descriptor
815
+ tools = snapshot.tools
816
+ inventory = snapshot.inventory
817
+ return {
818
+ "ecosystem": "dsh",
819
+ "profile": descriptor.profile,
820
+ "profileDigest": descriptor.profile_digest,
821
+ "descriptorDigest": descriptor.descriptor_digest,
822
+ "inventoryDigest": descriptor.inventory_digest,
823
+ "state": inventory.model_dump(by_alias=True, mode="json"),
824
+ "tools": [tool.model_dump(by_alias=True, mode="json") for tool in tools],
825
+ "bindableResource": resource.model_dump(by_alias=True, exclude_none=True, mode="json"),
826
+ }
827
+
828
+ @app.post("/api/v1/plugin-ecosystems/dsh/profile:migrate-layout")
829
+ async def migrate_dsh_profile_layout(payload: DshPluginUpdateRequest):
830
+ if not payload.accept_host_permissions:
831
+ raise _dsh_error(DshPluginApprovalRequired("approval required"))
832
+
833
+ def migrate(bridge: DshProfilePluginBridge):
834
+ bridge.migrate_to_isolated_layout(accept_host_permissions=True)
835
+ return bridge.project_profile()
836
+
837
+ async def operation():
838
+ # Do not release Studio's admission fence while a cancelled HTTP
839
+ # request still has a filesystem migration running in its thread.
840
+ task = asyncio.create_task(asyncio.to_thread(call_dsh, migrate, write=True))
841
+ cancelled = False
842
+ while not task.done():
843
+ try:
844
+ await asyncio.shield(task)
845
+ except asyncio.CancelledError:
846
+ cancelled = True
847
+ if cancelled:
848
+ # Retrieve any exception; the reconfiguration owner will recover
849
+ # before allowing another run even when the requester has gone.
850
+ error = task.exception()
851
+ if error is not None:
852
+ raise error
853
+ raise asyncio.CancelledError
854
+ return task.result()
855
+
856
+ host, projection = await studio.reconfigure_dsh_profile(operation)
857
+ return {
858
+ "profile": projection.model_dump(mode="json", by_alias=True),
859
+ "nodeLinker": "isolated",
860
+ "host": {"id": host.host_id, "version": host.version, "available": True},
861
+ }
416
862
 
417
863
  @app.post("/api/v1/plugin-ecosystems/dsh/plugins:install", status_code=201)
418
864
  async def install_dsh_plugin(payload: DshPluginInstallRequest):
419
865
  if not payload.accept_host_permissions:
420
866
  raise _dsh_error(DshPluginApprovalRequired("approval required"))
421
- host, item = await asyncio.to_thread(
422
- call_dsh,
423
- lambda bridge: bridge.install_plugin(payload.source, accept_host_permissions=True),
424
- )
425
- await studio.refresh_dsh_provider_registrations()
867
+
868
+ async def install(): # type: ignore[no-untyped-def]
869
+ return await asyncio.to_thread(
870
+ call_dsh,
871
+ lambda bridge: bridge.install_plugin(payload.source, accept_host_permissions=True),
872
+ write=True,
873
+ )
874
+
875
+ host, item = await studio.reconfigure_dsh_profile(install)
426
876
  return {"item": public_dsh(item, host)}
427
877
 
428
878
  async def mutate_dsh(plugin_name: str, operation: str):
@@ -435,29 +885,37 @@ def register_plugin_routes(app: FastAPI, studio: StudioService) -> None:
435
885
  return bridge.uninstall_plugin(plugin_name)
436
886
  return bridge.get_plugin(plugin_name)
437
887
 
438
- return await asyncio.to_thread(call_dsh, action)
888
+ if operation == "get":
889
+ return await asyncio.to_thread(call_dsh, action)
890
+
891
+ async def mutate(): # type: ignore[no-untyped-def]
892
+ return await asyncio.to_thread(call_dsh, action, write=True)
893
+
894
+ return await studio.reconfigure_dsh_profile(mutate)
439
895
 
440
896
  @app.post("/api/v1/plugin-ecosystems/dsh/plugins/{plugin_name:path}:enable")
441
897
  async def enable_dsh_plugin(plugin_name: str):
442
898
  host, item = await mutate_dsh(plugin_name, "enable")
443
- await studio.refresh_dsh_provider_registrations()
444
899
  return {"item": public_dsh(item, host)}
445
900
 
446
901
  @app.post("/api/v1/plugin-ecosystems/dsh/plugins/{plugin_name:path}:disable")
447
902
  async def disable_dsh_plugin(plugin_name: str):
448
903
  host, item = await mutate_dsh(plugin_name, "disable")
449
- await studio.refresh_dsh_provider_registrations()
450
904
  return {"item": public_dsh(item, host)}
451
905
 
452
906
  @app.post("/api/v1/plugin-ecosystems/dsh/plugins/{plugin_name:path}:update")
453
907
  async def update_dsh_plugin(plugin_name: str, payload: DshPluginUpdateRequest):
454
908
  if not payload.accept_host_permissions:
455
909
  raise _dsh_error(DshPluginApprovalRequired("approval required"))
456
- host, item = await asyncio.to_thread(
457
- call_dsh,
458
- lambda bridge: bridge.update_plugin(plugin_name, accept_host_permissions=True),
459
- )
460
- await studio.refresh_dsh_provider_registrations()
910
+
911
+ async def update(): # type: ignore[no-untyped-def]
912
+ return await asyncio.to_thread(
913
+ call_dsh,
914
+ lambda bridge: bridge.update_plugin(plugin_name, accept_host_permissions=True),
915
+ write=True,
916
+ )
917
+
918
+ host, item = await studio.reconfigure_dsh_profile(update)
461
919
  return {"item": public_dsh(item, host)}
462
920
 
463
921
  @app.get("/api/v1/plugin-ecosystems/dsh/plugins/{plugin_name:path}")
@@ -468,12 +926,12 @@ def register_plugin_routes(app: FastAPI, studio: StudioService) -> None:
468
926
  @app.delete("/api/v1/plugin-ecosystems/dsh/plugins/{plugin_name:path}", status_code=204)
469
927
  async def uninstall_dsh_plugin(plugin_name: str):
470
928
  await mutate_dsh(plugin_name, "uninstall")
471
- await studio.refresh_dsh_provider_registrations()
472
929
  return Response(status_code=204)
473
930
 
474
931
 
475
932
  __all__ = [
476
933
  "CodexPluginInstallRequest",
934
+ "CodexPluginSnapshotRequest",
477
935
  "DshPluginInstallRequest",
478
936
  "DshPluginUpdateRequest",
479
937
  "register_plugin_routes",