agentcore-cli 0.31.1__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 (655) hide show
  1. agentcore/__init__.py +1 -0
  2. agentcore/agent_inspector/NOTICE +9 -0
  3. agentcore/agent_inspector/favicon.svg +60 -0
  4. agentcore/agent_inspector/index.css +1 -0
  5. agentcore/agent_inspector/index.html +14 -0
  6. agentcore/agent_inspector/index.js +289 -0
  7. agentcore/assets/AGENTS.md +60 -0
  8. agentcore/assets/README.md +108 -0
  9. agentcore/assets/agents/AGENTS.md +218 -0
  10. agentcore/assets/cdk/.prettierrc +8 -0
  11. agentcore/assets/cdk/README.md +26 -0
  12. agentcore/assets/cdk/bin/cdk.ts +216 -0
  13. agentcore/assets/cdk/cdk.json +88 -0
  14. agentcore/assets/cdk/gitignore.template +9 -0
  15. agentcore/assets/cdk/jest.config.js +9 -0
  16. agentcore/assets/cdk/lib/cdk-stack.ts +291 -0
  17. agentcore/assets/cdk/npmignore.template +6 -0
  18. agentcore/assets/cdk/package.json +30 -0
  19. agentcore/assets/cdk/test/cdk.test.ts +31 -0
  20. agentcore/assets/cdk/tsconfig.json +28 -0
  21. agentcore/assets/container/python/Dockerfile +47 -0
  22. agentcore/assets/container/python/dockerignore.template +27 -0
  23. agentcore/assets/container/typescript/Dockerfile +25 -0
  24. agentcore/assets/container/typescript/dockerignore.template +24 -0
  25. agentcore/assets/datasets/predefined-v1.jsonl +3 -0
  26. agentcore/assets/datasets/simulated-v1.jsonl +3 -0
  27. agentcore/assets/evaluators/autoevals-lambda/execution-role-policy.json +15 -0
  28. agentcore/assets/evaluators/autoevals-lambda/lambda_function.py +37 -0
  29. agentcore/assets/evaluators/autoevals-lambda/pyproject.toml +22 -0
  30. agentcore/assets/evaluators/deepeval-lambda/execution-role-policy.json +15 -0
  31. agentcore/assets/evaluators/deepeval-lambda/lambda_function.py +29 -0
  32. agentcore/assets/evaluators/deepeval-lambda/pyproject.toml +19 -0
  33. agentcore/assets/evaluators/python-lambda/execution-role-policy.json +10 -0
  34. agentcore/assets/evaluators/python-lambda/lambda_function.py +19 -0
  35. agentcore/assets/evaluators/python-lambda/pyproject.toml +15 -0
  36. agentcore/assets/harness/invoke.py.template +74 -0
  37. agentcore/assets/mcp/python/README.md +27 -0
  38. agentcore/assets/mcp/python/pyproject.toml +22 -0
  39. agentcore/assets/mcp/python/server.py +117 -0
  40. agentcore/assets/mcp/python-lambda/README.md +22 -0
  41. agentcore/assets/mcp/python-lambda/handler.py +144 -0
  42. agentcore/assets/mcp/python-lambda/pyproject.toml +15 -0
  43. agentcore/assets/python/a2a/googleadk/base/README.md +22 -0
  44. agentcore/assets/python/a2a/googleadk/base/gitignore.template +41 -0
  45. agentcore/assets/python/a2a/googleadk/base/main.py +124 -0
  46. agentcore/assets/python/a2a/googleadk/base/model/__init__.py +1 -0
  47. agentcore/assets/python/a2a/googleadk/base/model/load.py +41 -0
  48. agentcore/assets/python/a2a/googleadk/base/pyproject.toml +22 -0
  49. agentcore/assets/python/a2a/langchain_langgraph/base/README.md +22 -0
  50. agentcore/assets/python/a2a/langchain_langgraph/base/gitignore.template +41 -0
  51. agentcore/assets/python/a2a/langchain_langgraph/base/main.py +144 -0
  52. agentcore/assets/python/a2a/langchain_langgraph/base/model/__init__.py +1 -0
  53. agentcore/assets/python/a2a/langchain_langgraph/base/model/load.py +123 -0
  54. agentcore/assets/python/a2a/langchain_langgraph/base/pyproject.toml +26 -0
  55. agentcore/assets/python/a2a/strands/base/README.md +22 -0
  56. agentcore/assets/python/a2a/strands/base/gitignore.template +41 -0
  57. agentcore/assets/python/a2a/strands/base/main.py +113 -0
  58. agentcore/assets/python/a2a/strands/base/model/__init__.py +1 -0
  59. agentcore/assets/python/a2a/strands/base/model/load.py +123 -0
  60. agentcore/assets/python/a2a/strands/base/pyproject.toml +23 -0
  61. agentcore/assets/python/a2a/strands/capabilities/memory/__init__.py +1 -0
  62. agentcore/assets/python/a2a/strands/capabilities/memory/session.py +46 -0
  63. agentcore/assets/python/agui/googleadk/base/README.md +30 -0
  64. agentcore/assets/python/agui/googleadk/base/gitignore.template +41 -0
  65. agentcore/assets/python/agui/googleadk/base/main.py +91 -0
  66. agentcore/assets/python/agui/googleadk/base/model/__init__.py +1 -0
  67. agentcore/assets/python/agui/googleadk/base/model/load.py +41 -0
  68. agentcore/assets/python/agui/googleadk/base/pyproject.toml +25 -0
  69. agentcore/assets/python/agui/langchain_langgraph/base/README.md +22 -0
  70. agentcore/assets/python/agui/langchain_langgraph/base/gitignore.template +41 -0
  71. agentcore/assets/python/agui/langchain_langgraph/base/main.py +130 -0
  72. agentcore/assets/python/agui/langchain_langgraph/base/model/__init__.py +1 -0
  73. agentcore/assets/python/agui/langchain_langgraph/base/model/load.py +123 -0
  74. agentcore/assets/python/agui/langchain_langgraph/base/pyproject.toml +31 -0
  75. agentcore/assets/python/agui/strands/base/README.md +22 -0
  76. agentcore/assets/python/agui/strands/base/gitignore.template +41 -0
  77. agentcore/assets/python/agui/strands/base/main.py +105 -0
  78. agentcore/assets/python/agui/strands/base/model/__init__.py +1 -0
  79. agentcore/assets/python/agui/strands/base/model/load.py +123 -0
  80. agentcore/assets/python/agui/strands/base/pyproject.toml +27 -0
  81. agentcore/assets/python/agui/strands/capabilities/memory/__init__.py +1 -0
  82. agentcore/assets/python/agui/strands/capabilities/memory/session.py +46 -0
  83. agentcore/assets/python/http/autogen/base/README.md +45 -0
  84. agentcore/assets/python/http/autogen/base/gitignore.template +41 -0
  85. agentcore/assets/python/http/autogen/base/main.py +145 -0
  86. agentcore/assets/python/http/autogen/base/mcp_client/__init__.py +1 -0
  87. agentcore/assets/python/http/autogen/base/mcp_client/client.py +28 -0
  88. agentcore/assets/python/http/autogen/base/model/__init__.py +1 -0
  89. agentcore/assets/python/http/autogen/base/model/load.py +136 -0
  90. agentcore/assets/python/http/autogen/base/pyproject.toml +34 -0
  91. agentcore/assets/python/http/bma/base/Dockerfile +41 -0
  92. agentcore/assets/python/http/bma/base/README.md +178 -0
  93. agentcore/assets/python/http/bma/base/client.py +200 -0
  94. agentcore/assets/python/http/bma/base/lifecycle/server.py +641 -0
  95. agentcore/assets/python/http/bma/base/otel/collector.yaml +69 -0
  96. agentcore/assets/python/http/bma/base/plugins/acr-report/.codex-plugin/plugin.json +6 -0
  97. agentcore/assets/python/http/bma/base/plugins/acr-report/skills/acr-report/SKILL.md +16 -0
  98. agentcore/assets/python/http/bma/base/policies/bma-acr-policy.json +11 -0
  99. agentcore/assets/python/http/bma/base/policies/bma-session-policy.json +35 -0
  100. agentcore/assets/python/http/bma/base/policies/bma-session-trust.json +20 -0
  101. agentcore/assets/python/http/bma/base/pyproject.toml +21 -0
  102. agentcore/assets/python/http/googleadk/base/README.md +45 -0
  103. agentcore/assets/python/http/googleadk/base/gitignore.template +41 -0
  104. agentcore/assets/python/http/googleadk/base/main.py +207 -0
  105. agentcore/assets/python/http/googleadk/base/mcp_client/__init__.py +1 -0
  106. agentcore/assets/python/http/googleadk/base/mcp_client/client.py +75 -0
  107. agentcore/assets/python/http/googleadk/base/model/__init__.py +1 -0
  108. agentcore/assets/python/http/googleadk/base/model/load.py +41 -0
  109. agentcore/assets/python/http/googleadk/base/pyproject.toml +24 -0
  110. agentcore/assets/python/http/langchain_langgraph/base/README.md +45 -0
  111. agentcore/assets/python/http/langchain_langgraph/base/gitignore.template +41 -0
  112. agentcore/assets/python/http/langchain_langgraph/base/main.py +227 -0
  113. agentcore/assets/python/http/langchain_langgraph/base/mcp_client/__init__.py +1 -0
  114. agentcore/assets/python/http/langchain_langgraph/base/mcp_client/client.py +79 -0
  115. agentcore/assets/python/http/langchain_langgraph/base/model/__init__.py +1 -0
  116. agentcore/assets/python/http/langchain_langgraph/base/model/load.py +123 -0
  117. agentcore/assets/python/http/langchain_langgraph/base/pyproject.toml +38 -0
  118. agentcore/assets/python/http/openaiagents/base/README.md +45 -0
  119. agentcore/assets/python/http/openaiagents/base/gitignore.template +41 -0
  120. agentcore/assets/python/http/openaiagents/base/main.py +200 -0
  121. agentcore/assets/python/http/openaiagents/base/mcp_client/__init__.py +1 -0
  122. agentcore/assets/python/http/openaiagents/base/mcp_client/client.py +74 -0
  123. agentcore/assets/python/http/openaiagents/base/model/__init__.py +1 -0
  124. agentcore/assets/python/http/openaiagents/base/model/load.py +37 -0
  125. agentcore/assets/python/http/openaiagents/base/pyproject.toml +21 -0
  126. agentcore/assets/python/http/strands/base/README.md +46 -0
  127. agentcore/assets/python/http/strands/base/gitignore.template +41 -0
  128. agentcore/assets/python/http/strands/base/main.py +714 -0
  129. agentcore/assets/python/http/strands/base/mcp_client/__init__.py +1 -0
  130. agentcore/assets/python/http/strands/base/mcp_client/client.py +116 -0
  131. agentcore/assets/python/http/strands/base/model/__init__.py +1 -0
  132. agentcore/assets/python/http/strands/base/model/load.py +239 -0
  133. agentcore/assets/python/http/strands/base/model/mantle_compat.py +21 -0
  134. agentcore/assets/python/http/strands/base/pyproject.toml +31 -0
  135. agentcore/assets/python/http/strands/base/skills/fetcher.py +279 -0
  136. agentcore/assets/python/http/strands/capabilities/execution-limits/hooks/execution_limits.py +54 -0
  137. agentcore/assets/python/http/strands/capabilities/memory/__init__.py +1 -0
  138. agentcore/assets/python/http/strands/capabilities/memory/session.py +47 -0
  139. agentcore/assets/python/http/strands/capabilities/payments/__init__.py +4 -0
  140. agentcore/assets/python/http/strands/capabilities/payments/payments.py +142 -0
  141. agentcore/assets/python/mcp/standalone/base/README.md +36 -0
  142. agentcore/assets/python/mcp/standalone/base/gitignore.template +41 -0
  143. agentcore/assets/python/mcp/standalone/base/main.py +83 -0
  144. agentcore/assets/python/mcp/standalone/base/pyproject.toml +16 -0
  145. agentcore/assets/typescript/.gitkeep +0 -0
  146. agentcore/assets/typescript/http/strands/base/README.md +42 -0
  147. agentcore/assets/typescript/http/strands/base/gitignore.template +22 -0
  148. agentcore/assets/typescript/http/strands/base/main.ts +149 -0
  149. agentcore/assets/typescript/http/strands/base/mcp_client/client.ts +11 -0
  150. agentcore/assets/typescript/http/strands/base/model/load.ts +102 -0
  151. agentcore/assets/typescript/http/strands/base/package.json +38 -0
  152. agentcore/assets/typescript/http/strands/base/tsconfig.json +19 -0
  153. agentcore/assets/typescript/http/strands/capabilities/memory/memory.ts +52 -0
  154. agentcore/assets/typescript/http/vercelai/base/README.md +42 -0
  155. agentcore/assets/typescript/http/vercelai/base/gitignore.template +22 -0
  156. agentcore/assets/typescript/http/vercelai/base/main.ts +70 -0
  157. agentcore/assets/typescript/http/vercelai/base/model/load.ts +121 -0
  158. agentcore/assets/typescript/http/vercelai/base/package.json +35 -0
  159. agentcore/assets/typescript/http/vercelai/base/tsconfig.json +19 -0
  160. agentcore/aws/__init__.py +263 -0
  161. agentcore/aws/_aws_errors.py +72 -0
  162. agentcore/aws/_http.py +176 -0
  163. agentcore/aws/_util.py +37 -0
  164. agentcore/aws/account.py +165 -0
  165. agentcore/aws/agentcore.py +971 -0
  166. agentcore/aws/agentcore_ab_tests.py +230 -0
  167. agentcore/aws/agentcore_batch_evaluation.py +227 -0
  168. agentcore/aws/agentcore_config_bundles.py +220 -0
  169. agentcore/aws/agentcore_control.py +994 -0
  170. agentcore/aws/agentcore_datasets.py +222 -0
  171. agentcore/aws/agentcore_harness.py +330 -0
  172. agentcore/aws/agentcore_payments.py +430 -0
  173. agentcore/aws/agentcore_recommendation.py +140 -0
  174. agentcore/aws/agui_parser.py +131 -0
  175. agentcore/aws/agui_types.py +342 -0
  176. agentcore/aws/api_client.py +87 -0
  177. agentcore/aws/arn.py +18 -0
  178. agentcore/aws/aws_context.py +23 -0
  179. agentcore/aws/bedrock.py +44 -0
  180. agentcore/aws/bedrock_agent.py +129 -0
  181. agentcore/aws/bedrock_import.py +252 -0
  182. agentcore/aws/bedrock_import_types.py +111 -0
  183. agentcore/aws/cloudwatch.py +136 -0
  184. agentcore/aws/connect_shell.py +266 -0
  185. agentcore/aws/iam.py +41 -0
  186. agentcore/aws/partition.py +58 -0
  187. agentcore/aws/policy_generation.py +116 -0
  188. agentcore/aws/region.py +54 -0
  189. agentcore/aws/retry.py +27 -0
  190. agentcore/aws/shell_framer.py +136 -0
  191. agentcore/aws/stage_endpoint.py +39 -0
  192. agentcore/aws/target_region.py +54 -0
  193. agentcore/aws/transaction_search.py +97 -0
  194. agentcore/cdk/__init__.py +10 -0
  195. agentcore/cdk/constants.py +13 -0
  196. agentcore/cdk/local_cdk_project.py +48 -0
  197. agentcore/cdk/toolkit.py +706 -0
  198. agentcore/cli/__init__.py +0 -0
  199. agentcore/cli/commands/__init__.py +0 -0
  200. agentcore/cli/commands/_jobs_common.py +39 -0
  201. agentcore/cli/commands/_run_wizards.py +639 -0
  202. agentcore/cli/commands/add/__init__.py +37 -0
  203. agentcore/cli/commands/add/_commander.py +52 -0
  204. agentcore/cli/commands/add/_common.py +47 -0
  205. agentcore/cli/commands/add/agent_wizard.py +528 -0
  206. agentcore/cli/commands/add/auth_options.py +154 -0
  207. agentcore/cli/commands/add/skill_action.py +105 -0
  208. agentcore/cli/commands/add/skill_command.py +87 -0
  209. agentcore/cli/commands/add/tool_action.py +160 -0
  210. agentcore/cli/commands/add/tool_command.py +117 -0
  211. agentcore/cli/commands/add/validate.py +333 -0
  212. agentcore/cli/commands/capacity_provider/__init__.py +86 -0
  213. agentcore/cli/commands/capacity_provider/action.py +114 -0
  214. agentcore/cli/commands/capacity_provider/constants.py +22 -0
  215. agentcore/cli/commands/config.py +91 -0
  216. agentcore/cli/commands/config_bundle.py +251 -0
  217. agentcore/cli/commands/create/__init__.py +643 -0
  218. agentcore/cli/commands/create/action.py +406 -0
  219. agentcore/cli/commands/create/dependencies.py +91 -0
  220. agentcore/cli/commands/create/harness_validate.py +82 -0
  221. agentcore/cli/commands/create/validate.py +195 -0
  222. agentcore/cli/commands/create/wizard.py +127 -0
  223. agentcore/cli/commands/dataset.py +119 -0
  224. agentcore/cli/commands/deploy/__init__.py +31 -0
  225. agentcore/cli/commands/deploy/_guards.py +25 -0
  226. agentcore/cli/commands/deploy/actions.py +840 -0
  227. agentcore/cli/commands/deploy/command.py +349 -0
  228. agentcore/cli/commands/deploy/progress.py +115 -0
  229. agentcore/cli/commands/deploy/types.py +68 -0
  230. agentcore/cli/commands/deploy/utils.py +43 -0
  231. agentcore/cli/commands/deploy/validate.py +21 -0
  232. agentcore/cli/commands/dev/__init__.py +5 -0
  233. agentcore/cli/commands/dev/_deps.py +50 -0
  234. agentcore/cli/commands/dev/browser_mode.py +270 -0
  235. agentcore/cli/commands/dev/command.py +450 -0
  236. agentcore/cli/commands/dev/terminal_mode.py +379 -0
  237. agentcore/cli/commands/exec/__init__.py +29 -0
  238. agentcore/cli/commands/exec/action.py +442 -0
  239. agentcore/cli/commands/exec/command.py +206 -0
  240. agentcore/cli/commands/exec/types.py +35 -0
  241. agentcore/cli/commands/export/__init__.py +114 -0
  242. agentcore/cli/commands/export/constants.py +21 -0
  243. agentcore/cli/commands/export/fetch_harness_spec.py +234 -0
  244. agentcore/cli/commands/export/harness_action.py +385 -0
  245. agentcore/cli/commands/export/harness_mapper.py +868 -0
  246. agentcore/cli/commands/export/harness_resolver.py +95 -0
  247. agentcore/cli/commands/export/types.py +90 -0
  248. agentcore/cli/commands/export/wizard.py +97 -0
  249. agentcore/cli/commands/feedback/__init__.py +69 -0
  250. agentcore/cli/commands/feedback/action.py +30 -0
  251. agentcore/cli/commands/feedback/consent_prompt.py +35 -0
  252. agentcore/cli/commands/feedback/wizard.py +49 -0
  253. agentcore/cli/commands/fetch/__init__.py +69 -0
  254. agentcore/cli/commands/fetch/action.py +62 -0
  255. agentcore/cli/commands/help.py +65 -0
  256. agentcore/cli/commands/import_/__init__.py +167 -0
  257. agentcore/cli/commands/import_/_js.py +72 -0
  258. agentcore/cli/commands/import_/actions.py +457 -0
  259. agentcore/cli/commands/import_/constants.py +45 -0
  260. agentcore/cli/commands/import_/import_evaluator.py +140 -0
  261. agentcore/cli/commands/import_/import_gateway.py +520 -0
  262. agentcore/cli/commands/import_/import_memory.py +128 -0
  263. agentcore/cli/commands/import_/import_online_eval.py +165 -0
  264. agentcore/cli/commands/import_/import_pipeline.py +145 -0
  265. agentcore/cli/commands/import_/import_runtime.py +214 -0
  266. agentcore/cli/commands/import_/import_utils.py +410 -0
  267. agentcore/cli/commands/import_/phase1_update.py +110 -0
  268. agentcore/cli/commands/import_/phase2_import.py +206 -0
  269. agentcore/cli/commands/import_/resource_import.py +228 -0
  270. agentcore/cli/commands/import_/template_utils.py +148 -0
  271. agentcore/cli/commands/import_/types.py +150 -0
  272. agentcore/cli/commands/import_/yaml_parser.py +265 -0
  273. agentcore/cli/commands/init.py +196 -0
  274. agentcore/cli/commands/invoke/__init__.py +32 -0
  275. agentcore/cli/commands/invoke/_deps.py +73 -0
  276. agentcore/cli/commands/invoke/action.py +840 -0
  277. agentcore/cli/commands/invoke/command.py +490 -0
  278. agentcore/cli/commands/invoke/constants.py +40 -0
  279. agentcore/cli/commands/invoke/guards.py +23 -0
  280. agentcore/cli/commands/invoke/interactive.py +604 -0
  281. agentcore/cli/commands/invoke/resolve.py +149 -0
  282. agentcore/cli/commands/invoke/resolve_prompt.py +60 -0
  283. agentcore/cli/commands/invoke/types.py +61 -0
  284. agentcore/cli/commands/invoke/validate.py +33 -0
  285. agentcore/cli/commands/job_actions.py +239 -0
  286. agentcore/cli/commands/job_history.py +380 -0
  287. agentcore/cli/commands/logs/__init__.py +53 -0
  288. agentcore/cli/commands/logs/action.py +159 -0
  289. agentcore/cli/commands/logs/filter_pattern.py +17 -0
  290. agentcore/cli/commands/logs/guards.py +51 -0
  291. agentcore/cli/commands/logs_evals.py +42 -0
  292. agentcore/cli/commands/package.py +118 -0
  293. agentcore/cli/commands/remove/__init__.py +172 -0
  294. agentcore/cli/commands/remove/skill_command.py +131 -0
  295. agentcore/cli/commands/remove/tool_command.py +59 -0
  296. agentcore/cli/commands/run.py +808 -0
  297. agentcore/cli/commands/run_ingest.py +97 -0
  298. agentcore/cli/commands/shared/__init__.py +0 -0
  299. agentcore/cli/commands/shared/arn_utils.py +9 -0
  300. agentcore/cli/commands/shared/filesystem_utils.py +421 -0
  301. agentcore/cli/commands/shared/header_utils.py +87 -0
  302. agentcore/cli/commands/shared/indexed_key_parser.py +76 -0
  303. agentcore/cli/commands/shared/lifecycle_utils.py +72 -0
  304. agentcore/cli/commands/shared/region_utils.py +20 -0
  305. agentcore/cli/commands/shared/vpc_utils.py +99 -0
  306. agentcore/cli/commands/status/__init__.py +30 -0
  307. agentcore/cli/commands/status/_guards.py +25 -0
  308. agentcore/cli/commands/status/action.py +741 -0
  309. agentcore/cli/commands/status/command.py +321 -0
  310. agentcore/cli/commands/status/constants.py +36 -0
  311. agentcore/cli/commands/status/format_knowledge_base.py +111 -0
  312. agentcore/cli/commands/telemetry.py +79 -0
  313. agentcore/cli/commands/traces/__init__.py +155 -0
  314. agentcore/cli/commands/traces/action.py +123 -0
  315. agentcore/cli/commands/update/__init__.py +63 -0
  316. agentcore/cli/commands/update/action.py +164 -0
  317. agentcore/cli/commands/validate.py +165 -0
  318. agentcore/cli/constants.py +96 -0
  319. agentcore/cli/errors.py +118 -0
  320. agentcore/cli/external_requirements/__init__.py +67 -0
  321. agentcore/cli/external_requirements/checks.py +280 -0
  322. agentcore/cli/external_requirements/detect.py +55 -0
  323. agentcore/cli/external_requirements/versions.py +57 -0
  324. agentcore/cli/groups.py +23 -0
  325. agentcore/cli/interactive.py +85 -0
  326. agentcore/cli/main.py +137 -0
  327. agentcore/cli/naming.py +11 -0
  328. agentcore/cli/notices.py +42 -0
  329. agentcore/cli/project.py +34 -0
  330. agentcore/cli/run_command.py +27 -0
  331. agentcore/cli/tree.py +135 -0
  332. agentcore/cli/update_notifier.py +123 -0
  333. agentcore/cli/variadic.py +50 -0
  334. agentcore/cloudformation/__init__.py +84 -0
  335. agentcore/cloudformation/bootstrap.py +64 -0
  336. agentcore/cloudformation/logical_ids.py +37 -0
  337. agentcore/cloudformation/outputs.py +566 -0
  338. agentcore/cloudformation/stack_discovery.py +75 -0
  339. agentcore/cloudformation/stack_events.py +107 -0
  340. agentcore/cloudformation/stack_status.py +98 -0
  341. agentcore/cloudformation/types.py +44 -0
  342. agentcore/lib/__init__.py +68 -0
  343. agentcore/lib/constants.py +77 -0
  344. agentcore/lib/dependency_management/__init__.py +23 -0
  345. agentcore/lib/dependency_management/messages.py +92 -0
  346. agentcore/lib/dependency_management/plan.py +98 -0
  347. agentcore/lib/dependency_management/semver.py +137 -0
  348. agentcore/lib/dependency_management/sync.py +139 -0
  349. agentcore/lib/dependency_management/types.py +56 -0
  350. agentcore/lib/errors/__init__.py +5 -0
  351. agentcore/lib/errors/types.py +352 -0
  352. agentcore/lib/errors/validation.py +121 -0
  353. agentcore/lib/packaging/__init__.py +81 -0
  354. agentcore/lib/packaging/build_args.py +23 -0
  355. agentcore/lib/packaging/build_context.py +26 -0
  356. agentcore/lib/packaging/build_context_dockerignore.py +45 -0
  357. agentcore/lib/packaging/container.py +95 -0
  358. agentcore/lib/packaging/helpers.py +289 -0
  359. agentcore/lib/packaging/node.py +153 -0
  360. agentcore/lib/packaging/python.py +135 -0
  361. agentcore/lib/packaging/types.py +69 -0
  362. agentcore/lib/packaging/uv.py +45 -0
  363. agentcore/lib/result.py +104 -0
  364. agentcore/lib/schemas/__init__.py +1 -0
  365. agentcore/lib/schemas/io/__init__.py +27 -0
  366. agentcore/lib/schemas/io/config_io.py +458 -0
  367. agentcore/lib/schemas/io/global_config.py +239 -0
  368. agentcore/lib/schemas/io/path_resolver.py +132 -0
  369. agentcore/lib/secrets/__init__.py +18 -0
  370. agentcore/lib/secrets/cipher.py +70 -0
  371. agentcore/lib/secrets/key_provider.py +163 -0
  372. agentcore/lib/secrets/sensitive_keys.py +55 -0
  373. agentcore/lib/time_constants.py +4 -0
  374. agentcore/lib/utils/__init__.py +47 -0
  375. agentcore/lib/utils/aws_account.py +15 -0
  376. agentcore/lib/utils/credentials.py +68 -0
  377. agentcore/lib/utils/dotenv.py +32 -0
  378. agentcore/lib/utils/env.py +105 -0
  379. agentcore/lib/utils/json_format.py +29 -0
  380. agentcore/lib/utils/json_rpc.py +22 -0
  381. agentcore/lib/utils/platform.py +33 -0
  382. agentcore/lib/utils/polling.py +86 -0
  383. agentcore/lib/utils/subprocess.py +135 -0
  384. agentcore/lib/utils/time_parser.py +48 -0
  385. agentcore/lib/utils/validation.py +106 -0
  386. agentcore/logging/__init__.py +10 -0
  387. agentcore/logging/_common.py +77 -0
  388. agentcore/logging/cdk_io_host.py +36 -0
  389. agentcore/logging/create_logger.py +107 -0
  390. agentcore/logging/dev_logger.py +63 -0
  391. agentcore/logging/exec_logger.py +159 -0
  392. agentcore/logging/invoke_logger.py +154 -0
  393. agentcore/logging/remove_logger.py +95 -0
  394. agentcore/operations/__init__.py +0 -0
  395. agentcore/operations/agent/__init__.py +0 -0
  396. agentcore/operations/agent/config_bundle_defaults.py +31 -0
  397. agentcore/operations/agent/generate/__init__.py +28 -0
  398. agentcore/operations/agent/generate/schema_mapper.py +319 -0
  399. agentcore/operations/agent/generate/types.py +172 -0
  400. agentcore/operations/agent/generate/write_agent_to_project.py +67 -0
  401. agentcore/operations/agent/import_/__init__.py +31 -0
  402. agentcore/operations/agent/import_/base_translator.py +449 -0
  403. agentcore/operations/agent/import_/constants.py +23 -0
  404. agentcore/operations/agent/import_/execute.py +127 -0
  405. agentcore/operations/agent/import_/langgraph_translator.py +294 -0
  406. agentcore/operations/agent/import_/pyproject_generator.py +73 -0
  407. agentcore/operations/agent/import_/strands_translator.py +289 -0
  408. agentcore/operations/config_bundle/__init__.py +1 -0
  409. agentcore/operations/config_bundle/bundle_name_variants.py +9 -0
  410. agentcore/operations/config_bundle/diff_versions.py +52 -0
  411. agentcore/operations/config_bundle/resolve_bundle.py +65 -0
  412. agentcore/operations/connectors/__init__.py +3 -0
  413. agentcore/operations/connectors/translators.py +63 -0
  414. agentcore/operations/dataset/__init__.py +21 -0
  415. agentcore/operations/dataset/delete.py +7 -0
  416. agentcore/operations/dataset/publish.py +16 -0
  417. agentcore/operations/dataset/pull.py +21 -0
  418. agentcore/operations/dataset/push.py +201 -0
  419. agentcore/operations/dataset/resolve_dataset.py +65 -0
  420. agentcore/operations/dataset/status.py +18 -0
  421. agentcore/operations/dataset/wait.py +25 -0
  422. agentcore/operations/deploy/__init__.py +152 -0
  423. agentcore/operations/deploy/backfill_vpc_id.py +90 -0
  424. agentcore/operations/deploy/change_detection.py +84 -0
  425. agentcore/operations/deploy/constants.py +58 -0
  426. agentcore/operations/deploy/dependency_sync.py +105 -0
  427. agentcore/operations/deploy/ensure_target.py +30 -0
  428. agentcore/operations/deploy/gateway_status.py +44 -0
  429. agentcore/operations/deploy/managed_memory_notice.py +36 -0
  430. agentcore/operations/deploy/payment_connector_authorization.py +106 -0
  431. agentcore/operations/deploy/post_deploy_datasets.py +96 -0
  432. agentcore/operations/deploy/post_deploy_knowledge_bases.py +104 -0
  433. agentcore/operations/deploy/post_deploy_observability.py +28 -0
  434. agentcore/operations/deploy/post_deploy_online_evals.py +60 -0
  435. agentcore/operations/deploy/pre_deploy_identity.py +505 -0
  436. agentcore/operations/deploy/preflight.py +385 -0
  437. agentcore/operations/deploy/region_override.py +45 -0
  438. agentcore/operations/deploy/teardown.py +153 -0
  439. agentcore/operations/dev/__init__.py +61 -0
  440. agentcore/operations/dev/_http.py +79 -0
  441. agentcore/operations/dev/_server.py +165 -0
  442. agentcore/operations/dev/codezip_dev_server.py +151 -0
  443. agentcore/operations/dev/config.py +128 -0
  444. agentcore/operations/dev/constants.py +9 -0
  445. agentcore/operations/dev/container_dev_server.py +237 -0
  446. agentcore/operations/dev/container_runtime.py +37 -0
  447. agentcore/operations/dev/dev_server.py +244 -0
  448. agentcore/operations/dev/gateway_env.py +25 -0
  449. agentcore/operations/dev/invoke.py +214 -0
  450. agentcore/operations/dev/invoke_a2a.py +204 -0
  451. agentcore/operations/dev/invoke_agui.py +88 -0
  452. agentcore/operations/dev/invoke_mcp.py +145 -0
  453. agentcore/operations/dev/invoke_types.py +30 -0
  454. agentcore/operations/dev/load_dev_env.py +26 -0
  455. agentcore/operations/dev/memory_env.py +19 -0
  456. agentcore/operations/dev/otel/__init__.py +5 -0
  457. agentcore/operations/dev/otel/collector.py +234 -0
  458. agentcore/operations/dev/otel/transforms.py +331 -0
  459. agentcore/operations/dev/payment_env.py +50 -0
  460. agentcore/operations/dev/server.py +28 -0
  461. agentcore/operations/dev/sse_transform.py +30 -0
  462. agentcore/operations/dev/utils.py +152 -0
  463. agentcore/operations/dev/web_ui/__init__.py +31 -0
  464. agentcore/operations/dev/web_ui/constants.py +25 -0
  465. agentcore/operations/dev/web_ui/handlers/__init__.py +36 -0
  466. agentcore/operations/dev/web_ui/handlers/_common.py +36 -0
  467. agentcore/operations/dev/web_ui/handlers/_deployed.py +37 -0
  468. agentcore/operations/dev/web_ui/handlers/a2a_proxy.py +37 -0
  469. agentcore/operations/dev/web_ui/handlers/cloudwatch_traces.py +71 -0
  470. agentcore/operations/dev/web_ui/handlers/harness_invocation.py +89 -0
  471. agentcore/operations/dev/web_ui/handlers/harness_utils.py +95 -0
  472. agentcore/operations/dev/web_ui/handlers/invocations.py +327 -0
  473. agentcore/operations/dev/web_ui/handlers/mcp_proxy.py +119 -0
  474. agentcore/operations/dev/web_ui/handlers/memory.py +84 -0
  475. agentcore/operations/dev/web_ui/handlers/resources.py +351 -0
  476. agentcore/operations/dev/web_ui/handlers/start.py +182 -0
  477. agentcore/operations/dev/web_ui/handlers/status.py +25 -0
  478. agentcore/operations/dev/web_ui/handlers/traces.py +50 -0
  479. agentcore/operations/dev/web_ui/run_web_ui.py +60 -0
  480. agentcore/operations/dev/web_ui/web_server.py +297 -0
  481. agentcore/operations/eval/__init__.py +8 -0
  482. agentcore/operations/eval/list_eval_runs.py +18 -0
  483. agentcore/operations/eval/logs_eval.py +119 -0
  484. agentcore/operations/eval/pause_resume.py +90 -0
  485. agentcore/operations/eval/run_eval.py +354 -0
  486. agentcore/operations/eval/shared/__init__.py +0 -0
  487. agentcore/operations/eval/shared/dataset_loader.py +68 -0
  488. agentcore/operations/eval/shared/dataset_session_provider.py +122 -0
  489. agentcore/operations/eval/shared/evaluator_runner.py +89 -0
  490. agentcore/operations/eval/shared/scenario_executor.py +71 -0
  491. agentcore/operations/eval/shared/span_collector.py +255 -0
  492. agentcore/operations/eval/storage.py +67 -0
  493. agentcore/operations/feedback/__init__.py +21 -0
  494. agentcore/operations/feedback/aperture_client.py +98 -0
  495. agentcore/operations/feedback/build_payload.py +97 -0
  496. agentcore/operations/feedback/constants.py +26 -0
  497. agentcore/operations/feedback/submit_feedback.py +150 -0
  498. agentcore/operations/fetch_access/__init__.py +36 -0
  499. agentcore/operations/fetch_access/_target.py +17 -0
  500. agentcore/operations/fetch_access/fetch_gateway_token.py +75 -0
  501. agentcore/operations/fetch_access/fetch_harness_token.py +72 -0
  502. agentcore/operations/fetch_access/fetch_runtime_token.py +76 -0
  503. agentcore/operations/fetch_access/list_agents.py +18 -0
  504. agentcore/operations/fetch_access/list_gateways.py +26 -0
  505. agentcore/operations/fetch_access/list_harnesses.py +23 -0
  506. agentcore/operations/fetch_access/oauth_token.py +162 -0
  507. agentcore/operations/fetch_access/types.py +34 -0
  508. agentcore/operations/harness/__init__.py +1 -0
  509. agentcore/operations/harness/orphan.py +84 -0
  510. agentcore/operations/harness/skill_utils.py +56 -0
  511. agentcore/operations/identity/__init__.py +33 -0
  512. agentcore/operations/identity/api_key_credential_provider.py +68 -0
  513. agentcore/operations/identity/oauth2_credential_provider.py +95 -0
  514. agentcore/operations/ingest/__init__.py +184 -0
  515. agentcore/operations/init/__init__.py +3 -0
  516. agentcore/operations/init/files.py +59 -0
  517. agentcore/operations/insights/__init__.py +21 -0
  518. agentcore/operations/insights/insights_storage.py +67 -0
  519. agentcore/operations/insights/run_insights.py +148 -0
  520. agentcore/operations/invoke/__init__.py +5 -0
  521. agentcore/operations/invoke/resolve_agent_context.py +85 -0
  522. agentcore/operations/jobs/__init__.py +38 -0
  523. agentcore/operations/jobs/ab_test/__init__.py +0 -0
  524. agentcore/operations/jobs/ab_test/build_options.py +126 -0
  525. agentcore/operations/jobs/ab_test/format.py +121 -0
  526. agentcore/operations/jobs/ab_test/handler.py +412 -0
  527. agentcore/operations/jobs/ab_test/promote.py +142 -0
  528. agentcore/operations/jobs/ab_test/resolve.py +221 -0
  529. agentcore/operations/jobs/batch_evaluation/__init__.py +0 -0
  530. agentcore/operations/jobs/batch_evaluation/build_source.py +68 -0
  531. agentcore/operations/jobs/batch_evaluation/dataset_phase1.py +95 -0
  532. agentcore/operations/jobs/batch_evaluation/format.py +58 -0
  533. agentcore/operations/jobs/batch_evaluation/handler.py +203 -0
  534. agentcore/operations/jobs/insights/__init__.py +0 -0
  535. agentcore/operations/jobs/insights/format.py +65 -0
  536. agentcore/operations/jobs/insights/handler.py +178 -0
  537. agentcore/operations/jobs/recommendation/__init__.py +0 -0
  538. agentcore/operations/jobs/recommendation/apply_to_bundle.py +76 -0
  539. agentcore/operations/jobs/recommendation/build_config.py +271 -0
  540. agentcore/operations/jobs/recommendation/fetch_session_spans.py +93 -0
  541. agentcore/operations/jobs/recommendation/format.py +77 -0
  542. agentcore/operations/jobs/recommendation/handler.py +331 -0
  543. agentcore/operations/jobs/shared/__init__.py +0 -0
  544. agentcore/operations/jobs/shared/constants.py +85 -0
  545. agentcore/operations/jobs/shared/engine.py +187 -0
  546. agentcore/operations/jobs/shared/format.py +104 -0
  547. agentcore/operations/jobs/shared/region.py +34 -0
  548. agentcore/operations/jobs/shared/resolve_agent_state.py +30 -0
  549. agentcore/operations/jobs/shared/storage.py +117 -0
  550. agentcore/operations/jobs/shared/wait.py +30 -0
  551. agentcore/operations/knowledge_base/__init__.py +33 -0
  552. agentcore/operations/knowledge_base/connector_config.py +105 -0
  553. agentcore/operations/knowledge_base/hydrate_data_sources.py +59 -0
  554. agentcore/operations/mcp/__init__.py +4 -0
  555. agentcore/operations/memory/__init__.py +13 -0
  556. agentcore/operations/memory/_records.py +72 -0
  557. agentcore/operations/memory/list_memory_records.py +45 -0
  558. agentcore/operations/memory/retrieve_memory_records.py +52 -0
  559. agentcore/operations/node/__init__.py +15 -0
  560. agentcore/operations/node/setup.py +36 -0
  561. agentcore/operations/python/__init__.py +17 -0
  562. agentcore/operations/python/setup.py +47 -0
  563. agentcore/operations/resolve_agent.py +159 -0
  564. agentcore/operations/session/__init__.py +86 -0
  565. agentcore/operations/traces/__init__.py +29 -0
  566. agentcore/operations/traces/get_trace.py +202 -0
  567. agentcore/operations/traces/insights_query.py +74 -0
  568. agentcore/operations/traces/list_traces.py +46 -0
  569. agentcore/operations/traces/trace_url.py +25 -0
  570. agentcore/operations/traces/types.py +55 -0
  571. agentcore/primitives/__init__.py +0 -0
  572. agentcore/primitives/_gateway_target_wizard.py +293 -0
  573. agentcore/primitives/_gateway_validation.py +442 -0
  574. agentcore/primitives/_harness_cli.py +557 -0
  575. agentcore/primitives/_harness_validation.py +163 -0
  576. agentcore/primitives/_harness_wizard.py +726 -0
  577. agentcore/primitives/_knowledge_base_wizard.py +259 -0
  578. agentcore/primitives/_payment_wizard.py +331 -0
  579. agentcore/primitives/_policy_form.py +160 -0
  580. agentcore/primitives/agent.py +817 -0
  581. agentcore/primitives/auth_utils.py +77 -0
  582. agentcore/primitives/base.py +178 -0
  583. agentcore/primitives/capacity_provider.py +501 -0
  584. agentcore/primitives/config_bundle.py +329 -0
  585. agentcore/primitives/credential.py +387 -0
  586. agentcore/primitives/credential_utils.py +45 -0
  587. agentcore/primitives/dataset.py +211 -0
  588. agentcore/primitives/deployed_gateways.py +34 -0
  589. agentcore/primitives/evaluator.py +909 -0
  590. agentcore/primitives/gateway.py +496 -0
  591. agentcore/primitives/gateway_target.py +988 -0
  592. agentcore/primitives/harness.py +706 -0
  593. agentcore/primitives/knowledge_base.py +477 -0
  594. agentcore/primitives/memory.py +387 -0
  595. agentcore/primitives/online_eval_config.py +365 -0
  596. agentcore/primitives/online_insights.py +275 -0
  597. agentcore/primitives/payment_connector.py +427 -0
  598. agentcore/primitives/payment_eligible.py +20 -0
  599. agentcore/primitives/payment_manager.py +605 -0
  600. agentcore/primitives/payment_validation.py +68 -0
  601. agentcore/primitives/policy.py +622 -0
  602. agentcore/primitives/policy_engine.py +358 -0
  603. agentcore/primitives/registry.py +56 -0
  604. agentcore/primitives/runtime_endpoint.py +361 -0
  605. agentcore/primitives/secret_flag_warning.py +17 -0
  606. agentcore/schema/__init__.py +14 -0
  607. agentcore/schema/_zod.py +395 -0
  608. agentcore/schema/constants.py +306 -0
  609. agentcore/schema/schemas/__init__.py +40 -0
  610. agentcore/schema/schemas/agent_env.py +545 -0
  611. agentcore/schema/schemas/agentcore_project.py +530 -0
  612. agentcore/schema/schemas/auth.py +286 -0
  613. agentcore/schema/schemas/aws_targets.py +72 -0
  614. agentcore/schema/schemas/connections.py +187 -0
  615. agentcore/schema/schemas/deployed_state.py +322 -0
  616. agentcore/schema/schemas/mcp.py +650 -0
  617. agentcore/schema/schemas/mcp_defs.py +54 -0
  618. agentcore/schema/schemas/primitives/__init__.py +52 -0
  619. agentcore/schema/schemas/primitives/ab_test.py +162 -0
  620. agentcore/schema/schemas/primitives/capacity_provider.py +214 -0
  621. agentcore/schema/schemas/primitives/config_bundle.py +48 -0
  622. agentcore/schema/schemas/primitives/dataset.py +55 -0
  623. agentcore/schema/schemas/primitives/evaluator.py +171 -0
  624. agentcore/schema/schemas/primitives/harness.py +710 -0
  625. agentcore/schema/schemas/primitives/knowledge_base.py +90 -0
  626. agentcore/schema/schemas/primitives/memory.py +113 -0
  627. agentcore/schema/schemas/primitives/online_eval_config.py +77 -0
  628. agentcore/schema/schemas/primitives/payment.py +114 -0
  629. agentcore/schema/schemas/primitives/policy.py +83 -0
  630. agentcore/schema/schemas/primitives/tags.py +50 -0
  631. agentcore/schema/schemas/zod_util.py +5 -0
  632. agentcore/schema/types/__init__.py +3 -0
  633. agentcore/schema/types/path.py +16 -0
  634. agentcore/templates/__init__.py +115 -0
  635. agentcore/templates/_handlebars.py +782 -0
  636. agentcore/templates/_js.py +164 -0
  637. agentcore/templates/base_renderer.py +107 -0
  638. agentcore/templates/cdk_renderer.py +129 -0
  639. agentcore/templates/evaluator_renderer.py +39 -0
  640. agentcore/templates/gateway_target_renderer.py +69 -0
  641. agentcore/templates/llm_context/README.md +16 -0
  642. agentcore/templates/llm_context/agentcore.ts +685 -0
  643. agentcore/templates/llm_context/aws-targets.ts +51 -0
  644. agentcore/templates/profiles.py +151 -0
  645. agentcore/templates/render.py +92 -0
  646. agentcore/templates/renderers.py +83 -0
  647. agentcore/templates/schema_assets.py +23 -0
  648. agentcore/templates/template_root.py +28 -0
  649. agentcore/templates/types.py +192 -0
  650. agentcore_cli-0.31.1.dist-info/METADATA +84 -0
  651. agentcore_cli-0.31.1.dist-info/RECORD +655 -0
  652. agentcore_cli-0.31.1.dist-info/WHEEL +4 -0
  653. agentcore_cli-0.31.1.dist-info/entry_points.txt +2 -0
  654. agentcore_cli-0.31.1.dist-info/licenses/LICENSE +175 -0
  655. agentcore_cli-0.31.1.dist-info/licenses/NOTICE +88 -0
