pi-powershell
Robust PowerShell extension for pi on Windows — token-based bash-to-PS translation, background jobs, diagnostics
Package details
Install pi-powershell from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-powershell- Package
pi-powershell- Version
3.0.0- Published
- Jun 19, 2026
- Downloads
- 517/mo · 37/wk
- Author
- ngsoftware
- License
- MIT
- Types
- extension
- Size
- 87.3 KB
- Dependencies
- 0 dependencies · 1 peer
Pi manifest JSON
{
"ps": {
"executable": "auto",
"translate": "hint",
"strict": false,
"utf8": true,
"killTreeOnAbort": true,
"aliasFile": "~/.pi-ps/aliases.json"
},
"extensions": [
"./src/extension.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-ps
Robust PowerShell extension for pi on Windows — token-based bash↔PS translation, background jobs, live background windows, diagnostics, and local telemetry.
Published on npm as pi-powershell — this is the v2 rewrite of the
package (1.x used a fragile regex translator). The command is /ps and
the config dir is ~/.pi-ps/.
Why?
The earlier 1.x release used a fragile regex-based bash→PS translator that broke on quoted args, spaces in paths, and nested pipes. This rewrite fixes all of that:
- Token-based parser — handles quoted args, multi-pipe chains, redirections, subshells
- 3 translation modes —
off(verbatim),hint(tips only),auto(rewrite) - Proper kill-tree —
taskkill /T /Fon abort, not just leader PID - Tracked background jobs —
/ps job startruns commands hidden with PID tracking and log files; inspect withjob log, stop withjob kill - Live background windows —
/ps runopens a visible PowerShell window (the direct successor torun-bg.ps1) for commands you want to watch - Open a new PowerShell tab —
/ps newand/ps clonespawn a separate PowerShell session beside pi (real Windows Terminal tab when available, otherwise a new window) - Diagnostics —
pi-ps doctorfor troubleshooting - Local telemetry — opt-in, privacy-first, never leaves your machine
- 120+ tests — translator rules, shell resolution, diagnostics, open-tab, visible window
Install
pi install npm:pi-powershell
Or local development:
pi -e ./src/extension.ts
Commands
| Command | Description |
|---|---|
/ps |
Show current status |
/ps doctor |
Full diagnostics (version, path, policy, UTF-8, peer deps) |
/ps translate "<cmd>" |
Dry-run translation (shows what would happen) |
/ps exec "<cmd>" |
Execute command explicitly through PS |
/ps new |
Open a new PowerShell tab at the standard location |
/ps clone |
Open a new PowerShell tab at pi's current path |
/ps run "<cmd>" |
Run a command in a new live window (replaces run-bg.ps1) |
/ps job start "<cmd>" |
Start a command as a tracked background job (hidden, logged) |
/ps job list |
List background jobs |
/ps job log <id> |
Show job output |
/ps job kill <id> |
Kill a background job |
/ps job cleanup |
Remove stale job files |
Opening a New PowerShell Tab
Pi occupies your terminal while it runs. /ps new and /ps clone
spawn a separate PowerShell session beside it so you can run a manual
command without interrupting pi:
| Command | Opens at |
|---|---|
/ps new |
The standard location (your Windows Terminal default profile's starting dir) |
/ps clone |
Pi's current working directory (same path) |
Host detection is automatic:
- Inside Windows Terminal (
WT_SESSIONis set) →wt.exe -w 0 new-tab, a real new tab in the current window. The-w 0(a.k.a.--window last) option explicitly targets the most-recently-used WT window; without it, launchingwt.exeas a detached child opens a brand-new window instead of reusing the current one (see microsoft/terminal#5447).Note:
-w 0targets the most-recently-used window, not the window identified byWT_SESSION(thewt.exeCLI cannot target windows by session id). If you have several WT windows open and the MRU one isn't the one running pi, the new tab will land in the MRU window. Click into the pi window first to make it MRU. - Otherwise (plain console / conhost) →
Start-Process pwsh, a new window (there is no tab concept outside Windows Terminal).newopens at your home directory;cloneopens at pi's cwd.
The tab/window always launches the same PowerShell pi is using (pwsh 7 if available, otherwise Windows PowerShell 5.1).
Running a Command in a New Window
/ps run "<cmd>" runs a command in a separate, visible PowerShell
window — the direct successor to the old run-bg.ps1. Use it for
long-running things you want to watch live (dev servers, file watchers,
tail logs) without them competing with pi for the current terminal:
/ps run "npm run dev"
/ps run "node server.js --port 3000"
The window stays open for as long as the command runs. The launcher is hidden and fire-and-forget, so closing pi does not depend on it.
Prefer /ps job start "<cmd>" when you want a hidden, tracked
job with its output captured to a log file you can inspect later with
/ps job log <id> and stop with /ps job kill <id>.
Background Jobs
/ps job start "<cmd>" runs a command as a hidden, tracked background
process — output is captured to a log file and the process is tracked by a
stable job id, so you can inspect or stop it later without keeping a window
open:
/ps job start "npm run build"
# → Started job job-1718793600001 (PID 12345)
| Command | Action |
|---|---|
/ps job start "<cmd>" |
Start a new background job |
/ps job list |
List tracked jobs (status, PID, command) |
/ps job log <id> |
Show captured output for a job |
/ps job kill <id> |
Kill a running job and its child processes |
/ps job cleanup |
Remove stale job files older than 24h |
Job metadata and logs live under ~/.pi-ps/jobs/ (<id>.json and <id>.log).
job kill uses taskkill /T /F so child processes are cleaned up rather
than orphaned.
run vs job start — when to use which?
/ps run→ you want to see it live (dev server, file watcher). Opens a visible window./ps job start→ you want it out of the way (build, export, long script). Hidden + logged.
Translation Modes
Set via PI_PS_TRANSLATE env var or pi.ps.translate in package.json:
| Mode | Behavior |
|---|---|
off |
Pass command verbatim to PowerShell |
hint (default) |
Detect bash idioms, run as-is, append PS tip to stderr |
auto |
Rewrite bash to PS, run the PS version |
Translation Support
Basic Commands
| Bash | PowerShell |
|---|---|
ls, ll, la |
Get-ChildItem |
pwd |
Get-Location |
cd dir |
Set-Location |
cat file |
Get-Content |
echo text |
Write-Output |
mkdir dir |
New-Item -ItemType Directory |
touch file |
New-Item -ItemType File |
rm -rf dir |
Remove-Item -Recurse -Force |
cp src dst |
Copy-Item |
mv src dst |
Move-Item |
grep pattern file |
Select-String |
find . -name "*.ts" |
Get-ChildItem -Recurse | Where-Object |
which cmd |
Get-Command | Select-Object -ExpandProperty Source |
ps |
Get-Process |
env |
Get-ChildItem Env: |
export VAR=val |
$env:VAR = val |
date |
Get-Date |
whoami |
[WindowsIdentity]::GetCurrent().Name |
sleep 5 |
Start-Sleep -Seconds 5 |
clear |
Clear-Host |
basename/dirname |
Split-Path -Leaf/-Parent |
test -f file |
Test-Path -PathType Leaf |
seq 1 10 |
1..10 |
Pipe Chains
| Bash | PowerShell |
|---|---|
ls | grep foo |
Get-ChildItem | Where-Object { $_ -match 'foo' } |
ls | head -5 |
Get-ChildItem | Select-Object -First 5 |
ls | tail -3 |
Get-ChildItem | Select-Object -Last 3 |
cat file | sort |
Get-Content file | Sort-Object |
cat file | uniq |
Get-Content file | Select-Object -Unique |
ls | wc -l |
Get-ChildItem | Measure-Object -Line |
Native Passthrough
PowerShell cmdlets pass through unchanged:
Get-*,Set-*,New-*,Remove-*etc. (Verb-Noun pattern)$variableexpressions&call operator,.dot-source
Settings
In package.json under pi.ps:
{
"pi": {
"ps": {
"executable": "auto",
"translate": "hint",
"strict": false,
"utf8": true,
"killTreeOnAbort": true,
"aliasFile": "~/.pi-ps/aliases.json"
}
}
}
Environment Variables
| Variable | Default | Description |
|---|---|---|
PI_PS_EXEC |
auto | Override PowerShell executable path |
PI_PS_TRANSLATE |
hint | Translation mode: off, hint, auto |
PI_PS_STRICT |
0 | Set $ErrorActionPreference = 'Stop' |
PI_PS_UTF8 |
1 | Enable UTF-8 encoding prefix |
PI_PS_KILL_TREE |
1 | Kill process tree on abort |
PI_PS_LOAD_PROFILE |
0 | Load user PS profile (default: -NoProfile) |
PI_PS_ALIAS_FILE |
~/.pi-ps/aliases.json | Custom alias file |
PI_PS_TELEMETRY |
0 | Enable local metrics recording |
Shell Resolution
Probe order:
$env:PI_PS_EXECoverridepwsh.exein PATHC:\Program Files\PowerShell\7\pwsh.exe- Windows PowerShell 5.1
If none found: extension disables with a structured warning (never silently routes to bash).
Diagnostics
/ps doctor
Outputs: shell version, resolved path, profile path, execution policy, UTF-8 status, peer dep version, last 10 translations, warnings.
Telemetry (Opt-in)
Set PI_PS_TELEMETRY=1 to record to ~/.pi-ps/metrics.jsonl:
- Command hash (SHA-256 truncated, never plaintext)
- Translation applied y/n
- Exit code
- Duration ms
Never sent over the network. Used purely for finding broken translations.
Testing
npm test # vitest run
npm run test:watch # vitest watch
npm run typecheck # tsc --noEmit
121 tests covering:
- Tokenizer (quoted args, pipes, redirections,
&&/||, semicolons) - Every translation rule (+/- cases)
- Idempotency (no double-rewrite)
- Shell resolution
- Diagnostics
- Open-tab (Windows Terminal
new/clone, fallback window, error path, path escaping) - Visible-window
run(Start-Process launch, command embedding, quoting, error path)
Requirements
- Windows (PowerShell 7+ recommended, or Windows PowerShell 5.1)
- Node.js 18+
- pi ≥ 0.74.0
License
MIT