mirror of
https://github.com/nexu-io/open-design.git
synced 2026-10-27 09:51:12 +01:00
d5549bf016d0ac791c40eac8bdf4bea8ae4485d8
259
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
d5549bf016 |
fix(tools-pack): replace corepack with npx in linux container build
release-stable run 25386360556 failed at the build_linux job with: bash: line 1: corepack: command not found Error: docker build exited with code 127 Although Node 16.10+ ships corepack, the `electronuserland/builder:base` image strips the corepack binary, so the inner `bash -lc` we pass to `docker exec` blows up before pnpm install ever starts. We can't `corepack enable` ourselves either — the container runs as the host's non-root uid (--user) and corepack would try to write shims next to the root-owned system Node binary. Switch to `npx --yes pnpm@10.33.2`: - npx ships with npm and is always present in the image - --yes skips the install confirmation - package caches under $HOME/.npm/_npx (writable by the unprivileged user) - the pinned version matches the `packageManager` field in the root package.json, preserving reproducibility Both invocations switch in lockstep: - `corepack pnpm install --frozen-lockfile` → `npx --yes pnpm@10.33.2 install --frozen-lockfile` - `corepack pnpm tools-pack linux build ...` → `npx --yes pnpm@10.33.2 tools-pack linux build ...` Local verify: pnpm --filter @open-design/tools-pack run typecheck (exit 0). Full e2e verification needs the actual docker run on a Linux runner — the next release-stable dispatch will exercise it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
963bbf2500 | release: Open Design 0.4.0 (#454) | ||
|
|
009d7a5478 |
refactor(daemon): eliminate duplicate dist tree from two-tsconfig build (#553)
Move sidecar source under src/ so a single tsconfig produces all daemon
output. Removes the parallel dist/src/ tree that was emitted by
tsconfig.sidecar.json (it included src/**/*.ts to type-check the
`../src/server.js` cross-tree import).
Build now emits:
- dist/<flat> (cli.js, server.js, app-version.js, ...)
- dist/sidecar/{index,server}.js
`dist/sidecar/server.js` reaches the main daemon via `../server.js`
instead of `../src/server.js`, so there is no second copy of the source
tree in the published tarball.
Background — issue #534 (already fixed by #537):
The packaged Settings → About panel showed 0.0.0 because the sidecar
chain loaded the duplicated `dist/src/app-version.js`, where the fixed
`new URL('../package.json', import.meta.url)` resolved to a non-existent
`dist/package.json`. #537 patched the symptom by walking parents until a
real `package.json` is found and by writing `appVersion` into the Linux
packaged config. Both stay in place — they're sound defenses — but the
underlying duplicate-emit was never addressed; any future relative
resource lookup (templates, schemas, prompts) anchored on
`import.meta.url` would have hit the same trap.
This change removes the trap.
|
||
|
|
6b7a40e5c3 | Fix file tab wheel scrolling (#549) | ||
|
|
14908e1aea | fix: typo in zh-TW README (#548) | ||
|
|
cbe2baf596 |
feat(web): add skills & design systems management page in settings (#535)
* feat(web): add skills & design systems management page in settings Add a new "Library" section in Settings that lets users browse, search, preview, and enable/disable skills and design systems. Disabled items are excluded from the create-project picker. Phase 1 — browse/toggle only. Closes #497 * fix(web): persist empty disabled lists and deduplicate DS preview Use empty array instead of undefined when all items are re-enabled so the daemon merge clears the key. Move DS preview panel outside the category group loop so it renders once, not per group. * fix(web): address review feedback on library settings Clear disabled lists on invalid daemon writes, memoize enabled item filters in App.tsx, and guard preview fetch against rapid-click race conditions. * fix(web): hydrate disabled lists from daemon and keep full lists in ProjectView Merge daemonConfig.disabledSkills/disabledDesignSystems during bootstrap so the values survive localStorage resets. Pass unfiltered skills and design systems to ProjectView so existing project metadata resolves correctly. |
||
|
|
4fa2df2ae3 |
docs(i18n): defer README template-driven generation, capture #195 discussion (#403)
Add NRG / template-driven README generation to TRANSLATIONS.md "Deferred decisions" with explicit re-evaluation triggers (≥15 locales or monthly+ README structural edits) and a record of the shared-structure trade-off that surfaced in #195. Captures the rationale (zh-TW's "上手體驗" section, pt-BR vs pt-PT content-level divergence precedent) so future contributors don't relitigate it from scratch. |
||
|
|
cc6da191e8 |
fix(version): resolve daemon package.json from any compiled layout (#537)
Settings -> About used to display 0.0.0 in packaged builds because `readCurrentAppVersionInfo` resolved `'../package.json'` relative to `import.meta.url`, which only points at the daemon package root from the flat CLI build (`dist/app-version.js`). The sidecar build emits `dist/src/app-version.js`, where the same relative path lands on the non-existent `dist/package.json`, so `readPackageMetadata` returned null and the version fell back to APP_VERSION_FALLBACK. Walk up from `import.meta.url` to find the nearest real `package.json` instead, so the daemon reports its actual version regardless of whether it runs from TypeScript source (tools-dev), the flat CLI dist, or the nested sidecar dist used by the packaged desktop app. The OD_APP_VERSION env still wins inside `resolveAppVersionInfo`, so callers that already inject it (mac/win packagers) keep working. Also write `appVersion` into the Linux packaged config so Linux follows the same env-injection path as mac/win and stays consistent with the new fallback resolution. Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
79fcaef129 |
Add Tweaks mode for HTML previews with picker, pod selection, and batched chat attachments (#513)
* Add tweaks mode for HTML preview comments * Fix tweaks geometry and restore critique migration * Harden tweaks mode reload sync * Guard tweaks batch sends during active runs --------- Co-authored-by: puma <puma@pumas-MacBook-Air.local> |
||
|
|
34e8db175d |
fix(daemon): preserve ANTHROPIC_API_KEY when ANTHROPIC_BASE_URL is set (#514)
* fix(daemon): preserve ANTHROPIC_API_KEY when ANTHROPIC_BASE_URL is set The claude adapter currently strips ANTHROPIC_API_KEY unconditionally so that Claude Code's own auth resolution (claude login) wins instead of silently falling back to API-key billing. However, when ANTHROPIC_BASE_URL is set the user is intentionally routing Claude Code to a custom endpoint (e.g. a Kimi/Moonshot proxy). In that case claude login is meaningless, so preserve the API key so the child can authenticate against the custom base URL. * fix(daemon): guard against empty ANTHROPIC_BASE_URL values Address review feedback: check that ANTHROPIC_BASE_URL contains a non-empty, non-whitespace string before preserving ANTHROPIC_API_KEY. This prevents the #398 billing guard from being bypassed when the variable is set to '' or whitespace. |
||
|
|
e5c9febf8c |
docs: surface desktop downloads in README badges and Quickstart (#522)
Desktop client v0.3.0 has shipped for macOS (Apple Silicon) and Windows (x64) at https://open-design.ai/ and the GitHub releases page. Surface that in 11 READMEs (en + 10 localized): - Add a 'Download' CTA badge as the first item in the shields row, linking to open-design.ai (orange #ff6b35, no platform-specific logo so it doesn't imply Mac-only or Windows-only). - Repoint the existing release badge link from /releases/latest to /releases (the general entry page, more stable for users browsing history). - Add &display_name=tag to the release shields URL so the badge shows the literal tag (e.g. open-design-v0.3.1-beta.5) instead of 'invalid' — shields.io's semver parser doesn't recognize the open-design- prefix. - Update the At-a-glance 'Deployable to' row: drop the 'placeholder, in-flight' note and call out the actual macOS/Windows downloads with links to open-design.ai and the releases page. - Insert a 'Download the desktop app (no build required)' subsection at the top of Quickstart, with a 'Run from source' subheading before the existing bash block — splits the funnel between non-developer users (download link) and developers (clone + pnpm). - Flip the roadmap entry for apps/packaged/ from [ ] to [x] and append the download links. zh-TW does not carry the release badge in its shields row, so the release-badge update is a no-op there; all other changes apply. |
||
|
|
e0a75ea8c8 |
fix: add lowercase 'todowrite' compatibility in ToolCard (#523)
Add backward compatibility for historic OpenCode CLI data: - Match both 'TodoWrite' and 'todowrite' tool names - Fixes rendering of TodoWrite cards from persisted chat history Scope: 1 line change, no other files modified Co-authored-by: bojiehuang <bojiehuang@bojiehuangdeMacBook-Pro.local> |
||
|
|
5da21e4054 |
feat(craft): animation-discipline module + opt-ins on mobile-app, mobile-onboarding, gamified-app (#515)
* feat(craft): add animation-discipline + opt-ins on mobile-app, mobile-onboarding, gamified-app Animation discipline is the second behavioral craft module proposed in #501 and explicitly invited in @mrcfps's post-merge comment on #502. Differentiation from prior art (LottieFiles motion-design-skill, MIT, 96 stars): citation-grounded against primary sources rather than asserted. Anchors: - Tversky/Morrison/Bétrancourt 2002 (IJHCS) on the one demonstrated win-condition for animation - Heer & Robertson TVCG 2007 on staging (with the actual durations they tested, not the laundered '300-1000ms' rule) - Harrison/Yeo/Hudson CHI 2010 on perceived-duration scope (progress bars only, not skeletons) - Doherty & Thadani IBM 1982 productivity numbers - Material 3 motion tokens (M3 standard vs M2 legacy delta) - IBM @carbon/motion durations - Apple SwiftUI Animation API published defaults - W3C View Transitions API + WCAG 2.2.2/2.3.3 calibration - WebKit 2017 prefers-reduced-motion rationale The 'common mistakes (lint these)' section busts five specific folklore claims that don't survive primary-source check, including the Doherty-400ms attribution and the M2-vs-M3 standard easing confusion. Three skills opt in via od.craft.requires: - mobile-app (animation-heavy mobile screens) - mobile-onboarding (multi-screen flow with transitions) - gamified-app (animations central to the format) Refs #501. * fix(craft): address review findings on animation-discipline Six findings from @lefarcen's CHANGES_REQUESTED review on #515, addressed in one pass. Reviewed by codex across three loops before push. P1 integration gaps: - gamified-app and mobile-onboarding skills now require both state-coverage and animation-discipline (both render stateful UI with motion). - craft/README.md silent-fallback example reframed as a planned-but-not-yet-vendored placeholder rather than a hard-coded next-to-ship slug. Note added pointing skill authors who arrive from older guidance at animation-discipline as the equivalent of the earlier 'motion' placeholder. P2 reasoning completeness: - > 500 ms duration row reframed: 'Reserved for cross-screen, staged, or platform-native transitions (e.g. M3 long2-extraLong4, Heer & Robertson 2007's per-stage recommendation)'. Surrounding paragraph rewritten with an enumerated category — 'Non-navigation microinteractions: hover, press, toggle, validation, chip selection, row expansion' — rather than the vague 'routine' term. - New 'Flashing limits' subsection added in the Reduced motion section. WCAG 2.3.1 (Level A) three-flashes-in-any-one-second-period rule with the area/brightness threshold qualifier; WCAG 2.3.2 (AAA) unconditional rule. Photosensitive epilepsy framing. - New 'Repeated and ambient motion' section added. Five rules covering iteration cap, WCAG 2.2.2 pause control after 5s, cancel-on-route, one-shot reward animations, and spinner timeout cross-referencing state-coverage.md. File length now 154 lines (was 130, 80-110 craft target). Trade is citation density and the new sections demanded by the integration context (gamified/onboarding skills with looping motion). Refs #501, #515. |
||
|
|
c3d9136a0c |
Add live artifacts and Composio connector catalog (#381)
* docs: add live artifacts implementation spec * docs: align live artifacts implementation plan * Ralph iteration 1: work in progress * Ralph iteration 2: work in progress * Ralph iteration 3: work in progress * Ralph iteration 4: work in progress * Ralph iteration 5: work in progress * Ralph iteration 6: work in progress * Ralph iteration 7: work in progress * Ralph iteration 8: work in progress * Ralph iteration 9: work in progress * Ralph iteration 10: work in progress * Ralph iteration 11: work in progress * Ralph iteration 12: work in progress * Ralph iteration 13: work in progress * Ralph iteration 14: work in progress * Ralph iteration 15: work in progress * Ralph iteration 16: work in progress * Ralph iteration 17: work in progress * Ralph iteration 18: work in progress * Ralph iteration 19: work in progress * Ralph iteration 20: work in progress * Ralph iteration 21: work in progress * Ralph iteration 22: work in progress * Ralph iteration 23: work in progress * Ralph iteration 24: work in progress * Ralph iteration 25: work in progress * Ralph iteration 26: work in progress * Ralph iteration 27: work in progress * Ralph iteration 28: work in progress * Ralph iteration 29: work in progress * Ralph iteration 30: work in progress * Ralph iteration 31: work in progress * Ralph iteration 32: work in progress * Ralph iteration 33: work in progress * Ralph iteration 34: work in progress * Ralph iteration 35: work in progress * Ralph iteration 36: work in progress * Ralph iteration 37: work in progress * Ralph iteration 38: work in progress * Ralph iteration 39: work in progress * Ralph iteration 40: work in progress * Ralph iteration 41: work in progress * Ralph iteration 42: work in progress * Ralph iteration 43: work in progress * Ralph iteration 44: work in progress * Ralph iteration 45: work in progress * Ralph iteration 46: work in progress * Ralph iteration 47: work in progress * Ralph iteration 48: work in progress * Ralph iteration 49: work in progress * Ralph iteration 50: work in progress * Ralph iteration 51: work in progress * Ralph iteration 52: work in progress * Ralph iteration 53: work in progress * Ralph iteration 54: work in progress * Ralph iteration 55: work in progress * Ralph iteration 56: work in progress * Ralph iteration 57: work in progress * Ralph iteration 58: work in progress * Ralph iteration 59: work in progress * Ralph iteration 60: work in progress * Ralph iteration 61: work in progress * Ralph iteration 62: work in progress * Ralph iteration 63: work in progress * Ralph iteration 64: work in progress * Ralph iteration 65: work in progress * Ralph iteration 1: work in progress * Ralph iteration 2: work in progress * Ralph iteration 3: work in progress * Ralph iteration 4: work in progress * Ralph iteration 5: work in progress * Ralph iteration 6: work in progress * Ralph iteration 8: work in progress * Ralph iteration 9: work in progress * Ralph iteration 17: work in progress * Add Composio-backed connectors * Add Composio-backed connector catalog * Fix connector callback flow * Update live artifact connector refresh * Fix live artifact refresh updates * Improve live artifact viewer toolbar * Refine live artifact source tabs * Expand Composio connector catalog * Improve Composio connector browsing * Fix artifact refresh source safety checks Generated-By: looper 0.4.1 (runner=fixer, agent=opencode) * Fix live artifacts PR feedback Generated-By: looper 0.5.0 (runner=fixer, agent=opencode) * Fix live artifact preview CORS validation Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode) * Fix connector OAuth IPv6 loopback hosts Allow bracketed IPv6 loopback Host headers when deriving connector OAuth callback URLs so IPv6-bound daemons can complete connection flow. Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode) * Preserve live artifact refresh permissions Respect explicit refresh permission choices during live artifact create and update flows so revoked connector sources remain gated. Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode) * Fix live artifact preview cache freshness Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode) * Fix live artifact refresh validation Guard manual refreshes with local daemon checks and reject daemon_tool sources without a toolName before refresh execution. Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode) * Fix Composio credential invalidation Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode) * Fix live artifact CORS methods Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode) * Fix workspace validation Restore media config test isolation under Vitest setup data-dir overrides and add the missing French live artifact display copy so the workspace test suite stays aligned.\n\nGenerated-By: looper 0.5.2 (runner=fixer, agent=opencode) * Fix connector safety filtering Keep agent-preview connector listings aligned with execution safety policy and prune stale Composio OAuth state records before they accumulate. Generated-By: looper 0.5.2 (runner=fixer, agent=opencode) * Fix agent runtime cleanup Generated-By: looper 0.5.2 (runner=fixer, agent=opencode) * Fix live artifact daemon access Validate local-only live artifact routes against the peer socket address and pass daemon-resolved CLI paths to ACP MCP descriptors.\n\nGenerated-By: looper 0.5.2 (runner=fixer, agent=opencode) * Fix connector run limit pruning Evict stale connector rate-limit buckets so long-lived daemon processes do not retain per-run entries indefinitely.\n\nGenerated-By: looper 0.5.2 (runner=fixer, agent=opencode) * Fix connector compact schemas Generated-By: looper 0.5.2 (runner=fixer, agent=opencode) * Improve connector connection feedback * Adjust connector gate positioning * Fix live artifact refresh commits Avoid marking refresh candidates failed after snapshot or state persistence errors by deferring live artifact mutations until the durable refresh metadata is written. Also align connector OAuth callback host validation with daemon loopback handling.\n\nGenerated-By: looper 0.5.4 (runner=fixer, agent=opencode) * Improve connector search relevance * fix(daemon): harden connector connection state Require loopback daemon validation before connector connect side effects and only clear provider-owned connector statuses during credential reset. Generated-By: looper 0.5.4 (runner=fixer, agent=opencode) * fix(daemon): guard connector disconnect route Require local daemon request validation before connector disconnect side effects. Generated-By: looper 0.5.4 (runner=fixer, agent=opencode) * fix(daemon): guard composio config updates Generated-By: looper 0.5.4 (runner=fixer, agent=opencode) * fix(daemon): dispatch live artifacts mcp first Route the live-artifacts MCP server before the generic MCP CLI so od mcp live-artifacts starts the dedicated server instead of failing generic argument parsing.\n\nGenerated-By: looper 0.5.4 (runner=fixer, agent=opencode) * fix(daemon): handle integer connector schemas Allow JSON Schema integer connector inputs while preserving fractional-value validation so generated connector tool schemas accept valid page sizes and limits. Generated-By: looper 0.5.4 (runner=fixer, agent=opencode) * fix: align live artifact refresh error codes Generated-By: looper 0.5.4 (runner=fixer, agent=opencode) * Fix live artifact connector refresh flow * Update live artifact design cards * Add beta badge to live artifact form * Remove live artifact tile model * Fix live artifact refresh sync * Fix live artifact MCP refresh durability Generated-By: looper 0.5.4 (runner=fixer, agent=opencode) * Fix live artifact refresh safety Enforce persisted refresh opt-out and connector auto-read gating before refresh sources execute. Generated-By: looper 0.5.5 (runner=fixer, agent=opencode) |
||
|
|
ab58b62b17 |
feat(craft): state-coverage module + opt-ins on dashboard, mobile-app, kanban-board (#502)
* feat(craft): add state-coverage rules + opt-ins on dashboard, mobile-app, kanban-board
State coverage is the most reliable AI-design failure: agents ship only the
populated state. This adds craft/state-coverage.md (108 lines, matches the
existing craft format) covering the five required states (loading, empty,
error, populated, edge), three form-specific states, ARIA/focus rules, and
loading-duration thresholds.
Sources are public: WCAG 2.2, NN/g, Material Design 3, Apple HIG, Baymard.
Three skills with stateful UI opt in via od.craft.requires:
- dashboard
- mobile-app
- kanban-board
Decks, ppt, image-poster and other static-output skills do not opt in.
Refs: see issue body for the broader proposal (state-coverage is module 1
of 5 behavioral craft modules).
* fix(craft): address review findings on state-coverage
Four P2 findings from #502 review addressed in one pass.
- Edge state Test matrix added under the five-states table (dashboard,
mobile, form, search, detail-view scenarios with concrete thresholds).
- Server-driven empty pattern added as trailing note in the empty-state
composition section.
- Retry discipline subsection added after error severity tiers
(immediate first retry, exponential 2s/4s/8s backoff, 3-retry floor,
Last-attempted timestamp).
- README enforcement-levels subsection added distinguishing auto-checked
P0 rules from guidance; partial-stateful skill clarification added
after the Files table.
No rewrites. ~30 lines added. File stays inside the 80-110-line craft
target.
* fix(craft): correct lint enforcement claim + remove duplicate threshold message
Two findings from @mrcfps review (Looper-generated against
|
||
|
|
76e6c7a9f6 |
feat: Critique Theater Phase 4 (persistence + transcript + orchestrator) (#481)
* docs(specs): add Critique Theater design spec for panel-tempered artifacts * docs(specs): add Critique Theater implementation plan * docs(specs): rename UI to Design Jury, add lane-density modes, ship-rule explainer, label sizing * feat(contracts): add CritiqueConfig schema and defaults * fix(contracts): apply Task 1.1 review (CRITIQUE_PROTOCOL_VERSION rename, descriptions, RoleWeights export) * feat(contracts): add PanelEvent discriminated union and isPanelEvent guard * fix(contracts): apply Task 1.2 review (exhaustive event-type list, runId guard, import order) * feat(contracts): add CritiqueSseEvent variants and panelEventToSse mapper * test(daemon): add v1 wire-protocol golden fixtures for Critique Theater parser * feat(daemon): add v1 streaming parser for Critique Theater wire protocol * chore(contracts): add .js extensions to relative imports for NodeNext consumers * fix(daemon): satisfy noUncheckedIndexedAccess in v1 parser regex match access * test(daemon): cover parser failure modes; fix unclosed-PANELIST swallow bug * fix(daemon,contracts): address PR #387 review - parser now clamps panelist + DIM scores against the run-declared scale captured from <CRITIQUE_RUN scale=...>, not a hardcoded 100 - PANELIST appearing before any <ROUND n=...> opens now throws MalformedBlockError rather than emitting events with NaN round - DIM_RE and MUST_FIX_RE hoisted to module scope and lastIndex reset per call so the parser hot path stops recompiling regex per artifact - overflow check after drain simplified to a plain buf.length > cap test (the prior compound condition was always true on the right side and obscured intent) - scoreThreshold <= scoreScale refine gains a 1e-9 epsilon so floating slack does not reject semantically valid configs - round-1 designer ARTIFACT guard gains a comment naming the spec invariant and the v2 relaxation path - 3 new regression tests cover the panelist-without-round, scale=10 clamp, and scale=20 plumbing cases * docs(specs): rationale for non-goals, failure-mode rate targets, Phase 10 matrix, Phase 14 doc layout * Merge branch 'main' into feat/critique-theater Resolves the contracts/index.ts conflict by keeping the .js extensions added by chore(contracts) |
||
|
|
bbdd4e84b5 |
chore: enforce test directory conventions (#496)
* 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. |
||
|
|
16693fdfa8 |
docs: add official Discord invite to README badges (#504)
Adds the official Discord community link (https://discord.gg/qhbcCH8Am4) as a badge in the badge row across all 11 localized READMEs so users have a clear, consistent entry point to the community. Co-authored-by: joey <joey@joeydeMacBook-Air.local> |
||
|
|
c2e3691130 |
docs: add Arabic (العربية) README translation (#458)
* docs: add Arabic README translation Adds README.ar.md — full Arabic translation of README.md, wrapped in a top-level <div dir="rtl"> for correct RTL rendering on GitHub. All URLs, file paths, code blocks, badges, and tables are preserved verbatim; prose and table cell text are translated to Modern Standard Arabic. Also wires up the language switcher in all nine sibling README files (en/de/fr/zh-CN/zh-TW/ko/ja-JP/ru/uk) so the previously-placeholder العربية entry now links to README.ar.md. The translation is an initial pass — native-Arabic-speaker review for phrasing/terminology is welcome. * docs(ar): preserve code fences verbatim and restore license attribution Address PR #458 review feedback (P2): 1. Revert translated prose inside fenced code blocks back to verbatim English, matching the source README.md: - Prompt-stack composition block - Architecture ASCII diagram (browser layer, daemon comments, bottom CLI row) - Quickstart bash comments - .od/ tree comments - Repository structure tree comments 2. Restore the License section's bundled-attribution sentence with links to skills/guizang-ppt/LICENSE (MIT, @op7418) and skills/html-ppt/LICENSE (MIT, @lewislulu); the previous version collapsed it to a generic 'see LICENSE' pointer. * docs(ar): translate Running the Project and MCP server sections Address PR #458 follow-up review (mrcfps): the Arabic README jumped from the .od/ first-run section straight to repository structure, missing the two sections added to README.md after this branch was forked: - ## Running the Project — web/localhost mode, fixed-port restarts, desktop/Electron commands, and the useful-commands table - ## Use Open Design from your coding agent — stdio MCP server setup, per-client install flow, daemon-must-be-running note, and the read-only security model Command blocks, table structure, and links are preserved verbatim from README.md per the same convention used elsewhere in the file. |
||
|
|
a3a0ae6ced |
fix(daemon): respect baseUrl path verbatim in OpenAI-compat proxy (#410)
* fix(daemon): respect baseUrl path verbatim in OpenAI-compat proxy `appendVersionedApiPath` previously force-injected `/v1` unless the supplied baseUrl ended with `/vN`. That broke any provider whose OpenAI-compatible surface lives under a sub-path: https://api.deepinfra.com/v1/openai → ".../v1/openai/v1/chat/completions" https://openrouter.ai/api/v1 → ".../api/v1/chat/completions" (worked, by luck of /vN suffix) Now the auto-`/v1` only fires when the user supplied no path at all, so DeepInfra, OpenRouter, and any other sub-path-mounted compat surface route to the right endpoint while the canonical `https://api.openai.com` / `https://api.anthropic.com` shortcuts still work. Adds a regression test table covering the matrix. * Account for Anthropic style URLs |
||
|
|
b5598572d8 |
fix(daemon): scope -32603 recovery to session/set_model request id (#492)
Address review feedback from lefarcen and mrcfps on PR #492: P1: Track setModelRequestId to scope the recovery block to the exact session/set_model request. This prevents duplicate prompt sends if session/prompt returns -32603 (which would otherwise match on expectedId + non-default model conditions). P1: Add promptRequestId === null guard so the recovery path only triggers before a prompt has been sent. P2: In detectAcpModels, only suppress -32603 on unexpected ids. Expected-id -32603 errors (initialize, session/new) are real probe failures and should reject immediately rather than causing a silent 15s timeout. P2: In attachAcpSession, expected-id -32603 errors that don't match setModelRequestId now call fail() instead of falling through. This prevents initialize/session/new/session/prompt failures from being silently swallowed. |
||
|
|
406a077ba7 |
docs(readme): point first-PR link to /contribute page (#494)
The `labels/good-first-issue` URL renders an empty list when no issues carry that label. GitHub's `/contribute` page auto-curates a mix of good-first-issue, help-wanted, and active items, so it stays useful for newcomers regardless of label coverage. Wording is unchanged across all 10 README locales. |
||
|
|
0ab98fed07 |
fix(daemon): correct Claude Code --add-dir capability detection (fix #430) (#440)
Probe 'claude -p --help' (subcommand help) instead of 'claude --help' (global help), because --add-dir and --include-partial-messages are subcommand-specific flags that do not appear in the global help output. Previously, successful capability probing would set caps.addDir = false because the flag was not found in global help, causing the daemon to never pass --add-dir to spawned Claude Code processes. This broke absolute-path reads for skill seeds and design-system specs, as Claude Code's sandbox policy blocks access to paths outside the project cwd unless explicitly allowed via --add-dir. The probing-failure / timeout path already worked correctly (empty caps object defaults to passing --add-dir). The failure manifested only when help probing succeeded and explicitly failed to locate the subcommand flags. Co-authored-by: bojiehuang <bojiehuang@bojiehuangdeMacBook-Pro.local> |
||
|
|
cc8add4f09 |
feat(daemon): add link code folder support for agent context (#455)
* feat(daemon): add link code folder support for agent context Users can now link local code directories to a project so the AI agent reads their source code via --add-dir when generating designs. The import menu's "Link code folder" item opens a native OS folder picker, and linked folders appear as removable chips below the chat input. - Add linkedDirs field to ProjectMetadata contract - Add POST /api/dialog/open-folder endpoint (osascript/zenity/PowerShell) - Add validateLinkedDirs with path safety checks (absolute, exists, blocklist) - Append linked dirs to extraAllowedDirs in startChatRun - Add system prompt hint listing linked code folders - Render linked folder chips in ChatComposer with add/remove - Add i18n strings for all 16 locales - Add 8 unit tests for validateLinkedDirs * fix: address PR review feedback - Add JSDoc type annotations to validateLinkedDirs for strict mode - Check path.isAbsolute before resolve to catch relative inputs - Allow linking when projectMetadata is undefined (default to prototype) - Remove redundant PATCH in ProjectView callback * fix: use inline TS annotations instead of JSDoc in linked-dirs.ts * fix(daemon): harden linked-dirs validation against security bypasses - Resolve symlinks with realpathSync.native before checking blocklist - Reject filesystem root (/) and drive roots as linked dirs - Canonicalize blocklist entries to handle macOS /etc -> /private/etc - Validate linkedDirs on project creation, not just PATCH - Re-validate persisted linkedDirs in startChatRun before use - Add tests for root, symlink-to-blocked-dir, and realpath resolution * fix: narrow union type before accessing .error in tests |
||
|
|
c219be622d |
docs(readme): refresh contributors wall (#490)
Co-authored-by: mrcfps <23410977+mrcfps@users.noreply.github.com> |
||
|
|
e9fd616a5a |
Update docs/assets/github-metrics.svg - [Skip GitHub Action] (#489)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
05623cd743 |
chore(scripts): seed daemon with pre-baked decks and web prototypes (#457)
* 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) |
||
|
|
3935aeb421 |
Optimize packaged mac artifact size (#424)
* optimize mac package payload reporting * optimize(pack): package standalone web runtime * optimize(pack): default to standalone web runtime * chore(release): bump beta base version * fix(pack): compress mac artifacts and report packaged version * fix(pack): preserve Next server fallback * fix(pack): clarify standalone startup failures * fix(release): gate beta platform builds * fix(web): bind standalone backend to parent * fix(pack): harden standalone and beta publishing |
||
|
|
e5ed4bbc76 |
fix(packaged): preserve *_API_KEY env vars for CLI agents (#404)
* Forward API key env vars to packaged sidecars ## Summary Forward provider credential environment variables from the packaged desktop app process to packaged sidecar children. ## Why The packaged app currently forwards only a small fixed environment allowlist to sidecars: - HOME - LANG - LC_ALL - LOGNAME - TMPDIR - USER This prevents CLI agents launched by the packaged daemon from seeing provider credentials such as `CODEX_API_KEY`, even when the desktop app itself was launched with that variable set. ## Fix This keeps the existing allowlist and additionally forwards environment variables ending in: - `_API_KEY` - `_TOKEN` I intentionally did not change PATH or Bun-related behavior in this PR, since CLI discovery already works. The issue here is specifically credential forwarding. ## Verification I verified the root cause locally by patching the packaged output: `@open-design/packaged/dist/index.mjs` After forwarding `CODEX_API_KEY`, the packaged desktop app was able to launch Codex successfully. ## Testing I did not run the full project build locally. I verified the behavior by patching the installed macOS app output and confirming that forwarding `CODEX_API_KEY` fixes the Codex launch failure. * Add includeProviderSecrets parameter to env functions Updated. Provider-secret forwarding is now daemon-only: *_API_KEY / *_TOKEN are included only when spawning the daemon sidecar, while the web/Next sidecar stays on the original minimal allowlist. |
||
|
|
9979afa3ae |
fix: cap htmlPreviewSlideState Map to prevent unbounded memory growth (#488)
The module-level Map cached slide state per project+file key but never evicted entries. In long-lived sessions with many projects, this grows without bound. Add a 64-entry cap with FIFO eviction. Co-authored-by: Test User <test@example.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
827e955be7 |
docs: add 'Running the Project' section to README (#468)
* docs: add 'Running the Project' section to README - Add comprehensive instructions for running in web and desktop modes - Clarify that ports are ephemeral by default, not fixed - Include table of useful commands with descriptions - Link to QUICKSTART.md for detailed troubleshooting - Position section after Quickstart, avoid duplicating existing content * docs(readme): address review feedback on Running the Project section - Fix foreground mode comment (logs written to files, not streamed) - Add restart alternative for switching ports in existing session - Correct table descriptions for logs/check commands - Move section after First-run state to keep Quickstart intact Addresses review comments from @lefarcen and @mrcfps |
||
|
|
ec7dafc007 |
feat(daemon): add Kilo CLI (ACP) (#480)
* docs(readme): refresh contributors wall * docs(readme): refresh contributors wall * feat: kilo cli * fix: use default model option for kilo * chore: add agent_diff id unique test * chore: add deepseek to docs |
||
|
|
6380c48a48 | Update Codex sandbox invocation (#477) | ||
|
|
df2e8adba0 |
docs: add Brazilian Portuguese (pt-BR) translations (#460)
* docs: add Brazilian Portuguese (pt-BR) translations Translate README, CONTRIBUTING, QUICKSTART, and the e2e/cases, e2e/reports, skills/html-ppt, skills/guizang-ppt READMEs into pt-BR. Add the pt-BR entry to the language switcher in every existing locale variant (en, de, fr, ko, ja-JP, ru, uk, zh-CN, zh-TW for README; en, de, fr, ja-JP, zh-CN for CONTRIBUTING; en, de, fr, ja-JP for QUICKSTART) so readers in any language can jump to the Portuguese version. Code blocks, file paths, identifiers, license attribution links and brand names are kept verbatim with the source. * docs(pt-BR): use repo-relative links in e2e READMEs Replace author-local absolute paths (/Users/mac/...) with repo-relative links so the translated docs navigate correctly on GitHub and other checkouts. * docs(pt-BR): fix README badge anchor and skill reference link - Update Agents badge href to the Portuguese fragment (#agentes-de-código-suportados) so the badge jumps to the translated heading. - Restore the [`SKILL.md`][skill] reference-link syntax in the comparison table; the opening bracket was lost in translation, breaking the row. |
||
|
|
de62baa0e8 |
fix(web): aspect ratio cards no longer overflow into siblings (#476)
The 380px sidebar gives the 3-column aspect grid only ~92px per cell. The flex-row card layout reserved 34px for the glyph plus 7px gap, leaving ~31px for the label — but "Landscape"/"Portrait" at 13px / weight 650 are ~75px wide. Without `min-width: 0` on the flex/grid items, the strong text refused to shrink and overflowed, so each card's label visually covered the next card's glyph. Switch the aspect cards to a column layout (glyph above, label + ratio below) so the label has the full card width. Add the missing `min-width: 0` on `.newproj-option-card` and `.aspect-copy` as a defense against future long-text regressions, and rebalance glyph dimensions and font sizes to match the tighter cards. Closes #242 |
||
|
|
2473ab9567 |
fix(web): add copy buttons for FileViewer code blocks (#471)
* fix(web): add copy buttons for FileViewer code blocks * fix(web): harden FileViewer markdown copy controls * fix(web): restore focus after clipboard fallback * test(e2e): restore execCommand after markdown copy tests |
||
|
|
a4fb90a9f3 |
fix(design-files): clear selection on project switch (#465)
* fix(design-files): clear selection on project switch to prevent cross-project leak
When switching from project A to project B, filenames present in both
projects (e.g. index.html) would survive the intersection-prune and
remain selected, causing handleBatchDownload() to post against the
wrong projectId. Now selection is fully cleared on projectId change.
* fix(design-files): use key-based remount to prevent cross-project selection leak
Replace the useEffect projectId clearing with a key={projectId} on
DesignFilesPanel. useEffect runs after render, leaving a window where
stale selections from project A could be used against project B. The
key tells React to unmount and remount the component synchronously on
project switch — no async gap.
|
||
|
|
b4e69ac61b | fix(copilot): copilot prompt processing with correct command format (#466) | ||
|
|
661465527b |
feat(daemon): add DeepSeek TUI as a code agent adapter (#439)
* feat(daemon): add DeepSeek TUI as a code agent adapter
Register `deepseek` (with `deepseek-tui` cargo-only fallback) in
AGENT_DEFS via `deepseek exec --auto [--model X] <prompt>` and plain-text
streaming. Ships `deepseek-v4-pro` / `deepseek-v4-flash` as fallback
model hints; users can paste any other id (incl. NIM / Fireworks /
SGLang routes) via the custom-model input.
Web UI gets a DeepSeek-blue gradient icon, label/alias mapping, and
docs/agent-adapters.md §5.9 documents the auth state, prompt-as-argv
Windows size limit, and the upstream gap that prevents stdin delivery
today (clap declares `prompt: String` as a required positional).
Adds .deepseek/ to .gitignore alongside the other per-agent runtime
data dirs so first-launch trust files don't leak into git.
* fix(daemon): drop unsupported deepseek-tui fallback bin
The `deepseek` dispatcher owns `exec` / `--auto`; `deepseek-tui` is the
runtime companion it invokes. Listing `deepseek-tui` in fallbackBins
advertised availability for a host that only had the TUI binary, but
buildArgs still emitted `<resolved> exec --auto <prompt>` — which
deepseek-tui itself doesn't accept, so the first /api/chat run would
fail. Upstream documents both binaries as required (npm and cargo paths
install them together), so the fallback didn't correspond to a supported
install. Pin the absence in the agents test and update docs §5.9 + the
adapter table to match.
Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code)
* fix(daemon): pre-flight DeepSeek TUI prompts against argv byte budget
DeepSeek's exec mode requires the prompt as a positional argv arg (no
`-` stdin sentinel upstream), so a fully composed OD prompt — system
text + history + skills + design-system content + the user message —
can blow Windows' ~32 KB CreateProcess limit (or Linux MAX_ARG_STRLEN
on extreme edges) and surface as a generic spawn failure instead of
a DeepSeek-specific, user-actionable message. The adapter now declares
`maxPromptArgBytes = 30_000` (leaves ~2.7 KB argv headroom for `exec
--auto --model <id>` and Windows quoting), and the /api/chat spawn
path checks the composed prompt against that budget before calling
`spawn`. Oversized prompts fail fast with `AGENT_PROMPT_TOO_LARGE`
and guidance to reduce skills/design context or pick an adapter with
stdin support.
Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code)
* test(daemon): pin DeepSeek argv-budget guard with regression tests
The previous spawn-path guard inlined the byte-budget check in the
chat handler, so the only safety net for the DeepSeek argv-only
prompt-delivery shape was a static "the field exists" assertion —
nothing actually exercised the AGENT_PROMPT_TOO_LARGE path or the
short-prompt happy path. Extract the check into a pure
`checkPromptArgvBudget(def, composed)` helper in agents.ts, call it
from /api/chat before bin resolution (so the guard is order-
independent and fires regardless of whether the adapter binary is
on PATH in CI), and add a regression test that exercises both the
oversized-prompt branch (over the conservative under-Windows-
CreateProcess budget) and the short-prompt branch, plus a UTF-8
byte-vs-codepoint case and a stdin-adapter no-op case so the guard
can't silently regress or leak onto adapters that ship the prompt
over stdin.
Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code)
* fix(daemon): pre-flight DeepSeek prompts against Windows .cmd-shim quoting
The first-pass argv-byte guard only inspects the raw composed prompt, so
on Windows an npm-installed `deepseek` resolves to a `.cmd` shim and the
spawn path then wraps the call in `cmd.exe /d /s /c "<inner>"` with
every embedded `"` doubled by `quoteWindowsCommandArg`. A quote-heavy
prompt (code blocks, JSON-shaped skill seeds) under the 30,000-byte
budget can therefore still expand past CreateProcess's 32_767-char
`lpCommandLine` cap and surface as a generic spawn ENAMETOOLONG instead
of the DeepSeek-named, actionable `AGENT_PROMPT_TOO_LARGE` the budget
guard was meant to provide. Add a second pure helper
`checkWindowsCmdShimCommandLineBudget(def, resolvedBin, args)` that
mirrors the platform layer's per-arg quoting and recomputes the would-be
command line length whenever the resolved binary is a `.cmd` / `.bat`
shim, and call it from `/api/chat` after `buildArgs` / `resolveAgentBin`
so the same SSE error fires before `spawn`. Pin the new path with a
quote-heavy regression (prompt is under the byte budget but doubles
past the kernel cap) plus no-op tests for non-`.cmd` resolutions, null
bin, and stdin-only adapters so the guard can't drift back.
Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code)
* fix(daemon): extend DeepSeek argv guard to direct .exe Windows installs
The cmd-shim guard added in
|
||
|
|
bc04d61903 |
feat(design-files): add batch ZIP download with multi-select (#405)
* feat(design-files): add batch ZIP download with multi-select Add checkbox-based multi-select to the Design Files panel and a new POST /api/projects/:id/archive/batch endpoint that zips selected files using the project name as the archive filename. * fix(i18n): add missing batch-download keys to uk locale The upstream main branch has a uk.ts locale that didn't exist in the fork. Without these keys the web typecheck fails against the full locale set. * fix(design-files): harden batch archive and prune stale selections - Use lstat to reject symlinks, dotfiles, and .artifact.json sidecars in buildBatchArchive (mirror listFiles/collectFiles allowlist) - Reject invalid names explicitly instead of silently skipping - Prune stale filenames from selected set on files/projectId change * fix(daemon): tighten batch archive allowlist with segment-level checks - Check every path segment for hidden directories, not just basename - Walk intermediate directories with lstat to reject symlinks at any level - Fail-fast on any ineligible file instead of silently skipping |
||
|
|
da2b007a43 |
feat(daemon): add DeepSeek TUI as a code agent adapter (#439)
* feat(daemon): add DeepSeek TUI as a code agent adapter
Register `deepseek` (with `deepseek-tui` cargo-only fallback) in
AGENT_DEFS via `deepseek exec --auto [--model X] <prompt>` and plain-text
streaming. Ships `deepseek-v4-pro` / `deepseek-v4-flash` as fallback
model hints; users can paste any other id (incl. NIM / Fireworks /
SGLang routes) via the custom-model input.
Web UI gets a DeepSeek-blue gradient icon, label/alias mapping, and
docs/agent-adapters.md §5.9 documents the auth state, prompt-as-argv
Windows size limit, and the upstream gap that prevents stdin delivery
today (clap declares `prompt: String` as a required positional).
Adds .deepseek/ to .gitignore alongside the other per-agent runtime
data dirs so first-launch trust files don't leak into git.
* fix(daemon): drop unsupported deepseek-tui fallback bin
The `deepseek` dispatcher owns `exec` / `--auto`; `deepseek-tui` is the
runtime companion it invokes. Listing `deepseek-tui` in fallbackBins
advertised availability for a host that only had the TUI binary, but
buildArgs still emitted `<resolved> exec --auto <prompt>` — which
deepseek-tui itself doesn't accept, so the first /api/chat run would
fail. Upstream documents both binaries as required (npm and cargo paths
install them together), so the fallback didn't correspond to a supported
install. Pin the absence in the agents test and update docs §5.9 + the
adapter table to match.
Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code)
* fix(daemon): pre-flight DeepSeek TUI prompts against argv byte budget
DeepSeek's exec mode requires the prompt as a positional argv arg (no
`-` stdin sentinel upstream), so a fully composed OD prompt — system
text + history + skills + design-system content + the user message —
can blow Windows' ~32 KB CreateProcess limit (or Linux MAX_ARG_STRLEN
on extreme edges) and surface as a generic spawn failure instead of
a DeepSeek-specific, user-actionable message. The adapter now declares
`maxPromptArgBytes = 30_000` (leaves ~2.7 KB argv headroom for `exec
--auto --model <id>` and Windows quoting), and the /api/chat spawn
path checks the composed prompt against that budget before calling
`spawn`. Oversized prompts fail fast with `AGENT_PROMPT_TOO_LARGE`
and guidance to reduce skills/design context or pick an adapter with
stdin support.
Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code)
* test(daemon): pin DeepSeek argv-budget guard with regression tests
The previous spawn-path guard inlined the byte-budget check in the
chat handler, so the only safety net for the DeepSeek argv-only
prompt-delivery shape was a static "the field exists" assertion —
nothing actually exercised the AGENT_PROMPT_TOO_LARGE path or the
short-prompt happy path. Extract the check into a pure
`checkPromptArgvBudget(def, composed)` helper in agents.ts, call it
from /api/chat before bin resolution (so the guard is order-
independent and fires regardless of whether the adapter binary is
on PATH in CI), and add a regression test that exercises both the
oversized-prompt branch (over the conservative under-Windows-
CreateProcess budget) and the short-prompt branch, plus a UTF-8
byte-vs-codepoint case and a stdin-adapter no-op case so the guard
can't silently regress or leak onto adapters that ship the prompt
over stdin.
Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code)
* fix(daemon): pre-flight DeepSeek prompts against Windows .cmd-shim quoting
The first-pass argv-byte guard only inspects the raw composed prompt, so
on Windows an npm-installed `deepseek` resolves to a `.cmd` shim and the
spawn path then wraps the call in `cmd.exe /d /s /c "<inner>"` with
every embedded `"` doubled by `quoteWindowsCommandArg`. A quote-heavy
prompt (code blocks, JSON-shaped skill seeds) under the 30,000-byte
budget can therefore still expand past CreateProcess's 32_767-char
`lpCommandLine` cap and surface as a generic spawn ENAMETOOLONG instead
of the DeepSeek-named, actionable `AGENT_PROMPT_TOO_LARGE` the budget
guard was meant to provide. Add a second pure helper
`checkWindowsCmdShimCommandLineBudget(def, resolvedBin, args)` that
mirrors the platform layer's per-arg quoting and recomputes the would-be
command line length whenever the resolved binary is a `.cmd` / `.bat`
shim, and call it from `/api/chat` after `buildArgs` / `resolveAgentBin`
so the same SSE error fires before `spawn`. Pin the new path with a
quote-heavy regression (prompt is under the byte budget but doubles
past the kernel cap) plus no-op tests for non-`.cmd` resolutions, null
bin, and stdin-only adapters so the guard can't drift back.
Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code)
* fix(daemon): extend DeepSeek argv guard to direct .exe Windows installs
The cmd-shim guard added in
|
||
|
|
59e1e01233 |
fix(web): prevent vertical scrollbar on artifact preview frame (#453)
* fix(web): prevent vertical scrollbar on artifact preview frame The preview uses transform: scale() for zoom, which doesn't affect layout size. When previewScale < 1, the scale wrapper's layout size (100/scale%) overflows the parent, triggering overflow: auto on .viewer-body. Add overflow: hidden on .comment-preview-layer to clip the layout overflow before it propagates. * fix(web): use iframe-only clip wrapper instead of layer-level overflow Move overflow: hidden from .comment-preview-layer to a dedicated .comment-frame-clip wrapper that only wraps the iframe. This prevents the layout overflow from propagating to .viewer-body while keeping comment overlays and popovers unclipped. |
||
|
|
33c3b94b42 |
feat(daemon): add od mcp - expose Open Design as an MCP server (#399)
* feat(daemon): add `od mcp` subcommand for stdio MCP server
Lets a coding agent in a different repo (Claude Code, Cursor, Zed)
pull files from a locally-running OD project over the Model Context
Protocol — no export/import zip dance.
The MCP server is a thin stdio process that proxies read-only tool
calls to the daemon's existing HTTP API; no daemon-side changes
required. Exposes 8 tools:
list_projects, get_project,
list_files, get_file,
list_skills, get_skill,
list_design_systems, get_design_system
Wired exactly like `od media`: a hoisted flag set, a SUBCOMMAND_MAP
entry, a thin handler that resolves OD_DAEMON_URL and hands off to
src/mcp.ts. Tool dispatch is a switch over the tool name; each branch
fetches the matching daemon route and surfaces the response as MCP
text content. Binary mimes return a clear error pending phase-2
support.
Lifecycle gotcha worth flagging: Server.connect(transport) only
*starts* the stdio reader; the promise resolves immediately. Without
holding the function awaiting until transport/stdin close, cli.ts's
top-level process.exit(0) kills the server before the first request
arrives. The fix in src/mcp.ts holds until onclose / stdin EOF.
Wire-up example for a consuming repo:
{
"mcpServers": {
"open-design": {
"command": "od",
"args": ["mcp"],
"env": { "OD_DAEMON_URL": "http://127.0.0.1:7456" }
}
}
}
New dep: @modelcontextprotocol/sdk (MIT, official Anthropic SDK).
* feat(daemon): add MCP server instructions for zero-shot LLM context
Hand the consuming LLM a system-prompt-style overview of the OD
workflow so it picks the right tool without prompt-engineering on
the user's side. Mentions get_artifact and project-name resolution
ahead of their actual implementation; both ship in the same batch.
* feat(daemon): resolve MCP project args by UUID, name, or substring
Lets a consuming agent say `project: "recaptr"` instead of pasting a
UUID. Match order: exact id → exact name (case-insensitive) →
slug-normalized name (strips trailing " (N)", normalizes whitespace) →
substring (errors if multiple). UUID inputs short-circuit and never
hit the daemon.
* feat(daemon): surface entryFile and kind on MCP get_project response
Promote metadata.entryFile and metadata.kind to top-level fields so
consumers (including get_artifact in this branch) can find the entry
without digging through nested metadata blobs.
* feat(daemon): add MCP get_artifact tool for bundle retrieval
A design rarely lives in a single file. get_artifact pulls the entry
HTML/JSX plus every sibling it references (tokens CSS, JSX modules,
imported components) in one call, so a consuming agent doesn't need
to parse HTML and round-trip per file.
Three modes:
auto (default): BFS over relative <script src>, <link href>,
<img src>, <source/video src>, JSX import/from, CSS url(), with
depth cap 3 and a visited set. CDN, data:, mailto:, anchors, and
paths containing .. are skipped.
all: every textual file in the project (mirror of /archive
minus binaries).
shallow: just the entry file (same as get_file).
Output is a structured JSON blob with name/mime/size/content per
file and the project's manifest metadata at the top.
* feat(daemon): add /api/projects/:id/search route + MCP search_files
Server-side substring search across textual project files. Returns
file, 1-indexed line, and snippet, capped at 1000 matches. Exposed
through the MCP layer as search_files(project, query, pattern?, max?).
Treats the query as a literal substring (regex chars escaped) to
avoid catastrophic-backtracking attacks from LLM-supplied input.
Honors the project dir's existing path-safety guards via listFiles.
* feat(daemon): add since= filter to /files route + MCP list_files arg
Lets a consumer poll for "what's changed since I last looked" without
re-walking every file. Daemon-side: parse since= as ms, filter
listFiles output by mtime. MCP-side: forward as URL query.
* feat(daemon): expose skills and design systems as MCP resources
Catalog reads are stable reference material — they fit MCP's
resources surface (LLM-passive) better than tools (LLM-active).
Skills and design systems each become resources at
od://skills/<id>/SKILL.md and od://design-systems/<id>/DESIGN.md;
existing list_skills / get_skill / list_design_systems /
get_design_system tools remain as fallbacks for clients that don't
handle resources cleanly.
* fix(daemon): tighten MCP correctness in get_artifact and resources
Several silent-failure paths and minor footguns the first pass missed:
- get_artifact auto: the entry's own fetch now raises a clear
error instead of returning files: []. Previously a typo in
`entry:` looked like an empty project.
- get_artifact: invalid `include` value returns a clear error
listing the valid modes instead of silently behaving as auto.
- get_artifact all: includes binary files as metadata stubs to
match auto's behavior. Both modes are now strict supersets of
shallow.
- extractRelativeRefs: gate JS-only patterns (import/from/require/
dynamic-import) by file mime/extension so prose in markdown or
HTML doesn't generate spurious 404 round-trips on words like
"imported from 'X'".
- extractRelativeRefs: cover <iframe>, <audio>, srcset, and
CSS @import — common in real OD output.
- resources/list descriptions are collapsed to a single line
(newlines + repeated whitespace -> one space) so MCP UIs that
don't normalize whitespace render cleanly.
- fetchProjectFile: 0-byte binary files no longer report size: null
due to falsy short-circuit on Number(content-length).
* perf(daemon): cache MCP project list for 5s in resolveProjectId
A typical agent session calls list_files/get_file/get_artifact several
times in a row, each with a project name argument. Each previously
re-fetched /api/projects. Cache the list in module scope with a 5s
TTL so back-to-back lookups are local; renames in the OD UI still
propagate within a few seconds.
* feat(daemon): MCP UX polish — tool order, annotations, get_artifact maxBytes
Three changes well-behaved MCP clients pick up automatically:
- Tool ordering. list_projects + get_artifact are now first; LLMs
that weight earlier entries surface the bundle path before
per-file fetching. Catalog tools (list_skills, get_skill,
list_design_systems, get_design_system) sit at the bottom; they
are also exposed as MCP resources.
- readOnlyHint / idempotentHint / openWorldHint annotations on
every tool so clients can skip confirmation prompts on safe
tools and let the LLM know re-running is fine. Per-tool `title`
annotations give clients a friendlier display name than the
snake_case tool id.
- get_artifact gains a `maxBytes` arg (default 1.5MB). Once the
accumulated textual content crosses the cap, remaining files
are dropped and `truncated: true` is set on the bundle so the
consumer knows to use list_files / get_file for the rest.
* feat(daemon): expose user's active OD project/file via MCP
The "what file are you on?" round-trip the agent had to do every
session is now answered automatically. Three pieces:
- Daemon: in-memory active-context slot with 5-minute TTL.
POST /api/active sets {projectId, fileName}; GET /api/active
returns the current value enriched with projectName, or
{active:false} when the slot is empty/stale. Cleared on
daemon restart.
- Web: a small useEffect in App.tsx posts the active project +
file to the daemon on every route change. Best-effort fire-
and-forget; a missing daemon doesn't surface an error.
- MCP: get_active_context tool (no args) and a matching MCP
resource at od://focus/active. The tool is listed second,
right after list_projects, so an LLM picks it up before
asking for ids. Server instructions tell the model to call
it FIRST when the user says "this file" / "the design I have
open" / "what I'm looking at."
End to end: user opens a project in OD, agent in another repo
calls get_active_context() → gets {projectName: "recaptr",
fileName: "recaptr-onboarding-4.html"}, then immediately calls
get_artifact(project: "recaptr") with no further user input.
* feat(daemon): make MCP project arg optional, fall back to active OD context
get_artifact, get_project, get_file, search_files, and list_files now
accept project as optional. When omitted, the MCP resolves project
from /api/active so an agent in another repo can call
search_files({ query: "Polaroid" })
without first asking the user "which project?". get_file and
get_artifact also default their path/entry to the active file, so
get_file({}) returns whatever the user is currently looking at.
The implicit path stamps `usedActiveContext` on JSON responses (or a
separate `[od:active-context …]` content block on get_file) so the
agent can see exactly which project/file got chosen. Explicit
project args pass through with zero added overhead.
Cuts the common case from two MCP round trips
(get_active_context → search_files) to one. Server instructions and
get_active_context's own description are updated to point at the
new default.
* fix(daemon): require same-origin for /api/active POST and GET
The active-context endpoint was added without isLocalSameOrigin
guard. Since the daemon binds 0.0.0.0 by default, a LAN peer could
GET it to learn what file the user has open, or POST it to redirect
the MCP fallback to a project of their choice. Same-origin only is
the right scope: the web app proxies its requests through Next.js
on the daemon port, and the MCP runs over loopback in-process, so
both legitimate callers pass.
Pattern matches the existing /api/app-config etc. guards.
* feat(daemon): add /api/mcp/install-info for cross-platform install snippets
The Settings -> MCP server panel needs absolute paths to node and
the daemon's built cli.js so it can render snippets that work on a
fresh source clone (where `od` is not on PATH) and dodge the
/usr/bin/od octal-dump tool that ships on macOS/Linux and would
otherwise shadow ours.
Endpoint returns:
- command: process.execPath (the node binary running the daemon)
- args: [<absolute path to dist/cli.js>, "mcp"]
- daemonUrl: http://127.0.0.1:<port>
- platform: process.platform (so the panel can localize ~/.cursor
vs %USERPROFILE%\.cursor and Cmd vs Ctrl shortcuts)
- cliExists / nodeExists: existsSync checks on both binaries
- buildHint: human-readable build/reinstall instructions when
either path is missing
isLocalSameOrigin guard same as /api/active. Cached for 5s because
the panel may re-fetch on every open and the paths cannot change
without a daemon restart.
Test file covers the happy path, cross-origin rejection, two
allowed-Origin variants, and the cache by counting fresh resolves
across rapid calls. 5/5 pass.
* refactor(daemon): tighten MCP surface, trim descriptions, polish copy
Three intertwined cleanups that all live in mcp.ts + cli.ts:
1. Drop catalog tools from MCP. list_skills / get_skill /
list_design_systems / get_design_system are removed. The audience
is a coding agent in a separate repo consuming Open Design's
output; it cannot run skills (those are recipes Open Design uses
to generate) and design-system DESIGN.md is reference material
that already ships as an MCP resource. Keeping the catalog as
tools cost ~350 token-overhead per turn for capabilities the
agent could not act on. Tool count: 11 -> 7.
2. Trim tool descriptions. The active-context fallback explanation
was repeated in 5 separate tool descriptions; hoisted into
PROJECT_ARG and explained once in the server `instructions`
block instead. Saves ~150-200 tokens per tools/list response.
3. User-facing branding pass. Tool titles, tool descriptions,
resource names, error messages, comments, and `od mcp --help`
now consistently use "Open Design" rather than "OD". Internal
abbreviation `OD` is retained only inside the server
instructions block where it is introduced inline as "Open Design
(OD)" for compactness across multi-paragraph guidance.
Em dashes replaced with hyphens throughout, per project style.
* feat(web): add MCP server install panel in Settings
New "MCP server" section in the Settings dialog, surfacing
copy-paste install snippets for the major MCP-compatible coding
agents (Claude Code, Cursor, VS Code, Antigravity, Zed, Windsurf).
Highlights:
- In-brand custom dropdown (reuses the existing .ds-picker
pattern from the design-system / prompt-template pickers, click
outside / Escape to close, chevron animates) instead of a
native <select>.
- Per-client snippet that uses absolute paths to node + cli.js
fetched from /api/mcp/install-info on mount, so it works even
when `od` is not on PATH.
- Cursor gets a one-click "Install in Cursor" deeplink
(cursor://anysphere.cursor-deeplink/mcp/install) that pops an
approval dialog and writes the config for the user. UTF-8-safe
base64 so paths with accented characters do not throw.
- Per-OS path hints (~/.cursor on POSIX, %USERPROFILE%\.cursor
on Windows) and keyboard shortcuts (Cmd vs Ctrl).
- Build-required warning card when cli.js or the node binary
does not exist on disk; deeplink button disables in that state.
- Prominent "restart your client to pick up the new server"
callout below the snippet, with per-client guidance.
- Capability list ("what your agent can do") instead of a tool-
name dump, so non-developer designers can also tell what is
possible without reading MCP docs.
README adds a short "Use Open Design from your coding agent"
section that points at the panel and summarizes the per-client
flow (one-click for Cursor, JSON merge elsewhere). Read-only by
design; the daemon must be running locally.
* docs(readme): align MCP server section with the Settings panel
The "Use Open Design from your coding agent" section had drifted
from what the panel actually emits and lists.
- Add Antigravity to the supported-client list (previously missing).
- Drop the "(GitHub Copilot)" parenthetical from VS Code so the
label matches the panel.
- Fix the Claude Code line: we no longer emit a single
`claude mcp add ...` shell command. The snippet is JSON; the
panel additionally suggests `claude mcp add-json` as the safer
way to apply it instead of hand-editing ~/.claude.json.
- Swap the "find the Polaroid section" example for two more
universal phrases ("build this in my app", "match these
styles") that match what the panel surfaces.
- Add a one-line "restart or reload your client after install"
note - this was prominent in the panel and absent from the
README.
- Trim the /usr/bin/od octal-dump aside; it was technical detail
that did not earn its space at the README intro level.
* feat(web): add Codex CLI to the MCP server install panel
Codex is a first-class supported coding agent (listed alongside
Claude Code, Cursor, etc. in the README's PATH-detected agent
table) but the install panel was missing it.
Codex stores MCP server config at ~/.codex/config.toml (TOML, not
JSON) under an `[mcp_servers.<name>]` table, and the same file is
shared between the Codex CLI and the Codex IDE extension - so one
install covers both. Added a 7th client entry that emits the right
TOML snippet, expanded the snippet-lang union to include 'toml'
(behaves like 'json' for whitespace handling, just a different
syntax-highlight hint).
For our minimal payload (just command + args), JSON.stringify
happens to produce valid TOML literal values since TOML basic
strings use the same double-quote escape rules as JSON, and TOML
inline arrays match JSON array syntax. No new TOML serializer
needed.
README updated to list Codex among the supported clients.
Schema verified against https://developers.openai.com/codex/mcp.
* fix(daemon): accept any loopback origin in same-origin guard
The previous port-pinned check required the request's Origin to match
either the daemon's own port or OD_WEB_PORT. tools-dev does not pass
OD_WEB_PORT to the daemon process, so any browser POST to /api/active
proxied through the dev web (port 17573 etc.) was rejected with 403,
and get_active_context always returned {active: false}.
Relax to a loopback-prefix match: any http://127.0.0.1:*,
http://localhost:*, or http://[::1]:* origin passes regardless of
port. Cross-origin (https://evil.com) is still rejected. The
trade-off is that another local web app on a different loopback port
could now CSRF the daemon; same-origin checks are inherently a CSRF
defense, not a network ACL.
* fix(web): make Claude Code MCP snippet a real copyable one-liner
claude mcp add-json open-design '<json>' takes only the inner
server-config object, not the full {"mcpServers": ...} wrapper, and
rejected the wrapped shape with "Invalid configuration: : Invalid
input". Pass only the inner config, and inline the JSON into the
command itself so the snippet is a real one-liner the user can copy
and paste, no template substitution.
* test(daemon): drop loopback-prefix assertions superseded by upstream origin policy
The two proxy-flow allow tests were added in
|
||
|
|
02d24c4fde |
fix(web): language option button height truncation in settings (#447)
* fix(web): remove min-height constraint on language option buttons The hardcoded min-height: 40px on .settings-language-option caused content to overflow when locale labels wrap to two lines. Remove the constraint so buttons size naturally, and update the menu max-height budget from 360px (9×40px) to 406px (7×58px) to match. * fix(web): bump menu max-height to 428px to account for chrome The previous 406px budget didn't account for menu padding (4px), row gaps (2px × 6), and border (1px × 2). Bump to 428px so all 7 visible items fit without clipping. |
||
|
|
cfd359e05a |
[codex] Fix Gemini CLI trust handling (#352)
* Fix Gemini CLI trust handling * Preserve agent spawn env filtering |
||
|
|
e9cc1fbda8 |
fix(web): prevent vertical scrollbar on ws-tabs-bar (#448)
Setting overflow-x: auto implicitly sets overflow-y to auto per CSS spec. With a fixed height of 44px, this causes a vertical scrollbar when content overflows by even 1px. Explicitly set overflow-y: hidden. |
||
|
|
d637297313 |
feat(preview): live-reload iframes when project files change on disk (#409)
* feat(preview): live-reload iframes when project files change on disk Add a chokidar-backed file watcher per active project on the daemon, surface changes via an SSE endpoint at /api/projects/:id/events, and consume them in the web app to bump the file list. The new mtime then propagates to the FileViewer iframe through PR #384's ?v=${mtime} cache-bust, reloading the preview automatically — no manual refresh click. Daemon: - New apps/daemon/src/project-watchers.ts: refcounted per-project watcher registry. First subscribe lazy-creates a chokidar watcher; last unsubscribe closes it. Ignores .git, node_modules, .od, debug, .DS_Store. Returns a ready promise so callers can await initial scan. - New endpoint GET /api/projects/:id/events using the existing createSseResponse helper. Sends one ready event after chokidar binds, then one file-changed event per add/change/unlink. - Adds chokidar ^5.0.0 dependency. Web: - New apps/web/src/providers/project-events.ts exposing createProjectEventsConnection (pure, testable) and useProjectFileEvents hook. EventSource with exponential backoff (1s -> 30s cap), reset on a successful ready event. - ProjectView.tsx subscribes when daemonLive && project.id, and on each event bumps the existing filesRefresh signal — no FileViewer changes needed because PR #384 already URL-loads with mtime cache-bust. Tests: - 6 new daemon unit + integration tests (refcounting, real chokidar add/change/unlink, ignore patterns). - 8 new web hook unit tests (URL encoding, payload parsing, malformed payload tolerance, exponential backoff, backoff reset on ready, close cancels reconnects, no-op when EventSource missing). Closes #370 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(preview): test ignore patterns relative to watch root The ignore predicate matched against absolute paths, so segments in the watch root's ancestors (e.g. the daemon's own .od/ runtime dir, which contains every project) silenced every event. In production this meant zero file-changed events ever fired — every file inside a project sat under .od/projects/<id>/, and .od matched the ignore. Tests passed because mkdtemp puts test roots in /tmp/od-watchers-XXX/, which has no .od ancestor. Fix: compute the path relative to the watch root, then test segments. Add a regression test that reproduces the production layout (.od/projects/<id>/...) and asserts events still fire. Also folds in a small consolidation of the SSE route handler from the prior commit on this branch (single route, surfaces sub.ready before emitting `ready`, propagates err.message in the error path). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(project-view): only auto-open files that exist in the project Agent Write/Edit tool results unconditionally called requestOpenFile on the basename of the edited path, which created permanent placeholder tabs ("Open a file from Design Files.") whenever the agent edited a file outside the project's working directory (e.g. an upstream repo source file). Add decideAutoOpenAfterWrite() — a pure helper that gates the auto-open on the file actually appearing in the refreshed project file list. Same nextFiles-from-then() pattern already used at ProjectView.tsx:968. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(preview): chokidar resilience + auto-open path-suffix matching Address PR #409 review feedback in one bundle: - chokidar error listener (codex P1): FSWatcher is an EventEmitter; without an error handler, transient FS faults (ENOSPC, EPERM, EMFILE) surfaced as unhandled exceptions and could crash the daemon. Watcher now logs in dev mode and continues; refcount cleanup unaffected. - followSymlinks: false (mrcfps): keep the watcher's resource boundary aligned with the project boundary so a symlink inside the project cannot traverse externally. Real-chokidar regression test included. - decideAutoOpenAfterWrite path-suffix matching (mrcfps): pass the agent's full file_path through (not just the basename); resolve via path-suffix match against project file paths, with single-unambiguous basename fallback only when filePath has no slash. Fixes the same-basename collision case where an external Write to App.jsx could open a project's prototype/App.jsx. - Dev-mode logs (lefarcen P3): warn when the broadcast subscriber loop or the SSE payload parser swallows an error, so subscriber bugs and payload-shape regressions don't go silent during testing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: DevForgeAI CI/CD Engineer <devforge-ai@development.ai> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
47eeaf445d |
feat: Critique Theater foundation (contracts + parser, Phases 0-2) (#387)
* docs(specs): add Critique Theater design spec for panel-tempered artifacts * docs(specs): add Critique Theater implementation plan * docs(specs): rename UI to Design Jury, add lane-density modes, ship-rule explainer, label sizing * feat(contracts): add CritiqueConfig schema and defaults * fix(contracts): apply Task 1.1 review (CRITIQUE_PROTOCOL_VERSION rename, descriptions, RoleWeights export) * feat(contracts): add PanelEvent discriminated union and isPanelEvent guard * fix(contracts): apply Task 1.2 review (exhaustive event-type list, runId guard, import order) * feat(contracts): add CritiqueSseEvent variants and panelEventToSse mapper * test(daemon): add v1 wire-protocol golden fixtures for Critique Theater parser * feat(daemon): add v1 streaming parser for Critique Theater wire protocol * chore(contracts): add .js extensions to relative imports for NodeNext consumers * fix(daemon): satisfy noUncheckedIndexedAccess in v1 parser regex match access * test(daemon): cover parser failure modes; fix unclosed-PANELIST swallow bug * fix(daemon,contracts): address PR #387 review - parser now clamps panelist + DIM scores against the run-declared scale captured from <CRITIQUE_RUN scale=...>, not a hardcoded 100 - PANELIST appearing before any <ROUND n=...> opens now throws MalformedBlockError rather than emitting events with NaN round - DIM_RE and MUST_FIX_RE hoisted to module scope and lastIndex reset per call so the parser hot path stops recompiling regex per artifact - overflow check after drain simplified to a plain buf.length > cap test (the prior compound condition was always true on the right side and obscured intent) - scoreThreshold <= scoreScale refine gains a 1e-9 epsilon so floating slack does not reject semantically valid configs - round-1 designer ARTIFACT guard gains a comment naming the spec invariant and the v2 relaxation path - 3 new regression tests cover the panelist-without-round, scale=10 clamp, and scale=20 plumbing cases * docs(specs): rationale for non-goals, failure-mode rate targets, Phase 10 matrix, Phase 14 doc layout * Merge branch 'main' into feat/critique-theater Resolves the contracts/index.ts conflict by keeping the .js extensions added by chore(contracts) |
||
|
|
aefba56a3f |
feat(skills): open-design-landing rename, kami skills, landing OG (#428)
* feat(skills): open-design-landing rename, kami skills, landing OG - Rename editorial-collage skills to open-design-landing and -deck; refresh examples and compose script layout - Add kami-deck and kami-landing skills with HTML examples - Landing page: og.astro, index wiring, and style tweaks; package.json bump - Web i18n: German and Russian copy for renamed and new skills - Daemon test: update skill-asset-rewrite expectations for new paths - Design systems: README and atelier-zero doc touch-ups - Cross-skill SKILL.md reference updates Co-authored-by: Cursor <cursoragent@cursor.com> * docs(landing-page): document version-slot invariant and deprecation timeline Address P3 review notes on PR #428: - Note the `data-github-version` wrapper invariant (version string only) near the canonical URL block in `app/page.tsx`. - Expand the `formatVersion` helper comment in `app/pages/index.astro` with concrete `release.name` / `tag_name` example shapes for each branch of the regex fallback. - Tighten the `EditorialCollageDeckInputs` deprecation in `skills/open-design-landing-deck/schema.ts` to a specific removal version (v0.4.0) and add a "Migrating from editorial-collage-deck" section to the skill README. Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code) * docs(landing-page, skills): clarify version slot script and rename migrations - Describe GitHub version slots as driven by the inline enhancement script, not React hydration. - Add editorial-collage → open-design-landing migration notes; fix README link copy (Astro static landing app). - Extend deck README migration table with shared asset path renames. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(daemon): alias deprecated editorial-collage skill ids The PR renames the editorial-collage / editorial-collage-deck skills to open-design-landing / open-design-landing-deck, but the daemon persists exact skill_id strings on projects and resolves them via listSkills().find((s) => s.id === storedId). After the rename, any project saved against an old id silently composes without the intended skill prompt because the listing no longer exposes that id. Add a SKILL_ID_ALIASES map in skills.ts plus a findSkillById() helper that rewrites deprecated ids to their current canonical form, then route every server-side lookup (skill detail, example HTML, asset proxy, system-prompt composer) through it. Cover the alias map, the resolver, and end-to-end resolution against a temp skills directory with a regression test. Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code) * fix(kami-deck): route host od:slide messages through local go() The host bridge classifies kami-deck as class-driven because go() toggles .slide.active, but the visible slide is moved by deck.style.transform which the bridge cannot drive. Listen for od:slide messages and dispatch them through the local go() so toolbar next/prev and initialSlideIndex restore actually shift the deck. Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code) * fix(kami-deck): sync deck transform with host-driven .active changes The previous fix added a local od:slide listener but the host bridge in apps/web/src/runtime/srcdoc.ts also listens for the same message and calls setActive() (toggles .slide.active) without driving the deck transform. Both listeners fired, the bridge re-read the just-toggled active class, and overshot by one — and the bridge's restoreInitialSlide path could move .active without a message at all, leaving the deck on the original transform. Stop the bridge from double-handling by calling stopImmediatePropagation in the local listener (registered first because the bridge script is appended to </body>), and add a MutationObserver that pulls the deck transform onto whichever slide currently carries .active so the bridge's direct setActive calls (notably the initial-slide restore) move the deck too. Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code) * fix(i18n): align French content with renamed/new skills PR #434 (French localization) merged into main with French copy for the old editorial-collage / editorial-collage-deck skill ids; this branch renamed those to open-design-landing / open-design-landing-deck and added kami-deck and kami-landing. Update content.fr.ts to track the rename and add French copy for the new kami skills so the LOCALIZED_CONTENT_IDS coverage test passes once main is merged. Generated-By: looper 0.4.0 (runner=fixer, agent=claude-code) * fix(open-design-landing-deck): sync deck transform with host-driven .active changes Apply the same fix that landed in skills/kami-deck/example.html (commits |
||
|
|
bf533c3d72 |
fix(web): split execution mode tabs and align active chip visuals (#418)
* Refine settings API configuration UX * Fix PR validation issues * Address settings review edge cases * Address BYOK settings review feedback * Fix BYOK provider labels and model display |