mirror of
https://github.com/multica-ai/multica.git
synced 2026-06-17 11:48:42 +02:00
* fix(agent/opencode): bypass npm .cmd shim on Windows to preserve multi-line prompts The npm-generated `opencode.cmd` shim forwards argv via Windows batch `%*`, which silently truncates positional arguments at the first newline. The daemon spawns OpenCode with a multi-line prompt (system prompt + user message), so on Windows the agent only ever sees the first line and responds generically as if it never received the user's message (reported in #1717 with native-binary repro confirming the same prompt arrives intact when cmd.exe is skipped). When `runtime.GOOS == "windows"` and `exec.LookPath` returns a `.cmd` shim, walk to the native binary that npm bundles next to the shim: <prefix>\opencode.cmd <prefix>\node_modules\opencode-ai\node_modules\opencode-windows-x64\bin\opencode.exe If the native binary is missing (unusual install layout), keep the original shim path so PATH lookup still wins. The resolver is a pure function with an injectable `statFn`, so layout assertions are testable on Linux: - shim resolves to the bundled native binary - missing native returns "" (caller keeps original path) - non-cmd paths (Linux/Mac binary, opencode.exe direct, empty) skip resolution - uppercase `.CMD` is accepted (PATHEXT entries can be either case) Closes the user-facing failure mode without restructuring exec resolution across the rest of the agent backends — the other shim-aware fixes can follow the same shape if/when they land in similar repros. * fix(agent/opencode): cover x64-baseline and arm64 npm package variants `npm install -g opencode-ai` ships three Windows platform packages (opencode-windows-x64, opencode-windows-x64-baseline for older CPUs without AVX2, opencode-windows-arm64 for Surface / Copilot+ PC) and installs whichever matches the host. The previous resolver only knew about opencode-windows-x64, so baseline-x64 and arm64 hosts would fall back to the .cmd shim and hit the multi-line prompt truncation again. Iterate the three package candidates in GOARCH-preferred order. ARM64 hosts try arm64 first; everything else tries x64, then baseline, then arm64 as a last resort. Cost is one extra statFn call per miss when the GOARCH-preferred package isn't installed. Surfaced by review on #1718. * test(agent): add Windows counterpart to writeTestExecutable writeTestExecutable in exec_fixture_unix_test.go is referenced by claude_test.go / codex_test.go / kimi_test.go, but the //go:build unix constraint meant `go test ./pkg/agent` failed to build on Windows. ETXTBSY is a Linux/Unix fork-exec race; Windows doesn't have that pathology, so a plain os.WriteFile is sufficient. Lifted from #1719 (Codex) with attribution. Surfaced by review on #1718.
25 lines
731 B
Go
25 lines
731 B
Go
//go:build windows
|
|
|
|
package agent
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
)
|
|
|
|
// writeTestExecutable is the Windows counterpart to the //go:build unix
|
|
// implementation in exec_fixture_unix_test.go. ETXTBSY is a Linux/Unix
|
|
// fork-exec race; Windows doesn't have that pathology, so a plain
|
|
// os.WriteFile is sufficient.
|
|
//
|
|
// The helper is referenced by claude_test.go / codex_test.go /
|
|
// kimi_test.go, so the absence of a Windows impl made
|
|
// `go test ./pkg/agent` fail to build on Windows. Lifted from #1719
|
|
// (Codex) with attribution.
|
|
func writeTestExecutable(tb testing.TB, path string, content []byte) {
|
|
tb.Helper()
|
|
if err := os.WriteFile(path, content, 0o755); err != nil {
|
|
tb.Fatalf("write test executable %s: %v", path, err)
|
|
}
|
|
}
|