codeplain 0.3.10.dev2__tar.gz → 0.3.10.dev4__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 (265) hide show
  1. codeplain-0.3.10.dev4/.github/dependabot.yml +28 -0
  2. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/.github/workflows/e2e.yml +10 -8
  3. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/.github/workflows/lint-and-test.yml +19 -17
  4. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/.github/workflows/lint-powershell.yml +2 -2
  5. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/.github/workflows/nofity-slack-on-main-merge.yml +3 -3
  6. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/.github/workflows/publish-install-script.yml +1 -1
  7. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/.github/workflows/publish-to-pypi.yml +46 -4
  8. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/PKG-INFO +1 -1
  9. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/codeplain_REST_api.py +6 -14
  10. codeplain-0.3.10.dev4/conformance_fix_journal.py +207 -0
  11. codeplain-0.3.10.dev4/memory_management.py +52 -0
  12. codeplain-0.3.10.dev4/render_machine/actions/distill_conformance_test_memory.py +56 -0
  13. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/actions/fix_conformance_test.py +58 -29
  14. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/actions/prepare_repositories.py +8 -0
  15. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/actions/run_conformance_tests.py +5 -11
  16. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/render_types.py +0 -4
  17. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/state_machine_config.py +10 -1
  18. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/states.py +1 -0
  19. codeplain-0.3.10.dev4/tests/test_conformance_fix_journal.py +259 -0
  20. codeplain-0.3.10.dev4/tests/test_distill_conformance_test_memory.py +145 -0
  21. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_prepare_repositories_layout.py +38 -0
  22. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tui/state_handlers.py +7 -1
  23. codeplain-0.3.10.dev2/.github/dependabot.yml +0 -11
  24. codeplain-0.3.10.dev2/memory_management.py +0 -132
  25. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/.claude/settings.json +0 -0
  26. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/.flake8 +0 -0
  27. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/.github/workflows/publish-dev-to-pypi.yml +0 -0
  28. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/.gitignore +0 -0
  29. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/.vscode/launch.json +0 -0
  30. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/.vscode/settings.json +0 -0
  31. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/CLAUDE.md +0 -0
  32. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/CONTRIBUTING.md +0 -0
  33. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/LICENSE +0 -0
  34. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/README.md +0 -0
  35. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/change_detection.py +0 -0
  36. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/cli_output/__init__.py +0 -0
  37. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/cli_output/dry_run.py +0 -0
  38. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/cli_output/render_summary.py +0 -0
  39. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/cli_output/status.py +0 -0
  40. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/concept_utils.py +0 -0
  41. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/config/__init__.py +0 -0
  42. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/config/system_config.yaml +0 -0
  43. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/diff_utils.py +0 -0
  44. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/docs/generate_cli.py +0 -0
  45. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/docs/plain2code_cli.md +0 -0
  46. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/docs/starting_a_plain_project_from_scratch.md +0 -0
  47. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/event_bus.py +0 -0
  48. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/examples/example_hello_world_golang/config.yaml +0 -0
  49. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/examples/example_hello_world_golang/harness_tests/hello_world_test.go +0 -0
  50. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/examples/example_hello_world_golang/hello_world_golang.plain +0 -0
  51. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/examples/example_hello_world_golang/run.sh +0 -0
  52. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/examples/example_hello_world_python/config.yaml +0 -0
  53. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/examples/example_hello_world_python/harness_tests/hello_world_display/test_hello_world.py +0 -0
  54. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/examples/example_hello_world_python/hello_world_python.plain +0 -0
  55. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/examples/example_hello_world_python/run.sh +0 -0
  56. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/examples/example_hello_world_react/config.yaml +0 -0
  57. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/e2e/hello_world.cy.ts +0 -0
  58. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress/support/e2e.ts +0 -0
  59. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/examples/example_hello_world_react/harness_tests/hello_world_display/cypress.config.ts +0 -0
  60. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/examples/example_hello_world_react/harness_tests/hello_world_display/package.json +0 -0
  61. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/examples/example_hello_world_react/harness_tests/hello_world_display/tsconfig.json +0 -0
  62. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/examples/example_hello_world_react/hello_world_react.plain +0 -0
  63. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/examples/example_hello_world_react/run.sh +0 -0
  64. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/examples/run.sh +0 -0
  65. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/file_utils.py +0 -0
  66. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/git_utils.py +0 -0
  67. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/install/bash/examples.sh +0 -0
  68. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/install/bash/install.sh +0 -0
  69. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/install/bash/walkthrough.sh +0 -0
  70. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/install/powershell/examples.ps1 +0 -0
  71. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/install/powershell/install.ps1 +0 -0
  72. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/install/powershell/walkthrough.ps1 +0 -0
  73. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/metadata_utils.py +0 -0
  74. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/module_renderer.py +0 -0
  75. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/partial_rendering.py +0 -0
  76. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/path_resolution.py +0 -0
  77. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/plain2code.py +0 -0
  78. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/plain2code_arguments.py +0 -0
  79. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/plain2code_cli.md +0 -0
  80. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/plain2code_console.py +0 -0
  81. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/plain2code_events.py +0 -0
  82. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/plain2code_exceptions.py +0 -0
  83. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/plain2code_logger.py +0 -0
  84. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/plain2code_nodes.py +0 -0
  85. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/plain2code_read_config.py +0 -0
  86. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/plain2code_state.py +0 -0
  87. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/plain2code_telemetry.py +0 -0
  88. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/plain2code_utils.py +0 -0
  89. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/plain_file.py +0 -0
  90. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/plain_modules.py +0 -0
  91. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/plain_spec.py +0 -0
  92. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/pyproject.toml +0 -0
  93. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/pytest.ini +0 -0
  94. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/__init__.py +0 -0
  95. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/actions/analyze_specification_ambiguity.py +0 -0
  96. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/actions/base_action.py +0 -0
  97. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/actions/commit_conformance_tests_changes.py +0 -0
  98. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/actions/commit_implementation_code_changes.py +0 -0
  99. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/actions/create_dist.py +0 -0
  100. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/actions/exit_with_error.py +0 -0
  101. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/actions/finish_functional_requirement.py +0 -0
  102. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/actions/fix_unit_tests.py +0 -0
  103. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/actions/prepare_testing_environment.py +0 -0
  104. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/actions/refactor_code.py +0 -0
  105. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/actions/render_conformance_tests.py +0 -0
  106. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/actions/render_functional_requirement.py +0 -0
  107. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/actions/run_unit_tests.py +0 -0
  108. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/actions/summarize_conformance_tests.py +0 -0
  109. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/code_renderer.py +0 -0
  110. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/conformance_tests.py +0 -0
  111. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/implementation_code_helpers.py +0 -0
  112. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/render_context.py +0 -0
  113. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/render_utils.py +0 -0
  114. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/render_machine/triggers.py +0 -0
  115. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/requirements.txt +0 -0
  116. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/resources/codeplain_overview.png +0 -0
  117. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/resources/plain_example.png +0 -0
  118. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/standard_template_library/golang-console-app-template.plain +0 -0
  119. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/standard_template_library/python-console-app-template.plain +0 -0
  120. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/standard_template_library/typescript-react-app-boilerplate.plain +0 -0
  121. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/standard_template_library/typescript-react-app-template.plain +0 -0
  122. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/system_config.py +0 -0
  123. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/test_scripts/run_conformance_tests_cypress.ps1 +0 -0
  124. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/test_scripts/run_conformance_tests_cypress.sh +0 -0
  125. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/test_scripts/run_conformance_tests_golang.ps1 +0 -0
  126. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/test_scripts/run_conformance_tests_golang.sh +0 -0
  127. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/test_scripts/run_conformance_tests_python.ps1 +0 -0
  128. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/test_scripts/run_conformance_tests_python.sh +0 -0
  129. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/test_scripts/run_unittests_flutter.ps1 +0 -0
  130. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/test_scripts/run_unittests_flutter.sh +0 -0
  131. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/test_scripts/run_unittests_golang.ps1 +0 -0
  132. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/test_scripts/run_unittests_golang.sh +0 -0
  133. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/test_scripts/run_unittests_python.ps1 +0 -0
  134. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/test_scripts/run_unittests_python.sh +0 -0
  135. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/test_scripts/run_unittests_react.ps1 +0 -0
  136. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/test_scripts/run_unittests_react.sh +0 -0
  137. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/__init__.py +0 -0
  138. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/conftest.py +0 -0
  139. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/acceptance_tests_warning/main_requiring_acceptance_tests.plain +0 -0
  140. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/acceptance_tests_warning/required_with_acceptance_tests.plain +0 -0
  141. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/imports/circular_imports_1.plain +0 -0
  142. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/imports/circular_imports_2.plain +0 -0
  143. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/imports/circular_imports_main.plain +0 -0
  144. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/imports/diamond_import_1.plain +0 -0
  145. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/imports/diamond_import_2.plain +0 -0
  146. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/imports/diamond_import_common.plain +0 -0
  147. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/imports/diamond_imports_main.plain +0 -0
  148. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/imports/import_with_functionalities.plain +0 -0
  149. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/imports/imports_module_with_functionalities.plain +0 -0
  150. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/imports/non_existent_import.plain +0 -0
  151. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/partial_rendering/pr_code_var.plain +0 -0
  152. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/partial_rendering/pr_implement.plain +0 -0
  153. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/partial_rendering/pr_leaf.plain +0 -0
  154. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/partial_rendering/pr_middle.plain +0 -0
  155. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/partial_rendering/pr_root.plain +0 -0
  156. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/partial_rendering/pr_solo.plain +0 -0
  157. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfile/add_new_task_modal_specification.yaml +0 -0
  158. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfile/duplicate_specification_heading.plain +0 -0
  159. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfile/empty_functional_specs_section.plain +0 -0
  160. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfile/invalid_specification_order.plain +0 -0
  161. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfile/missing_non_functional_requirements.plain +0 -0
  162. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfile/no_functional_specs_section.plain +0 -0
  163. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfile/plain_source_with_absolute_link.plain +0 -0
  164. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfile/plain_source_with_url_link.plain +0 -0
  165. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfile/task_list_ui_specification.yaml +0 -0
  166. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfile/task_manager_with_reference_links.plain +0 -0
  167. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfile/without_non_functional_requirement.plain +0 -0
  168. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/concept_validation_acceptance_tests.plain +0 -0
  169. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/concept_validation_acceptance_tests_nondefined.plain +0 -0
  170. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/concept_validation_defined_nondefined.plain +0 -0
  171. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/concept_validation_defined_nondefined_2.plain +0 -0
  172. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/concept_validation_definition.plain +0 -0
  173. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/concept_validation_noconcepts.plain +0 -0
  174. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/concept_validation_nonconcept.plain +0 -0
  175. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/concept_validation_nondefined.plain +0 -0
  176. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/concept_validation_redefinition.plain +0 -0
  177. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/concept_validation_several_concepts.plain +0 -0
  178. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/concept_validation_valid.plain +0 -0
  179. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/exported_concepts.plain +0 -0
  180. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/exported_concepts_base.plain +0 -0
  181. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/exported_concepts_example.plain +0 -0
  182. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/exported_concepts_missing.plain +0 -0
  183. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/exported_concepts_missing_example.plain +0 -0
  184. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/exported_concepts_nested.plain +0 -0
  185. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/exported_concepts_nested_example.plain +0 -0
  186. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/exported_concepts_transitive_example.plain +0 -0
  187. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/exported_concepts_transitive_l1.plain +0 -0
  188. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/exported_concepts_transitive_l2.plain +0 -0
  189. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/plain_file_parser_with_comments.plain +0 -0
  190. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/plain_file_with_comments_indented.plain +0 -0
  191. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/regular_plain_source.plain +0 -0
  192. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/required_concepts.plain +0 -0
  193. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/required_concepts_defs.plain +0 -0
  194. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/required_concepts_example.plain +0 -0
  195. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/required_concepts_l1.plain +0 -0
  196. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/required_concepts_l2.plain +0 -0
  197. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/required_concepts_missing.plain +0 -0
  198. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/required_concepts_module.plain +0 -0
  199. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/required_concepts_partial.plain +0 -0
  200. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/required_concepts_partial_duplicate.plain +0 -0
  201. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/topological_sort.plain +0 -0
  202. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/plainfileparser/topological_sort_not_referenced.plain +0 -0
  203. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/requires/circular_requires_main.plain +0 -0
  204. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/requires/circular_requires_sub.plain +0 -0
  205. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/requires/diamond_requires_1.plain +0 -0
  206. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/requires/diamond_requires_2.plain +0 -0
  207. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/requires/diamond_requires_common.plain +0 -0
  208. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/requires/diamond_requires_main.plain +0 -0
  209. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/requires/independent_requires_1.plain +0 -0
  210. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/requires/independent_requires_2.plain +0 -0
  211. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/requires/independent_requires_main.plain +0 -0
  212. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/requires/non_existent_require.plain +0 -0
  213. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/requires/normal_requires_1.plain +0 -0
  214. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/requires/normal_requires_2.plain +0 -0
  215. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/requires/normal_requires_common.plain +0 -0
  216. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/requires/normal_requires_main.plain +0 -0
  217. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/sample_base64_image.txt +0 -0
  218. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/simple.plain +0 -0
  219. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/templates/block_level_include.plain +0 -0
  220. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/templates/code_variables.plain +0 -0
  221. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/templates/header.plain +0 -0
  222. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/templates/implement.plain +0 -0
  223. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/templates/implement_2.plain +0 -0
  224. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/templates/template_include.plain +0 -0
  225. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/data/templates/test_hardest_problem.plain +0 -0
  226. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/e2e/Dockerfile +0 -0
  227. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/e2e/conftest.py +0 -0
  228. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/e2e/test_hello_world_python.py +0 -0
  229. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/e2e/test_hello_world_python_windows.py +0 -0
  230. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_arg_provenance.py +0 -0
  231. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_change_detection.py +0 -0
  232. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_cli_output.py +0 -0
  233. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_console_log_styles.py +0 -0
  234. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_file_utils.py +0 -0
  235. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_folder_path_resolution.py +0 -0
  236. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_git_utils.py +0 -0
  237. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_headless_logging.py +0 -0
  238. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_imports.py +0 -0
  239. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_log_file_name_resolution.py +0 -0
  240. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_logging_config_path_resolution.py +0 -0
  241. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_partial_rendering.py +0 -0
  242. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_path_resolution.py +0 -0
  243. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_plain2code.py +0 -0
  244. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_plain2code_state.py +0 -0
  245. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_plain2code_utils.py +0 -0
  246. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_plain_modules.py +0 -0
  247. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_plainfile.py +0 -0
  248. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_plainfileparser.py +0 -0
  249. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_plainspec.py +0 -0
  250. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_requires.py +0 -0
  251. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_resolve_config_file.py +0 -0
  252. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_script_path_resolution.py +0 -0
  253. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_system_config.py +0 -0
  254. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_telemetry.py +0 -0
  255. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_tui_usage.py +0 -0
  256. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tests/test_usage_summary.py +0 -0
  257. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tui/__init__.py +0 -0
  258. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tui/components.py +0 -0
  259. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tui/models.py +0 -0
  260. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tui/plain2code_tui.py +0 -0
  261. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tui/plain_module_render_choice_tui.py +0 -0
  262. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tui/spinner.py +0 -0
  263. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tui/styles.css +0 -0
  264. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/tui/widget_helpers.py +0 -0
  265. {codeplain-0.3.10.dev2 → codeplain-0.3.10.dev4}/usage_summary.py +0 -0
