diff --git a/.github/workflows/deploy-pages.yml b/.github/workflows/deploy-pages.yml index 4857a6b..85e6430 100644 --- a/.github/workflows/deploy-pages.yml +++ b/.github/workflows/deploy-pages.yml @@ -6,7 +6,6 @@ on: branches: [main] paths: - 'marketplace/**' - - 'catalog/**' - 'scripts/**' - 'docs/**' - '.github/workflows/deploy-pages.yml' diff --git a/AGENTS.md b/AGENTS.md index 35da3a2..42916ba 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -17,8 +17,6 @@ This is the **catalog and marketplace** for Red Hat agentic collections. It serv agentic-collections-catalog/ ├── marketplace/ │ └── rh-agentic-collection.yml # Single source of truth for pack discovery -├── catalog/ -│ └── schema.yaml # JSON Schema for .catalog/collection.yaml files in skills repos ├── docs/ # Static site (agentskills.io) │ ├── index.html # SPA entry point │ ├── app.js # Rendering and search logic (XSS-safe, no innerHTML) @@ -80,7 +78,7 @@ Do not add packs to `docs/data.json` or any other file directly. Add them to the - **Marketplace is the single source of truth.** Do not add packs, icons, or titles anywhere else. - **Generated files are read-only.** `docs/data.json`, `docs/mcp.json`, and `docs/collections/*.html` are rebuilt on every run — manual edits will be overwritten. - **No skills development here.** To create or modify skills, work in the appropriate skills source repo. -- **Schema changes need coordination.** Updating `catalog/schema.yaml` requires matching changes in all skills repos' `.catalog/` directories. +- **Schema changes need coordination.** Updating `.catalog/collection.yaml` in skills repos requires consistent field usage across all packs. - **Security.** All DOM manipulation in `app.js` uses `textContent` and `createElement` — never `innerHTML` with external data. ## CI diff --git a/OPEN_ITEMS.md b/OPEN_ITEMS.md index 93aee2b..85e4a20 100644 --- a/OPEN_ITEMS.md +++ b/OPEN_ITEMS.md @@ -5,8 +5,14 @@ * Replace [mcp.json](./docs/mcp.json) ### External contributions -* How to replace collection pack info in absemce of collection.yml? - * README - * License - * List of skills - * Installation \ No newline at end of file +* How to replace collection pack info in absence of collection.yml? + * ~~README~~ + * ~~License~~ + * ~~List of skills~~ + * ~~Installation~~ + +### Evals +* Replace eval with scorecards + +### ??? +* \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 87ea479..9264b23 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,6 @@ # Documentation Site -This directory contains the generated GitHub Pages site for agentic-collections. +This directory contains the generated GitHub Pages site for agentic-collections-catalog. ## Files @@ -42,7 +42,7 @@ When changing docs presentation metadata (`styles.css`, `app.js`, `mcp.json`): 2. Run validation checks: ```bash -make validate +make test ``` 3. Review validation output before merge. diff --git a/docs/app.js b/docs/app.js index 702fd2a..0bf65af 100644 --- a/docs/app.js +++ b/docs/app.js @@ -1,5 +1,5 @@ /** - * agentic-collections Documentation Site + * agentic-collections-catalog Documentation Site * * SECURITY: All DOM manipulation uses textContent and createElement * to prevent XSS vulnerabilities. No innerHTML with user data. @@ -17,7 +17,7 @@ const JS_STYLE_TOKENS = { }; /** Default LICENSE in upstream repo (collection legal_resources may override). */ -const UPSTREAM_REPO_LICENSE_URL = 'https://github.com/RHEcosystemAppEng/agentic-collections/blob/main/LICENSE'; +const UPSTREAM_REPO_LICENSE_URL = 'https://github.com/RHEcosystemAppEng/agentic-collections-catalog/blob/main/LICENSE'; /** * Update toolbar counter badges @@ -737,475 +737,6 @@ function toggleInstallCallout() { toggle.setAttribute('aria-expanded', callout.classList.contains('collapsed') ? 'false' : 'true'); } -/** - * Show pack details modal (XSS-safe) - */ -function showPackDetails(packName) { - const pack = data.packs.find(p => p.name === packName); - if (!pack) return; - - const modal = document.getElementById('pack-modal'); - const details = document.getElementById('pack-details'); - - // Clear previous content - details.textContent = ''; - - // Create modal header - const header = document.createElement('div'); - header.className = 'modal-header'; - - // Close button - const closeBtn = document.createElement('span'); - closeBtn.className = 'close'; - closeBtn.textContent = '×'; - closeBtn.onclick = () => { - modal.style.display = 'none'; - document.body.style.overflow = ''; // Restore background scrolling - }; - header.appendChild(closeBtn); - - const headerTop = document.createElement('div'); - headerTop.className = 'modal-header-top'; - - const titleGroup = document.createElement('div'); - titleGroup.className = 'modal-title-group'; - - const h2 = document.createElement('h2'); - h2.textContent = pack.plugin?.title || pack.plugin?.name || pack.name; - titleGroup.appendChild(h2); - - // Owner subtitle - const ownerSubtitle = document.createElement('div'); - ownerSubtitle.className = 'pack-owner-subtitle'; - ownerSubtitle.textContent = 'By Red Hat'; - ownerSubtitle.style.color = 'var(--text-muted)'; - ownerSubtitle.style.fontSize = '0.95rem'; - ownerSubtitle.style.marginTop = '0.5rem'; - titleGroup.appendChild(ownerSubtitle); - - // Counts (skills + agents + MCPs) - const counts = document.createElement('div'); - counts.className = 'modal-counts'; - const countParts = []; - if (pack.skills.length > 0) { - countParts.push(`${pack.skills.length} skill${pack.skills.length !== 1 ? 's' : ''}`); - } - if (pack.agents.length > 0) { - countParts.push(`${pack.agents.length} agent${pack.agents.length !== 1 ? 's' : ''}`); - } - // Count both Official and Community MCPs for this pack - const packMCPCount = [...allMCPServers, ...allCommunityMCPServers].filter(server => server.pack === pack.name).length; - if (packMCPCount > 0) { - countParts.push(`${packMCPCount} MCP`); - } - counts.textContent = countParts.join(' '); - titleGroup.appendChild(counts); - - headerTop.appendChild(titleGroup); - - // Meta (version badge + readme button if available) - const meta = document.createElement('div'); - meta.className = 'modal-meta'; - - const versionBadge = document.createElement('span'); - versionBadge.className = 'version-badge'; - versionBadge.textContent = `v${pack.plugin.version || '0.0.0'}`; - meta.appendChild(versionBadge); - - if (pack.has_readme) { - const readmeButton = document.createElement('a'); - readmeButton.className = 'readme-button'; - readmeButton.textContent = 'README'; - readmeButton.href = `https://github.com/RHEcosystemAppEng/agentic-collections/tree/main/${pack.name}`; - readmeButton.target = '_blank'; - meta.appendChild(readmeButton); - } - - headerTop.appendChild(meta); - header.appendChild(headerTop); - - // Description - if (pack.plugin.description) { - const desc = document.createElement('div'); - desc.className = 'modal-description'; - desc.textContent = pack.plugin.description; - header.appendChild(desc); - } - - // Plugin name field (if different from title) - if (pack.plugin.name && pack.plugin.name !== pack.plugin.title) { - const pluginNameDiv = document.createElement('div'); - pluginNameDiv.style.marginTop = '1rem'; - pluginNameDiv.style.fontSize = '0.9rem'; - pluginNameDiv.style.color = 'var(--text-muted)'; - - const label = document.createElement('strong'); - label.textContent = 'Plugin name: '; - label.style.color = 'var(--text-primary)'; - pluginNameDiv.appendChild(label); - - const nameCode = document.createElement('code'); - nameCode.textContent = pack.plugin.name; - nameCode.style.backgroundColor = JS_STYLE_TOKENS.subtleErrorBackground; - nameCode.style.padding = '0.25rem 0.5rem'; - nameCode.style.borderRadius = '4px'; - nameCode.style.fontSize = '0.85rem'; - pluginNameDiv.appendChild(nameCode); - - header.appendChild(pluginNameDiv); - } - - details.appendChild(header); - - // Create modal body - const body = document.createElement('div'); - body.className = 'modal-body'; - - // Installation section (Lola package manager) - const installSection = document.createElement('div'); - installSection.className = 'modal-section'; - - const installHeader = document.createElement('div'); - installHeader.className = 'modal-section-header'; - installHeader.textContent = 'INSTALLATION'; - installSection.appendChild(installHeader); - - const lolaNote = document.createElement('div'); - lolaNote.style.color = 'var(--text-muted)'; - lolaNote.style.fontSize = '0.85rem'; - lolaNote.style.marginBottom = '0.75rem'; - lolaNote.textContent = 'Lola. Applies to current folder only.'; - installSection.appendChild(lolaNote); - - const moduleName = pack.name; - - const codeWrapper = document.createElement('div'); - codeWrapper.className = 'install-code-wrapper'; - - const installPre = document.createElement('pre'); - const installCode = document.createElement('code'); - installCode.textContent = `lola market add rh-agentic-collections https://raw.githubusercontent.com/RHEcosystemAppEng/agentic-collections/main/marketplace/rh-agentic-collection.yml -lola install -f ${moduleName}`; - installPre.appendChild(installCode); - codeWrapper.appendChild(installPre); - - const copyBtn = document.createElement('button'); - copyBtn.className = 'copy-button'; - copyBtn.textContent = 'Copy'; - copyBtn.onclick = () => copyToClipboard(installCode.textContent, copyBtn); - codeWrapper.appendChild(copyBtn); - - installSection.appendChild(codeWrapper); - - const optNote = document.createElement('div'); - optNote.style.color = 'var(--text-muted)'; - optNote.style.fontSize = '0.8rem'; - optNote.style.marginTop = '0.5rem'; - optNote.textContent = 'Add -a claude-code or -a cursor to target one assistant.'; - installSection.appendChild(optNote); - - const lolaLink = document.createElement('div'); - lolaLink.style.marginTop = '0.5rem'; - lolaLink.style.fontSize = '0.85rem'; - const lolaAnchor = document.createElement('a'); - lolaAnchor.href = 'https://github.com/LobsterTrap/lola'; - lolaAnchor.target = '_blank'; - lolaAnchor.textContent = 'Lola →'; - lolaAnchor.style.color = 'var(--primary)'; - lolaAnchor.style.textDecoration = 'none'; - lolaAnchor.onmouseover = () => { lolaAnchor.style.textDecoration = 'underline'; }; - lolaAnchor.onmouseout = () => { lolaAnchor.style.textDecoration = 'none'; }; - lolaLink.appendChild(lolaAnchor); - installSection.appendChild(lolaLink); - - body.appendChild(installSection); - - // Agents section (shown first) - if (pack.agents.length > 0) { - const agentsSection = document.createElement('div'); - agentsSection.className = 'modal-section'; - - const agentsHeader = document.createElement('div'); - agentsHeader.className = 'modal-section-header'; - agentsHeader.textContent = 'AGENTS'; - agentsSection.appendChild(agentsHeader); - - const agentsList = document.createElement('div'); - agentsList.className = 'item-list'; - - pack.agents.forEach(agent => { - const agentDef = document.createElement('div'); - agentDef.className = 'agent-definition'; - - // Agent syntax block - const syntaxBlock = document.createElement('div'); - syntaxBlock.className = 'definition-syntax'; - const syntaxCode = document.createElement('code'); - syntaxCode.textContent = agent.name; - syntaxBlock.appendChild(syntaxCode); - agentDef.appendChild(syntaxBlock); - - // Agent description (with expand/collapse for long text) - const desc = document.createElement('div'); - desc.className = 'definition-description'; - desc.appendChild(createExpandableText(agent.description, 200)); - agentDef.appendChild(desc); - - agentsList.appendChild(agentDef); - }); - - agentsSection.appendChild(agentsList); - body.appendChild(agentsSection); - } - - // Skills section (shown second) - if (pack.skills.length > 0) { - const skillsSection = document.createElement('div'); - skillsSection.className = 'modal-section'; - - const skillsHeader = document.createElement('div'); - skillsHeader.className = 'modal-section-header'; - skillsHeader.textContent = 'SKILLS'; - skillsSection.appendChild(skillsHeader); - - const skillsList = document.createElement('div'); - skillsList.className = 'item-list'; - - pack.skills.forEach(skill => { - const skillDef = document.createElement('div'); - skillDef.className = 'skill-definition'; - - // Skill syntax block - const syntaxBlock = document.createElement('div'); - syntaxBlock.className = 'definition-syntax'; - const syntaxCode = document.createElement('code'); - syntaxCode.textContent = skill.name; - syntaxBlock.appendChild(syntaxCode); - skillDef.appendChild(syntaxBlock); - - // Skill description (with expand/collapse for long text) - const desc = document.createElement('div'); - desc.className = 'definition-description'; - desc.appendChild(createExpandableText(skill.description, 200)); - skillDef.appendChild(desc); - - skillsList.appendChild(skillDef); - }); - - skillsSection.appendChild(skillsList); - body.appendChild(skillsSection); - } - - // Docs section (shown third, if documentation exists) - if (pack.docs && pack.docs.length > 0) { - const docsSection = document.createElement('div'); - docsSection.className = 'modal-section'; - - const docsHeader = document.createElement('div'); - docsHeader.className = 'modal-section-header'; - docsHeader.textContent = 'DOCS'; - docsSection.appendChild(docsHeader); - - // Group docs by category - const docsByCategory = {}; - pack.docs.forEach(doc => { - const category = doc.category || 'general'; - if (!docsByCategory[category]) { - docsByCategory[category] = []; - } - docsByCategory[category].push(doc); - }); - - // Render each category - Object.keys(docsByCategory).sort().forEach(category => { - const categorySection = document.createElement('div'); - categorySection.style.marginBottom = '1.5rem'; - - // Category header - const categoryHeader = document.createElement('div'); - categoryHeader.className = 'modal-section-label'; - categoryHeader.textContent = category.charAt(0).toUpperCase() + category.slice(1); - categorySection.appendChild(categoryHeader); - - // Doc list for this category - const docsList = document.createElement('div'); - docsList.className = 'item-list'; - - docsByCategory[category].forEach(doc => { - const docDef = document.createElement('div'); - docDef.className = 'skill-definition'; - - // Doc title - const titleBlock = document.createElement('div'); - titleBlock.className = 'definition-syntax'; - const titleCode = document.createElement('code'); - titleCode.textContent = doc.title; - titleBlock.appendChild(titleCode); - docDef.appendChild(titleBlock); - - // Sources section - if (doc.sources && doc.sources.length > 0) { - const sourcesDiv = document.createElement('div'); - sourcesDiv.className = 'definition-description'; - - doc.sources.forEach((source, index) => { - // Add separator between sources - if (index > 0) { - sourcesDiv.appendChild(document.createElement('br')); - } - - // Source title label - const sourceLabel = document.createElement('span'); - sourceLabel.textContent = 'Source: '; - sourceLabel.style.color = 'var(--text-muted)'; - sourceLabel.style.fontSize = '0.85rem'; - sourcesDiv.appendChild(sourceLabel); - - // Source link - const sourceLink = document.createElement('a'); - sourceLink.href = source.url; - sourceLink.target = '_blank'; - sourceLink.textContent = source.title; - sourceLink.style.color = 'var(--primary)'; - sourceLink.style.textDecoration = 'none'; - sourceLink.onmouseover = () => { sourceLink.style.textDecoration = 'underline'; }; - sourceLink.onmouseout = () => { sourceLink.style.textDecoration = 'none'; }; - sourcesDiv.appendChild(sourceLink); - }); - - docDef.appendChild(sourcesDiv); - } - - docsList.appendChild(docDef); - }); - - categorySection.appendChild(docsList); - docsSection.appendChild(categorySection); - }); - - // Link to full documentation on GitHub - const docsLink = document.createElement('div'); - docsLink.style.marginTop = '1.5rem'; - docsLink.style.paddingTop = '1rem'; - docsLink.style.borderTop = '1px solid var(--border)'; - const link = document.createElement('a'); - link.href = `https://github.com/RHEcosystemAppEng/agentic-collections/tree/main/${pack.name}/docs`; - link.target = '_blank'; - link.textContent = 'View full documentation on GitHub →'; - link.style.color = 'var(--primary)'; - link.style.textDecoration = 'none'; - link.style.fontWeight = '600'; - link.onmouseover = () => { link.style.textDecoration = 'underline'; }; - link.onmouseout = () => { link.style.textDecoration = 'none'; }; - docsLink.appendChild(link); - docsSection.appendChild(docsLink); - - body.appendChild(docsSection); - } - - // MCP section (shown last, if MCP servers exist for this pack) - // Include both Official and Community MCP servers for this pack - const packMCPServers = [...allMCPServers, ...allCommunityMCPServers].filter(server => server.pack === pack.name); - if (packMCPServers.length > 0) { - const mcpSection = document.createElement('div'); - mcpSection.className = 'modal-section'; - - const mcpHeader = document.createElement('div'); - mcpHeader.className = 'modal-section-header'; - mcpHeader.textContent = 'MCP'; - mcpSection.appendChild(mcpHeader); - - const mcpList = document.createElement('div'); - mcpList.className = 'item-list'; - - packMCPServers.forEach(server => { - const mcpDef = document.createElement('div'); - mcpDef.className = 'skill-definition mcp-link-item'; - mcpDef.style.cursor = 'pointer'; - mcpDef.style.transition = 'all 0.2s ease'; - mcpDef.style.borderLeft = '3px solid transparent'; - mcpDef.style.paddingLeft = '1rem'; - - // MCP server name with icon and arrow (clickable) - const nameBlock = document.createElement('div'); - nameBlock.className = 'definition-syntax'; - nameBlock.style.display = 'flex'; - nameBlock.style.alignItems = 'center'; - nameBlock.style.gap = '0.5rem'; - nameBlock.style.justifyContent = 'space-between'; - - const nameGroup = document.createElement('div'); - nameGroup.style.display = 'flex'; - nameGroup.style.alignItems = 'center'; - nameGroup.style.gap = '0.5rem'; - - // Custom icon (if available) - if (server.icon) { - nameGroup.appendChild(createIconElement(server.icon, 'item-icon')); - } - - const nameCode = document.createElement('code'); - nameCode.textContent = server.title || server.name; - nameCode.style.color = 'var(--primary)'; - nameGroup.appendChild(nameCode); - - // HTTP remote indicator (if applicable) - if (server.type === 'http') { - const icon = document.createElement('span'); - icon.textContent = '🌐'; - icon.title = 'HTTP Remote Server'; - icon.style.fontSize = '0.9rem'; - nameGroup.appendChild(icon); - } - - nameBlock.appendChild(nameGroup); - - // Add arrow indicator - const arrow = document.createElement('span'); - arrow.textContent = '→'; - arrow.style.color = 'var(--text-muted)'; - arrow.style.fontSize = '1.2rem'; - arrow.style.transition = 'transform 0.2s ease'; - nameBlock.appendChild(arrow); - - mcpDef.appendChild(nameBlock); - - // MCP owner subtitle - const ownerText = document.createElement('div'); - ownerText.className = 'definition-description'; - ownerText.textContent = `By ${server.owner || 'Red Hat'}`; - ownerText.style.color = 'var(--text-muted)'; - ownerText.style.fontSize = '0.85rem'; - ownerText.style.marginTop = '0.25rem'; - mcpDef.appendChild(ownerText); - - // Hover effects - mcpDef.onmouseenter = () => { - mcpDef.style.borderLeftColor = 'var(--primary)'; - mcpDef.style.backgroundColor = JS_STYLE_TOKENS.softAccentBackground; - arrow.style.transform = 'translateX(4px)'; - }; - - mcpDef.onmouseleave = () => { - mcpDef.style.borderLeftColor = 'transparent'; - mcpDef.style.backgroundColor = 'transparent'; - arrow.style.transform = 'translateX(0)'; - }; - - // Click to open MCP details - mcpDef.onclick = () => showMCPDetails(server.name, server.pack); - - mcpList.appendChild(mcpDef); - }); - - mcpSection.appendChild(mcpList); - body.appendChild(mcpSection); - } - - details.appendChild(body); - modal.style.display = 'flex'; - document.body.style.overflow = 'hidden'; // Prevent background scrolling -} /** * Show MCP server details modal (XSS-safe) @@ -2268,8 +1799,8 @@ function appendSkillEvalBlock(li, skill) { }; const commitSha = String(ev.commit_sha || '').trim(); const commitShort = commitSha ? commitSha.slice(0, 8) : 'N/A'; - const commitHref = commitSha - ? `https://github.com/RHEcosystemAppEng/agentic-collections/commit/${commitSha}` + const commitHref = commitSha && ev.repository + ? `${String(ev.repository).replace(/\/$/, '')}/commit/${commitSha}` : ''; const prUrl = String(ev.related_pr || '').trim(); const prMatch = prUrl.match(/\/pull\/(\d+)(?:\/|$)/); diff --git a/docs/index.html b/docs/index.html index 7ebec99..60ae320 100644 --- a/docs/index.html +++ b/docs/index.html @@ -3,7 +3,7 @@ - Agentic Skills packs + Red Hat Agentic Catalog @@ -39,8 +39,8 @@

Red Hat Agentic Catalog

- Apache 2.0 License → - GitHub → + Apache 2.0 License → + GitHub →
@@ -52,11 +52,11 @@

Red Hat Agentic Catalog

-
lola market add rh-agentic-collections https://raw.githubusercontent.com/RHEcosystemAppEng/agentic-collections/main/marketplace/rh-agentic-collection.yml
+
lola market add rh-agentic-collections https://raw.githubusercontent.com/RHEcosystemAppEng/agentic-collections-catalog/main/marketplace/rh-agentic-collection.yml

Then lola install -f <module> — applies to current folder only.

@@ -76,7 +76,7 @@

Red Hat Agentic Catalog

- Apache 2.0 License → + Apache 2.0 License →
@@ -86,7 +86,7 @@

Red Hat Agentic Catalog

- Agentic Skills packs + Agentic Collections

Ready-to-use capability packs designed for Claude Code and Cursor to automate complex domain-specific tasks.

@@ -112,14 +112,9 @@

- - -