- Replaced the legacy tabbed categorization in `PluginsHomeSection` with a tag-driven approach, allowing dynamic filtering based on plugin tags.
- Introduced a new `PluginCard` component to encapsulate the rendering of individual plugin cards, improving separation of concerns and maintainability.
- Added a `usePluginCategories` hook to manage plugin visibility and filtering logic, enhancing the overall structure and testability of the component.
- Implemented a "More" pill for overflow tags in the filter row, improving user interaction with a cleaner UI.
- Updated CSS styles to support the new layout and improve visual consistency across the plugins home section.
This update significantly enhances the user experience by providing a more flexible and intuitive way to discover and interact with plugins.
Plan J4 / spec §15.4 / §15.5 / §16 Phase 5.
Three landings:
- deploy/Dockerfile now COPYs plugins/_official/ into the image so
the bundled atom plugins from §3.I3 register on container boot —
without this, registerBundledPlugins() silently no-ops inside the
container and the §23 self-bootstrap promise breaks for hosted
deployments.
- tools/pack/docker-compose.yml ships the canonical hosted-mode
manifest spec §15.4 calls out: two-volume layout (od-data +
od-config) per §15.2, OD_BIND_HOST=0.0.0.0 + OD_API_TOKEN +
OD_NAMESPACE + snapshot retention knobs as env, /api/daemon/status
as the healthcheck endpoint (Phase 1.5). Drop-in usable with
`docker compose -f tools/pack/docker-compose.yml up -d`.
- tools/pack/helm/open-design/{Chart.yaml,values.yaml,README.md}
pins the Helm chart parameter surface for the per-cloud overrides
spec §15.5 enumerates (AWS / GCP / Azure / Aliyun / Tencent /
Huawei / self-hosted). Templates land in the Phase 5 follow-up
PR; the values schema is locked here so the per-cloud override
files (values-<cloud>.yaml) review in isolation.
scripts/guard.ts allowlist gains
`packages/agui-adapter/esbuild.config.mjs` so the new package
passes the residual-JS guard.
Daemon tests stay at 1486/1486 (deploy artifacts only).
Co-authored-by: Tom Huang <1043269994@qq.com>
- Added support for a new plugin system, allowing users to install, uninstall, and manage plugins through the daemon.
- Implemented API endpoints for listing installed plugins, retrieving plugin details, and applying plugins with input validation.
- Introduced a plugin doctor feature to validate plugin manifests and check for issues before application.
- Established a plugin persistence layer with SQLite migrations for managing installed plugins and their metadata.
- Enhanced the CLI with commands for plugin operations, improving user interaction with the plugin ecosystem.
* feat(skills): add 32 zhangzara HTML deck templates
Vendored from upstream MIT-licensed
zarazhangrui/beautiful-html-templates — one Open Design skill per template
(name prefix `html-ppt-zhangzara-`) so each template surfaces as its own
entry in the Examples panel and renders its own preview.
Each skill ships:
- SKILL.md (frontmatter + workflow), description, triggers, and
od.upstream pointing at the source folder
- example.html (the self-contained deck; daemon's preview route looks
for <skillDir>/example.html)
- template.json (upstream metadata snapshot, with `slug` re-prefixed to
`zhangzara-<base>` and a `source` URL)
- assets/deck-stage.js / assets/styles.css for the 8 templates that
ship a runtime; HTML refs rewritten so the daemon's iframe URL
rewriter resolves them through /api/skills/<id>/assets/
scripts/guard.ts allowlist updated with the `html-ppt-zhangzara-` prefix
so the vendored upstream JS runtimes pass the residual-JS check.
* fix(skills, i18n): address PR #704 review feedback
- Add the 32 new html-ppt-zhangzara-* skill ids to the de/ru/fr
SKILL_IDS_WITH_EN_FALLBACK arrays so the localized-content
coverage e2e test passes. The vendored upstream templates are
English-only; falling back to the upstream English description
is the right semantic for this batch.
- Also add the pre-existing social-media-dashboard skill and
totality-festival design system to the same fallback arrays
(introduced in #678 without i18n coverage). Tagged with TODOs
so localized copy can land in a follow-up.
- Ship the upstream MIT LICENSE file in each
skills/html-ppt-zhangzara-*/ folder so the copyright/permission
notice travels with the vendored copy, as MIT requires for
redistributing substantial portions. Update each SKILL.md's
Source section to reference the bundled LICENSE.
- For the 8 runtime-backed templates (creative-mode,
editorial-tri-tone, neo-grid-bold, peoples-platform,
pin-and-paper, pink-script, soft-editorial, stencil-tablet),
expand the workflow's clone step to instruct the agent to copy
the assets/ folder alongside example.html — the skill HTML
references assets/deck-stage.js (and assets/styles.css for
pin-and-paper) as project-local paths, so cloning the HTML
alone produces an artifact whose runtime 404s.
Verified locally:
- pnpm guard passes.
- pnpm --filter @open-design/web typecheck passes.
- pnpm --filter @open-design/web test passes (309/309).
- pnpm --filter @open-design/e2e test passes (6/6 active,
including localized-content coverage for de/ru/fr).
* fix(i18n): drop duplicate totality-festival fallback after merge with main
Main already added 'totality-festival' to the design-system EN-fallback
lists; the TODO entry from this branch became a duplicate after merge.
* fix(skills, guard): address PR #704 follow-up review
- Pin Chart.js CDN to 4.4.7 in coral and cartesian example.html so
vendored decks no longer track the latest jsDelivr major.
- Narrow scripts/guard.ts zhangzara allowlist to a regex that only
permits skills/html-ppt-zhangzara-*/assets/deck-stage.js, restoring
the TypeScript-first guard for any other JS under those skill dirs.
- Reconcile slide_count and 'Slides in demo' with actual <section
class="slide"> counts: broadside 20 -> 16, monochrome 18 -> 16,
neo-grid-bold 13 -> 12.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(daemon): keep resolveDataDir return path stable, canonicalize at compare site
The realpathSync wrapper inside resolveDataDir was rewriting every
/var/... result to /private/var/... on macOS, which broke 11 hermetic
assertions in tests/resolve-data-dir.test.ts (absolute paths, relative
paths, and \$HOME / \${HOME} / ~ expansions whose mkdtempSync roots live
under /var/folders/...). It also changed the public OD_DATA_DIR
resolution contract for any downstream caller that compared against the
expanded user-supplied path.
Restore resolveDataDir to return the expanded resolved path unchanged,
and introduce RUNTIME_DATA_DIR_CANONICAL — a one-shot realpath of
RUNTIME_DATA_DIR — used only at the narrow folder-import comparison
site that needs to match against a user-supplied realpath() result. The
import-path symlink protection from #624 still works (a /var-rooted
data dir now compares against its /private/var canonical form), while
resolveDataDir keeps its stable, user-shaped contract.
Verified locally: pnpm --filter @open-design/daemon test (1083/1083),
including all 12 resolve-data-dir.test.ts cases.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(postinstall): auto-rebuild better-sqlite3 on Node.js ABI mismatch
prebuild-install fetches a prebuilt binary for the Node.js version active
at install time. On systems where the Node ABI differs from Node 24 (e.g.
Arch Linux system Node, Node 22 LTS, Node 25), or after switching versions,
the addon fails to dlopen at daemon startup.
postinstall now tries to load the native addon after the workspace builds.
On failure it locates node-gyp from the pnpm virtual store (bundled with
better-sqlite3) and rebuilds from source — no external tooling beyond a
C++ compiler required. pnpm install becomes self-healing across Node versions.
Also adds a QUICKSTART troubleshooting entry for users with ignore-scripts=true
who need to run `node scripts/postinstall.mjs` manually.
* fix(postinstall): correct better-sqlite3 path and rebuild mechanism
Two bugs in the initial implementation caught in review:
- better-sqlite3 is declared by apps/daemon, not the workspace root.
node_modules/better-sqlite3 at root does not exist in a normal pnpm
install, so existsSync() was always false and the check never ran.
Fix: resolve via createRequire from apps/daemon/package.json.
- better-sqlite3@12.9.0 depends only on bindings and prebuild-install,
not node-gyp. The assumed sibling path in the pnpm store does not
exist, so the rebuild branch was hitting the "not found" exit instead
of rebuilding. Fix: use pnpm --filter @open-design/daemon rebuild
better-sqlite3 so pnpm manages node-gyp through its own lifecycle.
Also expands the QUICKSTART troubleshooting entry with the manual
rebuild command, a verification step, and build tool prerequisites.
* fix(quickstart): scope better-sqlite3 verification to daemon package
* feat: pre-generation research (Tavily) for grounded generation
Adds an optional pre-generation research step so the agent can produce
slides / prototypes / decks grounded in real sources instead of guessing.
User flow:
1. Settings -> Tavily Search -> paste API key (or set TAVILY_API_KEY).
2. Click the new Research button in the chat composer.
3. On send, the daemon runs a Tavily search, prepends the findings
as a <research_context> block ahead of the system prompt, and
spawns the agent. Research progress shows up as status pills in
the chat stream; the agent cites sources inline as [1]/[2]/...
Phase 1 surface:
- Single provider (Tavily), single depth ('shallow'), no LLM
synthesis pass (Tavily's `answer` is the summary).
- Composer toggle only; no popover / depth picker yet.
- Reuses the existing `status` SSE agent payload + StatusPill UI
so no new event variants or renderer code are needed.
Layers touched:
- contracts: ResearchOptions / Source / Findings DTOs;
ChatRequest.research; export from index.
- daemon: apps/daemon/src/research/{index,tavily}.ts orchestrator
+ provider; tavily added to MEDIA_PROVIDERS and ENV_KEYS; hook
in startChatRun before prompt assembly.
- web: ChatComposer toggle + ChatSendMeta; threaded through
ChatPane / ProjectView / streamViaDaemon into ChatRequest.
Side fix (required to land the feature, but useful on its own):
contracts internal relative imports lacked the `.js` suffix that
NodeNext module resolution requires. This was already breaking
`pnpm --filter @open-design/daemon typecheck` on main; without the
fix, none of the new research types were visible to the daemon.
All internal contracts imports now carry `.js`.
Spec: specs/current/research-feature.md (phases 2-4 outlined for
follow-up: composer popover, multi-provider, deep recursion, example
skills with research_recommends).
Verified:
- pnpm --filter @open-design/contracts typecheck/test
- pnpm --filter @open-design/daemon typecheck (the chokidar
project-watchers test is a pre-existing flake, unrelated)
- pnpm --filter @open-design/web typecheck
- node scripts/verify-media-models.mjs
* fix(daemon): clamp Tavily max_results to 20
Tavily's /search endpoint requires `max_results` in [0, 20]; sending a
larger value (e.g. when `research.depth: "deep"` resolves to 30) returns
400 and `runResearch` silently falls back to no-research. Clamp at the
provider boundary so Phase 2 depth tiers above 20 still produce results
instead of failing the request.
Generated-By: looper 0.6.1 (runner=fixer, agent=claude-code)
* Remove stale research merge leftovers
* Add agent-callable research search
* Fix Indonesian locale typecheck
* Fix research command invocation edge cases
* Harden slash search prompt expansion
* Honor research source caps in command contract
* Require search reports in design files
* Add research data provider settings
* Wire web research provider fallback order
* Update research provider fallback wording
* Revert "Update research provider fallback wording"
This reverts commit 86fb6001e3.
* Revert "Wire web research provider fallback order"
This reverts commit 4c9e16036b.
* Revert "Add research data provider settings"
This reverts commit 23630d1746.
* Add Dexter and Last30Days research skills
* Add DCF and Last30Days OD skills
* Add Last30Days and Dexter skills
* Resolve research review threads
---------
Co-authored-by: a1chzt <chizblank@gmail.com>
* Optimize Windows packaged web output
* Fix packaged contracts runtime build
* Optimize Windows packaged size pruning
* Prune Windows root Next payload
* Remove Windows bundled Node runtime
* Prune Windows standalone duplicate Next
* Add tools-pack cache foundation
* Cache Windows packaged build layers
* Cache Windows workspace builds
* Cache Electron-ready Windows app
* Split Windows tools-pack module
* Cache Windows dir build outputs
* Split Windows pack build modules
* Document Windows NSIS smoke namespace limits
* Move Windows NSIS smoke note to agents guide
* Optimize Windows beta packaging
* Bump packaged beta base version
* Improve Windows installer namespace UX
* Improve Windows tools-pack cache keys
* Stabilize Windows beta cache version keys
* Cache Windows workspace build outputs
* Optimize windows release beta cache layers
* Cache windows release dependencies
* Trim windows release cache before save
* Refresh windows tools-pack cache key
* Improve windows installer preflight prompts
* Fallback NSIS installer strings to English
* Fix Windows installer cleanup and preflight
* Improve Windows NSIS state logging
* Fix system NSIS Persian language alias
* Use long-path removal for Windows uninstall
* Fix mac tools-pack tests on Windows
* Address Windows packaging review feedback
* Fix Windows installer cache namespace isolation
* Include web output mode in Windows tarball cache key
* Use unique Windows release cache save keys
* chore: enforce test directory conventions
Move package, app, and tool tests out of src and add guard enforcement so source directories stay source-only.
* ci: use guard and package-scoped tests
Run the new repository guard in CI and keep test execution aligned with package-scoped commands after removing root aliases.
* ci: align stable release guard check
Use the new repository guard in stable release verification after replacing the residual-JS-only script.
* chore: tighten test layout enforcement
Enforce sibling tests directories, typecheck moved test suites with dedicated configs, and refresh remaining guidance that pointed at src-based tests.
* chore: clarify no-emit test tsconfigs
Explicitly disable declaration-only emit in test tsconfigs so review tooling sees they are no-emit typecheck configs.
* 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)
* feat(editorial-collage): introduce Atelier Zero style landing page assets and documentation
- Added new design system for Atelier Zero, including a detailed `DESIGN.md` file.
- Created an `editorial-collage` skill with associated assets for a magazine-grade landing page.
- Included example HTML and image assets for various sections (hero, about, capabilities, etc.).
- Updated README files to guide usage and customization of the new skill and design system.
- Introduced a new image generation prompt pack for consistent visual style across the landing page.
* fix(i18n): cover atelier-zero design system and editorial-collage skill in German content
Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code)
* fix(editorial-collage): align manifest with shipped assets and address PR review
- Update image-manifest.json widths/heights/ratios to match the actual PNGs
on disk: hero/about/cap/testimonial/cta = 1024x1024 (1:1), method-1..4 =
816x816 (1:1), lab-1..5 and work-1..2 = 768x1024 (3:4). Mirror the new
dimensions in imagegen-prompts.md headings and in README.md.
- Mark testimonial.png as rekey_on_brand_change so the manifest agrees
with SKILL.md's "regenerate at minimum testimonial.png" guidance, and
add work-1/work-2 to the rekey list in SKILL.md and README.md.
- Add a Hero (I.) sec-rule and renumber every following section II..VIII
in example.html so the eight sections walk sequentially I -> VIII and
the page-of-008 counter starts at 001.
- Delete editorial-artifact-system/ (16 duplicate PNGs + index.html +
skills.md draft) — the canonical version is skills/editorial-collage/
and the duplicate had no consumer references.
- DESIGN.md: spell out which dimensions of each magazine reference
(Monocle/Apartamento/IDEA), document the rationale for single-accent
vs multi-accent, and extend the anti-pattern list with AI-image-gen
artifacts the system explicitly rejects.
- SKILL.md: add italic_words validation guidance (trim, cap at 4,
verb->noun rewrite, punctuation strip) and replace the broken-image
fallback with an inline SVG placeholder sized to the slot's
manifest aspect ratio.
Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code)
* fix(daemon): serve skill example assets via stable API route
Skill example HTML such as `skills/editorial-collage/example.html`
references shipped images via `./assets/*.png`. The web app loads the
example into a sandboxed iframe via `srcdoc`, where relative URLs
resolve against `about:srcdoc` and the PNGs render as broken images in
the Examples preview.
Add a `GET /api/skills/:id/assets/*` route that serves files under the
skill's `assets/` directory with path-traversal guards, and rewrite
`src='./assets/<file>'` / `href='./assets/<file>'` in the example
response to point at that route. The disk preview keeps working
because the on-disk files are unchanged.
Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code)
* feat(landing-page): add new static Next.js 16 site for Open Design marketing
- Introduced a new landing page application using Next.js 16, featuring a static export setup.
- Added essential files including `package.json`, `next.config.ts`, and TypeScript configuration.
- Implemented global styles in `globals.css` to match the Atelier Zero design system.
- Created a detailed `AGENTS.md` for module-level boundaries and purpose.
- Included various image assets for the landing page, ensuring a visually cohesive experience.
- Established a root layout and main page structure to support the marketing content.
* style(landing-page): enhance topbar layout and improve responsiveness
- Added nowrap styling to topbar elements to prevent text overflow.
- Introduced media query to hide mid text in the topbar for screen widths between 1200px and 1280px.
- Updated layout.tsx to suppress hydration warnings for better rendering consistency.
- Removed redundant "Compiled by Open Design" text from the page component.
* feat(landing-page): implement scroll-reveal animations for enhanced user experience
- Added a new `RevealRoot` component to manage scroll-triggered reveal animations.
- Updated `globals.css` with styles for elements using the `data-reveal` attribute, including opacity, translation, and scaling effects.
- Modified `layout.tsx` to include the `RevealRoot` component for managing animations.
- Enhanced `page.tsx` by adding `data-reveal` attributes to various elements for staggered reveal effects.
- Implemented reduced motion support to ensure accessibility for users with motion sensitivity.
* fix(landing-page): update import paths and enhance link styles
- Changed the import path in `next-env.d.ts` to reference the correct routes type definition.
- Enhanced `globals.css` with new styles for topbar links, work cards, and partner elements, improving hover effects and transitions.
- Updated `page.tsx` to include canonical project URLs and made various links point to these URLs for better navigation and accessibility.
* feat(landing-page): implement headroom-style sticky header with live GitHub star count
- Introduced a new `Header` component to manage sticky navigation behavior on scroll, enhancing user experience.
- Updated `globals.css` to style the sticky header, including transitions and visibility toggling based on scroll direction.
- Modified `page.tsx` to replace the static header with the new `Header` component, which fetches and displays the live GitHub star count.
- Ensured accessibility by providing a fallback for users who prefer reduced motion.
* feat(landing-page): enhance editorial landing page with global ticker and new styles
- Updated `next-env.d.ts` to reference the correct routes type definition for development.
- Enhanced `globals.css` with new styles for the global ticker, including responsive design and improved overflow handling.
- Introduced a new `WIRE_CITIES` and `WIRE_CONTRIBS` data structure in `page.tsx` to display a counter-scrolling marquee of cities and contributors.
- Added a ghost button style for the navigation call-to-action in the header.
- Updated various sections in `page.tsx` to integrate the new ticker and improve overall layout and accessibility.
* refactor(landing-page): update paper texture overlay and remove multica-ai link
- Enhanced comments in `globals.css` to clarify the purpose and behavior of the paper texture overlay.
- Adjusted z-index of the overlay to ensure proper layering with other elements.
- Removed the `multica-ai` partner link from `page.tsx` to streamline the partner section.
* feat(landing-page): implement dynamic contributor marquee with GitHub integration
- Added a new `Wire` component to display a counter-scrolling marquee of cities and contributors.
- The contributor list is fetched live from the GitHub API, ensuring up-to-date information.
- Updated `page.tsx` to integrate the `Wire` component, replacing the static contributor list with dynamic content.
- Enhanced comments for clarity regarding the functionality and purpose of the global wire.
* fix(i18n): add German display copy for editorial-collage-deck skill
The Validate workspace test asserts that GERMAN_CONTENT_IDS.skills covers
every curated skill on disk; the new editorial-collage-deck skill was
missing from DE_SKILL_COPY, causing src/i18n/content.test.ts to fail.
Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code)
* feat(landing-page): migrate marketing site to Astro
* perf(landing-page): remove React client runtime
* perf(landing-page): serve images from Cloudflare resizing
* fix(pr): address landing page review feedback
---------
Co-authored-by: mrcfps <mrc@powerformer.com>
* feat(web): add pet companion with Codex hatch-pet integration
Introduces a customizable floating pet companion (overlay + entry-view rail
+ composer menu + dedicated Settings → Pets section) that supports built-in
pets, user customization (glyph/image/spritesheet), and one-click adoption
of pets packaged by the upstream Codex `hatch-pet` skill via a new
`/api/codex-pets` daemon endpoint. Vendors the unmodified `hatch-pet`
skill under `skills/hatch-pet/` and adds i18n strings across all locales.
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(scripts): sync community Codex pets from public catalogs
Adds `pnpm sync:community-pets` which fetches all pets from
codex-pet-share.pages.dev (paginated Supabase Functions API) and
j20.nz/hatchery (single-shot JSON), then writes each one as
`<id>/pet.json` + `<id>/spritesheet.webp` under
`\${CODEX_HOME:-\$HOME/.codex}/pets/`. The existing daemon
`codex-pets` registry already scans that folder, so synced pets
appear under Settings → Pets → Recently hatched and adopt with one
click — no manual upload. Supports --source/--out/--force/--limit
flags and validates magic bytes so HTML error pages never end up
masquerading as `.webp` files.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(daemon): tighten codex-pets validation and document vendoring
- sanitizeId now rejects ids that still contain `..` after collapsing,
closing a defensive gap on the path-traversal guard for the
`/api/codex-pets/:id/spritesheet` route.
- listCodexPets emits the sanitised folder name as the public id so the
download route resolves directly against the on-disk folder, even when
`manifest.id` differs (manual drops, sanitiser-touched manifests).
- Drop `@ts-nocheck` from `codex-pets.ts`; module is now strict-typed
with explicit interfaces, an unknown-narrowed JSON.parse path, and a
`pickString` helper guarding manifest fields one by one.
- Restrict the spritesheet response CORS header to sandboxed-iframe
callers (Origin: null) instead of unconditional `*`, matching the
existing raw-file route pattern. Same-origin web traffic does not
need the header (web proxies `/api/*` through the daemon).
- Add `skills/hatch-pet/README.md` explaining the vendoring trade-off,
provenance, and re-sync procedure.
- Add `docs/codex-pets.md` covering where pets live, how to populate the
registry without Codex installed, and the manifest contract.
Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code)
* fix(i18n): add pet.* keys to Hungarian locale
Hungarian locale was added on main after this branch diverged, so the new
pet.* dictionary keys never landed there and tsc -b reports hu's Dict as
incomplete once main is merged in.
Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code)
* feat(web): atlas-driven pet animations + bundled community pets
Builds on the existing pet companion (#296) with a richer animation
loop, a curated set of community pets that ship with the repo, and a
one-click sync into ~/.codex/pets/.
- Atlas-mode rendering: PetSpriteFace can now play the full Codex 8x9
sprite atlas and swap rows from a JS-driven frame index. PetOverlay
classifies pointer interactions (idle / hover / drag-direction /
long-idle waiting) and maps them to the matching atlas row, so the
pet waves on hover, runs on drag, and falls into a waiting pose
after 6s of stillness. Single-strip pets keep their existing CSS
steps() animation, with the steps timing fixed to jump-none so frame
cells line up on cell boundaries.
- Atlas adoption: PetSettings exposes both "Use full atlas (animated)"
and "Freeze to this row" — full mode keeps every row for the
interaction state machine, single-row mode crops one strip via the
existing canvas helper. New prepareCodexAtlas downscales the atlas
to a localStorage-friendly PNG while preserving the grid layout.
- Settings tabs: pet sources are now split into Built-in / Custom /
Community tabs so each origin gets its own dedicated surface.
- Bundled pets: scripts/bake-community-pets.ts seeds a curated set
(clippit, dario, nyako-shigure, slavik, trump, tux, yelling-dario,
yorha-sit-2b) into assets/community-pets/. The daemon scans this
alongside the user's ~/.codex/pets/ root, with user pets winning
when ids collide. CodexPetSummary gains a `bundled` flag so the UI
can tag those cards with a "Bundled" pill.
- One-click community sync: daemon-side port of sync-community-pets
exposed via POST /api/codex-pets/sync. Returns the same
wrote/skipped/failed/total summary the CLI prints. Web Pet settings
surface this as a "Download community pets" button under the
Community tab.
- Avatar dropdown + hide rail: EntryView's avatar button is now a
small menu (mirrors the project-view AvatarMenu) with toggles for
hiding/showing the pet rail and opening Settings. PetRail gets a
matching × button for the same hide flow.
- Locales: 7 new pet.* keys for tabs, sync, hide/show, atlas full
mode, and the Bundled pill — translated into all 13 supported
locales.
Typechecks pass across all workspace packages; daemon + web vitest
suites stay green.
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(web): bundled-pets built-in tab, ambient atlas animations, and community sync button
The Built-in tab now sources its catalog from the bundled spritesheets
at `assets/community-pets/` instead of the eight emoji placeholders that
felt boring next to the Codex hatch-pet atlases.
- Daemon: `listCodexPets` flags `bundled: true` by curated-set membership
in `assets/community-pets/`, not by which folder the sprite happened to
be read from. Previously a fully-synced user inbox preempted every
bundled id and left the tab empty.
- Settings → Pets → Built-in renders the same sprite-card grid as
Community, filtered by `bundled: true`, and reuses the existing
`adoptCodexPet` flow. Community tab filters to non-bundled so the
curated set never appears twice.
- Community tab gains the long-promised "Download community pets"
trigger that calls `/api/codex-pets/sync` and shows an inline status
line for the run summary. Strings already existed in every locale; we
just plumbed the button.
- `PetOverlay` gets ambient atlas-row choreography — while idle, the
overlay occasionally swaps `idle` for a random non-idle row (wave /
hop / look) so the pet doesn't feel frozen. User gestures cancel the
beat and take over instantly. `pickAmbientRow` lives next to
`pickAtlasRow` so both row pickers share the fallback discipline.
- One-shot `migrateCustomPetAtlas` heals configs adopted before the
overlay learned row switching by re-downloading the full spritesheet
so hover / drag / ambient variety light up on next launch.
- `BUILT_IN_PETS` is now an empty array (the type stays for backwards
compat); legacy configs whose `petId` still points at an emoji id
(`mochi`, `pixel`, …) fall back to the user's custom slot in
`resolveActivePet` so the overlay never renders blank.
- i18n: refresh `pet.tabBuiltInHint` (drop "emoji companions") and add
`pet.builtInEmpty` across all locales.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(web,daemon): make max_tokens configurable (closes#29)
BYOK users on custom Anthropic-compatible providers (e.g. Xiaomi MiMo)
hit the hardcoded 8192 cap and saw artifacts truncated mid-stream.
- AppConfig.maxTokens with Settings input (EN/CN + 8 other locales)
- ProxyStreamRequest.maxTokens contract field
- anthropic, anthropic-compatible, and openai-compatible providers all
forward cfg.maxTokens
- /api/proxy/anthropic/stream and /api/proxy/stream payloads honor it,
defaulting to 8192 when unset so prior clients are unaffected
Original sketch by @mashu in #78 (50a9d14); rebased to the apps/web
layout and extended to the proxy paths actually used when baseUrl is
set, which is where #29's user actually traffics.
* feat(web): per-model max_tokens defaults
Adds a hand-maintained MODEL_MAX_TOKENS table (Claude 4.5 line → 64k,
mimo-v2.5-pro → 32k) and an effectiveMaxTokens helper layered over the
override field added in 6a3ae5f, so #29's user — and others on supported
models — don't have to discover Settings to avoid mid-stream truncation.
- apps/web/src/state/maxTokens.ts: lookup + helpers
- providers/{anthropic,anthropic-compatible,openai-compatible}.ts:
forward effectiveMaxTokens(cfg) instead of cfg.maxTokens ?? 8192
- SettingsDialog: input becomes an optional override (blank = default,
shown as placeholder)
- 10 locale hint strings updated to the new semantics
* feat(web): vendor LiteLLM model metadata for max_tokens defaults
Replaces the 4-entry hand-rolled MODEL_MAX_TOKENS map from 544e67e with
a vendored slice of BerriAI/litellm's model_prices_and_context_window
JSON (1970 chat models, ~97KB raw / ~25KB gzip). Future model launches
land in maxTokens.ts via `pnpm sync-litellm-models` instead of manual
edits.
- scripts/sync-litellm-models.ts: fetches the upstream JSON, filters to
chat-mode entries, projects each entry to its max_output_tokens (or
max_tokens fallback), and writes a sorted, license-attributed JSON
- apps/web/src/state/litellm-models.json: generated artifact, committed
- apps/web/src/state/maxTokens.ts: lookup is now
OVERRIDES → LITELLM_MODELS → FALLBACK_MAX_TOKENS. The OVERRIDES table
shrinks to just `mimo-v2.5-pro` (LiteLLM only ships MiMo via
OpenRouter/Novita aliases, not the canonical id Xiaomi's API uses).
LiteLLM is MIT-licensed (BerriAI/litellm/blob/main/LICENSE); attribution
is preserved in both the script header and the generated JSON's
_license field.
* test(web,docs): cover maxTokens lookup + document sync workflow
- apps/web/src/state/maxTokens.test.ts: six vitest cases pinning the
three-tier lookup (override → LiteLLM → fallback) and the
effectiveMaxTokens user-override path. Guards against a future sync
silently dropping the Anthropic 4.5 entries we rely on.
- CONTRIBUTING.md / CONTRIBUTING.zh-CN.md: new "Updating model
max_tokens metadata" section pointing future maintainers at
scripts/sync-litellm-models.ts and explaining when OVERRIDES is
appropriate (it's the rare exception, not the default).
* fix(web): mark Max tokens label as optional in 10 locales
The Settings field is optional (blank means "use the per-model default")
but the label gave no visual cue, breaking the implicit pattern that
every other API-mode field (key/model/baseUrl) is required. Append
"(optional)" — using the locale's natural parenthetical convention
(Chinese full-width brackets, Japanese 任意, Russian опционально, etc.)
— so the field reads as discretionary at a glance.
* fix(web): validate maxTokens override against advertised UI bounds
Addresses Siri-Ray's review on commit 0d98185. The Settings input
declares min={1024}/max={200000}/step={1024}, but until now
effectiveMaxTokens trusted any defined cfg.maxTokens, so a stale or
hand-edited localStorage value (negative, zero, fractional, billions)
would pass straight to the Anthropic SDK on the direct path while the
daemon proxy quietly clamped it back to 8192 on the proxied path —
same config, divergent behavior depending on route.
- maxTokens.ts: add MIN_MAX_TOKENS / MAX_MAX_TOKENS exports and
isValidOverride helper. effectiveMaxTokens only honors the override
when it is a finite integer in [1024, 200000]; otherwise falls back
to modelMaxTokensDefault.
- SettingsDialog.tsx: input bounds now reference the same constants so
the UI promise can't drift from the runtime check.
- maxTokens.test.ts: six new cases pinning the rejection of negative,
zero, sub-MIN, super-MAX, non-integer (fractional / NaN / Infinity)
overrides plus the inclusive MIN/MAX boundaries.
The daemon proxy's existing `> 0` fallback stays as defense-in-depth.
* feat(skills): integrate lewislulu/html-ppt-skill as html-ppt + 15 per-template Examples cards
Bring the MIT-licensed lewislulu/html-ppt-skill upstream into skills/html-ppt/
with its full asset tree (36 themes, 31 single-page layouts, 27 CSS + 20
canvas-FX animations, runtime + presenter mode, all 15 full-deck templates,
and the upstream LICENSE preserved verbatim).
Surface each full-deck template as its own Examples gallery card via thin
wrapper skills under skills/html-ppt-<template>/. Each wrapper ships:
- SKILL.md with `od.mode=deck`, scenario, `featured: 20-34` (slotting after
the existing curated cards), an `od.example_prompt` tuned to the template,
and `od.upstream` pointing at the upstream repo. Clicking "Use this prompt"
on a card now wires up `kind=deck` + `speakerNotes=true` and seeds the
composer with the upstream's authoring flow so the prompt -> output path
matches the upstream demo.
- example.html baked self-contained (fonts/base/animations/style/theme CSS
inlined, runtime <script> stripped) so the gallery srcdoc iframe renders
the upstream look without external paths.
scripts/scaffold-html-ppt-skills.mjs and scripts/bake-html-ppt-examples.mjs
are idempotent generators — re-run after editing skills/html-ppt/ to re-sync
all per-template wrappers and their baked examples.
Add a Credits section + extend the License section in README.md /
README.zh-CN.md / README.ko.md to credit the upstream alongside the
already-cited op7418/guizang-ppt-skill.
* fix(scripts): allowlist html-ppt skill JS for residual-js check
Add scripts/bake-html-ppt-examples.mjs and scripts/scaffold-html-ppt-skills.mjs
to allowedExactPaths, and skills/html-ppt/assets/ to allowedPathPrefixes so
pnpm check:residual-js no longer flags the vendored upstream runtime JS or the
new maintainer-only .mjs scripts.
* fix(skills): keep all slides in baked html-ppt examples + correct asset guidance
The bake script's `STATIC_FALLBACK_CSS` set `.slide+.slide{display:none}`,
which silently truncated every baked `example.html` to slide 1. That artifact
is also served by `/api/skills/:id/example` and reused by the Examples
preview modal's share/export and print-to-PDF, so the rule dropped the rest
of the deck from those flows. Drop the rule — slides now stack in the
print-style flow the surrounding comment already described, the gallery
thumbnail iframe still naturally lands on slide 1 (each `.slide` is `100vh`),
and modal/share/export contains the full deck.
The wrapper SKILL.md authoring instructions told agents to copy
`index.html` + `style.css` into a project while keeping the upstream
`../../../assets/...` links, but those parent-relative URLs only resolve
in-tree (the template sits three folders deep). Once the file lives in a
project artifact, `base.css`, `animations.css`, and `runtime.js` 404 and
the deck never activates. Replace step 3 with two recipes — copy the
shared assets into a project-local `assets/` and rewrite the four tags,
or inline the CSS/JS directly — and re-emit all 15 wrapper SKILL.md
files via the scaffold generator.
* feat(prompt-templates): add dance storyboard and ancient-china MMO HUD templates
- social-media-post-sensational-girl-dance-storyboard-8-shots: 8-shot storyboard
prompt set with shared global style tokens, negative prompt, and character
lock, tuned for GPT-Image-2. Produces a continuous dance choreography as a
coherent 8-frame sequence.
- game-ui-ancient-china-open-world-mmo-hud: HUD mockup for a Black Myth: Wukong
style ancient-China open-world MMO, centered on a female swordswoman
protagonist. Covers character panel, minimap with bagua frame, skill hotbar,
quest tracker, chat window, and world-space nameplates with Chinese
typography rules.
- scripts/import-prompt-templates.mjs: preserve hand-authored templates on
re-run by keeping any JSON whose source.repo is not the upstream CC-BY
corpus. Previously clearDir wiped the whole directory, which would delete
first-party curated prompts on the next import.
Both templates carry source attribution to nexu-io/open-design under
Apache-2.0. Categories reuse the existing 'Social Media Post' and 'Game UI'
enum values already present in the gallery.
* feat(prompt-templates): add preview images for dance and MMO HUD templates
- assets/prompt-templates/image/social-media-post-sensational-girl-dance-storyboard-8-shots.jpg:
an 8-panel storyboard render produced from the template itself, downscaled to
1024x1536 JPEG for gallery thumbnails.
- assets/prompt-templates/image/game-ui-ancient-china-open-world-mmo-hud.jpg:
a reference HUD screenshot rendered from the template prompt via gpt-image-2,
downscaled to 1536x1024 JPEG.
- Both templates now reference these previews via a raw.githubusercontent.com
URL pointing at nexu-io/open-design main, matching the pattern used by the
existing YouMind-sourced seeds (cms-assets.youmind.com) so every card in the
Prompt Gallery carries a thumbnail once the PR merges.
---------
Co-authored-by: Joey <joey@open-design.local>
Postinstall assumed `npm_execpath` always points to pnpm's JS entry and
invoked it via `node $npm_execpath`. When pnpm is installed as a
standalone binary (e.g. `@pnpm/exe` via mise / volta), `npm_execpath`
points to an ELF/Mach-O/PE executable and Node fails with
"Invalid or unexpected token" parsing the binary as JS.
Branch on the executable's extension: keep wrapping `.js`/`.cjs`/`.mjs`
entries with `node`, but spawn other paths directly so standalone pnpm
binaries work too.
Co-authored-by: decker <decker502@qq.com>
* feat(dev): add desktop tools-dev control plane
* refactor(sidecar): split Open Design contracts
Move Open Design-specific sidecar protocol definitions into @open-design/contracts so sidecar and platform can remain descriptor-driven primitives.
* refactor(daemon): organize package sources
Keep daemon app code, tests, and sidecar entrypoints in separate package directories so each layer can be built and verified independently.
* chore(repo): streamline maintenance entrypoints
Centralize agent guidance by directory and reduce root command chains while preserving the existing build scope.
* docs: translate agent guidance to English
* fix(sidecar): tolerate stale IPC sockets
Remove stale Unix socket files only after confirming no listener is active, so tools-dev can restart after unclean shutdowns.
* test: add e2e ui automation suite
* fix review feedback for ui e2e suite
Resolved the FileWorkspace.tsx merge-marker issue and kept the intended combination of multiple, accept="image/*", and data-testid.
Updated the e2e port handling so the test config no longer relies on a single hardcoded app port. It now resolves an available port first and passes the same port selection through the dev server and Playwright base URL. Since main has moved to the Next.js dev stack, this was also adapted from the old Vite-based flow to NEXT_PORT.
Kept test:ui serialized so cleanup completes before Playwright starts.
Updated reset-e2e-artifacts.mjs so cleanup failures are surfaced with a warning instead of being silently swallowed, except for the expected ENOENT case.
* Refactor project name from "Open Claude Design" to "Open Design"
- Updated project name in package.json, package-lock.json, and README files.
- Changed CLI commands and references from "ocd" to "od".
- Adjusted file structure references in documentation and code to reflect new naming conventions.
- Enhanced .gitignore to include new runtime data files.
- Updated metadata in LICENSE file to match new project name.
* chore: migrate frontend toolchain from Vite to Next.js 16 App Router
Replace the Vite SPA scaffold with Next.js 16 App Router while keeping
the existing daemon as the API/SSE/sqlite backend. The whole client
tree now mounts under a single optional catch-all route
(app/[[...slug]]) loaded with ssr:false; static export emits one shell
HTML the daemon serves as the SPA fallback for deep links. Dev uses
next.config rewrites to proxy /api, /artifacts, /frames to the daemon,
matching the previous Vite setup.
Made-with: Cursor
* fix: address Next migration review feedback
* fix: serve static export in preview script
---------
Co-authored-by: mrcfps <mrc@powerformer.com>
* Refactor project name from "Open Claude Design" to "Open Design"
- Updated project name in package.json, package-lock.json, and README files.
- Changed CLI commands and references from "ocd" to "od".
- Adjusted file structure references in documentation and code to reflect new naming conventions.
- Enhanced .gitignore to include new runtime data files.
- Updated metadata in LICENSE file to match new project name.
* Add contributing guidelines in English and Chinese
- Introduced CONTRIBUTING.md and CONTRIBUTING.zh-CN.md to provide clear instructions for contributors.
- Outlined contribution types, local setup instructions, and merging criteria for skills and design systems.
- Enhanced README files to reference the new contributing guidelines.
* Update README and documentation for deck framework directives
- Clarified DECK_FRAMEWORK_DIRECTIVE description in both English and Chinese README files to specify conditions for deck kind without a skill seed.
- Added detailed workflow instructions in deck-framework.ts to emphasize the importance of copying the framework before adding content.
- Enhanced discovery.ts to reinforce the framework-first approach for deck projects.
- Updated system.ts to ensure proper handling of deck projects with and without bound skills, preventing re-authorship of scaling and navigation logic.
* Update README and documentation for deck framework directives
- Clarified DECK_FRAMEWORK_DIRECTIVE description in both English and Chinese README files to specify conditions for deck kind without a skill seed.
- Added detailed workflow instructions in deck-framework.ts to emphasize the importance of copying the framework before adding content.
- Enhanced discovery.ts to reinforce the framework-first approach for deck projects.
- Updated system.ts to ensure proper handling of deck projects with and without bound skills, preventing re-authorship of scaling and navigation logic.
* Enhance README and add star promotion assets
- Added a "Star us" section in both English and Chinese README files to encourage users to star the project on GitHub.
- Included a new image asset for the star promotion.
- Introduced a new HTML file for a dedicated star promotion page.
- Updated .gitignore to exclude new cursor-related files.
* feat(dev): auto-switch ports on dev:all when defaults are busy
Adds a small launcher (scripts/dev-all.mjs) that probes free ports
for the daemon (OD_PORT, default 7456) and Vite (VITE_PORT, default
5173) before invoking concurrently, so a stray process holding
either port no longer breaks the boot. The resolved ports are
exported into the child env; vite.config.ts now reads VITE_PORT to
keep its dev server and /api proxy aligned with the daemon's actual
port.
Made-with: Cursor
- Created .gitignore to exclude build artifacts and dependencies.
- Added index.html as the main entry point for the application.
- Included LICENSE file with Apache 2.0 terms.
- Initialized package.json and package-lock.json for project dependencies.
- Added pnpm-lock.yaml for package management.
- Created QUICKSTART.md for setup instructions.
- Added README.md and README.zh-CN.md for project documentation in English and Chinese.