Fix Codex Windows hook fallback · Entire
Fix Codex Windows hook fallback
Sessions
Changes
4
cmd/entire/cli/agent
codex
Mhooks.go+64/-12
Mhooks_test.go+99
Mhook_command.go+68/-8
- Mhook_command_test.go+56
3 unmodified lines
4
5
6
7
8
9
10
11
12
13
14
15
16
11 unmodified lines
28
29
30
31
32
33
34
35
36
37
38
39
55 unmodified lines
95
96
97
98
99
89
100
101
102
103
104
105
95
96
97
106
107
108
109
110
111
112
102
103
113
114
115
116
106
107
117
118
119
120
110
111
121
122
123
124
114
115
125
126
127
128
129
47 unmodified lines
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
124 unmodified lines
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
3 unmodified lines
"context"
"encoding/json"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/entireio/cli/cmd/entire/cli/agent"
"github.com/entireio/cli/cmd/entire/cli/jsonutil"
11 unmodified lines
`go run "$(git rev-parse --show-toplevel)"/cmd/entire/main.go `,
}
var (
codexHookCommandOS = runtime.GOOS
codexProductionHookWrapperWorks = defaultCodexProductionHookWrapperWorks
codexHookWrapperCompatibilityProbe = `sh -c 'exit 0'`
)
// InstallHooks installs Codex hooks in .codex/hooks.json.
func (c *CodexAgent) InstallHooks(ctx context.Context, localDev bool, force bool) (int, error) {
repoRoot, err := paths.WorktreeRoot(ctx)
55 unmodified lines
cmdPrefix = "entire hooks codex "
}
sessionStartCmd := cmdPrefix + "session-start"
useWindowsProductionHooks := shouldUseWindowsProductionCodexHooks(ctx, localDev)
if !localDev {
sessionStartCmd = agent.WrapProductionJSONWarningHookCommand(sessionStartCmd, agent.WarningFormatSingleLine)
sessionStartCmd = wrapCodexSessionStartHookCommand(sessionStartCmd, useWindowsProductionHooks)
}
userPromptSubmitCmd := cmdPrefix + "user-prompt-submit"
stopCmd := cmdPrefix + "stop"
postToolUseCmd := cmdPrefix + "post-tool-use"
if !localDev {
userPromptSubmitCmd = agent.WrapProductionSilentHookCommand(userPromptSubmitCmd)
stopCmd = agent.WrapProductionSilentHookCommand(stopCmd)
postToolUseCmd = agent.WrapProductionSilentHookCommand(postToolUseCmd)
userPromptSubmitCmd = wrapCodexSilentHookCommand(userPromptSubmitCmd, useWindowsProductionHooks)
stopCmd = wrapCodexSilentHookCommand(stopCmd, useWindowsProductionHooks)
postToolUseCmd = wrapCodexSilentHookCommand(postToolUseCmd, useWindowsProductionHooks)
}
count := 0
if !hookCommandExists(sessionStart, sessionStartCmd) {
sessionStart = addHook(sessionStart, sessionStartCmd)
if updated, changed := syncHookCommand(sessionStart, sessionStartCmd); changed {
sessionStart = updated
count++
}
}
if !hookCommandExists(userPromptSubmit, userPromptSubmitCmd) {
userPromptSubmit = addHook(userPromptSubmit, userPromptSubmitCmd)
if updated, changed := syncHookCommand(userPromptSubmit, userPromptSubmitCmd); changed {
userPromptSubmit = updated
count++
}
}
if !hookCommandExists(stop, stopCmd) {
stop = addHook(stop, stopCmd)
if updated, changed := syncHookCommand(stop, stopCmd); changed {
stop = updated
count++
}
}
if !hookCommandExists(postToolUse, postToolUseCmd) {
postToolUse = addHook(postToolUse, postToolUseCmd)
if updated, changed := syncHookCommand(postToolUse, postToolUseCmd); changed {
postToolUse = updated
count++
}
}
47 unmodified lines
return count, nil
}
func shouldUseWindowsProductionCodexHooks(ctx context.Context, localDev bool) bool {
if localDev || codexHookCommandOS != "windows" {
return false
}
return !codexProductionHookWrapperWorks(ctx, codexHookWrapperCompatibilityProbe)
}
func wrapCodexSessionStartHookCommand(command string, useWindows bool) string {
if useWindows {
return agent.WrapWindowsProductionJSONWarningHookCommand(command, agent.WarningFormatSingleLine)
}
return agent.WrapProductionJSONWarningHookCommand(command, agent.WarningFormatSingleLine)
}
func wrapCodexSilentHookCommand(command string, useWindows bool) string {
if useWindows {
return agent.WrapWindowsProductionSilentHookCommand(command)
}
return agent.WrapProductionSilentHookCommand(command)
}
func defaultCodexProductionHookWrapperWorks(ctx context.Context, command string) bool {
probeCtx, cancel := context.WithTimeout(ctx, 2*time.Second)
defer cancel()
cmd := exec.CommandContext(probeCtx, "cmd.exe", "/d", "/s", "/c", command)
cmd.Stdout = io.Discard
cmd.Stderr = io.Discard
return cmd.Run() == nil
}
// UninstallHooks removes Entire hooks from Codex hooks.json.
func (c *CodexAgent) UninstallHooks(ctx context.Context) error {
repoRoot, err := paths.WorktreeRoot(ctx)
124 unmodified lines
return false
}
func syncHookCommand(groups []MatcherGroup, command string) ([]MatcherGroup, bool) {
if hookCommandExists(groups, command) {
return groups, false
}
if hasEntireHook(groups) {
groups = removeEntireHooks(groups)
}
return addHook(groups, command), true
}
func addHook(groups []MatcherGroup, command string) []MatcherGroup {
entry := HookEntry{
Type: "command",