You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Claude stores one shell-form command per hook. Paseo wrote the POSIX command on every platform, so native Windows Claude installations that select PowerShell fail while parsing [ -n ... ] before the terminal guard can run.
Windows now gets powershell.exe -NoProfile -NonInteractive -EncodedCommand <base64> with a UTF-16LE payload. Encoding avoids nested quoting and shell-tokenization problems. The wrapper preserves the terminal guard, CLI override, PATH fallback, child exit status, and inherited stdin. macOS and Linux keep the existing POSIX command.
The encoded command is opaque, so install detection and uninstall compare it with the exact command Paseo generates while retaining marker matching for legacy POSIX hooks.
Goals
Make all generated Claude hooks executable through Windows PowerShell.
Preserve PASEO_TERMINAL_ID, PASEO_HOOK_CLI, PATH fallback, exit-code, and stdin behavior.
Keep install and uninstall idempotent without removing unrelated user hooks.
Changing Claude event handling or activity mapping.
#3877 remains open and changes the analogous Codex Windows helper. This PR leaves Codex untouched and remains independently reviewable. If #3877 lands first, this branch can be rebased to reuse its encoded PowerShell helper.
QA
Windows 11 with Windows PowerShell 5.1:
Reproduced the old command under PowerShell: exit 1 with ParserError.
Executed the command read back from an isolated generated Claude settings file.
Verified all five no-terminal guards exit 0, and the guarded CLI is not invoked.
cd packages/server
npx vitest run src/terminal/agent-hooks/claude/claude.test.ts src/terminal/agent-hooks/codex/codex.test.ts src/terminal/agent-hooks/terminal-agent-hook-setting.test.ts --bail=1
# 3 files passed; 31 tests passed; 5 POSIX-only tests skipped on Windows
npm run typecheck --workspace=@getpaseo/server
# passed
npm run build:server
npm run typecheck
# passed
npm run lint -- docs/terminal-activity.md packages/server/src/terminal/agent-hooks/agent-hook-installer.ts packages/server/src/terminal/agent-hooks/claude/claude-settings.ts packages/server/src/terminal/agent-hooks/claude/claude.test.ts
# 0 warnings, 0 errors
npm run format:check:files -- docs/terminal-activity.md packages/server/src/terminal/agent-hooks/agent-hook-installer.ts packages/server/src/terminal/agent-hooks/claude/claude-settings.ts packages/server/src/terminal/agent-hooks/claude/claude.test.ts
# passed
Claude Code CLI was not installed in this environment, so an actual Claude session was not run. macOS/Linux runtime QA was not run locally; the POSIX generator is unchanged and its exact command remains covered.
Checklist
Plugin changes follow the SDK import boundaries (not applicable; no plugin changes)
One focused change
npm run typecheck passes
npm run lint passes for the changed source files
Changed files pass the repository formatter and formatting check
This PR makes Claude hooks executable on native Windows installations by generating UTF-16LE base64-encoded PowerShell commands while retaining the existing POSIX commands elsewhere.
Adds a PowerShell hook-command generator preserving the terminal guard, CLI override, stdin, and child exit status.
Centralizes Claude’s platform-aware command selection across installation, uninstallation, and detection.
Adds platform-specific command and Windows runtime coverage.
Documents the platform-specific Claude hook behavior and lifecycle matching.
Confidence Score: 5/5
The current changes appear safe to merge, although the existing non-blocking concern about version-stable identity for encoded Windows hooks remains unresolved.
No new actionable failure was introduced since the previous review. The platform discriminator is now centralized, and the tests no longer branch conditionally inside test bodies. The earlier encoded-hook identity finding remains outstanding because lifecycle detection and cleanup still depend on exact equality with the current generated payload, so a future payload change can orphan older hooks. The two rule-linked threads were manually resolved without explanatory replies.
Centralizes platform-aware Claude command selection and reuses it throughout hook lifecycle operations; the previously reported lack of stable identity for encoded hooks remains outstanding.
Splits platform expectations into gated tests and covers Windows execution, stdin forwarding, command resolution, and exit statuses.
docs/terminal-activity.md
Documents Claude’s POSIX and encoded PowerShell hook behavior.
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
I[Install Claude hooks] --> P{Host platform}
P -->|Windows| W[Generate encoded PowerShell command]
P -->|macOS or Linux| S[Generate POSIX shell command]
W --> C[Write Claude command hook]
S --> C
C --> G{PASEO_TERMINAL_ID set?}
G -->|No| X[Exit successfully]
G -->|Yes| R[Resolve PASEO_HOOK_CLI or paseo]
R --> H[Run paseo hooks claude event]
H --> E[Propagate child exit status]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Linked issue
Fixes #4554
Type of change
Reasoning
Claude stores one shell-form
commandper hook. Paseo wrote the POSIX command on every platform, so native Windows Claude installations that select PowerShell fail while parsing[ -n ... ]before the terminal guard can run.Windows now gets
powershell.exe -NoProfile -NonInteractive -EncodedCommand <base64>with a UTF-16LE payload. Encoding avoids nested quoting and shell-tokenization problems. The wrapper preserves the terminal guard, CLI override, PATH fallback, child exit status, and inherited stdin. macOS and Linux keep the existing POSIX command.The encoded command is opaque, so install detection and uninstall compare it with the exact command Paseo generates while retaining marker matching for legacy POSIX hooks.
Goals
PASEO_TERMINAL_ID,PASEO_HOOK_CLI, PATH fallback, exit-code, and stdin behavior.Non-goals
#3877 remains open and changes the analogous Codex Windows helper. This PR leaves Codex untouched and remains independently reviewable. If #3877 lands first, this branch can be rebased to reuse its encoded PowerShell helper.
QA
Windows 11 with Windows PowerShell 5.1:
1withParserError.0, and the guarded CLI is not invoked..cmdpath,paseo.cmdPATH fallback,.cmdexit7, native executable exit2, unresolved-command exit1, exact arguments, and byte-preserving Notification stdin forwarding.Claude Code CLI was not installed in this environment, so an actual Claude session was not run. macOS/Linux runtime QA was not run locally; the POSIX generator is unchanged and its exact command remains covered.
Checklist
npm run typecheckpassesnpm run lintpasses for the changed source files