From 0da696eb6c7cbfa48742f66dade4bb6b38d67c4a Mon Sep 17 00:00:00 2001 From: Tom Boucher Date: Thu, 16 Apr 2026 17:13:44 -0400 Subject: [PATCH] fix(install): replace all ~/.claude/ paths in Codex .toml files (#2320) (#2325) * fix(install): replace all ~/.claude/ paths in generated Codex .toml files (#2320) installCodexConfig() only rewrote get-shit-done/-scoped paths; all other ~/.claude/ references (hooks, skills, configDir) leaked into generated .toml files unchanged. Add three additional regex replacements to catch $HOME/.claude/, ~/.claude/, and ./.claude/ patterns and rewrite them to .codex equivalents. Adds regression test PATHS-01. Closes #2320 Co-Authored-By: Claude Sonnet 4.6 * fix(install): handle bare .claude end-of-string and scan all .toml files (CR feedback) - Use capture group (\/|$) so replacements handle both ~/.claude/ and bare ~/.claude at end of string, not just the trailing-slash form - Expand PATHS-01 test to scan agents/*.toml + top-level config.toml - Broaden leak pattern to match ./.claude, ~, and $HOME variants with or without trailing slash Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: Claude Sonnet 4.6 --- bin/install.js | 6 ++++++ tests/codex-config.test.cjs | 28 ++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/bin/install.js b/bin/install.js index 8d5543107..969e1f9dd 100755 --- a/bin/install.js +++ b/bin/install.js @@ -3016,6 +3016,12 @@ function installCodexConfig(targetDir, agentsSrc) { // Replace full .claude/get-shit-done prefix so path resolves to codex GSD install content = content.replace(/~\/\.claude\/get-shit-done\//g, codexGsdPath); content = content.replace(/\$HOME\/\.claude\/get-shit-done\//g, codexGsdPath); + // Replace remaining .claude paths with .codex equivalents (#2320). + // Capture group handles both trailing-slash form (~/.claude/) and + // bare end-of-string form (~/.claude) in a single pass. + content = content.replace(/\$HOME\/\.claude(\/|$)/g, '$HOME/.codex$1'); + content = content.replace(/~\/\.claude(\/|$)/g, '~/.codex$1'); + content = content.replace(/\.\/\.claude(\/|$)/g, './.codex$1'); const { frontmatter } = extractFrontmatterAndBody(content); const name = extractFrontmatterField(frontmatter, 'name') || file.replace('.md', ''); const description = extractFrontmatterField(frontmatter, 'description') || ''; diff --git a/tests/codex-config.test.cjs b/tests/codex-config.test.cjs index 60f863dea..671b5266e 100644 --- a/tests/codex-config.test.cjs +++ b/tests/codex-config.test.cjs @@ -810,6 +810,34 @@ describe('installCodexConfig (integration)', () => { assert.ok(checkerToml.includes('name = "gsd-plan-checker"'), 'plan-checker has name'); assert.ok(checkerToml.includes('sandbox_mode = "read-only"'), 'plan-checker is read-only'); }); + + // PATHS-01: no ~/.claude references should leak into generated .toml files (#2320) + // Covers both trailing-slash and bare end-of-string forms, and scans all .toml + // files (agents/ subdirectory + top-level config.toml if present). + (hasAgents ? test : test.skip)('generated .toml files contain no leaked ~/.claude paths (PATHS-01)', () => { + const { installCodexConfig } = require('../bin/install.js'); + installCodexConfig(tmpTarget, agentsSrc); + + // Collect all .toml files: per-agent files in agents/ plus top-level config.toml + const agentsDir = path.join(tmpTarget, 'agents'); + const tomlFiles = fs.readdirSync(agentsDir) + .filter(f => f.endsWith('.toml')) + .map(f => path.join(agentsDir, f)); + const topLevel = path.join(tmpTarget, 'config.toml'); + if (fs.existsSync(topLevel)) tomlFiles.push(topLevel); + assert.ok(tomlFiles.length > 0, 'at least one .toml file generated'); + + // Match ~/.claude, $HOME/.claude, or ./.claude with or without trailing slash + const leakPattern = /(?:~|\$HOME|\.)\/\.claude(?:\/|$)/; + const leaks = []; + for (const filePath of tomlFiles) { + const content = fs.readFileSync(filePath, 'utf8'); + if (leakPattern.test(content)) { + leaks.push(path.relative(tmpTarget, filePath)); + } + } + assert.deepStrictEqual(leaks, [], `No .toml files should contain .claude paths; found leaks in: ${leaks.join(', ')}`); + }); }); // ─── Codex config.toml [features] safety (#1202) ─────────────────────────────