Skip to content

fix(opencode): spawn PowerShell directly on Windows to remove bash dependency - #599

Closed
rafaelsnv wants to merge 11 commits into
PeonPing:mainfrom
rafaelsnv:opencode-windows-adapter
Closed

rafaelsnv wants to merge 11 commits into
PeonPing:mainfrom
rafaelsnv:opencode-windows-adapter

Conversation

@rafaelsnv

@rafaelsnv rafaelsnv commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Make the OpenCode peon-ping plugin work on Windows without Git Bash. The TypeScript plugin previously spawned bash peon.sh, which silently failed in PowerShell / cmd because bash wasn't in PATH.

Changes

Plugin (adapters/opencode/peon-ping.ts) — Detect platform. Windows spawns powershell.exe -File peon.ps1 directly. Unix keeps bash peon.sh. The hook lookup is a single per-platform existsSync loop — returns string | null keyed on IS_WINDOWS ? "ps1" : "sh".

Installer (adapters/opencode.ps1) — XDG-style plugin path (~/.config/opencode/) matching OpenCode v1 + v2 discovery. Drops the LOCALAPPDATA fallback.

Install (install.ps1) — Removes the peon.sh Git-Bash wrapper install step. The wrapper had no caller once the plugin started bypassing bash on Windows, so it was dead.

Test update (tests/adapters-windows.Tests.ps1) — Asserts the new XDG path instead of the dropped LOCALAPPDATA line.

Testing notes

During end-to-end validation, the installer URL was temporarily pointed at the contributor fork (rafaelsnv/peon-ping/opencode-windows-adapter) to pull the fixed .ts plugin before merge. The PR ships with $PluginUrl on PeonPing/peon-ping/main, so no URL flip is required at merge time.

After merge

Restart OpenCode in PowerShell or cmd — sounds fire without Git Bash in PATH.

Fixes #598

- Add adapters/opencode/peon.sh: Windows wrapper that pipes JSON from
  stdin to peon.ps1 via -File flag (supports stdin redirection)
- Fix scripts/win-play.ps1: check for ffplay first on mp3/wav/wma since
  WPF MediaPlayer hangs in headless/server environments (5s timeout)
  before falling back
OpenCode (v1 and v2) uses XDG-style paths (~/.config/opencode/) on all
platforms, not Windows-specific LOCALAPPDATA. The installer was using
%LOCALAPPDATA%\opencode\plugins\ which is incorrect.

Update path logic to use ~/.config/opencode/ as the primary path, matching
OpenCode's actual plugin discovery paths documented in v1 and v2 docs.
@vercel

vercel Bot commented Oct 3, 2026

Copy link
Copy Markdown

@rafaelsnv is attempting to deploy a commit to the Gary Sheng's projects Team on Vercel.

A member of the Team first needs to authorize it.

…pendency

The OpenCode TypeScript plugin previously hardcoded spawn("bash", ...),
requiring Git Bash or WSL to be installed and in PATH. On Windows
PowerShell, cmd.exe, or any non-bash terminal, the plugin would silently
fail because bash could not be found.

Changes:
- Plugin now detects platform: Windows spawns powershell.exe directly
  against peon.ps1, Unix keeps the existing bash + peon.sh path
- Plugin searches hooks dirs for both peon.sh and peon.ps1
- install.ps1 copies adapters/opencode/peon.sh to the hooks dir so the
  Unix wrapper is present even for users who never run bash
GitHub raw.githubusercontent.com URLs cache for ~5 minutes, which
caused the installer to fetch stale peon-ping.ts (missing Windows
PowerShell spawn fix). Switching to cdn.jsdelivr.net/gh bypasses the
cache and serves the latest committed version immediately.

Refs: rafaelsnv/peon-ping@opencode-windows-adapter
@rafaelsnv rafaelsnv changed the title fix(opencode): use XDG-style paths for OpenCode CLI compatibility fix(opencode): spawn PowerShell directly on Windows to remove bash dependency Oct 4, 2026
The upstream PeonPing/peon-ping doesn't have the PowerShell-spawn fix
yet (waiting for PR PeonPing#599 merge). For testing, fetch from the fork so
users get the bash-free plugin immediately.

Revert this before merging PR PeonPing#599 upstream.
…/rafaelsnv/peon-ping into opencode-windows-adapter"

This reverts commit d10c42c, reversing
changes made to 1a65654.
garysheng added a commit to MwC-Trexx/peon-ping that referenced this pull request Oct 4, 2026
…lity

Integrate PRs PeonPing#596 and PeonPing#599 through d0ab8c1 in an isolated triage candidate. Use official v2 sessionID and nested data.form payloads, gate duplicate starts, clear interruption state, and filter scoped server events by plugin location. Route Windows JSON directly to PowerShell and retain Unix Bash routing, explicit hook directories and OpenPeon discovery. Contain asynchronous launch and stdin errors.

Keep Kilo on its v1 server and properties contract in a dedicated adapter. Both Kilo installers download that adapter directly instead of applying fragile sed/regex patches. Omit the obsolete Windows Bash wrapper and its installer download.

Validation: 71 Vitest tests and 21 OpenCode Bats checks pass on macOS after red/green regressions. The OpenCode source typechecks with explicit Node 22 types. Native Windows executable and Pester installer checks are prepared for CI but were not executable on this macOS machine; this candidate is not Windows merge-ready until those jobs pass. Live OpenCode v2 host smoke also remains pending.
garysheng added a commit to MwC-Trexx/peon-ping that referenced this pull request Oct 4, 2026
Include PR PeonPing#599 head c2571cd in the candidate ancestry. Its only delta since d0ab8c1 temporarily points the Windows installer at the contributor fork for testing. Keep the official PeonPing download URL for the maintained installer; the native installer regression checks that download boundary.

The previous local 71-test Vitest and 21-check Bats results cover the adapter behavior. Native Windows bridge and Pester checks still require CI on this candidate, and live OpenCode v2 host smoke remains pending.
garysheng added a commit that referenced this pull request Oct 4, 2026
* fix(opencode): migrate adapter to the OpenCode v2 plugin API

OpenCode v2 removed the v1 server plugin API, so this adapter no longer
loads at all on opencode >= 2.0:

  PluginModule.LoadError: Plugin must export a default definition with an
  id and an effect or setup function.
  cause: SchemaError(Expected object at ["default"])

v2 requires the default export to be a definition object
(`{ id, effect }` or `{ id, setup }`); this adapter exported a bare async
function. 'Expected object' rather than 'Missing key' because the key is
present but is not an object.

The event taxonomy changed at the same time, so every event the adapter
switched on is gone. v2 payloads also carry the body under `data` rather
than `properties`. Mapping:

  SessionStart        session.created            -> session.execution.started (first)
  UserPromptSubmit    session.status (busy)      -> session.execution.started
  Stop                session.idle               -> session.execution.succeeded
  PostToolUseFailure  session.error              -> session.execution.failed
  PermissionRequest   permission.asked           -> permission.asked (unchanged)
  Notification        question.asked             -> form.created

`session.idle` survives only as a deprecated definition and
`session.status` is defined but never published.

Behaviour notes: a failed execution now reports PostToolUseFailure for any
failure rather than tool errors only, and PostToolUseFailure no longer has
a per-tool trigger. Elicitation ids are still never forwarded to peon.sh.

Adds docs/opencode-v2-events.md and updates the adapter tests to the v2
context contract.

* feat(opencode): add Windows adapter and fix headless audio playback

- Add adapters/opencode/peon.sh: Windows wrapper that pipes JSON from
  stdin to peon.ps1 via -File flag (supports stdin redirection)
- Fix scripts/win-play.ps1: check for ffplay first on mp3/wav/wma since
  WPF MediaPlayer hangs in headless/server environments (5s timeout)
  before falling back

* fix(opencode): use XDG-style paths for OpenCode CLI compatibility

OpenCode (v1 and v2) uses XDG-style paths (~/.config/opencode/) on all
platforms, not Windows-specific LOCALAPPDATA. The installer was using
%LOCALAPPDATA%\opencode\plugins\ which is incorrect.

Update path logic to use ~/.config/opencode/ as the primary path, matching
OpenCode's actual plugin discovery paths documented in v1 and v2 docs.

* style: clarify comment about native Windows playback scope in win-play.ps1

* fix(opencode): spawn PowerShell directly on Windows to remove bash dependency

The OpenCode TypeScript plugin previously hardcoded spawn("bash", ...),
requiring Git Bash or WSL to be installed and in PATH. On Windows
PowerShell, cmd.exe, or any non-bash terminal, the plugin would silently
fail because bash could not be found.

Changes:
- Plugin now detects platform: Windows spawns powershell.exe directly
  against peon.ps1, Unix keeps the existing bash + peon.sh path
- Plugin searches hooks dirs for both peon.sh and peon.ps1
- install.ps1 copies adapters/opencode/peon.sh to the hooks dir so the
  Unix wrapper is present even for users who never run bash

* fix(opencode): use jsdelivr CDN to avoid GitHub raw URL cache

GitHub raw.githubusercontent.com URLs cache for ~5 minutes, which
caused the installer to fetch stale peon-ping.ts (missing Windows
PowerShell spawn fix). Switching to cdn.jsdelivr.net/gh bypasses the
cache and serves the latest committed version immediately.

Refs: rafaelsnv/peon-ping@opencode-windows-adapter

* fix(opencode): fetch plugin from PeonPing/peon-ping upstream CDN

* fix(opencode): keep raw.githubusercontent.com URL for minimal change

* fix(opencode): point installer at fork to test bash-free Windows path

The upstream PeonPing/peon-ping doesn't have the PowerShell-spawn fix
yet (waiting for PR #599 merge). For testing, fetch from the fork so
users get the bash-free plugin immediately.

Revert this before merging PR #599 upstream.

* refactor(opencode): collapse script lookup, drop dead peon.sh wrapper

* Revert "Merge branch 'opencode-windows-adapter' of https://github.com/rafaelsnv/peon-ping into opencode-windows-adapter"

This reverts commit d10c42c, reversing
changes made to 1a65654.

* docs: sync OpenCode v2 and Kilo compatibility guidance

Synchronize Japanese, Chinese and public model-facing integration docs with the corrected candidate. Documentation-only; runtime verification is recorded on the preceding implementation commit.

* Route OpenCode global events by physical project and isolate installer tests

Official OpenCode 2.0.22 exposes unscoped durable execution events and can load the same physical project through multiple path aliases. Resolve session locations before forwarding, canonicalize directories, and assign one active bridge per physical directory. Release ownership on cleanup and reject lookups that complete after cleanup. Deleted sessions clear silent local state without retrieving a removed host record.

Pester 6.2.0 reproduced all three Windows installer failures: its TestDrive persisted between It blocks, and the mock counter's script scope belonged to the invoked installer. Use a fresh sandbox per test and Pester call-history assertions with exact official URL filters. Preserve wrong-location and content assertions.

Validation: red/green regressions for aliases, global routing, duplicate owners, cleanup races and deleted-session lookup; 77 Vitest and 21 Bats tests pass; Pester installer fixtures change from 0/3 to 3/3 under isolated official PowerShell 7.6.6. Exact adapter passes 10 checks in official OpenCode 2.0.22, including real nested forms, permissions, success/failure, child suppression, another project and three reloads with 12 closed streams. Dedicated Kilo adapter loads in official Kilo 7.8.3 and handles real primary/child session.created payloads. Strict production source typecheck passes. Fresh native Windows adapter and full Pester CI remain a merge gate.

* Clarify dedicated Kilo adapter installation and active configuration

Pure documentation correction. Verified the dedicated source URL and XDG directory in kilo.sh and the installed main peon.sh route in the unchanged Kilo plugin. Synchronize all three README sections and the public guide; inactive legacy adapter config is not the playback configuration.

* fix(kilo): preserve native session identities across events

Two independently-created sessions in one Kilo plugin instance emitted the same setup-time peon session ID, defeating independent pack selection. Route every existing hook through the native session identity while retaining the kilo namespace and the timestamp fallback for legacy id-less events. Preserve event mappings, child suppression, rate guards and cleanup.

Validation: nine regressions fail before the fix; all 87 adapter tests pass afterward. Official unchanged Kilo 7.8.3 reproduces the failure and verifies distinct primary identities, matching completion identities, silent children and stable identity after native instance dispose/reload. Only the dedicated Kilo adapter and its compatibility tests change.

* Document native Kilo session pack identities

Synchronize the English, Japanese, Chinese and public setup guides with the native session identity correction. Documentation-only follow-up; 87 adapter tests and actual Kilo 7.8.3 session creation, completion, child suppression and reload checks passed on unchanged runtime bytes.

---------

Co-authored-by: MwC-Trexx <>
Co-authored-by: Rafael Santos <rafael.snv@gmail.com>
Co-authored-by: Gary Sheng <garysheng11@gmail.com>
@garysheng

Copy link
Copy Markdown
Collaborator

The Windows bridge is integrated with the OpenCode v2 correction in #596, including direct PowerShell invocation and dedicated Kilo v1 compatibility. Closing this overlapping contribution after that combined change passed its required checks and merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OpenCode plugin not working on Windows (headless/server environments)

2 participants