11import { existsSync , readFileSync } from "node:fs" ;
22import { join } from "node:path" ;
33import { home } from "../util/paths.ts" ;
4- import { devStubStateForHarness } from "./agentlock-state.ts" ;
4+ import { codexAgentlockState } from "./agentlock-state.ts" ;
55import type { Detector , Detection , DetectedScope } from "./types.ts" ;
66
77// OpenAI Codex CLI: ~/.codex/{config.toml, auth.json, hooks.json}.
88// Lifecycle hooks (PreToolUse / PostToolUse / SessionStart / Stop) are
9- // available behind `codex_hooks = true` in config.toml. PreToolUse only
10- // fires for shell calls today — MCP coverage is tracked upstream.
9+ // available behind `[features].hooks = true` in config.toml. PreToolUse
10+ // only fires for shell calls today — MCP coverage is tracked upstream.
1111export const codex : Detector = {
1212 id : "codex" ,
1313 displayName : "Codex CLI (OpenAI)" ,
@@ -29,16 +29,16 @@ export const codex: Detector = {
2929 if ( existsSync ( configToml ) ) {
3030 evidence . push (
3131 flagEnabled
32- ? "config.toml: codex_hooks = true"
33- : "config.toml: codex_hooks not set (install will refuse until enabled )" ,
32+ ? "config.toml: [features].hooks = true"
33+ : "config.toml: [features].hooks not set (install will enable it )" ,
3434 ) ;
3535 }
3636
3737 const scopes : DetectedScope [ ] = [
3838 { kind : "global" , path : configToml , exists : existsSync ( configToml ) } ,
3939 ] ;
4040
41- const al = devStubStateForHarness ( this . id ) ;
41+ const al = codexAgentlockState ( hooksJson ) ;
4242
4343 return {
4444 id : this . id ,
@@ -48,7 +48,7 @@ export const codex: Detector = {
4848 scopes,
4949 surfaces : [ "lifecycle-hooks" , "mcp-stdio" ] ,
5050 notes : [
51- "Codex CLI hooks require `codex_hooks = true` in ~/.codex/config.toml." ,
51+ "Codex hooks require `[features].hooks = true` in ~/.codex/config.toml." ,
5252 "Bash-only today: PreToolUse does not fire for MCP tool calls (tracked upstream)." ,
5353 ] ,
5454 agentlockInstalled : al . installed ,
@@ -57,10 +57,10 @@ export const codex: Detector = {
5757 } ,
5858} ;
5959
60- // codexHooksFlagEnabled returns true when ~/.codex/config.toml has a
61- // top-level `codex_hooks = true` line. We avoid pulling in a TOML parser
62- // for a single-key probe: the simple line scan is good enough for
63- // detection (the install handler does the same check authoritatively) .
60+ // codexHooksFlagEnabled returns true when ~/.codex/config.toml enables
61+ // current `[features].hooks` or the legacy top-level `codex_hooks` flag.
62+ // We avoid pulling in a TOML parser for a single-key probe: the simple
63+ // section-aware scan is good enough for detection .
6464function codexHooksFlagEnabled ( configTomlPath : string ) : boolean {
6565 if ( ! existsSync ( configTomlPath ) ) return false ;
6666 let body : string ;
@@ -69,12 +69,30 @@ function codexHooksFlagEnabled(configTomlPath: string): boolean {
6969 } catch {
7070 return false ;
7171 }
72+ let inFeatures = false ;
73+ let seenSection = false ;
7274 for ( const raw of body . split ( / \r ? \n / ) ) {
7375 const line = raw . trim ( ) ;
7476 if ( ! line || line . startsWith ( "#" ) ) continue ;
75- if ( line . startsWith ( "[" ) ) break ; // first section ends top-level keys
76- const m = line . match ( / ^ c o d e x _ h o o k s \s * = \s * ( t r u e | f a l s e ) \b / ) ;
77- if ( m ) return m [ 1 ] === "true" ;
77+ if ( line . startsWith ( "[" ) ) {
78+ seenSection = true ;
79+ const header = line . split ( "#" , 1 ) [ 0 ] ?. trim ( ) ?? "" ;
80+ const name =
81+ header . startsWith ( "[" ) && header . endsWith ( "]" )
82+ ? header . slice ( 1 , - 1 ) . trim ( )
83+ : "" ;
84+ inFeatures = name === "features" ;
85+ continue ;
86+ }
87+ if ( inFeatures ) {
88+ const m = line . match ( / ^ h o o k s \s * = \s * ( t r u e | f a l s e ) \b / ) ;
89+ if ( m ) return m [ 1 ] === "true" ;
90+ continue ;
91+ }
92+ if ( ! seenSection ) {
93+ const legacy = line . match ( / ^ c o d e x _ h o o k s \s * = \s * ( t r u e | f a l s e ) \b / ) ;
94+ if ( legacy ) return legacy [ 1 ] === "true" ;
95+ }
7896 }
7997 return false ;
8098}
0 commit comments