Commit Graph
80 Commits
Author SHA1 Message Date
Dan WahlinandAaron Powell 3a685010a7 Update Agent Arcade canvas (#4482)
Co-authored-by: Aaron Powell <me@aaron-powell.com>
2026-10-07 17:24:23 +11:00
Burke HollandandCopilot App 44a37b59fa Add Draw canvas extension 🤖🤖🤖 (#3729)
* Add Draw canvas extension

Draw is a GitHub Copilot app canvas for simple diagrams: shapes, arrows
that stay attached, text and a freehand pen. The user and Copilot edit the
same drawing. Copilot can create, change, lay out and export it through
canvas actions, and the Ask Copilot button sends the drawing to the chat.

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

* Address Copilot review feedback

- Refuse changes that would take a drawing past 5,000 elements with a
  clear error instead of silently dropping elements, and stop the canvas
  from retrying a refused save.
- Keep collision suffixes within the 48-character id limit.
- Keep a drawing and report the error when deleting its file fails.
- Retry failed drawing writes, and report them in the canvas and in agent
  action results instead of only logging them.
- List pen strokes in the get_drawing outline.
- Let Space and Enter work normally on focused buttons.
- Only use Tab to add a step when a shape is selected, so Tab can move
  focus out of the canvas.
- Pick readable text colors for accent and danger backgrounds.
- Hide "Bring to front" and "Send to back" when only arrows are selected,
  since arrows always draw on top.
- Report theme save failures from /api/settings and set_theme.
- Keep the top bar buttons visible when the status text is long, and
  remove leftover theme debug logging.

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

* Address second Copilot review

- Add node:test suites for the loopback server (Host and token checks,
  static file allowlist and CSP, every API route, live events and save
  error reporting), the drawing store, layout label references and
  solid-fill text contrast. Run them with `node --test` in extensions/draw.
- Give every popover an accessible name. The delete confirmation is now an
  alertdialog described by its question.
- Build the id and label lookups in buildFromSpec once, instead of once per
  element or per edge.

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

* Address third Copilot review

- Switching drawings or asking Copilot no longer goes ahead when the edits
  on screen could not be saved first. Draw stays on the drawing and offers
  "Discard changes", and a switch started by the agent moves the server back
  to the drawing the panel still shows. Deleted drawings never hold the panel.
- Agent actions write the drawing before returning, so a disk problem is
  reported by the action that caused it.
- Count edge crossings with a Fenwick tree (O(E log V)) and typed arrays.
  The layout is unchanged; the worst case is about three times faster.
- Reconnecting brings back a save error that still applies.
- The selection keeps up to MAX_ELEMENTS ids instead of 1,000.
- Tests for the actions wrapper, the selection limit and crossing counts.

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

* Address fourth Copilot review

- Stop an old save from undoing the last one. Each change the page
  sends now has a number, and the server drops one older than a change
  it already applied (refused changes do not count). The save sent when
  the panel closes also sets every element the change still on its way
  touched to what the editor shows, so either arrival order ends with
  what is on screen.
- get_drawing reads a big drawing in parts of about 30,000 characters
  (start and nextStart), can list only some ids or the selection, cuts
  labels longer than 300 characters in the outline, and counts a huge
  selection instead of listing it.
- Ask sends at most about 16,000 characters of outline and says how
  to read the rest with get_drawing.
- After switching away from a drawing with "Discard changes" while a
  save was on its way, send edits made in the new drawing once it
  returns.
- Tests for all of the above.

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

* Address fifth Copilot review

- Exports stay with the drawing they came from. The agent's export
  request names the drawing, the page answers with the id it actually
  drew, and the server turns down a mismatch instead of saving the
  image under the wrong drawing. Save as PNG and Ask read the id right
  before rendering, and Ask keeps the question if another drawing
  opens while it is sending.
- When the server tidies up a save, for example by capping a size, it
  sends the stored drawing back and the page shows that instead of
  assuming it was stored as sent. The tidy-up is not an undo step, so
  undo cannot get stuck on it.
- Shapes are capped at 5000 wide or tall everywhere. Growing a shape
  for a longer label or a bigger text size caps the height before
  centering, so the shape no longer jumps.
- Rebuilding the style bar keeps keyboard focus on the same button,
  and hiding it moves focus to the canvas.
- Edits refresh the drawing list, batched so a burst of edits sends it
  once, and a copied drawing is listed with its real element count.

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

* Address sixth Copilot review

- Ask refuses (409) to send a question when the panel shows another
  drawing than the one it is about, and the page keeps the draft. The
  context it sends now includes the drawingId.
- Actions on the shown drawing take an optional drawingId. If the canvas
  shows a different drawing, they change nothing and say which one it
  shows.
- Temp file names for atomic writes include a counter, so two writes of
  one file in the same millisecond no longer share a temp file.
- The canvas works from the keyboard and with screen readers: the SVG is
  a focusable application with a description, N and Shift+N select
  elements, Enter adds shapes and text or connects shapes with the arrow
  tool, Ctrl+Shift+Arrow resizes, and a live region reads out the tool,
  the selection and each change. Tab now moves focus instead of adding a
  step, except while typing a label.

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

* Address seventh Copilot review

- Saving: a write that fails part way (a full disk, say) no longer leaves
  its temp file behind. Every retry picks a new temp name, so these used
  to pile up.
- Diagram specs: a node or text with only x or only y is now an error that
  names the item, instead of being laid out automatically and silently
  dropping the coordinate that was given. Non-numeric x or y is an error
  too.
- Switching drawings: while the panel waits to save the current drawing
  before showing another one, the server already sends the new drawing's
  changes, save status and selection. These are now kept and applied when
  the switch finishes, instead of being dropped.
- Showing the drawing that is already on screen (an agent calling
  open_drawing on it, or two switches to the same drawing) is now a normal
  update. It no longer reloads the editor, which wiped the undo history,
  the selection and the zoom, and it no longer warns about unsaved changes
  while a save is being refused. The server keeps the panel's selection in
  that case too.

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

* Address eighth Copilot review

- State file: writes of .state.json (which drawing each panel shows) now
  run one at a time, and each one takes the state as it is when its turn
  comes. An older write that is slow to finish (Windows can briefly lock
  a file) can no longer land after a newer one, and flush() now also
  waits for a state write that had already started.
- Placement: when every spot tried next to a shape is taken, a new shape
  now goes just past everything in that direction, in line with the
  shape, instead of on top of existing content. This covers both the
  editor's "add a connected step" command and add_elements.

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

* Address ninth Copilot review

Tab in the label editor now adds the next step only for shape labels.
For free text and arrow labels it keeps its normal job and moves focus
on, and the blur saves the edit. The README and the in-app shortcut list
now say "a shape's label".

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

* Address tenth Copilot review

- Label wrapping searches for how many words or characters fit on a
  line instead of adding one at a time, so a long label with no spaces
  is no longer quadratic. The output is unchanged.
- Arrows attached to nothing follow their elbow or curve route too.
- A selection the agent makes while the user drags or edits a label is
  shown once they finish, unless they picked something else meanwhile.
- A drawing name more than one drawing has no longer opens the first
  one; the error lists their ids, and an exact id always picks one.

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

* Address eleventh Copilot review

- Pen strokes stay bounded while drawing: once a stroke holds 10,000
  points it is simplified and thinned to 5,000. A saved stroke keeps an
  even spread of its points with both ends, instead of losing its end
  past 5,000 points. Simplification runs in pieces of 512 points, so its
  time grows in step with the stroke rather than with its square.
- Live updates send the element-level ops that made a change, against
  the drawing one change earlier, instead of the whole drawing to every
  other panel. A panel that finds a change missing fetches the whole
  drawing again.

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

* Address twelfth Copilot review

- The save a page sends as it closes is marked keepalive whenever it fits
  the browser's 64 KiB limit. That limit covers all keepalive requests
  together, so splitting would not help; a bigger save goes as an
  ordinary request.
- Pen strokes keep at most 2,000 points, so even the biggest one fits in
  that save. A test checks the biggest stroke and labels against the limit.
- A rename goes to the drawing it was typed for. It is cancelled if the
  panel moves to another drawing, it does not undo a rename the agent made
  meanwhile, and its reply never moves the panel.

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

* Address thirteenth Copilot review

- Turn down a layout that would put a shape or text past the +/-1,000,000
  position limit (very long arrow labels spread the layers that far).
  Saving used to move such positions back to the limit, stacking shapes on
  top of each other while the action reported success. set_diagram and
  add_elements now fail with invalid_diagram, and layout with
  layout_too_big, and nothing is changed.
- Fetch the drawing each time the event stream connects, not only on
  reconnects. A change made after the page loaded the drawing but before
  the server registered the new connection was never delivered.
- List text size on shapes, arrows and text, and color on text, in the
  get_drawing outline, and say that styles left out are the defaults.

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

* Address fourteenth Copilot review

- open_drawing now waits for the canvas to take the drawing. The switch
  carries an id, and the page confirms it once it shows the drawing, or,
  when it has edits it cannot save yet, moves the panel back with the same
  id. A refusal becomes an unsaved_changes error, and no answer within 10
  seconds is reported as unconfirmed, with advice to pin drawingId.
- Pen hit testing no longer makes an object for every point on every
  pointer move. Stroke extents are cached per points array, strokes out of
  reach are skipped by their box, and the rest are measured straight from
  the stored pairs.

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

* Address fifteenth Copilot review

- Automatic layout counts the placeholders its long arrows need before
  making any, and turns down a drawing that needs more than 100,000. A
  long chain with many arrows across it could otherwise need millions,
  which kept the extension busy for most of a minute. layout fails with
  layout_too_big, and set_diagram and add_elements with invalid_diagram,
  and nothing is changed.
- relayout now returns { elements, error } like buildFromSpec, so the
  layout action gets this and the position range check from one place.

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

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-10-07 14:46:01 +11:00
Fabrizio Lussana 23618867f1 Fix #3204: Color Orb glow does not update for non-hex CSS colors (#3205)
Removed background and boxShadow styles from orb on color event.
2026-09-17 11:40:22 +10:00
Marco Antonio SilvaandCopilot 5e59c61ead Add modernization workflow canvas (#2758)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-09-14 14:29:03 +10:00
Liz TomandCopilot App c2e1edf8c9 Fix sentry-triage bug bash issues and stream org project pagination (#2948)
Bug-bash fixes for the sentry-triage canvas extension:

- Model list: auto-refresh via session.rpc.model.list() with a static
  fallback, instead of a hardcoded list that went stale.
- Plain-English toggle: gate the toggle until enrichPlainEnglish()
  completes, fixing a race where it was interactive before enrichment
  finished. Add a preparing hint while it runs.
- Copy: 'Plain-English titles' -> 'Plain-English messages'; simplify the
  loading hint.
- Work status labels: distinguish 'starting Copilot fix session' vs
  'filing tracking issue' instead of a generic 'working', and mark the
  Fix-with-Copilot toast as non-blocking.
- Org project pagination: page the traversal as discrete queued tasks
  bounded by page count, driven by the SDK envelope hasMore flag, so a
  mega-org no longer starves interactive lookups and an incomplete
  traversal is never cached as complete. No Promise.race timeout is used
  because sentry@0.42.2 exposes no per-call cancellation and an abandoned
  call would corrupt module-global cursor state.

Bump plugin to 1.2.0 and regenerate marketplace.json.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-09-07 14:11:08 +10:00
Pierce BogganandCopilot App 5eaae7e2cd Add Jupyter notebooks canvas extension (#2889)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-09-01 15:05:04 +10:00
John HaugabookandCopilot Autofix powered by AI f118344017 Extension edit tutorial (#2806)
* canvas-extension: new edit-tutorial extension

* canvas-extension: new edit-tutorial extension

* canvas-extension: new edit-tutorial extension

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply edits from code review

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply edits from code review

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply edits from code review

* Apply edits from code review

* Apply edits from code review

* Apply edits from code review

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply edits from code review

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply edits from code review

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply edits from code review

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply edits from code review

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* improve: create tutorial from past commits

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply edit from code review

* Apply edit from code review

* Apply edits from code review

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply edit from code review

* apply review, preserve canvas in repo project sessions

Apply edit from code review

improve: preserve canvas render in project from repo

code-review: perform local code review

resolve: preserving canvas for repo projects

resolve: preserving canvas for repo projects

code-review: perform local code review

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply edit from code review

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply edit from code review

* Apply edit from code review

* Apply edits from code review

* Apply edits from code review

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply edits from code review

* resolve: reviewed formatting error

* Apply edit from code review

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-08-28 10:15:13 +10:00
Liz TomandCopilot App bbde357dbd Add one-click install/sign-in to sentry-triage setup gate (#2831)
The sentry-triage canvas's setup gate previously told users to ask
Copilot to install its optional `sentry` dependency and reload
extensions, and to run `sentry auth login` from a terminal. Both
flows were unreliable or high-friction in practice.

This adds real one-click buttons for both steps:

- sentryClient.mjs — installPackage() runs npm install (async, via
  execFile so the shared extension process's event loop isn't
  blocked) rooted at the file's own directory via import.meta.url, so
  the path is never guessed. loadFactory() falls back to importing
  the package's resolved entry file by absolute path when the bare
  import('sentry') fails, since Node caches a negative resolution for
  a bare specifier for the life of the process — while still
  distinguishing a genuinely missing package from a transitive-
  dependency defect so the latter isn't masked as "package missing."
  login() fails fast with a clear message when SENTRY_AUTH_TOKEN/
  SENTRY_TOKEN is active in the environment (which takes precedence
  over the OAuth login this button drives), and treats an empty/
  falsy auth.login() result as a failed sign-in instead of silently
  re-probing.
- preflight.mjs — installDependencies() runs the install and
  re-probes the connection; authenticate() classifies the new error
  codes for gate messaging.
- server.mjs / extension.mjs — wire POST /api/install-dependencies
  and POST /api/auth-login routes (through the existing CSRF/Host
  gate) to the new preflight functions, publishing refreshed
  connection state to the canvas.
- components/page.mjs / styles.mjs — the install and sign-in
  buttons, with loading/success/failure states and accessible live-
  region status updates; a live multi-org <select> dropdown that
  rebuilds in place once org discovery completes post-signin,
  without requiring a canvas reopen.
- README.md — documents the one-click flow; manual npm install /
  sentry auth login kept as a fallback.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-08-28 09:57:28 +10:00
Liz TomandCopilot App 36f9fe7883 Add an exact-slug Sentry project resolver to the sentry-triage canvas (#2819)
* Fix sentry-triage canvas crash when the `sentry` package isn't bundled

Published awesome-copilot plugins ship extension source only, so the optional
`sentry` npm package the canvas depends on at runtime may be absent. Previously
that made the canvas crash on open instead of guiding the user through setup.

- Load the optional `sentry` package lazily and translate only the top-level
  ERR_MODULE_NOT_FOUND for `sentry` into a package-missing setup state; any other
  import failure (missing transitive dep, entrypoint throwing) is rethrown so a
  real defect isn't masked behind a misleading "reinstall" message.
- Add a dedicated package-missing branch to the connection preflight and a
  matching setup gate, kept distinct from the auth and transient-network gates so
  the user never sees contradictory guidance. The canvas now opens and explains
  what to do rather than crashing.
- Clear `configured` for the package-missing state so the status is no longer the
  contradictory `configured:true` + `setup:'package-missing'`.
- Tell users to sign in with the package-local CLI via `npx sentry auth login`
  run from the extension folder — the only form that resolves after a local
  `npm install`, since a package-local binary isn't on the shell PATH.
- Update the README so the sign-in step and install guidance cover the
  published-plugin layout (`com.github.copilot/extensions/sentry-triage`), not
  just the standalone user/project extension paths.

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

* Add an exact-slug Sentry project resolver to the sentry-triage canvas

The project picker previously only offered projects from the paged list the
canvas had already loaded. Teams with many projects (or a project outside the
first page) had no way to target one by slug. This adds a verify-on-commit
resolver: when a user types a slug that isn't a local match, pressing Enter
checks it against Sentry and only commits the canonical slug once verified,
so a scan never runs against an unverified or wrong-org project.

Canvas / UX (components/page.mjs, styles.mjs):
- Autocomplete accepts an exact slug not in the local list; Enter is the
  explicit commit that triggers resolution (never an as-typed lookup).
- A visually-hidden aria-live region announces checking / verified / not
  found / couldn't-check state, and the resolved state is rendered before
  commit so screen readers hear the outcome.
- Footer/menu surfaces checking, prompt, missing, and error states, including
  when local partial matches are present.
- Project choices are read from an org-keyed cache so a slug from a previously
  selected org can never be treated as local after a free-text org switch;
  the stale-completion guard also compares the org captured for the request.

Server / resolution (server.mjs, sentry.mjs, sentryClient.mjs, extension.mjs):
- CSRF-gated /api/resolve-project verifies a single slug against Sentry.
- Resolution runs on the shared serial request chain and is hardened against
  Sentry outages and queue contention (transient errors are retryable, a
  confirmed miss is cached as "missing").

Also bumps sentry-triage to 1.1.0 (package.json, plugin.json,
marketplace.json).

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

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-08-27 11:36:09 +10:00
Liz TomandCopilot App c72fb21484 Harden sentry-triage repo/URL metadata validation and split issue/PR repos (#2815)
* Harden sentry-triage repo/URL metadata validation and split issue/PR repos

The canvas relays model-reported GitHub artifact URLs and numbers (from a
turn that also ingests untrusted Sentry text) into tracking badges and the
"Fix with Copilot" flow. Validate that data against trusted, outside-the-model
anchors so injected text can't mint misleading badges or steer a write to the
wrong repo, and support issue/PR repos that legitimately differ.

- Add path-type-aware URL validation (repoRefNumber/urlInRepo): a URL must be
  http(s), on the trusted host, in the expected owner/repo, and match the exact
  artifact kind (/issues/<n> vs /pull/<n>) with a path-segment boundary after
  the id. The id must be a positive safe integer. This rejects look-alikes like
  /pull/123evil, cross-kind spoofs (an issue URL minting a "PR #N" badge), and
  overflow/zero ids.
- Split the issue anchor from the PR anchor (deriveRepoAnchors): the tracking
  issue and the fix PR can live in different repos. Cloud mode anchors the PR on
  the issue/cloud repo; an explicitly selected local project anchors it on that
  project's config-time repo (frozen at save time); "Current project" anchors it
  on the trusted current-project repo from the git remote — never the issue repo.
  A missing/malformed PR repo fails closed with a clear, actionable error.
- Derive tracking issue/PR numbers from the validated URLs (not the model), and
  strip every pr* field when no concrete /pull/<n> in the PR repo is present, so
  a badge can't point at a different artifact than the one verified.
- Freeze the selected project's repo into PR-target config at save time
  (page.mjs/state.mjs/server.mjs) and include mode + local.repo in the
  repo-change identity so switching projects re-derives annotations.
- Roll the optimistic rescan overlay back on a failed /api/refresh POST instead
  of leaving a blocking overlay up until the fallback timer expires.

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

* Derive displayed numbers from validated URLs; isolate project enumeration

Address Copilot review on #2815.

Comment #2: every displayed issue/PR number is now re-extracted from the
same URL that was validated against the expected repo, instead of trusting
the model-reported *Number field. Fixes the skipped/dedup, done, and
submit_work_pr paths so a reply pairing /pull/1 with prNumber 999 can no
longer render "PR #999" linking to PR 1. Numbers with no concrete anchor
(placeholder repo / non-GitHub tracker) keep the model value.

Comment #1: the projectId->repo mapping is a security anchor (it decides
which repo fix-session PRs are validated against), so it must not be
produced in a turn that also ingests untrusted Sentry titles. Enumeration
now runs in its own Sentry-free turn (loadProjectOptions), and the save
path re-binds the repo/name server-side from the selected projectId against
trusted project state; the browser no longer supplies the auth repo.

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

* Demote sentry-triage project map from an authorization anchor

The projectId->repo map returned by the model's list_projects tool was
being used as the trust anchor for fix-session PR validation, and was
isolated into a separate "project enumeration" turn to keep untrusted
Sentry titles out of the prompt that produced it. But that turn joins the
same foreground conversation, so it is not a real trust boundary.

The SDK exposes no isolated model context and no trusted project-
enumeration API, so instead stop treating the model-relayed repo as an
authorization anchor at all. An explicitly selected project is authorized
by its host-resolved project_id (a trusted handle at create_session time),
so deriveRepoAnchors now returns prExpectedRepo='' + prProjectSelected for
that case and the preflight/URL gates skip the unbackable repo check. The
map is now display/dedup-search only, so enumeration is folded back into
the triage round-trip and the separate turn is removed.

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

* Fix fallout from demoting the sentry-triage project map

Follow-ups from review after the project-map demotion:

- Reject stale/forged local project IDs in set-pr-config. An unknown
  non-empty projectId left boundProject null but was still stored, and
  deriveRepoAnchors treats any non-empty id as an explicit selection —
  which skips the missing-repo/PR-URL preflight. Store the id only when it
  resolves to a known project, so an unresolvable id fails closed to ''
  (Current-project mode, which requires a trusted git remote).

- Restore tracked-PR badges for split-repo selected projects. The tracked
  badge validated the model-reported PR URL against the now-empty trusted
  PR anchor, so repoRefNumber always returned null and every discovered PR
  was stripped. The badge is read-only display, not a write gate, so anchor
  its search + URL/number validation on the model-declared project repo
  when there is no trusted anchor (still pins number->URL and host).

- Update set-pr-config and page.mjs comments: the bound repo/name are
  display + dedup-search metadata, not PR authorization, and drop the stale
  loadProjectOptions / "Sentry-free turn" references.

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

* Fail closed on an unconfirmable dedup skip for selected projects

After demoting the project map, prExpectedRepo is '' for an explicitly
selected project, so the dedup "already being worked on" skip accepted a
bare model-reported PR number as authoritative. Because the dedup result
and the project list come from the same Sentry-bearing model turn, injected
text could forge a skip to both suppress the trusted host-resolved
create_session flow and surface an arbitrary PR link.

An authoritative skip suppresses the trusted flow and surfaces a PR link,
so it now requires a trusted PR-repo anchor: a URL-bearing PR validated
against a concrete prExpectedRepo. A selected project has no trusted anchor,
so its skip is unconfirmable and fails closed to a retryable error instead
of being honored. The downstream dedup validation is now only reached with a
concrete PR anchor, so its dead no-anchor branches are removed.

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

* Anchor Current-project PR repo to the checkout cwd, not GITHUB_REPOSITORY

runtimeDefaults.repo prefers GITHUB_REPOSITORY, which is the configured ISSUE
target and may point at a separate cloud repo; seedDefaultsFromSession() does not
overwrite an explicit GITHUB_REPOSITORY. All three deriveRepoAnchors calls passed
that value as currentProjectRepo, so when the issue repo differed from the driving
checkout, Current-project mode gated PR validation and dedup on the issue repo and
rejected legitimate PRs from the current project.

Derive the Current-project anchor unconditionally from the resolved session cwd via
currentCheckoutRepo(defaults) = repoFromPath(localPath), which co-derives from the
same git remote as the trusted host, and use it at all three anchor derivations.

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

* Restrict local Copilot handoff to the current project

Remove the model-relayed "selected project" local write-handoff and its
whole plumbing (the Settings project dropdown, submit_projects/list_projects
enumeration, projectOptions state, and the server-side projectId re-bind).

The dropdown was the only thing feeding a model-supplied project_id into
create_session, and the only local mode whose PR repo came solely from the
untrusted Sentry triage turn. That made it both the write-steering vector the
reviewer flagged (server.mjs set-pr-config / deriveRepoAnchors) and the one
local mode where a dedup "skip" could never be verified against a trusted repo.

Local "Work on selected" now always runs the fix session in the CURRENT
project (the canvas's own checkout, host-trusted from its git remote), so the
PR repo is always a trusted anchor and dedup is always verifiable. Cross-repo
work goes through Cloud mode, whose repo the user types directly in Settings.

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

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-08-27 11:35:35 +10:00
Liz TomandCopilot App 3c1bebaded Fix sentry-triage canvas crash when the sentry package isn't bundled (#2810)
Published awesome-copilot plugins ship extension source only, so the optional
`sentry` npm package the canvas depends on at runtime may be absent. Previously
that made the canvas crash on open instead of guiding the user through setup.

- Load the optional `sentry` package lazily and translate only the top-level
  ERR_MODULE_NOT_FOUND for `sentry` into a package-missing setup state; any other
  import failure (missing transitive dep, entrypoint throwing) is rethrown so a
  real defect isn't masked behind a misleading "reinstall" message.
- Add a dedicated package-missing branch to the connection preflight and a
  matching setup gate, kept distinct from the auth and transient-network gates so
  the user never sees contradictory guidance. The canvas now opens and explains
  what to do rather than crashing.
- Clear `configured` for the package-missing state so the status is no longer the
  contradictory `configured:true` + `setup:'package-missing'`.
- Tell users to sign in with the package-local CLI via `npx sentry auth login`
  run from the extension folder — the only form that resolves after a local
  `npm install`, since a package-local binary isn't on the shell PATH.
- Update the README so the sign-in step and install guidance cover the
  published-plugin layout (`com.github.copilot/extensions/sentry-triage`), not
  just the standalone user/project extension paths.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-08-27 11:14:14 +10:00
ca87445cb2 Add Git Worktree Explorer canvas (#2344)
* Add Git Worktree Explorer canvas

Add an interactive repository, worktree, branch, and commit graph with GitHub PR enrichment, safe inspection actions, and shared lane visualization.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 69dd5824-7094-4b82-8cfa-83c2fbe53307

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Address review feedback for Git Worktree Explorer

Security
- Quote copied shell commands (git -C / git log) with shell-safe single quoting and --end-of-options via new public/shell-quote.mjs
- Move repository path into the untrusted data block of the commit Ask Copilot prompt

Performance
- Compute branch divergence with a single `git for-each-ref %(ahead-behind:...)` query (Git 2.41+), falling back to rev-list with bounded concurrency (8) instead of one process per branch
- Drop the unused `git show --stat` summary from commit details

Correctness
- Only attach same-repository pull requests to local branches (filter isCrossRepository / headRepositoryOwner)
- Resolve the default branch by full name or upstream instead of a suffix match (server + client)
- Preserve already-loaded commit pages when a load-more request fails; only reset requests show the error state
- Size the lane graph from the widest row (lanes + branch badges + text) and collapse >3 branch tips into a "+N more" badge

Accessibility / UX
- Add aria-pressed to view toggles and graph nodes; replace the unimplemented ARIA tree with group/button semantics
- preventDefault on Space/Enter for branch badges so keyboard activation does not scroll
- Use a lane palette that meets 3:1 contrast in both light and dark themes (tested)
- Mobile inspector no longer auto-opens on snapshot load and gains a close button

Tests: 19 -> 29

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 18350039-5e2b-40f0-b537-bc22cabcbb1b

* Migrate git-worktree-explorer to plugins/ manifest layout

Move the manifest from extensions/git-worktree-explorer/.github/plugin/plugin.json to plugins/git-worktree-explorer/plugin.json with README and copilot-extension.json, matching the extensions-container migration (#2334). Regenerated marketplace.json and docs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 18350039-5e2b-40f0-b537-bc22cabcbb1b

* Address follow-up review: shell-specific quoting and sibling row controls

- quoteShellArg/formatShellCommand take a target shell; PowerShell doubles apostrophes while POSIX uses '\\''. app.js detects the platform and reports which syntax was copied.
- Commit rows no longer nest branch badge buttons inside the row button; the row button and badges are sibling controls.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 18350039-5e2b-40f0-b537-bc22cabcbb1b

* Make the closed mobile inspector inert and restore focus to the graph

When the inspector overlay is dismissed on narrow viewports it is now marked inert/aria-hidden so its controls leave the tab order and accessibility tree, focus returns to the selected graph control, Escape closes it, and viewport changes re-sync the state.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 18350039-5e2b-40f0-b537-bc22cabcbb1b

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Aaron Powell <me@aaron-powell.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot-Session: 69dd5824-7094-4b82-8cfa-83c2fbe53307
Copilot-Session: 18350039-5e2b-40f0-b537-bc22cabcbb1b
2026-08-26 10:25:00 +10:00
James MontemagnoandCopilot 0976c94103 Improve Where Was I worktree context and Git history (#2342)
* Add worktree context collector

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

Copilot-Session: 2d224e01-e53f-46f8-beb2-0b8b64c5ee89

* Fix Where Was I worktree state

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

Copilot-Session: 2d224e01-e53f-46f8-beb2-0b8b64c5ee89

* Collect git graph and change details

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

Copilot-Session: 2d224e01-e53f-46f8-beb2-0b8b64c5ee89

* Add worktree git graph

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

Copilot-Session: 2d224e01-e53f-46f8-beb2-0b8b64c5ee89

* Add uncommitted change inspector

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

Copilot-Session: 2d224e01-e53f-46f8-beb2-0b8b64c5ee89

* Release Where Was I 1.1.0

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

Copilot-Session: 2d224e01-e53f-46f8-beb2-0b8b64c5ee89

* Normalize diff paths on Windows

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

Copilot-Session: 2d224e01-e53f-46f8-beb2-0b8b64c5ee89

* Fix change inspector clicks

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

Copilot-Session: 2d224e01-e53f-46f8-beb2-0b8b64c5ee89

* Collapse base branch graph history

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

Copilot-Session: 2d224e01-e53f-46f8-beb2-0b8b64c5ee89

* Keep diff drawer across context renders

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

Copilot-Session: 2d224e01-e53f-46f8-beb2-0b8b64c5ee89

* Fix Where Was I review feedback

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

Copilot-Session: c161d734-edb5-4707-a48c-966d4e83a2cf

* Address follow-up Where Was I review

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

Copilot-Session: c161d734-edb5-4707-a48c-966d4e83a2cf

* Harden Where Was I canvas against title injection and fix graph/diff edge cases

- Remove inline onclick handlers; PR/issue cards are buttons wired with addEventListener
  from data, the refresh/resume buttons use ids, and the page is served with a nonce-based
  CSP (script-src 'nonce-...', default-src 'none'). escapeHtml now also escapes apostrophes.
- Collapse only the graph suffix after the final branch commit (splitCommitGraph, computed
  server-side as baseGraphStart) so --topo-order interleaving never hides worktree commits.
- Preserve the selected status record through the UI, /file-diff, and get_file_diff so a path
  that appears twice (e.g. staged deletion + untracked re-creation) previews the right record.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 18350039-5e2b-40f0-b537-bc22cabcbb1b

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 2d224e01-e53f-46f8-beb2-0b8b64c5ee89
Copilot-Session: c161d734-edb5-4707-a48c-966d4e83a2cf
Copilot-Session: 18350039-5e2b-40f0-b537-bc22cabcbb1b
2026-08-26 10:24:20 +10:00
Liz TomandCopilot App b6da04c241 Add Sentry Triage canvas extension (#2802)
An on-call error-triage canvas for GitHub Copilot: scans live Sentry
issues, groups them by urgency, and hands issues off for tracking or a
fix PR. Registers a reusable canvas extension under extensions/ with a
matching plugins/sentry-triage manifest.

The extension runs a loopback HTTP/SSE server per canvas instance
(host-allow-listed, per-instance capability token never broadcast over
SSE), renders the triage board server- and client-side, and drives
model turns over a single shared Copilot session serialized so scan and
work turns can't interleave. Work state is prototype-pollution-guarded
against agent-controlled tracking keys, and sendAndWait timeouts are
handled without duplicating external side effects.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-08-26 10:04:22 +10:00
John HaugabookandCopilot Autofix powered by AI 927c1b5b38 canvas-extension: new chat cards extension (#2698)
* canvas-extension: new chat cards extension

* codespell: resolve mispelling

* code review, debug extension finding github app issue

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* apply edits from code review

* apply edits from code review

* apply edits from code review

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-08-21 12:14:17 +10:00
5163dc2e4d feat: add fail-closed Local Delegation to Cairn (signals-dashboard 0.3.0) (#2666)
* feat: add fail-closed Local Delegation to Cairn dashboard

Port the-workshop Local Delegation seam into signals-dashboard 0.3.0.
Orthogonal off/on control beside repo/connected profiles; enable only when
local-agent-delegation is installed and a qualified route receipt is present.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c39b7696-c854-40c2-b2d6-cce84ba09750

* fix: address Local Delegation review (skill path + README catalog)

- Walk marketplace/plugin and _direct install roots for local-agent-delegation
- Update plugins/signals-dashboard README and regenerate docs/README.plugins.md

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c39b7696-c854-40c2-b2d6-cce84ba09750

* fix: keep Local Delegation Windows launches from reparsing -i prompt

Long LD orientation text split under wt/cmd on Windows (0x80070002). Keep
-i short/quote-free; rely on WORKSHOP_LOCAL_DELEGATION=enabled (+ skill)
for policy. Add charset/length guard tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c39b7696-c854-40c2-b2d6-cce84ba09750

* fix: surface Local Delegation effective state on open toast and badge

Keep -i short with one optional ASCII line. Show operators
"Local Delegation effective · route <id>" on open and in the summary control.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c39b7696-c854-40c2-b2d6-cce84ba09750

* fix: address Local Delegation GHCP review comments

- Cross-platform path.join in receipt fixture
- Atomic .local-delegation.json write (no symlink follow)
- Case-insensitive WORKSHOP_LOCAL_DELEGATION env clear
- Windows Terminal: set/clear env via cmd before agent
- aria-pressed on Local toggle

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c39b7696-c854-40c2-b2d6-cce84ba09750

* fix: store Local Delegation preference user-locally, not in the workshop repo

A cloned workshop must not be able to ship preference:on. Key operator intent
under ~/.copilot/workshop-local-delegation/ by canonical workshop path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c39b7696-c854-40c2-b2d6-cce84ba09750

* fix: preserve path case in Local Delegation preference key

Lowercasing collided distinct workshops on case-sensitive filesystems.
Normalize separators only; realpath already supplies a stable path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c39b7696-c854-40c2-b2d6-cce84ba09750

* fix: allow parentheses in quoted Windows Local Delegation launches

Args are quote-wrapped; only block % and ! expanders inside quotes so paths
like C:\Work\Project (1) still launch.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c39b7696-c854-40c2-b2d6-cce84ba09750

* fix: apply quoted-arg Windows safety guard in launch path

Complete the parentheses fix: use isSafeQuotedWindowsCmdArg for cmdSafe.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c39b7696-c854-40c2-b2d6-cce84ba09750

---------

Co-authored-by: Jenny Ferries <jenny.ferries@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Michael Recachinas <mrecachinas@github.com>
Copilot-Session: c39b7696-c854-40c2-b2d6-cce84ba09750
2026-08-17 15:42:37 +10:00
Daniel Scott-RaynsfordandCopilot Autofix powered by AI df9116a689 Add Windows app storage inspector canvas 🤖🤖🤖 (#2620)
* feat: add Windows app storage inspector canvas

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fix: address storage inspector review findings

* Correction to package and plugin

* fix: harden storage inspector cleanup

* Harden cleanup operation outcomes

* Add select a file or folder path in the result tabs to navigate the treemap to its deepest visible parent folder.

* Fixes to ensure selftesst pass

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-08-12 10:06:08 +10:00
Jenny FerriesandCopilot 200213ed4c Merge upstream main and migrate daily focus board plugin
Adopt the Agent Plugins v1.0.0 namespaced composition model from #2546. Bundle the reusable daily-focus-board canvas into Ember only and remove its obsolete standalone catalog manifest.

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

Copilot-Session: 52be9c67-3ae4-4610-93d0-fe0b7ab95ccb
2026-08-06 09:18:07 -07:00
a7fdcd5006 Migrate plugins and canvas extensions to Agent Plugins spec (#2546)
* feat: migrate plugins and extensions to Agent Plugins v1.0.0 spec

- Add \ to all 69 curated plugin manifests
- Migrate all 18 extension manifests: add \, move logo into
  xtensions.com.github.copilot.logo namespace, remove top-level
  logo and string xtensions: '.'
- Update eng/validate-plugins.mjs: require \, validate
  namespace-keyed extensions object for canvas extensions, widen
  name pattern to allow dots (spec §5.5, max 64 chars)
- Update eng/materialize-plugins.mjs: emit spec-clean served manifests
  (only spec fields: \, name, version, description, author,
  homepage, repository, license, keywords, extensions)
- Update eng/generate-website-data.mjs: read logo from namespace
  with fallback to top-level logo for compatibility
- Update eng/create-plugin.mjs: scaffold emits \
- Add .github/workflows/validate-plugins.yml: blocking CI for PRs
  touching plugins/** or extensions/**
- Add spec compliance check to external plugin quality gates:
  non-blocking warnings with ✅/⚠️/🛑 emoji legend
- Update AGENTS.md: document new extension manifest shape,
  add \ to plugin checklist

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8f3a88cb-e01e-4760-8125-460490dc1a76

* refactor: consolidate canvas extension plugins

- Move all extension plugin manifests from extensions/<name> to plugins/<name>
- Keep extensions/<name> as reusable source only
- Remove standalone extension discovery from marketplace and website plugin catalogs
- Auto-bundle same-name extension sources during materialization
- Add build-only extensions.json references for sharing extensions across plugins
- Remove x-awesome-copilot extension metadata support
- Update validation and contributor documentation

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8f3a88cb-e01e-4760-8125-460490dc1a76

* feat: add canvas extension scaffolding skill

- Add repo-local skill for creating canvas extension sources
- Generate spec-compliant plugin manifests under plugins/
- Support registering reusable extensions with multiple plugins
- Remove guidance for extension-local plugin manifests and custom fields

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8f3a88cb-e01e-4760-8125-460490dc1a76

* fix: align extension namespaces with current guidance

- Use each extension ID as its manifest namespace key
- Update validation and website generation to resolve extension-specific namespaces
- Upsert plugin validation PR comments using the existing repository pattern

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8f3a88cb-e01e-4760-8125-460490dc1a76

* fix: use Copilot extension namespace

- Adopt com.github.copilot for all canvas extension manifests
- Require the namespace during validation and website generation
- Update extension scaffolding guidance

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8f3a88cb-e01e-4760-8125-460490dc1a76

* docs: regenerate plugin catalog after merge

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8f3a88cb-e01e-4760-8125-460490dc1a76

* refactor(plugins): move manifests to plugin roots

Use root plugin.json manifests and namespaced extension directories throughout local tooling, validation, generation, and contributor documentation. Restore materialize-plugins.mjs line breaks so the source remains readable in GitHub.

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

Copilot-Session: 8f3a88cb-e01e-4760-8125-460490dc1a76

* feat(plugins): migrate manifests to namespaced composition

Move repository composition metadata under com.github.awesome-copilot, materialize reusable extensions into the plugin extensions directory, and improve contributor and PR validation guidance.

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

Copilot-Session: 8f3a88cb-e01e-4760-8125-460490dc1a76

* fix(validation): address plugin review findings

Restore executable build scripts, validate namespaced manifests and hook directories, improve README item counts, and manage validation comments across reruns.

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

Copilot-Session: 8f3a88cb-e01e-4760-8125-460490dc1a76

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+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>
Copilot-Session: 8f3a88cb-e01e-4760-8125-460490dc1a76
2026-08-06 22:29:31 +10:00
4af329f943 Add cost-aware Workshop desk profiles (#2532)
* feat: add cost-aware Workshop desk profiles

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

Copilot-Session: 83dd4f49-a03d-44a0-bdd1-8c4f54da8ec2

* fix: address Copilot review feedback

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

Copilot-Session: 83dd4f49-a03d-44a0-bdd1-8c4f54da8ec2

* fix: isolate Agency MCP discovery

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

Copilot-Session: 83dd4f49-a03d-44a0-bdd1-8c4f54da8ec2

* fix: label desk launch profile controls

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

Copilot-Session: 83dd4f49-a03d-44a0-bdd1-8c4f54da8ec2

---------

Co-authored-by: Jenny Ferries <jenny.ferries@microsoft.com>
Copilot-Session: 83dd4f49-a03d-44a0-bdd1-8c4f54da8ec2
2026-08-05 13:58:54 +10:00
Jenny FerriesandCopilot 20208a6794 daily-focus-board: reject array progress/doc containers in normalize()
An array is typeof "object", so progress:[] (or a top-level array state file) was kept as the container; JSON.stringify then drops the non-index props (counters, t, day...), the API returns progress:[] and the canvas crashes reading state.counters. Guard both with !Array.isArray, matching looksLikeBoard. Headless regression tests added (48/48).

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

Copilot-Session: fd1eae93-cc9f-4777-812c-a2a9872e1c2b
2026-07-31 09:48:13 -07:00
Jenny FerriesandCopilot b1c1b32d47 daily-focus-board: filter malformed momentum/brain entries in normalize()
A state file with a non-string txt (e.g. {"txt":1}) previously loaded, then esc(n.txt) in the canvas threw (numbers have no .replace) and the whole board failed to render. Filter day/brain entries to require a string txt, mirroring the existing task-notes filter. Verified with a headless regression test (45/45).

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

Copilot-Session: fd1eae93-cc9f-4777-812c-a2a9872e1c2b
2026-07-30 17:54:30 -07:00
Jenny FerriesandCopilot 96ca38efa1 Merge upstream/main into add-daily-focus-board-skill
Resolve the .codespellrc conflict by retaining both the daily-focus-board checkin key and upstream ACI term.

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

Copilot-Session: fd1eae93-cc9f-4777-812c-a2a9872e1c2b
2026-07-29 21:22:17 -07:00
John HaugabookandClaude Opus 5 c46b4a919a Add flight-map-canvas extension (#2482)
* Add flight-map-canvas extension

A canvas port of the Flight Map VSCode extension: a first-person
satellite terrain map flown with flight simulator controls, for
session breaks while an agent works.

The simulator under game/ is copied verbatim from the source
extension's media/ folder. That page already reached its host through
one seam - an acquireVsCodeApi() object and a placeholder in its head -
so extension.mjs fills that seam for the canvas: a loopback server that
injects a policy, the render configuration, and a shim translating
Server-Sent Events into the messages the page already handles.

Two agent actions: fly_to sends the flight to a capital, a geocoded
city, or a raw lat/lng, and picks a random capital when called with no
input; report_job shows the current job step under the HUD.

Adds the vendored three.min.js to the codespell skip list, matching the
existing entry for arcade-canvas's phaser.min.js.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* Apply suggestions from code review

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 13:32:55 +10:00
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
Jenny FerriesandCopilot 0612442158 daily-focus-board: reject inherited-property-name task ids (prototype safety)
Resolves the Copilot review on board-core.mjs: task ids like `toString` /
`constructor` passed validId and, used as object keys, could resolve to
Object.prototype members. Now validId also rejects any inherited name (`s in {}`),
and the progress maps (counters, t) are null-prototype so a task id can never
resolve to an inherited member. (`__proto__` was already blocked by the id grammar.)

Headless test 43/43 (adds inherited-name rejection, drop-on-normalize, and an
Object.prototype-intact check).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cb356aa8-0af2-48f3-b3c6-8086c69d5308
2026-07-29 08:59:31 -07:00
Jenny FerriesandCopilot ea88e5fa68 daily-focus-board: explicit op results + date-scoped default state file
Resolves two more Copilot review comments on board-core.mjs:
- Mutations no longer report false success: every op returns an explicit error
  for unknown task ids, wrong task kinds, and empty/no-op inputs, and mutate
  propagates it (so set_status on a bad id fails instead of claiming { ok: true }).
- The default state filename is now date-scoped (focus-board-<YYYY-MM-DD>.json),
  so reopening the board tomorrow starts a fresh day instead of silently reusing
  today's tasks/progress. Explicit stateFile paths are used as-is; input doc updated.

Headless test 39/39 (adds op-error + date-scope cases).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cb356aa8-0af2-48f3-b3c6-8086c69d5308
2026-07-29 08:16:58 -07:00
Jenny FerriesandCopilot 227ede1ef9 daily-focus-board: harden canvas (DNS-rebind, XSS, destructive write) + skill a11y
Resolves the remaining Copilot review comments.

Canvas extension (board-core.mjs, board.html):
- DNS-rebinding: pin the Host header to the exact 127.0.0.1:<port> authority and
  require a per-server capability token (minted at startup, embedded in the served
  page, sent as x-board-token) on ALL /api/* routes -- so GET /api/state can't leak
  task data and POSTs can't be forged. Mirrors extensions/signals-dashboard.
- Destructive write: loadDoc only synthesizes a fresh board for ENOENT and now
  propagates I/O + JSON parse errors, so a transient/malformed state file is never
  overwritten by a later mutation.
- XSS: escape emoji (from the seed / add_task action) at render, like title/unit.

Skill (board.template.html, sample-board.html):
- a11y: each task card gets role=group + aria-label so screen readers get task context.
- counters: step=1 on the goal/update number inputs to match the positive-integer contract.

Verified headless (35/35): token gates reads+writes, CSRF + foreign-Host refused,
malformed file left intact. Repo plugin + skill validation green.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cb356aa8-0af2-48f3-b3c6-8086c69d5308
2026-07-28 20:50:59 -07:00
Jenny FerriesandCopilot c606f79f31 daily-focus-board: real board screenshot as extension preview
Replaces the generated placeholder with an actual rendered board (cropped to the
visible cards). Closes the last gap flagged in the review.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cb356aa8-0af2-48f3-b3c6-8086c69d5308
2026-07-28 18:57:09 -07:00
Jenny FerriesandCopilot 399479600d daily-focus-board: guard external stateFile + reserve feed sentinel ids
Addresses the Copilot review on board-core.mjs: an externally supplied
stateFile pointing at an existing non-board file was silently normalized to an
empty board and overwritten on first mutation. ensureStateFile now refuses an
existing file unless it parses as JSON and looks like a board (a
'daily-focus-board' marker or the board schema); the marker is stamped on every
write. Also reserve 'day'/'brain' as task ids so a task can't collide with the
momentum/brain-dump feed delete routing.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cb356aa8-0af2-48f3-b3c6-8086c69d5308
2026-07-28 16:54:25 -07:00
Jenny FerriesandCopilot 9f911f18ce ember: add daily-focus-board canvas extension
Adds a canvas version of the daily-focus-board alongside the skill, addressing
@aaronpowell's review suggestion. The canvas renders the board in the Copilot
app and is backed by a JSON state file the assistant reads and writes, so you
can mark tasks done, add tasks, log progress, and recap your day from chat --
the file-backed "close the loop" upgrade over the localStorage skill.

The skill stays as the zero-install universal fallback for anyone not in the
Copilot app (same both-not-either pattern as the-workshop's signals-dashboard).

- extensions/daily-focus-board/: extension.mjs (canvas + session wiring) +
  board-core.mjs (loopback server, JSON state file, mutations, recap) +
  assets/board.html (file-backed UI) + preview.png + manifests.
- plugins/ember: register via x-awesome-copilot.extensions, bump 1.1.0 -> 1.2.0,
  add a Components row.

Note: assets/preview.png is a placeholder pending a real board screenshot.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: cb356aa8-0af2-48f3-b3c6-8086c69d5308
2026-07-28 11:39:21 -07:00
Alex Yang (DevDiv)andCopilot App e7ce4a918e Remove local connector namespaces extension
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-07-23 15:18:46 -07:00
John HaugabookandCopilot Autofix powered by AI ae8ada62bd Extension backrooms (#2348)
* new extension backrooms-canvas

* new extension backrooms-canvas

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* update according to code review

update according to code review

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* apply code review, change backviews to backrooms

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-23 10:51:06 -07:00
c0869f6231 Improve connector reload authentication UX (#2370)
Keep Azure tokens in memory and preserve linked namespace context across extension reloads.

Co-authored-by: Alex Yang (DevDiv) <yangalex@microsoft.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-07-23 10:51:00 -07:00
Matt Soucoup 7de9e4f48c Merge branch 'main' into alexyaang-interactive-connector-sign-in 2026-07-20 16:06:11 -07:00
Alex Yang (DevDiv)andCopilot App ee5ab9a91f Harden sign-in cancellation behavior
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-07-20 15:22:39 -07:00
Alex Yang (DevDiv)andCopilot App b9705e9439 Fix concurrent token initialization
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-07-20 14:49:48 -07:00
Alex Yang (DevDiv)andCopilot App 463a876284 Harden persisted authentication recovery
Treat malformed authentication records as missing so browser sign-in can recover, preserve real file-read failures, and pin the Azure Identity persistence dependencies exactly.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-07-20 14:32:51 -07:00
Alex Yang (DevDiv)andCopilot App 59fc5616ec Address connector authentication review feedback
Keep terminal sign-in status retry-safe, preserve operational Azure Identity errors, retry transient legacy-cache cleanup, clarify secure persistence requirements, and fix the blocking spelling check.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-07-20 14:18:50 -07:00
Alex Yang (DevDiv)andCopilot App abd06a1c22 Polish connector canvas public listing
Rewrite the extension documentation around the GitHub Copilot app experience, add official Connector Namespace guidance, and align marketplace metadata with the public-facing product description.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-07-20 13:32:23 -07:00
Alex Yang (DevDiv)andCopilot App 2f258c7226 Add persistent browser auth to connector canvas
Replace Azure CLI-only authentication with InteractiveBrowserCredential, protected sign-in lifecycle endpoints, and subscription refresh after sign-in. Persist the Azure Identity cache securely across extension reloads and align connector restart guidance with the GitHub Copilot app.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-07-20 13:04:18 -07:00
jennyf19andCopilot 8ec1fe86d7 fix Cairn desk-launch containment + comment accuracy (GHCP review round 6)
Sync signals-dashboard/extension.mjs to the-workshop@f3d2298.

- isInsideRoot: reuse the trailing separator when the workshop root is a filesystem root (/ or C:\\) so desks below it aren't rejected.

- Correct the launch guard comment (macOS single-quotes deskPath; Linux uses cwd).

- Replace the stale double-quote-rejection claim with the real containment + quoting guarantees.

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

Copilot-Session: 26faf13e-639c-4a21-ac05-c0dc2bff7c62
2026-07-20 12:04:28 -07:00
jennyf19andCopilot 563148b5b4 harden Cairn desk launch (GHCP review round 5)
Sync signals-dashboard/extension.mjs to the-workshop@91c09d7.

- Render the desk open button unconditionally.

- Drop the deskPath double-quote guard (path is quoted/cwd/single-quoted per platform; guard rejected valid POSIX paths).

- Escape CR/LF in AppleScript string literals.

- On Windows run the agent through cmd.exe /k so PATHEXT resolves .cmd shims (copilot/agency).

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

Copilot-Session: 26faf13e-639c-4a21-ac05-c0dc2bff7c62
2026-07-20 11:55:23 -07:00
jennyf19andCopilot e43d6ea666 signals-dashboard: trySpawn resolves only from spawn/error
Synced from the-workshop@3cd8a0c6a1e24864d746fedb1f2f7ee4f3b17603. Round-4 review: remove the success timeout that could report an unconfirmed launch as launched:true; Node guarantees one of spawn/error fires.

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

Copilot-Session: 26faf13e-639c-4a21-ac05-c0dc2bff7c62
2026-07-20 11:41:51 -07:00
jennyf19andCopilot df4f3ebc42 signals-dashboard: drop unused existsSync import
Synced from the-workshop@591591c. Round-3 review: existsSync became dead after PATH validation moved to statSync/accessSync.

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

Copilot-Session: 26faf13e-639c-4a21-ac05-c0dc2bff7c62
2026-07-20 11:36:24 -07:00
jennyf19andCopilot 055dda1672 signals-dashboard: harden desk launch (round 2 review)
Synced from the-workshop@8106dd4. Addresses the second GHCP review pass on #2363:

- isOnPath now requires a runnable file (X_OK / PATHEXT), not just existsSync.

- launchDeskConsole adds a realpath-containment check (symlink escape) and takes workshopDir.

- Dashboard copies the path only on the non-launch fallback.

- Mutating /api/* routes now require the canonical loopback Host plus a per-server capability token (DNS-rebinding defense), mirroring connector-namespaces.

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

Copilot-Session: 26faf13e-639c-4a21-ac05-c0dc2bff7c62
2026-07-20 11:28:43 -07:00
jennyf19andCopilot d4656d988d fix(the-workshop): harden signals-dashboard desk launch
Addresses the Copilot review on this PR:

- deskAgentArgv: an explicit WORKSHOP_DESK_AGENT override is now
  authoritative. =agency insists on the wrapper even when it isn't on
  PATH; the PATH check is only used for automatic selection when unset.
- launchDeskConsole: restrict the desk name to a conservative slug
  before it reaches any shell, and drop the double quotes from the
  orientation prompt, so the cmd.exe `start` fallback can no longer be
  turned into command execution by a desk directory named e.g.
  "review&calc".
- macOS: drive Terminal via AppleScript to actually cd into the desk and
  exec the agent (POSIX single-quoted), instead of only opening Terminal
  and falsely reporting the CLI launched.
- Linux: pass the agent command after each emulator's exec flag, so the
  desk comes up running its agent instead of a bare shell.
- Client openDesk: track whether the clipboard write succeeded and stop
  claiming "path copied" when the browser blocked it.

Synced from the-workshop@8e22ce84b2b28d9c2205730b1cd52db8586a0416

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

Copilot-Session: 26faf13e-639c-4a21-ac05-c0dc2bff7c62
2026-07-20 11:09:46 -07:00
jennyf19andCopilot 517506a260 feat(the-workshop): sync signals-dashboard to the-workshop@bc708fe
Brings the awesome-copilot copy of the signals-dashboard (Cairn) extension to parity with jennyf19/the-workshop@bc708fe. The desk cards' path button becomes an open button: clicking it launches a Copilot CLI in that desk's folder, oriented to read the journal and continue, mirroring the workshop app's console launcher. This keeps every desk inside the one workshop repo instead of spinning off a separate checkout.

The launcher prefers a wrapper agent CLI when one is on PATH (env-overridable via WORKSHOP_DESK_AGENT), and falls back to vanilla 'copilot' otherwise, so it works out of the box for everyone. New open_desk canvas action; /api/open now returns whether a terminal launched. plugin.json and assets/preview.png are unchanged.

Provenance: jennyf19/the-workshop@bc708fe905

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 26faf13e-639c-4a21-ac05-c0dc2bff7c62
2026-07-20 10:49:35 -07:00
jennyf19andCopilot 670c5f0419 Address GHCP review: stash race, signal ordering, a11y, outcome schema, error handling
- extension.mjs: serialize stash read-modify-write behind a per-desk mutex;
  order signals by explicit ISO timestamp (clone-safe) not mtime; keep desks
  with malformed latest signal as 'awaiting'; gate calibration badge on a real
  gap value; add prefers-reduced-motion CSS; toast aria-live region; rename
  open_desk -> get_desk_path (returns path, no session); handle server.listen errors.
- signal-write/SKILL.md: document timestamp + run_id, ordering guidance, and the
  outcome (calibration) signal schema.
- workshop-ta.agent.md: a desk is a persistent workstream picked up by independent
  sessions, not one long-running process.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 26faf13e-639c-4a21-ac05-c0dc2bff7c62
2026-07-19 19:24:09 -07:00
jennyf19andCopilot d71864b706 fix(signals-dashboard): declare @github/copilot-sdk dependency
signals-dashboard imports '@github/copilot-sdk/extension' but shipped
without a package.json — the only SDK-importing extension in the repo
missing one (every peer that imports the SDK declares it). Without the
manifest the host has no dependency to resolve at load time. Add a
package.json matching the peer shape (type: module, main: extension.mjs,
'@github/copilot-sdk': latest — the modal peer convention).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 26faf13e-639c-4a21-ac05-c0dc2bff7c62
2026-07-19 18:19:22 -07:00