@@ -0,0 +1,706 @@
1
+ """CDK toolkit driver (port of upstream ``src/cli/cdk/toolkit-lib``).
2
+
3
+ Upstream drives ``@aws-cdk/toolkit-lib`` in-process. The Python port keeps the vended TypeScript
4
+ CDK app and shells out to the CDK CLI the project already depends on
5
+ (``agentcore/cdk/node_modules/.bin/cdk``, falling back to ``npx cdk``):
6
+
7
+ ===================================== ==========================================================
8
+ toolkit-lib call (upstream) cdk CLI invocation (here)
9
+ ===================================== ==========================================================
10
+ ``fromCdkApp('node dist/bin/cdk.js')`` ``--app "node dist/bin/cdk.js"`` with ``cwd`` = project dir
11
+ ``synth(source, {validateStacks})`` ``cdk synth --app ... --output cdk.out --quiet --validation``
12
+ ``fromAssemblyDirectory(dir)`` ``--app <assembly dir>`` for every later operation
13
+ ``deploy(src, {stacks})`` ``cdk deploy <patterns> --require-approval never --ci``
14
+ ``diff(src, {stacks})`` ``cdk diff <patterns>``
15
+ ``destroy(src, {stacks})`` ``cdk destroy <patterns> --force``
16
+ ``list(src, {stacks})`` ``cdk list <patterns>``
17
+ ``bootstrap(envs, {parameters})`` ``cdk bootstrap <envs> --bootstrap-customer-key`` (or
18
+ ``--bootstrap-kms-key-id <id>``)
19
+ ===================================== ==========================================================
20
+
21
+ The region override is forwarded through the child environment (``AWS_REGION`` /
22
+ ``AWS_DEFAULT_REGION``) exactly as upstream does for the app subprocess; a profile goes through
23
+ ``AWS_PROFILE``. Context comes from the project's ``cdk.json`` (the CLI reads it from ``cwd``),
24
+ just as toolkit-lib reads it for ``fromCdkApp``. No hotswap: deploys are full change-set deploys,
25
+ which is toolkit-lib's default.
26
+
27
+ Progress: toolkit-lib streams stack activity through its IoHost (``CDK_TOOLKIT_I5501..I5901``).
28
+ Here, while ``cdk deploy`` runs, CloudFormation stack events are polled with boto3 and turned into
29
+ the same message codes, so the IoHost contract (``SwitchableIoHost``) is unchanged.
30
+ """
31
+
32
+ from __future__ import annotations
33
+
34
+ import json
35
+ import os
36
+ import re
37
+ import threading
38
+ import time
39
+ from collections.abc import Callable, Mapping, Sequence
40
+ from dataclasses import dataclass, field
41
+ from datetime import UTC, datetime
42
+ from pathlib import Path
43
+ from typing import Any, Protocol
44
+
45
+ from agentcore.cdk.constants import CDK_APP_ENTRY, CDK_PROJECT_DIR
46
+ from agentcore.cli.errors import is_changeset_in_progress_error
47
+ from agentcore.cloudformation.stack_events import StackEventPoller, describe_failures, format_stack_event
48
+ from agentcore.lib.constants import CONFIG_DIR
49
+ from agentcore.lib.utils.platform import is_windows
50
+ from agentcore.lib.utils.subprocess import SubprocessResult, run_subprocess_capture
51
+
52
+ # Command used to execute the CDK app (matches "app" in cdk.json; requires `tsc` build first).
53
+ CDK_APP_COMMAND = "node"
54
+
55
+ # Default assembly output directory (relative to the CDK project directory).
56
+ CDK_OUT_DIR = "cdk.out"
57
+
58
+ # toolkit-lib message codes relevant for deploy progress display.
59
+ DEPLOY_MESSAGE_CODES = frozenset(
60
+ {
61
+ "CDK_TOOLKIT_I5501", # Stack monitoring start
62
+ "CDK_TOOLKIT_I5502", # Stack activity event (resource events with progress)
63
+ "CDK_TOOLKIT_I5503", # Stack monitoring end
64
+ "CDK_TOOLKIT_I5900", # Deployment results
65
+ "CDK_TOOLKIT_I5901", # Deployment success
66
+ }
67
+ )
68
+
69
+ # Retry policy for transient changeset conflicts (identical to upstream).
70
+ DEPLOY_MAX_RETRIES = 3
71
+ DEPLOY_BASE_DELAY_S = 5.0
72
+
73
+
74
+ class StackSelectionStrategy:
75
+ """String constants mirroring toolkit-lib's ``StackSelectionStrategy`` enum."""
76
+
77
+ ALL_STACKS = "all-stacks"
78
+ MAIN_ASSEMBLY = "main-assembly"
79
+ ONLY_SINGLE = "only-single"
80
+ PATTERN_MATCH = "pattern-match"
81
+ PATTERN_MUST_MATCH = "pattern-must-match"
82
+ PATTERN_MUST_MATCH_SINGLE = "pattern-must-match-single"
83
+
84
+
85
+ @dataclass(frozen=True)
86
+ class StackSelector:
87
+ strategy: str = StackSelectionStrategy.PATTERN_MUST_MATCH
88
+ patterns: tuple[str, ...] = ()
89
+
90
+
91
+ def pattern_must_match(*patterns: str) -> StackSelector:
92
+ return StackSelector(StackSelectionStrategy.PATTERN_MUST_MATCH, tuple(patterns))
93
+
94
+
95
+ # ---------------------------------------------------------------------------
96
+ # IoHost (port of toolkit-lib/types.ts)
97
+ # ---------------------------------------------------------------------------
98
+
99
+
100
+ @dataclass
101
+ class IoMessage:
102
+ code: str
103
+ message: str
104
+ level: str = "info"
105
+ time: datetime = field(default_factory=lambda: datetime.now(UTC))
106
+ action: str | None = None
107
+ data: Any = None
108
+
109
+
110
+ class IoHost(Protocol):
111
+ def notify(self, msg: IoMessage) -> None: ...
112
+
113
+
114
+ class _SilentIoHost:
115
+ """Suppresses all CDK output."""
116
+
117
+ def notify(self, msg: IoMessage) -> None:
118
+ return None
119
+
120
+
121
+ silent_io_host: IoHost = _SilentIoHost()
122
+
123
+
124
+ @dataclass
125
+ class ResourceProgress:
126
+ completed: int
127
+ total: int
128
+
129
+
130
+ @dataclass
131
+ class DeployMessage:
132
+ """CDK message filtered for deploy progress display (data pre-extracted)."""
133
+
134
+ code: str
135
+ message: str
136
+ level: str
137
+ timestamp: datetime
138
+ progress: ResourceProgress | None = None
139
+ outputs: dict[str, str] | None = None
140
+ stack_arn: str | None = None
141
+
142
+
143
+ _PROGRESS_RE = re.compile(r"\|\s*(\d+)/(\d+)\s*\|")
144
+
145
+
146
+ def extract_progress_from_message(message: str) -> ResourceProgress | None:
147
+ """I5502 lines look like ``StackName | X/Y | timestamp | STATUS | ...``."""
148
+ match = _PROGRESS_RE.search(message)
149
+ return ResourceProgress(int(match.group(1)), int(match.group(2))) if match else None
150
+
151
+
152
+ RawMessageCallback = Callable[[str, str, str, Any], None]
153
+
154
+
155
+ @dataclass
156
+ class SwitchableIoHost:
157
+ """IoHost that starts silent; ``set_verbose(True)`` enables message capture."""
158
+
159
+ verbose: bool = False
160
+ on_message: Callable[[DeployMessage], None] | None = None
161
+ on_raw_message: RawMessageCallback | None = None
162
+
163
+ @property
164
+ def io_host(self) -> IoHost:
165
+ return self
166
+
167
+ def set_verbose(self, verbose: bool) -> None:
168
+ self.verbose = verbose
169
+
170
+ def set_on_message(self, callback: Callable[[DeployMessage], None] | None) -> None:
171
+ self.on_message = callback
172
+
173
+ def set_on_raw_message(self, callback: RawMessageCallback | None) -> None:
174
+ self.on_raw_message = callback
175
+
176
+ def notify(self, msg: IoMessage) -> None:
177
+ if not self.verbose:
178
+ return
179
+ code = msg.code or "UNKNOWN"
180
+ text = msg.message if isinstance(msg.message, str) else ""
181
+ if self.on_raw_message:
182
+ self.on_raw_message(code, msg.level or "info", text, msg.data)
183
+ if self.on_message and msg.code in DEPLOY_MESSAGE_CODES:
184
+ deploy_message = DeployMessage(
185
+ code=msg.code,
186
+ message=text,
187
+ level=msg.level or "info",
188
+ timestamp=msg.time,
189
+ progress=extract_progress_from_message(text),
190
+ )
191
+ if msg.code == "CDK_TOOLKIT_I5900" and isinstance(msg.data, Mapping):
192
+ if msg.data.get("outputs"):
193
+ deploy_message.outputs = dict(msg.data["outputs"])
194
+ if msg.data.get("stackArn"):
195
+ deploy_message.stack_arn = msg.data["stackArn"]
196
+ self.on_message(deploy_message)
197
+
198
+
199
+ def create_switchable_io_host() -> SwitchableIoHost:
200
+ return SwitchableIoHost()
201
+
202
+
203
+ # ---------------------------------------------------------------------------
204
+ # Driver
205
+ # ---------------------------------------------------------------------------
206
+
207
+
208
+ @dataclass(frozen=True)
209
+ class SynthOutput:
210
+ stack_names: list[str]
211
+ assembly_directory: str
212
+
213
+
214
+ class CdkCommandError(RuntimeError):
215
+ """A cdk subprocess failed. The message carries the CLI's own error text for classification."""
216
+
217
+ def __init__(self, message: str, result: SubprocessResult | None = None):
218
+ super().__init__(message)
219
+ self.result = result
220
+
221
+
222
+ def _with_error_context(context: str, err: BaseException) -> BaseException:
223
+ """Prefix the error message with ``CDK <context> failed:`` (upstream mutates ``err.message``)."""
224
+ message = f"CDK {context} failed: {err}"
225
+ if isinstance(err, CdkCommandError):
226
+ return CdkCommandError(message, err.result)
227
+ wrapped = RuntimeError(message)
228
+ wrapped.__cause__ = err
229
+ return wrapped
230
+
231
+
232
+ _ANSI_RE = re.compile(r"\x1b\[[0-9;]*[a-zA-Z]")
233
+
234
+
235
+ def _strip_ansi(text: str) -> str:
236
+ return _ANSI_RE.sub("", text)
237
+
238
+
239
+ def _failure_text(result: SubprocessResult) -> str:
240
+ """The meaningful part of a failed cdk run's output."""
241
+ text = _strip_ansi((result.stderr or "").strip() or (result.stdout or "").strip())
242
+ if not text:
243
+ reason = f"code {result.code}" if result.code is not None else f"signal {result.signal}"
244
+ return f"cdk exited with {reason}"
245
+ # Prefer the CLI's explicit error lines ("❌ ...", "Error: ...") when present.
246
+ lines = [line for line in text.splitlines() if line.strip()]
247
+ errorish = [line for line in lines if line.lstrip().startswith(("❌", "Error", "error"))]
248
+ if errorish:
249
+ tail = lines[lines.index(errorish[0]) :]
250
+ return "\n".join(tail[-40:])
251
+ return "\n".join(lines[-40:])
252
+
253
+
254
+ def resolve_cdk_command(project_dir: str | os.PathLike[str]) -> tuple[str, list[str]]:
255
+ """The project's own CDK CLI (``node_modules/.bin/cdk``), else ``npx cdk``."""
256
+ bin_dir = Path(project_dir) / "node_modules" / ".bin"
257
+ candidates = ["cdk.cmd", "cdk"] if is_windows else ["cdk"]
258
+ for name in candidates:
259
+ path = bin_dir / name
260
+ if path.exists():
261
+ return str(path), []
262
+ return "npx", ["cdk"]
263
+
264
+
265
+ Runner = Callable[..., SubprocessResult]
266
+
267
+
268
+ class CdkToolkitWrapper:
269
+ """Thin driver around the CDK CLI, pre-configured for the vended AgentCore CDK project."""
270
+
271
+ def __init__(
272
+ self,
273
+ project_dir: str | os.PathLike[str] | None = None,
274
+ *,
275
+ io_host: IoHost | None = None,
276
+ profile: str | None = None,
277
+ region: str | None = None,
278
+ runner: Runner | None = None,
279
+ poll_interval: float = 2.0,
280
+ sleep: Callable[[float], None] = time.sleep,
281
+ ) -> None:
282
+ self.project_dir = str(project_dir or Path(os.getcwd()) / CONFIG_DIR / CDK_PROJECT_DIR)
283
+ self.io_host: IoHost = io_host or silent_io_host
284
+ self.profile = profile
285
+ self.region = region
286
+ self._runner = runner
287
+ self.poll_interval = poll_interval
288
+ self._sleep = sleep
289
+ self._command: tuple[str, list[str]] | None = None
290
+ self._env: dict[str, str] | None = None
291
+ self._assembly_dir: str | None = None
292
+ self._stack_names: list[str] = []
293
+
294
+ # -- setup -------------------------------------------------------------------------------
295
+
296
+ def get_project_dir(self) -> str:
297
+ return self.project_dir
298
+
299
+ def get_cdk_app_command(self) -> str:
300
+ return f"{CDK_APP_COMMAND} {CDK_APP_ENTRY}"
301
+
302
+ def initialize(self) -> None:
303
+ """Resolve the CDK CLI and the child environment. Must be called before any operation."""
304
+ try:
305
+ profile = self.profile or os.environ.get("AWS_PROFILE")
306
+ region = self.region or os.environ.get("AWS_REGION") or os.environ.get("AWS_DEFAULT_REGION")
307
+ env = dict(os.environ)
308
+ if region:
309
+ env["AWS_REGION"] = region
310
+ env["AWS_DEFAULT_REGION"] = region
311
+ if profile:
312
+ env["AWS_PROFILE"] = profile
313
+ # The CLI is driven programmatically: no update notices, no interactive prompts.
314
+ env.setdefault("CDK_DISABLE_VERSION_CHECK", "1")
315
+ self._env = env
316
+ self._command = resolve_cdk_command(self.project_dir)
317
+ except Exception as exc: # pragma: no cover - defensive, mirrors withErrorContext
318
+ raise _with_error_context(f"initialize (project: {self.project_dir})", exc) from exc
319
+
320
+ def _ensure_initialized(self) -> tuple[tuple[str, list[str]], dict[str, str]]:
321
+ if self._command is None or self._env is None:
322
+ raise RuntimeError("CdkToolkitWrapper not initialized. Call initialize() first.")
323
+ return self._command, self._env
324
+
325
+ def _run(self, args: Sequence[str]) -> SubprocessResult:
326
+ (command, prefix), env = self._ensure_initialized()
327
+ runner = self._runner or run_subprocess_capture
328
+ return runner(command, [*prefix, *args], cwd=self.project_dir, env=env)
329
+
330
+ def _app_args(self) -> list[str]:
331
+ """``--app`` for an operation: the synthesized assembly if any (no re-synth), else the app."""
332
+ return ["--app", self._assembly_dir or self.get_cdk_app_command()]
333
+
334
+ @staticmethod
335
+ def _selection_args(stacks: StackSelector | None) -> list[str]:
336
+ if stacks is None or stacks.strategy == StackSelectionStrategy.ALL_STACKS:
337
+ return ["--all"]
338
+ if stacks.patterns:
339
+ return list(stacks.patterns)
340
+ return ["--all"] if stacks.strategy == StackSelectionStrategy.MAIN_ASSEMBLY else []
341
+
342
+ def _notify(self, code: str, message: str, level: str = "info", data: Any = None, action: str | None = None):
343
+ self.io_host.notify(IoMessage(code=code, message=message, level=level, data=data, action=action))
344
+
345
+ def _forward_output(self, result: SubprocessResult, action: str) -> None:
346
+ """Pass the CLI's own output lines to the IoHost (visible only to verbose/raw listeners)."""
347
+ for stream, level in ((result.stdout, "info"), (result.stderr, "info")):
348
+ for line in (stream or "").splitlines():
349
+ if line.strip():
350
+ self._notify("CDK_TOOLKIT_I0000", _strip_ansi(line), level, action=action)
351
+
352
+ # -- synth -------------------------------------------------------------------------------
353
+
354
+ def synth(self) -> SynthOutput:
355
+ """Synthesize the app; later deploy/diff/destroy reuse the produced assembly."""
356
+ self._ensure_initialized()
357
+ self.dispose_synth_result()
358
+ out_dir = str(Path(self.project_dir) / CDK_OUT_DIR)
359
+ result = self._run(
360
+ [
361
+ "synth",
362
+ "--app",
363
+ self.get_cdk_app_command(),
364
+ "--output",
365
+ out_dir,
366
+ "--quiet",
367
+ "--validation",
368
+ "--no-notices",
369
+ ]
370
+ )
371
+ self._forward_output(result, "synth")
372
+ if result.code != 0:
373
+ raise _with_error_context("synth", CdkCommandError(_failure_text(result), result))
374
+ self._assembly_dir = out_dir
375
+ self._stack_names = read_assembly_stack_names(out_dir)
376
+ return SynthOutput(stack_names=list(self._stack_names), assembly_directory=out_dir)
377
+
378
+ def dispose_synth_result(self) -> None:
379
+ self._assembly_dir = None
380
+ self._stack_names = []
381
+
382
+ def dispose(self) -> None:
383
+ """Release state. The CLI holds no locks once it exits, so there is nothing else to free."""
384
+ self.dispose_synth_result()
385
+ self._command = None
386
+ self._env = None
387
+
388
+ # -- deploy ------------------------------------------------------------------------------
389
+
390
+ def deploy(self, stacks: StackSelector | None = None) -> None:
391
+ """Deploy, retrying transient changeset conflicts (5s, 10s backoff, 3 attempts)."""
392
+ self._ensure_initialized()
393
+ last_error: BaseException | None = None
394
+ for attempt in range(DEPLOY_MAX_RETRIES):
395
+ try:
396
+ self._deploy_once(stacks)
397
+ return
398
+ except Exception as exc:
399
+ last_error = _with_error_context("deploy", exc)
400
+ if is_changeset_in_progress_error(last_error) and attempt < DEPLOY_MAX_RETRIES - 1:
401
+ delay = DEPLOY_BASE_DELAY_S * (2**attempt)
402
+ self._notify(
403
+ "CDK_TOOLKIT_W0001",
404
+ f"Changeset operation in progress, retrying in {delay:g}s "
405
+ f"(attempt {attempt + 1}/{DEPLOY_MAX_RETRIES})...",
406
+ level="warn",
407
+ action="deploy",
408
+ )
409
+ self._sleep(delay)
410
+ continue
411
+ raise last_error from exc
412
+ raise last_error or RuntimeError("Deploy failed after retries") # pragma: no cover
413
+
414
+ def _deploy_once(self, stacks: StackSelector | None) -> None:
415
+ outputs_file = str(Path(self._assembly_dir or Path(self.project_dir) / CDK_OUT_DIR) / "agentcore-outputs.json")
416
+ args = [
417
+ "deploy",
418
+ *self._selection_args(stacks),
419
+ *self._app_args(),
420
+ "--require-approval",
421
+ "never",
422
+ "--ci",
423
+ "--progress",
424
+ "events",
425
+ "--no-notices",
426
+ "--outputs-file",
427
+ outputs_file,
428
+ ]
429
+ stack_names = self._target_stack_names(stacks)
430
+ region = (self._env or {}).get("AWS_REGION")
431
+ pollers = [StackEventPoller(region=region, stack_name=name) for name in stack_names] if region else []
432
+ totals = {name: self._template_resource_count(name) for name in stack_names}
433
+ completed: dict[str, set[str]] = {name: set() for name in stack_names}
434
+
435
+ holder: dict[str, Any] = {}
436
+
437
+ def run() -> None:
438
+ try:
439
+ holder["result"] = self._run(args)
440
+ except BaseException as exc: # noqa: BLE001 - re-raised on the calling thread
441
+ holder["error"] = exc
442
+
443
+ started = False
444
+ thread = threading.Thread(target=run, name="cdk-deploy", daemon=True)
445
+ thread.start()
446
+
447
+ def drain() -> None:
448
+ nonlocal started
449
+ for poller in pollers:
450
+ for event in poller.poll():
451
+ if not started:
452
+ started = True
453
+ self._notify("CDK_TOOLKIT_I5501", f"Deploying {poller.stack_name}", action="deploy")
454
+ logical = event.get("LogicalResourceId") or ""
455
+ status = event.get("ResourceStatus") or ""
456
+ if logical != poller.stack_name and status.endswith("_COMPLETE"):
457
+ completed[poller.stack_name].add(logical)
458
+ total = max(totals.get(poller.stack_name, 0), len(completed[poller.stack_name]))
459
+ line = format_stack_event(poller.stack_name, event, len(completed[poller.stack_name]), total)
460
+ level = "error" if status.endswith("FAILED") else "info"
461
+ self._notify("CDK_TOOLKIT_I5502", line, level, data=event, action="deploy")
462
+
463
+ while thread.is_alive():
464
+ thread.join(self.poll_interval)
465
+ drain()
466
+ drain()
467
+
468
+ if "error" in holder:
469
+ raise holder["error"]
470
+ result: SubprocessResult = holder["result"]
471
+ self._forward_output(result, "deploy")
472
+ if started:
473
+ self._notify("CDK_TOOLKIT_I5503", "Stack monitoring complete", action="deploy")
474
+ if result.code != 0:
475
+ message = _failure_text(result)
476
+ failures = describe_failures([f for p in pollers for f in p.failures])
477
+ if failures:
478
+ message = f"{message}\n\nResource failures:\n{failures}"
479
+ raise CdkCommandError(message, result)
480
+
481
+ stack_outputs = _read_outputs_file(outputs_file)
482
+ for name in stack_names or list(stack_outputs):
483
+ outputs = stack_outputs.get(name, {})
484
+ self._notify(
485
+ "CDK_TOOLKIT_I5900",
486
+ f"✅ {name}",
487
+ data={"outputs": outputs, "stackName": name},
488
+ action="deploy",
489
+ )
490
+ self._notify("CDK_TOOLKIT_I5901", "Deployment success", action="deploy")
491
+
492
+ def _target_stack_names(self, stacks: StackSelector | None) -> list[str]:
493
+ if stacks is not None and stacks.patterns and not any(ch in p for p in stacks.patterns for ch in "*?"):
494
+ return list(stacks.patterns)
495
+ return list(self._stack_names)
496
+
497
+ def _template_resource_count(self, stack_name: str) -> int:
498
+ if not self._assembly_dir:
499
+ return 0
500
+ template = read_assembly_template(self._assembly_dir, stack_name)
501
+ return len((template or {}).get("Resources") or {})
502
+
503
+ # -- destroy / diff / list / bootstrap ---------------------------------------------------
504
+
505
+ def destroy(self, stacks: StackSelector | None = None) -> None:
506
+ self._ensure_initialized()
507
+ result = self._run(["destroy", *self._selection_args(stacks), *self._app_args(), "--force", "--no-notices"])
508
+ self._forward_output(result, "destroy")
509
+ if result.code != 0:
510
+ raise _with_error_context("destroy", CdkCommandError(_failure_text(result), result))
511
+
512
+ def diff(self, stacks: StackSelector | None = None) -> None:
513
+ """Run ``cdk diff``; per-stack blocks go out as I4002, the summary line as I4001."""
514
+ self._ensure_initialized()
515
+ # Without --fail, `cdk diff` exits 0 whether or not there are differences.
516
+ result = self._run(["diff", *self._selection_args(stacks), *self._app_args(), "--no-notices"])
517
+ if result.code != 0:
518
+ raise _with_error_context("diff", CdkCommandError(_failure_text(result), result))
519
+ for code, text in split_diff_output((result.stderr or "") + "\n" + (result.stdout or "")):
520
+ self._notify(code, text, action="diff")
521
+
522
+ def list(self, stacks: StackSelector | None = None) -> list[str]:
523
+ self._ensure_initialized()
524
+ result = self._run(["list", *self._selection_args(stacks), *self._app_args(), "--no-notices"])
525
+ if result.code != 0:
526
+ raise _with_error_context("list", CdkCommandError(_failure_text(result), result))
527
+ return [line.strip() for line in (result.stdout or "").splitlines() if line.strip()]
528
+
529
+ def bootstrap(self, environments: Sequence[str], kms_key_id: str | None = None) -> None:
530
+ """Bootstrap the CDK toolkit stack; creates a KMS CMK for the staging bucket by default."""
531
+ self._ensure_initialized()
532
+ params = ["--bootstrap-kms-key-id", kms_key_id] if kms_key_id else ["--bootstrap-customer-key"]
533
+ result = self._run(["bootstrap", *environments, *self._app_args(), *params, "--ci", "--no-notices"])
534
+ self._forward_output(result, "bootstrap")
535
+ if result.code != 0:
536
+ message = _failure_text(result)
537
+ for env in environments:
538
+ message += explain_bootstrap_failure(env, self.profile)
539
+ raise _with_error_context("bootstrap", CdkCommandError(message, result))
540
+
541
+
542
+ BOOTSTRAP_STACK_NAME = "CDKToolkit"
543
+
544
+
545
+ def explain_bootstrap_failure(environment: str, profile: str | None = None) -> str:
546
+ """Why the CDKToolkit stack failed, from its CloudFormation events (best effort).
547
+
548
+ The cdk CLI often reports only "NoStack: CloudFormationStack object does not hold a stack";
549
+ the actionable reason (e.g. missing iam:CreateRole) is in the stack events.
550
+ """
551
+ match = re.match(r"^aws://([^/]+)/(.+)$", environment)
552
+ if not match:
553
+ return ""
554
+ region = match.group(2)
555
+ try:
556
+ from agentcore.aws.account import create_aws_client
557
+
558
+ cfn = create_aws_client("cloudformation", region)
559
+ status = cfn.describe_stacks(StackName=BOOTSTRAP_STACK_NAME)["Stacks"][0]["StackStatus"]
560
+ events = cfn.describe_stack_events(StackName=BOOTSTRAP_STACK_NAME)["StackEvents"]
561
+ except Exception: # noqa: BLE001 - diagnostics only; the original error still surfaces
562
+ return ""
563
+
564
+ reasons: list[str] = []
565
+ for event in events: # newest first; stop at the start of the latest attempt
566
+ if (
567
+ event.get("LogicalResourceId") == BOOTSTRAP_STACK_NAME
568
+ and event.get("ResourceStatus", "").endswith("_IN_PROGRESS")
569
+ and event.get("ResourceStatusReason") == "User Initiated"
570
+ ):
571
+ break
572
+ if event.get("ResourceStatus", "").endswith("_FAILED") and event.get("ResourceStatusReason"):
573
+ line = f"{event['LogicalResourceId']}: {event['ResourceStatusReason']}"
574
+ if line not in reasons:
575
+ reasons.append(line)
576
+
577
+ lines: list[str] = []
578
+ if reasons:
579
+ lines.append(f"\n\nCloudFormation reported for {BOOTSTRAP_STACK_NAME} in {region}:")
580
+ lines.extend(f" - {r}" for r in reasons[:3])
581
+ if any("iam:" in r and "not authorized" in r for r in reasons):
582
+ lines.append(
583
+ "\nYour AWS identity cannot create IAM roles, which CDK bootstrap (and deploy) requires. "
584
+ "Use a role with IAM permissions, e.g. AdministratorAccess in a sandbox account."
585
+ )
586
+ if status in ("ROLLBACK_COMPLETE", "ROLLBACK_FAILED", "DELETE_FAILED"):
587
+ profile_flag = f" --profile {profile}" if profile else ""
588
+ lines.append(
589
+ f"\nThe {BOOTSTRAP_STACK_NAME} stack is in {status} and must be deleted before retrying:\n"
590
+ f" aws cloudformation delete-stack --stack-name {BOOTSTRAP_STACK_NAME} --region {region}{profile_flag}"
591
+ )
592
+ return "\n".join(lines)
593
+
594
+
595
+ def create_cdk_toolkit_wrapper(
596
+ project_dir: str | os.PathLike[str] | None = None,
597
+ *,
598
+ io_host: IoHost | None = None,
599
+ profile: str | None = None,
600
+ region: str | None = None,
601
+ **kwargs: Any,
602
+ ) -> CdkToolkitWrapper:
603
+ """Create and initialize a :class:`CdkToolkitWrapper`."""
604
+ wrapper = CdkToolkitWrapper(project_dir, io_host=io_host, profile=profile, region=region, **kwargs)
605
+ wrapper.initialize()
606
+ return wrapper
607
+
608
+
609
+ # ---------------------------------------------------------------------------
610
+ # Cloud assembly helpers
611
+ # ---------------------------------------------------------------------------
612
+
613
+
614
+ def _read_json(path: Path) -> Any:
615
+ try:
616
+ return json.loads(path.read_text(encoding="utf-8"))
617
+ except (OSError, ValueError):
618
+ return None
619
+
620
+
621
+ def _stack_artifacts(assembly_dir: str | os.PathLike[str]) -> list[tuple[str, dict[str, Any]]]:
622
+ manifest = _read_json(Path(assembly_dir) / "manifest.json") or {}
623
+ artifacts = manifest.get("artifacts") or {}
624
+ return [
625
+ (artifact_id, artifact)
626
+ for artifact_id, artifact in artifacts.items()
627
+ if isinstance(artifact, dict) and artifact.get("type") == "aws:cloudformation:stack"
628
+ ]
629
+
630
+
631
+ def read_assembly_stack_names(assembly_dir: str | os.PathLike[str]) -> list[str]:
632
+ """Stack names in a synthesized cloud assembly (``manifest.json``), in manifest order."""
633
+ names = []
634
+ for artifact_id, artifact in _stack_artifacts(assembly_dir):
635
+ props = artifact.get("properties") or {}
636
+ names.append(props.get("stackName") or artifact.get("displayName") or artifact_id)
637
+ return names
638
+
639
+
640
+ def read_assembly_template(assembly_dir: str | os.PathLike[str], stack_name: str) -> dict[str, Any] | None:
641
+ for artifact_id, artifact in _stack_artifacts(assembly_dir):
642
+ props = artifact.get("properties") or {}
643
+ if (props.get("stackName") or artifact_id) == stack_name:
644
+ template_file = props.get("templateFile") or f"{artifact_id}.template.json"
645
+ return _read_json(Path(assembly_dir) / template_file)
646
+ return None
647
+
648
+
649
+ def _read_outputs_file(path: str) -> dict[str, dict[str, str]]:
650
+ data = _read_json(Path(path))
651
+ if not isinstance(data, dict):
652
+ return {}
653
+ return {k: {str(ok): str(ov) for ok, ov in v.items()} for k, v in data.items() if isinstance(v, dict)}
654
+
655
+
656
+ _DIFF_SUMMARY_RE = re.compile(r"Number of stacks with differences:\s*\d+")
657
+
658
+
659
+ def split_diff_output(text: str) -> list[tuple[str, str]]:
660
+ """Split ``cdk diff`` output into per-stack blocks (I4002) and the summary line (I4001)."""
661
+ clean = _strip_ansi(text)
662
+ messages: list[tuple[str, str]] = []
663
+ current: list[str] = []
664
+ summary: str | None = None
665
+ for line in clean.splitlines():
666
+ if _DIFF_SUMMARY_RE.search(line):
667
+ summary = line.strip()
668
+ continue
669
+ if line.startswith("Stack "):
670
+ if any(item.strip() for item in current):
671
+ messages.append(("CDK_TOOLKIT_I4002", "\n".join(current).strip("\n")))
672
+ current = [line]
673
+ continue
674
+ if current:
675
+ current.append(line)
676
+ if any(item.strip() for item in current):
677
+ messages.append(("CDK_TOOLKIT_I4002", "\n".join(current).strip("\n")))
678
+ if summary:
679
+ messages.append(("CDK_TOOLKIT_I4001", summary))
680
+ return messages
681
+
682
+
683
+ __all__ = [
684
+ "CDK_APP_COMMAND",
685
+ "CDK_OUT_DIR",
686
+ "DEPLOY_MESSAGE_CODES",
687
+ "CdkCommandError",
688
+ "CdkToolkitWrapper",
689
+ "DeployMessage",
690
+ "IoHost",
691
+ "IoMessage",
692
+ "ResourceProgress",
693
+ "StackSelectionStrategy",
694
+ "StackSelector",
695
+ "SwitchableIoHost",
696
+ "SynthOutput",
697
+ "create_cdk_toolkit_wrapper",
698
+ "create_switchable_io_host",
699
+ "extract_progress_from_message",
700
+ "pattern_must_match",
701
+ "read_assembly_stack_names",
702
+ "read_assembly_template",
703
+ "resolve_cdk_command",
704
+ "silent_io_host",
705
+ "split_diff_output",
706
+ ]