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.
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/CHANGELOG.md +92 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/PKG-INFO +4 -3
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/README.md +3 -2
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/pyproject.toml +1 -1
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/__init__.py +4 -4
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/cli.py +50 -2
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/lint.py +170 -4
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/scorer.py +90 -28
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/rewrite_terminal.py +50 -3
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/terminal.py +34 -14
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/wrapped_html.py +3 -3
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_cli.py +2 -2
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_coverage_boost.py +6 -6
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_lint.py +176 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/uv.lock +1 -1
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.editorconfig +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.github/dependabot.yml +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.github/workflows/ci.yml +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.github/workflows/publish.yml +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.gitignore +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.pre-commit-config.yaml +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.pre-commit-hooks.yaml +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.testmondata-shm +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/.testmondata-wal +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/CODE_OF_CONDUCT.md +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/CONTRIBUTING.md +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/LICENSE +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/SECURITY.md +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/Screenshot 2026-03-24 at 09.45.03.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/action.yml +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/demo.gif +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/brand-icon-128.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/brand-icon-16.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/brand-icon-256.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/brand-icon-32.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/brand-icon-48.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/brand-icon-512.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/brand-icon-96.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/brand-icon.svg +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-favicon-128.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-favicon-16.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-favicon-256.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-favicon-32.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-favicon-48.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-favicon-512.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-favicon-96.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-favicon.svg +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-icon-128.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-icon-16.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-icon-256.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-icon-32.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-icon-48.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-icon-512.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-icon-96.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/cli-icon.svg +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/favicon-128.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/favicon-16.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/favicon-256.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/favicon-32.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/favicon-48.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/favicon-512.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/favicon-96.png +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/favicon.svg +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/icons/generate.sh +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/superpowers/specs/2026-03-24-v14-command-consolidation-design.md +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/docs/superpowers/specs/2026-03-25-v1.5-dashboard-design.md +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/scripts/generate_demo_data.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/adapters/__init__.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/adapters/aider.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/adapters/base.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/adapters/chatgpt.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/adapters/claude_chat.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/adapters/claude_code.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/adapters/cline.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/adapters/codex.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/adapters/cursor.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/adapters/filters.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/adapters/gemini.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/adapters/openclaw.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/bridge/__init__.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/bridge/handler.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/bridge/host.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/bridge/manifest.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/bridge/protocol.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/commands/__init__.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/commands/telemetry.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/commands/wrapped.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/config.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/__init__.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/agent.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/analyzer.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/compress.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/conversation.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/cost.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/dashboard.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/dedup.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/digest.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/distill.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/effectiveness.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/extractors.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/extractors_zh.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/insights.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/lang_detect.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/library.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/merge_view.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/models.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/persona.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/pipeline.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/privacy.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/privacy_scan.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/prompt_dna.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/recommend.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/repetition.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/rewrite.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/segmenter.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/session_meta.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/session_quality.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/session_type.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/style.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/suggestions.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/templates.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/timeutil.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/trends.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/core/wrapped.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/demo.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/embeddings/__init__.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/embeddings/base.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/embeddings/local_embed.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/embeddings/ollama.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/embeddings/openai_embed.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/embeddings/tfidf.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/mcp.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/mcp_main.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/__init__.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/agent_terminal.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/chartjs.min.js +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/compress_terminal.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/dashboard_terminal.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/distill_terminal.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/export.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/html_report.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/json_out.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/markdown.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/projects_terminal.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/repetition_terminal.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/sessions_terminal.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/output/wrapped_terminal.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/py.typed +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/sharing/__init__.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/sharing/client.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/sharing/clipboard.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/storage/__init__.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/storage/db.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/telemetry/__init__.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/telemetry/collector.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/telemetry/consent.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/telemetry/events.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/telemetry/prompt.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/telemetry/queue.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/src/reprompt/telemetry/sender.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/__init__.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/conftest.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/fixtures/aider_chat_history.md +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/fixtures/chatgpt_conversations.json +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/fixtures/claude_chat_export.json +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/fixtures/claude_session.jsonl +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/fixtures/cline_task/api_conversation_history.json +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/fixtures/export/default_export.md +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/fixtures/export/full_export.md +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/fixtures/gemini_session.json +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/fixtures/openclaw_session.jsonl +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_adapter_aider.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_adapter_chatgpt.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_adapter_claude.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_adapter_claude_chat.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_adapter_cline.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_adapter_gemini.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_adapter_openclaw.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_agent.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_agent_cli.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_analyzer.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_bridge_cli.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_bridge_e2e.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_bridge_handler.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_bridge_integration.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_bridge_manifest.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_bridge_protocol.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_cli_deprecations.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_cli_library_effectiveness.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_clipboard.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_codex_adapter.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_compare_best_worst.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_compress.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_compress_cli.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_compress_dna.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_compress_html.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_compress_insights.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_config.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_conversation.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_copy_flag.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_cost.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_cursor_adapter.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_dashboard.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_db.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_db_digest.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_db_effectiveness.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_db_session_quality.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_db_trends.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_dedup.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_demo.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_deprecated_commands.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_digest.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_digest_cli.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_distill.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_distill_cli.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_distill_weights.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_e2e.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_effectiveness.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_embeddings_local.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_embeddings_ollama.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_embeddings_openai.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_empty_state.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_export.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_export_cli.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_export_snapshot.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_extractors.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_extractors_routing.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_extractors_zh.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_extractors_zh_e2e.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_html_report.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_import_cli.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_import_e2e.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_init_cli.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_insights.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_insights_cli.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_insights_expanded.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_install_hook.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_lang_detect.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_library.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_lint_cli.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_markdown.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_mcp.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_merge_view.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_models.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_output.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_parse_conversation_base.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_parse_conversation_chatgpt.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_parse_conversation_claude.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_persona.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_pipeline.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_privacy.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_privacy_cli.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_privacy_e2e.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_privacy_output.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_privacy_scan.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_projects.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_prompt_dna.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_public_api.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_recommend.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_repetition.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_repetition_cli.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_repetition_output.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_rewrite.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_schema_version.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_score_cli.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_scorer.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_segmenter.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_session_quality.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_session_type.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_sessions_cli.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_sessions_output.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_share_e2e.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_sharing_client.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_source_filter.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_style.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_style_trends.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_suggestions.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_telemetry_cli.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_telemetry_collector.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_telemetry_consent.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_telemetry_e2e.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_telemetry_events.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_telemetry_prompt.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_telemetry_queue.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_telemetry_sender.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_template_cli.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_templates.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_timeutil.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_trends.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_trends_cli.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_use_cli.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_wrapped.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_wrapped_cli.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_wrapped_e2e.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_wrapped_html.py +0 -0
- {reprompt_cli-2.0.1 → reprompt_cli-2.1.0}/tests/test_wrapped_output.py +0 -0
- {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
|
|
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:
|
|
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:
|
|
186
|
+
rev: v2.1.0
|
|
186
187
|
hooks:
|
|
187
188
|
- id: reprompt-lint
|
|
188
189
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""reprompt — Discover, analyze, and evolve your best prompts from AI coding sessions."""
|
|
2
2
|
|
|
3
|
-
__version__ = "2.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 >=
|
|
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 "
|
|
1121
|
+
reprompt rewrite "fix the login" --diff
|
|
1085
1122
|
|
|
1086
|
-
reprompt rewrite "
|
|
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
|
-
|
|
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)
|