reprompt-cli 2.1.0__tar.gz → 2.2.0__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 (315) hide show
  1. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/CHANGELOG.md +8 -0
  2. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/PKG-INFO +4 -2
  3. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/README.md +3 -1
  4. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/pyproject.toml +1 -1
  5. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/cli.py +172 -0
  6. reprompt_cli-2.2.0/src/reprompt/core/build.py +246 -0
  7. reprompt_cli-2.2.0/src/reprompt/core/check.py +115 -0
  8. reprompt_cli-2.2.0/src/reprompt/core/explain.py +208 -0
  9. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/suggestions.py +3 -0
  10. reprompt_cli-2.2.0/src/reprompt/output/build_terminal.py +52 -0
  11. reprompt_cli-2.2.0/src/reprompt/output/check_terminal.py +105 -0
  12. reprompt_cli-2.2.0/src/reprompt/output/explain_terminal.py +58 -0
  13. reprompt_cli-2.2.0/tests/test_build.py +270 -0
  14. reprompt_cli-2.2.0/tests/test_build_cli.py +126 -0
  15. reprompt_cli-2.2.0/tests/test_build_output.py +59 -0
  16. reprompt_cli-2.2.0/tests/test_check.py +101 -0
  17. reprompt_cli-2.2.0/tests/test_check_cli.py +80 -0
  18. reprompt_cli-2.2.0/tests/test_explain.py +100 -0
  19. reprompt_cli-2.2.0/tests/test_explain_cli.py +56 -0
  20. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/uv.lock +1 -1
  21. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/.editorconfig +0 -0
  22. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  23. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  24. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  25. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  26. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  27. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/.github/dependabot.yml +0 -0
  28. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/.github/workflows/ci.yml +0 -0
  29. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/.github/workflows/publish.yml +0 -0
  30. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/.gitignore +0 -0
  31. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/.pre-commit-config.yaml +0 -0
  32. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/.pre-commit-hooks.yaml +0 -0
  33. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/.testmondata-shm +0 -0
  34. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/.testmondata-wal +0 -0
  35. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/CODE_OF_CONDUCT.md +0 -0
  36. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/CONTRIBUTING.md +0 -0
  37. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/LICENSE +0 -0
  38. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/SECURITY.md +0 -0
  39. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/Screenshot 2026-03-24 at 09.45.03.png +0 -0
  40. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/action.yml +0 -0
  41. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/demo.gif +0 -0
  42. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/brand-icon-128.png +0 -0
  43. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/brand-icon-16.png +0 -0
  44. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/brand-icon-256.png +0 -0
  45. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/brand-icon-32.png +0 -0
  46. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/brand-icon-48.png +0 -0
  47. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/brand-icon-512.png +0 -0
  48. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/brand-icon-96.png +0 -0
  49. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/brand-icon.svg +0 -0
  50. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/cli-favicon-128.png +0 -0
  51. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/cli-favicon-16.png +0 -0
  52. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/cli-favicon-256.png +0 -0
  53. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/cli-favicon-32.png +0 -0
  54. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/cli-favicon-48.png +0 -0
  55. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/cli-favicon-512.png +0 -0
  56. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/cli-favicon-96.png +0 -0
  57. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/cli-favicon.svg +0 -0
  58. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/cli-icon-128.png +0 -0
  59. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/cli-icon-16.png +0 -0
  60. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/cli-icon-256.png +0 -0
  61. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/cli-icon-32.png +0 -0
  62. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/cli-icon-48.png +0 -0
  63. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/cli-icon-512.png +0 -0
  64. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/cli-icon-96.png +0 -0
  65. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/cli-icon.svg +0 -0
  66. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/favicon-128.png +0 -0
  67. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/favicon-16.png +0 -0
  68. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/favicon-256.png +0 -0
  69. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/favicon-32.png +0 -0
  70. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/favicon-48.png +0 -0
  71. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/favicon-512.png +0 -0
  72. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/favicon-96.png +0 -0
  73. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/favicon.svg +0 -0
  74. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/icons/generate.sh +0 -0
  75. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/superpowers/specs/2026-03-24-v14-command-consolidation-design.md +0 -0
  76. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/docs/superpowers/specs/2026-03-25-v1.5-dashboard-design.md +0 -0
  77. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/scripts/generate_demo_data.py +0 -0
  78. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/__init__.py +0 -0
  79. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/adapters/__init__.py +0 -0
  80. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/adapters/aider.py +0 -0
  81. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/adapters/base.py +0 -0
  82. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/adapters/chatgpt.py +0 -0
  83. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/adapters/claude_chat.py +0 -0
  84. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/adapters/claude_code.py +0 -0
  85. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/adapters/cline.py +0 -0
  86. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/adapters/codex.py +0 -0
  87. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/adapters/cursor.py +0 -0
  88. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/adapters/filters.py +0 -0
  89. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/adapters/gemini.py +0 -0
  90. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/adapters/openclaw.py +0 -0
  91. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/bridge/__init__.py +0 -0
  92. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/bridge/handler.py +0 -0
  93. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/bridge/host.py +0 -0
  94. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/bridge/manifest.py +0 -0
  95. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/bridge/protocol.py +0 -0
  96. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/commands/__init__.py +0 -0
  97. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/commands/telemetry.py +0 -0
  98. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/commands/wrapped.py +0 -0
  99. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/config.py +0 -0
  100. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/__init__.py +0 -0
  101. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/agent.py +0 -0
  102. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/analyzer.py +0 -0
  103. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/compress.py +0 -0
  104. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/conversation.py +0 -0
  105. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/cost.py +0 -0
  106. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/dashboard.py +0 -0
  107. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/dedup.py +0 -0
  108. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/digest.py +0 -0
  109. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/distill.py +0 -0
  110. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/effectiveness.py +0 -0
  111. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/extractors.py +0 -0
  112. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/extractors_zh.py +0 -0
  113. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/insights.py +0 -0
  114. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/lang_detect.py +0 -0
  115. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/library.py +0 -0
  116. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/lint.py +0 -0
  117. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/merge_view.py +0 -0
  118. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/models.py +0 -0
  119. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/persona.py +0 -0
  120. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/pipeline.py +0 -0
  121. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/privacy.py +0 -0
  122. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/privacy_scan.py +0 -0
  123. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/prompt_dna.py +0 -0
  124. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/recommend.py +0 -0
  125. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/repetition.py +0 -0
  126. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/rewrite.py +0 -0
  127. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/scorer.py +0 -0
  128. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/segmenter.py +0 -0
  129. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/session_meta.py +0 -0
  130. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/session_quality.py +0 -0
  131. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/session_type.py +0 -0
  132. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/style.py +0 -0
  133. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/templates.py +0 -0
  134. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/timeutil.py +0 -0
  135. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/trends.py +0 -0
  136. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/core/wrapped.py +0 -0
  137. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/demo.py +0 -0
  138. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/embeddings/__init__.py +0 -0
  139. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/embeddings/base.py +0 -0
  140. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/embeddings/local_embed.py +0 -0
  141. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/embeddings/ollama.py +0 -0
  142. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/embeddings/openai_embed.py +0 -0
  143. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/embeddings/tfidf.py +0 -0
  144. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/mcp.py +0 -0
  145. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/mcp_main.py +0 -0
  146. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/output/__init__.py +0 -0
  147. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/output/agent_terminal.py +0 -0
  148. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/output/chartjs.min.js +0 -0
  149. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/output/compress_terminal.py +0 -0
  150. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/output/dashboard_terminal.py +0 -0
  151. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/output/distill_terminal.py +0 -0
  152. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/output/export.py +0 -0
  153. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/output/html_report.py +0 -0
  154. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/output/json_out.py +0 -0
  155. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/output/markdown.py +0 -0
  156. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/output/projects_terminal.py +0 -0
  157. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/output/repetition_terminal.py +0 -0
  158. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/output/rewrite_terminal.py +0 -0
  159. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/output/sessions_terminal.py +0 -0
  160. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/output/terminal.py +0 -0
  161. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/output/wrapped_html.py +0 -0
  162. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/output/wrapped_terminal.py +0 -0
  163. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/py.typed +0 -0
  164. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/sharing/__init__.py +0 -0
  165. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/sharing/client.py +0 -0
  166. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/sharing/clipboard.py +0 -0
  167. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/storage/__init__.py +0 -0
  168. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/storage/db.py +0 -0
  169. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/telemetry/__init__.py +0 -0
  170. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/telemetry/collector.py +0 -0
  171. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/telemetry/consent.py +0 -0
  172. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/telemetry/events.py +0 -0
  173. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/telemetry/prompt.py +0 -0
  174. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/telemetry/queue.py +0 -0
  175. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/src/reprompt/telemetry/sender.py +0 -0
  176. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/__init__.py +0 -0
  177. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/conftest.py +0 -0
  178. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/fixtures/aider_chat_history.md +0 -0
  179. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/fixtures/chatgpt_conversations.json +0 -0
  180. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/fixtures/claude_chat_export.json +0 -0
  181. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/fixtures/claude_session.jsonl +0 -0
  182. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/fixtures/cline_task/api_conversation_history.json +0 -0
  183. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/fixtures/export/default_export.md +0 -0
  184. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/fixtures/export/full_export.md +0 -0
  185. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/fixtures/gemini_session.json +0 -0
  186. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/fixtures/openclaw_session.jsonl +0 -0
  187. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_adapter_aider.py +0 -0
  188. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_adapter_chatgpt.py +0 -0
  189. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_adapter_claude.py +0 -0
  190. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_adapter_claude_chat.py +0 -0
  191. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_adapter_cline.py +0 -0
  192. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_adapter_gemini.py +0 -0
  193. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_adapter_openclaw.py +0 -0
  194. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_agent.py +0 -0
  195. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_agent_cli.py +0 -0
  196. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_analyzer.py +0 -0
  197. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_bridge_cli.py +0 -0
  198. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_bridge_e2e.py +0 -0
  199. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_bridge_handler.py +0 -0
  200. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_bridge_integration.py +0 -0
  201. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_bridge_manifest.py +0 -0
  202. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_bridge_protocol.py +0 -0
  203. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_cli.py +0 -0
  204. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_cli_deprecations.py +0 -0
  205. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_cli_library_effectiveness.py +0 -0
  206. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_clipboard.py +0 -0
  207. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_codex_adapter.py +0 -0
  208. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_compare_best_worst.py +0 -0
  209. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_compress.py +0 -0
  210. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_compress_cli.py +0 -0
  211. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_compress_dna.py +0 -0
  212. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_compress_html.py +0 -0
  213. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_compress_insights.py +0 -0
  214. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_config.py +0 -0
  215. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_conversation.py +0 -0
  216. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_copy_flag.py +0 -0
  217. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_cost.py +0 -0
  218. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_coverage_boost.py +0 -0
  219. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_cursor_adapter.py +0 -0
  220. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_dashboard.py +0 -0
  221. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_db.py +0 -0
  222. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_db_digest.py +0 -0
  223. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_db_effectiveness.py +0 -0
  224. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_db_session_quality.py +0 -0
  225. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_db_trends.py +0 -0
  226. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_dedup.py +0 -0
  227. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_demo.py +0 -0
  228. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_deprecated_commands.py +0 -0
  229. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_digest.py +0 -0
  230. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_digest_cli.py +0 -0
  231. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_distill.py +0 -0
  232. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_distill_cli.py +0 -0
  233. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_distill_weights.py +0 -0
  234. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_e2e.py +0 -0
  235. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_effectiveness.py +0 -0
  236. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_embeddings_local.py +0 -0
  237. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_embeddings_ollama.py +0 -0
  238. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_embeddings_openai.py +0 -0
  239. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_empty_state.py +0 -0
  240. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_export.py +0 -0
  241. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_export_cli.py +0 -0
  242. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_export_snapshot.py +0 -0
  243. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_extractors.py +0 -0
  244. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_extractors_routing.py +0 -0
  245. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_extractors_zh.py +0 -0
  246. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_extractors_zh_e2e.py +0 -0
  247. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_html_report.py +0 -0
  248. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_import_cli.py +0 -0
  249. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_import_e2e.py +0 -0
  250. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_init_cli.py +0 -0
  251. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_insights.py +0 -0
  252. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_insights_cli.py +0 -0
  253. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_insights_expanded.py +0 -0
  254. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_install_hook.py +0 -0
  255. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_lang_detect.py +0 -0
  256. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_library.py +0 -0
  257. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_lint.py +0 -0
  258. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_lint_cli.py +0 -0
  259. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_markdown.py +0 -0
  260. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_mcp.py +0 -0
  261. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_merge_view.py +0 -0
  262. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_models.py +0 -0
  263. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_output.py +0 -0
  264. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_parse_conversation_base.py +0 -0
  265. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_parse_conversation_chatgpt.py +0 -0
  266. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_parse_conversation_claude.py +0 -0
  267. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_persona.py +0 -0
  268. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_pipeline.py +0 -0
  269. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_privacy.py +0 -0
  270. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_privacy_cli.py +0 -0
  271. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_privacy_e2e.py +0 -0
  272. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_privacy_output.py +0 -0
  273. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_privacy_scan.py +0 -0
  274. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_projects.py +0 -0
  275. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_prompt_dna.py +0 -0
  276. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_public_api.py +0 -0
  277. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_recommend.py +0 -0
  278. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_repetition.py +0 -0
  279. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_repetition_cli.py +0 -0
  280. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_repetition_output.py +0 -0
  281. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_rewrite.py +0 -0
  282. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_schema_version.py +0 -0
  283. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_score_cli.py +0 -0
  284. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_scorer.py +0 -0
  285. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_segmenter.py +0 -0
  286. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_session_quality.py +0 -0
  287. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_session_type.py +0 -0
  288. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_sessions_cli.py +0 -0
  289. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_sessions_output.py +0 -0
  290. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_share_e2e.py +0 -0
  291. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_sharing_client.py +0 -0
  292. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_source_filter.py +0 -0
  293. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_style.py +0 -0
  294. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_style_trends.py +0 -0
  295. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_suggestions.py +0 -0
  296. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_telemetry_cli.py +0 -0
  297. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_telemetry_collector.py +0 -0
  298. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_telemetry_consent.py +0 -0
  299. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_telemetry_e2e.py +0 -0
  300. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_telemetry_events.py +0 -0
  301. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_telemetry_prompt.py +0 -0
  302. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_telemetry_queue.py +0 -0
  303. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_telemetry_sender.py +0 -0
  304. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_template_cli.py +0 -0
  305. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_templates.py +0 -0
  306. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_timeutil.py +0 -0
  307. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_trends.py +0 -0
  308. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_trends_cli.py +0 -0
  309. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_use_cli.py +0 -0
  310. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_wrapped.py +0 -0
  311. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_wrapped_cli.py +0 -0
  312. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_wrapped_e2e.py +0 -0
  313. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_wrapped_html.py +0 -0
  314. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_wrapped_output.py +0 -0
  315. {reprompt_cli-2.1.0 → reprompt_cli-2.2.0}/tests/test_wrapped_share.py +0 -0
@@ -2,6 +2,14 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [2.2.0] - 2026-04-01
6
+
7
+ ### Added
8
+ - **Prompt builder** — `reprompt build "task" --file src/auth.ts --error "TypeError" --constraint "keep tests"` assembles well-scored prompts from components. Model-aware formatting: XML tags for Claude, markdown headers for GPT. Shows score, tier, and suggestions for missing components.
9
+ - **Unified diagnostic** — `reprompt check "prompt"` runs score + lint + rewrite in one command. Shows dimensional breakdown, strengths, suggestions with point values, lint issues, and auto-rewrite preview.
10
+ - **Prompt explainer** — `reprompt explain "prompt"` explains what makes a prompt good or bad in plain English. Educational feedback with research-backed insights per dimension.
11
+ - Tests: 1741 → 1846
12
+
5
13
  ## [2.1.0] - 2026-04-01
6
14
 
7
15
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: reprompt-cli
3
- Version: 2.1.0
3
+ Version: 2.2.0
4
4
  Summary: Discover, analyze, and optimize your prompts from AI coding sessions
5
5
  Project-URL: Homepage, https://github.com/reprompt-dev/reprompt
6
6
  Project-URL: Repository, https://github.com/reprompt-dev/reprompt
@@ -104,6 +104,7 @@ $ reprompt
104
104
  |---------|-------------|
105
105
  | `reprompt` | Instant dashboard -- prompts, sessions, avg score, top categories |
106
106
  | `reprompt scan` | Auto-discover prompts from 9 AI tools |
107
+ | `reprompt check "prompt"` | **Full diagnostic** -- score + lint + rewrite preview in one command |
107
108
  | `reprompt score "prompt"` | Research-backed 0-100 scoring with 30+ features |
108
109
  | `reprompt compare "a" "b"` | Side-by-side prompt analysis (or `--best-worst` for auto-selection) |
109
110
  | `reprompt insights` | Personal patterns vs research-optimal benchmarks |
@@ -117,6 +118,7 @@ $ reprompt
117
118
 
118
119
  | Command | Description |
119
120
  |---------|-------------|
121
+ | `reprompt build "task"` | **Build prompts from components** -- task, context, files, errors, constraints. Model-aware (Claude/GPT/Gemini) |
120
122
  | `reprompt rewrite "prompt"` | **Rewrite prompts to score higher** -- filler removal, restructuring, hedging cleanup |
121
123
  | `reprompt compress "prompt"` | 4-layer prompt compression (40-60% token savings typical) |
122
124
  | `reprompt distill` | Extract important turns from conversations with 6-signal scoring |
@@ -228,7 +230,7 @@ Captured prompts sync locally via Native Messaging -- nothing leaves your machin
228
230
  # .pre-commit-config.yaml
229
231
  repos:
230
232
  - repo: https://github.com/reprompt-dev/reprompt
231
- rev: v2.1.0
233
+ rev: v2.2.0
232
234
  hooks:
233
235
  - id: reprompt-lint
234
236
  ```
@@ -59,6 +59,7 @@ $ reprompt
59
59
  |---------|-------------|
60
60
  | `reprompt` | Instant dashboard -- prompts, sessions, avg score, top categories |
61
61
  | `reprompt scan` | Auto-discover prompts from 9 AI tools |
62
+ | `reprompt check "prompt"` | **Full diagnostic** -- score + lint + rewrite preview in one command |
62
63
  | `reprompt score "prompt"` | Research-backed 0-100 scoring with 30+ features |
63
64
  | `reprompt compare "a" "b"` | Side-by-side prompt analysis (or `--best-worst` for auto-selection) |
64
65
  | `reprompt insights` | Personal patterns vs research-optimal benchmarks |
@@ -72,6 +73,7 @@ $ reprompt
72
73
 
73
74
  | Command | Description |
74
75
  |---------|-------------|
76
+ | `reprompt build "task"` | **Build prompts from components** -- task, context, files, errors, constraints. Model-aware (Claude/GPT/Gemini) |
75
77
  | `reprompt rewrite "prompt"` | **Rewrite prompts to score higher** -- filler removal, restructuring, hedging cleanup |
76
78
  | `reprompt compress "prompt"` | 4-layer prompt compression (40-60% token savings typical) |
77
79
  | `reprompt distill` | Extract important turns from conversations with 6-signal scoring |
@@ -183,7 +185,7 @@ Captured prompts sync locally via Native Messaging -- nothing leaves your machin
183
185
  # .pre-commit-config.yaml
184
186
  repos:
185
187
  - repo: https://github.com/reprompt-dev/reprompt
186
- rev: v2.1.0
188
+ rev: v2.2.0
187
189
  hooks:
188
190
  - id: reprompt-lint
189
191
  ```
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "reprompt-cli"
3
- version = "2.1.0"
3
+ version = "2.2.0"
4
4
  description = "Discover, analyze, and optimize your prompts from AI coding sessions"
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -946,6 +946,111 @@ def lint(
946
946
  raise typer.Exit(1)
947
947
 
948
948
 
949
+ @app.command(rich_help_panel="Analyze")
950
+ def check(
951
+ text: str = typer.Argument(..., help="Prompt text to check"),
952
+ model: str = typer.Option("", "--model", "-m", help="Target model (claude/gpt/gemini)"),
953
+ max_tokens: int = typer.Option(0, "--max-tokens", help="Token budget (0 = disabled)"),
954
+ json_output: bool = typer.Option(False, "--json", help="Output as JSON"),
955
+ copy: bool = typer.Option(False, "--copy", help="Copy rewritten prompt to clipboard"),
956
+ ) -> None:
957
+ """Full prompt diagnostic — score + lint + rewrite in one command.
958
+
959
+ Runs all quality checks and shows a unified report with score breakdown,
960
+ strengths, suggestions, lint issues, and auto-rewrite preview.
961
+
962
+ Examples:
963
+
964
+ reprompt check "fix the auth bug in login.ts"
965
+
966
+ reprompt check "refactor the middleware" --model claude
967
+
968
+ reprompt check "help me debug this crash" --json
969
+ """
970
+ from reprompt.core.check import check_prompt
971
+
972
+ result = check_prompt(text, model=model, max_tokens=max_tokens)
973
+
974
+ if json_output:
975
+ import json as json_mod
976
+
977
+ data = {
978
+ "total": result.total,
979
+ "tier": result.tier,
980
+ "clarity": result.clarity,
981
+ "context": result.context,
982
+ "position": result.position,
983
+ "structure": result.structure,
984
+ "repetition": result.repetition,
985
+ "word_count": result.word_count,
986
+ "token_count": result.token_count,
987
+ "confirmations": result.confirmations,
988
+ "suggestions": result.suggestions,
989
+ "lint_issues": result.lint_issues,
990
+ "rewritten": result.rewritten,
991
+ "rewrite_delta": result.rewrite_delta,
992
+ "rewrite_changes": result.rewrite_changes,
993
+ }
994
+ typer.echo(json_mod.dumps(data, indent=2, ensure_ascii=False))
995
+ else:
996
+ from reprompt.output.check_terminal import render_check
997
+
998
+ typer.echo(render_check(result))
999
+
1000
+ if copy:
1001
+ _copy_to_clip(result.rewritten, quiet=json_output)
1002
+
1003
+ from reprompt.core.suggestions import get_suggestion
1004
+
1005
+ hint = get_suggestion("check")
1006
+ if hint and not json_output:
1007
+ console.print(f" [dim]→ Try: {hint}[/dim]\n")
1008
+
1009
+
1010
+ @app.command(rich_help_panel="Analyze")
1011
+ def explain(
1012
+ text: str = typer.Argument(..., help="Prompt text to explain"),
1013
+ json_output: bool = typer.Option(False, "--json", help="Output as JSON"),
1014
+ ) -> None:
1015
+ """Explain what makes a prompt good or bad in plain English.
1016
+
1017
+ Analyzes the prompt and provides educational feedback: what's working,
1018
+ what's missing, and specific tips to improve. No LLM needed.
1019
+
1020
+ Examples:
1021
+
1022
+ reprompt explain "fix the auth bug"
1023
+
1024
+ reprompt explain "Fix the JWT expiration in src/auth.ts line 42" --json
1025
+ """
1026
+ from reprompt.core.explain import explain_prompt
1027
+
1028
+ result = explain_prompt(text)
1029
+
1030
+ if json_output:
1031
+ import json as json_mod
1032
+
1033
+ data = {
1034
+ "score": result.score,
1035
+ "tier": result.tier,
1036
+ "summary": result.summary,
1037
+ "strengths": result.strengths,
1038
+ "weaknesses": result.weaknesses,
1039
+ "tips": result.tips,
1040
+ }
1041
+ typer.echo(json_mod.dumps(data, indent=2, ensure_ascii=False))
1042
+ else:
1043
+ from reprompt.output.explain_terminal import render_explain
1044
+
1045
+ typer.echo(render_explain(result))
1046
+
1047
+ from reprompt.core.suggestions import get_suggestion
1048
+
1049
+ hint = get_suggestion("explain")
1050
+ if hint and not json_output:
1051
+ console.print(f" [dim]→ Try: {hint}[/dim]\n")
1052
+
1053
+
949
1054
  @app.command(rich_help_panel="Analyze")
950
1055
  def score(
951
1056
  text: str = typer.Argument(..., help="Prompt text to score"),
@@ -1158,6 +1263,73 @@ def rewrite(
1158
1263
  console.print(f" [dim]→ Try: {hint}[/dim]\n")
1159
1264
 
1160
1265
 
1266
+ @app.command(rich_help_panel="Optimize")
1267
+ def build(
1268
+ task: str = typer.Argument(..., help="What the AI should do"),
1269
+ context: str = typer.Option("", "--context", "-c", help="Background information"),
1270
+ file: list[str] = typer.Option([], "--file", "-f", help="File references (repeatable)"),
1271
+ error: str = typer.Option("", "--error", "-e", help="Error message or stack trace"),
1272
+ constraint: list[str] = typer.Option([], "--constraint", help="Constraints (repeatable)"),
1273
+ example: str = typer.Option("", "--example", help="Example input/output"),
1274
+ output_format: str = typer.Option("", "--output-format", help="Expected response format"),
1275
+ role: str = typer.Option("", "--role", "-r", help="AI role/persona"),
1276
+ model: str = typer.Option("", "--model", "-m", help="Target model (claude/gpt/gemini)"),
1277
+ json_output: bool = typer.Option(False, "--json", help="Output as JSON"),
1278
+ copy: bool = typer.Option(False, "--copy", help="Copy built prompt to clipboard"),
1279
+ ) -> None:
1280
+ """Build a well-structured prompt from components.
1281
+
1282
+ Assembles a prompt that maximizes quality score by combining
1283
+ your task with context, files, errors, and constraints.
1284
+
1285
+ Examples:
1286
+
1287
+ reprompt build "fix the auth bug"
1288
+
1289
+ reprompt build "fix the crash" --file src/auth.ts --error "TypeError: ..."
1290
+
1291
+ reprompt build "refactor" -f src/app.py --constraint "keep tests" --model claude
1292
+ """
1293
+ from reprompt.core.build import build_prompt
1294
+
1295
+ result = build_prompt(
1296
+ task,
1297
+ context=context,
1298
+ files=file if file else None,
1299
+ error=error,
1300
+ constraints=constraint if constraint else None,
1301
+ examples=example,
1302
+ output_format=output_format,
1303
+ role=role,
1304
+ model=model,
1305
+ )
1306
+
1307
+ if json_output:
1308
+ import json as json_mod
1309
+
1310
+ data = {
1311
+ "prompt": result.prompt,
1312
+ "score": result.score,
1313
+ "tier": result.tier,
1314
+ "components_used": result.components_used,
1315
+ "suggestions": result.suggestions,
1316
+ }
1317
+ typer.echo(json_mod.dumps(data, indent=2, ensure_ascii=False))
1318
+ else:
1319
+ from reprompt.output.build_terminal import render_build
1320
+
1321
+ typer.echo(render_build(result))
1322
+
1323
+ if copy:
1324
+ _copy_to_clip(result.prompt, quiet=json_output)
1325
+
1326
+ from reprompt.core.suggestions import get_suggestion
1327
+
1328
+ hint = get_suggestion("build")
1329
+ if hint and not json_output:
1330
+ console.print(f" [dim]→ Try: {hint}[/dim]\n")
1331
+
1332
+
1161
1333
  @app.command(rich_help_panel="Optimize")
1162
1334
  def distill(
1163
1335
  session_id: str = typer.Argument(None, help="Session ID to distill"),
@@ -0,0 +1,246 @@
1
+ """Prompt builder — assemble a well-structured prompt from components.
2
+
3
+ Takes a task description and optional context, files, errors, constraints,
4
+ and examples, then assembles a prompt that maximizes the scoring dimensions.
5
+ Scoring-aware: structures the output to hit clarity, context, and position.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass, field
11
+
12
+
13
+ @dataclass
14
+ class BuildResult:
15
+ """Result of building a prompt from components."""
16
+
17
+ prompt: str
18
+ score: float = 0.0
19
+ tier: str = ""
20
+ components_used: list[str] = field(default_factory=list)
21
+ suggestions: list[str] = field(default_factory=list)
22
+
23
+
24
+ def build_prompt(
25
+ task: str,
26
+ *,
27
+ context: str = "",
28
+ files: list[str] | None = None,
29
+ error: str = "",
30
+ constraints: list[str] | None = None,
31
+ examples: str = "",
32
+ output_format: str = "",
33
+ role: str = "",
34
+ model: str = "",
35
+ ) -> BuildResult:
36
+ """Build a well-structured prompt from components.
37
+
38
+ Returns the assembled prompt with its score and suggestions
39
+ for components the user could still add.
40
+ """
41
+ parts: list[str] = []
42
+ components: list[str] = []
43
+
44
+ # Role (if provided) — goes first
45
+ if role:
46
+ parts.append(f"You are {role}.")
47
+ components.append("role")
48
+
49
+ # Task — always present, imperative form, at the front (position bias)
50
+ task_text = _ensure_imperative(task.strip())
51
+ if task_text and task_text[-1] not in ".!?":
52
+ task_text += "."
53
+ parts.append(task_text)
54
+ components.append("task")
55
+
56
+ # File references — high context value
57
+ if files:
58
+ if len(files) == 1:
59
+ parts.append(f"File: {files[0]}")
60
+ else:
61
+ file_list = ", ".join(files)
62
+ parts.append(f"Files: {file_list}")
63
+ components.append("files")
64
+
65
+ # Error context — critical for debug prompts
66
+ if error:
67
+ parts.append(f"Error: {error}")
68
+ components.append("error")
69
+
70
+ # Context — background information
71
+ if context:
72
+ parts.append(f"Context: {context}")
73
+ components.append("context")
74
+
75
+ # Examples
76
+ if examples:
77
+ parts.append(f"Example:\n{examples}")
78
+ components.append("examples")
79
+
80
+ # Constraints
81
+ if constraints:
82
+ if len(constraints) == 1:
83
+ parts.append(f"Constraint: {constraints[0]}")
84
+ else:
85
+ constraint_lines = "\n".join(f"- {c}" for c in constraints)
86
+ parts.append(f"Constraints:\n{constraint_lines}")
87
+ components.append("constraints")
88
+
89
+ # Output format
90
+ if output_format:
91
+ parts.append(f"Output format: {output_format}")
92
+ components.append("output_format")
93
+
94
+ # Model-specific formatting
95
+ prompt = _format_for_model(parts, model)
96
+
97
+ # Score the assembled prompt
98
+ from reprompt.core.extractors import extract_features
99
+ from reprompt.core.scorer import score_prompt
100
+
101
+ dna = extract_features(prompt, source="build", session_id="")
102
+ score_result = score_prompt(dna)
103
+
104
+ # Determine tier
105
+ tier = _get_tier(score_result.total)
106
+
107
+ # Generate suggestions for missing components
108
+ suggestions = _missing_suggestions(components)
109
+
110
+ return BuildResult(
111
+ prompt=prompt,
112
+ score=score_result.total,
113
+ tier=tier,
114
+ components_used=components,
115
+ suggestions=suggestions,
116
+ )
117
+
118
+
119
+ def _ensure_imperative(task: str) -> str:
120
+ """Strip filler prefixes to get an imperative task statement."""
121
+ import re
122
+
123
+ # Remove common polite/filler prefixes
124
+ cleaned = re.sub(
125
+ r"^(?:please\s+|can you\s+|could you\s+|i need you to\s+|"
126
+ r"i want you to\s+|i would like you to\s+|help me\s+|"
127
+ r"i was wondering if you could\s+)",
128
+ "",
129
+ task,
130
+ flags=re.IGNORECASE,
131
+ )
132
+ # Capitalize first letter
133
+ if cleaned:
134
+ cleaned = cleaned[0].upper() + cleaned[1:]
135
+ return cleaned
136
+
137
+
138
+ def _format_for_model(parts: list[str], model: str) -> str:
139
+ """Format prompt parts with model-appropriate structure."""
140
+ if model == "claude":
141
+ return _format_xml(parts)
142
+ elif model == "gpt":
143
+ return _format_markdown(parts)
144
+ else:
145
+ # Default: clean plain text with double newlines
146
+ return "\n\n".join(parts)
147
+
148
+
149
+ def _format_xml(parts: list[str]) -> str:
150
+ """Format with XML tags (preferred by Claude)."""
151
+ if len(parts) <= 2:
152
+ # Short prompts don't need XML
153
+ return "\n\n".join(parts)
154
+
155
+ sections: list[str] = []
156
+ for part in parts:
157
+ lower = part.lower()
158
+ if lower.startswith("you are "):
159
+ sections.append(part)
160
+ elif lower.startswith("context:"):
161
+ content = part[len("Context:") :].strip()
162
+ sections.append(f"<context>\n{content}\n</context>")
163
+ elif lower.startswith("error:"):
164
+ content = part[len("Error:") :].strip()
165
+ sections.append(f"<context>\n{content}\n</context>")
166
+ elif lower.startswith("constraint"):
167
+ content = part.split(":", 1)[1].strip() if ":" in part else part
168
+ sections.append(f"<constraints>\n{content}\n</constraints>")
169
+ elif lower.startswith("example"):
170
+ content = part.split(":", 1)[1].strip() if ":" in part else part
171
+ content = part.split("\n", 1)[1].strip() if "\n" in part else content
172
+ sections.append(f"<examples>\n{content}\n</examples>")
173
+ elif lower.startswith("output format:"):
174
+ content = part[len("Output format:") :].strip()
175
+ sections.append(f"<output>\n{content}\n</output>")
176
+ else:
177
+ sections.append(part)
178
+
179
+ return "\n\n".join(sections)
180
+
181
+
182
+ def _format_markdown(parts: list[str]) -> str:
183
+ """Format with markdown headers (preferred by GPT)."""
184
+ if len(parts) <= 2:
185
+ return "\n\n".join(parts)
186
+
187
+ sections: list[str] = []
188
+ for part in parts:
189
+ lower = part.lower()
190
+ if lower.startswith("you are "):
191
+ sections.append(part)
192
+ elif lower.startswith("context:"):
193
+ content = part[len("Context:") :].strip()
194
+ sections.append(f"## Context\n{content}")
195
+ elif lower.startswith("error:"):
196
+ content = part[len("Error:") :].strip()
197
+ sections.append(f"## Error\n{content}")
198
+ elif lower.startswith("constraint"):
199
+ content = part.split(":", 1)[1].strip() if ":" in part else part
200
+ sections.append(f"## Constraints\n{content}")
201
+ elif lower.startswith("example"):
202
+ content = part.split(":", 1)[1].strip() if ":" in part else part
203
+ content = part.split("\n", 1)[1].strip() if "\n" in part else content
204
+ sections.append(f"## Examples\n{content}")
205
+ elif lower.startswith("output format:"):
206
+ content = part[len("Output format:") :].strip()
207
+ sections.append(f"## Output Format\n{content}")
208
+ else:
209
+ sections.append(part)
210
+
211
+ return "\n\n".join(sections)
212
+
213
+
214
+ def _get_tier(score: float) -> str:
215
+ """Map score to tier label."""
216
+ if score >= 85:
217
+ return "EXPERT"
218
+ if score >= 70:
219
+ return "STRONG"
220
+ if score >= 50:
221
+ return "GOOD"
222
+ if score >= 30:
223
+ return "BASIC"
224
+ return "DRAFT"
225
+
226
+
227
+ def _missing_suggestions(components: list[str]) -> list[str]:
228
+ """Suggest components the user could add to improve the prompt."""
229
+ suggestions: list[str] = []
230
+
231
+ if "files" not in components:
232
+ suggestions.append("Add --file to reference specific files (+6 pts)")
233
+ if "error" not in components:
234
+ suggestions.append("Add --error with the actual error message (+6 pts)")
235
+ if "constraints" not in components:
236
+ suggestions.append("Add --constraint to set boundaries (+5 pts)")
237
+ if "context" not in components:
238
+ suggestions.append("Add --context for background information (+4 pts)")
239
+ if "examples" not in components:
240
+ suggestions.append("Add --example with expected input/output (+3 pts)")
241
+ if "role" not in components:
242
+ suggestions.append("Add --role to set the AI's perspective (+3 pts)")
243
+ if "output_format" not in components:
244
+ suggestions.append("Add --output-format to specify response structure (+2 pts)")
245
+
246
+ return suggestions
@@ -0,0 +1,115 @@
1
+ """Unified prompt diagnostic — score + lint + rewrite in one pass.
2
+
3
+ Single-command quality check that runs all engines and returns a combined result.
4
+ Designed as the "one command" onboarding experience.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from dataclasses import dataclass, field
10
+
11
+
12
+ @dataclass
13
+ class CheckResult:
14
+ """Combined result from all quality engines."""
15
+
16
+ # Score
17
+ total: float = 0.0
18
+ tier: str = ""
19
+ clarity: float = 0.0
20
+ context: float = 0.0
21
+ position: float = 0.0
22
+ structure: float = 0.0
23
+ repetition: float = 0.0
24
+
25
+ # Strengths
26
+ confirmations: list[dict] = field(default_factory=list)
27
+
28
+ # Suggestions with points
29
+ suggestions: list[dict] = field(default_factory=list)
30
+
31
+ # Lint violations
32
+ lint_issues: list[dict] = field(default_factory=list)
33
+
34
+ # Rewrite
35
+ rewritten: str = ""
36
+ rewrite_delta: float = 0.0
37
+ rewrite_changes: list[str] = field(default_factory=list)
38
+
39
+ # Meta
40
+ word_count: int = 0
41
+ token_count: int = 0
42
+
43
+
44
+ def check_prompt(
45
+ text: str,
46
+ *,
47
+ model: str = "",
48
+ max_tokens: int = 0,
49
+ ) -> CheckResult:
50
+ """Run all quality checks on a prompt in one pass."""
51
+ from reprompt.core.extractors import extract_features
52
+ from reprompt.core.lint import LintConfig, lint_prompt
53
+ from reprompt.core.rewrite import rewrite_prompt
54
+ from reprompt.core.scorer import score_prompt
55
+
56
+ # 1. Score
57
+ dna = extract_features(text, source="check", session_id="")
58
+ breakdown = score_prompt(dna)
59
+
60
+ # 2. Lint
61
+ lint_config = LintConfig()
62
+ if model and model in ("claude", "gpt", "gemini"):
63
+ lint_config.model = model
64
+ if max_tokens > 0:
65
+ lint_config.max_tokens = max_tokens
66
+ violations = lint_prompt(text, lint_config)
67
+
68
+ # 3. Rewrite
69
+ rewrite_result = rewrite_prompt(text)
70
+
71
+ # Build result
72
+ tier = _get_tier(breakdown.total)
73
+
74
+ return CheckResult(
75
+ total=breakdown.total,
76
+ tier=tier,
77
+ clarity=breakdown.clarity,
78
+ context=breakdown.context,
79
+ position=breakdown.position,
80
+ structure=breakdown.structure,
81
+ repetition=breakdown.repetition,
82
+ confirmations=[
83
+ {"category": c.category, "message": c.message, "score": c.score}
84
+ for c in breakdown.confirmations
85
+ ],
86
+ suggestions=[
87
+ {
88
+ "category": s.category,
89
+ "message": s.message,
90
+ "impact": s.impact,
91
+ "points": s.points,
92
+ }
93
+ for s in breakdown.suggestions
94
+ ],
95
+ lint_issues=[
96
+ {"rule": v.rule, "severity": v.severity, "message": v.message} for v in violations
97
+ ],
98
+ rewritten=rewrite_result.rewritten,
99
+ rewrite_delta=rewrite_result.score_delta,
100
+ rewrite_changes=rewrite_result.changes,
101
+ word_count=dna.word_count,
102
+ token_count=dna.token_count,
103
+ )
104
+
105
+
106
+ def _get_tier(score: float) -> str:
107
+ if score >= 85:
108
+ return "EXPERT"
109
+ if score >= 70:
110
+ return "STRONG"
111
+ if score >= 50:
112
+ return "GOOD"
113
+ if score >= 30:
114
+ return "BASIC"
115
+ return "DRAFT"