Repository navigation
Description
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:
- Start the madz TUI.
- Open the
/projectspanel and select a project (a subdirectory underprojects/). - Observe that the process working directory is not changed to the selected project.
- Select "(clear active project)".
- 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— callssetActiveProject(projectPath)andsetProjectCwd(projectPath)but neverprocess.chdir(projectPath). The OS process cwd is left at the original root. This is the primary bug. - src/tui/app.js:184-190
handleClearProject— callssetActiveProject("")andsetProjectCwd("")but never restores the process cwd.configis already a prop ofApp, so the restore target isconfig.cwd(withprocess.cwd()fallback). - src/tui/app.js:339-346
handleNewSession— also resetssetActiveProject("")but does not touch the process cwd. Judgment call: decide whether a new session should likewise restore the process cwd toconfig.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 laterprocess.chdir. Even with the fix, this snapshot will not track a runtime cwd change; callers must passtargetCwdexplicitly. 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.chdirthrows on an invalid target path. The fix must wrap each call in try/catch with a structured logger — no silent catch.
Fix Steps
- Locate the bug — Open
src/tui/app.jsand findhandleSelectProject(lines 166-178) andhandleClearProject(lines 184-190). - Add chdir on select — In
handleSelectProject, aftersetProjectCwd(projectPath), add a guardedprocess.chdir(projectPath)(try/catch + structured logger per AGENTS.md 1.1). - Add chdir on clear — In
handleClearProject, aftersetProjectCwd(""), add a guardedprocess.chdir(config.cwd || process.cwd()). - Decide handleNewSession — Determine whether
handleNewSession(lines 339-346) should also restore the process cwd toconfig.cwd; if yes, apply the same guarded pattern. - Add a regression test — Create
tests/unit/tui/app.test.jsassertingprocess.cwd()reflects the selected project afterhandleSelectProjectand is restored toconfig.cwdafterhandleClearProject; cover the invalid-path case (chdir throws, logger records, no crash). - Verify — Run
npm run testandnpm run coverageto confirm no regressions.
Activity
fix: wire TUI process cwd to active project
avoidwork commentedon Nov 1, 2026
Fixed in #1632.