Skip to content

Artifact Explorer: resilient jobs, browser emulator, Docs, sharing, and workflow re-run - #5068

Open
IEvangelist wants to merge 22 commits into
github:mainfrom
IEvangelist:ievangelist-artifact-explorer-resilient-canvas
Open

IEvangelist wants to merge 22 commits into
github:mainfrom
IEvangelist:ievangelist-artifact-explorer-resilient-canvas

Conversation

@IEvangelist

Copy link
Copy Markdown
Contributor

Pull Request Checklist

  • I have read and followed the CONTRIBUTING.md guidelines.
  • I have read and followed the Guidance for submissions involving paid services.
  • My contribution adds a new instruction, prompt, agent, skill, workflow, or canvas extension file in the correct directory.
  • The file follows the required naming convention.
  • The content is clearly structured and follows the example format.
  • I have tested my instructions, prompt, agent, skill, workflow, or canvas extension with GitHub Copilot.
  • I have run npm start and verified that README.md is up to date. (npm run build passes.)
  • I am targeting the main branch for this pull request.

Description

Updates the Artifact Explorer canvas (extensions/pr-artifact-explorer, plugin and skill) with:

  • Resilience: retry and full restart; background download/index/extract jobs that survive request/view changes; ZIP64 and bounded central-directory handling; soft limit prompts (download, indexing, decompression, idle) that never stop work, with raised limits checked against live progress. Integrity and disk guards stay hard.
  • Sharing and skill: unified targets (repo, PR, issue, artifact, route) for sharing links and the AI skill.
  • Browser emulator: localhost/HTTP(S) preview with mobile/tablet/desktop presets, viewport vs. visual zoom, history/refresh, natural-language navigation, real Playwright/Chromium screenshots and device emulation (explicit setup, no silent install), keyboard hints.
  • Docs tab: built-in usage docs.
  • Artifact preview: universal Preview/Raw toggle, native video, JUnit viewer, HTML Browser action, per-render race guards, theme sync, open in default browser.
  • UX: copy title / copy link buttons, #number links to GitHub, compact Back/Forward route history, full PR-detail skeleton.
  • Workflow re-run: confirmation-gated re-run of the originating Actions run (all or failed jobs), permission- and eligibility-aware, original actor/SHA warning.

Type of Contribution

  • Update to existing instruction, prompt, agent, plugin, skill, workflow, or canvas extension.

Additional Notes

Verification: extension suite 92/92 (--test-concurrency=2), plugin:validate, skill:validate, npm run build, and line-ending normalization pass. Re-run behavior was tested only against mocked GitHub APIs; no real CI was triggered.


By submitting this pull request, I confirm that my contribution abides by the Code of Conduct and will be licensed under the MIT License.

IEvangelist and others added 20 commits October 12, 2026 23:23
…browser preview, and sharing skill

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 72ee5a2d-bcbb-4e0f-b86f-6ad56d4fc033
…nit XML viewer

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 72ee5a2d-bcbb-4e0f-b86f-6ad56d4fc033
…contextual UI, media, JUnit

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 72ee5a2d-bcbb-4e0f-b86f-6ad56d4fc033
Parse JUnit times strictly, showing unknown timings as Not recorded.
Scope video error listener to its live preview and distinguish
network/integrity from decode failures.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 72ee5a2d-bcbb-4e0f-b86f-6ad56d4fc033
Per-term substring matching made 'Browser A' match every row via the 'a' term. Match the whole normalized phrase and cover it in the Chromium regression.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 72ee5a2d-bcbb-4e0f-b86f-6ad56d4fc033
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 72ee5a2d-bcbb-4e0f-b86f-6ad56d4fc033
…e, open in default browser

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

