fix(cli): all LLM CLIs spawn in temp staging dir instead of user's working directory#157
fix(cli): all LLM CLIs spawn in temp staging dir instead of user's working directory#157
Conversation
Agent-Logs-Url: https://github.com/microsoft/PromptKit/sessions/95707a0f-de3a-4112-87d9-3b326e318d4c Co-authored-by: abeltrano <2082148+abeltrano@users.noreply.github.com>
- In launch.js, capture originalCwd = process.cwd() before staging content - Spawn claude with cwd: originalCwd (user's dir) instead of tmpDir - Pass absolute path to bootstrap.md so claude can find staged content - Add REQ-CLI-024 and update REQ-CLI-015/016/017 in requirements.md - Add TC-CLI-082 in validation.md and traceability matrix - Add automated TC-CLI-082 test in launch.test.js Agent-Logs-Url: https://github.com/microsoft/PromptKit/sessions/95707a0f-de3a-4112-87d9-3b326e318d4c Co-authored-by: abeltrano <2082148+abeltrano@users.noreply.github.com>
…for all CLIs - launch.js: all CLIs spawn with cwd: originalCwd; all get --add-dir tmpDir; all use absolute path to bootstrap.md. Remove per-CLI spawnCwd variation. - requirements.md: REQ-CLI-015/016/017 unified; REQ-CLI-024 extended to all CLIs; add REQ-CLI-025 (--add-dir for staging dir). - validation.md: TC-CLI-080/081/082 updated; add TC-CLI-083; update traceability. - launch.test.js: TC-CLI-082/083 combined parameterized tests for claude and copilot verifying cwd + --add-dir; TC-CLI-080/081 updated. Agent-Logs-Url: https://github.com/microsoft/PromptKit/sessions/2aa941b1-bf52-44c8-8b39-455117a46247 Co-authored-by: abeltrano <2082148+abeltrano@users.noreply.github.com>
…case, normalize CRLF → LF) Agent-Logs-Url: https://github.com/microsoft/PromptKit/sessions/d1cc34e5-c022-40a0-a5eb-c6e39ad08113 Co-authored-by: abeltrano <2082148+abeltrano@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Fixes PromptKit CLI interactive launch so spawned LLM CLIs start in the user’s original working directory (instead of the temp staging dir), while still granting access to staged PromptKit content via --add-dir and using an absolute bootstrap.md path.
Changes:
- Update
launchInteractive()to preserve the user’s CWD, switch bootstrap prompt to an absolute staged path, and add--add-dir <tmpDir>for supported CLIs. - Update CLI requirements/validation specs to codify the CWD preservation +
--add-dirbehavior. - Add launch-module tests covering CWD preservation and presence of
--add-dir.
Reviewed changes
Copilot reviewed 4 out of 6 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| docs/case-studies/ebpf-epoch.md | Housekeeping/normalization of a case study doc (formatting/line endings). |
| cli/lib/launch.js | Spawn child CLIs with cwd: originalCwd, absolute bootstrap path, and --add-dir <tmpDir>. |
| cli/tests/launch.test.js | Adds tests for absolute bootstrap prompt, preserved CWD, and --add-dir. |
| cli/specs/requirements.md | Updates/extends requirements for CWD preservation + --add-dir staging access. |
| cli/specs/validation.md | Updates validation cases and traceability for new/updated requirements. |
| cli/package-lock.json | Version bump reflected in lockfile. |
Files not reviewed (1)
- cli/package-lock.json: Language not supported
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
- Quote process.execPath in POSIX mock wrapper using JSON.stringify to handle paths with spaces - Fix misleading comment claiming createCapturingMock returns a cleanup function when it returns nothing - Use envWithPath() helper in runAndCapture() instead of manual spread to properly normalize PATH casing on Windows - Add gh-copilot to integration test loop so TC-CLI-082/083 covers all supported CLIs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Rename TC-CLI-080/081 test to reflect actual scope (export/source checks) and add comment clarifying that spawn arg validation is covered by TC-CLI-082/083 integration tests - Update requirements.md frontmatter version 0.3.0 -> 0.4.0 and date to 2026-03-31 to match latest revision history entry - Update validation.md frontmatter version 0.3.0 -> 0.4.0 and date to 2026-03-31 to match latest revision history entry Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Review: PR #157 — CWD preservation for LLM CLIsOverallThe core fix in 🔴 All 3 new integration tests fail on WindowsRunning Root cause: The tests create mock CLI executables as The result: the Empirical verificationI tested all three behaviors independently on this machine:
Test script: const { execFileSync, spawn } = require('child_process');
const fs = require('fs');
const path = require('path');
const os = require('os');
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'spawn-test-'));
fs.writeFileSync(path.join(tmpDir, 'fakecli.cmd'), '@echo FOUND_ME\r\n');
// 'where' finds .cmd files
execFileSync('where', ['fakecli'], {
env: { ...process.env, PATH: tmpDir + ';' + process.env.PATH },
encoding: 'utf8'
});
// => "C:\Users\...\spawn-test-xxx\fakecli.cmd"
// spawn WITHOUT shell: true — FAILS
spawn('fakecli', [], { env: { ...process.env, PATH: tmpDir }, stdio: 'pipe' });
// => error event: ENOENT
// spawn WITH shell: true — WORKS
spawn('fakecli', [], { env: { ...process.env, PATH: tmpDir }, stdio: 'pipe', shell: true });
// => exits 0, output: "FOUND_ME"Detection-vs-execution mismatch (pre-existing)This also reveals a pre-existing issue in On this machine all three CLIs are But npm global installs on Windows produce Suggested fixAdding const child = spawn(cmd, args, {
cwd: originalCwd,
stdio: "inherit",
shell: true, // Required on Windows to resolve .cmd/.bat files
});The args are all programmatically constructed (no user input), so there's no shell-injection risk. 🟡 Minor: Traceability matrix orderingIn ℹ️ Notes
|
spawn() on Windows cannot execute .cmd/.bat files without shell: true. This caused TC-CLI-082/083 integration tests to fail (mock .cmd wrappers were invisible to spawn) and was also a pre-existing production issue where CLIs installed via npm global (which produce .cmd wrappers) would be detected by detectCli() but fail to launch. All spawn args are programmatically constructed with no user input, so there is no shell-injection risk. Also fix traceability matrix ordering in validation.md: move REQ-CLI-024/025 after REQ-CLI-023 for sequential consistency. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Both items addressed in 7797ba0: 🔴 Windows .cmd spawn failure (TC-CLI-082/083)Added
All spawn args are programmatically constructed (no user input), so there is no shell-injection risk. All 27 tests now pass (including the 3 previously-failing TC-CLI-082/083 integration tests). 🟡 Traceability matrix orderingMoved REQ-CLI-024/025 after REQ-CLI-023 so the table follows sequential REQ numbering. |
Problem
Fixes #156 — Launching LLM CLI does not preserve current working directory
When running
npx @alan-jowett/promptkit --cli claude(or any non-Copilot CLI), the LLM session started in the temporary staging directory (/tmp/promptkit-xxx/) instead of the user's actual working directory. This meant the LLM had no awareness of the user's project files and could not operate on their codebase.Root cause:
launch.jsspawned all CLI child processes withcwd: tmpDir— the temporary directory where PromptKit content files are staged. The Copilot CLI happened to work around this because it resolved the working directory differently, but Claude and other CLIs honored the spawncwdliterally.Additionally, the bootstrap prompt used a relative path (
"Read and execute bootstrap.md"), which only resolved correctly whencwdwas the staging directory. Changingcwdto the user's directory required switching to an absolute path.Fix
Core change (
cli/lib/launch.js)originalCwd— recordprocess.cwd()before any directory changes.cwd: originalCwd— all CLI child processes now start in the user's working directory instead of the temp staging dir."Read and execute /tmp/promptkit-xxx/bootstrap.md"(absolute), so the LLM can locate it regardless of working directory.--add-dir <tmpDir>— all CLIs (copilot, gh-copilot, claude) receive--add-dirpointing at the staging directory, granting file access to PromptKit content without requiringcwdto be set there.Spec updates (
cli/specs/requirements.md)cwdmust be the user's original directory (not temp dir).bootstrap.md.--add-dir <tmpDir>and absolute bootstrap path.--add-dirstaging directory requirement for all CLIs.Validation updates (
cli/specs/validation.md)--add-dirand absolute path.--add-diris in spawn args.Tests (
cli/tests/launch.test.js)--add-dirbehaviors.Housekeeping
docs/case-studies/ebpf_epoch.md→docs/case-studies/ebpf-epoch.md(snake_case → kebab-case filename convention; also fixes CRLF line endings via.gitattributesnormalization).0.2.0→0.5.0inpackage-lock.json.Changed Files
cli/lib/launch.js--add-dircli/specs/requirements.mdcli/specs/validation.mdcli/tests/launch.test.jscli/package-lock.jsondocs/case-studies/ebpf-epoch.mdebpf_epoch.md(kebab-case + LF fix)