reprompt-cli 2.0.0__tar.gz → 2.0.2__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.0 → reprompt_cli-2.0.2}/CHANGELOG.md +77 -0
  2. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/PKG-INFO +4 -3
  3. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/README.md +3 -2
  4. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/pyproject.toml +1 -1
  5. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/__init__.py +4 -4
  6. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/cli.py +69 -0
  7. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/scorer.py +79 -28
  8. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/suggestions.py +1 -0
  9. reprompt_cli-2.0.2/src/reprompt/output/projects_terminal.py +101 -0
  10. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/output/rewrite_terminal.py +3 -3
  11. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/output/terminal.py +36 -14
  12. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/output/wrapped_html.py +3 -3
  13. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/storage/db.py +44 -0
  14. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_cli.py +2 -2
  15. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_coverage_boost.py +6 -6
  16. reprompt_cli-2.0.2/tests/test_projects.py +200 -0
  17. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_suggestions.py +1 -0
  18. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/uv.lock +1 -1
  19. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/.editorconfig +0 -0
  20. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  21. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  22. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  23. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  24. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  25. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/.github/dependabot.yml +0 -0
  26. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/.github/workflows/ci.yml +0 -0
  27. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/.github/workflows/publish.yml +0 -0
  28. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/.gitignore +0 -0
  29. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/.pre-commit-config.yaml +0 -0
  30. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/.pre-commit-hooks.yaml +0 -0
  31. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/.testmondata-shm +0 -0
  32. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/.testmondata-wal +0 -0
  33. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/CODE_OF_CONDUCT.md +0 -0
  34. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/CONTRIBUTING.md +0 -0
  35. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/LICENSE +0 -0
  36. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/SECURITY.md +0 -0
  37. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/Screenshot 2026-03-24 at 09.45.03.png +0 -0
  38. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/action.yml +0 -0
  39. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/demo.gif +0 -0
  40. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/brand-icon-128.png +0 -0
  41. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/brand-icon-16.png +0 -0
  42. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/brand-icon-256.png +0 -0
  43. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/brand-icon-32.png +0 -0
  44. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/brand-icon-48.png +0 -0
  45. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/brand-icon-512.png +0 -0
  46. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/brand-icon-96.png +0 -0
  47. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/brand-icon.svg +0 -0
  48. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/cli-favicon-128.png +0 -0
  49. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/cli-favicon-16.png +0 -0
  50. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/cli-favicon-256.png +0 -0
  51. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/cli-favicon-32.png +0 -0
  52. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/cli-favicon-48.png +0 -0
  53. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/cli-favicon-512.png +0 -0
  54. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/cli-favicon-96.png +0 -0
  55. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/cli-favicon.svg +0 -0
  56. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/cli-icon-128.png +0 -0
  57. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/cli-icon-16.png +0 -0
  58. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/cli-icon-256.png +0 -0
  59. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/cli-icon-32.png +0 -0
  60. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/cli-icon-48.png +0 -0
  61. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/cli-icon-512.png +0 -0
  62. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/cli-icon-96.png +0 -0
  63. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/cli-icon.svg +0 -0
  64. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/favicon-128.png +0 -0
  65. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/favicon-16.png +0 -0
  66. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/favicon-256.png +0 -0
  67. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/favicon-32.png +0 -0
  68. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/favicon-48.png +0 -0
  69. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/favicon-512.png +0 -0
  70. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/favicon-96.png +0 -0
  71. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/favicon.svg +0 -0
  72. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/icons/generate.sh +0 -0
  73. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/superpowers/specs/2026-03-24-v14-command-consolidation-design.md +0 -0
  74. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/docs/superpowers/specs/2026-03-25-v1.5-dashboard-design.md +0 -0
  75. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/scripts/generate_demo_data.py +0 -0
  76. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/adapters/__init__.py +0 -0
  77. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/adapters/aider.py +0 -0
  78. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/adapters/base.py +0 -0
  79. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/adapters/chatgpt.py +0 -0
  80. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/adapters/claude_chat.py +0 -0
  81. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/adapters/claude_code.py +0 -0
  82. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/adapters/cline.py +0 -0
  83. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/adapters/codex.py +0 -0
  84. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/adapters/cursor.py +0 -0
  85. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/adapters/filters.py +0 -0
  86. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/adapters/gemini.py +0 -0
  87. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/adapters/openclaw.py +0 -0
  88. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/bridge/__init__.py +0 -0
  89. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/bridge/handler.py +0 -0
  90. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/bridge/host.py +0 -0
  91. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/bridge/manifest.py +0 -0
  92. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/bridge/protocol.py +0 -0
  93. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/commands/__init__.py +0 -0
  94. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/commands/telemetry.py +0 -0
  95. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/commands/wrapped.py +0 -0
  96. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/config.py +0 -0
  97. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/__init__.py +0 -0
  98. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/agent.py +0 -0
  99. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/analyzer.py +0 -0
  100. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/compress.py +0 -0
  101. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/conversation.py +0 -0
  102. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/cost.py +0 -0
  103. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/dashboard.py +0 -0
  104. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/dedup.py +0 -0
  105. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/digest.py +0 -0
  106. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/distill.py +0 -0
  107. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/effectiveness.py +0 -0
  108. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/extractors.py +0 -0
  109. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/extractors_zh.py +0 -0
  110. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/insights.py +0 -0
  111. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/lang_detect.py +0 -0
  112. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/library.py +0 -0
  113. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/lint.py +0 -0
  114. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/merge_view.py +0 -0
  115. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/models.py +0 -0
  116. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/persona.py +0 -0
  117. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/pipeline.py +0 -0
  118. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/privacy.py +0 -0
  119. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/privacy_scan.py +0 -0
  120. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/prompt_dna.py +0 -0
  121. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/recommend.py +0 -0
  122. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/repetition.py +0 -0
  123. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/rewrite.py +0 -0
  124. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/segmenter.py +0 -0
  125. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/session_meta.py +0 -0
  126. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/session_quality.py +0 -0
  127. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/session_type.py +0 -0
  128. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/style.py +0 -0
  129. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/templates.py +0 -0
  130. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/timeutil.py +0 -0
  131. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/trends.py +0 -0
  132. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/core/wrapped.py +0 -0
  133. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/demo.py +0 -0
  134. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/embeddings/__init__.py +0 -0
  135. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/embeddings/base.py +0 -0
  136. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/embeddings/local_embed.py +0 -0
  137. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/embeddings/ollama.py +0 -0
  138. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/embeddings/openai_embed.py +0 -0
  139. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/embeddings/tfidf.py +0 -0
  140. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/mcp.py +0 -0
  141. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/mcp_main.py +0 -0
  142. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/output/__init__.py +0 -0
  143. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/output/agent_terminal.py +0 -0
  144. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/output/chartjs.min.js +0 -0
  145. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/output/compress_terminal.py +0 -0
  146. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/output/dashboard_terminal.py +0 -0
  147. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/output/distill_terminal.py +0 -0
  148. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/output/export.py +0 -0
  149. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/output/html_report.py +0 -0
  150. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/output/json_out.py +0 -0
  151. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/output/markdown.py +0 -0
  152. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/output/repetition_terminal.py +0 -0
  153. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/output/sessions_terminal.py +0 -0
  154. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/output/wrapped_terminal.py +0 -0
  155. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/py.typed +0 -0
  156. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/sharing/__init__.py +0 -0
  157. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/sharing/client.py +0 -0
  158. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/sharing/clipboard.py +0 -0
  159. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/storage/__init__.py +0 -0
  160. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/telemetry/__init__.py +0 -0
  161. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/telemetry/collector.py +0 -0
  162. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/telemetry/consent.py +0 -0
  163. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/telemetry/events.py +0 -0
  164. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/telemetry/prompt.py +0 -0
  165. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/telemetry/queue.py +0 -0
  166. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/src/reprompt/telemetry/sender.py +0 -0
  167. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/__init__.py +0 -0
  168. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/conftest.py +0 -0
  169. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/fixtures/aider_chat_history.md +0 -0
  170. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/fixtures/chatgpt_conversations.json +0 -0
  171. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/fixtures/claude_chat_export.json +0 -0
  172. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/fixtures/claude_session.jsonl +0 -0
  173. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/fixtures/cline_task/api_conversation_history.json +0 -0
  174. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/fixtures/export/default_export.md +0 -0
  175. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/fixtures/export/full_export.md +0 -0
  176. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/fixtures/gemini_session.json +0 -0
  177. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/fixtures/openclaw_session.jsonl +0 -0
  178. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_adapter_aider.py +0 -0
  179. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_adapter_chatgpt.py +0 -0
  180. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_adapter_claude.py +0 -0
  181. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_adapter_claude_chat.py +0 -0
  182. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_adapter_cline.py +0 -0
  183. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_adapter_gemini.py +0 -0
  184. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_adapter_openclaw.py +0 -0
  185. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_agent.py +0 -0
  186. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_agent_cli.py +0 -0
  187. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_analyzer.py +0 -0
  188. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_bridge_cli.py +0 -0
  189. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_bridge_e2e.py +0 -0
  190. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_bridge_handler.py +0 -0
  191. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_bridge_integration.py +0 -0
  192. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_bridge_manifest.py +0 -0
  193. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_bridge_protocol.py +0 -0
  194. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_cli_deprecations.py +0 -0
  195. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_cli_library_effectiveness.py +0 -0
  196. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_clipboard.py +0 -0
  197. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_codex_adapter.py +0 -0
  198. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_compare_best_worst.py +0 -0
  199. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_compress.py +0 -0
  200. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_compress_cli.py +0 -0
  201. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_compress_dna.py +0 -0
  202. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_compress_html.py +0 -0
  203. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_compress_insights.py +0 -0
  204. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_config.py +0 -0
  205. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_conversation.py +0 -0
  206. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_copy_flag.py +0 -0
  207. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_cost.py +0 -0
  208. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_cursor_adapter.py +0 -0
  209. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_dashboard.py +0 -0
  210. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_db.py +0 -0
  211. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_db_digest.py +0 -0
  212. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_db_effectiveness.py +0 -0
  213. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_db_session_quality.py +0 -0
  214. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_db_trends.py +0 -0
  215. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_dedup.py +0 -0
  216. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_demo.py +0 -0
  217. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_deprecated_commands.py +0 -0
  218. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_digest.py +0 -0
  219. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_digest_cli.py +0 -0
  220. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_distill.py +0 -0
  221. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_distill_cli.py +0 -0
  222. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_distill_weights.py +0 -0
  223. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_e2e.py +0 -0
  224. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_effectiveness.py +0 -0
  225. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_embeddings_local.py +0 -0
  226. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_embeddings_ollama.py +0 -0
  227. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_embeddings_openai.py +0 -0
  228. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_empty_state.py +0 -0
  229. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_export.py +0 -0
  230. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_export_cli.py +0 -0
  231. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_export_snapshot.py +0 -0
  232. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_extractors.py +0 -0
  233. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_extractors_routing.py +0 -0
  234. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_extractors_zh.py +0 -0
  235. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_extractors_zh_e2e.py +0 -0
  236. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_html_report.py +0 -0
  237. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_import_cli.py +0 -0
  238. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_import_e2e.py +0 -0
  239. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_init_cli.py +0 -0
  240. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_insights.py +0 -0
  241. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_insights_cli.py +0 -0
  242. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_insights_expanded.py +0 -0
  243. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_install_hook.py +0 -0
  244. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_lang_detect.py +0 -0
  245. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_library.py +0 -0
  246. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_lint.py +0 -0
  247. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_lint_cli.py +0 -0
  248. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_markdown.py +0 -0
  249. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_mcp.py +0 -0
  250. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_merge_view.py +0 -0
  251. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_models.py +0 -0
  252. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_output.py +0 -0
  253. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_parse_conversation_base.py +0 -0
  254. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_parse_conversation_chatgpt.py +0 -0
  255. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_parse_conversation_claude.py +0 -0
  256. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_persona.py +0 -0
  257. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_pipeline.py +0 -0
  258. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_privacy.py +0 -0
  259. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_privacy_cli.py +0 -0
  260. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_privacy_e2e.py +0 -0
  261. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_privacy_output.py +0 -0
  262. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_privacy_scan.py +0 -0
  263. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_prompt_dna.py +0 -0
  264. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_public_api.py +0 -0
  265. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_recommend.py +0 -0
  266. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_repetition.py +0 -0
  267. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_repetition_cli.py +0 -0
  268. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_repetition_output.py +0 -0
  269. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_rewrite.py +0 -0
  270. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_schema_version.py +0 -0
  271. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_score_cli.py +0 -0
  272. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_scorer.py +0 -0
  273. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_segmenter.py +0 -0
  274. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_session_quality.py +0 -0
  275. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_session_type.py +0 -0
  276. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_sessions_cli.py +0 -0
  277. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_sessions_output.py +0 -0
  278. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_share_e2e.py +0 -0
  279. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_sharing_client.py +0 -0
  280. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_source_filter.py +0 -0
  281. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_style.py +0 -0
  282. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_style_trends.py +0 -0
  283. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_telemetry_cli.py +0 -0
  284. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_telemetry_collector.py +0 -0
  285. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_telemetry_consent.py +0 -0
  286. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_telemetry_e2e.py +0 -0
  287. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_telemetry_events.py +0 -0
  288. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_telemetry_prompt.py +0 -0
  289. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_telemetry_queue.py +0 -0
  290. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_telemetry_sender.py +0 -0
  291. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_template_cli.py +0 -0
  292. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_templates.py +0 -0
  293. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_timeutil.py +0 -0
  294. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_trends.py +0 -0
  295. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_trends_cli.py +0 -0
  296. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_use_cli.py +0 -0
  297. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_wrapped.py +0 -0
  298. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_wrapped_cli.py +0 -0
  299. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_wrapped_e2e.py +0 -0
  300. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_wrapped_html.py +0 -0
  301. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_wrapped_output.py +0 -0
  302. {reprompt_cli-2.0.0 → reprompt_cli-2.0.2}/tests/test_wrapped_share.py +0 -0
@@ -2,6 +2,83 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [2.0.1] - 2026-03-31
6
+
7
+ ### Added
8
+ - **Project-level quality comparison** — `reprompt projects` aggregates session quality, efficiency, focus scores, and frustration signals per project. Supports `--source` filter, `--json`, `--copy`.
9
+ - Tests: 1670 → 1716
10
+
11
+ ## [2.0.0] - 2026-03-31
12
+
13
+ ### Changed
14
+ - **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.
15
+
16
+ ## [1.10.0] - 2026-03-31
17
+
18
+ ### Added
19
+ - **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.
20
+ - **`reprompt init` command** — generates `.reprompt.toml` config with all lint rules documented and commented defaults. `--force` to overwrite existing.
21
+ - Tests: 1597 → 1670
22
+
23
+ ## [1.9.1] - 2026-03-31
24
+
25
+ ### Added
26
+ - **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.
27
+ - Tests: 1567 → 1597
28
+
29
+ ## [1.9.0] - 2026-03-31
30
+
31
+ ### Added
32
+ - **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.
33
+ - `get_recent_scores(limit)` DB method for trend computation.
34
+ - Tests: 1545 → 1567
35
+
36
+ ## [1.8.1] - 2026-03-31
37
+
38
+ ### Added
39
+ - **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.
40
+ - Tests: 1529 → 1545
41
+
42
+ ## [1.8.0] - 2026-03-31
43
+
44
+ ### Added
45
+ - **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.
46
+
47
+ ### Fixed
48
+ - **Pipeline type mismatch** — `parse_conversation()` returns `list[ConversationTurn]`, not `Conversation`. Pipeline now wraps turns correctly. Without this fix, session quality scoring silently failed.
49
+ - **Bridge shell injection** — quoted `sys.executable` in bridge wrapper script to prevent command injection when Python path contains spaces.
50
+ - **Unclamped scores** — efficiency and focus component scores now clamped to 0-100 range.
51
+ - Tests: 1497 → 1529
52
+
53
+ ## [1.7.1] - 2026-03-29
54
+
55
+ ### Added
56
+ - **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.
57
+
58
+ ## [1.7.0] - 2026-03-28
59
+
60
+ ### Added
61
+ - **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).
62
+ - **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.
63
+ - Locale-aware token counting: 1.3x words (EN), 1.5x chars (CJK).
64
+ - Price table: Claude Sonnet/Opus/Haiku, GPT-4o/mini, Gemini, DeepSeek. Auto-detect model from adapter source.
65
+ - Tests: 1497 → 1529
66
+
67
+ ## [1.6.2] - 2026-03-28
68
+
69
+ ### Fixed
70
+ - **Security: shell injection in GitHub Action** — inputs now passed via env vars, not string interpolation.
71
+ - **Bridge: 1MB message limit** — enforce Chrome Native Messaging size limit with proper JSON decode error handling.
72
+
73
+ ### Improved
74
+ - SQLite WAL mode + 10s timeout for concurrent access safety.
75
+ - MCP: all 6 tools wrapped in try/except with structured error responses; `check_privacy` uses SQL LIMIT.
76
+ - Dedup: skip O(n²) semantic layer when batch > 5000 prompts.
77
+ - ChatGPT adapter: warn on files > 200MB.
78
+ - First-run dashboard shows "Found N sessions (~M turns) across K tools".
79
+ - `purge --all` now requires confirmation.
80
+ - MCP server consolidated from 10 to 6 focused tools.
81
+
5
82
  ## [1.6.1] - 2026-03-28
