From 0c9536a16bebe26ff3bb3a5425df292c864a3b12 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 3 Nov 2026 15:03:45 +0000 Subject: [PATCH] Install plugins over HTTPS, not SSH A git-subdir url in the short owner/repo form clones over SSH, so installing crew or board fails with "Permission denied (publickey)" for any user with no GitHub SSH key. Use the full HTTPS clone URL, and make the validator require it. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01KCgMeGSUWjfoweh4qiasse --- .claude-plugin/marketplace.json | 4 ++-- .github/workflows/validate.yml | 8 +++++++- README.md | 3 ++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index d863924..783bfd8 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -9,7 +9,7 @@ "name": "crew", "source": { "source": "git-subdir", - "url": "johantor/crew", + "url": "https://github.com/johantor/crew.git", "path": "plugin" }, "description": "Team-style feature delivery for Claude Code: a captain agent plans the work and delegates each step to backend, frontend, test, and design specialists behind hook-enforced guardrails, with a consolidated review gate before anything ships. Also pays down tech debt one verified, gated batch at a time." @@ -18,7 +18,7 @@ "name": "board", "source": { "source": "git-subdir", - "url": "johantor/board", + "url": "https://github.com/johantor/board.git", "path": "plugin" }, "description": "A local kanban board of every Claude Code session: what needs you, what is running, what you closed today. Hooks log each session's state, a small Node server on 127.0.0.1 shows it as cards, and a click copies the resume command. Crew runs show their subagents on the session's card." diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 76ef2da..9366756 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -28,7 +28,13 @@ jobs: while IFS=$'\x1f' read -r name kind repo path desc; do case "$kind" in github) url="https://raw.githubusercontent.com/$repo/HEAD/.claude-plugin/plugin.json" ;; - git-subdir) url="https://raw.githubusercontent.com/$repo/HEAD/$path/.claude-plugin/plugin.json" ;; + git-subdir) + # A short owner/repo url clones over SSH, which fails for users with no GitHub key. + case "$repo" in + https://github.com/*.git) repo="${repo#https://github.com/}"; repo="${repo%.git}" ;; + *) echo "FAIL: $name: git-subdir url must be https://github.com//.git"; fail=1; continue ;; + esac + url="https://raw.githubusercontent.com/$repo/HEAD/$path/.claude-plugin/plugin.json" ;; *) echo "FAIL: $name: unsupported source '$kind'"; fail=1; continue ;; esac manifest="$(curl -fsSL "$url")" || { echo "FAIL: $name: cannot fetch $url"; fail=1; continue; } diff --git a/README.md b/README.md index 3aa0e30..aaaa40f 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,8 @@ claude plugin install crew@johantor # and board@johantor ## Maintaining Each plugin lives in the `plugin/` folder of its repository, and the entries install that folder -only (`git-subdir`), so a repo's site and tooling never reach users. +only (`git-subdir`), so a repo's site and tooling never reach users. Each `url` is the full HTTPS +clone URL: the short `owner/repo` form clones over SSH and fails for users with no GitHub SSH key. A plugin entry's `name` and `description` copy the plugin's own `plugin.json`, which is canonical. CI (`validate.yml`) fetches each `plugin.json` from its repository and fails on a