reprompt-cli 2.1.0__tar.gz → 2.2.1__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.1.0 → reprompt_cli-2.2.1}/CHANGELOG.md +15 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/PKG-INFO +4 -2
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/README.md +3 -1
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/pyproject.toml +1 -1
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/cli.py +203 -6
- reprompt_cli-2.2.1/src/reprompt/core/build.py +246 -0
- reprompt_cli-2.2.1/src/reprompt/core/check.py +115 -0
- reprompt_cli-2.2.1/src/reprompt/core/explain.py +208 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/suggestions.py +3 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/mcp.py +128 -1
- reprompt_cli-2.2.1/src/reprompt/output/build_terminal.py +52 -0
- reprompt_cli-2.2.1/src/reprompt/output/check_terminal.py +105 -0
- reprompt_cli-2.2.1/src/reprompt/output/explain_terminal.py +58 -0
- reprompt_cli-2.2.1/tests/test_build.py +270 -0
- reprompt_cli-2.2.1/tests/test_build_cli.py +126 -0
- reprompt_cli-2.2.1/tests/test_build_output.py +59 -0
- reprompt_cli-2.2.1/tests/test_check.py +101 -0
- reprompt_cli-2.2.1/tests/test_check_cli.py +80 -0
- reprompt_cli-2.2.1/tests/test_explain.py +100 -0
- reprompt_cli-2.2.1/tests/test_explain_cli.py +56 -0
- reprompt_cli-2.2.1/tests/test_file_input.py +107 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_mcp.py +69 -2
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/uv.lock +1 -1
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/.editorconfig +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/.github/dependabot.yml +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/.github/workflows/ci.yml +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/.github/workflows/publish.yml +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/.gitignore +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/.pre-commit-config.yaml +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/.pre-commit-hooks.yaml +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/.testmondata-shm +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/.testmondata-wal +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/CODE_OF_CONDUCT.md +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/CONTRIBUTING.md +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/LICENSE +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/SECURITY.md +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/Screenshot 2026-03-24 at 09.45.03.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/action.yml +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/demo.gif +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/brand-icon-128.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/brand-icon-16.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/brand-icon-256.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/brand-icon-32.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/brand-icon-48.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/brand-icon-512.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/brand-icon-96.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/brand-icon.svg +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/cli-favicon-128.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/cli-favicon-16.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/cli-favicon-256.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/cli-favicon-32.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/cli-favicon-48.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/cli-favicon-512.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/cli-favicon-96.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/cli-favicon.svg +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/cli-icon-128.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/cli-icon-16.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/cli-icon-256.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/cli-icon-32.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/cli-icon-48.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/cli-icon-512.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/cli-icon-96.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/cli-icon.svg +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/favicon-128.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/favicon-16.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/favicon-256.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/favicon-32.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/favicon-48.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/favicon-512.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/favicon-96.png +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/favicon.svg +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/icons/generate.sh +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/superpowers/specs/2026-03-24-v14-command-consolidation-design.md +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/docs/superpowers/specs/2026-03-25-v1.5-dashboard-design.md +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/scripts/generate_demo_data.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/__init__.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/adapters/__init__.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/adapters/aider.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/adapters/base.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/adapters/chatgpt.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/adapters/claude_chat.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/adapters/claude_code.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/adapters/cline.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/adapters/codex.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/adapters/cursor.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/adapters/filters.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/adapters/gemini.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/adapters/openclaw.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/bridge/__init__.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/bridge/handler.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/bridge/host.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/bridge/manifest.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/bridge/protocol.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/commands/__init__.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/commands/telemetry.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/commands/wrapped.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/config.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/__init__.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/agent.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/analyzer.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/compress.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/conversation.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/cost.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/dashboard.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/dedup.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/digest.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/distill.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/effectiveness.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/extractors.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/extractors_zh.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/insights.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/lang_detect.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/library.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/lint.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/merge_view.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/models.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/persona.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/pipeline.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/privacy.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/privacy_scan.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/prompt_dna.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/recommend.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/repetition.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/rewrite.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/scorer.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/segmenter.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/session_meta.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/session_quality.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/session_type.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/style.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/templates.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/timeutil.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/trends.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/core/wrapped.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/demo.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/embeddings/__init__.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/embeddings/base.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/embeddings/local_embed.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/embeddings/ollama.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/embeddings/openai_embed.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/embeddings/tfidf.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/mcp_main.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/output/__init__.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/output/agent_terminal.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/output/chartjs.min.js +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/output/compress_terminal.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/output/dashboard_terminal.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/output/distill_terminal.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/output/export.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/output/html_report.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/output/json_out.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/output/markdown.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/output/projects_terminal.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/output/repetition_terminal.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/output/rewrite_terminal.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/output/sessions_terminal.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/output/terminal.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/output/wrapped_html.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/output/wrapped_terminal.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/py.typed +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/sharing/__init__.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/sharing/client.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/sharing/clipboard.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/storage/__init__.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/storage/db.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/telemetry/__init__.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/telemetry/collector.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/telemetry/consent.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/telemetry/events.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/telemetry/prompt.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/telemetry/queue.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/src/reprompt/telemetry/sender.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/__init__.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/conftest.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/fixtures/aider_chat_history.md +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/fixtures/chatgpt_conversations.json +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/fixtures/claude_chat_export.json +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/fixtures/claude_session.jsonl +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/fixtures/cline_task/api_conversation_history.json +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/fixtures/export/default_export.md +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/fixtures/export/full_export.md +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/fixtures/gemini_session.json +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/fixtures/openclaw_session.jsonl +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_adapter_aider.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_adapter_chatgpt.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_adapter_claude.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_adapter_claude_chat.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_adapter_cline.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_adapter_gemini.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_adapter_openclaw.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_agent.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_agent_cli.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_analyzer.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_bridge_cli.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_bridge_e2e.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_bridge_handler.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_bridge_integration.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_bridge_manifest.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_bridge_protocol.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_cli.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_cli_deprecations.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_cli_library_effectiveness.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_clipboard.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_codex_adapter.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_compare_best_worst.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_compress.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_compress_cli.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_compress_dna.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_compress_html.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_compress_insights.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_config.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_conversation.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_copy_flag.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_cost.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_coverage_boost.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_cursor_adapter.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_dashboard.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_db.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_db_digest.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_db_effectiveness.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_db_session_quality.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_db_trends.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_dedup.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_demo.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_deprecated_commands.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_digest.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_digest_cli.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_distill.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_distill_cli.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_distill_weights.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_e2e.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_effectiveness.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_embeddings_local.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_embeddings_ollama.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_embeddings_openai.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_empty_state.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_export.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_export_cli.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_export_snapshot.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_extractors.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_extractors_routing.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_extractors_zh.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_extractors_zh_e2e.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_html_report.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_import_cli.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_import_e2e.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_init_cli.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_insights.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_insights_cli.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_insights_expanded.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_install_hook.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_lang_detect.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_library.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_lint.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_lint_cli.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_markdown.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_merge_view.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_models.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_output.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_parse_conversation_base.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_parse_conversation_chatgpt.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_parse_conversation_claude.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_persona.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_pipeline.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_privacy.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_privacy_cli.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_privacy_e2e.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_privacy_output.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_privacy_scan.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_projects.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_prompt_dna.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_public_api.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_recommend.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_repetition.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_repetition_cli.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_repetition_output.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_rewrite.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_schema_version.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_score_cli.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_scorer.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_segmenter.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_session_quality.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_session_type.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_sessions_cli.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_sessions_output.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_share_e2e.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_sharing_client.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_source_filter.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_style.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_style_trends.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_suggestions.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_telemetry_cli.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_telemetry_collector.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_telemetry_consent.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_telemetry_e2e.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_telemetry_events.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_telemetry_prompt.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_telemetry_queue.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_telemetry_sender.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_template_cli.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_templates.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_timeutil.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_trends.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_trends_cli.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_use_cli.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_wrapped.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_wrapped_cli.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_wrapped_e2e.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_wrapped_html.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_wrapped_output.py +0 -0
- {reprompt_cli-2.1.0 → reprompt_cli-2.2.1}/tests/test_wrapped_share.py +0 -0
|
@@ -2,6 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [2.2.1] - 2026-04-01
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **MCP server expanded** — 6→9 tools: `check_prompt_quality` (unified diagnostic), `build_prompt_from_parts` (prompt constructor), `explain_prompt_quality` (educational analysis). IDE integration now covers all prompt quality features.
|
|
9
|
+
- **File input** — all prompt commands (`check`, `score`, `explain`, `rewrite`, `compress`) accept `--file` to read from file and `-` for stdin. Enables pipeline integration and multi-line prompts.
|
|
10
|
+
- Tests: 1846 → 1864
|
|
11
|
+
|
|
12
|
+
## [2.2.0] - 2026-04-01
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- **Prompt builder** — `reprompt build "task" --file src/auth.ts --error "TypeError" --constraint "keep tests"` assembles well-scored prompts from components. Model-aware formatting: XML tags for Claude, markdown headers for GPT. Shows score, tier, and suggestions for missing components.
|
|
16
|
+
- **Unified diagnostic** — `reprompt check "prompt"` runs score + lint + rewrite in one command. Shows dimensional breakdown, strengths, suggestions with point values, lint issues, and auto-rewrite preview.
|
|
17
|
+
- **Prompt explainer** — `reprompt explain "prompt"` explains what makes a prompt good or bad in plain English. Educational feedback with research-backed insights per dimension.
|
|
18
|
+
- Tests: 1741 → 1846
|
|
19
|
+
|
|
5
20
|
## [2.1.0] - 2026-04-01
|
|
6
21
|
|
|
7
22
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: reprompt-cli
|
|
3
|
-
Version: 2.1
|
|
3
|
+
Version: 2.2.1
|
|
4
4
|
Summary: Discover, analyze, and optimize your prompts from AI coding sessions
|
|
5
5
|
Project-URL: Homepage, https://github.com/reprompt-dev/reprompt
|
|
6
6
|
Project-URL: Repository, https://github.com/reprompt-dev/reprompt
|
|
@@ -104,6 +104,7 @@ $ reprompt
|
|
|
104
104
|
|---------|-------------|
|
|
105
105
|
| `reprompt` | Instant dashboard -- prompts, sessions, avg score, top categories |
|
|
106
106
|
| `reprompt scan` | Auto-discover prompts from 9 AI tools |
|
|
107
|
+
| `reprompt check "prompt"` | **Full diagnostic** -- score + lint + rewrite preview in one command |
|
|
107
108
|
| `reprompt score "prompt"` | Research-backed 0-100 scoring with 30+ features |
|
|
108
109
|
| `reprompt compare "a" "b"` | Side-by-side prompt analysis (or `--best-worst` for auto-selection) |
|
|
109
110
|
| `reprompt insights` | Personal patterns vs research-optimal benchmarks |
|
|
@@ -117,6 +118,7 @@ $ reprompt
|
|
|
117
118
|
|
|
118
119
|
| Command | Description |
|
|
119
120
|
|---------|-------------|
|
|
121
|
+
| `reprompt build "task"` | **Build prompts from components** -- task, context, files, errors, constraints. Model-aware (Claude/GPT/Gemini) |
|
|
120
122
|
| `reprompt rewrite "prompt"` | **Rewrite prompts to score higher** -- filler removal, restructuring, hedging cleanup |
|
|
121
123
|
| `reprompt compress "prompt"` | 4-layer prompt compression (40-60% token savings typical) |
|
|
122
124
|
| `reprompt distill` | Extract important turns from conversations with 6-signal scoring |
|
|
@@ -228,7 +230,7 @@ Captured prompts sync locally via Native Messaging -- nothing leaves your machin
|
|
|
228
230
|
# .pre-commit-config.yaml
|
|
229
231
|
repos:
|
|
230
232
|
- repo: https://github.com/reprompt-dev/reprompt
|
|
231
|
-
rev: v2.1
|
|
233
|
+
rev: v2.2.1
|
|
232
234
|
hooks:
|
|
233
235
|
- id: reprompt-lint
|
|
234
236
|
```
|
|
@@ -59,6 +59,7 @@ $ reprompt
|
|
|
59
59
|
|---------|-------------|
|
|
60
60
|
| `reprompt` | Instant dashboard -- prompts, sessions, avg score, top categories |
|
|
61
61
|
| `reprompt scan` | Auto-discover prompts from 9 AI tools |
|
|
62
|
+
| `reprompt check "prompt"` | **Full diagnostic** -- score + lint + rewrite preview in one command |
|
|
62
63
|
| `reprompt score "prompt"` | Research-backed 0-100 scoring with 30+ features |
|
|
63
64
|
| `reprompt compare "a" "b"` | Side-by-side prompt analysis (or `--best-worst` for auto-selection) |
|
|
64
65
|
| `reprompt insights` | Personal patterns vs research-optimal benchmarks |
|
|
@@ -72,6 +73,7 @@ $ reprompt
|
|
|
72
73
|
|
|
73
74
|
| Command | Description |
|
|
74
75
|
|---------|-------------|
|
|
76
|
+
| `reprompt build "task"` | **Build prompts from components** -- task, context, files, errors, constraints. Model-aware (Claude/GPT/Gemini) |
|
|
75
77
|
| `reprompt rewrite "prompt"` | **Rewrite prompts to score higher** -- filler removal, restructuring, hedging cleanup |
|
|
76
78
|
| `reprompt compress "prompt"` | 4-layer prompt compression (40-60% token savings typical) |
|
|
77
79
|
| `reprompt distill` | Extract important turns from conversations with 6-signal scoring |
|
|
@@ -183,7 +185,7 @@ Captured prompts sync locally via Native Messaging -- nothing leaves your machin
|
|
|
183
185
|
# .pre-commit-config.yaml
|
|
184
186
|
repos:
|
|
185
187
|
- repo: https://github.com/reprompt-dev/reprompt
|
|
186
|
-
rev: v2.1
|
|
188
|
+
rev: v2.2.1
|
|
187
189
|
hooks:
|
|
188
190
|
- id: reprompt-lint
|
|
189
191
|
```
|
|
@@ -15,6 +15,21 @@ if TYPE_CHECKING:
|
|
|
15
15
|
from reprompt.storage.db import PromptDB
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
def _resolve_text(text: str, file: str) -> str:
|
|
19
|
+
"""Resolve prompt text from argument or --file option."""
|
|
20
|
+
if file:
|
|
21
|
+
p = Path(file)
|
|
22
|
+
if not p.is_file():
|
|
23
|
+
typer.echo(f"Error: file not found: {file}", err=True)
|
|
24
|
+
raise typer.Exit(1)
|
|
25
|
+
return p.read_text(encoding="utf-8").strip()
|
|
26
|
+
if text == "-":
|
|
27
|
+
import sys
|
|
28
|
+
|
|
29
|
+
return sys.stdin.read().strip()
|
|
30
|
+
return text
|
|
31
|
+
|
|
32
|
+
|
|
18
33
|
def _copy_to_clip(text: str, quiet: bool = False) -> None:
|
|
19
34
|
"""Copy text to clipboard with user feedback."""
|
|
20
35
|
from reprompt.sharing.clipboard import copy_to_clipboard
|
|
@@ -946,9 +961,119 @@ def lint(
|
|
|
946
961
|
raise typer.Exit(1)
|
|
947
962
|
|
|
948
963
|
|
|
964
|
+
@app.command(rich_help_panel="Analyze")
|
|
965
|
+
def check(
|
|
966
|
+
text: str = typer.Argument(..., help="Prompt text to check (use '-' for stdin)"),
|
|
967
|
+
model: str = typer.Option("", "--model", "-m", help="Target model (claude/gpt/gemini)"),
|
|
968
|
+
max_tokens: int = typer.Option(0, "--max-tokens", help="Token budget (0 = disabled)"),
|
|
969
|
+
file: str = typer.Option("", "--file", "-f", help="Read prompt from file"),
|
|
970
|
+
json_output: bool = typer.Option(False, "--json", help="Output as JSON"),
|
|
971
|
+
copy: bool = typer.Option(False, "--copy", help="Copy rewritten prompt to clipboard"),
|
|
972
|
+
) -> None:
|
|
973
|
+
"""Full prompt diagnostic — score + lint + rewrite in one command.
|
|
974
|
+
|
|
975
|
+
Runs all quality checks and shows a unified report with score breakdown,
|
|
976
|
+
strengths, suggestions, lint issues, and auto-rewrite preview.
|
|
977
|
+
|
|
978
|
+
Examples:
|
|
979
|
+
|
|
980
|
+
reprompt check "fix the auth bug in login.ts"
|
|
981
|
+
|
|
982
|
+
reprompt check "refactor the middleware" --model claude
|
|
983
|
+
|
|
984
|
+
reprompt check "help me debug this crash" --json
|
|
985
|
+
"""
|
|
986
|
+
text = _resolve_text(text, file)
|
|
987
|
+
from reprompt.core.check import check_prompt
|
|
988
|
+
|
|
989
|
+
result = check_prompt(text, model=model, max_tokens=max_tokens)
|
|
990
|
+
|
|
991
|
+
if json_output:
|
|
992
|
+
import json as json_mod
|
|
993
|
+
|
|
994
|
+
data = {
|
|
995
|
+
"total": result.total,
|
|
996
|
+
"tier": result.tier,
|
|
997
|
+
"clarity": result.clarity,
|
|
998
|
+
"context": result.context,
|
|
999
|
+
"position": result.position,
|
|
1000
|
+
"structure": result.structure,
|
|
1001
|
+
"repetition": result.repetition,
|
|
1002
|
+
"word_count": result.word_count,
|
|
1003
|
+
"token_count": result.token_count,
|
|
1004
|
+
"confirmations": result.confirmations,
|
|
1005
|
+
"suggestions": result.suggestions,
|
|
1006
|
+
"lint_issues": result.lint_issues,
|
|
1007
|
+
"rewritten": result.rewritten,
|
|
1008
|
+
"rewrite_delta": result.rewrite_delta,
|
|
1009
|
+
"rewrite_changes": result.rewrite_changes,
|
|
1010
|
+
}
|
|
1011
|
+
typer.echo(json_mod.dumps(data, indent=2, ensure_ascii=False))
|
|
1012
|
+
else:
|
|
1013
|
+
from reprompt.output.check_terminal import render_check
|
|
1014
|
+
|
|
1015
|
+
typer.echo(render_check(result))
|
|
1016
|
+
|
|
1017
|
+
if copy:
|
|
1018
|
+
_copy_to_clip(result.rewritten, quiet=json_output)
|
|
1019
|
+
|
|
1020
|
+
from reprompt.core.suggestions import get_suggestion
|
|
1021
|
+
|
|
1022
|
+
hint = get_suggestion("check")
|
|
1023
|
+
if hint and not json_output:
|
|
1024
|
+
console.print(f" [dim]→ Try: {hint}[/dim]\n")
|
|
1025
|
+
|
|
1026
|
+
|
|
1027
|
+
@app.command(rich_help_panel="Analyze")
|
|
1028
|
+
def explain(
|
|
1029
|
+
text: str = typer.Argument(..., help="Prompt text to explain (use '-' for stdin)"),
|
|
1030
|
+
file: str = typer.Option("", "--file", "-f", help="Read prompt from file"),
|
|
1031
|
+
json_output: bool = typer.Option(False, "--json", help="Output as JSON"),
|
|
1032
|
+
) -> None:
|
|
1033
|
+
"""Explain what makes a prompt good or bad in plain English.
|
|
1034
|
+
|
|
1035
|
+
Analyzes the prompt and provides educational feedback: what's working,
|
|
1036
|
+
what's missing, and specific tips to improve. No LLM needed.
|
|
1037
|
+
|
|
1038
|
+
Examples:
|
|
1039
|
+
|
|
1040
|
+
reprompt explain "fix the auth bug"
|
|
1041
|
+
|
|
1042
|
+
reprompt explain --file prompt.txt --json
|
|
1043
|
+
"""
|
|
1044
|
+
text = _resolve_text(text, file)
|
|
1045
|
+
from reprompt.core.explain import explain_prompt
|
|
1046
|
+
|
|
1047
|
+
result = explain_prompt(text)
|
|
1048
|
+
|
|
1049
|
+
if json_output:
|
|
1050
|
+
import json as json_mod
|
|
1051
|
+
|
|
1052
|
+
data = {
|
|
1053
|
+
"score": result.score,
|
|
1054
|
+
"tier": result.tier,
|
|
1055
|
+
"summary": result.summary,
|
|
1056
|
+
"strengths": result.strengths,
|
|
1057
|
+
"weaknesses": result.weaknesses,
|
|
1058
|
+
"tips": result.tips,
|
|
1059
|
+
}
|
|
1060
|
+
typer.echo(json_mod.dumps(data, indent=2, ensure_ascii=False))
|
|
1061
|
+
else:
|
|
1062
|
+
from reprompt.output.explain_terminal import render_explain
|
|
1063
|
+
|
|
1064
|
+
typer.echo(render_explain(result))
|
|
1065
|
+
|
|
1066
|
+
from reprompt.core.suggestions import get_suggestion
|
|
1067
|
+
|
|
1068
|
+
hint = get_suggestion("explain")
|
|
1069
|
+
if hint and not json_output:
|
|
1070
|
+
console.print(f" [dim]→ Try: {hint}[/dim]\n")
|
|
1071
|
+
|
|
1072
|
+
|
|
949
1073
|
@app.command(rich_help_panel="Analyze")
|
|
950
1074
|
def score(
|
|
951
|
-
text: str = typer.Argument(..., help="Prompt text to score"),
|
|
1075
|
+
text: str = typer.Argument(..., help="Prompt text to score (use '-' for stdin)"),
|
|
1076
|
+
file: str = typer.Option("", "--file", "-f", help="Read prompt from file"),
|
|
952
1077
|
json_output: bool = typer.Option(False, "--json", help="Output as JSON"),
|
|
953
1078
|
copy: bool = typer.Option(False, "--copy", help="Copy result to clipboard"),
|
|
954
1079
|
) -> None:
|
|
@@ -958,10 +1083,11 @@ def score(
|
|
|
958
1083
|
|
|
959
1084
|
reprompt score "Fix the auth bug in login.ts where JWT expires"
|
|
960
1085
|
|
|
961
|
-
reprompt score
|
|
1086
|
+
reprompt score --file prompt.txt --json
|
|
962
1087
|
|
|
963
1088
|
reprompt score "Fix bug" --copy
|
|
964
1089
|
"""
|
|
1090
|
+
text = _resolve_text(text, file)
|
|
965
1091
|
from reprompt.core.cost import estimate_cost, format_cost, model_for_source
|
|
966
1092
|
from reprompt.core.extractors import extract_features
|
|
967
1093
|
from reprompt.core.scorer import score_prompt
|
|
@@ -1069,7 +1195,8 @@ def score(
|
|
|
1069
1195
|
|
|
1070
1196
|
@app.command(rich_help_panel="Optimize")
|
|
1071
1197
|
def compress(
|
|
1072
|
-
text: str = typer.Argument(..., help="Prompt text to compress"),
|
|
1198
|
+
text: str = typer.Argument(..., help="Prompt text to compress (use '-' for stdin)"),
|
|
1199
|
+
file: str = typer.Option("", "--file", "-f", help="Read prompt from file"),
|
|
1073
1200
|
json_output: bool = typer.Option(False, "--json", help="Output as JSON"),
|
|
1074
1201
|
copy: bool = typer.Option(False, "--copy", help="Copy compressed text to clipboard"),
|
|
1075
1202
|
) -> None:
|
|
@@ -1079,10 +1206,11 @@ def compress(
|
|
|
1079
1206
|
|
|
1080
1207
|
reprompt compress "Can you please help me refactor this code?"
|
|
1081
1208
|
|
|
1082
|
-
reprompt compress
|
|
1209
|
+
reprompt compress --file prompt.txt --json
|
|
1083
1210
|
|
|
1084
1211
|
reprompt compress "verbose prompt here" --copy
|
|
1085
1212
|
"""
|
|
1213
|
+
text = _resolve_text(text, file)
|
|
1086
1214
|
from reprompt.core.compress import compress_text
|
|
1087
1215
|
|
|
1088
1216
|
result = compress_text(text)
|
|
@@ -1103,7 +1231,8 @@ def compress(
|
|
|
1103
1231
|
|
|
1104
1232
|
@app.command(rich_help_panel="Optimize")
|
|
1105
1233
|
def rewrite(
|
|
1106
|
-
text: str = typer.Argument(..., help="Prompt text to improve"),
|
|
1234
|
+
text: str = typer.Argument(..., help="Prompt text to improve (use '-' for stdin)"),
|
|
1235
|
+
file: str = typer.Option("", "--file", "-f", help="Read prompt from file"),
|
|
1107
1236
|
json_output: bool = typer.Option(False, "--json", help="Output as JSON"),
|
|
1108
1237
|
diff: bool = typer.Option(False, "--diff", help="Show unified diff (red/green)"),
|
|
1109
1238
|
copy: bool = typer.Option(False, "--copy", help="Copy rewritten text to clipboard"),
|
|
@@ -1118,10 +1247,11 @@ def rewrite(
|
|
|
1118
1247
|
|
|
1119
1248
|
reprompt rewrite "I was wondering if you could fix the authentication bug"
|
|
1120
1249
|
|
|
1121
|
-
reprompt rewrite
|
|
1250
|
+
reprompt rewrite --file prompt.txt --diff
|
|
1122
1251
|
|
|
1123
1252
|
reprompt rewrite "please help me refactor this code to be better" --copy
|
|
1124
1253
|
"""
|
|
1254
|
+
text = _resolve_text(text, file)
|
|
1125
1255
|
from reprompt.core.rewrite import rewrite_prompt
|
|
1126
1256
|
|
|
1127
1257
|
result = rewrite_prompt(text)
|
|
@@ -1158,6 +1288,73 @@ def rewrite(
|
|
|
1158
1288
|
console.print(f" [dim]→ Try: {hint}[/dim]\n")
|
|
1159
1289
|
|
|
1160
1290
|
|
|
1291
|
+
@app.command(rich_help_panel="Optimize")
|
|
1292
|
+
def build(
|
|
1293
|
+
task: str = typer.Argument(..., help="What the AI should do"),
|
|
1294
|
+
context: str = typer.Option("", "--context", "-c", help="Background information"),
|
|
1295
|
+
file: list[str] = typer.Option([], "--file", "-f", help="File references (repeatable)"),
|
|
1296
|
+
error: str = typer.Option("", "--error", "-e", help="Error message or stack trace"),
|
|
1297
|
+
constraint: list[str] = typer.Option([], "--constraint", help="Constraints (repeatable)"),
|
|
1298
|
+
example: str = typer.Option("", "--example", help="Example input/output"),
|
|
1299
|
+
output_format: str = typer.Option("", "--output-format", help="Expected response format"),
|
|
1300
|
+
role: str = typer.Option("", "--role", "-r", help="AI role/persona"),
|
|
1301
|
+
model: str = typer.Option("", "--model", "-m", help="Target model (claude/gpt/gemini)"),
|
|
1302
|
+
json_output: bool = typer.Option(False, "--json", help="Output as JSON"),
|
|
1303
|
+
copy: bool = typer.Option(False, "--copy", help="Copy built prompt to clipboard"),
|
|
1304
|
+
) -> None:
|
|
1305
|
+
"""Build a well-structured prompt from components.
|
|
1306
|
+
|
|
1307
|
+
Assembles a prompt that maximizes quality score by combining
|
|
1308
|
+
your task with context, files, errors, and constraints.
|
|
1309
|
+
|
|
1310
|
+
Examples:
|
|
1311
|
+
|
|
1312
|
+
reprompt build "fix the auth bug"
|
|
1313
|
+
|
|
1314
|
+
reprompt build "fix the crash" --file src/auth.ts --error "TypeError: ..."
|
|
1315
|
+
|
|
1316
|
+
reprompt build "refactor" -f src/app.py --constraint "keep tests" --model claude
|
|
1317
|
+
"""
|
|
1318
|
+
from reprompt.core.build import build_prompt
|
|
1319
|
+
|
|
1320
|
+
result = build_prompt(
|
|
1321
|
+
task,
|
|
1322
|
+
context=context,
|
|
1323
|
+
files=file if file else None,
|
|
1324
|
+
error=error,
|
|
1325
|
+
constraints=constraint if constraint else None,
|
|
1326
|
+
examples=example,
|
|
1327
|
+
output_format=output_format,
|
|
1328
|
+
role=role,
|
|
1329
|
+
model=model,
|
|
1330
|
+
)
|
|
1331
|
+
|
|
1332
|
+
if json_output:
|
|
1333
|
+
import json as json_mod
|
|
1334
|
+
|
|
1335
|
+
data = {
|
|
1336
|
+
"prompt": result.prompt,
|
|
1337
|
+
"score": result.score,
|
|
1338
|
+
"tier": result.tier,
|
|
1339
|
+
"components_used": result.components_used,
|
|
1340
|
+
"suggestions": result.suggestions,
|
|
1341
|
+
}
|
|
1342
|
+
typer.echo(json_mod.dumps(data, indent=2, ensure_ascii=False))
|
|
1343
|
+
else:
|
|
1344
|
+
from reprompt.output.build_terminal import render_build
|
|
1345
|
+
|
|
1346
|
+
typer.echo(render_build(result))
|
|
1347
|
+
|
|
1348
|
+
if copy:
|
|
1349
|
+
_copy_to_clip(result.prompt, quiet=json_output)
|
|
1350
|
+
|
|
1351
|
+
from reprompt.core.suggestions import get_suggestion
|
|
1352
|
+
|
|
1353
|
+
hint = get_suggestion("build")
|
|
1354
|
+
if hint and not json_output:
|
|
1355
|
+
console.print(f" [dim]→ Try: {hint}[/dim]\n")
|
|
1356
|
+
|
|
1357
|
+
|
|
1161
1358
|
@app.command(rich_help_panel="Optimize")
|
|
1162
1359
|
def distill(
|
|
1163
1360
|
session_id: str = typer.Argument(None, help="Session ID to distill"),
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
"""Prompt builder — assemble a well-structured prompt from components.
|
|
2
|
+
|
|
3
|
+
Takes a task description and optional context, files, errors, constraints,
|
|
4
|
+
and examples, then assembles a prompt that maximizes the scoring dimensions.
|
|
5
|
+
Scoring-aware: structures the output to hit clarity, context, and position.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class BuildResult:
|
|
15
|
+
"""Result of building a prompt from components."""
|
|
16
|
+
|
|
17
|
+
prompt: str
|
|
18
|
+
score: float = 0.0
|
|
19
|
+
tier: str = ""
|
|
20
|
+
components_used: list[str] = field(default_factory=list)
|
|
21
|
+
suggestions: list[str] = field(default_factory=list)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def build_prompt(
|
|
25
|
+
task: str,
|
|
26
|
+
*,
|
|
27
|
+
context: str = "",
|
|
28
|
+
files: list[str] | None = None,
|
|
29
|
+
error: str = "",
|
|
30
|
+
constraints: list[str] | None = None,
|
|
31
|
+
examples: str = "",
|
|
32
|
+
output_format: str = "",
|
|
33
|
+
role: str = "",
|
|
34
|
+
model: str = "",
|
|
35
|
+
) -> BuildResult:
|
|
36
|
+
"""Build a well-structured prompt from components.
|
|
37
|
+
|
|
38
|
+
Returns the assembled prompt with its score and suggestions
|
|
39
|
+
for components the user could still add.
|
|
40
|
+
"""
|
|
41
|
+
parts: list[str] = []
|
|
42
|
+
components: list[str] = []
|
|
43
|
+
|
|
44
|
+
# Role (if provided) — goes first
|
|
45
|
+
if role:
|
|
46
|
+
parts.append(f"You are {role}.")
|
|
47
|
+
components.append("role")
|
|
48
|
+
|
|
49
|
+
# Task — always present, imperative form, at the front (position bias)
|
|
50
|
+
task_text = _ensure_imperative(task.strip())
|
|
51
|
+
if task_text and task_text[-1] not in ".!?":
|
|
52
|
+
task_text += "."
|
|
53
|
+
parts.append(task_text)
|
|
54
|
+
components.append("task")
|
|
55
|
+
|
|
56
|
+
# File references — high context value
|
|
57
|
+
if files:
|
|
58
|
+
if len(files) == 1:
|
|
59
|
+
parts.append(f"File: {files[0]}")
|
|
60
|
+
else:
|
|
61
|
+
file_list = ", ".join(files)
|
|
62
|
+
parts.append(f"Files: {file_list}")
|
|
63
|
+
components.append("files")
|
|
64
|
+
|
|
65
|
+
# Error context — critical for debug prompts
|
|
66
|
+
if error:
|
|
67
|
+
parts.append(f"Error: {error}")
|
|
68
|
+
components.append("error")
|
|
69
|
+
|
|
70
|
+
# Context — background information
|
|
71
|
+
if context:
|
|
72
|
+
parts.append(f"Context: {context}")
|
|
73
|
+
components.append("context")
|
|
74
|
+
|
|
75
|
+
# Examples
|
|
76
|
+
if examples:
|
|
77
|
+
parts.append(f"Example:\n{examples}")
|
|
78
|
+
components.append("examples")
|
|
79
|
+
|
|
80
|
+
# Constraints
|
|
81
|
+
if constraints:
|
|
82
|
+
if len(constraints) == 1:
|
|
83
|
+
parts.append(f"Constraint: {constraints[0]}")
|
|
84
|
+
else:
|
|
85
|
+
constraint_lines = "\n".join(f"- {c}" for c in constraints)
|
|
86
|
+
parts.append(f"Constraints:\n{constraint_lines}")
|
|
87
|
+
components.append("constraints")
|
|
88
|
+
|
|
89
|
+
# Output format
|
|
90
|
+
if output_format:
|
|
91
|
+
parts.append(f"Output format: {output_format}")
|
|
92
|
+
components.append("output_format")
|
|
93
|
+
|
|
94
|
+
# Model-specific formatting
|
|
95
|
+
prompt = _format_for_model(parts, model)
|
|
96
|
+
|
|
97
|
+
# Score the assembled prompt
|
|
98
|
+
from reprompt.core.extractors import extract_features
|
|
99
|
+
from reprompt.core.scorer import score_prompt
|
|
100
|
+
|
|
101
|
+
dna = extract_features(prompt, source="build", session_id="")
|
|
102
|
+
score_result = score_prompt(dna)
|
|
103
|
+
|
|
104
|
+
# Determine tier
|
|
105
|
+
tier = _get_tier(score_result.total)
|
|
106
|
+
|
|
107
|
+
# Generate suggestions for missing components
|
|
108
|
+
suggestions = _missing_suggestions(components)
|
|
109
|
+
|
|
110
|
+
return BuildResult(
|
|
111
|
+
prompt=prompt,
|
|
112
|
+
score=score_result.total,
|
|
113
|
+
tier=tier,
|
|
114
|
+
components_used=components,
|
|
115
|
+
suggestions=suggestions,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _ensure_imperative(task: str) -> str:
|
|
120
|
+
"""Strip filler prefixes to get an imperative task statement."""
|
|
121
|
+
import re
|
|
122
|
+
|
|
123
|
+
# Remove common polite/filler prefixes
|
|
124
|
+
cleaned = re.sub(
|
|
125
|
+
r"^(?:please\s+|can you\s+|could you\s+|i need you to\s+|"
|
|
126
|
+
r"i want you to\s+|i would like you to\s+|help me\s+|"
|
|
127
|
+
r"i was wondering if you could\s+)",
|
|
128
|
+
"",
|
|
129
|
+
task,
|
|
130
|
+
flags=re.IGNORECASE,
|
|
131
|
+
)
|
|
132
|
+
# Capitalize first letter
|
|
133
|
+
if cleaned:
|
|
134
|
+
cleaned = cleaned[0].upper() + cleaned[1:]
|
|
135
|
+
return cleaned
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _format_for_model(parts: list[str], model: str) -> str:
|
|
139
|
+
"""Format prompt parts with model-appropriate structure."""
|
|
140
|
+
if model == "claude":
|
|
141
|
+
return _format_xml(parts)
|
|
142
|
+
elif model == "gpt":
|
|
143
|
+
return _format_markdown(parts)
|
|
144
|
+
else:
|
|
145
|
+
# Default: clean plain text with double newlines
|
|
146
|
+
return "\n\n".join(parts)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _format_xml(parts: list[str]) -> str:
|
|
150
|
+
"""Format with XML tags (preferred by Claude)."""
|
|
151
|
+
if len(parts) <= 2:
|
|
152
|
+
# Short prompts don't need XML
|
|
153
|
+
return "\n\n".join(parts)
|
|
154
|
+
|
|
155
|
+
sections: list[str] = []
|
|
156
|
+
for part in parts:
|
|
157
|
+
lower = part.lower()
|
|
158
|
+
if lower.startswith("you are "):
|
|
159
|
+
sections.append(part)
|
|
160
|
+
elif lower.startswith("context:"):
|
|
161
|
+
content = part[len("Context:") :].strip()
|
|
162
|
+
sections.append(f"<context>\n{content}\n</context>")
|
|
163
|
+
elif lower.startswith("error:"):
|
|
164
|
+
content = part[len("Error:") :].strip()
|
|
165
|
+
sections.append(f"<context>\n{content}\n</context>")
|
|
166
|
+
elif lower.startswith("constraint"):
|
|
167
|
+
content = part.split(":", 1)[1].strip() if ":" in part else part
|
|
168
|
+
sections.append(f"<constraints>\n{content}\n</constraints>")
|
|
169
|
+
elif lower.startswith("example"):
|
|
170
|
+
content = part.split(":", 1)[1].strip() if ":" in part else part
|
|
171
|
+
content = part.split("\n", 1)[1].strip() if "\n" in part else content
|
|
172
|
+
sections.append(f"<examples>\n{content}\n</examples>")
|
|
173
|
+
elif lower.startswith("output format:"):
|
|
174
|
+
content = part[len("Output format:") :].strip()
|
|
175
|
+
sections.append(f"<output>\n{content}\n</output>")
|
|
176
|
+
else:
|
|
177
|
+
sections.append(part)
|
|
178
|
+
|
|
179
|
+
return "\n\n".join(sections)
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def _format_markdown(parts: list[str]) -> str:
|
|
183
|
+
"""Format with markdown headers (preferred by GPT)."""
|
|
184
|
+
if len(parts) <= 2:
|
|
185
|
+
return "\n\n".join(parts)
|
|
186
|
+
|
|
187
|
+
sections: list[str] = []
|
|
188
|
+
for part in parts:
|
|
189
|
+
lower = part.lower()
|
|
190
|
+
if lower.startswith("you are "):
|
|
191
|
+
sections.append(part)
|
|
192
|
+
elif lower.startswith("context:"):
|
|
193
|
+
content = part[len("Context:") :].strip()
|
|
194
|
+
sections.append(f"## Context\n{content}")
|
|
195
|
+
elif lower.startswith("error:"):
|
|
196
|
+
content = part[len("Error:") :].strip()
|
|
197
|
+
sections.append(f"## Error\n{content}")
|
|
198
|
+
elif lower.startswith("constraint"):
|
|
199
|
+
content = part.split(":", 1)[1].strip() if ":" in part else part
|
|
200
|
+
sections.append(f"## Constraints\n{content}")
|
|
201
|
+
elif lower.startswith("example"):
|
|
202
|
+
content = part.split(":", 1)[1].strip() if ":" in part else part
|
|
203
|
+
content = part.split("\n", 1)[1].strip() if "\n" in part else content
|
|
204
|
+
sections.append(f"## Examples\n{content}")
|
|
205
|
+
elif lower.startswith("output format:"):
|
|
206
|
+
content = part[len("Output format:") :].strip()
|
|
207
|
+
sections.append(f"## Output Format\n{content}")
|
|
208
|
+
else:
|
|
209
|
+
sections.append(part)
|
|
210
|
+
|
|
211
|
+
return "\n\n".join(sections)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def _get_tier(score: float) -> str:
|
|
215
|
+
"""Map score to tier label."""
|
|
216
|
+
if score >= 85:
|
|
217
|
+
return "EXPERT"
|
|
218
|
+
if score >= 70:
|
|
219
|
+
return "STRONG"
|
|
220
|
+
if score >= 50:
|
|
221
|
+
return "GOOD"
|
|
222
|
+
if score >= 30:
|
|
223
|
+
return "BASIC"
|
|
224
|
+
return "DRAFT"
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def _missing_suggestions(components: list[str]) -> list[str]:
|
|
228
|
+
"""Suggest components the user could add to improve the prompt."""
|
|
229
|
+
suggestions: list[str] = []
|
|
230
|
+
|
|
231
|
+
if "files" not in components:
|
|
232
|
+
suggestions.append("Add --file to reference specific files (+6 pts)")
|
|
233
|
+
if "error" not in components:
|
|
234
|
+
suggestions.append("Add --error with the actual error message (+6 pts)")
|
|
235
|
+
if "constraints" not in components:
|
|
236
|
+
suggestions.append("Add --constraint to set boundaries (+5 pts)")
|
|
237
|
+
if "context" not in components:
|
|
238
|
+
suggestions.append("Add --context for background information (+4 pts)")
|
|
239
|
+
if "examples" not in components:
|
|
240
|
+
suggestions.append("Add --example with expected input/output (+3 pts)")
|
|
241
|
+
if "role" not in components:
|
|
242
|
+
suggestions.append("Add --role to set the AI's perspective (+3 pts)")
|
|
243
|
+
if "output_format" not in components:
|
|
244
|
+
suggestions.append("Add --output-format to specify response structure (+2 pts)")
|
|
245
|
+
|
|
246
|
+
return suggestions
|