mirror of
https://github.com/nexu-io/open-design.git
synced 2026-06-01 03:14:35 +07:00
10 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
59c8d72ae4
|
feat(tweaks): bind toolbar toggle to artifact panel (#2348)
* feat(tweaks): bind toolbar toggle to artifact panel
Wires the host viewer's Tweaks toggle to artifact panels via two
protocols: postMessage __edit_mode_* for agent-generated .twk-panel
artifacts, and the existing class-based bridge for tweaks-skill
.tw-panel artifacts. Toggle disables itself when the artifact exposes
no panel, syncs state when the user closes the panel locally, and no
longer regenerates srcdoc on toggle (no iframe remount).
- bridge: emit od:tweaks-available + MutationObserver-driven
od:tweaks-panel-state so host learns availability and mirrors local
closes; transform-based hide preserves the artifact's transition
- host: listen for both od:tweaks-* (bridge) and __edit_mode_*
(artifact) dialects, send both on toggle, disable button when no
panel, reset state on file change
- skill: document the two protocols as a host integration contract
- i18n: add fileViewer.tweaksUnavailable for all 13 locales
* fix(tweaks): keep srcDoc path for `.tw-panel` artifacts
The class based tweaks template (`.tw-panel` / `.tw-hidden`) needs the
bridge `injectTweaksBridge` emits, but the default plain HTML preview
URL loads the iframe, which bypasses buildSrcdoc entirely. Without the
bridge there is no `od:tweaks-available` ping, so the toolbar toggle
stays disabled on first load of a tweaks template artifact unless an
unrelated mode (palette, inspect, etc.) coincidentally forces srcDoc.
Add a `tweaksBridge` flag to `shouldUrlLoadHtmlPreview` and detect the
fixed `.tw-panel` / `.tw-hidden` template selectors in the artifact
source via a new `hasTweaksTemplate` helper. FileViewer passes the
detected flag through so tweaks template artifacts pick the srcDoc
render path on first load.
Tests in `file-viewer-render-mode.test.ts` cover the new disqualifier,
the helper positive and negative cases, and combinations with the
existing flags.
* fix(tweaks): resolve v0.7 UI ambiguity between toolbar toggle and palette
After rebasing onto v0.7, three problems surfaced. v0.7 ships a palette
popover button also labeled `Tweaks` with the same sliders icon as the
new toolbar toggle. Toggling that popover flipped render mode (URL load
to srcDoc) and reloaded the iframe, flashing the preview. The resulting
iframe remount caused agent protocol artifacts to re-announce
`__edit_mode_available`, which flipped the toolbar toggle back on
without user input.
Rename the palette popover button to `Themes` (button label, dialog
title, `aria-label`) and swap its icon to a new `paint-bucket` glyph.
The artifact tweaks toggle keeps the `tweaks` sliders icon. Internal
identifiers (`data-testid="palette-tweaks-toggle"`, CSS classes, the
`PaletteTweaks` component name) stay stable so existing tests and
styles still target the same elements.
Drop the auto set true on `__edit_mode_available`; that signal now
flips `tweaksAvailable` only. `syncBridgeModes` posts the current
`tweaksMode` to the artifact (both the bridge dialect and
`__activate_edit_mode` / `__deactivate_edit_mode`) on every iframe
load so the panel matches the toolbar.
Mount both URL load and srcDoc iframes simultaneously, absolutely
positioned and overlapping, with CSS visibility flipping between
them. Toggling render mode no longer reloads the iframe so there is
no flash. `isOurIframe(source)` accepts messages from either iframe
so startup announcements from the hidden iframe are not lost; six
receive filter sites switch from `iframeRef.current?.contentWindow`
to the helper. Sends still target `iframeRef.current`, kept aligned
with the active iframe via a `useEffect`, and a `syncBridgeModesRef`
pushes current bridge state to the now visible iframe whenever the
render mode flips.
Tests that previously asserted exclusive render mode (`url-load`
vs. `srcdoc` presence) now assert the active `data-testid` sits on
the expected iframe via a co-attribute regex. The Draw bar element
picking test switches from a cached frame reference to a `getFrame()`
helper since `data-testid` follows the active iframe across toggles.
Add a `paint-bucket` entry to `Icon` (Lucide style stroke icon).
* fix(tweaks): scope `od:tweaks-available` to the active iframe
The dual iframe setup mounts both the URL load and srcDoc iframes at
once and accepts postMessage events from either via `isOurIframe`. The
srcDoc iframe always carries the always injected tweaks bridge, which
runs `document.querySelector('.tw-panel')` on mount and posts
`{ type: 'od:tweaks-available', available: false }` for any artifact
that does not ship the class based panel. For an agent protocol
artifact (`.twk-panel`, `__edit_mode_*`), the URL load iframe correctly
announces `__edit_mode_available` and the host sets
`tweaksAvailable = true`. The hidden srcDoc iframe's `available: false`
ping arrives shortly after and overrides that to false, silently
disabling the toolbar button.
Scope `od:tweaks-available` to the active iframe only by re-checking
`ev.source === iframeRef.current?.contentWindow` before applying it.
`__edit_mode_available` and `__edit_mode_dismissed` stay accepted from
either iframe so the artifact's own announcement still drives the
toolbar toggle across render mode flips.
Spotted by Siri-Ray on PR #1643.
* fix(tweaks): start the toolbar toggle ON when the artifact mounts its panel visible
Both tweaks dialects (the class-based `.tw-panel` skill template and the
`.twk-panel` agent-generated edit-mode protocol) mount their panel visible
by default. Before this change the toolbar `Tweaks` toggle started in the
OFF state regardless, so the user saw the panel but had to click
toggle-on → toggle-off to actually hide it — confusing because the toggle
disagreed with what they could plainly see in the preview.
Two changes wire the initial state through to the toolbar:
- `srcdoc.ts` (class-based dialect): the tweaks bridge's `onReady` now
fires `postState()` alongside `postAvailability()`. `postState()` reads
`!panel.classList.contains('tw-hidden')` and posts the artifact's actual
initial visibility, so the host's existing `od:tweaks-panel-state`
handler picks it up and mirrors it into `tweaksMode`. Previously only
MutationObserver-driven changes were posted, so the host never learned
the artifact's initial state.
- `FileViewer.tsx` (twk-panel dialect): the agent dialect's
`__edit_mode_available` carries no visibility payload, so we infer
default-open from the fact that the artifact bothered to announce
availability at all (the SDK pattern is `useState(true)`). Mirror that
into `tweaksMode` exactly once per file (tracked by
`firstEditModeAvailableSeenForFileRef`), so an iframe remount triggered
by, e.g., flipping render mode through the Themes popover does not snap
a user-driven OFF back to ON.
Also fix a runtime `ReferenceError: panel is not defined` regression
this same change introduced when first written with backticks inside the
new code comment — the comment lived inside a `\`...\``-delimited script
template literal, so the embedded backticks closed and reopened the outer
literal and broke the bridge's JS body. Replaced with plain text.
Validation: web typecheck clean, 1597/1597 tests pass. Manually verified
with a `.twk-panel` artifact: open file → tweaks toggle is ON, panel
visible → one click hides both.
* fix(tweaks): seed bridge state from the panel's authored class, not from the host hidden attribute
The bridge installs `data-od-tweaks-hidden` on `<html>` synchronously in
`<head>` so the panel never flashes on initial paint. That attribute is
therefore *always* present by the time `onReady()` fires, which meant the
previous `applyClassesToPanel(!hasAttribute(...))` call unconditionally
forced `.tw-hidden` onto the panel, the follow-up `postState()` read that
forced-hidden class, and the host saw `visible: false` even when the
artifact had authored the panel as default-visible. The PR-1643 attempt
at "start ON when the artifact mounts visible" therefore still reported
OFF for the class-based template path.
Read the panel's authored class state first (the artifact body has just
parsed, so the panel's class is what the artifact wrote and nothing
else has touched it yet), then drive the attribute, the applied class,
and the `od:tweaks-panel-state` post from that captured value:
```ts
var panel = panelEl();
var initialVisible = !!panel && !panel.classList.contains('tw-hidden');
document.documentElement.toggleAttribute('data-od-tweaks-hidden', !initialVisible);
applyClassesToPanel(initialVisible);
attachObserver();
postAvailability();
postState();
```
A default-visible `.tw-panel` now reports `visible: true` on mount, the
host mirrors that into `tweaksMode = true`, and the toolbar Tweaks toggle
starts in the ON state instead of disagreeing with what the user sees in
the preview. The `.twk-panel` agent-protocol path is unaffected; its
initial-state mirror still goes through the
`firstEditModeAvailableSeenForFileRef` guard in `FileViewer.tsx`.
Surfaced by Siri-Ray in https://github.com/nexu-io/open-design/pull/1643#discussion_r3263571196.
Validation: web typecheck clean, 1597/1597 tests pass.
* fix(tweaks): re-mirror __edit_mode_available default-open state when switching .twk-panel files
The once-per-file guard that mirrors a `.twk-panel` artifact's
default-open state into the toolbar `tweaksMode` lives inside a
`window.addEventListener('message', ...)` handler installed in a
`useEffect(..., [])` with an empty dep list. The handler therefore
closed over the first-render `file.name`. After opening one
`.twk-panel` artifact, `firstEditModeAvailableSeenForFileRef.current`
got set to that first file; switching to a second `.twk-panel` file
left the message listener still comparing the new artifact's
`__edit_mode_available` against the stale captured name, so the
guard never re-fired and the toolbar stayed OFF while the new
artifact's panel was clearly visible — exactly the mismatch the
guard was supposed to prevent on initial load.
Add `file.name` to the listener effect's dep list so the handler
gets a fresh closure on every file switch. The bridge-message setters
(`setTweaksAvailable`, `setTweaksMode`), `isOurPreviewIframeSource`,
and `firstEditModeAvailableSeenForFileRef` are stable across renders,
so re-binding the listener has no other side effects beyond updating
the captured `file.name`.
Surfaced by Siri-Ray in
https://github.com/nexu-io/open-design/pull/1643#discussion_r3266838151.
Red-spec regression test added: `FileViewer tweaks toolbar > mirrors
__edit_mode_available default-open state for each switched-to
.twk-panel file`. Verified to go red on the bug (deps `[]`) and green
on the fix (deps `[file.name]`).
Validation: web typecheck clean, 1598/1598 tests pass (was 1597).
* i18n(tweaks): add fileViewer.tweaksUnavailable to the remaining 6 locales
The toolbar's disabled-Tweaks tooltip key landed in 13 locale files but
6 were missed (ar, fr, id, it, th, uk). Those locales were still falling
through to the English string via the `...en` spread, which contradicts
the repo convention that every key be defined explicitly in each locale.
Add the translation alongside the existing `fileViewer.tweaks` entry so
the full set of 19 locales now ships native copy for the disabled state.
Surfaced by Siri-Ray in
https://github.com/nexu-io/open-design/pull/1643#discussion_r3267654385.
* fix(tweaks): respect default-closed dynamic panels in __edit_mode_available
Protocol A in `design-templates/tweaks/SKILL.md` documents that the
artifact may default the panel to either open or closed and the host
should sync its toolbar toggle to whichever state the artifact reports.
The previous handler ignored that and unconditionally mirrored
availability into `tweaksMode = true`, so a default-closed dynamic
artifact would be force-opened the moment `syncBridgeModes` ran and
fired `__activate_edit_mode` — the artifact could not stay closed even
though the contract said it could.
Extend the message shape so the artifact can report its initial state
on the same payload:
{ type: '__edit_mode_available', visible?: boolean }
The host now reads `data.visible`:
- omitted → treat as `true` (back-compat: existing artifacts
emitting the legacy zero-arg shape mount with the
panel already on screen, which is the SDK pattern
`useState(true)`).
- `visible: true` → toolbar starts ON.
- `visible: false` → toolbar starts OFF, panel stays closed; the user
opts in by clicking the toggle, which then fires
`__activate_edit_mode` via the existing
`syncBridgeModes` path.
Update `design-templates/tweaks/SKILL.md` to document the new optional
field alongside the legacy shape.
Surfaced by Siri-Ray in
https://github.com/nexu-io/open-design/pull/1643#discussion_r3269955351.
Red-spec regression test added: `FileViewer tweaks toolbar > respects
__edit_mode_available { visible: false } for default-closed dynamic
artifacts`. Verified red without the fix (always-true mirror) and green
with the fix (`data.visible !== false`).
Validation: web typecheck clean, 1599/1599 tests pass.
|
||
|
|
d1eb8b7bef
|
Fix editorial deck navigation (#2173) | ||
|
|
db9752f5ae
|
fix(template): make orbit github example static (#1829)
* fix(template): make orbit github example static * fix(template): preserve static github link targets |
||
|
|
f1870cbf3d
|
chore(featured): curate Featured picks down to top 10 across categories (#1966)
* chore(featured): curate Featured picks down to top 10 across categories
The picker's Featured chip currently surfaces 64 plugins because
`isFeaturedPlugin` (apps/web/src/components/plugins-home/facets.ts)
treats any finite `od.featured` number as featured, and the field
had been adopted incrementally by 51 skills + 13 templates without
a curation step. The result is a "Featured" tab that's effectively
"everything tagged at all" — no editorial signal.
Curate down to 10 picks, allocated to keep the showcase legible:
0.001 skills/deck-swiss-international
0.01 skills/deck-guizang-editorial
0.02 design-templates/magazine-poster [add]
0.04 skills/doc-kami-parchment
0.10 design-templates/web-prototype-taste-brutalist [add od: block]
0.13 skills/video-hyperframes
0.14 skills/frame-glitch-title
0.15 skills/vfx-text-cursor
0.16 skills/frame-logo-outro
0.17 skills/deck-open-slide-canvas
Selection mirrors the html-anything `recommended: 1..10` ranking
(html-anything is the upstream content source for these skills, per
the `od.upstream` field on each SKILL.md). Two of those 10 picks
weren't in the prior featured set at all — `magazine-poster` had no
`od.featured` field and `web-prototype-taste-brutalist` had no `od:`
block at all — so they get added rather than just rebalanced.
Removes `od.featured` from the other 56 files. No UI code change;
the existing `isFeaturedPlugin` logic now reads a curated set
instead of an accidental one.
* chore(featured): align baked plugin manifests with curated top 10
The picker reads `od.featured` from each plugin's
`plugins/_official/examples/<id>/open-design.json` manifest, not from
the SKILL.md frontmatter the previous commit edited. Without this
follow-up the curated set of 10 would be invisible to users — the
picker's Featured chip would still surface 27 baked plugins from the
pre-existing manifests.
Mirror the SKILL.md curation into the baked layer:
removed `od.featured` from 19 manifests:
article-magazine, card-xiaohongshu, data-report,
frame-data-chart-nyt, frame-flowchart-sticky,
frame-light-leak-cinema, frame-liquid-bg-hero,
frame-macos-notification, guizang-ppt, html-ppt,
kami-deck, kami-landing, mockup-device-3d,
open-design-landing-deck, ppt-keynote, resume-modern,
social-reddit-card, social-spotify-card, social-x-post-card
added `od.featured` to 2 manifests:
magazine-poster -> 0.02
web-prototype-taste-brutalist -> 0.10
Verified locally against `daemon /api/plugins`: featured count is
now exactly 10, matching the SKILL.md source of truth from the
previous commit.
|
||
|
|
6c16283850 |
Merge origin/main (post-7c8305f4) into reconcile branch
Brings in 10 new main commits: routine deep-link to specific conversations (#1508), Windows resource cache fix for Orbit templates, collapsible comment side panel (#1607), routines project radio polish, Copilot logo swap, and minor UI fixes. Conflicts resolved: - router.ts: garnet's home/view + marketplace routes + main's per-project conversationId deep-link field coexist on Route union - ProjectView.tsx: garnet's isPhantomDaemonRunMessage helper + main's isStoppableAssistantMessage helper both kept - ProjectView.run-cleanup.test.tsx: accepted HEAD (garnet's phantom-row regression test); main's three new tests for finalizeActiveAssistantMessagesOnStop / clearStreamingConversationMarker / shouldClearActiveRunRefs are queued as a follow-up TODO inline. |
||
|
|
c942d99b14
|
fix(orbit): avoid sample identity leakage (#1608) | ||
|
|
d83b228c81 | Merge remote-tracking branch 'origin/garnet-hemisphere' into reconcile/garnet-main-merge | ||
|
|
5077a1cd38
|
feat(landing-page): split catalog into per-facet pages + auto-deploy on content changes (#1158)
* feat(landing-page): split catalog into per-facet pages + auto-deploy on content changes
Convert the single-page landing into a content-driven multi-page site
sourced directly from the canonical Markdown bundles in the repo root,
and close the deploy loop so contributor edits go live without manual
follow-up.
## What's new
- `/skills/`, `/systems/`, `/craft/`, `/templates/` index + detail
pages, generated from `skills/<slug>/SKILL.md`,
`design-systems/<slug>/DESIGN.md`, `craft/*.md`, and
`templates/live-artifacts/<slug>/README.md` via Astro content
collections (`app/content.config.ts`). No mirroring of content into
the landing-page package — `glob` re-scans on every build.
- Faceted sub-routes generated from frontmatter:
- `/skills/mode/<slug>/` — 8 pages (deck, prototype, image, …)
- `/skills/scenario/<slug>/` — 18 pages after alias collapse
- `/systems/category/<slug>/` — 21 pages
Each page owns its own `<title>`, meta description, and
`CollectionPage` JSON-LD; chips on the parent index pages are now
real anchors that link to these facet routes.
- Updated top-bar nav (`_components/header.tsx`) to point at the new
internal routes with live counts pulled from the catalog. Counts in
the homepage hero meta description likewise driven by
`getCatalogCounts()` so they never drift.
- Per-skill / per-template thumbnails. A Playwright generator
(`scripts/generate-previews.ts`) walks every `example.html` and
`templates/live-artifacts/<slug>/index.html`, screenshots them at
1440×900@2x, and writes PNGs to `public/previews/`. The catalog
data layer auto-detects presence and degrades gracefully when an
artifact has no renderable HTML.
## Plumbing the auto-update loop
- `landing-page-deploy.yml` and `landing-page-ci.yml` now trigger on
changes under `skills/`, `design-systems/`, `craft/`, and
`templates/`. Without this, a contributor adding a new SKILL.md to
`main` would silently skip the deploy and the published site would
fall behind.
- Both workflows now install Playwright Chromium (cached by version)
and run `pnpm previews` before `astro build`, so generated
thumbnails ship in `out/previews/` automatically. Preview generation
is `continue-on-error: true` — a single broken example.html should
not block the deploy of the rest of the catalog.
- `apps/landing-page/public/previews/` is gitignored: the directory
is owned by CI and would otherwise add ~70MB of binary churn to the
repo on every regeneration.
## Tag canonicalization
- `app/_lib/catalog.ts` adds a small per-scope alias table so
authoring drift like `od.scenario: operation` vs `operations`, or
`live` vs `live-artifacts`, collapses to a single canonical route
instead of leaking two near-empty pages. Mode and category alias
tables are scaffolded but currently empty.
## Validation
- `pnpm --filter @open-design/landing-page typecheck` — 0 errors,
0 warnings, 0 hints across 25 Astro files
- `pnpm --filter @open-design/landing-page build` — 341 pages built
(1 home + 8 mode + 18 scenario + 21 category + N detail pages +
sitemap + RSS), zero external JS, ≥16 Cloudflare-resized hero
image URLs intact
## Why this matters
After merge, any push to `main` that adds, removes, or edits a skill,
design system, craft principle, or live-artifact template
automatically triggers a fresh build that:
1. picks up the new Markdown via the content-collection glob,
2. regenerates thumbnails for any matching example.html,
3. emits new sitemap entries and JSON-LD,
4. and ships to Cloudflare Pages — no landing-page-side change
required.
* fix(landing-page): address review feedback on PR #1158
Five fixes from the review pass — none change scope, all close the
"contradictory totals" / "stale data" / "silent CI failure" gaps the
reviewers flagged.
## Hero / catalog claims now read live counts everywhere
`apps/landing-page/app/page.tsx` previously hardcoded `31` skills and
`72` systems in the hero copy and stat rings, while the nav and meta
description had already moved to `getCatalogCounts()`. After this PR
every visible "X skills / Y systems" claim — hero lead, hero stat
rings, capabilities cards body copy, labs section meta + filter pills,
selected-work fractions, the labs CTA, and the footer Library — reads
from a single `counts` prop. `Header` and `Page` now both require
`counts` (no optional fallback) so a future caller can never silently
publish stale numbers.
The labs-section filter pills also stop being decorative buttons:
they now link to the actual `/skills/mode/<slug>/` and `/skills/`
catalog routes the new multi-page architecture exposes.
## Craft README no longer publishes
`apps/landing-page/app/_lib/catalog.ts` filtered out `e.id !== 'README'`,
but Astro normalizes `craft/README.md`'s id to lowercase `readme`, so
the published site shipped `/craft/readme/` as a public craft principle
and the nav badge counted 12 instead of 11. Compare case-insensitively
(`e.id.toLowerCase() !== 'readme'`) so any future README casing is
also filtered out. Verified locally: `apps/landing-page/out/craft/`
now contains exactly 11 entries.
## Preview URL preserves actual file extension
`listPreviews()` was already discovering `.png`, `.webp`, `.jpg`, and
`.jpeg`, but `previewUrlFor()` always emitted `.png`, so a future
sharp/webp post-processor (or a manually committed template asset)
would mark the record as available while the rendered `<img src>`
404'd. Switched the structure from `Set<slug>` to `Map<slug, filename>`
and emit the actual on-disk filename verbatim.
## Preview script: per-artifact soft, systemic hard
Previously any single failed `example.html` capture exited the script
non-zero, which forced both workflows to mark the entire preview step
`continue-on-error: true`. That blanket tolerance also masked
systemic generator failures — a chromium launch that never finds the
browser binary would silently ship a deploy with zero thumbnails.
`scripts/generate-previews.ts` now distinguishes:
- per-artifact failures → logged and skipped, exit 0 (catalog
degrades gracefully for those skills),
- discoverJobs / chromium.launch / 100%-failure run → exit 1
(systemic, must fail the build).
Both workflows drop their `continue-on-error: true` flags so a real
problem actually surfaces.
## AGENTS.md reflects the multi-page architecture
`apps/landing-page/AGENTS.md` previously declared the landing page
single-route ("Not multi-page. There is exactly one route ('/')").
That guidance is now wrong — there are six top-level route groups
(`/`, `/skills/`, `/systems/`, `/craft/`, `/templates/`, plus their
facet variants). Updated to describe content-collection sourcing, the
no-mirror rule, the auto-deploy workflow contract, and the
"never hardcode catalog claims" boundary.
## Validation
- `pnpm --filter @open-design/landing-page typecheck` — 0 errors,
0 warnings, 0 hints across 25 Astro files
- `pnpm --filter @open-design/landing-page build` — 340 pages built
(was 341 before the README filter; the README route is now
correctly absent), live counts visible in the built `out/index.html`:
`driven by 125 composable skills and 149 brand-grade design systems`
- Verified `out/craft/` no longer contains `readme/`
- Verified preview URLs resolve to the actual on-disk filename via
the regenerated catalog index page
* fix(landing-page): clean up live-artifact template name + summary parsing
Address @mrcfps's follow-up review on `0715d8c`. The
`shapeLiveArtifactTemplate()` parser was passing the README's H1
verbatim (literal backticks intact) and using the first non-empty
post-H1 line as the summary, even when that line was the
`> Category: **Live Artifacts**` editorial blockquote. Result:
`/templates/live-otd-operations-brief/` was shipping a
`<meta name="description" content=">">` and a card title with raw
Markdown noise — a regression for both SEO snippets and the
templates catalog at-a-glance scan.
## Two new shared helpers
- `stripMarkdownInline()` — strip backticks, asterisks, and link
wrappers so `# \`otd-operations-brief\` · live-artifact template`
becomes `otd-operations-brief · live-artifact template` before any
further trimming.
- `extractFirstProseParagraph()` — walk the body after the H1 and
skip blockquotes (`>`), list markers, table rows, fenced code, and
HR rules. Stop at the first contiguous prose paragraph and pass it
through `stripMarkdownInline()` so the result is human-readable.
Both helpers live next to `titleizeSlug()` and are used by
`shapeCraft()` and `shapeLiveArtifactTemplate()` so they share one
implementation.
## Live-artifact title boilerplate trim
Live-artifact READMEs commonly title themselves
`# \`<slug>\` · live-artifact template`. After stripping the inline
backticks the trailing `· live-artifact template` is redundant
("Templates" already groups them) and adds a wide noisy suffix on
catalog cards. Removed it via a narrow regex tail-strip.
## Result on the existing fixture
Verified locally for `templates/live-artifacts/otd-operations-brief/`:
- before: `<title>\`otd-operations-brief\` · live-artifact template …</title>`,
`<meta name="description" content=">">`
- after: `<title>otd-operations-brief — Open Design template</title>`,
`<meta name="description" content="A drop-in html_template_v1
live-artifact template for an editorial On-Time Delivery brief.
It ships:">`
Typecheck 0/0/0, build 340 pages.
---------
Co-authored-by: Joey <joey@cursor.so>
Co-authored-by: Joey-nexu <236967869+joeylee12629-star@users.noreply.github.com>
|
||
|
|
bbd14bd6fb
|
replace time-specific Orbit greetings with neutral defaults (#1291)
* replace time-specific Orbit greetings with neutral defaults Orbit default greeting is hard-coded to a morning-specific phrase and is not suitable as generic copy issue * fix skill trigger mistake 每日简报 -> 早安简报 |
||
|
|
b5eb8c1647
|
feat: generic skills + split skills/design-templates + finalize-design API (#955)
* feat: general-purpose skills with @-mention composition and user import
Lift skills from "one mode-bound skill per project" to a generic capability
the user can compose per turn:
- Daemon: scan multiple skill roots (user-skills under runtime data, then
the bundled `skills/`); user-imported skills can shadow built-ins by id.
- New `POST /api/skills/import` and `DELETE /api/skills/:id` endpoints,
with CONFLICT/BAD_REQUEST/NOT_FOUND error codes and built-in delete
protection.
- ChatRequest gains `skillIds: string[]`; the chat run concatenates each
picked skill's body (and merges craftRequires) into the system prompt
for that turn only — the project's persistent `skillId` is untouched.
- Web composer: `@` popover now lists skills alongside project files;
picks render as removable chips above the textarea and ride along with
the request as `skillIds`.
- Settings → Library: import form (name/description/triggers/body),
per-card delete for user skills, "user" origin badge.
* chore(web): drop welcome pet teaser + add ds→prompt-template mapping util
- SettingsDialog: remove the inline pet adoption teaser from the welcome
panel so the first-run modal stays focused on configuration.
- New `inferPromptTemplateCategoriesForDs(ds)` helper that maps a design
system's authored metadata to prompt-template gallery categories.
Imported by the design-system gallery wiring on a sibling branch; no
callers in this branch yet.
* feat: split skills/design-templates and add finalize-design API
Phase 0 of the skills/design-templates refactor (specs/current/
skills-and-design-templates.md):
- Move ~104 rendering catalogue entries from skills/ to design-templates/
and keep skills/ for the small set of functional skills that *do work*
on user input (utilities, briefs, packagers).
- Add design-templates/AGENTS.md and skills/AGENTS.md describing the
contract, and a brand-agnostic craft/ surface for opt-in craft rules.
- Daemon: add DESIGN_TEMPLATES_DIR / USER_DESIGN_TEMPLATES_DIR roots and
an /api/design-templates surface mirroring /api/skills. Asset/example
routes still span both registries so existing srcdoc URLs keep
resolving across the rename.
- Web: split LibrarySection into SkillsSection + DesignSystemsSection,
rename the EntryView "Examples" tab to "Templates", and update locales
+ the New-project picker accordingly.
Adds the finalize-design endpoint:
- New apps/daemon/src/finalize-design.ts and packages/contracts/src/api/
finalize.ts — one-shot synthesis of a project's transcript + active
design system + current artifact into <projectDir>/DESIGN.md via the
Anthropic Messages API. Per-project .finalize.lock mirrors the
transcript-export hygiene from PR #493; provider credentials are not
persisted by the daemon.
Other supporting changes:
- README + AGENTS.md updates to document the new directory split and
craft/ surface, plus i18n strings across 13 locales.
- Test refactors and new coverage (finalize-design, runs, sidecar
server, plus refreshed daemon integration tests).
- .gitignore: scope the *.exe ignore to /OpenDesign.exe so legitimate
vendor binaries are no longer hidden.
* fix(merge): move clinical-case-report to design-templates/
Origin/main added the clinical-case-report skill under skills/ before
the skills/design-templates split landed. Its od.mode is prototype, so
per specs/current/skills-and-design-templates.md it is a design template
and belongs alongside the other rendering catalogue entries — not under
the slimmed-down functional skills/ root. Moving it keeps the EntryView
Templates tab consistent with origin/main's intent.
* feat(skills): curated design/creative catalogue + collapsible Settings rows
Seed ~100 curated design/creative skill stubs under skills/ sourced from
awesome-claude-skills (ComposioHQ) and awesome-agent-skills (VoltAgent).
Each stub carries an od.category tag so the new filter pill row in
Settings -> Skills can group them. The seed script
(scripts/seed-curated-design-skills.ts, pnpm seed:curated-design-skills)
is idempotent: it only creates folders that don't already exist, so
hand-edited stubs are never overwritten.
- Daemon: parse and surface od.category on SkillInfo with a strict slug
normaliser; mirror the field on SkillSummary in @open-design/contracts.
Category is purely a UI hint — system-prompt composition is unchanged.
- Web: rewrite SkillsSection from a left-list / right-detail grid into a
vertical stack of collapsible rows mirroring the External MCP panel
(header always visible with name + mode/source/category pills + per-row
enable toggle; SKILL.md preview, file tree and inline edit form expand
on demand). Add a Category filter row above the list. Reorder Settings
nav so Skills + External MCP sit above the Composio/MCP cluster. Update
composer placeholder/hint across 17 locales to advertise '@ files or
skills · / for commands'.
- Docs: extend skills/AGENTS.md with the curated catalogue rules
(idempotency, category vocabulary, no upstream vendoring).
Co-authored-by: Cursor <cursoragent@cursor.com>
* test(skills): teach localized-content + system-prompt tests about the skills/design-templates split
mrcfps blocking review on PR #955: the skills/design-templates split
(
|