@@ -0,0 +1,28 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "pip"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ open-pull-requests-limit: 3
8
+ commit-message:
9
+ prefix: "dependabot"
10
+ labels:
11
+ - "dependencies"
12
+
13
+ # Keeps the SHA-pinned actions in publish-to-pypi.yml patched.
14
+ - package-ecosystem: "github-actions"
15
+ directory: "/"
16
+ schedule:
17
+ interval: "weekly"
18
+ open-pull-requests-limit: 5
19
+ commit-message:
20
+ prefix: "ci"
21
+ labels:
22
+ - "dependencies"
23
+ - "github-actions"
24
+ groups:
25
+ actions-minor-and-patch:
26
+ update-types:
27
+ - "minor"
28
+ - "patch"
@@ -11,19 +11,19 @@ jobs:
11
11
  runs-on: ubuntu-latest
12
12
  timeout-minutes: 15
13
13
  steps:
14
- - uses: actions/checkout@v4
14
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
15
15
 
16
- - uses: actions/setup-python@v5
16
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
17
17
  with:
18
18
  python-version: '3.12'
19
19
 
20
20
  - run: pip install pytest
21
21
 
22
22
  - name: Set up Docker Buildx
23
- uses: docker/setup-buildx-action@v3
23
+ uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
24
24
 
