Commit Graph
5 Commits
Author SHA1 Message Date
jennyf19andCopilot fcae8c506d fix(the-workshop): add HTTP error boundary and make workshop detection non-terminal
Two follow-up review findings:
- signals-dashboard: the async createServer callback had no top-level
  error boundary, so a malformed %-encoded path, a stash write on a
  read-only workshop, or a scan failure rejected a promise the server
  never awaits — hanging the request and risking an unhandled-rejection
  crash. Wrap the handler and return a controlled 500.
- workshop-create: Path A treated finding a marker (desks/, CAIRN.md,
  etc.) as 'just use it', an early stop that left partially initialized
  workshops incomplete. Make it detection-only and continue scaffolding
  whatever is missing, per the 'only add what's missing' principle.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 26faf13e-639c-4a21-ac05-c0dc2bff7c62
2026-07-18 19:58:49 -07:00
jennyf19andCopilot fa1f154155 docs(the-workshop): fix workshop scaffold, bench location, and component list
Address the remaining doc/skill review findings:
- workshop-create: 'gh repo create --clone' clones into the CWD, which
  nests the new repo when run from inside a checkout. Add an explicit
  clone-parent selection + 'rev-parse --is-inside-work-tree' guard, and
  run the create from that parent.
- workshop-create: desks/ and bench/ were scaffolded empty, so Git drops
  them and a later clone loses the scaffold. Scaffold .gitkeep in each
  and commit the placeholders.
- bench-read: make <workshop>/bench/ the primary shared location (the
  directory workshop-create actually establishes) with desk-local
  artifacts as a secondary source, instead of treating the repo root as
  the bench.
- the-workshop README: add the Workshop Create skill to the component
  table so all six packaged components are documented.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 26faf13e-639c-4a21-ac05-c0dc2bff7c62
2026-07-18 19:56:18 -07:00
jennyf19andCopilot f9061f6fcc fix(signals-dashboard): coerce untrusted signal fields, block cross-site POSTs, preserve focus
Second review round on the Cairn canvas extension:
- XSS via numeric fields: self-assessment scores, quality rating, and
  token counts are read from unvalidated agent JSON and interpolated
  into HTML/style/title. Coerce them at the source in scanSignals via
  toScore (clamped 0..5) and toCount (finite nonnegative int), and
  esc() the effort label, so a nonnumeric value can neither inject
  markup nor break layout/width.
- CSRF: /api/stash, /api/restore, /api/open are state-changing loopback
  POSTs that previously accepted any origin, so a web page that guessed
  the port could mutate .desk-stash.json. Add isCrossSiteRequest() and
  reject cross-site POST /api/* (Origin / Sec-Fetch-Site check), mirroring
  the loopback protection in connector-namespaces/server.mjs.
- Accessibility: the 5s auto-refresh replaced the whole #content subtree,
  dropping keyboard focus. Skip the swap when markup is unchanged and
  restore focus to the same desk/action button when it does change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 26faf13e-639c-4a21-ac05-c0dc2bff7c62
2026-07-18 19:50:58 -07:00
jennyf19andCopilot 967f0d8ede fix(signals-dashboard): harden canvas against XSS, path traversal, and malformed signals
Address PR review findings on the Cairn canvas extension:
- XSS: replace inline onclick handlers (which used HTML-escape that
  does not escape single quotes) with event delegation via
  data-act/data-desk attributes and one document click listener that
  survives the innerHTML auto-refresh.
- Path traversal: add isValidDeskName() and enforce it in every HTTP
  and canvas-action handler that takes a desk name (reject empty, /,
  \\, null byte, '.' and '..').
- Crash safety: String()-coerce in esc()/truncate() and guard
  outcomeIssues with Array.isArray so a malformed signal cannot take
  down the whole dashboard render.
- Honest UI: the per-desk button no longer claims to 'open' a desk;
  it is relabeled 'path' and copies the desk's filesystem path to the
  clipboard with an accurate toast built via textContent (not innerHTML).
- Correctness: outcome signals only pair with a signal when emitted at
  or after it (within 1hr), and activeCount is computed by excluding
  stashed desks instead of subtracting counts (no longer goes negative).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 26faf13e-639c-4a21-ac05-c0dc2bff7c62
2026-07-18 19:44:45 -07:00
jennyf19andCopilot c33470a0b4 docs(the-workshop): install dashboard via awesome-copilot, not jennyf19 repo
The signals-dashboard canvas extension bundles with the-workshop
plugin (x-awesome-copilot.extensions), so installing the plugin from
awesome-copilot includes the dashboard. Drop the pointers telling
users to install from jennyf19/the-workshop.

Addresses PR review comments on README (Cairn Dashboard section),
signal-write SKILL note, and workshop-ta agent viewing-signals note.

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