From 562f2137298fa2d6ec16ec0278b9bd34c3841527 Mon Sep 17 00:00:00 2001 From: Eddie A Tejeda <669988+eddietejeda@users.noreply.github.com> Date: Tue, 27 Oct 2026 14:45:45 -0700 Subject: [PATCH 1/3] chore(plugin): move the Claude Code plugin into plugin/ The plugin directory scans every file under the plugin root. With the root at the repo top, src/, tests/, CI workflows and scripts/install.sh were flagged as plugin code and held the submission. The marketplace entry will point at plugin/ with a git-subdir source. skills.tar.gz keeps its skills/ prefix (tar -C plugin), so installed CLIs extract it as before. --- .github/workflows/cut-release.yml | 2 +- Cargo.toml | 10 +++++----- README.md | 2 +- dist-workspace.toml | 4 ++-- docs/RELEASING.md | 10 +++++----- .../.claude-plugin}/icon.png | Bin .../.claude-plugin}/plugin.json | 0 {hooks => plugin/hooks}/check-cli.sh | 0 {hooks => plugin/hooks}/hooks.json | 0 {skills => plugin/skills}/hotdata/SKILL.md | 0 .../hotdata/references/DATA_MODEL.template.md | 0 .../skills}/hotdata/references/MODEL_BUILD.md | 0 .../skills}/hotdata/references/WORKFLOWS.md | 0 .../hotdata/subskills/analytics/SKILL.md | 0 .../analytics/references/WORKFLOWS.md | 0 .../hotdata/subskills/geospatial/SKILL.md | 0 .../geospatial/references/functions.md | 0 .../skills}/hotdata/subskills/search/SKILL.md | 0 .../subskills/search/references/INDEXES.md | 0 scripts/check-skills.sh | 18 +++++++++--------- 20 files changed, 23 insertions(+), 23 deletions(-) rename {.claude-plugin => plugin/.claude-plugin}/icon.png (100%) rename {.claude-plugin => plugin/.claude-plugin}/plugin.json (100%) rename {hooks => plugin/hooks}/check-cli.sh (100%) rename {hooks => plugin/hooks}/hooks.json (100%) rename {skills => plugin/skills}/hotdata/SKILL.md (100%) rename {skills => plugin/skills}/hotdata/references/DATA_MODEL.template.md (100%) rename {skills => plugin/skills}/hotdata/references/MODEL_BUILD.md (100%) rename {skills => plugin/skills}/hotdata/references/WORKFLOWS.md (100%) rename {skills => plugin/skills}/hotdata/subskills/analytics/SKILL.md (100%) rename {skills => plugin/skills}/hotdata/subskills/analytics/references/WORKFLOWS.md (100%) rename {skills => plugin/skills}/hotdata/subskills/geospatial/SKILL.md (100%) rename {skills => plugin/skills}/hotdata/subskills/geospatial/references/functions.md (100%) rename {skills => plugin/skills}/hotdata/subskills/search/SKILL.md (100%) rename {skills => plugin/skills}/hotdata/subskills/search/references/INDEXES.md (100%) diff --git a/.github/workflows/cut-release.yml b/.github/workflows/cut-release.yml index 2fb093e5..27a5efa5 100644 --- a/.github/workflows/cut-release.yml +++ b/.github/workflows/cut-release.yml @@ -24,7 +24,7 @@ # tag. # # The skill-drift check inside `prepare` is not bypassed here (no -# SKIP_SKILL_DRIFT). If the job fails on it, update skills/ on main first and +# SKIP_SKILL_DRIFT). If the job fails on it, update plugin/skills/ on main first and # dispatch again. name: Cut Release diff --git a/Cargo.toml b/Cargo.toml index ae5968f0..2cde711f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -101,11 +101,11 @@ homebrew_formula = "hotdata-dev/tap/cli" pre-release-hook = ["git-cliff", "--unreleased", "--tag", "v{{version}}", "--prepend", "CHANGELOG.md"] publish = false pre-release-replacements = [ - { file = "skills/hotdata/SKILL.md", search = "^version: .+", replace = "version: {{version}}", exactly = 1 }, - { file = "skills/hotdata/subskills/search/SKILL.md", search = "^version: .+", replace = "version: {{version}}", exactly = 1 }, - { file = "skills/hotdata/subskills/analytics/SKILL.md", search = "^version: .+", replace = "version: {{version}}", exactly = 1 }, - { file = "skills/hotdata/subskills/geospatial/SKILL.md", search = "^version: .+", replace = "version: {{version}}", exactly = 1 }, - { file = ".claude-plugin/plugin.json", search = "\"version\": \"[^\"]+\"", replace = "\"version\": \"{{version}}\"", exactly = 1 }, + { file = "plugin/skills/hotdata/SKILL.md", search = "^version: .+", replace = "version: {{version}}", exactly = 1 }, + { file = "plugin/skills/hotdata/subskills/search/SKILL.md", search = "^version: .+", replace = "version: {{version}}", exactly = 1 }, + { file = "plugin/skills/hotdata/subskills/analytics/SKILL.md", search = "^version: .+", replace = "version: {{version}}", exactly = 1 }, + { file = "plugin/skills/hotdata/subskills/geospatial/SKILL.md", search = "^version: .+", replace = "version: {{version}}", exactly = 1 }, + { file = "plugin/.claude-plugin/plugin.json", search = "\"version\": \"[^\"]+\"", replace = "\"version\": \"{{version}}\"", exactly = 1 }, # README.md no longer carries a hardcoded version badge — it tracks GitHub releases. ] diff --git a/README.md b/README.md index f6de5344..a3ba209f 100644 --- a/README.md +++ b/README.md @@ -203,7 +203,7 @@ will list the skill twice. What the plugin runs, sends, and fetches: -- **SessionStart hook** (`hooks/check-cli.sh`, Claude Code and Cowork only): +- **SessionStart hook** (`plugin/hooks/check-cli.sh`, Claude Code and Cowork only): checks whether `hotdata` is on `PATH` or in `~/.hotdata/cli`. If it's only in `~/.hotdata/cli`, it adds that folder to `PATH` for the session. If it's missing, it asks Claude to offer to install the CLI. The hook makes no diff --git a/dist-workspace.toml b/dist-workspace.toml index 6b726a55..9c3662b3 100644 --- a/dist-workspace.toml +++ b/dist-workspace.toml @@ -24,11 +24,11 @@ install-updater = false [[dist.extra-artifacts]] artifacts = ["skills.tar.gz"] -build = ["tar", "-czf", "skills.tar.gz", "skills/"] +build = ["tar", "-czf", "skills.tar.gz", "-C", "plugin", "skills/"] [[dist.extra-artifacts]] artifacts = ["SKILL.md"] -build = ["cp", "skills/hotdata/SKILL.md", "SKILL.md"] +build = ["cp", "plugin/skills/hotdata/SKILL.md", "SKILL.md"] [[dist.extra-artifacts]] artifacts = ["install.sh"] diff --git a/docs/RELEASING.md b/docs/RELEASING.md index 3f0a34ff..ff5873ac 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -14,7 +14,7 @@ gh workflow run cut-release.yml -f version=0.40.0 The workflow acts as the `hotdata-automation` GitHub App. A PR opened or a tag pushed with the default `GITHUB_TOKEN` would trigger no other workflows. -If the `prepare` job fails on the skill check, the skills lag the code: update `skills/` on `main` first (see below), then dispatch again. CI does not set `SKIP_SKILL_DRIFT=1`. +If the `prepare` job fails on the skill check, the skills lag the code: update `plugin/skills/` on `main` first (see below), then dispatch again. CI does not set `SKIP_SKILL_DRIFT=1`. ## Manual path @@ -29,10 +29,10 @@ If you run `prepare` locally, the merge of its `release/` PR still trig ## Skill check -Both phases run `scripts/check-skills.sh`. The agent skills under `skills/` ship in every release (`skills.tar.gz`, `SKILL.md`), so the script refuses to release when they lag the code: +Both phases run `scripts/check-skills.sh`. The agent skills under `plugin/skills/` ship in every release (`skills.tar.gz`, `SKILL.md`), so the script refuses to release when they lag the code: -- **Drift** — if `src/` or `README.md` changed since the last `v*` tag and `skills/` did not, the run fails and lists the commits to review. Update the skills and commit, or set `SKIP_SKILL_DRIFT=1` (local runs only) when the release is verified to be skill-neutral. -- **Coverage** — every subcommand the built binary exposes must appear as `hotdata ` somewhere in `skills/**/*.md`, and every long flag in its `--help` must be mentioned too. CI runs this check on every pull request (with the drift check skipped), so a new command or flag cannot merge undocumented. +- **Drift** — if `src/` or `README.md` changed since the last `v*` tag and `plugin/skills/` did not, the run fails and lists the commits to review. Update the skills and commit, or set `SKIP_SKILL_DRIFT=1` (local runs only) when the release is verified to be skill-neutral. +- **Coverage** — every subcommand the built binary exposes must appear as `hotdata ` somewhere in `plugin/skills/**/*.md`, and every long flag in its `--help` must be mentioned too. CI runs this check on every pull request (with the drift check skipped), so a new command or flag cannot merge undocumented. - **Version** (`finish` only) — every `SKILL.md` frontmatter `version:` must equal the crate version. -The drift check is a reminder, not a judge of prose. Before cutting a release, read the commits since the last tag and update `skills/hotdata/SKILL.md` and the subskills to match the current `--help` output and behavior. +The drift check is a reminder, not a judge of prose. Before cutting a release, read the commits since the last tag and update `plugin/skills/hotdata/SKILL.md` and the subskills to match the current `--help` output and behavior. diff --git a/.claude-plugin/icon.png b/plugin/.claude-plugin/icon.png similarity index 100% rename from .claude-plugin/icon.png rename to plugin/.claude-plugin/icon.png diff --git a/.claude-plugin/plugin.json b/plugin/.claude-plugin/plugin.json similarity index 100% rename from .claude-plugin/plugin.json rename to plugin/.claude-plugin/plugin.json diff --git a/hooks/check-cli.sh b/plugin/hooks/check-cli.sh similarity index 100% rename from hooks/check-cli.sh rename to plugin/hooks/check-cli.sh diff --git a/hooks/hooks.json b/plugin/hooks/hooks.json similarity index 100% rename from hooks/hooks.json rename to plugin/hooks/hooks.json diff --git a/skills/hotdata/SKILL.md b/plugin/skills/hotdata/SKILL.md similarity index 100% rename from skills/hotdata/SKILL.md rename to plugin/skills/hotdata/SKILL.md diff --git a/skills/hotdata/references/DATA_MODEL.template.md b/plugin/skills/hotdata/references/DATA_MODEL.template.md similarity index 100% rename from skills/hotdata/references/DATA_MODEL.template.md rename to plugin/skills/hotdata/references/DATA_MODEL.template.md diff --git a/skills/hotdata/references/MODEL_BUILD.md b/plugin/skills/hotdata/references/MODEL_BUILD.md similarity index 100% rename from skills/hotdata/references/MODEL_BUILD.md rename to plugin/skills/hotdata/references/MODEL_BUILD.md diff --git a/skills/hotdata/references/WORKFLOWS.md b/plugin/skills/hotdata/references/WORKFLOWS.md similarity index 100% rename from skills/hotdata/references/WORKFLOWS.md rename to plugin/skills/hotdata/references/WORKFLOWS.md diff --git a/skills/hotdata/subskills/analytics/SKILL.md b/plugin/skills/hotdata/subskills/analytics/SKILL.md similarity index 100% rename from skills/hotdata/subskills/analytics/SKILL.md rename to plugin/skills/hotdata/subskills/analytics/SKILL.md diff --git a/skills/hotdata/subskills/analytics/references/WORKFLOWS.md b/plugin/skills/hotdata/subskills/analytics/references/WORKFLOWS.md similarity index 100% rename from skills/hotdata/subskills/analytics/references/WORKFLOWS.md rename to plugin/skills/hotdata/subskills/analytics/references/WORKFLOWS.md diff --git a/skills/hotdata/subskills/geospatial/SKILL.md b/plugin/skills/hotdata/subskills/geospatial/SKILL.md similarity index 100% rename from skills/hotdata/subskills/geospatial/SKILL.md rename to plugin/skills/hotdata/subskills/geospatial/SKILL.md diff --git a/skills/hotdata/subskills/geospatial/references/functions.md b/plugin/skills/hotdata/subskills/geospatial/references/functions.md similarity index 100% rename from skills/hotdata/subskills/geospatial/references/functions.md rename to plugin/skills/hotdata/subskills/geospatial/references/functions.md diff --git a/skills/hotdata/subskills/search/SKILL.md b/plugin/skills/hotdata/subskills/search/SKILL.md similarity index 100% rename from skills/hotdata/subskills/search/SKILL.md rename to plugin/skills/hotdata/subskills/search/SKILL.md diff --git a/skills/hotdata/subskills/search/references/INDEXES.md b/plugin/skills/hotdata/subskills/search/references/INDEXES.md similarity index 100% rename from skills/hotdata/subskills/search/references/INDEXES.md rename to plugin/skills/hotdata/subskills/search/references/INDEXES.md diff --git a/scripts/check-skills.sh b/scripts/check-skills.sh index 66716711..959ab984 100755 --- a/scripts/check-skills.sh +++ b/scripts/check-skills.sh @@ -4,12 +4,12 @@ # Runs before a release branch is cut and again before the tag is pushed. # Three checks, all mechanical: # -# 1. Drift: if src/ changed since the last release tag, skills/ must have +# 1. Drift: if src/ changed since the last release tag, plugin/skills/ must have # changed too. The script cannot judge prose, so this is the reminder # that a code change needs its SKILL.md follow-up. Override with # SKIP_SKILL_DRIFT=1 when a release is verified to be skill-neutral. # 2. Coverage: every subcommand the built binary exposes, and every long -# flag in its --help, must be named in skills/**/*.md, so a new command +# flag in its --help, must be named in plugin/skills/**/*.md, so a new command # or flag cannot ship undocumented. Hidden flags are not in --help and # are not checked. # 3. Version: every SKILL.md frontmatter `version:`, and the Claude Code @@ -27,7 +27,7 @@ REQUIRE_VERSION=0 [ "${1:-}" = "--require-version" ] && REQUIRE_VERSION=1 BIN="${HOTDATA_BIN:-target/debug/hotdata}" -SKILL_FILES=(skills/hotdata/SKILL.md skills/hotdata/subskills/*/SKILL.md) +SKILL_FILES=(plugin/skills/hotdata/SKILL.md plugin/skills/hotdata/subskills/*/SKILL.md) fail=0 # --- 1. drift --------------------------------------------------------------- @@ -36,16 +36,16 @@ if [ -z "$LAST_TAG" ]; then echo "→ skills: no previous v* tag; skipping drift check" else src_changes="$(git log --oneline "$LAST_TAG"..HEAD -- src/ README.md | grep -v -E 'chore\(deps\)|chore: Release' || true)" - skill_changes="$(git log --oneline "$LAST_TAG"..HEAD -- skills/ || true)" + skill_changes="$(git log --oneline "$LAST_TAG"..HEAD -- plugin/skills/ || true)" if [ -n "$src_changes" ] && [ -z "$skill_changes" ]; then if [ "${SKIP_SKILL_DRIFT:-}" = "1" ]; then echo "→ skills: code changed since $LAST_TAG without a skills change (SKIP_SKILL_DRIFT=1, continuing)" else - echo "error: code changed since $LAST_TAG but skills/ did not." >&2 + echo "error: code changed since $LAST_TAG but plugin/skills/ did not." >&2 echo "" >&2 echo "$src_changes" | sed 's/^/ /' >&2 echo "" >&2 - echo "Review each commit against skills/hotdata/SKILL.md and the subskills, update them," >&2 + echo "Review each commit against plugin/skills/hotdata/SKILL.md and the subskills, update them," >&2 echo "and commit. If none of these change agent-visible behavior, rerun with SKIP_SKILL_DRIFT=1." >&2 fail=1 fi @@ -79,7 +79,7 @@ walk() { } walk -skill_text="$(cat "${SKILL_FILES[@]}" skills/hotdata/references/*.md skills/hotdata/subskills/*/references/*.md)" +skill_text="$(cat "${SKILL_FILES[@]}" plugin/skills/hotdata/references/*.md plugin/skills/hotdata/subskills/*/references/*.md)" missing=() for leaf in "${leaves[@]}"; do if ! grep -qF "hotdata $leaf" <<<"$skill_text"; then @@ -126,9 +126,9 @@ if [ "$REQUIRE_VERSION" = 1 ]; then fail=1 fi done - pv="$(sed -nE 's/^ *"version": "([^"]+)".*/\1/p' .claude-plugin/plugin.json | head -1)" + pv="$(sed -nE 's/^ *"version": "([^"]+)".*/\1/p' plugin/.claude-plugin/plugin.json | head -1)" if [ "$pv" != "$crate" ]; then - echo "error: .claude-plugin/plugin.json declares version $pv, Cargo.toml is $crate" >&2 + echo "error: plugin/.claude-plugin/plugin.json declares version $pv, Cargo.toml is $crate" >&2 fail=1 fi [ "$fail" = 0 ] && echo "→ skills: version ok ($crate)" From b23f90eb78352ad25b0c93edb360f0d30c2268ef Mon Sep 17 00:00:00 2001 From: Eddie A Tejeda <669988+eddietejeda@users.noreply.github.com> Date: Tue, 27 Oct 2026 14:48:23 -0700 Subject: [PATCH 2/3] chore(plugin): drop the listing icon An image referenced from plugin.json is held for manual review. --- plugin/.claude-plugin/icon.png | Bin 11381 -> 0 bytes plugin/.claude-plugin/plugin.json | 3 +-- 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 plugin/.claude-plugin/icon.png diff --git a/plugin/.claude-plugin/icon.png b/plugin/.claude-plugin/icon.png deleted file mode 100644 index c19fd97b1339150ac7bd8f2a2a0ccd1d5b81c170..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11381 zcmeHt`9IYC*FR&_45w~*2hy_y_%qlklU`xji!k@NpGYg z1)qzmxE9C>KHNCsB7aA?i0561Qb9*tx`}z}RgI%Xo}XW^{F^Mw9#|CBrdT=Z{ABIW z3`lG6blG&Xr!Tc^UWO3J#f?CsnCtU3YvfjKS^nr})@^iO!@a-St-m_0@6a)zz(^AU z%by}1?kLkZS?V{_rs|5r<*m)@@|=Bo{fa1?2T(9jdlz51l`y8)n;yQ1(?eQ0l}xVRe;Tv$WgPCntH>pJFov=W1~cT9H0NN#dNMimh9ZZ>y@Lc@ zqEL|Tl1N-s83scby)2=0c;GeKR=(?OVS f-YV#eVN53ZeFah@QR9|f!8QkrR5&2K@Ag-*zaIM=ihpzL|5ov!s`jl* zA4Yxgo2aQMaJLQi+B?}jR;lja<;LppS{FS!lM`Rw_u*l1QrTQzPsZXO_lnW^&QY79 z5tfP9dMKs@db#njjXvHlTAcGb_I>gHoo92I|BLTvNyXyAaM$KimTy_oNVweN1+(}+ zlVc0({M@dL6buL&pBIMqkS#wp$6vc{$I1DUnFNL!eKav1UVb5EiNfnYNbQcC*yA=C$M8|1C?_Zk< zejI*6+!q1g+YRkNHvW1|S=!fT6$GhDbjEez=$WzyLS)K=7gKTwv9OMaG)5RPke~p~^yucB_D2as`&}nyWeBIXbMv0xe&VN~ z25^qy8pnc6o*=rGTk(Er3j#4jBuA1Pk;aF^rEPVzv4_L5KZ%BMQTGGur^;dVcLQnl zrcIut!1B`wzN*tMod>$@xUqe9di)say3D|9^=|pO4?wr~@%Pba%y9#P?uoY@X6Ta} z$&_@nX&yK&ogas5#?Mj9eL!xXsW_uRf(b}zyFKv-nLr#=_ORSaIF$;Pi>%~FK7j8% zP-pE&ATNPPn(jM~zD1BoZ+qJJa3h+*B0q%}2+|-EO`bmjBb|8%zILZ5Nl2=0*ggak$_D?~T+qVD2}`+PD6roZhMEKw6e@B@2zQJ4(=H z8_dB347Z&k4u%T`-aKy)A+yjpe5>Hjb=(Md;N117ST>}9W_Sb@W!w0 zgpjBh44G^aI87sjgV^CIQBhn}D=_zViH!Bhh6G{?Zrd|KX=MclBTTS>O3(%(?GsUS zE@}r5xkzOQCWF{1+f{gkq}>2OUE&LMU7u_PkF<3sgrpga=`|R;BcPbt@phTI5O5l? zF1IxaJZn4RY0TgSTooidOf6r_jXl5m&O;Q&5OiRMSDr%lg2^-vDXy2!3*H0E-b}^KxTpCPekn8NDTs#Acpo$E-De! zl-sT@WM>9Ss2(elA-@2a=zZ9KDbZV0Z_^_hCqL44Gn1U>W{5Ub(0d;AY}_ z8zJdTI%rSN9>64n6;sqS&I%=i9w~bXUxkkAfj#tERZ*Dy!vx)e!xiypOp5}8>69=I zl}HsVqROzK5mLcrsqfo1QvE=vQX`}N(m4>sdn7B?+W~5}-%1kSk{JWR7?UHv{yW6t z;4bgkt!~Uf+9f$g9tdDY&~1JH^#J59n6}8H_+Vi9PB6+&pUy*pn-T@_Ph5EZiE&Db?jbi zx&P)1YBTWO>}to0&<0OxC%V)kMW7yvtYT>(1mJrDH|+S?cBd@a{TDp(&QeBG`+-rv zY_2W>>I_M=uaLiFvi{J|wcUfrDUf68#wBs;M{x1MeO$GBCyZpZo`*|9d`MDq4G?c3 zFW=52c(Vrfu@>vA&tMRkjI}r*F-q{zcYz#W~M^26C zEKZb(?wfrrWIv!PN_7T@?-uKluY*EfPhJ@H?b@++nV?k`G z`W-2~icR>%6>hpL<3o_qn&#pjPa;JZv~A$#ePi4GIFQzR9TJ+hl+bSMo?dw9Vb@Vg zVOU9&u_C@^zr8HGqTu$SG9YTKU-sOt0?$_=RJSji$Qn%KV_X`3RT1y}&2A%7SU8?) z2H|9O!tcdOYg`t91p;*Ha9P8M{RknuQpJ}(@+}nqJ zG1S8lvGjKWY=fqp8L5?HFwc=HwsCrx&R1Y9c2P;YD3GS2^?WsESq`^ks9ec0tn=V7 z73Qg%957>ZYLrxkcqh3N+OCRtS`a!63dFPhE*jY%?T!QzL6=nc5AgueC^S z0I_dGSlla5hWbYOb`!^q#ggjxI6{g$Ci`Bfg^Z{j%*gb@p6B(ry9R*WE1c4Q{E`i& zU&)~a3&LY_v{N~bIrgQ9mL*eaAf*I_%Gi#3#nkL(6092HITy|CERxPxt$fF7c&!dE=A4Fub!G~#_9Ji|=P@ev`DeN1%5!Pc*PM4h1r zLCEo}$l(Z%a(wUWasyO-Vi(TgoB^gL@oo{jmh&{Z}aykGHMer*_isM@o*t zxE~^dcQ>~0xz5~cx8_(c6aNf#%y&*ehEA2@@k?e%RBkDzx7=5^sA#e|hui4aMY$}`E@KsPxKlfkB&*w2X$`ipHga)* zre}|@S(xgTODL=M?Rb8z-tkxLs3mc5j)y!m70Wy#$rxt=GMYMb$?P^n-0hU97xMD> z`EwmVO*XKx*{CD5{dG_YO(+f~wL@ot@1uLo(ExBC-_0Ks*h946)0wWG#PE;k>ys{QUM5ZhV&_R?r!Pd3&`!@1 zG>6y-Qbg#N&joIId{o2E_DA5mt>1o+KouC#K^*1LAg1goO%FasF1*v#&w|-uD)N%e zK_C`0+u6V&zKrOC81fT#5P|dDeXf2?XG}&FSxEuj+>9D<#v@~x%v&!pzEHt@^$Nma z5z1)*U?QWm+NcfmeeQWbm&e7cM}c+fFW>1nuv{G3Mb-^mt%>jb`53q~(#_*vDB!O4 zyEN;9@iENv=Ih;PS$svoBY5b-=)T>Ec4&9bDy25p%lqZ}Ap1_`|NN-sDB2t*0bNld z$T@WaO29;`g||Nx9sjeYkG3-yM(Pu55lPT#lCq{RV1Y4K_p(~zwfe&?xqHf>{FXhJ zua<{eWb4>B2vT{dj4bE@k6xl8NjlFw)P1ttd$`Kqh9y*p99ueggu)KIILl4 zI#JshaTg-#j(YYh4=4+TQC=7g7oXrN6vg0!66QD#>-kg3E zf@mgHv6lsSying4|62eWZarpUGysijB5Ey<0Y~$@jA(9Qy35ntPcW~M64k0zU@DGM z=wHx>B+_pz4kiSGl!103pFx$+-;2C6uhknj?tXk2rrAfKQB$0_=-LA2+2YWtFAdWw z`gL|=FLa0AZykHdx`SIC#A~)eKQwvkbQYdMQmli8_}ar0l5FIU2jqWgC%9zi4;M)$ z!$T-1ya|9fdmzf=H1$OcH9Ea?u&+kkwP<*%X9^bo4hG##maY<|^X;P&Bc-z=Jr68h z>}}6V41J699T8h-UYwJv$n*OU@cmR?Zp-8HjiqBjJuid({n*hJu^K) zsb%VA!t|);&BqrmXB62^yOvEp=~gzq*-nnP4tIX%jm0Dkaie}2*_8r>ulWbHQJTXvvtW@YL3)lTt zTRTy*$d(t|j+Hok*4(?-r27y6v|hEeZ0N>W*;g!U&0ys+ zaYt)J)PKI&|8oA!h5Ne&2Y)-`@USO%q6f9&RUIvCD4>Rhyf`GPGtn6@IZ`}fdDp6P zHiFNIR5iaYX5wocb4JuL4;aG2B?$(Uq@p9Nj=a*}Z~uvIEpI@^`TzOQykJrlVY*Lq zIDBO5Jp#ljM(?~V4j0Lr>-=T(Px@%*6m3*pE>n}J={vGT9xrgdt-+j5kE`G3pTSo( zeiLs#*7d<~eT9tv^u=14YDpCUY$`%d*FPxW1a3MU8s?`Fikwlt&fLVWz(-T42=a}GhKqijVGGRWdc;n z!sP|?Lgu_=2q+~n)Pxh$CIOpGMqlOEI!3WD-08oLk5rtp0sXHGgZb~Pkta)q;+*~m z7^Z^k6_IqnyN@9~A2-~Nx6%z!&yk@Xg^x#PwC4<=#2S|0>`Y(cioro5+;>ZZ2v6CW zGYwS=GFs3OFbTVst%ho``qi$<-Mk4;l%0dh|5Kh}R3j<+n{$+-fKDmB%GLWJuw{0x7EpU)Lrw zUPoKpCpZAIyS(?NIMmXEft!3z=-T6qEVpE4fPpgTvnn8-m{~|Xk)xpkB(1_3m2V=z zir+}T%bdK4ufZH;1X-IHTA%~IqT$1*PY5rmm`pllM)?@$Yo`&g;CIwr{6YCaXo@U% zC@RruvFlqbyKmdf)w?b73_wwP^W_ndL8ohtrV9xf>&nSyLQi& zuPeqk7+%nXeI~m;p|f#-!xl_Px8F}aPx308wYut*eceg{Cvn5+HZqYNKBS4nIFRoR(JH~{$Kz-h6_atlNPbNX&UT4dmW z;CE9PUF9Y+{D0eQY7KEdw_)sS+`sQ1-6li>wQRw{gwCQFd-SeGMANcnc6|JE(X^jl zeUKpl!%_I=VAHFARKtf}@6O_%))B3ayElW%hDkE}{@1ZjcNa#+hF;X}&Ju5bx1H?& zCUf(wNvfx6w9|K17VVOSlR$UX2=#nLaBuJ3aPJR*FLLRPf#jy*8vV zTZEf)>nLEQGc|6iLA1x!ZpwYSRE*J$u#jzxZ0>B>vxLHz+c0c&0KKTq>AKNi$w|yh zWXcIt9!Dy`!dPLAbJaT&N}^qXIy9URa`q~2ID2(Gw0VgeF;2JHO)gBIp$ArZRkv2G zmB?-&?qM(!g~hQ1VJYS@DF$2*w-9sxValOji7s;;esn*Ux%t^ZNicMe;AC&uIr5Q$ zm)PDc{q-P{9?3Iy1+f7z$A+6CJF_C_r~{5hkS!p{LoPV%Yi(cz{Z56A{ZCRAX-x9a zvIH^)o;1M}`?RZ&GFRze^aBI0^{Ogs5XZM1hYj!vi!T$XMtLy7!`5v=TEwWJ&rh|0 zQbNNTwxBQ|qtf{`hy^A+>-Zt{`E`BQQ28LB`1GUQ&&lK6e^|__L6K40&?O7&rg5=p zFMx>)5+SbD&>5@OIC(G2oBJ9p_JBMUCJsq2zH2TD1b$-+i{A)(nws?^Hb6i(Wv!U^ zJs4tJ%J2yQj&BBF{|@)Zz3$2i-E!Wrp5gdbYM6_*_tQPTve#xk<0{-fN zD{E=|FJS|JgQ2m}Oq!)oy%*@_*D>h-+Zy5I1y{ee4-E!EldOg6B_$4eE1YQq% za$d5PNb2`!i!tWxJlSj98z2CzPrGkHCqjHXzs%IU0!-^*n35(INzeV2Exx3d6S(2R zvz)P|`WWUaluU+=rE>P;gPk!&5&l4hL#Iy$DtW$?0qJb5BuB#?h2`a_0!Yx zk`j{M-}FgUdyCDr4*;g(eUpbe0_ku>Rdq8V&h>k&RXMS0 z=(VI98-#K99ztvYqiqQK{3_W5n%MJnZ5;k`-+7DW+yC2W4I+E-SPHFS8iz@S%9FC= z#n!E!wEF#FN1gSEDGJ*w1Vx2~rLKJjnEda-uHoyEbeCs&Mj7{4b>ayxEr7)!JpyES1X;B^?WX^ti94Q@P9&aw!4Xho`r2R5O;JIpEp^5MMG&Fv6Sp*Ma~0O(Tc z;~I)!N}iQxQ0KLX_R_Dba$(XHd2}%q4Eax3O`SaCUyShh?=L|8;pLyPiqT^x zYXvl0XRC-+LHrwO#!a0Xwfkm=#$M>KCaQ?~p8%=?Li~z|E{pi}(W}(AWv*gddj`9| z-}EY()vid|Hy`EnENTEnH73sVNX=wa*v4P!y>+zs^274}Z{G|8hMX&ACKfuIwkNe& zPsql#397o@Do?eU|It%2I-k-r?CSe-OrmQ%wj$Qc-|=0c*~Zqn^DO~$Zv#a4O+@KP zEYunV*s|}76Swy)gd#hCJy=w6@^73@RKL17*4A9=ncw%oQsMEw+T`enO1Q6mF~k2n zy3GBTLBQl&6O&)B-5cf97j7BoYKGQFFTWIoql)u~N{#PNu?Xh8{DXp30DI@hc}r+N z6rIDgrsX%LUcsoxMopZTh7Lmn(V3T*Ur Date: Tue, 27 Oct 2026 14:49:49 -0700 Subject: [PATCH 3/3] docs(skill): install with Homebrew, or a downloaded script the user reviews Replace curl | sh so the plugin no longer directs a download-and-run. --- README.md | 7 ++++--- plugin/skills/hotdata/SKILL.md | 13 ++++++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a3ba209f..26baa46e 100644 --- a/README.md +++ b/README.md @@ -208,9 +208,10 @@ What the plugin runs, sends, and fetches: `~/.hotdata/cli`, it adds that folder to `PATH` for the session. If it's missing, it asks Claude to offer to install the CLI. The hook makes no network requests, installs nothing, and sends no data. -- **Installer**, only after you agree: `curl -fsSL https://hotdata.dev/install | - HOTDATA_NO_SKILLS=1 sh` downloads the CLI from this repository's GitHub - releases, or installs it with Homebrew if `brew` is present. +- **Installer**, only after you agree: `brew install hotdata-dev/tap/cli` when + `brew` is present. Otherwise Claude downloads `https://hotdata.dev/install` to + a file, shows it to you, and runs it with `HOTDATA_NO_SKILLS=1`. It installs + the CLI from this repository's GitHub releases. - **The skill** teaches Claude to run `hotdata` commands. Those commands talk to the Hotdata API (`https://api.hotdata.dev/v1`, or `HOTDATA_API_URL`) with your Hotdata credentials, and send the queries, files, and data source settings diff --git a/plugin/skills/hotdata/SKILL.md b/plugin/skills/hotdata/SKILL.md index 4293afd5..18b65e93 100644 --- a/plugin/skills/hotdata/SKILL.md +++ b/plugin/skills/hotdata/SKILL.md @@ -489,13 +489,20 @@ hotdata manage upgrade Upgrades the CLI in place to the latest release (`brew upgrade` for Homebrew installs, otherwise a direct binary download), refreshing bundled skills to match. After a successful upgrade, re-run your command. -If `hotdata` is not installed at all (not on PATH and not at `~/.hotdata/cli/hotdata`), install it with: +If `hotdata` is not installed at all (not on PATH and not at `~/.hotdata/cli/hotdata`), ask the user before installing. When `brew` is present, install with Homebrew: ```sh -curl -fsSL https://hotdata.dev/install | sh +brew install hotdata-dev/tap/cli ``` -The installer uses Homebrew (`brew install hotdata-dev/tap/cli`) when `brew` is present, otherwise it places a prebuilt binary at `~/.hotdata/cli/hotdata`, and then installs this skill. `HOTDATA_NO_BREW=1` forces the prebuilt path; `HOTDATA_NO_SKILLS=1` skips the skill step. When this skill came from the `hotdata-cli` Claude Code plugin, always set `HOTDATA_NO_SKILLS=1` (`curl -fsSL https://hotdata.dev/install | HOTDATA_NO_SKILLS=1 sh`) so the installer does not add a second copy. +Without Homebrew, download the installer to a file, show it to the user, and run it only after they agree: + +```sh +curl -fsSL https://hotdata.dev/install -o hotdata-install.sh +HOTDATA_NO_SKILLS=1 sh hotdata-install.sh +``` + +The installer places a prebuilt binary at `~/.hotdata/cli/hotdata` (or uses Homebrew if present; `HOTDATA_NO_BREW=1` forces the prebuilt path) and then installs this skill unless `HOTDATA_NO_SKILLS=1` is set. When this skill came from the `hotdata-cli` Claude Code plugin, always set `HOTDATA_NO_SKILLS=1` so the installer does not add a second copy. A newer release can be incompatible with the API, so in an **interactive terminal** the CLI checks for a new release before running any API-touching command and prompts to upgrade. Declining (or `Ctrl-D`) exits without running the command — `hotdata manage upgrade` is then required to continue. The check is a **no-op in non-interactive sessions** (no TTY, `--no-input`, or `HOTDATA_NO_UPDATE_CHECK` set), so typical agent and CI usage is never blocked; set `HOTDATA_NO_UPDATE_CHECK=1` to disable it entirely.