From 77dfd2e0689940890e1c32c399a60017ec0c6b86 Mon Sep 17 00:00:00 2001 From: Tibsfox Date: Sat, 28 Feb 2026 05:40:27 -0800 Subject: [PATCH] fix(opencode): detect runtime config directory instead of hardcoding .claude Three files had hardcoded `.claude` paths that break OpenCode and Gemini installations where the config directory is `.config/opencode`, `.opencode`, or `.gemini` respectively. Changes: - hooks/gsd-check-update.js: add detectConfigDir() helper that checks all runtime directories for get-shit-done/VERSION, falling back to .claude. Used for cache dir, project VERSION, and global VERSION. - commands/gsd/reapply-patches.md: detect runtime directory for both global and local patch directories instead of hardcoding ~/.claude/ and ./.claude/ - workflows/update.md: detect runtime directory for local and global VERSION/marker files, and clear cache across all runtime directories Closes #682 Co-Authored-By: Claude Opus 4.6 --- commands/gsd/reapply-patches.md | 21 +++++++++++++++---- get-shit-done/workflows/update.md | 35 ++++++++++++++++++++++--------- hooks/gsd-check-update.js | 19 ++++++++++++++--- 3 files changed, 58 insertions(+), 17 deletions(-) diff --git a/commands/gsd/reapply-patches.md b/commands/gsd/reapply-patches.md index f6eb8107b..91ede1530 100644 --- a/commands/gsd/reapply-patches.md +++ b/commands/gsd/reapply-patches.md @@ -14,11 +14,24 @@ After a GSD update wipes and reinstalls files, this command merges user's previo Check for local patches directory: ```bash -# Global install (path templated at install time) -PATCHES_DIR=~/.claude/gsd-local-patches -# Local install fallback +# Global install — detect runtime config directory +if [ -d "$HOME/.config/opencode/gsd-local-patches" ]; then + PATCHES_DIR="$HOME/.config/opencode/gsd-local-patches" +elif [ -d "$HOME/.opencode/gsd-local-patches" ]; then + PATCHES_DIR="$HOME/.opencode/gsd-local-patches" +elif [ -d "$HOME/.gemini/gsd-local-patches" ]; then + PATCHES_DIR="$HOME/.gemini/gsd-local-patches" +else + PATCHES_DIR="$HOME/.claude/gsd-local-patches" +fi +# Local install fallback — check all runtime directories if [ ! -d "$PATCHES_DIR" ]; then - PATCHES_DIR=./.claude/gsd-local-patches + for dir in .config/opencode .opencode .gemini .claude; do + if [ -d "./$dir/gsd-local-patches" ]; then + PATCHES_DIR="./$dir/gsd-local-patches" + break + fi + done fi ``` diff --git a/get-shit-done/workflows/update.md b/get-shit-done/workflows/update.md index 3a184500c..d14522451 100644 --- a/get-shit-done/workflows/update.md +++ b/get-shit-done/workflows/update.md @@ -13,16 +13,28 @@ Detect whether GSD is installed locally or globally by checking both locations a ```bash # Check local first (takes priority only if valid) -# Paths templated at install time for runtime compatibility -LOCAL_VERSION_FILE="./.claude/get-shit-done/VERSION" -LOCAL_MARKER_FILE="./.claude/get-shit-done/workflows/update.md" -GLOBAL_VERSION_FILE="$HOME/.claude/get-shit-done/VERSION" -GLOBAL_MARKER_FILE="$HOME/.claude/get-shit-done/workflows/update.md" +# Detect runtime config directory (supports Claude, OpenCode, Gemini) +LOCAL_VERSION_FILE="" LOCAL_MARKER_FILE="" +for dir in .claude .config/opencode .opencode .gemini; do + if [ -f "./$dir/get-shit-done/VERSION" ]; then + LOCAL_VERSION_FILE="./$dir/get-shit-done/VERSION" + LOCAL_MARKER_FILE="./$dir/get-shit-done/workflows/update.md" + break + fi +done +GLOBAL_VERSION_FILE="" GLOBAL_MARKER_FILE="" +for dir in .claude .config/opencode .opencode .gemini; do + if [ -f "$HOME/$dir/get-shit-done/VERSION" ]; then + GLOBAL_VERSION_FILE="$HOME/$dir/get-shit-done/VERSION" + GLOBAL_MARKER_FILE="$HOME/$dir/get-shit-done/workflows/update.md" + break + fi +done -if [ -f "$LOCAL_VERSION_FILE" ] && [ -f "$LOCAL_MARKER_FILE" ] && grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+' "$LOCAL_VERSION_FILE"; then +if [ -n "$LOCAL_VERSION_FILE" ] && [ -f "$LOCAL_VERSION_FILE" ] && [ -f "$LOCAL_MARKER_FILE" ] && grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+' "$LOCAL_VERSION_FILE"; then cat "$LOCAL_VERSION_FILE" echo "LOCAL" -elif [ -f "$GLOBAL_VERSION_FILE" ] && [ -f "$GLOBAL_MARKER_FILE" ] && grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+' "$GLOBAL_VERSION_FILE"; then +elif [ -n "$GLOBAL_VERSION_FILE" ] && [ -f "$GLOBAL_VERSION_FILE" ] && [ -f "$GLOBAL_MARKER_FILE" ] && grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+' "$GLOBAL_VERSION_FILE"; then cat "$GLOBAL_VERSION_FILE" echo "GLOBAL" else @@ -165,11 +177,14 @@ Capture output. If install fails, show error and exit. Clear the update cache so statusline indicator disappears: ```bash -rm -f ./.claude/cache/gsd-update-check.json -rm -f ~/.claude/cache/gsd-update-check.json +# Clear update cache across all runtime directories +for dir in .claude .config/opencode .opencode .gemini; do + rm -f "./$dir/cache/gsd-update-check.json" + rm -f "$HOME/$dir/cache/gsd-update-check.json" +done ``` -The SessionStart hook (`gsd-check-update.js`) always writes to `~/.claude/cache/` via `os.homedir()` regardless of install type, so both paths must be cleared to prevent stale update indicators. +The SessionStart hook (`gsd-check-update.js`) writes to the detected runtime's cache directory, so all paths must be cleared to prevent stale update indicators. diff --git a/hooks/gsd-check-update.js b/hooks/gsd-check-update.js index df3cd2281..c5bb67034 100755 --- a/hooks/gsd-check-update.js +++ b/hooks/gsd-check-update.js @@ -9,12 +9,25 @@ const { spawn } = require('child_process'); const homeDir = os.homedir(); const cwd = process.cwd(); -const cacheDir = path.join(homeDir, '.claude', 'cache'); + +// Detect runtime config directory (supports Claude, OpenCode, Gemini) +function detectConfigDir(baseDir) { + for (const dir of ['.config/opencode', '.opencode', '.gemini', '.claude']) { + if (fs.existsSync(path.join(baseDir, dir, 'get-shit-done', 'VERSION'))) { + return path.join(baseDir, dir); + } + } + return path.join(baseDir, '.claude'); +} + +const globalConfigDir = detectConfigDir(homeDir); +const projectConfigDir = detectConfigDir(cwd); +const cacheDir = path.join(globalConfigDir, 'cache'); const cacheFile = path.join(cacheDir, 'gsd-update-check.json'); // VERSION file locations (check project first, then global) -const projectVersionFile = path.join(cwd, '.claude', 'get-shit-done', 'VERSION'); -const globalVersionFile = path.join(homeDir, '.claude', 'get-shit-done', 'VERSION'); +const projectVersionFile = path.join(projectConfigDir, 'get-shit-done', 'VERSION'); +const globalVersionFile = path.join(globalConfigDir, 'get-shit-done', 'VERSION'); // Ensure cache directory exists if (!fs.existsSync(cacheDir)) {