pi-pwsh-native 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +26 -2
- package/package.json +4 -3
- package/src/index.ts +37 -31
- package/src/powershell-source.ts +4 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,26 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented here.
|
|
4
4
|
|
|
5
|
+
## 0.1.3 — 2026-08-01
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Respect the final PowerShell command's success state instead of allowing a stale native `$LASTEXITCODE` to override it.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Reduced recurring model prompt overhead by shortening the shell description and consolidating PowerShell guidance.
|
|
14
|
+
- Deferred PowerShell runtime probing until a session starts, avoiding unnecessary subprocesses in Pi invocations that only load extensions.
|
|
15
|
+
- Declared the supported Pi and Node.js version ranges explicitly.
|
|
16
|
+
- Added minimum/latest Pi compatibility coverage and prompt-budget regression tests.
|
|
17
|
+
|
|
18
|
+
## 0.1.2 — 2026-07-30
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- `pi` npm keyword for broader package-gallery discoverability.
|
|
23
|
+
- README comparison with the audited `@4fu/pi-pwsh@0.6.2` baseline.
|
|
24
|
+
|
|
5
25
|
## 0.1.1 — 2026-07-30
|
|
6
26
|
|
|
7
27
|
### Added
|
package/README.md
CHANGED
|
@@ -7,6 +7,29 @@ Native PowerShell 7 tooling for the [Pi coding agent](https://pi.dev/) on Window
|
|
|
7
7
|
|
|
8
8
|
`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.
|
|
9
9
|
|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
## How this differs from `@4fu/pi-pwsh`
|
|
13
|
+
|
|
14
|
+
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`.
|
|
15
|
+
|
|
16
|
+
| Area | `pi-pwsh-native` | `@4fu/pi-pwsh@0.6.2` |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| Primary focus | Predictable, dependency-free foreground PowerShell execution | Feature-rich PowerShell execution with persistent jobs and interactive sessions |
|
|
19
|
+
| Model shell tool | Replaces `bash` with `pwsh` | Replaces `bash` with `pwsh` |
|
|
20
|
+
| Pi discovery tools | Preserves `ls`, `find`, and `grep` by default | Disables `ls`, `find`, and `grep` in favor of PowerShell |
|
|
21
|
+
| Interactive `!` / `!!` | Routes both through the verified PowerShell runtime | Does not replace Pi's `user_bash` handling |
|
|
22
|
+
| PowerShell executable | Resolves, verifies, and retains an absolute PowerShell 7 path | Probes PowerShell 7, while foreground execution invokes `pwsh` by name |
|
|
23
|
+
| Execution policy | No override by default; `Bypass` must be explicitly configured | Passes `-ExecutionPolicy Bypass` |
|
|
24
|
+
| Command transport | UTF-8 base64 source over stdin, avoiding Windows command-line limits | Injected source passed through `-Command` |
|
|
25
|
+
| `.cmd` fallback | No retry through `cmd.exe` | Can retry failed direct command-shim execution through `cmd /c` |
|
|
26
|
+
| Background jobs and PTYs | Intentionally omitted from the lean core | Includes detached jobs, ConPTY sessions, and user-request helpers |
|
|
27
|
+
| Runtime dependencies | None | Uses `node-pty` and `@xterm/headless` |
|
|
28
|
+
| Configuration | Strict JSON configuration plus environment overrides | Primarily opinionated built-in behavior |
|
|
29
|
+
| Missing/invalid PowerShell | Fails visibly without silently restoring Bash | Leaves the built-in Bash tool active when PowerShell is unavailable |
|
|
30
|
+
|
|
31
|
+
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.
|
|
32
|
+
|
|
10
33
|
## Design
|
|
11
34
|
|
|
12
35
|
- Registers a real `pwsh` tool so models are prompted to write PowerShell, not POSIX shell syntax.
|
|
@@ -24,7 +47,8 @@ Native PowerShell 7 tooling for the [Pi coding agent](https://pi.dev/) on Window
|
|
|
24
47
|
|
|
25
48
|
- Windows
|
|
26
49
|
- PowerShell 7+
|
|
27
|
-
-
|
|
50
|
+
- Node.js 22.19 or newer
|
|
51
|
+
- Pi 0.83.0 or newer (before 1.0)
|
|
28
52
|
|
|
29
53
|
The initial implementation is developed and tested against:
|
|
30
54
|
|
|
@@ -36,7 +60,7 @@ The initial implementation is developed and tested against:
|
|
|
36
60
|
Install the pinned npm release:
|
|
37
61
|
|
|
38
62
|
```powershell
|
|
39
|
-
pi install npm:pi-pwsh-native@0.1.
|
|
63
|
+
pi install npm:pi-pwsh-native@0.1.3
|
|
40
64
|
```
|
|
41
65
|
|
|
42
66
|
Alternatively, install the public GitHub package directly:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-pwsh-native",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Native PowerShell 7 tooling for the Pi coding agent on Windows",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Tako (https://github.com/takomine)",
|
|
@@ -20,10 +20,11 @@
|
|
|
20
20
|
"win32"
|
|
21
21
|
],
|
|
22
22
|
"engines": {
|
|
23
|
-
"node": ">=
|
|
23
|
+
"node": ">=22.19.0"
|
|
24
24
|
},
|
|
25
25
|
"keywords": [
|
|
26
26
|
"pi-package",
|
|
27
|
+
"pi",
|
|
27
28
|
"pi-extension",
|
|
28
29
|
"powershell",
|
|
29
30
|
"pwsh",
|
|
@@ -54,7 +55,7 @@
|
|
|
54
55
|
"smoke": "npm run test:runtime && npm run test:exitcode && npm run test:timeout"
|
|
55
56
|
},
|
|
56
57
|
"peerDependencies": {
|
|
57
|
-
"@earendil-works/pi-coding-agent": "
|
|
58
|
+
"@earendil-works/pi-coding-agent": ">=0.83.0 <1.0.0"
|
|
58
59
|
},
|
|
59
60
|
"devDependencies": {
|
|
60
61
|
"@earendil-works/pi-coding-agent": "^0.83.0",
|
package/src/index.ts
CHANGED
|
@@ -27,11 +27,17 @@ export function selectActiveTools(
|
|
|
27
27
|
return [...new Set(selected)];
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return
|
|
30
|
+
export const PWSH_TOOL_DESCRIPTION =
|
|
31
|
+
"Execute native PowerShell 7 on Windows. Output is tail-truncated to 2,000 lines or 50 KB; full output is saved to a temporary file. Optional timeout is in seconds.";
|
|
32
|
+
|
|
33
|
+
export function createPromptGuidelines(config: PwshNativeConfig): string[] {
|
|
34
|
+
return [
|
|
35
|
+
"Use pwsh only when a shell is needed; use native PowerShell syntax and $env:NAME for environment variables.",
|
|
36
|
+
"Prefer dedicated file and search tools over pwsh; otherwise bound recursive output and prefer rg or fd when available.",
|
|
37
|
+
config.elevationGuidance
|
|
38
|
+
? "In pwsh, elevation guidance is enabled, but elevate only after an explicit user request."
|
|
39
|
+
: "Do not elevate from pwsh unless the user explicitly requests it.",
|
|
40
|
+
];
|
|
35
41
|
}
|
|
36
42
|
|
|
37
43
|
function unavailableUserCommand(reason: string) {
|
|
@@ -55,51 +61,51 @@ export default function piPwshNative(pi: ExtensionAPI): void {
|
|
|
55
61
|
|
|
56
62
|
let config: PwshNativeConfig | undefined;
|
|
57
63
|
let runtime: PowerShellRuntime | undefined;
|
|
64
|
+
let operations: ReturnType<typeof createPowerShellOperations> | undefined;
|
|
58
65
|
let setupError: string | undefined;
|
|
59
66
|
try {
|
|
60
67
|
config = loadConfig({ agentDir: getAgentDir() }).config;
|
|
61
|
-
runtime = resolvePowerShellRuntime(config);
|
|
62
68
|
} catch (error) {
|
|
63
69
|
setupError = errorMessage(error);
|
|
64
70
|
}
|
|
65
71
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
72
|
+
pi.on("session_start", (_event, ctx) => {
|
|
73
|
+
if (!setupError && config && !runtime) {
|
|
74
|
+
try {
|
|
75
|
+
runtime = resolvePowerShellRuntime(config);
|
|
76
|
+
operations = createPowerShellOperations(runtime, config);
|
|
77
|
+
} catch (error) {
|
|
78
|
+
setupError = errorMessage(error);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (setupError || !config || !runtime || !operations) {
|
|
83
|
+
const reason = setupError ?? "unknown setup failure";
|
|
69
84
|
pi.setActiveTools(selectActiveTools(pi.getActiveTools(), true, false));
|
|
70
85
|
ctx.ui.notify(`pi-pwsh-native: ${reason} Bash was disabled; no shell fallback was activated.`, "error");
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const resolvedConfig = config;
|
|
77
|
-
const resolvedRuntime = runtime;
|
|
78
|
-
const operations = createPowerShellOperations(resolvedRuntime, resolvedConfig);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
79
88
|
|
|
80
|
-
pi.on("session_start", (_event, ctx) => {
|
|
81
89
|
const definition = createBashToolDefinition(ctx.cwd, { operations });
|
|
82
90
|
pi.registerTool({
|
|
83
91
|
...definition,
|
|
84
92
|
name: "pwsh",
|
|
85
93
|
label: "pwsh",
|
|
86
|
-
description:
|
|
87
|
-
promptSnippet: "Execute native PowerShell 7 commands
|
|
88
|
-
promptGuidelines:
|
|
89
|
-
"Use pwsh only when a shell is needed; write native PowerShell syntax and avoid Bash-only syntax or implicit Bash translation.",
|
|
90
|
-
"Prefer read, write, edit, ls, find, and grep over pwsh when a dedicated tool can complete the task more directly.",
|
|
91
|
-
"In pwsh, use $env:NAME for environment variables; single quotes are literal, double quotes interpolate, and the backtick is the escape character.",
|
|
92
|
-
"Prefer bounded rg or fd commands for repository search; tightly bound recursive Get-ChildItem and Select-String operations.",
|
|
93
|
-
"Do not elevate pwsh commands unless the user explicitly requests elevation.",
|
|
94
|
-
"Inspect PI_* environment variables in pwsh when current Pi model or session metadata is needed.",
|
|
95
|
-
],
|
|
94
|
+
description: PWSH_TOOL_DESCRIPTION,
|
|
95
|
+
promptSnippet: "Execute native PowerShell 7 commands",
|
|
96
|
+
promptGuidelines: createPromptGuidelines(config),
|
|
96
97
|
});
|
|
97
98
|
pi.setActiveTools(
|
|
98
|
-
selectActiveTools(pi.getActiveTools(),
|
|
99
|
+
selectActiveTools(pi.getActiveTools(), config.preserveDiscoveryTools, true),
|
|
99
100
|
);
|
|
100
101
|
});
|
|
101
102
|
|
|
102
|
-
|
|
103
|
-
|
|
103
|
+
const replaceUserBash = config?.replaceUserBash ?? true;
|
|
104
|
+
if (replaceUserBash) {
|
|
105
|
+
pi.on("user_bash", () =>
|
|
106
|
+
operations
|
|
107
|
+
? { operations }
|
|
108
|
+
: unavailableUserCommand(setupError ?? "PowerShell has not been initialized"),
|
|
109
|
+
);
|
|
104
110
|
}
|
|
105
111
|
}
|
package/src/powershell-source.ts
CHANGED
|
@@ -10,15 +10,16 @@ export const UTF8_PREFIX = [
|
|
|
10
10
|
].join("; ") + "; ";
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
14
|
-
* LASTEXITCODE
|
|
13
|
+
* Report the final command's status. A successful final command wins over a
|
|
14
|
+
* stale LASTEXITCODE; a failed final native command retains its real code;
|
|
15
|
+
* other PowerShell failures map to 1.
|
|
15
16
|
*
|
|
16
17
|
* The leading newline detaches the epilogue from a trailing line comment. The
|
|
17
18
|
* leading semicolon also prevents a trailing backtick from joining the
|
|
18
19
|
* epilogue to the user's final command.
|
|
19
20
|
*/
|
|
20
21
|
export const EXIT_EPILOGUE =
|
|
21
|
-
"\n; $__pi_ok = $?; if ($null -ne $global:LASTEXITCODE) { exit $global:LASTEXITCODE } else { exit
|
|
22
|
+
"\n; $__pi_ok = $?; if ($__pi_ok) { exit 0 } elseif ($null -ne $global:LASTEXITCODE -and $global:LASTEXITCODE -ne 0) { exit $global:LASTEXITCODE } else { exit 1 }";
|
|
22
23
|
|
|
23
24
|
export function buildPowerShellSource(command: string, config: PwshNativeConfig): string {
|
|
24
25
|
const strict = config.strictMode ? "$ErrorActionPreference = 'Stop'; " : "";
|