draft-board 0.1.0-beta.0

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 (250) hide show
  1. package/app/backend/.env.example +9 -0
  2. package/app/backend/.smartkanban/evidence/8b383839-cbec-45af-86ee-c7708d075cbe/bddf2ed5-2e21-4d46-a62b-10b87f1642a6_patch.txt +195 -0
  3. package/app/backend/.smartkanban/evidence/8b383839-cbec-45af-86ee-c7708d075cbe/bddf2ed5-2e21-4d46-a62b-10b87f1642a6_stat.txt +6 -0
  4. package/app/backend/CURL_EXAMPLES.md +335 -0
  5. package/app/backend/ENV_SETUP.md +65 -0
  6. package/app/backend/alembic/env.py +71 -0
  7. package/app/backend/alembic/script.py.mako +28 -0
  8. package/app/backend/alembic/versions/001_initial_schema.py +104 -0
  9. package/app/backend/alembic/versions/002_add_jobs_table.py +52 -0
  10. package/app/backend/alembic/versions/003_add_workspace_table.py +48 -0
  11. package/app/backend/alembic/versions/004_add_evidence_table.py +56 -0
  12. package/app/backend/alembic/versions/005_add_verification_commands.py +32 -0
  13. package/app/backend/alembic/versions/006_add_planner_lock_table.py +39 -0
  14. package/app/backend/alembic/versions/007_add_revision_review_tables.py +126 -0
  15. package/app/backend/alembic/versions/008_add_revision_idempotency_and_traceability.py +52 -0
  16. package/app/backend/alembic/versions/009_add_job_health_fields.py +46 -0
  17. package/app/backend/alembic/versions/010_add_review_comment_line_content.py +36 -0
  18. package/app/backend/alembic/versions/011_add_analysis_cache.py +47 -0
  19. package/app/backend/alembic/versions/012_add_boards_table.py +102 -0
  20. package/app/backend/alembic/versions/013_add_ticket_blocking.py +45 -0
  21. package/app/backend/alembic/versions/014_add_agent_sessions.py +220 -0
  22. package/app/backend/alembic/versions/015_add_ticket_sort_order.py +33 -0
  23. package/app/backend/alembic/versions/03220f0b93ae_add_pr_fields_to_ticket.py +49 -0
  24. package/app/backend/alembic/versions/0c2d89fff3b1_seed_board_configs_from_yaml.py +206 -0
  25. package/app/backend/alembic/versions/3348e5cf54c1_add_merge_checklist_table.py +67 -0
  26. package/app/backend/alembic/versions/357c780ee445_add_goal_status.py +34 -0
  27. package/app/backend/alembic/versions/553340b7e26c_add_autonomy_fields_to_goal.py +65 -0
  28. package/app/backend/alembic/versions/774dc335c679_merge_migration_heads.py +23 -0
  29. package/app/backend/alembic/versions/7b307e847cbd_merge_heads.py +23 -0
  30. package/app/backend/alembic/versions/82ecd978cc70_add_missing_indexes.py +48 -0
  31. package/app/backend/alembic/versions/8ef5054dc280_add_normalized_log_entries.py +173 -0
  32. package/app/backend/alembic/versions/8f3e2bd8ea3b_merge_migration_heads.py +23 -0
  33. package/app/backend/alembic/versions/9d17f0698d3b_add_config_column_to_boards_table.py +30 -0
  34. package/app/backend/alembic/versions/add_agent_conversation_history.py +72 -0
  35. package/app/backend/alembic/versions/add_job_variant.py +34 -0
  36. package/app/backend/alembic/versions/add_performance_indexes.py +95 -0
  37. package/app/backend/alembic/versions/add_repos_and_board_repos.py +174 -0
  38. package/app/backend/alembic/versions/add_session_id_to_jobs.py +27 -0
  39. package/app/backend/alembic/versions/add_sqlite_backend_tables.py +104 -0
  40. package/app/backend/alembic/versions/b10fb0b62240_add_diff_content_to_revisions.py +34 -0
  41. package/app/backend/alembic.ini +89 -0
  42. package/app/backend/app/__init__.py +3 -0
  43. package/app/backend/app/data_dir.py +85 -0
  44. package/app/backend/app/database.py +70 -0
  45. package/app/backend/app/database_sync.py +64 -0
  46. package/app/backend/app/dependencies/__init__.py +5 -0
  47. package/app/backend/app/dependencies/auth.py +80 -0
  48. package/app/backend/app/dependencies.py +43 -0
  49. package/app/backend/app/exceptions.py +178 -0
  50. package/app/backend/app/executors/__init__.py +1 -0
  51. package/app/backend/app/executors/adapters/__init__.py +1 -0
  52. package/app/backend/app/executors/adapters/aider.py +152 -0
  53. package/app/backend/app/executors/adapters/amazon_q.py +103 -0
  54. package/app/backend/app/executors/adapters/amp.py +123 -0
  55. package/app/backend/app/executors/adapters/claude.py +177 -0
  56. package/app/backend/app/executors/adapters/cline.py +127 -0
  57. package/app/backend/app/executors/adapters/codex.py +167 -0
  58. package/app/backend/app/executors/adapters/copilot.py +202 -0
  59. package/app/backend/app/executors/adapters/cursor.py +87 -0
  60. package/app/backend/app/executors/adapters/droid.py +123 -0
  61. package/app/backend/app/executors/adapters/gemini.py +132 -0
  62. package/app/backend/app/executors/adapters/goose.py +131 -0
  63. package/app/backend/app/executors/adapters/opencode.py +123 -0
  64. package/app/backend/app/executors/adapters/qwen.py +123 -0
  65. package/app/backend/app/executors/plugins/__init__.py +1 -0
  66. package/app/backend/app/executors/registry.py +202 -0
  67. package/app/backend/app/executors/spec.py +226 -0
  68. package/app/backend/app/main.py +486 -0
  69. package/app/backend/app/middleware/__init__.py +13 -0
  70. package/app/backend/app/middleware/idempotency.py +426 -0
  71. package/app/backend/app/middleware/rate_limit.py +312 -0
  72. package/app/backend/app/middleware/security_headers.py +43 -0
  73. package/app/backend/app/middleware/timeout.py +37 -0
  74. package/app/backend/app/models/__init__.py +56 -0
  75. package/app/backend/app/models/agent_conversation_history.py +56 -0
  76. package/app/backend/app/models/agent_session.py +127 -0
  77. package/app/backend/app/models/analysis_cache.py +49 -0
  78. package/app/backend/app/models/base.py +9 -0
  79. package/app/backend/app/models/board.py +79 -0
  80. package/app/backend/app/models/board_repo.py +68 -0
  81. package/app/backend/app/models/cost_budget.py +42 -0
  82. package/app/backend/app/models/enums.py +40 -0
  83. package/app/backend/app/models/evidence.py +132 -0
  84. package/app/backend/app/models/goal.py +102 -0
  85. package/app/backend/app/models/idempotency_entry.py +30 -0
  86. package/app/backend/app/models/job.py +163 -0
  87. package/app/backend/app/models/job_queue.py +39 -0
  88. package/app/backend/app/models/kv_store.py +28 -0
  89. package/app/backend/app/models/merge_checklist.py +87 -0
  90. package/app/backend/app/models/normalized_log.py +100 -0
  91. package/app/backend/app/models/planner_lock.py +43 -0
  92. package/app/backend/app/models/rate_limit_entry.py +25 -0
  93. package/app/backend/app/models/repo.py +66 -0
  94. package/app/backend/app/models/review_comment.py +91 -0
  95. package/app/backend/app/models/review_summary.py +69 -0
  96. package/app/backend/app/models/revision.py +130 -0
  97. package/app/backend/app/models/ticket.py +223 -0
  98. package/app/backend/app/models/ticket_event.py +83 -0
  99. package/app/backend/app/models/user.py +47 -0
  100. package/app/backend/app/models/workspace.py +71 -0
  101. package/app/backend/app/redis_client.py +119 -0
  102. package/app/backend/app/routers/__init__.py +29 -0
  103. package/app/backend/app/routers/agents.py +296 -0
  104. package/app/backend/app/routers/auth.py +94 -0
  105. package/app/backend/app/routers/board.py +885 -0
  106. package/app/backend/app/routers/dashboard.py +351 -0
  107. package/app/backend/app/routers/debug.py +528 -0
  108. package/app/backend/app/routers/evidence.py +96 -0
  109. package/app/backend/app/routers/executors.py +324 -0
  110. package/app/backend/app/routers/goals.py +574 -0
  111. package/app/backend/app/routers/jobs.py +448 -0
  112. package/app/backend/app/routers/maintenance.py +172 -0
  113. package/app/backend/app/routers/merge.py +360 -0
  114. package/app/backend/app/routers/planner.py +537 -0
  115. package/app/backend/app/routers/pull_requests.py +382 -0
  116. package/app/backend/app/routers/repos.py +263 -0
  117. package/app/backend/app/routers/revisions.py +939 -0
  118. package/app/backend/app/routers/settings.py +267 -0
  119. package/app/backend/app/routers/tickets.py +2003 -0
  120. package/app/backend/app/routers/webhooks.py +143 -0
  121. package/app/backend/app/routers/websocket.py +249 -0
  122. package/app/backend/app/schemas/__init__.py +109 -0
  123. package/app/backend/app/schemas/board.py +87 -0
  124. package/app/backend/app/schemas/common.py +33 -0
  125. package/app/backend/app/schemas/evidence.py +87 -0
  126. package/app/backend/app/schemas/goal.py +90 -0
  127. package/app/backend/app/schemas/job.py +97 -0
  128. package/app/backend/app/schemas/merge.py +139 -0
  129. package/app/backend/app/schemas/planner.py +500 -0
  130. package/app/backend/app/schemas/repo.py +187 -0
  131. package/app/backend/app/schemas/review.py +137 -0
  132. package/app/backend/app/schemas/revision.py +114 -0
  133. package/app/backend/app/schemas/ticket.py +238 -0
  134. package/app/backend/app/schemas/ticket_event.py +72 -0
  135. package/app/backend/app/schemas/workspace.py +19 -0
  136. package/app/backend/app/services/__init__.py +31 -0
  137. package/app/backend/app/services/agent_memory_service.py +223 -0
  138. package/app/backend/app/services/agent_registry.py +346 -0
  139. package/app/backend/app/services/agent_session_manager.py +318 -0
  140. package/app/backend/app/services/agent_session_service.py +219 -0
  141. package/app/backend/app/services/agent_tools.py +379 -0
  142. package/app/backend/app/services/auth_service.py +98 -0
  143. package/app/backend/app/services/autonomy_service.py +380 -0
  144. package/app/backend/app/services/board_repo_service.py +201 -0
  145. package/app/backend/app/services/board_service.py +326 -0
  146. package/app/backend/app/services/cleanup_service.py +1085 -0
  147. package/app/backend/app/services/config_service.py +908 -0
  148. package/app/backend/app/services/context_gatherer.py +557 -0
  149. package/app/backend/app/services/cost_tracking_service.py +293 -0
  150. package/app/backend/app/services/cursor_log_normalizer.py +536 -0
  151. package/app/backend/app/services/delivery_pipeline.py +440 -0
  152. package/app/backend/app/services/executor_service.py +634 -0
  153. package/app/backend/app/services/git_host/__init__.py +11 -0
  154. package/app/backend/app/services/git_host/factory.py +87 -0
  155. package/app/backend/app/services/git_host/github.py +270 -0
  156. package/app/backend/app/services/git_host/gitlab.py +194 -0
  157. package/app/backend/app/services/git_host/protocol.py +75 -0
  158. package/app/backend/app/services/git_merge_simple.py +346 -0
  159. package/app/backend/app/services/git_ops.py +384 -0
  160. package/app/backend/app/services/github_service.py +233 -0
  161. package/app/backend/app/services/goal_service.py +113 -0
  162. package/app/backend/app/services/job_service.py +423 -0
  163. package/app/backend/app/services/job_watchdog_service.py +424 -0
  164. package/app/backend/app/services/langchain_adapter.py +122 -0
  165. package/app/backend/app/services/llm_provider_clients.py +351 -0
  166. package/app/backend/app/services/llm_service.py +285 -0
  167. package/app/backend/app/services/log_normalizer.py +342 -0
  168. package/app/backend/app/services/log_stream_service.py +276 -0
  169. package/app/backend/app/services/merge_checklist_service.py +264 -0
  170. package/app/backend/app/services/merge_service.py +784 -0
  171. package/app/backend/app/services/orchestrator_log.py +84 -0
  172. package/app/backend/app/services/planner_service.py +1662 -0
  173. package/app/backend/app/services/planner_tick_sync.py +1040 -0
  174. package/app/backend/app/services/queued_message_service.py +156 -0
  175. package/app/backend/app/services/reliability_wrapper.py +389 -0
  176. package/app/backend/app/services/repo_discovery_service.py +318 -0
  177. package/app/backend/app/services/review_service.py +334 -0
  178. package/app/backend/app/services/revision_service.py +389 -0
  179. package/app/backend/app/services/safe_autopilot.py +510 -0
  180. package/app/backend/app/services/sqlite_worker.py +372 -0
  181. package/app/backend/app/services/task_dispatch.py +135 -0
  182. package/app/backend/app/services/ticket_generation_service.py +1781 -0
  183. package/app/backend/app/services/ticket_service.py +486 -0
  184. package/app/backend/app/services/udar_planner_service.py +1007 -0
  185. package/app/backend/app/services/webhook_service.py +126 -0
  186. package/app/backend/app/services/workspace_service.py +465 -0
  187. package/app/backend/app/services/worktree_file_service.py +92 -0
  188. package/app/backend/app/services/worktree_validator.py +213 -0
  189. package/app/backend/app/sqlite_kv.py +278 -0
  190. package/app/backend/app/state_machine.py +128 -0
  191. package/app/backend/app/templates/__init__.py +5 -0
  192. package/app/backend/app/templates/registry.py +243 -0
  193. package/app/backend/app/utils/__init__.py +5 -0
  194. package/app/backend/app/utils/artifact_reader.py +87 -0
  195. package/app/backend/app/utils/circuit_breaker.py +229 -0
  196. package/app/backend/app/utils/db_retry.py +136 -0
  197. package/app/backend/app/utils/ignored_fields.py +123 -0
  198. package/app/backend/app/utils/validators.py +54 -0
  199. package/app/backend/app/websocket/__init__.py +5 -0
  200. package/app/backend/app/websocket/manager.py +179 -0
  201. package/app/backend/app/websocket/state_tracker.py +113 -0
  202. package/app/backend/app/worker.py +3190 -0
  203. package/app/backend/calculator_tickets.json +40 -0
  204. package/app/backend/canary_tests.sh +591 -0
  205. package/app/backend/celerybeat-schedule +0 -0
  206. package/app/backend/celerybeat-schedule-shm +0 -0
  207. package/app/backend/celerybeat-schedule-wal +0 -0
  208. package/app/backend/logs/.gitkeep +3 -0
  209. package/app/backend/multiplication_division_implementation_tickets.json +55 -0
  210. package/app/backend/multiplication_division_tickets.json +42 -0
  211. package/app/backend/pyproject.toml +45 -0
  212. package/app/backend/requirements-dev.txt +8 -0
  213. package/app/backend/requirements.txt +20 -0
  214. package/app/backend/run.sh +30 -0
  215. package/app/backend/run_with_logs.sh +10 -0
  216. package/app/backend/scientific_calculator_tickets.json +40 -0
  217. package/app/backend/scripts/extract_openapi.py +21 -0
  218. package/app/backend/scripts/seed_demo.py +187 -0
  219. package/app/backend/setup_demo_review.py +302 -0
  220. package/app/backend/test_actual_parse.py +41 -0
  221. package/app/backend/test_agent_streaming.py +61 -0
  222. package/app/backend/test_parse.py +51 -0
  223. package/app/backend/test_streaming.py +51 -0
  224. package/app/backend/test_subprocess_streaming.py +50 -0
  225. package/app/backend/tests/__init__.py +1 -0
  226. package/app/backend/tests/conftest.py +46 -0
  227. package/app/backend/tests/test_auth.py +341 -0
  228. package/app/backend/tests/test_autonomy_service.py +391 -0
  229. package/app/backend/tests/test_cleanup_service_safety.py +417 -0
  230. package/app/backend/tests/test_middleware.py +279 -0
  231. package/app/backend/tests/test_planner_providers.py +290 -0
  232. package/app/backend/tests/test_planner_unblock.py +183 -0
  233. package/app/backend/tests/test_revision_invariants.py +618 -0
  234. package/app/backend/tests/test_sqlite_kv.py +290 -0
  235. package/app/backend/tests/test_sqlite_worker.py +353 -0
  236. package/app/backend/tests/test_task_dispatch.py +100 -0
  237. package/app/backend/tests/test_ticket_validation.py +304 -0
  238. package/app/backend/tests/test_udar_agent.py +693 -0
  239. package/app/backend/tests/test_webhook_service.py +184 -0
  240. package/app/backend/tickets_output.json +59 -0
  241. package/app/backend/user_management_tickets.json +50 -0
  242. package/app/backend/uvicorn.log +0 -0
  243. package/app/draft.yaml +313 -0
  244. package/app/frontend/dist/assets/index-LcjCczu5.js +155 -0
  245. package/app/frontend/dist/assets/index-_FP_279e.css +1 -0
  246. package/app/frontend/dist/index.html +14 -0
  247. package/app/frontend/dist/vite.svg +1 -0
  248. package/app/frontend/package.json +101 -0
  249. package/bin/cli.js +527 -0
  250. package/package.json +37 -0
@@ -0,0 +1,55 @@
1
+ {
2
+ "tickets": [
3
+ {
4
+ "title": "Implement multiply and divide functions in calculator module",
5
+ "description": "Create app/utils/calculator.py with two arithmetic functions:\n\n1. multiply(a, b) - multiply two numbers\n2. divide(a, b) - divide two numbers with ZeroDivisionError handling when b is 0\n\nAll functions must:\n- Include proper type hints (use float | int for numeric types, compatible with Python 3.11+)\n- Have comprehensive docstrings following Google/NumPy style with Args, Returns, and Raises sections\n- Handle edge cases appropriately (division by zero, decimal precision)\n- Support both int and float inputs\n- Return float for divide() to ensure accurate decimal results\n- Export functions in app/utils/__init__.py\n- Follow project code style (ruff formatting, double quotes, 88 char line length)\n\nAcceptance criteria:\n- File app/utils/calculator.py exists with multiply and divide functions\n- Both functions have complete type hints (float | int for parameters, float | int for multiply return, float for divide return)\n- Both functions have docstrings with Args, Returns, and Raises sections\n- divide() raises ZeroDivisionError when divisor is 0\n- Functions are exported in app/utils/__init__.py\n- Code passes ruff linting and formatting checks\n- Functions handle both int and float inputs correctly",
6
+ "priority_bucket": "P1",
7
+ "priority_rationale": "Core feature implementation - required foundation for calculator functionality. All other tickets depend on this. High priority because it's the essential functionality needed to achieve the goal.",
8
+ "verification": [
9
+ "test -f app/utils/calculator.py",
10
+ "python -c 'from app.utils import multiply, divide; assert multiply(2, 3) == 6; assert divide(10, 2) == 5.0'",
11
+ "python -c 'from app.utils.calculator import divide; import pytest; pytest.raises(ZeroDivisionError, divide, 1, 0)'",
12
+ "ruff check app/utils/calculator.py"
13
+ ],
14
+ "notes": "Use standard Python operators (* and /). For type hints, Python 3.11+ supports float | int syntax. Ensure divide() returns float for accurate decimal results. Handle edge cases like multiply(0, x) and divide(x, 1)."
15
+ },
16
+ {
17
+ "title": "Add comprehensive test coverage for multiply and divide functions",
18
+ "description": "Create tests/test_calculator.py with comprehensive test coverage for multiply and divide functions.\n\nTest requirements:\n- Test normal operation with various inputs:\n - Positive integers: multiply(2, 3), divide(10, 2)\n - Negative numbers: multiply(-2, 3), divide(-10, 2)\n - Decimal numbers: multiply(2.5, 4), divide(7.5, 2.5)\n - Zero multiplication: multiply(0, 5), multiply(5, 0)\n - Mixed types: multiply(2, 3.5), divide(10, 2.0)\n- Test error cases:\n - ZeroDivisionError for divide(1, 0)\n - ZeroDivisionError for divide(-5, 0)\n - ZeroDivisionError for divide(0.0, 0)\n- Test edge cases:\n - divide(0, 5) = 0.0\n - multiply with very large numbers\n - divide with very small numbers (but not zero)\n - multiply with negative numbers (both positive, both negative, mixed)\n- Test type handling: ensure functions work with both int and float inputs and return appropriate types\n- Use pytest.raises context manager for exception testing\n- Use @pytest.mark.parametrize for testing multiple input combinations efficiently\n- Follow existing test patterns from tests/test_middleware.py\n\nAcceptance criteria:\n- File tests/test_calculator.py exists\n- Both functions have comprehensive test coverage (aim for 100% function coverage)\n- Error cases are tested and raise correct exceptions\n- Edge cases are covered\n- Tests pass with pytest -v\n- Test coverage demonstrates correct behavior for all scenarios\n- Tests use parametrize decorator where appropriate to reduce duplication",
19
+ "priority_bucket": "P1",
20
+ "priority_rationale": "Critical for ensuring code quality and preventing regressions - tests validate correctness of core functionality and catch bugs early.",
21
+ "verification": [
22
+ "test -f tests/test_calculator.py",
23
+ "pytest tests/test_calculator.py -v",
24
+ "pytest tests/test_calculator.py --cov=app.utils.calculator --cov-report=term-missing | grep -q 'multiply\\|divide'"
25
+ ],
26
+ "notes": "Use pytest.raises context manager for exception testing. Consider parametrize decorator for testing multiple input combinations efficiently. Test both int and float inputs for each function. Include tests for decimal precision handling."
27
+ },
28
+ {
29
+ "title": "Create API endpoint for calculator operations",
30
+ "description": "Create app/routers/calculator.py with FastAPI endpoints for multiply and divide operations.\n\nEndpoint requirements:\n- POST /calculator/multiply - accepts JSON body with 'a' and 'b' fields, returns result\n- POST /calculator/divide - accepts JSON body with 'a' and 'b' fields, returns result\n- Both endpoints should:\n - Use Pydantic schemas for request/response validation (create app/schemas/calculator.py)\n - Return appropriate HTTP status codes (200 for success, 400 for division by zero)\n - Include proper error handling and error messages\n - Follow existing router patterns from app/routers/goals.py\n - Use app/exceptions.py patterns for error handling\n- Register router in app/main.py\n- Include OpenAPI documentation with examples\n\nAcceptance criteria:\n- File app/routers/calculator.py exists with both endpoints\n- File app/schemas/calculator.py exists with request/response models\n- Endpoints are registered in app/main.py\n- Request/response schemas are defined using Pydantic\n- Division by zero returns 400 status with clear error message\n- Endpoints are documented in OpenAPI/Swagger UI\n- Endpoints can be tested via curl or HTTP client",
31
+ "priority_bucket": "P2",
32
+ "priority_rationale": "Important for making calculator functionality accessible via API, but not blocking for core functionality. Users can still use the functions directly if needed. Medium priority as it enhances usability.",
33
+ "verification": [
34
+ "test -f app/routers/calculator.py",
35
+ "test -f app/schemas/calculator.py",
36
+ "grep -q 'calculator' app/main.py",
37
+ "curl -X POST http://localhost:8000/calculator/multiply -H 'Content-Type: application/json' -d '{\"a\": 2, \"b\": 3}' 2>/dev/null | grep -q '6' || echo 'Server may not be running - check manually'"
38
+ ],
39
+ "notes": "Follow FastAPI patterns from existing routers. Use app/schemas/calculator.py for request/response models. Consider adding GET endpoints with query parameters as alternative interface. Ensure error responses follow project error format from app/exceptions.py."
40
+ },
41
+ {
42
+ "title": "Enhance divide function with robust decimal precision handling",
43
+ "description": "Enhance the divide function in app/utils/calculator.py to properly handle decimal precision and document floating-point limitations.\n\nRequirements:\n- Ensure accurate decimal results (e.g., divide(1, 3) returns appropriate float precision)\n- Document precision limitations in docstring (floating-point arithmetic has inherent precision limitations)\n- Ensure consistent return type (always float, even for integer division results like divide(10, 2))\n- Handle very large numbers appropriately (test with sys.maxsize)\n- Handle very small numbers (near-zero divisors) appropriately - ensure near-zero positive numbers still work, but exact zero raises error\n- Add examples in docstring showing expected behavior\n- Update tests to verify decimal precision handling\n\nAcceptance criteria:\n- divide() handles decimal division accurately\n- Docstring documents precision behavior and limitations\n- divide() always returns float type (not int)\n- Function handles edge cases without errors (very large numbers, very small positive numbers)\n- Tests verify decimal precision handling\n- Documentation is clear about floating-point precision limitations",
44
+ "priority_bucket": "P2",
45
+ "priority_rationale": "Important for user experience and correctness, but not blocking - improves robustness of division operation and ensures proper decimal handling. Core functionality works without this enhancement.",
46
+ "verification": [
47
+ "python -c 'from app.utils.calculator import divide; result = divide(1, 3); assert isinstance(result, float); assert abs(result - 0.3333333333333333) < 1e-10'",
48
+ "python -c 'from app.utils.calculator import divide; assert isinstance(divide(10, 2), float)'",
49
+ "grep -q 'precision' app/utils/calculator.py || grep -q 'floating-point' app/utils/calculator.py",
50
+ "pytest tests/test_calculator.py -k 'decimal' -v 2>/dev/null || pytest tests/test_calculator.py -v"
51
+ ],
52
+ "notes": "Python's float division handles precision automatically. Document that floating-point arithmetic has inherent precision limitations. Consider using Decimal type for exact decimal arithmetic if needed in future enhancements, but standard float is acceptable for this implementation."
53
+ }
54
+ ]
55
+ }
@@ -0,0 +1,42 @@
1
+ {
2
+ "tickets": [
3
+ {
4
+ "title": "Implement multiply and divide functions in calculator module",
5
+ "description": "Create app/utils/calculator.py with two arithmetic functions:\n\n1. multiply(a, b) - multiply two numbers\n2. divide(a, b) - divide two numbers with ZeroDivisionError handling when b is 0\n\nAll functions must:\n- Include proper type hints (use float | int for numeric types, compatible with Python 3.11+)\n- Have comprehensive docstrings following Google/NumPy style with Args, Returns, and Raises sections\n- Handle edge cases appropriately (division by zero, decimal precision)\n- Support both int and float inputs\n- Return float for divide() to ensure accurate decimal results\n- Export functions in app/utils/__init__.py\n- Follow project code style (ruff formatting, double quotes, 88 char line length)\n\nAcceptance criteria:\n- File app/utils/calculator.py exists with multiply and divide functions\n- Both functions have complete type hints (float | int for parameters, float | int for multiply return, float for divide return)\n- Both functions have docstrings with Args, Returns, and Raises sections\n- divide() raises ZeroDivisionError when divisor is 0\n- Functions are exported in app/utils/__init__.py\n- Code passes ruff linting and formatting checks\n- Functions handle both int and float inputs correctly",
6
+ "priority_bucket": "P1",
7
+ "priority_rationale": "Core feature implementation - required foundation for calculator functionality. All other tickets depend on this. High priority because it's the essential functionality needed to achieve the goal.",
8
+ "verification": [
9
+ "test -f app/utils/calculator.py",
10
+ "python -c 'from app.utils import multiply, divide; assert multiply(2, 3) == 6; assert divide(10, 2) == 5.0'",
11
+ "python -c 'from app.utils.calculator import divide; import pytest; pytest.raises(ZeroDivisionError, divide, 1, 0)'",
12
+ "ruff check app/utils/calculator.py"
13
+ ],
14
+ "notes": "Use standard Python operators (* and /). For type hints, Python 3.11+ supports float | int syntax. Ensure divide() returns float for accurate decimal results. Handle edge cases like multiply(0, x) and divide(x, 1)."
15
+ },
16
+ {
17
+ "title": "Add comprehensive test coverage for multiply and divide functions",
18
+ "description": "Create tests/test_calculator.py with comprehensive test coverage for multiply and divide functions.\n\nTest requirements:\n- Test normal operation with various inputs:\n - Positive integers: multiply(2, 3), divide(10, 2)\n - Negative numbers: multiply(-2, 3), divide(-10, 2)\n - Decimal numbers: multiply(2.5, 4), divide(7.5, 2.5)\n - Zero multiplication: multiply(0, 5), multiply(5, 0)\n - Mixed types: multiply(2, 3.5), divide(10, 2.0)\n- Test error cases:\n - ZeroDivisionError for divide(1, 0)\n - ZeroDivisionError for divide(-5, 0)\n - ZeroDivisionError for divide(0.0, 0)\n- Test edge cases:\n - divide(0, 5) = 0.0\n - multiply with very large numbers\n - divide with very small numbers (but not zero)\n - multiply with negative numbers (both positive, both negative, mixed)\n- Test type handling: ensure functions work with both int and float inputs and return appropriate types\n- Use pytest.raises context manager for exception testing\n- Use @pytest.mark.parametrize for testing multiple input combinations efficiently\n- Follow existing test patterns from tests/test_middleware.py\n\nAcceptance criteria:\n- File tests/test_calculator.py exists\n- Both functions have comprehensive test coverage (aim for 100% function coverage)\n- Error cases are tested and raise correct exceptions\n- Edge cases are covered\n- Tests pass with pytest -v\n- Test coverage demonstrates correct behavior for all scenarios\n- Tests use parametrize decorator where appropriate to reduce duplication",
19
+ "priority_bucket": "P1",
20
+ "priority_rationale": "Critical for ensuring code quality and preventing regressions - tests validate correctness of core functionality and catch bugs early.",
21
+ "verification": [
22
+ "test -f tests/test_calculator.py",
23
+ "pytest tests/test_calculator.py -v",
24
+ "pytest tests/test_calculator.py --cov=app.utils.calculator --cov-report=term-missing | grep -q 'multiply\\|divide'"
25
+ ],
26
+ "notes": "Use pytest.raises context manager for exception testing. Consider parametrize decorator for testing multiple input combinations efficiently. Test both int and float inputs for each function. Include tests for decimal precision handling."
27
+ },
28
+ {
29
+ "title": "Handle decimal precision and edge cases in divide function",
30
+ "description": "Enhance the divide function in app/utils/calculator.py to properly handle decimal precision and edge cases.\n\nRequirements:\n- Ensure accurate decimal results (e.g., divide(1, 3) returns 0.3333333333333333)\n- Handle division by zero with clear ZeroDivisionError message\n- Handle very large numbers appropriately (test with sys.maxsize)\n- Handle very small numbers (near-zero divisors) appropriately - ensure near-zero positive numbers still work, but exact zero raises error\n- Document precision limitations in docstring (floating-point arithmetic has inherent precision limitations)\n- Ensure consistent return type (always float, even for integer division results like divide(10, 2))\n\nAcceptance criteria:\n- divide() handles decimal division accurately\n- ZeroDivisionError is raised with appropriate message for division by zero\n- Function handles edge cases without errors (very large numbers, very small positive numbers)\n- Docstring documents precision behavior and limitations\n- Tests verify decimal precision handling\n- divide() always returns float type (not int)",
31
+ "priority_bucket": "P2",
32
+ "priority_rationale": "Important for user experience and correctness, but not blocking - improves robustness of division operation and ensures proper decimal handling.",
33
+ "verification": [
34
+ "python -c 'from app.utils.calculator import divide; result = divide(1, 3); assert isinstance(result, float); assert abs(result - 0.3333333333333333) < 1e-10'",
35
+ "python -c 'from app.utils.calculator import divide; divide(1, 0)' 2>&1 | grep -q ZeroDivisionError",
36
+ "python -c 'from app.utils.calculator import divide; assert isinstance(divide(10, 2), float)'",
37
+ "pytest tests/test_calculator.py::test_divide_decimal_precision -v"
38
+ ],
39
+ "notes": "Python's float division handles precision automatically. Document that floating-point arithmetic has inherent precision limitations. Consider using Decimal type for exact decimal arithmetic if needed in future enhancements."
40
+ }
41
+ ]
42
+ }
@@ -0,0 +1,45 @@
1
+ [project]
2
+ name = "draft-backend"
3
+ version = "0.1.0"
4
+ description = "Draft Backend API"
5
+ license = {text = "BSL-1.1"}
6
+ requires-python = ">=3.11"
7
+
8
+ [tool.ruff]
9
+ target-version = "py311"
10
+ line-length = 88
11
+
12
+ [tool.ruff.lint]
13
+ select = [
14
+ "E", # pycodestyle errors
15
+ "W", # pycodestyle warnings
16
+ "F", # Pyflakes
17
+ "I", # isort
18
+ "B", # flake8-bugbear
19
+ "C4", # flake8-comprehensions
20
+ "UP", # pyupgrade
21
+ ]
22
+ ignore = [
23
+ "E501", # line too long (handled by formatter)
24
+ "B008", # function call in default argument (standard FastAPI pattern for Depends())
25
+ "B904", # raise from in except (too noisy to fix everywhere)
26
+ "E402", # module level import not at top (conditional imports)
27
+ "E741", # ambiguous variable name
28
+ "B026", # star-arg unpacking after keyword
29
+ "F821", # undefined name (false positive in dynamic imports)
30
+ "E722", # bare except in test files
31
+ "B023", # loop variable binding in test files
32
+ ]
33
+
34
+ [tool.ruff.lint.isort]
35
+ known-first-party = ["app"]
36
+
37
+ [tool.ruff.format]
38
+ quote-style = "double"
39
+ indent-style = "space"
40
+ skip-magic-trailing-comma = false
41
+ line-ending = "auto"
42
+
43
+ [tool.pytest.ini_options]
44
+ asyncio_mode = "auto"
45
+ asyncio_default_fixture_loop_scope = "function"
@@ -0,0 +1,8 @@
1
+ -r requirements.txt
2
+ ruff>=0.1.14
3
+ pytest>=7.4.0
4
+ pytest-asyncio>=0.23.0
5
+ httpx>=0.26.0
6
+
7
+
8
+ gitpython
@@ -0,0 +1,20 @@
1
+ fastapi>=0.109.0
2
+ uvicorn[standard]>=0.27.0
3
+ python-dotenv>=1.0.0
4
+ sqlalchemy>=2.0.0
5
+ alembic>=1.13.0
6
+ aiosqlite>=0.19.0
7
+ greenlet>=3.0.0
8
+ httpx>=0.25.0
9
+ litellm>=1.0.0
10
+ boto3>=1.42.0 # AWS SDK for Bedrock LLM support
11
+ sse-starlette>=2.0.0 # Server-Sent Events for real-time log streaming
12
+ jsonpatch>=1.33 # RFC 6902 JSON Patch for incremental WebSocket updates
13
+ langgraph>=0.2.0 # State machine agent framework for UDAR
14
+ langchain-core>=0.3.0 # Core abstractions for LangGraph
15
+ langchain-community>=0.3.0 # Community tools (optional)
16
+ gitpython
17
+ bcrypt>=4.0.0
18
+ python-jose[cryptography]>=3.3.0
19
+ pydantic[email]>=2.0.0 # email-validator for Pydantic EmailStr
20
+ pyyaml>=6.0 # YAML config parsing
@@ -0,0 +1,30 @@
1
+ #!/bin/bash
2
+ # Auto-restart wrapper for uvicorn backend
3
+ # Restarts automatically if the process dies unexpectedly
4
+
5
+ set -e
6
+
7
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
8
+ cd "$SCRIPT_DIR"
9
+
10
+ # Activate venv if present
11
+ if [ -f venv/bin/activate ]; then
12
+ source venv/bin/activate
13
+ fi
14
+
15
+ RESTART_DELAY=3
16
+
17
+ echo "Starting uvicorn with auto-restart (Ctrl+C to stop)..."
18
+
19
+ while true; do
20
+ python3 -m uvicorn app.main:app --host 0.0.0.0 --port 8000 --log-level info
21
+ EXIT_CODE=$?
22
+
23
+ if [ $EXIT_CODE -eq 0 ]; then
24
+ echo "uvicorn exited cleanly (code 0). Stopping."
25
+ break
26
+ fi
27
+
28
+ echo "uvicorn exited with code $EXIT_CODE. Restarting in ${RESTART_DELAY}s..."
29
+ sleep "$RESTART_DELAY"
30
+ done
@@ -0,0 +1,10 @@
1
+ #!/bin/bash
2
+ # Run backend with full logging to file
3
+
4
+ LOG_FILE="ticket_generation_debug.log"
5
+
6
+ echo "Starting backend with logging to $LOG_FILE"
7
+ echo "Tail the log file with: tail -f $LOG_FILE"
8
+
9
+ # Set Python to unbuffered mode and run uvicorn with all logs
10
+ PYTHONUNBUFFERED=1 python3 -m uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload --log-level debug 2>&1 | tee "$LOG_FILE"
@@ -0,0 +1,40 @@
1
+ {
2
+ "tickets": [
3
+ {
4
+ "title": "Create calculator.py with basic operations and extend with scientific functions",
5
+ "description": "Create calculator.py in the project root (or app/utils/calculator.py if following backend structure) with add() and subtract() functions if they don't exist, then add six new scientific calculator functions:\n\n1. multiply(a, b) - multiply two numbers\n2. divide(a, b) - divide two numbers, raise ZeroDivisionError when b is 0\n3. power(base, exp) - raise base to exponent power\n4. sqrt(n) - calculate square root, raise ValueError for negative numbers\n5. modulo(a, b) - remainder operation (a % b)\n6. factorial(n) - calculate factorial for non-negative integers, raise ValueError for negative numbers\n\nAll functions must:\n- Include proper type hints using float | int (or Union[float, int] for Python < 3.10)\n- Have comprehensive docstrings following Google/NumPy style with Args, Returns, and Raises sections\n- Handle edge cases appropriately (division by zero, negative sqrt, negative factorial)\n- Use math.sqrt and math.factorial from standard library where applicable\n\nAcceptance criteria:\n- calculator.py exists with all 8 functions (add, subtract, plus 6 new)\n- All functions have complete type hints\n- All functions have docstrings with Args, Returns, and Raises\n- Functions raise appropriate exceptions for invalid inputs\n- Code follows project style (ruff formatting)",
6
+ "priority_bucket": "P1",
7
+ "priority_rationale": "Core feature implementation - required foundation for calculator functionality. All other tickets depend on this.",
8
+ "verification": [
9
+ "test -f calculator.py || test -f app/utils/calculator.py",
10
+ "python -c 'from calculator import multiply, divide, power, sqrt, modulo, factorial; assert multiply(2, 3) == 6' || python -c 'from app.utils.calculator import multiply, divide, power, sqrt, modulo, factorial; assert multiply(2, 3) == 6'",
11
+ "python -c 'from calculator import divide; divide(1, 0)' 2>&1 | grep -q ZeroDivisionError || python -c 'from app.utils.calculator import divide; divide(1, 0)' 2>&1 | grep -q ZeroDivisionError"
12
+ ],
13
+ "notes": "Check if calculator.py exists in project root first. If not, create it. If following backend structure, use app/utils/calculator.py. Use math.sqrt() and math.factorial() from standard library. For modulo, use % operator. Python 3.11+ supports float | int syntax for type hints."
14
+ },
15
+ {
16
+ "title": "Add comprehensive test coverage for calculator functions",
17
+ "description": "Create tests/test_calculator.py with comprehensive test coverage for all calculator functions (add, subtract, multiply, divide, power, sqrt, modulo, factorial).\n\nTest requirements:\n- Test normal operation for each function with various positive and negative inputs\n- Test error cases:\n - ZeroDivisionError for divide(1, 0)\n - ValueError for sqrt(-1) and factorial(-1)\n- Test edge cases:\n - factorial(0) = 1\n - power(2, 0) = 1\n - power(0, 0) = 1\n - modulo with negative numbers\n - divide with float results\n- Test type handling: ensure functions work with both int and float inputs\n- Use pytest.raises context manager for exception testing\n- Use @pytest.mark.parametrize for testing multiple input combinations\n- Follow existing test patterns from tests/test_middleware.py\n\nAcceptance criteria:\n- File tests/test_calculator.py exists\n- All 8 functions have test coverage\n- Error cases are tested and raise correct exceptions\n- Edge cases are covered\n- Tests pass with pytest -v\n- Test coverage is comprehensive (aim for 100% function coverage)",
18
+ "priority_bucket": "P1",
19
+ "priority_rationale": "Critical for ensuring code quality and preventing regressions - tests validate correctness of core functionality and catch bugs early.",
20
+ "verification": [
21
+ "test -f tests/test_calculator.py",
22
+ "pytest tests/test_calculator.py -v",
23
+ "pytest tests/test_calculator.py --cov=calculator --cov-report=term-missing || pytest tests/test_calculator.py --cov=app.utils.calculator --cov-report=term-missing"
24
+ ],
25
+ "notes": "Use pytest.raises context manager for exception testing. Consider parametrize decorator for testing multiple input combinations efficiently. Follow pytest patterns from existing test files like tests/test_middleware.py. Test both int and float inputs for each function."
26
+ },
27
+ {
28
+ "title": "Update README.md to document calculator module",
29
+ "description": "Update README.md in the project root to document the calculator module and its scientific operations.\n\nDocumentation should include:\n- Overview section describing the calculator module\n- List of all available functions (add, subtract, multiply, divide, power, sqrt, modulo, factorial) with brief descriptions\n- Usage examples for each function using code blocks\n- Error handling information:\n - ZeroDivisionError for divide() when divisor is 0\n - ValueError for sqrt() with negative numbers\n - ValueError for factorial() with negative numbers\n- Type information (functions accept int or float, return float for most operations)\n- Link to test file (tests/test_calculator.py) for more examples\n\nAcceptance criteria:\n- README.md exists in project root\n- Calculator module section is added or updated\n- All 8 functions are documented\n- Usage examples are provided with code blocks\n- Error handling is clearly documented\n- Documentation is clear, follows project conventions, and matches existing README style",
30
+ "priority_bucket": "P2",
31
+ "priority_rationale": "Important for usability and maintainability, but not blocking for functionality - documentation helps users understand the module but code works without it.",
32
+ "verification": [
33
+ "test -f README.md",
34
+ "grep -qi 'calculator' README.md",
35
+ "grep -q 'multiply\\|divide\\|power\\|sqrt\\|modulo\\|factorial' README.md"
36
+ ],
37
+ "notes": "Add a new section to README.md for the calculator module. Include code examples using triple backticks with python syntax highlighting. Follow the existing README.md style and structure. Place the section in an appropriate location (e.g., after the main project description or in a 'Modules' section)."
38
+ }
39
+ ]
40
+ }
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env python3
2
+ """Extract OpenAPI JSON schema from FastAPI app without starting the server."""
3
+
4
+ import json
5
+ import sys
6
+ from pathlib import Path
7
+
8
+ # Add backend directory to path
9
+ backend_dir = Path(__file__).resolve().parent.parent
10
+ sys.path.insert(0, str(backend_dir))
11
+
12
+ from app.main import app # noqa: E402
13
+
14
+ if __name__ == "__main__":
15
+ schema = app.openapi()
16
+ output = json.dumps(schema, indent=2)
17
+
18
+ if len(sys.argv) > 1:
19
+ Path(sys.argv[1]).write_text(output)
20
+ else:
21
+ print(output)
@@ -0,0 +1,187 @@
1
+ #!/usr/bin/env python3
2
+ """Seed the database with demo data for first-time users.
3
+
4
+ This script creates:
5
+ - A demo board pointing to the demo-repo
6
+ - Demo goals with realistic descriptions (no pre-seeded tickets)
7
+ - Ready for live ticket generation demo
8
+
9
+ Run with: python -m scripts.seed_demo
10
+ """
11
+
12
+ import asyncio
13
+ import sys
14
+ import uuid
15
+ from pathlib import Path
16
+
17
+ import yaml
18
+
19
+ # Add backend to path so we can import app modules
20
+ sys.path.insert(0, str(Path(__file__).parent.parent))
21
+
22
+ from sqlalchemy import select
23
+
24
+ from app.database import async_session_maker, init_db
25
+ from app.models.board import Board
26
+ from app.models.goal import Goal
27
+ from app.services.config_service import DraftConfig
28
+
29
+ BOARD_ID = "demo-board"
30
+
31
+
32
+ def _load_demo_config(demo_repo_path: Path) -> dict:
33
+ """Load demo-repo/draft.yaml and set dynamic paths.
34
+
35
+ Reads the YAML config and sets the yolo_allowlist to the actual
36
+ demo-repo path so it works on any machine.
37
+ """
38
+ yaml_path = demo_repo_path / "draft.yaml"
39
+ if yaml_path.exists():
40
+ with open(yaml_path) as f:
41
+ raw = yaml.safe_load(f) or {}
42
+ else:
43
+ raw = {}
44
+
45
+ # Parse through DraftConfig for proper defaults, then convert back
46
+ config = DraftConfig.from_dict(raw)
47
+ config_dict = config.to_dict()
48
+
49
+ # Set yolo_allowlist dynamically to the resolved demo-repo path
50
+ config_dict["execute_config"]["yolo_allowlist"] = [str(demo_repo_path)]
51
+
52
+ return config_dict
53
+
54
+
55
+ async def seed_demo_data():
56
+ """Seed the database with demo board and goals (no tickets).
57
+
58
+ Creates a clean board with goals ready for live ticket generation.
59
+ """
60
+ await init_db()
61
+
62
+ async with async_session_maker() as session:
63
+ # Check if demo board already exists
64
+ result = await session.execute(select(Board).where(Board.id == BOARD_ID))
65
+ existing_board = result.scalar_one_or_none()
66
+
67
+ if existing_board:
68
+ print("Demo board already exists, skipping seed.")
69
+ print("Run with --clear first to reset.")
70
+ return
71
+
72
+ # Get the project root (where demo-repo lives)
73
+ project_root = Path(__file__).parent.parent.parent.resolve()
74
+ demo_repo_path = project_root / "demo-repo"
75
+
76
+ if not demo_repo_path.exists():
77
+ print(f"ERROR: demo-repo not found at {demo_repo_path}")
78
+ return
79
+
80
+ # Load demo config from draft.yaml and set dynamic yolo_allowlist
81
+ board_config = _load_demo_config(demo_repo_path)
82
+
83
+ # Create demo board
84
+ demo_board = Board(
85
+ id=BOARD_ID,
86
+ name="Calculator Bug Fix",
87
+ description=(
88
+ "A simple calculator app with intentional bugs. "
89
+ "Use the goals below to generate tickets and watch AI fix everything."
90
+ ),
91
+ repo_root=str(demo_repo_path),
92
+ default_branch="main",
93
+ config=board_config,
94
+ )
95
+ session.add(demo_board)
96
+
97
+ # --- Goals (no tickets - generate them live!) ---
98
+
99
+ goals = [
100
+ Goal(
101
+ id=str(uuid.uuid4()),
102
+ board_id=BOARD_ID,
103
+ title="Fix all calculator bugs",
104
+ description=(
105
+ "The calculator has three critical bugs that crash the app:\n"
106
+ "\n"
107
+ "1. Division by zero - divide() raises ZeroDivisionError\n"
108
+ "2. Negative square root - square_root() raises ValueError\n"
109
+ "3. Modulo by zero - modulo() raises ZeroDivisionError\n"
110
+ "\n"
111
+ "Each bug needs proper error handling that returns a clear\n"
112
+ "error message instead of crashing. Add tests for each fix."
113
+ ),
114
+ ),
115
+ Goal(
116
+ id=str(uuid.uuid4()),
117
+ board_id=BOARD_ID,
118
+ title="Add missing calculator features",
119
+ description=(
120
+ "The calculator is missing several features marked as TODOs:\n"
121
+ "\n"
122
+ "- percentage(value, percent) - calculate percentage of a value\n"
123
+ "- factorial(n) - compute n! iteratively\n"
124
+ "- logarithm(x, base) - compute log with given base\n"
125
+ "\n"
126
+ "Each new method needs input validation and tests."
127
+ ),
128
+ ),
129
+ ]
130
+
131
+ for goal in goals:
132
+ session.add(goal)
133
+
134
+ await session.commit()
135
+
136
+ print("Demo data seeded successfully!")
137
+ print()
138
+ print(f" Board: {demo_board.name} (ID: {BOARD_ID})")
139
+ print(f" Repo: {demo_board.repo_root}")
140
+ print(f" Goals: {len(goals)}")
141
+ for g in goals:
142
+ print(f" - {g.title}")
143
+ print()
144
+ print("Next Steps:")
145
+ print(" 1. make run")
146
+ print(" 2. Open http://localhost:5173")
147
+ print(" 3. Select the 'Calculator Bug Fix' board")
148
+ print(" 4. Click a goal -> 'Generate Tickets'")
149
+ print()
150
+
151
+
152
+ async def clear_demo_data():
153
+ """Clear demo data (useful for resetting)."""
154
+ await init_db()
155
+
156
+ async with async_session_maker() as session:
157
+ result = await session.execute(select(Board).where(Board.id == BOARD_ID))
158
+ demo_board = result.scalar_one_or_none()
159
+
160
+ if demo_board:
161
+ await session.delete(demo_board)
162
+ await session.commit()
163
+ print("Demo data cleared.")
164
+ else:
165
+ print("No demo data found.")
166
+
167
+
168
+ def main():
169
+ """Main entry point."""
170
+ import argparse
171
+
172
+ parser = argparse.ArgumentParser(description="Seed demo data for Draft")
173
+ parser.add_argument(
174
+ "--clear",
175
+ action="store_true",
176
+ help="Clear existing demo data instead of seeding",
177
+ )
178
+ args = parser.parse_args()
179
+
180
+ if args.clear:
181
+ asyncio.run(clear_demo_data())
182
+ else:
183
+ asyncio.run(seed_demo_data())
184
+
185
+
186
+ if __name__ == "__main__":
187
+ main()