rpr-cli 0.1.1__py3-none-any.whl

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 (97) hide show
  1. rpr/__init__.py +1 -0
  2. rpr/agent/__init__.py +29 -0
  3. rpr/agent/approval.py +19 -0
  4. rpr/agent/bootstrap.py +60 -0
  5. rpr/agent/client.py +115 -0
  6. rpr/agent/control.py +16 -0
  7. rpr/agent/mock.py +158 -0
  8. rpr/agent/runtime.py +291 -0
  9. rpr/agent/session.py +91 -0
  10. rpr/agent/tools/__init__.py +10 -0
  11. rpr/agent/tools/base.py +62 -0
  12. rpr/agent/tools/mutating.py +47 -0
  13. rpr/agent/tools/readonly.py +147 -0
  14. rpr/agent/tools/registry.py +30 -0
  15. rpr/application/__init__.py +1 -0
  16. rpr/application/catalog.py +427 -0
  17. rpr/application/chat_service.py +413 -0
  18. rpr/application/checks.py +49 -0
  19. rpr/application/cli_adapter.py +36 -0
  20. rpr/application/completer.py +163 -0
  21. rpr/application/conversation_service.py +92 -0
  22. rpr/application/prompt_service.py +85 -0
  23. rpr/application/selector.py +240 -0
  24. rpr/application/shell.py +543 -0
  25. rpr/checks/__init__.py +0 -0
  26. rpr/checks/base.py +13 -0
  27. rpr/checks/instructions.py +89 -0
  28. rpr/checks/packages.py +619 -0
  29. rpr/checks/workspace.py +170 -0
  30. rpr/cli.py +78 -0
  31. rpr/commands/__init__.py +0 -0
  32. rpr/commands/add.py +166 -0
  33. rpr/commands/chat.py +48 -0
  34. rpr/commands/check.py +53 -0
  35. rpr/commands/generate/__init__.py +0 -0
  36. rpr/commands/generate/api.py +228 -0
  37. rpr/commands/generate/domain.py +383 -0
  38. rpr/commands/generate/engine.py +148 -0
  39. rpr/commands/generate/storybook.py +442 -0
  40. rpr/commands/generate/ui.py +414 -0
  41. rpr/commands/init.py +822 -0
  42. rpr/commands/map.py +113 -0
  43. rpr/commands/settings.py +102 -0
  44. rpr/commands/sync.py +97 -0
  45. rpr/context.py +203 -0
  46. rpr/generators/__init__.py +0 -0
  47. rpr/generators/base.py +110 -0
  48. rpr/generators/claude.py +33 -0
  49. rpr/generators/copilot.py +36 -0
  50. rpr/generators/cursor.py +38 -0
  51. rpr/generators/gemini.py +33 -0
  52. rpr/map/__init__.py +0 -0
  53. rpr/map/architecture.py +495 -0
  54. rpr/map/chains.py +317 -0
  55. rpr/map/classifier.py +170 -0
  56. rpr/map/coverage.py +200 -0
  57. rpr/map/dependencies.py +243 -0
  58. rpr/map/extractor.py +223 -0
  59. rpr/map/graph.py +318 -0
  60. rpr/map/output.py +1030 -0
  61. rpr/map/responsibility.py +345 -0
  62. rpr/map/topology.py +327 -0
  63. rpr/map/walker.py +151 -0
  64. rpr/scaffolds/domain/base_entity.md +30 -0
  65. rpr/scaffolds/domain/base_repo.md +48 -0
  66. rpr/scaffolds/domain/container.md +76 -0
  67. rpr/scaffolds/domain/settings.md +57 -0
  68. rpr/scaffolds/instructions/all.instructions.md +50 -0
  69. rpr/scaffolds/instructions/api.instructions.md +42 -0
  70. rpr/scaffolds/instructions/domain.instructions.md +93 -0
  71. rpr/scaffolds/instructions/frontend.instructions.md +97 -0
  72. rpr/scaffolds/instructions/rust-engine.instructions.md +40 -0
  73. rpr/scaffolds/instructions/setup-guide.instructions.md +86 -0
  74. rpr/scaffolds/instructions/tooling-setup.instructions.md +97 -0
  75. rpr/scaffolds/instructions/tooling.instructions.md +42 -0
  76. rpr/scaffolds/js_special_files/fetch.service.md +222 -0
  77. rpr/scaffolds/js_special_files/sticky-navigation.md +164 -0
  78. rpr/scaffolds/special_files/domain_container.md +76 -0
  79. rpr/scaffolds/special_files/domain_settings.md +57 -0
  80. rpr/scaffolds/special_files/dto_util.md +62 -0
  81. rpr/scaffolds/special_files/encrypted_column.md +98 -0
  82. rpr/scaffolds/special_files/mapper_util.md +159 -0
  83. rpr/scaffolds/special_files/partial_update.md +61 -0
  84. rpr/templates/__init__.py +0 -0
  85. rpr/templates/registry.py +81 -0
  86. rpr/ui/__init__.py +0 -0
  87. rpr/ui/console.py +32 -0
  88. rpr/ui/markdown.py +59 -0
  89. rpr/ui/prompt_session.py +430 -0
  90. rpr/ui/renderers.py +167 -0
  91. rpr/ui/theme.py +286 -0
  92. rpr/workspace.py +131 -0
  93. rpr_cli-0.1.1.dist-info/METADATA +201 -0
  94. rpr_cli-0.1.1.dist-info/RECORD +97 -0
  95. rpr_cli-0.1.1.dist-info/WHEEL +4 -0
  96. rpr_cli-0.1.1.dist-info/entry_points.txt +2 -0
  97. rpr_cli-0.1.1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,414 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from pathlib import Path
5
+ from typing import Annotated
6
+
7
+ import typer
8
+ from rich.console import Console
9
+
10
+ from rpr.cli import generate_app
11
+ from rpr.context import RunContext
12
+ from rpr.workspace import ensure_npm_workspaces, write_package_json
13
+
14
+ console = Console()
15
+
16
+ _UI_LIBRARY_DEPENDENCIES = {
17
+ "@mui/material": "^6",
18
+ "@emotion/react": "^11",
19
+ "@emotion/styled": "^11",
20
+ "@tanstack/react-query": "^5",
21
+ "@tanstack/react-router": "^1",
22
+ "react": "^19",
23
+ "react-dom": "^19",
24
+ }
25
+ _UI_LIBRARY_DEV_DEPENDENCIES = {
26
+ "@types/react": "^19",
27
+ "@types/react-dom": "^19",
28
+ "typescript": "^5",
29
+ "vite": "^6",
30
+ "vitest": "^3",
31
+ }
32
+ _WEB_APP_DEV_DEPENDENCIES = {
33
+ "@types/react": "^19",
34
+ "@types/react-dom": "^19",
35
+ "@vitejs/plugin-react": "^4",
36
+ "typescript": "^5",
37
+ "vite": "^6",
38
+ "vitest": "^3",
39
+ }
40
+
41
+
42
+ def _web_app_dependencies(ui_pkg_name: str) -> dict[str, str]:
43
+ return {
44
+ f"@repo/{ui_pkg_name}": "workspace:*",
45
+ "react": "^19",
46
+ "react-dom": "^19",
47
+ }
48
+
49
+
50
+ @generate_app.command()
51
+ def ui(
52
+ name: Annotated[
53
+ str | None, typer.Argument(help="App name (used as package prefix).")
54
+ ] = None,
55
+ dry_run: Annotated[
56
+ bool, typer.Option("--dry-run", help="Preview changes without writing.")
57
+ ] = False,
58
+ include_library: Annotated[
59
+ bool,
60
+ typer.Option(
61
+ "--library/--no-library",
62
+ help="Generate the reusable UI library.",
63
+ ),
64
+ ] = True,
65
+ include_web: Annotated[
66
+ bool,
67
+ typer.Option(
68
+ "--web/--no-web",
69
+ help="Generate the thin web app shell.",
70
+ ),
71
+ ] = True,
72
+ ) -> None:
73
+ """Scaffold a React UI library and slim frontend app."""
74
+ if not name:
75
+ name = typer.prompt("App name")
76
+ if not include_library and not include_web:
77
+ raise typer.BadParameter("At least one of --library or --web must be enabled.")
78
+
79
+ ctx = RunContext(dry_run=dry_run, project_dir=Path.cwd())
80
+ ui_pkg_name = f"{name}-ui"
81
+ app_name = f"{name}-web"
82
+
83
+ generated_parts = []
84
+ if include_library:
85
+ generated_parts.append(ui_pkg_name)
86
+ if include_web:
87
+ generated_parts.append(app_name)
88
+
89
+ console.print(
90
+ f"\n[bold]Generating frontend projects:[/] {' + '.join(generated_parts)}\n"
91
+ )
92
+
93
+ ensure_npm_workspaces(ctx, package_name=ctx.project_dir.name)
94
+ if include_library:
95
+ _scaffold_ui_library(ctx, ui_pkg_name)
96
+ if include_web:
97
+ _scaffold_frontend_app(ctx, app_name, ui_pkg_name)
98
+
99
+ if include_library:
100
+ ctx.preview_dependencies(
101
+ manager="npm",
102
+ target=f"packages/node/{ui_pkg_name}",
103
+ runtime=list(_UI_LIBRARY_DEPENDENCIES),
104
+ dev=list(_UI_LIBRARY_DEV_DEPENDENCIES),
105
+ )
106
+ if include_web:
107
+ ctx.preview_dependencies(
108
+ manager="npm",
109
+ target=f"apps/{app_name}",
110
+ runtime=list(_web_app_dependencies(ui_pkg_name)),
111
+ dev=list(_WEB_APP_DEV_DEPENDENCIES),
112
+ )
113
+
114
+ if not dry_run:
115
+ ctx.run_command(["npm", "install"], cwd=ctx.project_dir)
116
+
117
+ console.print("\n[bold green]Done![/] Frontend scaffolding created.")
118
+ if include_web:
119
+ console.print(f" Run with: npx nx serve {app_name}")
120
+ if include_library:
121
+ console.print(" Optional templates: rpr add template fetch_service")
122
+ console.print(" rpr add template sticky_navigation")
123
+
124
+
125
+ def _scaffold_ui_library(ctx: RunContext, ui_pkg_name: str) -> None:
126
+ lib_root = ctx.project_dir / "packages" / "node" / ui_pkg_name
127
+ src = lib_root / "src"
128
+
129
+ for d in ["hooks", "components", "services/base", "state"]:
130
+ ctx.ensure_dir(src / d)
131
+
132
+ _write_ui_package_json(ctx, lib_root, ui_pkg_name)
133
+ _write_ui_project_json(ctx, lib_root, ui_pkg_name)
134
+ _write_ui_tsconfig(ctx, lib_root)
135
+ _write_ui_eslint_config(ctx, lib_root)
136
+ ctx.write_file(src / "index.ts", f'export const uiPackageName = "{ui_pkg_name}";\n')
137
+ _write_ui_test(ctx, src / "index.test.ts", ui_pkg_name)
138
+ ctx.write_file(src / "hooks" / ".gitkeep", "")
139
+ ctx.write_file(src / "components" / ".gitkeep", "")
140
+ ctx.write_file(src / "state" / ".gitkeep", "")
141
+ ctx.write_file(src / "services" / "base" / ".gitkeep", "")
142
+
143
+
144
+ def _scaffold_frontend_app(ctx: RunContext, app_name: str, ui_pkg_name: str) -> None:
145
+ app_root = ctx.project_dir / "apps" / app_name
146
+ src = app_root / "src"
147
+
148
+ ctx.ensure_dir(src)
149
+
150
+ _write_app_package_json(ctx, app_root, app_name, ui_pkg_name)
151
+ _write_app_project_json(ctx, app_root, app_name)
152
+ _write_app_tsconfig(ctx, app_root)
153
+ _write_app_eslint_config(ctx, app_root)
154
+ _write_app_index_html(ctx, app_root, app_name)
155
+ _write_app_main_tsx(ctx, src)
156
+ _write_app_tsx(ctx, src, app_name, ui_pkg_name)
157
+ _write_app_test(ctx, src / "App.test.ts", app_name)
158
+ _write_vite_config(ctx, app_root, app_name)
159
+
160
+
161
+ def _write_ui_package_json(ctx: RunContext, lib_root: Path, ui_pkg_name: str) -> None:
162
+ write_package_json(
163
+ ctx,
164
+ lib_root / "package.json",
165
+ defaults={
166
+ "name": f"@repo/{ui_pkg_name}",
167
+ "version": "0.1.0",
168
+ "private": True,
169
+ "main": "src/index.ts",
170
+ "types": "src/index.ts",
171
+ },
172
+ dependencies=_UI_LIBRARY_DEPENDENCIES,
173
+ dev_dependencies=_UI_LIBRARY_DEV_DEPENDENCIES,
174
+ )
175
+
176
+
177
+ def _write_ui_project_json(ctx: RunContext, lib_root: Path, ui_pkg_name: str) -> None:
178
+ project = {
179
+ "name": ui_pkg_name,
180
+ "root": f"packages/node/{ui_pkg_name}",
181
+ "targets": {
182
+ "build": {
183
+ "executor": "nx:run-commands",
184
+ "options": {
185
+ "command": "npx tsc -p tsconfig.json",
186
+ "cwd": f"packages/node/{ui_pkg_name}",
187
+ },
188
+ },
189
+ "lint": {
190
+ "executor": "nx:run-commands",
191
+ "options": {
192
+ "command": "npx eslint .",
193
+ "cwd": f"packages/node/{ui_pkg_name}",
194
+ },
195
+ },
196
+ "test": {
197
+ "executor": "nx:run-commands",
198
+ "options": {
199
+ "command": "npx vitest run",
200
+ "cwd": f"packages/node/{ui_pkg_name}",
201
+ },
202
+ },
203
+ "typecheck": {
204
+ "executor": "nx:run-commands",
205
+ "options": {
206
+ "command": "npx tsc --noEmit",
207
+ "cwd": f"packages/node/{ui_pkg_name}",
208
+ },
209
+ },
210
+ },
211
+ }
212
+ ctx.write_file(lib_root / "project.json", json.dumps(project, indent=2) + "\n")
213
+
214
+
215
+ def _write_ui_tsconfig(ctx: RunContext, lib_root: Path) -> None:
216
+ content = """{
217
+ "extends": "../../../tsconfig.base.json",
218
+ "compilerOptions": {
219
+ "jsx": "react-jsx",
220
+ "outDir": "dist",
221
+ "rootDir": "src"
222
+ },
223
+ "include": ["src"]
224
+ }
225
+ """
226
+ ctx.write_file(lib_root / "tsconfig.json", content)
227
+
228
+
229
+ def _write_ui_eslint_config(ctx: RunContext, lib_root: Path) -> None:
230
+ content = """import baseConfig from \"../../../eslint.config.mjs\";
231
+
232
+ export default [...baseConfig];
233
+ """
234
+ ctx.write_file(lib_root / "eslint.config.mjs", content)
235
+
236
+
237
+ def _write_app_package_json(
238
+ ctx: RunContext, app_root: Path, app_name: str, ui_pkg_name: str
239
+ ) -> None:
240
+ write_package_json(
241
+ ctx,
242
+ app_root / "package.json",
243
+ defaults={
244
+ "name": f"@repo/{app_name}",
245
+ "version": "0.1.0",
246
+ "private": True,
247
+ "type": "module",
248
+ },
249
+ dependencies=_web_app_dependencies(ui_pkg_name),
250
+ dev_dependencies=_WEB_APP_DEV_DEPENDENCIES,
251
+ )
252
+
253
+
254
+ def _write_app_project_json(ctx: RunContext, app_root: Path, app_name: str) -> None:
255
+ project = {
256
+ "name": app_name,
257
+ "root": f"apps/{app_name}",
258
+ "targets": {
259
+ "serve": {
260
+ "executor": "nx:run-commands",
261
+ "options": {
262
+ "command": "npx vite",
263
+ "cwd": f"apps/{app_name}",
264
+ },
265
+ },
266
+ "build": {
267
+ "executor": "nx:run-commands",
268
+ "options": {
269
+ "command": "npx vite build",
270
+ "cwd": f"apps/{app_name}",
271
+ },
272
+ },
273
+ "lint": {
274
+ "executor": "nx:run-commands",
275
+ "options": {
276
+ "command": "npx eslint .",
277
+ "cwd": f"apps/{app_name}",
278
+ },
279
+ },
280
+ "test": {
281
+ "executor": "nx:run-commands",
282
+ "options": {
283
+ "command": "npx vitest run",
284
+ "cwd": f"apps/{app_name}",
285
+ },
286
+ },
287
+ "typecheck": {
288
+ "executor": "nx:run-commands",
289
+ "options": {
290
+ "command": "npx tsc --noEmit",
291
+ "cwd": f"apps/{app_name}",
292
+ },
293
+ },
294
+ },
295
+ }
296
+ ctx.write_file(app_root / "project.json", json.dumps(project, indent=2) + "\n")
297
+
298
+
299
+ def _write_app_tsconfig(ctx: RunContext, app_root: Path) -> None:
300
+ content = """{
301
+ "extends": "../../tsconfig.base.json",
302
+ "compilerOptions": {
303
+ "jsx": "react-jsx",
304
+ "outDir": "dist",
305
+ "rootDir": "src"
306
+ },
307
+ "include": ["src"]
308
+ }
309
+ """
310
+ ctx.write_file(app_root / "tsconfig.json", content)
311
+
312
+
313
+ def _write_app_eslint_config(ctx: RunContext, app_root: Path) -> None:
314
+ content = """import baseConfig from \"../../eslint.config.mjs\";
315
+
316
+ export default [...baseConfig];
317
+ """
318
+ ctx.write_file(app_root / "eslint.config.mjs", content)
319
+
320
+
321
+ def _write_app_index_html(ctx: RunContext, app_root: Path, app_name: str) -> None:
322
+ title = app_name.replace("-", " ").title()
323
+ content = f"""<!DOCTYPE html>
324
+ <html lang="en">
325
+ <head>
326
+ <meta charset="UTF-8" />
327
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
328
+ <title>{title}</title>
329
+ </head>
330
+ <body>
331
+ <div id="root"></div>
332
+ <script type="module" src="/src/main.tsx"></script>
333
+ </body>
334
+ </html>
335
+ """
336
+ ctx.write_file(app_root / "index.html", content)
337
+
338
+
339
+ def _write_app_main_tsx(ctx: RunContext, src: Path) -> None:
340
+ content = """import React from "react";
341
+ import ReactDOM from "react-dom/client";
342
+ import { App } from "./App";
343
+
344
+ ReactDOM.createRoot(document.getElementById("root")!).render(
345
+ <React.StrictMode>
346
+ <App />
347
+ </React.StrictMode>,
348
+ );
349
+ """
350
+ ctx.write_file(src / "main.tsx", content)
351
+
352
+
353
+ def _write_app_tsx(ctx: RunContext, src: Path, app_name: str, ui_pkg_name: str) -> None:
354
+ title = app_name.replace("-", " ").title()
355
+ content = f"""import {{ uiPackageName }} from "@repo/{ui_pkg_name}";
356
+
357
+ export const appTitle = "{title}";
358
+
359
+ export const App = () => {{
360
+ return (
361
+ <div>
362
+ <h1>{{appTitle}}</h1>
363
+ <p>Shared UI package: {{uiPackageName}}</p>
364
+ </div>
365
+ );
366
+ }};
367
+ """
368
+ ctx.write_file(src / "App.tsx", content)
369
+
370
+
371
+ def _write_vite_config(ctx: RunContext, app_root: Path, app_name: str) -> None:
372
+ content = """import { defineConfig } from "vite";
373
+ import react from "@vitejs/plugin-react";
374
+
375
+ export default defineConfig({
376
+ plugins: [react()],
377
+ server: {
378
+ port: 3000,
379
+ open: true,
380
+ },
381
+ });
382
+ """
383
+ ctx.write_file(app_root / "vite.config.ts", content)
384
+
385
+
386
+ def _write_ui_test(ctx: RunContext, path: Path, ui_pkg_name: str) -> None:
387
+ content = f"""import {{ describe, expect, it }} from "vitest";
388
+
389
+ import {{ uiPackageName }} from "./index";
390
+
391
+
392
+ describe("ui package", () => {{
393
+ it("exports the package name", () => {{
394
+ expect(uiPackageName).toBe("{ui_pkg_name}");
395
+ }});
396
+ }});
397
+ """
398
+ ctx.write_file(path, content)
399
+
400
+
401
+ def _write_app_test(ctx: RunContext, path: Path, app_name: str) -> None:
402
+ title = app_name.replace("-", " ").title()
403
+ content = f"""import {{ describe, expect, it }} from "vitest";
404
+
405
+ import {{ appTitle }} from "./App";
406
+
407
+
408
+ describe("web app", () => {{
409
+ it("exports the app title", () => {{
410
+ expect(appTitle).toBe("{title}");
411
+ }});
412
+ }});
413
+ """
414
+ ctx.write_file(path, content)