Skip to content

fix: process cwd not updated on /projects select/clear #1629

Closed

Description

@avoidwork

Summary

The TUI's /projects panel does not update the process working directory. When the user selects a project, handleSelectProject sets the in-memory active-project state but never calls process.chdir(), so the OS process cwd stays at the madz root. When the user clears the project, handleClearProject likewise never restores the process cwd. Code that reads process.cwd() directly therefore runs in the wrong directory.

Environment

  • OS: Linux 7.0.14-linuxkit
  • Node.js: v26.13.0
  • madz version: 1.129.3
  • LLM provider: Unknown — user to confirm

Reproduction

Steps to reproduce the behavior:

  1. Start the madz TUI.
  2. Open the /projects panel and select a project (a subdirectory under projects/).
  3. Observe that the process working directory is not changed to the selected project.
  4. Select "(clear active project)".
  5. Observe that the process working directory is not restored to the original root.

Expected Behavior

Selecting a project should move the process cwd into the project directory; clearing the project should restore it to config.cwd (the madz root). Consumers of process.cwd() should reflect the active project.

Actual Behavior

handleSelectProject and handleClearProject update the in-memory active-project state (setActiveProject, setProjectCwd) but never call process.chdir. The process cwd remains at the original root throughout, so consumers of process.cwd() run in the wrong directory.

Additional Context

Consumers that read process.cwd() directly: src/workspace/loadAgents.js:5 (snapshots the cwd at module-load time) and the cron command builders src/scheduler/cron.js:14,509 and src/tools/cron/index.js:285, which embed cd ${process.cwd()}. These run in the wrong directory until the fix is applied.

Root Cause Analysis

src/tui/app.js handleSelectProject (lines 166-178) and handleClearProject (lines 184-190) call setProjectCwd but omit process.chdir. The fix is to add a guarded process.chdir(projectPath) on select and process.chdir(config.cwd || process.cwd()) on clear. Note: src/workspace/loadAgents.js:5 snapshots process.cwd() at module load, so a runtime chdir alone will not make it track the active project — callers must pass targetCwd explicitly.

Testing Strategy

Add a regression test asserting process.cwd() reflects the selected project after handleSelectProject and is restored to config.cwd after handleClearProject, plus the invalid-path case (chdir throws, is logged, and does not crash).

Security Considerations

process.chdir throws on an invalid target path. The fix must guard each call with try/catch and a structured logger (AGENTS.md 1.1 — no silent catch). No credential or auth surface is affected.

Audit Findings (for Issue 1629)

  • src/tui/app.js:166-178 handleSelectProject — calls setActiveProject(projectPath) and setProjectCwd(projectPath) but never process.chdir(projectPath). The OS process cwd is left at the original root. This is the primary bug.
  • src/tui/app.js:184-190 handleClearProject — calls setActiveProject("") and setProjectCwd("") but never restores the process cwd. config is already a prop of App, so the restore target is config.cwd (with process.cwd() fallback).
  • src/tui/app.js:339-346 handleNewSession — also resets setActiveProject("") but does not touch the process cwd. Judgment call: decide whether a new session should likewise restore the process cwd to config.cwd. Flagged here, not decided.
  • src/workspace/loadAgents.js:5 const cwd = process.cwd(); — captured at module-load time (top-level const), so it reflects the cwd only at import, not after a later process.chdir. Even with the fix, this snapshot will not track a runtime cwd change; callers must pass targetCwd explicitly. Note this when wiring the fix.
  • src/scheduler/cron.js:14, 509 and src/tools/cron/index.js:285 — cron command builders embed cd ${process.cwd()}. These read the live process cwd at build time, so they run in the wrong directory until the fix is applied.
  • Guard requirement (AGENTS.md 1.1): process.chdir throws on an invalid target path. The fix must wrap each call in try/catch with a structured logger — no silent catch.

Fix Steps

  1. Locate the bug — Open src/tui/app.js and find handleSelectProject (lines 166-178) and handleClearProject (lines 184-190).
  2. Add chdir on select — In handleSelectProject, after setProjectCwd(projectPath), add a guarded process.chdir(projectPath) (try/catch + structured logger per AGENTS.md 1.1).
  3. Add chdir on clear — In handleClearProject, after setProjectCwd(""), add a guarded process.chdir(config.cwd || process.cwd()).
  4. Decide handleNewSession — Determine whether handleNewSession (lines 339-346) should also restore the process cwd to config.cwd; if yes, apply the same guarded pattern.
  5. Add a regression test — Create tests/unit/tui/app.test.js asserting process.cwd() reflects the selected project after handleSelectProject and is restored to config.cwd after handleClearProject; cover the invalid-path case (chdir throws, logger records, no crash).
  6. Verify — Run npm run test and npm run coverage to confirm no regressions.

Activity

  1. added
    bugSomething isn't working
    approvedAn identifier for Madz to take action.
    and removed
    approvedAn identifier for Madz to take action.
    on Nov 1, 2026
  2. added a commit that references this issue on Nov 1, 2026
    acd1b39
  3. avoidwork commented on Nov 1, 2026

    @avoidwork
    OwnerAuthor

    Fixed in #1632.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    approvedAn identifier for Madz to take action.bugSomething isn't workingin progress

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions