Skip to content

Make run/list language-aware and fix Windows run-command quoting#106

Merged
kalil0321 merged 3 commits into
mainfrom
fix-multi-language-run-support
Jul 22, 2026
Merged

Make run/list language-aware and fix Windows run-command quoting#106
kalil0321 merged 3 commits into
mainfrom
fix-multi-language-run-support

Conversation

@kalil0321

@kalil0321 kalil0321 commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Fixes the outstanding issues found while testing the six output-language PRs (#100#105).

1. run/list were Python-only (found on #100, affected every language)

discover_scripts() only globbed .py, so reverse-api-engineer run <run_id> failed with "No Python scripts found" for JS/TS/Go/Java/C#/PHP/Ruby/C clients, and the run path always executed the shared-venv Python interpreter.

  • Discovery now covers all supported extensions, with the language→extension map moved to utils.OUTPUT_LANGUAGE_EXTENSIONS as the single source of truth (BaseEngineer reuses it), and excludes build dirs (node_modules, bin, obj, target) and the vendored cJSON.c/cJSON.h.
  • build_script_commands() dispatches per language: node / npx tsx / go run / mvn -q -f pom.xml compile exec:exec / dotnet run --project / php / ruby, and compile-then-execute for C. Missing toolchains produce a clear error naming the required binary instead of a crash. Java rejects extra script args explicitly (mvn exec's program args are fixed in the pom); C# passes them after --.
  • Both the machine (--json/--json-stream) and interactive run paths use the dispatch; the Python venv flow is unchanged.

2. Windows quoting (flagged on #101#105)

The Java/C#/PHP/Ruby/C run commands quoted paths with POSIX-only shlex.quote, which cmd.exe/PowerShell parse incorrectly for paths containing spaces. BaseEngineer._quote_path() now uses subprocess.list2cmdline on Windows and shlex.quote elsewhere.

3. C compiler warnings (found on #105, minor)

The C partial now asks for -Wall -Wextra-clean code — the live-tested client had unused-parameter warnings.

Testing

  • 771 tests pass (21 new: multi-language discovery, cJSON/build-dir exclusion, per-language command dispatch).
  • ruff: exactly the 19 pre-existing findings on the touched files, none new.
  • Verified live against real clients generated during the Add go output language #100Add C as a supported output language #105 testing sessions: run --json executed the Go, PHP, C (compile step included), C#, and Ruby clients end-to-end with exit 0. (The Java run surfaced a runtime fragility in that one generated artifact's second example call — the dispatch itself correctly ran Maven and propagated the exit code.)

🤖 Generated with Claude Code

https://claude.ai/code/session_01KpXzPMFT1X8YCZQcxaFYVE


Summary by cubic

Make run and list work across all output languages and fix Windows path quoting so commands run reliably. Discovery is now robust across directories, and commands use absolute paths to run correctly from any working directory.

  • Bug Fixes
    • Script discovery covers all supported extensions and ignores support files (cJSON.*, __init__.py). It no longer misfires when parent paths contain build-dir names; utils.OUTPUT_LANGUAGE_EXTENSIONS is the single source of truth.
    • Run dispatch is per language (node, npx tsx, go run, mvn -q -f pom.xml compile exec:exec, dotnet run --project, php, ruby; C compiles then runs). Commands use absolute paths and run with cwd=script.parent. Clear missing-tool errors; in machine mode they are config_invalid. Java rejects extra args; C# forwards args after --.
    • Windows-safe quoting for run commands: uses subprocess.list2cmdline on Windows and shlex.quote elsewhere. Documented PowerShell $/backtick limits; cmd.exe-safe quoting is the baseline.
    • CLI copy now says “No runnable scripts” when nothing is found.

Written for commit 21fc967. Summary will update on new commits.

Review in cubic

Greptile Summary

This PR makes script discovery and execution aware of every supported output language. The main changes are:

  • Centralized language-to-extension mappings.
  • Added toolchain-specific commands for non-Python clients.
  • Added platform-specific quoting for generated run commands.
  • Expanded discovery and command-building tests.
  • Updated C generation guidance to avoid compiler warnings.

Confidence Score: 5/5

The changed flow looks mergeable after a small PowerShell quoting cleanup.

  • Language-specific execution uses argv lists and clear tool checks.
  • Known generated support files are excluded from discovery.
  • PowerShell metacharacters in generated command paths can still be interpreted by the shell.

src/reverse_api/base_engineer.py

Important Files Changed

Filename Overview
src/reverse_api/base_engineer.py Reuses the centralized extension map and adds Windows path quoting, but the quoting does not safely cover PowerShell metacharacters.
src/reverse_api/cli.py Routes non-Python clients through language-specific subprocess commands in interactive and machine-readable modes.
src/reverse_api/utils.py Adds shared extension constants, multilingual script discovery, and argv-based command construction for each supported toolchain.
tests/test_run_command.py Adds broad discovery and command-construction coverage, without Windows shell-specific path cases.
src/reverse_api/prompts/partials/_language_c.md Adds guidance for warning-clean generated C code.
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
src/reverse_api/base_engineer.py:485-486
**PowerShell Paths Remain Unsafe**

`list2cmdline()` applies Windows C-runtime/cmd.exe quoting, but the returned text is interpolated into a shell command that may run in PowerShell. A valid path containing PowerShell metacharacters such as `$` or a backtick can therefore be expanded or escaped, causing the generated run command to use the wrong path or fail.

Reviews (1): Last reviewed commit: "Make run/list language-aware and quote r..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

Two gaps found while testing the language PRs (#100-#105):

- discover_scripts() only globbed .py, so 'reverse-api-engineer run' and
  'list' reported 'No Python scripts found' for every non-Python client,
  and the run path always executed the shared-venv Python interpreter.
  Discovery now covers all supported extensions (single source of truth
  in utils.OUTPUT_LANGUAGE_EXTENSIONS, shared with BaseEngineer),
  excludes build dirs and the vendored cJSON sources, and the run
  command dispatches per language - node/npx tsx/go run/mvn exec:exec/
  dotnet run/php/ruby, plus compile-then-execute for C - with a clear
  error when the required tool is missing from PATH.

- The Java/C#/PHP/Ruby/C run commands quoted paths with POSIX-only
  shlex.quote, which cmd.exe/PowerShell parse incorrectly for paths
  with spaces. BaseEngineer._quote_path() now uses
  subprocess.list2cmdline on Windows and shlex.quote elsewhere.

Also asks the C partial for -Wall -Wextra-clean code (generated client
had unused-parameter warnings in live testing).

Verified live: run --json executed real generated Go/PHP/C/C#/Ruby
clients from earlier agent sessions end-to-end (C compiling first).
@cursor

cursor Bot commented Jul 22, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

Comment on lines +485 to +486
if sys.platform == "win32":
return subprocess.list2cmdline([str(path)])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 PowerShell Paths Remain Unsafe

list2cmdline() applies Windows C-runtime/cmd.exe quoting, but the returned text is interpolated into a shell command that may run in PowerShell. A valid path containing PowerShell metacharacters such as $ or a backtick can therefore be expanded or escaped, causing the generated run command to use the wrong path or fail.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/reverse_api/base_engineer.py
Line: 485-486

Comment:
**PowerShell Paths Remain Unsafe**

`list2cmdline()` applies Windows C-runtime/cmd.exe quoting, but the returned text is interpolated into a shell command that may run in PowerShell. A valid path containing PowerShell metacharacters such as `$` or a backtick can therefore be expanded or escaped, causing the generated run command to use the wrong path or fail.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acknowledged — this is a real boundary, but not one that quoting can close: PowerShell expands $/backtick inside double quotes, while PowerShell-safe alternatives (single quotes, backtick escapes) are parsed literally/incorrectly by cmd.exe, and the executing shell isn't detectable from here. list2cmdline (cmd.exe/CreateProcess-safe) is the deliberate baseline; 21fc967 documents in the docstring that Windows paths containing $/backtick are unsupported. Happy to revisit if we ever pin the agent's shell on Windows.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6544087f2f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/reverse_api/utils.py Outdated
if f.is_file() and f.suffix == ".py" and f.name not in exclude_files:
if f.is_file() and f.suffix in SCRIPT_EXTENSIONS and f.name not in exclude_files:
scripts.append(f)
scripts = [s for s in scripts if not any(part in exclude_dirs for part in s.parts)]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Compare excluded dirs relative to scripts_dir

When a custom output directory contains one of these newly added names, this filters out every generated client because s.parts includes the entire path, not just children below the scripts directory; for example output_dir=/tmp/target makes /tmp/target/scripts/<run>/api_client.go look like it is inside an excluded build dir and run/--ls report no scripts. Since this function only iterates direct children of scripts_dir, compare relative parts or remove this filter.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed and fixed in 21fc967 — reproduced with output_dir=/tmp/target/... returning zero scripts. Since iterdir() doesn't recurse and non-files are already skipped, the parts-based filter could only ever misfire on parent components, so it's removed entirely (with a comment explaining why no explicit build-dir filter is needed). Regression test added.

Comment thread src/reverse_api/utils.py
ValueError: For unsupported extensions, or script_args with a Java
client (mvn exec's program arguments are fixed in the pom).
"""
d = script.parent

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Resolve script paths before changing cwd

If the configured output_dir is relative, discover_scripts() returns a relative script, but both non-Python runners execute the argv with cwd=script.parent; e.g. out/scripts/<run>/api_client.js is then resolved by node from out/scripts/<run> as out/scripts/<run>/out/scripts/<run>/api_client.js, so every non-Python client fails to start. Build commands from script.resolve() or pass only the filename once the cwd is changed.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed and fixed in 21fc967build_script_commands() now resolves the script path before building argv, so commands stay absolute regardless of a relative output_dir, and cwd=script.parent can no longer re-anchor them. Verified live with a relative path + node subprocess, plus a regression test.

- The missing-toolchain message contained 'not found', which
  _classify_error's heuristics remap to engine_failure, overriding the
  config_invalid hint. Reworded so the intended kind survives.
- Unit tests for _quote_path on both platforms (list2cmdline quoting on
  win32, shlex on POSIX) and for spaced paths surviving intact in the
  dispatch argv lists.

Live matrix via the CLI: go/php/c/csharp/ruby clients from the language-PR
test sessions plus hand-written js/ts clients all ran with exit 0,
including --file selection, --ls listing, args passthrough (node),
the Java script-args misuse error, and the missing-tool config_invalid
error under a stripped PATH.
…s, document quoting boundary

- discover_scripts filtered on every component of the full path, so a
  custom output_dir under a directory named like a build dir (e.g.
  /tmp/target/...) excluded all scripts. iterdir() doesn't recurse and
  non-files are already skipped, so the parts-based filter could only
  misfire - removed it.
- build_script_commands now resolves the script path before building
  argv: callers run with cwd=script.parent, which would re-anchor a
  relative path (from a relative output_dir) and fail to start.
- _quote_path docstring now states the Windows quoting boundary
  precisely: list2cmdline is cmd.exe/CreateProcess-safe; PowerShell
  additionally expands $/backtick inside double quotes and no quoting
  satisfies both shells for such paths.
@kalil0321
kalil0321 merged commit 40c4618 into main Jul 22, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant