# pi-pwsh-native

[![npm version](https://img.shields.io/npm/v/pi-pwsh-native.svg)](https://www.npmjs.com/package/pi-pwsh-native)
[![CI](https://github.com/takomine/pi-pwsh-native/actions/workflows/ci.yml/badge.svg)](https://github.com/takomine/pi-pwsh-native/actions/workflows/ci.yml)

Native PowerShell 7 tooling for the [Pi coding agent](https://pi.dev/) on Windows.

`pi-pwsh-native` replaces Pi's model-callable `bash` tool with a tool named `pwsh` and routes interactive `!`/`!!` commands through the same verified PowerShell executable. It does not translate Bash syntax and does not silently fall back to another shell.

![PowerShell 7 preview](https://raw.githubusercontent.com/takomine/pi-pwsh-native/main/public/img.png)

## How this differs from `@4fu/pi-pwsh`

This package derives from [`@4fu/pi-pwsh`](https://github.com/4fuu/pi-pwsh), but it is a deliberately leaner shell replacement rather than a drop-in feature superset. The comparison below is against the audited upstream baseline, `@4fu/pi-pwsh@0.6.2`.

| Area | `pi-pwsh-native` | `@4fu/pi-pwsh@0.6.2` |
|---|---|---|
| Primary focus | Predictable, dependency-free foreground PowerShell execution | Feature-rich PowerShell execution with persistent jobs and interactive sessions |
| Model shell tool | Replaces `bash` with `pwsh` | Replaces `bash` with `pwsh` |
| Pi discovery tools | Preserves `ls`, `find`, and `grep` by default | Disables `ls`, `find`, and `grep` in favor of PowerShell |
| Interactive `!` / `!!` | Routes both through the verified PowerShell runtime | Does not replace Pi's `user_bash` handling |
| PowerShell executable | Resolves, verifies, and retains an absolute PowerShell 7 path | Probes PowerShell 7, while foreground execution invokes `pwsh` by name |
| Execution policy | No override by default; `Bypass` must be explicitly configured | Passes `-ExecutionPolicy Bypass` |
| Command transport | UTF-8 base64 source over stdin, avoiding Windows command-line limits | Injected source passed through `-Command` |
| `.cmd` fallback | No retry through `cmd.exe` | Can retry failed direct command-shim execution through `cmd /c` |
| Background jobs and PTYs | Intentionally omitted from the lean core | Includes detached jobs, ConPTY sessions, and user-request helpers |
| Runtime dependencies | None | Uses `node-pty` and `@xterm/headless` |
| Configuration | Strict JSON configuration plus environment overrides | Primarily opinionated built-in behavior |
| Missing/invalid PowerShell | Fails visibly without silently restoring Bash | Leaves the built-in Bash tool active when PowerShell is unavailable |

Choose `pi-pwsh-native` when you want a small, auditable PowerShell 7 replacement with dedicated Pi file/search tools left intact. Choose `@4fu/pi-pwsh` when persistent background jobs, PTYs, and its interactive helper layer are more important. Do not enable competing shell-adapter extensions simultaneously.

## Design

- Registers a real `pwsh` tool so models are prompted to write PowerShell, not POSIX shell syntax.
- Reuses Pi's built-in shell tool definition for streaming previews, the standard renderer, non-zero exit handling, tail truncation (2,000 lines / 50 KB), and full-output temporary files.
- Keeps Pi's dedicated `read`, `write`, `edit`, `ls`, `find`, and `grep` tools active by default. Dedicated tools avoid unnecessary PowerShell startup and usually produce more focused output.
- Routes user-entered `!command` and `!!command` through PowerShell by default while preserving Pi's context-inclusion semantics.
- Requires PowerShell 7 or newer. Windows PowerShell 5.1 and Bash are not fallbacks.
- Resolves and uses an absolute `pwsh.exe` path for every command.
- Uses an ASCII bootstrap plus base64-over-stdin source transport. This preserves Unicode and multiline source without Windows command-line length limitations.
- Forces plain UTF-8 output without a BOM and preserves native executable exit codes.
- Kills the full process tree on timeout or cancellation.
- Has no runtime dependencies, native install scripts, telemetry, or network calls.

## Requirements

- Windows
- PowerShell 7+
- Node.js 22.19 or newer
- Pi 0.83.0 or newer (before 1.0)

The current release is tested against:

- Pi `0.83.0` and `0.84.2`
- PowerShell `7.6.5`

## Installation

Install the pinned npm release:

```powershell
pi install npm:pi-pwsh-native@0.1.4
```

Alternatively, install the public GitHub package directly:

```powershell
pi install git:github.com/takomine/pi-pwsh-native
```

## Try from source

```powershell
Set-Location D:\pi\pi-pwsh-native
npm install --ignore-scripts
pi -e .\src\index.ts
```

For global development use, add the source path to `~/.pi/agent/settings.json`:

```json
{
  "extensions": [
    "D:/pi/pi-pwsh-native/src/index.ts"
  ]
}
```

Restart Pi or run `/reload` after changing extension code or configuration.

The npm package name is `pi-pwsh-native`. Releases are validated by Windows CI and published from version tags after the initial package bootstrap.

## Tool behavior

With the default configuration:

- `bash` is inactive.
- `pwsh` is active.
- `ls`, `find`, and `grep` remain active.
- Existing tools from other extensions remain active.
- `!` and `!!` execute through the selected PowerShell 7 runtime.

Example model commands:

```powershell
Get-ChildItem
$env:NODE_ENV = 'test'; npm test
rg --glob '*.ts' 'createFileRoute' src
fd --extension ts . src
```

PowerShell syntax is not translated. A Bash-only command fails visibly so the model can correct it.

## Configuration

The global configuration file is:

```text
~/.pi/agent/pwsh-native.json
```

Example:

```json
{
  "executable": "C:\\Program Files\\PowerShell\\7\\pwsh.exe",
  "loadProfile": false,
  "executionPolicy": null,
  "replaceUserBash": true,
  "preserveDiscoveryTools": true,
  "strictMode": false,
  "pythonUtf8": true,
  "pythonUnbuffered": true,
  "elevationGuidance": false
}
```

All fields are optional. Unknown fields and malformed values are rejected rather than ignored.

| Field | Default | Meaning |
|---|---:|---|
| `executable` | `"auto"` | `"auto"` or an absolute path to PowerShell 7 `pwsh.exe` |
| `loadProfile` | `false` | Load the user's PowerShell profile instead of passing `-NoProfile` |
| `executionPolicy` | `null` | Optional explicit process execution policy; no override is passed by default |
| `replaceUserBash` | `true` | Route Pi's `!` and `!!` commands through PowerShell |
| `preserveDiscoveryTools` | `true` | Keep Pi's `ls`, `find`, and `grep` tools active |
| `strictMode` | `false` | Set `$ErrorActionPreference = 'Stop'` for each command |
| `pythonUtf8` | `true` | Default `PYTHONIOENCODING=utf-8` and `PYTHONUTF8=1` when unset |
| `pythonUnbuffered` | `true` | Default `PYTHONUNBUFFERED=1` when unset |
| `elevationGuidance` | `false` | Allow elevation-related prompt guidance; never auto-elevates |

Supported explicit execution policies are `AllSigned`, `Bypass`, `Default`, `RemoteSigned`, `Restricted`, `Undefined`, and `Unrestricted`. `Bypass` is accepted only as an explicit user choice.

### Environment overrides

Environment variables override file values:

- `PI_PWSH_NATIVE_CONFIG` — alternate configuration file path
- `PI_PWSH_NATIVE_EXECUTABLE`
- `PI_PWSH_NATIVE_LOAD_PROFILE`
- `PI_PWSH_NATIVE_EXECUTION_POLICY`
- `PI_PWSH_NATIVE_REPLACE_USER_BASH`
- `PI_PWSH_NATIVE_PRESERVE_DISCOVERY_TOOLS`
- `PI_PWSH_NATIVE_STRICT`
- `PI_PWSH_NATIVE_PYTHON_UTF8`
- `PI_PWSH_NATIVE_PYTHON_UNBUFFERED`
- `PI_PWSH_NATIVE_ELEVATION_GUIDANCE`

Boolean environment values accept `true/false`, `1/0`, `yes/no`, or `on/off`.

## Runtime resolution

When `executable` is `"auto"`, resolution checks:

1. `pwsh.exe` found by `where.exe`.
2. `C:\Program Files\PowerShell\7\pwsh.exe`.

Each candidate is started and its version is verified. The selected absolute path is retained for all model and user commands.

If an explicit executable is invalid, the extension reports that exact failure and does not try another shell. If setup fails, the model's Bash tool is disabled and manual shell commands return an actionable error.

## Environment and exit codes

Model tool calls retain Pi's session environment, including:

- `PI_SESSION_ID`
- `PI_SESSION_FILE`
- `PI_PROVIDER`
- `PI_MODEL`
- `PI_REASONING_LEVEL`

Manual `!`/`!!` commands follow Pi's documented user-command environment behavior.

The command epilogue preserves `$LASTEXITCODE` when a native program ran. Commands that only use PowerShell map `$?` to exit code `0` or `1`.

## Timeouts and cancellation

There is no default timeout. The model can supply a timeout in seconds for a `pwsh` call. Timeout and Pi cancellation both invoke `taskkill.exe /T /F` for the spawned process, preventing common child-process leaks from tools such as `npm` and development servers.

Persistent background jobs and interactive PTYs are intentionally outside the core package. Use an external terminal for long-running interactive processes until separately reviewed companion functionality is available.

## Development

```powershell
npm install --ignore-scripts
npm run typecheck
npm test
npm run test:windows
npm run smoke
npm run check
```

Test coverage includes configuration, runtime selection, tool activation, Unicode, multiline/long source transport, native exit codes, `.cmd` execution, timeout, cancellation, inherited stdio handles, and process-tree cleanup.

## Security

Pi extensions execute with the user's full permissions. Review source before installation.

This package:

- does not make network requests;
- does not collect telemetry;
- does not auto-elevate;
- does not override execution policy by default;
- does not silently retry through `cmd.exe`, Bash, or PowerShell 5.1;
- does not have runtime dependencies or install scripts;
- does not accumulate unbounded shell output outside Pi's standard bounded output pipeline.

## Limitations

- Windows-only in the initial release.
- Each command starts a fresh PowerShell process for isolation and predictable state.
- PowerShell profiles are disabled by default.
- Background-job emulation and PTY helpers from the upstream project are not included in the lean core.
- Competing shell-adapter extensions should not be enabled simultaneously.

## Attribution

This project derives from [`@4fu/pi-pwsh`](https://github.com/4fuu/pi-pwsh), licensed under MIT. See [`THIRD_PARTY_NOTICES.md`](THIRD_PARTY_NOTICES.md) and [`LICENSE`](LICENSE).
