mirror of
https://github.com/github/awesome-copilot.git
synced 2026-04-24 09:05:55 +00:00
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>
This commit is contained in:
@@ -21,7 +21,8 @@ See [CONTRIBUTING.md](../CONTRIBUTING.md#adding-skills) for guidelines on how to
|
|||||||
|
|
||||||
**Usage:**
|
**Usage:**
|
||||||
- Browse the skills table below to find relevant capabilities
|
- Browse the skills table below to find relevant capabilities
|
||||||
- Copy the skill folder to your local skills directory
|
- 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/))
|
||||||
|
- Or copy the skill folder manually to your local skills directory
|
||||||
- Reference skills in your prompts or let the agent discover them automatically
|
- Reference skills in your prompts or let the agent discover them automatically
|
||||||
|
|
||||||
| Name | Description | Bundled Assets |
|
| Name | Description | Bundled Assets |
|
||||||
|
|||||||
@@ -103,7 +103,8 @@ See [CONTRIBUTING.md](../CONTRIBUTING.md#adding-skills) for guidelines on how to
|
|||||||
|
|
||||||
**Usage:**
|
**Usage:**
|
||||||
- Browse the skills table below to find relevant capabilities
|
- Browse the skills table below to find relevant capabilities
|
||||||
- Copy the skill folder to your local skills directory
|
- 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/))
|
||||||
|
- Or copy the skill folder manually to your local skills directory
|
||||||
- Reference skills in your prompts or let the agent discover them automatically`,
|
- Reference skills in your prompts or let the agent discover them automatically`,
|
||||||
|
|
||||||
hooksSection: `## 🪝 Hooks
|
hooksSection: `## 🪝 Hooks
|
||||||
|
|||||||
@@ -50,6 +50,27 @@
|
|||||||
<div id="modal-file-menu" class="modal-file-menu" role="menu"></div>
|
<div id="modal-file-menu" class="modal-file-menu" role="menu"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<button
|
||||||
|
id="install-command-btn"
|
||||||
|
class="btn btn-secondary hidden"
|
||||||
|
aria-label="Copy install command"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
fill="currentColor"
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
<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"
|
||||||
|
></path>
|
||||||
|
<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"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
<span aria-hidden="true">Copy Install</span>
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
id="raw-btn"
|
id="raw-btn"
|
||||||
class="btn btn-secondary hidden"
|
class="btn btn-secondary hidden"
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
escapeHtml,
|
escapeHtml,
|
||||||
getResourceIconSvg,
|
getResourceIconSvg,
|
||||||
sanitizeUrl,
|
sanitizeUrl,
|
||||||
|
REPO_IDENTIFIER,
|
||||||
} from "./utils";
|
} from "./utils";
|
||||||
import fm from "front-matter";
|
import fm from "front-matter";
|
||||||
|
|
||||||
@@ -498,6 +499,7 @@ export function setupModal(): void {
|
|||||||
|
|
||||||
const closeBtn = document.getElementById("close-modal");
|
const closeBtn = document.getElementById("close-modal");
|
||||||
const copyBtn = document.getElementById("copy-btn");
|
const copyBtn = document.getElementById("copy-btn");
|
||||||
|
const installCommandBtn = document.getElementById("install-command-btn");
|
||||||
const downloadBtn = document.getElementById("download-btn");
|
const downloadBtn = document.getElementById("download-btn");
|
||||||
const shareBtn = document.getElementById("share-btn");
|
const shareBtn = document.getElementById("share-btn");
|
||||||
const renderBtn = document.getElementById("render-btn");
|
const renderBtn = document.getElementById("render-btn");
|
||||||
@@ -535,6 +537,30 @@ export function setupModal(): void {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
installCommandBtn?.addEventListener("click", async () => {
|
||||||
|
if (currentFilePath && currentFileType === "skill") {
|
||||||
|
const skill = await getSkillItemByFilePath(currentFilePath);
|
||||||
|
if (!skill) {
|
||||||
|
showToast("Could not resolve skill ID.", "error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const command = `gh skill install ${REPO_IDENTIFIER} ${skill.id}`;
|
||||||
|
const originalContent = installCommandBtn.innerHTML;
|
||||||
|
const success = await copyToClipboard(command);
|
||||||
|
showToast(
|
||||||
|
success ? "Install command copied!" : "Failed to copy",
|
||||||
|
success ? "success" : "error"
|
||||||
|
);
|
||||||
|
if (success) {
|
||||||
|
installCommandBtn.innerHTML =
|
||||||
|
'<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>';
|
||||||
|
setTimeout(() => {
|
||||||
|
installCommandBtn.innerHTML = originalContent;
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
downloadBtn?.addEventListener("click", async () => {
|
downloadBtn?.addEventListener("click", async () => {
|
||||||
if (currentFilePath) {
|
if (currentFilePath) {
|
||||||
if (currentFileType === "skill") {
|
if (currentFileType === "skill") {
|
||||||
@@ -849,6 +875,7 @@ export async function openFileModal(
|
|||||||
"install-insiders"
|
"install-insiders"
|
||||||
) as HTMLAnchorElement | null;
|
) as HTMLAnchorElement | null;
|
||||||
const copyBtn = document.getElementById("copy-btn");
|
const copyBtn = document.getElementById("copy-btn");
|
||||||
|
const installCommandBtn = document.getElementById("install-command-btn");
|
||||||
const downloadBtn = document.getElementById("download-btn");
|
const downloadBtn = document.getElementById("download-btn");
|
||||||
const closeBtn = document.getElementById("close-modal");
|
const closeBtn = document.getElementById("close-modal");
|
||||||
if (!modal || !title) return;
|
if (!modal || !title) return;
|
||||||
@@ -885,6 +912,10 @@ export async function openFileModal(
|
|||||||
if (type === "plugin") {
|
if (type === "plugin") {
|
||||||
const modalContent = getModalContent();
|
const modalContent = getModalContent();
|
||||||
if (!modalContent) return;
|
if (!modalContent) return;
|
||||||
|
if (installCommandBtn) {
|
||||||
|
installCommandBtn.style.display = "none";
|
||||||
|
installCommandBtn.classList.add("hidden");
|
||||||
|
}
|
||||||
hideSkillFileSwitcher();
|
hideSkillFileSwitcher();
|
||||||
await openPluginModal(
|
await openPluginModal(
|
||||||
filePath,
|
filePath,
|
||||||
@@ -906,6 +937,11 @@ export async function openFileModal(
|
|||||||
type === "skill" ? "Download skill as ZIP" : "Download file"
|
type === "skill" ? "Download skill as ZIP" : "Download file"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
// Show copy install button only for skills
|
||||||
|
if (installCommandBtn) {
|
||||||
|
installCommandBtn.style.display = type === "skill" ? "inline-flex" : "none";
|
||||||
|
installCommandBtn.classList.toggle("hidden", type !== "skill");
|
||||||
|
}
|
||||||
renderPlainText("Loading...");
|
renderPlainText("Loading...");
|
||||||
hideSkillFileSwitcher();
|
hideSkillFileSwitcher();
|
||||||
updateViewButtons();
|
updateViewButtons();
|
||||||
|
|||||||
@@ -93,6 +93,15 @@ export function renderSkillsHtml(
|
|||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<div class="resource-actions">
|
<div class="resource-actions">
|
||||||
|
<button class="btn btn-secondary copy-install-btn" data-skill-id="${escapeHtml(
|
||||||
|
item.id
|
||||||
|
)}" title="Copy install command">
|
||||||
|
<svg viewBox="0 0 16 16" width="16" height="16" fill="currentColor" aria-hidden="true">
|
||||||
|
<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"/>
|
||||||
|
<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"/>
|
||||||
|
</svg>
|
||||||
|
Copy Install
|
||||||
|
</button>
|
||||||
<button class="btn btn-primary download-skill-btn" data-skill-id="${escapeHtml(
|
<button class="btn btn-primary download-skill-btn" data-skill-id="${escapeHtml(
|
||||||
item.id
|
item.id
|
||||||
)}" title="Download as ZIP">
|
)}" title="Download as ZIP">
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ import {
|
|||||||
showToast,
|
showToast,
|
||||||
downloadZipBundle,
|
downloadZipBundle,
|
||||||
updateQueryParams,
|
updateQueryParams,
|
||||||
|
copyToClipboard,
|
||||||
|
REPO_IDENTIFIER,
|
||||||
} from "../utils";
|
} from "../utils";
|
||||||
import { setupModal, openFileModal } from "../modal";
|
import { setupModal, openFileModal } from "../modal";
|
||||||
import {
|
import {
|
||||||
@@ -109,6 +111,17 @@ function setupResourceListHandlers(list: HTMLElement | null): void {
|
|||||||
|
|
||||||
list.addEventListener("click", (event) => {
|
list.addEventListener("click", (event) => {
|
||||||
const target = event.target as HTMLElement;
|
const target = event.target as HTMLElement;
|
||||||
|
|
||||||
|
const copyInstallButton = target.closest(
|
||||||
|
".copy-install-btn"
|
||||||
|
) as HTMLButtonElement | null;
|
||||||
|
if (copyInstallButton) {
|
||||||
|
event.stopPropagation();
|
||||||
|
const skillId = copyInstallButton.dataset.skillId;
|
||||||
|
if (skillId) copyInstallCommand(skillId, copyInstallButton);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const downloadButton = target.closest(
|
const downloadButton = target.closest(
|
||||||
".download-skill-btn"
|
".download-skill-btn"
|
||||||
) as HTMLButtonElement | null;
|
) as HTMLButtonElement | null;
|
||||||
@@ -138,6 +151,26 @@ function syncUrlState(searchInput: HTMLInputElement | null): void {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function copyInstallCommand(
|
||||||
|
skillId: string,
|
||||||
|
btn: HTMLButtonElement
|
||||||
|
): Promise<void> {
|
||||||
|
const command = `gh skill install ${REPO_IDENTIFIER} ${skillId}`;
|
||||||
|
const originalContent = btn.innerHTML;
|
||||||
|
const success = await copyToClipboard(command);
|
||||||
|
showToast(
|
||||||
|
success ? "Install command copied!" : "Failed to copy",
|
||||||
|
success ? "success" : "error"
|
||||||
|
);
|
||||||
|
if (success) {
|
||||||
|
btn.innerHTML =
|
||||||
|
'<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!';
|
||||||
|
setTimeout(() => {
|
||||||
|
btn.innerHTML = originalContent;
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function downloadSkill(
|
async function downloadSkill(
|
||||||
skillId: string,
|
skillId: string,
|
||||||
btn: HTMLButtonElement
|
btn: HTMLButtonElement
|
||||||
|
|||||||
@@ -8,6 +8,11 @@ const REPO_BASE_URL =
|
|||||||
"https://raw.githubusercontent.com/github/awesome-copilot/main";
|
"https://raw.githubusercontent.com/github/awesome-copilot/main";
|
||||||
const REPO_GITHUB_URL = "https://github.com/github/awesome-copilot/blob/main";
|
const REPO_GITHUB_URL = "https://github.com/github/awesome-copilot/blob/main";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The GitHub repo identifier used for `gh skill install` commands
|
||||||
|
*/
|
||||||
|
export const REPO_IDENTIFIER = "github/awesome-copilot";
|
||||||
|
|
||||||
// VS Code install URL configurations
|
// VS Code install URL configurations
|
||||||
const VSCODE_INSTALL_CONFIG: Record<
|
const VSCODE_INSTALL_CONFIG: Record<
|
||||||
string,
|
string,
|
||||||
|
|||||||
Reference in New Issue
Block a user