@caupulican/pi-adaptative 0.91.4 → 0.92.0

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.
Files changed (59) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/cli.js +6 -1
  3. package/dist/cli.js.map +1 -1
  4. package/dist/core/autonomy/lane-tool-surface.d.ts.map +1 -1
  5. package/dist/core/autonomy/lane-tool-surface.js +7 -1
  6. package/dist/core/autonomy/lane-tool-surface.js.map +1 -1
  7. package/dist/core/bash-execution-controller.d.ts.map +1 -1
  8. package/dist/core/bash-execution-controller.js +1 -0
  9. package/dist/core/bash-execution-controller.js.map +1 -1
  10. package/dist/core/bash-executor.d.ts +2 -0
  11. package/dist/core/bash-executor.d.ts.map +1 -1
  12. package/dist/core/bash-executor.js +13 -4
  13. package/dist/core/bash-executor.js.map +1 -1
  14. package/dist/core/tools/bash.d.ts +2 -0
  15. package/dist/core/tools/bash.d.ts.map +1 -1
  16. package/dist/core/tools/bash.js +27 -12
  17. package/dist/core/tools/bash.js.map +1 -1
  18. package/dist/core/tools/early-powershell-session.d.ts +21 -0
  19. package/dist/core/tools/early-powershell-session.d.ts.map +1 -0
  20. package/dist/core/tools/early-powershell-session.js +137 -0
  21. package/dist/core/tools/early-powershell-session.js.map +1 -0
  22. package/dist/core/tools/output-accumulator.d.ts +2 -0
  23. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  24. package/dist/core/tools/output-accumulator.js +2 -1
  25. package/dist/core/tools/output-accumulator.js.map +1 -1
  26. package/dist/core/tools/persistent-process-coordinator.d.ts.map +1 -1
  27. package/dist/core/tools/persistent-process-coordinator.js +2 -11
  28. package/dist/core/tools/persistent-process-coordinator.js.map +1 -1
  29. package/dist/core/tools/shell-output-decoder.d.ts +7 -0
  30. package/dist/core/tools/shell-output-decoder.d.ts.map +1 -0
  31. package/dist/core/tools/shell-output-decoder.js +135 -0
  32. package/dist/core/tools/shell-output-decoder.js.map +1 -0
  33. package/dist/core/tools/shell-session.d.ts +23 -6
  34. package/dist/core/tools/shell-session.d.ts.map +1 -1
  35. package/dist/core/tools/shell-session.js +275 -88
  36. package/dist/core/tools/shell-session.js.map +1 -1
  37. package/dist/utils/child-process-ref.d.ts +4 -0
  38. package/dist/utils/child-process-ref.d.ts.map +1 -0
  39. package/dist/utils/child-process-ref.js +15 -0
  40. package/dist/utils/child-process-ref.js.map +1 -0
  41. package/dist/utils/powershell-session-protocol.d.ts +16 -0
  42. package/dist/utils/powershell-session-protocol.d.ts.map +1 -0
  43. package/dist/utils/powershell-session-protocol.js +63 -0
  44. package/dist/utils/powershell-session-protocol.js.map +1 -0
  45. package/dist/utils/shell.d.ts +7 -4
  46. package/dist/utils/shell.d.ts.map +1 -1
  47. package/dist/utils/shell.js +38 -23
  48. package/dist/utils/shell.js.map +1 -1
  49. package/docs/settings.md +2 -2
  50. package/docs/windows.md +9 -8
  51. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  52. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  53. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  54. package/examples/extensions/sandbox/package-lock.json +2 -2
  55. package/examples/extensions/sandbox/package.json +1 -1
  56. package/examples/extensions/with-deps/package-lock.json +2 -2
  57. package/examples/extensions/with-deps/package.json +1 -1
  58. package/npm-shrinkwrap.json +12 -12
  59. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"shell-session.js","sourceRoot":"","sources":["../../../src/core/tools/shell-session.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Persistent shell sessions for the bash tool.\n *\n * One long-lived shell process per agent (keyed registry) replaces process-per-command spawning.\n * On Windows every command previously paid a full PowerShell boot; a persistent session pays it\n * once. Shell state (current directory, environment variables) persists across an agent's\n * commands; each key gets an isolated session so concurrently running agents never share state.\n *\n * Protocol: commands stream to the session over stdin and are terminated by a per-command\n * sentinel carrying a random nonce and the exit code. Bash wraps commands in an eval of a quoted\n * heredoc (arbitrary content stays data; syntax errors stay contained in eval); PowerShell runs a\n * ReadLine loop decoding base64 lines (no external binaries involved). On bash, command stderr is\n * merged into stdout at the shell so sentinel ordering is guaranteed on one pipe.\n *\n * PowerShell runs each command as a bare `Invoke-Expression`, NOT piped into `Out-Default`: piping\n * a native command's output into another pipeline stage forces PowerShell's NativeCommandProcessor\n * to capture that child's stdout/stderr into an internal pipe and read it to EOF before the\n * pipeline completes. A detached grandchild that inherited those handles (e.g. `start /b` holding\n * stdio open) then keeps that internal pipe's write end open, so the sentinel — written after the\n * pipeline \"completes\" — waits for the grandchild to die instead of the direct child. The bare\n * invocation lets a native command's stdout/stderr handles be inherited directly by the child\n * process; the direct child's own exit is what unblocks the sentinel line, exactly like the\n * per-command backend and like bash's stdio inheritance above. The bounded consequence: a native\n * command's stderr no longer merges into the session's stdout pipe (there is no capturing pipeline\n * stage to merge it) — it arrives on the session's own stderr pipe instead, forwarded via\n * `onStderr` -> `onData` same as the shell's own diagnostics. PowerShell 5.1's habit of wrapping\n * redirected stderr text in a `NativeCommandError` record also disappears, which is an accuracy\n * improvement (the raw stderr bytes are reported, not a wrapped/duplicated rendering of them).\n *\n * Kill semantics: timeout/abort/silence kill the WHOLE session process tree (a hung foreground\n * command cannot be killed individually without job control) and the next exec respawns a fresh\n * session, losing accumulated shell state by design. A command that exits the shell itself\n * (`exit 3`) reports the shell's exit code and also respawns lazily afterwards.\n */\n\nimport { randomBytes } from \"node:crypto\";\nimport { basename } from \"node:path\";\nimport { createSilenceWatchdog } from \"@caupulican/pi-agent-core/reliability\";\nimport { spawn } from \"child_process\";\nimport { getShellConfig, getShellEnv, type PlatformShellToolName } from \"../../utils/shell.ts\";\nimport { PersistentProcessCoordinator } from \"./persistent-process-coordinator.ts\";\n\nconst SENTINEL_BYTE = 0x1e;\n/** Longest possible sentinel: \"\\n\" + 0x1e + 16-hex nonce + \":\" + exit code digits + 0x1e. */\nconst SENTINEL_HOLDBACK_BYTES = 64;\n\nexport interface ShellSessionExecOptions {\n\tonData: (data: Buffer) => void;\n\tsignal?: AbortSignal;\n\t/** Wall-clock bound in seconds; when set, a breach kills the session and throws `timeout:<s>`. */\n\ttimeoutSeconds?: number;\n\t/** Output-silence bound in ms; when set, silence kills the session and throws `silence:<s>`. */\n\tsilenceMs?: number;\n\tenv?: NodeJS.ProcessEnv;\n}\n\nfunction escapeSingleQuotesPosix(value: string): string {\n\treturn value.replace(/'/g, \"'\\\\''\");\n}\n\nfunction escapeSingleQuotesPowerShell(value: string): string {\n\treturn value.replace(/'/g, \"''\");\n}\n\n/**\n * The whole command is heredoc-quoted data: eval keeps syntax errors contained (a raw syntax\n * error on the session's stdin would abort the shell), and the random delimiter makes content\n * collisions with agent output practically impossible. `< /dev/null` gives commands the same\n * EOF-stdin the per-command backend's `stdio: [\"ignore\", ...]` provided.\n */\nexport function buildBashWire(command: string, nonce: string, cdTo: string | null): string {\n\tconst body = cdTo ? `command cd -- '${escapeSingleQuotesPosix(cdTo)}' && {\\n${command}\\n}` : command;\n\treturn [\n\t\t`{ eval \"$(cat <<'PI_EOF_${nonce}'`,\n\t\tbody,\n\t\t`PI_EOF_${nonce}`,\n\t\t`)\"; } < /dev/null 2>&1`,\n\t\t`printf '\\\\n\\\\036%s:%s\\\\036' '${nonce}' \"$?\"`,\n\t\t\"\",\n\t].join(\"\\n\");\n}\n\n/** One protocol line: `<nonce> <base64(utf8 command)>`. Base64 keeps arbitrary multi-line commands line-safe. */\nexport function buildPowerShellWire(command: string, nonce: string, cdTo: string | null): string {\n\tconst body = cdTo\n\t\t? `Set-Location -LiteralPath '${escapeSingleQuotesPowerShell(cdTo)}' -ErrorAction Stop\\n${command}`\n\t\t: command;\n\treturn `${nonce} ${Buffer.from(body, \"utf8\").toString(\"base64\")}\\n`;\n}\n\n/**\n * PowerShell 5.1-compatible REPL bootstrap. Exit code mirrors `-Command` semantics as closely as\n * a loop can: a native command's $LASTEXITCODE wins, a terminating error forces 1, otherwise 0.\n * Passed as one direct `-Command` argument. `-EncodedCommand` makes PowerShell serialize host,\n * warning, and progress records as CLIXML on stderr whenever pipes are attached; Pi then sees\n * duplicate XML mixed into the same command's plain stdout. Node preserves this script as one\n * argv entry without involving cmd.exe quoting.\n *\n * The command runs as a bare `Invoke-Expression` (no `2>&1 | Out-Default` capture pipeline) — see\n * the module doc header for why: a native command's stdio handles are inherited directly by its\n * child process instead of being captured through a PowerShell-internal pipe, so the sentinel is\n * unblocked by the direct child's own exit rather than by any grandchild holding those handles.\n */\nconst POWERSHELL_BOOTSTRAP = [\n\t\"$ProgressPreference = 'SilentlyContinue'\",\n\t\"try { [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 } catch {}\",\n\t\"function global:__pi_complete_status([int]$Code) { $global:LASTEXITCODE = $Code }\",\n\t\"$__pi_in = [Console]::In\",\n\t\"while ($true) {\",\n\t\"\\t$__pi_line = $__pi_in.ReadLine()\",\n\t\"\\tif ($null -eq $__pi_line) { break }\",\n\t\"\\t$__pi_sp = $__pi_line.IndexOf(' ')\",\n\t\"\\tif ($__pi_sp -lt 1) { continue }\",\n\t\"\\t$__pi_nonce = $__pi_line.Substring(0, $__pi_sp)\",\n\t\"\\t$__pi_cmd = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($__pi_line.Substring($__pi_sp + 1)))\",\n\t\"\\t$global:LASTEXITCODE = $null\",\n\t\"\\t$__pi_thrown = $false\",\n\t\"\\t$__pi_succeeded = $false\",\n\t\"\\ttry { Invoke-Expression $__pi_cmd; $__pi_succeeded = $? } catch { $__pi_thrown = $true; $__pi_msg = ($_ | Out-String).TrimEnd(); if ($__pi_msg) { [Console]::Out.WriteLine($__pi_msg) } }\",\n\t\"\\t$__pi_code = $global:LASTEXITCODE\",\n\t\"\\tif ($null -eq $__pi_code) { $__pi_code = if ($__pi_succeeded) { 0 } else { 1 } }\",\n\t\"\\tif ($__pi_thrown -and ($__pi_code -eq 0)) { $__pi_code = 1 }\",\n\t\"\\t[Console]::Out.Write(('{0}{1}{2}:{3}{1}' -f [char]10, [char]30, $__pi_nonce, $__pi_code))\",\n\t\"}\",\n].join(\"\\n\");\n\nfunction shallowEnvEquals(a: NodeJS.ProcessEnv, b: NodeJS.ProcessEnv): boolean {\n\tconst aKeys = Object.keys(a);\n\tconst bKeys = Object.keys(b);\n\tif (aKeys.length !== bKeys.length) return false;\n\tfor (const key of aKeys) {\n\t\tif (a[key] !== b[key]) return false;\n\t}\n\treturn true;\n}\n\ninterface ActiveExec {\n\tonStdout(data: Buffer): void;\n\tonStderr(data: Buffer): void;\n\tonChildClose(code: number | null): void;\n\tfail(error: Error): void;\n}\n\nexport class PersistentShellSession {\n\tprivate readonly key: string;\n\tprivate readonly kind: PlatformShellToolName;\n\tprivate readonly coordinator = new PersistentProcessCoordinator();\n\tprivate childEnv: NodeJS.ProcessEnv | null = null;\n\tprivate lastRequestedCwd: string | null = null;\n\tprivate activeExec: ActiveExec | null = null;\n\tprivate disposed = false;\n\n\tconstructor(key: string, kind: PlatformShellToolName) {\n\t\tthis.key = key;\n\t\tthis.kind = kind;\n\t}\n\n\tget sessionKind(): PlatformShellToolName {\n\t\treturn this.kind;\n\t}\n\n\t/** Serialized: one command at a time per session, later calls queue behind earlier ones. */\n\texec(command: string, cwd: string, options: ShellSessionExecOptions): Promise<{ exitCode: number | null }> {\n\t\treturn this.coordinator.runSerialized(() => this.execNow(command, cwd, options));\n\t}\n\n\tdispose(): void {\n\t\tif (this.disposed) return;\n\t\tthis.disposed = true;\n\t\tthis.activeExec?.fail(new Error(`Shell session \"${this.key}\" is disposed`));\n\t\tthis.coordinator.dispose();\n\t\tthis.resetChildState();\n\t}\n\n\tprivate async execNow(\n\t\tcommand: string,\n\t\tcwd: string,\n\t\t{ onData, signal, timeoutSeconds, silenceMs, env }: ShellSessionExecOptions,\n\t): Promise<{ exitCode: number | null }> {\n\t\tif (this.disposed) throw new Error(`Shell session \"${this.key}\" is disposed`);\n\t\tif (signal?.aborted) throw new Error(\"aborted\");\n\n\t\tconst resolvedEnv = env ?? getShellEnv();\n\t\t// The environment is spawn-time shell config: an env that differs from the running\n\t\t// session's (e.g. a spawn hook rewriting it per command) requires a fresh shell.\n\t\tif (this.coordinator.child && this.childEnv && !shallowEnvEquals(this.childEnv, resolvedEnv)) {\n\t\t\tthis.killChild();\n\t\t}\n\n\t\t// Re-enter the host-requested cwd only when it CHANGES between calls; an unchanged\n\t\t// request preserves the agent's own in-session `cd` (that persistence is the feature).\n\t\tlet cdTo: string | null = null;\n\t\tif (!this.coordinator.child) {\n\t\t\tthis.spawnChild(cwd, resolvedEnv);\n\t\t} else if (this.lastRequestedCwd !== cwd) {\n\t\t\tcdTo = cwd;\n\t\t}\n\t\tthis.lastRequestedCwd = cwd;\n\n\t\tconst child = this.coordinator.child;\n\t\tif (!child?.stdin || !child.stdout || !child.stderr) {\n\t\t\tthis.killChild();\n\t\t\tthrow new Error(`Failed to start ${this.kind} session`);\n\t\t}\n\n\t\tconst nonce = randomBytes(8).toString(\"hex\");\n\t\tconst wire =\n\t\t\tthis.kind === \"powershell\" ? buildPowerShellWire(command, nonce, cdTo) : buildBashWire(command, nonce, cdTo);\n\t\tconst sentinelPrefix = Buffer.from(`\\n\\x1e${nonce}:`, \"latin1\");\n\n\t\tthis.coordinator.setLoopRef(true);\n\t\ttry {\n\t\t\treturn await new Promise<{ exitCode: number | null }>((resolve, reject) => {\n\t\t\t\tlet settled = false;\n\t\t\t\tlet pending: Buffer = Buffer.alloc(0);\n\t\t\t\tlet timeoutTimer: NodeJS.Timeout | undefined;\n\n\t\t\t\tconst silenceWatchdog =\n\t\t\t\t\ttimeoutSeconds === undefined && silenceMs !== undefined && silenceMs > 0\n\t\t\t\t\t\t? createSilenceWatchdog({\n\t\t\t\t\t\t\t\tsilenceMs,\n\t\t\t\t\t\t\t\tonSilence: () => {\n\t\t\t\t\t\t\t\t\tthis.killChild();\n\t\t\t\t\t\t\t\t\tsettle(() => reject(new Error(`silence:${silenceMs / 1000}`)));\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t: undefined;\n\n\t\t\t\tconst settle = (finish: () => void) => {\n\t\t\t\t\tif (settled) return;\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tif (timeoutTimer) clearTimeout(timeoutTimer);\n\t\t\t\t\tsilenceWatchdog?.disarm();\n\t\t\t\t\tif (signal) signal.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\tthis.activeExec = null;\n\t\t\t\t\tfinish();\n\t\t\t\t};\n\n\t\t\t\tconst onAbort = () => {\n\t\t\t\t\tthis.killChild();\n\t\t\t\t\tsettle(() => reject(new Error(\"aborted\")));\n\t\t\t\t};\n\n\t\t\t\tconst emitPending = (upTo: number) => {\n\t\t\t\t\tif (upTo <= 0) return;\n\t\t\t\t\tonData(pending.subarray(0, upTo));\n\t\t\t\t\tpending = pending.subarray(upTo);\n\t\t\t\t};\n\n\t\t\t\tthis.activeExec = {\n\t\t\t\t\tonStdout: (data) => {\n\t\t\t\t\t\tsilenceWatchdog?.touch();\n\t\t\t\t\t\tpending = pending.length === 0 ? data : Buffer.concat([pending, data]);\n\t\t\t\t\t\tconst prefixIndex = pending.indexOf(sentinelPrefix);\n\t\t\t\t\t\tif (prefixIndex !== -1) {\n\t\t\t\t\t\t\tconst closeIndex = pending.indexOf(SENTINEL_BYTE, prefixIndex + sentinelPrefix.length);\n\t\t\t\t\t\t\tif (closeIndex !== -1) {\n\t\t\t\t\t\t\t\tconst codeText = pending\n\t\t\t\t\t\t\t\t\t.subarray(prefixIndex + sentinelPrefix.length, closeIndex)\n\t\t\t\t\t\t\t\t\t.toString(\"latin1\");\n\t\t\t\t\t\t\t\temitPending(prefixIndex);\n\t\t\t\t\t\t\t\tconst parsed = Number.parseInt(codeText, 10);\n\t\t\t\t\t\t\t\t// Defer the settle by one microtask turn: with the bare Invoke-Expression\n\t\t\t\t\t\t\t\t// form a native command's stderr now arrives on the session's OWN stderr\n\t\t\t\t\t\t\t\t// pipe (see module doc header) instead of being pre-merged into the same\n\t\t\t\t\t\t\t\t// stdout bytes the sentinel rides on. Node fires already-queued stream\n\t\t\t\t\t\t\t\t// 'data' events in event-loop order; queueing the resolution behind a\n\t\t\t\t\t\t\t\t// microtask guarantees any stderr chunk the kernel delivered alongside (or\n\t\t\t\t\t\t\t\t// just before) this stdout chunk has already run its 'data' handler — and\n\t\t\t\t\t\t\t\t// thus reached `onData` — before the promise settles, so callers never see a\n\t\t\t\t\t\t\t\t// truncated stderr tail immediately after resolution.\n\t\t\t\t\t\t\t\tqueueMicrotask(() => settle(() => resolve({ exitCode: Number.isNaN(parsed) ? null : parsed })));\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Stream promptly but retain a tail large enough to hold any split sentinel.\n\t\t\t\t\t\temitPending(pending.length - SENTINEL_HOLDBACK_BYTES);\n\t\t\t\t\t},\n\t\t\t\t\tonStderr: (data) => {\n\t\t\t\t\t\t// The command's stderr is merged into stdout at the shell; this pipe only\n\t\t\t\t\t\t// carries the session shell's own diagnostics. Forward for visibility.\n\t\t\t\t\t\tsilenceWatchdog?.touch();\n\t\t\t\t\t\tonData(data);\n\t\t\t\t\t},\n\t\t\t\t\tonChildClose: (code) => {\n\t\t\t\t\t\t// The command terminated the shell itself (e.g. `exit 3`) or the shell\n\t\t\t\t\t\t// crashed: report its exit code like the per-command backend would.\n\t\t\t\t\t\temitPending(pending.length);\n\t\t\t\t\t\tsettle(() => resolve({ exitCode: code }));\n\t\t\t\t\t},\n\t\t\t\t\tfail: (error) => {\n\t\t\t\t\t\tthis.killChild();\n\t\t\t\t\t\tsettle(() => reject(error));\n\t\t\t\t\t},\n\t\t\t\t};\n\n\t\t\t\tif (signal) signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\tif (timeoutSeconds !== undefined && timeoutSeconds > 0) {\n\t\t\t\t\ttimeoutTimer = setTimeout(() => {\n\t\t\t\t\t\tthis.killChild();\n\t\t\t\t\t\tsettle(() => reject(new Error(`timeout:${timeoutSeconds}`)));\n\t\t\t\t\t}, timeoutSeconds * 1000);\n\t\t\t\t}\n\n\t\t\t\tchild.stdin?.write(wire, (error) => {\n\t\t\t\t\tif (!error) return;\n\t\t\t\t\tthis.killChild();\n\t\t\t\t\tsettle(() => reject(new Error(`Failed to write to ${this.kind} session: ${error.message}`)));\n\t\t\t\t});\n\t\t\t});\n\t\t} finally {\n\t\t\tthis.coordinator.setLoopRef(false);\n\t\t}\n\t}\n\n\tprivate spawnChild(cwd: string, env: NodeJS.ProcessEnv): void {\n\t\tconst { shell } = getShellConfig(undefined, this.kind);\n\t\tconst args =\n\t\t\tthis.kind === \"powershell\"\n\t\t\t\t? [\"-NoLogo\", \"-NoProfile\", \"-NonInteractive\", \"-Command\", POWERSHELL_BOOTSTRAP]\n\t\t\t\t: basename(shell).toLowerCase().includes(\"bash\")\n\t\t\t\t\t? [\"--noprofile\", \"--norc\"]\n\t\t\t\t\t: [];\n\t\tconst child = spawn(shell, args, {\n\t\t\tcwd,\n\t\t\tenv,\n\t\t\tdetached: process.platform !== \"win32\",\n\t\t\tstdio: [\"pipe\", \"pipe\", \"pipe\"],\n\t\t\twindowsHide: true,\n\t\t});\n\t\tthis.coordinator.attach(child, {\n\t\t\tonStdout: (data) => this.activeExec?.onStdout(data),\n\t\t\tonStderr: (data) => this.activeExec?.onStderr(data),\n\t\t\tonError: (error) => {\n\t\t\t\tthis.resetChildState();\n\t\t\t\tthis.activeExec?.fail(error);\n\t\t\t},\n\t\t\tonClose: (code) => {\n\t\t\t\tthis.resetChildState();\n\t\t\t\tthis.activeExec?.onChildClose(code);\n\t\t\t},\n\t\t});\n\t\tthis.childEnv = env;\n\t\tthis.lastRequestedCwd = cwd;\n\t}\n\n\tprivate resetChildState(): void {\n\t\tthis.childEnv = null;\n\t\tthis.lastRequestedCwd = null;\n\t}\n\n\tprivate killChild(): void {\n\t\tthis.coordinator.kill();\n\t\tthis.resetChildState();\n\t}\n}\n\nconst shellSessions = new Map<string, PersistentShellSession>();\n\n/** Get or lazily create the persistent session for a key. A kind change replaces the session. */\nexport function acquirePersistentShellSession(key: string, kind: PlatformShellToolName): PersistentShellSession {\n\tconst existing = shellSessions.get(key);\n\tif (existing && existing.sessionKind === kind) return existing;\n\texisting?.dispose();\n\tconst session = new PersistentShellSession(key, kind);\n\tshellSessions.set(key, session);\n\treturn session;\n}\n\n/** Kill and forget a session (agent teardown). Safe to call for keys that never spawned. */\nexport function disposePersistentShellSession(key: string): void {\n\tconst session = shellSessions.get(key);\n\tif (!session) return;\n\tshellSessions.delete(key);\n\tsession.dispose();\n}\n"]}
