Reviewed PR description, comments, commits, and changed files.
UnderstandIdentified and read linked issues.
UnderstandAnalyzed PR diff and relevant code files.
UnderstandChecked documentation and implementation details.
UnderstandProvided structured review with feedback and changelog note.
VerifyYou are given one or more GitHub PR URLs: https://github.com/badlogic/pi-mono/pull/903
For each PR URL, do the following in order:
packages/*/CHANGELOG.md files. Report whether an entry exists. If missing, state that a changelog entry is required before merge and that you will add it if the user decides to merge. Follow the changelog format rules in AGENTS.md. Verify:
### Breaking Changes, ### Added, ### Fixed, etc.)Fixed foo ([#123](https://github.com/badlogic/pi-mono/pull/123) by [@user](https://github.com/user))### Breaking Changes, not just ### FixedOutput format per PR: PR: Changelog:
If no issues are found, say so under Bad and Ugly.
The user wants me to review a GitHub PR. Let me start by fetching the PR details including description, comments, commits, and changed files.
>gh pr view 903 --repo badlogic/pi-mono --json title,body,comments,commits,files,author,labels,state,baseRefName,headRefName>gh pr diff 903 --repo badlogic/pi-monoLet me analyze this PR. The key changes are:
before_bash_exec event that allows extensions to intercept and modify bash commands before executionuv.ts that demonstrates this by redirecting Python invocations through uvLet me read the relevant source files to understand the context better.
Let me read the relevant files to fully understand the context and validate the implementation:
Now let me check the changelog and the shell.ts utility, and look at the existing bash-executor to understand the full implementation:
Now let me check the index.ts to see what's exported and examine the documentation files:
Let me also check if there's related documentation in the README.md:
Let me check the README.md and understand what documentation changes might be needed:
>grep -n "before_bash_exec\|user_bash\|bash_exec\|BashExec" packages/coding-agent/README.md packages/coding-agent/docs/*.md 2>/dev/null | head -100>cd /Users/badlogic/workspaces/pi-mono && grep -n "BeforeBashExecEvent\|before_bash_exec" packages/coding-agent/src --include="*.ts" -rLet me search more carefully for the new types added:
>cd /Users/badlogic/workspaces/pi-mono && grep -rn "BeforeBashExec\|before_bash_exec" packages/coding-agent/src/Hmm, seems like the grep didn't find anything. But the PR diff shows the changes. Let me re-check the current state of main branch to see if these files exist there:
>cd /Users/badlogic/workspaces/pi-mono && git log --oneline -5>cd /Users/badlogic/workspaces/pi-mono && gh pr view 903 --json headRefOid,baseRefOidThe PR is targeting a specific base commit that's not on my current HEAD. Let me understand the diff better and analyze it:
From the PR diff, I can see:
New types added in types.ts:
BashExecSource - "tool" | "user_bash"BashExecOverrides - interface for command/cwd/env/shell/args overridesBashExecEvent - base event with command, originalCommand, cwd, env, shell, argsBeforeBashExecEvent - extends BashExecEvent with type: "before_bash_exec"BeforeBashExecEventResult - alias for BashExecOverridesNew method in runner.ts:
emitBeforeBashExec(event) - emits the new event to extensionsAgent session changes (agent-session.ts):
before_bash_exec event for user bash commands (! prefix)Wrapper changes (wrapper.ts):
before_bash_exec eventNew example extension (uv.ts):
Exports in index.ts:
Now let me evaluate the PR:
Issues I see:
wrapper.ts changes intercept the bash tool, but the execEvent values like cwd, env, shell, args are not being passed to the actual bash executor. The executeBash and executeBashWithOperations functions in bash-executor.ts don't accept these parameters. The only thing being passed is execEvent.command. So the extensions can modify cwd, env, shell, args but they're ignored.The user bash path in agent-session.ts has the same problem—it doesn't apply the overrides to actual execution. Additionally, some core types like BashExecSource, BashExecOverrides, and BashExecEvent aren't exported from index.ts, only the event and result types are. The documentation in docs/extensions.md also doesn't cover the new before_bash_exec event, only mentioning user_bash.
There's no changelog entry for this feature, and the models.generated.ts changes appear to be unrelated model updates that should probably be in a separate commit. I need to check how the bash-executor is actually being invoked to understand the full picture.
Let me verify a key implementation detail - whether the bash-executor can accept the overridden values:
Now I understand better. The bash tool has a BashOperations interface that allows custom execution. But looking at the PR:
In wrapper.ts, the PR intercepts the bash tool and emits before_bash_exec, but only uses execEvent.command to update the params. The cwd, env, shell, args overrides are computed but NOT passed to the actual execution.
In agent-session.ts, for user bash (!), the event is emitted but only the command is used. The cwd, env, shell, args are not passed.
This is a significant gap in the implementation. The PR adds the ability for extensions to return these overrides, but they're not being applied.
Let me also check what the example extension uv.ts expects:
Looking at uv.ts:
pi.on("before_bash_exec", (event) => { // ... return { command: uvCommand, // Only returns command };});The example only modifies command, so it would work. But the types advertise that extensions can also modify cwd, env, shell, args, which would not work.
Summary of Issues:
cwd, env, shell, args overrides are not applied to actual bash executionBashExecSource, BashExecOverrides, BashExecEvent are not exportedbefore_bash_exec eventmodels.generated.ts changes should be a separate commitLet me write up the review.
Now I have a complete picture. Let me provide the structured review.
PR: https://github.com/badlogic/pi-mono/pull/903
Changelog:
Good:
BeforeBashExecEvent is well-structured with source ("tool" | "user_bash"), originalCommand, and full execution context (cwd, env, shell, args)emitBeforeBashExec() using applyBashExecOverrides follows established patterns in the codebaseuv.ts example is practical and demonstrates a real use case (redirecting Python through uv)! prefix), providing unified interceptionBad:
Incomplete implementation of overrides: Extensions can return cwd, env, shell, args overrides, but these are NOT applied to actual execution:
wrapper.ts (lines 81-95): only execEvent.command is used to update effectiveParams, the other overrides are ignoredagent-session.ts (lines 1776-1792): only execEvent.command is passed to executeBash/executeBashWithOperations, the cwd, env, shell, args overrides are computed but discardedexecuteBash() and executeBashWithOperations() functions don't even accept these parametersMissing exports: BashExecSource, BashExecOverrides, BashExecEvent types are defined but not exported in index.ts. Only BeforeBashExecEvent and BeforeBashExecEventResult are exported.
Unrelated changes in PR: The models.generated.ts diff contains model pricing updates (cacheWrite values, removal of qwen/qwen2.5-vl-72b-instruct, cacheRead change for a model) that are unrelated to bash interception. These should be a separate commit.
No documentation: The docs/extensions.md documents user_bash but the new before_bash_exec event is not documented.
Ugly:
BeforeBashExecEventResult type (aliased to BashExecOverrides) advertises that extensions can override cwd, env, shell, args, but these are silently ignored. This is a footgun for extension authors who will expect these to work based on the types.Questions or Assumptions:
command rewriting initially, with cwd/env/shell/args planned for a follow-up? If so, the types should be narrowed or documented as "not yet implemented".before_bash_exec be emitted for user bash (! prefix) at all? The existing user_bash event already handles that case. Having both events fire could be confusing.Change summary:
before_bash_exec extension event for intercepting bash commands before execution! commandscommand (other overrides are defined but not implemented)uv.ts demonstrating Python-to-uv redirectionmodels.generated.tsTests:
pi.on("before_bash_exec", (event) => { // ... return { command: uvCommand, // Only returns command };});