Copilot-Session: 72ee5a2d-bcbb-4e0f-b86f-6ad56d4fc033
…und-trip

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 72ee5a2d-bcbb-4e0f-b86f-6ad56d4fc033
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 72ee5a2d-bcbb-4e0f-b86f-6ad56d4fc033
… teardown, preserve report state across Raw/Preview

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 72ee5a2d-bcbb-4e0f-b86f-6ad56d4fc033
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 72ee5a2d-bcbb-4e0f-b86f-6ad56d4fc033
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 72ee5a2d-bcbb-4e0f-b86f-6ad56d4fc033
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 72ee5a2d-bcbb-4e0f-b86f-6ad56d4fc033
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 72ee5a2d-bcbb-4e0f-b86f-6ad56d4fc033
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 72ee5a2d-bcbb-4e0f-b86f-6ad56d4fc033
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 72ee5a2d-bcbb-4e0f-b86f-6ad56d4fc033
…on permission lookup errors

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

Copilot-Session: 72ee5a2d-bcbb-4e0f-b86f-6ad56d4fc033
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 72ee5a2d-bcbb-4e0f-b86f-6ad56d4fc033
@IEvangelist
IEvangelist requested review from a team as code owners October 14, 2026 02:54
Copilot AI balanced review requested due to automatic review settings October 14, 2026 02:54
@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

🔒 PR Risk Scan Results

Scanned 52 changed file(s).

Severity Count
🔴 High 0
🟠 Medium 4
ℹ️ Info 0
Severity Rule File Line Match
🟠 package-exec-command extensions/pr-artifact-explorer/README.md 39 npm install playwright-core # then: npx playwright install chromium
🟠 package-exec-command extensions/pr-artifact-explorer/assets/browser.js 503 &lt;details class="docs-details"&gt;&lt;summary&gt;Set up Chromium if capture is unavailable&lt;/summary&gt;&lt;p&gt;Setup is explicit; Explorer does not install anything silently. Use an existing Playwri
🟠 package-exec-command extensions/pr-artifact-explorer/capture.mjs 37 "2. Install the browser once: npx playwright install chromium",
🟠 package-exec-command extensions/pr-artifact-explorer/capture.test.mjs 32 if (error.code === "playwright_missing") assert.match(error.message, /npx playwright install chromium/);
Skipped non-text or missing files
  • extensions/pr-artifact-explorer/assets/docs/continuing-job.png
  • extensions/pr-artifact-explorer/assets/docs/preview-controls.png
  • extensions/pr-artifact-explorer/assets/docs/preview-options.png

This is an automated soft-gate report. Findings indicate review targets and do not block merge by themselves.

@github-actions github-actions Bot added canvas-extension PR touches canvas extensions new-submission PR adds at least one new contribution plugin PR touches plugins skills PR touches skills labels Oct 14, 2026
@github-actions

github-actions Bot commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor

🚦 Submission status: 🛠️ Requires submitter fixes

Risk tier: merge-risk:high — Privileged execution, automation, or review-policy change
Required to merge: passing submission-gate checks plus 1 approval from reviewers with write access, including a maintainer with admin or maintain permission.

Why this tier
  • Spawns processes or evaluates code in extensions/pr-artifact-explorer/external-open.mjs
  • Spawns processes or evaluates code in extensions/pr-artifact-explorer/markdown-preview.test.mjs

Automated checks

Check Status Details
Line endings ✅ Passed Passed · logs
Spelling ✅ Passed Passed · logs
Generated README consistency ✅ Passed Passed · logs
Plugin and extension validation ✅ Passed Passed · logs
Canvas extension validation ✅ Passed Passed · logs
Plugin structure ✅ Passed Passed · logs
Skill validation ✅ Passed Passed · logs
Skill lint (vally) ✅ Passed Passed · logs
Risk scan ✅ Passed Passed · logs
Contributor reputation ✅ Passed Passed · logs
Duplicate resource scan ✅ Passed Passed · logs
PR quality signal ⏭️ Skipped Skipped by its workflow · logs
Canvas/plugin smoke test ❌ Contribution failure Failed step: Run canvas smoke test · logs

Action needed

  • Canvas/plugin smoke test failed. See the smoke-test job log for the failing plugin or extension.

