Skip to content

Commit dddab5e

Browse files
Copilotaaronpowell
andauthored
feat: add copy install command from skills list and modal (#1424)
* docs: reference gh skill install command for managing agent skills Agent-Logs-Url: https://github.com/github/awesome-copilot/sessions/e8324f6a-26ee-4d2c-b86f-028cf78499d5 Co-authored-by: aaronpowell <434140+aaronpowell@users.noreply.github.com> * feat: add copy install command button to skills list and modal Agent-Logs-Url: https://github.com/github/awesome-copilot/sessions/efbb7ae2-6ff7-40d2-a8fe-45253caea717 Co-authored-by: aaronpowell <434140+aaronpowell@users.noreply.github.com> * revert: undo changes to 05-skills.md as requested Agent-Logs-Url: https://github.com/github/awesome-copilot/sessions/ba67c365-f36a-47de-af44-629305b9eb94 Co-authored-by: aaronpowell <434140+aaronpowell@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: aaronpowell <434140+aaronpowell@users.noreply.github.com>
1 parent 8ffb353 commit dddab5e

File tree

7 files changed

+108
-2
lines changed

7 files changed

+108
-2
lines changed

docs/README.skills.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ See [CONTRIBUTING.md](../CONTRIBUTING.md#adding-skills) for guidelines on how to
2121

2222
**Usage:**
2323
- Browse the skills table below to find relevant capabilities
24-
- Copy the skill folder to your local skills directory
24+
- Install a skill using the GitHub CLI: `gh skill install github/awesome-copilot <skill-name>` (requires [GitHub CLI v2.90.0+](https://github.blog/changelog/2026-04-16-manage-agent-skills-with-github-cli/))
25+
- Or copy the skill folder manually to your local skills directory
2526
- Reference skills in your prompts or let the agent discover them automatically
2627

2728
| Name | Description | Bundled Assets |

eng/constants.mjs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ See [CONTRIBUTING.md](../CONTRIBUTING.md#adding-skills) for guidelines on how to
103103
104104
**Usage:**
105105
- Browse the skills table below to find relevant capabilities
106-
- Copy the skill folder to your local skills directory
106+
- Install a skill using the GitHub CLI: \`gh skill install github/awesome-copilot <skill-name>\` (requires [GitHub CLI v2.90.0+](https://github.blog/changelog/2026-04-16-manage-agent-skills-with-github-cli/))
107+
- Or copy the skill folder manually to your local skills directory
107108
- Reference skills in your prompts or let the agent discover them automatically`,
108109

109110
hooksSection: `## 🪝 Hooks

website/src/components/Modal.astro

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,27 @@
5050
<div id="modal-file-menu" class="modal-file-menu" role="menu"></div>
5151
</div>
5252
</div>
53+
<button
54+
id="install-command-btn"
55+
class="btn btn-secondary hidden"
56+
aria-label="Copy install command"
57+
>
58+
<svg
59+
viewBox="0 0 16 16"
60+
width="16"
61+
height="16"
62+
fill="currentColor"
63+
aria-hidden="true"
64+
>
65+
<path
66+
d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"
67+
></path>
68+
<path
69+
d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"
70+
></path>
71+
</svg>
72+
<span aria-hidden="true">Copy Install</span>
73+
</button>
5374
<button
5475
id="raw-btn"
5576
class="btn btn-secondary hidden"

website/src/scripts/modal.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
escapeHtml,
1717
getResourceIconSvg,
1818
sanitizeUrl,
19+
REPO_IDENTIFIER,
1920
} from "./utils";
2021
import fm from "front-matter";
2122

@@ -498,6 +499,7 @@ export function setupModal(): void {
498499

499500
const closeBtn = document.getElementById("close-modal");
500501
const copyBtn = document.getElementById("copy-btn");
502+
const installCommandBtn = document.getElementById("install-command-btn");
501503
const downloadBtn = document.getElementById("download-btn");
502504
const shareBtn = document.getElementById("share-btn");
503505
const renderBtn = document.getElementById("render-btn");
@@ -535,6 +537,30 @@ export function setupModal(): void {
535537
}
536538
});
537539

540+
installCommandBtn?.addEventListener("click", async () => {
541+
if (currentFilePath && currentFileType === "skill") {
542+
const skill = await getSkillItemByFilePath(currentFilePath);
543+
if (!skill) {
544+
showToast("Could not resolve skill ID.", "error");
545+
return;
546+
}
547+
const command = `gh skill install ${REPO_IDENTIFIER} ${skill.id}`;
548+
const originalContent = installCommandBtn.innerHTML;
549+
const success = await copyToClipboard(command);
550+
showToast(
551+
success ? "Install command copied!" : "Failed to copy",
552+
success ? "success" : "error"
553+
);
554+
if (success) {
555+
installCommandBtn.innerHTML =
556+
'<svg viewBox="0 0 16 16" width="16" height="16" fill="currentColor" aria-hidden="true"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.75.75 0 0 1 1.06-1.06L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0z"/></svg><span aria-hidden="true">Copied!</span>';
557+
setTimeout(() => {
558+
installCommandBtn.innerHTML = originalContent;
559+
}, 2000);
560+
}
561+
}
562+
});
563+
538564
downloadBtn?.addEventListener("click", async () => {
539565
if (currentFilePath) {
540566
if (currentFileType === "skill") {
@@ -849,6 +875,7 @@ export async function openFileModal(
849875
"install-insiders"
850876
) as HTMLAnchorElement | null;
851877
const copyBtn = document.getElementById("copy-btn");
878+
const installCommandBtn = document.getElementById("install-command-btn");
852879
const downloadBtn = document.getElementById("download-btn");
853880
const closeBtn = document.getElementById("close-modal");
854881
if (!modal || !title) return;
@@ -885,6 +912,10 @@ export async function openFileModal(
885912
if (type === "plugin") {
886913
const modalContent = getModalContent();
887914
if (!modalContent) return;
915+
if (installCommandBtn) {
916+
installCommandBtn.style.display = "none";
917+
installCommandBtn.classList.add("hidden");
918+
}
888919
hideSkillFileSwitcher();
889920
await openPluginModal(
890921
filePath,
@@ -906,6 +937,11 @@ export async function openFileModal(
906937
type === "skill" ? "Download skill as ZIP" : "Download file"
907938
);
908939
}
940+
// Show copy install button only for skills
941+
if (installCommandBtn) {
942+
installCommandBtn.style.display = type === "skill" ? "inline-flex" : "none";
943+
installCommandBtn.classList.toggle("hidden", type !== "skill");
944+
}
909945
renderPlainText("Loading...");
910946
hideSkillFileSwitcher();
911947
updateViewButtons();

website/src/scripts/pages/skills-render.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,15 @@ export function renderSkillsHtml(
9393
</div>
9494
</button>
9595
<div class="resource-actions">
96+
<button class="btn btn-secondary copy-install-btn" data-skill-id="${escapeHtml(
97+
item.id
98+
)}" title="Copy install command">
99+
<svg viewBox="0 0 16 16" width="16" height="16" fill="currentColor" aria-hidden="true">
100+
<path d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"/>
101+
<path d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"/>
102+
</svg>
103+
Copy Install
104+
</button>
96105
<button class="btn btn-primary download-skill-btn" data-skill-id="${escapeHtml(
97106
item.id
98107
)}" title="Download as ZIP">

website/src/scripts/pages/skills.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import {
1717
showToast,
1818
downloadZipBundle,
1919
updateQueryParams,
20+
copyToClipboard,
21+
REPO_IDENTIFIER,
2022
} from "../utils";
2123
import { setupModal, openFileModal } from "../modal";
2224
import {
@@ -109,6 +111,17 @@ function setupResourceListHandlers(list: HTMLElement | null): void {
109111

110112
list.addEventListener("click", (event) => {
111113
const target = event.target as HTMLElement;
114+
115+
const copyInstallButton = target.closest(
116+
".copy-install-btn"
117+
) as HTMLButtonElement | null;
118+
if (copyInstallButton) {
119+
event.stopPropagation();
120+
const skillId = copyInstallButton.dataset.skillId;
121+
if (skillId) copyInstallCommand(skillId, copyInstallButton);
122+
return;
123+
}
124+
112125
const downloadButton = target.closest(
113126
".download-skill-btn"
114127
) as HTMLButtonElement | null;
@@ -138,6 +151,26 @@ function syncUrlState(searchInput: HTMLInputElement | null): void {
138151
});
139152
}
140153

154+
async function copyInstallCommand(
155+
skillId: string,
156+
btn: HTMLButtonElement
157+
): Promise<void> {
158+
const command = `gh skill install ${REPO_IDENTIFIER} ${skillId}`;
159+
const originalContent = btn.innerHTML;
160+
const success = await copyToClipboard(command);
161+
showToast(
162+
success ? "Install command copied!" : "Failed to copy",
163+
success ? "success" : "error"
164+
);
165+
if (success) {
166+
btn.innerHTML =
167+
'<svg viewBox="0 0 16 16" width="16" height="16" fill="currentColor"><path d="M13.78 4.22a.75.75 0 0 1 0 1.06l-7.25 7.25a.75.75 0 0 1-1.06 0L2.22 9.28a.75.75 0 0 1 1.06-1.06L6 10.94l6.72-6.72a.75.75 0 0 1 1.06 0z"/></svg> Copied!';
168+
setTimeout(() => {
169+
btn.innerHTML = originalContent;
170+
}, 2000);
171+
}
172+
}
173+
141174
async function downloadSkill(
142175
skillId: string,
143176
btn: HTMLButtonElement

website/src/scripts/utils.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ const REPO_BASE_URL =
88
"https://raw.githubusercontent.com/github/awesome-copilot/main";
99
const REPO_GITHUB_URL = "https://github.com/github/awesome-copilot/blob/main";
1010

11+
/**
12+
* The GitHub repo identifier used for `gh skill install` commands
13+
*/
14+
export const REPO_IDENTIFIER = "github/awesome-copilot";
15+
1116
// VS Code install URL configurations
1217
const VSCODE_INSTALL_CONFIG: Record<
1318
string,

0 commit comments

Comments
 (0)