mirror of
https://github.com/walter-base/common-workflow.git
synced 2026-09-08 19:26:46 -04:00
The generic archive and its installer are opaque to coding agents: something external has to download and unpack them, which is why the generated installer script exists. Agents can resolve npm packages on their own, so publishing the same release contents to an npm registry lets them install and update without an installer in the loop. Opt in with `publish_npm`. The package is built from the same staged directory as the generic archive, so the two cannot drift, and `package.json` is generated with the release version so it stays in step with the plugin manifest versions that release-please already bumps. Two npm behaviours are handled explicitly: - `npm pack <path>` without a leading `./` is parsed as a GitHub owner/repo spec, so npm attempts a clone instead of packing the directory. - npm's ignore rules can drop dot-directories, and the agent catalogs live in `.agents/` and `.claude-plugin/`. The packed tarball is verified to contain every released path before publishing, rather than shipping a package that installs but has no catalog. The generic archive, installer, and GitHub Release paths are unchanged, so existing consumers are unaffected. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Jm9AfbCJBD4tkxnxxnq7Wm
547 lines
23 KiB
YAML
547 lines
23 KiB
YAML
name: Agent marketplace release
|
|
|
|
on:
|
|
workflow_call:
|
|
inputs:
|
|
target_branch:
|
|
description: Branch that receives release-please changes.
|
|
required: false
|
|
type: string
|
|
default: main
|
|
skill_root:
|
|
description: Canonical skill directory relative to the repository root.
|
|
required: false
|
|
type: string
|
|
default: skills
|
|
claude_marketplace_file:
|
|
description: Claude marketplace manifest relative to the repository root.
|
|
required: false
|
|
type: string
|
|
default: .claude-plugin/marketplace.json
|
|
claude_plugin_file:
|
|
description: Claude plugin manifest relative to the repository root.
|
|
required: false
|
|
type: string
|
|
default: .claude-plugin/plugin.json
|
|
codex_plugin_root:
|
|
description: Codex plugin root relative to the repository root.
|
|
required: false
|
|
type: string
|
|
default: plugins/marketplace
|
|
cursor_plugin_root:
|
|
description: Cursor plugin root relative to the repository root.
|
|
required: false
|
|
type: string
|
|
default: plugins/marketplace
|
|
release_config_file:
|
|
description: Release Please configuration file.
|
|
required: false
|
|
type: string
|
|
default: release-please-config.json
|
|
release_manifest_file:
|
|
description: Release Please manifest file.
|
|
required: false
|
|
type: string
|
|
default: .release-please-manifest.json
|
|
package_paths:
|
|
description: Space-separated paths to package into the release archive.
|
|
required: false
|
|
type: string
|
|
default: skills .claude-plugin .cursor-plugin .agents plugins README.md CHANGELOG.md
|
|
archive_name:
|
|
description: Prefix used for the release archive.
|
|
required: false
|
|
type: string
|
|
default: agent-marketplace
|
|
gitea_package_name:
|
|
description: Public Gitea generic package name for the release artifact.
|
|
required: false
|
|
type: string
|
|
default: agent-marketplace
|
|
claude_plugin_name:
|
|
description: Claude plugin name used in the installation summary.
|
|
required: false
|
|
type: string
|
|
default: marketplace
|
|
codex_plugin_name:
|
|
description: Codex plugin name used in the installation summary.
|
|
required: false
|
|
type: string
|
|
default: marketplace
|
|
claude_marketplace_name:
|
|
description: Claude marketplace name used in the installation summary.
|
|
required: false
|
|
type: string
|
|
default: marketplace
|
|
codex_marketplace_name:
|
|
description: Codex marketplace name shown in the installation summary.
|
|
required: false
|
|
type: string
|
|
default: marketplace
|
|
cursor_plugin_name:
|
|
description: Cursor plugin name shown in the installation summary.
|
|
required: false
|
|
type: string
|
|
default: marketplace
|
|
publish_gitea:
|
|
description: Upload public installers for Claude, Codex, OpenCode, and Cursor to Gitea.
|
|
required: false
|
|
type: boolean
|
|
default: false
|
|
gitea_url:
|
|
description: Base URL of the Gitea instance.
|
|
required: false
|
|
type: string
|
|
default: ""
|
|
gitea_user:
|
|
description: Gitea user or organization that owns the generic package.
|
|
required: false
|
|
type: string
|
|
default: ""
|
|
publish_npm:
|
|
description: >-
|
|
Publish the release contents as an npm package so agents that support npm
|
|
marketplace catalogs can install and auto-update from the registry.
|
|
required: false
|
|
type: boolean
|
|
default: false
|
|
npm_package_name:
|
|
description: >-
|
|
Scoped npm package name, for example `@acme/agent-skills`. The scope must
|
|
match the registry owner. Required when publish_npm is enabled.
|
|
required: false
|
|
type: string
|
|
default: ""
|
|
npm_registry:
|
|
description: >-
|
|
npm registry base URL, for example
|
|
`https://gitea.example.com/api/packages/acme/npm/`. Defaults to the Gitea
|
|
npm registry for gitea_user when gitea_url is set.
|
|
required: false
|
|
type: string
|
|
default: ""
|
|
secrets:
|
|
GITHUB_PAT:
|
|
description: Optional GitHub token for release-please pull requests.
|
|
required: false
|
|
GITEA_TOKEN:
|
|
description: Gitea token with permission to publish generic packages.
|
|
required: false
|
|
NPM_TOKEN:
|
|
description: >-
|
|
Token for the npm registry. Falls back to GITEA_TOKEN when unset, which
|
|
covers publishing to a Gitea npm registry.
|
|
required: false
|
|
|
|
permissions:
|
|
contents: write
|
|
pull-requests: write
|
|
|
|
concurrency:
|
|
group: release-please
|
|
cancel-in-progress: false
|
|
|
|
jobs:
|
|
release-please:
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
release_created: ${{ steps.release.outputs.release_created }}
|
|
tag_name: ${{ steps.release.outputs.tag_name }}
|
|
version: ${{ steps.release.outputs.version }}
|
|
steps:
|
|
- name: Create or update release PR
|
|
id: release
|
|
uses: googleapis/release-please-action@v4
|
|
with:
|
|
token: ${{ secrets.GITHUB_PAT || github.token }}
|
|
target-branch: ${{ inputs.target_branch }}
|
|
config-file: ${{ inputs.release_config_file }}
|
|
manifest-file: ${{ inputs.release_manifest_file }}
|
|
|
|
publish:
|
|
needs: release-please
|
|
if: needs.release-please.outputs.release_created == 'true'
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: write
|
|
steps:
|
|
- name: Check out released version
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ needs.release-please.outputs.tag_name }}
|
|
|
|
- name: Validate released marketplace
|
|
uses: walter-base/common-workflow/actions/validate-agent-marketplace@master
|
|
with:
|
|
skill_root: ${{ inputs.skill_root }}
|
|
claude_marketplace_file: ${{ inputs.claude_marketplace_file }}
|
|
claude_plugin_file: ${{ inputs.claude_plugin_file }}
|
|
codex_plugin_root: ${{ inputs.codex_plugin_root }}
|
|
cursor_plugin_root: ${{ inputs.cursor_plugin_root }}
|
|
|
|
- name: Build release archive
|
|
env:
|
|
VERSION: ${{ needs.release-please.outputs.version }}
|
|
PACKAGE_PATHS: ${{ inputs.package_paths }}
|
|
ARCHIVE_NAME: ${{ inputs.archive_name }}
|
|
shell: bash
|
|
run: |
|
|
dir="${ARCHIVE_NAME}-${VERSION}"
|
|
mkdir -p "dist/${dir}"
|
|
for path in ${PACKAGE_PATHS}; do
|
|
cp -R "$path" "dist/${dir}/"
|
|
done
|
|
tar -czf "dist/${ARCHIVE_NAME}-${VERSION}.tar.gz" -C dist "${dir}"
|
|
|
|
- name: Set up Node
|
|
if: inputs.publish_npm
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 20
|
|
|
|
- name: Publish npm package
|
|
if: inputs.publish_npm
|
|
id: npm
|
|
env:
|
|
ARCHIVE_NAME: ${{ inputs.archive_name }}
|
|
GITEA_URL: ${{ inputs.gitea_url }}
|
|
GITEA_USER: ${{ inputs.gitea_user }}
|
|
NPM_PACKAGE_NAME: ${{ inputs.npm_package_name }}
|
|
NPM_REGISTRY: ${{ inputs.npm_registry }}
|
|
NPM_TOKEN: ${{ secrets.NPM_TOKEN || secrets.GITEA_TOKEN }}
|
|
PACKAGE_PATHS: ${{ inputs.package_paths }}
|
|
VERSION: ${{ needs.release-please.outputs.version }}
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
: "${NPM_PACKAGE_NAME:?Set npm_package_name when publish_npm is enabled}"
|
|
: "${NPM_TOKEN:?Pass NPM_TOKEN or GITEA_TOKEN when publish_npm is enabled}"
|
|
|
|
registry="${NPM_REGISTRY}"
|
|
if [[ -z "$registry" ]]; then
|
|
: "${GITEA_URL:?Set npm_registry, or gitea_url and gitea_user, when publish_npm is enabled}"
|
|
: "${GITEA_USER:?Set npm_registry, or gitea_url and gitea_user, when publish_npm is enabled}"
|
|
registry="${GITEA_URL%/}/api/packages/${GITEA_USER}/npm/"
|
|
fi
|
|
[[ "$registry" == */ ]] || registry="${registry}/"
|
|
|
|
scope="${NPM_PACKAGE_NAME%%/*}"
|
|
if [[ "$scope" != @* ]]; then
|
|
echo "npm_package_name must be scoped (for example @acme/agent-skills) so the registry mapping is unambiguous" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# The staged directory already holds exactly the released content, so the npm
|
|
# package and the generic archive can never drift apart.
|
|
pkg_dir="dist/${ARCHIVE_NAME}-${VERSION}"
|
|
files_json="$(printf '%s\n' ${PACKAGE_PATHS} | jq -R . | jq -s .)"
|
|
jq -n \
|
|
--arg name "$NPM_PACKAGE_NAME" \
|
|
--arg version "$VERSION" \
|
|
--argjson files "$files_json" \
|
|
'{name: $name, version: $version, files: $files, private: false}' \
|
|
> "${pkg_dir}/package.json"
|
|
|
|
# `npm pack <path>` without a leading `./` is parsed as a GitHub owner/repo
|
|
# spec, so npm tries to clone it instead of packing the directory.
|
|
tarball_name="$(npm pack --pack-destination dist "./${pkg_dir}")"
|
|
: "${tarball_name:?npm pack did not produce a tarball}"
|
|
tarball="dist/${tarball_name}"
|
|
|
|
# npm's default ignore rules have historically surprised people with
|
|
# dot-directories, and the agent catalogs live in `.agents/` and
|
|
# `.claude-plugin/`. Fail here rather than shipping an unusable package.
|
|
contents="$(tar -tzf "$tarball")"
|
|
missing=0
|
|
for path in ${PACKAGE_PATHS}; do
|
|
[[ -e "$path" ]] || continue
|
|
if ! grep -q "^package/${path}" <<<"$contents"; then
|
|
echo "npm package is missing released path: ${path}" >&2
|
|
missing=1
|
|
fi
|
|
done
|
|
if [[ "$missing" -ne 0 ]]; then
|
|
echo "Refusing to publish an npm package that does not match the release archive." >&2
|
|
exit 1
|
|
fi
|
|
|
|
registry_auth="${registry#https://}"
|
|
registry_auth="${registry_auth#http://}"
|
|
{
|
|
printf '%s:registry=%s\n' "$scope" "$registry"
|
|
printf '//%s:_authToken=%s\n' "$registry_auth" "$NPM_TOKEN"
|
|
} > "$HOME/.npmrc"
|
|
trap 'rm -f "$HOME/.npmrc"' EXIT
|
|
|
|
npm publish "./${tarball}" --registry "$registry"
|
|
# Keep the packed tarball out of the GitHub Release upload glob.
|
|
rm -f "$tarball"
|
|
|
|
echo "npm_package=${NPM_PACKAGE_NAME}" >> "$GITHUB_OUTPUT"
|
|
echo "npm_registry=${registry}" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Build Gitea installers
|
|
if: inputs.publish_gitea
|
|
env:
|
|
ARCHIVE_NAME: ${{ inputs.archive_name }}
|
|
GITEA_PACKAGE_NAME: ${{ inputs.gitea_package_name }}
|
|
GITEA_URL: ${{ inputs.gitea_url }}
|
|
GITEA_USER: ${{ inputs.gitea_user }}
|
|
VERSION: ${{ needs.release-please.outputs.version }}
|
|
shell: bash
|
|
run: |
|
|
: "${GITEA_URL:?Set gitea_url when publish_gitea is enabled}"
|
|
: "${GITEA_USER:?Set gitea_user when publish_gitea is enabled}"
|
|
cat > "dist/install-${ARCHIVE_NAME}-${VERSION}.sh" <<EOF
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
command="\${1:-}"
|
|
agent="\$command"
|
|
version="\${2:-${VERSION}}"
|
|
if [[ "\$command" == update ]]; then
|
|
agent="\${2:-all}"
|
|
version="latest"
|
|
fi
|
|
if [[ "\$command" == update && "\$agent" == all ]]; then
|
|
for target in claude codex opencode cursor; do
|
|
"\$0" "\$target" latest
|
|
done
|
|
exit 0
|
|
fi
|
|
case "\$agent" in
|
|
claude|codex|opencode|cursor) ;;
|
|
*) echo "Usage: \$0 {claude|codex|opencode|cursor} [version] | update [agent|all]" >&2; exit 2 ;;
|
|
esac
|
|
if [[ "\$version" == latest ]]; then
|
|
version="\$(curl --fail --location --retry 3 "${GITEA_URL%/}/api/v1/packages/${GITEA_USER}/generic/${GITEA_PACKAGE_NAME}/-/latest" | jq -r '.version // empty')"
|
|
: "\${version:?Gitea did not return a latest package version}"
|
|
fi
|
|
install_dir="\${MEDIVA_PLUGIN_DIR:-\$HOME/.local/share/${ARCHIVE_NAME}/\$agent}"
|
|
archive_url="${GITEA_URL%/}/api/packages/${GITEA_USER}/generic/${GITEA_PACKAGE_NAME}/\${version}/${ARCHIVE_NAME}-\${version}.tar.gz"
|
|
tmp_dir="\$(mktemp -d)"
|
|
trap 'rm -rf "\$tmp_dir"' EXIT
|
|
|
|
curl --fail --location --retry 3 "\$archive_url" -o "\$tmp_dir/plugin.tar.gz"
|
|
mkdir -p "\$tmp_dir/extracted"
|
|
tar -xzf "\$tmp_dir/plugin.tar.gz" -C "\$tmp_dir/extracted"
|
|
rm -rf "\$install_dir"
|
|
mkdir -p "\$(dirname "\$install_dir")"
|
|
mv "\$tmp_dir/extracted/${ARCHIVE_NAME}-\${version}" "\$install_dir"
|
|
|
|
case "\$agent" in
|
|
claude)
|
|
marketplace_name="\$(jq -r '.name // empty' "\$install_dir/.claude-plugin/marketplace.json")"
|
|
: "\${marketplace_name:?Claude marketplace manifest is missing a name}"
|
|
claude plugin marketplace remove "\$marketplace_name" >/dev/null 2>&1 || true
|
|
claude plugin marketplace add "\$install_dir"
|
|
plugin_name="\$(jq -r '.plugins[0].name // empty' "\$install_dir/.claude-plugin/marketplace.json")"
|
|
claude plugin install "\$plugin_name@\$marketplace_name"
|
|
;;
|
|
codex)
|
|
marketplace_name="\$(jq -r '.name // empty' "\$install_dir/.agents/plugins/marketplace.json")"
|
|
: "\${marketplace_name:?Codex marketplace manifest is missing a name}"
|
|
codex plugin marketplace remove "\$marketplace_name" >/dev/null 2>&1 || true
|
|
codex plugin marketplace add "\$install_dir"
|
|
plugin_name="\$(jq -r '.plugins[0].name // empty' "\$install_dir/.agents/plugins/marketplace.json")"
|
|
codex plugin add "\$plugin_name@\$marketplace_name"
|
|
;;
|
|
opencode|cursor)
|
|
npx --yes skills add "\$install_dir/skills" --agent "\$agent" --skill '*' --yes --global
|
|
;;
|
|
esac
|
|
echo "Installed skills for \$agent from Gitea."
|
|
EOF
|
|
chmod +x "dist/install-${ARCHIVE_NAME}-${VERSION}.sh"
|
|
|
|
if false; then
|
|
cat > "dist/install-${ARCHIVE_NAME}-codex-${VERSION}.sh" <<EOF
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
version="\${1:-${VERSION}}"
|
|
install_dir="\${MEDIVA_PLUGIN_DIR:-\$HOME/.local/share/${ARCHIVE_NAME}/codex}"
|
|
archive_url="${GITEA_URL%/}/api/packages/${GITEA_USER}/generic/${CODEX_PACKAGE_NAME}/\${version}/${ARCHIVE_NAME}-codex-\${version}.tar.gz"
|
|
tmp_dir="\$(mktemp -d)"
|
|
trap 'rm -rf "\$tmp_dir"' EXIT
|
|
|
|
curl --fail --location --retry 3 "\$archive_url" -o "\$tmp_dir/plugin.tar.gz"
|
|
mkdir -p "\$tmp_dir/extracted"
|
|
tar -xzf "\$tmp_dir/plugin.tar.gz" -C "\$tmp_dir/extracted"
|
|
rm -rf "\$install_dir"
|
|
mkdir -p "\$(dirname "\$install_dir")"
|
|
mv "\$tmp_dir/extracted/${ARCHIVE_NAME}-\${version}" "\$install_dir"
|
|
|
|
marketplace_name="\$(jq -r '.name // empty' "\$install_dir/.agents/plugins/marketplace.json")"
|
|
: "\${marketplace_name:?Codex marketplace manifest is missing a name}"
|
|
codex plugin marketplace remove '${CODEX_MARKETPLACE_NAME}' >/dev/null 2>&1 || true
|
|
codex plugin marketplace remove "\$marketplace_name" >/dev/null 2>&1 || true
|
|
codex plugin marketplace add "\$install_dir"
|
|
codex plugin add "${CODEX_PLUGIN_NAME}@\$marketplace_name"
|
|
echo "Installed ${CODEX_PLUGIN_NAME} for Codex from Gitea marketplace \$marketplace_name."
|
|
EOF
|
|
chmod +x "dist/install-${ARCHIVE_NAME}-codex-${VERSION}.sh"
|
|
|
|
cat > "dist/install-${ARCHIVE_NAME}-opencode-${VERSION}.sh" <<EOF
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
version="\${1:-${VERSION}}"
|
|
install_dir="\${MEDIVA_PLUGIN_DIR:-\$HOME/.local/share/${ARCHIVE_NAME}/opencode}"
|
|
archive_url="${GITEA_URL%/}/api/packages/${GITEA_USER}/generic/${OPENCODE_PACKAGE_NAME}/\${version}/${ARCHIVE_NAME}-opencode-\${version}.tar.gz"
|
|
tmp_dir="\$(mktemp -d)"
|
|
trap 'rm -rf "\$tmp_dir"' EXIT
|
|
|
|
curl --fail --location --retry 3 "\$archive_url" -o "\$tmp_dir/plugin.tar.gz"
|
|
mkdir -p "\$tmp_dir/extracted"
|
|
tar -xzf "\$tmp_dir/plugin.tar.gz" -C "\$tmp_dir/extracted"
|
|
rm -rf "\$install_dir"
|
|
mkdir -p "\$(dirname "\$install_dir")"
|
|
mv "\$tmp_dir/extracted/${ARCHIVE_NAME}-\${version}" "\$install_dir"
|
|
|
|
npx --yes skills add "\$install_dir/skills" --agent opencode --skill '*' --yes --global
|
|
echo "Installed skills for OpenCode from Gitea."
|
|
EOF
|
|
chmod +x "dist/install-${ARCHIVE_NAME}-opencode-${VERSION}.sh"
|
|
|
|
cat > "dist/install-${ARCHIVE_NAME}-cursor-${VERSION}.sh" <<EOF
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
version="\${1:-${VERSION}}"
|
|
install_dir="\${MEDIVA_PLUGIN_DIR:-\$HOME/.local/share/${ARCHIVE_NAME}/cursor}"
|
|
archive_url="${GITEA_URL%/}/api/packages/${GITEA_USER}/generic/${CURSOR_PACKAGE_NAME}/\${version}/${ARCHIVE_NAME}-cursor-\${version}.tar.gz"
|
|
tmp_dir="\$(mktemp -d)"
|
|
trap 'rm -rf "\$tmp_dir"' EXIT
|
|
|
|
curl --fail --location --retry 3 "\$archive_url" -o "\$tmp_dir/plugin.tar.gz"
|
|
mkdir -p "\$tmp_dir/extracted"
|
|
tar -xzf "\$tmp_dir/plugin.tar.gz" -C "\$tmp_dir/extracted"
|
|
rm -rf "\$install_dir"
|
|
mkdir -p "\$(dirname "\$install_dir")"
|
|
mv "\$tmp_dir/extracted/${ARCHIVE_NAME}-\${version}" "\$install_dir"
|
|
|
|
npx --yes skills add "\$install_dir/skills" --agent cursor --skill '*' --yes --global
|
|
echo "Installed skills for Cursor from Gitea."
|
|
EOF
|
|
chmod +x "dist/install-${ARCHIVE_NAME}-cursor-${VERSION}.sh"
|
|
fi
|
|
|
|
- name: Upload archive to Gitea
|
|
if: inputs.publish_gitea
|
|
id: gitea
|
|
env:
|
|
ARCHIVE_NAME: ${{ inputs.archive_name }}
|
|
GITEA_PACKAGE_NAME: ${{ inputs.gitea_package_name }}
|
|
GITEA_URL: ${{ inputs.gitea_url }}
|
|
GITEA_USER: ${{ inputs.gitea_user }}
|
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
|
VERSION: ${{ needs.release-please.outputs.version }}
|
|
run: |
|
|
: "${GITEA_URL:?Set gitea_url when publish_gitea is enabled}"
|
|
: "${GITEA_USER:?Set gitea_user when publish_gitea is enabled}"
|
|
: "${GITEA_TOKEN:?Pass GITEA_TOKEN when publish_gitea is enabled}"
|
|
archive="${ARCHIVE_NAME}-${VERSION}.tar.gz"
|
|
installer="install-${ARCHIVE_NAME}-${VERSION}.sh"
|
|
package_base="${GITEA_URL%/}/api/packages/${GITEA_USER}/generic/${GITEA_PACKAGE_NAME}/${VERSION}"
|
|
for upload in \
|
|
"dist/${archive}|${package_base}/${archive}" \
|
|
"dist/${installer}|${package_base}/${installer}"; do
|
|
file="${upload%%|*}"
|
|
url="${upload#*|}"
|
|
curl --fail-with-body --retry 3 \
|
|
--user "${GITEA_USER}:${GITEA_TOKEN}" \
|
|
--upload-file "$file" \
|
|
"$url"
|
|
done
|
|
echo "installer_url=${package_base}/${installer}" >> "$GITHUB_OUTPUT"
|
|
|
|
- name: Upload archive to GitHub Release
|
|
if: ${{ !inputs.publish_gitea }}
|
|
uses: softprops/action-gh-release@v2
|
|
with:
|
|
tag_name: ${{ needs.release-please.outputs.tag_name }}
|
|
files: dist/*
|
|
|
|
- name: Write GitHub installation summary
|
|
env:
|
|
VERSION: ${{ needs.release-please.outputs.version }}
|
|
TAG: ${{ needs.release-please.outputs.tag_name }}
|
|
ARCHIVE_NAME: ${{ inputs.archive_name }}
|
|
REPOSITORY: ${{ github.repository }}
|
|
SERVER_URL: ${{ github.server_url }}
|
|
SKILL_ROOT: ${{ inputs.skill_root }}
|
|
CLAUDE_PLUGIN_NAME: ${{ inputs.claude_plugin_name }}
|
|
CLAUDE_MARKETPLACE_NAME: ${{ inputs.claude_marketplace_name }}
|
|
CODEX_PLUGIN_NAME: ${{ inputs.codex_plugin_name }}
|
|
CODEX_MARKETPLACE_NAME: ${{ inputs.codex_marketplace_name }}
|
|
CURSOR_PLUGIN_NAME: ${{ inputs.cursor_plugin_name }}
|
|
GITEA_INSTALLER_URL: ${{ steps.gitea.outputs.installer_url }}
|
|
NPM_PACKAGE: ${{ steps.npm.outputs.npm_package }}
|
|
NPM_REGISTRY_URL: ${{ steps.npm.outputs.npm_registry }}
|
|
run: |
|
|
{
|
|
printf '# Agent plugin %s\n\n' "$VERSION"
|
|
printf 'Release tag: `%s`\n\n' "$TAG"
|
|
|
|
if [[ -n "$NPM_PACKAGE" ]]; then
|
|
printf '## npm registry\n\n'
|
|
printf 'Published `%s@%s` to `%s`.\n\n' "$NPM_PACKAGE" "$VERSION" "$NPM_REGISTRY_URL"
|
|
printf 'Agents that support npm marketplace catalogs can install this package '
|
|
printf 'directly and pick up later releases without re-running an installer. '
|
|
printf 'Authenticate first if the registry is private:\n\n'
|
|
printf '%s\n' '```bash'
|
|
printf 'npm config set %s:registry %s\n' "${NPM_PACKAGE%%/*}" "$NPM_REGISTRY_URL"
|
|
printf '%s\n\n' '```'
|
|
fi
|
|
|
|
if [[ -n "$GITEA_INSTALLER_URL" ]]; then
|
|
printf '## Claude Code\n\n'
|
|
printf '%s\n' '```bash'
|
|
printf 'curl --fail --location --retry 3 "%s" | bash -s -- claude\n' "$GITEA_INSTALLER_URL"
|
|
printf '%s\n\n' '```'
|
|
|
|
printf '## Codex\n\n'
|
|
printf '%s\n' '```bash'
|
|
printf 'curl --fail --location --retry 3 "%s" | bash -s -- codex\n' "$GITEA_INSTALLER_URL"
|
|
printf '%s\n\n' '```'
|
|
else
|
|
printf '## Claude Code\n\n'
|
|
printf '%s\n' '```bash'
|
|
printf 'claude plugin marketplace add %s@%s\n' "$REPOSITORY" "$TAG"
|
|
printf 'claude plugin install %s@%s\n' "$CLAUDE_PLUGIN_NAME" "$CLAUDE_MARKETPLACE_NAME"
|
|
printf '%s\n\n' '```'
|
|
|
|
printf '## Codex\n\n'
|
|
printf '%s\n' '```bash'
|
|
printf 'codex plugin marketplace add %s --ref %s\n' "$REPOSITORY" "$TAG"
|
|
printf 'codex plugin add %s@%s\n' "$CODEX_PLUGIN_NAME" "$CODEX_MARKETPLACE_NAME"
|
|
printf '%s\n\n' '```'
|
|
fi
|
|
|
|
if [[ -n "$GITEA_INSTALLER_URL" ]]; then
|
|
printf '## OpenCode\n\n'
|
|
printf '%s\n' '```bash'
|
|
printf 'curl --fail --location --retry 3 "%s" | bash -s -- opencode\n' "$GITEA_INSTALLER_URL"
|
|
printf '%s\n\n' '```'
|
|
|
|
printf '## Cursor\n\n'
|
|
printf '%s\n' '```bash'
|
|
printf 'curl --fail --location --retry 3 "%s" | bash -s -- cursor\n' "$GITEA_INSTALLER_URL"
|
|
printf '%s\n\n' '```'
|
|
else
|
|
printf '## OpenCode and Cursor\n\n'
|
|
printf '%s\n' '```bash'
|
|
printf 'npx skills add %s/%s/tree/%s/%s --agent opencode --skill '\''*'\'' --yes --global\n' "$SERVER_URL" "$REPOSITORY" "$TAG" "$SKILL_ROOT"
|
|
printf 'npx skills add %s/%s/tree/%s/%s --agent cursor --skill '\''*'\'' --yes --global\n' "$SERVER_URL" "$REPOSITORY" "$TAG" "$SKILL_ROOT"
|
|
printf '%s\n' '```'
|
|
fi
|
|
|
|
if [[ -n "$GITEA_INSTALLER_URL" ]]; then
|
|
printf '\nUpdate all installed agents later with:\n\n%s\n\n' '```bash'
|
|
printf 'curl --fail --location --retry 3 "%s" | bash -s -- update all\n' "$GITEA_INSTALLER_URL"
|
|
printf '%s\n' '```'
|
|
printf 'Installers are public Gitea artifacts; no Gitea token is required.\n'
|
|
fi
|
|
} >> "$GITHUB_STEP_SUMMARY"
|