Skip to content

OMO LSP post-tool-use hook blocks every edit of files outside the session cwd with 'LSP file path must be inside request cwd' #154

Description

@THRILLUV

Summary

Every edit to a file outside the Codex session cwd makes the OMO LSP PostToolUse hook emit a blocking feedback block LSP file path must be inside request cwd: <file> instead of running diagnostics, so the model sees this noise (twice per edit in this session) and never gets real diagnostics for the edited file.

Environment

  • LazyCodex version: lazycodex-ai 4.19.4 (plugin cache ~/.codex/plugins/cache/sisyphuslabs/omo/4.19.4; same code present in code-yeongyu/lazycodex@main)
  • Codex version: codex-cli 0.146.1
  • OS: Linux x86_64 (WSL2), Node v22.23.1
  • Install method: installed Codex plugin (OMO 4.19.4)
  • Relevant config: session cwd = /home/th930/Projects/Aoom_HOME/runtime/state/companies/02_Definish/04_agents/00_D-CEO; edited files under /home/th930/Projects/Aoom_HOME/runtime/state/companies/02_Definish/01_repo/00_main/... (outside session cwd)

Repository Decision

  • Target repository: code-yeongyu/lazycodex
  • Why this belongs there: the failing surface is the bundled OMO codex-lsp hook CLI (plugins/omo/components/lsp@code-yeongyu/codex-lsp) and its lsp-daemon path validation, both distributed by LazyCodex. Clean upstream Codex contains no omo-lsp / codex-lsp / lsp-daemon code.
  • LazyCodex evidence (runtime + $LAZYCODEX_SOURCE_ROOT/lazycodex-source):
    • Repro (see below) reproduces with the shipped bundled CLI at ~/.codex/plugins/cache/sisyphuslabs/omo/4.19.4/components/lsp/dist/cli.js, and the same code exists in lazycodex-source/plugins/omo/components/lsp/dist/cli.js (4.19.4, current main).
    • Hook entry: plugins/omo/components/lsp/src/codex-hook.tsrunLspDiagnosticsTextcallDiagnosticsViaDaemon(filePath, { context: codexLspRequestContext() }); codexLspRequestContext() builds the LSP request context from process.cwd() (line ~94: cwd: canonicalCwd where canonicalCwd = realpathSync(resolve(cwd)) with cwd = process.cwd()).
    • Daemon rejects paths outside that cwd: resolvePathInsideContextif (!isPathInside(cwd, canonical)) throw new LspInvalidPathError(\LSP file path must be inside request cwd: ${filePath}`)` (dist line 4123-4130).
    • The hook then wraps the thrown error as a blocking block: runLspPostToolUseHook returns { decision: "block", reason: "LSP diagnostics after editing <file>:\n\n<error>" } (codex-hook.ts lines 115-127).
  • Upstream Codex source evidence from $LAZYCODEX_SOURCE_ROOT/openai-codex-source:
    • Codex core runs each hook process with .current_dir(cwd) where cwd is PostToolUseRequest.cwd, the session working directory (codex-rs/hooks/src/engine/command_runner.rs:62; codex-rs/hooks/src/events/post_tool_use.rs:29 + :111).
    • No omo-lsp, codex-lsp, lsp-daemon, or LSP path validation exists in openai/codex. The bug disappears in clean upstream Codex because the hook itself is LazyCodex-owned.

Reproduction

  1. Start a Codex session whose cwd is NOT an ancestor of the file to edit (e.g. session cwd .../04_agents/00_D-CEO, target file .../01_repo/00_main/apps/webapp/src/App.tsx).
  2. Edit the target file with a mutation tool (e.g. apply_patch).
  3. Observe the injected hook feedback.

Minimal standalone repro (no real edit required; feeds the same payload shape the hook consumes):

cd /home/th930/Projects/Aoom_HOME/runtime/state/companies/02_Definish/04_agents/00_D-CEO
node -e "
const { spawnSync } = require('child_process');
const payload = {
  session_id: 'test-session',
  tool_name: 'apply_patch',
  tool_input: {
    input: '*** Begin Patch\n*** Update File: /home/th930/Projects/Aoom_HOME/runtime/state/companies/02_Definish/01_repo/00_main/apps/webapp/src/App.tsx\n*** End Patch'
  },
  tool_response: { isError: false },
};
const cli = '/home/th930/.codex/plugins/cache/sisyphuslabs/omo/4.19.4/components/lsp/dist/cli.js';
const res = spawnSync('node', [cli, 'hook', 'post-tool-use'], { input: JSON.stringify(payload), encoding: 'utf8', timeout: 30000 });
console.log('EXIT:', res.status);
console.log('STDOUT:', res.stdout);
"

Expected Behavior

  • Editing a file anywhere the agent legitimately touches (monorepo subdirectories, sibling projects, worktrees outside the session root) should run diagnostics for that file, or silently skip when no language server is configured.
  • A path outside the session cwd should not be reported as a blocking "LSP diagnostics after editing" failure on every edit.

Actual Behavior

The hook emits a blocking block on every such edit:

LSP diagnostics after editing /home/th930/Projects/Aoom_HOME/runtime/state/companies/02_Definish/01_repo/00_main/apps/webapp/src/App.tsx:

LSP file path must be inside request cwd: /home/th930/Projects/Aoom_HOME/runtime/state/companies/02_Definish/01_repo/00_main/apps/webapp/src/App.tsx

Observed twice per edit in this session (each apply_patch triggers the feedback twice), with no real diagnostics ever produced. A control case editing a file inside the session cwd produces empty output (no block).

Evidence

  • Repro output (above): exit 0, stdout contains the exact blocking JSON with decision: "block" and the LspInvalidPathError text.
  • Control: same payload with a file inside the session cwd (.../04_agents/00_D-CEO/HANDOFF.md) yields empty stdout (no block).
  • Session log: the identical message was injected after every apply_patch in this thread (e.g. after edits to apps/webapp/src/lib/auth-proxy.test.ts, apps/webapp/src/pages/History.route-a11y.test.tsx, apps/webapp/src/components/AppShell.tsx), with the hook output saved under /tmp/hook_outputs/019fd769-a648-7451-b165-387c00547aa1/.

Root Cause

codexLspRequestContext() in plugins/omo/components/lsp/src/codex-hook.ts hardcodes the hook's own process cwd as the LSP request cwd:

export function codexLspRequestContext(
  env = process.env,
  cwd: string = process.cwd(),
): LspRequestContext {
  const canonicalCwd = realpathSync(resolve(cwd));
  ...
  return parseLspRequestContext({ cwd: canonicalCwd, ... });
}

Codex launches hooks with current_dir(PostToolUseRequest.cwd) (openai-codex-source/codex-rs/hooks/src/engine/command_runner.rs:62), so process.cwd() equals the session cwd. The daemon then enforces that every edited file lives inside that cwd (resolvePathInsideContext, dist line 4123-4130). Editing a file outside the session cwd therefore always throws, and runLspPostToolUseHook surfaces the throw as a blocking diagnostics block instead of treating it as "no diagnostics available".

The cwd restriction is reasonable for daemon path safety, but the hook must not (a) derive the LSP context from the hook process cwd when the edited file is outside it, and (b) must not surface an LspInvalidPathError as a blocking diagnostics failure.

Proposed Fix

In plugins/omo/components/lsp/src/codex-hook.ts (or the lsp-core post-edit collector):

  1. Resolve each mutated file path relative to a context cwd that actually contains it, or pass an explicit context whose cwd is the common ancestor of the edited files, instead of blindly using process.cwd().
  2. Treat LspInvalidPathError (and any "outside cwd" failure) as a non-blocking "skipped" outcome in collectPostEditDiagnostics / runLspPostToolUseHook — filter it out like the existing isLspDaemonUnreachableDiagnostics filter (codex-hook.ts line 113) — so legitimate edits outside the session cwd do not inject noise and do not suppress diagnostics for in-cwd files.

Likely files:

  • plugins/omo/components/lsp/src/codex-hook.ts (codexLspRequestContext, runLspPostToolUseHook filter)
  • plugins/omo/components/lsp/src/codex-hook-cli.ts (hook stdin wiring)
  • lsp-core post-edit collector (collectPostEditDiagnostics) and the daemon resolvePathInsideContext error handling in lsp-daemon

Verification Plan

  • Repro check that fails before the fix: run the standalone repro above; assert stdout contains LSP file path must be inside request cwd.
  • Fix check: same repro with a file outside the session cwd now yields empty stdout (no block) or real diagnostics; a file inside the cwd still yields diagnostics when a language server is configured.
  • Regression check: edits inside the session cwd still produce normal post-edit diagnostics; no new blocking noise is injected for any mutation tool.

This issue or PR was generated by LazyCodex.
Tag: lazycodex-generated

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions