reprompt-cli 2.0.1__tar.gz → 2.1.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 (302) hide show
  1. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/CHANGELOG.md +92 -0
  2. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/PKG-INFO +4 -3
  3. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/README.md +3 -2
  4. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/pyproject.toml +1 -1
  5. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/__init__.py +4 -4
  6. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/cli.py +50 -2
  7. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/lint.py +170 -4
  8. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/scorer.py +90 -28
  9. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/rewrite_terminal.py +50 -3
  10. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/terminal.py +34 -14
  11. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/wrapped_html.py +3 -3
  12. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_cli.py +2 -2
  13. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_coverage_boost.py +6 -6
  14. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_lint.py +176 -0
  15. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/uv.lock +1 -1
  16. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.editorconfig +0 -0
  17. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  18. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  19. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  20. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  21. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  22. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.github/dependabot.yml +0 -0
  23. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.github/workflows/ci.yml +0 -0
  24. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.github/workflows/publish.yml +0 -0
  25. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.gitignore +0 -0
  26. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.pre-commit-config.yaml +0 -0
  27. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.pre-commit-hooks.yaml +0 -0
  28. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.testmondata-shm +0 -0
  29. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.testmondata-wal +0 -0
  30. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/CODE_OF_CONDUCT.md +0 -0
  31. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/CONTRIBUTING.md +0 -0
  32. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/LICENSE +0 -0
  33. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/SECURITY.md +0 -0
  34. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/Screenshot 2026-03-24 at 09.45.03.png +0 -0
  35. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/action.yml +0 -0
  36. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/demo.gif +0 -0
  37. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/brand-icon-128.png +0 -0
  38. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/brand-icon-16.png +0 -0
  39. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/brand-icon-256.png +0 -0
  40. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/brand-icon-32.png +0 -0
  41. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/brand-icon-48.png +0 -0
  42. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/brand-icon-512.png +0 -0
  43. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/brand-icon-96.png +0 -0
  44. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/brand-icon.svg +0 -0
  45. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-favicon-128.png +0 -0
  46. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-favicon-16.png +0 -0
  47. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-favicon-256.png +0 -0
  48. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-favicon-32.png +0 -0
  49. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-favicon-48.png +0 -0
  50. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-favicon-512.png +0 -0
  51. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-favicon-96.png +0 -0
  52. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-favicon.svg +0 -0
  53. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-icon-128.png +0 -0
  54. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-icon-16.png +0 -0
  55. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-icon-256.png +0 -0
  56. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-icon-32.png +0 -0
  57. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-icon-48.png +0 -0
  58. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-icon-512.png +0 -0
  59. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-icon-96.png +0 -0
  60. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-icon.svg +0 -0
  61. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/favicon-128.png +0 -0
  62. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/favicon-16.png +0 -0
  63. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/favicon-256.png +0 -0
  64. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/favicon-32.png +0 -0
  65. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/favicon-48.png +0 -0
  66. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/favicon-512.png +0 -0
  67. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/favicon-96.png +0 -0
  68. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/favicon.svg +0 -0
  69. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/generate.sh +0 -0
  70. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/superpowers/specs/2026-03-24-v14-command-consolidation-design.md +0 -0
  71. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/superpowers/specs/2026-03-25-v1.5-dashboard-design.md +0 -0
  72. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/scripts/generate_demo_data.py +0 -0
  73. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/adapters/__init__.py +0 -0
  74. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/adapters/aider.py +0 -0
  75. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/adapters/base.py +0 -0
  76. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/adapters/chatgpt.py +0 -0
  77. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/adapters/claude_chat.py +0 -0
  78. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/adapters/claude_code.py +0 -0
  79. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/adapters/cline.py +0 -0
  80. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/adapters/codex.py +0 -0
  81. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/adapters/cursor.py +0 -0
  82. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/adapters/filters.py +0 -0
  83. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/adapters/gemini.py +0 -0
  84. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/adapters/openclaw.py +0 -0
  85. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/bridge/__init__.py +0 -0
  86. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/bridge/handler.py +0 -0
  87. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/bridge/host.py +0 -0
  88. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/bridge/manifest.py +0 -0
  89. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/bridge/protocol.py +0 -0
  90. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/commands/__init__.py +0 -0
  91. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/commands/telemetry.py +0 -0
  92. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/commands/wrapped.py +0 -0
  93. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/config.py +0 -0
  94. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/__init__.py +0 -0
  95. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/agent.py +0 -0
  96. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/analyzer.py +0 -0
  97. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/compress.py +0 -0
  98. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/conversation.py +0 -0
  99. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/cost.py +0 -0
  100. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/dashboard.py +0 -0
  101. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/dedup.py +0 -0
  102. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/digest.py +0 -0
  103. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/distill.py +0 -0
  104. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/effectiveness.py +0 -0
  105. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/extractors.py +0 -0
  106. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/extractors_zh.py +0 -0
  107. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/insights.py +0 -0
  108. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/lang_detect.py +0 -0
  109. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/library.py +0 -0
  110. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/merge_view.py +0 -0
  111. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/models.py +0 -0
  112. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/persona.py +0 -0
  113. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/pipeline.py +0 -0
  114. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/privacy.py +0 -0
  115. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/privacy_scan.py +0 -0
  116. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/prompt_dna.py +0 -0
  117. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/recommend.py +0 -0
  118. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/repetition.py +0 -0
  119. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/rewrite.py +0 -0
  120. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/segmenter.py +0 -0
  121. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/session_meta.py +0 -0
  122. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/session_quality.py +0 -0
  123. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/session_type.py +0 -0
  124. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/style.py +0 -0
  125. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/suggestions.py +0 -0
  126. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/templates.py +0 -0
  127. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/timeutil.py +0 -0
  128. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/trends.py +0 -0
  129. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/wrapped.py +0 -0
  130. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/demo.py +0 -0
  131. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/embeddings/__init__.py +0 -0
  132. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/embeddings/base.py +0 -0
  133. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/embeddings/local_embed.py +0 -0
  134. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/embeddings/ollama.py +0 -0
  135. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/embeddings/openai_embed.py +0 -0
  136. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/embeddings/tfidf.py +0 -0
  137. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/mcp.py +0 -0
  138. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/mcp_main.py +0 -0
  139. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/__init__.py +0 -0
  140. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/agent_terminal.py +0 -0
  141. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/chartjs.min.js +0 -0
  142. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/compress_terminal.py +0 -0
  143. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/dashboard_terminal.py +0 -0
  144. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/distill_terminal.py +0 -0
  145. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/export.py +0 -0
  146. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/html_report.py +0 -0
  147. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/json_out.py +0 -0
  148. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/markdown.py +0 -0
  149. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/projects_terminal.py +0 -0
  150. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/repetition_terminal.py +0 -0
  151. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/sessions_terminal.py +0 -0
  152. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/wrapped_terminal.py +0 -0
  153. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/py.typed +0 -0
  154. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/sharing/__init__.py +0 -0
  155. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/sharing/client.py +0 -0
  156. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/sharing/clipboard.py +0 -0
  157. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/storage/__init__.py +0 -0
  158. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/storage/db.py +0 -0
  159. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/telemetry/__init__.py +0 -0
  160. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/telemetry/collector.py +0 -0
  161. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/telemetry/consent.py +0 -0
  162. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/telemetry/events.py +0 -0
  163. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/telemetry/prompt.py +0 -0
  164. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/telemetry/queue.py +0 -0
  165. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/telemetry/sender.py +0 -0
  166. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/__init__.py +0 -0
  167. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/conftest.py +0 -0
  168. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/fixtures/aider_chat_history.md +0 -0
  169. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/fixtures/chatgpt_conversations.json +0 -0
  170. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/fixtures/claude_chat_export.json +0 -0
  171. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/fixtures/claude_session.jsonl +0 -0
  172. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/fixtures/cline_task/api_conversation_history.json +0 -0
  173. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/fixtures/export/default_export.md +0 -0
  174. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/fixtures/export/full_export.md +0 -0
  175. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/fixtures/gemini_session.json +0 -0
  176. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/fixtures/openclaw_session.jsonl +0 -0
  177. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_adapter_aider.py +0 -0
  178. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_adapter_chatgpt.py +0 -0
  179. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_adapter_claude.py +0 -0
  180. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_adapter_claude_chat.py +0 -0
  181. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_adapter_cline.py +0 -0
  182. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_adapter_gemini.py +0 -0
  183. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_adapter_openclaw.py +0 -0
  184. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_agent.py +0 -0
  185. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_agent_cli.py +0 -0
  186. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_analyzer.py +0 -0
  187. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_bridge_cli.py +0 -0
  188. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_bridge_e2e.py +0 -0
  189. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_bridge_handler.py +0 -0
  190. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_bridge_integration.py +0 -0
  191. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_bridge_manifest.py +0 -0
  192. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_bridge_protocol.py +0 -0
  193. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_cli_deprecations.py +0 -0
  194. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_cli_library_effectiveness.py +0 -0
  195. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_clipboard.py +0 -0
  196. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_codex_adapter.py +0 -0
  197. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_compare_best_worst.py +0 -0
  198. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_compress.py +0 -0
  199. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_compress_cli.py +0 -0
  200. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_compress_dna.py +0 -0
  201. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_compress_html.py +0 -0
  202. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_compress_insights.py +0 -0
  203. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_config.py +0 -0
  204. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_conversation.py +0 -0
  205. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_copy_flag.py +0 -0
  206. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_cost.py +0 -0
  207. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_cursor_adapter.py +0 -0
  208. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_dashboard.py +0 -0
  209. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_db.py +0 -0
  210. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_db_digest.py +0 -0
  211. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_db_effectiveness.py +0 -0
  212. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_db_session_quality.py +0 -0
  213. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_db_trends.py +0 -0
  214. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_dedup.py +0 -0
  215. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_demo.py +0 -0
  216. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_deprecated_commands.py +0 -0
  217. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_digest.py +0 -0
  218. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_digest_cli.py +0 -0
  219. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_distill.py +0 -0
  220. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_distill_cli.py +0 -0
  221. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_distill_weights.py +0 -0
  222. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_e2e.py +0 -0
  223. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_effectiveness.py +0 -0
  224. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_embeddings_local.py +0 -0
  225. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_embeddings_ollama.py +0 -0
  226. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_embeddings_openai.py +0 -0
  227. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_empty_state.py +0 -0
  228. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_export.py +0 -0
  229. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_export_cli.py +0 -0
  230. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_export_snapshot.py +0 -0
  231. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_extractors.py +0 -0
  232. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_extractors_routing.py +0 -0
  233. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_extractors_zh.py +0 -0
  234. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_extractors_zh_e2e.py +0 -0
  235. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_html_report.py +0 -0
  236. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_import_cli.py +0 -0
  237. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_import_e2e.py +0 -0
  238. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_init_cli.py +0 -0
  239. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_insights.py +0 -0
  240. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_insights_cli.py +0 -0
  241. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_insights_expanded.py +0 -0
  242. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_install_hook.py +0 -0
  243. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_lang_detect.py +0 -0
  244. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_library.py +0 -0
  245. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_lint_cli.py +0 -0
  246. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_markdown.py +0 -0
  247. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_mcp.py +0 -0
  248. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_merge_view.py +0 -0
  249. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_models.py +0 -0
  250. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_output.py +0 -0
  251. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_parse_conversation_base.py +0 -0
  252. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_parse_conversation_chatgpt.py +0 -0
  253. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_parse_conversation_claude.py +0 -0
  254. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_persona.py +0 -0
  255. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_pipeline.py +0 -0
  256. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_privacy.py +0 -0
  257. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_privacy_cli.py +0 -0
  258. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_privacy_e2e.py +0 -0
  259. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_privacy_output.py +0 -0
  260. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_privacy_scan.py +0 -0
  261. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_projects.py +0 -0
  262. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_prompt_dna.py +0 -0
  263. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_public_api.py +0 -0
  264. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_recommend.py +0 -0
  265. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_repetition.py +0 -0
  266. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_repetition_cli.py +0 -0
  267. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_repetition_output.py +0 -0
  268. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_rewrite.py +0 -0
  269. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_schema_version.py +0 -0
  270. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_score_cli.py +0 -0
  271. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_scorer.py +0 -0
  272. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_segmenter.py +0 -0
  273. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_session_quality.py +0 -0
  274. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_session_type.py +0 -0
  275. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_sessions_cli.py +0 -0
  276. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_sessions_output.py +0 -0
  277. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_share_e2e.py +0 -0
  278. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_sharing_client.py +0 -0
  279. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_source_filter.py +0 -0
  280. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_style.py +0 -0
  281. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_style_trends.py +0 -0
  282. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_suggestions.py +0 -0
  283. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_telemetry_cli.py +0 -0
  284. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_telemetry_collector.py +0 -0
  285. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_telemetry_consent.py +0 -0
  286. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_telemetry_e2e.py +0 -0
  287. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_telemetry_events.py +0 -0
  288. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_telemetry_prompt.py +0 -0
  289. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_telemetry_queue.py +0 -0
  290. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_telemetry_sender.py +0 -0
  291. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_template_cli.py +0 -0
  292. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_templates.py +0 -0
  293. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_timeutil.py +0 -0
  294. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_trends.py +0 -0
  295. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_trends_cli.py +0 -0
  296. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_use_cli.py +0 -0
  297. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_wrapped.py +0 -0
  298. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_wrapped_cli.py +0 -0
  299. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_wrapped_e2e.py +0 -0
  300. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_wrapped_html.py +0 -0
  301. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_wrapped_output.py +0 -0
  302. {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_wrapped_share.py +0 -0
@@ -2,6 +2,98 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [2.1.0] - 2026-04-01
6
+
7
+ ### Added
8
+ - **Model-specific lint rules** — `reprompt lint --model claude/gpt/gemini` checks prompts against model-specific best practices. 8 rules: XML tag preference (Claude), markdown structure (GPT), JSON instruction requirements (GPT), CoT anti-pattern for o-series (GPT), prompt length limits (Gemini), broad negative detection (Gemini). Based on official model documentation.
9
+ - **Diff preview for rewrite** — `reprompt rewrite --diff` shows a git-style unified diff between original and rewritten prompt. Color-coded: red removals, green additions, cyan range markers.
10
+ - **Token budget lint** — `reprompt lint --max-tokens 4096` warns when prompts exceed a token budget. Configurable via `.reprompt.toml` (`max-tokens`) or CLI flag. Uses locale-aware token estimation from cost module.
11
+ - Tests: 1716 → 1741
12
+
13
+ ## [2.0.2] - 2026-04-01
14
+
15
+ ### Changed
16
+ - **Scoring rebalance** — Structure weight reduced 25→15, Clarity increased 15→25. Plain-text prompts now score 55-65 instead of 35-45. Real-world conversational prompts are no longer penalized for lacking markdown structure.
17
+ - **Tier labels** — Scores display as EXPERT (85+), STRONG (70+), GOOD (50+), BASIC (30+), DRAFT (<30) instead of raw numbers. Applied across CLI, extension badge, popup, and HTML dashboard.
18
+ - **Positive UX feedback** — Score output now includes "Strengths" section showing what the prompt does well. Suggestions show expected point gain (`+N pts`). Badge color thresholds adjusted: 85/60/40/25.
19
+
20
+ ## [2.0.1] - 2026-03-31
21
+
22
+ ### Added
23
+ - **Project-level quality comparison** — `reprompt projects` aggregates session quality, efficiency, focus scores, and frustration signals per project. Supports `--source` filter, `--json`, `--copy`.
24
+ - Tests: 1670 → 1716
25
+
26
+ ## [2.0.0] - 2026-03-31
27
+
28
+ ### Changed
29
+ - **Major version bump** — the rewrite engine marks the shift from passive analysis (v1.x) to active prompt coaching (v2.0). reprompt now scores, rewrites, and optimizes your AI prompts automatically.
30
+
31
+ ## [1.10.0] - 2026-03-31
32
+
33
+ ### Added
34
+ - **Prompt rewrite engine** — `reprompt rewrite "prompt"` applies 4 rule-based transformations: filler removal (reuses compress engine), instruction front-loading (Stanford position bias), key requirement echo (Google repetition research), hedging cleanup (12 regex patterns). Shows before/after score delta and manual suggestions. No LLM needed, under 50ms.
35
+ - **`reprompt init` command** — generates `.reprompt.toml` config with all lint rules documented and commented defaults. `--force` to overwrite existing.
36
+ - Tests: 1597 → 1670
37
+
38
+ ## [1.9.1] - 2026-03-31
39
+
40
+ ### Added
41
+ - **Configurable lint rules** — `.reprompt.toml` or `[tool.reprompt.lint]` in `pyproject.toml`. Supports `score-threshold`, `min-length`, `short-prompt`, `vague-prompt`, `debug-needs-reference`, `file-extensions`. Config walks up from CWD. CLI flags override file config.
42
+ - Tests: 1567 → 1597
43
+
44
+ ## [1.9.0] - 2026-03-31
45
+
46
+ ### Added
47
+ - **Bidirectional bridge** — Native Messaging `sync_result` now returns insights (avg score, score trend, top coaching tip) back to the browser extension. New `get_insights` message type for full analysis including repetition data and pattern info.
48
+ - `get_recent_scores(limit)` DB method for trend computation.
49
+ - Tests: 1545 → 1567
50
+
51
+ ## [1.8.1] - 2026-03-31
52
+
53
+ ### Added
54
+ - **Cross-session repetition detection** — `reprompt repetition` detects recurring prompts across different AI sessions using TF-IDF + containment clustering (threshold 0.75). Shows repetition rate, recurring topics ranked by session count, and date ranges. Integrated into `reprompt insights` output.
55
+ - Tests: 1529 → 1545
56
+
57
+ ## [1.8.0] - 2026-03-31
58
+
59
+ ### Added
60
+ - **Session quality metrics** — `reprompt sessions` provides composite 0-100 session scoring combining prompt quality, efficiency, focus, and outcome. Frustration signal detection: abandonment, escalation, stall turns. Rich table and detail views.
61
+
62
+ ### Fixed
63
+ - **Pipeline type mismatch** — `parse_conversation()` returns `list[ConversationTurn]`, not `Conversation`. Pipeline now wraps turns correctly. Without this fix, session quality scoring silently failed.
64
+ - **Bridge shell injection** — quoted `sys.executable` in bridge wrapper script to prevent command injection when Python path contains spaces.
65
+ - **Unclamped scores** — efficiency and focus component scores now clamped to 0-100 range.
66
+ - Tests: 1497 → 1529
67
+
68
+ ## [1.7.1] - 2026-03-29
69
+
70
+ ### Added
71
+ - **Expanded privacy scanner** — 10 new detection patterns: SSH private keys (RSA/EC/DSA/OPENSSH/PKCS#8), PEM certificates, service tokens (Slack bot/user/app, Google API, npm), database connection strings (PostgreSQL, MySQL, MongoDB, Redis). 28 new tests. Closes #12.
72
+
73
+ ## [1.7.0] - 2026-03-28
74
+
75
+ ### Added
76
+ - **GitHub Action PR comments** — `comment-on-pr: true` posts quality report as PR comment with markdown table, collapsible violations, and score summary. Updates existing comment on re-push (no duplicates).
77
+ - **Token cost estimation** — `reprompt score` shows ~tokens and $cost. `reprompt insights` shows total prompt cost. `reprompt report` overview includes estimated cost. MCP `score_prompt` includes token count and cost.
78
+ - Locale-aware token counting: 1.3x words (EN), 1.5x chars (CJK).
79
+ - Price table: Claude Sonnet/Opus/Haiku, GPT-4o/mini, Gemini, DeepSeek. Auto-detect model from adapter source.
80
+ - Tests: 1497 → 1529
81
+
82
+ ## [1.6.2] - 2026-03-28
83
+
84
+ ### Fixed
85
+ - **Security: shell injection in GitHub Action** — inputs now passed via env vars, not string interpolation.
86
+ - **Bridge: 1MB message limit** — enforce Chrome Native Messaging size limit with proper JSON decode error handling.
87
+
88
+ ### Improved
89
+ - SQLite WAL mode + 10s timeout for concurrent access safety.
90
+ - MCP: all 6 tools wrapped in try/except with structured error responses; `check_privacy` uses SQL LIMIT.
91
+ - Dedup: skip O(n²) semantic layer when batch > 5000 prompts.
92
+ - ChatGPT adapter: warn on files > 200MB.
93
+ - First-run dashboard shows "Found N sessions (~M turns) across K tools".
94
+ - `purge --all` now requires confirmation.
95
+ - MCP server consolidated from 10 to 6 focused tools.
96
+
5
97
  ## [1.6.1] - 2026-03-28
6
98
 
7
99
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: reprompt-cli
3
- Version: 2.0.1
3
+ Version: 2.1.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
@@ -111,6 +111,7 @@ $ reprompt
111
111
  | `reprompt agent` | Agent workflow analysis -- error loops, tool patterns, session efficiency |
112
112
  | `reprompt sessions` | Session quality scores with frustration signal detection |
113
113
  | `reprompt repetition` | Cross-session repetition detection -- spot recurring prompts |
114
+ | `reprompt projects` | Per-project quality breakdown -- sessions, scores, frustration signals |
114
115
 
115
116
  ### Optimize
116
117
 
@@ -200,7 +201,7 @@ reprompt install-hook # adds post-session hook to Claude Code
200
201
 
201
202
  ### Browser extension
202
203
 
203
- Capture prompts from ChatGPT, Claude.ai, and Gemini directly in your browser:
204
+ Capture prompts from ChatGPT, Claude.ai, and Gemini directly in your browser. Live score badge shows prompt quality as you type.
204
205
 
205
206
  1. **Install the extension** from [Chrome Web Store](https://chromewebstore.google.com/detail/reprompt/ojdccpagaanchmkninlbgbgemdcjckhn) or [Firefox Add-ons](https://addons.mozilla.org/addon/reprompt-cli/)
206
207
  2. **Connect to the CLI:** `reprompt install-extension`
@@ -227,7 +228,7 @@ Captured prompts sync locally via Native Messaging -- nothing leaves your machin
227
228
  # .pre-commit-config.yaml
228
229
  repos:
229
230
  - repo: https://github.com/reprompt-dev/reprompt
230
- rev: v1.7.0
231
+ rev: v2.1.0
231
232
  hooks:
232
233
  - id: reprompt-lint
233
234
  ```
@@ -66,6 +66,7 @@ $ reprompt
66
66
  | `reprompt agent` | Agent workflow analysis -- error loops, tool patterns, session efficiency |
67
67
  | `reprompt sessions` | Session quality scores with frustration signal detection |
68
68
  | `reprompt repetition` | Cross-session repetition detection -- spot recurring prompts |
69
+ | `reprompt projects` | Per-project quality breakdown -- sessions, scores, frustration signals |
69
70
 
70
71
  ### Optimize
71
72
 
@@ -155,7 +156,7 @@ reprompt install-hook # adds post-session hook to Claude Code
155
156
 
156
157
  ### Browser extension
157
158
 
158
- Capture prompts from ChatGPT, Claude.ai, and Gemini directly in your browser:
159
+ Capture prompts from ChatGPT, Claude.ai, and Gemini directly in your browser. Live score badge shows prompt quality as you type.
159
160
 
160
161
  1. **Install the extension** from [Chrome Web Store](https://chromewebstore.google.com/detail/reprompt/ojdccpagaanchmkninlbgbgemdcjckhn) or [Firefox Add-ons](https://addons.mozilla.org/addon/reprompt-cli/)
161
162
  2. **Connect to the CLI:** `reprompt install-extension`
@@ -182,7 +183,7 @@ Captured prompts sync locally via Native Messaging -- nothing leaves your machin
182
183
  # .pre-commit-config.yaml
183
184
  repos:
184
185
  - repo: https://github.com/reprompt-dev/reprompt
185
- rev: v1.7.0
186
+ rev: v2.1.0
186
187
  hooks:
187
188
  - id: reprompt-lint
188
189
  ```
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "reprompt-cli"
3
- version = "2.0.1"
3
+ version = "2.1.0"
4
4
  description = "Discover, analyze, and optimize your prompts from AI coding sessions"
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -1,6 +1,6 @@
1
1
  """reprompt — Discover, analyze, and evolve your best prompts from AI coding sessions."""
2
2
 
3
- __version__ = "2.0.1"
3
+ __version__ = "2.0.2"
4
4
 
5
5
  __all__ = [
6
6
  "__version__",
@@ -19,11 +19,11 @@ def _grade(total: float) -> str:
19
19
  """Map 0-100 score to letter grade."""
20
20
  if total >= 85:
21
21
  return "A"
22
- if total >= 70:
22
+ if total >= 60:
23
23
  return "B"
24
- if total >= 55:
25
- return "C"
26
24
  if total >= 40:
25
+ return "C"
26
+ if total >= 25:
27
27
  return "D"
28
28
  return "F"
29
29
 
@@ -797,6 +797,12 @@ def lint(
797
797
  score_threshold: int = typer.Option(
798
798
  0, "--score-threshold", help="Fail if avg prompt score < threshold (CI mode)"
799
799
  ),
800
+ model: str = typer.Option(
801
+ None, "--model", "-m", help="Target model for model-specific rules (claude/gpt/gemini)"
802
+ ),
803
+ max_tokens: int = typer.Option(
804
+ 0, "--max-tokens", help="Warn when prompts exceed token budget (0 = disabled)"
805
+ ),
800
806
  copy: bool = typer.Option(False, "--copy", help="Copy result to clipboard"),
801
807
  ) -> None:
802
808
  """Check prompt quality against lint rules.
@@ -806,6 +812,12 @@ def lint(
806
812
  - short-prompt: prompts under 40 chars (warning)
807
813
  - vague-prompt: overly vague prompts like "fix it"
808
814
  - debug-needs-reference: debug prompts without file/function references
815
+ - max-tokens: prompt exceeds token budget
816
+
817
+ Model-specific rules (--model):
818
+ - claude: suggests XML tags for structure
819
+ - gpt: warns on XML tags (may echo verbatim), prefers markdown
820
+ - gemini: warns on very long prompts
809
821
 
810
822
  CI mode: use --score-threshold to fail if average score is below a threshold.
811
823
 
@@ -813,6 +825,8 @@ def lint(
813
825
 
814
826
  reprompt lint # lint stored prompts
815
827
 
828
+ reprompt lint --model claude # with Claude-specific hints
829
+
816
830
  reprompt lint --score-threshold 50 # fail if avg score < 50 (CI mode)
817
831
 
818
832
  reprompt lint --strict --json # strict mode with JSON output
@@ -832,6 +846,10 @@ def lint(
832
846
 
833
847
  # CLI flags override config file
834
848
  effective_threshold = score_threshold if score_threshold > 0 else lint_config.score_threshold
849
+ if model:
850
+ lint_config.model = model.lower()
851
+ if max_tokens > 0:
852
+ lint_config.max_tokens = max_tokens
835
853
 
836
854
  # Collect prompts from DB (already scanned)
837
855
  rows = db.get_all_prompts()
@@ -982,9 +1000,18 @@ def score(
982
1000
  "paper": s.paper,
983
1001
  "message": s.message,
984
1002
  "impact": s.impact,
1003
+ "points": s.points,
985
1004
  }
986
1005
  for s in breakdown.suggestions
987
1006
  ],
1007
+ "confirmations": [
1008
+ {
1009
+ "category": c.category,
1010
+ "message": c.message,
1011
+ "score": c.score,
1012
+ }
1013
+ for c in breakdown.confirmations
1014
+ ],
988
1015
  }
989
1016
  typer.echo(json_mod.dumps(data, indent=2))
990
1017
  else:
@@ -1004,9 +1031,18 @@ def score(
1004
1031
  "paper": s.paper,
1005
1032
  "message": s.message,
1006
1033
  "impact": s.impact,
1034
+ "points": s.points,
1007
1035
  }
1008
1036
  for s in breakdown.suggestions
1009
1037
  ],
1038
+ "confirmations": [
1039
+ {
1040
+ "category": c.category,
1041
+ "message": c.message,
1042
+ "score": c.score,
1043
+ }
1044
+ for c in breakdown.confirmations
1045
+ ],
1010
1046
  }
1011
1047
  typer.echo(render_score(data))
1012
1048
  from reprompt.core.suggestions import get_suggestion
@@ -1069,6 +1105,7 @@ def compress(
1069
1105
  def rewrite(
1070
1106
  text: str = typer.Argument(..., help="Prompt text to improve"),
1071
1107
  json_output: bool = typer.Option(False, "--json", help="Output as JSON"),
1108
+ diff: bool = typer.Option(False, "--diff", help="Show unified diff (red/green)"),
1072
1109
  copy: bool = typer.Option(False, "--copy", help="Copy rewritten text to clipboard"),
1073
1110
  ) -> None:
1074
1111
  """Rewrite a prompt to improve its score. Rule-based, no LLM needed.
@@ -1081,9 +1118,9 @@ def rewrite(
1081
1118
 
1082
1119
  reprompt rewrite "I was wondering if you could fix the authentication bug"
1083
1120
 
1084
- reprompt rewrite "please help me refactor this code to be better" --copy
1121
+ reprompt rewrite "fix the login" --diff
1085
1122
 
1086
- reprompt rewrite "fix the login" --json
1123
+ reprompt rewrite "please help me refactor this code to be better" --copy
1087
1124
  """
1088
1125
  from reprompt.core.rewrite import rewrite_prompt
1089
1126
 
@@ -1102,6 +1139,10 @@ def rewrite(
1102
1139
  "manual_suggestions": result.manual_suggestions,
1103
1140
  }
1104
1141
  typer.echo(json_mod.dumps(data, indent=2, ensure_ascii=False))
1142
+ elif diff:
1143
+ from reprompt.output.rewrite_terminal import render_rewrite_diff
1144
+
1145
+ typer.echo(render_rewrite_diff(result))
1105
1146
  else:
1106
1147
  from reprompt.output.rewrite_terminal import render_rewrite
1107
1148
 
@@ -2024,6 +2065,13 @@ def init(
2024
2065
  # Useful for CI: reprompt lint --score-threshold reads this value
2025
2066
  # score-threshold = 50
2026
2067
 
2068
+ # Target model for model-specific rules (claude, gpt, gemini)
2069
+ # Enables rules like "prefer XML tags" (Claude) or "avoid XML tags" (GPT)
2070
+ # model = "claude"
2071
+
2072
+ # Token budget — warn when prompts exceed this limit (0 = disabled)
2073
+ # max-tokens = 4096
2074
+
2027
2075
  [lint.rules]
2028
2076
  # min-length: error if prompt < N chars (0 = disabled)
2029
2077
  min-length = 20
@@ -4,7 +4,7 @@ Checks prompts against configurable quality rules and returns violations.
4
4
  Designed for CI integration — each rule produces a severity + message.
5
5
 
6
6
  Configuration loaded from (highest priority wins):
7
- 1. CLI flags (--score-threshold, --strict)
7
+ 1. CLI flags (--score-threshold, --strict, --model)
8
8
  2. .reprompt.toml in CWD or parents
9
9
  3. [tool.reprompt.lint] in pyproject.toml
10
10
  4. Built-in defaults
@@ -12,6 +12,7 @@ Configuration loaded from (highest priority wins):
12
12
 
13
13
  from __future__ import annotations
14
14
 
15
+ import re
15
16
  import sys
16
17
  from dataclasses import dataclass, field
17
18
  from pathlib import Path
@@ -24,13 +25,16 @@ else:
24
25
  except ModuleNotFoundError: # Python 3.10
25
26
  import tomli as tomllib # type: ignore[no-redefine]
26
27
 
28
+ # Valid model targets
29
+ VALID_MODELS = {"claude", "gpt", "gemini"}
30
+
27
31
 
28
32
  @dataclass
29
33
  class LintViolation:
30
34
  """A single lint rule violation."""
31
35
 
32
36
  rule: str
33
- severity: str # "error" | "warning"
37
+ severity: str # "error" | "warning" | "hint"
34
38
  message: str
35
39
  prompt_text: str
36
40
 
@@ -55,6 +59,12 @@ class LintConfig:
55
59
  # CI score threshold (0 = disabled, set via --score-threshold or config)
56
60
  score_threshold: int = 0
57
61
 
62
+ # Token budget (0 = disabled). Warn when prompt exceeds this many tokens.
63
+ max_tokens: int = 0
64
+
65
+ # Target model for model-specific rules (None = universal rules only)
66
+ model: str | None = None
67
+
58
68
 
59
69
  # --- Default config ---
60
70
  DEFAULT_CONFIG = LintConfig()
@@ -126,6 +136,14 @@ def _build_config(lint_data: dict) -> LintConfig:
126
136
  if "score-threshold" in lint_data:
127
137
  config.score_threshold = int(lint_data["score-threshold"])
128
138
 
139
+ if "max-tokens" in lint_data:
140
+ config.max_tokens = int(lint_data["max-tokens"])
141
+
142
+ if "model" in lint_data:
143
+ model = str(lint_data["model"]).lower()
144
+ if model in VALID_MODELS:
145
+ config.model = model
146
+
129
147
  # Rule settings
130
148
  rules = lint_data.get("rules", {})
131
149
 
@@ -210,6 +228,150 @@ def lint_prompt(text: str, config: LintConfig | None = None) -> list[LintViolati
210
228
  )
211
229
  )
212
230
 
231
+ # Rule 4: Token budget
232
+ if config.max_tokens > 0:
233
+ from reprompt.core.cost import estimate_tokens
234
+
235
+ tokens = estimate_tokens(text)
236
+ if tokens > config.max_tokens:
237
+ violations.append(
238
+ LintViolation(
239
+ rule="max-tokens",
240
+ severity="warning",
241
+ message=(
242
+ f"Prompt is ~{tokens} tokens (budget: {config.max_tokens}) — "
243
+ "consider compressing with `reprompt compress`"
244
+ ),
245
+ prompt_text=text,
246
+ )
247
+ )
248
+
249
+ # ── Model-specific rules ──
250
+ if config.model and len(stripped) >= 30:
251
+ violations.extend(_check_model_rules(text, config.model))
252
+
253
+ return violations
254
+
255
+
256
+ # ── Model-specific patterns ──
257
+
258
+ _XML_TAG_RE = re.compile(r"<(?:context|instructions|examples?|constraints?|output|task|role)\b")
259
+ _MD_HEADER_RE = re.compile(r"^#{1,3}\s+\w", re.MULTILINE)
260
+ _JSON_MODE_RE = re.compile(r"(?:respond|output|return|reply|format).*\bjson\b", re.IGNORECASE)
261
+ _COT_RE = re.compile(
262
+ r"\b(?:think step by step|let'?s think|chain of thought|step-by-step reasoning)\b",
263
+ re.IGNORECASE,
264
+ )
265
+ _BROAD_NEGATIVE_RE = re.compile(
266
+ r"\bdo not (?:infer|guess|assume|speculate|make assumptions)\b", re.IGNORECASE
267
+ )
268
+
269
+
270
+ def _check_model_rules(text: str, model: str) -> list[LintViolation]:
271
+ """Return model-specific lint violations and hints."""
272
+ violations: list[LintViolation] = []
273
+ has_xml = bool(_XML_TAG_RE.search(text))
274
+ has_md_headers = bool(_MD_HEADER_RE.search(text))
275
+ word_count = len(text.split())
276
+
277
+ if model == "claude":
278
+ # Claude: XML tags are preferred for structured prompts
279
+ if not has_xml and word_count > 50 and not has_md_headers:
280
+ violations.append(
281
+ LintViolation(
282
+ rule="claude-prefer-xml",
283
+ severity="hint",
284
+ message=(
285
+ "Claude handles XML tags well for structured prompts — "
286
+ "try <context>, <instructions>, <constraints>"
287
+ ),
288
+ prompt_text=text,
289
+ )
290
+ )
291
+
292
+ elif model == "gpt":
293
+ # GPT: XML tags may be echoed verbatim; prefer markdown
294
+ if has_xml:
295
+ violations.append(
296
+ LintViolation(
297
+ rule="gpt-avoid-xml",
298
+ severity="warning",
299
+ message=(
300
+ "GPT may echo XML tags verbatim — "
301
+ "use markdown headers (## Context, ## Instructions) instead"
302
+ ),
303
+ prompt_text=text,
304
+ )
305
+ )
306
+ # GPT: markdown headers are preferred
307
+ if not has_md_headers and word_count > 50:
308
+ violations.append(
309
+ LintViolation(
310
+ rule="gpt-prefer-markdown",
311
+ severity="hint",
312
+ message=(
313
+ "Long prompts for GPT benefit from markdown headers — "
314
+ "use ## sections for clarity"
315
+ ),
316
+ prompt_text=text,
317
+ )
318
+ )
319
+ # GPT: JSON mode needs explicit instruction
320
+ if _JSON_MODE_RE.search(text) is None and "json" in text.lower():
321
+ violations.append(
322
+ LintViolation(
323
+ rule="gpt-json-instruction",
324
+ severity="warning",
325
+ message=(
326
+ "GPT requires explicit JSON instruction — "
327
+ 'add "Respond in JSON format" for reliable JSON output'
328
+ ),
329
+ prompt_text=text,
330
+ )
331
+ )
332
+
333
+ elif model == "gemini":
334
+ # Gemini: very long prompts may lose focus
335
+ if word_count > 500:
336
+ violations.append(
337
+ LintViolation(
338
+ rule="gemini-prompt-length",
339
+ severity="warning",
340
+ message=(
341
+ f"Prompt is {word_count} words — "
342
+ "Gemini may lose focus on long instructions, consider splitting"
343
+ ),
344
+ prompt_text=text,
345
+ )
346
+ )
347
+ # Gemini: broad negatives break reasoning (official Gemini 3 guide)
348
+ if _BROAD_NEGATIVE_RE.search(text):
349
+ violations.append(
350
+ LintViolation(
351
+ rule="gemini-broad-negative",
352
+ severity="warning",
353
+ message=(
354
+ 'Broad negatives ("do not infer/guess/assume") break '
355
+ "Gemini's reasoning — use positive instructions instead"
356
+ ),
357
+ prompt_text=text,
358
+ )
359
+ )
360
+
361
+ # Cross-model: CoT anti-pattern for reasoning models
362
+ if model == "gpt" and _COT_RE.search(text):
363
+ violations.append(
364
+ LintViolation(
365
+ rule="gpt-no-cot-reasoning",
366
+ severity="hint",
367
+ message=(
368
+ '"Think step by step" hurts o-series reasoning models — '
369
+ "give high-level goals instead of prescriptive steps"
370
+ ),
371
+ prompt_text=text,
372
+ )
373
+ )
374
+
213
375
  return violations
214
376
 
215
377
 
@@ -228,15 +390,19 @@ def format_lint_results(violations: list[LintViolation], total_prompts: int) ->
228
390
 
229
391
  errors = [v for v in violations if v.severity == "error"]
230
392
  warnings = [v for v in violations if v.severity == "warning"]
393
+ hints = [v for v in violations if v.severity == "hint"]
231
394
 
232
395
  lines: list[str] = []
233
396
  lines.append(f"Checked {total_prompts} prompts\n")
234
397
 
235
398
  for v in violations:
236
- prefix = "✗" if v.severity == "error" else "!"
399
+ prefix = "✗" if v.severity == "error" else "!" if v.severity == "warning" else "→"
237
400
  display = v.prompt_text[:60] + "..." if len(v.prompt_text) > 60 else v.prompt_text
238
401
  lines.append(f' {prefix} [{v.rule}] "{display}"')
239
402
  lines.append(f" {v.message}")
240
403
 
241
- lines.append(f"\n{len(errors)} error(s), {len(warnings)} warning(s)")
404
+ parts = [f"{len(errors)} error(s)", f"{len(warnings)} warning(s)"]
405
+ if hints:
406
+ parts.append(f"{len(hints)} hint(s)")
407
+ lines.append(f"\n{', '.join(parts)}")
242
408
  return "\n".join(lines)