redeploy 0.2.67__tar.gz → 0.2.68__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 (243) hide show
  1. {redeploy-0.2.67 → redeploy-0.2.68}/PKG-INFO +6 -6
  2. {redeploy-0.2.67 → redeploy-0.2.68}/README.md +5 -5
  3. {redeploy-0.2.67 → redeploy-0.2.68}/pyproject.toml +1 -1
  4. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/__init__.py +1 -1
  5. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/prompt_cmd.py +81 -5
  6. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy.egg-info/PKG-INFO +6 -6
  7. {redeploy-0.2.67 → redeploy-0.2.68}/tests/test_prompt_llm.py +50 -0
  8. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/analyze/__init__.py +0 -0
  9. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/analyze/checkers/__init__.py +0 -0
  10. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/analyze/preflight_schema.py +0 -0
  11. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/analyze/spec_analyzer.py +0 -0
  12. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/apply/__init__.py +0 -0
  13. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/apply/exceptions.py +0 -0
  14. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/apply/executor.py +0 -0
  15. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/apply/handlers.py +0 -0
  16. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/apply/progress.py +0 -0
  17. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/apply/rollback.py +0 -0
  18. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/apply/state.py +0 -0
  19. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/apply/state_apply.py +0 -0
  20. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/apply/utils/__init__.py +0 -0
  21. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/apply/utils/run_container_build.py +0 -0
  22. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/audit.py +0 -0
  23. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/blueprint/__init__.py +0 -0
  24. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/blueprint/extractor.py +0 -0
  25. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/blueprint/generators/__init__.py +0 -0
  26. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/blueprint/generators/docker_compose.py +0 -0
  27. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/blueprint/generators/migration.py +0 -0
  28. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/blueprint/sources/__init__.py +0 -0
  29. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/blueprint/sources/compose.py +0 -0
  30. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/blueprint/sources/hardware.py +0 -0
  31. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/blueprint/sources/infra.py +0 -0
  32. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/blueprint/sources/migration.py +0 -0
  33. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/__init__.py +0 -0
  34. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/__init__.py +0 -0
  35. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/audit.py +0 -0
  36. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/blueprint.py +0 -0
  37. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/bump_fix.py +0 -0
  38. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/detect.py +0 -0
  39. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/device_map.py +0 -0
  40. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/device_map_renderers.py +0 -0
  41. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/devices.py +0 -0
  42. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/diagnose.py +0 -0
  43. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/diff.py +0 -0
  44. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/exec_.py +0 -0
  45. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/export.py +0 -0
  46. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/hardware.py +0 -0
  47. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/import_.py +0 -0
  48. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/init.py +0 -0
  49. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/inspect.py +0 -0
  50. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/lint.py +0 -0
  51. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/mcp_cmd.py +0 -0
  52. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/patterns.py +0 -0
  53. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/plan_apply.py +0 -0
  54. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/plugin.py +0 -0
  55. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/probe.py +0 -0
  56. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/push.py +0 -0
  57. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/state.py +0 -0
  58. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/status.py +0 -0
  59. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/target.py +0 -0
  60. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/version/__init__.py +0 -0
  61. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/version/commands.py +0 -0
  62. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/version/helpers.py +0 -0
  63. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/version/monorepo.py +0 -0
  64. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/version/release.py +0 -0
  65. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/version/scanner.py +0 -0
  66. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/version/utils/__init__.py +0 -0
  67. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/version/utils/changelog_config.py +0 -0
  68. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/version/utils/git_config.py +0 -0
  69. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/commands/workflow.py +0 -0
  70. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/core.py +0 -0
  71. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/display.py +0 -0
  72. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli/query.py +0 -0
  73. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/cli.py +0 -0
  74. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/config_apply/__init__.py +0 -0
  75. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/config_apply/applier.py +0 -0
  76. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/config_apply/loader.py +0 -0
  77. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/data_sync.py +0 -0
  78. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/detect/__init__.py +0 -0
  79. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/detect/builtin/__init__.py +0 -0
  80. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/detect/detector.py +0 -0
  81. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/detect/hardware.py +0 -0
  82. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/detect/hardware_rules.py +0 -0
  83. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/detect/probes.py +0 -0
  84. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/detect/remote.py +0 -0
  85. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/detect/templates.py +0 -0
  86. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/detect/workflow.py +0 -0
  87. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/discovery.py +0 -0
  88. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/dsl/__init__.py +0 -0
  89. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/dsl/loader.py +0 -0
  90. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/dsl/parser.py +0 -0
  91. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/dsl_python/__init__.py +0 -0
  92. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/dsl_python/context.py +0 -0
  93. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/dsl_python/decorators.py +0 -0
  94. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/dsl_python/docker_steps.py +0 -0
  95. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/dsl_python/exceptions.py +0 -0
  96. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/dsl_python/runner.py +0 -0
  97. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/dsl_python/steps.py +0 -0
  98. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/fleet.py +0 -0
  99. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/hardware/__init__.py +0 -0
  100. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/hardware/config_txt.py +0 -0
  101. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/hardware/data/__init__.py +0 -0
  102. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/hardware/data/hyperpixel.py +0 -0
  103. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/hardware/data/official.py +0 -0
  104. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/hardware/data/waveshare.py +0 -0
  105. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/hardware/fixes.py +0 -0
  106. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/hardware/kiosk/__init__.py +0 -0
  107. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/hardware/kiosk/autostart.py +0 -0
  108. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/hardware/kiosk/browsers.py +0 -0
  109. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/hardware/kiosk/compositors.py +0 -0
  110. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/hardware/kiosk/output_profiles.py +0 -0
  111. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/hardware/panels.py +0 -0
  112. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/hardware/raspi_config.py +0 -0
  113. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/heal/__init__.py +0 -0
  114. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/heal/decider.py +0 -0
  115. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/heal/hint_provider.py +0 -0
  116. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/heal/log_writer.py +0 -0
  117. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/heal/loop_detector.py +0 -0
  118. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/heal/runner.py +0 -0
  119. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/heal.py +0 -0
  120. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/iac/__init__.py +0 -0
  121. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/iac/base.py +0 -0
  122. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/iac/config_hints.py +0 -0
  123. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/iac/docker_compose.py +0 -0
  124. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/iac/parsers/__init__.py +0 -0
  125. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/iac/parsers/compose.py +0 -0
  126. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/iac/registry.py +0 -0
  127. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/integrations/__init__.py +0 -0
  128. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/integrations/op3_bridge.py +0 -0
  129. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/markpact/__init__.py +0 -0
  130. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/markpact/compiler.py +0 -0
  131. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/markpact/models.py +0 -0
  132. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/markpact/parser.py +0 -0
  133. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/mcp_server.py +0 -0
  134. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/models/__init__.py +0 -0
  135. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/models/blueprint.py +0 -0
  136. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/models/devices.py +0 -0
  137. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/models/enums.py +0 -0
  138. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/models/hardware.py +0 -0
  139. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/models/infra.py +0 -0
  140. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/models/manifest.py +0 -0
  141. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/models/persisted.py +0 -0
  142. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/models/pipeline.py +0 -0
  143. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/models/plan.py +0 -0
  144. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/models/spec.py +0 -0
  145. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/observe.py +0 -0
  146. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/parse.py +0 -0
  147. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/patterns.py +0 -0
  148. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/plan/__init__.py +0 -0
  149. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/plan/planner.py +0 -0
  150. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/plugins/__init__.py +0 -0
  151. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/plugins/builtin/__init__.py +0 -0
  152. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/plugins/builtin/browser_reload.py +0 -0
  153. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/plugins/builtin/hardware_diagnostic.py +0 -0
  154. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/plugins/builtin/notify.py +0 -0
  155. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/plugins/builtin/process_control.py +0 -0
  156. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/plugins/builtin/systemd_reload.py +0 -0
  157. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/schema.py +0 -0
  158. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/spec_loader.py +0 -0
  159. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/ssh.py +0 -0
  160. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/steps/__init__.py +0 -0
  161. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/steps/builtins.py +0 -0
  162. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/steps/kiosk.py +0 -0
  163. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/__init__.py +0 -0
  164. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_analyze.py +0 -0
  165. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_audit.py +0 -0
  166. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_cli.py +0 -0
  167. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_data_sync.py +0 -0
  168. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_discovery.py +0 -0
  169. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_dsl.py +0 -0
  170. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_examples.py +0 -0
  171. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_executor.py +0 -0
  172. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_fleet.py +0 -0
  173. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_git_integration.py +0 -0
  174. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_heal.py +0 -0
  175. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_heal_decider.py +0 -0
  176. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_hooks.py +0 -0
  177. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_iac.py +0 -0
  178. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_iac_compose_contract.py +0 -0
  179. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_iac_docker_compose_contract.py +0 -0
  180. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_manifest.py +0 -0
  181. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_markpact_compiler.py +0 -0
  182. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_markpact_parser.py +0 -0
  183. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_models.py +0 -0
  184. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_observe.py +0 -0
  185. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_parse.py +0 -0
  186. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_patterns.py +0 -0
  187. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_planner_edge.py +0 -0
  188. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_plugins.py +0 -0
  189. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_probes.py +0 -0
  190. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_public_api.py +0 -0
  191. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_resume.py +0 -0
  192. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_spec_loader.py +0 -0
  193. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_ssh.py +0 -0
  194. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_templates.py +0 -0
  195. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_verify.py +0 -0
  196. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_version.py +0 -0
  197. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_version_changelog.py +0 -0
  198. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_version_cli.py +0 -0
  199. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_version_manifest.py +0 -0
  200. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_version_sources.py +0 -0
  201. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/tests/test_workflow.py +0 -0
  202. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/verify.py +0 -0
  203. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/version/__init__.py +0 -0
  204. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/version/bump.py +0 -0
  205. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/version/changelog.py +0 -0
  206. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/version/commits.py +0 -0
  207. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/version/diff.py +0 -0
  208. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/version/git_integration.py +0 -0
  209. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/version/git_transaction.py +0 -0
  210. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/version/manifest.py +0 -0
  211. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/version/sources/__init__.py +0 -0
  212. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/version/sources/base.py +0 -0
  213. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/version/sources/json_.py +0 -0
  214. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/version/sources/plain.py +0 -0
  215. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/version/sources/regex.py +0 -0
  216. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/version/sources/toml_.py +0 -0
  217. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/version/sources/yaml_.py +0 -0
  218. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/version/transaction.py +0 -0
  219. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy/version.py +0 -0
  220. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy.egg-info/SOURCES.txt +0 -0
  221. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy.egg-info/dependency_links.txt +0 -0
  222. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy.egg-info/entry_points.txt +0 -0
  223. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy.egg-info/requires.txt +0 -0
  224. {redeploy-0.2.67 → redeploy-0.2.68}/redeploy.egg-info/top_level.txt +0 -0
  225. {redeploy-0.2.67 → redeploy-0.2.68}/setup.cfg +0 -0
  226. {redeploy-0.2.67 → redeploy-0.2.68}/tests/test_blueprint_sources.py +0 -0
  227. {redeploy-0.2.67 → redeploy-0.2.68}/tests/test_blueprint_sources_compose.py +0 -0
  228. {redeploy-0.2.67 → redeploy-0.2.68}/tests/test_cli_query.py +0 -0
  229. {redeploy-0.2.67 → redeploy-0.2.68}/tests/test_example_argocd_flux_plugin.py +0 -0
  230. {redeploy-0.2.67 → redeploy-0.2.68}/tests/test_example_gitops_ci_plugin.py +0 -0
  231. {redeploy-0.2.67 → redeploy-0.2.68}/tests/test_example_helm_kustomize_plugin.py +0 -0
  232. {redeploy-0.2.67 → redeploy-0.2.68}/tests/test_hardware_config.py +0 -0
  233. {redeploy-0.2.67 → redeploy-0.2.68}/tests/test_hardware_kiosk.py +0 -0
  234. {redeploy-0.2.67 → redeploy-0.2.68}/tests/test_hardware_rules.py +0 -0
  235. {redeploy-0.2.67 → redeploy-0.2.68}/tests/test_heal_decider.py +0 -0
  236. {redeploy-0.2.67 → redeploy-0.2.68}/tests/test_heal_loop_detector.py +0 -0
  237. {redeploy-0.2.67 → redeploy-0.2.68}/tests/test_iac.py +0 -0
  238. {redeploy-0.2.67 → redeploy-0.2.68}/tests/test_iac_config_hints.py +0 -0
  239. {redeploy-0.2.67 → redeploy-0.2.68}/tests/test_iac_plugin_loading.py +0 -0
  240. {redeploy-0.2.67 → redeploy-0.2.68}/tests/test_import_plugin_template.py +0 -0
  241. {redeploy-0.2.67 → redeploy-0.2.68}/tests/test_parse.py +0 -0
  242. {redeploy-0.2.67 → redeploy-0.2.68}/tests/test_redeploy.py +0 -0
  243. {redeploy-0.2.67 → redeploy-0.2.68}/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.67
