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
Start-Transcript now records the commands the AI runs, not just their output (Discussion #57). A transcript started in an MCP console — from your $PROFILE or by hand — captured the output of every command but not a single command line, leaving a log of results with no record of what produced them. The console's echo of the incoming command was written straight to the terminal with [Console]::Write, token by token, to colour it the way PSReadLine would; that path bypasses the host UI, which is where transcription taps. The echo now goes through the host as a single Write-Host call, so the command lands in the transcript as one plain line — transcription strips the ANSI, leaving text you can grep — directly above the output it produced. One call rather than one per token is deliberate: transcription writes one record per call, so a per-token echo would arrive in the file shredded across one line per token. The echo still runs before the stream capture is installed, so it is not reflected back into the result the AI sees. With default settings the visible echo looks as before, for multi-line commands and for one that fails to parse too; because it now goes through the host it also follows $PSStyle.OutputRendering, so with PlainText (which NO_COLOR selects) it is shown without colour. For anyone who turns transcription on, this makes Start-Transcript a complete per-console record of an AI session — command and output, in order. The new Auditing an AI Session section in SECURITY.md covers it alongside PowerShell's Script Block Logging.
Register-PwshToClaudeCode can now point Claude Code at a newly installed proxy. Re-registering over an existing pwsh entry failed: claude mcp add refuses a name already registered at the same scope, so after Update-Module PowerShell.MCP the cmdlet only relayed the CLI's refusal and Claude Code went on launching the previous install's proxy — the one the stale entry still named, and the one whose version-mismatch error tells you to run this very cmdlet. The user-scope entry is now removed and re-added, which turns registration into an update; the arguments and environment variables it carried (--no-profile, POWERSHELL_MCP_TIMEOUT_CEILING, …) are carried across, and if the new entry cannot be added the old one is put back. The entry is read from an empty directory, because claude mcp get reports only the entry that wins for the current directory: an entry of your own at local or project scope no longer hides the user-scope one from the update, and is itself left alone and named in a warning, since it still takes precedence where it applies. A failed add is reported as a PowerShell error rather than only by the CLI, and the reminder to restart Claude Code now follows a first registration too. The migration of the legacy PowerShell entry also runs for the first time: it probed with claude mcp get PowerShell -s user, but mcp get takes no -s, so the probe always failed with "unknown option"; it now reports a removal only when one actually happened.
Register-PwshToClaudeDesktop no longer drops an entry's args and env. It could always repoint the command at a newly installed proxy, but it did so by assigning a fresh { "command": ... } over the whole pwsh entry, discarding the args (proxy flags such as --no-profile) and env (settings such as POWERSHELL_MCP_TIMEOUT_CEILING) that had been configured on it — silently, so the loss surfaced later as a flag that had stopped taking effect. Only the command is replaced now; everything else on the entry is left as it stands. The "Restart Claude Desktop to apply changes" notice is also shown when an existing entry is updated, not only when one is added — updating is precisely the case where the restart is what puts the new proxy into service.
A console the proxy has just started is no longer mistaken for one a user is typing in, which made it start a second console. A brand-new console could report itself busy with (user command) for 11–16 seconds although nobody had touched it, and the proxy, following its rule for a console a human is using, abandoned it and started another in the same tool call — one call, two new windows. The detector treats a runspace that has not ticked for 10 seconds as running a user's command, but a freshly launched console can go that long without ticking while its startup work finishes. A console launched by the proxy now has a startup window that closes on the first tick after the host shows its first prompt; until then a gap is startup work, so the command waits for that console instead of being routed elsewhere. The window closes after 60 seconds regardless, so a console that genuinely hangs before its first prompt is still reported busy, and a long-running command you type after startup is still detected as before. Consoles you import the module into by hand are unaffected.
Improvements
close_console now says a console has already exited instead of calling it "not owned". Asked to close a console that was already gone — typically an idle standby console that had closed itself minutes earlier — it answered PID … is not a console owned by this session, which reads as an ownership fault and invites a retry or an investigation. It now tells apart a PID that is no longer running, a PowerShell.MCP console that belongs to another session, agent or user, and a process that is not a PowerShell.MCP console at all.
wait_for_completion explains an empty answer instead of looking as if a command was lost. With nothing running and nothing cached it replied only "No commands to wait for completion." (or "No busy consoles or cached results."), which read as though a command still in progress had vanished — typically right after the MCP client moved a long call to the background. That call is still in flight in the proxy and receives its own result when the command finishes; the reply now says so.
The var1/var2 check now says it needs the tool argument, not a variable.Add-LinesToFile, Update-LinesInFile, Update-MatchInFile, and Remove-LinesFromFile -Pattern/-Contains are refused unless their text arrives through execute_command's var1/var2 arguments, but the error said only "requires the var2 parameter", so a pipeline that assigned $var2 = … itself was refused with a message it seemed to satisfy already. The error now names the execute_command argument and says that assigning the variable inside the pipeline does not count.
Internal
Tests/Run-AllTests.ps1 runs every integration suite. It collected *.Tests.ps1 from Tests/Integration without -Recurse, so everything below its top level — the Cmdlets and Scenarios suites, most of the integration coverage — was silently skipped by the runner RELEASE.md has maintainers run before tagging.
The post-release verification snippet in RELEASE.md creates its temporary directory before calling Save-Module, which requires the destination to exist.