From 109bc8a81cdeb71d601276657572bf165d453cb7 Mon Sep 17 00:00:00 2001 From: Corvid Agent <0xopenbytes@gmail.com> Date: Thu, 21 May 2026 17:52:47 -0700 Subject: [PATCH 1/2] fix(v0.6.5): workspaces under ~/.fledge/workspaces, not /tmp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit macOS auto-prunes /tmp aggressively, and well-meaning disk-cleanup sweeps (rm -rf /tmp/fledge-gh-*) wipe agent workspaces mid-task — we burned a Discord session today watching the corvidagent edit a JwtTokenService.swift in a workspace that got cleaned up between turns, then try to push to a path that no longer existed. Move the default workspace root to ~/.fledge/workspaces, override- able via FLEDGE_WORKSPACES_DIR for tests / CI. The new location: - survives /tmp pruning, - shows up next to the rest of fledge state for disk-audit visibility, - costs nothing in performance (still local disk). workspace-clean and workspace-push still accept the legacy /tmp/fledge-gh-* prefix so any in-flight workspaces from v0.6.4 and earlier can be pushed or cleaned without manual intervention. Bash strict-mode safe; shellcheck clean. --- .DS_Store | Bin 0 -> 6148 bytes CHANGELOG.md | 8 ++++++ bin/fledge-github-repo | 63 ++++++++++++++++++++++++++++------------- plugin.toml | 2 +- 4 files changed, 52 insertions(+), 21 deletions(-) create mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..b2ddfb0d7dc8456f409863ed7e4c2856fcf91f83 GIT binary patch literal 6148 zcmeHKJx{|h5Iwh%TEx%DCL~5?CL~rC zCT8B**VHC0BSPp-vY&Gwe$Go2$3$fM%W;pWLqu&f#>Ni14aRY9HEW26iw(~)oAidG zV!o(ls^hOJz|StBE=}l+ZldScIJgUA^CHXgS&_rn9z0yw_t&SxI6nR{zL*B@Myo_A zwN|_|r6uJNJGEZw8Q~gE9*>hZzlLw~%!~C(wr54_Aw=SJb>QQ@DKoy7;X!^?z@Bf4C=l{4!uT%k5;9n_Vl5Cju zaZ9qd)^3jXT8nmy#>RQ2$EpMaw-qCox8glCXYgAd08_!zBRnwu5pXhSrwaV40$*ih Bf}Q{X literal 0 HcmV?d00001 diff --git a/CHANGELOG.md b/CHANGELOG.md index a0502c8..3d076f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [v0.6.5] - 2026-05-21 + +### Fixes + +- `repo workspace` now creates clones under `~/.fledge/workspaces/--XXXXXX/` instead of `/tmp/fledge-gh-XXXXXX/`. macOS auto-prunes `/tmp` and well-meaning disk-cleanup sweeps wipe it, both of which were destroying agent workspaces mid-task. The new location is stable across reboots and shows up alongside the rest of fledge state. +- `repo workspace-clean` and `repo workspace-push` still accept the legacy `/tmp/fledge-gh-*` prefix so any in-flight workspaces from v0.6.4 and earlier can be pushed or cleaned without manual intervention. +- Override the workspace root with `FLEDGE_WORKSPACES_DIR` for tests / CI / custom layouts. + ## [v0.6.4] - 2026-05-21 ### Features diff --git a/bin/fledge-github-repo b/bin/fledge-github-repo index 3bccb1d..40d6dcc 100755 --- a/bin/fledge-github-repo +++ b/bin/fledge-github-repo @@ -122,11 +122,17 @@ is a directory — same command, agent can browse and read with one tool. `clone` wraps `gh repo clone OWNER/NAME [DIR]` directly. `workspace` is the higher-level "give me a sandbox" command for -agents: creates a fresh `/tmp/fledge-gh---XXXXXX/` +agents: creates a fresh `~/.fledge/workspaces/--XXXXXX/` directory, clones the repo there (optionally shallow + at a specific ref), and prints the absolute path on stdout. Cleanup via `workspace-clean ` which `rm -rf`s after sanity-checking the -path is under `/tmp/fledge-gh-`. +path is under the workspace root. + +Override the workspace root with `FLEDGE_WORKSPACES_DIR` if you want +a different location (tests, CI, custom layouts). Workspaces from +the legacy `/tmp/fledge-gh-*` location (v0.6.4 and earlier) still +clean up correctly so in-flight directories aren't orphaned by the +upgrade. EXAMPLES: fledge github repo @@ -182,8 +188,8 @@ if [ "$ACTION" = "workspace" ]; then # Sanitize OWNER/NAME for use in a path: replace anything that isn't # alnum/-/./_ with `_`. That keeps the resulting dir name human- # readable (so the agent's logs make sense) and avoids the very real - # risk of an attacker-controlled repo name escaping the /tmp prefix - # via something cute like `../../etc/passwd`. + # risk of an attacker-controlled repo name escaping the workspace + # root via something cute like `../../etc/passwd`. OWNER_NAME_SAFE="$(printf '%s' "$REPO" | tr '/' '-' | tr -c 'A-Za-z0-9._-' '_')" # The plain repo name (post-slash) becomes the inner clone dir, so @@ -192,10 +198,18 @@ if [ "$ACTION" = "workspace" ]; then NAME_ONLY="${REPO#*/}" NAME_ONLY_SAFE="$(printf '%s' "$NAME_ONLY" | tr -c 'A-Za-z0-9._-' '_')" + # Workspaces live under $FLEDGE_WORKSPACES_DIR (default + # ~/.fledge/workspaces) so they survive macOS /tmp cleanups, OS + # reboots, and well-meaning `rm -rf /tmp/...` sweeps. Plus they + # show up in disk-audit reports alongside the rest of fledge state + # instead of hiding in /tmp. The env var override is for tests. + WORKSPACE_ROOT="${FLEDGE_WORKSPACES_DIR:-$HOME/.fledge/workspaces}" + mkdir -p "$WORKSPACE_ROOT" + # mktemp -d gives us a unique parent. The clone target is one level # deeper so cleanup of the parent removes both the dir and any junk # gh / git leave behind. - PARENT="$(mktemp -d "/tmp/fledge-gh-${OWNER_NAME_SAFE}-XXXXXX")" + PARENT="$(mktemp -d "${WORKSPACE_ROOT}/${OWNER_NAME_SAFE}-XXXXXX")" TARGET="${PARENT}/${NAME_ONLY_SAFE}" # Build the gh repo clone arg list. Everything after `--` is passed @@ -231,16 +245,19 @@ fi if [ "$ACTION" = "workspace-push" ]; then if [ -z "$CLONE_DIR" ]; then - echo "fledge github repo workspace-push: missing DIR. Try: fledge github repo workspace-push /tmp/fledge-gh-XXX -b feat/fix -m \"msg\"" >&2 + echo "fledge github repo workspace-push: missing DIR. Try: fledge github repo workspace-push -b feat/fix -m \"msg\"" >&2 exit 64 fi - # Same safety guard as workspace-clean: only operate on dirs we - # ourselves created, so an agent reasoning bug can't shove arbitrary - # local changes upstream via this command. + # Safety guard: only operate on dirs we ourselves created. Accept + # both the new ~/.fledge/workspaces/ location (v0.6.5+) AND the + # legacy /tmp/fledge-gh-* prefix so in-flight workspaces from + # older plugin versions still work. + WORKSPACE_ROOT="${FLEDGE_WORKSPACES_DIR:-$HOME/.fledge/workspaces}" case "$CLONE_DIR" in + "$WORKSPACE_ROOT"/*) ;; /tmp/fledge-gh-*) ;; *) - echo "fledge github repo workspace-push: refusing to push from '$CLONE_DIR' (must be a /tmp/fledge-gh-* workspace)" >&2 + echo "fledge github repo workspace-push: refusing to push from '$CLONE_DIR' (must be a workspace created by 'repo workspace')" >&2 exit 64 ;; esac @@ -309,17 +326,22 @@ fi if [ "$ACTION" = "workspace-clean" ]; then if [ -z "$CLONE_DIR" ]; then - echo "fledge github repo workspace-clean: missing DIR. Try: fledge github repo workspace-clean /tmp/fledge-gh-XXXX" >&2 + echo "fledge github repo workspace-clean: missing DIR. Try: fledge github repo workspace-clean " >&2 exit 64 fi - # Safety: only delete dirs that look like fledge-gh workspaces. A - # bug in the agent's reasoning shouldn't be able to wipe arbitrary - # paths via this tool. The prefix check is intentionally strict — - # symlinks and `..` segments fail it cleanly. + # Safety: only delete dirs that look like workspaces we ourselves + # created. Accept the v0.6.5+ ~/.fledge/workspaces/ location AND + # the legacy /tmp/fledge-gh-* prefix so this tool can clean up + # in-flight workspaces from older plugin versions. A bug in the + # agent's reasoning shouldn't be able to wipe arbitrary paths via + # this tool — the prefix check is intentionally strict, and + # symlinks / `..` segments fail it cleanly. + WORKSPACE_ROOT="${FLEDGE_WORKSPACES_DIR:-$HOME/.fledge/workspaces}" case "$CLONE_DIR" in + "$WORKSPACE_ROOT"/*) ;; /tmp/fledge-gh-*) ;; *) - echo "fledge github repo workspace-clean: refusing to remove '$CLONE_DIR' (must start with /tmp/fledge-gh-)" >&2 + echo "fledge github repo workspace-clean: refusing to remove '$CLONE_DIR' (must be a workspace created by 'repo workspace')" >&2 exit 64 ;; esac @@ -328,12 +350,13 @@ if [ "$ACTION" = "workspace-clean" ]; then exit 1 fi # If the caller passed the inner clone path, we still want to remove - # the parent so we don't leave an empty fledge-gh-* shell behind. - # Walk up only when CLONE_DIR's parent itself matches our prefix. + # the parent so we don't leave an empty shell behind. Walk up only + # when CLONE_DIR's parent itself matches one of our workspace roots. PARENT_OF="$(dirname "$CLONE_DIR")" case "$PARENT_OF" in - /tmp/fledge-gh-*) rm -rf -- "$PARENT_OF";; - *) rm -rf -- "$CLONE_DIR";; + "$WORKSPACE_ROOT"/*) rm -rf -- "$PARENT_OF";; + /tmp/fledge-gh-*) rm -rf -- "$PARENT_OF";; + *) rm -rf -- "$CLONE_DIR";; esac exit 0 fi diff --git a/plugin.toml b/plugin.toml index 121eaae..e8fa18e 100644 --- a/plugin.toml +++ b/plugin.toml @@ -1,6 +1,6 @@ [plugin] name = "fledge-plugin-github" -version = "0.6.4" +version = "0.6.5" description = "GitHub commands for fledge — list/view/create/comment/review/merge PRs, list/view/create/comment/close issues, read repo files, view CI checks, and poll for daemon events via the gh CLI" author = "0xLeif" license = "MIT" From 65930617581de6b37e151ceeba0bffe37b5bee3e Mon Sep 17 00:00:00 2001 From: Corvid Agent <0xopenbytes@gmail.com> Date: Thu, 21 May 2026 17:52:58 -0700 Subject: [PATCH 2/2] chore: gitignore .DS_Store (accidentally committed in 109bc8a) --- .DS_Store | Bin 6148 -> 0 bytes .gitignore | 1 + 2 files changed, 1 insertion(+) delete mode 100644 .DS_Store create mode 100644 .gitignore diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index b2ddfb0d7dc8456f409863ed7e4c2856fcf91f83..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKJx{|h5Iwh%TEx%DCL~5?CL~rC zCT8B**VHC0BSPp-vY&Gwe$Go2$3$fM%W;pWLqu&f#>Ni14aRY9HEW26iw(~)oAidG zV!o(ls^hOJz|StBE=}l+ZldScIJgUA^CHXgS&_rn9z0yw_t&SxI6nR{zL*B@Myo_A zwN|_|r6uJNJGEZw8Q~gE9*>hZzlLw~%!~C(wr54_Aw=SJb>QQ@DKoy7;X!^?z@Bf4C=l{4!uT%k5;9n_Vl5Cju zaZ9qd)^3jXT8nmy#>RQ2$EpMaw-qCox8glCXYgAd08_!zBRnwu5pXhSrwaV40$*ih Bf}Q{X diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store