From 35b1c6879cc49e7db6776b021af18152b5cece40 Mon Sep 17 00:00:00 2001 From: lucianlamp Date: Fri, 19 Jun 2026 21:45:35 +0900 Subject: [PATCH] refactor: drop the Windows PowerShell launcher in favor of Git Bash The PowerShell launcher (scripts/windows/agmsg.ps1 + install-agmsg.ps1) was a thin shim that located Git Bash and forwarded to the Bash scripts. Codex on Windows runs commands through PowerShell, so agents can call the scripts directly via Git Bash (`bash -lc 'scripts/*.sh'`), and delivery hooks are already wrapped for Git Bash by windows_wrap() in delivery.sh. The separate PowerShell reimplementation is now redundant. Removed: - scripts/windows/agmsg.ps1, scripts/windows/install-agmsg.ps1 - docs/windows.md - tests/smoke_windows_powershell.ps1, tests/test_windows_powershell.bats - the PowerShell launcher install step in install.sh - the README "Native Windows / PowerShell" section (replaced with a Git Bash note) Kept (general Windows support): the Bash dispatcher (dispatch.sh), the delivery hook Git Bash wrapping (delivery.sh windows_wrap), the sqlite3 shim, and install.sh's legacy-helper cleanup. BREAKING CHANGE: the `agmsg` PowerShell command is no longer installed. On Windows, call the scripts through Git Bash, e.g. `bash -lc 'scripts/whoami.sh "$(pwd)" codex'`. If a bare `bash` resolves to the WSL shim, pin Git Bash in your PowerShell profile: Set-Alias bash 'C:\Program Files\Git\bin\bash.exe'. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01XpJ8VvSV1hNdJWy875V5tm --- .github/workflows/tests.yml | 27 ++--- README.md | 52 +++++----- docs/windows.md | 126 ----------------------- install.sh | 9 -- llms.txt | 1 - scripts/windows/agmsg.ps1 | 132 ------------------------ scripts/windows/install-agmsg.ps1 | 57 ----------- tests/smoke_windows_powershell.ps1 | 159 ----------------------------- tests/test_install.bats | 11 +- tests/test_windows_powershell.bats | 38 ------- 10 files changed, 39 insertions(+), 573 deletions(-) delete mode 100644 docs/windows.md delete mode 100644 scripts/windows/agmsg.ps1 delete mode 100644 scripts/windows/install-agmsg.ps1 delete mode 100644 tests/smoke_windows_powershell.ps1 delete mode 100644 tests/test_windows_powershell.bats diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index aec4e12..bed4c35 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -119,9 +119,9 @@ jobs: if: needs.changes.outputs.docs_only != 'true' run: bats --print-output-on-failure tests/ - # Windows coverage for the native helpers shipped in #103 (PowerShell wrapper, - # Git Bash runner, sqlite3 compatibility shim, cygpath normalization). The - # POSIX-assuming suite is not fully green on Windows yet, so this is staged + # Windows coverage for the native helpers shipped in #103 (Git Bash runner, + # sqlite3 compatibility shim, cygpath normalization). The POSIX-assuming suite + # is not fully green on Windows yet, so this is staged # (#125): a focused leg targeting the Windows-relevant tests, plus a full leg # that is informational only (continue-on-error) to track how far the rest # gets. Neither is a required check yet — promote the focused leg to required @@ -143,22 +143,13 @@ jobs: fail-fast: false matrix: include: - # Required-candidate leg: the Windows-tagged tests that pass on - # windows-latest today — the install-side native helpers (#103) and - # the PowerShell runner smoke. This leg is promoted to a required - # check so native Windows behaviour can't silently regress. - # - # Scoped to test_install + test_windows_powershell on purpose: the - # delivery "commandWindows" cases also match the [Ww]indows filter but - # one still fails on windows-latest (the codex Stop entry's - # commandWindows is empty after the hook-JSON round-trip), so - # test_delivery stays in the informational `full (experimental)` leg - # with the other known-broken Windows areas (actas liveness #134, - # codex-bridge spawn EFTYPE, delivery path/sqlite). As each is fixed - # its file moves into this required leg. - - leg: windows tests + # Focused leg: the install-side native Windows helpers (#103). These + # are green on windows-latest today and are the candidate to promote + # to a required check. Other Windows-relevant tests stay in the + # informational full leg until they are fixed in separate PRs. + - leg: install helpers filter: "[Ww]indows" - target: tests/test_install.bats tests/test_windows_powershell.bats + target: tests/test_install.bats experimental: false - leg: full (experimental) filter: "" diff --git a/README.md b/README.md index 1baa5aa..3b4d1ae 100644 --- a/README.md +++ b/README.md @@ -113,34 +113,30 @@ The **command name** determines: After install, **restart your agent** (Claude Code / Codex / Gemini CLI / Copilot CLI / Antigravity / OpenCode) so it picks up the new skill. -### Native Windows / PowerShell profile function - -When `install.sh` runs under Git Bash on Windows, it installs the PowerShell -launcher under the skill tree. To enable an `agmsg` PowerShell command, add the -profile function from the PowerShell host you use: - -```powershell -pwsh -ExecutionPolicy Bypass -File "$HOME\.agents\skills\agmsg\scripts\windows\install-agmsg.ps1" -``` - -Use `powershell` instead of `pwsh` if you use Windows PowerShell rather than -PowerShell 7; each host has its own profile path. - -Then a PowerShell session can run: - -```powershell -agmsg -agmsg history -agmsg team -agmsg send alice "hello from PowerShell" -agmsg mode turn -``` - -The PowerShell launcher delegates to the existing Bash scripts; it does not -reimplement agmsg logic or read the SQLite database directly. Git Bash and -`sqlite3` must both be available from the Windows environment. See -[Windows PowerShell launcher](docs/windows.md) for details and an optional -profile installer. +### Windows: Git Bash & Codex + +agmsg's implementation is the Bash script set under `scripts/`, so on Windows the +scripts run through **Git Bash** (Git for Windows, with `sqlite3` available on the +Git Bash PATH). There is no PowerShell reimplementation. + +- In Windows environments, Claude Code naturally works with Bash/Git Bash for + these script calls, but native Windows Codex commands and hooks often start + from PowerShell. Keep the actual agmsg execution path pinned to Git Bash so + all agents share the same `$HOME` and SQLite database. +- **Codex delivery hooks** are wrapped automatically. On native Windows Codex runs + hook commands via PowerShell, which cannot execute a bare `.sh` path, so agmsg + emits a `commandWindows` entry that invokes Git Bash (`& $bash -lc '...'`). No + setup needed — see `windows_wrap()` in `scripts/delivery.sh`. +- **Interactive / agent-typed commands** call the scripts through Git Bash, e.g. + `bash -lc 'scripts/whoami.sh "$(pwd)" codex'`. +- Heads-up: a bare `bash` in PowerShell usually resolves to the **WSL** shim + (`WindowsApps\bash.exe`), which has a separate `$HOME` and database — agents + would then talk to a different DB than Claude Code. Pin Git Bash in your + PowerShell profile so everything shares one database: + + ```powershell + Set-Alias bash 'C:\Program Files\Git\bin\bash.exe' + ``` ## First run diff --git a/docs/windows.md b/docs/windows.md deleted file mode 100644 index 7827942..0000000 --- a/docs/windows.md +++ /dev/null @@ -1,126 +0,0 @@ -# Windows PowerShell launcher - -agmsg's implementation remains the Bash script set under `scripts/`. The -PowerShell launcher is a thin platform shim: it finds Git Bash, checks that -`sqlite3` is available from Git Bash, sets UTF-8-oriented child process -environment, and delegates to `scripts/dispatch.sh`. The dispatcher then calls -the existing `scripts/*.sh` commands. Neither script reads or writes the SQLite -database directly. - -This is separate from Codex sandbox permissions. The launcher improves the -Windows invocation path; Codex sandbox write access is handled with -`writable_roots` as described in the README's Codex sandbox section. - -## Requirements - -- Git for Windows, including Git Bash (`bash.exe`) -- `sqlite3` executable from Git Bash -- An installed agmsg skill tree, or a cloned repository when running from source - -The launcher searches for Git Bash in this order: - -1. `$env:GIT_BASH` -2. `$env:AGMSG_BASH` -3. `C:\Program Files\Git\bin\bash.exe` -4. `C:\Program Files\Git\usr\bin\bash.exe` -5. `C:\Program Files (x86)\Git\bin\bash.exe` -6. `bash.exe` on `PATH`, preferring Git for Windows and avoiding the WindowsApps - WSL shim when possible - -## Install the optional profile function - -If you installed the default `agmsg` command: - -```powershell -pwsh -ExecutionPolicy Bypass -File "$HOME\.agents\skills\agmsg\scripts\windows\install-agmsg.ps1" -WhatIf -pwsh -ExecutionPolicy Bypass -File "$HOME\.agents\skills\agmsg\scripts\windows\install-agmsg.ps1" -``` - -Run the installer from the PowerShell host you use. Use `powershell` instead of -`pwsh` if you use Windows PowerShell rather than PowerShell 7; each host has its -own profile path. - -The installer adds or updates a marked block in your PowerShell profile: - -```powershell -function agmsg { - & '\agmsg.ps1' @args -} -``` - -If you installed agmsg under a custom command name, pass the matching launcher -and function name: - -```powershell -pwsh -ExecutionPolicy Bypass -File "$HOME\.agents\skills\m\scripts\windows\install-agmsg.ps1" -FunctionName m -``` - -The Git Bash installer does not write a top-level `~/.agents/.ps1` -shortcut. PowerShell integration is kept under the installed skill tree and is -enabled by the marked profile block above. - -## Usage - -```powershell -agmsg -agmsg send claude-fable "確認しました" -agmsg history -agmsg team -agmsg mode off -agmsg mode turn -agmsg join emeria game-maker -``` - -For Codex sessions, `mode monitor` and `mode both` are rejected because Codex -does not have Claude Code's Monitor tool. - -You can pass identity explicitly: - -```powershell -agmsg -Team emeria -Agent game-maker inbox -agmsg -Team emeria -Agent game-maker send claude-fable "確認しました" -``` - -Or set identity for the current PowerShell session: - -```powershell -$env:AGMSG_TEAM = "emeria" -$env:AGMSG_AGENT = "game-maker" -agmsg inbox -``` - -If neither `-Team` / `-Agent` nor `AGMSG_TEAM` / `AGMSG_AGENT` are set, the -launcher calls: - -```bash -scripts/whoami.sh "$(pwd)" codex -``` - -It auto-selects only a single identity response: - -```text -agent= teams= type=codex project= -``` - -For `multiple=true`, `not_joined=true`, or `suggest=true`, it prints the -current `whoami.sh` output and command examples, then exits non-zero rather than -guessing. - -## Command mapping - -| PowerShell command | Delegated script | -| --- | --- | -| `agmsg`, `agmsg inbox` | `scripts/dispatch.sh` -> `scripts/inbox.sh` | -| `agmsg send ` | `scripts/dispatch.sh` -> `scripts/send.sh` | -| `agmsg history` | `scripts/dispatch.sh` -> `scripts/history.sh` | -| `agmsg team [team]` | `scripts/dispatch.sh` -> `scripts/team.sh` | -| `agmsg config ...` | `scripts/dispatch.sh` -> `scripts/config.sh` | -| `agmsg mode [mode]` | `scripts/dispatch.sh` -> `scripts/delivery.sh` | -| `agmsg join ` | `scripts/dispatch.sh` -> `scripts/join.sh` | -| `agmsg reset [agent]`, `agmsg drop ` | `scripts/dispatch.sh` -> `scripts/reset.sh` | -| `agmsg actas ` | `scripts/dispatch.sh` -> `scripts/identities.sh` / `scripts/join.sh` with follow-up env guidance | - -Message bodies are passed across the PowerShell to Git Bash boundary as argv -values and are handed to `send.sh` by the Bash dispatcher, so spaces, quotes, -Japanese text, and emoji are preserved without reimplementing message storage -in PowerShell. diff --git a/install.sh b/install.sh index e1a4c17..b4bc69a 100755 --- a/install.sh +++ b/install.sh @@ -127,11 +127,6 @@ install_windows_helpers() { mkdir -p "$AGENTS_DIR" - local profile_installer="$SKILL_DIR/scripts/windows/install-agmsg.ps1" - if command -v cygpath >/dev/null 2>&1; then - profile_installer=$(cygpath -w "$profile_installer" 2>/dev/null || printf '%s' "$profile_installer") - fi - # Clean up legacy helpers created by the earlier native-Windows approaches. local ps_shortcut="$AGENTS_DIR/$CMD_NAME.ps1" if [ -f "$ps_shortcut" ] && grep -q "PowerShell shortcut for agmsg on native Windows" "$ps_shortcut" 2>/dev/null; then @@ -147,10 +142,6 @@ install_windows_helpers() { if [ "$removed_sqlite_shim" = true ]; then rm -f "$AGENTS_DIR/run/sqlite3-shim.cache" fi - - echo " ~ To enable the PowerShell command, run this from the PowerShell host you use:" - echo " pwsh -ExecutionPolicy Bypass -File \"$profile_installer\" -FunctionName $CMD_NAME" - echo " # or use powershell.exe if you use Windows PowerShell instead of PowerShell 7" } # --- Parse args --- diff --git a/llms.txt b/llms.txt index 345c525..02be16d 100644 --- a/llms.txt +++ b/llms.txt @@ -56,7 +56,6 @@ plugin marketplace (`/plugin marketplace add fujibee/agmsg`). All paths land at - [docs/teams.md](docs/teams.md): team registry and membership model. - [docs/spec/driver-interface.md](docs/spec/driver-interface.md): the formal driver contract. - [docs/adr/](docs/adr/): architecture decision records (the "why"). -- [docs/windows.md](docs/windows.md): native Windows / Git Bash / PowerShell notes. - [docs/opencode.md](docs/opencode.md): OpenCode-specific integration. - [CONTRIBUTING.md](CONTRIBUTING.md): how to propose changes. diff --git a/scripts/windows/agmsg.ps1 b/scripts/windows/agmsg.ps1 deleted file mode 100644 index 30070e4..0000000 --- a/scripts/windows/agmsg.ps1 +++ /dev/null @@ -1,132 +0,0 @@ -[CmdletBinding()] -param( - [string] $Team, - [string] $Agent, - [Parameter(Position = 0)] - [string] $Command = 'inbox', - [Parameter(ValueFromRemainingArguments = $true)] - [string[]] $Rest -) - -$ErrorActionPreference = 'Stop' -$utf8NoBom = [System.Text.UTF8Encoding]::new($false) -[Console]::InputEncoding = $utf8NoBom -[Console]::OutputEncoding = $utf8NoBom -$OutputEncoding = $utf8NoBom - -$script:ScriptsDir = Split-Path -Parent $PSScriptRoot -$script:AgentType = if ($env:AGMSG_AGENT_TYPE) { $env:AGMSG_AGENT_TYPE } else { 'codex' } -$script:Bash = $null - -function Find-GitBash { - $candidates = @() - if ($env:GIT_BASH) { $candidates += $env:GIT_BASH } - if ($env:AGMSG_BASH) { $candidates += $env:AGMSG_BASH } - $candidates += @( - 'C:\Program Files\Git\bin\bash.exe', - 'C:\Program Files\Git\usr\bin\bash.exe', - 'C:\Program Files (x86)\Git\bin\bash.exe' - ) - - foreach ($cmd in Get-Command bash.exe -All -ErrorAction SilentlyContinue) { - $path = if ($cmd.Source) { $cmd.Source } else { $cmd.Path } - if ($path) { $candidates += $path } - } - - foreach ($candidate in $candidates) { - if (-not $candidate) { continue } - if ($candidate -match '\\WindowsApps\\bash\.exe$') { continue } - if ($candidate -notmatch '\\Git\\') { continue } - if (Test-Path -LiteralPath $candidate) { - return (Resolve-Path -LiteralPath $candidate).Path - } - } - - foreach ($candidate in $candidates) { - if (-not $candidate) { continue } - if ($candidate -match '\\WindowsApps\\bash\.exe$') { continue } - if (Test-Path -LiteralPath $candidate) { - return (Resolve-Path -LiteralPath $candidate).Path - } - } - - throw 'Git Bash not found. Install Git for Windows or set GIT_BASH to Git for Windows bash.exe.' -} - -function Invoke-WithPythonUtf8 { - param([scriptblock] $Block) - - $oldPythonIoEncoding = $env:PYTHONIOENCODING - try { - $env:PYTHONIOENCODING = 'utf-8' - & $Block - } finally { - if ($null -eq $oldPythonIoEncoding) { - Remove-Item Env:PYTHONIOENCODING -ErrorAction SilentlyContinue - } else { - $env:PYTHONIOENCODING = $oldPythonIoEncoding - } - } -} - -function ConvertTo-BashPath { - param([string] $Path) - - $resolved = if (Test-Path -LiteralPath $Path) { - (Resolve-Path -LiteralPath $Path).Path - } else { - $Path - } - - $converted = (& $script:Bash -lc 'cygpath -u "$1"' agmsg-path $resolved 2>&1 | Out-String).Trim() - if ($LASTEXITCODE -ne 0 -or -not $converted) { - return $resolved - } - return $converted -} - -function Test-SqliteAvailable { - Invoke-WithPythonUtf8 { - & $script:Bash -lc 'command -v sqlite3 >/dev/null 2>&1 && sqlite3 --version >/dev/null' - if ($LASTEXITCODE -ne 0) { - Write-Error 'sqlite3 is required and must be executable from Git Bash. Install sqlite3 or add it to the Git Bash PATH.' - exit 127 - } - } -} - -$script:Bash = Find-GitBash -Test-SqliteAvailable - -$dispatcher = Join-Path $script:ScriptsDir 'dispatch.sh' -if (-not (Test-Path -LiteralPath $dispatcher)) { - throw "Missing agmsg dispatcher: $dispatcher" -} - -$argsForDispatcher = @( - '--type', $script:AgentType, - '--project', (ConvertTo-BashPath (Get-Location).Path) -) -if ($Team) { $argsForDispatcher += @('--team', $Team) } -if ($Agent) { $argsForDispatcher += @('--agent', $Agent) } - -$argvFile = [System.IO.Path]::GetTempFileName() -try { - $commandArgs = @() - if ($Command) { $commandArgs += $Command } - if ($Rest) { $commandArgs += $Rest } - - $encodedArgs = foreach ($arg in $commandArgs) { - [Convert]::ToBase64String($utf8NoBom.GetBytes([string] $arg)) - } - [System.IO.File]::WriteAllLines($argvFile, [string[]] $encodedArgs, $utf8NoBom) - $argsForDispatcher += @('--argv-file', (ConvertTo-BashPath $argvFile)) - - Invoke-WithPythonUtf8 { - & $script:Bash $dispatcher @argsForDispatcher - $code = $LASTEXITCODE - if ($code -ne 0) { exit $code } - } -} finally { - Remove-Item -LiteralPath $argvFile -Force -ErrorAction SilentlyContinue -} diff --git a/scripts/windows/install-agmsg.ps1 b/scripts/windows/install-agmsg.ps1 deleted file mode 100644 index d72e1b0..0000000 --- a/scripts/windows/install-agmsg.ps1 +++ /dev/null @@ -1,57 +0,0 @@ -[CmdletBinding(SupportsShouldProcess = $true)] -param( - [string] $LauncherPath, - [string] $FunctionName = 'agmsg', - [string] $ProfilePath = $PROFILE.CurrentUserAllHosts -) - -$ErrorActionPreference = 'Stop' - -if (-not $LauncherPath) { - $LauncherPath = Join-Path $PSScriptRoot 'agmsg.ps1' -} - -if (-not (Test-Path -LiteralPath $LauncherPath)) { - throw "Launcher not found: $LauncherPath" -} - -$resolvedLauncher = (Resolve-Path -LiteralPath $LauncherPath).Path -$profileDir = Split-Path -Parent $ProfilePath -if ($profileDir -and -not (Test-Path -LiteralPath $profileDir)) { - New-Item -ItemType Directory -Force -Path $profileDir | Out-Null -} - -$start = "# >>> agmsg PowerShell launcher >>>" -$end = "# <<< agmsg PowerShell launcher <<<" -$escapedLauncher = $resolvedLauncher.Replace("'", "''") -$block = @" -$start -function $FunctionName { - & '$escapedLauncher' @args -} -$end -"@ - -$existing = '' -if (Test-Path -LiteralPath $ProfilePath) { - $existing = Get-Content -Raw -LiteralPath $ProfilePath -} - -$pattern = "(?s)\r?\n?$([regex]::Escape($start)).*?$([regex]::Escape($end))\r?\n?" -if ($existing -match $pattern) { - $updated = [regex]::Replace($existing, $pattern, "`r`n$block`r`n", 1) -} elseif ($existing -match "(?m)^\s*function\s+$([regex]::Escape($FunctionName))\b") { - Write-Warning "Profile already defines function $FunctionName outside the agmsg managed block: $ProfilePath" - Write-Output "No changes written. Remove or rename the existing function, or rerun with -FunctionName ." - exit 2 -} else { - $prefix = if ($existing.Trim().Length -gt 0) { "$existing`r`n" } else { '' } - $updated = "$prefix$block`r`n" -} - -if ($PSCmdlet.ShouldProcess($ProfilePath, "Install $FunctionName launcher for $resolvedLauncher")) { - Set-Content -LiteralPath $ProfilePath -Value $updated -Encoding UTF8 - Write-Output "Installed $FunctionName launcher in $ProfilePath" -} else { - Write-Output $block -} diff --git a/tests/smoke_windows_powershell.ps1 b/tests/smoke_windows_powershell.ps1 deleted file mode 100644 index 8d19abe..0000000 --- a/tests/smoke_windows_powershell.ps1 +++ /dev/null @@ -1,159 +0,0 @@ -param( - [string] $RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path -) - -$ErrorActionPreference = 'Stop' -$utf8NoBom = [System.Text.UTF8Encoding]::new($false) -[Console]::InputEncoding = $utf8NoBom -[Console]::OutputEncoding = $utf8NoBom -$OutputEncoding = $utf8NoBom - -function Assert-Contains { - param( - [string] $Text, - [string] $Needle, - [string] $Label - ) - if (-not $Text.Contains($Needle)) { - throw "$Label did not contain expected text: $Needle`nActual:`n$Text" - } -} - -function Assert-NotContains { - param( - [string] $Text, - [string] $Needle, - [string] $Label - ) - if ($Text.Contains($Needle)) { - throw "$Label contained unexpected text: $Needle`nActual:`n$Text" - } -} - -function Invoke-Checked { - param( - [scriptblock] $Block, - [string] $Label - ) - $output = & $Block 2>&1 | Out-String - if ($LASTEXITCODE -ne 0) { - throw "$Label exited $LASTEXITCODE`n$output" - } - return $output -} - -$testRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("agmsg-win-ps-" + [Guid]::NewGuid().ToString('N')) -$skillDir = Join-Path $testRoot '.agents/skills/agmsg' -$scriptsDir = Join-Path $skillDir 'scripts' -$storageDir = Join-Path $testRoot 'storage' -$projectSingle = Join-Path $testRoot 'project-single' -$projectBob = Join-Path $testRoot 'project-bob' -$projectMulti = Join-Path $testRoot 'project-multi' - -try { - New-Item -ItemType Directory -Force -Path $scriptsDir, (Join-Path $skillDir 'db'), (Join-Path $skillDir 'teams'), $storageDir, $projectSingle, $projectBob, $projectMulti | Out-Null - Copy-Item -Recurse -Force -Path (Join-Path $RepoRoot 'scripts/*') -Destination $scriptsDir - - $wrapper = Join-Path $scriptsDir 'windows/agmsg.ps1' - if (-not (Test-Path $wrapper)) { - throw "missing wrapper: $wrapper" - } - - $env:AGMSG_STORAGE_PATH = $storageDir - $env:PYTHONIOENCODING = '' - $env:AGMSG_TEAM = '' - $env:AGMSG_AGENT = '' - - $bash = 'C:\Program Files\Git\bin\bash.exe' - if (-not (Test-Path $bash)) { - $bashCmd = Get-Command bash.exe -ErrorAction Stop - $bash = $bashCmd.Source - } - $projectSingleBash = (& $bash -lc 'cygpath -u "$1"' agmsg-path $projectSingle | Out-String).Trim() - $projectBobBash = (& $bash -lc 'cygpath -u "$1"' agmsg-path $projectBob | Out-String).Trim() - $projectMultiBash = (& $bash -lc 'cygpath -u "$1"' agmsg-path $projectMulti | Out-String).Trim() - - & $bash (Join-Path $scriptsDir 'init-db.sh') | Out-Null - if ($LASTEXITCODE -ne 0) { throw "init-db failed: $LASTEXITCODE" } - & $bash (Join-Path $scriptsDir 'join.sh') demo alice codex $projectSingleBash | Out-Null - if ($LASTEXITCODE -ne 0) { throw "join alice failed: $LASTEXITCODE" } - & $bash (Join-Path $scriptsDir 'join.sh') demo bob codex $projectBobBash | Out-Null - if ($LASTEXITCODE -ne 0) { throw "join bob failed: $LASTEXITCODE" } - - $out = Invoke-Checked { & $wrapper -Team demo -Agent bob inbox } '-Team/-Agent inbox' - Assert-Contains $out 'No new messages.' '-Team/-Agent inbox' - - $env:AGMSG_TEAM = 'demo' - $env:AGMSG_AGENT = 'bob' - $out = Invoke-Checked { & $wrapper inbox } 'env inbox' - Assert-Contains $out 'No new messages.' 'env inbox' - $env:AGMSG_TEAM = '' - $env:AGMSG_AGENT = '' - - Push-Location $projectSingle - try { - $out = Invoke-Checked { & $wrapper inbox } 'whoami inbox' - Assert-Contains $out 'No new messages.' 'whoami inbox' - } finally { - Pop-Location - } - - $message = ([string]::Concat([char]0x78BA, [char]0x8A8D, [char]0x3057, [char]0x307E, [char]0x3057, [char]0x305F)) + ' "quoted" emoji ' + [char]::ConvertFromUtf32(0x1F680) - Invoke-Checked { & $wrapper -Team demo -Agent alice send bob $message } 'send japanese' | Out-Null - $out = Invoke-Checked { & $wrapper -Team demo history } 'history japanese' - Assert-Contains $out $message 'history japanese' - - $out = Invoke-Checked { & $wrapper -Team demo team } 'team explicit' - Assert-Contains $out 'Team: demo' 'team explicit' - - Push-Location $projectSingle - try { - $out = Invoke-Checked { & $wrapper mode off } 'mode off' - Assert-Contains $out "Delivery mode set to 'off'" 'mode off' - $out = Invoke-Checked { & $wrapper mode turn } 'mode turn' - Assert-Contains $out "Delivery mode set to 'turn'" 'mode turn' - $encoded = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes("Set-Location -LiteralPath '$projectSingle'; & '$wrapper' mode monitor")) - $stdoutFile = Join-Path $testRoot 'mode-stdout.txt' - $stderrFile = Join-Path $testRoot 'mode-stderr.txt' - $proc = Start-Process -FilePath powershell.exe -ArgumentList @('-NoProfile', '-ExecutionPolicy', 'Bypass', '-EncodedCommand', $encoded) -Wait -PassThru -NoNewWindow -RedirectStandardOutput $stdoutFile -RedirectStandardError $stderrFile - $modeOutput = ((Get-Content -Raw -LiteralPath $stdoutFile -ErrorAction SilentlyContinue) + (Get-Content -Raw -LiteralPath $stderrFile -ErrorAction SilentlyContinue)) - if ($proc.ExitCode -eq 0) { throw "mode monitor unexpectedly succeeded`n$modeOutput" } - Assert-Contains $modeOutput 'Codex has no Monitor tool' 'mode monitor' - } finally { - Pop-Location - } - - $out = Invoke-Checked { & $wrapper join smoke charlie } 'join command' - Assert-Contains $out 'Joined team smoke as charlie' 'join command' - - & $bash (Join-Path $scriptsDir 'join.sh') many first codex $projectMultiBash | Out-Null - if ($LASTEXITCODE -ne 0) { throw "join first failed: $LASTEXITCODE" } - & $bash (Join-Path $scriptsDir 'join.sh') many second codex $projectMultiBash | Out-Null - if ($LASTEXITCODE -ne 0) { throw "join second failed: $LASTEXITCODE" } - Push-Location $projectMulti - try { - $encoded = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes("Set-Location -LiteralPath '$projectMulti'; & '$wrapper' inbox")) - $stdoutFile = Join-Path $testRoot 'multi-stdout.txt' - $stderrFile = Join-Path $testRoot 'multi-stderr.txt' - $proc = Start-Process -FilePath powershell.exe -ArgumentList @('-NoProfile', '-ExecutionPolicy', 'Bypass', '-EncodedCommand', $encoded) -Wait -PassThru -NoNewWindow -RedirectStandardOutput $stdoutFile -RedirectStandardError $stderrFile - $multiOutput = ((Get-Content -Raw -LiteralPath $stdoutFile -ErrorAction SilentlyContinue) + (Get-Content -Raw -LiteralPath $stderrFile -ErrorAction SilentlyContinue)) - if ($proc.ExitCode -eq 0) { throw "multiple identity command unexpectedly succeeded`n$multiOutput" } - Assert-Contains $multiOutput 'multiple=true' 'multiple identity' - Assert-Contains $multiOutput 'agmsg -Team -Agent inbox' 'multiple identity guidance' - } finally { - Pop-Location - } - - $wrapperText = Get-Content -Raw -LiteralPath $wrapper - Assert-NotContains $wrapperText "AGMSG_TEAM = 'emeria'" 'wrapper source' - Assert-NotContains $wrapperText "AGMSG_AGENT = 'codex'" 'wrapper source' - Assert-NotContains $wrapperText 'sqlite3-shim' 'wrapper source' - Assert-NotContains $wrapperText 'agmsg-run.sh' 'wrapper source' - - Write-Output 'windows powershell smoke ok' -} finally { - Remove-Item Env:AGMSG_STORAGE_PATH -ErrorAction SilentlyContinue - Remove-Item Env:AGMSG_TEAM -ErrorAction SilentlyContinue - Remove-Item Env:AGMSG_AGENT -ErrorAction SilentlyContinue - Remove-Item -Recurse -Force -LiteralPath $testRoot -ErrorAction SilentlyContinue -} diff --git a/tests/test_install.bats b/tests/test_install.bats index df84921..8e85ae9 100644 --- a/tests/test_install.bats +++ b/tests/test_install.bats @@ -191,14 +191,15 @@ wait_for_pidfile_pid() { grep -q "whoami.sh \"\$(pwd)\" opencode" "$FAKE_HOME/.config/opencode/skills/agmsg/SKILL.md" } -@test "install: Windows PowerShell launcher stays under the skill tree" { +@test "install: no PowerShell launcher is shipped (dispatcher only)" { AGMSG_FORCE_WINDOWS=1 HOME="$FAKE_HOME" bash "$REPO_ROOT/install.sh" --cmd msg [ ! -f "$FAKE_HOME/.agents/msg.ps1" ] [ ! -f "$FAKE_HOME/.agents/msg-run.sh" ] [ ! -f "$FAKE_HOME/.agents/bin/sqlite3" ] - [ -f "$FAKE_HOME/.agents/skills/msg/scripts/windows/agmsg.ps1" ] - [ -f "$FAKE_HOME/.agents/skills/msg/scripts/windows/install-agmsg.ps1" ] + # The PowerShell port was removed; only the Bash dispatcher ships. + [ ! -f "$FAKE_HOME/.agents/skills/msg/scripts/windows/agmsg.ps1" ] + [ ! -f "$FAKE_HOME/.agents/skills/msg/scripts/windows/install-agmsg.ps1" ] [ -f "$FAKE_HOME/.agents/skills/msg/scripts/dispatch.sh" ] } @@ -232,8 +233,8 @@ PS1 @test "install: Windows dispatcher is shipped with the skill scripts" { AGMSG_FORCE_WINDOWS=1 HOME="$FAKE_HOME" bash "$REPO_ROOT/install.sh" --cmd agmsg - [ -f "$SK/scripts/windows/agmsg.ps1" ] - [ -f "$SK/scripts/windows/install-agmsg.ps1" ] + [ ! -f "$SK/scripts/windows/agmsg.ps1" ] + [ ! -f "$SK/scripts/windows/install-agmsg.ps1" ] [ -f "$SK/scripts/dispatch.sh" ] [ ! -f "$SK/scripts/windows/agmsg-run.sh" ] [ ! -f "$SK/scripts/windows/sqlite3-shim.sh" ] diff --git a/tests/test_windows_powershell.bats b/tests/test_windows_powershell.bats deleted file mode 100644 index 48184d4..0000000 --- a/tests/test_windows_powershell.bats +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bats - -setup() { - export REPO_ROOT="$(cd "$BATS_TEST_DIRNAME/.." && pwd)" -} - -powershell_bin() { - command -v pwsh 2>/dev/null || - command -v powershell.exe 2>/dev/null || - command -v powershell 2>/dev/null -} - -@test "windows powershell launcher smoke" { - case "$(uname -s)" in - MINGW*|MSYS*|CYGWIN*) ;; - *) skip "native Windows PowerShell smoke" ;; - esac - - local ps - ps="$(powershell_bin)" || skip "PowerShell is not available" - - run "$ps" -NoProfile -ExecutionPolicy Bypass -File "$REPO_ROOT/tests/smoke_windows_powershell.ps1" -RepoRoot "$REPO_ROOT" - [ "$status" -eq 0 ] - [[ "$output" =~ "windows powershell smoke ok" ]] -} - -@test "windows powershell launcher source does not hardcode team or agent names" { - local launcher="$REPO_ROOT/scripts/windows/agmsg.ps1" - local dispatcher="$REPO_ROOT/scripts/dispatch.sh" - [ -f "$launcher" ] - [ -f "$dispatcher" ] - ! grep -q "AGMSG_TEAM.*emeria" "$launcher" - ! grep -q "AGMSG_AGENT.*codex" "$launcher" - ! grep -q "claude-fable" "$launcher" - ! grep -q "AGMSG_TEAM.*emeria" "$dispatcher" - ! grep -q "AGMSG_AGENT.*codex" "$dispatcher" - ! grep -q "claude-fable" "$dispatcher" -}