25
25
  - name: Build E2E image (cached)
26
- uses: docker/build-push-action@v5
26
+ uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5
27
27
  with:
28
28
  context: .
29
29
  file: tests/e2e/Dockerfile
@@ -39,7 +39,7 @@ jobs:
39
39
 
40
40
  - name: Upload generated outputs on failure
41
41
  if: failure()
42
- uses: actions/upload-artifact@v4
42
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
43
43
  with:
44
44
  name: e2e-outputs-linux
45
45
  path: /tmp/pytest-of-runner/**/container_work*/**
@@ -48,9 +48,9 @@ jobs:
48
48
  runs-on: windows-latest
49
49
  timeout-minutes: 15
50
50
  steps:
51
- - uses: actions/checkout@v4
51
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
52
52
 
53
- - uses: actions/setup-python@v5
53
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
54
54
  with:
55
55
  python-version: '3.12'
56
56
 
@@ -81,8 +81,10 @@ jobs:
81
81
 
82
82
  - name: Send failure notification to Slack
83
83
  if: ${{ env.SLACK_WEBHOOK_URL != '' }}
84
- uses: slackapi/slack-github-action@v1.24.0
84
+ uses: slackapi/slack-github-action@dcb1066f776dd043e64d0e8ba94ca15cc7e1875d # v4.0.0
85
85
  with:
86
+ webhook: ${{ env.SLACK_WEBHOOK_URL }}
87
+ webhook-type: incoming-webhook
86
88
  payload: |
87
89
  {
88
90
  "text": ${{ toJSON(format('[Codeplain Client] E2E tests FAILED on {0}. See <{1}/{2}/actions/runs/{3}|the run log>.', steps.platforms.outputs.failed, github.server_url, github.repository, github.run_id)) }}
@@ -12,13 +12,13 @@ jobs:
12
12
  name: Black Formatting
13
13
  runs-on: ubuntu-latest
14
14
  steps:
15
- - uses: actions/checkout@v4
15
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
16
16
  - name: Set up Python
17
- uses: actions/setup-python@v5
17
+ uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
18
18
  with:
19
19
  python-version: ${{ env.PYTHON_VERSION }}
20
20
  - name: Cache pip
21
- uses: actions/cache@v4
21
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
22
22
  with:
23
23
  path: ~/.cache/pip
24
24
  key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
@@ -33,13 +33,13 @@ jobs:
33
33
  name: Import Sorting
34
34
  runs-on: ubuntu-latest
35
35
  steps:
36
- - uses: actions/checkout@v4
36
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
37
37
  - name: Set up Python
38
- uses: actions/setup-python@v5
38
+ uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
39
39
  with:
40
40
  python-version: ${{ env.PYTHON_VERSION }}
41
41
  - name: Cache pip
42
- uses: actions/cache@v4
42
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
43
43
  with:
44
44
  path: ~/.cache/pip
45
45
  key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
@@ -54,13 +54,13 @@ jobs:
54
54
  name: Flake8 Linting
55
55
  runs-on: ubuntu-latest
56
56
  steps:
57
- - uses: actions/checkout@v4
57
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
58
58
  - name: Set up Python
59
- uses: actions/setup-python@v5
59
+ uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
60
60
  with:
61
61
  python-version: ${{ env.PYTHON_VERSION }}
62
62
  - name: Cache pip
63
- uses: actions/cache@v4
63
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
64
64
  with:
65
65
  path: ~/.cache/pip
66
66
  key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
@@ -75,13 +75,13 @@ jobs:
75
75
  name: MyPy Type Checking
76
76
  runs-on: ubuntu-latest
77
77
  steps:
78
- - uses: actions/checkout@v4
78
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
79
79
  - name: Set up Python
80
- uses: actions/setup-python@v5
80
+ uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
81
81
  with:
82
82
  python-version: ${{ env.PYTHON_VERSION }}
83
83
  - name: Cache pip
84
- uses: actions/cache@v4
84
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
85
85
  with:
86
86
  path: ~/.cache/pip
87
87
  key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
@@ -96,9 +96,9 @@ jobs:
96
96
  name: Run Tests
97
97
  runs-on: ubuntu-latest
98
98
  steps:
99
- - uses: actions/checkout@v4
99
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
100
100
  - name: Set up Python
101
- uses: actions/setup-python@v5
101
+ uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
102
102
  with:
103
103
  python-version: ${{ env.PYTHON_VERSION }}
104
104
  - name: Configure git for tests
@@ -107,7 +107,7 @@ jobs:
107
107
  git config --global user.name "Test Runner"
108
108
  git config --global init.defaultBranch main
109
109
  - name: Cache pip
110
- uses: actions/cache@v4
110
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
111
111
  with:
112
112
  path: ~/.cache/pip
113
113
  key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
@@ -122,5 +122,7 @@ jobs:
122
122
  coverage run -m pytest tests/ -v
123
123
  coverage xml
124
124
  coverage report
125
- - name: Upload coverage reports
126
- uses: codecov/codecov-action@v3
125
+ # Disabled: v3's Node runtime is gone from the runners. Re-enable with a
126
+ # current major version, which renamed several inputs.
127
+ # - name: Upload coverage reports
128
+ # uses: codecov/codecov-action@v3
@@ -16,7 +16,7 @@ jobs:
16
16
  name: Parse under Windows PowerShell 5.1
17
17
  runs-on: windows-latest
18
18
  steps:
19
- - uses: actions/checkout@v4
19
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
20
20
 
21
21
  # The install scripts are fetched over HTTP and executed on stock Windows,
22
22
  # where powershell.exe (5.1) is the default shell. 5.1 reads BOM-less files
@@ -96,7 +96,7 @@ jobs:
96
96
  name: Parse under PowerShell 7
97
97
  runs-on: windows-latest
98
98
  steps:
99
- - uses: actions/checkout@v4
99
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
100
100
 
101
101
  - name: Parse each script with 7
102
102
  shell: pwsh
@@ -12,11 +12,11 @@ jobs:
12
12
  if: github.event.pull_request.merged == true
13
13
  steps:
14
14
  - name: Send notification to Slack
15
- uses: slackapi/slack-github-action@v1.24.0
15
+ uses: slackapi/slack-github-action@dcb1066f776dd043e64d0e8ba94ca15cc7e1875d # v4.0.0
16
16
  with:
17
+ webhook: ${{ secrets.SLACK_WEBHOOK_URL }}
18
+ webhook-type: incoming-webhook
17
19
  payload: |
18
20
  {
19
21
  "text": ${{ toJSON(format('[Codeplain Client] PR <{0}|#{1}: {2}> was merged to main by `{3}`.', github.event.pull_request.html_url, github.event.pull_request.number, github.event.pull_request.title, github.actor)) }}
20
22
  }
21
- env:
22
- SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
@@ -18,7 +18,7 @@ jobs:
18
18
  SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
19
19
 
20
20
  steps:
21
- - uses: actions/checkout@v4
21
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
22
22
 
23
23
  - name: Upload install scripts to R2
24
24
  env:
@@ -19,7 +19,7 @@ jobs:
19
19
  SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
20
20
 
21
21
  steps:
22
- - uses: actions/checkout@v4
22
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
23
23
  with:
24
24
  # hatch-vcs derives the version from git tags, so we need full history.
25
25
  fetch-depth: 0
@@ -46,7 +46,7 @@ jobs:
46
46
  ls -l dist/
47
47
 
48
48
  - name: Store the distribution packages
49
- uses: actions/upload-artifact@v4
49
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
50
50
  with:
51
51
  name: python-package-distributions
52
52
  path: dist/
@@ -81,13 +81,13 @@ jobs:
81
81
 
82
82
  steps:
83
83
  - name: Download distribution packages
84
- uses: actions/download-artifact@v4
84
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
85
85
  with:
86
86
  name: python-package-distributions
87
87
  path: dist/
88
88
 
89
89
  - name: Publish to PyPI
90
- uses: pypa/gh-action-pypi-publish@release/v1
90
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
91
91
 
92
92
  - name: Notify Slack (success)
93
93
  if: ${{ success() && env.SLACK_WEBHOOK_URL != '' }}
@@ -115,3 +115,45 @@ jobs:
115
115
  curl -s -X POST "$SLACK_WEBHOOK_URL" \
116
116
  -H 'Content-type: application/json' \
117
117
  --data "{\"text\":\"*Codeplain Client*: Publishing \`${{ github.ref_name }}\` to PyPI FAILED :x:. See <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|the run log>.\"}"
118
+
119
+ # Release pipelines to be turned on only after the rest of the infrastructure
120
+ # is ready.
121
+ #
122
+ # # Runs only after the package is on PyPI. Kept as its own job so the publish job
123
+ # # keeps its minimal permissions and no checkout.
124
+ # linear-release:
125
+ # name: Record release in Linear
126
+ # needs: publish-to-pypi
127
+ # runs-on: ubuntu-latest
128
+ #
129
+ # permissions:
130
+ # contents: read
131
+ #
132
+ # env:
133
+ # SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
134
+ #
135
+ # steps:
136
+ # - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
137
+ # with:
138
+ # # The scan needs full history.
139
+ # fetch-depth: 0
140
+ #
141
+ # # Non-fatal: the package is already published.
142
+ # - name: Record release in Linear
143
+ # id: linear
144
+ # continue-on-error: true
145
+ # uses: linear/linear-release-action@0a25abab892a91062ebf42260dbb2ce6277aa205 # v0.16.0
146
+ # with:
147
+ # access_key: ${{ secrets.LINEAR_ACCESS_KEY }}
148
+ # version: ${{ github.ref_name }}
149
+ # # Pin the CLI the action downloads, not just the action.
150
+ # cli_version: v0.16.0
151
+ #
152
+ # # continue-on-error keeps the job green, so this checks the step's own
153
+ # # outcome — `failure()` would never fire.
154
+ # - name: Notify Slack (release not recorded)
155
+ # if: ${{ steps.linear.outcome == 'failure' && env.SLACK_WEBHOOK_URL != '' }}
156
+ # run: |
157
+ # curl -s -X POST "$SLACK_WEBHOOK_URL" \
158
+ # -H 'Content-type: application/json' \
159
+ # --data "{\"text\":\"*Codeplain Client*: \`${{ github.ref_name }}\` is on PyPI, but recording it in Linear FAILED :warning:. See <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|the run log>.\"}"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: codeplain
3
- Version: 0.3.10.dev2
3
+ Version: 0.3.10.dev4
4
4
  Summary: Transform plain language specifications into working code
5
5
  License-File: LICENSE
6
6
  Classifier: Environment :: Console
@@ -254,7 +254,7 @@ class CodeplainAPI:
254
254
 
255
255
  return self.post_request(endpoint_url, headers, payload, run_state)
256
256
 
257
- def create_conformance_test_memory(
257
+ def distill_conformance_test_memory(
258
258
  self,
259
259
  frid,
260
260
  plain_source_tree,
@@ -263,15 +263,10 @@ class CodeplainAPI:
263
263
  memory_files_content,
264
264
  module_name,
265
265
  required_modules,
266
- code_diff,
267
- conformance_tests_files,
268
- acceptance_tests,
269
- conformance_tests_issue,
270
- conformance_tests_folder_name,
271
- previous_conformance_tests_issue_old,
266
+ fix_journals,
272
267
  run_state: RunState,
273
268
  ):
274
- endpoint_url = f"{self.api_url}/create_conformance_test_memory"
269
+ endpoint_url = f"{self.api_url}/distill_conformance_test_memory"
275
270
  headers = {"X-API-Key": self.api_key, "Content-Type": "application/json"}
276
271
 
277
272
  payload = {
@@ -282,12 +277,7 @@ class CodeplainAPI:
282
277
  "memory_files_content": memory_files_content,
283
278
  "module_name": module_name,
284
279
  "required_modules": required_modules,
285
- "code_diff": code_diff,
286
- "conformance_tests_files": conformance_tests_files,
287
- "acceptance_tests": acceptance_tests,
288
- "conformance_tests_issue": conformance_tests_issue,
289
- "conformance_tests_folder_name": conformance_tests_folder_name,
290
- "previous_conformance_tests_issue": previous_conformance_tests_issue_old,
280
+ "fix_journals": fix_journals,
291
281
  }
292
282
 
293
283
  return self.post_request(endpoint_url, headers, payload, run_state)
@@ -381,6 +371,7 @@ class CodeplainAPI:
381
371
  conformance_tests_folder_name,
382
372
  current_testing_frid_high_level_implementation_plan: Optional[str],
383
373
  conflicting_requirements_count: int,
374
+ fix_attempts_journal: list,
384
375
  run_state: RunState,
385
376
  ):
386
377
  endpoint_url = f"{self.api_url}/fix_conformance_tests_issue"
@@ -403,6 +394,7 @@ class CodeplainAPI:
403
394
  "conformance_tests_folder_name": conformance_tests_folder_name,
404
395
  "current_testing_frid_high_level_implementation_plan": current_testing_frid_high_level_implementation_plan,
405
396
  "conflicting_requirements_count": conflicting_requirements_count,
397
+ "fix_attempts_journal": fix_attempts_journal,
406
398
  }
407
399
 
408
400
  if acceptance_tests is not None:
@@ -0,0 +1,207 @@
1
+ """Deterministic journal of conformance tests fix attempts.
2
+
3
+ While a functionality's conformance tests are failing, every fix attempt is recorded here: the
4
+ issue that triggered it, what the fixer said it tried, which files it changed and whether the tests
5
+ passed afterwards. A digest of the journal is sent back with every fix request so the fixer does
6
+ not repeat attempts that already failed, and once the functionality's conformance tests all pass
7
+ the journal is distilled into durable memories and deleted.
8
+
9
+ Each entry carries the issue in two forms: the raw script output (kept untruncated, on disk only)
10
+ and the prepared form the server built for the fix prompt (trimmed, and summarized or truncated
11
+ when oversized) - the issue exactly the way the fixer saw it. The prepared form is what travels in
12
+ the fix digest and the distillation payload; the raw form exists for humans debugging a render.
13
+ An attempt's outcome text is not stored twice: the output produced after an attempt is the raw
14
+ issue of the next attempt.
15
+
16
+ Journals are keyed by the (module, frid) whose tests are being fixed - during the regression sweep
17
+ that can be a previously implemented functionality, possibly from a required module.
18
+ """
19
+
20
+ import hashlib
21
+ import json
22
+ import os
23
+ import shutil
24
+
25
+ from plain2code_console import console
26
+
27
+ CONFORMANCE_TEST_JOURNAL_SUBFOLDER = "conformance_test_journal"
28
+
29
+ # Cap for the issue excerpts included in payloads (the per-attempt issue in the fix digest, and the
30
+ # initial issue in the distillation payload). The server-prepared issue is already bounded (LLM
31
+ # summary or ~10k-char truncation), so this only trims the rare oversized case - it must not
32
+ # routinely cut into summaries the server already sized for a prompt.
33
+ MAX_ISSUE_EXCERPT_CHARS = 8000
34
+
35
+ # The keys of a journal entry that make up the digest sent to the fixer and the distiller.
36
+ DIGEST_KEYS = ["attempt", "hypothesis", "approach", "target", "files_changed", "duplicate_of", "result"]
37
+
38
+
39
+ def _trim_issue(issue: str | None, max_chars: int) -> str | None:
40
+ if issue is None or len(issue) <= max_chars:
41
+ return issue
42
+ return f"(TRUNCATED - showing the last {max_chars} characters)\n" + issue[-max_chars:]
43
+
44
+
45
+ def normalized_diff_hash(diff_files: dict[str, str] | None) -> str | None:
46
+ """Hashes a fix's diff so that essentially identical retries can be detected.
47
+
48
+ Whitespace-only differences are ignored - a fix that reproduces an earlier failed change with
49
+ different formatting is still the same attempt.
50
+ """
51
+ if not diff_files:
52
+ return None
53
+
54
+ normalized_parts = []
55
+ for file_name in sorted(diff_files):
56
+ content_lines = [line.strip() for line in (diff_files[file_name] or "").splitlines() if line.strip()]
57
+ normalized_parts.append(file_name + "\n" + "\n".join(content_lines))
58
+
59
+ return hashlib.sha256("\n".join(normalized_parts).encode("utf-8")).hexdigest()
60
+
61
+
62
+ class FixAttemptJournal:
63
+ """File-backed journal, one JSONL file per (module, frid) whose conformance tests are fixed."""
64
+
65
+ def __init__(self, memory_folder: str):
66
+ self.journal_folder = os.path.join(memory_folder, CONFORMANCE_TEST_JOURNAL_SUBFOLDER)
67
+
68
+ def _journal_path(self, module_name: str, frid: str) -> str:
69
+ return os.path.join(self.journal_folder, f"{module_name}__{frid}.jsonl")
70
+
71
+ def _read_entries(self, module_name: str, frid: str) -> list[dict]:
72
+ journal_path = self._journal_path(module_name, frid)
73
+ if not os.path.exists(journal_path):
74
+ return []
75
+
76
+ entries = []
77
+ with open(journal_path, "r", encoding="utf-8") as journal_file:
78
+ for line in journal_file:
79
+ line = line.strip()
80
+ if not line:
81
+ continue
82
+ try:
83
+ entries.append(json.loads(line))
84
+ except json.JSONDecodeError:
85
+ console.error(f"Skipping malformed journal entry in {journal_path}.")
86
+
87
+ return entries
88
+
89
+ def _write_entries(self, module_name: str, frid: str, entries: list[dict]):
90
+ os.makedirs(self.journal_folder, exist_ok=True)
91
+ with open(self._journal_path(module_name, frid), "w", encoding="utf-8") as journal_file:
92
+ for entry in entries:
93
+ journal_file.write(json.dumps(entry) + "\n")
94
+
95
+ def open_attempt(self, module_name: str, frid: str, attempt_no: int, issue_before: str):
96
+ """Starts a new journal entry for a fix attempt that is about to be made.
97
+
98
+ The raw issue is stored untruncated - it never travels in a payload, only its prepared form
99
+ (recorded later by record_fix) does.
100
+ """
101
+ entries = self._read_entries(module_name, frid)
102
+ entries.append({"attempt": attempt_no, "issue_before_raw": issue_before})
103
+ self._write_entries(module_name, frid, entries)
104
+
105
+ def record_fix(
106
+ self,
107
+ module_name: str,
108
+ frid: str,
109
+ fix_attempt_summary: dict | None,
110
+ files_changed: list[str],
111
+ target: str,
112
+ diff_files: dict[str, str] | None,
113
+ prepared_issue: str | None,
114
+ ):
115
+ """Completes the open attempt with what the fix actually did.
116
+
117
+ The prepared issue is the form the server built for the fix prompt - the issue exactly the
118
+ way the fixer saw it. The diff hash marks the attempt as a duplicate when an earlier attempt
119
+ in the same journal produced essentially the same change - the strongest signal that the
120
+ fixer is going in circles.
121
+ """
122
+ entries = self._read_entries(module_name, frid)
123
+ if not entries:
124
+ console.error("Cannot record a fix - no journal entry is open.")
125
+ return
126
+
127
+ entry = entries[-1]
128
+ if isinstance(fix_attempt_summary, dict):
129
+ entry["hypothesis"] = fix_attempt_summary.get("hypothesis")
130
+ entry["approach"] = fix_attempt_summary.get("approach")
131
+ if prepared_issue:
132
+ entry["issue_before"] = prepared_issue
133
+ entry["files_changed"] = sorted(files_changed)
134
+ entry["target"] = target
135
+
136
+ diff_hash = normalized_diff_hash(diff_files)
137
+ entry["diff_hash"] = diff_hash
138
+ if diff_hash is not None:
139
+ for earlier_entry in entries[:-1]:
140
+ if earlier_entry.get("diff_hash") == diff_hash:
141
+ entry["duplicate_of"] = earlier_entry["attempt"]
142
+ break
143
+
144
+ self._write_entries(module_name, frid, entries)
145
+
146
+ def record_result(self, module_name: str, frid: str, passed: bool):
147
+ """Records whether the conformance tests passed after the last fix attempt was applied.
148
+
149
+ A failed run's output is not stored here - it becomes the raw issue of the next attempt.
150
+ Does nothing when no attempt is pending: the first test run of a functionality has no fix
151
+ attempt behind it.
152
+ """
153
+ entries = self._read_entries(module_name, frid)
154
+ if not entries or "result" in entries[-1]:
155
+ return
156
+
157
+ entries[-1]["result"] = "conformance tests passed" if passed else "conformance tests still failed"
158
+ self._write_entries(module_name, frid, entries)
159
+
160
+ def build_digest(self, module_name: str, frid: str) -> list[dict]:
161
+ """Builds the compact attempt history sent with a fix request.
162
+
163
+ Only attempts whose fix has been recorded are included - the entry just opened for the
164
+ attempt being made (and any dangling entry an interrupted render left behind) carries no
165
+ information for the fixer. Each included attempt carries the prepared issue it addressed,
166
+ so the fixer can see how the issue evolved across attempts. Raw outputs never travel - the
167
+ current issue is sent with the request separately.
168
+ """
169
+ return [self._digest_entry(entry) for entry in self._read_entries(module_name, frid) if "target" in entry]
170
+
171
+ @staticmethod
172
+ def _digest_entry(entry: dict) -> dict:
173
+ digest_entry = {key: entry[key] for key in DIGEST_KEYS if key in entry}
174
+ if entry.get("issue_before"):
175
+ digest_entry["issue"] = _trim_issue(entry["issue_before"], MAX_ISSUE_EXCERPT_CHARS)
176
+ return digest_entry
177
+
178
+ def collect_all(self) -> list[dict]:
179
+ """Collects the digests of every journal, keyed by the tested module and frid, for distillation."""
180
+ if not os.path.exists(self.journal_folder):
181
+ return []
182
+
183
+ journals = []
184
+ for file_name in sorted(os.listdir(self.journal_folder)):
185
+ if not file_name.endswith(".jsonl") or "__" not in file_name:
186
+ continue
187
+ module_name, _, frid = file_name[: -len(".jsonl")].rpartition("__")
188
+ entries = [entry for entry in self._read_entries(module_name, frid) if "target" in entry]
189
+ if not entries:
190
+ continue
191
+ initial_issue = entries[0].get("issue_before") or _trim_issue(
192
+ entries[0].get("issue_before_raw"), MAX_ISSUE_EXCERPT_CHARS
193
+ )
194
+ journal = {
195
+ "module": module_name,
196
+ "frid": frid,
197
+ "initial_issue": initial_issue,
198
+ "attempts": [self._digest_entry(entry) for entry in entries],
199
+ }
200
+ journals.append(journal)
201
+
202
+ return journals
203
+
204
+ def clear_all(self):
205
+ """Deletes every journal. Called after the journals have been distilled into memories."""
206
+ if os.path.exists(self.journal_folder):
207
+ shutil.rmtree(self.journal_folder)
@@ -0,0 +1,52 @@
1
+ import os
2
+
3
+ import file_utils
4
+ from conformance_fix_journal import FixAttemptJournal
5
+ from plain2code_console import console
6
+
7
+ CONFORMANCE_TEST_MEMORY_SUBFOLDER = "conformance_test_memory"
8
+
9
+
10
+ class MemoryManager:
11
+ """Manages a module's memory store at <build>/<module>/.memory.
12
+
13
+ The distilled memories are inherited by the next module in the chain (copied over when its
14
+ render starts, like the code repo), so learnings travel across modules.
15
+ """
16
+
17
+ @staticmethod
18
+ def fetch_memory_files(memory_folder: str) -> tuple[list[str], dict[str, str]]:
19
+ """Fetch memory files from memory_folder/conformance_test_memory."""
20
+ memory_path = os.path.join(memory_folder, CONFORMANCE_TEST_MEMORY_SUBFOLDER)
21
+ if not os.path.exists(memory_path):
22
+ return [], {}
23
+ memory_files = file_utils.list_all_text_files(memory_path)
24
+ memory_files_content = file_utils.get_existing_files_content(memory_path, memory_files)
25
+ console.debug(f"Loaded {len(memory_files_content)} memory files.")
26
+ return memory_files, memory_files_content
27
+
28
+ def __init__(self, codeplain_api, memory_folder: str):
29
+ self.codeplain_api = codeplain_api
30
+ self.memory_folder = memory_folder
31
+ self.journal = FixAttemptJournal(memory_folder)
32
+
33
+ def store_memory_files(self, response_files: dict[str, str]):
34
+ """Stores distilled memory files, applying deletions (None content) to existing memories."""
35
+ memory_path = os.path.join(self.memory_folder, CONFORMANCE_TEST_MEMORY_SUBFOLDER)
36
+ memory_files, _ = MemoryManager.fetch_memory_files(self.memory_folder)
37
+ file_utils.store_response_files(memory_path, response_files, memory_files)
38
+
39
+ @staticmethod
40
+ def inherit_memories(source_memory_folder: str, destination_memory_folder: str):
41
+ """Copies the distilled memories of a previously rendered module into this module's store.
42
+
43
+ Only the distilled memories travel - fix attempt journals are transient state of one
44
+ module's render. A previous module without memories (e.g. shipped as an archive that
45
+ carries only code) is a no-op.
46
+ """
47
+ source_path = os.path.join(source_memory_folder, CONFORMANCE_TEST_MEMORY_SUBFOLDER)
48
+ if not os.path.isdir(source_path):
49
+ return
50
+ file_utils.copy_folder_content(
51
+ source_path, os.path.join(destination_memory_folder, CONFORMANCE_TEST_MEMORY_SUBFOLDER)
52
+ )