Review

  • Approvals: 0/1
  • Assigned reviewer: not assigned yet — comment /request-review to ask for one
  • Review target date: not set
  • Still needed: 1 more approval(s); an approval from a maintainer with admin or maintain permission
  • The core-maintainers pool is not staffed yet; an approver with admin or maintain permission is required instead.

Commands

Command Who What it does
/rerun-checks PR author, maintainers Re-runs failed or incomplete checks and re-evaluates this gate
/request-review PR author, maintainers Asks the review rotation to assign a reviewer (adds needs-reviewer)

Updated for 23f5137 · gate run · This comment is maintained automatically — see submission gate docs.

@github-actions github-actions Bot added requires-submitter-fixes Submission has quality-gate findings that submitter must fix before maintainer review and removed awaiting-automation labels Oct 14, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🔍 Vally Lint Results

✅ All checks passed

Scope Checked
Skills 1
Agents 0
Total 1
Severity Count
❌ Errors 0
⚠️ Warnings 0
ℹ️ Advisories 0

Summary

Level Finding
ℹ️ ✅ pr-artifact-explorer (2/2 checks passed)
ℹ️ ✓ [spec-compliance] All 1 skill(s) are spec-compliant.
ℹ️ ✓ spec-compliance: All spec checks passed.
ℹ️ ✓ [valid-refs] All file references across 1 skill(s) are valid.
ℹ️ ✓ valid-refs: All file references resolve to existing files within the skill directory.
ℹ️ 1 skill(s) linted, 1 passed
Full linter output
### Linting skills/pr-artifact-explorer
✅ pr-artifact-explorer (2/2 checks passed)
    ✓ [spec-compliance] All 1 skill(s) are spec-compliant.
        ✓ spec-compliance: All spec checks passed.
    ✓ [valid-refs] All file references across 1 skill(s) are valid.
        ✓ valid-refs: All file references resolve to existing files within the skill directory.

1 skill(s) linted, 1 passed

IEvangelist and others added 2 commits October 13, 2026 21:56
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 72ee5a2d-bcbb-4e0f-b86f-6ad56d4fc033
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 72ee5a2d-bcbb-4e0f-b86f-6ad56d4fc033

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Embedded credentials, malformed routes, and unbounded finished-job retention must be addressed.

7 open findings
What changed in this PR

Expands Artifact Explorer with resilient artifact processing, browser emulation, richer previews, sharing, documentation, and workflow re-runs.

Changes:

  • Adds persistent jobs, configurable soft limits, ZIP64 handling, and integrity checks.
  • Adds browser emulation, screenshots, raw/video/JUnit previews, navigation, and sharing.
  • Adds confirmation-gated workflow re-runs and a canvas-driving skill.

Repository fit: High—provides concrete, canvas-specific workflows and safety constraints.

File Description
skills/​pr-artifact-explorer/​SKILL.md Documents canvas actions and recovery workflows.
plugins/​pr-artifact-explorer/​plugin.json Bundles the new skill.
extensions/​pr-artifact-explorer/​zip64.test.mjs Tests ZIP32/ZIP64 validation.
extensions/​pr-artifact-explorer/​video-http.test.mjs Tests video range serving.
extensions/​pr-artifact-explorer/​targets.test.mjs Tests target and share parsing.
extensions/​pr-artifact-explorer/​targets.mjs Implements unified target routing.
extensions/​pr-artifact-explorer/​server.test.mjs Covers server APIs and restart behavior.
extensions/​pr-artifact-explorer/​rerun.test.mjs Tests re-run eligibility and confirmation.
extensions/​pr-artifact-explorer/​rerun.mjs Implements workflow re-run requests.
extensions/​pr-artifact-explorer/​report-state.test.mjs Tests JUnit view-state preservation.
extensions/​pr-artifact-explorer/​render.mjs Adds navigation and browser UI assets.
extensions/​pr-artifact-explorer/​README.md Documents the expanded feature set.
extensions/​pr-artifact-explorer/​raw.mjs Implements bounded raw previews.
extensions/​pr-artifact-explorer/​raw-wiring.test.mjs Verifies raw-preview UI wiring.
extensions/​pr-artifact-explorer/​raw-open.test.mjs Tests raw views and external opening.
extensions/​pr-artifact-explorer/​range-integrity.test.mjs Tests range-read integrity enforcement.
extensions/​pr-artifact-explorer/​pull-loading.test.mjs Tests PR loading and race handling.
extensions/​pr-artifact-explorer/​preview.mjs Adds verified streaming and owned previews.
extensions/​pr-artifact-explorer/​owned-theme.test.mjs Tests preview theme synchronization.
extensions/​pr-artifact-explorer/​nav-history.test.mjs Tests in-canvas route history.
extensions/​pr-artifact-explorer/​mode-race.test.mjs Tests preview-mode race guards.
extensions/​pr-artifact-explorer/​media-junit.test.mjs Tests media ranges and JUnit rendering.
extensions/​pr-artifact-explorer/​limits.mjs Implements persistent soft limits.
extensions/​pr-artifact-explorer/​jobs.mjs Implements background job tracking.
extensions/​pr-artifact-explorer/​jobs-limits.test.mjs Tests jobs and limit persistence.
extensions/​pr-artifact-explorer/​github.mjs Adds GitHub issue retrieval.
extensions/​pr-artifact-explorer/​external-open.mjs Adds validated OS-browser launching.
extensions/​pr-artifact-explorer/​detector.mjs Recognizes common video formats.
extensions/​pr-artifact-explorer/​constants.mjs Defines job storage and soft limits.
extensions/​pr-artifact-explorer/​close-bounded.test.mjs Tests bounded Chromium shutdown.
extensions/​pr-artifact-explorer/​capture.test.mjs Tests screenshots and controlled browsing.
extensions/​pr-artifact-explorer/​capture.mjs Implements Chromium capture and emulation.
extensions/​pr-artifact-explorer/​backend-gaps.test.mjs Covers ZIP, limits, and persistence edge cases.
extensions/​pr-artifact-explorer/​assets/​octicons/​plus.svg Adds plus icon.
extensions/​pr-artifact-explorer/​assets/​octicons/​keyboard.svg Adds keyboard icon.
extensions/​pr-artifact-explorer/​assets/​octicons/​device-mobile.svg Adds mobile-device icon.
extensions/​pr-artifact-explorer/​assets/​octicons/​device-camera.svg Adds screenshot icon.
extensions/​pr-artifact-explorer/​assets/​octicons/​dash.svg Adds minus icon.
extensions/​pr-artifact-explorer/​assets/​octicons/​copy.svg Adds copy icon.
extensions/​pr-artifact-explorer/​assets/​octicons/​book.svg Adds documentation icon.
extensions/​pr-artifact-explorer/​assets/​octicons/​arrow-right.svg Adds forward-navigation icon.
extensions/​pr-artifact-explorer/​assets/​octicons/​arrow-left.svg Adds back-navigation icon.
extensions/​pr-artifact-explorer/​assets/​junit-preview.js Implements the JUnit report viewer.
docs/​README.skills.md Registers the new skill.
docs/​README.plugins.md Updates the plugin item count.

🧠 Review effort: Balanced


💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +96 to +100
if (url.protocol !== "http:" && url.protocol !== "https:") {
throw new CaptureError("invalid_url", "Only http and https URLs can be captured.");
}
return url;
}
job.unregister = [];
this.#emit(job);
this.#syncIdleTimer();
this.#schedulePersist();
Comment on lines +207 to +208
// Finished streams are transient; only failures remain visible.
if (job.status === "succeeded" || job.status === "cancelled") this.#jobs.delete(job.id);
Comment on lines +95 to +99
let match = route.match(/^\/pull\/([^/]+)\/(\d+)$/);
if (match) return { kind: "pull", repository: decodeURIComponent(match[1]), number: Number(match[2]) };
match = route.match(/^\/issue\/([^/]+)\/(\d+)$/);
if (match) return { kind: "issue", repository: decodeURIComponent(match[1]), number: Number(match[2]) };
match = route.match(/^\/artifact\/([^/]+)\/(\d+)\/(\d+)$/);
Comment on lines +82 to +83
- `share { input, preset?, zoom?, width?, height? }` - build shareable links that round-trip through `open_target`.
- `share { input }` - produce a shareable link, route, and text for a target.
const { dir, policy: p } = await policy();
try {
p.submit("downloadBytes", 123456789);
await new Promise((resolve) => setTimeout(resolve, 100));
onSoftLimit: (kind, current) => warnings.push([kind, current]),
});
assert.equal(index.entries.length, 1);
assert.ok(Array.isArray(warnings));
Copilot AI balanced review requested due to automatic review settings October 14, 2026 02:59
@github-actions github-actions Bot added awaiting-automation and removed requires-submitter-fixes Submission has quality-gate findings that submitter must fix before maintainer review labels Oct 14, 2026
@github-actions github-actions Bot added requires-submitter-fixes Submission has quality-gate findings that submitter must fix before maintainer review and removed awaiting-automation labels Oct 14, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unsafe browser-route decoding permits script execution, while advertised commands and cleanup paths also contain correctness and reliability defects.

9 open findings
Previously missed (4)

In code that hasn't changed since last review

Medium severity Preserve or terminate browsers after shutdown timeout

extensions/​pr-artifact-explorer/​capture.mjs:392

When browser shutdown times out, closeBrowserBounded returns false, but this method has already discarded every reference to the still-running browser. The process can no longer be retried or reclaimed, so repeated controlled sessions can leak Chromium processes. Preserve a cleanup handle on timeout or forcibly terminate the browser process before clearing the fields.

Medium severity Trim retained failed stream jobs

extensions/​pr-artifact-explorer/​jobs.mjs:208

Failed stream jobs are deliberately retained, but unlike artifact jobs this path never calls #trim(). Repeated failed decompressions therefore grow #jobs, /api/jobs, and the visible failed-job panel without bound despite MAX_FINISHED_JOBS. Trim after retaining a failed stream and persist if trimming removes stored artifact history.

Medium severity Dispatch natural-language browser commands to the correct channel

extensions/​pr-artifact-explorer/​targets.mjs:164

These parser branches advertise natural-language zoom, viewport, rotate, screenshot, and navigation commands, but the open_target action only executes back/forward/refresh when a controlled browser is active and rejects every other command target. Thus skill examples such as zoom 150%, tablet, screenshot, and even go back in the normal preview always fail. Dispatch these commands to the regular browser command channel (and screenshot action), with controlled-browser handling where appropriate.

Medium severity Reject unsafe numeric IDs instead of returning null targets

extensions/​pr-artifact-explorer/​targets.mjs:202

positive() returns null for integers outside JavaScript's safe range, but the natural-language parser still returns an artifact/PR/issue target containing that null ID. For example, show artifact #9007199254740992 in o/r becomes { artifactId: null } and later generates a broken route instead of a user-facing input error.

🧠 Review effort: Balanced

Comment on lines +38 to +48
function decodeViewClient(text) {
if (!text) return {};
try {
const padded = text.replaceAll("-", "+").replaceAll("_", "/");
const binary = atob(padded + "=".repeat((4 - (padded.length % 4)) % 4));
const body = JSON.parse(new TextDecoder().decode(Uint8Array.from(binary, (c) => c.charCodeAt(0))));
return { url: body.url, preset: body.preset, width: body.w, height: body.h, zoom: body.z, orientation: body.o };
} catch {
return {};
}
}
Comment on lines +96 to +99
if (url.protocol !== "http:" && url.protocol !== "https:") {
throw new CaptureError("invalid_url", "Only http and https URLs can be captured.");
}
return url;

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

canvas-extension PR touches canvas extensions merge-risk:high new-submission PR adds at least one new contribution plugin PR touches plugins requires-submitter-fixes Submission has quality-gate findings that submitter must fix before maintainer review skills PR touches skills

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants