Merge of `origin/main` (`03ed3960`, 2026-05-13 pre-0.7.0) into the
161-commit garnet-hemisphere line, reconciling the product-vibe-coded
plugin/marketplace/EntryShell surfaces from garnet with the routines /
skills / live-artifacts feature work landed on main since the fork point.
Headline decisions (full rationale + side-by-side screenshots in
`specs/change/20260513-garnet-skills-automations/reconcile-result-vs-garnet.md`):
- #1 SettingsDialog: keep main's Memory / Skills / External MCP /
Connectors / Routines / MCP server nav items even though the top-level
/integrations + /automations routes also cover them. Two entries
coexist for now; revisit once Track A/B fill in the placeholder content.
- #2 EntryView: accept garnet's thin wrapper delegating to EntryShell.
Main's PetRail sidebar + image-templates/video-templates tabs are
intentionally deferred to a follow-up that re-integrates them into
the new EntryShell layout.
- #3 /integrations + /automations top-level routes: kept (garnet's
product intent). Skills tab is still a "Coming soon" placeholder
awaiting Track A; Routines/Schedules/Live-artifacts cards on
/automations are still mock awaiting Track B.
- #5 DesignFilesPanel: hybrid — main's pagination as primary list,
garnet's Plugin folders section preserved between the live-artifacts
block and the pagination block. (by-kind sections drop in favour of
pagination; plugin-folders rendering stays because it is a
garnet-specific product addition.)
- #7 server.ts (10 hunks, ~5400 conflict lines): manual hunk-by-hunk
merge. Both daemon admin routes + plugin/genui routes (garnet) and
routines/memory/skills upgrades (main) preserved. Garnet's inline
project route block kept alongside main's `registerProjectRoutes` /
`registerProjectUploadRoutes` modular wiring — duplicate route
audit is a follow-up. Garnet's POST /api/projects plugin-snapshot
resolution + default-scenario fallback is intentionally dropped from
the inline body (now handled by registerProjectRoutes) and listed for
follow-up re-integration into `project-routes.ts`.
Verification (worktree at /Users/elian/Documents/open-design-garnet):
- `pnpm typecheck` exits 0 across all workspace packages
- daemon (`pnpm tools-dev run web --namespace reconcile-shots`) boots,
serves `/api/daemon/status` healthy, and survives a Playwright
walkthrough of /integrations / /automations / home / projects /
design-systems / plugins / settings dialog
- `@open-design/plugin-runtime` package built (was missing dist/ on
garnet); without it the daemon's plugins/* imports fail at boot
Track A (Skills tab → real SkillsSection) and Track B (Automations
cards → real routines / live-artifacts backend) are the two remaining
follow-ups blocking the placeholder/mock content from going live. See
`spec.md` and `track-skills.md` in the same directory.
- Updated the plugin sharing prompts to utilize local daemon endpoints for publishing to GitHub and contributing to Open Design, streamlining the user experience.
- Refactored the `PluginsView` and `PluginShareMenu` components to support new sharing functionalities, including confirmation modals and improved link handling.
- Enhanced the CSS styles for the plugin share confirmation modal and related UI elements for better visual consistency.
- Added tests to verify the functionality of the new sharing workflows and ensure proper integration within the existing plugin management system.
This update significantly improves the plugin sharing experience, making it easier for users to publish and contribute their plugins effectively.
* feat(hyperframes): land HTML-in-Canvas across web + skills
Ships HTML-in-Canvas as a first-class HyperFrames video path:
- 7 new video prompt templates (liquid glass, iPhone+MacBook, portal,
shatter, magnetic, liquid background, text-cursor reveal).
- skills/hyperframes/references/html-in-canvas.md, surfaced via
SKILL.md description+triggers and the system-prompt pre-flight
references list.
- ChatPane starter prompts now branch by project kind and video model,
so the hyperframes-html surface shows HTML-in-canvas-shaped prompts
instead of the generic prototype trio.
- NewProjectPanel propagates a picked template's model+aspect onto
the project, and defaults videoModel to hyperframes-html when the
hyperframes skill resolves for the video tab.
Polish bundled in the same branch:
- DesignFilesPanel empty state becomes a centered pill with a "New
sketch" CTA; designFiles.empty copy simplified across 19 locales.
- Topbar project title + meta render on one baseline row separated
by a middot.
- scripts/seed-test-projects.ts hardens daemon URL discovery against
pnpm engine warnings on stdout.
* fix(new-project): preserve explicit video model choice across tab revisits
Latch a videoModelTouched guard once the user picks a model via the
dropdown or via a template that declares one, so the hyperframes-html
auto-default no longer silently overwrites the override when the Video
tab is re-entered.
Generated-By: looper 0.6.1 (runner=fixer, agent=claude-code)
* fix(i18n): register hyperframes html-in-canvas templates, category, and tags
Adds the seven new prompt-template ids, the "VFX / HTML-in-Canvas"
category, and the new tag set to the de/ru/fr i18n bundles so the
e2e localized-content coverage test passes.
Generated-By: looper 0.6.1 (runner=fixer, agent=claude-code)
* fix(daemon): inject html-in-canvas preflight for hyperframes runs
The contracts-side derivePreflight() learned about
references/html-in-canvas.md when this PR landed, but the daemon
copy at apps/daemon/src/prompts/system.ts kept the older five-ref
allowlist. server.ts:4138 wires composeSystemPrompt from the
daemon copy into live chat runs, so the main HyperFrames flow this
PR is meant to improve still wasn't auto-injecting the preflight
directive in production.
Mirror the html-in-canvas case into the daemon composer and lock it
behind a daemon-side test so the two copies cannot drift again on
this reference. The broader live-artifact preflight gap (artifact-
schema / connector-policy / refresh-contract) is pre-existing drift
and is intentionally out of scope here.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web): restyle designs empty state as centered card on grid backdrop
Swap the horizontal pill for a stacked card and add a faint grid backdrop
so the empty designs surface reads as an intentional canvas rather than a
gap. Title now wraps instead of truncating; container is taller.
* fix(new-project): pin skillId to hyperframes when videoModel is hyperframes-html
When the Video tab resolves its skill it used to fall back to `list[0]?.id`
if no skill declared `default_for: video`. That list is built from an
unsorted `readdir()` in apps/daemon/src/skills.ts, so a freshly mounted
project could land on `video-shortform` even when the user had explicitly
chosen the HyperFrames-HTML model (or one of the new
`hyperframes-html-in-canvas-*` templates). The agent then ran without the
hyperframes SKILL body or its `references/html-in-canvas.md` preflight —
the exact regression PR #866 was meant to land.
`skillIdForTab` now pins to `hyperframes` whenever the current video model
is `hyperframes-html`, regardless of discovery order. Added a unit test
that mounts both `video-shortform` and `hyperframes` (with hyperframes
last, simulating the bad readdir order) and asserts the create payload
routes through `hyperframes`.
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* chore(scripts): seed daemon with pre-baked decks and web prototypes
Adds `pnpm seed:test-projects`, a small HTTP client that talks to the
running daemon and creates curated slide decks + web prototypes loaded
from each skill's example.html. Each seeded project gets `index.html`,
an active tab, and two fake chat messages so the UI renders fully
without waiting for an LLM run. `--clear` removes everything prefixed
with `seed-`.
* fix(scripts): exit non-zero when any seed fixture fails
Track per-fixture failures in seed:test-projects and exit 1 when at
least one fixture errored, so CI/scripts no longer treat a partially
failed seed run (e.g. unreachable daemon) as success.
Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code)
* fix(scripts): wire ProjectFile contract through seed assistant message
The seeded assistant message was passing producedFiles as a string array,
but the UI consumes ProjectFile[] (name/size/mtime/kind/mime), so seeded
projects rendered with a broken produced-file chip. Capture the upload
response and forward uploaded.file as the chip payload.
Also tighten --clear: only delete projects that match the seed- prefix
AND carry the seeded/source metadata stamp this script writes, so a
manually-created project sharing the prefix isn't removed.
Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code)
* fix(scripts): auto-discover daemon URL from tools-dev status
Previously the seed script defaulted to 127.0.0.1:7456 when neither
OD_DAEMON_URL nor OD_PORT was set in the calling shell. `pnpm tools-dev`
runs in a sibling shell with an ephemeral daemon port, so that default
was almost never the right URL and broke the documented two-shell flow.
Resolution now goes: --daemon flag, then OD_DAEMON_URL, then
http://127.0.0.1:$OD_PORT (only when OD_PORT is a real port — OD_PORT=0
falls through), and finally a discovery step that parses the daemon URL
out of `pnpm exec tools-dev status --json`. If everything fails the
script aborts with a hint instead of silently fetching against the
wrong port.
Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code)