fix(extensions): isolate subprocess process groups
- commit
- 6d28881e78a294509a11b43c721490ad78dd8cd9
- author
- patriceckhart · · 2026-06-18 05:27 UTC
- parent
- 4615780
- signature
- unsigned
- refs
- tag: v0.2.38
3 files · +27 -0
M packages/agent/extensions/manager.go +1 -0
| @@ -537,6 +537,7 @@ func (m *Manager) spawn(ctx context.Context, ext *Extension) error { | |||
| 537 | 537 | cmd := exec.CommandContext(ctx, execPath, ext.Manifest.Args...) | |
| 538 | 538 | cmd.Dir = ext.Dir | |
| 539 | 539 | cmd.Stderr = logFile | |
| 540 | + | isolateExtensionProcess(cmd) | |
| 540 | 541 | ||
| 541 | 542 | stdin, err := cmd.StdinPipe() | |
| 542 | 543 | if err != nil { | |
| @@ -537,6 +537,7 @@ func (m *Manager) spawn(ctx context.Context, ext *Extension) error { | |||||
| 537 | cmd := exec.CommandContext(ctx, execPath, ext.Manifest.Args...) | 537 | cmd := exec.CommandContext(ctx, execPath, ext.Manifest.Args...) | ||
| 538 | cmd.Dir = ext.Dir | 538 | cmd.Dir = ext.Dir | ||
| 539 | cmd.Stderr = logFile | 539 | cmd.Stderr = logFile | ||
| 540 | + | isolateExtensionProcess(cmd) | |||
| 540 | 541 | ||||
| 541 | stdin, err := cmd.StdinPipe() | 542 | stdin, err := cmd.StdinPipe() | ||
| 542 | if err != nil { | 543 | if err != nil { | ||
A packages/agent/extensions/proc_unix.go +19 -0
| @@ -0,0 +1,19 @@ | |||
| 1 | + | //go:build !windows | |
| 2 | + | ||
| 3 | + | package extensions | |
| 4 | + | ||
| 5 | + | import ( | |
| 6 | + | "os/exec" | |
| 7 | + | "syscall" | |
| 8 | + | ) | |
| 9 | + | ||
| 10 | + | // isolateExtensionProcess moves extension subprocesses out of zot's | |
| 11 | + | // foreground process group. Some terminals, including kitty, inspect | |
| 12 | + | // foreground-process-group members when deciding the cwd for "open new | |
| 13 | + | // tab/split here". Extensions run with cmd.Dir set to their own install | |
| 14 | + | // directory, so leaving them in zot's process group can make the terminal | |
| 15 | + | // believe the tab cwd is an extension directory even after zot reports the | |
| 16 | + | // project cwd with OSC 7. | |
| 17 | + | func isolateExtensionProcess(cmd *exec.Cmd) { | |
| 18 | + | cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} | |
| 19 | + | } | |
| @@ -0,0 +1,19 @@ | |||||
| 1 | + | //go:build !windows | |||
| 2 | + | ||||
| 3 | + | package extensions | |||
| 4 | + | ||||
| 5 | + | import ( | |||
| 6 | + | "os/exec" | |||
| 7 | + | "syscall" | |||
| 8 | + | ) | |||
| 9 | + | ||||
| 10 | + | // isolateExtensionProcess moves extension subprocesses out of zot's | |||
| 11 | + | // foreground process group. Some terminals, including kitty, inspect | |||
| 12 | + | // foreground-process-group members when deciding the cwd for "open new | |||
| 13 | + | // tab/split here". Extensions run with cmd.Dir set to their own install | |||
| 14 | + | // directory, so leaving them in zot's process group can make the terminal | |||
| 15 | + | // believe the tab cwd is an extension directory even after zot reports the | |||
| 16 | + | // project cwd with OSC 7. | |||
| 17 | + | func isolateExtensionProcess(cmd *exec.Cmd) { | |||
| 18 | + | cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} | |||
| 19 | + | } | |||
A packages/agent/extensions/proc_windows.go +7 -0
| @@ -0,0 +1,7 @@ | |||
| 1 | + | //go:build windows | |
| 2 | + | ||
| 3 | + | package extensions | |
| 4 | + | ||
| 5 | + | import "os/exec" | |
| 6 | + | ||
| 7 | + | func isolateExtensionProcess(_ *exec.Cmd) {} | |
| @@ -0,0 +1,7 @@ | |||||
| 1 | + | //go:build windows | |||
| 2 | + | ||||
| 3 | + | package extensions | |||
| 4 | + | ||||
| 5 | + | import "os/exec" | |||
| 6 | + | ||||
| 7 | + | func isolateExtensionProcess(_ *exec.Cmd) {} | |||