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