3
+ Version: 0.2.68
4
4
  Summary: Infrastructure migration toolkit: detect → plan → apply
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -32,17 +32,17 @@ Requires-Dist: mcp>=1.0; extra == "mcp"
32
32
 
33
33
  ## AI Cost Tracking
34
34
 
35
- ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.67-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
36
- ![AI Cost](https://img.shields.io/badge/AI%20Cost-$7.50-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-34.2h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
35
+ ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.68-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
36
+ ![AI Cost](https://img.shields.io/badge/AI%20Cost-$7.50-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-35.1h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
37
37
 
38
- - 🤖 **LLM usage:** $7.5000 (88 commits)
39
- - 👤 **Human dev:** ~$3416 (34.2h @ $100/h, 30min dedup)
38
+ - 🤖 **LLM usage:** $7.5000 (89 commits)
39
+ - 👤 **Human dev:** ~$3512 (35.1h @ $100/h, 30min dedup)
40
40
 
41
41
  Generated on 2026-04-23 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
42
42
 
43
43
  ---
44
44
 
45
- ![PyPI](https://img.shields.io/badge/pypi-redeploy-blue) ![Version](https://img.shields.io/badge/version-0.2.67-blue) ![Python](https://img.shields.io/badge/python-3.10+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
45
+ ![PyPI](https://img.shields.io/badge/pypi-redeploy-blue) ![Version](https://img.shields.io/badge/version-0.2.68-blue) ![Python](https://img.shields.io/badge/python-3.10+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
46
46
 
47
47
  Infrastructure migration and device deploy toolkit — VPS, Raspberry Pi kiosk, Podman Quadlet, k3s.
48
48
 
@@ -3,17 +3,17 @@
3
3
 
4
4
  ## AI Cost Tracking
5
5
 
6
- ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.67-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-$7.50-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-34.2h-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.68-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-$7.50-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-35.1h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
8
8
 
9
- - 🤖 **LLM usage:** $7.5000 (88 commits)
10
- - 👤 **Human dev:** ~$3416 (34.2h @ $100/h, 30min dedup)
9
+ - 🤖 **LLM usage:** $7.5000 (89 commits)
10
+ - 👤 **Human dev:** ~$3512 (35.1h @ $100/h, 30min dedup)
11
11
 
12
12
  Generated on 2026-04-23 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
13
13
 
14
14
  ---
15
15
 
16
- ![PyPI](https://img.shields.io/badge/pypi-redeploy-blue) ![Version](https://img.shields.io/badge/version-0.2.67-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.68-blue) ![Python](https://img.shields.io/badge/python-3.10+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
17
17
 
18
18
  Infrastructure migration and device deploy toolkit — VPS, Raspberry Pi kiosk, Podman Quadlet, k3s.
19
19
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "redeploy"
7
- version = "0.2.67"
7
+ version = "0.2.68"
8
8
  description = "Infrastructure migration toolkit: detect → plan → apply"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -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.67"
10
+ __version__ = "0.2.68"
11
11
 
12
12
  # ── Core models ───────────────────────────────────────────────────────────────
13
13
  from .models import ( # noqa: F401
@@ -121,6 +121,8 @@ def _call_llm(schema: dict, user_prompt: str) -> str:
121
121
 
122
122
  def _parse_llm_response(raw: str) -> dict:
123
123
  """Parse JSON from LLM response, strip accidental fences and escape control characters."""
124
+ import re
125
+
124
126
  # Strip ```json ... ``` if present
125
127
  clean = raw.strip()
126
128
  if clean.startswith("```"):
@@ -129,18 +131,92 @@ def _parse_llm_response(raw: str) -> dict:
129
131
  line for line in lines
130
132
  if not line.strip().startswith("```")
131
133
  )
134
+
135
+ # Extract innermost balanced {...} if extra text surrounds it
136
+ def _extract_json(text: str) -> str:
137
+ start = text.find("{")
138
+ if start == -1:
139
+ return text
140
+ depth = 0
141
+ for i, ch in enumerate(text[start:], start):
142
+ if ch == "{":
143
+ depth += 1
144
+ elif ch == "}":
145
+ depth -= 1
146
+ if depth == 0:
147
+ return text[start : i + 1]
148
+ return text
149
+
150
+ clean = _extract_json(clean)
151
+
132
152
  # Escape control characters (except \n, \r, \t) for JSON safety
133
153
  def escape_control_char(match):
134
154
  char = match.group(0)
135
- # Keep allowed whitespace, escape others as \uXXXX
136
155
  if char in "\n\r\t":
137
156
  return char
138
157
  return f"\\u{ord(char):04x}"
139
-
140
- # Match any control character (ord < 32) except \n, \r, \t
141
- import re
158
+
142
159
  clean = re.sub(r"[\x00-\x08\x0b\x0c\x0e-\x1f]", escape_control_char, clean)
143
- return json.loads(clean)
160
+
161
+ # Try strict parse first
162
+ try:
163
+ return json.loads(clean)
164
+ except json.JSONDecodeError:
165
+ pass
166
+
167
+ # Fallback: try ujson (more lenient with some LLM quirks) if available
168
+ try:
169
+ import ujson
170
+ return ujson.loads(clean)
171
+ except Exception:
172
+ pass
173
+
174
+ # Repair trailing commas before ] or }
175
+ repaired = re.sub(r",(\s*[}\]])", r"\1", clean)
176
+ try:
177
+ return json.loads(repaired)
178
+ except json.JSONDecodeError:
179
+ pass
180
+
181
+ # Repair raw newlines inside string values by escaping them
182
+ def _escape_newlines_in_strings(text: str) -> str:
183
+ result = []
184
+ in_string = False
185
+ escape = False
186
+ for ch in text:
187
+ if escape:
188
+ result.append(ch)
189
+ escape = False
190
+ continue
191
+ if ch == "\\":
192
+ result.append(ch)
193
+ escape = True
194
+ continue
195
+ if ch == '"' and not in_string:
196
+ in_string = True
197
+ result.append(ch)
198
+ continue
199
+ if ch == '"' and in_string:
200
+ in_string = False
201
+ result.append(ch)
202
+ continue
203
+ if ch == "\n" and in_string:
204
+ result.append("\\n")
205
+ continue
206
+ if ch == "\r" and in_string:
207
+ result.append("\\r")
208
+ continue
209
+ result.append(ch)
210
+ return "".join(result)
211
+
212
+ repaired = _escape_newlines_in_strings(clean)
213
+ try:
214
+ return json.loads(repaired)
215
+ except json.JSONDecodeError:
216
+ pass
217
+
218
+ # Last resort: raise original error with cleaned text for debugging
219
+ raise json.JSONDecodeError("Failed to parse LLM JSON after all repairs", clean, 0)
144
220
 
145
221
 
146
222
  # ---------------------------------------------------------------------------
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: redeploy
3
- Version: 0.2.67
3
+ Version: 0.2.68
4
4
  Summary: Infrastructure migration toolkit: detect → plan → apply
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -32,17 +32,17 @@ Requires-Dist: mcp>=1.0; extra == "mcp"
32
32
 
33
33
  ## AI Cost Tracking
34
34
 
35
- ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.67-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
36
- ![AI Cost](https://img.shields.io/badge/AI%20Cost-$7.50-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-34.2h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
35
+ ![PyPI](https://img.shields.io/badge/pypi-costs-blue) ![Version](https://img.shields.io/badge/version-0.2.68-blue) ![Python](https://img.shields.io/badge/python-3.9+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
36
+ ![AI Cost](https://img.shields.io/badge/AI%20Cost-$7.50-orange) ![Human Time](https://img.shields.io/badge/Human%20Time-35.1h-blue) ![Model](https://img.shields.io/badge/Model-openrouter%2Fqwen%2Fqwen3--coder--next-lightgrey)
37
37
 
38
- - 🤖 **LLM usage:** $7.5000 (88 commits)
39
- - 👤 **Human dev:** ~$3416 (34.2h @ $100/h, 30min dedup)
38
+ - 🤖 **LLM usage:** $7.5000 (89 commits)
39
+ - 👤 **Human dev:** ~$3512 (35.1h @ $100/h, 30min dedup)
40
40
 
41
41
  Generated on 2026-04-23 using [openrouter/qwen/qwen3-coder-next](https://openrouter.ai/qwen/qwen3-coder-next)
42
42
 
43
43
  ---
44
44
 
45
- ![PyPI](https://img.shields.io/badge/pypi-redeploy-blue) ![Version](https://img.shields.io/badge/version-0.2.67-blue) ![Python](https://img.shields.io/badge/python-3.10+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
45
+ ![PyPI](https://img.shields.io/badge/pypi-redeploy-blue) ![Version](https://img.shields.io/badge/version-0.2.68-blue) ![Python](https://img.shields.io/badge/python-3.10+-blue) ![License](https://img.shields.io/badge/license-Apache--2.0-green)
46
46
 
47
47
  Infrastructure migration and device deploy toolkit — VPS, Raspberry Pi kiosk, Podman Quadlet, k3s.
48
48
 
@@ -369,3 +369,53 @@ def test_parse_llm_response_preserves_newlines():
369
369
 
370
370
  result = _parse_llm_response(response_with_whitespace)
371
371
  assert "Line 1\nLine 2\rLine 3\tTabbed" in result["thought"]
372
+
373
+
374
+ def test_parse_llm_response_handles_trailing_commas():
375
+ """_parse_llm_response must repair trailing commas before } or ]."""
376
+ from redeploy.cli.commands.prompt_cmd import _parse_llm_response
377
+
378
+ response_with_trailing_comma = '''{
379
+ "thought": "test",
380
+ "argv": ["redeploy", "status",],
381
+ "confirm": false,
382
+ "human_summary": "Status check",
383
+ }'''
384
+
385
+ result = _parse_llm_response(response_with_trailing_comma)
386
+ assert result["argv"] == ["redeploy", "status"]
387
+ assert result["confirm"] is False
388
+
389
+
390
+ def test_parse_llm_response_handles_raw_newlines_in_strings():
391
+ """_parse_llm_response must escape raw newlines that appear inside JSON strings."""
392
+ from redeploy.cli.commands.prompt_cmd import _parse_llm_response
393
+
394
+ response_with_raw_newlines = '''{
395
+ "thought": "Line one
396
+ Line two",
397
+ "argv": ["redeploy", "status"],
398
+ "confirm": false,
399
+ "human_summary": "Status check"
400
+ }'''
401
+
402
+ result = _parse_llm_response(response_with_raw_newlines)
403
+ assert "Line one\nLine two" in result["thought"]
404
+
405
+
406
+ def test_parse_llm_response_extracts_json_from_surrounding_text():
407
+ """_parse_llm_response must find the JSON object if the LLM adds extra text."""
408
+ from redeploy.cli.commands.prompt_cmd import _parse_llm_response
409
+
410
+ response_with_extra_text = '''Here is the JSON you requested:
411
+ {
412
+ "thought": "test",
413
+ "argv": ["redeploy", "status"],
414
+ "confirm": false,
415
+ "human_summary": "Status check"
416
+ }
417
+ Hope that helps!'''
418
+
419
+ result = _parse_llm_response(response_with_extra_text)
420
+ assert result["argv"] == ["redeploy", "status"]
421
+ assert result["confirm"] is False
File without changes
File without changes
File without changes
File without changes