reverse-api-engineer 0.4.3__tar.gz → 0.4.5__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.
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/.claude/settings.local.json +8 -1
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/.gitignore +3 -1
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/CHANGELOG.md +17 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/PKG-INFO +2 -2
- reverse_api_engineer-0.4.5/chrome-extension/packed/reverse-api-engineer-chrome.zip +0 -0
- reverse_api_engineer-0.4.5/chrome-extension/store-assets/screenshot-1280x800.png +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/pyproject.toml +2 -2
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/src/reverse_api/auto_engineer.py +84 -98
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/src/reverse_api/base_engineer.py +35 -10
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/src/reverse_api/browser.py +16 -15
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/src/reverse_api/cli.py +12 -26
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/src/reverse_api/collector.py +2 -2
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/src/reverse_api/collector_ui.py +3 -2
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/src/reverse_api/copilot_engineer.py +1 -1
- reverse_api_engineer-0.4.5/src/reverse_api/engineer.py +239 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/src/reverse_api/opencode_engineer.py +3 -3
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/src/reverse_api/opencode_ui.py +8 -5
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/src/reverse_api/playwright_codegen.py +27 -24
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/src/reverse_api/tui.py +9 -7
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/uv.lock +977 -1001
- reverse_api_engineer-0.4.3/llm-docs/claude-agent-sdk/QUICKSTART.md +0 -2017
- reverse_api_engineer-0.4.3/llm-docs/claude-agent-sdk/TODO_LIST.md +0 -176
- reverse_api_engineer-0.4.3/llm-docs/claude-agent-sdk/TOOLS.md +0 -0
- reverse_api_engineer-0.4.3/src/reverse_api/engineer.py +0 -255
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/.claude-plugin/marketplace.json +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/.python-version +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/CLAUDE.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/CONTRIBUTING.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/INTERVIEW.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/LICENSE +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/PROMPT_STASH.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/README.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/RELEASING.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/assets/reverse-api-banner.svg +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/assets/reverse-api-engineer.gif +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/assets/reverse-api-logo.svg +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/.claude/settings.local.json +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/components.json +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/package-lock.json +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/package.json +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/postcss.config.js +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/public/_locales/en/messages.json +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/public/icons/icon-128.png +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/public/icons/icon-16.png +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/public/icons/icon-32.png +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/public/icons/icon-48.png +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/public/manifest.json +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/src/background/service-worker.ts +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/src/components/agent-action.tsx +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/src/components/chat-input.tsx +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/src/components/icons.tsx +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/src/components/markdown-renderer.tsx +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/src/components/mode-selector.tsx +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/src/components/plan.tsx +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/src/components/session-selector.tsx +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/src/components/terminal.tsx +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/src/components/ui/code-block.tsx +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/src/content/codegen-recorder.ts +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/src/index.css +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/src/shared/capture.ts +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/src/shared/native-host.ts +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/src/shared/storage.ts +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/src/shared/types.ts +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/src/sidepanel/index.html +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/src/sidepanel/main.tsx +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/src/sidepanel/side-panel.tsx +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/src/vite-env.d.ts +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/tailwind.config.js +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/tsconfig.json +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/chrome-extension/vite.config.ts +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/apple/INDEX.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/apple/QUICKSTART.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/apple/README.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/apple/SUMMARY.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/apple/api_client.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/apple/extract_job_fields.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/apple/main.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/apple/quick_example.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/apple/requirements.txt +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/ashby/API_SUMMARY.txt +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/ashby/QUICKSTART.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/ashby/README.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/ashby/api_client.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/ashby/example_usage.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/ashby/requirements.txt +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/autoscout24/README.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/autoscout24/SUMMARY.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/autoscout24/api_client.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/ikea/README.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/ikea/api_client.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/mintlify/README.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/mintlify/api_client.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/uber/API_ANALYSIS_SUMMARY.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/uber/README.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/uber/api_client.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/uber/example_fetch_all_jobs.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/uber/quick_start.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/examples/uber/requirements.txt +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/llm-docs/OPENCODE_API_SUMMARY.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/llm-docs/opencode-api.json +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/plugins/reverse-api-engineer/.claude-plugin/plugin.json +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/plugins/reverse-api-engineer/CHANGELOG.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/plugins/reverse-api-engineer/LICENSE +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/plugins/reverse-api-engineer/README.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/plugins/reverse-api-engineer/agents/api-reverse-engineer.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/plugins/reverse-api-engineer/commands/agent.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/plugins/reverse-api-engineer/commands/capture.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/plugins/reverse-api-engineer/commands/engineer.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/plugins/reverse-api-engineer/commands/manual.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/plugins/reverse-api-engineer/skills/reverse-engineering-api/CHANGELOG.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/plugins/reverse-api-engineer/skills/reverse-engineering-api/LICENSE +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/plugins/reverse-api-engineer/skills/reverse-engineering-api/SKILL.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/plugins/reverse-api-engineer/skills/reverse-engineering-api/references/AUTH_PATTERNS.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/plugins/reverse-api-engineer/skills/reverse-engineering-api/references/HAR_ANALYSIS.md +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/plugins/reverse-api-engineer/skills/reverse-engineering-api/scripts/har_analyze.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/plugins/reverse-api-engineer/skills/reverse-engineering-api/scripts/har_filter.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/plugins/reverse-api-engineer/skills/reverse-engineering-api/scripts/har_utils.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/plugins/reverse-api-engineer/skills/reverse-engineering-api/scripts/har_validate.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/plugins/reverse-api-engineer/skills/reverse-engineering-api/templates/api_client.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/scripts/clean_build.sh +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/src/reverse_api/__init__.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/src/reverse_api/action_recorder.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/src/reverse_api/config.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/src/reverse_api/messages.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/src/reverse_api/native_host.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/src/reverse_api/pricing.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/src/reverse_api/session.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/src/reverse_api/sync.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/src/reverse_api/utils.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/tests/__init__.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/tests/conftest.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/tests/test_action_recorder.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/tests/test_auto_engineer.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/tests/test_base_engineer.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/tests/test_collector.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/tests/test_collector_ui.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/tests/test_config.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/tests/test_engineer.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/tests/test_init.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/tests/test_messages.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/tests/test_native_host.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/tests/test_opencode_engineer.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/tests/test_opencode_ui.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/tests/test_pricing.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/tests/test_session.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/tests/test_sync.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/tests/test_tui.py +0 -0
- {reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/tests/test_utils.py +0 -0
|
@@ -113,7 +113,14 @@
|
|
|
113
113
|
"Bash(npx rollup-plugin-visualizer:*)",
|
|
114
114
|
"Bash(git pull:*)",
|
|
115
115
|
"WebFetch(domain:docs.anthropic.com)",
|
|
116
|
-
"WebFetch(domain:docs.claude.com)"
|
|
116
|
+
"WebFetch(domain:docs.claude.com)",
|
|
117
|
+
"Bash(uv lock:*)",
|
|
118
|
+
"Bash(cd /Users/kalilbouzigues/Projects/browgents/reverse-api/chrome-extension/dist && zip -r ../packed/reverse-api-engineer-chrome.zip . && ls -lh ../packed/)",
|
|
119
|
+
"mcp__plugin_reverse-api-engineer_rae-playwright-mcp__browser_resize",
|
|
120
|
+
"mcp__plugin_reverse-api-engineer_rae-playwright-mcp__browser_take_screenshot",
|
|
121
|
+
"Bash(gh issue:*)",
|
|
122
|
+
"Bash(CLAUDECODE= uv run python3 /tmp/test_hook.py 2>&1)",
|
|
123
|
+
"Bash(CLAUDECODE=1 uv run python3 /tmp/test_hook4.py 2>&1)"
|
|
117
124
|
]
|
|
118
125
|
}
|
|
119
126
|
}
|
|
@@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.4.5] - 2026-03-15
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **Stream closed errors (#51)**: Reverted from `query()` to `ClaudeSDKClient` which maintains a persistent bidirectional connection, eliminating "Error in hook callback hook_0: Stream closed" errors. The original AUQ fix (v0.4.3) unnecessarily switched APIs — only the `can_use_tool` callback signature needed updating
|
|
12
|
+
- **CLAUDECODE env var leak**: Clear inherited `CLAUDECODE` env var from CLI subprocess to prevent nested session interference when running inside Claude Code
|
|
13
|
+
- **CLI stderr noise**: Filter minified JS stack traces into a single clean error line (use `DEBUG=1` for full output)
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- **claude-agent-sdk**: Bumped minimum version to 0.1.48
|
|
17
|
+
- **Agent mode**: No longer prompts for URL (agent navigates autonomously)
|
|
18
|
+
- **Header UI**: Version and task labels now use mode-specific colors (agent=coral, engineer=blue, collector=gold)
|
|
19
|
+
|
|
20
|
+
## [0.4.4] - 2026-03-15
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
- **Stream closed errors (#51)**: Partial fix using `query()` with env var workarounds (superseded by v0.4.5)
|
|
24
|
+
|
|
8
25
|
## [0.4.3] - 2026-03-12
|
|
9
26
|
|
|
10
27
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: reverse-api-engineer
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.5
|
|
4
4
|
Summary: A tool to capture browser traffic for API reverse engineering
|
|
5
5
|
Project-URL: Homepage, https://github.com/kalil0321/reverse-api-engineer
|
|
6
6
|
Project-URL: Repository, https://github.com/kalil0321/reverse-api-engineer
|
|
@@ -22,7 +22,7 @@ Requires-Python: >=3.11
|
|
|
22
22
|
Requires-Dist: aiohttp>=3.12.15
|
|
23
23
|
Requires-Dist: anthropic>=0.40.0
|
|
24
24
|
Requires-Dist: brotli>=1.2.0
|
|
25
|
-
Requires-Dist: claude-agent-sdk>=0.1.
|
|
25
|
+
Requires-Dist: claude-agent-sdk>=0.1.48
|
|
26
26
|
Requires-Dist: click>=8.1.0
|
|
27
27
|
Requires-Dist: playwright-stealth>=1.0.0
|
|
28
28
|
Requires-Dist: playwright>=1.40.0
|
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "reverse-api-engineer"
|
|
3
|
-
version = "0.4.
|
|
3
|
+
version = "0.4.5"
|
|
4
4
|
description = "A tool to capture browser traffic for API reverse engineering"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -24,7 +24,7 @@ dependencies = [
|
|
|
24
24
|
"playwright>=1.40.0",
|
|
25
25
|
"playwright-stealth>=1.0.0",
|
|
26
26
|
"click>=8.1.0",
|
|
27
|
-
"claude-agent-sdk>=0.1.
|
|
27
|
+
"claude-agent-sdk>=0.1.48",
|
|
28
28
|
"rich>=13.0.0",
|
|
29
29
|
"questionary>=2.0.0",
|
|
30
30
|
"requests>=2.32.5",
|
|
@@ -11,14 +11,13 @@ import httpx
|
|
|
11
11
|
from claude_agent_sdk import (
|
|
12
12
|
AssistantMessage,
|
|
13
13
|
ClaudeAgentOptions,
|
|
14
|
-
|
|
14
|
+
ClaudeSDKClient,
|
|
15
15
|
PermissionResultAllow,
|
|
16
16
|
ResultMessage,
|
|
17
17
|
TextBlock,
|
|
18
18
|
ToolPermissionContext,
|
|
19
19
|
ToolResultBlock,
|
|
20
20
|
ToolUseBlock,
|
|
21
|
-
query,
|
|
22
21
|
)
|
|
23
22
|
|
|
24
23
|
from .engineer import ClaudeEngineer
|
|
@@ -229,9 +228,7 @@ Your final response should confirm the files were created and provide a brief su
|
|
|
229
228
|
- Any limitations or caveats
|
|
230
229
|
"""
|
|
231
230
|
|
|
232
|
-
async def _handle_tool_permission(
|
|
233
|
-
self, tool_name: str, input_data: dict[str, Any], context: ToolPermissionContext
|
|
234
|
-
) -> PermissionResultAllow:
|
|
231
|
+
async def _handle_tool_permission(self, tool_name: str, input_data: dict[str, Any], context: ToolPermissionContext) -> PermissionResultAllow:
|
|
235
232
|
"""Handle tool permission requests, with interactive UI for AskUserQuestion."""
|
|
236
233
|
if tool_name == "AskUserQuestion":
|
|
237
234
|
questions = input_data.get("questions", [])
|
|
@@ -244,7 +241,7 @@ Your final response should confirm the files were created and provide a brief su
|
|
|
244
241
|
|
|
245
242
|
async def analyze_and_generate(self) -> dict[str, Any] | None:
|
|
246
243
|
"""Run auto mode with MCP browser integration."""
|
|
247
|
-
self.ui.header(self.run_id, self.prompt, self.model)
|
|
244
|
+
self.ui.header(self.run_id, self.prompt, self.model, mode="agent")
|
|
248
245
|
self.ui.start_analysis()
|
|
249
246
|
self.message_store.save_prompt(self._build_auto_prompt())
|
|
250
247
|
|
|
@@ -259,104 +256,93 @@ Your final response should confirm the files were created and provide a brief su
|
|
|
259
256
|
],
|
|
260
257
|
}
|
|
261
258
|
|
|
262
|
-
# Required workaround: dummy hook keeps the stream open for can_use_tool
|
|
263
|
-
# See: https://platform.claude.com/docs/en/agent-sdk/user-input
|
|
264
|
-
async def _dummy_hook(input_data: dict[str, Any], tool_use_id: str | None, context: Any) -> dict[str, Any]:
|
|
265
|
-
return {"continue_": True}
|
|
266
|
-
|
|
267
|
-
prompt_text = self._build_auto_prompt()
|
|
268
|
-
|
|
269
|
-
async def _prompt_stream() -> Any:
|
|
270
|
-
yield {
|
|
271
|
-
"type": "user",
|
|
272
|
-
"message": {"role": "user", "content": prompt_text},
|
|
273
|
-
}
|
|
274
|
-
|
|
275
259
|
options = ClaudeAgentOptions(
|
|
276
260
|
mcp_servers={"playwright": mcp_config},
|
|
261
|
+
permission_mode="bypassPermissions",
|
|
277
262
|
can_use_tool=self._handle_tool_permission,
|
|
278
|
-
hooks={"PreToolUse": [HookMatcher(matcher=None, hooks=[_dummy_hook])]},
|
|
279
263
|
cwd=str(self.scripts_dir.parent.parent), # Project root
|
|
280
264
|
model=self.model,
|
|
265
|
+
env={"CLAUDECODE": ""},
|
|
266
|
+
stderr=self._handle_cli_stderr,
|
|
281
267
|
)
|
|
282
268
|
|
|
283
269
|
try:
|
|
284
|
-
async
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
270
|
+
async with ClaudeSDKClient(options=options) as client:
|
|
271
|
+
await client.query(self._build_auto_prompt())
|
|
272
|
+
|
|
273
|
+
async for message in client.receive_response():
|
|
274
|
+
if hasattr(message, "usage") and isinstance(message.usage, dict):
|
|
275
|
+
self.usage_metadata.update(message.usage)
|
|
276
|
+
|
|
277
|
+
if isinstance(message, AssistantMessage):
|
|
278
|
+
last_tool_name = None
|
|
279
|
+
for block in message.content:
|
|
280
|
+
if isinstance(block, ToolUseBlock):
|
|
281
|
+
last_tool_name = block.name
|
|
282
|
+
self.ui.tool_start(block.name, block.input)
|
|
283
|
+
self.message_store.save_tool_start(block.name, block.input)
|
|
284
|
+
elif isinstance(block, ToolResultBlock):
|
|
285
|
+
is_error = block.is_error if block.is_error else False
|
|
286
|
+
|
|
287
|
+
output = None
|
|
288
|
+
if hasattr(block, "content"):
|
|
289
|
+
output = block.content
|
|
290
|
+
elif hasattr(block, "result"):
|
|
291
|
+
output = block.result
|
|
292
|
+
elif hasattr(block, "output"):
|
|
293
|
+
output = block.output
|
|
294
|
+
|
|
295
|
+
tool_name = last_tool_name or "Tool"
|
|
296
|
+
self.ui.tool_result(tool_name, is_error, output)
|
|
297
|
+
self.message_store.save_tool_result(tool_name, is_error, str(output) if output else None)
|
|
298
|
+
elif isinstance(block, TextBlock):
|
|
299
|
+
self.ui.thinking(block.text)
|
|
300
|
+
self.message_store.save_thinking(block.text)
|
|
301
|
+
|
|
302
|
+
elif isinstance(message, ResultMessage):
|
|
303
|
+
if message.is_error:
|
|
304
|
+
self.ui.error(message.result or "Unknown error")
|
|
305
|
+
self.message_store.save_error(message.result or "Unknown error")
|
|
306
|
+
return None
|
|
307
|
+
else:
|
|
308
|
+
script_path = str(self.scripts_dir / self._get_client_filename())
|
|
309
|
+
local_path = str(self.local_scripts_dir / self._get_client_filename()) if self.local_scripts_dir else None
|
|
310
|
+
self.ui.success(script_path, local_path)
|
|
311
|
+
|
|
312
|
+
if self.usage_metadata:
|
|
313
|
+
input_tokens = self.usage_metadata.get("input_tokens", 0)
|
|
314
|
+
output_tokens = self.usage_metadata.get("output_tokens", 0)
|
|
315
|
+
cache_creation_tokens = self.usage_metadata.get("cache_creation_input_tokens", 0)
|
|
316
|
+
cache_read_tokens = self.usage_metadata.get("cache_read_input_tokens", 0)
|
|
317
|
+
|
|
318
|
+
from .pricing import calculate_cost
|
|
319
|
+
|
|
320
|
+
cost = calculate_cost(
|
|
321
|
+
model_id=self.model,
|
|
322
|
+
input_tokens=input_tokens,
|
|
323
|
+
output_tokens=output_tokens,
|
|
324
|
+
cache_creation_tokens=cache_creation_tokens,
|
|
325
|
+
cache_read_tokens=cache_read_tokens,
|
|
326
|
+
)
|
|
327
|
+
self.usage_metadata["estimated_cost_usd"] = cost
|
|
328
|
+
|
|
329
|
+
self.ui.console.print(" [dim]Usage:[/dim]")
|
|
330
|
+
if input_tokens > 0:
|
|
331
|
+
self.ui.console.print(f" [dim] input: {input_tokens:,} tokens[/dim]")
|
|
332
|
+
if cache_creation_tokens > 0:
|
|
333
|
+
self.ui.console.print(f" [dim] cache creation: {cache_creation_tokens:,} tokens[/dim]")
|
|
334
|
+
if cache_read_tokens > 0:
|
|
335
|
+
self.ui.console.print(f" [dim] cache read: {cache_read_tokens:,} tokens[/dim]")
|
|
336
|
+
if output_tokens > 0:
|
|
337
|
+
self.ui.console.print(f" [dim] output: {output_tokens:,} tokens[/dim]")
|
|
338
|
+
self.ui.console.print(f" [dim] total cost: ${cost:.4f}[/dim]")
|
|
339
|
+
|
|
340
|
+
result: dict[str, Any] = {
|
|
341
|
+
"script_path": script_path,
|
|
342
|
+
"usage": self.usage_metadata,
|
|
343
|
+
}
|
|
344
|
+
self.message_store.save_result(result)
|
|
345
|
+
return result
|
|
360
346
|
|
|
361
347
|
except Exception as e:
|
|
362
348
|
error_msg = str(e)
|
|
@@ -404,7 +390,7 @@ class OpenCodeAutoEngineer(OpenCodeEngineer):
|
|
|
404
390
|
|
|
405
391
|
async def analyze_and_generate(self) -> dict[str, Any] | None:
|
|
406
392
|
"""Run auto mode with OpenCode MCP integration."""
|
|
407
|
-
self.opencode_ui.header(self.run_id, self.prompt, self.opencode_model)
|
|
393
|
+
self.opencode_ui.header(self.run_id, self.prompt, self.opencode_model, mode="agent")
|
|
408
394
|
self.opencode_ui.start_analysis()
|
|
409
395
|
self.message_store.save_prompt(self._build_auto_prompt())
|
|
410
396
|
|
|
@@ -639,7 +625,7 @@ class CopilotAutoEngineer:
|
|
|
639
625
|
return None
|
|
640
626
|
|
|
641
627
|
eng = self._engineer
|
|
642
|
-
eng.ui.header(eng.run_id, eng.prompt, eng.copilot_model, eng.sdk)
|
|
628
|
+
eng.ui.header(eng.run_id, eng.prompt, eng.copilot_model, eng.sdk, mode="agent")
|
|
643
629
|
eng.ui.start_analysis()
|
|
644
630
|
|
|
645
631
|
auto_prompt = ClaudeAutoEngineer._build_auto_prompt(eng)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Abstract base class for API reverse engineering."""
|
|
2
2
|
|
|
3
|
+
import os
|
|
3
4
|
from abc import ABC, abstractmethod
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
from typing import Any
|
|
@@ -12,6 +13,8 @@ from .sync import FileSyncWatcher, get_available_directory
|
|
|
12
13
|
from .tui import THEME_PRIMARY, THEME_SECONDARY, ClaudeUI
|
|
13
14
|
from .utils import generate_folder_name, get_docs_dir, get_history_path, get_scripts_dir
|
|
14
15
|
|
|
16
|
+
DEBUG = os.environ.get("DEBUG", "0") == "1"
|
|
17
|
+
|
|
15
18
|
|
|
16
19
|
class BaseEngineer(ABC):
|
|
17
20
|
"""Abstract base class for API reverse engineering implementations."""
|
|
@@ -60,6 +63,24 @@ class BaseEngineer(ABC):
|
|
|
60
63
|
self.existing_client_path = self._get_existing_client_path()
|
|
61
64
|
self.sync_watcher: FileSyncWatcher | None = None
|
|
62
65
|
self.local_scripts_dir: Path | None = None
|
|
66
|
+
self._stderr_error_shown = False
|
|
67
|
+
|
|
68
|
+
def _handle_cli_stderr(self, line: str) -> None:
|
|
69
|
+
"""Filter CLI subprocess stderr. Shows full output in DEBUG mode, otherwise shows a single clean error."""
|
|
70
|
+
if DEBUG:
|
|
71
|
+
self.ui.console.print(f"[dim] stderr: {line.rstrip()}[/dim]")
|
|
72
|
+
return
|
|
73
|
+
|
|
74
|
+
# Known noisy errors from the CLI control protocol — show once
|
|
75
|
+
if "Error in hook callback" in line or "Stream closed" in line:
|
|
76
|
+
if not self._stderr_error_shown:
|
|
77
|
+
self._stderr_error_shown = True
|
|
78
|
+
self.ui.console.print(" [dim]![/dim] [dim]cli stream error (set DEBUG=1 for details)[/dim]")
|
|
79
|
+
return
|
|
80
|
+
|
|
81
|
+
# Suppress other common noise (stack traces, source maps)
|
|
82
|
+
if line.startswith(" at ") or "| " in line[:20]:
|
|
83
|
+
return
|
|
63
84
|
|
|
64
85
|
def start_sync(self):
|
|
65
86
|
"""Start real-time file sync if enabled."""
|
|
@@ -532,16 +553,20 @@ Your OpenAPI spec should be production-ready and suitable for:
|
|
|
532
553
|
mode_description = f"reverse engineer API calls and generate production-ready {language_name} code that replicates"
|
|
533
554
|
task_description = f"{language_name} API client"
|
|
534
555
|
|
|
535
|
-
attempt_log_section =
|
|
536
|
-
"
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
556
|
+
attempt_log_section = (
|
|
557
|
+
""
|
|
558
|
+
if self.output_mode == "docs"
|
|
559
|
+
else (
|
|
560
|
+
"If your first attempt doesn't work, analyze what went wrong and try again. "
|
|
561
|
+
"Document each attempt and what you learned.\n\n"
|
|
562
|
+
"<attempt_log>\n"
|
|
563
|
+
"For each attempt (up to 5), document:\n"
|
|
564
|
+
"- Attempt number\n"
|
|
565
|
+
"- What approach you tried\n"
|
|
566
|
+
"- What error or issue occurred (if any)\n"
|
|
567
|
+
"- What you changed for the next attempt\n"
|
|
568
|
+
"</attempt_log>\n\n"
|
|
569
|
+
)
|
|
545
570
|
)
|
|
546
571
|
after_verb = "documenting" if self.output_mode == "docs" else "testing"
|
|
547
572
|
output_type = "spec" if self.output_mode == "docs" else "code"
|
|
@@ -210,11 +210,11 @@ class ManualBrowser:
|
|
|
210
210
|
self.output_dir = output_dir
|
|
211
211
|
self.use_real_chrome = use_real_chrome
|
|
212
212
|
self.enable_action_recording = enable_action_recording
|
|
213
|
-
|
|
213
|
+
|
|
214
214
|
self.har_dir = get_har_dir(run_id, output_dir)
|
|
215
215
|
self.har_path = self.har_dir / "recording.har"
|
|
216
216
|
self.metadata_path = self.har_dir / "metadata.json"
|
|
217
|
-
|
|
217
|
+
|
|
218
218
|
self._playwright = None
|
|
219
219
|
self._browser: Browser | None = None
|
|
220
220
|
self._context: BrowserContext | None = None
|
|
@@ -226,15 +226,15 @@ class ManualBrowser:
|
|
|
226
226
|
|
|
227
227
|
def _inject_action_recorder(self, page: Page) -> None:
|
|
228
228
|
"""Inject action recording script into page.
|
|
229
|
-
|
|
229
|
+
|
|
230
230
|
Uses console.log + page.on('console') for reliable capture.
|
|
231
231
|
Works best with stealth Chromium mode (not real Chrome).
|
|
232
232
|
"""
|
|
233
233
|
if not self.enable_action_recording:
|
|
234
234
|
return
|
|
235
|
-
|
|
235
|
+
|
|
236
236
|
# Simple JS that logs actions to console with a special prefix
|
|
237
|
-
recorder_js =
|
|
237
|
+
recorder_js = """
|
|
238
238
|
window.__recordedActions = [];
|
|
239
239
|
window.__lastUrl = null;
|
|
240
240
|
|
|
@@ -378,34 +378,35 @@ class ManualBrowser:
|
|
|
378
378
|
}
|
|
379
379
|
}
|
|
380
380
|
}
|
|
381
|
-
|
|
382
|
-
|
|
381
|
+
"""
|
|
382
|
+
|
|
383
383
|
# Listen to console for actions
|
|
384
384
|
import json
|
|
385
|
+
|
|
385
386
|
last_url = [None] # Mutable to track last URL
|
|
386
|
-
|
|
387
|
+
|
|
387
388
|
def on_console(msg):
|
|
388
389
|
text = msg.text
|
|
389
|
-
if text.startswith(
|
|
390
|
+
if text.startswith("__ACTION__"):
|
|
390
391
|
try:
|
|
391
392
|
action_json = text[10:] # Remove '__ACTION__' prefix
|
|
392
393
|
action_data = json.loads(action_json)
|
|
393
|
-
|
|
394
|
+
|
|
394
395
|
# Filter duplicate navigations
|
|
395
|
-
if action_data.get(
|
|
396
|
-
url = action_data.get(
|
|
396
|
+
if action_data.get("type") == "navigate":
|
|
397
|
+
url = action_data.get("url", "")
|
|
397
398
|
if url == last_url[0]:
|
|
398
399
|
return # Skip duplicate
|
|
399
400
|
last_url[0] = url
|
|
400
|
-
|
|
401
|
+
|
|
401
402
|
if self.action_recorder:
|
|
402
403
|
self.action_recorder.add_action(RecordedAction(**action_data))
|
|
403
404
|
except Exception as e:
|
|
404
405
|
console.print(f" [dim]action parse error: {e}[/dim]")
|
|
405
|
-
|
|
406
|
+
|
|
406
407
|
page.on("console", on_console)
|
|
407
408
|
page.add_init_script(recorder_js)
|
|
408
|
-
|
|
409
|
+
|
|
409
410
|
console.print(" [dim]action recording enabled[/dim]")
|
|
410
411
|
|
|
411
412
|
def _save_metadata(self, end_time: str) -> None:
|
|
@@ -54,7 +54,7 @@ config_manager = ConfigManager(get_config_path())
|
|
|
54
54
|
session_manager = SessionManager(get_history_path())
|
|
55
55
|
|
|
56
56
|
# Mode definitions
|
|
57
|
-
MODES = ["
|
|
57
|
+
MODES = ["agent", "manual", "engineer", "collector"]
|
|
58
58
|
MODE_DESCRIPTIONS = {
|
|
59
59
|
"manual": "full pipeline",
|
|
60
60
|
"engineer": "reverse engineer only",
|
|
@@ -68,7 +68,7 @@ def prompt_interactive_options(
|
|
|
68
68
|
url: str | None = None,
|
|
69
69
|
reverse_engineer: bool | None = None,
|
|
70
70
|
model: str | None = None,
|
|
71
|
-
current_mode: str = "
|
|
71
|
+
current_mode: str = "agent",
|
|
72
72
|
) -> dict:
|
|
73
73
|
"""Prompt user for essential options interactively (Browgents style).
|
|
74
74
|
|
|
@@ -267,29 +267,15 @@ def prompt_interactive_options(
|
|
|
267
267
|
"model": model or config_manager.get("claude_code_model", "claude-sonnet-4-6"),
|
|
268
268
|
}
|
|
269
269
|
|
|
270
|
-
# Agent mode:
|
|
270
|
+
# Agent mode: autonomous browser, no URL needed (agent navigates on its own)
|
|
271
271
|
if result_mode == "agent":
|
|
272
|
-
if url is None:
|
|
273
|
-
try:
|
|
274
|
-
url = questionary.text(
|
|
275
|
-
" > url",
|
|
276
|
-
instruction="(Enter for none)",
|
|
277
|
-
qmark="",
|
|
278
|
-
style=questionary.Style(
|
|
279
|
-
[
|
|
280
|
-
("question", f"fg:{THEME_SECONDARY}"),
|
|
281
|
-
("instruction", f"fg:{THEME_DIM} italic"),
|
|
282
|
-
]
|
|
283
|
-
),
|
|
284
|
-
).ask()
|
|
285
|
-
if url is None: # questionary returns None on Ctrl+C
|
|
286
|
-
raise click.Abort()
|
|
287
|
-
except KeyboardInterrupt:
|
|
288
|
-
raise click.Abort()
|
|
289
|
-
|
|
290
272
|
if model is None:
|
|
291
273
|
model = config_manager.get("claude_code_model", "claude-sonnet-4-6")
|
|
292
274
|
|
|
275
|
+
mode_color = MODE_COLORS.get("agent", THEME_PRIMARY)
|
|
276
|
+
console = Console()
|
|
277
|
+
console.print(f" [{mode_color}]autonomous[/{mode_color}] [dim]agent will navigate on its own[/dim]")
|
|
278
|
+
|
|
293
279
|
return {
|
|
294
280
|
"mode": result_mode,
|
|
295
281
|
"prompt": prompt,
|
|
@@ -372,7 +358,7 @@ def repl_loop():
|
|
|
372
358
|
model = config_manager.get("claude_code_model", "claude-sonnet-4-6")
|
|
373
359
|
|
|
374
360
|
display_banner(console, sdk=sdk, model=model)
|
|
375
|
-
console.print(" [dim]shift+tab to cycle modes:
|
|
361
|
+
console.print(" [dim]shift+tab to cycle modes: agent | manual | engineer | collector[/dim]")
|
|
376
362
|
display_footer(console)
|
|
377
363
|
|
|
378
364
|
# Show update message if background check has completed
|
|
@@ -386,14 +372,14 @@ def repl_loop():
|
|
|
386
372
|
finally:
|
|
387
373
|
update_executor.shutdown(wait=False)
|
|
388
374
|
|
|
389
|
-
current_mode = "
|
|
375
|
+
current_mode = "agent"
|
|
390
376
|
|
|
391
377
|
while True:
|
|
392
378
|
try:
|
|
393
379
|
options = prompt_interactive_options(current_mode=current_mode)
|
|
394
380
|
|
|
395
381
|
# Update current mode for next iteration
|
|
396
|
-
current_mode = options.get("mode", "
|
|
382
|
+
current_mode = options.get("mode", "agent")
|
|
397
383
|
|
|
398
384
|
if "command" in options:
|
|
399
385
|
cmd = options["command"]
|
|
@@ -430,7 +416,7 @@ def repl_loop():
|
|
|
430
416
|
console.print(" [dim]Available commands: /settings, /history, /messages, /help, /exit[/dim]")
|
|
431
417
|
continue
|
|
432
418
|
|
|
433
|
-
mode = options.get("mode", "
|
|
419
|
+
mode = options.get("mode", "agent")
|
|
434
420
|
|
|
435
421
|
# Handle different modes
|
|
436
422
|
if mode == "engineer":
|
|
@@ -1106,9 +1092,9 @@ def handle_help(mode_color=THEME_PRIMARY):
|
|
|
1106
1092
|
modes_table.add_column(style=f"{mode_color} bold", justify="left", width=15)
|
|
1107
1093
|
modes_table.add_column(style="dim", justify="left")
|
|
1108
1094
|
|
|
1095
|
+
modes_table.add_row("agent", "Autonomous agent + capture")
|
|
1109
1096
|
modes_table.add_row("manual", "Full pipeline: browser + reverse engineering")
|
|
1110
1097
|
modes_table.add_row("engineer", "Reverse engineer only (enter run_id)")
|
|
1111
|
-
modes_table.add_row("agent", "Autonomous agent + capture")
|
|
1112
1098
|
|
|
1113
1099
|
console.print(" [bold white]Modes[/bold white] [dim]Shift+Tab to cycle[/dim]")
|
|
1114
1100
|
console.print(modes_table)
|
|
@@ -66,7 +66,7 @@ class Collector:
|
|
|
66
66
|
Returns:
|
|
67
67
|
Result dict with output_path and collected_items, or None on error
|
|
68
68
|
"""
|
|
69
|
-
self.ui.header(self.run_id, self.prompt, self.model)
|
|
69
|
+
self.ui.header(self.run_id, self.prompt, self.model, mode="collector")
|
|
70
70
|
self.ui.start_collecting()
|
|
71
71
|
|
|
72
72
|
self._folder_name = generate_folder_name(self.prompt)
|
|
@@ -288,7 +288,7 @@ When complete, briefly summarize what was collected.
|
|
|
288
288
|
def _export_readme(self, readme_path: Path, items: list[dict[str, Any]], sources: set[str]) -> None:
|
|
289
289
|
"""Generate README with collection metadata."""
|
|
290
290
|
folder_name = self._folder_name or "collection"
|
|
291
|
-
readme_content = f"""# {folder_name.replace(
|
|
291
|
+
readme_content = f"""# {folder_name.replace("_", " ").title()}
|
|
292
292
|
|
|
293
293
|
## Query
|
|
294
294
|
{self.prompt}
|
|
@@ -15,12 +15,12 @@ class CollectorUI:
|
|
|
15
15
|
self.verbose = verbose
|
|
16
16
|
self._items_collected = 0
|
|
17
17
|
|
|
18
|
-
def header(self, run_id: str, prompt: str, model: str | None = None) -> None:
|
|
18
|
+
def header(self, run_id: str, prompt: str, model: str | None = None, **kwargs) -> None:
|
|
19
19
|
"""Display the collector session header."""
|
|
20
20
|
from . import __version__
|
|
21
21
|
|
|
22
22
|
self.console.print()
|
|
23
|
-
self.console.print(f" [white]reverse-api[/white] [
|
|
23
|
+
self.console.print(f" [white]reverse-api[/white] [{COLLECTOR_COLOR}]v{__version__}[/{COLLECTOR_COLOR}]")
|
|
24
24
|
self.console.print(f" [dim]━[/dim] [white]{run_id}[/white]")
|
|
25
25
|
self.console.print(f" [{COLLECTOR_COLOR}]collector[/{COLLECTOR_COLOR}] [dim]|[/dim] [dim]model[/dim] [white]{model or '---'}[/white]")
|
|
26
26
|
self.console.print(f" [{COLLECTOR_COLOR}]task[/{COLLECTOR_COLOR}] [white]{prompt[:80]}{'...' if len(prompt) > 80 else ''}[/white]")
|
|
@@ -86,6 +86,7 @@ class CollectorUI:
|
|
|
86
86
|
def error(self, message: str) -> None:
|
|
87
87
|
"""Display error message."""
|
|
88
88
|
from .tui import ERROR_CTA
|
|
89
|
+
|
|
89
90
|
self.console.print()
|
|
90
91
|
self.console.print(f" [dim]![/dim] [red]error:[/red] {message}")
|
|
91
92
|
self.console.print(f" [dim]{ERROR_CTA}[/dim]")
|
{reverse_api_engineer-0.4.3 → reverse_api_engineer-0.4.5}/src/reverse_api/copilot_engineer.py
RENAMED
|
@@ -69,7 +69,7 @@ class CopilotEngineer(BaseEngineer):
|
|
|
69
69
|
)
|
|
70
70
|
return None
|
|
71
71
|
|
|
72
|
-
self.ui.header(self.run_id, self.prompt, self.copilot_model, self.sdk)
|
|
72
|
+
self.ui.header(self.run_id, self.prompt, self.copilot_model, self.sdk, mode="engineer")
|
|
73
73
|
self.ui.start_analysis()
|
|
74
74
|
|
|
75
75
|
prompt = self._build_analysis_prompt()
|