rpr-cli 0.1.28__tar.gz → 0.1.30__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 (273) hide show
  1. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/PKG-INFO +2 -1
  2. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/README.md +1 -0
  3. rpr_cli-0.1.30/src/rpr/__init__.py +1 -0
  4. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/commands/generate/domain.py +6 -1
  5. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/context.py +37 -9
  6. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/instructions/domain.instructions.md +1 -1
  7. rpr_cli-0.1.30/src/rpr/scaffolds/special_files/camel_case_model.md +60 -0
  8. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/templates/registry.py +6 -0
  9. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/02-rpr-generate-domain.md +2 -2
  10. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/08-rpr-add-template.md +1 -0
  11. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_add.py +75 -0
  12. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_context.py +42 -0
  13. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_generate_domain.py +37 -0
  14. rpr_cli-0.1.28/src/rpr/__init__.py +0 -1
  15. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/.github/agents/story.agent.md +0 -0
  16. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/.github/workflows/publish-pypi.yml +0 -0
  17. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/.gitignore +0 -0
  18. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/CLAUDE.md +0 -0
  19. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/GEMINI.md +0 -0
  20. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/LICENSE +0 -0
  21. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/Sample-dot-github/instructions/all.instructions.md +0 -0
  22. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/Sample-dot-github/instructions/api.instructions.md +0 -0
  23. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/Sample-dot-github/instructions/domain.instructions.md +0 -0
  24. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/Sample-dot-github/instructions/frontend.instructions.md +0 -0
  25. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/Sample-dot-github/instructions/rust-engine.instructions.md +0 -0
  26. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/Sample-dot-github/instructions/setup-guide.instructions.md +0 -0
  27. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/Sample-dot-github/instructions/tooling-setup.instructions.md +0 -0
  28. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/Sample-dot-github/instructions/tooling.instructions.md +0 -0
  29. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/Sample-dot-github/scaffolds/README.md +0 -0
  30. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/Sample-dot-github/scaffolds/api/main.py +0 -0
  31. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/Sample-dot-github/scaffolds/domain/base-repo.md +0 -0
  32. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/Sample-dot-github/scaffolds/domain/base_entity.md +0 -0
  33. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/Sample-dot-github/scaffolds/frontend/api.service.ts +0 -0
  34. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/Sample-dot-github/scaffolds/frontend/useStateNavigation.ts +0 -0
  35. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/Sample-dot-github/scaffolds/frontend/virtual-list/VirtualComponent.spec.tsx +0 -0
  36. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/Sample-dot-github/scaffolds/frontend/virtual-list/VirtualComponent.tsx +0 -0
  37. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/Sample-dot-github/scaffolds/frontend/virtual-list/VirtualComponentList.spec.tsx +0 -0
  38. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/Sample-dot-github/scaffolds/frontend/virtual-list/VirtualComponentList.tsx +0 -0
  39. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/Sample-dot-github/scaffolds/frontend/virtual-list/index.ts +0 -0
  40. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/changelogs/mui_v9.txt +0 -0
  41. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/code-map.md +0 -0
  42. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/nx_uv_setup.md +0 -0
  43. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/patch_output.py +0 -0
  44. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/plan-languageAwareTemplateAdd.prompt.md +0 -0
  45. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/pyproject.toml +0 -0
  46. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/rpr-parser/Cargo.lock +0 -0
  47. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/rpr-parser/Cargo.toml +0 -0
  48. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/rpr-parser/pyproject.toml +0 -0
  49. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/rpr-parser/rpr_parser.pyi +0 -0
  50. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/rpr-parser/src/config/container.rs +0 -0
  51. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/rpr-parser/src/config/mod.rs +0 -0
  52. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/rpr-parser/src/config/settings.rs +0 -0
  53. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/rpr-parser/src/graph.rs +0 -0
  54. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/rpr-parser/src/lib.rs +0 -0
  55. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/rpr-parser/src/models/dtos/mod.rs +0 -0
  56. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/rpr-parser/src/models/entities/mod.rs +0 -0
  57. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/rpr-parser/src/models/entities/users.rs +0 -0
  58. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/rpr-parser/src/models/mod.rs +0 -0
  59. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/rpr-parser/src/parse.rs +0 -0
  60. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/rpr-parser/src/repos/base.rs +0 -0
  61. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/rpr-parser/src/repos/mod.rs +0 -0
  62. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/rpr-parser/src/repos/users.rs +0 -0
  63. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/rpr-parser/src/resolve.rs +0 -0
  64. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/rpr-parser/src/walker.rs +0 -0
  65. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/rpr-parser/uv.lock +0 -0
  66. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/special_files.md +0 -0
  67. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/agent/__init__.py +0 -0
  68. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/agent/approval.py +0 -0
  69. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/agent/bootstrap.py +0 -0
  70. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/agent/client.py +0 -0
  71. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/agent/control.py +0 -0
  72. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/agent/mock.py +0 -0
  73. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/agent/runtime.py +0 -0
  74. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/agent/session.py +0 -0
  75. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/agent/tools/__init__.py +0 -0
  76. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/agent/tools/base.py +0 -0
  77. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/agent/tools/mutating.py +0 -0
  78. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/agent/tools/readonly.py +0 -0
  79. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/agent/tools/registry.py +0 -0
  80. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/application/__init__.py +0 -0
  81. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/application/catalog.py +0 -0
  82. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/application/chat_service.py +0 -0
  83. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/application/checks.py +0 -0
  84. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/application/cli_adapter.py +0 -0
  85. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/application/completer.py +0 -0
  86. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/application/conversation_service.py +0 -0
  87. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/application/prompt_service.py +0 -0
  88. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/application/selector.py +0 -0
  89. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/application/shell.py +0 -0
  90. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/checks/__init__.py +0 -0
  91. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/checks/base.py +0 -0
  92. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/checks/instructions.py +0 -0
  93. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/checks/packages.py +0 -0
  94. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/checks/workspace.py +0 -0
  95. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/cli.py +0 -0
  96. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/commands/__init__.py +0 -0
  97. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/commands/add.py +0 -0
  98. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/commands/chat.py +0 -0
  99. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/commands/check.py +0 -0
  100. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/commands/generate/__init__.py +0 -0
  101. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/commands/generate/api.py +0 -0
  102. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/commands/generate/engine.py +0 -0
  103. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/commands/generate/storybook.py +0 -0
  104. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/commands/generate/ui.py +0 -0
  105. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/commands/init.py +0 -0
  106. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/commands/map.py +0 -0
  107. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/commands/refresh.py +0 -0
  108. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/commands/settings.py +0 -0
  109. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/commands/sync.py +0 -0
  110. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/dependencies.py +0 -0
  111. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/dependency_manifest_data.py +0 -0
  112. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/generators/__init__.py +0 -0
  113. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/generators/base.py +0 -0
  114. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/generators/claude.py +0 -0
  115. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/generators/copilot.py +0 -0
  116. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/generators/cursor.py +0 -0
  117. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/generators/gemini.py +0 -0
  118. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/generators/github.py +0 -0
  119. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/manifest_refresh.py +0 -0
  120. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/map/__init__.py +0 -0
  121. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/map/architecture.py +0 -0
  122. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/map/chains.py +0 -0
  123. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/map/classifier.py +0 -0
  124. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/map/coverage.py +0 -0
  125. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/map/dependencies.py +0 -0
  126. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/map/extractor.py +0 -0
  127. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/map/graph.py +0 -0
  128. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/map/output.py +0 -0
  129. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/map/responsibility.py +0 -0
  130. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/map/topology.py +0 -0
  131. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/map/walker.py +0 -0
  132. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/domain/base_entity.md +0 -0
  133. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/domain/base_repo.md +0 -0
  134. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/domain/container.md +0 -0
  135. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/domain/settings.md +0 -0
  136. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/instructions/all.instructions.md +0 -0
  137. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/instructions/api.instructions.md +0 -0
  138. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/instructions/frontend.instructions.md +0 -0
  139. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/instructions/rust-engine.instructions.md +0 -0
  140. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/instructions/setup-guide.instructions.md +0 -0
  141. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/instructions/tooling-setup.instructions.md +0 -0
  142. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/instructions/tooling.instructions.md +0 -0
  143. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/README.md +0 -0
  144. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/client/index.ts +0 -0
  145. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/client/types.ts +0 -0
  146. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/composer/ChatComposer.spec.tsx +0 -0
  147. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/composer/ChatComposer.tsx +0 -0
  148. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/composer/__screenshots__/ChatComposer.spec.tsx/ChatComposer-renders-custom-action-buttons-beside-the-attachment-control-1.png +0 -0
  149. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/composer/fileDrop.spec.ts +0 -0
  150. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/composer/fileDrop.ts +0 -0
  151. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/composer/index.ts +0 -0
  152. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/composer/suggestions/ChatComposerMentionTokens.tsx +0 -0
  153. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/composer/suggestions/ChatSuggestionsPopover.tsx +0 -0
  154. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/composer/suggestions/LocalFileSuggestionAction.tsx +0 -0
  155. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/composer/suggestions/index.ts +0 -0
  156. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/composer/suggestions/localFileSuggestions.spec.ts +0 -0
  157. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/composer/suggestions/localFileSuggestions.ts +0 -0
  158. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/composer/suggestions/triggerDetection.spec.ts +0 -0
  159. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/composer/suggestions/triggerDetection.ts +0 -0
  160. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/composer/suggestions/types.ts +0 -0
  161. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/composer/suggestions/useChatSuggestions.ts +0 -0
  162. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/composer/types.ts +0 -0
  163. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/composer/useChatComposer.ts +0 -0
  164. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/composer/useChatStream.spec.tsx +0 -0
  165. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/composer/useChatStream.ts +0 -0
  166. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/index.ts +0 -0
  167. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/testing/createMockChatStreamClient.ts +0 -0
  168. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/testing/createMockSuggestionProvider.ts +0 -0
  169. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/testing/index.ts +0 -0
  170. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/thread/ChatMessage.tsx +0 -0
  171. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/thread/ChatMessageContent.spec.tsx +0 -0
  172. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/thread/ChatMessageContent.tsx +0 -0
  173. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/thread/ChatThread.spec.tsx +0 -0
  174. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/thread/ChatThread.tsx +0 -0
  175. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/thread/README.md +0 -0
  176. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/thread/contentFormat.ts +0 -0
  177. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/thread/index.ts +0 -0
  178. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/thread/streaming.ts +0 -0
  179. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/thread/types.ts +0 -0
  180. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/virtual-list/VirtualComponent.spec.tsx +0 -0
  181. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/virtual-list/VirtualComponent.tsx +0 -0
  182. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/virtual-list/VirtualComponentList.spec.tsx +0 -0
  183. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/virtual-list/VirtualComponentList.tsx +0 -0
  184. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/chat/virtual-list/index.ts +0 -0
  185. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/fetch.service.md +0 -0
  186. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/sticky-navigation.md +0 -0
  187. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/sticky-navigation.spec.md +0 -0
  188. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/js_special_files/vitest-browser-config.md +0 -0
  189. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/special_files/domain_container.md +0 -0
  190. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/special_files/domain_settings.md +0 -0
  191. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/special_files/dto_util.md +0 -0
  192. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/special_files/encrypted_column.md +0 -0
  193. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/special_files/mapper_util.md +0 -0
  194. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/scaffolds/special_files/partial_update.md +0 -0
  195. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/templates/__init__.py +0 -0
  196. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/ui/__init__.py +0 -0
  197. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/ui/console.py +0 -0
  198. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/ui/markdown.py +0 -0
  199. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/ui/prompt_session.py +0 -0
  200. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/ui/renderers.py +0 -0
  201. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/ui/theme.py +0 -0
  202. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/src/rpr/workspace.py +0 -0
  203. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/README.md +0 -0
  204. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/00-bootstrap-cli.md +0 -0
  205. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/01-rpr-init.md +0 -0
  206. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/03-rpr-generate-api.md +0 -0
  207. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/04-rpr-generate-ui.md +0 -0
  208. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/05-rpr-generate-engine.md +0 -0
  209. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/06-rpr-generate-storybook.md +0 -0
  210. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/07-rpr-sync-rules.md +0 -0
  211. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/09-rpr-check.md +0 -0
  212. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/10-rpr-domain-config.md +0 -0
  213. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/chat/18-rpr-terminal-ui-foundation.md +0 -0
  214. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/chat/19-rpr-markdown-rendering.md +0 -0
  215. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/chat/20-rpr-chat-repl.md +0 -0
  216. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/chat/21-rpr-agent-tool-loop.md +0 -0
  217. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/chat/22-rpr-chat-tui.md +0 -0
  218. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/chat/23-rpr-chat-unified-command-shell.md +0 -0
  219. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/chat/24-rpr-async-chat-runtime-and-services.md +0 -0
  220. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/chat/25-rpr-prompt-service-and-conversation-lifecycle.md +0 -0
  221. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/chat/26-rpr-shared-command-catalog.md +0 -0
  222. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/chat/27-rpr-slash-command-selection-panel.md +0 -0
  223. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/chat/28-rpr-chat-cancellable-and-multiline-input.md +0 -0
  224. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/chat/29-rpr-file-context-selection.md +0 -0
  225. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/map/11-rpr-map-command.md +0 -0
  226. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/map/12-rpr-map-file-walker.md +0 -0
  227. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/map/13-rpr-map-rust-engine.md +0 -0
  228. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/map/13a-rpr-map-gitignore.md +0 -0
  229. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/map/14-rpr-map-graph-builder.md +0 -0
  230. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/map/15-rpr-map-analysis-bridge.md +0 -0
  231. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/map/16-rpr-map-layer-classifier.md +0 -0
  232. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/map/17-rpr-map-output.md +0 -0
  233. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/map/17a-rpr-map-directory-topology.md +0 -0
  234. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/map/17b-rpr-map-architecture-assessment.md +0 -0
  235. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/map/17c-rpr-map-representative-chains.md +0 -0
  236. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/completed/map/17d-rpr-map-multi-resolution-output.md +0 -0
  237. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/map/30-rpr-map-directory-view-and-cycle-detection.md +0 -0
  238. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/map/31-rpr-map-coupling-hotspots-and-verdict-reasoning.md +0 -0
  239. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/stories/map/32-rpr-map-dependencies-responsibilities-and-test-coverage.md +0 -0
  240. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/__init__.py +0 -0
  241. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_architecture.py +0 -0
  242. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_architecture_unwrapped.py +0 -0
  243. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_catalog.py +0 -0
  244. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_chat.py +0 -0
  245. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_chat_service.py +0 -0
  246. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_check.py +0 -0
  247. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_completer.py +0 -0
  248. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_generate_api.py +0 -0
  249. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_generate_engine.py +0 -0
  250. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_generate_storybook.py +0 -0
  251. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_generate_ui.py +0 -0
  252. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_init.py +0 -0
  253. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_map.py +0 -0
  254. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_map_chains.py +0 -0
  255. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_map_classifier.py +0 -0
  256. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_map_coverage.py +0 -0
  257. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_map_dependencies.py +0 -0
  258. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_map_extractor.py +0 -0
  259. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_map_graph.py +0 -0
  260. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_map_output.py +0 -0
  261. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_map_responsibility.py +0 -0
  262. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_map_topology.py +0 -0
  263. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_map_walker.py +0 -0
  264. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_packaging.py +0 -0
  265. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_prompt_session.py +0 -0
  266. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_refresh.py +0 -0
  267. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_rpr_parser_stub.py +0 -0
  268. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_selector.py +0 -0
  269. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_settings.py +0 -0
  270. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_sync.py +0 -0
  271. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/tests/test_ui.py +0 -0
  272. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/update_output.py +0 -0
  273. {rpr_cli-0.1.28 → rpr_cli-0.1.30}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rpr-cli
3
- Version: 0.1.28
3
+ Version: 0.1.30
4
4
  Summary: RPR CLI -- React Python Rust monorepo scaffolding orchestrator
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -109,6 +109,7 @@ Sync project context to your favorite AI tools and add common code patterns.
109
109
  ```bash
110
110
  rpr sync rules # Sync AI instructions to Cursor, Copilot, Claude Code, and Gemini
111
111
  rpr add template python mapper_util # Add a Python code template to your project
112
+ rpr add template python camel_case_model
112
113
  rpr add template node sticky_navigation --include-tests
113
114
  rpr add template node -l # List available Node/TSX templates
114
115
  rpr add template --list # List all available code templates
@@ -94,6 +94,7 @@ Sync project context to your favorite AI tools and add common code patterns.
94
94
  ```bash
95
95
  rpr sync rules # Sync AI instructions to Cursor, Copilot, Claude Code, and Gemini
96
96
  rpr add template python mapper_util # Add a Python code template to your project
97
+ rpr add template python camel_case_model
97
98
  rpr add template node sticky_navigation --include-tests
98
99
  rpr add template node -l # List available Node/TSX templates
99
100
  rpr add template --list # List all available code templates
@@ -0,0 +1 @@
1
+ __version__ = "0.1.30"
@@ -17,7 +17,12 @@ console = Console()
17
17
 
18
18
  _SCAFFOLD_DIR = Path(__file__).parent.parent.parent / "scaffolds" / "domain"
19
19
 
20
- _UTILITY_TEMPLATES = ["mapper_util", "dto_util", "partial_update"]
20
+ _UTILITY_TEMPLATES = [
21
+ "mapper_util",
22
+ "dto_util",
23
+ "camel_case_model",
24
+ "partial_update",
25
+ ]
21
26
 
22
27
 
23
28
  @generate_app.command()
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import os
4
+ import shutil
4
5
  import subprocess
5
6
  from dataclasses import dataclass, field
6
7
  from pathlib import Path
@@ -53,7 +54,7 @@ def _uv_activation_env(
53
54
  ) -> dict[str, str]:
54
55
  effective_env = dict(env or {})
55
56
  venv_dir = project_dir / ".venv"
56
- venv_bin = venv_dir / "bin"
57
+ venv_bin = venv_dir / ("Scripts" if os.name == "nt" else "bin")
57
58
  if venv_bin.exists():
58
59
  current_path = effective_env.get("PATH", os.environ.get("PATH", ""))
59
60
  effective_env["VIRTUAL_ENV"] = str(venv_dir)
@@ -61,6 +62,38 @@ def _uv_activation_env(
61
62
  return effective_env
62
63
 
63
64
 
65
+ def _resolve_windows_command_shim(
66
+ cmd: list[str], env: dict[str, str] | None = None
67
+ ) -> list[str]:
68
+ if os.name != "nt" or not cmd:
69
+ return cmd
70
+
71
+ executable = cmd[0]
72
+ if Path(executable).suffix or any(
73
+ separator and separator in executable for separator in (os.sep, os.altsep)
74
+ ):
75
+ return cmd
76
+
77
+ resolved = shutil.which(executable, path=(env or os.environ).get("PATH"))
78
+ if resolved is None:
79
+ return cmd
80
+
81
+ return [resolved, *cmd[1:]]
82
+
83
+
84
+ def _format_display_command(cmd: list[str], env: dict[str, str] | None = None) -> str:
85
+ display_cmd = " ".join(cmd)
86
+ if not env:
87
+ return display_cmd
88
+
89
+ if os.name == "nt":
90
+ env_prefix = "; ".join(f'$env:{key}="{value}"' for key, value in env.items())
91
+ return f"{env_prefix}; {display_cmd}"
92
+
93
+ env_prefix = " ".join(f"{key}={value}" for key, value in env.items())
94
+ return f"{env_prefix} {display_cmd}"
95
+
96
+
64
97
  @dataclass
65
98
  class RunContext:
66
99
  dry_run: bool = False
@@ -95,11 +128,7 @@ class RunContext:
95
128
  supports_dry_run: bool = False,
96
129
  ) -> subprocess.CompletedProcess[str]:
97
130
  resolved_cwd = str(cwd) if cwd else str(self.project_dir)
98
- env_prefix = " ".join(f"{key}={value}" for key, value in (env or {}).items())
99
-
100
- display_cmd = " ".join(cmd)
101
- if env_prefix:
102
- display_cmd = f"{env_prefix} {display_cmd}"
131
+ display_cmd = _format_display_command(cmd, env)
103
132
 
104
133
  if self.dry_run and not supports_dry_run:
105
134
  render_command_start(display_cmd, resolved_cwd, is_dry_run=True)
@@ -109,9 +138,7 @@ class RunContext:
109
138
  cmd + ["--dry-run"] if (self.dry_run and supports_dry_run) else cmd
110
139
  )
111
140
  if self.dry_run and supports_dry_run:
112
- display_cmd = " ".join(effective_cmd)
113
- if env_prefix:
114
- display_cmd = f"{env_prefix} {display_cmd}"
141
+ display_cmd = _format_display_command(effective_cmd, env)
115
142
 
116
143
  render_command_start(display_cmd, resolved_cwd, is_dry_run=False)
117
144
 
@@ -119,6 +146,7 @@ class RunContext:
119
146
  if env:
120
147
  effective_env = os.environ.copy()
121
148
  effective_env.update(env)
149
+ effective_cmd = _resolve_windows_command_shim(effective_cmd, effective_env)
122
150
  result = subprocess.run(
123
151
  effective_cmd,
124
152
  cwd=resolved_cwd,
@@ -78,7 +78,7 @@ npx nx run {name_underscore}_domain:migrate -- downgrade -1
78
78
  - Reuse existing DTOs when the contract is the same. Do not create near-duplicate DTOs for every small variation.
79
79
  - DTOs exposed through the API should stay minimal and focused on the contract, not internal persistence details.
80
80
  - Mapper functions should live in the DTO or mapper layer and follow a clear `to_dto()` naming convention.
81
- - DTOs that are serialized to JSON should use the project's camelCase-aware base model.
81
+ - DTOs that are serialized to JSON should inherit from `CamelCaseModel` in `utils/camel_case_model.py`.
82
82
  - DTOs that represent external-service payloads can use `TypedDict` when a Pydantic model would add unnecessary weight.
83
83
  - Internal data containers that are not serialized can use `@dataclass` when that is the simplest fit.
84
84
 
@@ -0,0 +1,60 @@
1
+ ## Camel Case Model Template
2
+
3
+ Target path: `/packages/python/{name_underscore}_domain/src/{name_underscore}_domain/utils/camel_case_model.py`
4
+
5
+ Use this base model for DTOs that should accept snake_case, camelCase, and PascalCase input while serializing JSON with camelCase field names.
6
+
7
+ The first Python block is the generated file used by `rpr add template camel_case_model`.
8
+
9
+ ```python
10
+ from pydantic import AliasChoices, AliasGenerator, BaseModel, ConfigDict
11
+ from pydantic.alias_generators import to_camel, to_pascal
12
+
13
+
14
+ def validation_alias_generator(field_name: str) -> AliasChoices:
15
+ """
16
+ Generate validation aliases for camelCase, PascalCase, and snake_case field names.
17
+
18
+ Examples:
19
+ rules_checked -> accepts: rulesChecked, RulesChecked, rules_checked
20
+ user_id -> accepts: userId, UserId, user_id
21
+ """
22
+ return AliasChoices(to_camel(field_name), to_pascal(field_name), field_name)
23
+
24
+
25
+ class CamelCaseModel(BaseModel):
26
+ """
27
+ Base model that accepts flexible input field names and serializes JSON as camelCase.
28
+ """
29
+
30
+ model_config = ConfigDict(
31
+ alias_generator=AliasGenerator(
32
+ validation_alias=validation_alias_generator,
33
+ serialization_alias=to_camel,
34
+ ),
35
+ populate_by_name=True,
36
+ ser_json_timedelta="float",
37
+ validate_assignment=True,
38
+ )
39
+ ```
40
+
41
+ ## Usage
42
+
43
+ ```python
44
+ from your_app_domain.utils.camel_case_model import CamelCaseModel
45
+
46
+
47
+ class RuleCheckDTO(CamelCaseModel):
48
+ rules_checked: int
49
+ user_id: str
50
+
51
+
52
+ dto = RuleCheckDTO(rulesChecked=3, UserId="user-1")
53
+ payload = dto.model_dump(by_alias=True)
54
+ ```
55
+
56
+ ## What This Template Solves
57
+
58
+ - API DTOs can accept payloads from clients that use snake_case, camelCase, or PascalCase.
59
+ - JSON serialization remains consistent by using camelCase aliases.
60
+ - Assignment validation stays enabled for DTO instances that are updated in code.
@@ -211,6 +211,12 @@ TEMPLATES: dict[str, TemplateEntry] = {
211
211
  source_filename="dto_util.md",
212
212
  target_path="packages/python/{name_underscore}_domain/src/{name_underscore}_domain/utils/dto_util.py",
213
213
  ),
214
+ "camel_case_model": python_template(
215
+ id="camel_case_model",
216
+ description="Pydantic BaseModel with camelCase JSON and flexible validation aliases",
217
+ source_filename="camel_case_model.md",
218
+ target_path="packages/python/{name_underscore}_domain/src/{name_underscore}_domain/utils/camel_case_model.py",
219
+ ),
214
220
  "partial_update": python_template(
215
221
  id="partial_update",
216
222
  description="apply_partial_update utility for PATCH endpoints",
@@ -74,8 +74,8 @@ The `project.json` must define at minimum `test` and `lint` targets. Use `uv run
74
74
 
75
75
  - The domain package name uses underscores in the Python import path (`{name_underscore}_domain`) and dashes in the directory and `pyproject.toml` name (`{name}-domain`).
76
76
  - Use `uv add` if stored dependencies need to be managed programmatically.
77
- - The utils folder is scaffolded empty; use `rpr add template mapper_util`, `rpr add template dto_util`, `rpr add template partial_update`, or `rpr add template encrypted_column` to add those utilities.
78
- - After scaffolding, offer to run `rpr add template` for the most common utilities (mapper_util, dto_util, partial_update).
77
+ - The utils folder is scaffolded empty; use `rpr add template mapper_util`, `rpr add template dto_util`, `rpr add template camel_case_model`, `rpr add template partial_update`, or `rpr add template encrypted_column` to add those utilities.
78
+ - After scaffolding, offer to run `rpr add template` for the most common utilities (mapper_util, dto_util, camel_case_model, partial_update).
79
79
  - `config/settings.py` and `config/container.py` are generated from `src/rpr/scaffolds/domain/settings.md` and `container.md` (bundled templates that mirror `special_files/domain_settings.md` and `special_files/domain_container.md`). They can be reset at any time via `rpr add template domain_settings` or `rpr add template domain_container`.
80
80
  - If the domain Container ever needs lifecycle hooks (startup/shutdown), see the lifecycle extension pattern documented in Story 10.
81
81
 
@@ -25,6 +25,7 @@ Neither `rpr init` nor `rpr generate ui` add these files directly — they deleg
25
25
  | `domain_container` | `special_files/domain_container.md` | `packages/python/domain/src/<name>_domain/config/container.py` |
26
26
  | `mapper_util` | `special_files/mapper_util.md` | Python domain package (e.g., `packages/python/domain/src/<name>_domain/utils/mapper_util.py`) |
27
27
  | `dto_util` | `special_files/dto_util.md` | Python domain package utils |
28
+ | `camel_case_model` | `special_files/camel_case_model.md` | Python domain package utils |
28
29
  | `partial_update` | `special_files/partial_update.md` | Python domain package utils |
29
30
  | `encrypted_column` | `special_files/encrypted_column.md` | Python domain package (models/config) |
30
31
  | `sticky_navigation` | `js_special_files/sticky-navigation.md` | `packages/node/<name>-ui/src/hooks/useStateNavigation.ts` |
@@ -1,7 +1,9 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import importlib.util
3
4
  from pathlib import Path
4
5
 
6
+ import pytest
5
7
  from typer.testing import CliRunner
6
8
 
7
9
  from rpr.cli import app
@@ -39,6 +41,7 @@ def test_add_template_list():
39
41
  assert "domain_settings" in result.stdout
40
42
  assert "domain_container" in result.stdout
41
43
  assert "mapper_util" in result.stdout
44
+ assert "camel_case_model" in result.stdout
42
45
  assert "sticky_navigation" in result.stdout
43
46
  assert "virtual_list" in result.stdout
44
47
  # Should show placeholders if no name/config
@@ -61,10 +64,12 @@ def test_add_template_list_by_language():
61
64
  assert "node fetch_service" in node_result.stdout
62
65
  assert "node virtual_list" in node_result.stdout
63
66
  assert "python mapper_util" not in node_result.stdout
67
+ assert "python camel_case_model" not in node_result.stdout
64
68
 
65
69
  python_result = runner.invoke(app, ["add", "template", "python", "--list"])
66
70
  assert python_result.exit_code == 0, python_result.stdout
67
71
  assert "python mapper_util" in python_result.stdout
72
+ assert "python camel_case_model" in python_result.stdout
68
73
  assert "python domain_settings" in python_result.stdout
69
74
  assert "node sticky_navigation" not in python_result.stdout
70
75
 
@@ -146,6 +151,76 @@ def test_add_domain_container_template_execution():
146
151
  assert "override __new__" in content
147
152
 
148
153
 
154
+ def test_add_camel_case_model_template_execution():
155
+ with runner.isolated_filesystem():
156
+ project_dir = Path.cwd()
157
+ scaffolds_dir = _repo_scaffolds_dir()
158
+ _write_rpr_config(scaffolds_dir)
159
+
160
+ result = runner.invoke(app, ["add", "template", "camel_case_model", "--force"])
161
+ assert result.exit_code == 0, result.stdout
162
+
163
+ target_path = (
164
+ project_dir
165
+ / "packages/python/test_app_domain/src/test_app_domain/utils/camel_case_model.py"
166
+ )
167
+ assert target_path.exists()
168
+
169
+ content = target_path.read_text()
170
+ assert "class CamelCaseModel(BaseModel):" in content
171
+ assert (
172
+ "def validation_alias_generator(field_name: str) -> AliasChoices:"
173
+ in content
174
+ )
175
+ assert (
176
+ "AliasChoices(to_camel(field_name), to_pascal(field_name), field_name)"
177
+ in content
178
+ )
179
+ assert "serialization_alias=to_camel" in content
180
+ assert "populate_by_name=True" in content
181
+ assert "validate_assignment=True" in content
182
+
183
+
184
+ def test_camel_case_model_accepts_common_alias_styles():
185
+ pytest.importorskip("pydantic")
186
+
187
+ with runner.isolated_filesystem():
188
+ project_dir = Path.cwd()
189
+ scaffolds_dir = _repo_scaffolds_dir()
190
+ _write_rpr_config(scaffolds_dir)
191
+
192
+ result = runner.invoke(app, ["add", "template", "camel_case_model", "--force"])
193
+ assert result.exit_code == 0, result.stdout
194
+
195
+ target_path = (
196
+ project_dir
197
+ / "packages/python/test_app_domain/src/test_app_domain/utils/camel_case_model.py"
198
+ )
199
+ module_spec = importlib.util.spec_from_file_location(
200
+ "camel_case_model", target_path
201
+ )
202
+ assert module_spec is not None
203
+ assert module_spec.loader is not None
204
+ module = importlib.util.module_from_spec(module_spec)
205
+ module_spec.loader.exec_module(module)
206
+
207
+ class RuleCheckDTO(module.CamelCaseModel):
208
+ rules_checked: int
209
+ user_id: str
210
+
211
+ camel_dto = RuleCheckDTO(rulesChecked=2, userId="user-1")
212
+ pascal_dto = RuleCheckDTO(RulesChecked=3, UserId="user-2")
213
+ snake_dto = RuleCheckDTO(rules_checked=4, user_id="user-3")
214
+
215
+ assert camel_dto.rules_checked == 2
216
+ assert pascal_dto.user_id == "user-2"
217
+ assert snake_dto.rules_checked == 4
218
+ assert snake_dto.model_dump(by_alias=True) == {
219
+ "rulesChecked": 4,
220
+ "userId": "user-3",
221
+ }
222
+
223
+
149
224
  def test_add_template_dry_run():
150
225
  with runner.isolated_filesystem():
151
226
  scaffolds_dir = _repo_scaffolds_dir()
@@ -75,6 +75,37 @@ class TestRunCommandLive:
75
75
  _, kwargs = mock_run.call_args
76
76
  assert kwargs["env"]["NX_NO_CLOUD"] == "true"
77
77
 
78
+ def test_run_uv_command_uses_windows_venv_scripts_path(self, tmp_path):
79
+ scripts_dir = tmp_path / ".venv" / "Scripts"
80
+ scripts_dir.mkdir(parents=True)
81
+ ctx = make_ctx(dry_run=False, project_dir=tmp_path)
82
+ fake_result = completed(["uv", "sync"])
83
+
84
+ with (
85
+ patch("rpr.context.os.name", "nt"),
86
+ patch("rpr.context.shutil.which", return_value=None),
87
+ patch("subprocess.run", return_value=fake_result) as mock_run,
88
+ ):
89
+ ctx.run_uv_command(["uv", "sync"])
90
+
91
+ _, kwargs = mock_run.call_args
92
+ assert kwargs["env"]["VIRTUAL_ENV"] == str(tmp_path / ".venv")
93
+ assert kwargs["env"]["PATH"].startswith(str(scripts_dir))
94
+
95
+ def test_resolves_windows_command_shim_before_executing(self):
96
+ ctx = make_ctx(dry_run=False)
97
+ fake_result = completed(["npx", "nx", "init"])
98
+ with (
99
+ patch("rpr.context.os.name", "nt"),
100
+ patch("rpr.context.shutil.which", return_value=r"C:\\nodejs\\npx.cmd") as mock_which,
101
+ patch("subprocess.run", return_value=fake_result) as mock_run,
102
+ ):
103
+ ctx.run_command(["npx", "nx", "init"], env={"NX_NO_CLOUD": "true"})
104
+
105
+ args, _ = mock_run.call_args
106
+ assert args[0] == [r"C:\\nodejs\\npx.cmd", "nx", "init"]
107
+ mock_which.assert_called_once()
108
+
78
109
 
79
110
  # ---------------------------------------------------------------------------
80
111
  # run_command — dry-run mode, nested CLI does NOT support --dry-run
@@ -119,6 +150,17 @@ class TestRunCommandDryRunUnsupported:
119
150
  captured = capsys.readouterr().out
120
151
  assert "NX_NO_CLOUD=true npx nx init" in captured
121
152
 
153
+ def test_dry_run_shows_powershell_env_prefix_on_windows(self, capsys):
154
+ ctx = make_ctx(dry_run=True)
155
+ with (
156
+ patch("rpr.context.os.name", "nt"),
157
+ patch("rpr.ui.renderers.console", Console(highlight=False, no_color=True)),
158
+ patch("subprocess.run"),
159
+ ):
160
+ ctx.run_command(["npx", "nx", "init"], env={"NX_NO_CLOUD": "true"})
161
+ captured = capsys.readouterr().out
162
+ assert '$env:NX_NO_CLOUD="true"; npx nx init' in captured
163
+
122
164
 
123
165
  # ---------------------------------------------------------------------------
124
166
  # run_command — dry-run mode, nested CLI DOES support --dry-run
@@ -184,6 +184,43 @@ def test_generate_domain_with_migrations_scaffolds_alembic_and_target(monkeypatc
184
184
  ]
185
185
 
186
186
 
187
+ def test_generate_domain_can_run_common_utility_templates(monkeypatch):
188
+ recorded_calls: list[tuple[list[str], Path | str | None]] = []
189
+
190
+ def fake_run_command(
191
+ self, cmd, *, cwd=None, env=None, capture=False, supports_dry_run=False
192
+ ):
193
+ recorded_calls.append((cmd, cwd))
194
+ return _completed(cmd)
195
+
196
+ monkeypatch.setattr("rpr.context.RunContext.run_command", fake_run_command)
197
+ monkeypatch.setattr(
198
+ "rpr.commands.generate.domain.typer.confirm", lambda *args, **kwargs: True
199
+ )
200
+
201
+ with runner.isolated_filesystem():
202
+ _write_root_pyproject()
203
+
204
+ result = runner.invoke(app, ["generate", "domain", "my-app"])
205
+ assert result.exit_code == 0, result.stdout
206
+
207
+ utility_commands = [cmd for cmd, _ in recorded_calls[2:]]
208
+ assert utility_commands == [
209
+ ["rpr", "add", "template", "python", "mapper_util", "--name", "my-app"],
210
+ ["rpr", "add", "template", "python", "dto_util", "--name", "my-app"],
211
+ [
212
+ "rpr",
213
+ "add",
214
+ "template",
215
+ "python",
216
+ "camel_case_model",
217
+ "--name",
218
+ "my-app",
219
+ ],
220
+ ["rpr", "add", "template", "python", "partial_update", "--name", "my-app"],
221
+ ]
222
+
223
+
187
224
  def test_generate_domain_dry_run_previews_config_files(monkeypatch, capsys):
188
225
  monkeypatch.setattr(
189
226
  "rpr.context.console", Console(highlight=False, no_color=True), raising=False
@@ -1 +0,0 @@
1
- __version__ = "0.1.28"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes