On Windows, spawn(..., { detached: true }) prevents pwsh.exe (PowerShell) from
producing any stdout/stderr through pipe streams. This is because detached creates
a new process group which breaks pwsh's console host communication.
bash.exe and other cygwin/msys2 shells are unaffected by detached: true, but
they don't need it either -- on Windows, killProcessTree() already uses
taskkill /F /T /PID which kills the process tree by PID regardless of
whether the process was spawned detached.
The detached flag only matters on Unix, where kill(-pid, SIGKILL) requires a
process group that is only created via detached: true.
Fixes#4012
* fix(coding-agent): report edit access failures correctly closes#3894
- classify edit and edit-preview access errors by errno
- add regressions for missing, permission, and fallback cases
- document the fix in the coding-agent changelog
* chore: get rid of CHANGELOG.md entry
* refactor(coding-agent): apply review suggestions - use single error msg
* refactor(coding-agent): clean up test cases
* Revert "fix(coding-agent): use alternate logic to find Bun's node_modules (#3861)"
This reverts commit c241c6d6d0. The logic
is faulty: the original strategy of looking for node_modules by asking
the package manager is not incorrect even on bun. Instead, it should
learn a different method of asking the package manager for node_modules
when the *package manager* is bun, not the *runtime*.
* feat(coding-agent): detect bun as package manager and use alternate root query
When `"npmCommand": ["bun"]` is configured in settings.json, pi fails to
start because it invokes `bun root -g`, which doesn't exist:
error: Failed to run bun root -g: error: Script not found "root"
Add a (simple) check for Bun being used as package manager, and instead
build the relative path starting from Bun's bin directory.
Use a <picture> element with prefers-color-scheme so the white logo on
pi.dev stays visible in dark mode and a black variant is shown in light
mode. GitHub's HTML sanitizer strips style attributes and inline SVG, so
the two-file pattern is the only reliable theme-aware approach.
Co-authored-by: julien-agent <Agents+cyolo@huggingface.co>
When `"npmCommand": ["bun"]` is configured in settings.json, pi fails to
start because it invokes `bun root -g`, which doesn't exist:
error: Failed to run bun root -g: error: Script not found "root"
Add a check for the Bun runtime using the logic already used elsewhere,
and build the relative path starting from Bun's bin directory.
* feat(ai): add Cloudflare Workers AI as a provider
Cloudflare Workers AI hosts open-weight LLMs (Kimi K2.6, GPT-OSS,
GLM-4.7, Llama 4, Gemma 4, Nemotron 3) on Cloudflare's GPU network with
an OpenAI-compatible endpoint. Reuses the openai-completions API
protocol; the per-account URL contains a {CLOUDFLARE_ACCOUNT_ID}
placeholder resolved at request time by a small helper.
Pi automatically sets x-session-affinity for prefix caching:
https://developers.cloudflare.com/workers-ai/features/prompt-caching/
Auth: CLOUDFLARE_API_KEY (matches pi's *_API_KEY convention) +
CLOUDFLARE_ACCOUNT_ID. The User-Agent identifies traffic as
'pi-coding-agent' in Cloudflare analytics.
Verified end-to-end against a real Cloudflare account: 17 e2e tests
pass across stream/empty/tokens/unicode/tool-call-without-result/
total-tokens against @cf/moonshotai/kimi-k2.6.
Cloudflare AI Gateway is a separate, larger change (it requires routing
through provider-specific subpaths with the matching API protocol per
upstream) and will land in a follow-up PR.
* refactor(ai): move Cloudflare User-Agent and session-affinity flag to per-model metadata
Instead of conditionally setting them in openai-completions.ts based on
provider detection, declare them as model-level fields in the catalog
(headers + compat). This is consistent with how the github-copilot and
kimi-coding entries already declare their static headers.
packages/ai/scripts/generate-models.ts: emit headers and compat fields
on each cloudflare-workers-ai entry (CLOUDFLARE_STATIC_HEADERS).
packages/ai/src/providers/openai-completions.ts: drop the
isCloudflareProvider conditional that injected User-Agent and the
isCloudflareWorkersAI override of sendSessionAffinityHeaders.
packages/ai/src/models.generated.ts: re-spliced 8 cloudflare-workers-ai
entries with headers + compat.
Behavior is unchanged - verified via fetch interceptor that User-Agent
and x-session-affinity / session_id / x-client-request-id are still sent
on outbound requests. 5/5 e2e tests pass.
Long local-LLM SSE streams (e.g. vLLM buffering large tool calls) exceeded
undici's default 300s bodyTimeout and aborted with UND_ERR_BODY_TIMEOUT.
retry.provider.timeoutMs cannot lift this cap because it controls the
provider SDK's AbortController deadline, not undici's per-socket idle timer.
Pass { bodyTimeout: 0, headersTimeout: 0 } to EnvHttpProxyAgent. Provider
SDKs still enforce their own timeouts via retry.provider.timeoutMs.
closes#3715