diff --git a/.github/plugin/marketplace.json b/.github/plugin/marketplace.json index e1394b4324..1d84efe57a 100644 --- a/.github/plugin/marketplace.json +++ b/.github/plugin/marketplace.json @@ -280,6 +280,12 @@ "sha": "0c2716ca4f28df375529c67b4504b41f7bd29a66" } }, + { + "name": "chat-cards", + "source": "plugins/chat-cards", + "description": "Interactive card deck in a GHCP canvas: tab cards, tables, SVG charts, show/hide sections, numbered outlines, rendered markdown documents, video clips, and forms whose submissions come back to the conversation as prompts.", + "version": "0.1.0" + }, { "name": "chrome-devtools-plugin", "description": "Reliable automation, in-depth debugging, and performance analysis in Chrome using Chrome DevTools and Puppeteer.", diff --git a/docs/README.plugins.md b/docs/README.plugins.md index 0d89c85ffc..ba76c8438a 100644 --- a/docs/README.plugins.md +++ b/docs/README.plugins.md @@ -41,6 +41,7 @@ See [CONTRIBUTING.md](../CONTRIBUTING.md#adding-plugins) for guidelines on how t | [backlog-swipe-triage](../plugins/backlog-swipe-triage/README.md) | Quickly swipe through backlog issues to triage decisions like assign, needs-info, defer, close, or ignore. | 1 items | agent-assignment, backlog-triage, github-issues, issue-prioritization, swipe-interface, workflow-automation | | [backrooms-canvas](../plugins/backrooms-canvas/README.md) | Wander an endless first-person backrooms in a Copilot canvas while agents work; their status ghost-writes on the walls. | 1 items | backrooms, copilot-canvas, interactive-canvas, first-person, procedural-generation, session-breaks | | [cast-imaging](../plugins/cast-imaging/README.md) | A comprehensive collection of specialized agents for software analysis, impact assessment, structural quality advisories, and architectural review using CAST Imaging. | 3 items | cast-imaging, software-analysis, architecture, quality, impact-analysis, devops | +| [chat-cards](../plugins/chat-cards/README.md) | Interactive card deck in a GHCP canvas: tab cards, tables, SVG charts, show/hide sections, numbered outlines, rendered markdown documents, video clips, and forms whose submissions come back to the conversation as prompts. | 1 items | interactive-cards, charts, forms, education, visual-explanations | | [chromium-control-canvas](../plugins/chromium-control-canvas/README.md) | Opens a real Chromium window you can navigate and interact with from a Copilot canvas control panel and agent actions. | 1 items | browser-control, chromium-browser, interactive-canvas, playwright-automation, screenshots, ui-testing, web-navigation | | [clojure-interactive-programming](../plugins/clojure-interactive-programming/README.md) | Tools for REPL-first Clojure workflows featuring Clojure instructions, the interactive programming chat mode and supporting guidance. | 2 items | clojure, repl, interactive-programming | | [cms-development](../plugins/cms-development/README.md) | Skills for CMS development across themes, plugins, admin tooling, media workflows, markdown rendering, and static export pipelines. | 3 items | cms, content-management-system, wordpress, shopify, drupal, theme, plugin, media, static-site | diff --git a/extensions/chat-cards/README.md b/extensions/chat-cards/README.md new file mode 100644 index 0000000000..5ee84d780d --- /dev/null +++ b/extensions/chat-cards/README.md @@ -0,0 +1,154 @@ +# Chat Cards + +Interactive card deck for GitHub Copilot canvas. Instead of walls of text, the +agent explains things visually with a live deck of interactive cards: tab boxes, +tables, SVG charts, forms, collapsible sections, numbered outlines, rendered +markdown documents, and short video clips. Forms are two-way: submitting one +sends the values back to the conversation as the agent's next prompt, so a card +can gather context and steer the session as easily as it presents information. + +The extension is a port of an MCP server, which is similar; but renders the cards +inline of the conversation, instead of rendering the HTML in a separate panel. + + + +## What is in the deck + +| Action | Card | +| ------ | ---- | +| `create_tab_card` | Tabbed views of one subject (markdown, text, HTML, or code per tab with copy buttons) | +| `create_table_card` | HTML table from explicit rows or loosely delimited raw text (delimiter auto-detected, URL cells become links) | +| `create_chart_card` | SVG bar, line, pie, or donut chart with legend and a collapsible data table | +| `create_form_card` | Form whose submission becomes the next conversation prompt | +| `create_reveal_card` | Collapsible show/hide sections with show-all/hide-all controls | +| `create_list_card` | Nested sequential outline numbered 1., 1.1., 1.1.1. | +| `create_markdown_card` | Render a markdown document as one card: H1 becomes the title, H2 sections fold into reveals | +| `create_video_card` | HTML video player for a short clip (direct file URL, `data:video/*`, or `blob:`) | +| `update_card` | Re-render an existing card in place | +| `remove_card` / `clear_cards` | Take cards off the deck | +| `list_cards` | See the deck (the user may have reordered or removed cards) | +| `get_form_responses` | Read form submissions, newest first | + +Every card keeps the signature interactions of the MCP version: a "Copy card" button that +copies the card as a standalone HTML document, a `>` toggle that shows the card's own +HTML source, a collapse toggle, drag to reorder cards in the deck, tutor terms that show +tooltips after a hover dwell, and model-defined right-click actions that send prompts back +to the conversation (`{{selection}}` in an action prompt is replaced with the user's +selected text). The deck has a light and a dark theme. + +## Example action inputs + +`create_table_card`: + +```json +{ + "title": "JavaScript array methods", + "headers": ["Method", "Purpose"], + "rows": [ + ["map", "Transform each item"], + ["filter", "Keep matching items"], + ["reduce", "Fold items into one value"] + ] +} +``` + +`create_form_card`: + +```json +{ + "title": "Study preferences", + "promptTemplate": "Teach {{topic}} with {{style}} examples.", + "fields": [ + { "name": "topic", "label": "Topic", "required": true }, + { "name": "style", "type": "select", "options": ["practical", "theoretical"] } + ] +} +``` + +When the user submits the form, the filled template is handed to the agent as the next +prompt. If the handoff fails, the card reveals the prompt text with a copy button, and the +agent can always read submissions later with `get_form_responses`. + +## Installation + +Requires Node.js 18.17 or newer and a GitHub Copilot client that supports +canvas extensions (*such as GitHub Copilot CLI*). + +Drop this folder at `~/.copilot/extensions/chat-cards/` for user scope, or +in a repository at `.github/extensions/chat-cards/` for project scope. Then +install dependencies from inside the copied folder: + +```bash +# User scope +cd ~/.copilot/extensions/chat-cards + +# Or project scope, from the repository root +cd .github/extensions/chat-cards + +npm install +``` + +`npm install` pulls the extension's single dependency (`@github/copilot-sdk`). +Then register the `extension/` folder with your Copilot client as a local +extension, start a session, and ask the agent to open the Chat Cards canvas. + +Reload extensions in the GitHub Copilot app, then open the chat-cards canvas in +a conversation. + +## How the port maps to the MCP server + +| MCP server | Canvas extension | +| ---------- | ---------------- | +| MCP tools (`create_tab_card`, ...) | Canvas actions with the same names and input shapes | +| MCP Apps iframe / embedded HTML resource | Live canvas page served on `127.0.0.1` | +| Form submit posts `ui/message` to the host | Form submit calls `session.send({ prompt })` | +| Card HTML per tool result | Deck state pushed to the page over SSE | +| `src/cards/*` + `src/util/*` (TypeScript) | `cards-core.mjs` (dependency-free port, testable without the SDK) | + +Deliberate differences: + +- **Stricter HTML sanitizing.** Tab and reveal content can be markdown, text, code, or + HTML, like the MCP server, but where the server sanitizes HTML with a parser dependency, + the extension rebuilds it against a strict tag and attribute allowlist: unknown or + malformed tags render as visible literal text, attributes are re-emitted from scratch, + and closing tags are balanced. A tab or section with no usable content is rejected with + an error naming it, instead of rendering an empty panel. +- **No file, archive, or web-fetch actions.** `read_local_file`, `unpack_archive`, + `fetch_reference`, `mirror_web_form`, and `submit_web_form` stay MCP-only: a Copilot + agent already reads files and pages natively, so it passes content inline (for example + `create_markdown_card` takes the markdown itself rather than a path). +- **No multi-part splitting.** MCP hosts cap tool-result sizes, so the server splits large + documents into parts. The canvas renders directly and needs no parts; the deck instead + keeps at most 60 cards, dropping the oldest. + +## Folder layout + +```text +extension/ + extension.mjs Canvas/session wiring, actions, local HTTP + SSE server + cards-core.mjs Card builders and rendering (no SDK import; unit-testable) + copilot-extension.json Plugin manifest for the awesome-copilot submission + package.json Extension package manifest + assets/ + canvas.html The canvas page (theme, card runtime, deck UI) + preview.png Screenshot used as the extension logo/preview +``` + +## Security notes + +- The card server binds to `127.0.0.1` on an ephemeral port; every request must carry the + per-canvas token, and request bodies are size-capped. +- All model- and user-supplied text is HTML-escaped before it reaches card markup, and the + markdown renderer emits only escaped text nodes. +- The canvas page loads no external scripts, stylesheets, or fonts. +- Prompts sent from the canvas (form submissions and context actions) are length-capped. + +## Development + +The rendering core has no SDK dependency, so it can be exercised directly: + +```bash +node -e "import('./cards-core.mjs').then(m => console.log(m.buildTableCard({ title: 'Demo', rows: [['a', 'b']] }).summary))" +``` + +To run the extension itself, follow [Installation](#installation) above. diff --git a/extensions/chat-cards/assets/canvas.html b/extensions/chat-cards/assets/canvas.html new file mode 100644 index 0000000000..6e3fd60cd8 --- /dev/null +++ b/extensions/chat-cards/assets/canvas.html @@ -0,0 +1,896 @@ + + +
+ + +Ask your agent for a tab, table, chart, form, show/hide, list, document, or video card
and it will appear here.