6
83
 
7
84
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: reprompt-cli
3
- Version: 2.0.0
3
+ Version: 2.0.2
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.0.1
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.0.1
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.0"
3
+ version = "2.0.2"
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.0"
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
 
@@ -982,9 +982,18 @@ def score(
982
982
  "paper": s.paper,
983
983
  "message": s.message,
984
984
  "impact": s.impact,
985
+ "points": s.points,
985
986
  }
986
987
  for s in breakdown.suggestions
987
988
  ],
989
+ "confirmations": [
990
+ {
991
+ "category": c.category,
992
+ "message": c.message,
993
+ "score": c.score,
994
+ }
995
+ for c in breakdown.confirmations
996
+ ],
988
997
  }
989
998
  typer.echo(json_mod.dumps(data, indent=2))
990
999
  else:
@@ -1004,9 +1013,18 @@ def score(
1004
1013
  "paper": s.paper,
1005
1014
  "message": s.message,
1006
1015
  "impact": s.impact,
1016
+ "points": s.points,
1007
1017
  }
1008
1018
  for s in breakdown.suggestions
1009
1019
  ],
1020
+ "confirmations": [
1021
+ {
1022
+ "category": c.category,
1023
+ "message": c.message,
1024
+ "score": c.score,
1025
+ }
1026
+ for c in breakdown.confirmations
1027
+ ],
1010
1028
  }
1011
1029
  typer.echo(render_score(data))
1012
1030
  from reprompt.core.suggestions import get_suggestion
@@ -2046,6 +2064,57 @@ debug-needs-reference = true
2046
2064
  console.print(" Edit rules, then run [bold]reprompt lint[/bold] to verify.")
2047
2065
 
2048
2066
 
2067
+ @app.command(rich_help_panel="Analyze")
2068
+ def projects(
2069
+ source: str = typer.Option(
2070
+ None, "--source", "-s", help="Filter by source (e.g. claude-code, cursor)"
2071
+ ),
2072
+ json_output: bool = typer.Option(False, "--json", help="Output as JSON"),
2073
+ copy: bool = typer.Option(False, "--copy", help="Copy result to clipboard"),
2074
+ ) -> None:
2075
+ """Compare prompt quality across projects.
2076
+
2077
+ Shows per-project breakdown: sessions, prompts, quality scores,
2078
+ efficiency, focus, and frustration signals.
2079
+
2080
+ Examples:
2081
+
2082
+ reprompt projects # all projects
2083
+
2084
+ reprompt projects --source claude-code # filter by source
2085
+
2086
+ reprompt projects --json # machine-readable
2087
+ """
2088
+ import json as json_mod
2089
+
2090
+ from reprompt.config import Settings
2091
+ from reprompt.output.projects_terminal import render_projects_table
2092
+ from reprompt.storage.db import PromptDB
2093
+
2094
+ settings = Settings()
2095
+ db = PromptDB(settings.db_path)
2096
+
2097
+ project_data = db.get_project_summary(source=source)
2098
+
2099
+ if json_output:
2100
+ print(json_mod.dumps(project_data, indent=2, default=str))
2101
+ else:
2102
+ output = render_projects_table(project_data)
2103
+ print(output)
2104
+
2105
+ if copy:
2106
+ if json_output:
2107
+ _copy_to_clip(json_mod.dumps(project_data, indent=2, default=str), quiet=True)
2108
+ else:
2109
+ _copy_to_clip(output)
2110
+
2111
+ from reprompt.core.suggestions import get_suggestion
2112
+
2113
+ hint = get_suggestion("projects")
2114
+ if hint and not json_output:
2115
+ console.print(f" [dim]→ Try: {hint}[/dim]\n")
2116
+
2117
+
2049
2118
  @app.command(rich_help_panel="Analyze")
