fix(install): emit event-name leaf key for Codex AoT hooks migration (#3346)
migrateCodexHooksMapFormat re-emitted the raw `[hooks.<X>]` path segment as the leaf TOML key of the new `[[hooks.<EVENT>]]` block. When the legacy table key was a `<file>:<event>:<line>:<col>` location identifier and the real event lived in an `event = "..."` body field, the migration emitted a header like `[[hooks."C:\\Users\\helen\\.codex\\config.toml:session_start:0:0"]]` that Codex 0.124.0+ refuses to load — causing `npx get-shit-done-cc@latest` to abort the Codex runtime install on Windows configs that pre-date AoT. Mirror the flat-AoT branch in the map-format and stale-namespaced-AoT branches: when the section body declares `event = "..."`, that name wins as the leaf key and `event` is excluded from the re-emitted handler body. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3572,18 +3572,29 @@ function migrateCodexHooksMapFormat(content) {
|
||||
const mapOnlyBlocks = legacyMapSections
|
||||
.filter((s) => s.path !== 'hooks') // skip bare [hooks] container
|
||||
.map((s) => {
|
||||
const type = s.path.slice('hooks.'.length);
|
||||
const body = content.slice(s.headerEnd, s.end);
|
||||
return buildNestedBlock(type, body);
|
||||
// #3346: when the legacy `[hooks.<X>]` body declares `event = "..."`,
|
||||
// prefer that as the event-name leaf key. The path segment <X> may be
|
||||
// a `<file>:<event>:<line>:<col>` location identifier (Codex pre-AoT
|
||||
// wrote those as table keys), which is not a valid leaf event name —
|
||||
// emitting it verbatim produces a TOML key chain Codex 0.124.0+ rejects.
|
||||
const bodyEvent = extractFlatHookEventName(body);
|
||||
const type = bodyEvent !== null ? bodyEvent : s.path.slice('hooks.'.length);
|
||||
const skipKeys = bodyEvent !== null ? new Set(['event']) : new Set();
|
||||
return buildNestedBlock(type, body, skipKeys);
|
||||
});
|
||||
|
||||
// Stale namespaced AoT blocks: [[hooks.TYPE]] entries with handler fields at
|
||||
// event-entry level (no .hooks sub-table). Treated like map-format blocks —
|
||||
// inserted before the first remaining table section.
|
||||
const staleNamespacedAotBlocks = staleNamespacedAotSections.map((s) => {
|
||||
const type = s.path.slice('hooks.'.length);
|
||||
const body = content.slice(s.headerEnd, s.end);
|
||||
return buildNestedBlock(type, body);
|
||||
// #3346: see note in mapOnlyBlocks — body `event = "..."` wins over the
|
||||
// raw path segment when both are present.
|
||||
const bodyEvent = extractFlatHookEventName(body);
|
||||
const type = bodyEvent !== null ? bodyEvent : s.path.slice('hooks.'.length);
|
||||
const skipKeys = bodyEvent !== null ? new Set(['event']) : new Set();
|
||||
return buildNestedBlock(type, body, skipKeys);
|
||||
});
|
||||
|
||||
const flatAotBlocks = migratedFlatAotSections.map((s) => {
|
||||
|
||||
Reference in New Issue
Block a user