From dd2f3c13ecd0ac92182c243b6a72444cd07fdbad Mon Sep 17 00:00:00 2001 From: garrytan Date: Wed, 28 Oct 2026 01:40:21 +0000 Subject: [PATCH] fix(harness): keep edits beside themselves, never follow symlinks, cut only gstack's own context block Review blockers on #3526: uninstall deleted the edit backups under the state root; unregister followed a symlinked folder below the destination; a lone or edited context marker made the cut eat user lines; a re-register adding --context left an unrecorded block. Also: ledger written before the files, --refresh-registered no longer re-runs harness hosts through setup (gstack-harness refresh keeps their mode), bash goes through runBashSync, and setup tests follow openclaw/hermes becoming installs. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --- CHANGELOG.md | 4 +- bin/gstack-harness | 1 + bin/gstack-harness-ledger.sh | 58 +++++++++++------ docs/hosts.md | 6 +- docs/troubleshooting.md | 4 +- lib/harness-register.ts | 118 +++++++++++++++++++++++----------- setup | 1 + test/gen-skill-docs.test.ts | 4 +- test/harness-register.test.ts | 70 ++++++++++++++++++-- test/setup-help.test.ts | 5 +- 10 files changed, 200 insertions(+), 71 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95058d261..06a61f393 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ ### Added - **`bin/gstack-harness`** (`lib/harness-register.ts`, `lib/harness-qm.ts`): `register`, `unregister`, `status`, `detect`, `refresh`, `auto` and `manifest` for seven targets. OpenClaw gets one `gstack` router skill (one 254-byte description line in every request; its body lists every skill with its path) in `$OPENCLAW_STATE_DIR/skills`, or every skill with `--skills all`. Hermes gets every skill as `gstack-` in one `gstack` category, because it opens only skills it has indexed. A Dot gets the router in `/home/dot/skills`. QM gets an org skill pack (`github.com/garrytan/gstack` at the installed commit) through one explicit admin command, `register qm --yes`, which lists packs first so a retry never makes a second one. Muse Code and Grok Build already read `~/.claude/skills`; `status` reports them as discovered, Claude-rendered and unverified. Any other harness gets the router in a skills folder (`--skills-dir`) or a routing block of at most 600 bytes between `gstack:begin`/`gstack:end` markers in a context file (`--context`), and `--print` writes both to stdout for chat-only apps such as Grok Bot. -- **Ownership ledger**: every file gstack-harness writes goes into `$GSTACK_STATE_ROOT/harness/.ledger` with its sha256. Registering again changes only what changed; a folder or a skill name gstack did not write stops it; a destination that is your home, the checkout, a symlink or outside a plain path is refused. `gstack-uninstall` reads the ledgers with `bin/gstack-harness-ledger.sh` (bash only) before it removes the checkout, and moves any file you edited to `$GSTACK_STATE_ROOT/backups/harness/`. +- **Ownership ledger**: every file gstack-harness writes goes into `$GSTACK_STATE_ROOT/harness/.ledger` with its sha256. Registering again changes only what changed; a folder or a skill name gstack did not write stops it; a destination that is your home, the checkout, a symlink or outside a plain path is refused. `gstack-uninstall` reads the ledgers with `bin/gstack-harness-ledger.sh` (bash only) before it removes the checkout, never follows a symlink below the destination, and renames any file you edited to `.edited-