Skip to content

Capture native Codex exec context - #671

Merged
bcdonadio merged 6 commits into
mainfrom
fix/604-codex-post-tool-capture
Aug 12, 2026
Merged

Capture native Codex exec context#671
bcdonadio merged 6 commits into
mainfrom
fix/604-codex-post-tool-capture

Conversation

@bcdonadio

Copy link
Copy Markdown
Contributor

Summary

  • normalize native Codex functions.exec and functions.exec_command payloads into bounded, scrubbed passive-learning semantics
  • persist recognized Git, environment, and error events without retaining raw stdout, stderr, response, or unknown fields
  • make targeted Codex connector diagnostics verify the exact PostToolUse installation and a pure no-write functional probe
  • document the capture boundary and add patch release metadata

Testing

  • strict RED/GREEN regression coverage for the normalizer, real EventsDb persistence path, CLI client injection, and connector diagnostics
  • npm run build
  • npm run typecheck
  • npm run lint
  • npm run test:ci (261 files passed, 2 skipped; 6430 tests passed, 12 skipped; 100% statements, branches, functions, and lines)

Closes #604

Signed-off-by: Bernardo Donadio <bcdonadio@bcdonadio.com>
Signed-off-by: Bernardo Donadio <bcdonadio@bcdonadio.com>
Signed-off-by: Bernardo Donadio <bcdonadio@bcdonadio.com>
Signed-off-by: Bernardo Donadio <bcdonadio@bcdonadio.com>
Signed-off-by: Bernardo Donadio <bcdonadio@bcdonadio.com>
Signed-off-by: Bernardo Donadio <bcdonadio@bcdonadio.com>
Copilot AI lite review requested due to automatic review settings August 12, 2026 11:33
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Capture bounded Codex native exec context from PostToolUse events

🐞 Bug fix ✨ Enhancement 🧪 Tests 📝 Documentation ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Normalize Codex native exec payloads into bounded, scrubbed Bash-style passive-learning events.
• Persist only allowlisted command/status context and suppress LCM self-write feedback loops.
• Extend connectors doctor codex to verify exact hook structure and run a no-write functional
 probe.
Diagram

graph TD
  A[Codex] --> B["~/.codex/hooks.json"] --> C["lcm CLI"] --> D["post-tool normalizer"] --> E["event extractors"] --> F[("EventsDb sidecar")]
  C --> G["Codex hook inspector"] --> B
  C --> H["No-write probe"] --> D
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Dedicated Codex extractor pipeline
  • ➕ Avoids mapping Codex native exec into Bash semantics, reducing semantic coupling
  • ➕ Allows future Codex-specific structured payload fields (files/ops) without Bash constraints
  • ➖ More code paths to maintain/test; duplicates classification logic already implemented for Bash
  • ➖ Harder to keep capture boundary tight without re-creating existing scrub/truncation guarantees
2. Doctor runs an end-to-end hook invocation in a temp workspace
  • ➕ More realistic validation (covers dispatch/handler wiring and persistence end-to-end)
  • ➖ Violates no-write expectation unless heavily sandboxed; risk of touching user state
  • ➖ Adds filesystem/DB flakiness to a health check that should be deterministic

Recommendation: The PR’s approach (normalize Codex functions.exec* into a bounded canonical Bash input, then reuse the existing extractor + scrubbing/persistence pipeline) is the best fit for the current payload reality: it reuses proven extraction/scrub logic and enforces a strict data minimization boundary. A dedicated Codex extractor only becomes compelling once Codex provides stable structured file-operation semantics that can’t be expressed via existing Bash events.

Files changed (17) +1082 / -41

Enhancement (1) +47 / -1
codex-hooks.tsAdd exact PostToolUse hook inspection and canonical path resolver +47/-1

Add exact PostToolUse hook inspection and canonical path resolver

• Introduces 'inspectCodexPostToolHook()' to validate the exact Codex PostToolUse command hook contract without writing. Adds 'resolveCodexHooksPath()' to resolve the canonical '~/.codex/hooks.json' path consistent with installation logic, and returns absent/incomplete/installed states.

src/connectors/codex-hooks.ts

