Skip to content

refactor(hooks): clean up Codex CLI hooks implementation (#1445)#1451

Closed
dyoshikawa wants to merge 2 commits intomainfrom
refactor/codexcli-hooks-cleanup
Closed

refactor(hooks): clean up Codex CLI hooks implementation (#1445)#1451
dyoshikawa wants to merge 2 commits intomainfrom
refactor/codexcli-hooks-cleanup

Conversation

@dyoshikawa
Copy link
Copy Markdown
Owner

Summary

Addresses the code-quality follow-ups from #1445 (review of #1439).

  • DRY: codexcli-hooks.ts and geminicli-hooks.ts now delegate to the shared canonicalToToolHooks / toolHooksToCanonical helpers in tool-hooks-converter.ts instead of reimplementing the conversion logic. ToolHooksConverterConfig gained supportedHookTypes, omitEmptyEvents, and empty-projectDirVar support to express the Codex CLI quirks (command-only hooks, no project dir variable, drop empty events). The shared converter also now passes name/description through in both directions, fixing the silent drop on Codex CLI export.
  • OCP: removed the if (toolTarget === 'codexcli') branch in hooks-processor.ts. Tools that need extra files now expose an optional static getAuxiliaryFiles({ baseDir }), and CodexcliHooks implements it to emit .codex/config.toml.
  • Error handling: wrapped smolToml.parse() in buildCodexConfigTomlContent with try/catch and formatError, so a malformed config.toml produces a clear error mentioning the path.
  • Round-trip safety: toolHooksToCanonical intentionally still preserves prompt-type hooks on import even for Codex CLI; the asymmetry is now documented in the converter config so the next export silently filters them (with the existing hooks-processor warning making the loss visible).
  • Cleanup: consolidated the duplicate AiFileParams / ValidationResult import lines.
  • Tests: added coverage for the [features] section merge in CodexcliConfigToml and for the malformed-TOML error path.

Test plan

  • pnpm cicheck (lint, typecheck, 4774 tests, content checks) — all green

…verter

- Extend ToolHooksConverterConfig with supportedHookTypes, omitEmptyEvents,
  empty-projectDirVar support, and pass-through of name/description fields,
  then refactor codexcli-hooks.ts and geminicli-hooks.ts to delegate to the
  shared canonicalToToolHooks/toolHooksToCanonical helpers instead of
  reimplementing the conversion logic.
- Generalize auxiliary file generation in hooks-processor.ts via an optional
  getAuxiliaryFiles() factory hook so the codexcli-specific config.toml
  branch is no longer hardcoded.
- Wrap smolToml.parse() in buildCodexConfigTomlContent() with try/catch and
  formatError so malformed config.toml files surface a clear error.
- Consolidate duplicate AiFileParams/ValidationResult imports.
- Add tests covering the [features] section merge and the malformed
  config.toml error path for CodexcliConfigToml.

Refs #1445

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 8, 2026 05:32
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors Codex CLI (and Gemini CLI) hooks handling to reuse the shared tool-hooks converter, removes codexcli-specific branching in the hooks processor via an auxiliary-files hook, and improves Codex CLI config.toml error handling + test coverage.

Changes:

  • Extend tool-hooks-converter.ts with Codex CLI–specific config options (supported hook types, omit empty events, empty project dir var) and preserve name/description in conversions.
  • Generalize auxiliary file emission in hooks-processor.ts via optional getAuxiliaryFiles(), implemented by CodexcliHooks to emit .codex/config.toml.
  • Add Codex CLI tests for [features] merge behavior and malformed TOML error messaging.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/features/hooks/tool-hooks-converter.ts Adds converter config knobs for Codex CLI quirks; passes through name/description; supports omitting empty events.
src/features/hooks/hooks-processor.ts Replaces codexcli-specific branching with a generic getAuxiliaryFiles() extension point.
src/features/hooks/geminicli-hooks.ts Removes duplicated conversion logic and delegates to the shared converter.
src/features/hooks/codexcli-hooks.ts Delegates to shared converter, adds auxiliary file generation, and improves TOML parse error handling.
src/features/hooks/codexcli-hooks.test.ts Adds coverage for [features] merge and malformed TOML error path.

Comment on lines 170 to +179
for (const rawEntry of matcherEntries) {
if (!isToolMatcherEntry(rawEntry)) continue;
const hookDefs = rawEntry.hooks ?? [];
for (const h of hookDefs) {
const cmd = typeof h.command === "string" ? h.command : undefined;
const prefixingEnabled = converterConfig.projectDirVar !== "";
const command =
typeof cmd === "string" && cmd.includes(`${converterConfig.projectDirVar}/`)
prefixingEnabled &&
typeof cmd === "string" &&
cmd.includes(`${converterConfig.projectDirVar}/`)
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toolHooksToCanonical assumes every element of rawEntry.hooks is a non-null object, but isToolMatcherEntry() only checks that hooks is an array. If a tool config is manually edited (or otherwise malformed) and includes null/primitives inside hooks, typeof h.command will throw at runtime. Please harden parsing by skipping non-object hook entries (e.g., guard h with h && typeof h === "object") or strengthen isToolMatcherEntry() to validate hook array elements before iterating.

Copilot uses AI. Check for mistakes.
- Add logger to ToolHooksFromRulesyncHooksParams and pass this.logger
  from HooksProcessor so converter warnings actually fire (#1).
- Add passthroughNameDescription flag to ToolHooksConverterConfig and
  enable it only for codexcli/geminicli, preventing the unconditional
  pass-through from leaking unknown 'name'/'description' keys into
  Claude Code / Factory Droid hook outputs (#2).
- Document the Codex CLI command-passthrough behavior for hand-edited
  configs containing other tools' project-dir variables (#3).

Refs #1445

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@cm-dyoshikawa cm-dyoshikawa deleted the refactor/codexcli-hooks-cleanup branch April 9, 2026 07:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants