Add a Copilot Canvas extension for agentic workflow operations#42137
Conversation
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
|
|
@copilot a tabbed view design so that it is easy and modular to add views |
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Implemented in
|
|
@copilot modularize to allow reuse, apply SOLID, DRY, YAGNI. |
|
@copilot also wire gh aw audit-diff and gh aw compile commands |
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
|
|
@copilot init impeccable (https://github.com/pbakaus/impeccable) for the canvas Configure it as a github.com like experience for exploring, managing, running agentic workflows. |
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Addressed in 2735ec5 and 6dfe1c2. I refactored the dashboard to a reusable tab model with shared view-switch helpers, removed duplicated run-detail navigation logic, and added guarded tab selection for cleaner SOLID/DRY behavior while keeping scope minimal.
Implemented in 2735ec5 and finalized in 6dfe1c2. The dashboard now uses a metadata-driven tabbed view system (Workflows/Runs/Run details/Commands), with each view rendered as an independent panel to make future view additions modular. |
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Implemented in 06e1f42 (plus follow-up polish in 4e3d023): wired
Implemented in 06e1f42: initialized Impeccable context for this canvas with |
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
|
/matt |
|
🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅ |
There was a problem hiding this comment.
Pull request overview
This pull request introduces a project-scoped GitHub Copilot Canvas extension that provides a lightweight “agentic workflows” dashboard surface (definitions, runs, run details, and a command panel), along with build/lint/fmt targets wired into the repo Makefile.
Changes:
- Added a new Copilot Canvas extension under
.github/extensions/agentic-workflows-dashboard, including the extension entrypoint (extension.mjs) and a static dashboard UI (Primer CSS styling + Alpine.js-driven views). - Introduced a strict TypeScript domain model + pagination helper (with Vitest coverage for pagination) and compiled runtime assets under
web/. - Integrated extension formatting/linting/testing into top-level
make fmt,make lint, and added a dedicatedtest-canvas-extensiontarget.
Show a summary per file
| File | Description |
|---|---|
| Makefile | Adds build/test/fmt/lint targets for the Canvas extension and wires fmt/lint into existing top-level targets. |
| .github/extensions/agentic-workflows-dashboard/web/styles.css | Adds minimal dashboard-specific CSS utilities (shell spacing, scroll containers, selection styling). |
| .github/extensions/agentic-workflows-dashboard/web/pagination.js | Adds web runtime pagination helper used by the dashboard bundle. |
| .github/extensions/agentic-workflows-dashboard/web/models.js | Adds an (empty) module stub emitted for TS module boundary. |
| .github/extensions/agentic-workflows-dashboard/web/index.html | Adds the dashboard HTML template (Primer layout, tabbed panels, and markdown summary rendering surface). |
| .github/extensions/agentic-workflows-dashboard/web/app.js | Adds the dashboard’s Alpine.js app runtime (definitions/runs datasets, command simulation, safe markdown rendering). |
| .github/extensions/agentic-workflows-dashboard/vitest.config.ts | Configures Vitest discovery for extension tests. |
| .github/extensions/agentic-workflows-dashboard/tsconfig.json | Defines strict TypeScript compilation settings and emits JS into web/. |
| .github/extensions/agentic-workflows-dashboard/test/pagination.test.ts | Adds unit tests for pagination behavior. |
| .github/extensions/agentic-workflows-dashboard/src/pagination.ts | Adds typed pagination helper used by TS sources. |
| .github/extensions/agentic-workflows-dashboard/src/models.ts | Adds strict domain model types for definitions, runs, steps, and paged results. |
| .github/extensions/agentic-workflows-dashboard/src/app.ts | Adds typed dashboard runtime (rendering logic, command simulation, and safe markdown rendering). |
| .github/extensions/agentic-workflows-dashboard/PRODUCT.md | Documents product intent and UI design lane for the extension. |
| .github/extensions/agentic-workflows-dashboard/package.json | Defines extension package scripts/deps (build, lint, test, fmt). |
| .github/extensions/agentic-workflows-dashboard/package-lock.json | Locks dependency tree for the extension. |
| .github/extensions/agentic-workflows-dashboard/extension.mjs | Implements the Copilot Canvas extension (actions, in-memory data, and dashboard open() URL rendering). |
| .github/extensions/agentic-workflows-dashboard/copilot-extension.json | Adds Copilot extension metadata (name/version). |
| .github/extensions/agentic-workflows-dashboard/.impeccable/config.json | Enables Impeccable detector config for the dashboard’s web assets. |
Review details
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Files not reviewed (1)
- .github/extensions/agentic-workflows-dashboard/package-lock.json: Generated file
- Files reviewed: 17/20 changed files
- Comments generated: 8
- Review effort level: Low
| export function paginate<T>(items: T[], page: number, pageSize: number): PagedResult<T> { | ||
| const totalItems = items.length; | ||
| const totalPages = Math.max(1, Math.ceil(totalItems / pageSize)); | ||
| const safePage = Math.min(Math.max(1, page), totalPages); | ||
| const start = (safePage - 1) * pageSize; | ||
| const end = start + pageSize; | ||
|
|
||
| return { | ||
| items: items.slice(start, end), | ||
| page: safePage, | ||
| pageSize, | ||
| totalItems, | ||
| totalPages, | ||
| hasNextPage: safePage < totalPages, | ||
| hasPreviousPage: safePage > 1, | ||
| }; | ||
| } |
| const status = statuses[index % statuses.length] ?? "queued"; | ||
| const definition = sourceDefinitions[index % sourceDefinitions.length]; | ||
| const stepStatuses = stepStatusMap[status] ?? stepStatusMap.queued; | ||
|
|
||
| return { | ||
| id: `run-${String(index).padStart(5, "0")}`, | ||
| definitionId: definition.id, | ||
| status, |
| </main> | ||
| </div> | ||
| <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.15.0/dist/cdn.min.js"></script> | ||
| <script type="module"> |
| async function renderDashboardUrl() { | ||
| const htmlPath = join(__dirname, "web", "index.html"); | ||
| const appPath = join(__dirname, "web", "app.js"); | ||
| const cssPath = join(__dirname, "web", "styles.css"); | ||
|
|
||
| const [htmlTemplate, appBundle, cssBundle] = await Promise.all([readFile(htmlPath, "utf8"), readFile(appPath, "utf8"), readFile(cssPath, "utf8")]); | ||
|
|
||
| const html = htmlTemplate.replace("/*__APP_CSS__*/", cssBundle).replace("/*__APP_JS__*/", appBundle); | ||
| return `data:text/html;charset=utf-8,${encodeURIComponent(html)}`; | ||
| } |
| "devDependencies": { | ||
| "typescript": "6.0.3", | ||
| "vitest": "4.1.9" | ||
| }, | ||
| "scripts": { | ||
| "build": "tsc -p tsconfig.json", | ||
| "typecheck": "tsc -p tsconfig.json --noEmit", | ||
| "test": "vitest run", | ||
| "lint": "npm run typecheck && npm test", | ||
| "fmt": "npm run fmt:ts && npm run fmt:html && npm run fmt:css && npm run fmt:js && npm run fmt:json", | ||
| "fmt:ts": "npx prettier --write --parser typescript \"src/**/*.ts\" \"test/**/*.ts\" \"vitest.config.ts\"", | ||
| "fmt:html": "npx prettier --write --parser html \"web/index.html\"", | ||
| "fmt:css": "npx prettier --write --parser css \"web/styles.css\"", | ||
| "fmt:js": "npx prettier --write --parser babel \"extension.mjs\"", | ||
| "fmt:json": "npx prettier --write --parser json \"copilot-extension.json\" \"package.json\"", | ||
| "impeccable:detect": "npx impeccable detect web/index.html web/styles.css" | ||
| } |
Review complete: 3 blocking issues, 4 medium priorityApplied 🔴 Blocking (must fix)
🟡 Medium priority
@copilot please address the review comments above.
|
There was a problem hiding this comment.
Skills-Based Review 🧠
Applied /tdd, /zoom-out, /improve-codebase-architecture, /grill-with-docs, and /diagnose — requesting changes on three blocking issues.
📋 Key Themes & Findings
Blocking Issues
-
Mutable global state (
extension.mjs:116) —runs.unshift()mutates module-level state shared across all sessions. In any multi-user deployment this is a correctness bug. -
Test coverage gap (
test/pagination.test.ts) — 414-lineapp.tsand 353-lineextension.mjscontain complex branchy logic (renderSafeMarkdown,runGhCommand,dispatchWorkflow) with zero tests. The HTML injection surface and command parser both need coverage before this ships. -
Generated artifacts committed (
web/app.js) — TypeScript compiler output is checked in alongside source, creating silent drift risk on everysrc/*.tsedit.
Medium Priority
tsconfig.jsonexcludestest/— test files not type-checked bynpm run typecheckrunFlagMatchhoisted with implicit branch-ordering dependency — fragile, needs localisation and tests- Command handling duplicated between
extension.mjsandapp.tswith no documented relationship dispatchSelectedWorkflow()operates on a separate dataset from the canvasdispatchWorkflowaction — no documented design intent
Positive Highlights
- ✅ Clean domain model in
src/models.tswith strict TypeScript (noUncheckedIndexedAccess,exactOptionalPropertyTypes) - ✅ Generic
paginate<T>function with proper clamping and tested behaviour - ✅
escapeHtmlruns before all inline transforms — XSS fundamentals are sound - ✅ Makefile integration (
test-canvas-extension,lint-canvas-extension,fmt-canvas-extension) is well-structured - ✅ Progressive disclosure design in the Primer-based UI is clean and consistent
🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 139.1 AIC · ⌖ 10.1 AIC · ⊞ 6.6K
Comment /matt to run again
…K dep - Replace data URI with a per-instance loopback HTTP server; the runtime rejects data: scheme URLs with canvas_provider_url_disallowed - Serve web/app.js and web/pagination.js as separate routes so the ES module import chain resolves correctly from the loopback origin - Add onClose handler to shut down the server when a panel is closed - Fix Alpine.js x-for directives: move them from <div> to <template> elements as required by Alpine v3 (list rendering was silently broken) - Remove @github/copilot-sdk from package.json dependencies; the CLI auto-resolves the SDK, and listing it risks installing a conflicting version if someone runs npm install Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Alpine's defer script fires alpine:init before the type=module app.js
has run, so Alpine.data('dashboardApp') was never registered and the
dashboard rendered blank.
Fix: import Alpine as an ESM module directly in app.js and call
Alpine.start() at the end of the module. This gives the module full
control over startup order — Alpine.data() is registered synchronously
before Alpine.start() walks the DOM.
- Remove the defer CDN script tag from index.html (Alpine is now
imported by app.js via the +esm CDN path)
- Remove the document.addEventListener('alpine:init', ...) wrapper;
register Alpine.data() at module scope instead
- Add Alpine.start() at the end of app.js
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- extension.mjs: use execFile to call ./gh-aw (dev) or gh aw (installed); add /api/status, /api/runs, /api/run-command, /api/refresh routes; add 60s result cache; add systemMessage with CLI usage instructions; assign workspacePath after joinSession; remove all dummy data functions - web/app.js: fetch from /api/* endpoints; map real field names (workflow, engine_id, run_id, workflow_name, duration, token_usage, turns, error_count); add loadingDefinitions/loadingRuns/error state; add refresh() - web/index.html: update templates for real field names; add loading spinners; replace step list in Details tab with metrics grid; add Refresh button; update Commands tab quick-fill buttons to real commands Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
🤖 PR Triage — §28342769269
Score breakdown: Impact 42 · Urgency 15 · Quality 12 Rationale: New GitHub Copilot Canvas extension for agentic workflow operations (+2777/−2, 20 files). Significant new product surface: dashboard for browsing workflow definitions/runs, dispatching workflows, and invoking Next steps:
|
Covers the week's highlights including: - Copilot Canvas extension for agentic workflow operations (PR #42137) - create-canvas skill (PR #42147) - sandbox.agent.sudo: false coverage hits 80% (PR #42119) - Code Scanning Fixer expanded to all severity levels (PR #42139) - mcpg v0.3.32 + firewall v0.27.13 bump (PR #42146) - Agent of the Week: agent-persona-explorer Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This PR adds a project-scoped GitHub Copilot Canvas extension specialized for agentic workflows in
github/gh-aw. It introduces a minimal, GitHub-styled dashboard for browsing workflow definitions and runs, reviewing safe markdown step summaries, dispatching predefined workflows, and invokinggh aw logs/gh aw auditcommands at canvas level.Extension surface and wiring
.github/extensions/agentic-workflows-dashboardwith Copilot extension metadata and entrypoint.listDefinitions(page, pageSize)listRuns(page, pageSize)getRun(id)dispatchWorkflow(definitionId, inputs)runGhAwLogs(args)runGhAwAudit(args)Strict TypeScript domain model + paging
WorkflowDefinition,WorkflowRun,WorkflowStep, and genericPagedResult<T>.Dashboard UI (Alpine.js + Primer CSS, native modules)
gh aw logsgh aw logs --run <id>gh aw auditgh aw audit --run <id>Safe markdown rendering for run summaries