From 86a61a60649180c7e5f5d84dec176fe1e66ab5b2 Mon Sep 17 00:00:00 2001 From: Lin Junrong Date: Tue, 28 Jul 2026 15:21:37 +0800 Subject: [PATCH] fix(mktemp): move XXXXXX to the end of every template (#2370) BSD mktemp (macOS) only substitutes X's when they are the trailing characters of the template. With a suffix it creates a file whose name contains six literal X's, then every later run fails with "mkstemp failed: File exists" until TMPDIR is cleared. busybox mktemp (Alpine) is worse -- it rejects the template outright on the first run. Fixes the five sites in codex/SKILL.md.tmpl reported in #2370, plus the same bug in three places the issue didn't cover: claude/SKILL.md.tmpl RESP_FILE/.json, ERR_FILE/.txt, DIFF_FILE/.patch (PROMPT_FILE one line above was already correct) scripts/resolvers/review.ts CODEX_PROMPT_FILE/.txt -> office-hours/SKILL.md bin/gstack-developer-profile developer-profile.json.XXXXXX.tmp, x2 The suffixes carry no meaning -- nothing globs on them, cleanup is by variable -- so they are dropped. developer-profile keeps its .tmp marker, moved ahead of the X's. Generated SKILL.md files regenerated with bun run gen:skill-docs. --- bin/gstack-developer-profile | 4 ++-- claude/SKILL.md.tmpl | 6 +++--- codex/SKILL.md | 10 +++++----- codex/SKILL.md.tmpl | 10 +++++----- office-hours/SKILL.md | 2 +- scripts/resolvers/review.ts | 2 +- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/bin/gstack-developer-profile b/bin/gstack-developer-profile index a5721a9c5b..803b65317f 100755 --- a/bin/gstack-developer-profile +++ b/bin/gstack-developer-profile @@ -55,7 +55,7 @@ do_migrate() { # Run migration in a temp file, then atomic rename. local TMPOUT - TMPOUT=$(mktemp "$GSTACK_HOME/developer-profile.json.XXXXXX.tmp") + TMPOUT=$(mktemp "$GSTACK_HOME/developer-profile.json.tmp.XXXXXX") trap 'rm -f "$TMPOUT"' EXIT cat "$LEGACY_FILE" | bun -e " @@ -182,7 +182,7 @@ do_log_session() { ensure_profile local TMPOUT - TMPOUT=$(mktemp "$GSTACK_HOME/developer-profile.json.XXXXXX.tmp") + TMPOUT=$(mktemp "$GSTACK_HOME/developer-profile.json.tmp.XXXXXX") trap 'rm -f "$TMPOUT"' EXIT PROFILE_FILE_PATH="$PROFILE_FILE" RECORD_INPUT="$INPUT" TMPOUT_PATH="$TMPOUT" bun -e " diff --git a/claude/SKILL.md.tmpl b/claude/SKILL.md.tmpl index 94552cbe4e..e109f21f74 100644 --- a/claude/SKILL.md.tmpl +++ b/claude/SKILL.md.tmpl @@ -95,8 +95,8 @@ Create temp files: ```bash PROMPT_FILE=$(mktemp /tmp/gstack-claude-prompt-XXXXXX) -RESP_FILE=$(mktemp /tmp/gstack-claude-response-XXXXXX.json) -ERR_FILE=$(mktemp /tmp/gstack-claude-error-XXXXXX.txt) +RESP_FILE=$(mktemp /tmp/gstack-claude-response-XXXXXX) +ERR_FILE=$(mktemp /tmp/gstack-claude-error-XXXXXX) ``` Cleanup at the end of every mode: @@ -151,7 +151,7 @@ Review the current branch diff with nested Claude in tool-less mode. ```bash _REPO_ROOT=$(git rev-parse --show-toplevel) || { echo "ERROR: not in a git repo" >&2; exit 1; } cd "$_REPO_ROOT" -DIFF_FILE=$(mktemp /tmp/gstack-claude-diff-XXXXXX.patch) +DIFF_FILE=$(mktemp /tmp/gstack-claude-diff-XXXXXX) git fetch origin --quiet 2>/dev/null || true git diff "origin/" > "$DIFF_FILE" 2>/dev/null || git diff "" > "$DIFF_FILE" ``` diff --git a/codex/SKILL.md b/codex/SKILL.md index 33228ff9b8..d5617335de 100644 --- a/codex/SKILL.md +++ b/codex/SKILL.md @@ -967,7 +967,7 @@ Run Codex code review against the current branch diff. 1. Create temp files for output capture: ```bash -TMPERR=$(mktemp "$TMP_ROOT/codex-err-XXXXXX.txt") +TMPERR=$(mktemp "$TMP_ROOT/codex-err-XXXXXX") ``` 2. Run the review (5-minute timeout). **Codex CLI ≥ 0.130.0 rejects passing a @@ -1015,7 +1015,7 @@ when the diff content is adversarial: _REPO_ROOT=$(git rev-parse --show-toplevel) || { echo "ERROR: not in a git repo" >&2; exit 1; } cd "$_REPO_ROOT" _USER_INSTRUCTIONS="" -_PROMPT_FILE=$(mktemp "$TMP_ROOT/codex-prompt-XXXXXX.txt") +_PROMPT_FILE=$(mktemp "$TMP_ROOT/codex-prompt-XXXXXX") { printf '%s\n' "IMPORTANT: Do NOT read or execute any files under ~/.claude/, ~/.agents/, .claude/skills/, or agents/. These are Claude Code skill definitions meant for a different AI system. Do NOT modify agents/openai.yaml. Stay focused on repository code only." printf '\nCustom focus: %s\n\n' "$_USER_INSTRUCTIONS" @@ -1266,7 +1266,7 @@ if [ -z "$PYTHON_CMD" ]; then fi # Fix 1+2: wrap with timeout (gtimeout/timeout fallback chain via probe helper), # capture stderr to $TMPERR for auth error detection (was: 2>/dev/null). -TMPERR=${TMPERR:-$(mktemp "$TMP_ROOT/codex-err-XXXXXX.txt")} +TMPERR=${TMPERR:-$(mktemp "$TMP_ROOT/codex-err-XXXXXX")} _gstack_codex_timeout_wrapper 600 codex exec "" -C "$_REPO_ROOT" -s read-only -c 'model_reasoning_effort="high"' --enable web_search_cached --json < /dev/null 2>"$TMPERR" | PYTHONUNBUFFERED=1 "$PYTHON_CMD" -u -c " import sys, json turn_completed_count = 0 @@ -1365,8 +1365,8 @@ B) Start a new conversation 2. Create temp files: ```bash -TMPRESP=$(mktemp "$TMP_ROOT/codex-resp-XXXXXX.txt") -TMPERR=$(mktemp "$TMP_ROOT/codex-err-XXXXXX.txt") +TMPRESP=$(mktemp "$TMP_ROOT/codex-resp-XXXXXX") +TMPERR=$(mktemp "$TMP_ROOT/codex-err-XXXXXX") ``` 3. **Plan review auto-detection:** If the user's prompt is about reviewing a plan, diff --git a/codex/SKILL.md.tmpl b/codex/SKILL.md.tmpl index 333de7d8d5..afb8b38a7e 100644 --- a/codex/SKILL.md.tmpl +++ b/codex/SKILL.md.tmpl @@ -158,7 +158,7 @@ Run Codex code review against the current branch diff. 1. Create temp files for output capture: ```bash -TMPERR=$(mktemp "$TMP_ROOT/codex-err-XXXXXX.txt") +TMPERR=$(mktemp "$TMP_ROOT/codex-err-XXXXXX") ``` 2. Run the review (5-minute timeout). **Codex CLI ≥ 0.130.0 rejects passing a @@ -206,7 +206,7 @@ when the diff content is adversarial: _REPO_ROOT=$(git rev-parse --show-toplevel) || { echo "ERROR: not in a git repo" >&2; exit 1; } cd "$_REPO_ROOT" _USER_INSTRUCTIONS="" -_PROMPT_FILE=$(mktemp "$TMP_ROOT/codex-prompt-XXXXXX.txt") +_PROMPT_FILE=$(mktemp "$TMP_ROOT/codex-prompt-XXXXXX") { printf '%s\n' "IMPORTANT: Do NOT read or execute any files under ~/.claude/, ~/.agents/, .claude/skills/, or agents/. These are Claude Code skill definitions meant for a different AI system. Do NOT modify agents/openai.yaml. Stay focused on repository code only." printf '\nCustom focus: %s\n\n' "$_USER_INSTRUCTIONS" @@ -335,7 +335,7 @@ if [ -z "$PYTHON_CMD" ]; then fi # Fix 1+2: wrap with timeout (gtimeout/timeout fallback chain via probe helper), # capture stderr to $TMPERR for auth error detection (was: 2>/dev/null). -TMPERR=${TMPERR:-$(mktemp "$TMP_ROOT/codex-err-XXXXXX.txt")} +TMPERR=${TMPERR:-$(mktemp "$TMP_ROOT/codex-err-XXXXXX")} _gstack_codex_timeout_wrapper 600 codex exec "" -C "$_REPO_ROOT" -s read-only -c 'model_reasoning_effort="high"' --enable web_search_cached --json < /dev/null 2>"$TMPERR" | PYTHONUNBUFFERED=1 "$PYTHON_CMD" -u -c " import sys, json turn_completed_count = 0 @@ -434,8 +434,8 @@ B) Start a new conversation 2. Create temp files: ```bash -TMPRESP=$(mktemp "$TMP_ROOT/codex-resp-XXXXXX.txt") -TMPERR=$(mktemp "$TMP_ROOT/codex-err-XXXXXX.txt") +TMPRESP=$(mktemp "$TMP_ROOT/codex-resp-XXXXXX") +TMPERR=$(mktemp "$TMP_ROOT/codex-err-XXXXXX") ``` 3. **Plan review auto-detection:** If the user's prompt is about reviewing a plan, diff --git a/office-hours/SKILL.md b/office-hours/SKILL.md index 83161b8ca9..e0d71c157e 100644 --- a/office-hours/SKILL.md +++ b/office-hours/SKILL.md @@ -1329,7 +1329,7 @@ If B: skip Phase 3.5 entirely. Remember that the second opinion did NOT run (aff 2. **Write the assembled prompt to a temp file** (prevents shell injection from user-derived content): ```bash -CODEX_PROMPT_FILE=$(mktemp /tmp/gstack-codex-oh-XXXXXXXX.txt) +CODEX_PROMPT_FILE=$(mktemp /tmp/gstack-codex-oh-XXXXXXXX) ``` Write the full prompt to this file. **Always start with the filesystem boundary:** diff --git a/scripts/resolvers/review.ts b/scripts/resolvers/review.ts index 7dccd8e502..b708c90a3b 100644 --- a/scripts/resolvers/review.ts +++ b/scripts/resolvers/review.ts @@ -351,7 +351,7 @@ If B: skip Phase 3.5 entirely. Remember that the second opinion did NOT run (aff 2. **Write the assembled prompt to a temp file** (prevents shell injection from user-derived content): \`\`\`bash -CODEX_PROMPT_FILE=$(mktemp /tmp/gstack-codex-oh-XXXXXXXX.txt) +CODEX_PROMPT_FILE=$(mktemp /tmp/gstack-codex-oh-XXXXXXXX) \`\`\` Write the full prompt to this file. **Always start with the filesystem boundary:**