feat(canvas): agent calls from browser clients and CodeRabbit round one

Merged
GN
2d ago
+1512-684

Summary

  • Browser clients must serve agents like desktop windows, and review findings need fixes.
  • Part 9 of 10 in a stacked series. Review and merge bottom-up; each PR targets the one below it. Canvas mode v3 (figcraft engine). Spec: spec-openpencil-canvas-mode; architecture spine 2026-10-16 (AD-17 to AD-31).

Related Issue

No issue. Split from #1369 so each part stays under 50 files.

Type of Change

  • feat: new feature

What Changed

  • Agent calls reach a browser lease holder and wait through a short reconnect; a canvas document must sit inside its own project.
  • Fixes from the first CodeRabbit review: token in the bundle path instead of a third-party cookie, close by mountSeq, .figcraft-only mounts, request size limits, queued unmount questions.

Scope

  • E3-3 plus review fixes.

How It Was Tested

  • bun run typecheck on this branch
  • Each part is a checkpoint that was built and tested when it was made (cargo test for canvas and host_mcp, vitest, real runs in headless Edge). The bottom and top of the stack were rebuilt and re-tested on current dev.

Checklist

  • PR title follows the conventional commit format
  • Explained why no issue exists
  • Added or updated tests
  • Read AGENTS.md
  • A human reviewed the complete diff before submission

🤖 Generated with Claude Code


Summary by cubic

Browser clients now serve agents the same way desktop windows do, with the first round of CodeRabbit review fixes on top.

New Features

  • Agent canvas calls reach a browser lease holder through the shared relay: calls wait through a reconnecting renderer inside the lease grace and resolve CANVAS_CLOSED when the grace expires. Covered on both the browser socket and desktop Channel carriers.

Bug Fixes

  • The canvas token is a path segment now, not a cookie; macOS and Linux webviews drop third-party cookies, so the bundle's sub-resources were failing to load.
  • The document path must lie in the opening project's own root on both transports; desktop opens only canonicalized the path, so any file on disk could be opened.
  • Close targets the renderer's mountSeq, so a late close can't unmount a newer mount, and the bundle token is revoked only when the project has no mount.
  • Only .figcraft documents mount; the extension check existed only at write time.
  • An oversize agent request answers ENGINE_ERROR naming the limit instead of a misread CANVAS_CLOSED; /ws accepts frames up to the bridge's reply cap.
  • Unmount questions queue instead of answering each other, and canvas iframes stay mounted behind the mid-session web token screen so a fresh iframe can't autosave an empty editor over the document.