Type a value for CLAUDE_PROJECT_DIR. The simulator runs the
same checks the real OrchestKit hooks now do — safeProjectDir()
in src/hooks/src/lib/paths.ts and safeMkdirSync()
in src/hooks/src/lib/safe-fs.ts. The bug from
this PR
was that hook stdout JSON ended up in this env var and got passed straight
to fs.mkdirSync, creating a literal
{"continue":true,"suppressOutput":true}/ directory at the
project root.
// src/hooks/src/lib/paths.ts
function stripJsonLeak(value, fallback = '.') {
if (!value) return fallback;
if (value.startsWith('{') || value.startsWith('[')) return fallback;
return value;
}
export function safeProjectDir(candidate) {
if (candidate && !candidate.startsWith('{') && !candidate.startsWith('[')) {
return candidate;
}
const env = stripJsonLeak(process.env.CLAUDE_PROJECT_DIR, '');
return env || process.cwd();
}
// src/hooks/src/lib/safe-fs.ts — last-line defence
export function safeMkdirSync(path, options) {
if (!looksLikePath(path)) {
process.stderr.write(`[orchestkit] safeMkdirSync refused: ${JSON.stringify(path)}\n`);
return undefined; // fail closed, do NOT create the directory
}
return mkdirSync(path, options);
}