reprompt-cli 1.9.1__tar.gz → 1.10.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-1.9.1 → reprompt_cli-1.10.0}/PKG-INFO +23 -2
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/README.md +22 -1
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/pyproject.toml +1 -1
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/__init__.py +1 -1
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/cli.py +111 -0
- reprompt_cli-1.10.0/src/reprompt/core/rewrite.py +221 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/suggestions.py +2 -0
- reprompt_cli-1.10.0/src/reprompt/output/rewrite_terminal.py +69 -0
- reprompt_cli-1.10.0/tests/test_init_cli.py +80 -0
- reprompt_cli-1.10.0/tests/test_rewrite.py +157 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_suggestions.py +4 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/uv.lock +1 -1
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/.editorconfig +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/.github/dependabot.yml +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/.github/workflows/ci.yml +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/.github/workflows/publish.yml +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/.gitignore +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/.pre-commit-config.yaml +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/.pre-commit-hooks.yaml +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/.testmondata-shm +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/.testmondata-wal +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/CHANGELOG.md +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/CODE_OF_CONDUCT.md +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/CONTRIBUTING.md +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/LICENSE +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/SECURITY.md +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/Screenshot 2026-03-24 at 09.45.03.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/action.yml +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/demo.gif +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/brand-icon-128.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/brand-icon-16.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/brand-icon-256.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/brand-icon-32.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/brand-icon-48.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/brand-icon-512.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/brand-icon-96.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/brand-icon.svg +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/cli-favicon-128.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/cli-favicon-16.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/cli-favicon-256.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/cli-favicon-32.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/cli-favicon-48.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/cli-favicon-512.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/cli-favicon-96.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/cli-favicon.svg +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/cli-icon-128.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/cli-icon-16.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/cli-icon-256.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/cli-icon-32.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/cli-icon-48.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/cli-icon-512.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/cli-icon-96.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/cli-icon.svg +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/favicon-128.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/favicon-16.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/favicon-256.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/favicon-32.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/favicon-48.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/favicon-512.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/favicon-96.png +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/favicon.svg +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/icons/generate.sh +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/superpowers/specs/2026-03-24-v14-command-consolidation-design.md +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/docs/superpowers/specs/2026-03-25-v1.5-dashboard-design.md +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/scripts/generate_demo_data.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/adapters/__init__.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/adapters/aider.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/adapters/base.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/adapters/chatgpt.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/adapters/claude_chat.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/adapters/claude_code.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/adapters/cline.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/adapters/codex.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/adapters/cursor.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/adapters/filters.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/adapters/gemini.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/adapters/openclaw.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/bridge/__init__.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/bridge/handler.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/bridge/host.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/bridge/manifest.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/bridge/protocol.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/commands/__init__.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/commands/telemetry.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/commands/wrapped.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/config.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/__init__.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/agent.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/analyzer.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/compress.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/conversation.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/cost.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/dashboard.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/dedup.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/digest.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/distill.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/effectiveness.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/extractors.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/extractors_zh.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/insights.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/lang_detect.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/library.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/lint.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/merge_view.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/models.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/persona.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/pipeline.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/privacy.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/privacy_scan.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/prompt_dna.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/recommend.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/repetition.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/scorer.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/segmenter.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/session_meta.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/session_quality.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/session_type.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/style.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/templates.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/timeutil.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/trends.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/core/wrapped.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/demo.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/embeddings/__init__.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/embeddings/base.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/embeddings/local_embed.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/embeddings/ollama.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/embeddings/openai_embed.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/embeddings/tfidf.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/mcp.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/mcp_main.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/output/__init__.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/output/agent_terminal.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/output/chartjs.min.js +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/output/compress_terminal.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/output/dashboard_terminal.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/output/distill_terminal.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/output/export.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/output/html_report.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/output/json_out.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/output/markdown.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/output/repetition_terminal.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/output/sessions_terminal.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/output/terminal.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/output/wrapped_html.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/output/wrapped_terminal.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/py.typed +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/sharing/__init__.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/sharing/client.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/sharing/clipboard.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/storage/__init__.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/storage/db.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/telemetry/__init__.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/telemetry/collector.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/telemetry/consent.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/telemetry/events.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/telemetry/prompt.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/telemetry/queue.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/src/reprompt/telemetry/sender.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/__init__.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/conftest.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/fixtures/aider_chat_history.md +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/fixtures/chatgpt_conversations.json +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/fixtures/claude_chat_export.json +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/fixtures/claude_session.jsonl +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/fixtures/cline_task/api_conversation_history.json +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/fixtures/export/default_export.md +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/fixtures/export/full_export.md +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/fixtures/gemini_session.json +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/fixtures/openclaw_session.jsonl +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_adapter_aider.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_adapter_chatgpt.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_adapter_claude.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_adapter_claude_chat.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_adapter_cline.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_adapter_gemini.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_adapter_openclaw.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_agent.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_agent_cli.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_analyzer.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_bridge_cli.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_bridge_e2e.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_bridge_handler.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_bridge_integration.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_bridge_manifest.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_bridge_protocol.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_cli.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_cli_deprecations.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_cli_library_effectiveness.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_clipboard.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_codex_adapter.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_compare_best_worst.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_compress.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_compress_cli.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_compress_dna.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_compress_html.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_compress_insights.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_config.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_conversation.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_copy_flag.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_cost.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_coverage_boost.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_cursor_adapter.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_dashboard.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_db.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_db_digest.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_db_effectiveness.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_db_session_quality.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_db_trends.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_dedup.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_demo.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_deprecated_commands.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_digest.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_digest_cli.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_distill.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_distill_cli.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_distill_weights.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_e2e.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_effectiveness.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_embeddings_local.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_embeddings_ollama.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_embeddings_openai.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_empty_state.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_export.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_export_cli.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_export_snapshot.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_extractors.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_extractors_routing.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_extractors_zh.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_extractors_zh_e2e.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_html_report.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_import_cli.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_import_e2e.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_insights.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_insights_cli.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_insights_expanded.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_install_hook.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_lang_detect.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_library.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_lint.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_lint_cli.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_markdown.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_mcp.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_merge_view.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_models.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_output.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_parse_conversation_base.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_parse_conversation_chatgpt.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_parse_conversation_claude.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_persona.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_pipeline.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_privacy.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_privacy_cli.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_privacy_e2e.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_privacy_output.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_privacy_scan.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_prompt_dna.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_public_api.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_recommend.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_repetition.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_repetition_cli.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_repetition_output.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_schema_version.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_score_cli.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_scorer.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_segmenter.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_session_quality.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_session_type.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_sessions_cli.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_sessions_output.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_share_e2e.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_sharing_client.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_source_filter.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_style.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_style_trends.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_telemetry_cli.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_telemetry_collector.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_telemetry_consent.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_telemetry_e2e.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_telemetry_events.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_telemetry_prompt.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_telemetry_queue.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_telemetry_sender.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_template_cli.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_templates.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_timeutil.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_trends.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_trends_cli.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_use_cli.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_wrapped.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_wrapped_cli.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_wrapped_e2e.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_wrapped_html.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_wrapped_output.py +0 -0
- {reprompt_cli-1.9.1 → reprompt_cli-1.10.0}/tests/test_wrapped_share.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: reprompt-cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.10.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
|
|
@@ -96,6 +96,8 @@ $ reprompt compress "I was wondering if you could please help me refactor this c
|
|
|
96
96
|
| `reprompt insights` | Personal patterns vs research-optimal benchmarks |
|
|
97
97
|
| `reprompt style` | Prompting fingerprint with `--trends` for evolution tracking |
|
|
98
98
|
| `reprompt agent` | Agent workflow analysis -- error loops, tool patterns, session efficiency |
|
|
99
|
+
| `reprompt sessions` | Session quality scores with frustration signal detection |
|
|
100
|
+
| `reprompt repetition` | Cross-session repetition detection -- spot recurring prompts |
|
|
99
101
|
|
|
100
102
|
### Optimize
|
|
101
103
|
|
|
@@ -104,7 +106,8 @@ $ reprompt compress "I was wondering if you could please help me refactor this c
|
|
|
104
106
|
| `reprompt compress "prompt"` | 4-layer prompt compression (40-60% token savings typical) |
|
|
105
107
|
| `reprompt distill` | Extract important turns from conversations with 6-signal scoring |
|
|
106
108
|
| `reprompt distill --export` | Recover context when a session runs out -- paste into new session |
|
|
107
|
-
| `reprompt lint` |
|
|
109
|
+
| `reprompt lint` | Configurable prompt quality linter with CI/GitHub Action support |
|
|
110
|
+
| `reprompt init` | Generate `.reprompt.toml` config for your project |
|
|
108
111
|
|
|
109
112
|
### Manage
|
|
110
113
|
|
|
@@ -223,6 +226,24 @@ reprompt lint --strict # exit 1 on warnings
|
|
|
223
226
|
reprompt lint --json # machine-readable output
|
|
224
227
|
```
|
|
225
228
|
|
|
229
|
+
#### Project configuration
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
reprompt init # generates .reprompt.toml with all rules documented
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
```toml
|
|
236
|
+
# .reprompt.toml (or [tool.reprompt.lint] in pyproject.toml)
|
|
237
|
+
[lint]
|
|
238
|
+
score-threshold = 50 # fail if avg score < 50
|
|
239
|
+
|
|
240
|
+
[lint.rules]
|
|
241
|
+
min-length = 20 # error if prompt < 20 chars (0 = off)
|
|
242
|
+
short-prompt = 40 # warning if < 40 chars (0 = off)
|
|
243
|
+
vague-prompt = true # error on "fix it" etc (false = off)
|
|
244
|
+
debug-needs-reference = true
|
|
245
|
+
```
|
|
246
|
+
|
|
226
247
|
## Privacy
|
|
227
248
|
|
|
228
249
|
- All analysis runs locally. No prompts leave your machine.
|
|
@@ -51,6 +51,8 @@ $ reprompt compress "I was wondering if you could please help me refactor this c
|
|
|
51
51
|
| `reprompt insights` | Personal patterns vs research-optimal benchmarks |
|
|
52
52
|
| `reprompt style` | Prompting fingerprint with `--trends` for evolution tracking |
|
|
53
53
|
| `reprompt agent` | Agent workflow analysis -- error loops, tool patterns, session efficiency |
|
|
54
|
+
| `reprompt sessions` | Session quality scores with frustration signal detection |
|
|
55
|
+
| `reprompt repetition` | Cross-session repetition detection -- spot recurring prompts |
|
|
54
56
|
|
|
55
57
|
### Optimize
|
|
56
58
|
|
|
@@ -59,7 +61,8 @@ $ reprompt compress "I was wondering if you could please help me refactor this c
|
|
|
59
61
|
| `reprompt compress "prompt"` | 4-layer prompt compression (40-60% token savings typical) |
|
|
60
62
|
| `reprompt distill` | Extract important turns from conversations with 6-signal scoring |
|
|
61
63
|
| `reprompt distill --export` | Recover context when a session runs out -- paste into new session |
|
|
62
|
-
| `reprompt lint` |
|
|
64
|
+
| `reprompt lint` | Configurable prompt quality linter with CI/GitHub Action support |
|
|
65
|
+
| `reprompt init` | Generate `.reprompt.toml` config for your project |
|
|
63
66
|
|
|
64
67
|
### Manage
|
|
65
68
|
|
|
@@ -178,6 +181,24 @@ reprompt lint --strict # exit 1 on warnings
|
|
|
178
181
|
reprompt lint --json # machine-readable output
|
|
179
182
|
```
|
|
180
183
|
|
|
184
|
+
#### Project configuration
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
reprompt init # generates .reprompt.toml with all rules documented
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
```toml
|
|
191
|
+
# .reprompt.toml (or [tool.reprompt.lint] in pyproject.toml)
|
|
192
|
+
[lint]
|
|
193
|
+
score-threshold = 50 # fail if avg score < 50
|
|
194
|
+
|
|
195
|
+
[lint.rules]
|
|
196
|
+
min-length = 20 # error if prompt < 20 chars (0 = off)
|
|
197
|
+
short-prompt = 40 # warning if < 40 chars (0 = off)
|
|
198
|
+
vague-prompt = true # error on "fix it" etc (false = off)
|
|
199
|
+
debug-needs-reference = true
|
|
200
|
+
```
|
|
201
|
+
|
|
181
202
|
## Privacy
|
|
182
203
|
|
|
183
204
|
- All analysis runs locally. No prompts leave your machine.
|
|
@@ -1065,6 +1065,58 @@ def compress(
|
|
|
1065
1065
|
_copy_to_clip(result.compressed, quiet=json_output)
|
|
1066
1066
|
|
|
1067
1067
|
|
|
1068
|
+
@app.command(rich_help_panel="Optimize")
|
|
1069
|
+
def rewrite(
|
|
1070
|
+
text: str = typer.Argument(..., help="Prompt text to improve"),
|
|
1071
|
+
json_output: bool = typer.Option(False, "--json", help="Output as JSON"),
|
|
1072
|
+
copy: bool = typer.Option(False, "--copy", help="Copy rewritten text to clipboard"),
|
|
1073
|
+
) -> None:
|
|
1074
|
+
"""Rewrite a prompt to improve its score. Rule-based, no LLM needed.
|
|
1075
|
+
|
|
1076
|
+
Applies 4 layers: filler removal, instruction front-loading,
|
|
1077
|
+
key requirement echo, and hedging cleanup. Also suggests manual
|
|
1078
|
+
improvements you can make.
|
|
1079
|
+
|
|
1080
|
+
Examples:
|
|
1081
|
+
|
|
1082
|
+
reprompt rewrite "I was wondering if you could fix the authentication bug"
|
|
1083
|
+
|
|
1084
|
+
reprompt rewrite "please help me refactor this code to be better" --copy
|
|
1085
|
+
|
|
1086
|
+
reprompt rewrite "fix the login" --json
|
|
1087
|
+
"""
|
|
1088
|
+
from reprompt.core.rewrite import rewrite_prompt
|
|
1089
|
+
|
|
1090
|
+
result = rewrite_prompt(text)
|
|
1091
|
+
|
|
1092
|
+
if json_output:
|
|
1093
|
+
import json as json_mod
|
|
1094
|
+
|
|
1095
|
+
data = {
|
|
1096
|
+
"original": result.original,
|
|
1097
|
+
"rewritten": result.rewritten,
|
|
1098
|
+
"score_before": result.score_before,
|
|
1099
|
+
"score_after": result.score_after,
|
|
1100
|
+
"score_delta": result.score_delta,
|
|
1101
|
+
"changes": result.changes,
|
|
1102
|
+
"manual_suggestions": result.manual_suggestions,
|
|
1103
|
+
}
|
|
1104
|
+
typer.echo(json_mod.dumps(data, indent=2, ensure_ascii=False))
|
|
1105
|
+
else:
|
|
1106
|
+
from reprompt.output.rewrite_terminal import render_rewrite
|
|
1107
|
+
|
|
1108
|
+
typer.echo(render_rewrite(result))
|
|
1109
|
+
|
|
1110
|
+
if copy:
|
|
1111
|
+
_copy_to_clip(result.rewritten, quiet=json_output)
|
|
1112
|
+
|
|
1113
|
+
from reprompt.core.suggestions import get_suggestion
|
|
1114
|
+
|
|
1115
|
+
hint = get_suggestion("rewrite")
|
|
1116
|
+
if hint and not json_output:
|
|
1117
|
+
console.print(f" [dim]→ Try: {hint}[/dim]\n")
|
|
1118
|
+
|
|
1119
|
+
|
|
1068
1120
|
@app.command(rich_help_panel="Optimize")
|
|
1069
1121
|
def distill(
|
|
1070
1122
|
session_id: str = typer.Argument(None, help="Session ID to distill"),
|
|
@@ -1935,6 +1987,65 @@ def extension_status() -> None:
|
|
|
1935
1987
|
console.print(" Last sync: never")
|
|
1936
1988
|
|
|
1937
1989
|
|
|
1990
|
+
@app.command(rich_help_panel="Setup")
|
|
1991
|
+
def init(
|
|
1992
|
+
force: bool = typer.Option(False, "--force", "-f", help="Overwrite existing config"),
|
|
1993
|
+
) -> None:
|
|
1994
|
+
"""Generate a .reprompt.toml config file in the current directory.
|
|
1995
|
+
|
|
1996
|
+
Creates a starter config with all lint rules documented and commented.
|
|
1997
|
+
Use this to customize reprompt for your project or CI pipeline.
|
|
1998
|
+
|
|
1999
|
+
Examples:
|
|
2000
|
+
|
|
2001
|
+
reprompt init # create .reprompt.toml
|
|
2002
|
+
|
|
2003
|
+
reprompt init --force # overwrite existing config
|
|
2004
|
+
"""
|
|
2005
|
+
config_path = Path.cwd() / ".reprompt.toml"
|
|
2006
|
+
|
|
2007
|
+
if config_path.exists() and not force:
|
|
2008
|
+
console.print(
|
|
2009
|
+
f"[yellow]{config_path.name} already exists.[/yellow]"
|
|
2010
|
+
" Use [bold]--force[/bold] to overwrite."
|
|
2011
|
+
)
|
|
2012
|
+
raise typer.Exit(1)
|
|
2013
|
+
|
|
2014
|
+
config_content = """\
|
|
2015
|
+
# reprompt configuration
|
|
2016
|
+
# Docs: https://github.com/reprompt-dev/reprompt
|
|
2017
|
+
#
|
|
2018
|
+
# This file configures `reprompt lint` rules and CI thresholds.
|
|
2019
|
+
# Place in your project root — reprompt walks up from CWD to find it.
|
|
2020
|
+
# Alternatively, add [tool.reprompt.lint] to pyproject.toml.
|
|
2021
|
+
|
|
2022
|
+
[lint]
|
|
2023
|
+
# Fail `reprompt lint` if average prompt score < threshold (0 = disabled)
|
|
2024
|
+
# Useful for CI: reprompt lint --score-threshold reads this value
|
|
2025
|
+
# score-threshold = 50
|
|
2026
|
+
|
|
2027
|
+
[lint.rules]
|
|
2028
|
+
# min-length: error if prompt < N chars (0 = disabled)
|
|
2029
|
+
min-length = 20
|
|
2030
|
+
|
|
2031
|
+
# short-prompt: warning if prompt < N chars (0 = disabled)
|
|
2032
|
+
short-prompt = 40
|
|
2033
|
+
|
|
2034
|
+
# vague-prompt: error on vague prompts like "fix it" (false = disabled)
|
|
2035
|
+
vague-prompt = true
|
|
2036
|
+
|
|
2037
|
+
# debug-needs-reference: warning if debug prompt lacks file reference (false = disabled)
|
|
2038
|
+
debug-needs-reference = true
|
|
2039
|
+
|
|
2040
|
+
# file-extensions: extensions recognized as file references
|
|
2041
|
+
# file-extensions = [".py", ".ts", ".js", ".go", ".rs", ".java", ".rb", ".cpp", ".c"]
|
|
2042
|
+
"""
|
|
2043
|
+
|
|
2044
|
+
config_path.write_text(config_content)
|
|
2045
|
+
console.print(f"[green]Created[/green] {config_path.name}")
|
|
2046
|
+
console.print(" Edit rules, then run [bold]reprompt lint[/bold] to verify.")
|
|
2047
|
+
|
|
2048
|
+
|
|
1938
2049
|
@app.command(rich_help_panel="Analyze")
|
|
1939
2050
|
def sessions(
|
|
1940
2051
|
last: int = typer.Option(10, "--last", help="Show N most recent sessions"),
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"""Rule-based prompt rewrite engine.
|
|
2
|
+
|
|
3
|
+
Transforms low-scoring prompts into better versions using research-backed
|
|
4
|
+
rules. No LLM required — pure regex + structural transforms.
|
|
5
|
+
|
|
6
|
+
Layers:
|
|
7
|
+
1. Compress — remove filler (reuse compress engine)
|
|
8
|
+
2. Restructure — front-load instructions (move imperative to start)
|
|
9
|
+
3. Reinforce — echo key requirement at end for long prompts
|
|
10
|
+
4. Annotate — suggest what the user should add manually
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import re
|
|
16
|
+
from dataclasses import dataclass, field
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class RewriteResult:
|
|
21
|
+
"""Result of rewriting a prompt."""
|
|
22
|
+
|
|
23
|
+
original: str
|
|
24
|
+
rewritten: str
|
|
25
|
+
changes: list[str] = field(default_factory=list)
|
|
26
|
+
manual_suggestions: list[str] = field(default_factory=list)
|
|
27
|
+
score_before: float = 0.0
|
|
28
|
+
score_after: float = 0.0
|
|
29
|
+
score_delta: float = 0.0
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def rewrite_prompt(text: str) -> RewriteResult:
|
|
33
|
+
"""Rewrite a prompt to improve its score. Returns before/after with changes."""
|
|
34
|
+
from reprompt.core.compress import compress_text
|
|
35
|
+
from reprompt.core.extractors import extract_features
|
|
36
|
+
from reprompt.core.scorer import score_prompt
|
|
37
|
+
from reprompt.core.segmenter import segment_prompt
|
|
38
|
+
|
|
39
|
+
# Score original
|
|
40
|
+
dna = extract_features(text, source="rewrite", session_id="")
|
|
41
|
+
score_before = score_prompt(dna)
|
|
42
|
+
|
|
43
|
+
result = text
|
|
44
|
+
changes: list[str] = []
|
|
45
|
+
|
|
46
|
+
# Layer 1: Compress (filler removal)
|
|
47
|
+
compressed = compress_text(result)
|
|
48
|
+
if compressed.savings_pct > 5:
|
|
49
|
+
result = compressed.compressed
|
|
50
|
+
changes.append(f"Removed filler ({compressed.savings_pct:.0f}% shorter)")
|
|
51
|
+
|
|
52
|
+
# Layer 2: Front-load instruction (if buried in middle)
|
|
53
|
+
if dna.key_instruction_position > 0.3:
|
|
54
|
+
segments = segment_prompt(result)
|
|
55
|
+
new_result = _front_load_instruction(result, segments)
|
|
56
|
+
if new_result != result:
|
|
57
|
+
result = new_result
|
|
58
|
+
changes.append("Moved main instruction to front")
|
|
59
|
+
|
|
60
|
+
# Layer 3: Echo key requirement (for long prompts with low repetition)
|
|
61
|
+
current_word_count = len(result.split())
|
|
62
|
+
if dna.keyword_repetition_freq < 0.15 and current_word_count > 40:
|
|
63
|
+
echoed = _echo_key_requirement(result)
|
|
64
|
+
if echoed != result:
|
|
65
|
+
result = echoed
|
|
66
|
+
changes.append("Echoed key requirement at end")
|
|
67
|
+
|
|
68
|
+
# Layer 4: Clarity — replace hedge phrases
|
|
69
|
+
cleaned = _remove_hedging(result)
|
|
70
|
+
if cleaned != result:
|
|
71
|
+
result = cleaned
|
|
72
|
+
changes.append("Removed hedging language")
|
|
73
|
+
|
|
74
|
+
# Score rewritten
|
|
75
|
+
dna_after = extract_features(result, source="rewrite", session_id="")
|
|
76
|
+
score_after = score_prompt(dna_after)
|
|
77
|
+
|
|
78
|
+
# Generate manual suggestions for things we can't auto-fix
|
|
79
|
+
manual = _generate_manual_suggestions(dna)
|
|
80
|
+
|
|
81
|
+
return RewriteResult(
|
|
82
|
+
original=text,
|
|
83
|
+
rewritten=result,
|
|
84
|
+
changes=changes,
|
|
85
|
+
manual_suggestions=manual,
|
|
86
|
+
score_before=score_before.total,
|
|
87
|
+
score_after=score_after.total,
|
|
88
|
+
score_delta=round(score_after.total - score_before.total, 1),
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _front_load_instruction(text: str, segments: list) -> str:
|
|
93
|
+
"""Move the first instruction segment to the front of the prompt."""
|
|
94
|
+
instruction_seg = None
|
|
95
|
+
instruction_idx = -1
|
|
96
|
+
|
|
97
|
+
for i, seg in enumerate(segments):
|
|
98
|
+
if seg.segment_type == "instruction" and seg.start_pos > 0.2:
|
|
99
|
+
instruction_seg = seg
|
|
100
|
+
instruction_idx = i
|
|
101
|
+
break
|
|
102
|
+
|
|
103
|
+
if instruction_seg is None:
|
|
104
|
+
return text
|
|
105
|
+
|
|
106
|
+
# Extract the instruction text and rebuild
|
|
107
|
+
inst_text = instruction_seg.text.strip()
|
|
108
|
+
# Remove the instruction from its original position
|
|
109
|
+
remaining_parts = []
|
|
110
|
+
for i, seg in enumerate(segments):
|
|
111
|
+
if i == instruction_idx:
|
|
112
|
+
continue
|
|
113
|
+
remaining_parts.append(seg.text.strip())
|
|
114
|
+
|
|
115
|
+
remaining = "\n\n".join(p for p in remaining_parts if p)
|
|
116
|
+
|
|
117
|
+
# Ensure instruction ends with period for clean sentence
|
|
118
|
+
if inst_text and inst_text[-1] not in ".!?":
|
|
119
|
+
inst_text = inst_text + "."
|
|
120
|
+
|
|
121
|
+
return f"{inst_text}\n\n{remaining}".strip()
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _echo_key_requirement(text: str) -> str:
|
|
125
|
+
"""Add a reinforcement of the key requirement at the end."""
|
|
126
|
+
# Extract the most important action phrase from the first sentence
|
|
127
|
+
lines = text.strip().split("\n")
|
|
128
|
+
first_line = ""
|
|
129
|
+
for line in lines:
|
|
130
|
+
stripped = line.strip()
|
|
131
|
+
if stripped and not stripped.startswith("#") and not stripped.startswith("```"):
|
|
132
|
+
first_line = stripped
|
|
133
|
+
break
|
|
134
|
+
|
|
135
|
+
if not first_line or len(first_line) < 10:
|
|
136
|
+
return text
|
|
137
|
+
|
|
138
|
+
# Extract the core verb+object phrase
|
|
139
|
+
key_phrase = _extract_key_phrase(first_line)
|
|
140
|
+
if not key_phrase or len(key_phrase) < 8:
|
|
141
|
+
return text
|
|
142
|
+
|
|
143
|
+
# Don't echo if text already ends with similar content
|
|
144
|
+
last_100 = text[-100:].lower()
|
|
145
|
+
if key_phrase.lower() in last_100:
|
|
146
|
+
return text
|
|
147
|
+
|
|
148
|
+
return f"{text.rstrip()}\n\nImportant: {key_phrase}."
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _extract_key_phrase(sentence: str) -> str:
|
|
152
|
+
"""Extract the core verb+object from a sentence."""
|
|
153
|
+
# Remove leading filler
|
|
154
|
+
cleaned = re.sub(
|
|
155
|
+
r"^(?:please\s+|can you\s+|could you\s+|i need you to\s+|i want you to\s+|"
|
|
156
|
+
r"i would like you to\s+|help me\s+)",
|
|
157
|
+
"",
|
|
158
|
+
sentence.strip(),
|
|
159
|
+
flags=re.IGNORECASE,
|
|
160
|
+
)
|
|
161
|
+
# Take the main clause (before first comma or period)
|
|
162
|
+
main = re.split(r"[,.]", cleaned)[0].strip()
|
|
163
|
+
# Cap length
|
|
164
|
+
if len(main) > 80:
|
|
165
|
+
words = main.split()
|
|
166
|
+
main = " ".join(words[:12])
|
|
167
|
+
return main
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
_HEDGE_PATTERNS = [
|
|
171
|
+
(re.compile(r"\bI was wondering if you could\b", re.IGNORECASE), ""),
|
|
172
|
+
(re.compile(r"\bI think maybe\b", re.IGNORECASE), ""),
|
|
173
|
+
(re.compile(r"\bif possible,?\s*", re.IGNORECASE), ""),
|
|
174
|
+
(re.compile(r"\bif you don'?t mind,?\s*", re.IGNORECASE), ""),
|
|
175
|
+
(re.compile(r"\bbasically,?\s*", re.IGNORECASE), ""),
|
|
176
|
+
(re.compile(r"\bkind of\b", re.IGNORECASE), ""),
|
|
177
|
+
(re.compile(r"\bsort of\b", re.IGNORECASE), ""),
|
|
178
|
+
(re.compile(r"\bjust\s+", re.IGNORECASE), ""),
|
|
179
|
+
(re.compile(r"\bmaybe\s+", re.IGNORECASE), ""),
|
|
180
|
+
(re.compile(r"\bperhaps\s+", re.IGNORECASE), ""),
|
|
181
|
+
(re.compile(r"\ba little bit\b", re.IGNORECASE), ""),
|
|
182
|
+
(re.compile(r"\bI guess\s+", re.IGNORECASE), ""),
|
|
183
|
+
]
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def _remove_hedging(text: str) -> str:
|
|
187
|
+
"""Remove hedging language that weakens the prompt."""
|
|
188
|
+
result = text
|
|
189
|
+
for pattern, replacement in _HEDGE_PATTERNS:
|
|
190
|
+
result = pattern.sub(replacement, result)
|
|
191
|
+
# Clean up double spaces
|
|
192
|
+
result = re.sub(r" +", " ", result)
|
|
193
|
+
# Clean up leading spaces on lines
|
|
194
|
+
lines = result.split("\n")
|
|
195
|
+
result = "\n".join(line.lstrip() if line.strip() else line for line in lines)
|
|
196
|
+
return result
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def _generate_manual_suggestions(dna: object) -> list[str]:
|
|
200
|
+
"""Generate suggestions for improvements that require human input."""
|
|
201
|
+
suggestions: list[str] = []
|
|
202
|
+
|
|
203
|
+
specificity = getattr(dna, "context_specificity", 1.0)
|
|
204
|
+
if specificity < 0.4:
|
|
205
|
+
suggestions.append("Add actual code snippets or error messages for context")
|
|
206
|
+
|
|
207
|
+
if not getattr(dna, "has_constraints", True):
|
|
208
|
+
suggestions.append('Add constraints (e.g., "Do not modify existing tests")')
|
|
209
|
+
|
|
210
|
+
if not getattr(dna, "has_output_format", True):
|
|
211
|
+
suggestions.append("Specify expected output format (e.g., JSON, code block)")
|
|
212
|
+
|
|
213
|
+
if not getattr(dna, "has_file_references", True):
|
|
214
|
+
task = getattr(dna, "task_type", "")
|
|
215
|
+
if task in ("debug", "implement", "refactor", "test"):
|
|
216
|
+
suggestions.append("Reference specific files or functions by name")
|
|
217
|
+
|
|
218
|
+
if not getattr(dna, "has_examples", True):
|
|
219
|
+
suggestions.append("Add an example of expected input/output")
|
|
220
|
+
|
|
221
|
+
return suggestions
|
|
@@ -22,6 +22,8 @@ SUGGESTIONS: dict[str, str] = {
|
|
|
22
22
|
'reprompt template save "..." (reuse patterns) · reprompt insights (all patterns)'
|
|
23
23
|
),
|
|
24
24
|
"template": "reprompt insights (see which patterns work best)",
|
|
25
|
+
"lint": "reprompt init (generate .reprompt.toml) · reprompt rewrite (improve prompts)",
|
|
26
|
+
"rewrite": "reprompt compress (reduce tokens) · reprompt score (verify improvement)",
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Rich terminal output for rewrite command."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from io import StringIO
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
from rich.panel import Panel
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from reprompt.core.rewrite import RewriteResult
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def render_rewrite(result: RewriteResult) -> str:
|
|
16
|
+
"""Render a rewrite result as a Rich-formatted string."""
|
|
17
|
+
buf = StringIO()
|
|
18
|
+
console = Console(file=buf, width=100, record=True)
|
|
19
|
+
|
|
20
|
+
# Score change header
|
|
21
|
+
delta = result.score_delta
|
|
22
|
+
if delta > 0:
|
|
23
|
+
delta_str = f"[green]+{delta:.0f}[/green]"
|
|
24
|
+
elif delta < 0:
|
|
25
|
+
delta_str = f"[red]{delta:.0f}[/red]"
|
|
26
|
+
else:
|
|
27
|
+
delta_str = "[dim]±0[/dim]"
|
|
28
|
+
|
|
29
|
+
before_color = _score_color(result.score_before)
|
|
30
|
+
after_color = _score_color(result.score_after)
|
|
31
|
+
|
|
32
|
+
console.print(
|
|
33
|
+
f"\n [{before_color}]{result.score_before:.0f}[/{before_color}]"
|
|
34
|
+
f" → [{after_color}]{result.score_after:.0f}[/{after_color}]"
|
|
35
|
+
f" ({delta_str})\n"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# Rewritten prompt
|
|
39
|
+
if result.changes:
|
|
40
|
+
console.print(Panel(result.rewritten, title="Rewritten", border_style="green"))
|
|
41
|
+
else:
|
|
42
|
+
console.print("[dim]No automated improvements found.[/dim]")
|
|
43
|
+
|
|
44
|
+
# Changes applied
|
|
45
|
+
if result.changes:
|
|
46
|
+
console.print("\n [bold]Changes[/bold]")
|
|
47
|
+
for change in result.changes:
|
|
48
|
+
console.print(f" [green]✓[/green] {change}")
|
|
49
|
+
|
|
50
|
+
# Manual suggestions
|
|
51
|
+
if result.manual_suggestions:
|
|
52
|
+
console.print("\n [bold]You should also[/bold]")
|
|
53
|
+
for s in result.manual_suggestions:
|
|
54
|
+
console.print(f" [yellow]→[/yellow] {s}")
|
|
55
|
+
|
|
56
|
+
console.print()
|
|
57
|
+
return buf.getvalue()
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _score_color(score: float) -> str:
|
|
61
|
+
if score >= 85:
|
|
62
|
+
return "bold magenta"
|
|
63
|
+
if score >= 70:
|
|
64
|
+
return "bold green"
|
|
65
|
+
if score >= 55:
|
|
66
|
+
return "bold yellow"
|
|
67
|
+
if score >= 40:
|
|
68
|
+
return "yellow"
|
|
69
|
+
return "bold red"
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""Tests for reprompt init command."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from typer.testing import CliRunner
|
|
9
|
+
|
|
10
|
+
from reprompt.cli import app
|
|
11
|
+
|
|
12
|
+
runner = CliRunner()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_init_creates_config(tmp_path: Path) -> None:
|
|
16
|
+
os.chdir(tmp_path)
|
|
17
|
+
result = runner.invoke(app, ["init"])
|
|
18
|
+
assert result.exit_code == 0
|
|
19
|
+
config = tmp_path / ".reprompt.toml"
|
|
20
|
+
assert config.exists()
|
|
21
|
+
content = config.read_text()
|
|
22
|
+
assert "[lint]" in content
|
|
23
|
+
assert "[lint.rules]" in content
|
|
24
|
+
assert "min-length" in content
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def test_init_refuses_overwrite(tmp_path: Path) -> None:
|
|
28
|
+
os.chdir(tmp_path)
|
|
29
|
+
(tmp_path / ".reprompt.toml").write_text("existing")
|
|
30
|
+
result = runner.invoke(app, ["init"])
|
|
31
|
+
assert result.exit_code == 1
|
|
32
|
+
assert "already exists" in result.output
|
|
33
|
+
# Original content preserved
|
|
34
|
+
assert (tmp_path / ".reprompt.toml").read_text() == "existing"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_init_force_overwrites(tmp_path: Path) -> None:
|
|
38
|
+
os.chdir(tmp_path)
|
|
39
|
+
(tmp_path / ".reprompt.toml").write_text("old content")
|
|
40
|
+
result = runner.invoke(app, ["init", "--force"])
|
|
41
|
+
assert result.exit_code == 0
|
|
42
|
+
content = (tmp_path / ".reprompt.toml").read_text()
|
|
43
|
+
assert "[lint]" in content
|
|
44
|
+
assert "old content" not in content
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_init_config_is_valid_toml(tmp_path: Path) -> None:
|
|
48
|
+
"""Generated config should be parseable TOML."""
|
|
49
|
+
import sys
|
|
50
|
+
|
|
51
|
+
if sys.version_info >= (3, 11):
|
|
52
|
+
import tomllib
|
|
53
|
+
else:
|
|
54
|
+
try:
|
|
55
|
+
import tomllib
|
|
56
|
+
except ModuleNotFoundError:
|
|
57
|
+
import tomli as tomllib # type: ignore[no-redefine]
|
|
58
|
+
|
|
59
|
+
os.chdir(tmp_path)
|
|
60
|
+
runner.invoke(app, ["init"])
|
|
61
|
+
with open(tmp_path / ".reprompt.toml", "rb") as f:
|
|
62
|
+
data = tomllib.load(f)
|
|
63
|
+
assert "lint" in data
|
|
64
|
+
assert "rules" in data["lint"]
|
|
65
|
+
assert data["lint"]["rules"]["min-length"] == 20
|
|
66
|
+
assert data["lint"]["rules"]["vague-prompt"] is True
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def test_init_config_works_with_lint(tmp_path: Path) -> None:
|
|
70
|
+
"""Generated config should be loadable by lint config loader."""
|
|
71
|
+
os.chdir(tmp_path)
|
|
72
|
+
runner.invoke(app, ["init"])
|
|
73
|
+
|
|
74
|
+
from reprompt.core.lint import load_lint_config
|
|
75
|
+
|
|
76
|
+
config = load_lint_config(start_dir=tmp_path)
|
|
77
|
+
assert config.min_length == 20
|
|
78
|
+
assert config.short_prompt == 40
|
|
79
|
+
assert config.vague_prompt is True
|
|
80
|
+
assert config.debug_needs_reference is True
|