1
+ {"version":3,"file":"shell-session.js","sourceRoot":"","sources":["../../../src/core/tools/shell-session.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Persistent shell sessions for the bash tool.\n *\n * One long-lived shell process per agent (keyed registry) replaces process-per-command spawning.\n * On Windows every command previously paid a full PowerShell boot; a persistent session pays it\n * once. Shell state (current directory, environment variables) persists across an agent's\n * commands; each key gets an isolated session so concurrently running agents never share state.\n *\n * Protocol: commands stream to the session over stdin and are terminated by a per-command\n * sentinel carrying a random nonce and the exit code. Bash wraps commands in an eval of a quoted\n * heredoc (arbitrary content stays data; syntax errors stay contained in eval); PowerShell runs a\n * ReadLine loop decoding base64 lines (no external binaries involved). On bash, command stderr is\n * merged into stdout at the shell so sentinel ordering is guaranteed on one pipe.\n *\n * PowerShell runs each command as a bare `Invoke-Expression`, NOT piped into `Out-Default`: piping\n * a native command's output into another pipeline stage forces PowerShell's NativeCommandProcessor\n * to capture that child's stdout/stderr into an internal pipe and read it to EOF before the\n * pipeline completes. A detached grandchild that inherited those handles (e.g. `start /b` holding\n * stdio open) then keeps that internal pipe's write end open, so the sentinel — written after the\n * pipeline \"completes\" — waits for the grandchild to die instead of the direct child. The bare\n * invocation lets a native command's stdout/stderr handles be inherited directly by the child\n * process; the direct child's own exit is what unblocks the sentinel line, exactly like the\n * per-command backend and like bash's stdio inheritance above. The bounded consequence: a native\n * command's stderr no longer merges into the session's stdout pipe (there is no capturing pipeline\n * stage to merge it) — it arrives on the session's own stderr pipe instead. A nonce-bearing barrier\n * on that pipe joins it deterministically with the stdout completion frame before the command\n * resolves. PowerShell 5.1's habit of wrapping redirected stderr text in a `NativeCommandError`\n * record also disappears, which is an accuracy improvement (the raw stderr bytes are reported,\n * not a wrapped/duplicated rendering of them).\n *\n * Kill semantics: timeout/abort/silence kill the WHOLE session process tree (a hung foreground\n * command cannot be killed individually without job control) and the next exec respawns a fresh\n * session, losing accumulated shell state by design. A command that exits the shell itself\n * (`exit 3`) reports the shell's exit code and also respawns lazily afterwards.\n */\n\nimport { randomBytes } from \"node:crypto\";\nimport { basename } from \"node:path\";\nimport { createSilenceWatchdog } from \"@caupulican/pi-agent-core/reliability\";\nimport { type ChildProcess, type SpawnOptions, spawn } from \"child_process\";\nimport {\n\tcreatePowerShellHostEnvironment,\n\tPOWERSHELL_ARGS,\n\tPOWERSHELL_BOOTSTRAP,\n\tPOWERSHELL_SESSION_READY_MARKER,\n\tPOWERSHELL_SESSION_STDERR_READY_MARKER,\n\tPOWERSHELL_STDERR_BARRIER_LABEL,\n} from \"../../utils/powershell-session-protocol.ts\";\nimport {\n\tgetPowerShellCandidateConfigs,\n\tgetShellConfig,\n\tgetShellEnv,\n\ttype PlatformShellToolName,\n\tPOWERSHELL_STARTUP_PROBE_TIMEOUT_MS,\n\ttype ShellConfig,\n} from \"../../utils/shell.ts\";\nimport { claimCliPowerShellWarmStart } from \"./early-powershell-session.ts\";\nimport { PersistentProcessCoordinator } from \"./persistent-process-coordinator.ts\";\n\nexport {\n\tPOWERSHELL_SESSION_READY_MARKER,\n\tPOWERSHELL_SESSION_STDERR_READY_MARKER,\n} from \"../../utils/powershell-session-protocol.ts\";\n\nconst SENTINEL_BYTE = 0x1e;\n/** Longest possible sentinel: \"\\n\" + 0x1e + 16-hex nonce + \":\" + exit code digits + 0x1e. */\nconst SENTINEL_HOLDBACK_BYTES = 64;\nconst MAX_STARTUP_DIAGNOSTIC_BYTES = 16 * 1024;\nconst POWERSHELL_SESSION_READY_BYTES = Buffer.from(POWERSHELL_SESSION_READY_MARKER, \"latin1\");\nconst POWERSHELL_SESSION_STDERR_READY_BYTES = Buffer.from(POWERSHELL_SESSION_STDERR_READY_MARKER, \"latin1\");\n\nexport interface ShellSessionExecOptions {\n\tonData: (data: Buffer) => void;\n\tsignal?: AbortSignal;\n\t/** Wall-clock bound in seconds; when set, a breach kills the session and throws `timeout:<s>`. */\n\ttimeoutSeconds?: number;\n\t/** Output-silence bound in ms; when set, silence kills the session and throws `silence:<s>`. */\n\tsilenceMs?: number;\n\tenv?: NodeJS.ProcessEnv;\n}\n\nexport interface PersistentShellSessionOptions {\n\tresolvePowerShellCandidates?: () => ShellConfig[];\n\tspawn?: (command: string, args: string[], options: SpawnOptions) => ChildProcess;\n\tstartupTimeoutMs?: number;\n}\n\nfunction escapeSingleQuotesPosix(value: string): string {\n\treturn value.replace(/'/g, \"'\\\\''\");\n}\n\nfunction escapeSingleQuotesPowerShell(value: string): string {\n\treturn value.replace(/'/g, \"''\");\n}\n\n/**\n * The whole command is heredoc-quoted data: eval keeps syntax errors contained (a raw syntax\n * error on the session's stdin would abort the shell), and the random delimiter makes content\n * collisions with agent output practically impossible. `< /dev/null` gives commands the same\n * EOF-stdin the per-command backend's `stdio: [\"ignore\", ...]` provided.\n */\nexport function buildBashWire(command: string, nonce: string, cdTo: string | null): string {\n\tconst body = cdTo ? `command cd -- '${escapeSingleQuotesPosix(cdTo)}' && {\\n${command}\\n}` : command;\n\treturn [\n\t\t`{ eval \"$(cat <<'PI_EOF_${nonce}'`,\n\t\tbody,\n\t\t`PI_EOF_${nonce}`,\n\t\t`)\"; } < /dev/null 2>&1`,\n\t\t`printf '\\\\n\\\\036%s:%s\\\\036' '${nonce}' \"$?\"`,\n\t\t\"\",\n\t].join(\"\\n\");\n}\n\n/** One protocol line: `<nonce> <base64(utf8 command)>`. Base64 keeps arbitrary multi-line commands line-safe. */\nexport function buildPowerShellWire(command: string, nonce: string, cdTo: string | null): string {\n\tconst body = cdTo\n\t\t? `Set-Location -LiteralPath '${escapeSingleQuotesPowerShell(cdTo)}' -ErrorAction Stop\\n${command}`\n\t\t: command;\n\treturn `${nonce} ${Buffer.from(body, \"utf8\").toString(\"base64\")}\\n`;\n}\n\nfunction shallowEnvEquals(a: NodeJS.ProcessEnv, b: NodeJS.ProcessEnv): boolean {\n\tconst aKeys = Object.keys(a);\n\tconst bKeys = Object.keys(b);\n\tif (aKeys.length !== bKeys.length) return false;\n\tfor (const key of aKeys) {\n\t\tif (a[key] !== b[key]) return false;\n\t}\n\treturn true;\n}\n\nfunction buildPowerShellEnvironmentPrelude(current: NodeJS.ProcessEnv, desired: NodeJS.ProcessEnv): string | null {\n\tconst currentByName = new Map(\n\t\tObject.entries(current)\n\t\t\t.filter((entry): entry is [string, string] => entry[1] !== undefined)\n\t\t\t.map(([name, value]) => [name.toLowerCase(), { name, value }]),\n\t);\n\tconst desiredByName = new Map(\n\t\tObject.entries(desired)\n\t\t\t.filter((entry): entry is [string, string] => entry[1] !== undefined)\n\t\t\t.map(([name, value]) => [name.toLowerCase(), { name, value }]),\n\t);\n\tconst setValues = [...desiredByName.entries()].flatMap(([identity, entry]) =>\n\t\tcurrentByName.get(identity)?.value === entry.value ? [] : [entry],\n\t);\n\tconst removeNames = [...currentByName.entries()].flatMap(([identity, entry]) =>\n\t\tdesiredByName.has(identity) ? [] : [entry.name],\n\t);\n\tif (setValues.length === 0 && removeNames.length === 0) return null;\n\tconst encoded = Buffer.from(JSON.stringify({ setValues, removeNames }), \"utf8\").toString(\"base64\");\n\treturn [\n\t\t`$__pi_env_delta = ConvertFrom-Json ([System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('${encoded}')))`,\n\t\t\"foreach ($__pi_env_item in @($__pi_env_delta.setValues)) { [System.Environment]::SetEnvironmentVariable([string]$__pi_env_item.name, [string]$__pi_env_item.value, 'Process') }\",\n\t\t\"foreach ($__pi_env_name in @($__pi_env_delta.removeNames)) { [System.Environment]::SetEnvironmentVariable([string]$__pi_env_name, $null, 'Process') }\",\n\t\t\"Remove-Variable -Name __pi_env_delta,__pi_env_item,__pi_env_name -ErrorAction SilentlyContinue\",\n\t].join(\"\\n\");\n}\n\ninterface ActiveExec {\n\tonStdout(data: Buffer): void;\n\tonStderr(data: Buffer): void;\n\tonChildClose(code: number | null): void;\n\tfail(error: Error): void;\n}\n\nexport class PersistentShellSession {\n\tprivate readonly key: string;\n\tprivate readonly kind: PlatformShellToolName;\n\tprivate readonly resolvePowerShellCandidates: () => ShellConfig[];\n\tprivate readonly spawnProcess: (command: string, args: string[], options: SpawnOptions) => ChildProcess;\n\tprivate readonly startupTimeoutMs: number;\n\tprivate readonly coordinator = new PersistentProcessCoordinator();\n\tprivate childEnv: NodeJS.ProcessEnv | null = null;\n\tprivate lastRequestedCwd: string | null = null;\n\tprivate activeExec: ActiveExec | null = null;\n\tprivate rejectStartup: ((error: Error) => void) | null = null;\n\tprivate disposed = false;\n\n\tconstructor(key: string, kind: PlatformShellToolName, options: PersistentShellSessionOptions = {}) {\n\t\tthis.key = key;\n\t\tthis.kind = kind;\n\t\tthis.resolvePowerShellCandidates = options.resolvePowerShellCandidates ?? getPowerShellCandidateConfigs;\n\t\tthis.spawnProcess = options.spawn ?? spawn;\n\t\tthis.startupTimeoutMs = options.startupTimeoutMs ?? POWERSHELL_STARTUP_PROBE_TIMEOUT_MS;\n\t}\n\n\tget sessionKind(): PlatformShellToolName {\n\t\treturn this.kind;\n\t}\n\n\t/** Serialized: one command at a time per session, later calls queue behind earlier ones. */\n\texec(command: string, cwd: string, options: ShellSessionExecOptions): Promise<{ exitCode: number | null }> {\n\t\treturn this.coordinator.runSerialized(() => this.execNow(command, cwd, options));\n\t}\n\n\t/** Start and validate the long-lived shell before the first user command. Idempotent per session. */\n\tprewarm(cwd: string, env: NodeJS.ProcessEnv = getShellEnv()): Promise<void> {\n\t\treturn this.coordinator.runSerialized(async () => {\n\t\t\tif (this.disposed) throw new Error(`Shell session \"${this.key}\" is disposed`);\n\t\t\tconst resolvedEnv = this.kind === \"powershell\" ? createPowerShellHostEnvironment(env) : env;\n\t\t\tif (\n\t\t\t\tthis.kind !== \"powershell\" &&\n\t\t\t\tthis.coordinator.child &&\n\t\t\t\tthis.childEnv &&\n\t\t\t\t!shallowEnvEquals(this.childEnv, resolvedEnv)\n\t\t\t) {\n\t\t\t\tthis.killChild();\n\t\t\t}\n\t\t\tif (!this.coordinator.child) await this.spawnChild(cwd, resolvedEnv);\n\t\t\tif (\n\t\t\t\tthis.kind === \"powershell\" &&\n\t\t\t\tthis.childEnv &&\n\t\t\t\t(!shallowEnvEquals(this.childEnv, resolvedEnv) || this.lastRequestedCwd !== cwd)\n\t\t\t) {\n\t\t\t\tconst result = await this.execNow(\"\", cwd, { onData: () => {}, env: resolvedEnv });\n\t\t\t\tif (result.exitCode !== 0) {\n\t\t\t\t\tthis.killChild();\n\t\t\t\t\tthrow new Error(`PowerShell session reconciliation failed with exit code ${result.exitCode ?? \"null\"}`);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.coordinator.setLoopRef(false);\n\t\t});\n\t}\n\n\tdispose(): void {\n\t\tif (this.disposed) return;\n\t\tthis.disposed = true;\n\t\tthis.rejectStartup?.(new Error(`Shell session \"${this.key}\" is disposed`));\n\t\tthis.activeExec?.fail(new Error(`Shell session \"${this.key}\" is disposed`));\n\t\tthis.coordinator.dispose();\n\t\tthis.resetChildState();\n\t}\n\n\tprivate async execNow(\n\t\tcommand: string,\n\t\tcwd: string,\n\t\t{ onData, signal, timeoutSeconds, silenceMs, env }: ShellSessionExecOptions,\n\t): Promise<{ exitCode: number | null }> {\n\t\tif (this.disposed) throw new Error(`Shell session \"${this.key}\" is disposed`);\n\t\tif (signal?.aborted) throw new Error(\"aborted\");\n\n\t\tconst requestedEnv = env ?? getShellEnv();\n\t\tconst resolvedEnv = this.kind === \"powershell\" ? createPowerShellHostEnvironment(requestedEnv) : requestedEnv;\n\t\t// The environment is spawn-time shell config: an env that differs from the running\n\t\t// session's (e.g. a spawn hook rewriting it per command) requires a fresh shell.\n\t\tif (\n\t\t\tthis.kind !== \"powershell\" &&\n\t\t\tthis.coordinator.child &&\n\t\t\tthis.childEnv &&\n\t\t\t!shallowEnvEquals(this.childEnv, resolvedEnv)\n\t\t) {\n\t\t\tthis.killChild();\n\t\t}\n\n\t\t// Re-enter the host-requested cwd only when it CHANGES between calls; an unchanged\n\t\t// request preserves the agent's own in-session `cd` (that persistence is the feature).\n\t\tlet cdTo: string | null = null;\n\t\tif (!this.coordinator.child) await this.spawnChild(cwd, resolvedEnv);\n\t\tif (this.lastRequestedCwd !== cwd) cdTo = cwd;\n\t\tthis.lastRequestedCwd = cwd;\n\t\tlet resolvedCommand = command;\n\t\tif (this.kind === \"powershell\" && this.childEnv && !shallowEnvEquals(this.childEnv, resolvedEnv)) {\n\t\t\tconst environmentPrelude = buildPowerShellEnvironmentPrelude(this.childEnv, resolvedEnv);\n\t\t\tif (environmentPrelude) resolvedCommand = `${environmentPrelude}\\n${command}`;\n\t\t\tthis.childEnv = { ...resolvedEnv };\n\t\t}\n\n\t\tconst child = this.coordinator.child;\n\t\tif (!child?.stdin || !child.stdout || !child.stderr) {\n\t\t\tthis.killChild();\n\t\t\tthrow new Error(`Failed to start ${this.kind} session`);\n\t\t}\n\n\t\tconst nonce = randomBytes(8).toString(\"hex\");\n\t\tconst wire =\n\t\t\tthis.kind === \"powershell\"\n\t\t\t\t? buildPowerShellWire(resolvedCommand, nonce, cdTo)\n\t\t\t\t: buildBashWire(resolvedCommand, nonce, cdTo);\n\t\tconst sentinelPrefix = Buffer.from(`\\n\\x1e${nonce}:`, \"latin1\");\n\t\tconst stderrBarrier = Buffer.from(`\\x1e${nonce}:${POWERSHELL_STDERR_BARRIER_LABEL}\\x1e\\n`, \"latin1\");\n\n\t\tthis.coordinator.setLoopRef(true);\n\t\ttry {\n\t\t\treturn await new Promise<{ exitCode: number | null }>((resolve, reject) => {\n\t\t\t\tlet settled = false;\n\t\t\t\tlet stdoutPending: Buffer = Buffer.alloc(0);\n\t\t\t\tlet stderrPending: Buffer = Buffer.alloc(0);\n\t\t\t\tlet commandExitCode: number | null | undefined;\n\t\t\t\tlet stderrBarrierSeen = this.kind !== \"powershell\";\n\t\t\t\tlet timeoutTimer: NodeJS.Timeout | undefined;\n\n\t\t\t\tconst silenceWatchdog =\n\t\t\t\t\ttimeoutSeconds === undefined && silenceMs !== undefined && silenceMs > 0\n\t\t\t\t\t\t? createSilenceWatchdog({\n\t\t\t\t\t\t\t\tsilenceMs,\n\t\t\t\t\t\t\t\tonSilence: () => {\n\t\t\t\t\t\t\t\t\tthis.killChild();\n\t\t\t\t\t\t\t\t\tsettle(() => reject(new Error(`silence:${silenceMs / 1000}`)));\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t: undefined;\n\n\t\t\t\tconst settle = (finish: () => void) => {\n\t\t\t\t\tif (settled) return;\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tif (timeoutTimer) clearTimeout(timeoutTimer);\n\t\t\t\t\tsilenceWatchdog?.disarm();\n\t\t\t\t\tif (signal) signal.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\tthis.activeExec = null;\n\t\t\t\t\tfinish();\n\t\t\t\t};\n\n\t\t\t\tconst onAbort = () => {\n\t\t\t\t\tthis.killChild();\n\t\t\t\t\tsettle(() => reject(new Error(\"aborted\")));\n\t\t\t\t};\n\n\t\t\t\tconst emitStdoutPending = (upTo: number) => {\n\t\t\t\t\tif (upTo <= 0) return;\n\t\t\t\t\tonData(stdoutPending.subarray(0, upTo));\n\t\t\t\t\tstdoutPending = stdoutPending.subarray(upTo);\n\t\t\t\t};\n\t\t\t\tconst emitStderrPending = (upTo: number) => {\n\t\t\t\t\tif (upTo <= 0) return;\n\t\t\t\t\tonData(stderrPending.subarray(0, upTo));\n\t\t\t\t\tstderrPending = stderrPending.subarray(upTo);\n\t\t\t\t};\n\t\t\t\tconst resolveWhenComplete = () => {\n\t\t\t\t\tconst exitCode = commandExitCode;\n\t\t\t\t\tif (exitCode === undefined || !stderrBarrierSeen) return;\n\t\t\t\t\tsettle(() => resolve({ exitCode }));\n\t\t\t\t};\n\n\t\t\t\tthis.activeExec = {\n\t\t\t\t\tonStdout: (data) => {\n\t\t\t\t\t\tsilenceWatchdog?.touch();\n\t\t\t\t\t\tif (commandExitCode !== undefined) {\n\t\t\t\t\t\t\tonData(data);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tstdoutPending = stdoutPending.length === 0 ? data : Buffer.concat([stdoutPending, data]);\n\t\t\t\t\t\tconst prefixIndex = stdoutPending.indexOf(sentinelPrefix);\n\t\t\t\t\t\tif (prefixIndex !== -1) {\n\t\t\t\t\t\t\tconst closeIndex = stdoutPending.indexOf(SENTINEL_BYTE, prefixIndex + sentinelPrefix.length);\n\t\t\t\t\t\t\tif (closeIndex !== -1) {\n\t\t\t\t\t\t\t\tconst codeText = stdoutPending\n\t\t\t\t\t\t\t\t\t.subarray(prefixIndex + sentinelPrefix.length, closeIndex)\n\t\t\t\t\t\t\t\t\t.toString(\"latin1\");\n\t\t\t\t\t\t\t\temitStdoutPending(prefixIndex);\n\t\t\t\t\t\t\t\tstdoutPending = stdoutPending.subarray(closeIndex - prefixIndex + 1);\n\t\t\t\t\t\t\t\temitStdoutPending(stdoutPending.length);\n\t\t\t\t\t\t\t\tconst parsed = Number.parseInt(codeText, 10);\n\t\t\t\t\t\t\t\tcommandExitCode = Number.isNaN(parsed) ? null : parsed;\n\t\t\t\t\t\t\t\tresolveWhenComplete();\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Stream promptly but retain a tail large enough to hold any split sentinel.\n\t\t\t\t\t\temitStdoutPending(stdoutPending.length - SENTINEL_HOLDBACK_BYTES);\n\t\t\t\t\t},\n\t\t\t\t\tonStderr: (data) => {\n\t\t\t\t\t\tsilenceWatchdog?.touch();\n\t\t\t\t\t\tif (this.kind !== \"powershell\" || stderrBarrierSeen) {\n\t\t\t\t\t\t\tonData(data);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tstderrPending = stderrPending.length === 0 ? data : Buffer.concat([stderrPending, data]);\n\t\t\t\t\t\tconst barrierIndex = stderrPending.indexOf(stderrBarrier);\n\t\t\t\t\t\tif (barrierIndex !== -1) {\n\t\t\t\t\t\t\temitStderrPending(barrierIndex);\n\t\t\t\t\t\t\tstderrPending = stderrPending.subarray(stderrBarrier.length);\n\t\t\t\t\t\t\temitStderrPending(stderrPending.length);\n\t\t\t\t\t\t\tstderrBarrierSeen = true;\n\t\t\t\t\t\t\tresolveWhenComplete();\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// Preserve enough bytes to recognize a barrier split across chunks.\n\t\t\t\t\t\temitStderrPending(stderrPending.length - stderrBarrier.length + 1);\n\t\t\t\t\t},\n\t\t\t\t\tonChildClose: (code) => {\n\t\t\t\t\t\t// The command terminated the shell itself (e.g. `exit 3`) or the shell\n\t\t\t\t\t\t// crashed: report its exit code like the per-command backend would.\n\t\t\t\t\t\temitStdoutPending(stdoutPending.length);\n\t\t\t\t\t\temitStderrPending(stderrPending.length);\n\t\t\t\t\t\tsettle(() => resolve({ exitCode: code }));\n\t\t\t\t\t},\n\t\t\t\t\tfail: (error) => {\n\t\t\t\t\t\tthis.killChild();\n\t\t\t\t\t\tsettle(() => reject(error));\n\t\t\t\t\t},\n\t\t\t\t};\n\n\t\t\t\tif (signal) signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\tif (timeoutSeconds !== undefined && timeoutSeconds > 0) {\n\t\t\t\t\ttimeoutTimer = setTimeout(() => {\n\t\t\t\t\t\tthis.killChild();\n\t\t\t\t\t\tsettle(() => reject(new Error(`timeout:${timeoutSeconds}`)));\n\t\t\t\t\t}, timeoutSeconds * 1000);\n\t\t\t\t}\n\n\t\t\t\tchild.stdin?.write(wire, (error) => {\n\t\t\t\t\tif (!error) return;\n\t\t\t\t\tthis.killChild();\n\t\t\t\t\tsettle(() => reject(new Error(`Failed to write to ${this.kind} session: ${error.message}`)));\n\t\t\t\t});\n\t\t\t});\n\t\t} finally {\n\t\t\tthis.coordinator.setLoopRef(false);\n\t\t}\n\t}\n\n\tprivate async spawnChild(cwd: string, env: NodeJS.ProcessEnv): Promise<void> {\n\t\tlet spawnedCwd = cwd;\n\t\tlet spawnedEnv = env;\n\t\tif (this.kind === \"powershell\") {\n\t\t\t({ cwd: spawnedCwd, env: spawnedEnv } = await this.spawnPowerShellChild(cwd, env));\n\t\t} else {\n\t\t\tconst { shell } = getShellConfig(undefined, this.kind);\n\t\t\tconst args = basename(shell).toLowerCase().includes(\"bash\") ? [\"--noprofile\", \"--norc\"] : [];\n\t\t\tconst child = this.spawnProcess(shell, args, {\n\t\t\t\tcwd,\n\t\t\t\tenv,\n\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\tstdio: [\"pipe\", \"pipe\", \"pipe\"],\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t\tthis.attachReadyChild(child);\n\t\t}\n\t\tthis.childEnv = { ...spawnedEnv };\n\t\tthis.lastRequestedCwd = spawnedCwd;\n\t}\n\n\tprivate async spawnPowerShellChild(\n\t\tcwd: string,\n\t\tenv: NodeJS.ProcessEnv,\n\t): Promise<{ cwd: string; env: NodeJS.ProcessEnv }> {\n\t\tconst warmStart = await claimCliPowerShellWarmStart();\n\t\tif (warmStart) {\n\t\t\ttry {\n\t\t\t\tthis.attachReadyChild(warmStart.child);\n\t\t\t} finally {\n\t\t\t\twarmStart.releaseStartupListeners();\n\t\t\t}\n\t\t\treturn { cwd: warmStart.cwd, env: warmStart.env };\n\t\t}\n\t\tconst failures: string[] = [];\n\t\tfor (const candidate of this.resolvePowerShellCandidates()) {\n\t\t\ttry {\n\t\t\t\tawait this.spawnPowerShellCandidate(candidate.shell, cwd, env);\n\t\t\t\treturn { cwd, env };\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tfailures.push(`${candidate.shell}: ${message}`);\n\t\t\t}\n\t\t}\n\t\tconst detail = failures.length > 0 ? ` Candidate failures: ${failures.join(\"; \")}` : \"\";\n\t\tthrow new Error(`PowerShell 7 (pwsh) was not found. Install pwsh before using the Windows shell.${detail}`);\n\t}\n\n\tprivate spawnPowerShellCandidate(shell: string, cwd: string, env: NodeJS.ProcessEnv): Promise<void> {\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\tlet startupSettled = false;\n\t\t\tlet startupStdout: Buffer = Buffer.alloc(0);\n\t\t\tlet startupStderr: Buffer = Buffer.alloc(0);\n\t\t\tlet stdoutReady = false;\n\t\t\tlet stderrReady = false;\n\t\t\tlet timeoutTimer: NodeJS.Timeout | undefined;\n\n\t\t\tconst settleStartup = (finish: () => void): void => {\n\t\t\t\tif (startupSettled) return;\n\t\t\t\tstartupSettled = true;\n\t\t\t\tif (timeoutTimer) clearTimeout(timeoutTimer);\n\t\t\t\tif (this.rejectStartup === rejectStartup) this.rejectStartup = null;\n\t\t\t\tfinish();\n\t\t\t};\n\t\t\tconst startupDiagnostic = (): string => {\n\t\t\t\tconst combined = Buffer.concat([startupStdout, startupStderr]).toString(\"utf8\").trim();\n\t\t\t\treturn combined ? `: ${combined}` : \"\";\n\t\t\t};\n\t\t\tconst rejectStartup = (error: Error): void => {\n\t\t\t\tsettleStartup(() => reject(error));\n\t\t\t};\n\t\t\tconst resolveWhenReady = (): void => {\n\t\t\t\tif (!stdoutReady || !stderrReady) return;\n\t\t\t\tsettleStartup(resolve);\n\t\t\t};\n\n\t\t\tlet child: ChildProcess;\n\t\t\ttry {\n\t\t\t\tchild = this.spawnProcess(shell, [...POWERSHELL_ARGS, POWERSHELL_BOOTSTRAP], {\n\t\t\t\t\tcwd,\n\t\t\t\t\tenv,\n\t\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\t\tstdio: [\"pipe\", \"pipe\", \"pipe\"],\n\t\t\t\t\twindowsHide: true,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\trejectStartup(new Error(`spawn failed: ${message}`));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.rejectStartup = rejectStartup;\n\t\t\tthis.coordinator.attach(child, {\n\t\t\t\tonStdout: (data) => {\n\t\t\t\t\tif (startupSettled) {\n\t\t\t\t\t\tthis.activeExec?.onStdout(data);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tstartupStdout =\n\t\t\t\t\t\tstartupStdout.length === 0\n\t\t\t\t\t\t\t? data\n\t\t\t\t\t\t\t: Buffer.concat([startupStdout, data]).subarray(-MAX_STARTUP_DIAGNOSTIC_BYTES);\n\t\t\t\t\tstdoutReady ||= startupStdout.indexOf(POWERSHELL_SESSION_READY_BYTES) !== -1;\n\t\t\t\t\tresolveWhenReady();\n\t\t\t\t},\n\t\t\t\tonStderr: (data) => {\n\t\t\t\t\tif (startupSettled) {\n\t\t\t\t\t\tthis.activeExec?.onStderr(data);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tstartupStderr =\n\t\t\t\t\t\tstartupStderr.length === 0\n\t\t\t\t\t\t\t? data\n\t\t\t\t\t\t\t: Buffer.concat([startupStderr, data]).subarray(-MAX_STARTUP_DIAGNOSTIC_BYTES);\n\t\t\t\t\tstderrReady ||= startupStderr.indexOf(POWERSHELL_SESSION_STDERR_READY_BYTES) !== -1;\n\t\t\t\t\tresolveWhenReady();\n\t\t\t\t},\n\t\t\t\tonError: (error) => {\n\t\t\t\t\tthis.resetChildState();\n\t\t\t\t\tif (!startupSettled) rejectStartup(new Error(`${error.message}${startupDiagnostic()}`));\n\t\t\t\t\telse this.activeExec?.fail(error);\n\t\t\t\t},\n\t\t\t\tonClose: (code) => {\n\t\t\t\t\tthis.resetChildState();\n\t\t\t\t\tif (!startupSettled) {\n\t\t\t\t\t\trejectStartup(new Error(`exited with code ${code ?? \"null\"} before readiness${startupDiagnostic()}`));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.activeExec?.onChildClose(code);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t});\n\t\t\ttimeoutTimer = setTimeout(() => {\n\t\t\t\tthis.coordinator.kill();\n\t\t\t\tthis.resetChildState();\n\t\t\t\trejectStartup(new Error(`startup timed out after ${this.startupTimeoutMs}ms${startupDiagnostic()}`));\n\t\t\t}, this.startupTimeoutMs);\n\t\t});\n\t}\n\n\tprivate attachReadyChild(child: ChildProcess): void {\n\t\tthis.coordinator.attach(child, {\n\t\t\tonStdout: (data) => this.activeExec?.onStdout(data),\n\t\t\tonStderr: (data) => this.activeExec?.onStderr(data),\n\t\t\tonError: (error) => {\n\t\t\t\tthis.resetChildState();\n\t\t\t\tthis.activeExec?.fail(error);\n\t\t\t},\n\t\t\tonClose: (code) => {\n\t\t\t\tthis.resetChildState();\n\t\t\t\tthis.activeExec?.onChildClose(code);\n\t\t\t},\n\t\t});\n\t}\n\n\tprivate resetChildState(): void {\n\t\tthis.childEnv = null;\n\t\tthis.lastRequestedCwd = null;\n\t}\n\n\tprivate killChild(): void {\n\t\tthis.coordinator.kill();\n\t\tthis.resetChildState();\n\t}\n}\n\nconst shellSessions = new Map<string, PersistentShellSession>();\n\n/** Get or lazily create the persistent session for a key. A kind change replaces the session. */\nexport function acquirePersistentShellSession(key: string, kind: PlatformShellToolName): PersistentShellSession {\n\tconst existing = shellSessions.get(key);\n\tif (existing && existing.sessionKind === kind) return existing;\n\texisting?.dispose();\n\tconst session = new PersistentShellSession(key, kind);\n\tshellSessions.set(key, session);\n\treturn session;\n}\n\n/** Kill and forget a session (agent teardown). Safe to call for keys that never spawned. */\nexport function disposePersistentShellSession(key: string): void {\n\tconst session = shellSessions.get(key);\n\tif (!session) return;\n\tshellSessions.delete(key);\n\tsession.dispose();\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import type { ChildProcess } from "node:child_process";
2
+ /** Toggle every handle owned by a child so idle processes do not keep one-shot CLI modes alive. */
3
+ export declare function setChildProcessLoopRef(child: ChildProcess, active: boolean): void;
4
+ //# sourceMappingURL=child-process-ref.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"child-process-ref.d.ts","sourceRoot":"","sources":["../../src/utils/child-process-ref.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,mGAAmG;AACnG,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAYjF"}
@@ -0,0 +1,15 @@
1
+ /** Toggle every handle owned by a child so idle processes do not keep one-shot CLI modes alive. */
2
+ export function setChildProcessLoopRef(child, active) {
3
+ const streams = [child.stdin, child.stdout, child.stderr];
4
+ if (active) {
5
+ child.ref();
6
+ for (const stream of streams)
7
+ stream?.ref?.();
8
+ }
9
+ else {
10
+ child.unref();
11
+ for (const stream of streams)
12
+ stream?.unref?.();
13
+ }
14
+ }
15
+ //# sourceMappingURL=child-process-ref.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"child-process-ref.js","sourceRoot":"","sources":["../../src/utils/child-process-ref.ts"],"names":[],"mappings":"AAEA,mGAAmG;AACnG,MAAM,UAAU,sBAAsB,CAAC,KAAmB,EAAE,MAAe;IAC1E,MAAM,OAAO,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAG/C,CAAC;IACV,IAAI,MAAM,EAAE,CAAC;QACZ,KAAK,CAAC,GAAG,EAAE,CAAC;QACZ,KAAK,MAAM,MAAM,IAAI,OAAO;YAAE,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;IAC/C,CAAC;SAAM,CAAC;QACP,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,KAAK,MAAM,MAAM,IAAI,OAAO;YAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;IACjD,CAAC;AACF,CAAC","sourcesContent":["import type { ChildProcess } from \"node:child_process\";\n\n/** Toggle every handle owned by a child so idle processes do not keep one-shot CLI modes alive. */\nexport function setChildProcessLoopRef(child: ChildProcess, active: boolean): void {\n\tconst streams = [child.stdin, child.stdout, child.stderr] as unknown as Array<{\n\t\tref?: () => void;\n\t\tunref?: () => void;\n\t} | null>;\n\tif (active) {\n\t\tchild.ref();\n\t\tfor (const stream of streams) stream?.ref?.();\n\t} else {\n\t\tchild.unref();\n\t\tfor (const stream of streams) stream?.unref?.();\n\t}\n}\n"]}
@@ -0,0 +1,16 @@
1
+ /** Native PowerShell cold starts can cross five seconds under loaded Windows/WSL hosts. */
2
+ export declare const POWERSHELL_STARTUP_PROBE_TIMEOUT_MS = 15000;
3
+ export declare const POWERSHELL_ARGS: readonly ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command"];
4
+ export declare const POWERSHELL_7_GUARD = "if ($PSVersionTable.PSVersion.Major -lt 7) { throw 'Pi requires PowerShell 7 or newer.' }\n";
5
+ export declare const POWERSHELL_SESSION_READY_MARKER = "\u001Epi-shell-ready\u001E";
6
+ export declare const POWERSHELL_SESSION_STDERR_READY_MARKER = "\u001Epi-shell-stderr-ready\u001E\n";
7
+ export declare const POWERSHELL_STDERR_BARRIER_LABEL = "stderr";
8
+ /** Deterministic process-only settings for Pi's non-interactive PowerShell host. */
9
+ export declare function createPowerShellHostEnvironment(environment: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
10
+ /**
11
+ * PowerShell 7 persistent REPL bootstrap. The stdout/stderr readiness markers let the process that
12
+ * actually serves commands double as its own availability probe and prime both pipes. Command I/O
13
+ * encoding remains owned by PowerShell and the invoked program; only Pi's base64 wire is UTF-8.
14
+ */
15
+ export declare const POWERSHELL_BOOTSTRAP: string;
16
+ //# sourceMappingURL=powershell-session-protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"powershell-session-protocol.d.ts","sourceRoot":"","sources":["../../src/utils/powershell-session-protocol.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,eAAO,MAAM,mCAAmC,QAAS,CAAC;AAC1D,eAAO,MAAM,eAAe,YAAI,SAAS,EAAE,YAAY,EAAE,iBAAiB,EAAE,UAAU,CAAU,CAAC;AACjG,eAAO,MAAM,kBAAkB,gGAC+D,CAAC;AAC/F,eAAO,MAAM,+BAA+B,+BAA2B,CAAC;AACxE,eAAO,MAAM,sCAAsC,wCAAoC,CAAC;AACxF,eAAO,MAAM,+BAA+B,WAAW,CAAC;AAYxD,oFAAoF;AACpF,wBAAgB,+BAA+B,CAAC,WAAW,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAMjG;AAED;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,QAiCrB,CAAC"}
@@ -0,0 +1,63 @@
1
+ /** Native PowerShell cold starts can cross five seconds under loaded Windows/WSL hosts. */
2
+ export const POWERSHELL_STARTUP_PROBE_TIMEOUT_MS = 15_000;
3
+ export const POWERSHELL_ARGS = ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command"];
4
+ export const POWERSHELL_7_GUARD = "if ($PSVersionTable.PSVersion.Major -lt 7) { throw 'Pi requires PowerShell 7 or newer.' }\n";
5
+ export const POWERSHELL_SESSION_READY_MARKER = "\x1epi-shell-ready\x1e";
6
+ export const POWERSHELL_SESSION_STDERR_READY_MARKER = "\x1epi-shell-stderr-ready\x1e\n";
7
+ export const POWERSHELL_STDERR_BARRIER_LABEL = "stderr";
8
+ const POWERSHELL_HEADLESS_ENVIRONMENT = {
9
+ NO_COLOR: "1",
10
+ POWERSHELL_DIAGNOSTICS_OPTOUT: "1",
11
+ POWERSHELL_TELEMETRY_OPTOUT: "1",
12
+ POWERSHELL_UPDATECHECK: "Off",
13
+ };
14
+ const POWERSHELL_HEADLESS_ENVIRONMENT_NAMES = new Set(Object.keys(POWERSHELL_HEADLESS_ENVIRONMENT).map((name) => name.toLowerCase()));
15
+ /** Deterministic process-only settings for Pi's non-interactive PowerShell host. */
16
+ export function createPowerShellHostEnvironment(environment) {
17
+ const resolved = {};
18
+ for (const [name, value] of Object.entries(environment)) {
19
+ if (!POWERSHELL_HEADLESS_ENVIRONMENT_NAMES.has(name.toLowerCase()))
20
+ resolved[name] = value;
21
+ }
22
+ return { ...resolved, ...POWERSHELL_HEADLESS_ENVIRONMENT };
23
+ }
24
+ /**
25
+ * PowerShell 7 persistent REPL bootstrap. The stdout/stderr readiness markers let the process that
26
+ * actually serves commands double as its own availability probe and prime both pipes. Command I/O
27
+ * encoding remains owned by PowerShell and the invoked program; only Pi's base64 wire is UTF-8.
28
+ */
29
+ export const POWERSHELL_BOOTSTRAP = [
30
+ POWERSHELL_7_GUARD.trimEnd(),
31
+ "$ProgressPreference = 'SilentlyContinue'",
32
+ "$__pi_stdout = [System.IO.StreamWriter]::new([Console]::OpenStandardOutput(), [System.Text.UTF8Encoding]::new($false))",
33
+ "$__pi_stdout.AutoFlush = $true",
34
+ "[Console]::SetOut($__pi_stdout)",
35
+ "$__pi_stderr = [System.IO.StreamWriter]::new([Console]::OpenStandardError(), [System.Text.UTF8Encoding]::new($false))",
36
+ "$__pi_stderr.AutoFlush = $true",
37
+ "[Console]::SetError($__pi_stderr)",
38
+ "$null = Invoke-Expression \"Write-Output '__pi_warmup'\"",
39
+ "[Console]::Error.Write(([char]30) + 'pi-shell-stderr-ready' + ([char]30) + ([char]10))",
40
+ "[Console]::Error.Flush()",
41
+ "[Console]::Out.Write(([char]30) + 'pi-shell-ready' + ([char]30))",
42
+ "function global:__pi_complete_status([int]$Code) { $global:LASTEXITCODE = $Code }",
43
+ "$__pi_in = [Console]::In",
44
+ "while ($true) {",
45
+ "\t$__pi_line = $__pi_in.ReadLine()",
46
+ "\tif ($null -eq $__pi_line) { break }",
47
+ "\t$__pi_sp = $__pi_line.IndexOf(' ')",
48
+ "\tif ($__pi_sp -lt 1) { continue }",
49
+ "\t$__pi_nonce = $__pi_line.Substring(0, $__pi_sp)",
50
+ "\t$__pi_cmd = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($__pi_line.Substring($__pi_sp + 1)))",
51
+ "\t$global:LASTEXITCODE = $null",
52
+ "\t$__pi_thrown = $false",
53
+ "\t$__pi_succeeded = $false",
54
+ "\ttry { Invoke-Expression $__pi_cmd; $__pi_succeeded = $? } catch { $__pi_thrown = $true; $__pi_msg = ($_ | Out-String).TrimEnd(); if ($__pi_msg) { [Console]::Out.WriteLine($__pi_msg) } }",
55
+ "\t$__pi_code = $global:LASTEXITCODE",
56
+ "\tif ($null -eq $__pi_code) { $__pi_code = if ($__pi_succeeded) { 0 } else { 1 } }",
57
+ "\tif ($__pi_thrown -and ($__pi_code -eq 0)) { $__pi_code = 1 }",
58
+ `\t[Console]::Error.Write(('{0}{1}:${POWERSHELL_STDERR_BARRIER_LABEL}{0}{2}' -f [char]30, $__pi_nonce, [char]10))`,
59
+ "\t[Console]::Error.Flush()",
60
+ "\t[Console]::Out.Write(('{0}{1}{2}:{3}{1}' -f [char]10, [char]30, $__pi_nonce, $__pi_code))",
61
+ "}",
62
+ ].join("\n");
63
+ //# sourceMappingURL=powershell-session-protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"powershell-session-protocol.js","sourceRoot":"","sources":["../../src/utils/powershell-session-protocol.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,MAAM,CAAC,MAAM,mCAAmC,GAAG,MAAM,CAAC;AAC1D,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,SAAS,EAAE,YAAY,EAAE,iBAAiB,EAAE,UAAU,CAAU,CAAC;AACjG,MAAM,CAAC,MAAM,kBAAkB,GAC9B,6FAA6F,CAAC;AAC/F,MAAM,CAAC,MAAM,+BAA+B,GAAG,wBAAwB,CAAC;AACxE,MAAM,CAAC,MAAM,sCAAsC,GAAG,iCAAiC,CAAC;AACxF,MAAM,CAAC,MAAM,+BAA+B,GAAG,QAAQ,CAAC;AAExD,MAAM,+BAA+B,GAAG;IACvC,QAAQ,EAAE,GAAG;IACb,6BAA6B,EAAE,GAAG;IAClC,2BAA2B,EAAE,GAAG;IAChC,sBAAsB,EAAE,KAAK;CACpB,CAAC;AACX,MAAM,qCAAqC,GAAG,IAAI,GAAG,CACpD,MAAM,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAC9E,CAAC;AAEF,oFAAoF;AACpF,MAAM,UAAU,+BAA+B,CAAC,WAA8B;IAC7E,MAAM,QAAQ,GAAsB,EAAE,CAAC;IACvC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QACzD,IAAI,CAAC,qCAAqC,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC;IAC5F,CAAC;IACD,OAAO,EAAE,GAAG,QAAQ,EAAE,GAAG,+BAA+B,EAAE,CAAC;AAC5D,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG;IACnC,kBAAkB,CAAC,OAAO,EAAE;IAC5B,0CAA0C;IAC1C,wHAAwH;IACxH,gCAAgC;IAChC,iCAAiC;IACjC,uHAAuH;IACvH,gCAAgC;IAChC,mCAAmC;IACnC,0DAA0D;IAC1D,wFAAwF;IACxF,0BAA0B;IAC1B,kEAAkE;IAClE,mFAAmF;IACnF,0BAA0B;IAC1B,iBAAiB;IACjB,oCAAoC;IACpC,uCAAuC;IACvC,sCAAsC;IACtC,oCAAoC;IACpC,mDAAmD;IACnD,8HAA8H;IAC9H,gCAAgC;IAChC,yBAAyB;IACzB,4BAA4B;IAC5B,6LAA6L;IAC7L,qCAAqC;IACrC,oFAAoF;IACpF,gEAAgE;IAChE,qCAAqC,+BAA+B,8CAA8C;IAClH,4BAA4B;IAC5B,6FAA6F;IAC7F,GAAG;CACH,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC","sourcesContent":["/** Native PowerShell cold starts can cross five seconds under loaded Windows/WSL hosts. */\nexport const POWERSHELL_STARTUP_PROBE_TIMEOUT_MS = 15_000;\nexport const POWERSHELL_ARGS = [\"-NoLogo\", \"-NoProfile\", \"-NonInteractive\", \"-Command\"] as const;\nexport const POWERSHELL_7_GUARD =\n\t\"if ($PSVersionTable.PSVersion.Major -lt 7) { throw 'Pi requires PowerShell 7 or newer.' }\\n\";\nexport const POWERSHELL_SESSION_READY_MARKER = \"\\x1epi-shell-ready\\x1e\";\nexport const POWERSHELL_SESSION_STDERR_READY_MARKER = \"\\x1epi-shell-stderr-ready\\x1e\\n\";\nexport const POWERSHELL_STDERR_BARRIER_LABEL = \"stderr\";\n\nconst POWERSHELL_HEADLESS_ENVIRONMENT = {\n\tNO_COLOR: \"1\",\n\tPOWERSHELL_DIAGNOSTICS_OPTOUT: \"1\",\n\tPOWERSHELL_TELEMETRY_OPTOUT: \"1\",\n\tPOWERSHELL_UPDATECHECK: \"Off\",\n} as const;\nconst POWERSHELL_HEADLESS_ENVIRONMENT_NAMES = new Set(\n\tObject.keys(POWERSHELL_HEADLESS_ENVIRONMENT).map((name) => name.toLowerCase()),\n);\n\n/** Deterministic process-only settings for Pi's non-interactive PowerShell host. */\nexport function createPowerShellHostEnvironment(environment: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n\tconst resolved: NodeJS.ProcessEnv = {};\n\tfor (const [name, value] of Object.entries(environment)) {\n\t\tif (!POWERSHELL_HEADLESS_ENVIRONMENT_NAMES.has(name.toLowerCase())) resolved[name] = value;\n\t}\n\treturn { ...resolved, ...POWERSHELL_HEADLESS_ENVIRONMENT };\n}\n\n/**\n * PowerShell 7 persistent REPL bootstrap. The stdout/stderr readiness markers let the process that\n * actually serves commands double as its own availability probe and prime both pipes. Command I/O\n * encoding remains owned by PowerShell and the invoked program; only Pi's base64 wire is UTF-8.\n */\nexport const POWERSHELL_BOOTSTRAP = [\n\tPOWERSHELL_7_GUARD.trimEnd(),\n\t\"$ProgressPreference = 'SilentlyContinue'\",\n\t\"$__pi_stdout = [System.IO.StreamWriter]::new([Console]::OpenStandardOutput(), [System.Text.UTF8Encoding]::new($false))\",\n\t\"$__pi_stdout.AutoFlush = $true\",\n\t\"[Console]::SetOut($__pi_stdout)\",\n\t\"$__pi_stderr = [System.IO.StreamWriter]::new([Console]::OpenStandardError(), [System.Text.UTF8Encoding]::new($false))\",\n\t\"$__pi_stderr.AutoFlush = $true\",\n\t\"[Console]::SetError($__pi_stderr)\",\n\t\"$null = Invoke-Expression \\\"Write-Output '__pi_warmup'\\\"\",\n\t\"[Console]::Error.Write(([char]30) + 'pi-shell-stderr-ready' + ([char]30) + ([char]10))\",\n\t\"[Console]::Error.Flush()\",\n\t\"[Console]::Out.Write(([char]30) + 'pi-shell-ready' + ([char]30))\",\n\t\"function global:__pi_complete_status([int]$Code) { $global:LASTEXITCODE = $Code }\",\n\t\"$__pi_in = [Console]::In\",\n\t\"while ($true) {\",\n\t\"\\t$__pi_line = $__pi_in.ReadLine()\",\n\t\"\\tif ($null -eq $__pi_line) { break }\",\n\t\"\\t$__pi_sp = $__pi_line.IndexOf(' ')\",\n\t\"\\tif ($__pi_sp -lt 1) { continue }\",\n\t\"\\t$__pi_nonce = $__pi_line.Substring(0, $__pi_sp)\",\n\t\"\\t$__pi_cmd = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($__pi_line.Substring($__pi_sp + 1)))\",\n\t\"\\t$global:LASTEXITCODE = $null\",\n\t\"\\t$__pi_thrown = $false\",\n\t\"\\t$__pi_succeeded = $false\",\n\t\"\\ttry { Invoke-Expression $__pi_cmd; $__pi_succeeded = $? } catch { $__pi_thrown = $true; $__pi_msg = ($_ | Out-String).TrimEnd(); if ($__pi_msg) { [Console]::Out.WriteLine($__pi_msg) } }\",\n\t\"\\t$__pi_code = $global:LASTEXITCODE\",\n\t\"\\tif ($null -eq $__pi_code) { $__pi_code = if ($__pi_succeeded) { 0 } else { 1 } }\",\n\t\"\\tif ($__pi_thrown -and ($__pi_code -eq 0)) { $__pi_code = 1 }\",\n\t`\\t[Console]::Error.Write(('{0}{1}:${POWERSHELL_STDERR_BARRIER_LABEL}{0}{2}' -f [char]30, $__pi_nonce, [char]10))`,\n\t\"\\t[Console]::Error.Flush()\",\n\t\"\\t[Console]::Out.Write(('{0}{1}{2}:{3}{1}' -f [char]10, [char]30, $__pi_nonce, $__pi_code))\",\n\t\"}\",\n].join(\"\\n\");\n"]}
@@ -1,13 +1,16 @@
1
+ export { POWERSHELL_STARTUP_PROBE_TIMEOUT_MS } from "./powershell-session-protocol.ts";
1
2
  export type PlatformShellToolName = "bash" | "powershell";
2
3
  export interface ShellConfig {
3
4
  shell: string;
4
5
  args: string[];
5
6
  }
6
- export declare const POWERSHELL_UTF8_PREFIX = "try { [Console]::OutputEncoding=[System.Text.Encoding]::UTF8 } catch {}\n";
7
- /** Native PowerShell cold starts can cross five seconds under loaded Windows/WSL hosts. */
8
- export declare const POWERSHELL_STARTUP_PROBE_TIMEOUT_MS = 15000;
9
7
  export declare function getPlatformShellToolName(platform?: NodeJS.Platform): PlatformShellToolName;
10
- export declare function prefixPowerShellCommand(command: string): string;
8
+ /**
9
+ * Ordered PowerShell candidates without launching a disposable interpreter. Persistent sessions
10
+ * validate these candidates with their real long-lived bootstrap, so the normal path pays for one
11
+ * PowerShell process instead of probing one process and then spawning another.
12
+ */
13
+ export declare function getPowerShellCandidateConfigs(): ShellConfig[];
11
14
  /** Resolve the requested shell. Runtime callers omit shellName to select PowerShell on Windows and Bash elsewhere. */
12
15
  export declare function getShellConfig(customShellPath?: string, shellName?: PlatformShellToolName): ShellConfig;
13
16
  export declare function getShellEnv(): NodeJS.ProcessEnv;
@@ -1 +1 @@
1
- {"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../../src/utils/shell.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,YAAY,CAAC;AAE1D,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,EAAE,CAAC;CACf;AAED,eAAO,MAAM,sBAAsB,8EAA8E,CAAC;AAClH,2FAA2F;AAC3F,eAAO,MAAM,mCAAmC,QAAS,CAAC;AAI1D,wBAAgB,wBAAwB,CAAC,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAAG,qBAAqB,CAE5G;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE/D;AAqFD,sHAAsH;AACtH,wBAAgB,cAAc,CAC7B,eAAe,CAAC,EAAE,MAAM,EACxB,SAAS,GAAE,qBAAkD,GAC3D,WAAW,CAeb;AAED,wBAAgB,WAAW,IAAI,MAAM,CAAC,UAAU,CAoB/C;AAQD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEvD;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEzD;AAED,wBAAgB,2BAA2B,IAAI,IAAI,CAKlD;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAyBjD"}
1
+ {"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../../src/utils/shell.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,mCAAmC,EAAE,MAAM,kCAAkC,CAAC;AAEvF,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,YAAY,CAAC;AAE1D,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,EAAE,CAAC;CACf;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAAG,qBAAqB,CAE5G;AAuCD;;;;GAIG;AACH,wBAAgB,6BAA6B,IAAI,WAAW,EAAE,CAqB7D;AAkCD,sHAAsH;AACtH,wBAAgB,cAAc,CAC7B,eAAe,CAAC,EAAE,MAAM,EACxB,SAAS,GAAE,qBAAkD,GAC3D,WAAW,CAkBb;AAED,wBAAgB,WAAW,IAAI,MAAM,CAAC,UAAU,CAoB/C;AAQD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEvD;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEzD;AAED,wBAAgB,2BAA2B,IAAI,IAAI,CAKlD;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAyBjD"}
@@ -1,19 +1,14 @@
1
1
  import { existsSync } from "node:fs";
2
- import { delimiter } from "node:path";
2
+ import { basename, delimiter } from "node:path";
3
3
  import { spawnSync } from "child_process";
4
4
  import { getBinDir } from "../config.js";
5
5
  import { ensureManagedJscpd } from "./bundled-jscpd.js";
6
6
  import { normalizePath } from "./paths.js";
7
- export const POWERSHELL_UTF8_PREFIX = "try { [Console]::OutputEncoding=[System.Text.Encoding]::UTF8 } catch {}\n";
8
- /** Native PowerShell cold starts can cross five seconds under loaded Windows/WSL hosts. */
9
- export const POWERSHELL_STARTUP_PROBE_TIMEOUT_MS = 15_000;
10
- const POWERSHELL_ARGS = ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command"];
7
+ import { createPowerShellHostEnvironment, POWERSHELL_7_GUARD, POWERSHELL_ARGS, POWERSHELL_STARTUP_PROBE_TIMEOUT_MS, } from "./powershell-session-protocol.js";
8
+ export { POWERSHELL_STARTUP_PROBE_TIMEOUT_MS } from "./powershell-session-protocol.js";
11
9
  export function getPlatformShellToolName(platform = process.platform) {
12
10
  return platform === "win32" ? "powershell" : "bash";
13
11
  }
14
- export function prefixPowerShellCommand(command) {
15
- return command.trimStart().startsWith(POWERSHELL_UTF8_PREFIX) ? command : `${POWERSHELL_UTF8_PREFIX}${command}`;
16
- }
17
12
  function findExecutableOnPath(executable) {
18
13
  const locator = process.platform === "win32" ? "where" : "which";
19
14
  try {
@@ -35,8 +30,9 @@ function findExecutableOnPath(executable) {
35
30
  }
36
31
  function isPowerShellExecutableAvailable(executable) {
37
32
  try {
38
- return (spawnSync(executable, [...POWERSHELL_ARGS, "Write-Output ok"], {
33
+ return (spawnSync(executable, [...POWERSHELL_ARGS, `${POWERSHELL_7_GUARD}Write-Output ok`], {
39
34
  encoding: "utf-8",
35
+ env: createPowerShellHostEnvironment(process.env),
40
36
  timeout: POWERSHELL_STARTUP_PROBE_TIMEOUT_MS,
41
37
  windowsHide: true,
42
38
  }).status === 0);
@@ -45,28 +41,44 @@ function isPowerShellExecutableAvailable(executable) {
45
41
  return false;
46
42
  }
47
43
  }
48
- function getPowerShellConfig() {
44
+ function isPowerShell7Executable(executable) {
45
+ return /^pwsh(?:\.exe)?$/iu.test(basename(executable));
46
+ }
47
+ /**
48
+ * Ordered PowerShell candidates without launching a disposable interpreter. Persistent sessions
49
+ * validate these candidates with their real long-lived bootstrap, so the normal path pays for one
50
+ * PowerShell process instead of probing one process and then spawning another.
51
+ */
52
+ export function getPowerShellCandidateConfigs() {
53
+ const candidates = [];
54
+ const seen = new Set();
55
+ const addCandidate = (shell) => {
56
+ if (!shell || !isPowerShell7Executable(shell))
57
+ return;
58
+ const identity = process.platform === "win32" ? shell.toLowerCase() : shell;
59
+ if (seen.has(identity))
60
+ return;
61
+ seen.add(identity);
62
+ candidates.push({ shell, args: [...POWERSHELL_ARGS] });
63
+ };
49
64
  const pwshOnPath = findExecutableOnPath(process.platform === "win32" ? "pwsh.exe" : "pwsh");
50
- if (pwshOnPath && isPowerShellExecutableAvailable(pwshOnPath)) {
51
- return { shell: pwshOnPath, args: [...POWERSHELL_ARGS] };
52
- }
65
+ addCandidate(pwshOnPath);
53
66
  const knownPaths = [];
54
67
  const programFiles = process.env.ProgramFiles;
55
68
  if (programFiles)
56
69
  knownPaths.push(`${programFiles}\\PowerShell\\7\\pwsh.exe`);
57
- const systemRoot = process.env.SystemRoot;
58
- if (systemRoot)
59
- knownPaths.push(`${systemRoot}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`);
60
70
  for (const path of knownPaths) {
61
- if (existsSync(path) && isPowerShellExecutableAvailable(path)) {
62
- return { shell: path, args: [...POWERSHELL_ARGS] };
63
- }
71
+ if (existsSync(path))
72
+ addCandidate(path);
64
73
  }
65
- const windowsPowerShellOnPath = findExecutableOnPath("powershell.exe");
66
- if (windowsPowerShellOnPath && isPowerShellExecutableAvailable(windowsPowerShellOnPath)) {
67
- return { shell: windowsPowerShellOnPath, args: [...POWERSHELL_ARGS] };
74
+ return candidates;
75
+ }
76
+ function getPowerShellConfig() {
77
+ for (const candidate of getPowerShellCandidateConfigs()) {
78
+ if (isPowerShellExecutableAvailable(candidate.shell))
79
+ return candidate;
68
80
  }
69
- throw new Error("No PowerShell executable found. Install PowerShell 7 (pwsh), restore Windows PowerShell, or set shellPath in settings.json.");
81
+ throw new Error("PowerShell 7 (pwsh) was not found. Install pwsh or set shellPath to a pwsh executable.");
70
82
  }
71
83
  function getBashConfig() {
72
84
  if (process.platform === "win32") {
@@ -100,6 +112,9 @@ let managedJscpdProvisionAttempted = false;
100
112
  export function getShellConfig(customShellPath, shellName = getPlatformShellToolName()) {
101
113
  if (customShellPath) {
102
114
  const resolvedShellPath = normalizePath(customShellPath);
115
+ if (shellName === "powershell" && !isPowerShell7Executable(resolvedShellPath)) {
116
+ throw new Error(`Custom PowerShell host must be PowerShell 7 (pwsh): ${resolvedShellPath}`);
117
+ }
103
118
  if (!existsSync(resolvedShellPath))
104
119
  throw new Error(`Custom shell path not found: ${resolvedShellPath}`);
105
120
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"shell.js","sourceRoot":"","sources":["../../src/utils/shell.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { delimiter } from \"node:path\";\nimport { spawnSync } from \"child_process\";\nimport { getBinDir } from \"../config.ts\";\nimport { ensureManagedJscpd } from \"./bundled-jscpd.ts\";\nimport { normalizePath } from \"./paths.ts\";\n\nexport type PlatformShellToolName = \"bash\" | \"powershell\";\n\nexport interface ShellConfig {\n\tshell: string;\n\targs: string[];\n}\n\nexport const POWERSHELL_UTF8_PREFIX = \"try { [Console]::OutputEncoding=[System.Text.Encoding]::UTF8 } catch {}\\n\";\n/** Native PowerShell cold starts can cross five seconds under loaded Windows/WSL hosts. */\nexport const POWERSHELL_STARTUP_PROBE_TIMEOUT_MS = 15_000;\n\nconst POWERSHELL_ARGS = [\"-NoLogo\", \"-NoProfile\", \"-NonInteractive\", \"-Command\"];\n\nexport function getPlatformShellToolName(platform: NodeJS.Platform = process.platform): PlatformShellToolName {\n\treturn platform === \"win32\" ? \"powershell\" : \"bash\";\n}\n\nexport function prefixPowerShellCommand(command: string): string {\n\treturn command.trimStart().startsWith(POWERSHELL_UTF8_PREFIX) ? command : `${POWERSHELL_UTF8_PREFIX}${command}`;\n}\n\nfunction findExecutableOnPath(executable: string): string | null {\n\tconst locator = process.platform === \"win32\" ? \"where\" : \"which\";\n\ttry {\n\t\tconst result = spawnSync(locator, [executable], {\n\t\t\tencoding: \"utf-8\",\n\t\t\ttimeout: 5_000,\n\t\t\twindowsHide: true,\n\t\t});\n\t\tif (result.status === 0 && result.stdout) {\n\t\t\tconst firstMatch = result.stdout.trim().split(/\\r?\\n/)[0];\n\t\t\tif (firstMatch && (process.platform !== \"win32\" || existsSync(firstMatch))) return firstMatch;\n\t\t}\n\t} catch {\n\t\t// Resolution falls through to known paths or the platform fallback.\n\t}\n\treturn null;\n}\n\nfunction isPowerShellExecutableAvailable(executable: string): boolean {\n\ttry {\n\t\treturn (\n\t\t\tspawnSync(executable, [...POWERSHELL_ARGS, \"Write-Output ok\"], {\n\t\t\t\tencoding: \"utf-8\",\n\t\t\t\ttimeout: POWERSHELL_STARTUP_PROBE_TIMEOUT_MS,\n\t\t\t\twindowsHide: true,\n\t\t\t}).status === 0\n\t\t);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction getPowerShellConfig(): ShellConfig {\n\tconst pwshOnPath = findExecutableOnPath(process.platform === \"win32\" ? \"pwsh.exe\" : \"pwsh\");\n\tif (pwshOnPath && isPowerShellExecutableAvailable(pwshOnPath)) {\n\t\treturn { shell: pwshOnPath, args: [...POWERSHELL_ARGS] };\n\t}\n\n\tconst knownPaths: string[] = [];\n\tconst programFiles = process.env.ProgramFiles;\n\tif (programFiles) knownPaths.push(`${programFiles}\\\\PowerShell\\\\7\\\\pwsh.exe`);\n\tconst systemRoot = process.env.SystemRoot;\n\tif (systemRoot) knownPaths.push(`${systemRoot}\\\\System32\\\\WindowsPowerShell\\\\v1.0\\\\powershell.exe`);\n\tfor (const path of knownPaths) {\n\t\tif (existsSync(path) && isPowerShellExecutableAvailable(path)) {\n\t\t\treturn { shell: path, args: [...POWERSHELL_ARGS] };\n\t\t}\n\t}\n\n\tconst windowsPowerShellOnPath = findExecutableOnPath(\"powershell.exe\");\n\tif (windowsPowerShellOnPath && isPowerShellExecutableAvailable(windowsPowerShellOnPath)) {\n\t\treturn { shell: windowsPowerShellOnPath, args: [...POWERSHELL_ARGS] };\n\t}\n\tthrow new Error(\n\t\t\"No PowerShell executable found. Install PowerShell 7 (pwsh), restore Windows PowerShell, or set shellPath in settings.json.\",\n\t);\n}\n\nfunction getBashConfig(): ShellConfig {\n\tif (process.platform === \"win32\") {\n\t\tconst knownPaths: string[] = [];\n\t\tconst programFiles = process.env.ProgramFiles;\n\t\tif (programFiles) knownPaths.push(`${programFiles}\\\\Git\\\\bin\\\\bash.exe`);\n\t\tconst programFilesX86 = process.env[\"ProgramFiles(x86)\"];\n\t\tif (programFilesX86) knownPaths.push(`${programFilesX86}\\\\Git\\\\bin\\\\bash.exe`);\n\t\tfor (const path of knownPaths) {\n\t\t\tif (existsSync(path)) return { shell: path, args: [\"-c\"] };\n\t\t}\n\t\tconst bashOnPath = findExecutableOnPath(\"bash.exe\");\n\t\tif (bashOnPath) return { shell: bashOnPath, args: [\"-c\"] };\n\t\tthrow new Error(\"No Bash executable found. Install Git Bash or set shellPath in settings.json.\");\n\t}\n\tif (existsSync(\"/bin/bash\")) return { shell: \"/bin/bash\", args: [\"-c\"] };\n\tconst bashOnPath = findExecutableOnPath(\"bash\");\n\treturn bashOnPath ? { shell: bashOnPath, args: [\"-c\"] } : { shell: \"sh\", args: [\"-c\"] };\n}\n\n// Platform shell resolution spawns probe processes (`where`/`which`, plus a full PowerShell\n// boot on Windows) and is a process-lifetime invariant, so successful resolutions are cached.\n// Failures are not cached: the user can install a shell and retry without restarting.\nconst resolvedPlatformShellConfigs = new Map<PlatformShellToolName, ShellConfig>();\nlet managedJscpdProvisionAttempted = false;\n\n/** Resolve the requested shell. Runtime callers omit shellName to select PowerShell on Windows and Bash elsewhere. */\nexport function getShellConfig(\n\tcustomShellPath?: string,\n\tshellName: PlatformShellToolName = getPlatformShellToolName(),\n): ShellConfig {\n\tif (customShellPath) {\n\t\tconst resolvedShellPath = normalizePath(customShellPath);\n\t\tif (!existsSync(resolvedShellPath)) throw new Error(`Custom shell path not found: ${resolvedShellPath}`);\n\t\treturn {\n\t\t\tshell: resolvedShellPath,\n\t\t\targs: shellName === \"powershell\" ? [...POWERSHELL_ARGS] : [\"-c\"],\n\t\t};\n\t}\n\tlet resolved = resolvedPlatformShellConfigs.get(shellName);\n\tif (!resolved) {\n\t\tresolved = shellName === \"powershell\" ? getPowerShellConfig() : getBashConfig();\n\t\tresolvedPlatformShellConfigs.set(shellName, resolved);\n\t}\n\treturn { shell: resolved.shell, args: [...resolved.args] };\n}\n\nexport function getShellEnv(): NodeJS.ProcessEnv {\n\tif (!managedJscpdProvisionAttempted) {\n\t\tmanagedJscpdProvisionAttempted = true;\n\t\ttry {\n\t\t\tensureManagedJscpd();\n\t\t} catch {\n\t\t\t// The jscpd wrapper and doctor surface the exact packaging failure. Shell startup stays usable.\n\t\t}\n\t}\n\tconst binDir = getBinDir();\n\tconst pathKey = Object.keys(process.env).find((key) => key.toLowerCase() === \"path\") ?? \"PATH\";\n\tconst currentPath = process.env[pathKey] ?? \"\";\n\tconst pathEntries = currentPath.split(delimiter).filter(Boolean);\n\tconst hasBinDir = pathEntries.includes(binDir);\n\tconst updatedPath = hasBinDir ? currentPath : [binDir, currentPath].filter(Boolean).join(delimiter);\n\n\treturn {\n\t\t...process.env,\n\t\t[pathKey]: updatedPath,\n\t};\n}\n\n/**\n * Detached child processes must be tracked so they can be killed on parent\n * shutdown signals (SIGHUP/SIGTERM).\n */\nconst trackedDetachedChildPids = new Set<number>();\n\nexport function trackDetachedChildPid(pid: number): void {\n\ttrackedDetachedChildPids.add(pid);\n}\n\nexport function untrackDetachedChildPid(pid: number): void {\n\ttrackedDetachedChildPids.delete(pid);\n}\n\nexport function killTrackedDetachedChildren(): void {\n\tfor (const pid of trackedDetachedChildPids) {\n\t\tkillProcessTree(pid);\n\t}\n\ttrackedDetachedChildPids.clear();\n}\n\n/**\n * Kill a process and all its children (cross-platform).\n *\n * Windows uses `spawnSync` (not `spawn`) deliberately: callers rely on this function returning\n * only once the tree is actually gone (e.g. before removing a directory that was the killed\n * process's cwd — a directory Windows keeps locked until every handle into it, including a\n * live process's cwd handle, is released). A fire-and-forget async `taskkill` would return before\n * termination completed, leaving a race where the directory is still locked.\n */\nexport function killProcessTree(pid: number): void {\n\tif (process.platform === \"win32\") {\n\t\t// Use taskkill on Windows to kill process tree; spawnSync blocks until taskkill itself\n\t\t// (and therefore the termination it requested) has finished.\n\t\ttry {\n\t\t\tspawnSync(\"taskkill\", [\"/F\", \"/T\", \"/PID\", String(pid)], {\n\t\t\t\tstdio: \"ignore\",\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t} catch {\n\t\t\t// Ignore errors if taskkill fails\n\t\t}\n\t} else {\n\t\t// Use SIGKILL on Unix/Linux/Mac\n\t\ttry {\n\t\t\tprocess.kill(-pid, \"SIGKILL\");\n\t\t} catch {\n\t\t\t// Fallback to killing just the child if process group kill fails\n\t\t\ttry {\n\t\t\t\tprocess.kill(pid, \"SIGKILL\");\n\t\t\t} catch {\n\t\t\t\t// Process already dead\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"shell.js","sourceRoot":"","sources":["../../src/utils/shell.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EACN,+BAA+B,EAC/B,kBAAkB,EAClB,eAAe,EACf,mCAAmC,GACnC,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EAAE,mCAAmC,EAAE,MAAM,kCAAkC,CAAC;AASvF,MAAM,UAAU,wBAAwB,CAAC,QAAQ,GAAoB,OAAO,CAAC,QAAQ;IACpF,OAAO,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC;AACrD,CAAC;AAED,SAAS,oBAAoB,CAAC,UAAkB;IAC/C,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;IACjE,IAAI,CAAC;QACJ,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC,UAAU,CAAC,EAAE;YAC/C,QAAQ,EAAE,OAAO;YACjB,OAAO,EAAE,KAAK;YACd,WAAW,EAAE,IAAI;SACjB,CAAC,CAAC;QACH,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAC1C,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;YAC1D,IAAI,UAAU,IAAI,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,IAAI,UAAU,CAAC,UAAU,CAAC,CAAC;gBAAE,OAAO,UAAU,CAAC;QAC/F,CAAC;IACF,CAAC;IAAC,MAAM,CAAC;QACR,oEAAoE;IACrE,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED,SAAS,+BAA+B,CAAC,UAAkB;IAC1D,IAAI,CAAC;QACJ,OAAO,CACN,SAAS,CAAC,UAAU,EAAE,CAAC,GAAG,eAAe,EAAE,GAAG,kBAAkB,iBAAiB,CAAC,EAAE;YACnF,QAAQ,EAAE,OAAO;YACjB,GAAG,EAAE,+BAA+B,CAAC,OAAO,CAAC,GAAG,CAAC;YACjD,OAAO,EAAE,mCAAmC;YAC5C,WAAW,EAAE,IAAI;SACjB,CAAC,CAAC,MAAM,KAAK,CAAC,CACf,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,KAAK,CAAC;IACd,CAAC;AACF,CAAC;AAED,SAAS,uBAAuB,CAAC,UAAkB;IAClD,OAAO,oBAAoB,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;AACxD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,6BAA6B;IAC5C,MAAM,UAAU,GAAkB,EAAE,CAAC;IACrC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,YAAY,GAAG,CAAC,KAAoB,EAAQ,EAAE;QACnD,IAAI,CAAC,KAAK,IAAI,CAAC,uBAAuB,CAAC,KAAK,CAAC;YAAE,OAAO;QACtD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;QAC5E,IAAI,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;YAAE,OAAO;QAC/B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACnB,UAAU,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,GAAG,eAAe,CAAC,EAAE,CAAC,CAAC;IACxD,CAAC,CAAC;IAEF,MAAM,UAAU,GAAG,oBAAoB,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC5F,YAAY,CAAC,UAAU,CAAC,CAAC;IAEzB,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;IAC9C,IAAI,YAAY;QAAE,UAAU,CAAC,IAAI,CAAC,GAAG,YAAY,2BAA2B,CAAC,CAAC;IAC9E,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC/B,IAAI,UAAU,CAAC,IAAI,CAAC;YAAE,YAAY,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,UAAU,CAAC;AACnB,CAAC;AAED,SAAS,mBAAmB;IAC3B,KAAK,MAAM,SAAS,IAAI,6BAA6B,EAAE,EAAE,CAAC;QACzD,IAAI,+BAA+B,CAAC,SAAS,CAAC,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;IACxE,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,wFAAwF,CAAC,CAAC;AAC3G,CAAC;AAED,SAAS,aAAa;IACrB,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QAClC,MAAM,UAAU,GAAa,EAAE,CAAC;QAChC,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;QAC9C,IAAI,YAAY;YAAE,UAAU,CAAC,IAAI,CAAC,GAAG,YAAY,sBAAsB,CAAC,CAAC;QACzE,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QACzD,IAAI,eAAe;YAAE,UAAU,CAAC,IAAI,CAAC,GAAG,eAAe,sBAAsB,CAAC,CAAC;QAC/E,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;YAC/B,IAAI,UAAU,CAAC,IAAI,CAAC;gBAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5D,CAAC;QACD,MAAM,UAAU,GAAG,oBAAoB,CAAC,UAAU,CAAC,CAAC;QACpD,IAAI,UAAU;YAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3D,MAAM,IAAI,KAAK,CAAC,+EAA+E,CAAC,CAAC;IAClG,CAAC;IACD,IAAI,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;IACzE,MAAM,UAAU,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAChD,OAAO,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;AACzF,CAAC;AAED,4FAA4F;AAC5F,8FAA8F;AAC9F,sFAAsF;AACtF,MAAM,4BAA4B,GAAG,IAAI,GAAG,EAAsC,CAAC;AACnF,IAAI,8BAA8B,GAAG,KAAK,CAAC;AAE3C,sHAAsH;AACtH,MAAM,UAAU,cAAc,CAC7B,eAAwB,EACxB,SAAS,GAA0B,wBAAwB,EAAE;IAE7D,IAAI,eAAe,EAAE,CAAC;QACrB,MAAM,iBAAiB,GAAG,aAAa,CAAC,eAAe,CAAC,CAAC;QACzD,IAAI,SAAS,KAAK,YAAY,IAAI,CAAC,uBAAuB,CAAC,iBAAiB,CAAC,EAAE,CAAC;YAC/E,MAAM,IAAI,KAAK,CAAC,uDAAuD,iBAAiB,EAAE,CAAC,CAAC;QAC7F,CAAC;QACD,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,gCAAgC,iBAAiB,EAAE,CAAC,CAAC;QACzG,OAAO;YACN,KAAK,EAAE,iBAAiB;YACxB,IAAI,EAAE,SAAS,KAAK,YAAY,CAAC,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;SAChE,CAAC;IACH,CAAC;IACD,IAAI,QAAQ,GAAG,4BAA4B,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC3D,IAAI,CAAC,QAAQ,EAAE,CAAC;QACf,QAAQ,GAAG,SAAS,KAAK,YAAY,CAAC,CAAC,CAAC,mBAAmB,EAAE,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;QAChF,4BAA4B,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,WAAW;IAC1B,IAAI,CAAC,8BAA8B,EAAE,CAAC;QACrC,8BAA8B,GAAG,IAAI,CAAC;QACtC,IAAI,CAAC;YACJ,kBAAkB,EAAE,CAAC;QACtB,CAAC;QAAC,MAAM,CAAC;YACR,gGAAgG;QACjG,CAAC;IACF,CAAC;IACD,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC;IAC/F,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;IAC/C,MAAM,WAAW,GAAG,WAAW,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACjE,MAAM,SAAS,GAAG,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC/C,MAAM,WAAW,GAAG,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAEpG,OAAO;QACN,GAAG,OAAO,CAAC,GAAG;QACd,CAAC,OAAO,CAAC,EAAE,WAAW;KACtB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,wBAAwB,GAAG,IAAI,GAAG,EAAU,CAAC;AAEnD,MAAM,UAAU,qBAAqB,CAAC,GAAW;IAChD,wBAAwB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,GAAW;IAClD,wBAAwB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,2BAA2B;IAC1C,KAAK,MAAM,GAAG,IAAI,wBAAwB,EAAE,CAAC;QAC5C,eAAe,CAAC,GAAG,CAAC,CAAC;IACtB,CAAC;IACD,wBAAwB,CAAC,KAAK,EAAE,CAAC;AAClC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IAC1C,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QAClC,uFAAuF;QACvF,6DAA6D;QAC7D,IAAI,CAAC;YACJ,SAAS,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE;gBACxD,KAAK,EAAE,QAAQ;gBACf,WAAW,EAAE,IAAI;aACjB,CAAC,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACR,kCAAkC;QACnC,CAAC;IACF,CAAC;SAAM,CAAC;QACP,gCAAgC;QAChC,IAAI,CAAC;YACJ,OAAO,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACR,iEAAiE;YACjE,IAAI,CAAC;gBACJ,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YAC9B,CAAC;YAAC,MAAM,CAAC;gBACR,uBAAuB;YACxB,CAAC;QACF,CAAC;IACF,CAAC;AACF,CAAC","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { basename, delimiter } from \"node:path\";\nimport { spawnSync } from \"child_process\";\nimport { getBinDir } from \"../config.ts\";\nimport { ensureManagedJscpd } from \"./bundled-jscpd.ts\";\nimport { normalizePath } from \"./paths.ts\";\nimport {\n\tcreatePowerShellHostEnvironment,\n\tPOWERSHELL_7_GUARD,\n\tPOWERSHELL_ARGS,\n\tPOWERSHELL_STARTUP_PROBE_TIMEOUT_MS,\n} from \"./powershell-session-protocol.ts\";\n\nexport { POWERSHELL_STARTUP_PROBE_TIMEOUT_MS } from \"./powershell-session-protocol.ts\";\n\nexport type PlatformShellToolName = \"bash\" | \"powershell\";\n\nexport interface ShellConfig {\n\tshell: string;\n\targs: string[];\n}\n\nexport function getPlatformShellToolName(platform: NodeJS.Platform = process.platform): PlatformShellToolName {\n\treturn platform === \"win32\" ? \"powershell\" : \"bash\";\n}\n\nfunction findExecutableOnPath(executable: string): string | null {\n\tconst locator = process.platform === \"win32\" ? \"where\" : \"which\";\n\ttry {\n\t\tconst result = spawnSync(locator, [executable], {\n\t\t\tencoding: \"utf-8\",\n\t\t\ttimeout: 5_000,\n\t\t\twindowsHide: true,\n\t\t});\n\t\tif (result.status === 0 && result.stdout) {\n\t\t\tconst firstMatch = result.stdout.trim().split(/\\r?\\n/)[0];\n\t\t\tif (firstMatch && (process.platform !== \"win32\" || existsSync(firstMatch))) return firstMatch;\n\t\t}\n\t} catch {\n\t\t// Resolution falls through to known paths or the platform fallback.\n\t}\n\treturn null;\n}\n\nfunction isPowerShellExecutableAvailable(executable: string): boolean {\n\ttry {\n\t\treturn (\n\t\t\tspawnSync(executable, [...POWERSHELL_ARGS, `${POWERSHELL_7_GUARD}Write-Output ok`], {\n\t\t\t\tencoding: \"utf-8\",\n\t\t\t\tenv: createPowerShellHostEnvironment(process.env),\n\t\t\t\ttimeout: POWERSHELL_STARTUP_PROBE_TIMEOUT_MS,\n\t\t\t\twindowsHide: true,\n\t\t\t}).status === 0\n\t\t);\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction isPowerShell7Executable(executable: string): boolean {\n\treturn /^pwsh(?:\\.exe)?$/iu.test(basename(executable));\n}\n\n/**\n * Ordered PowerShell candidates without launching a disposable interpreter. Persistent sessions\n * validate these candidates with their real long-lived bootstrap, so the normal path pays for one\n * PowerShell process instead of probing one process and then spawning another.\n */\nexport function getPowerShellCandidateConfigs(): ShellConfig[] {\n\tconst candidates: ShellConfig[] = [];\n\tconst seen = new Set<string>();\n\tconst addCandidate = (shell: string | null): void => {\n\t\tif (!shell || !isPowerShell7Executable(shell)) return;\n\t\tconst identity = process.platform === \"win32\" ? shell.toLowerCase() : shell;\n\t\tif (seen.has(identity)) return;\n\t\tseen.add(identity);\n\t\tcandidates.push({ shell, args: [...POWERSHELL_ARGS] });\n\t};\n\n\tconst pwshOnPath = findExecutableOnPath(process.platform === \"win32\" ? \"pwsh.exe\" : \"pwsh\");\n\taddCandidate(pwshOnPath);\n\n\tconst knownPaths: string[] = [];\n\tconst programFiles = process.env.ProgramFiles;\n\tif (programFiles) knownPaths.push(`${programFiles}\\\\PowerShell\\\\7\\\\pwsh.exe`);\n\tfor (const path of knownPaths) {\n\t\tif (existsSync(path)) addCandidate(path);\n\t}\n\treturn candidates;\n}\n\nfunction getPowerShellConfig(): ShellConfig {\n\tfor (const candidate of getPowerShellCandidateConfigs()) {\n\t\tif (isPowerShellExecutableAvailable(candidate.shell)) return candidate;\n\t}\n\tthrow new Error(\"PowerShell 7 (pwsh) was not found. Install pwsh or set shellPath to a pwsh executable.\");\n}\n\nfunction getBashConfig(): ShellConfig {\n\tif (process.platform === \"win32\") {\n\t\tconst knownPaths: string[] = [];\n\t\tconst programFiles = process.env.ProgramFiles;\n\t\tif (programFiles) knownPaths.push(`${programFiles}\\\\Git\\\\bin\\\\bash.exe`);\n\t\tconst programFilesX86 = process.env[\"ProgramFiles(x86)\"];\n\t\tif (programFilesX86) knownPaths.push(`${programFilesX86}\\\\Git\\\\bin\\\\bash.exe`);\n\t\tfor (const path of knownPaths) {\n\t\t\tif (existsSync(path)) return { shell: path, args: [\"-c\"] };\n\t\t}\n\t\tconst bashOnPath = findExecutableOnPath(\"bash.exe\");\n\t\tif (bashOnPath) return { shell: bashOnPath, args: [\"-c\"] };\n\t\tthrow new Error(\"No Bash executable found. Install Git Bash or set shellPath in settings.json.\");\n\t}\n\tif (existsSync(\"/bin/bash\")) return { shell: \"/bin/bash\", args: [\"-c\"] };\n\tconst bashOnPath = findExecutableOnPath(\"bash\");\n\treturn bashOnPath ? { shell: bashOnPath, args: [\"-c\"] } : { shell: \"sh\", args: [\"-c\"] };\n}\n\n// Platform shell resolution spawns probe processes (`where`/`which`, plus a full PowerShell\n// boot on Windows) and is a process-lifetime invariant, so successful resolutions are cached.\n// Failures are not cached: the user can install a shell and retry without restarting.\nconst resolvedPlatformShellConfigs = new Map<PlatformShellToolName, ShellConfig>();\nlet managedJscpdProvisionAttempted = false;\n\n/** Resolve the requested shell. Runtime callers omit shellName to select PowerShell on Windows and Bash elsewhere. */\nexport function getShellConfig(\n\tcustomShellPath?: string,\n\tshellName: PlatformShellToolName = getPlatformShellToolName(),\n): ShellConfig {\n\tif (customShellPath) {\n\t\tconst resolvedShellPath = normalizePath(customShellPath);\n\t\tif (shellName === \"powershell\" && !isPowerShell7Executable(resolvedShellPath)) {\n\t\t\tthrow new Error(`Custom PowerShell host must be PowerShell 7 (pwsh): ${resolvedShellPath}`);\n\t\t}\n\t\tif (!existsSync(resolvedShellPath)) throw new Error(`Custom shell path not found: ${resolvedShellPath}`);\n\t\treturn {\n\t\t\tshell: resolvedShellPath,\n\t\t\targs: shellName === \"powershell\" ? [...POWERSHELL_ARGS] : [\"-c\"],\n\t\t};\n\t}\n\tlet resolved = resolvedPlatformShellConfigs.get(shellName);\n\tif (!resolved) {\n\t\tresolved = shellName === \"powershell\" ? getPowerShellConfig() : getBashConfig();\n\t\tresolvedPlatformShellConfigs.set(shellName, resolved);\n\t}\n\treturn { shell: resolved.shell, args: [...resolved.args] };\n}\n\nexport function getShellEnv(): NodeJS.ProcessEnv {\n\tif (!managedJscpdProvisionAttempted) {\n\t\tmanagedJscpdProvisionAttempted = true;\n\t\ttry {\n\t\t\tensureManagedJscpd();\n\t\t} catch {\n\t\t\t// The jscpd wrapper and doctor surface the exact packaging failure. Shell startup stays usable.\n\t\t}\n\t}\n\tconst binDir = getBinDir();\n\tconst pathKey = Object.keys(process.env).find((key) => key.toLowerCase() === \"path\") ?? \"PATH\";\n\tconst currentPath = process.env[pathKey] ?? \"\";\n\tconst pathEntries = currentPath.split(delimiter).filter(Boolean);\n\tconst hasBinDir = pathEntries.includes(binDir);\n\tconst updatedPath = hasBinDir ? currentPath : [binDir, currentPath].filter(Boolean).join(delimiter);\n\n\treturn {\n\t\t...process.env,\n\t\t[pathKey]: updatedPath,\n\t};\n}\n\n/**\n * Detached child processes must be tracked so they can be killed on parent\n * shutdown signals (SIGHUP/SIGTERM).\n */\nconst trackedDetachedChildPids = new Set<number>();\n\nexport function trackDetachedChildPid(pid: number): void {\n\ttrackedDetachedChildPids.add(pid);\n}\n\nexport function untrackDetachedChildPid(pid: number): void {\n\ttrackedDetachedChildPids.delete(pid);\n}\n\nexport function killTrackedDetachedChildren(): void {\n\tfor (const pid of trackedDetachedChildPids) {\n\t\tkillProcessTree(pid);\n\t}\n\ttrackedDetachedChildPids.clear();\n}\n\n/**\n * Kill a process and all its children (cross-platform).\n *\n * Windows uses `spawnSync` (not `spawn`) deliberately: callers rely on this function returning\n * only once the tree is actually gone (e.g. before removing a directory that was the killed\n * process's cwd — a directory Windows keeps locked until every handle into it, including a\n * live process's cwd handle, is released). A fire-and-forget async `taskkill` would return before\n * termination completed, leaving a race where the directory is still locked.\n */\nexport function killProcessTree(pid: number): void {\n\tif (process.platform === \"win32\") {\n\t\t// Use taskkill on Windows to kill process tree; spawnSync blocks until taskkill itself\n\t\t// (and therefore the termination it requested) has finished.\n\t\ttry {\n\t\t\tspawnSync(\"taskkill\", [\"/F\", \"/T\", \"/PID\", String(pid)], {\n\t\t\t\tstdio: \"ignore\",\n\t\t\t\twindowsHide: true,\n\t\t\t});\n\t\t} catch {\n\t\t\t// Ignore errors if taskkill fails\n\t\t}\n\t} else {\n\t\t// Use SIGKILL on Unix/Linux/Mac\n\t\ttry {\n\t\t\tprocess.kill(-pid, \"SIGKILL\");\n\t\t} catch {\n\t\t\t// Fallback to killing just the child if process group kill fails\n\t\t\ttry {\n\t\t\t\tprocess.kill(pid, \"SIGKILL\");\n\t\t\t} catch {\n\t\t\t\t// Process already dead\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
package/docs/settings.md CHANGED
@@ -480,12 +480,12 @@ To keep captures in an explicit location:
480
480
 
481
481
  | Setting | Type | Default | Description |
482
482
  |---------|------|---------|-------------|
483
- | `shellPath` | string | platform default | Custom platform-shell path (`pwsh.exe`/`powershell.exe` on Windows; Bash-compatible shell elsewhere) |
483
+ | `shellPath` | string | platform default | Custom platform-shell path (`pwsh.exe` on Windows; Bash-compatible shell elsewhere) |
484
484
  | `shellCommandPrefix` | string | - | Platform-shell snippet prepended to every command (for example, `"shopt -s expand_aliases"` on Bash) |
485
485
  | `npmCommand` | string[] | - | Command argv used for npm package lookup/install operations (e.g., `["mise", "exec", "node@24", "--", "npm"]`) |
486
486
  | `windowsShell.pythonEngine` | boolean | `true` | Windows only. Routes pipelines, redirection, expansion, chaining, and state-mutating commands (`cd`/`export`/`unset`) through the bundled Python shell engine. Explicit `false` restores the PowerShell-only, simple-command-only contract verbatim — the same fail-closed behavior for pipelines/redirection/expansion/chaining as before the engine existed. |
487
487
 
488
- Pi exposes one stable `bash` contract to the model on every platform. On Windows, the tool router parses a finite simple-command grammar, converts supported Bash-like forms to literal-path PowerShell, and rejects pipelines, redirection, expansion, chaining, nested shells, POSIX scripts, and unsupported builtin forms instead of guessing. Legacy `powershell` tool/profile references map to `bash`. The Windows backend prefers PowerShell 7 (`pwsh.exe`), falls back to Windows PowerShell, and runs with `-NoLogo -NoProfile -NonInteractive -Command` plus UTF-8 console output setup. `shellCommandPrefix` uses backend-native syntax because Pi applies it after routing. Agent, interactive, and RPC shell calls default to a 120-second wall-clock deadline; agent-tool overrides cap at one hour.
488
+ Pi exposes one stable `bash` contract to the model on every platform. On Windows, the tool router parses a finite simple-command grammar, converts supported Bash-like forms to literal-path PowerShell, and rejects pipelines, redirection, expansion, chaining, nested shells, POSIX scripts, and unsupported builtin forms instead of guessing. Legacy `powershell` tool/profile references map to `bash`. The Windows backend requires PowerShell 7 (`pwsh.exe`) and runs it with `-NoLogo -NoProfile -NonInteractive -Command`, process-only headless settings, silent progress, and a warmed persistent command path. Pi does not overwrite PowerShell's input or output encoding; its output path preserves Unicode UTF-8 and recovers Windows-1252 bytes. `shellCommandPrefix` uses backend-native syntax because Pi applies it after routing. Agent, interactive, and RPC shell calls default to a 120-second wall-clock deadline; agent-tool overrides cap at one hour.
489
489
 
490
490
  With `windowsShell.pythonEngine` at its default (`true`), the router also sends pipelines, redirection, expansion, chaining, and `cd`/`export`/`unset` to a bundled, uv-provisioned Python 3.13 engine implementing a bounded Bash grammar and coreutils vocabulary; state persists across calls and across the PowerShell/engine tiers. If the Python runtime cannot be resolved (uv/network unavailable), the simple-command PowerShell floor keeps working and engine-only commands return a named, actionable error — never a silent downgrade. See [Windows](windows.md) for the full supported-forms table.
491
491
 
package/docs/windows.md CHANGED
@@ -6,7 +6,7 @@ Pi supports native Windows on x64 and ARM64. The Node.js package runs under Wind
6
6
 
7
7
  - Windows 10 or newer
8
8
  - Node.js 24.18 or newer for the npm package
9
- - Windows PowerShell 5.1 or PowerShell 7
9
+ - PowerShell 7 (`pwsh.exe`)
10
10
  - Git for Windows for native Git commands
11
11
  - Windows Terminal, WezTerm, or the VS Code terminal for the best keyboard support
12
12
 
@@ -20,13 +20,12 @@ External programs are not reimplemented. A simple `rg` call runs the installed n
20
20
 
21
21
  Shell persistence preserves process state; it does not require every raw command byte to remain in model context. Recognized single test-runner commands use a bounded command-aware projection after execution: passing/progress chatter is counted, failure blocks and summaries remain visible, exit status is unchanged, and exact raw bytes are saved to the reported managed path. Mixed commands and unknown nonzero formats stay raw, and Pi also falls back to raw output if it cannot create the exact-output handoff.
22
22
 
23
- The agent never selects a shell or emits native PowerShell or Python. Pi resolves the PowerShell executable in this order:
23
+ The agent never selects a shell or emits native PowerShell or Python. Pi accepts only PowerShell 7 and resolves its executable in this order:
24
24
 
25
- 1. `shellPath` in `%USERPROFILE%\.pi\agent\settings.json`
25
+ 1. A `shellPath` ending in `pwsh.exe` in `%USERPROFILE%\.pi\agent\settings.json`
26
26
  2. PowerShell 7 (`pwsh.exe`) on `PATH` or under `Program Files`
27
- 3. Windows PowerShell (`powershell.exe`) under `System32` or on `PATH`
28
27
 
29
- The PowerShell tier runs with `-NoLogo -NoProfile -NonInteractive -Command` and a best-effort UTF-8 console-output prefix. Every agent, interactive, and RPC shell call has a 120-second wall-clock default, even while output continues.
28
+ The PowerShell tier runs with `-NoLogo -NoProfile -NonInteractive -Command`. Pi applies process-only headless settings before startup: PowerShell telemetry, update notifications, diagnostic IPC, ANSI color, and progress rendering are disabled. It warms the long-lived command path once, then reuses that process. Pi gives managed PowerShell output a UTF-8 writer without overwriting `[Console]::InputEncoding`, `[Console]::OutputEncoding`, or `$OutputEncoding`, so native programs retain their code-page choice. The Windows output decoder preserves valid Unicode UTF-8 and recovers Windows-1252 bytes, including mixed streams and UTF-8 sequences split across chunks. Pi's private command framing remains line-safe Base64 with ASCII control markers. Every agent, interactive, and RPC shell call has a 120-second wall-clock default, even while output continues.
30
29
 
31
30
  ### Supported forms
32
31
 
@@ -106,6 +105,8 @@ The Windows release archive includes `collect-pi-incident.ps1` beside `pi.exe`.
106
105
  powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -File .\collect-pi-incident.ps1
107
106
  ```
108
107
 
108
+ This explicit `powershell.exe` invocation is an isolated Windows incident-collection integration, not the agent shell. The agent shell itself requires `pwsh.exe`.
109
+
109
110
  From a source checkout, use `-File .\scripts\collect-pi-incident.ps1`. The collector selects the latest human session by default and creates `pi-incident-<timestamp>.zip` beside the collector script. To select exact evidence or another destination:
110
111
 
111
112
  ```powershell
@@ -169,12 +170,12 @@ See [Terminal setup](terminal-setup.md) for VS Code, WezTerm, and other terminal
169
170
 
170
171
  ## Troubleshooting
171
172
 
172
- ### No PowerShell executable found
173
+ ### PowerShell 7 (`pwsh`) not found
173
174
 
174
- Restore Windows PowerShell, install PowerShell 7, or set `shellPath` to an existing `pwsh.exe`/`powershell.exe`. Confirm discovery from a terminal:
175
+ Install PowerShell 7 or set `shellPath` to an existing `pwsh.exe`. Confirm discovery from a terminal:
175
176
 
176
177
  ```powershell
177
- Get-Command pwsh, powershell -ErrorAction SilentlyContinue
178
+ Get-Command pwsh -ErrorAction Stop
178
179
  ```
179
180
 
180
181
  ### Modified Enter does not reach Pi
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider",
3
- "version": "0.91.4",
3
+ "version": "0.92.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-custom-provider",
9
- "version": "0.91.4",
9
+ "version": "0.92.0",
10
10
  "dependencies": {
11
11
  "@anthropic-ai/sdk": "^0.52.0"
12
12
  }