Bug fix (3) +155 / -16
lcm.tsFail 'connectors doctor codex' on hook/coverage errors +33/-0

Fail 'connectors doctor codex' on hook/coverage errors

• Extends connector health output to include Codex-specific PostToolUse structural inspection and a pure in-memory functional coverage probe. Aggregates failures and exits non-zero when Codex hook structure is missing/incomplete or functional probe fails.

bin/lcm.ts

post-tool-normalization.tsNormalize Codex native exec into bounded canonical PostToolInput +118/-0

Normalize Codex native exec into bounded canonical PostToolInput

• Adds a dedicated normalizer that only recognizes Codex 'functions.exec' and 'functions.exec_command' payloads and maps them to 'tool_name: "Bash"' with a bounded command. Projects status via an allowlisted precedence policy, suppresses 'lcm store' feedback-loop commands, and provides a pure functional coverage helper.

src/hooks/post-tool-normalization.ts

post-tool.tsRoute PostToolUse parsing through the new normalizer +4/-16

Route PostToolUse parsing through the new normalizer

• Refactors 'handlePostToolUse' to call 'normalizePostToolInput' before extracting events, removing ad-hoc tool_output normalization in the handler. Ensures the handler can consume the top-level 'client' field for Codex-native normalization decisions.

src/hooks/post-tool.ts

Refactor (1) +1 / -1
extractors.tsExport 'PostToolInput' type for reuse by normalizer +1/-1

Export 'PostToolInput' type for reuse by normalizer

• Exports the 'PostToolInput' interface so normalization can produce the canonical shape consumed by existing extractors.

src/hooks/extractors.ts

Tests (6) +703 / -2
lcm-run-cli.test.tsTest Codex client injection and doctor diagnostics branching +103/-0

Test Codex client injection and doctor diagnostics branching

• Adds mocks and tests ensuring the CLI preserves/injects the Codex client for post-tool dispatch and that 'connectors doctor codex' reports structural status, runs/skips the functional probe appropriately, and exits non-zero on failures or probe exceptions.

test/bin/lcm-run-cli.test.ts

codecov-config.test.tsUpdate expected production file count for new hook module +2/-2

Update expected production file count for new hook module

• Updates Codecov configuration tests to account for the newly added production file under 'src/hooks/'.

test/codecov-config.test.ts

codex-hooks.test.tsCover exact Codex PostToolUse contract inspection and path resolution +55/-0

Cover exact Codex PostToolUse contract inspection and path resolution

• Adds tests verifying permissive broad discovery remains unchanged while exact inspection requires the native PostToolUse command hook. Covers absent/malformed/incomplete states, exact-match success, canonical path resolution, and no-write inspection behavior.

test/connectors/codex-hooks.test.ts

dispatch.test.tsEnsure dispatch preserves top-level Codex client for post-tool +14/-0

Ensure dispatch preserves top-level Codex client for post-tool

• Adds coverage that direct post-tool dispatch forwards the payload unchanged, including 'client: "codex"', so downstream normalization can apply.

test/hooks/dispatch.test.ts

post-tool-normalization.test.tsAdd table-driven tests for Codex exec normalization boundary +359/-0

Add table-driven tests for Codex exec normalization boundary

• Introduces comprehensive unit coverage for command selection and bounding, status precedence and fallback rules, feedback-loop suppression, and guarantees that raw stdout/stderr/unknown fields never cross into normalized inputs or extracted events.

test/hooks/post-tool-normalization.test.ts

post-tool.test.tsPersist Codex native exec events through EventsDb with boundary guarantees +170/-0

Persist Codex native exec events through EventsDb with boundary guarantees

• Adds integration-style tests asserting native Codex exec payloads persist as allowlisted extracted events via the real EventsDb path, including success/error status mapping and command suppression. Verifies raw output/response secrets are not persisted and invalid identities/shapes produce no writes.

test/hooks/post-tool.test.ts

Documentation (4) +168 / -21
hook-protocol.mdDocument Codex PostToolUse contract and capture boundary +72/-0

Document Codex PostToolUse contract and capture boundary

• Adds explicit documentation of the exact Codex PostToolUse hook structure and the bounded capture policy (command selection, truncation, status projection, and no raw output persistence). Describes doctor’s structural check and the no-write functional probe behavior.