2050
2119
  def sessions(
2051
2120
  last: int = typer.Option(10, "--last", help="Show N most recent sessions"),
@@ -2,13 +2,18 @@
2
2
  """Weighted prompt scoring engine with research-calibrated weights.
3
3
 
4
4
  Scores a PromptDNA feature vector on a 0-100 scale across five categories:
5
- 1. Structure (0-25): role, constraints, examples, output format
5
+ 1. Clarity (0-25): low ambiguity, good opening, reasonable length
6
6
  2. Context (0-25): code blocks, file refs, error messages, specificity
7
7
  3. Position (0-20): instruction placement (Lost in the Middle)
8
- 4. Repetition (0-15): keyword reinforcement (Google Research)
9
- 5. Clarity (0-15): low ambiguity, good opening, reasonable length
8
+ 4. Structure (0-15): role, constraints, examples, output format
9
+ 5. Repetition (0-15): keyword reinforcement (Google Research)
10
10
 
11
- Each weight is derived from published research findings:
11
+ Weight rationale: clarity and context are what normal developers can
12
+ improve immediately; structure and repetition are advanced techniques
13
+ that provide additional lift. This ensures a clear, specific prompt
14
+ scores 55-65 without requiring markdown or role definitions.
15
+
16
+ Research references:
12
17
  - Position weights from the U-curve in arXiv:2307.03172 (30% degradation)
13
18
  - Repetition weights from arXiv:2512.14982 (up to 76% improvement)
14
19
  - Specificity weights from DETAIL arXiv:2512.02246
@@ -53,6 +58,16 @@ class Suggestion:
53
58
  paper: str # short citation
54
59
  message: str
55
60
  impact: str # "high", "medium", "low"
61
+ points: int = 0 # expected score gain if applied
62
+
63
+
64
+ @dataclass
65
+ class Confirmation:
66
+ """Positive feedback for a detected feature."""
67
+
68
+ category: str
69
+ message: str
70
+ score: str # e.g. "20/20"
56
71
 
57
72
 
58
73
  @dataclass
@@ -62,13 +77,14 @@ class ScoreBreakdown:
62
77
  total: float = 0.0
63
78
 
64
79
  # Category scores (each out of their max)
65
- structure: float = 0.0 # max 25
80
+ structure: float = 0.0 # max 15
66
81
  context: float = 0.0 # max 25
67
82
  position: float = 0.0 # max 20
68
83
  repetition: float = 0.0 # max 15
69
- clarity: float = 0.0 # max 15
84
+ clarity: float = 0.0 # max 25
70
85
 
71
86
  suggestions: list[Suggestion] = field(default_factory=list)
87
+ confirmations: list[Confirmation] = field(default_factory=list)
72
88
 
73
89
 
74
90
  def score_prompt(dna: PromptDNA) -> ScoreBreakdown:
@@ -78,22 +94,23 @@ def score_prompt(dna: PromptDNA) -> ScoreBreakdown:
78
94
  """
79
95
  suggestions: list[Suggestion] = []
80
96
 
81
- # ── Structure (0-25) ──
97
+ # ── Structure (0-15) ──
82
98
  structure = 0.0
83
99
  if dna.has_role_definition:
84
- structure += 5.0
100
+ structure += 3.0
85
101
  else:
86
102
  suggestions.append(
87
103
  Suggestion(
88
104
  "structure",
89
105
  "Prompt Report",
90
106
  'Add a role definition (e.g., "You are a senior Python developer")',
91
- "medium",
107
+ "low",
108
+ points=3,
92
109
  )
93
110
  )
94
111
 
95
112
  if dna.has_constraints:
96
- structure += 4.0 + min(dna.constraint_count, 3) * 1.0
113
+ structure += 3.0 + min(dna.constraint_count, 2) * 1.0
97
114
  else:
98
115
  suggestions.append(
99
116
  Suggestion(
@@ -101,20 +118,21 @@ def score_prompt(dna: PromptDNA) -> ScoreBreakdown:
101
118
  "Prompt Report",
102
119
  'Add constraints (e.g., "Do not modify tests", "Must be backward-compatible")',
103
120
  "medium",
121
+ points=5,
104
122
  )
105
123
  )
106
124
 
107
125
  if dna.has_examples:
108
- structure += 4.0 + min(dna.example_count, 2) * 1.0
126
+ structure += 2.0 + min(dna.example_count, 1) * 1.0
109
127
 
110
128
  if dna.has_output_format:
111
- structure += 3.0
129
+ structure += 2.0
112
130
 
113
131
  if dna.has_step_by_step:
114
- structure += 2.0
132
+ structure += 1.0
115
133
 
116
- structure += min(dna.section_count, 3) * 1.0
117
- structure = min(structure, 25.0)
134
+ structure += min(dna.section_count, 2) * 1.0
135
+ structure = min(structure, 15.0)
118
136
 
119
137
  # ── Context (0-25) ──
120
138
  context = 0.0
@@ -130,6 +148,7 @@ def score_prompt(dna: PromptDNA) -> ScoreBreakdown:
130
148
  "DETAIL arXiv:2512.02246",
131
149
  "Add file path references — specificity improves output quality significantly",
132
150
  "high",
151
+ points=6,
133
152
  )
