Add Windows PowerShell hook commands - #2
Conversation
|
@liliwilson Would you be able to take a look when you have a chance? This implements the |
|
Hi @AndreKalberer — thanks for this PR, I've been running it on native Windows and it's very close, but I hit one blocking issue with the notification transport that I'd like to share along with a working fix. The problemOn native Windows (Windows 11, Windows PowerShell 5.1, Codex running inside Warp's ConPTY), Stdout/stderr can't be used as a fallback either: the Codex hook runner reserves stdout for hook-control JSON and captures stderr, so neither reaches the PTY. The fixWrite to the console directly through the Win32 API: diff --git a/plugins/warp/scripts/common.ps1 b/plugins/warp/scripts/common.ps1
index 6c91da7..5d40f26 100644
--- a/plugins/warp/scripts/common.ps1
+++ b/plugins/warp/scripts/common.ps1
@@ -123,18 +123,93 @@ function Send-WarpNotification {
$message = "$escape]777;notify;$Title;$Body$bell"
try {
- $stream = [System.IO.File]::Open("CONOUT$", [System.IO.FileMode]::Open, [System.IO.FileAccess]::Write, [System.IO.FileShare]::Write)
- try {
- $writer = New-Object System.IO.StreamWriter($stream, [Console]::OutputEncoding)
- $writer.AutoFlush = $true
- $writer.Write($message)
- } finally {
- if ($writer) {
- $writer.Dispose()
- } else {
- $stream.Dispose()
+ if (-not ("WarpConsoleWriter" -as [type])) {
+ Add-Type -TypeDefinition @"
+using System;
+using System.Runtime.InteropServices;
+
+public static class WarpConsoleWriter
+{
+ private const uint GenericWrite = 0x40000000;
+ private const uint FileShareRead = 0x00000001;
+ private const uint FileShareWrite = 0x00000002;
+ private const uint OpenExisting = 3;
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
+ private static extern IntPtr CreateFileW(
+ string fileName,
+ uint desiredAccess,
+ uint shareMode,
+ IntPtr securityAttributes,
+ uint creationDisposition,
+ uint flagsAndAttributes,
+ IntPtr templateFile);
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
+ private static extern bool WriteConsoleW(
+ IntPtr consoleOutput,
+ string buffer,
+ uint charsToWrite,
+ out uint charsWritten,
+ IntPtr reserved);
+
+ [DllImport("kernel32.dll")]
+ private static extern bool CloseHandle(IntPtr handle);
+
+ public static bool Write(string message)
+ {
+ IntPtr handle = CreateFileW(
+ "CONOUT$",
+ GenericWrite,
+ FileShareRead | FileShareWrite,
+ IntPtr.Zero,
+ OpenExisting,
+ 0,
+ IntPtr.Zero);
+
+ if (handle == new IntPtr(-1))
+ {
+ return false;
+ }
+
+ try
+ {
+ // WriteConsoleW counts UTF-16 chars and may write fewer than requested for
+ // large buffers, so loop until the whole message is out. Avoid splitting a
+ // surrogate pair at a chunk boundary.
+ int offset = 0;
+ while (offset < message.Length)
+ {
+ int chunkLength = Math.Min(16384, message.Length - offset);
+ if (offset + chunkLength < message.Length
+ && char.IsHighSurrogate(message[offset + chunkLength - 1]))
+ {
+ chunkLength--;
+ }
+
+ string chunk = message.Substring(offset, chunkLength);
+ uint written;
+ if (!WriteConsoleW(handle, chunk, (uint)chunk.Length, out written, IntPtr.Zero)
+ || written == 0)
+ {
+ return false;
+ }
+
+ offset += (int)written;
}
+
+ return true;
+ }
+ finally
+ {
+ CloseHandle(handle);
}
+ }
+}
+"@
+ }
+
+ [void][WarpConsoleWriter]::Write($message)
} catch {
# Hook stdout is reserved for Codex hook control JSON. If there is no
# attached console device, drop the notification rather than emittingImplementation notes:
Verification (Windows 11, Windows PowerShell 5.1.26100)
Two smaller observations while testing, take or leave:
Relates to warpdotdev/warp#13391 (Codex hooks on Windows defaulting to PowerShell). |
|
Thanks for the detailed report and patch, @TheQmaks. I reproduced the |
|
Verified
Keeping |
Summary
commandWindowsoverrides so Codex uses PowerShell hook entrypoints on Windows instead of invoking.shfiles directly.Linked Issue
Closes warpdotdev/warp#13391
Manual Windows Evidence
Before - upstream
mainuses.shhook commands on WindowsTested against upstream
mainatf11334d. Installingwarp@codex-warpand running the Codex hook smoke test causes Windows to show the app-selection dialog for opening a.shfile.before-sh-dialog-compressed.mp4
After - this PR uses PowerShell hook commands on Windows
Tested against this PR at
5c01e7c. Installingwarp@codex-warpfrom the patched branch and running the same Codex hook smoke test completes without the.shapp-selection dialog. The visible hook log showsSessionStart,UserPromptSubmit, andStopcompleting.after-powershell-hooks-compressed.mp4
Testing
Get-ChildItem -Recurse -Filter *.ps1 | ForEach-Object { ... [System.Management.Automation.Language.Parser]::ParseFile(...) ... }Get-Content -Raw plugins/warp/hooks/hooks.json | ConvertFrom-Json; Get-Content -Raw plugins/orchestration/hooks/hooks.json | ConvertFrom-JsonC:\Program Files\Git\bin\bash.exe tests/test-hooks.shon-session-start.ps1+ cleanup throughon-session-end.ps1warp@codex-warpfrom upstreammain(f11334d) and this PR branch (5c01e7c)