From 9fb19eae633f529de4d197b645a4e81bdda79064 Mon Sep 17 00:00:00 2001 From: Trevin Chow Date: Fri, 15 May 2026 23:42:31 -0700 Subject: [PATCH] refactor: delete sync.sh, dev workflow moves to `npx skills add . -g -y` + native installers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every job sync.sh did has a better replacement: - Per-harness skill dirs (~/.claude/skills, ~/.codex/skills, ~/.agents/skills): `npx skills add . -g -y` writes to every detected harness's home dir and uses symlinks by default. Edits propagate live — no re-deploy step. - Hermes (~/.hermes/skills/research/last30days): `hermes skills install mvanhorn/last30days-skill --force` pulls from GitHub and handles the deploy itself. The script wrapping was redundant. - OpenClaw variant: `clawhub install last30days-official` is what users already run per the README; the maintainer doesn't need a separate variant-deploy step in the public repo's scripts. - Claude marketplace cache (~/.claude/plugins/cache/...): this was a "test against the official install path" hack we shouldn't have been recommending. With PR #400's resolver collapse, STEP 0 no longer enforces the cache as the only valid SKILL.md location. Just install the skill normally via `npx skills` or the marketplace. Cleanup: - DELETE skills/last30days/scripts/sync.sh - tests/test_version_consistency.py — drop test_sync_cache_path_uses_skill_version - CLAUDE.md — replace the sync.sh command + rule with `npx skills add . -g -y` - HERMES_SETUP.md — Installation now uses `hermes skills install --force`; developer-alternative section shows the symlink pattern for live editing - render.py — _skill_version docstring no longer attributes the ".claude-plugin absent" case to sync.sh; explains it via per-harness install paths in general - .github/PULL_REQUEST_TEMPLATE.md — drop the "Ran bash scripts/sync.sh" checklist item CHANGELOG and historical docs (release notes, plan files) keep their existing sync.sh mentions as accurate history. --- .github/PULL_REQUEST_TEMPLATE.md | 1 - CHANGELOG.md | 3 +- CLAUDE.md | 4 +- HERMES_SETUP.md | 32 +++--- skills/last30days/scripts/lib/render.py | 8 +- skills/last30days/scripts/sync.sh | 126 ------------------------ tests/test_version_consistency.py | 8 -- 7 files changed, 20 insertions(+), 162 deletions(-) delete mode 100755 skills/last30days/scripts/sync.sh diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index ad42bd8..50ddb26 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -13,7 +13,6 @@ - [ ] Ran `uv run python -m pytest -q --tb=short` -- [ ] Ran `bash scripts/sync.sh` (if scripts/ changed) ## Related Issues diff --git a/CHANGELOG.md b/CHANGELOG.md index dfd2eb2..cdf4f4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed -- **BREAKING for Codex native-plugin users:** `.codex-plugin/plugin.json` and the matching SKILL_ROOT resolver branch in SKILL.md Step 1. Codex users should install via `npx skills add mvanhorn/last30days-skill` or copy the skill to `~/.codex/skills/last30days/` (which `sync.sh` already writes to in this repo). +- **BREAKING for Codex native-plugin users:** `.codex-plugin/plugin.json` and the matching SKILL_ROOT resolver branch in SKILL.md Step 1. Codex users should install via `npx skills add mvanhorn/last30days-skill` or copy the skill to `~/.codex/skills/last30days/`. +- **`skills/last30days/scripts/sync.sh`.** The maintainer dev-deploy script is gone. Every job it did has a better replacement: `npx skills add . -g -y` symlinks the working tree into every detected harness's skill dir (better than sync.sh's copy model — edits propagate live), `hermes skills install mvanhorn/last30days-skill --force` handles Hermes, `clawhub install last30days-official` handles OpenClaw, and the Claude marketplace cache target was a "test against the official install path" hack we shouldn't have been recommending in the first place. The `test_sync_cache_path_uses_skill_version` test was dropped along with it. CLAUDE.md, HERMES_SETUP.md, the PR template, and a render.py docstring were updated to drop references; CHANGELOG and historical docs (release notes, plan files) keep their existing mentions as accurate history. ## [3.2.0] - 2026-05-09 diff --git a/CLAUDE.md b/CLAUDE.md index 410e382..a48197a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -12,12 +12,12 @@ Python scripts with multi-source search aggregation. ## Commands ```bash python3 skills/last30days/scripts/last30days.py "test query" --emit=compact -bash skills/last30days/scripts/sync.sh +npx skills add . -g -y # one-time: symlink this repo into every detected harness's skill dir ``` ## Rules - `lib/__init__.py` must be bare package marker (comment only, NO eager imports) -- After edits: run `bash skills/last30days/scripts/sync.sh` to deploy +- One-time setup: `npx skills add . -g -y` creates symlinks from each detected harness's skill dir to this repo. Edits in the working tree propagate live to every harness — no re-deploy step needed. - Git remote: origin = public (`mvanhorn/last30days-skill`) ## Beta channel diff --git a/HERMES_SETUP.md b/HERMES_SETUP.md index ce0d36b..f72d667 100644 --- a/HERMES_SETUP.md +++ b/HERMES_SETUP.md @@ -10,28 +10,20 @@ This guide covers installing last30days on Hermes AI Agent. ## Installation -### Option 1: Via sync.sh (Recommended) - ```bash -# Clone the repo -git clone https://github.com/mvanhorn/last30days-skill.git -cd last30days-skill - -# Run the sync script -bash skills/last30days/scripts/sync.sh +hermes skills install mvanhorn/last30days-skill --force ``` -This will auto-detect Hermes and deploy to `~/.hermes/skills/research/last30days/` +This pulls the latest release from GitHub and deploys to `~/.hermes/skills/research/last30days/`. `--force` reinstalls over any existing copy. -### Option 2: Manual Copy +### Developer / live-edit alternative + +If you're hacking on the skill locally and want edits to propagate to Hermes without re-installing, symlink your working tree: ```bash -# Create directory -mkdir -p ~/.hermes/skills/research/last30days - -# Copy files -cp skills/last30days/SKILL.md ~/.hermes/skills/research/last30days/ -cp -r skills/last30days/scripts ~/.hermes/skills/research/last30days/ +git clone https://github.com/mvanhorn/last30days-skill.git +mkdir -p ~/.hermes/skills/research +ln -s "$(pwd)/last30days-skill/skills/last30days" ~/.hermes/skills/research/last30days ``` ## Usage @@ -106,14 +98,12 @@ python3.12 scripts/last30days.py --diagnose ## Updating -To update to the latest version: - ```bash -cd last30days-skill -git pull -bash skills/last30days/scripts/sync.sh +hermes skills install mvanhorn/last30days-skill --force ``` +If you symlinked your working tree (developer alternative above), just `git pull` in the repo — edits propagate live, no re-install step. + ## Support - Original repo: https://github.com/mvanhorn/last30days-skill diff --git a/skills/last30days/scripts/lib/render.py b/skills/last30days/scripts/lib/render.py index 7e4aeff..f8f1541 100644 --- a/skills/last30days/scripts/lib/render.py +++ b/skills/last30days/scripts/lib/render.py @@ -21,9 +21,11 @@ _VERSION_RE = re.compile( def _skill_version() -> str: """Read plugin version from .claude-plugin/plugin.json, falling back to SKILL.md frontmatter. - sync.sh does not copy .claude-plugin/ to non-cache install dirs (~/.codex/skills, - ~/.agents/skills, Hermes), so SKILL.md frontmatter is the fallback that keeps the - badge from emitting v? on those installs. Returns "?" only if both sources are missing. + Per-harness skill install dirs (`~/.claude/skills`, `~/.codex/skills`, `~/.agents/skills`, + Hermes, etc.) do not always carry `.claude-plugin/plugin.json` — that file ships with + plugin-cache installs but not with per-harness skill installs. SKILL.md frontmatter is + the fallback that keeps the badge from emitting v? on those installs. Returns "?" only + if both sources are missing. A corrupt manifest at one ancestor does not shadow a valid manifest at a deeper one (continue, not break). YAML frontmatter accepts double-quoted, single-quoted, or diff --git a/skills/last30days/scripts/sync.sh b/skills/last30days/scripts/sync.sh deleted file mode 100755 index 09a7e08..0000000 --- a/skills/last30days/scripts/sync.sh +++ /dev/null @@ -1,126 +0,0 @@ -#!/usr/bin/env bash -# sync.sh - Deploy last30days skill to all host locations -# Usage: bash skills/last30days/scripts/sync.sh (run from repo root) -set -euo pipefail - -SRC="$(cd "$(dirname "$0")/.." && pwd)" -echo "Source: $SRC" - -COMMON_TARGETS=( - # Claude Code plugin cache for this (public) repo's marketplace install. - # Marketplace name = last30days-skill (.claude-plugin/marketplace.json). - # Plugin name = last30days (.claude-plugin/plugin.json). - # Path shape = .../cache/{marketplace-name}/{plugin-name}/{version}. - # Marketplace pulls overwrite this on update; local sync keeps it fresh - # against the working tree so /last30days reflects local dev without - # waiting for a release. Do NOT add ~/.claude/skills/last30days - it - # creates a duplicate slash-command entry alongside the plugin version. - "$HOME/.claude/plugins/cache/last30days-skill/last30days/3.2.3" - "$HOME/.agents/skills/last30days" - "$HOME/.codex/skills/last30days" -) -OPENCLAW_TARGET="$HOME/.openclaw/skills/last30days" - -sync_target() { - local target="$1" - local skill_md="$2" - - echo "" - echo "--- Syncing to $target ---" - mkdir -p "$target/scripts/lib" - - cp "$skill_md" "$target/SKILL.md" - - rsync -a \ - "$SRC/scripts/last30days.py" \ - "$SRC/scripts/watchlist.py" \ - "$SRC/scripts/briefing.py" \ - "$SRC/scripts/store.py" \ - "$target/scripts/" - rsync -a "$SRC/scripts/lib/"*.py "$target/scripts/lib/" - - # The OpenClaw variant lives in the private repo only. Skip cleanly when - # running this script from the public repo where variants/open does not exist. - if [ -d "$SRC/variants/open" ]; then - mkdir -p "$target/variants/open/references" - rsync -a "$SRC/variants/open/" "$target/variants/open/" - fi - - if [ -d "$SRC/scripts/lib/vendor" ]; then - rsync -a "$SRC/scripts/lib/vendor" "$target/scripts/lib/" - fi - - if [ -d "$SRC/fixtures" ]; then - mkdir -p "$target/fixtures" - rsync -a "$SRC/fixtures/" "$target/fixtures/" - fi - - mod_count=$(ls "$target/scripts/lib/"*.py 2>/dev/null | wc -l | tr -d ' ') - echo " Copied $mod_count modules" - - if ( - cd "$target/scripts" && - python3 -c "import briefing, store, watchlist; from lib import youtube_yt, bird_x, render, ui; print(' Import check: OK')" - ); then - true - else - echo " Import check FAILED" - fi -} - -for t in "${COMMON_TARGETS[@]}"; do - sync_target "$t" "$SRC/SKILL.md" -done - -# Hermes sync: deploy to Hermes skills directory if it exists -HERMES_TARGET="$HOME/.hermes/skills/research/last30days" -if [ -d "$HOME/.hermes/skills/research" ]; then - echo "" - echo "--- Syncing to Hermes ---" - mkdir -p "$HERMES_TARGET/scripts/lib" - - cp "$SRC/SKILL.md" "$HERMES_TARGET/SKILL.md" - - rsync -a \ - "$SRC/scripts/last30days.py" \ - "$SRC/scripts/watchlist.py" \ - "$SRC/scripts/briefing.py" \ - "$SRC/scripts/store.py" \ - "$HERMES_TARGET/scripts/" - rsync -a "$SRC/scripts/lib/"*.py "$HERMES_TARGET/scripts/lib/" - - if [ -d "$SRC/scripts/lib/vendor" ]; then - rsync -a "$SRC/scripts/lib/vendor" "$HERMES_TARGET/scripts/lib/" - fi - - if [ -d "$SRC/fixtures" ]; then - mkdir -p "$HERMES_TARGET/fixtures" - rsync -a "$SRC/fixtures/" "$HERMES_TARGET/fixtures/" - fi - - mod_count=$(ls "$HERMES_TARGET/scripts/lib/"*.py 2>/dev/null | wc -l | tr -d ' ') - echo " Copied $mod_count modules to Hermes" - - if ( - cd "$HERMES_TARGET/scripts" && - python3 -c "import briefing, store, watchlist; from lib import youtube_yt, bird_x, render, ui; print(' Import check: OK')" - ); then - true - else - echo " Import check FAILED" - fi -fi - -# OpenClaw sync only runs when the private-repo OpenClaw variant is present -# in the source tree. The public repo does not ship variants/open (the variant -# is sanitized via strip_for_openclaw.py and published separately from -# last30days-skill-private). -if [ -d "$SRC/variants/open" ]; then - sync_target "$OPENCLAW_TARGET" "$SRC/variants/open/SKILL.md" -else - echo "" - echo "Skipping OpenClaw target (no variants/open in this repo)" -fi - -echo "" -echo "Sync complete." diff --git a/tests/test_version_consistency.py b/tests/test_version_consistency.py index 47d0255..e7fef5d 100644 --- a/tests/test_version_consistency.py +++ b/tests/test_version_consistency.py @@ -21,14 +21,6 @@ class TestVersionConsistency(unittest.TestCase): version = _skill_version() self.assertIn(f"# last30days v{version}:", text) - def test_sync_cache_path_uses_skill_version(self) -> None: - sync_text = (SKILL_ROOT / "scripts" / "sync.sh").read_text(encoding="utf-8") - version = _skill_version() - self.assertIn( - f'last30days-skill/last30days/{version}"', - sync_text, - ) - def test_memory_save_dir_uses_single_env_variable(self) -> None: skill_text = (SKILL_ROOT / "SKILL.md").read_text(encoding="utf-8") compare_text = (SKILL_ROOT / "scripts" / "compare.sh").read_text(encoding="utf-8")