134
153
  )
135
154
 
@@ -142,6 +161,7 @@ def score_prompt(dna: PromptDNA) -> ScoreBreakdown:
142
161
  "DETAIL arXiv:2512.02246",
143
162
  "Include the actual error message — debug prompts with errors are 3.7x more effective", # noqa: E501
144
163
  "high",
164
+ points=6,
145
165
  )
146
166
  )
147
167
 
@@ -157,9 +177,9 @@ def score_prompt(dna: PromptDNA) -> ScoreBreakdown:
157
177
  Suggestion(
158
178
  "position",
159
179
  "Lost in the Middle arXiv:2307.03172",
160
- "Your key instruction is buried in the middle "
161
- "move it to the start or end for better attention (30% degradation in middle)",
180
+ "Move your key instruction to the start or end (30% degradation in middle)",
162
181
  "high",
182
+ points=10,
163
183
  )
164
184
  )
165
185
 
@@ -175,48 +195,78 @@ def score_prompt(dna: PromptDNA) -> ScoreBreakdown:
175
195
  Suggestion(
176
196
  "repetition",
177
197
  "Google Research arXiv:2512.14982",
178
- "Repeating your core requirement at the end of the prompt "
179
- "can improve accuracy by up to 76%",
198
+ "Repeat your core requirement at the end can improve accuracy up to 76%",
180
199
  "medium",
200
+ points=8,
181
201
  )
182
202
  )
183
203
 
184
- # ── Clarity (0-15) ──
204
+ # ── Clarity (0-25) ──
185
205
  clarity = 0.0
186
206
 
187
207
  # Opening quality
188
- clarity += 5.0 * min(dna.opening_quality, 1.0)
208
+ clarity += 9.0 * min(dna.opening_quality, 1.0)
189
209
 
190
210
  # Low ambiguity
191
- clarity += 5.0 * max(0.0, 1.0 - dna.ambiguity_score)
211
+ clarity += 8.0 * max(0.0, 1.0 - dna.ambiguity_score)
192
212
  if dna.ambiguity_score > 0.5:
193
213
  suggestions.append(
194
214
  Suggestion(
195
215
  "clarity",
196
216
  "DETAIL arXiv:2512.02246",
197
- "Prompt is vague — replace pronouns ('it', 'this') with specific names",
217
+ "Replace pronouns ('it', 'this') with specific names",
198
218
  "high",
219
+ points=4,
199
220
  )
200
221
  )
201
222
 
202
223
  # Reasonable length (not too short)
203
224
  if dna.word_count >= 20:
204
- clarity += 5.0
225
+ clarity += 8.0
205
226
  elif dna.word_count >= 10:
206
- clarity += 3.0
227
+ clarity += 5.0
207
228
  elif dna.word_count >= 5:
208
- clarity += 1.0
229
+ clarity += 2.0
209
230
  else:
210
231
  suggestions.append(
211
232
  Suggestion(
212
233
  "clarity",
213
234
  "DETAIL arXiv:2512.02246",
214
- "Prompt is very short — add context about what, where, and why",
235
+ "Add more context about what, where, and why",
215
236
  "high",
237
+ points=6,
216
238
  )
217
239
  )
218
240
 
219
- clarity = min(clarity, 15.0)
241
+ clarity = min(clarity, 25.0)
242
+
243
+ # ── Positive confirmations ──
244
+ confirmations: list[Confirmation] = []
245
+ if pos_score >= 0.8:
246
+ confirmations.append(
247
+ Confirmation("position", "Key instruction at the start — optimal placement",
248
+ f"{round(position)}/20")
249
+ )
250
+ if dna.has_file_references:
251
+ confirmations.append(
252
+ Confirmation("context", "File references detected — specificity matters",
253
+ f"{round(min(context, 25))}/25")
254
+ )
255
+ if dna.has_error_messages:
256
+ confirmations.append(
257
+ Confirmation("context", "Error context included — 3.7x more effective",
258
+ f"{round(min(context, 25))}/25")
259
+ )
260
+ if dna.has_constraints:
261
+ confirmations.append(
262
+ Confirmation("structure", "Constraints defined — clear boundaries set",
263
+ f"{round(structure)}/15")
264
+ )
265
+ if dna.opening_quality >= 0.4:
266
+ confirmations.append(
267
+ Confirmation("clarity", "Strong opening — starts with clear intent",
268
+ f"{round(clarity)}/25")
269
+ )
220
270
 
221
271
  # ── Total ──
222
272
  total = structure + context + position + repetition + clarity
@@ -230,4 +280,5 @@ def score_prompt(dna: PromptDNA) -> ScoreBreakdown:
230
280
  repetition=round(repetition, 1),
231
281
  clarity=round(clarity, 1),
232
282
  suggestions=suggestions,
283
+ confirmations=confirmations,
233
284
  )
@@ -24,6 +24,7 @@ SUGGESTIONS: dict[str, str] = {
24
24
  "template": "reprompt insights (see which patterns work best)",
25
25
  "lint": "reprompt init (generate .reprompt.toml) · reprompt rewrite (improve prompts)",
26
26
  "rewrite": "reprompt compress (reduce tokens) · reprompt score (verify improvement)",
27
+ "projects": "reprompt sessions --detail <id> (deep-dive) · reprompt insights (patterns)",
27
28
  }
28
29
 
29
30
 
@@ -0,0 +1,101 @@
1
+ """Rich terminal output for projects command."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from io import StringIO
6
+ from typing import Any
7
+
8
+ from rich.console import Console
9
+ from rich.panel import Panel
10
+ from rich.table import Table
11
+
12
+
13
+ def _score_style(score: float | None) -> str:
14
+ if score is None:
15
+ return "dim"
16
+ if score >= 80:
17
+ return "bold green"
18
+ if score >= 60:
19
+ return "green"
20
+ if score >= 40:
21
+ return "yellow"
22
+ return "red"
23
+
24
+
25
+ def render_projects_table(projects: list[dict[str, Any]]) -> str:
26
+ """Render project quality summary as a Rich table."""
27
+ buf = StringIO()
28
+ console = Console(file=buf, width=110, record=True)
29
+
30
+ if not projects:
31
+ console.print("\n [dim]No project data. Run [bold]reprompt scan[/bold] first.[/dim]\n")
32
+ return buf.getvalue()
33
+
34
+ # Header stats
35
+ total_sessions = sum(p.get("session_count", 0) for p in projects)
36
+ total_prompts = sum(p.get("prompt_count", 0) or 0 for p in projects)
37
+ quality_scores = [p["avg_quality"] for p in projects if p.get("avg_quality") is not None]
38
+ avg_quality = round(sum(quality_scores) / len(quality_scores), 1) if quality_scores else 0
39
+
40
+ console.print(
41
+ Panel(
42
+ f" [bold]{len(projects)}[/bold] projects · "
43
+ f"[bold]{total_sessions}[/bold] sessions · "
44
+ f"[bold]{total_prompts}[/bold] prompts · "
45
+ f"avg quality [bold]{avg_quality}[/bold]/100",
46
+ title="[bold]Project Quality[/bold]",
47
+ border_style="blue",
48
+ )
49
+ )
50
+
51
+ # Table
52
+ table = Table(show_header=True, header_style="bold", padding=(0, 1), expand=True)
53
+ table.add_column("Project", style="bold", min_width=12)
54
+ table.add_column("Sessions", justify="right", width=8)
55
+ table.add_column("Prompts", justify="right", width=8)
56
+ table.add_column("Quality", justify="right", width=8)
57
+ table.add_column("Efficiency", justify="right", width=10)
58
+ table.add_column("Focus", justify="right", width=7)
59
+ table.add_column("Frustration", justify="right", width=11)
60
+ table.add_column("Source", width=14)
61
+
62
+ for p in projects:
63
+ quality = p.get("avg_quality")
64
+ efficiency = p.get("avg_efficiency")
65
+ focus = p.get("avg_focus")
66
+
67
+ abandon = p.get("abandonment_count", 0) or 0
68
+ escalate = p.get("escalation_count", 0) or 0
69
+ frustration_total = abandon + escalate
70
+ sessions = p.get("session_count", 0)
71
+ frust_pct = round(frustration_total / sessions * 100) if sessions > 0 else 0
72
+
73
+ q_str = f"[{_score_style(quality)}]{quality:.0f}[/]" if quality else "[dim]--[/dim]"
74
+ e_str = (
75
+ f"[{_score_style(efficiency)}]{efficiency:.0f}[/]" if efficiency else "[dim]--[/dim]"
76
+ )
77
+ f_str = f"[{_score_style(focus)}]{focus:.0f}[/]" if focus else "[dim]--[/dim]"
78
+
79
+ frust_style = "red" if frust_pct > 30 else "yellow" if frust_pct > 15 else "dim"
80
+ frust_str = f"[{frust_style}]{frust_pct}%[/]" if frustration_total > 0 else "[dim]--[/dim]"
81
+
82
+ sources = p.get("sources", "")
83
+ # Shorten source names
84
+ short_sources = (
85
+ sources.replace("claude-code", "claude").replace("-ext", "") if sources else ""
86
+ )
87
+
88
+ table.add_row(
89
+ p.get("project", "unknown"),
90
+ str(sessions),
91
+ str(p.get("prompt_count", 0) or 0),
92
+ q_str,
93
+ e_str,
94
+ f_str,
95
+ frust_str,
96
+ short_sources,
97
+ )
98
+
99
+ console.print(table)
100
+ console.print()
101
+ return buf.getvalue()
@@ -60,10 +60,10 @@ def render_rewrite(result: RewriteResult) -> str:
60
60
  def _score_color(score: float) -> str:
61
61
  if score >= 85:
62
62
  return "bold magenta"
63
- if score >= 70:
63
+ if score >= 60:
64
64
  return "bold green"
65
- if score >= 55:
66
- return "bold yellow"
67
65
  if score >= 40:
66
+ return "bold yellow"
67
+ if score >= 25:
68
68
  return "yellow"
69
69
  return "bold red"