mirror of
https://github.com/multica-ai/multica.git
synced 2026-06-17 03:38:32 +02:00
On Windows the official cursor-agent installer ships cursor-agent.cmd whose body is `powershell ... -File cursor-agent.ps1 %*`. CreateProcess for a .cmd file goes through cmd.exe, and `%*` in a batch file is expanded by re-tokenising the original command line, which mangles arguments containing newlines or other whitespace - most notably a long, multi-line `-p <prompt>`. The agent then only sees a truncated prompt and fails with "Workspace Trust Required" or exits 1 immediately. When LookPath resolves cursor-agent to a .cmd/.bat launcher and a sibling cursor-agent.ps1 exists, invoke PowerShell directly with `-File <ps1>` so Go's os/exec passes each argv as a discrete token. This is exactly what the .cmd does internally; we just skip the cmd.exe re-tokenisation step. PowerShell host resolution prefers pwsh.exe (PS 7) on PATH, then powershell.exe on PATH, and finally falls back to %SystemRoot%\System32\WindowsPowerShell\v1.0. Platform-specific code is split via build tags (cursor_invocation_windows.go / cursor_invocation_other.go) so non-Windows builds carry no Windows-only dependencies. The lookup is exposed as a package variable to make the Windows path fully unit-testable without spawning real PowerShell. Five unit tests cover: passthrough on non-launcher targets, successful rewrite with a multi-line prompt, .exe direct launch (skip), missing .ps1 (skip), and missing PowerShell host (skip). The change leaves macOS / Linux behaviour entirely untouched and stays on the official cursor-agent launch chain - no node.exe direct invocation, no prompt mutation, no extra flags. Closes #1297 Made-with: Cursor
32 lines
1.0 KiB
Go
32 lines
1.0 KiB
Go
package agent
|
|
|
|
import (
|
|
"io"
|
|
"log/slog"
|
|
"path/filepath"
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
// TestChooseCursorInvocation_PassthroughForNonLauncher verifies that when the
|
|
// resolved executable is not a Windows .cmd/.bat launcher, both argv[0] and
|
|
// the argv list are returned unchanged on every platform. This guards against
|
|
// accidental rewriting on macOS/Linux and for direct binary launches on
|
|
// Windows.
|
|
func TestChooseCursorInvocation_PassthroughForNonLauncher(t *testing.T) {
|
|
logger := slog.New(slog.NewTextHandler(io.Discard, nil))
|
|
|
|
execName := "cursor-agent"
|
|
lookedUp := filepath.Join(t.TempDir(), "cursor-agent") // no .cmd / .bat
|
|
args := []string{"chat", "-p", "hello\nworld", "--output-format", "stream-json", "--yolo"}
|
|
|
|
gotExec, gotArgs := chooseCursorInvocation(execName, lookedUp, args, logger)
|
|
|
|
if gotExec != execName {
|
|
t.Errorf("argv0 changed unexpectedly: got %q want %q", gotExec, execName)
|
|
}
|
|
if !reflect.DeepEqual(gotArgs, args) {
|
|
t.Errorf("argv changed unexpectedly:\n got %#v\n want %#v", gotArgs, args)
|
|
}
|
|
}
|