Port the app workspace and runtime session inventory fixes from the personal James Hub canvas into the generic Work Hub extension. This lets the cleanup and recent-session surfaces read current app workspaces before falling back to the legacy session store.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* Add APNG Studio canvas extension
APNG Studio is an interactive GitHub Copilot canvas extension for building
Animated PNG (APNG) files from frames: draw or upload frames, tune per-frame
timing and compositing, preview live, send the result to a phone by QR, and
export an animated .png.
Adds extensions/apng-studio/ with the required .github/plugin/plugin.json and
assets/preview.png, and regenerates .github/plugin/marketplace.json.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Address review feedback for APNG Studio
Security and robustness (extension.mjs):
- Reject "." and ".." project ids so canvas/action input cannot resolve
outside artifacts/.
- Bound request bodies (1 MiB JSON, 40 MiB frame upload); return 413 when
exceeded.
- Reject malformed JSON with 400 instead of coercing to {}, so a truncated
body cannot trigger destructive routes such as /frames/clear.
- Scope shares per project so one canvas cannot rotate or stop another's
share; the LAN server is shared and torn down once no shares remain.
- get_state treats hiddenFirst as active only with >=2 frames, matching the
encoder, so a single-frame project reports the correct duration.
Accessibility (web/):
- Expose Pen/Eraser state with aria-pressed and keep it in sync in setTool.
- Mark the toast as an aria-live status region.
Packaging:
- Add extensions/apng-studio/.gitignore with artifacts/ so the documented
runtime-data exclusion holds for this extension.
- Update the README install section to reference the committed awesome-copilot
extension path.
Regenerated .github/plugin/marketplace.json.
* Use "GitHub Copilot app" wording
Update the plugin description (and regenerated marketplace entry) to refer to
the host as the GitHub Copilot app.
* Address deeper review for APNG Studio
Security:
- Require a per-server access token on every loopback data/mutation request
(minted per canvas server, carried in the iframe URL, attached to every
renderer request). Static assets stay public. Blocks a local process or
cross-origin page from reading state or driving mutations.
Concurrency and durability:
- Serialize the load-mutate-save cycle per project; dedupe concurrent first
loads; write project.json via temp file + rename.
Lifecycle:
- Track SSE clients per instance and end them before server.close().
- Stop a project's LAN share only when no other panel references it.
Correctness:
- Report exact numerator/denominator total duration; handle pointercancel.
QR and accessibility:
- Place QR version bits least-significant-bit first (versions 7-10).
- Associate delay/fps/dispose/blend labels with their inputs via for=.
* Address deeper concurrency and validation review for APNG Studio
- Run assemble() under the project lock; add_color_frame renders and appends
within one lock.
- Validate uploaded frames (PNG chunk scan, size + dimension checks) before
writing; first frame stores real dimensions; CanvasError maps to 400.
- Validate move delta; clear frames in memory before deleting files.
- Route the open-handler rename through applySettings.
- Deduplicate LAN share startup; clean up if the canvas closes mid-start.
- End SSE streams before server.close(); skip dead streams in broadcast.
- Exact fractional duration; drawing surface stays >= 1px; refresh state before
re-seeding "start from last frame".
* Address review: PNG format validation, share bind, limits, a11y
- Validate uploaded frames are 8-bit RGBA non-interlaced PNGs (standard
compression/filter); reject formats the codec can't encode.
- Cap projects at 600 frames (add + duplicate).
- Bind the LAN share server to the private address, not 0.0.0.0; require a
private address and rebind when it changes while idle; build the URL from the
bound address.
- Align width/height inputs and clampSize to the 2048 maximum.
- Size the drawing surface by width + aspect ratio for narrow panels.
- set_frame with an unknown frameId returns a validation error.
* Address review: encoded-byte budget, timing modes, id keys, load errors
- 256 MiB aggregate encoded-byte budget (add + duplicate); per-frame size
tracked and backfilled on load, so a frame count alone no longer bounds
assembly memory.
- Frame timing is one exclusive mode (delayMs | fps | delayNum/delayDen);
combinations are rejected instead of producing hybrid delays.
- Collision-resistant project storage keys: safe ids are used verbatim (existing
projects still load) and only unsafe ids get a hash suffix, so "foo/bar" and
"foo?bar" can't share a directory.
- Load only treats a missing file as a new project; other read/parse errors
surface instead of silently overwriting real data.
- Share server binds to a real LAN interface (skips virtual/VPN/container,
prefers physical NICs and common ranges).
- Generated export names get millisecond + random suffix to avoid same-second
overwrite.
- PNG validator accepts the encoder's Uint8Array so agent solid-color frames
aren't rejected.
* Address review: crash-safe frame writes, server startup, APNG first frame
- Write the PNG before mutating project metadata on add/duplicate, and delete
after persisting, so an interrupted disk op can't dangle a reference or
advance unsaved state.
- Evict a project from the in-memory cache if its save fails, so a transient
write error can't desync the live session from disk.
- Reject on the loopback server's listen error and drop a half-initialized
instance so startup failures clean up and can retry.
- Normalize APNG dispose_op PREVIOUS to BACKGROUND on the first animated frame
(spec requirement).
- Release decoded ImageBitmaps after use so a large upload batch doesn't retain
native image memory.
- Surface otherwise-silent async UI failures via a toast; check the state
response is ok before parsing it.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Stop the accessibility kanban extension from persisting raw refresh failure details to browser-visible state. Use a generic safe error message for clients, clear any previously persisted detailed refresh errors during state normalization, and keep detailed diagnostics server-side via console logging.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* Add Tiny Tool Town submission canvas
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* Add generated description choices
Resolve picker opens from the active session working directory so linked worktrees work without an explicit repository path.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* Address Tiny Tool review comments
Detect root .csproj files as build signals and hide canvas access tokens from the visible URL after first load.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* Address latest Tiny Tool review comments
Handle root-relative README images, preserve drafts during refresh, and suppress GitHub mentions before public issue creation.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* Address canvas shutdown and CSP review
Close all canvas servers during shutdown, use nonce-based CSP, make theme optional, and hide decorative preview dots from assistive tech.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Canvas extensions (accessibility-kanban, where-was-i) resolved git state
against the extension's install directory or the session-state folder
instead of the repo the session was opened in. This broke repo/branch
detection for user-scoped installs and worktrees ("unknown/unknown",
"detached HEAD"). Both now read the active session's working directory
from the canvas request context on open and on each action, so they
follow whichever project/worktree opened them.
where-was-i also re-gathers context on open when the saved branch is
blank, so it never opens stuck on stale data.
Also compress oversized extension preview images (pngquant, with a mild
resize for the photographic arcade-canvas art) so every preview.png is
comfortably under the installer's inline-byte cap that was blocking
release-notes-showcase from installing.
Update release-notes-showcase author to Kayla Cinnamon.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* Remove pluginRoots property from marketplace.json
The pluginRoots property is not used by install tooling and was only
informational about the extension/plugin source directories. Removing it
simplifies the marketplace.json structure while maintaining all functionality.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* Migrate java-modernization-studio to plugin.json and update validation workflow
- Create .github/plugin/plugin.json for java-modernization-studio extension
- Remove legacy canvas.json from java-modernization-studio
- Update validate-canvas-extensions.yml workflow to check for plugin.json instead of canvas.json
- Update workflow to trigger on .schemas/plugin.schema.json changes (instead of canvas.schema.json)
- Remove schema validation logic that relied on canvas.schema.json
- All 12 extensions now use plugin.json for metadata
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* Add extensions field to all extension plugin.json files
Per https://github.com/github/copilot-agent-runtime/pull/9929, plugins that ship
extensions need to include an extensions field specifying where the extension code
is located. All 12 extensions now have extensions set to '.' to reference the
current directory where extension.mjs is located.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* Enforce convention-based extension metadata and remove x-awesome-copilot
- Remove x-awesome-copilot.screenshots from all extension plugin.json files
- Enforce logo=assets/preview.png convention for all extensions
- Enforce extensions=. per copilot-agent-runtime#9929
- Update validate-plugins.mjs to enforce conventions
- Update validate-canvas-extensions.yml workflow with convention checks
- Update AGENTS.md and CONTRIBUTING.md documentation
All 12 extensions validated successfully.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Use standard plugin validation for extensions
Remove the custom extension schema and schema validation helper, and
validate extension plugin.json files through the existing plugin validator
instead. Update workflows to stop depending on the removed schema.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Add Java Modernization Studio canvas extension
A canvas extension that drives the GitHub Copilot App Modernization for Java workflow from an interactive dashboard: environment readiness checks, repo assessment, prioritized plan/progress, validation gates (CVE scan, test generation), and one-click predefined-task runs — all grounded in the repo's real artifacts (.appmod/assessment.json, plan.md, progress.md). Includes a node:test suite (109 tests) for the grounding logic.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Ayan Gupta <74832088+ayangupt@users.noreply.github.com>
* Secure cockpit loopback server with a per-instance token
Address Copilot review feedback on the Java Modernization Studio canvas:
- Mint a per-instance secret in createInstanceServer, embed it in the
iframe URL, and validate it on every loopback request (/, /state,
/events, /action). Other local processes can no longer read repo
state or dispatch agent actions just by guessing the random port.
Mirrors the existing diagram-viewer token pattern; the client echoes
the token from its boot payload. The guard is a no-op when no token is
set, so direct makeHandler unit tests are unaffected.
- Handle async request-handler rejections in createServer with a .catch
that returns 500 and logs, instead of leaking an unhandled rejection
that could destabilize the extension process.
- Tests: token guard 403s unauthenticated /, /state, /events and
/action and allows valid-token requests; the end-to-end test asserts
the tokenized URL and a tokenless 403.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix CI: add preview screenshot and clear codespell hits
Add the required assets/preview.png screenshot for the canvas-extension
validator, and resolve two codespell findings in the cockpit:
rename the planSim helper's `nd` variable to `notDone` and reword a
catalog comment to avoid the `invokable`/`invocable` flag.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Harden cockpit loopback server per Copilot review
Address the second-round Copilot review comments on the loopback server:
- broadcast(): drop an SSE client whose write() throws instead of keeping
it in the Set, so a uncleanly-disconnected client can't cause repeated
exceptions or leak dead entries on every subsequent broadcast.
- POST /action: treat a malformed JSON body or a missing/invalid "kind"
as a 400 client error (with an application/json body) instead of a 200
carrying { ok:false, error:"Unknown action: undefined" }.
- Handler catch: set Content-Type: application/json on the 500 error
response so it is consistent with the other JSON routes.
Adds four tests covering dead-client eviction, the two 400 paths, and the
JSON-typed 500. Full suite: 115 passing.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Ayan Gupta <74832088+ayangupt@users.noreply.github.com>
* Add canvas.json gallery metadata for Java Modernization Studio
Aaron requested a canvas.json so the awesome-copilot website/gallery can
list this extension. Generated via `npm run website:data`
(writePerExtensionCanvasManifests), which derives id/name/description/
version/keywords/screenshots from package.json + the createCanvas source +
assets, and carries the author through. Output committed verbatim so a CI
regeneration produces no diff.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Ayan Gupta <74832088+ayangupt@users.noreply.github.com>
* Add author tag to package.json
Declare the author in the package manifest (object form, matching the
author already carried in canvas.json so it includes the profile URL).
The published gallery sources author from canvas.json; this adds the
conventional npm author tag to package.json for completeness. Verified
`npm run website:data` still emits the author on the extensions record
and leaves canvas.json byte-identical.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Ayan Gupta <74832088+ayangupt@users.noreply.github.com>
---------
Signed-off-by: Ayan Gupta <74832088+ayangupt@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add Site Studio canvas extension
Site Studio is a canvas extension for planning, drafting, and tracking a
personal website section by section. It gives you and your agent a shared
dashboard with a status board, an autosaving content editor (with AI-draft
and [Sample: ...] placeholders), and a live feed of every change and milestone.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Address Copilot review feedback
Robustness, prototype-pollution safety, and accessibility fixes from the
Copilot code review on #2117:
- Add "ai_request" to VALID_CHANGE_TYPES so log_change accepts the change
type the server itself emits (e.g. /api/request-generation).
- Bound the git branch lookup with timeout + maxBuffer so a hung git can't
block the extension process and canvas UI.
- Serialize state persistence via a promise queue and snapshot state
synchronously, so concurrent mutations can't clobber newer state on disk.
- Enforce a maximum request body size in readBodyJson to avoid unbounded
memory use on the loopback server.
- Guard the /events handler against a missing/closed instance instead of
throwing when servers.get(instanceId) is undefined.
- Reject unsafe field names (__proto__, prototype, constructor) in
upsertSectionContent and use an own-property check in deleteSectionContent
to prevent prototype pollution.
- Make the "Generate with AI" info tooltip reachable by keyboard and screen
readers (focusable, labelled) instead of mouse-hover only.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: ayangupt <ayangupt@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Show "by @handle" on each canvas extension card and in the details
modal, linking to the contributor's GitHub profile. Author metadata
lives in each extension's canvas.json (and external.json for external
extensions), where the rest of the canvas metadata is stored.
- Store author {name, url} in canvas.json / external.json
- Read author from canvas.json in the website data generator and emit
it to extensions.json
- Render the GitHub @handle, derived from the profile URL, as the link
text, with the contributor's name as the link title
- Escape the sanitized author URL before interpolating it into href
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Load open issues from the current repository instead of hardcoded SignalBox data, preserve board metadata across refreshes, and expose filter state through canvas actions/API.
Update the canvas UI and metadata to Repository Issues Kanban, add multi-label OR filtering controls, and surface repo detection/fetch errors in the board.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Load PRs from the active workspace repo instead of the extension directory, surface PR load errors in the canvas UI, and add MediaPipe CDN fallbacks for better runtime reliability.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add keyword display to extension cards on website
- Add .resource-keywords and .keyword-tag CSS styles for rendering keyword badges
- Update renderExtensionsHtml() to display keywords below extension description
- Keywords now visible on the website extensions page with styled badges
- Regenerate website data to include keyword metadata
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Canvas manifest implementation for all extensions
Add per-extension canvas manifests with:
- Structured canvas metadata (name, description, version, keywords)
- Screenshot definitions (icon and gallery with path/type)
- Relative paths for images within each extension directory
Enhance extension metadata:
- Generate meaningful descriptions from source analysis
- Extract and assign keywords for discoverability
- Store metadata in package.json and extension source files
Update website rendering and data generation:
- Include keywords in extension cards and search index
- Add per-extension canvas.json files for independent evolution
- Support screenshot metadata in manifest structure
- Generate extensions.json with full canonical paths for website
All 9 local canvas extensions now have complete manifests with descriptions, keywords, and screenshot references.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Tweaking some descriptions
* Fix description priority to prefer package.json over in-source metadata
Reverse the priority in canvasDescription so that package.json descriptions
(which contain the enhanced, manually-curated descriptions) take precedence
over older in-source descriptions extracted from createCanvas(...) calls.
This prevents regression when npm run website:data regenerates outputs,
ensuring that committed canvas.json files maintain the current descriptions.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix canvas validation to skip external.json file
The validation script was treating extensions/external.json as if it were
a directory, causing false validation failures. Added check to skip files
(identified by presence of dot in filename) and only validate actual
canvas extension directories.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Generate extensions data, add the extensions listing route/navigation, and include install URL copy actions pinned to the build commit SHA.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>