docs/hook-protocol.md

passive-learning.mdDescribe Codex native exec adaptation into Bash semantics +34/-2

Describe Codex native exec adaptation into Bash semantics

• Documents how 'functions.exec' / 'functions.exec_command' are adapted into existing Bash event semantics, including command bounding, status precedence rules, and suppressed feedback-loop commands. Updates “not captured” section to explicitly exclude unknown Codex output fields.

docs/passive-learning.md

2026-08-11-codex-post-tool-capture.mdRefine implementation plan for bounded Codex exec capture +23/-17

Refine implementation plan for bounded Codex exec capture

• Updates the plan to reflect the 2,000-character adapter bound, strict command selection semantics, status precedence rules, and the requirement that doctor’s probe remains pure/no-write.

docs/superpowers/plans/2026-08-11-codex-post-tool-capture.md

vscode-codex.mdExplain Codex PostToolUse capture boundary and diagnostics +39/-2

Explain Codex PostToolUse capture boundary and diagnostics

• Updates the Codex connector docs to state PostToolUse captures only bounded semantic signals for native exec tools. Adds a detailed section describing the exact hook entry and the doctor structural + no-write functional checks.

docs/vscode-codex.md

Other (2) +8 / -0
capture-codex-exec-context.mdAdd patch changeset for Codex exec capture +7/-0

Add patch changeset for Codex exec capture

• Introduces a patch-level changeset describing bounded semantic capture for Codex native exec events and new connector doctor validation behavior.

.changeset/capture-codex-exec-context.md

codecov.ymlClarify hooks component ownership for native adapters +1/-0

Clarify hooks component ownership for native adapters

• Documents that 'src/hooks/' ownership includes native hook adapters to keep coverage component mapping consistent.

codecov.yml

@codecov

codecov Bot commented Aug 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

📢 Thoughts on this report? Let us know!

@bcdonadio
bcdonadio merged commit accb1a2 into main Aug 12, 2026
22 checks passed
@bcdonadio
bcdonadio deleted the fix/604-codex-post-tool-capture branch August 12, 2026 11:37

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes missing passive-learning capture for native Codex shell tool calls by normalizing functions.exec / functions.exec_command PostToolUse payloads into the existing “Bash” extractor semantics, while enforcing a strict boundary that avoids persisting raw stdout/stderr/response fields. It also strengthens the Codex connector doctor flow with structural validation plus a pure in-memory functional probe, and documents the new capture boundary as a patch release.

Changes:

  • Add a Codex-specific PostToolUse normalizer that bounds commands, projects only allowlisted status fields, and suppresses lcm store feedback-loop commands.
  • Extend Codex connector diagnostics (“doctor”) to verify exact PostToolUse hook structure and run a no-write functional coverage probe.
  • Add comprehensive regression tests, update docs, and update Codecov component metadata/counts.

Reviewed changes

Copilot reviewed 15 out of 17 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
test/hooks/post-tool.test.ts Adds integration-style persistence assertions for native Codex exec normalization and bounded storage behavior.
test/hooks/post-tool-normalization.test.ts New table-driven tests covering normalization, status precedence, bounding, and secret-boundary guarantees.
test/hooks/dispatch.test.ts Verifies Codex client propagation through direct post-tool dispatch.
test/connectors/codex-hooks.test.ts Adds tests for exact PostToolUse structural inspection and canonical hooks path resolution.
test/codecov-config.test.ts Updates expected production file counts to reflect the new production module.
test/bin/lcm-run-cli.test.ts Adds CLI tests for post-tool client injection and Codex doctor structural/functional output paths.
src/hooks/post-tool.ts Routes all PostToolUse inputs through the new normalizer before extraction.
src/hooks/post-tool-normalization.ts New normalization module for Codex native exec payloads + pure functional probe helper.
src/hooks/extractors.ts Exports PostToolInput to support typed normalization tests.
src/connectors/codex-hooks.ts Adds exact PostToolUse hook inspection and canonical path resolution helper.
bin/lcm.ts Implements targeted Codex doctor structural + pure functional checks with aggregated exit status.
codecov.yml Clarifies src/hooks/ component ownership for the new adapter module.
docs/vscode-codex.md Documents the Codex PostToolUse capture boundary and doctor behavior.
docs/passive-learning.md Documents native Codex command capture semantics and boundary constraints.
docs/hook-protocol.md Documents Codex native PostToolUse contract and doctor checks (needs a small correction per comments).
docs/superpowers/plans/2026-08-11-codex-post-tool-capture.md Updates the implementation plan to reflect the final rules and probe behavior.
.changeset/capture-codex-exec-context.md Patch release metadata for the Codex capture/diagnostics change.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread docs/hook-protocol.md
Comment on lines +171 to +185
```json
{
"PostToolUse": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "lcm post-tool --client codex"
}
]
}
]
}
```
Comment on lines +273 to +277
/** Resolve the Codex hooks path using the same `~/` convention as installation. */
export function resolveCodexHooksPath(cwd: string = process.cwd()): string {
void cwd;
return join(homedir(), CODEX_HOOKS_PATH.slice(2));
}
@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (3) 📘 Rule violations (3) 📜 Skill insights (0)

