From 590ec682045c4313dc9fe45e87967694c3ef5d17 Mon Sep 17 00:00:00 2001 From: Preetham Kyanam <37784174+pkyanam@users.noreply.github.com> Date: Wed, 28 Oct 2026 12:24:44 +0000 Subject: [PATCH] Ship a reproducible 0.2.1 archive and keep uninstall backups outside the hstack directory. --- .github/workflows/ci.yml | 1 + README.md | 2 +- VERSION | 2 +- docs/v0.2-DESIGN.md | 2 +- install.ps1 | 2 +- install.sh | 2 +- scripts/apply_hooks.py | 11 +-- scripts/check_hooks.py | 23 ++++- scripts/check_piped_install.sh | 2 +- scripts/check_skills.py | 4 +- site/DEPLOY.md | 15 +-- site/_headers | 8 ++ site/content/changelog.md | 11 ++- site/content/docs/index.md | 2 +- site/content/docs/install.md | 4 +- site/content/integrations.md | 2 +- site/scripts/archive.mjs | 110 +++++++++++++++++++++ site/scripts/build.mjs | 72 +++++--------- site/scripts/check-archives.mjs | 29 ++++++ site/scripts/check-no-html.mjs | 15 ++- site/scripts/check-vercel.mjs | 2 +- site/vendor/dl/hstack-v0.2.0.tar.gz | Bin 0 -> 30914 bytes site/vendor/dl/hstack-v0.2.0.tar.gz.sha256 | 1 + site/vendor/dl/hstack-v0.2.1.tar.gz | Bin 0 -> 31006 bytes site/vendor/dl/hstack-v0.2.1.tar.gz.sha256 | 1 + site/vercel.json | 12 +++ skills/hstack/arena/SKILL.md | 2 +- skills/hstack/blast/SKILL.md | 2 +- skills/hstack/council/SKILL.md | 2 +- skills/hstack/hstack/SKILL.md | 2 +- skills/hstack/modernize/SKILL.md | 2 +- skills/hstack/principles/SKILL.md | 2 +- skills/hstack/prove/SKILL.md | 2 +- skills/hstack/reframe/SKILL.md | 2 +- skills/hstack/shape/SKILL.md | 2 +- skills/hstack/ship/SKILL.md | 2 +- skills/hstack/swarm/SKILL.md | 2 +- skills/hstack/takeover/SKILL.md | 2 +- 38 files changed, 266 insertions(+), 93 deletions(-) create mode 100644 site/scripts/archive.mjs create mode 100644 site/scripts/check-archives.mjs create mode 100644 site/vendor/dl/hstack-v0.2.0.tar.gz create mode 100644 site/vendor/dl/hstack-v0.2.0.tar.gz.sha256 create mode 100644 site/vendor/dl/hstack-v0.2.1.tar.gz create mode 100644 site/vendor/dl/hstack-v0.2.1.tar.gz.sha256 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 005e8e8..c1a6a6a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,6 +32,7 @@ jobs: run: | cd site npm ci + node scripts/check-archives.mjs npm run build node scripts/check-no-html.mjs node scripts/check-pages.mjs diff --git a/README.md b/README.md index 94f1d52..c8d8c52 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Twelve skills for Hermes Agent. Frame the job, shape the change, prove it, and o curl -fsSL https://hstack.sh/install | sh ``` -The curl form downloads `install.sh` and the skill archive from hstack.sh, checks the sha256, and extracts into the Hermes skills directory. It does not clone this repository. `HSTACK_BASE_URL` points the download at another host, such as a `*.vercel.app` URL before DNS is in place. With no version set, the installer fetches the latest alias, `hstack.tar.gz`, which is 0.2.0. `HSTACK_VERSION=0.1.0` still fetches `hstack-v0.1.0.tar.gz`. The archive is one directory containing the skills, `scripts/apply_addons.py`, `scripts/apply_hooks.py`, `hooks/`, and the `bin/` helpers, so `--with` works from the curl form too. +The curl form downloads `install.sh` and the skill archive from hstack.sh, checks the sha256, and extracts into the Hermes skills directory. It does not clone this repository. `HSTACK_BASE_URL` points the download at another host, such as a `*.vercel.app` URL before DNS is in place. With no version set, the installer fetches the latest alias, `hstack.tar.gz`, which is 0.2.1. `HSTACK_VERSION=0.2.0` still fetches the frozen `hstack-v0.2.0.tar.gz`. `HSTACK_VERSION=0.1.0` still fetches `hstack-v0.1.0.tar.gz`. The archive is one directory containing the skills, `scripts/apply_addons.py`, `scripts/apply_hooks.py`, `hooks/`, and the `bin/` helpers, so `--with` works from the curl form too. From a checkout of this repo, `sh install.sh` installs the skills beside the script. A second run replaces the HStack skills and leaves every other skill alone. Pass `--dry-run` to print the plan and write nothing. diff --git a/VERSION b/VERSION index 0ea3a94..0c62199 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.2.0 +0.2.1 diff --git a/docs/v0.2-DESIGN.md b/docs/v0.2-DESIGN.md index d5984d3..edc9ead 100644 --- a/docs/v0.2-DESIGN.md +++ b/docs/v0.2-DESIGN.md @@ -25,7 +25,7 @@ Each installed hook is a few lines that call `hooks/hstack_hook.py`. The skills Hermes still asks the first time it sees each `(event, command)` pair and stores the answer in `~/.hermes/shell-hooks-allowlist.json`. The installer does not write that file. A gateway, cron job, or other non-interactive surface will not run a new hook until that prompt has been answered, or until the user passes `--accept-hooks` / `HERMES_ACCEPT_HOOKS=1` themselves. Editing the script later does not clear the allowlist. Hermes keys it on the command string (`hermes hooks doctor` reports mtime drift). -`--with hermes-hooks` installs all three. A subset is `hermes-hooks-guard`, `hermes-hooks-save`, or `hermes-hooks-suggest`. The installer copies the shims to `$HERMES_HOME/hstack/hooks/`, edits `config.yaml`, and copies `apply_hooks.py` beside the addon script so a later `curl | sh -s -- --uninstall` can remove them. It backs up `config.yaml` to `$HERMES_HOME/hstack/backups/` before a change. A second run that would write the same block does not write and does not take another backup. `--uninstall` removes only the entries marked `# hstack:` and the files this installer wrote. Another product's hook stays. +`--with hermes-hooks` installs all three. A subset is `hermes-hooks-guard`, `hermes-hooks-save`, or `hermes-hooks-suggest`. The installer copies the shims to `$HERMES_HOME/hstack/hooks/`, edits `config.yaml`, and copies `apply_hooks.py` beside the addon script so a later `curl | sh -s -- --uninstall` can remove them. It backs up `config.yaml` to `$HERMES_HOME/hstack-backups/` before a change. Uninstall removes `$HERMES_HOME/hstack/` and leaves that backup directory in place. A second run that would write the same block does not write and does not take another backup. `--uninstall` removes only the entries marked `# hstack:` and the files this installer wrote. Another product's hook stays. ### `guard` — `pre_tool_call` on `terminal` diff --git a/install.ps1 b/install.ps1 index f4c6d61..ad93d42 100644 --- a/install.ps1 +++ b/install.ps1 @@ -348,7 +348,7 @@ if ($links.Count -gt 0) { Die 'refusing to copy a link or special file from the skill tree' } -$ver = '0.2.0' +$ver = '0.2.1' $versionFile = if ($AddonRoot) { Join-Path $AddonRoot 'VERSION' } else { $null } if ($versionFile -and (Test-Path -LiteralPath $versionFile)) { $digits = ([System.IO.File]::ReadAllText($versionFile) -replace '[^0-9.]', '') diff --git a/install.sh b/install.sh index 4361cab..2327366 100755 --- a/install.sh +++ b/install.sh @@ -446,7 +446,7 @@ if find "$SRC" \( -type l -o -type b -o -type c -o -type p -o -type s \) -print die "refusing to copy a link or special file from the skill tree" fi -ver=0.2.0 +ver=0.2.1 if [ -n "$ADDON_ROOT" ] && [ -f "$ADDON_ROOT/VERSION" ]; then got=$(tr -cd '0-9.' < "$ADDON_ROOT/VERSION") if [ -n "$got" ]; then diff --git a/scripts/apply_hooks.py b/scripts/apply_hooks.py index 7b32c30..d69f036 100644 --- a/scripts/apply_hooks.py +++ b/scripts/apply_hooks.py @@ -332,9 +332,13 @@ def copy_self(dest_root: Path, dry_run: bool) -> None: target.chmod(0o644) +def backup_dir(root: Path) -> Path: + return root / "hstack-backups" + + def backup_config(config: Path, root: Path) -> None: stamp = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%S%fZ") - dest = root / "hstack" / "backups" / f"config.yaml.{stamp}" + dest = backup_dir(root) / f"config.yaml.{stamp}" dest.parent.mkdir(parents=True, exist_ok=True) shutil.copyfile(config, dest) say(f"backed up config.yaml to {dest}") @@ -437,11 +441,6 @@ def apply(root: Path, source: Path | None, hooks: list[str], remove: bool, dry_r self_copy = dest_root / "apply_hooks.py" if self_copy.is_file() and not self_copy.is_symlink(): self_copy.unlink() - backups = dest_root / "backups" - if backups.is_dir(): - for child in backups.iterdir(): - if child.is_file() and child.name.startswith("config.yaml."): - child.unlink() prune_root(dest_root) return if not marker.exists(): diff --git a/scripts/check_hooks.py b/scripts/check_hooks.py index d9d858d..79abb8d 100644 --- a/scripts/check_hooks.py +++ b/scripts/check_hooks.py @@ -72,10 +72,10 @@ def live(root: Path, command_home: str, hooks: list[str]) -> None: fail(f"dry-run wrote config for {command_home}") apply_hooks.apply(root, source, hooks, remove=False, dry_run=False, command_home=command_home) config = (root / "config.yaml").read_text(encoding="utf-8") - backups = list((root / "hstack" / "backups").glob("config.yaml.*")) if (root / "hstack" / "backups").exists() else [] + backups = list((root / "hstack-backups").glob("config.yaml.*")) if (root / "hstack-backups").exists() else [] # First write creates the file, so there is no previous config to back up. apply_hooks.apply(root, source, hooks, remove=False, dry_run=False, command_home=command_home) - backups_after = list((root / "hstack" / "backups").glob("config.yaml.*")) if (root / "hstack" / "backups").exists() else [] + backups_after = list((root / "hstack-backups").glob("config.yaml.*")) if (root / "hstack-backups").exists() else [] if len(backups_after) != len(backups): fail(f"idempotent install took another backup for {command_home}") again = (root / "config.yaml").read_text(encoding="utf-8") @@ -93,6 +93,11 @@ def live(root: Path, command_home: str, hooks: list[str]) -> None: fail(f"uninstall left config for {command_home}") if (root / "hstack" / "hooks").exists(): fail(f"uninstall left hook scripts for {command_home}") + kept = list((root / "hstack-backups").glob("config.yaml.*")) + if len(kept) != 1 or kept[0].read_text(encoding="utf-8") != config: + fail(f"uninstall deleted the config backup for {command_home}") + if (root / "hstack" / "backups").exists(): + fail(f"uninstall left a backup inside hstack for {command_home}") def foreign_backup(root: Path) -> None: @@ -100,13 +105,13 @@ def foreign_backup(root: Path) -> None: original = 'model: local\nhooks:\n post_tool_call:\n - command: "/usr/bin/log"\n' (root / "config.yaml").write_text(original, encoding="utf-8") apply_hooks.apply(root, ROOT, ["guard"], remove=False, dry_run=False, command_home=root.as_posix()) - backups = list((root / "hstack" / "backups").glob("config.yaml.*")) + backups = list((root / "hstack-backups").glob("config.yaml.*")) if len(backups) != 1: fail(f"expected one backup, found {len(backups)}") if backups[0].read_text(encoding="utf-8") != original: fail("backup is not the original config") apply_hooks.apply(root, ROOT, ["guard"], remove=False, dry_run=False, command_home=root.as_posix()) - if len(list((root / "hstack" / "backups").glob("config.yaml.*"))) != 1: + if len(list((root / "hstack-backups").glob("config.yaml.*"))) != 1: fail("second install added a backup") text = (root / "config.yaml").read_text(encoding="utf-8") if "/usr/bin/log" not in text or "# hstack:guard" not in text: @@ -117,6 +122,11 @@ def foreign_backup(root: Path) -> None: fail("guard uninstall left its entry") if "/usr/bin/log" not in left: fail("guard uninstall removed the foreign hook") + surviving = list((root / "hstack-backups").glob("config.yaml.*")) + if not any(item.read_text(encoding="utf-8") == original for item in surviving): + fail("uninstall deleted the original config backup") + if (root / "hstack" / "backups").exists(): + fail("uninstall left a backup inside hstack") def installer() -> None: @@ -157,6 +167,11 @@ def installer() -> None: state = home / "hstack" / "hooks.json" if state.exists(): fail(f"hook state remained: {state.read_text()}") + kept = list((home / "hstack-backups").glob("config.yaml.*")) + if not kept or not any("hstack" in item.read_text(encoding="utf-8") for item in kept): + fail("uninstall deleted its config backup") + if (home / "hstack" / "backups").exists(): + fail("uninstall left a backup inside the removed tree") def behavior() -> None: diff --git a/scripts/check_piped_install.sh b/scripts/check_piped_install.sh index f60560a..990c9bb 100755 --- a/scripts/check_piped_install.sh +++ b/scripts/check_piped_install.sh @@ -63,7 +63,7 @@ install_with() { test -f "$home/hermes/skills/hstack/hstack/references/frame.md" || fail "$label missing playbook" test "$(count_skills "$home/hermes")" -eq 12 || fail "$label expected 12 skills" test ! -e "$home/hermes/skills/hstack/VERSION" || fail "$label left VERSION in the skill tree" - grep -q 'version: 0.2.0' "$home/hermes/skills/hstack/.hstack-managed" || fail "$label marker version" + grep -q 'version: 0.2.1' "$home/hermes/skills/hstack/.hstack-managed" || fail "$label marker version" diff -q "$ROOT/skills/hstack/reframe/SKILL.md" "$home/hermes/skills/hstack/reframe/SKILL.md" >/dev/null \ || fail "$label skill bytes differ" if [ -n "$path_value" ]; then diff --git a/scripts/check_skills.py b/scripts/check_skills.py index a6c7ab8..6f0a7e4 100755 --- a/scripts/check_skills.py +++ b/scripts/check_skills.py @@ -291,8 +291,8 @@ def check_skills() -> dict[str, int]: fail(f"{name}: description must be one sentence of at most 60 characters") if clip_description(desc) != desc or clip_description_stable(desc) != desc: fail(f"{name}: Hermes would clip the description") - if meta.get("version") != "0.2.0": - fail(f"{name}: version must be 0.2.0") + if meta.get("version") != "0.2.1": + fail(f"{name}: version must be 0.2.1") if meta.get("license") != "MIT": fail(f"{name}: license must be MIT") if meta.get("author") != "Preetham Kyanam": diff --git a/site/DEPLOY.md b/site/DEPLOY.md index 12cb38d..53d2f72 100644 --- a/site/DEPLOY.md +++ b/site/DEPLOY.md @@ -38,19 +38,22 @@ Leave the Porkbun nameservers alone. The registrar stays Porkbun. Vercel does no - Any other path under `/install/` is a plain-text 404 (`not found`), not an HTML page. - `curl -fsSL hstack.sh/install` follows HTTP to HTTPS and receives the script. `curl -fsSL www.hstack.sh/install` follows the 308 to the apex and receives the same script. -Do not rebuild `/dl/hstack-v0.1.0.tar.gz`. The site build copies `site/vendor/dl/hstack-v0.1.0.tar.gz` into `dist` unchanged. Those bytes are the archive already on hstack.sh. sha256 `0c8009ee04fb31126b76e4202c91eee14e8d5be7d1cd42ac0cee551012eeda6e`, 19967 bytes. The checksum file is that digest, two spaces, then `hstack-v0.1.0.tar.gz`. +Do not rebuild `/dl/hstack-v0.1.0.tar.gz` or `/dl/hstack-v0.2.0.tar.gz`. The site build copies both from `site/vendor/dl/` unchanged. + +`hstack-v0.1.0.tar.gz` is sha256 `0c8009ee04fb31126b76e4202c91eee14e8d5be7d1cd42ac0cee551012eeda6e`, 19967 bytes. `hstack-v0.2.0.tar.gz` is the file hstack.sh served for 0.2.0, sha256 `c16dfee4cd2841939a97a5cebf816c3fc3e8d71e28f2f1874639ea539ea20810`, 30914 bytes. Each checksum line is that digest, two spaces, then the filename. After this deploy, `/dl` is: | Path | Bytes | Cache-Control | |---|---|---| -| `/dl/hstack-v0.1.0.tar.gz` and `.sha256` | the vendored 0.1.0 archive, unchanged | `public, max-age=31536000, immutable` | -| `/dl/hstack-v0.2.0.tar.gz` and `.sha256` | the new archive from this tree | `public, max-age=31536000, immutable` | -| `/dl/hstack.tar.gz` and `.sha256` | the same bytes as `hstack-v0.2.0.tar.gz` | `public, max-age=300` | +| `/dl/hstack-v0.1.0.tar.gz` and `.sha256` | the vendored 0.1.0 archive | `public, max-age=31536000, immutable` | +| `/dl/hstack-v0.2.0.tar.gz` and `.sha256` | the vendored live 0.2.0 archive, not a rebuild | `public, max-age=31536000, immutable` | +| `/dl/hstack-v0.2.1.tar.gz` and `.sha256` | the vendored 0.2.1 archive | `public, max-age=31536000, immutable` | +| `/dl/hstack.tar.gz` and `.sha256` | the same bytes as `hstack-v0.2.1.tar.gz` | `public, max-age=300` | -`HSTACK_VERSION=0.1.0` requests the versioned 0.1.0 file, not the alias. The alias changes on this deploy. Its five-minute cache is the existing rule. Until this build is deployed, hstack.sh still serves 0.1.0 at `/dl/hstack.tar.gz`. +`HSTACK_VERSION=0.1.0` and `HSTACK_VERSION=0.2.0` request those versioned files, not the alias. The alias changes on this deploy. Its five-minute cache is the existing rule. Until this build is deployed, hstack.sh still serves 0.2.0 at `/dl/hstack.tar.gz`. -The 0.2.0 archive has one top-level directory. Inside it are `skills/hstack/`, `scripts/apply_addons.py`, `scripts/apply_hooks.py`, `hooks/`, `bin/` (the addon helpers), and `VERSION`. +The 0.2.1 archive has one top-level directory. Inside it are `skills/hstack/`, `scripts/apply_addons.py`, `scripts/apply_hooks.py`, `hooks/`, `bin/` (the addon helpers), and `VERSION`. ## Cloudflare Pages fallback diff --git a/site/_headers b/site/_headers index bf35749..2f4330e 100644 --- a/site/_headers +++ b/site/_headers @@ -46,6 +46,14 @@ Content-Type: text/plain; charset=utf-8 Cache-Control: public, max-age=31536000, immutable +/dl/hstack-v0.2.1.tar.gz + Content-Type: application/gzip + Cache-Control: public, max-age=31536000, immutable + +/dl/hstack-v0.2.1.tar.gz.sha256 + Content-Type: text/plain; charset=utf-8 + Cache-Control: public, max-age=31536000, immutable + /fonts/* Access-Control-Allow-Origin: * Cache-Control: public, max-age=31536000, immutable diff --git a/site/content/changelog.md b/site/content/changelog.md index ff4b575..2462bd2 100644 --- a/site/content/changelog.md +++ b/site/content/changelog.md @@ -1,8 +1,17 @@ --- title: Changelog -description: HStack 0.2.0. Optional Hermes hooks, a consent gate for outside stacks, and the same 204-token idle index. +description: HStack 0.2.1. Frozen release archives, deterministic builds, and config backups that survive uninstall. --- +## 0.2.1 + +28 October 2026. + +- `/dl/hstack-v0.2.0.tar.gz` is the archive that hstack.sh already served. The build copies those bytes and does not rebuild them. The latest alias is 0.2.1. +- New archives use a fixed mtime, sorted names, numeric owner 0, and `gzip -n`. Two builds of the same tree produce the same sha256. +- `--uninstall` keeps `config.yaml` backups in `$HERMES_HOME/hstack-backups/`. It no longer stores them under `$HERMES_HOME/hstack/`, which uninstall removes. +- Idle index stays 204. + ## 0.2.0 28 October 2026. diff --git a/site/content/docs/index.md b/site/content/docs/index.md index 2837b9a..ed5420f 100644 --- a/site/content/docs/index.md +++ b/site/content/docs/index.md @@ -17,4 +17,4 @@ Skills land in `~/.hermes/skills/hstack/`. Set `HERMES_HOME` when Hermes lives s The planning path is `hstack`, `reframe`, and `shape`: 1,052 tokens, under 2% of GStack's planning load on Hermes. The idle index is 204 tokens. All twelve `SKILL.md` bodies are 3,907. Counts use Hermes's estimator, `ceil(bytes / 4)`. -Playbooks live under `skills/hstack/hstack/references/` and load one at a time. After that playbook, the router may read `stacks.md` and ask before using gstack, pstack, tstack, or gbrain. Hermes shell hooks stay off unless the install names `--with hermes-hooks`. The [skills index](/skills) lists each skill. [Parity](/parity) has one row for every GStack, TStack, and PStack feature that was inventoried. +Playbooks live under `skills/hstack/hstack/references/` and load one at a time. After that playbook, the router may read `stacks.md` and ask before using gstack, pstack, tstack, or gbrain. Hermes shell hooks, since 0.2.0, stay off unless the install names `--with hermes-hooks`. The [skills index](/skills) lists each skill. [Parity](/parity) has one row for every GStack, TStack, and PStack feature that was inventoried. diff --git a/site/content/docs/install.md b/site/content/docs/install.md index 35664fd..ea7aeaf 100644 --- a/site/content/docs/install.md +++ b/site/content/docs/install.md @@ -56,12 +56,12 @@ powershell -ExecutionPolicy Bypass -File .\install.ps1 --uninstall ## Version and host -With no version set, the installer fetches `/dl/hstack.tar.gz`, the latest alias. That alias is 0.2.0. `HSTACK_VERSION=0.1.0` still fetches `/dl/hstack-v0.1.0.tar.gz`, the previous archive, byte for byte. `HSTACK_BASE_URL` points the download at another host, such as a `*.vercel.app` URL before DNS is in place. +With no version set, the installer fetches `/dl/hstack.tar.gz`, the latest alias. That alias is 0.2.1. `HSTACK_VERSION=0.2.0` still fetches `/dl/hstack-v0.2.0.tar.gz`, and `HSTACK_VERSION=0.1.0` still fetches `/dl/hstack-v0.1.0.tar.gz`. Those versioned files stay byte for byte. `HSTACK_BASE_URL` points the download at another host, such as a `*.vercel.app` URL before DNS is in place. ```sh install.sh curl -fsSL https://hstack.sh/install | HSTACK_VERSION=0.1.0 sh ``` -The archive is one directory. Inside 0.2.0: the skills, `scripts/apply_addons.py`, `scripts/apply_hooks.py`, `hooks/`, and the `bin/` helpers. The published checksum files are `HEX filename`, two spaces. A mismatch stops the install and does not write skills. +The archive is one directory. Inside 0.2.1: the skills, `scripts/apply_addons.py`, `scripts/apply_hooks.py`, `hooks/`, and the `bin/` helpers. The published checksum files are `HEX filename`, two spaces. A mismatch stops the install and does not write skills. WSL can run `install.sh`. The Windows script takes the same flags and the same archive. diff --git a/site/content/integrations.md b/site/content/integrations.md index 3cc2fc4..466fec8 100644 --- a/site/content/integrations.md +++ b/site/content/integrations.md @@ -28,7 +28,7 @@ Commands, dry-run, and the Windows `-File` form are on the [add-ons](/docs/addon ## Hooks -`--with hermes-hooks` registers shell hooks in `~/.hermes/config.yaml`. Nothing in the skills imports them, so a Hermes update that moves a Python API does not break the router. The guard blocks a short denylist of destructive terminal commands. The session hook appends a stamp when the session actually ends (`on_session_finalize`, not `on_session_end`, which fires every turn). The suggest hook can add context on the first turn only, and only an HStack playbook name. Hermes still asks before a new hook command runs, unless you pass `--accept-hooks` yourself. +Since 0.2.0, `--with hermes-hooks` registers shell hooks in `~/.hermes/config.yaml`. Nothing in the skills imports them, so a Hermes update that moves a Python API does not break the router. The guard blocks a short denylist of destructive terminal commands. The session hook appends a stamp when the session actually ends (`on_session_finalize`, not `on_session_end`, which fires every turn). The suggest hook can add context on the first turn only, and only an HStack playbook name. Hermes still asks before a new hook command runs, unless you pass `--accept-hooks` yourself. ## Outside stacks diff --git a/site/scripts/archive.mjs b/site/scripts/archive.mjs new file mode 100644 index 0000000..d3a9649 --- /dev/null +++ b/site/scripts/archive.mjs @@ -0,0 +1,110 @@ +import { createHash } from "node:crypto"; +import { spawnSync } from "node:child_process"; +import { chmodSync, cpSync, lstatSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import path from "node:path"; + +// Commit time of 13678a1, the 0.2.0 release. SOURCE_DATE_EPOCH overrides it. +export const ARCHIVE_MTIME = process.env.SOURCE_DATE_EPOCH || "1793189427"; + +export const PINS = { + "0.1.0": "0c8009ee04fb31126b76e4202c91eee14e8d5be7d1cd42ac0cee551012eeda6e", + "0.2.0": "c16dfee4cd2841939a97a5cebf816c3fc3e8d71e28f2f1874639ea539ea20810", + "0.2.1": "61108ad0d5f54ffa2f42ce91ee50758fc459eca7520ba6a1956353678c3c7816", +}; + +export const CURRENT = "0.2.1"; + +const HELPERS = [ + "hstack-bench", + "hstack-decisions", + "hstack-pr", + "hstack-scan", + "hstack-test", + "hstack-visdiff", +]; + +export function sha256(bytes) { + return createHash("sha256").update(bytes).digest("hex"); +} + +export function vendorArchive(site, version) { + return path.join(site, "vendor", "dl", `hstack-v${version}.tar.gz`); +} + +function skipCache(src) { + return !src.split(path.sep).includes("__pycache__"); +} + +function normalizeTree(top) { + const stack = [top]; + while (stack.length) { + const dir = stack.pop(); + chmodSync(dir, 0o755); + for (const name of readdirSync(dir)) { + const file = path.join(dir, name); + const info = lstatSync(file); + if (info.isSymbolicLink()) { + throw new Error(`refusing symlink in archive tree: ${file}`); + } + if (info.isDirectory()) { + stack.push(file); + continue; + } + const rel = path.relative(top, file).split(path.sep).join("/"); + chmodSync(file, rel.startsWith("bin/") ? 0o755 : 0o644); + } + } +} + +export function buildReleaseArchive(root, version) { + const skillsRoot = path.join(root, "skills", "hstack"); + const stage = mkdtempSync(path.join(tmpdir(), "hstack-archive-")); + try { + const top = path.join(stage, "hstack"); + mkdirSync(path.join(top, "scripts"), { recursive: true }); + mkdirSync(path.join(top, "bin"), { recursive: true }); + cpSync(skillsRoot, path.join(top, "skills", "hstack"), { recursive: true, filter: skipCache }); + cpSync(path.join(root, "hooks"), path.join(top, "hooks"), { recursive: true, filter: skipCache }); + cpSync(path.join(root, "scripts", "apply_addons.py"), path.join(top, "scripts", "apply_addons.py")); + cpSync(path.join(root, "scripts", "apply_hooks.py"), path.join(top, "scripts", "apply_hooks.py")); + for (const helper of HELPERS) { + cpSync(path.join(root, "bin", helper), path.join(top, "bin", helper)); + } + writeFileSync(path.join(top, "VERSION"), `${version}\n`); + normalizeTree(top); + const tar = spawnSync("tar", [ + "--format=ustar", + "--owner=0", + "--group=0", + "--numeric-owner", + `--mtime=@${ARCHIVE_MTIME}`, + "--sort=name", + "-cf", + "-", + "-C", + stage, + "hstack", + ], { maxBuffer: 20 * 1024 * 1024 }); + if (tar.status !== 0) { + throw new Error(`tar failed: ${tar.stderr.toString()}`); + } + const gzip = spawnSync("gzip", ["-n", "-c"], { input: tar.stdout, maxBuffer: 20 * 1024 * 1024 }); + if (gzip.status !== 0) { + throw new Error(`gzip failed: ${gzip.stderr.toString()}`); + } + return gzip.stdout; + } finally { + rmSync(stage, { recursive: true, force: true }); + } +} + +export function assertVendoredPins(site) { + for (const [version, pin] of Object.entries(PINS)) { + const file = vendorArchive(site, version); + const digest = sha256(readFileSync(file)); + if (digest !== pin) { + throw new Error(`vendored hstack-v${version}.tar.gz is ${digest}, pin is ${pin}`); + } + } +} diff --git a/site/scripts/build.mjs b/site/scripts/build.mjs index b66b05a..f9405f5 100644 --- a/site/scripts/build.mjs +++ b/site/scripts/build.mjs @@ -1,10 +1,9 @@ -import { cpSync, mkdirSync, readFileSync, rmSync, writeFileSync, copyFileSync } from "node:fs"; -import { mkdtempSync } from "node:fs"; -import { tmpdir } from "node:os"; +import { copyFileSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import path from "node:path"; import { execFileSync } from "node:child_process"; import crypto from "node:crypto"; import { emitSite } from "./render.mjs"; +import { assertVendoredPins, CURRENT, PINS, vendorArchive } from "./archive.mjs"; const site = path.resolve(import.meta.dirname, ".."); const root = path.resolve(site, ".."); @@ -59,8 +58,8 @@ const version = skills[0].version; if (!skills.every((skill) => skill.version === version)) { throw new Error("skill versions differ"); } -if (version !== "0.2.0") { - throw new Error(`version is ${version}; dist publishes hstack-v0.2.0.tar.gz`); +if (version !== CURRENT) { + throw new Error(`version is ${version}; dist publishes hstack-v${CURRENT}.tar.gz`); } const idle = tokens(" hstack:", "category") + skills.reduce((sum, skill) => sum + skill.idle, 0); @@ -93,34 +92,22 @@ const helpers = [ "hstack-test", "hstack-visdiff", ]; -const stage = mkdtempSync(path.join(tmpdir(), "hstack-skills-")); -try { - const top = path.join(stage, "hstack"); - mkdirSync(path.join(top, "skills"), { recursive: true }); - mkdirSync(path.join(top, "scripts"), { recursive: true }); - mkdirSync(path.join(top, "bin"), { recursive: true }); - mkdirSync(path.join(top, "hooks"), { recursive: true }); - const skipCache = (src) => !src.split(path.sep).includes("__pycache__"); - cpSync(skillsRoot, path.join(top, "skills", "hstack"), { recursive: true, filter: skipCache }); - cpSync(path.join(root, "hooks"), path.join(top, "hooks"), { recursive: true, filter: skipCache }); - cpSync(path.join(root, "scripts", "apply_addons.py"), path.join(top, "scripts", "apply_addons.py")); - cpSync(path.join(root, "scripts", "apply_hooks.py"), path.join(top, "scripts", "apply_hooks.py")); - for (const helper of helpers) { - cpSync(path.join(root, "bin", helper), path.join(top, "bin", helper)); +assertVendoredPins(site); +{ + for (const [frozenVersion, pin] of Object.entries(PINS)) { + const bytes = readFileSync(vendorArchive(site, frozenVersion)); + const digest = crypto.createHash("sha256").update(bytes).digest("hex"); + if (digest !== pin) { + throw new Error(`vendored hstack-v${frozenVersion}.tar.gz is ${digest}`); + } + const target = path.join(dist, "dl", `hstack-v${frozenVersion}.tar.gz`); + writeFileSync(target, bytes); + writeFileSync(`${target}.sha256`, `${digest} hstack-v${frozenVersion}.tar.gz\n`); + } + const versioned = path.join(dist, "dl", `hstack-v${CURRENT}.tar.gz`); + if (!PINS[CURRENT]) { + throw new Error(`missing pin for hstack-v${CURRENT}.tar.gz`); } - writeFileSync(path.join(top, "VERSION"), `${version}\n`); - const versioned = path.join(dist, "dl", `hstack-v${version}.tar.gz`); - execFileSync("tar", [ - "--format=ustar", - "--owner=0", - "--group=0", - "--numeric-owner", - "-czf", - versioned, - "-C", - stage, - "hstack", - ], { stdio: "inherit" }); const members = execFileSync("tar", ["-tzf", versioned], { encoding: "utf8" }).trim().split("\n"); const tops = new Set(members.map((member) => member.replace(/^\.\//, "").split("/")[0]).filter(Boolean)); if (tops.size !== 1 || !tops.has("hstack")) { @@ -162,24 +149,15 @@ try { throw new Error(`archive helper is not executable: ${helper}`); } } - const frozenVersion = "0.1.0"; - const frozenSha = "0c8009ee04fb31126b76e4202c91eee14e8d5be7d1cd42ac0cee551012eeda6e"; - const vendorArchive = path.join(site, "vendor", "dl", `hstack-v${frozenVersion}.tar.gz`); - const frozenBytes = readFileSync(vendorArchive); - const frozenDigest = crypto.createHash("sha256").update(frozenBytes).digest("hex"); - if (frozenDigest !== frozenSha) { - throw new Error(`vendored hstack-v${frozenVersion}.tar.gz hash is ${frozenDigest}`); - } - const frozenTarget = path.join(dist, "dl", `hstack-v${frozenVersion}.tar.gz`); - writeFileSync(frozenTarget, frozenBytes); - copyFileSync(`${vendorArchive}.sha256`, `${frozenTarget}.sha256`); const latest = path.join(dist, "dl", "hstack.tar.gz"); copyFileSync(versioned, latest); const hash = crypto.createHash("sha256").update(readFileSync(versioned)).digest("hex"); - if (hash === frozenSha) { - throw new Error("0.2.0 archive matches the frozen 0.1.0 bytes"); + if (hash !== PINS[CURRENT]) { + throw new Error(`latest alias is ${hash}, vendored ${CURRENT} pin is ${PINS[CURRENT]}`); + } + if (hash === PINS["0.1.0"] || hash === PINS["0.2.0"]) { + throw new Error("latest alias still matches an older frozen archive"); } - writeFileSync(`${versioned}.sha256`, `${hash} hstack-v${version}.tar.gz\n`); writeFileSync(`${latest}.sha256`, `${hash} hstack.tar.gz\n`); for (const published of ["install.sh", "install.ps1"]) { if (readFileSync(path.join(dist, published), "utf8").includes("github.com")) { @@ -187,6 +165,4 @@ try { } } console.log(`idle ${idle} planning ${planning} bodies ${bodies} js ${jsGzip} gzip ${hash.slice(0, 12)}`); -} finally { - rmSync(stage, { recursive: true, force: true }); } diff --git a/site/scripts/check-archives.mjs b/site/scripts/check-archives.mjs new file mode 100644 index 0000000..fcafaac --- /dev/null +++ b/site/scripts/check-archives.mjs @@ -0,0 +1,29 @@ +import { buildReleaseArchive, CURRENT, PINS, sha256, vendorArchive } from "./archive.mjs"; +import { readFileSync } from "node:fs"; +import path from "node:path"; + +const site = path.resolve(import.meta.dirname, ".."); +const root = path.resolve(site, ".."); + +function fail(message) { + console.error(`check-archives: ${message}`); + process.exit(1); +} + +for (const [version, pin] of Object.entries(PINS)) { + const file = vendorArchive(site, version); + const digest = sha256(readFileSync(file)); + if (digest !== pin) fail(`vendored hstack-v${version}.tar.gz is ${digest}, pin is ${pin}`); + console.log(`vendored ${version} ${digest}`); +} + +const first = buildReleaseArchive(root, CURRENT); +const second = buildReleaseArchive(root, CURRENT); +const firstHash = sha256(first); +const secondHash = sha256(second); +console.log(`determinism: first ${firstHash}`); +console.log(`determinism: second ${secondHash}`); +if (firstHash !== secondHash) fail("two archive builds differ"); +if (!PINS[CURRENT]) fail(`missing pin for ${CURRENT}`); +if (firstHash !== PINS[CURRENT]) fail(`build ${firstHash} does not match vendored ${CURRENT} pin ${PINS[CURRENT]}`); +console.log(`determinism: match ${firstHash}`); diff --git a/site/scripts/check-no-html.mjs b/site/scripts/check-no-html.mjs index 0e400d3..b5830a4 100644 --- a/site/scripts/check-no-html.mjs +++ b/site/scripts/check-no-html.mjs @@ -38,6 +38,8 @@ const urls = new Set([ "/dl/hstack-v0.1.0.tar.gz.sha256", "/dl/hstack-v0.2.0.tar.gz", "/dl/hstack-v0.2.0.tar.gz.sha256", + "/dl/hstack-v0.2.1.tar.gz", + "/dl/hstack-v0.2.1.tar.gz.sha256", ]); const external = new Set(); @@ -106,16 +108,23 @@ try { const { createHash } = await import("node:crypto"); const actual = createHash("sha256").update(archive).digest("hex"); if (actual !== digest) fail("hstack.tar.gz does not match its sha256"); - const current = Buffer.from(await (await fetch(`${base}/dl/hstack-v0.2.0.tar.gz`)).arrayBuffer()); - if (!current.equals(archive)) fail("latest alias is not hstack-v0.2.0.tar.gz"); + const current = Buffer.from(await (await fetch(`${base}/dl/hstack-v0.2.1.tar.gz`)).arrayBuffer()); + if (!current.equals(archive)) fail("latest alias is not hstack-v0.2.1.tar.gz"); const frozen = Buffer.from(await (await fetch(`${base}/dl/hstack-v0.1.0.tar.gz`)).arrayBuffer()); const frozenHash = createHash("sha256").update(frozen).digest("hex"); if (frozenHash !== "0c8009ee04fb31126b76e4202c91eee14e8d5be7d1cd42ac0cee551012eeda6e") { fail("hstack-v0.1.0.tar.gz bytes changed"); } - if (frozen.equals(archive)) fail("latest alias is still the 0.1.0 archive"); + const previous = Buffer.from(await (await fetch(`${base}/dl/hstack-v0.2.0.tar.gz`)).arrayBuffer()); + const previousHash = createHash("sha256").update(previous).digest("hex"); + if (previousHash !== "c16dfee4cd2841939a97a5cebf816c3fc3e8d71e28f2f1874639ea539ea20810") { + fail("hstack-v0.2.0.tar.gz bytes changed"); + } + if (frozen.equals(archive) || previous.equals(archive)) fail("latest alias still matches an older archive"); const frozenSum = await (await fetch(`${base}/dl/hstack-v0.1.0.tar.gz.sha256`)).text(); if (!frozenSum.startsWith(`${frozenHash} hstack-v0.1.0.tar.gz`)) fail("v0.1.0 checksum file drifted"); + const previousSum = await (await fetch(`${base}/dl/hstack-v0.2.0.tar.gz.sha256`)).text(); + if (!previousSum.startsWith(`${previousHash} hstack-v0.2.0.tar.gz`)) fail("v0.2.0 checksum file drifted"); const page = await (await fetch(`${base}/no-such-page`)).text(); if (!page.includes("0V>`(^ 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 literal 0 HcmV?d00001 diff --git a/site/vendor/dl/hstack-v0.2.0.tar.gz.sha256 b/site/vendor/dl/hstack-v0.2.0.tar.gz.sha256 new file mode 100644 index 0000000..c937615 --- /dev/null +++ b/site/vendor/dl/hstack-v0.2.0.tar.gz.sha256 @@ -0,0 +1 @@ +c16dfee4cd2841939a97a5cebf816c3fc3e8d71e28f2f1874639ea539ea20810 hstack-v0.2.0.tar.gz diff --git a/site/vendor/dl/hstack-v0.2.1.tar.gz b/site/vendor/dl/hstack-v0.2.1.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..013459f9e36f9797a4cd42af128ec5ca4eab1251 GIT binary patch literal 31006 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 literal 0 HcmV?d00001 diff --git a/site/vendor/dl/hstack-v0.2.1.tar.gz.sha256 b/site/vendor/dl/hstack-v0.2.1.tar.gz.sha256 new file mode 100644 index 0000000..dea61c3 --- /dev/null +++ b/site/vendor/dl/hstack-v0.2.1.tar.gz.sha256 @@ -0,0 +1 @@ +61108ad0d5f54ffa2f42ce91ee50758fc459eca7520ba6a1956353678c3c7816 hstack-v0.2.1.tar.gz diff --git a/site/vercel.json b/site/vercel.json index 02614ee..71314ef 100644 --- a/site/vercel.json +++ b/site/vercel.json @@ -99,6 +99,18 @@ { "key": "Cache-Control", "value": "public, max-age=31536000, immutable" } ] }, + { + "source": "/dl/hstack-v0.2.1.tar.gz", + "headers": [ + { "key": "Cache-Control", "value": "public, max-age=31536000, immutable" } + ] + }, + { + "source": "/dl/hstack-v0.2.1.tar.gz.sha256", + "headers": [ + { "key": "Cache-Control", "value": "public, max-age=31536000, immutable" } + ] + }, { "source": "/fonts/(.*)", "headers": [ diff --git a/skills/hstack/arena/SKILL.md b/skills/hstack/arena/SKILL.md index 78bcd3a..cb461a9 100644 --- a/skills/hstack/arena/SKILL.md +++ b/skills/hstack/arena/SKILL.md @@ -1,7 +1,7 @@ --- name: arena description: Try competing approaches, then keep the best parts. -version: 0.2.0 +version: 0.2.1 author: Preetham Kyanam license: MIT platforms: [linux, macos, windows] diff --git a/skills/hstack/blast/SKILL.md b/skills/hstack/blast/SKILL.md index 211cd09..38560ca 100644 --- a/skills/hstack/blast/SKILL.md +++ b/skills/hstack/blast/SKILL.md @@ -1,7 +1,7 @@ --- name: blast description: Find what a small diff can break, and prove the safe fact. -version: 0.2.0 +version: 0.2.1 author: Preetham Kyanam license: MIT platforms: [linux, macos, windows] diff --git a/skills/hstack/council/SKILL.md b/skills/hstack/council/SKILL.md index c017c9e..b38709f 100644 --- a/skills/hstack/council/SKILL.md +++ b/skills/hstack/council/SKILL.md @@ -1,7 +1,7 @@ --- name: council description: Have other models challenge the diff, then fix blockers. -version: 0.2.0 +version: 0.2.1 author: Preetham Kyanam license: MIT platforms: [linux, macos, windows] diff --git a/skills/hstack/hstack/SKILL.md b/skills/hstack/hstack/SKILL.md index 2430685..08da321 100644 --- a/skills/hstack/hstack/SKILL.md +++ b/skills/hstack/hstack/SKILL.md @@ -1,7 +1,7 @@ --- name: hstack description: Pick the playbook for this task and load it. -version: 0.2.0 +version: 0.2.1 author: Preetham Kyanam license: MIT platforms: [linux, macos, windows] diff --git a/skills/hstack/modernize/SKILL.md b/skills/hstack/modernize/SKILL.md index 9474e42..1077ac4 100644 --- a/skills/hstack/modernize/SKILL.md +++ b/skills/hstack/modernize/SKILL.md @@ -1,7 +1,7 @@ --- name: modernize description: Rebase an old PR and decide if it still belongs. -version: 0.2.0 +version: 0.2.1 author: Preetham Kyanam license: MIT platforms: [linux, macos, windows] diff --git a/skills/hstack/principles/SKILL.md b/skills/hstack/principles/SKILL.md index ac0f670..ad1efad 100644 --- a/skills/hstack/principles/SKILL.md +++ b/skills/hstack/principles/SKILL.md @@ -1,7 +1,7 @@ --- name: principles description: Apply the design rule that should change this decision. -version: 0.2.0 +version: 0.2.1 author: Preetham Kyanam license: MIT platforms: [linux, macos, windows] diff --git a/skills/hstack/prove/SKILL.md b/skills/hstack/prove/SKILL.md index b310c5e..885bb73 100644 --- a/skills/hstack/prove/SKILL.md +++ b/skills/hstack/prove/SKILL.md @@ -1,7 +1,7 @@ --- name: prove description: Show a failing check, then a passing one, on real behavior. -version: 0.2.0 +version: 0.2.1 author: Preetham Kyanam license: MIT platforms: [linux, macos, windows] diff --git a/skills/hstack/reframe/SKILL.md b/skills/hstack/reframe/SKILL.md index 3a08969..a6322d2 100644 --- a/skills/hstack/reframe/SKILL.md +++ b/skills/hstack/reframe/SKILL.md @@ -1,7 +1,7 @@ --- name: reframe description: Name the real job before any plan or code. -version: 0.2.0 +version: 0.2.1 author: Preetham Kyanam license: MIT platforms: [linux, macos, windows] diff --git a/skills/hstack/shape/SKILL.md b/skills/hstack/shape/SKILL.md index 629d63a..361a1bf 100644 --- a/skills/hstack/shape/SKILL.md +++ b/skills/hstack/shape/SKILL.md @@ -1,7 +1,7 @@ --- name: shape description: Settle data shape and module boundaries first. -version: 0.2.0 +version: 0.2.1 author: Preetham Kyanam license: MIT platforms: [linux, macos, windows] diff --git a/skills/hstack/ship/SKILL.md b/skills/hstack/ship/SKILL.md index 141d780..2a85234 100644 --- a/skills/hstack/ship/SKILL.md +++ b/skills/hstack/ship/SKILL.md @@ -1,7 +1,7 @@ --- name: ship description: Open a short PR, watch CI, and merge only if told. -version: 0.2.0 +version: 0.2.1 author: Preetham Kyanam license: MIT platforms: [linux, macos, windows] diff --git a/skills/hstack/swarm/SKILL.md b/skills/hstack/swarm/SKILL.md index af7a176..717b169 100644 --- a/skills/hstack/swarm/SKILL.md +++ b/skills/hstack/swarm/SKILL.md @@ -1,7 +1,7 @@ --- name: swarm description: Fan out parallel subagents and return one report. -version: 0.2.0 +version: 0.2.1 author: Preetham Kyanam license: MIT platforms: [linux, macos, windows] diff --git a/skills/hstack/takeover/SKILL.md b/skills/hstack/takeover/SKILL.md index 9634cd8..f27db3b 100644 --- a/skills/hstack/takeover/SKILL.md +++ b/skills/hstack/takeover/SKILL.md @@ -1,7 +1,7 @@ --- name: takeover description: Finish someone else's branch and keep their git credit. -version: 0.2.0 +version: 0.2.1 author: Preetham Kyanam license: MIT platforms: [linux, macos, windows]