redeploy 0.2.78__tar.gz → 0.2.80__tar.gz

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 (308) hide show
  1. {redeploy-0.2.78/redeploy.egg-info → redeploy-0.2.80}/PKG-INFO +83 -14
  2. redeploy-0.2.78/PKG-INFO → redeploy-0.2.80/README.md +78 -37
  3. {redeploy-0.2.78 → redeploy-0.2.80}/pyproject.toml +21 -7
  4. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/__init__.py +1 -1
  5. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/analyze/checkers/binary.py +27 -2
  6. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/analyze/checkers/reference.py +13 -1
  7. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/apply/executor.py +157 -21
  8. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/apply/handlers.py +174 -26
  9. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/apply/progress.py +25 -10
  10. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/__init__.py +10 -0
  11. redeploy-0.2.80/redeploy/cli/commands/db_data.py +158 -0
  12. redeploy-0.2.80/redeploy/cli/commands/deploy_cmd.py +323 -0
  13. redeploy-0.2.80/redeploy/cli/commands/fleet_cmd.py +135 -0
  14. redeploy-0.2.80/redeploy/cli/commands/hash_cmd.py +61 -0
  15. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/plan_apply_run.py +29 -3
  16. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/plan_apply_shared.py +2 -0
  17. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/run_cmd.py +39 -4
  18. redeploy-0.2.80/redeploy/cli/commands/sync_git.py +94 -0
  19. redeploy-0.2.80/redeploy/deploy_watch.py +264 -0
  20. redeploy-0.2.80/redeploy/detect/builtin/templates.yaml +215 -0
  21. redeploy-0.2.80/redeploy/fleet_ops.py +215 -0
  22. redeploy-0.2.80/redeploy/gitsync.py +380 -0
  23. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/heal/hint_provider.py +6 -0
  24. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/heal.py +7 -0
  25. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/mcp_server.py +175 -24
  26. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/models/enums.py +4 -0
  27. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/models/plan.py +17 -0
  28. redeploy-0.2.80/redeploy/pg_sync.py +198 -0
  29. redeploy-0.2.80/redeploy/source_hash.py +170 -0
  30. redeploy-0.2.80/redeploy/templates/process_control_template.yaml +164 -0
  31. redeploy-0.2.78/README.md → redeploy-0.2.80/redeploy.egg-info/PKG-INFO +106 -7
  32. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy.egg-info/SOURCES.txt +15 -45
  33. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy.egg-info/requires.txt +4 -6
  34. redeploy-0.2.80/tests/test_gitsync_pg_hash.py +416 -0
  35. redeploy-0.2.80/tests/test_mcp_server.py +97 -0
  36. redeploy-0.2.80/tests/test_parallel_groups.py +252 -0
  37. {redeploy-0.2.78 → redeploy-0.2.80}/tests/test_prompt_llm.py +15 -5
  38. redeploy-0.2.78/redeploy/tests/__init__.py +0 -0
  39. redeploy-0.2.78/redeploy/tests/test_analyze.py +0 -193
  40. redeploy-0.2.78/redeploy/tests/test_audit.py +0 -244
  41. redeploy-0.2.78/redeploy/tests/test_cli.py +0 -328
  42. redeploy-0.2.78/redeploy/tests/test_data_sync.py +0 -117
  43. redeploy-0.2.78/redeploy/tests/test_devices_display.py +0 -33
  44. redeploy-0.2.78/redeploy/tests/test_discovery.py +0 -231
  45. redeploy-0.2.78/redeploy/tests/test_discovery_probe.py +0 -45
  46. redeploy-0.2.78/redeploy/tests/test_dsl.py +0 -354
  47. redeploy-0.2.78/redeploy/tests/test_examples.py +0 -518
  48. redeploy-0.2.78/redeploy/tests/test_executor.py +0 -732
  49. redeploy-0.2.78/redeploy/tests/test_fleet.py +0 -525
  50. redeploy-0.2.78/redeploy/tests/test_git_integration.py +0 -325
  51. redeploy-0.2.78/redeploy/tests/test_heal.py +0 -182
  52. redeploy-0.2.78/redeploy/tests/test_heal_decider.py +0 -91
  53. redeploy-0.2.78/redeploy/tests/test_hooks.py +0 -123
  54. redeploy-0.2.78/redeploy/tests/test_iac.py +0 -461
  55. redeploy-0.2.78/redeploy/tests/test_iac_compose_contract.py +0 -181
  56. redeploy-0.2.78/redeploy/tests/test_iac_docker_compose_contract.py +0 -172
  57. redeploy-0.2.78/redeploy/tests/test_manifest.py +0 -338
  58. redeploy-0.2.78/redeploy/tests/test_markpact_compiler.py +0 -147
  59. redeploy-0.2.78/redeploy/tests/test_markpact_parser.py +0 -93
  60. redeploy-0.2.78/redeploy/tests/test_models.py +0 -224
  61. redeploy-0.2.78/redeploy/tests/test_observe.py +0 -369
  62. redeploy-0.2.78/redeploy/tests/test_parse.py +0 -268
  63. redeploy-0.2.78/redeploy/tests/test_patterns.py +0 -287
  64. redeploy-0.2.78/redeploy/tests/test_plan_apply_report.py +0 -91
  65. redeploy-0.2.78/redeploy/tests/test_plan_apply_shared.py +0 -21
  66. redeploy-0.2.78/redeploy/tests/test_planner_edge.py +0 -350
  67. redeploy-0.2.78/redeploy/tests/test_plugins.py +0 -410
  68. redeploy-0.2.78/redeploy/tests/test_probes.py +0 -346
  69. redeploy-0.2.78/redeploy/tests/test_public_api.py +0 -243
  70. redeploy-0.2.78/redeploy/tests/test_resume.py +0 -271
  71. redeploy-0.2.78/redeploy/tests/test_security_hardening.py +0 -93
  72. redeploy-0.2.78/redeploy/tests/test_spec_loader.py +0 -105
  73. redeploy-0.2.78/redeploy/tests/test_ssh.py +0 -258
  74. redeploy-0.2.78/redeploy/tests/test_steps_registry.py +0 -109
  75. redeploy-0.2.78/redeploy/tests/test_templates.py +0 -429
  76. redeploy-0.2.78/redeploy/tests/test_verify.py +0 -218
  77. redeploy-0.2.78/redeploy/tests/test_version.py +0 -219
  78. redeploy-0.2.78/redeploy/tests/test_version_changelog.py +0 -356
  79. redeploy-0.2.78/redeploy/tests/test_version_cli.py +0 -887
  80. redeploy-0.2.78/redeploy/tests/test_version_manifest.py +0 -658
  81. redeploy-0.2.78/redeploy/tests/test_version_sources.py +0 -517
  82. redeploy-0.2.78/redeploy/tests/test_workflow.py +0 -286
  83. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/analyze/__init__.py +0 -0
  84. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/analyze/checkers/__init__.py +0 -0
  85. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/analyze/checkers/base.py +0 -0
  86. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/analyze/checkers/command_ref.py +0 -0
  87. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/analyze/checkers/compose.py +0 -0
  88. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/analyze/checkers/docker_build.py +0 -0
  89. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/analyze/checkers/env.py +0 -0
  90. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/analyze/checkers/path.py +0 -0
  91. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/analyze/ignore.py +0 -0
  92. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/analyze/models.py +0 -0
  93. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/analyze/preflight_schema.py +0 -0
  94. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/analyze/spec_analyzer.py +0 -0
  95. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/apply/__init__.py +0 -0
  96. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/apply/exceptions.py +0 -0
  97. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/apply/rollback.py +0 -0
  98. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/apply/state.py +0 -0
  99. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/apply/state_apply.py +0 -0
  100. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/apply/utils/__init__.py +0 -0
  101. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/apply/utils/run_container_build.py +0 -0
  102. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/audit/__init__.py +0 -0
  103. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/audit/auditor.py +0 -0
  104. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/audit/extractor.py +0 -0
  105. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/audit/models.py +0 -0
  106. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/audit/paths.py +0 -0
  107. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/audit/patterns.py +0 -0
  108. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/audit/probe.py +0 -0
  109. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/blueprint/__init__.py +0 -0
  110. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/blueprint/extractor.py +0 -0
  111. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/blueprint/generators/__init__.py +0 -0
  112. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/blueprint/generators/docker_compose.py +0 -0
  113. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/blueprint/generators/migration.py +0 -0
  114. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/blueprint/sources/__init__.py +0 -0
  115. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/blueprint/sources/compose.py +0 -0
  116. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/blueprint/sources/hardware.py +0 -0
  117. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/blueprint/sources/infra.py +0 -0
  118. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/blueprint/sources/migration.py +0 -0
  119. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/__init__.py +0 -0
  120. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/apply_cmd.py +0 -0
  121. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/audit.py +0 -0
  122. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/blueprint.py +0 -0
  123. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/bump_fix.py +0 -0
  124. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/detect.py +0 -0
  125. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/device_map.py +0 -0
  126. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/device_map_actions.py +0 -0
  127. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/device_map_renderers.py +0 -0
  128. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/devices.py +0 -0
  129. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/devices_display.py +0 -0
  130. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/diagnose.py +0 -0
  131. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/diff.py +0 -0
  132. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/exec_.py +0 -0
  133. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/export.py +0 -0
  134. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/gh_workflow.py +0 -0
  135. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/hardware.py +0 -0
  136. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/import_.py +0 -0
  137. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/init.py +0 -0
  138. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/inspect.py +0 -0
  139. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/lint.py +0 -0
  140. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/mcp_cmd.py +0 -0
  141. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/migrate_cmd.py +0 -0
  142. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/patterns.py +0 -0
  143. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/plan_apply.py +0 -0
  144. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/plan_apply_report.py +0 -0
  145. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/plan_cmd.py +0 -0
  146. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/plugin.py +0 -0
  147. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/probe.py +0 -0
  148. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/probe_display.py +0 -0
  149. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/prompt_cmd.py +0 -0
  150. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/push.py +0 -0
  151. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/state.py +0 -0
  152. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/status.py +0 -0
  153. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/target.py +0 -0
  154. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/version/__init__.py +0 -0
  155. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/version/commands.py +0 -0
  156. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/version/helpers.py +0 -0
  157. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/version/monorepo.py +0 -0
  158. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/version/release.py +0 -0
  159. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/version/scanner.py +0 -0
  160. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/version/utils/__init__.py +0 -0
  161. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/version/utils/changelog_config.py +0 -0
  162. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/version/utils/git_config.py +0 -0
  163. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/commands/workflow.py +0 -0
  164. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/core.py +0 -0
  165. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/display.py +0 -0
  166. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli/query.py +0 -0
  167. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/cli.py +0 -0
  168. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/config_apply/__init__.py +0 -0
  169. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/config_apply/applier.py +0 -0
  170. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/config_apply/handlers/__init__.py +0 -0
  171. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/config_apply/handlers/display.py +0 -0
  172. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/config_apply/loader.py +0 -0
  173. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/data_sync.py +0 -0
  174. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/detect/__init__.py +0 -0
  175. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/detect/builtin/__init__.py +0 -0
  176. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/detect/detector.py +0 -0
  177. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/detect/hardware.py +0 -0
  178. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/detect/hardware_rules.py +0 -0
  179. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/detect/probes.py +0 -0
  180. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/detect/remote.py +0 -0
  181. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/detect/templates.py +0 -0
  182. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/detect/workflow.py +0 -0
  183. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/discovery/__init__.py +0 -0
  184. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/discovery/auto_probe.py +0 -0
  185. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/discovery/helpers.py +0 -0
  186. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/discovery/probe_parse.py +0 -0
  187. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/discovery/registry.py +0 -0
  188. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/discovery/scanners.py +0 -0
  189. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/discovery/ssh_credentials.py +0 -0
  190. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/discovery/types.py +0 -0
  191. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/dsl/__init__.py +0 -0
  192. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/dsl/loader.py +0 -0
  193. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/dsl/parser.py +0 -0
  194. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/dsl_python/__init__.py +0 -0
  195. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/dsl_python/context.py +0 -0
  196. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/dsl_python/decorators.py +0 -0
  197. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/dsl_python/docker_steps.py +0 -0
  198. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/dsl_python/exceptions.py +0 -0
  199. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/dsl_python/runner.py +0 -0
  200. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/dsl_python/steps.py +0 -0
  201. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/fleet.py +0 -0
  202. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/hardware/__init__.py +0 -0
  203. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/hardware/config_txt.py +0 -0
  204. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/hardware/data/__init__.py +0 -0
  205. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/hardware/data/hyperpixel.py +0 -0
  206. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/hardware/data/official.py +0 -0
  207. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/hardware/data/waveshare.py +0 -0
  208. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/hardware/fixes.py +0 -0
  209. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/hardware/kiosk/__init__.py +0 -0
  210. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/hardware/kiosk/autostart.py +0 -0
  211. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/hardware/kiosk/browsers.py +0 -0
  212. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/hardware/kiosk/compositors.py +0 -0
  213. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/hardware/kiosk/output_profiles.py +0 -0
  214. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/hardware/panels.py +0 -0
  215. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/hardware/raspi_config.py +0 -0
  216. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/heal/__init__.py +0 -0
  217. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/heal/decider.py +0 -0
  218. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/heal/log_writer.py +0 -0
  219. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/heal/loop_detector.py +0 -0
  220. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/heal/runner.py +0 -0
  221. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/iac/__init__.py +0 -0
  222. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/iac/base.py +0 -0
  223. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/iac/config_hints.py +0 -0
  224. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/iac/docker_compose.py +0 -0
  225. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/iac/parsers/__init__.py +0 -0
  226. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/iac/parsers/compose.py +0 -0
  227. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/iac/registry.py +0 -0
  228. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/integrations/__init__.py +0 -0
  229. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/integrations/op3_bridge.py +0 -0
  230. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/markpact/__init__.py +0 -0
  231. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/markpact/compiler.py +0 -0
  232. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/markpact/models.py +0 -0
  233. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/markpact/parser.py +0 -0
  234. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/models/__init__.py +0 -0
  235. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/models/blueprint.py +0 -0
  236. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/models/devices.py +0 -0
  237. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/models/hardware.py +0 -0
  238. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/models/infra.py +0 -0
  239. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/models/manifest.py +0 -0
  240. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/models/persisted.py +0 -0
  241. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/models/pipeline.py +0 -0
  242. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/models/spec.py +0 -0
  243. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/observe.py +0 -0
  244. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/parse.py +0 -0
  245. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/patterns.py +0 -0
  246. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/plan/__init__.py +0 -0
  247. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/plan/planner.py +0 -0
  248. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/plugins/__init__.py +0 -0
  249. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/plugins/builtin/__init__.py +0 -0
  250. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/plugins/builtin/browser_reload.py +0 -0
  251. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/plugins/builtin/hardware_diagnostic.py +0 -0
  252. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/plugins/builtin/notify.py +0 -0
  253. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/plugins/builtin/process_control.py +0 -0
  254. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/plugins/builtin/systemd_reload.py +0 -0
  255. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/schema.py +0 -0
  256. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/spec_loader.py +0 -0
  257. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/ssh.py +0 -0
  258. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/steps/__init__.py +0 -0
  259. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/steps/docker.py +0 -0
  260. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/steps/generic.py +0 -0
  261. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/steps/hardware.py +0 -0
  262. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/steps/k3s.py +0 -0
  263. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/steps/kiosk.py +0 -0
  264. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/steps/podman.py +0 -0
  265. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/steps/process.py +0 -0
  266. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/steps/scm.py +0 -0
  267. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/steps/transfer.py +0 -0
  268. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/verify.py +0 -0
  269. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/version/__init__.py +0 -0
  270. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/version/bump.py +0 -0
  271. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/version/changelog.py +0 -0
  272. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/version/commits.py +0 -0
  273. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/version/diff.py +0 -0
  274. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/version/git_integration.py +0 -0
  275. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/version/git_transaction.py +0 -0
  276. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/version/manifest.py +0 -0
  277. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/version/sources/__init__.py +0 -0
  278. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/version/sources/base.py +0 -0
  279. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/version/sources/json_.py +0 -0
  280. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/version/sources/plain.py +0 -0
  281. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/version/sources/regex.py +0 -0
  282. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/version/sources/toml_.py +0 -0
  283. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/version/sources/yaml_.py +0 -0
  284. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/version/transaction.py +0 -0
  285. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy/version.py +0 -0
  286. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy.egg-info/dependency_links.txt +0 -0
  287. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy.egg-info/entry_points.txt +0 -0
  288. {redeploy-0.2.78 → redeploy-0.2.80}/redeploy.egg-info/top_level.txt +0 -0
  289. {redeploy-0.2.78 → redeploy-0.2.80}/setup.cfg +0 -0
  290. {redeploy-0.2.78 → redeploy-0.2.80}/tests/test_blueprint_sources.py +0 -0
  291. {redeploy-0.2.78 → redeploy-0.2.80}/tests/test_blueprint_sources_compose.py +0 -0
  292. {redeploy-0.2.78 → redeploy-0.2.80}/tests/test_cli_gh_workflow.py +0 -0
  293. {redeploy-0.2.78 → redeploy-0.2.80}/tests/test_cli_query.py +0 -0
  294. {redeploy-0.2.78 → redeploy-0.2.80}/tests/test_example_argocd_flux_plugin.py +0 -0
  295. {redeploy-0.2.78 → redeploy-0.2.80}/tests/test_example_gitops_ci_plugin.py +0 -0
  296. {redeploy-0.2.78 → redeploy-0.2.80}/tests/test_example_helm_kustomize_plugin.py +0 -0
  297. {redeploy-0.2.78 → redeploy-0.2.80}/tests/test_hardware_config.py +0 -0
  298. {redeploy-0.2.78 → redeploy-0.2.80}/tests/test_hardware_kiosk.py +0 -0
  299. {redeploy-0.2.78 → redeploy-0.2.80}/tests/test_hardware_rules.py +0 -0
  300. {redeploy-0.2.78 → redeploy-0.2.80}/tests/test_heal_decider.py +0 -0
  301. {redeploy-0.2.78 → redeploy-0.2.80}/tests/test_heal_loop_detector.py +0 -0
  302. {redeploy-0.2.78 → redeploy-0.2.80}/tests/test_iac.py +0 -0
  303. {redeploy-0.2.78 → redeploy-0.2.80}/tests/test_iac_config_hints.py +0 -0
  304. {redeploy-0.2.78 → redeploy-0.2.80}/tests/test_iac_plugin_loading.py +0 -0
  305. {redeploy-0.2.78 → redeploy-0.2.80}/tests/test_import_plugin_template.py +0 -0
  306. {redeploy-0.2.78 → redeploy-0.2.80}/tests/test_parse.py +0 -0
  307. {redeploy-0.2.78 → redeploy-0.2.80}/tests/test_redeploy.py +0 -0
  308. {redeploy-0.2.78 → redeploy-0.2.80}/tests/test_steps_kiosk.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: redeploy
3
- Version: 0.2.78
3
+ Version: 0.2.80
4
4
  Summary: Infrastructure migration toolkit: detect → plan → apply
5
5
  License-Expression: Apache-2.0
6
6
  Requires-Python: >=3.11
@@ -14,15 +14,13 @@ Requires-Dist: paramiko>=3.0
14
14
  Requires-Dist: httpx>=0.25
15
15
  Requires-Dist: rich>=13.0
16
16
  Requires-Dist: jmespath>=1.0
17
- Requires-Dist: goal>=2.1.0
18
- Requires-Dist: costs>=0.1.20
19
- Requires-Dist: pfix>=0.1.60
17
+ Requires-Dist: costs>=0.2.0
18
+ Requires-Dist: pfix>=0.1.79
20
19
  Provides-Extra: dev
21
20
  Requires-Dist: pytest>=8.0; extra == "dev"
22
21
  Requires-Dist: ruff>=0.4; extra == "dev"
23
- Requires-Dist: goal>=2.1.0; extra == "dev"
24
- Requires-Dist: costs>=0.1.20; extra == "dev"
25
- Requires-Dist: pfix>=0.1.60; extra == "dev"
22
+ Requires-Dist: costs>=0.2.0; extra == "dev"
23
+ Requires-Dist: pfix>=0.1.79; extra == "dev"
26
24
  Provides-Extra: op3
27
25
  Requires-Dist: op3>=0.1.8; extra == "op3"
28
26
  Provides-Extra: mcp
@@ -33,17 +31,17 @@ Requires-Dist: mcp>=1.0; extra == "mcp"
33
31
 
34
32
  ## AI Cost Tracking
35
33
 
36
- ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.78-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
37
- ![AI Cost](https://img.shields.io/badge/AI%20Cost-$6.32-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-42.0h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
34
+ ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.80-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
35
+ ![AI Cost](https://img.shields.io/badge/AI%20Cost-$1.86-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-58.6h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
38
36
 
39
- - 🤖 **LLM usage:** $6.3244 (100 commits)
40
- - 👤 **Human dev:** ~$4198 (42.0h @ $100/h, 30min dedup)
37
+ - 🤖 **LLM usage:** $1.8574 (124 commits)
38
+ - 👤 **Human dev:** ~$5861 (58.6h @ $100/h, 30min dedup)
41
39
 
42
- Generated on 2026-05-20 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
40
+ Generated on 2026-09-06 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
43
41
 
44
42
  ---
45
43
 
46
- ![PyPI](https://img.shields.io/badge/pypi-redeploy-blue) ![Version](https://img.shields.io/badge/version-0.2.78-blue) ![Python](https://img.shields.io/badge/python-3.10+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
44
+ ![PyPI](https://img.shields.io/badge/pypi-redeploy-blue) ![Version](https://img.shields.io/badge/version-0.2.80-blue) ![Python](https://img.shields.io/badge/python-3.11+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
47
45
 
48
46
  Infrastructure migration and device deploy toolkit — VPS, Raspberry Pi kiosk, Podman Quadlet, k3s.
49
47
 
@@ -111,6 +109,24 @@ redeploy run migration.yaml --detect
111
109
  redeploy run migration.yaml
112
110
  ```
113
111
 
112
+ ## Safe post-deploy verification
113
+
114
+ Steps roll back completed actions on failure by default. A post-deploy check
115
+ can fail the run without undoing an otherwise healthy deployment:
116
+
117
+ ```yaml
118
+ extra_steps:
119
+ - id: smoke_after_commit
120
+ action: testql
121
+ query_source: tests/smoke.testql.toon.yaml
122
+ url: https://example.test
123
+ rollback_on_failure: false
124
+ ```
125
+
126
+ `redeploy run SPEC --plan-only` evaluates lint and preflight locally without
127
+ contacting the target or writing generated state. Use
128
+ `--preflight-schema-out PATH` when a persisted planning artifact is required.
129
+
114
130
  ## Quick start — Raspberry Pi kiosk
115
131
 
116
132
  ```bash
@@ -509,6 +525,57 @@ extra_steps:
509
525
  insert_before: docker_build_pull # runs before build, not after verify
510
526
  ```
511
527
 
528
+ ## Query-language post-deploy tests — `testql` / `oql` / `aql`
529
+
530
+ Beyond `http_check`/`inline_script`, redeploy can run **query-language test
531
+ scenarios** as post-deploy verification. Each runs the interpreter **locally**
532
+ (on the controller, where it is installed) and targets the freshly deployed
533
+ host via `url`. The step fails — and thus the deploy fails/rolls back — when the
534
+ scenario fails.
535
+
536
+ | Action | Default runner | Verdict | Purpose |
537
+ |--------|----------------|---------|---------|
538
+ | `testql` | `testql run --url <url> <file>` | exit 0 (+ optional `expect` in output) | API/GUI smoke of the deployed app |
539
+ | `oql` | `oqlctl <file> -m <mode> --json [--firmware-url <url>]` | JSON `ok == true` (fallback: exit 0) | run an OQL scenario against the deployed runtime/firmware |
540
+ | `aql` | `aql <file> [locale]` | exit 0 (+ optional `expect`, e.g. a variant name) | evaluate an AQL decision model and assert the verdict |
541
+
542
+ Fields (on top of `url` / `expect`):
543
+
544
+ - `query_source` — path to the `.testql.toon.yaml` / `.oql` / `.aql` scenario.
545
+ - `query_mode` — OQL mode: `validate` \| `dry-run` \| `execute`.
546
+ - `query_runner` — override the runner binary (absolute path is fine).
547
+ - `query_locale` — AQL locale (`en` \| `pl`).
548
+ - `query_context` — AQL: path to a context JSON for resolve.
549
+ - `command` — full command-template override; placeholders `{url} {source} {mode} {locale} {context}` are substituted (literal `{}` in the command are left intact — no `str.format`).
550
+
551
+ ```yaml
552
+ extra_steps:
553
+ - id: post_deploy_oql
554
+ action: oql
555
+ description: "OQL: real sensor read from the deployed firmware"
556
+ query_source: deploy-tests/oql/firmware-sensor-read.oql
557
+ query_mode: execute
558
+ url: http://192.168.188.122:8202 # oqlctl --firmware-url
559
+
560
+ - id: post_deploy_testql
561
+ action: testql
562
+ description: "TestQL: API smoke of the deployed app"
563
+ query_source: deploy-tests/testql/post-deploy-api-smoke.testql.toon.yaml
564
+ flags: ["--output", "json", "--quiet"]
565
+ url: http://192.168.188.109:8100 # testql run --url
566
+
567
+ - id: post_deploy_aql
568
+ action: aql
569
+ description: "AQL: decision model returns the expected variant"
570
+ query_source: deploy-tests/aql/personalization.en.aql
571
+ command: "python3 /path/to/aql/cli.py {source} {locale}"
572
+ query_locale: en
573
+ expect: technical_deep
574
+ ```
575
+
576
+ A ready example spec lives in c2004: `deploy-tests/post-deploy.redeploy.md`
577
+ (run with `redeploy run deploy-tests/post-deploy.redeploy.md`).
578
+
512
579
  ## Plugin system
513
580
 
514
581
  Extend the step pipeline with custom action types using `action: plugin`:
@@ -934,7 +1001,9 @@ Language is auto-detected — Polish, English, or any language the model support
934
1001
 
935
1002
  redeploy exposes an [MCP (Model Context Protocol)](https://modelcontextprotocol.io) server,
936
1003
  letting AI assistants (Claude Desktop, VS Code Copilot, custom agents) call redeploy operations
937
- as structured tools.
1004
+ as structured tools. Planning is enabled by default. Deployment, version, generated-command, and SSH
1005
+ mutations require the server-side capability `REDEPLOY_MCP_ALLOW_APPLY=1`, an
1006
+ `actor`, and the exact `approval_hash` returned for that operation.
938
1007
 
939
1008
  ### Start
940
1009
 
@@ -1,49 +1,19 @@
1
- Metadata-Version: 2.4
2
- Name: redeploy
3
- Version: 0.2.78
4
- Summary: Infrastructure migration toolkit: detect → plan → apply
5
- License-Expression: Apache-2.0
6
- Requires-Python: >=3.11
7
- Description-Content-Type: text/markdown
8
- Requires-Dist: pydantic>=2.0
9
- Requires-Dist: pyyaml>=6.0
10
- Requires-Dist: markdown-it-py>=3.0
11
- Requires-Dist: click>=8.0
12
- Requires-Dist: loguru>=0.7
13
- Requires-Dist: paramiko>=3.0
14
- Requires-Dist: httpx>=0.25
15
- Requires-Dist: rich>=13.0
16
- Requires-Dist: jmespath>=1.0
17
- Requires-Dist: goal>=2.1.0
18
- Requires-Dist: costs>=0.1.20
19
- Requires-Dist: pfix>=0.1.60
20
- Provides-Extra: dev
21
- Requires-Dist: pytest>=8.0; extra == "dev"
22
- Requires-Dist: ruff>=0.4; extra == "dev"
23
- Requires-Dist: goal>=2.1.0; extra == "dev"
24
- Requires-Dist: costs>=0.1.20; extra == "dev"
25
- Requires-Dist: pfix>=0.1.60; extra == "dev"
26
- Provides-Extra: op3
27
- Requires-Dist: op3>=0.1.8; extra == "op3"
28
- Provides-Extra: mcp
29
- Requires-Dist: mcp>=1.0; extra == "mcp"
30
-
31
1
  # redeploy
32
2
 
33
3
 
34
4
  ## AI Cost Tracking
35
5
 
36
- ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.78-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
37
- ![AI Cost](https://img.shields.io/badge/AI%20Cost-$6.32-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-42.0h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
6
+ ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.80-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
7
+ ![AI Cost](https://img.shields.io/badge/AI%20Cost-$1.86-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-58.6h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
38
8
 
39
- - 🤖 **LLM usage:** $6.3244 (100 commits)
40
- - 👤 **Human dev:** ~$4198 (42.0h @ $100/h, 30min dedup)
9
+ - 🤖 **LLM usage:** $1.8574 (124 commits)
10
+ - 👤 **Human dev:** ~$5861 (58.6h @ $100/h, 30min dedup)
41
11
 
42
- Generated on 2026-05-20 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
12
+ Generated on 2026-09-06 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
43
13
 
44
14
  ---
45
15
 
46
- ![PyPI](https://img.shields.io/badge/pypi-redeploy-blue) ![Version](https://img.shields.io/badge/version-0.2.78-blue) ![Python](https://img.shields.io/badge/python-3.10+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
16
+ ![PyPI](https://img.shields.io/badge/pypi-redeploy-blue) ![Version](https://img.shields.io/badge/version-0.2.80-blue) ![Python](https://img.shields.io/badge/python-3.11+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
47
17
 
48
18
  Infrastructure migration and device deploy toolkit — VPS, Raspberry Pi kiosk, Podman Quadlet, k3s.
49
19
 
@@ -111,6 +81,24 @@ redeploy run migration.yaml --detect
111
81
  redeploy run migration.yaml
112
82
  ```
113
83
 
84
+ ## Safe post-deploy verification
85
+
86
+ Steps roll back completed actions on failure by default. A post-deploy check
87
+ can fail the run without undoing an otherwise healthy deployment:
88
+
89
+ ```yaml
90
+ extra_steps:
91
+ - id: smoke_after_commit
92
+ action: testql
93
+ query_source: tests/smoke.testql.toon.yaml
94
+ url: https://example.test
95
+ rollback_on_failure: false
96
+ ```
97
+
98
+ `redeploy run SPEC --plan-only` evaluates lint and preflight locally without
99
+ contacting the target or writing generated state. Use
100
+ `--preflight-schema-out PATH` when a persisted planning artifact is required.
101
+
114
102
  ## Quick start — Raspberry Pi kiosk
115
103
 
116
104
  ```bash
@@ -509,6 +497,57 @@ extra_steps:
509
497
  insert_before: docker_build_pull # runs before build, not after verify
510
498
  ```
511
499
 
500
+ ## Query-language post-deploy tests — `testql` / `oql` / `aql`
501
+
502
+ Beyond `http_check`/`inline_script`, redeploy can run **query-language test
503
+ scenarios** as post-deploy verification. Each runs the interpreter **locally**
504
+ (on the controller, where it is installed) and targets the freshly deployed
505
+ host via `url`. The step fails — and thus the deploy fails/rolls back — when the
506
+ scenario fails.
507
+
508
+ | Action | Default runner | Verdict | Purpose |
509
+ |--------|----------------|---------|---------|
510
+ | `testql` | `testql run --url <url> <file>` | exit 0 (+ optional `expect` in output) | API/GUI smoke of the deployed app |
511
+ | `oql` | `oqlctl <file> -m <mode> --json [--firmware-url <url>]` | JSON `ok == true` (fallback: exit 0) | run an OQL scenario against the deployed runtime/firmware |
512
+ | `aql` | `aql <file> [locale]` | exit 0 (+ optional `expect`, e.g. a variant name) | evaluate an AQL decision model and assert the verdict |
513
+
514
+ Fields (on top of `url` / `expect`):
515
+
516
+ - `query_source` — path to the `.testql.toon.yaml` / `.oql` / `.aql` scenario.
517
+ - `query_mode` — OQL mode: `validate` \| `dry-run` \| `execute`.
518
+ - `query_runner` — override the runner binary (absolute path is fine).
519
+ - `query_locale` — AQL locale (`en` \| `pl`).
520
+ - `query_context` — AQL: path to a context JSON for resolve.
521
+ - `command` — full command-template override; placeholders `{url} {source} {mode} {locale} {context}` are substituted (literal `{}` in the command are left intact — no `str.format`).
522
+
523
+ ```yaml
524
+ extra_steps:
525
+ - id: post_deploy_oql
526
+ action: oql
527
+ description: "OQL: real sensor read from the deployed firmware"
528
+ query_source: deploy-tests/oql/firmware-sensor-read.oql
529
+ query_mode: execute
530
+ url: http://192.168.188.122:8202 # oqlctl --firmware-url
531
+
532
+ - id: post_deploy_testql
533
+ action: testql
534
+ description: "TestQL: API smoke of the deployed app"
535
+ query_source: deploy-tests/testql/post-deploy-api-smoke.testql.toon.yaml
536
+ flags: ["--output", "json", "--quiet"]
537
+ url: http://192.168.188.109:8100 # testql run --url
538
+
539
+ - id: post_deploy_aql
540
+ action: aql
541
+ description: "AQL: decision model returns the expected variant"
542
+ query_source: deploy-tests/aql/personalization.en.aql
543
+ command: "python3 /path/to/aql/cli.py {source} {locale}"
544
+ query_locale: en
545
+ expect: technical_deep
546
+ ```
547
+
548
+ A ready example spec lives in c2004: `deploy-tests/post-deploy.redeploy.md`
549
+ (run with `redeploy run deploy-tests/post-deploy.redeploy.md`).
550
+
512
551
  ## Plugin system
513
552
 
514
553
  Extend the step pipeline with custom action types using `action: plugin`:
@@ -934,7 +973,9 @@ Language is auto-detected — Polish, English, or any language the model support
934
973
 
935
974
  redeploy exposes an [MCP (Model Context Protocol)](https://modelcontextprotocol.io) server,
936
975
  letting AI assistants (Claude Desktop, VS Code Copilot, custom agents) call redeploy operations
937
- as structured tools.
976
+ as structured tools. Planning is enabled by default. Deployment, version, generated-command, and SSH
977
+ mutations require the server-side capability `REDEPLOY_MCP_ALLOW_APPLY=1`, an
978
+ `actor`, and the exact `approval_hash` returned for that operation.
938
979
 
939
980
  ### Start
940
981
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "redeploy"
7
- version = "0.2.78"
7
+ version = "0.2.80"
8
8
  description = "Infrastructure migration toolkit: detect → plan → apply"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -18,9 +18,8 @@ dependencies = [
18
18
  "httpx>=0.25",
19
19
  "rich>=13.0",
20
20
  "jmespath>=1.0",
21
- "goal>=2.1.0",
22
- "costs>=0.1.20",
23
- "pfix>=0.1.60",
21
+ "costs>=0.2.0",
22
+ "pfix>=0.1.79",
24
23
  ]
25
24
  license = "Apache-2.0"
26
25
 
@@ -30,9 +29,8 @@ redeploy-mcp = "redeploy.mcp_server:serve"
30
29
 
31
30
  [project.optional-dependencies]
32
31
  dev = ["pytest>=8.0", "ruff>=0.4",
33
- "goal>=2.1.0",
34
- "costs>=0.1.20",
35
- "pfix>=0.1.60",
32
+ "costs>=0.2.0",
33
+ "pfix>=0.1.79",
36
34
  ]
37
35
  op3 = ["op3>=0.1.8"]
38
36
  mcp = ["mcp>=1.0"]
@@ -40,9 +38,19 @@ mcp = ["mcp>=1.0"]
40
38
  [tool.ruff]
41
39
  line-length = 100
42
40
 
41
+ [tool.setuptools]
42
+ include-package-data = false
43
+
43
44
  [tool.setuptools.packages.find]
44
45
  where = ["."]
45
46
  include = ["redeploy*"]
47
+ exclude = ["redeploy.tests*"]
48
+
49
+ [tool.setuptools.package-data]
50
+ redeploy = ["**/*.yaml"]
51
+
52
+ [tool.setuptools.exclude-package-data]
53
+ redeploy = ["tests/*", "tests/**/*"]
46
54
 
47
55
  [tool.pfix]
48
56
  # Self-healing Python configuration
@@ -72,3 +80,9 @@ max_commits = 500
72
80
 
73
81
  # Cost thresholds for badge colors (USD)
74
82
  badge_color_thresholds = { low = 1.0, medium = 5.0, high = 10.0, critical = 50.0 }
83
+
84
+ [dependency-groups]
85
+ automation = ["goal>=2.2.0"]
86
+
87
+ [tool.uv.dependency-groups.automation]
88
+ requires-python = ">=3.12"
@@ -7,7 +7,7 @@ Public API (stable from 0.2.0, semver guaranteed)::
7
7
 
8
8
  Everything not listed in ``__all__`` is internal and may change without notice.
9
9
  """
10
- __version__ = "0.2.78"
10
+ __version__ = "0.2.80"
11
11
 
12
12
  # ── Core models ───────────────────────────────────────────────────────────────
13
13
  from .models import ( # noqa: F401
@@ -5,15 +5,37 @@ import re
5
5
  import shlex
6
6
  import shutil
7
7
 
8
- from ..models import AnalysisResult, IssueSeverity
8
+ from ..models import IssueSeverity
9
9
  from .base import Checker
10
10
 
11
11
  _WRAPPERS = frozenset({"sudo", "env", "command", "nohup", "time", "exec"})
12
12
  _KEYWORDS = frozenset({
13
13
  "if", "then", "else", "fi", "for", "do", "done", "while", "case", "esac",
14
14
  "function", "in", "until", "select", "echo", "true", "false", "test", "[", "[[",
15
+ "break", "continue", "return", "exit", "shift", "read", "printf", "cd", "pwd",
16
+ "export", "readonly", "local", "declare", "typeset", "unset", "set", "source", ".",
17
+ "alias", "unalias", "trap", "wait", "jobs", "fg", "bg", "getopts", "hash",
15
18
  })
16
19
  _SEPARATORS = frozenset({"&&", "||", "|", ";", "(", ")", "{", "}"})
20
+ _REMOTE_ACTIONS = frozenset({
21
+ "ssh_cmd",
22
+ "inline_script",
23
+ "systemctl_stop",
24
+ "systemctl_disable",
25
+ "systemctl_start",
26
+ "kubectl_delete",
27
+ "docker_compose_up",
28
+ "docker_compose_down",
29
+ "docker_build",
30
+ "docker_health_wait",
31
+ "container_log_tail",
32
+ "podman_build",
33
+ "ensure_config_line",
34
+ "raspi_config",
35
+ "ensure_kanshi_profile",
36
+ "ensure_autostart_entry",
37
+ "ensure_browser_kiosk_script",
38
+ })
17
39
 
18
40
 
19
41
  def extract_binaries(cmd: str) -> list[str]:
@@ -57,7 +79,10 @@ class BinaryChecker(Checker):
57
79
  def check(self, spec, document, base_dir, result):
58
80
  for step in spec.extra_steps:
59
81
  action = str(step.get("action") or "")
60
- if action in {"ensure_kanshi_profile"}:
82
+ # Commands for these actions execute on the deployment target.
83
+ # Checking them with shutil.which() on the controller produces
84
+ # false warnings and says nothing about target availability.
85
+ if action in _REMOTE_ACTIONS:
61
86
  continue
62
87
  cmd = step.get("command") or ""
63
88
  for binary in extract_binaries(cmd):
@@ -1,7 +1,7 @@
1
1
  """Reference integrity checkers for migration specs."""
2
2
  from __future__ import annotations
3
3
 
4
- from ..models import AnalysisResult, IssueSeverity
4
+ from ..models import IssueSeverity
5
5
  from .base import Checker
6
6
 
7
7
 
@@ -13,6 +13,18 @@ class ReferenceChecker(Checker):
13
13
 
14
14
  step_ids = {s.get("id") for s in spec.extra_steps if s.get("id")}
15
15
  step_ids |= set(StepLibrary.list())
16
+ # Strategy steps (for example install_quadlet_files or
17
+ # stop_<app>) are generated by Planner at runtime and are valid
18
+ # insertion anchors even though they are absent from extra_steps.
19
+ try:
20
+ from ...plan import Planner
21
+
22
+ generated = Planner.from_spec(spec).run()
23
+ step_ids |= {step.id for step in generated.steps}
24
+ except Exception:
25
+ # The remaining analyzers report malformed specs. Reference
26
+ # checking stays best-effort and must not mask their diagnostics.
27
+ pass
16
28
  ref_ids: set[str] = set()
17
29
  if document:
18
30
  for block in document.blocks: