rpr-cli 0.3.10__tar.gz → 0.3.12__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 (236) hide show
  1. rpr_cli-0.3.10/README.md → rpr_cli-0.3.12/PKG-INFO +24 -3
  2. rpr_cli-0.3.10/PKG-INFO → rpr_cli-0.3.12/README.md +6 -21
  3. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/pyproject.toml +9 -2
  4. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/rpr-parser/Cargo.lock +1 -1
  5. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/rpr-parser/Cargo.toml +1 -1
  6. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/rpr-parser/src/graph.rs +8 -15
  7. rpr_cli-0.3.12/rpr-parser/src/models/dtos/mod.rs +1 -0
  8. rpr_cli-0.3.12/rpr-parser/src/models/mod.rs +2 -0
  9. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/rpr-parser/src/parse.rs +11 -6
  10. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/rpr-parser/src/resolve.rs +8 -1
  11. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/rpr-parser/src/walker.rs +11 -2
  12. rpr_cli-0.3.12/src/rpr/__init__.py +1 -0
  13. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/agent/tools/readonly.py +2 -2
  14. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/application/catalog.py +18 -1
  15. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/application/chat_service.py +23 -2
  16. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/application/checks.py +7 -3
  17. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/application/prompt_service.py +1 -1
  18. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/application/shell.py +65 -11
  19. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/checks/base.py +0 -1
  20. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/checks/packages.py +18 -9
  21. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/checks/workspace.py +12 -5
  22. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/cli.py +2 -1
  23. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/commands/add.py +4 -4
  24. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/commands/check.py +10 -1
  25. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/commands/generate/domain.py +1 -1
  26. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/commands/generate/storybook.py +21 -86
  27. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/commands/generate/ui.py +22 -240
  28. rpr_cli-0.3.12/src/rpr/commands/generate/web.py +468 -0
  29. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/commands/init.py +63 -59
  30. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/commands/rename.py +1 -1
  31. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/commands/version.py +9 -9
  32. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/context.py +2 -2
  33. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/dependencies.py +17 -9
  34. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/dependency_manifest_data.py +15 -0
  35. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/generators/base.py +18 -3
  36. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/generators/claude.py +2 -1
  37. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/generators/cursor.py +3 -3
  38. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/generators/github.py +3 -3
  39. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/map/graph.py +3 -3
  40. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/package_updates.py +3 -3
  41. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/project_rename.py +21 -7
  42. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/instructions/all.instructions.md +13 -0
  43. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/instructions/frontend.instructions.md +19 -2
  44. rpr_cli-0.3.12/src/rpr/scaffolds/instructions/notebook.instructions.md +10 -0
  45. rpr_cli-0.3.12/src/rpr/scaffolds/instructions/stories-tracking.instructions.md +12 -0
  46. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/instructions/tooling-setup.instructions.md +3 -0
  47. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/templates/registry.py +9 -6
  48. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/ui/prompt_session.py +1 -1
  49. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/ui/theme.py +14 -12
  50. rpr_cli-0.3.12/src/rpr/workspace.py +303 -0
  51. rpr_cli-0.3.10/rpr-parser/src/models/dtos/mod.rs +0 -0
  52. rpr_cli-0.3.10/rpr-parser/src/models/mod.rs +0 -2
  53. rpr_cli-0.3.10/src/rpr/__init__.py +0 -1
  54. rpr_cli-0.3.10/src/rpr/workspace.py +0 -139
  55. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/LICENSE +0 -0
  56. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/rpr-parser/src/config/container.rs +0 -0
  57. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/rpr-parser/src/config/mod.rs +0 -0
  58. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/rpr-parser/src/config/settings.rs +0 -0
  59. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/rpr-parser/src/lib.rs +1 -1
  60. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/rpr-parser/src/models/entities/mod.rs +0 -0
  61. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/rpr-parser/src/models/entities/users.rs +0 -0
  62. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/rpr-parser/src/rename.rs +0 -0
  63. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/rpr-parser/src/repos/base.rs +0 -0
  64. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/rpr-parser/src/repos/mod.rs +0 -0
  65. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/rpr-parser/src/repos/users.rs +0 -0
  66. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/_native.pyi +0 -0
  67. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/agent/__init__.py +0 -0
  68. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/agent/approval.py +0 -0
  69. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/agent/bootstrap.py +0 -0
  70. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/agent/client.py +0 -0
  71. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/agent/control.py +0 -0
  72. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/agent/mock.py +0 -0
  73. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/agent/runtime.py +0 -0
  74. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/agent/session.py +0 -0
  75. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/agent/tools/__init__.py +0 -0
  76. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/agent/tools/base.py +0 -0
  77. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/agent/tools/mutating.py +0 -0
  78. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/agent/tools/registry.py +0 -0
  79. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/application/__init__.py +0 -0
  80. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/application/cli_adapter.py +0 -0
  81. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/application/completer.py +0 -0
  82. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/application/conversation_service.py +0 -0
  83. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/application/selector.py +0 -0
  84. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/checks/__init__.py +0 -0
  85. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/checks/instructions.py +0 -0
  86. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/commands/__init__.py +0 -0
  87. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/commands/chat.py +0 -0
  88. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/commands/generate/__init__.py +0 -0
  89. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/commands/generate/api.py +0 -0
  90. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/commands/generate/engine.py +0 -0
  91. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/commands/map.py +0 -0
  92. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/commands/refresh.py +0 -0
  93. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/commands/settings.py +0 -0
  94. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/commands/sync.py +0 -0
  95. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/commands/update.py +0 -0
  96. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/generators/__init__.py +0 -0
  97. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/generators/codex.py +0 -0
  98. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/generators/copilot.py +0 -0
  99. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/generators/gemini.py +0 -0
  100. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/manifest_refresh.py +0 -0
  101. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/map/__init__.py +0 -0
  102. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/map/architecture.py +0 -0
  103. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/map/chains.py +0 -0
  104. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/map/classifier.py +0 -0
  105. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/map/coverage.py +0 -0
  106. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/map/dependencies.py +0 -0
  107. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/map/extractor.py +0 -0
  108. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/map/output.py +0 -0
  109. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/map/responsibility.py +0 -0
  110. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/map/topology.py +0 -0
  111. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/map/walker.py +0 -0
  112. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/domain/base_entity.md +0 -0
  113. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/domain/base_repo.md +0 -0
  114. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/domain/container.md +0 -0
  115. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/domain/settings.md +0 -0
  116. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/instructions/api.instructions.md +0 -0
  117. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/instructions/domain.instructions.md +0 -0
  118. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/instructions/rust-engine.instructions.md +0 -0
  119. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/instructions/setup-guide.instructions.md +0 -0
  120. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/instructions/tooling.instructions.md +0 -0
  121. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/BACKEND_FLOW.md +0 -0
  122. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/README.md +0 -0
  123. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/client/content.ts +0 -0
  124. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/client/httpChatStreamClient.spec.ts +0 -0
  125. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/client/httpChatStreamClient.ts +0 -0
  126. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/client/index.ts +0 -0
  127. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/client/types.ts +0 -0
  128. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/composer/ChatComposer.spec.tsx +0 -0
  129. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/composer/ChatComposer.tsx +0 -0
  130. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/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
  131. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/composer/fileDrop.spec.ts +0 -0
  132. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/composer/fileDrop.ts +0 -0
  133. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/composer/index.ts +0 -0
  134. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/composer/suggestions/ChatComposerMentionTokens.tsx +0 -0
  135. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/composer/suggestions/ChatSuggestionsPopover.tsx +0 -0
  136. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/composer/suggestions/LocalFileSuggestionAction.tsx +0 -0
  137. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/composer/suggestions/index.ts +0 -0
  138. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/composer/suggestions/localFileSuggestions.spec.ts +0 -0
  139. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/composer/suggestions/localFileSuggestions.ts +0 -0
  140. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/composer/suggestions/triggerDetection.spec.ts +0 -0
  141. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/composer/suggestions/triggerDetection.ts +0 -0
  142. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/composer/suggestions/types.ts +0 -0
  143. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/composer/suggestions/useChatSuggestions.ts +0 -0
  144. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/composer/types.ts +0 -0
  145. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/composer/useChatComposer.ts +0 -0
  146. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/composer/useChatStream.spec.tsx +0 -0
  147. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/composer/useChatStream.ts +0 -0
  148. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/experience/ChatExperience.spec.tsx +0 -0
  149. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/experience/ChatExperience.styles.tsx +0 -0
  150. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/experience/ChatExperience.tsx +0 -0
  151. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/experience/ChatExperienceComposer.styles.tsx +0 -0
  152. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/experience/ChatExperienceComposer.tsx +0 -0
  153. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/experience/ChatExperienceHeader.styles.tsx +0 -0
  154. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/experience/ChatExperienceHeader.tsx +0 -0
  155. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/experience/ThreadHistory.styles.tsx +0 -0
  156. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/experience/ThreadHistory.tsx +0 -0
  157. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/experience/chatStorage.spec.ts +0 -0
  158. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/experience/chatStorage.ts +0 -0
  159. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/experience/index.ts +0 -0
  160. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/experience/types.ts +0 -0
  161. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/experience/useChatExperience.spec.tsx +0 -0
  162. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/experience/useChatExperience.ts +0 -0
  163. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/index.ts +0 -0
  164. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/testing/createMockChatStreamClient.ts +0 -0
  165. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/testing/createMockSuggestionProvider.ts +0 -0
  166. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/testing/index.ts +0 -0
  167. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/thread/ChatMessage.tsx +0 -0
  168. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/thread/ChatMessageActions.tsx +0 -0
  169. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/thread/ChatMessageContent.spec.tsx +0 -0
  170. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/thread/ChatMessageContent.tsx +0 -0
  171. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/thread/ChatThread.spec.tsx +0 -0
  172. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/thread/ChatThread.tsx +0 -0
  173. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/thread/README.md +0 -0
  174. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/thread/contentFormat.ts +0 -0
  175. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/thread/index.ts +0 -0
  176. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/thread/streaming.ts +0 -0
  177. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/thread/types.ts +0 -0
  178. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/virtual-list/VirtualComponent.spec.tsx +0 -0
  179. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/virtual-list/VirtualComponent.tsx +0 -0
  180. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/virtual-list/VirtualComponentList.spec.tsx +0 -0
  181. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/virtual-list/VirtualComponentList.tsx +0 -0
  182. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/chat/virtual-list/index.ts +0 -0
  183. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/fetch.service.md +0 -0
  184. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/sticky-navigation.md +0 -0
  185. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/sticky-navigation.spec.md +0 -0
  186. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/js_special_files/vitest-browser-config.md +0 -0
  187. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/chat/api/routes/chat_routes.py +0 -0
  188. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/chat/api/tests/test_chat.py +0 -0
  189. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/chat/domain/models/dtos/chat_dtos.py +0 -0
  190. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/chat/domain/models/dtos/conversation_history_dtos.py +0 -0
  191. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/chat/domain/models/entities/conversation_history.py +0 -0
  192. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/chat/domain/repos/conversation_history.py +0 -0
  193. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/chat/domain/services/agent_session_codec.py +0 -0
  194. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/chat/domain/services/chat_service.py +0 -0
  195. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/chat/domain/services/conversation_history_service.py +0 -0
  196. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/chat/domain/services/conversation_operations.py +0 -0
  197. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/chat/domain/services/history_codec.py +0 -0
  198. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/chat/domain/services/in_memory_history_store.py +0 -0
  199. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/chat/domain/services/postgres_history_store.py +0 -0
  200. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/chat/domain/services/protocols/conversation_history_store.py +0 -0
  201. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/chat/domain/services/protocols/conversation_runtime.py +0 -0
  202. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/chat/domain/services/protocols/llm_provider.py +0 -0
  203. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/chat/domain/tests/test_chat_dtos.py +0 -0
  204. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/chat/domain/tests/test_chat_service.py +0 -0
  205. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/chat/domain/tests/test_history_codec.py +0 -0
  206. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/chat/domain/tests/test_history_projection.py +0 -0
  207. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/chat/domain/tests/test_persistence_config.py +0 -0
  208. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/chat/domain/tests/test_postgres_history_store.py +0 -0
  209. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/vllm_provider/domain/models/dtos/__init__.py +0 -0
  210. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/vllm_provider/domain/models/dtos/vllm_model_dtos.py +0 -0
  211. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/vllm_provider/domain/services/agents/VLLM_SETUP.md +0 -0
  212. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/vllm_provider/domain/services/agents/__init__.py +0 -0
  213. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/vllm_provider/domain/services/agents/model_catalog.py +0 -0
  214. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/vllm_provider/domain/services/agents/vllm_agent_factory.py +0 -0
  215. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/vllm_provider/domain/services/agents/vllm_agent_factory_protocol.py +0 -0
  216. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/vllm_provider/domain/services/agents/vllm_inference_coordinator.py +0 -0
  217. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/vllm_provider/domain/services/runtimes/__init__.py +0 -0
  218. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/vllm_provider/domain/services/runtimes/agents_sdk.py +0 -0
  219. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/vllm_provider/domain/services/runtimes/agents_sdk_message_mapping.py +0 -0
  220. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/vllm_provider/domain/tests/test_agents_sdk_runtime.py +0 -0
  221. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/vllm_provider/domain/tests/test_vllm_model_catalog.py +0 -0
  222. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/py_special_files/vllm_provider/domain/tests/test_vllm_provider.py +0 -0
  223. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/special_files/camel_case_model.md +0 -0
  224. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/special_files/domain_container.md +0 -0
  225. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/special_files/domain_settings.md +0 -0
  226. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/special_files/dto_util.md +0 -0
  227. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/special_files/encrypted_column.md +0 -0
  228. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/special_files/logging.md +0 -0
  229. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/special_files/mapper_util.md +0 -0
  230. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/special_files/partial_update.md +0 -0
  231. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/scaffolds/special_files/test_encrypted_column.md +0 -0
  232. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/templates/__init__.py +0 -0
  233. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/ui/__init__.py +0 -0
  234. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/ui/console.py +0 -0
  235. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/ui/markdown.py +0 -0
  236. {rpr_cli-0.3.10 → rpr_cli-0.3.12}/src/rpr/ui/renderers.py +0 -0
@@ -1,3 +1,20 @@
1
+ Metadata-Version: 2.4
2
+ Name: rpr-cli
3
+ Version: 0.3.12
4
+ Requires-Dist: typer>=0.24.1,<0.26
5
+ Requires-Dist: jinja2>=3.1.5
6
+ Requires-Dist: pyyaml>=6.0.2
7
+ Requires-Dist: rich>=14.3.3
8
+ Requires-Dist: pathspec>=1.0.4
9
+ Requires-Dist: prompt-toolkit>=3.0.52
10
+ Requires-Dist: tomlkit>=0.15.0
11
+ Requires-Dist: packaging>=26.2
12
+ License-File: LICENSE
13
+ Summary: RPR CLI -- React Python Rust monorepo scaffolding orchestrator
14
+ License-Expression: MIT
15
+ Requires-Python: >=3.14
16
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
17
+
1
18
  # RPR CLI
2
19
 
3
20
  React Python Rust monorepo scaffolding orchestrator.
@@ -53,6 +70,7 @@ cd my-app
53
70
  rpr generate domain my-app # Add a Python domain package
54
71
  rpr generate api my-app # Add a FastAPI application
55
72
  rpr generate ui my-app # Add a React UI library and web app
73
+ rpr generate web landing # Add another web app; asks whether to depend on the UI library
56
74
  rpr generate engine my-app # Add a Rust/PyO3 computation engine
57
75
  rpr generate storybook # Add Storybook for UI component development
58
76
  rpr rename new-app # Rename the workspace identity and references
@@ -107,14 +125,16 @@ Available scaffolds are:
107
125
 
108
126
  ### Dependency Placement
109
127
 
110
- RPR keeps dependencies close to the package that uses them.
128
+ RPR keeps Python dependencies close to the package that uses them and Node dependencies at the workspace root.
111
129
 
112
130
  - Root Python tooling such as Ruff, pytest, pyright, pre-commit, and maturin lives in the root `pyproject.toml`.
113
131
  - Domain runtime dependencies such as `sqlmodel`, `asyncpg`, `pydantic-settings`, and optional `alembic` are added to `packages/python/domain/pyproject.toml`.
114
132
  - API runtime dependencies such as `fastapi`, `uvicorn`, and the workspace domain package are added to `apps/<name>-api/pyproject.toml`.
115
- - Node dependencies are written to the relevant package-level `package.json` files, and `npm install` runs from the root workspace.
133
+ - Node dependencies are declared and installed only in the root `package.json`, so every app and package shares one version of each. Package-level `package.json` files carry metadata and workspace links such as `@my-app/ui`. Generators install only the dependencies the root does not already declare, so adding another app never bumps existing versions.
134
+
135
+ `rpr generate web <name>` adds another web app (for example a landing page) at `apps/<name>-web`. When a UI library exists it asks whether to add the library as a dependency (`--link-ui` / `--no-link-ui` skip the prompt); linked apps get a starter page in the library's `src/pages/`, and unlinked apps are fully standalone. Each web app gets its own dev-server port (3000, 3001, ...), so `npx nx serve <name>-web` runs alongside the others. The generated workspace requires Node 24 LTS or newer.
116
136
 
117
- Python dependency changes are made with `uv` so they are tracked in `pyproject.toml`. Node dependency changes are made through npm workspace package metadata and root `npm install`.
137
+ Python dependency changes are made with `uv` so they are tracked in `pyproject.toml`. Node dependency changes are made from the root with `npm install`.
118
138
 
119
139
  Update project-owned package manifests from upstream registries with `rpr update node` or `rpr update python`. Node updates target `package.json`; Python updates target `pyproject.toml` by default and fall back to `requirements.txt` when no `pyproject.toml` exists. Use `--file` to update a nested manifest, `--dry-run` to preview without changing files or running installers, and `--include-major` to opt into major-version updates.
120
140
 
@@ -278,3 +298,4 @@ git push origin main --tags
278
298
  The workflow in `.github/workflows/publish-pypi.yml` checks both version declarations against the
279
299
  tag, builds an sdist plus native wheels for Linux x86-64/AArch64, Windows x86-64, and macOS
280
300
  x86-64/Apple Silicon, then publishes all artifacts to PyPI.
301
+
@@ -1,20 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: rpr-cli
3
- Version: 0.3.10
4
- Requires-Dist: typer>=0.24.1
5
- Requires-Dist: jinja2>=3.1.5
6
- Requires-Dist: pyyaml>=6.0.2
7
- Requires-Dist: rich>=14.3.3
8
- Requires-Dist: pathspec>=1.0.4
9
- Requires-Dist: prompt-toolkit>=3.0.52
10
- Requires-Dist: tomlkit>=0.15.0
11
- Requires-Dist: packaging>=26.2
12
- License-File: LICENSE
13
- Summary: RPR CLI -- React Python Rust monorepo scaffolding orchestrator
14
- License-Expression: MIT
15
- Requires-Python: >=3.14
16
- Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
17
-
18
1
  # RPR CLI
19
2
 
20
3
  React Python Rust monorepo scaffolding orchestrator.
@@ -70,6 +53,7 @@ cd my-app
70
53
  rpr generate domain my-app # Add a Python domain package
71
54
  rpr generate api my-app # Add a FastAPI application
72
55
  rpr generate ui my-app # Add a React UI library and web app
56
+ rpr generate web landing # Add another web app; asks whether to depend on the UI library
73
57
  rpr generate engine my-app # Add a Rust/PyO3 computation engine
74
58
  rpr generate storybook # Add Storybook for UI component development
75
59
  rpr rename new-app # Rename the workspace identity and references
@@ -124,14 +108,16 @@ Available scaffolds are:
124
108
 
125
109
  ### Dependency Placement
126
110
 
127
- RPR keeps dependencies close to the package that uses them.
111
+ RPR keeps Python dependencies close to the package that uses them and Node dependencies at the workspace root.
128
112
 
129
113
  - Root Python tooling such as Ruff, pytest, pyright, pre-commit, and maturin lives in the root `pyproject.toml`.
130
114
  - Domain runtime dependencies such as `sqlmodel`, `asyncpg`, `pydantic-settings`, and optional `alembic` are added to `packages/python/domain/pyproject.toml`.
131
115
  - API runtime dependencies such as `fastapi`, `uvicorn`, and the workspace domain package are added to `apps/<name>-api/pyproject.toml`.
132
- - Node dependencies are written to the relevant package-level `package.json` files, and `npm install` runs from the root workspace.
116
+ - Node dependencies are declared and installed only in the root `package.json`, so every app and package shares one version of each. Package-level `package.json` files carry metadata and workspace links such as `@my-app/ui`. Generators install only the dependencies the root does not already declare, so adding another app never bumps existing versions.
117
+
118
+ `rpr generate web <name>` adds another web app (for example a landing page) at `apps/<name>-web`. When a UI library exists it asks whether to add the library as a dependency (`--link-ui` / `--no-link-ui` skip the prompt); linked apps get a starter page in the library's `src/pages/`, and unlinked apps are fully standalone. Each web app gets its own dev-server port (3000, 3001, ...), so `npx nx serve <name>-web` runs alongside the others. The generated workspace requires Node 24 LTS or newer.
133
119
 
134
- Python dependency changes are made with `uv` so they are tracked in `pyproject.toml`. Node dependency changes are made through npm workspace package metadata and root `npm install`.
120
+ Python dependency changes are made with `uv` so they are tracked in `pyproject.toml`. Node dependency changes are made from the root with `npm install`.
135
121
 
136
122
  Update project-owned package manifests from upstream registries with `rpr update node` or `rpr update python`. Node updates target `package.json`; Python updates target `pyproject.toml` by default and fall back to `requirements.txt` when no `pyproject.toml` exists. Use `--file` to update a nested manifest, `--dry-run` to preview without changing files or running installers, and `--include-major` to opt into major-version updates.
137
123
 
@@ -295,4 +281,3 @@ git push origin main --tags
295
281
  The workflow in `.github/workflows/publish-pypi.yml` checks both version declarations against the
296
282
  tag, builds an sdist plus native wheels for Linux x86-64/AArch64, Windows x86-64, and macOS
297
283
  x86-64/Apple Silicon, then publishes all artifacts to PyPI.
298
-
@@ -6,7 +6,7 @@ readme = "README.md"
6
6
  license = "MIT"
7
7
  requires-python = ">=3.14"
8
8
  dependencies = [
9
- "typer>=0.24.1",
9
+ "typer>=0.24.1,<0.26",
10
10
  "jinja2>=3.1.5",
11
11
  "pyyaml>=6.0.2",
12
12
  "rich>=14.3.3",
@@ -20,7 +20,7 @@ dependencies = [
20
20
  rpr = "rpr.cli:app"
21
21
 
22
22
  [dependency-groups]
23
- dev = ["pytest>=9.0.2", "maturin>=1.8.2"]
23
+ dev = ["pytest>=9.0.2", "maturin>=1.12.6,<2.0", "ruff>=0.15"]
24
24
 
25
25
  [build-system]
26
26
  requires = ["maturin>=1.12.6,<2.0"]
@@ -35,3 +35,10 @@ include = [{ path = "LICENSE", format = "sdist" }]
35
35
 
36
36
  [tool.pytest.ini_options]
37
37
  testpaths = ["tests"]
38
+
39
+ [tool.ruff]
40
+ # The scaffolds are templates (many are not valid Python/TS until rendered).
41
+ extend-exclude = ["src/rpr/scaffolds", "rpr-parser/target"]
42
+
43
+ [tool.ruff.lint]
44
+ select = ["E4", "E7", "E9", "F"]
@@ -1981,7 +1981,7 @@ dependencies = [
1981
1981
 
1982
1982
  [[package]]
1983
1983
  name = "rpr-parser"
1984
- version = "0.3.10"
1984
+ version = "0.3.12"
1985
1985
  dependencies = [
1986
1986
  "dirs",
1987
1987
  "dotenvy",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "rpr-parser"
3
- version = "0.3.10"
3
+ version = "0.3.12"
4
4
  edition = "2021"
5
5
 
6
6
  [lib]
@@ -127,14 +127,9 @@ fn dfs_iterative<'a>(
127
127
  match color.get(neighbor).copied().unwrap_or(0) {
128
128
  1 => {
129
129
  // Back edge — found a cycle. Trace path back to neighbor.
130
- let cycle_start = path
131
- .iter()
132
- .position(|&n| n == neighbor)
133
- .unwrap_or(0);
134
- let mut cycle: Vec<String> = path[cycle_start..]
135
- .iter()
136
- .map(|s| s.to_string())
137
- .collect();
130
+ let cycle_start = path.iter().position(|&n| n == neighbor).unwrap_or(0);
131
+ let mut cycle: Vec<String> =
132
+ path[cycle_start..].iter().map(|s| s.to_string()).collect();
138
133
  cycle.push(neighbor.to_string()); // close the cycle
139
134
  cycles.push(cycle);
140
135
  }
@@ -163,12 +158,7 @@ mod tests {
163
158
  fn edges(pairs: &[(&str, &[&str])]) -> HashMap<String, Vec<String>> {
164
159
  pairs
165
160
  .iter()
166
- .map(|(k, vs)| {
167
- (
168
- k.to_string(),
169
- vs.iter().map(|s| s.to_string()).collect(),
170
- )
171
- })
161
+ .map(|(k, vs)| (k.to_string(), vs.iter().map(|s| s.to_string()).collect()))
172
162
  .collect()
173
163
  }
174
164
 
@@ -235,7 +225,10 @@ mod tests {
235
225
  // Simulate what build() does for dedup
236
226
  let deps = vec!["B".to_string(), "B".to_string(), "C".to_string()];
237
227
  let mut seen: HashSet<String> = HashSet::new();
238
- let deduped: Vec<String> = deps.into_iter().filter(|d| seen.insert(d.clone())).collect();
228
+ let deduped: Vec<String> = deps
229
+ .into_iter()
230
+ .filter(|d| seen.insert(d.clone()))
231
+ .collect();
239
232
  assert_eq!(deduped.len(), 2);
240
233
  assert!(deduped.contains(&"B".to_string()));
241
234
  assert!(deduped.contains(&"C".to_string()));
@@ -0,0 +1,2 @@
1
+ pub mod dtos;
2
+ pub mod entities;
@@ -166,7 +166,10 @@ fn extract_js_ts_imports(source: &[u8], parser: &mut Parser) -> Vec<String> {
166
166
  let mut cursor = node.walk();
167
167
  for child in node.children(&mut cursor) {
168
168
  if child.kind() == "string" {
169
- let raw = node_text(child, source).trim_matches('"').trim_matches('\'').to_string();
169
+ let raw = node_text(child, source)
170
+ .trim_matches('"')
171
+ .trim_matches('\'')
172
+ .to_string();
170
173
  if !raw.is_empty() {
171
174
  imports.push(raw);
172
175
  }
@@ -257,7 +260,9 @@ fn parse_rust(source: &[u8]) -> Vec<String> {
257
260
  // Only `mod foo;` (without a body block), not `mod foo { ... }`
258
261
  let has_body = {
259
262
  let mut cursor = node.walk();
260
- let result = node.children(&mut cursor).any(|c| c.kind() == "declaration_list");
263
+ let result = node
264
+ .children(&mut cursor)
265
+ .any(|c| c.kind() == "declaration_list");
261
266
  result
262
267
  };
263
268
  if !has_body {
@@ -317,9 +322,7 @@ fn parse_cpp(source: &[u8]) -> Vec<String> {
317
322
  match child.kind() {
318
323
  "string_literal" => {
319
324
  // Quoted include — keep it (strip surrounding quotes)
320
- let raw = node_text(child, source)
321
- .trim_matches('"')
322
- .to_string();
325
+ let raw = node_text(child, source).trim_matches('"').to_string();
323
326
  if !raw.is_empty() {
324
327
  imports.push(raw);
325
328
  }
@@ -475,7 +478,9 @@ mod tests {
475
478
  let f = rs_file();
476
479
  let src = b"use crate::map::walker;";
477
480
  let result = parse_imports(&f, src);
478
- assert!(result.iter().any(|s| s.contains("map") && s.contains("walker")));
481
+ assert!(result
482
+ .iter()
483
+ .any(|s| s.contains("map") && s.contains("walker")));
479
484
  }
480
485
 
481
486
  #[test]
@@ -3,7 +3,14 @@ use std::collections::HashMap;
3
3
  use std::path::{Path, PathBuf};
4
4
 
5
5
  const TS_JS_EXTENSIONS: &[&str] = &["ts", "tsx", "js", "jsx", "mjs", "cjs"];
6
- const INDEX_NAMES: &[&str] = &["index.ts", "index.tsx", "index.js", "index.jsx", "index.mjs", "index.cjs"];
6
+ const INDEX_NAMES: &[&str] = &[
7
+ "index.ts",
8
+ "index.tsx",
9
+ "index.js",
10
+ "index.jsx",
11
+ "index.mjs",
12
+ "index.cjs",
13
+ ];
7
14
 
8
15
  pub fn resolve_imports(
9
16
  file: &SourceFile,
@@ -2,8 +2,17 @@ use ignore::WalkBuilder;
2
2
  use std::path::{Path, PathBuf};
3
3
 
4
4
  const IGNORED_DIRS: &[&str] = &[
5
- ".venv", "venv", ".env", "node_modules", "__pycache__",
6
- "dist", "build", ".nx", "target", ".git", "vendor",
5
+ ".venv",
6
+ "venv",
7
+ ".env",
8
+ "node_modules",
9
+ "__pycache__",
10
+ "dist",
11
+ "build",
12
+ ".nx",
13
+ "target",
14
+ ".git",
15
+ "vendor",
7
16
  ];
8
17
 
9
18
  #[derive(Debug, Clone, PartialEq)]
@@ -0,0 +1 @@
1
+ __version__ = "0.3.12"
@@ -31,7 +31,7 @@ class ReadFileTool(AgentTool):
31
31
  path = resolve_project_path(ctx.project_dir, arguments.get("path"))
32
32
  start_line = int(arguments.get("start_line", 1))
33
33
  end_line = arguments.get("end_line")
34
- content = path.read_text()
34
+ content = path.read_text(encoding="utf-8")
35
35
  lines = content.splitlines()
36
36
  if end_line is None:
37
37
  end_line = len(lines)
@@ -122,7 +122,7 @@ class SearchTextTool(AgentTool):
122
122
  )
123
123
  path = current_root / file_name
124
124
  try:
125
- content = path.read_text()
125
+ content = path.read_text(encoding="utf-8")
126
126
  except (OSError, UnicodeDecodeError):
127
127
  continue
128
128
 
@@ -188,6 +188,23 @@ COMMAND_CATALOG: tuple[CommandDefinition, ...] = (
188
188
  ),
189
189
  ),
190
190
  ),
191
+ CommandDefinition(
192
+ name="web",
193
+ description="Generate a web app.",
194
+ action_id="generate.web",
195
+ arguments=(CommandArgument("name", "App name."),),
196
+ options=(
197
+ CommandOption(
198
+ "--ui-package",
199
+ "Target UI package.",
200
+ kind="value",
201
+ value_name="PACKAGE",
202
+ ),
203
+ CommandOption(
204
+ "--dry-run", "Preview changes without writing.", kind="flag"
205
+ ),
206
+ ),
207
+ ),
191
208
  CommandDefinition(
192
209
  name="engine",
193
210
  description="Generate a Rust engine package.",
@@ -462,7 +479,7 @@ def usage_string(cmd: CommandDefinition) -> str:
462
479
 
463
480
  Group commands show pipe-separated child names::
464
481
 
465
- /generate <domain|api|ui|engine|storybook>
482
+ /generate <domain|api|ui|web|engine|storybook>
466
483
 
467
484
  Leaf commands show arguments and options::
468
485
 
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import asyncio
4
+ import sys
4
5
  from collections import deque
5
6
  from contextlib import suppress
6
7
  from dataclasses import dataclass
@@ -9,7 +10,9 @@ from typing import ClassVar
9
10
 
10
11
  from prompt_toolkit import print_formatted_text
11
12
  from prompt_toolkit.application.current import get_app_session
13
+ from prompt_toolkit.data_structures import Size
12
14
  from prompt_toolkit.formatted_text import FormattedText
15
+ from prompt_toolkit.output.vt100 import Vt100_Output
13
16
 
14
17
  from rpr.agent.approval import ApprovalDecision, ApprovalMode
15
18
  from rpr.agent.bootstrap import build_chat_runtime_bundle
@@ -26,7 +29,7 @@ from rpr.application.completer import (
26
29
  from rpr.application.prompt_service import PromptService
27
30
  from rpr.application.shell import CommandShellService, ShellPresenter
28
31
  from rpr.context import RunContext
29
- from rpr.ui.console import console, refresh_console
32
+ from rpr.ui.console import refresh_console
30
33
  from rpr.ui.renderers import (
31
34
  render_approval_prompt,
32
35
  render_chat_hint,
@@ -47,6 +50,24 @@ type AgentClientFactory = Callable[[str | None, str | None], AgentClient]
47
50
  type ContextFactory = Callable[[], RunContext]
48
51
 
49
52
 
53
+ def _terminal_output():
54
+ """Return prompt_toolkit's output, falling back to plain stdout.
55
+
56
+ On Windows prompt_toolkit raises when stdout is not a real console (piped
57
+ output, CI, redirected runs). Binding a plain VT100 writer to `sys.stdout`
58
+ keeps `rpr chat` working there; `reset()` clears it with the app session.
59
+ """
60
+ session = get_app_session()
61
+ try:
62
+ return session.output
63
+ except Exception:
64
+ output = Vt100_Output(
65
+ sys.stdout, lambda: Size(rows=24, columns=80), term="dumb"
66
+ )
67
+ session._output = output
68
+ return output
69
+
70
+
50
71
  @dataclass(slots=True)
51
72
  class AssistantStreamRenderer:
52
73
  _accumulated: str = ""
@@ -54,7 +75,7 @@ class AssistantStreamRenderer:
54
75
 
55
76
  def append(self, chunk: str) -> None:
56
77
  self._accumulated += chunk
57
- output = get_app_session().output
78
+ output = _terminal_output()
58
79
  if self._lines_printed > 0:
59
80
  output.cursor_up(self._lines_printed)
60
81
  output.erase_down()
@@ -3,16 +3,20 @@ from __future__ import annotations
3
3
  from dataclasses import dataclass
4
4
  from pathlib import Path
5
5
 
6
+ from rpr.checks.base import CheckResult
6
7
  from rpr.checks.instructions import check_instructions
7
8
  from rpr.checks.packages import check_packages
8
9
  from rpr.checks.workspace import check_workspace
9
10
  from rpr.generators.base import SyncConfig
10
11
 
11
12
 
13
+ CHECK_GROUPS = ("workspace", "instructions", "packages")
14
+
15
+
12
16
  @dataclass(slots=True, frozen=True)
13
17
  class CheckReport:
14
18
  project_name: str
15
- results: list[object]
19
+ results: list[CheckResult]
16
20
 
17
21
 
18
22
  def collect_check_report(project_dir: Path, group: str | None = None) -> CheckReport:
@@ -22,7 +26,7 @@ def collect_check_report(project_dir: Path, group: str | None = None) -> CheckRe
22
26
  variables = config.variables or {}
23
27
  project_name = variables.get("name", "(unknown)")
24
28
  requested_group = None if group is None else group.lower()
25
- results: list[object] = []
29
+ results: list[CheckResult] = []
26
30
 
27
31
  if requested_group in {None, "workspace"}:
28
32
  results.extend(check_workspace(project_dir))
@@ -36,7 +40,7 @@ def collect_check_report(project_dir: Path, group: str | None = None) -> CheckRe
36
40
  return CheckReport(project_name=project_name, results=results)
37
41
 
38
42
 
39
- def serialize_check_results(results: list[object]) -> list[dict[str, object]]:
43
+ def serialize_check_results(results: list[CheckResult]) -> list[dict[str, object]]:
40
44
  return [
41
45
  {
42
46
  "group": result.group,
@@ -12,7 +12,7 @@ from rpr.agent.session import ChatSession
12
12
  from rpr.application.conversation_service import (
13
13
  ConversationService,
14
14
  ConversationSummary,
15
- InMemoryConversationRepository,
15
+ InMemoryConversationRepository, # noqa: F401 (re-exported)
16
16
  )
17
17
  from rpr.ui.prompt_session import PromptSessionAdapter
18
18
 
@@ -6,6 +6,7 @@ from dataclasses import dataclass
6
6
  from pathlib import Path
7
7
  from typing import ClassVar, Protocol
8
8
 
9
+ import click
9
10
  import typer
10
11
 
11
12
  from rpr.agent.bootstrap import ChatRuntimeBundle
@@ -287,6 +288,7 @@ class CommandShellService:
287
288
  self._active_presenter.info(f"Running /init for {project_name}.")
288
289
  exit_code = self._invoke_command(
289
290
  init_command.init,
291
+ typer.Context(click.Command("init")),
290
292
  project_name=project_name,
291
293
  dry_run=namespace.dry_run,
292
294
  python_version=namespace.python,
@@ -301,6 +303,9 @@ class CommandShellService:
301
303
  from rpr.commands.generate import engine as generate_engine_command
302
304
  from rpr.commands.generate import storybook as generate_storybook_command
303
305
  from rpr.commands.generate import ui as generate_ui_command
306
+ from rpr.commands.generate import web as generate_web_command
307
+ from rpr.dependencies import node_project_name, ui_package_name
308
+ from rpr.workspace import find_ui_packages
304
309
 
305
310
  parser = ShellArgumentParser(prog="/generate", add_help=False)
306
311
  subparsers = parser.add_subparsers(dest="target")
@@ -314,11 +319,21 @@ class CommandShellService:
314
319
  storybook_parser.add_argument("--dry-run", action="store_true")
315
320
  storybook_parser.add_argument("--ui-package")
316
321
 
322
+ web_parser = subparsers.add_parser("web", add_help=False)
323
+ web_parser.add_argument("name", nargs="?")
324
+ web_parser.add_argument("--dry-run", action="store_true")
325
+ web_parser.add_argument("--ui-package")
326
+ web_parser.add_argument(
327
+ "--link-ui", action=argparse.BooleanOptionalAction, default=None
328
+ )
329
+
317
330
  namespace = self._parse_args(parser, parsed.args)
318
331
  if namespace is None:
319
332
  return True
320
333
  if namespace.target is None:
321
- raise ValueError("Usage: /generate <domain|api|ui|engine|storybook> ...")
334
+ raise ValueError(
335
+ "Usage: /generate <domain|api|ui|web|engine|storybook> ..."
336
+ )
322
337
 
323
338
  if namespace.target == "domain":
324
339
  name = namespace.name or await self._active_prompts.prompt("App name")
@@ -345,11 +360,43 @@ class CommandShellService:
345
360
  )
346
361
  return True
347
362
 
363
+ if namespace.target == "web":
364
+ name = namespace.name or await self._active_prompts.prompt("App name")
365
+ ui_package = namespace.ui_package
366
+ link_ui = namespace.link_ui
367
+ ui_packages = find_ui_packages(self._bundle.ctx.project_dir)
368
+ if ui_packages and not ui_package:
369
+ ui_package = ui_packages[0]
370
+ if len(ui_packages) > 1:
371
+ self._active_presenter.table(
372
+ "Web App Targets",
373
+ ["Package"],
374
+ [[package] for package in ui_packages],
375
+ )
376
+ ui_package = (
377
+ await self._active_prompts.prompt(
378
+ "UI package", default=ui_packages[0]
379
+ )
380
+ ).strip() or ui_packages[0]
381
+ if ui_package and link_ui is None:
382
+ answer = await self._active_prompts.prompt(
383
+ f"Add {ui_package_name(ui_package)} as a dependency of "
384
+ f"{node_project_name(name, 'web')}? (Y/n)",
385
+ default="y",
386
+ )
387
+ link_ui = answer.strip().lower() not in {"n", "no"}
388
+ self._invoke_command(
389
+ generate_web_command.web,
390
+ name=name,
391
+ ui_package=ui_package,
392
+ link_ui=link_ui,
393
+ dry_run=namespace.dry_run,
394
+ )
395
+ return True
396
+
348
397
  ui_package = namespace.ui_package
349
398
  if not ui_package:
350
- ui_packages = generate_storybook_command._find_ui_packages(
351
- self._bundle.ctx.project_dir
352
- )
399
+ ui_packages = find_ui_packages(self._bundle.ctx.project_dir)
353
400
  if len(ui_packages) == 1:
354
401
  ui_package = ui_packages[0]
355
402
  elif len(ui_packages) > 1:
@@ -376,7 +423,7 @@ class CommandShellService:
376
423
 
377
424
  parser = ShellArgumentParser(prog="/sync", add_help=False)
378
425
  parser.add_argument("action", nargs="?", default="rules")
379
- parser.add_argument("--target")
426
+ parser.add_argument("--target", action="append")
380
427
  parser.add_argument("--dry-run", action="store_true")
381
428
  namespace = self._parse_args(parser, parsed.args)
382
429
  if namespace is None:
@@ -385,7 +432,9 @@ class CommandShellService:
385
432
  raise ValueError("Usage: /sync [rules] [--target cursor] [--dry-run]")
386
433
 
387
434
  self._invoke_command(
388
- sync_command.rules, target=namespace.target, dry_run=namespace.dry_run
435
+ sync_command.rules,
436
+ target=namespace.target or [],
437
+ dry_run=namespace.dry_run,
389
438
  )
390
439
  return True
391
440
 
@@ -395,6 +444,7 @@ class CommandShellService:
395
444
  parser = ShellArgumentParser(prog="/add", add_help=False)
396
445
  parser.add_argument("action", nargs="?", default="template")
397
446
  parser.add_argument("template_id", nargs="?")
447
+ parser.add_argument("template_name", nargs="?")
398
448
  parser.add_argument("--list", action="store_true")
399
449
  parser.add_argument("--force", action="store_true")
400
450
  parser.add_argument("--name")
@@ -405,16 +455,20 @@ class CommandShellService:
405
455
  return True
406
456
  if namespace.action != "template":
407
457
  raise ValueError(
408
- "Usage: /add template <template-id> [--name app] [--force] [--dry-run]"
458
+ "Usage: /add template [node|python] <template-id> "
459
+ "[--name app] [--force] [--dry-run]"
409
460
  )
410
461
 
411
- template_id = namespace.template_id
412
- if template_id is None and not namespace.list:
413
- template_id = await self._active_prompts.prompt("Template ID")
462
+ # `/add template [lang] <id>`: the command takes the language (or the id,
463
+ # when no language is given) as its first positional argument.
464
+ lang_or_template_id = namespace.template_id
465
+ if lang_or_template_id is None and not namespace.list:
466
+ lang_or_template_id = await self._active_prompts.prompt("Template ID")
414
467
 
415
468
  self._invoke_command(
416
469
  add_command.template,
417
- template_id=template_id,
470
+ lang_or_template_id=lang_or_template_id,
471
+ template_id=namespace.template_name,
418
472
  list_templates=namespace.list,
419
473
  force=namespace.force,
420
474
  name=namespace.name,
@@ -1,7 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from dataclasses import dataclass
4
- from pathlib import Path
5
4
 
6
5
 
7
6
  @dataclass