JSON-leak guard playground

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.

JSON leak (the bug) JSON array real path empty relative
What is happening?

      
// 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);
}