Files
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

115 lines
3.0 KiB
Go

package hooks
import (
"encoding/json"
"io"
"os"
)
// RunCodex handles the Codex hook wire shape. Codex support is deliberately
// soft-only: PreToolUse is forced through ModeEnrich, PostToolUse only emits
// additionalContext, and UserPromptSubmit re-surfaces prompt-relevant graph
// symbols on every turn. No branch ever denies a tool call.
func RunCodex(port int) {
data, err := io.ReadAll(os.Stdin)
if err != nil {
return
}
runCodex(data, port)
}
func runCodex(data []byte, port int) {
var peek struct {
HookEventName string `json:"hook_event_name"`
ToolName string `json:"tool_name"`
}
if err := json.Unmarshal(data, &peek); err != nil {
return
}
switch {
case peek.HookEventName == "PreToolUse" && peek.ToolName == "Bash":
runPreToolUse(data, port, ModeEnrich)
case peek.HookEventName == "PreToolUse" && codexMCPReadPreToolUseTool(peek.ToolName):
runCodexMCPReadPreToolUse(data)
case peek.HookEventName == "PostToolUse" && peek.ToolName == "Bash":
runCodexPostToolUse(data)
case peek.HookEventName == "UserPromptSubmit":
// Re-surface graph symbols relevant to the prompt on every turn.
// Codex forgets MCP tools as context grows, so a SessionStart
// orientation alone fades; this lands a fresh, prompt-specific
// nudge at the top of each turn (the wire shape is shared with
// Claude Code — hookSpecificOutput.additionalContext).
runUserPromptSubmit(data)
}
}
func codexMCPReadPreToolUseTool(toolName string) bool {
switch toolName {
case gortexReadFileTool, gortexEditingContextTool:
return true
default:
return false
}
}
func runCodexMCPReadPreToolUse(data []byte) {
var input HookInput
if err := json.Unmarshal(data, &input); err != nil {
return
}
if input.HookEventName != "PreToolUse" || !codexMCPReadPreToolUseTool(input.ToolName) {
return
}
ctx := gortexReadNudge(input.ToolName, input.ToolInput)
if ctx == "" {
return
}
emitPreToolUse(HookOutput{
HookSpecificOutput: &HookSpecificOutput{
HookEventName: "PreToolUse",
AdditionalContext: ctx,
},
})
}
func runCodexPostToolUse(data []byte) {
var input postHookInput
if err := json.Unmarshal(data, &input); err != nil {
return
}
if input.HookEventName != "PostToolUse" || input.ToolName != "Bash" {
return
}
cmd, _ := input.ToolInput["command"].(string)
classification := classifyBashCommand(cmd)
switch classification.Action {
case BashActionGrepLike:
// Codex wraps grep/rg/ag in Bash. Re-label that narrow shape as Grep so
// the existing PostToolUse enrichment can parse path:line output and do
// the graph lookup without changing Claude Code behavior.
input.ToolName = "Grep"
case BashActionFindName:
input.ToolName = "Glob"
case BashActionReadSource:
if classification.Path == "" {
return
}
if input.ToolInput == nil {
input.ToolInput = make(map[string]any)
}
input.ToolName = "Read"
input.ToolInput["file_path"] = classification.Path
default:
return
}
normalized, err := json.Marshal(input)
if err != nil {
return
}
runPostToolUse(normalized)
}