Files
David Pine 5b6da4c588 Add PR Artifact Explorer canvas 🤖🤖🤖 (#2341)
* Add PR Artifact Explorer canvas

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 33fefd65-ed18-4eda-9c7d-48008f4a9c9d

* Address PR #2341 review feedback and codespell CI failures

PR review fixes:

- zip.mjs: bounded streaming inflate for readZipEntry (output cap = entry.uncompressedSize) to prevent memory exhaustion from malformed entries

- zip.mjs: new bounded verify Transform in streamZipEntry that enforces decompressed byte cap and verifies CRC32 on flush

- zip.mjs: new readEntryPrefix() helper that inflates only up to a byte cap for indexing use cases

- preview.mjs: move URL/path parsing inside the try block so URIError becomes a 400 response instead of an unhandled rejection

- cache.mjs: buildMetadata uses bounded readEntryPrefix (8 KiB) instead of full readEntry+slice, eliminating unbounded decompression during indexing

- cache.mjs: clearArtifactCache aborts and awaits in-flight downloads via AbortController before removing cache dirs so clear cannot be repopulated

- server.mjs / preview.mjs: track static preview servers by canvas origin and stop them on canvas close, preventing loopback server leaks

- trx-preview.js: prefer authoritative ResultSummary.outcome when it is a recognized TRX value; only infer from counters when unknown

- extension.mjs: set_account validates the requested id resolves to the active account before persisting; unknown ids now return an error

- server.mjs: reject progressive-pull offsets that are not multiples of PROGRESSIVE_PULL_BATCH_SIZE to prevent caching incomplete pulls as complete

- README.md: remove Markdown-rendering claim (files are shown as escaped text)

CI fix:

- .codespellrc: skip vendored asciinema-player(*.min.js) and primer-*.css bundles

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 47369ff4-859a-425f-8a47-763cc1a5f25f

* Address second round of PR #2341 review feedback

- github.mjs: request isDraft in the pullRequestSignals GraphQL enrichment and propagate draft into search-sourced pulls (search REST API has no draft field)

- cache.mjs: give each writeJsonAtomic write a unique temp filename via a module sequence and clean up the temp file on failure to avoid concurrent-write races

- cache.mjs: deleteCachedArtifact now aborts and awaits any in-flight download for the artifact before removing files; internal mismatched-metadata purge uses a raw removeArtifactFiles helper to avoid aborting its own operation

- accounts.mjs: skip non-github.com CLI accounts before reading tokens so GitHub Enterprise Server credentials are never sent to api.github.com

- preview.mjs: require the requested entry to be the root index.html before launching a static preview (previously any nested HTML file could start one)

- zip.mjs: validate the EOCD comment length ends exactly at the archive tail so a file comment containing the EOCD signature is not mistaken for the record

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 47369ff4-859a-425f-8a47-763cc1a5f25f

* Address remaining PR artifact explorer feedback

Fix malformed preference normalization, replace artifact-presence request fanout with cached repository artifact pagination, restrict static previews to the root index, and derive completed TRX outcomes from counters. Add focused regression coverage for all four behaviors.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: db486df1-17f1-4623-ac7e-61eff2c76da4

* Fix PR artifact explorer review feedback

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 6ee2bc81-2114-4b1f-987a-cb47ea35e132

* Stabilize artifact discovery and cache cleanup

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 6ee2bc81-2114-4b1f-987a-cb47ea35e132

---------

Co-authored-by: David Pine <7679720+IEvangelist@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 33fefd65-ed18-4eda-9c7d-48008f4a9c9d
Copilot-Session: 47369ff4-859a-425f-8a47-763cc1a5f25f
Copilot-Session: db486df1-17f1-4623-ac7e-61eff2c76da4
Copilot-Session: 6ee2bc81-2114-4b1f-987a-cb47ea35e132
2026-07-30 10:16:58 +10:00
..
2026-07-30 10:16:58 +10:00
2026-07-30 10:16:58 +10:00
2026-07-30 10:16:58 +10:00
2026-07-30 10:16:58 +10:00
2026-07-30 10:16:58 +10:00
2026-07-30 10:16:58 +10:00
2026-07-30 10:16:58 +10:00
2026-07-30 10:16:58 +10:00
2026-07-30 10:16:58 +10:00
2026-07-30 10:16:58 +10:00
2026-07-30 10:16:58 +10:00
2026-07-30 10:16:58 +10:00
2026-07-30 10:16:58 +10:00
2026-07-30 10:16:58 +10:00
2026-07-30 10:16:58 +10:00
2026-07-30 10:16:58 +10:00
2026-07-30 10:16:58 +10:00
2026-07-30 10:16:58 +10:00
2026-07-30 10:16:58 +10:00

Artifact Explorer

GitHub, the missing parts: GitHub Actions makes artifacts easy to produce, but pull-request reviewers still have to download opaque ZIP files and inspect them out of context. Artifact Explorer turns those artifacts into a fast, GitHub-native, navigable experience inside Copilot.

Artifact Explorer is a community-built Copilot canvas extension with the internal extension ID pr-artifact-explorer. It is not an official GitHub product or endorsed feature.

Artifact Explorer showing pull request workflow artifacts in a responsive GitHub-style interface

What it does

  • Navigates repositories, pull requests, artifacts, and files with persistent breadcrumbs.
  • Loads pull requests progressively, caches result pages, and supports query filters for fast review.
  • Bounds artifact discovery to the newest 30 workflow runs per head commit and reports when older runs are omitted.
  • Downloads an artifact once, indexes its ZIP, and streams entries directly from the archive without extracting them to disk.
  • Previews root-level static sites in a sandboxed loopback frame when the artifact contains index.html.
  • Plays asciinema terminal recordings and renders structured TRX test reports.
  • Syntax-highlights JSON and XML, previews images and PDFs, renders text with safe escaping, and identifies binary content.
  • Keeps large files available for direct download and falls back to the original artifact archive when a ZIP entry uses an unsupported encoding.
  • Provides per-artifact cleanup, clear-all cleanup, and a cache usage view.
  • Uses a responsive Primer interface that follows Copilot's light and dark themes.

Security and local data

Artifact Explorer inherits eligible GitHub accounts from the Copilot app, GitHub CLI, or process environment. Tokens remain inside the extension process: the canvas receives only sanitized account metadata, while authenticated GitHub API requests are made by the local extension server.

Artifact ZIPs and preferences are stored under:

$COPILOT_HOME/extensions/pr-artifact-explorer/artifacts/

When COPILOT_HOME is unset, it defaults to ~/.copilot. Cached archives remain local until removed through the per-artifact or clear-all controls.

The canvas server validates its canonical loopback host and requires a per-instance capability token for API, artifact-content, and event requests. Static-site previews bind to a separate ephemeral 127.0.0.1 port, validate their loopback host, apply a restrictive content security policy, prevent path traversal, and stream files from the ZIP. A preview requires index.html at the artifact root. Static content is untrusted, remains sandboxed by the canvas, and has no access to GitHub tokens.

Install

Ask Copilot to install the committed extension:

Install this extension: https://github.com/github/awesome-copilot/tree/main/extensions/pr-artifact-explorer

You can also copy the folder to one of the supported extension locations:

  • ~/.copilot/extensions/pr-artifact-explorer/ for user scope
  • .github/extensions/pr-artifact-explorer/ for project scope

Reload extensions, then ask Copilot to open the pr-artifact-explorer canvas. You can optionally provide a repository (owner/name), pull request number, or GitHub pull request URL when opening it.

Agent actions

  • open_pull_request { repository, pullNumber } - navigate an open canvas to a pull request.
  • inspect_artifact { repository, artifactId } - download, index, detect, and open an Actions artifact.
  • cache_status - report local artifact cache usage.
  • clear_cache { artifactId? } - remove one cached artifact or clear the entire cache.
  • accounts - list sanitized GitHub account metadata available to the extension.
  • set_account { id } - select the GitHub account used for repository and artifact requests.

Included third-party components

The extension bundles Primer CSS, Octicons, and the asciinema player for offline rendering. Their notices are preserved in third-party-licenses/.