Grey Divider


Action required

1. Codex health check skipped without explicit agent 🐞 Bug ≡ Correctness
Description
The connectors doctor command's new Codex structural/functional check is guarded by `agentName ===
undefined, so running the documented broad lcm connectors doctor` (no agent argument) silently
skips both the exact PostToolUse structural inspection and the native-exec functional probe, even
though the loop still iterates Codex within the AGENTS list. This causes the new health
verification introduced by this PR to be effectively unreachable for the command's most common
invocation form.
Code

bin/lcm.ts[2394]

+        if ((agent as any).id !== "codex" || agentName === undefined) continue;
Relevance

●●● Strong

Seems like a real bug: broad doctor should not skip Codex checks silently.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
bin/lcm.ts:2377 builds agents as AGENTS (all agents) when agentName is undefined, so Codex is
included in the broad loop. But line 2394 (`if ((agent as any).id !== "codex" || agentName ===
undefined) continue;`) skips the new inspectCodexPostToolHook/codexPostToolFunctionalCoverage checks
whenever agentName is undefined — i.e. for every broad lcm connectors doctor invocation.
src/cli-help.ts:361 documents lcm connectors doctor (no agent) as 'Check health of all
connectors', confirming this is the primary, documented broad-check path where the new Codex
diagnostics should run but don't.

bin/lcm.ts[2368-2427]
src/cli-help.ts[361-364]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Codex-specific PostToolUse structural/functional health check added in this PR is skipped whenever `lcm connectors doctor` is invoked without an explicit agent name (broad mode over all agents), because of an added `agentName === undefined` condition in the skip check. This means the new diagnostics never run for the most common/documented usage of `lcm connectors doctor`.

## Issue Context
`agents` is populated with all agents (including Codex) when `agentName` is undefined (broad mode). The loop over `agents` should run the Codex-specific checks whenever the current `agent.id === "codex"`, regardless of whether the user passed an explicit agent name.

## Fix Focus Areas
- bin/lcm.ts[2394-2394]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Implicit any in hook scan 📘 Rule violation ⚙ Maintainability
Description
The new hasExactPostToolHook() logic relies on Array.isArray() narrowing to any[], causing
callback parameters like group/hook to be inferred as any. This violates the requirement to
avoid inferred any in TypeScript function/callback signatures.
Code

src/connectors/codex-hooks.ts[R284-286]

+  return postToolUse.some((group) => {
+    if (!isObject(group) || group.matcher !== "*" || !Array.isArray(group.hooks)) return false;
+    return group.hooks.some((hook) =>
Relevance

●●● Strong

Repo enforces no implicit any; similar explicit typing fixes accepted.

PR-#666

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2445781 requires avoiding inferred any in TypeScript function/callback
parameters. In hasExactPostToolHook, postToolUse is narrowed with Array.isArray and then
iterated with .some((group) => ...) / .some((hook) => ...), which infers any for
group/hook.

Rule 2445781: Disallow implicit any in TypeScript function signatures and object types
src/connectors/codex-hooks.ts[279-291]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
New callbacks infer `any` (via `Array.isArray` → `any[]`), violating the no-inferred-`any` requirement.

## Issue Context
`hasExactPostToolHook()` uses `Array.isArray(postToolUse)` which narrows to `any[]`, so `.some((group) => ...)` and nested `.some((hook) => ...)` infer `any`.

## Fix Focus Areas
- src/connectors/codex-hooks.ts[279-291]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Undocumented as any cast 📘 Rule violation ⚙ Maintainability
Description
A new (agent as any) cast was added without an adjacent justification comment. This violates the
requirement that each as any usage in changed TypeScript code be explicitly justified.
Code

bin/lcm.ts[2394]

+        if ((agent as any).id !== "codex" || agentName === undefined) continue;
Relevance

●●● Strong

Repo often removes/justifies as any; similar TS-cast cleanups accepted.

PR-#111

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2445790 requires every as any in changed TypeScript code to have an adjacent
comment explaining why it’s needed. The added line uses (agent as any).id without any
justification comment.

Rule 2445790: Document justification for each as any type assertion
bin/lcm.ts[2393-2395]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A newly added `as any` type assertion is missing the required justification comment.

## Issue Context
The checklist requires an immediately-adjacent comment explaining why `as any` is necessary.

## Fix Focus Areas
- bin/lcm.ts[2393-2395]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


4. @donadiosolutions/lcm patch bump too low 📘 Rule violation § Compliance
Description
The changeset declares a patch release, but the PR introduces new user-facing behavior (native
Codex exec capture and new connector diagnostics). Per the checklist, this should be at least a
minor bump.
Code

.changeset/capture-codex-exec-context.md[2]

+"@donadiosolutions/lcm": patch
Relevance

●●● Strong

Accepted precedents for patch→minor when changeset describes user-visible behavior.

PR-#531
PR-#331

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2446377 requires selecting patch only for behavior-preserving changes; the
changeset itself describes new Codex capture/diagnostics behavior while declaring a patch bump.

Rule 2446377: Select semantic bump level based on behavioral impact
.changeset/capture-codex-exec-context.md[1-7]
src/hooks/post-tool-normalization.ts[74-98]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The changeset uses a `patch` bump even though the change adds new user-facing behavior.

## Issue Context
This PR adds native Codex `functions.exec` / `functions.exec_command` capture behavior and new `lcm connectors doctor codex` diagnostics, which is more than a patch-level internal fix.

## Fix Focus Areas
- .changeset/capture-codex-exec-context.md[1-3]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Doctor ignores hooks feature flag 🐞 Bug ≡ Correctness
Description
Targeted Codex doctor declares PostToolUse installed after checking only hooks.json, while Codex
also requires [features].hooks = true in config.toml. If that flag is missing or disabled, the
pure adapter probe still passes and doctor reports healthy even though Codex will not dispatch the
hook.
Code

bin/lcm.ts[R2401-2403]

+        const inspection = inspectCodexPostToolHook(
+          resolveCodexHooksPath(opts.global ? homedir() : process.cwd()),
+        );
Relevance

●● Moderate

Depends on intended doctor scope; no clear precedent on checking config feature flags.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new doctor passes only the hooks-file path to its structural inspection and then treats a
passing in-memory normalizer probe as functional health. Connector installation separately calls
enableCodexHooksFeature(configPath), and the Codex setup documentation identifies
[features].hooks = true as part of the required connector installation, proving that hooks.json
alone is insufficient.

bin/lcm.ts[2401-2414]
src/connectors/codex-hooks.ts[236-246]
docs/vscode-codex.md[54-57]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`lcm connectors doctor codex` checks the PostToolUse entry and an in-memory adapter probe but does not verify that Codex hook execution is enabled in `config.toml`. Extend structural health validation to require `[features].hooks = true`, reporting failure and skipping the functional probe when the runtime feature is absent or disabled.

## Issue Context
Codex connector installation enables the feature separately from writing `hooks.json`, so either file can drift independently. Resolve and inspect the canonical config path using the same installation scope and keep the check pure/no-write.

## Fix Focus Areas
- bin/lcm.ts[2396-2422]
- src/connectors/codex-hooks.ts[273-307]
- src/connectors/codex-hooks.ts[173-238]
- test/connectors/codex-hooks.test.ts[104-154]
- test/bin/lcm-run-cli.test.ts[886-946]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

6. Status precedence ignores tool_response when output invalid 🐞 Bug ≡ Correctness
Description
normalizeStatus in post-tool-normalization.ts only checks statusFromRecord(toolOutput) and
falls back to toolResponse only when the *entire* output-derived status is undefined; but per
the documented policy this fallback should also occur when tool_output is a record with no valid
recognized field, which is exactly what happens — statusFromRecord returns undefined when no
field matches, so this path is actually followed correctly. However, the same function returns early
with the tool_output result even when it's a valid false/0, which is correct per docs ("A
valid false or zero value is authoritative"), so on closer inspection the implementation matches the
documented precedence rules; this specific concern converges to no defect and should not be
reported.
Code

src/hooks/post-tool-normalization.ts[R39-45]

+function normalizeStatus(toolOutput: unknown, toolResponse: unknown): { isError?: boolean } | undefined {
+  const outputStatus = isRecord(toolOutput) ? statusFromRecord(toolOutput) : undefined;
+  if (outputStatus !== undefined) return { isError: outputStatus };
+
+  const responseStatus = isRecord(toolResponse) ? statusFromRecord(toolResponse) : undefined;
+  return responseStatus === undefined ? undefined : { isError: responseStatus };
+}
Relevance

●● Moderate

This is a “no defect” note; likely ignored, but no close rejection precedent found.

PR-#53

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Self-review determined the fallback logic correctly matches the documented spec; retained only as an
informational note that the logic is subtle enough to warrant a comment for maintainability.

src/hooks/post-tool-normalization.ts[39-45]


Grey Divider

Context
✅ Compliance rules (platform): 141 rules
Review mode: 🧠 Deep: This is a behavior-changing, security/privacy-sensitive capture path spanning normalization, persistence, CLI diagnostics, connector inspection, and many independent code and test sites, so redundant review could catch subtle boundary or regression defects.

Grey Divider

Tip of the day
💡 Did you know, you can enable the Remediation agent and Qodo fixes findings in a dedicated fix PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment on lines +284 to +286
return postToolUse.some((group) => {
if (!isObject(group) || group.matcher !== "*" || !Array.isArray(group.hooks)) return false;
return group.hooks.some((hook) =>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

1. Implicit any in hook scan 📘 Rule violation ⚙ Maintainability

The new hasExactPostToolHook() logic relies on Array.isArray() narrowing to any[], causing
callback parameters like group/hook to be inferred as any. This violates the requirement to
avoid inferred any in TypeScript function/callback signatures.
Agent Prompt
## Issue description
New callbacks infer `any` (via `Array.isArray` → `any[]`), violating the no-inferred-`any` requirement.

## Issue Context
`hasExactPostToolHook()` uses `Array.isArray(postToolUse)` which narrows to `any[]`, so `.some((group) => ...)` and nested `.some((hook) => ...)` infer `any`.

## Fix Focus Areas
- src/connectors/codex-hooks.ts[279-291]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread bin/lcm.ts
}
}

if ((agent as any).id !== "codex" || agentName === undefined) continue;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

2. Undocumented as any cast 📘 Rule violation ⚙ Maintainability

A new (agent as any) cast was added without an adjacent justification comment. This violates the
requirement that each as any usage in changed TypeScript code be explicitly justified.
Agent Prompt
## Issue description
A newly added `as any` type assertion is missing the required justification comment.

## Issue Context
The checklist requires an immediately-adjacent comment explaining why `as any` is necessary.

## Fix Focus Areas
- bin/lcm.ts[2393-2395]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@@ -0,0 +1,7 @@
---
"@donadiosolutions/lcm": patch

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

3. @donadiosolutions/lcm patch bump too low 📘 Rule violation § Compliance

The changeset declares a patch release, but the PR introduces new user-facing behavior (native
Codex exec capture and new connector diagnostics). Per the checklist, this should be at least a
minor bump.
Agent Prompt
## Issue description
The changeset uses a `patch` bump even though the change adds new user-facing behavior.

## Issue Context
This PR adds native Codex `functions.exec` / `functions.exec_command` capture behavior and new `lcm connectors doctor codex` diagnostics, which is more than a patch-level internal fix.

## Fix Focus Areas
- .changeset/capture-codex-exec-context.md[1-3]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread bin/lcm.ts
Comment on lines +2401 to +2403
const inspection = inspectCodexPostToolHook(
resolveCodexHooksPath(opts.global ? homedir() : process.cwd()),
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

4. Doctor ignores hooks feature flag 🐞 Bug ≡ Correctness

Targeted Codex doctor declares PostToolUse installed after checking only hooks.json, while Codex
also requires [features].hooks = true in config.toml. If that flag is missing or disabled, the
pure adapter probe still passes and doctor reports healthy even though Codex will not dispatch the
hook.
Agent Prompt
## Issue description
`lcm connectors doctor codex` checks the PostToolUse entry and an in-memory adapter probe but does not verify that Codex hook execution is enabled in `config.toml`. Extend structural health validation to require `[features].hooks = true`, reporting failure and skipping the functional probe when the runtime feature is absent or disabled.

## Issue Context
Codex connector installation enables the feature separately from writing `hooks.json`, so either file can drift independently. Resolve and inspect the canonical config path using the same installation scope and keep the check pure/no-write.

## Fix Focus Areas
- bin/lcm.ts[2396-2422]
- src/connectors/codex-hooks.ts[273-307]
- src/connectors/codex-hooks.ts[173-238]
- test/connectors/codex-hooks.test.ts[104-154]
- test/bin/lcm-run-cli.test.ts[886-946]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread bin/lcm.ts
}
}

if ((agent as any).id !== "codex" || agentName === undefined) continue;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

5. Codex health check skipped without explicit agent 🐞 Bug ≡ Correctness

The connectors doctor command's new Codex structural/functional check is guarded by `agentName ===
undefined, so running the documented broad lcm connectors doctor` (no agent argument) silently
skips both the exact PostToolUse structural inspection and the native-exec functional probe, even
though the loop still iterates Codex within the AGENTS list. This causes the new health
verification introduced by this PR to be effectively unreachable for the command's most common
invocation form.
Agent Prompt
## Issue description
The Codex-specific PostToolUse structural/functional health check added in this PR is skipped whenever `lcm connectors doctor` is invoked without an explicit agent name (broad mode over all agents), because of an added `agentName === undefined` condition in the skip check. This means the new diagnostics never run for the most common/documented usage of `lcm connectors doctor`.

## Issue Context
`agents` is populated with all agents (including Codex) when `agentName` is undefined (broad mode). The loop over `agents` should run the Codex-specific checks whenever the current `agent.id === "codex"`, regardless of whether the user passed an explicit agent name.

## Fix Focus Areas
- bin/lcm.ts[2394-2394]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +39 to +45
function normalizeStatus(toolOutput: unknown, toolResponse: unknown): { isError?: boolean } | undefined {
const outputStatus = isRecord(toolOutput) ? statusFromRecord(toolOutput) : undefined;
if (outputStatus !== undefined) return { isError: outputStatus };

const responseStatus = isRecord(toolResponse) ? statusFromRecord(toolResponse) : undefined;
return responseStatus === undefined ? undefined : { isError: responseStatus };
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Informational

6. Status precedence ignores tool_response when output invalid 🐞 Bug ≡ Correctness

normalizeStatus in post-tool-normalization.ts only checks statusFromRecord(toolOutput) and
falls back to toolResponse only when the *entire* output-derived status is undefined; but per
the documented policy this fallback should also occur when tool_output is a record with no valid
recognized field, which is exactly what happens — statusFromRecord returns undefined when no
field matches, so this path is actually followed correctly. However, the same function returns early
with the tool_output result even when it's a valid false/0, which is correct per docs ("A
valid false or zero value is authoritative"), so on closer inspection the implementation matches the
documented precedence rules; this specific concern converges to no defect and should not be
reported.

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.

Bug: Codex PostToolUse hook does not capture normal exec tool calls

2 participants