Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions home/.chezmoidata/ai.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,19 @@ ai:
skill: context7-cli
work: []
plugins:
# copilot: how the plugin installs for the github-copilot target.
# plugin -> native `copilot plugin marketplace add/install` (Copilot CLI).
# skill -> `npx skills add <source> -a github-copilot` (no native plugin).
# The claude-code target always installs every entry as a native plugin.
shared:
- name: caveman
marketplace: caveman
source: JuliusBrussee/caveman
copilot: skill
- name: superpowers
marketplace: superpowers-dev
source: obra/superpowers
copilot: plugin
mcp:
shared:
- name: grep
Expand Down
1 change: 1 addition & 0 deletions home/.chezmoidata/packages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ packages:
taps: []
formulas: []
casks:
- copilot-cli
- microsoft-office
- microsoft-teams
- slack
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ AI_PLUGIN_TARGETS=(
)
AI_PLUGINS=(
{{ range $activePlugins -}}
"{{ .name }}|{{ .marketplace }}|{{ .source }}"
"{{ .name }}|{{ .marketplace }}|{{ .source }}|{{ .copilot }}"
{{ end -}}
)
{{ template "lib/install/ai-plugins.sh" . }}
Expand Down
61 changes: 46 additions & 15 deletions home/.chezmoitemplates/lib/install/ai-plugins.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
# @brief Install cross-agent AI plugins for the active agent targets.
# @description
# Installs each plugin in AI_PLUGINS for every agent in AI_PLUGIN_TARGETS.
# Claude Code plugins install through the marketplace CLI; GitHub Copilot has
# no plugin runtime, so the plugin source installs as a skill instead.
# Sourceable from bats tests and injected into chezmoi run scripts via
# chezmoi template rendering.
# Each entry is name|marketplace|source|copilot. Claude Code always installs
# every entry as a native marketplace plugin. GitHub Copilot routes per entry
# on the copilot field: `plugin` uses the native Copilot CLI marketplace,
# `skill` (or anything else) falls back to `npx skills add`. Sourceable from
# bats tests and injected into chezmoi run scripts via chezmoi template
# rendering.

set -Eeuo pipefail

Expand All @@ -22,6 +24,18 @@ function _ai_plugins_add_to_claude() {
claude plugin install "${name}@${marketplace}"
}

#
# @description Add one plugin's marketplace and install it into the Copilot CLI.
# @arg $1 string Plugin name.
# @arg $2 string Marketplace name.
# @arg $3 string Marketplace source repo.
#
function _ai_plugins_add_copilot_plugin() {
local name="$1" marketplace="$2" src="$3"
copilot plugin marketplace add "${src}" &&
copilot plugin install "${name}@${marketplace}"
}

#
# @description Install one plugin source into GitHub Copilot as a skill.
# @arg $1 string Marketplace source repo.
Expand All @@ -48,7 +62,8 @@ function _ai_plugins_for_claude_code() {
name="${entry%%|*}"
rest="${entry#*|}"
marketplace="${rest%%|*}"
src="${rest##*|}"
rest="${rest#*|}"
src="${rest%%|*}"
_ai_plugins_add_to_claude "${name}" "${marketplace}" "${src}" || failed+=("${name}")
done

Expand All @@ -58,23 +73,39 @@ function _ai_plugins_for_claude_code() {
}

#
# @description Install every plugin for the GitHub Copilot target.
# @description Install every plugin for the GitHub Copilot target, routing each
# entry on its copilot field: `plugin` installs natively through the Copilot
# CLI, anything else installs the source as a skill. A missing required CLI
# fails only that entry, so one broken mechanism never blocks the other.
# @exitcode 0 Plugins processed (failures are warned, not fatal).
# @exitcode 1 npx is missing.
#
function _ai_plugins_for_copilot() {
if ! command -v npx >/dev/null 2>&1; then
log_error "[ai-plugins] npx not found. Ensure Node.js is installed (run_onchange_03_install-mise-tools)."
return 1
fi

local -a failed=()
local entry name src
local entry name marketplace src mech rest
for entry in "${AI_PLUGINS[@]-}"; do
[[ -z "${entry}" ]] && continue
name="${entry%%|*}"
src="${entry##*|}"
_ai_plugins_add_to_copilot "${src}" || failed+=("${name}")
rest="${entry#*|}"
marketplace="${rest%%|*}"
rest="${rest#*|}"
src="${rest%%|*}"
mech="${rest##*|}"

if [[ "${mech}" == "plugin" ]]; then
if ! command -v copilot >/dev/null 2>&1; then
log_error "[ai-plugins] copilot CLI not found. Install it (brew install copilot-cli)."
failed+=("${name}")
continue
fi
_ai_plugins_add_copilot_plugin "${name}" "${marketplace}" "${src}" || failed+=("${name}")
else
if ! command -v npx >/dev/null 2>&1; then
log_error "[ai-plugins] npx not found. Ensure Node.js is installed (run_onchange_03_install-mise-tools)."
failed+=("${name}")
continue
fi
_ai_plugins_add_to_copilot "${src}" || failed+=("${name}")
fi
done

if ((${#failed[@]} > 0)); then
Expand Down
8 changes: 5 additions & 3 deletions tests/template/darwin-install-scripts.bats
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ AI_MCP_TEMPLATE="$DOTFILES_ROOT/home/.chezmoiscripts/darwin/run_onchange_08_inst
assert_line 'brew "mise"'
assert_line 'cask "discord"'
assert_line 'mas "Klack", id: 6446206067'
refute_line 'cask "copilot-cli"'
refute_line 'cask "microsoft-office"'
refute_line 'cask "microsoft-teams"'
refute_line 'cask "slack"'
Expand All @@ -67,6 +68,7 @@ AI_MCP_TEMPLATE="$DOTFILES_ROOT/home/.chezmoiscripts/darwin/run_onchange_08_inst

assert_success
assert_line 'brew "mas"'
assert_line 'cask "copilot-cli"'
assert_line 'cask "microsoft-office"'
assert_line 'cask "microsoft-teams"'
assert_line 'cask "slack"'
Expand Down Expand Up @@ -170,8 +172,8 @@ AI_MCP_TEMPLATE="$DOTFILES_ROOT/home/.chezmoiscripts/darwin/run_onchange_08_inst
assert_line 'AI_PLUGIN_TARGETS=('
assert_line --partial '"claude-code"'
refute_line --partial '"github-copilot"'
assert_line --partial '"caveman|caveman|JuliusBrussee/caveman"'
assert_line --partial '"superpowers|superpowers-dev|obra/superpowers"'
assert_line --partial '"caveman|caveman|JuliusBrussee/caveman|skill"'
assert_line --partial '"superpowers|superpowers-dev|obra/superpowers|plugin"'
assert_line --partial 'ai_plugins_install_main'
}

Expand All @@ -182,7 +184,7 @@ AI_MCP_TEMPLATE="$DOTFILES_ROOT/home/.chezmoiscripts/darwin/run_onchange_08_inst
assert_line 'AI_PLUGIN_TARGETS=('
assert_line --partial '"github-copilot"'
refute_line --partial '"claude-code"'
assert_line --partial '"caveman|caveman|JuliusBrussee/caveman"'
assert_line --partial '"caveman|caveman|JuliusBrussee/caveman|skill"'
assert_line --partial 'ai_plugins_install_main'
}

Expand Down
Loading
Loading