Commit graph

299 commits

Author SHA1 Message Date
zztdan
f3024fdc22
feat(media): add Nano Banana image provider (#631)
* feat(media): add Nano Banana image provider

* fix(media): support Gemini API key headers for Nano Banana

* refactor(media): move Nano Banana model override flag into provider metadata
2026-05-06 20:26:31 +08:00
Caprika
8dc0875147
fix(i18n): remove duplicate Ukrainian prompt template keys (#680) 2026-05-06 20:25:00 +08:00
iulian
f880fd8c1d
docs(tools-pack): fix Linux namespace env var (#670)
* docs(tools-pack): fix linux namespace env var

* fix(web): remove duplicate Ukrainian prompt labels
2026-05-06 20:11:40 +08:00
Mohamed Abdallah
d80402a8ca
craft: add form-validation so generated forms aren't stuck in 2018 RHF/Formik patterns (#625)
* feat(craft): add form-validation + opt-ins on saas-landing, mobile-onboarding

Module 5 of 5 in the behavioral craft series proposed in #501.
Modules 1-4 merged: state-coverage (#502), animation-discipline (#515),
accessibility-baseline (#587), rtl-and-bidi (#595).

Picks up where accessibility-baseline.md ends (label + describedby +
invalid + role=alert for inline errors) and connects the four layers a
real form spans: WHATWG Constraint Validation as the platform floor,
validation timing as a state machine on the input, WCAG 3.3.x as the
announcement and recovery contract, schema as the cross-stack truth.

Sections: input state machine; validation timing (4 rules anchored on
:user-invalid Baseline 2023); Constraint Validation API rules
(setCustomValidity, requestSubmit vs submit, readonly + #11841,
inputmode); error wiring beyond the baseline (adaptive messages,
error summary without role=alert, preserve user input on error);
schema as cross-stack contract (Standard Schema, server-authoritative,
Zod 4 z.email() form); WCAG 3.3.3 / 3.3.4 / 3.3.8 / 3.3.9; native
mobile parity (UIKit, SwiftUI, Compose, Flutter, RN); common mistakes.

Reviewed in 3 loops with Claude CLI Opus 4.7 xhigh effort:
- Loop 1: 6 P0s caught (SwiftUI Form validity claim, SwiftUI
  announcement primitive, Compose semantics syntax, UIKit
  UIAlertController, contradictory Baymard stats, 3.3.8 CAPTCHA
  framing reversed) + 11 P1/P2s; all addressed.
- Loop 2: verified P0 fixes; flagged 1 P1 (RN table row scrambled) +
  4 P2s; all addressed.
- Loop 3: SHIP verdict. Three P2 nits applied (Zod 4 z.email() form,
  WebAIM Million 2026 stat woven in: 51% page-level, 33.1% input-level).

WebAIM Million 2026 numbers verified directly against
webaim.org/projects/million/.

Skill opt-ins: saas-landing (lead capture form), mobile-onboarding
(sign-in screen). Skill bodies do not contain validation-specific
instructions that would override craft guidance — opt-in alone is
sufficient. README updated.

Refs #501.

* fix(craft+skills): form-validation review fixes (lefarcen + mrcfps P2s)

Both non-blocking findings addressed:

- Drop form-validation from saas-landing.craft.requires. The skill body
  produces a CTA-driven landing page with no JS and no interactive
  form. Adding form-validation injected ~221 lines of irrelevant prompt
  pressure and conflicted with the README opt-in rule ("primary
  artifact contains an interactive form"). mobile-onboarding keeps the
  opt-in — sign-in screen is a real form.
- Reword timing rule 4 (async checks). Previous "never block submit on
  a network round-trip" was too broad and conflicted with the
  schema-layer "server is the truth" rule. Split into two paths:
  background preflight (uniqueness, address lookup) doesn't gate the
  form; authoritative submit-path server validation must await the
  server response and surface its field errors. The rule is "don't let
  a slow background check freeze the form," not "don't ever wait for
  the server."

* fix(craft): form-validation mrcfps round-2 (novalidate trade-off, Flutter RTL)

Two non-blocking precision items:

- novalidate trade-off: previous wording said keeping required/pattern/type
  preserves no-JS PE, but a literal server-rendered <form novalidate>
  disables the browser's submit-blocking and validation UI even when
  JS is unavailable — losing the no-JS constraint-validation floor.
  Reworded to spell out the two safe patterns: (A) render <form>
  without novalidate server-side and have the form library set
  form.noValidate = true after hydration, or (B) ship novalidate from
  the start only when the submit path reaches server validation
  without JS. Either way, keep the constraint attributes.
- Flutter announcement example: hardcoded TextDirection.ltr would
  announce Arabic/Hebrew/Persian validation messages with wrong bidi
  direction when this craft is combined with rtl-and-bidi. Switched
  to SemanticsService.announce(message, Directionality.of(context))
  with an explicit warning never to hardcode the direction.

* fix(craft): form-validation mrcfps round-3 (readonly safety, Compose error message)

Two non-blocking precision items:

- Non-input readonly fallback: previous text said `aria-readonly` plus
  hidden mirror input was an option for non-input controls that need
  to submit. But `aria-readonly` doesn't actually stop a `<select>` or
  custom widget from being changed, so the visible control can drift
  while the hidden input ships a stale value — user sees one option,
  server gets another. Tightened: prefer `disabled` plus a same-named
  hidden input, or non-editable text plus hidden input. If using
  `aria-readonly`, the interaction must also be blocked or the two
  values kept in sync.
- Compose error message: previous rule was too absolute about avoiding
  `Modifier.semantics { error("…") }`. `isError = true` flips the
  field state but does not carry the localized error message; Android
  Compose accessibility guidance pairs `isError` with
  `semantics { error(message) }` so the accessibility service gets the
  real text. The trap is duplication, not the API itself. Reframed
  the rule: use both, source the message from the same state field as
  `supportingText` so they stay in sync.

* fix(craft): form-validation Compose live-region API name

Compose row in the native-mobile parity table named a "LiveRegion"
semantic that doesn't exist. Real API is `Modifier.semantics
{ liveRegion = LiveRegionMode.Polite }` on the supporting-text node.
Also replaced the generic `view.announceForAccessibility(…)` with the
Compose-idiomatic `LocalView.current.announceForAccessibility(message)`
so generated snippets compile.
2026-05-06 20:09:30 +08:00
Jie Zhu
dbd28b79c0
fix(web): improve settings dialog scroll behavior (#667)
* fix(web): improve settings dialog scroll behavior

- Remove double scroll containers by changing modal-body overflow from auto to hidden, letting only settings-content handle scrolling

- Add min-height: 0 to settings-content and settings-sidebar to allow proper shrinking in grid layout

- Add overscroll-behavior: contain to prevent scroll chaining (scroll bleed-through to parent page)

- Add overflow-y: auto to settings-sidebar for cases where navigation items exceed viewport height

These changes fix the nested scroll issue that caused confusing scroll behavior and prevent content overflow on smaller viewports.

* fix(i18n): add missing Ukrainian translations for promptTemplates

Add promptTemplates.allSources and promptTemplates.sourceFilterAria translations to fix TypeScript error.
2026-05-06 20:09:17 +08:00
Siri-Ray
26636384a8
Fix desktop entry chrome consistency (#655)
* Fix desktop entry chrome consistency

* Fix mobile entry chrome overflow

* Fix Ukrainian prompt template source labels
2026-05-06 19:55:27 +08:00
mamba
570d06419c
feat[qoder cli] add Qoder CLI agent support (#626)
* chore(agent): 增加对 Qoder CLI 的支持和识别

- 在 QUICKSTART 文档中添加 Qoder CLI 为可选本地 agent CLI
- 更新代码中 agents.ts 注释包含 Qoder CLI 扫描支持
- 修改首次加载时检测的可用 CLI 列表,加入 Qoder CLI
- 在多个语言版本的 README 中增加 Qoder CLI 支持及相关徽章统计
- 更新 agent 适配器与事件解析相关的代码注释和文档,包含 qoder-stream-json 解析器
- 调整 Windows 下 spawn 行为以支持 Qoder CLI 的 stdin 提供 prompt
- 修复多语言文档对支持的 CLI 数量描述错误,确保数据保持同步

Change-Id: I388f2f61c60ce8faa7cef5d84eb407950f8bdbfb
Co-developed-by: Qoder <noreply@qoder.com>

* chore(agent): 增加对 Qoder CLI 的支持和识别

- 在 QUICKSTART 文档中添加 Qoder CLI 为可选本地 agent CLI
- 更新代码中 agents.ts 注释包含 Qoder CLI 扫描支持
- 修改首次加载时检测的可用 CLI 列表,加入 Qoder CLI
- 在多个语言版本的 README 中增加 Qoder CLI 支持及相关徽章统计
- 更新 agent 适配器与事件解析相关的代码注释和文档,包含 qoder-stream-json 解析器
- 调整 Windows 下 spawn 行为以支持 Qoder CLI 的 stdin 提供 prompt
- 修复多语言文档对支持的 CLI 数量描述错误,确保数据保持同步

Change-Id: Id33f125b7c0b1a1c0b0274073da74d1578c324f7
Co-developed-by: Qoder <noreply@qoder.com>

* feat(agent-icon): 添加新的Qoder徽标SVG图形组件

- 新增qoderGlyph函数,返回指定大小的SVG格式图形
- 图形包含多路径定义,颜色使用深灰和绿色填充
- 该组件可用于替代或补充现有AgentIcon图标功能
- 提升应用程序的品牌标识和视觉表现力

Change-Id: I4eca18166b5e33bc6229b40b2531d5a54607a560
Co-developed-by: Qoder <noreply@qoder.com>

* Translate to English:

---

**docs(readme): update to expand CLI agents to 16**

- Increased the number of coding agent CLIs from 11 to 16
- New agents included: Devin for Terminal, Kiro CLI, Kilo, Mistral Vibe CLI, DeepSeek TUI

**docs(readme): update to expand supported coding agents to 16**

- Increased the number of supported code agent CLIs from 11 to 16
- Added support for new CLI tools: Devin for Terminal, Kiro CLI, Kilo, Mistral Vibe CLI, DeepSeek CLI
- Added automatic CLI detection and switching while maintaining support for more agents
- Added BYOK proxy TUI
- Expanded compatibility and support coverage in the README’s multiple language versions
- Reflected changes across all README translations (Arabic, German, French, Japanese, Korean)
- Updated badges and descriptions to reflect CLI count and feature changes
- Added event parsers and protocols for the new CLIs in the agent transport implementation
- Updated the BYOK proxy and tool exploration features to be compatible with the expanded CLIs

Change-Id: I89786b4a0b09bd279fb23265c2177076206fc5af
Co-developed-by: Qoder <noreply@qoder.com>

* feat(daemon): 支持 imagePaths 参数作为附件路径传递给 Qoder

- 修改 buildArgs 函数,添加 --attachment 参数处理 imagePaths 中的绝对路径
- 过滤并忽略空字符串、非字符串及相对路径的 imagePaths 项
- 在单元测试中覆盖 imagePaths 参数支持及无效项过滤逻辑
- 在文档中补充 Qoder 运行时适配器对 --attachment 参数的说明

Change-Id: Ibfc3583ba86c6d258d524912559e97b77bf1dc87
Co-developed-by: Qoder <noreply@qoder.com>

* docs(runtime): 说明Qoder适配器继承用户令牌的环境变量

- 添加文档说明检测代理仅为可用性探针,不进行身份验证
- 说明Qoder CLI账号状态独立,认证通过运行时错误路径反馈
- 详细描述子进程环境继承机制及静态环境变量与用户私密令牌区分
- 明确QODER_PERSONAL_ACCESS_TOKEN通过守护进程环境传递,不写入静态环境
- 解释Qoder验证由Qoder CLI负责,支持持久登录和自动化环境变量注入

test(agent): 添加QODER_PERSONAL_ACCESS_TOKEN环境变量继承测试

- 验证qoder适配器环境继承守护进程中的QODER_PERSONAL_ACCESS_TOKEN
- 确认qoder适配器未在静态环境变量中定义用户令牌
- 保证用户私密令牌不会被写入静态适配器环境配置

Change-Id: Ie61869afbe497df1b16879b4e47b35123f758ed8
Co-developed-by: Qoder <noreply@qoder.com>

* fix(daemon): 改进Qoder模式支持及错误处理机制

- 更新Qoder CLI参数,使用`--yolo`替代`--permission-mode bypass_permissions`
- 将工作目录参数从`--cwd`改为`-w`以符合Qoder文档
- 在agent流事件处理中新增错误捕获并通过SSE错误事件发送
- 运行结束时若检测到agent流错误,则标记运行失败
- 测试中fix(daemon): 优化Qoder代理参数与错误处理

- 调整Qoder启动参数,改用`--yolo`和`-w`替代旧参数,避开argv长度限制
- 增强代理流事件处理,捕获并通过SSE错误通同步更新Qoder参数使用及相应断言
- 新增端到端测试,覆盖Qoder助手错误通过SSE错误通道反馈及运行状态失败处理
- 补充工具函数辅助测试事件流读取与运行状态轮询

Change-Id: I5d933745c3659e093b0d2d807f22726e7f83eb48
Co-developed-by: Qoder <noreply@qoder.com>

* feat(qoder-stream): 识别并报告Qoder运行错误事件

- 新增messageFromResult函数以从结果对象提取错误信息
- 在处理result事件时根据is_error字段触发error事件
- error事件携带具体错误消息和原始数据
- 添加测试验证Qoder运行返回is_error且退出码为0时正确触发错误事件
- 更新qoder流解析测试以校验错误事件映射
- 在聊天路由测试中增加针对Qoder错误运行的端到端场景验证

Change-Id: Ie98ac518135dbec3181c52de5a49afdea993e279
Co-developed-by: Qoder <noreply@qoder.com>
2026-05-06 19:54:03 +08:00
Caprika
c317c889fd
Fix Ukrainian prompt template translations (#674) 2026-05-06 19:49:21 +08:00
Deheng Huang
09b78c2f9b
feat(daemon): let Codex image projects use built-in imagegen (#622)
* feat(daemon): let Codex image projects avoid API-key setup

Codex has a built-in image generation path available inside the agent runtime, while the generic media dispatcher still routes gpt-image models through the daemon OpenAI provider. Pass the active agent id into prompt composition so Codex-only gpt-image projects can use built-in imagegen first without changing non-Codex media behavior.

Constraint: Existing media contract remains the default path for non-Codex agents and explicit provider fallback
Rejected: Add a nested daemon Codex media provider | heavier auth, streaming, timeout, cancellation, and output parsing surface for this parity fix
Confidence: high
Scope-risk: narrow
Directive: Keep this override after the media contract so it can intentionally supersede dispatcher-only wording for Codex gpt-image projects
Tested: pnpm --dir apps/daemon exec vitest run -c vitest.config.ts tests/system-prompt-template.test.ts
Tested: pnpm --filter @open-design/daemon typecheck
Tested: pnpm guard
Tested: pnpm typecheck
Not-tested: Live Codex image generation inside the Open Design UI

* fix(daemon): harden Codex imagegen prompt routing

PR review found the Codex override could be superseded by the web-supplied media contract, trusted unvalidated image model metadata, and assumed generated image paths outside the workspace were readable.

This keeps the override daemon-owned, appends it last in the live prompt, validates against registered gpt-image model IDs, allowlists only Codex's generated_images folder, and tightens copy-failure instructions.

Constraint: The web contracts composer still emits the generic media contract without agent identity.

Rejected: Mirror Codex-specific prompt logic into contracts/web | duplicates daemon model registry and still leaves final ordering fragile.

Confidence: high

Scope-risk: narrow

Directive: Keep Codex imagegen override appended after client systemPrompt so it remains the final media instruction for Codex gpt-image projects.

Tested: pnpm --dir apps/daemon exec vitest run -c vitest.config.ts tests/system-prompt-template.test.ts tests/agents.test.ts tests/chat-route.test.ts

Tested: pnpm --filter @open-design/daemon typecheck

Tested: pnpm guard

Tested: pnpm typecheck

Not-tested: Live Codex image generation inside the Open Design UI

* fix(daemon): keep Codex add-dir writable scope narrow

PR review found Codex --add-dir grants writable workspace access, so passing skill, design-system, and linked reference directories through the same chat allowlist broke their documented read-only boundary.

This routes chat extra directories by active agent: Codex receives only the validated generated_images output directory needed for built-in imagegen, while non-Codex adapters keep the existing resource and linked-directory read access behavior.

Constraint: Codex CLI treats --add-dir as writable sandbox expansion.

Constraint: The daemon still stages active skill files into the project cwd as Codex's read-safe path.

Rejected: Keep one shared extraAllowedDirs list for all agents | grants Codex write access to read-only resources.

Confidence: high

Scope-risk: narrow

Directive: Do not add read-only resource/reference directories to Codex --add-dir unless Codex gains a read-only allowlist flag.

Tested: git diff --check -- apps/daemon/src/server.ts apps/daemon/tests/chat-route.test.ts

Tested: pnpm --filter @open-design/daemon exec vitest run tests/chat-route.test.ts

Tested: pnpm --filter @open-design/daemon typecheck

Tested: pnpm guard

Tested: pnpm typecheck

Not-tested: Live Codex image generation inside the Open Design UI

* fix(daemon): validate Codex imagegen add-dir grants

PR review found the generated_images grant still trusted symlinked paths and rendered the Codex override before proving the sandbox grant would be present.

This validates the generated_images directory before prompt assembly, rejects final-component symlinks and protected-root canonical escapes, passes Codex the canonical grant path, and only appends the Codex imagegen override when that same path is in extraAllowedDirs.

Constraint: Codex --add-dir grants writable workspace access, so path aliases into read-only resource roots must be rejected.

Rejected: Keep returning the nominal CODEX_HOME path after validation | leaves Codex operating through a symlink alias instead of the audited grant target.

Confidence: high

Scope-risk: narrow

Directive: Keep Codex imagegen prompt rendering downstream of generated_images validation and grant resolution.

Tested: git diff --check -- apps/daemon/src/server.ts apps/daemon/tests/chat-route.test.ts

Tested: pnpm --filter @open-design/daemon exec vitest run -c vitest.config.ts tests/chat-route.test.ts

Tested: pnpm --filter @open-design/daemon exec vitest run -c vitest.config.ts tests/agents.test.ts tests/chat-route.test.ts

Tested: pnpm --filter @open-design/daemon typecheck

Tested: pnpm guard

Tested: pnpm typecheck

Not-tested: Live Codex image generation inside the Open Design UI
2026-05-06 18:28:16 +08:00
Israel Castro
c8127b78fd
i18n(es): align README.es.md UI references to es-ES.ts locale (#611)
* i18n(es): align README.es.md UI references to es-ES.ts locale

The README.es.md merged in #552 references the UI in English in a
handful of places where the actual Spanish locale (es-ES.ts, shipped
in #182) renders different strings. A reader who follows the README
into the app sees mismatched button and tab names. This PR aligns
those references.

- 'Send' -> 'Enviar' (chat.send: 'Enviar' in es-ES.ts)
- 'Save to disk' -> 'Guardar en disco' (common.save / fileViewer.save
  resolve to 'Guardar'; 'en disco' mirrors the descriptive looseness
  of the English original which is also not a strict button label)
- 'Image templates' / 'Video templates' tabs ->
  'Plantillas de imagen' / 'Plantillas de vídeo' (entry.tabImageTemplates
  and entry.tabVideoTemplates in es-ES.ts)
- 'Use this prompt' -> 'Usar este prompt' (examples.usePrompt)
- Persistencia bullet: 'tabs' / 'tab activa' -> 'pestañas' /
  'pestaña activa' (workspace.closeTab: 'Cerrar pestaña' and 8+ other
  uses establish 'pestaña' as the canonical Spanish term in the UI)
- Subsection 5: 'Sessions, conversations, messages y tabs persisten…'
  -> 'Sesiones, conversaciones, mensajes y pestañas persisten…'.
  Fixes the inconsistency of mixing English nouns with Spanish
  conjunction; treating these as concepts (parallel to the English
  original's lowercase non-code list) reads as Spanish prose.

ASCII tree comments and SQLite literal table names ('tabs' as a
column reference, 'projects · conversations · messages · tabs' code
identifiers) are intentionally left untouched.

* i18n(es): align Settings → Ajustes (MCP server section)

Spotted in PR review: line 407 in the 'Usar Open Design desde tu
coding agent' section references the settings entry as 'Settings'
when es-ES.ts consistently renders it as 'Ajustes' (settings.kicker,
entry.openSettingsTitle, avatar.settings — three independent uses
in the locale, all 'Ajustes').

The 'MCP server' part of the path is currently hardcoded in the UI,
so it stays in English.
2026-05-06 18:10:23 +08:00
Tom Huang
9d176ef12e
feat(prompt-templates): HyperFrames video previews + provider badge + source filter (#293)
* feat(prompt-templates): add 11 HyperFrames video prompts and surface media generation in README

Adds eleven `hyperframes-*` prompt templates under `prompt-templates/video/`,
each one a concrete brief with scene-by-scene timing, GSAP eases, palette,
and the HyperFrames non-negotiables (deterministic, paused timelines,
entrance-only motion, lint/inspect commands). Archetypes covered:

- minimal product reveal (5s, 16:9)
- SaaS product promo (30s, 16:9, Linear/ClickUp-style)
- TikTok karaoke talking-head (9:16, TTS + word-synced captions)
- brand sizzle reel (30s, beat-synced kinetic typography)
- animated bar-chart race (NYT-style data infographic)
- Apple-style flight map route (origin → destination)
- 4s cinematic logo outro
- $0 → $10K money counter hype (9:16)
- 3-phone app showcase
- 9:16 social overlay stack (X · Reddit · Spotify · Instagram)
- 15s website-to-video pipeline

Each template uses `model: "hyperframes-html"`, real catalog-block thumbnails
from HeyGen's CDN as previewImageUrl, and source attribution to
`heygen-com/hyperframes` (Apache-2.0).

README also gets a new **Media generation** section between *Visual directions*
and *Beyond chat*, plus a new row in the *At a glance* table. The section
documents the three model families currently surfaced as templates
(gpt-image-2, Seedance 2.0, HyperFrames) with example galleries — gpt-image-2
thumbnails, Seedance MP4-linked thumbnails, and the 11 HyperFrames tiles —
and notes the wider model coverage (Kling, Veo, Sora, MiniMax, Suno, Udio,
Lyria, TTS) already wired in `VIDEO_MODELS` / `AUDIO_MODELS_BY_KIND` and
open for community templates.

* i18n(de): register new HyperFrames templates, categories, tags

Adds German titles/summaries for the 11 new hyperframes-* video templates
plus the Product/Marketing/Data/Travel/Branding/Short Form categories and
hyperframes/title-card/sizzle/etc. tags they introduce, so the German sync
guarantees enforced by apps/web/src/i18n/content.test.ts hold.

* docs(readme): sync Media generation section to de / ja / ko / zh-CN; bump counts to 93 (43 + 39 + 11)

Mirrors the English Media generation row + section into the four locale READMEs
(README.de.md, README.ja-JP.md, README.ko.md, README.zh-CN.md), translating
prose / table headers / captions while keeping the gpt-image-2, Seedance MP4,
and HyperFrames catalog-block thumbnails identical across all five locales so
the galleries render the same images.

Counts updated to reflect current main (after rebase): 43 gpt-image-2 + 39
Seedance + 11 HyperFrames = 93 prompts total. The English README's At-a-glance
row, intro paragraph, and gallery sub-headers now read "sample of 43" /
"sample of 39" / "11 ready-to-replicate templates" — locales follow.

Resolves the Codex review's German-i18n flag end-to-end: README copy is in
sync, and the German content map (DE_PROMPT_TEMPLATE_*) was already extended
in the prior commit on this branch.

* feat(prompt-templates): video previews + provider badge + source filter for HyperFrames

- Add `previewVideoUrl` to all 11 HyperFrames video templates so the preview
  modal plays the real catalog clip instead of falling back to a static image.
- Add a per-card provider badge (top-left thumbnail chip) keyed off
  `source.repo`. HyperFrames cards get a HeyGen-accent gradient so they are
  identifiable at a glance; other repos get a neutral pill.
- Add a Source filter dropdown next to Category in PromptTemplatesTab,
  populated from the small enumerated repo set (HyperFrames, Seedance 2,
  GPT Image 2, Open Design). Auto-hides when only one source is present.
  The text search now also matches the provider name.
- Wire i18n keys `promptTemplates.allSources` and
  `promptTemplates.sourceFilterAria` across all 9 locales.
2026-05-06 18:09:30 +08:00
brown2hm
99d443c512
fix(daemon): ignore .venv and other large dirs in project file watcher (#531)
* fix(daemon): ignore .venv and other large dirs in project file watcher

A project containing a Python virtual environment (.venv) could exhaust
the daemon's file descriptor table — chokidar recursively watched every
file in the tree, opening ~18 000 fds. With the fd table full, macOS
posix_spawn returned EBADF when the daemon tried to create stdio pipes
for a child process (codex exec, or any other agent), surfacing as
"spawn failed: spawn EBADF" on every chat request.

Adds .venv, venv, __pycache__, .mypy_cache, .pytest_cache, .tox,
.ruff_cache, target, vendor, and .cargo to the per-segment IGNORE_NAMES
set so the watcher skips these trees in any project.

* fix(daemon): narrow project-watcher ignores to safe Python dirs only

Remove target, vendor, and .cargo from IGNORE_NAMES — they match any
path segment, so src/vendor/… or .cargo/config.toml (a valid Rust
project file) would be silently dropped from file-change events.

Keep only the Python-specific names (.venv, venv, __pycache__, and the
mypy/pytest/tox/ruff caches) which are never legitimate authored source
at any depth and were the root cause of the fd-exhaustion bug.

Add a real-chokidar test covering all seven newly added ignore dirs.

---------

Co-authored-by: hbrown <hbrown@mitre.org>
2026-05-06 18:07:08 +08:00
github-actions[bot]
b1121c04f5
docs(readme): refresh contributors wall (#594)
Co-authored-by: mrcfps <23410977+mrcfps@users.noreply.github.com>
2026-05-06 18:06:21 +08:00
lefarcen
ae4a08773a
chore(release): prepare 0.4.1 (#659)
- bump remaining monorepo package.json files to 0.4.1 after apps/packaged was already bumped in #637
- add CHANGELOG.md [0.4.1] - 2026-05-06 entry covering the startup hotfix and 19 merged PRs since 0.4.0:
  - Added: manual edit mode (#620), Cmd/Ctrl+P quick file switcher (#556), resizable chat panel (#563), PI status/cancel updates (#618), accessibility and RTL/Bidi craft modules (#587, #595), i18n structure checks (#608)
  - Changed: first-PR README links now surface help-wanted issues (#605)
  - Fixed: packaged contracts runtime exports (#577), packaged runtime beta gating (#637), ACP/MCP/agent fixes (#604, #612, #627), conversation error recovery (#623), native mac quit (#637)
  - Documentation/Internal: OD_DATA_DIR migration docs (#570), Simplified Chinese QUICKSTART (#578), zh-TW/ko README syncs (#586, #619), generated metrics (#592)

Release workflow validation runs after merge via release-stable.
2026-05-06 18:05:56 +08:00
czL
3b6df849ce
fix linux test path (#657) 2026-05-06 18:00:48 +08:00
bojie.hbj
f0185f4d2c
fix: constrain chat panel width overflow (#644)
- Add min-width: 0 on .split-chat-slot, .pane, .chat-log-wrap, .chat-log to break flex content width propagation
- Add min-width: 0 and max-width: 100% to .op-card for tool cards
- Use responsive max-width: min(220px, 100%) for file paths in tool cards

Co-authored-by: bojiehuang <bojiehuang@bojiehuangdeMacBook-Pro.local>
2026-05-06 17:45:03 +08:00
PerishFire
f1cdb2844a
test(e2e): gate beta packaged runtime (#637)
* test(e2e): gate beta mac packaged runtime

* test(e2e): separate ui automation layout

* test(e2e): move localized content coverage

* chore(release): prepare packaged 0.4.1 beta validation

* test(e2e): keep ui lane playwright-only

* fix(web): keep chat recoverable after conversation load failure

* fix(desktop): honor native mac quit
2026-05-06 17:44:29 +08:00
Goemon
95bd7e5373
fix(daemon): add required env field to McpServerStdio + recover from -32602 on set_model (#627)
* fix(daemon): add required env field to McpServerStdio in live-artifacts MCP descriptor

The ACP schema's McpServerStdio marks env as a required field
(List[EnvVariable] with no default). Omitting it causes Pydantic V2
Union validation to fail across all three variants (HttpMcpServer,
SseMcpServer, McpServerStdio), returning -32602 Invalid params on
session/new for agents with mcpDiscovery: 'mature-acp' (Hermes,
Devin, Kimi).

This bug is invisible when mcpServers resolves to an empty array
(no live-artifacts token), so it only manifests when the MCP
live-artifacts integration is enabled.

* fix(daemon): recover from -32602 Invalid params on session/set_model

Extend the existing -32603 Internal error recovery logic to also
handle -32602 (Invalid params) when the set_model request fails.
This allows the prompt to proceed with the default model instead of
hanging or timing out.

Some ACP agents may not support session/set_model or may reject the
model ID — treating this as a non-fatal condition and falling back to
the default model is more resilient than failing the entire run.

* fix(daemon): narrow -32602 handling and update test fixtures for env field

Address PR #627 review feedback:

1. Narrow -32602 Invalid params suppression to setModelRequestId only.
   Unexpected-id -32602 errors are now treated as real protocol failures
   and propagated via fail(), matching the reviewer's suggestion. Only
   -32603 Internal errors from unexpected IDs are still suppressed as
   cleanup noise.

2. Update all buildLiveArtifactsMcpServersForAgent test fixtures to
   include the new required env: [] field.
2026-05-06 16:28:43 +08:00
Caprika
8eb9b1b506
Implement manual edit mode (#620) 2026-05-06 16:13:52 +08:00
Sid
33255a8fdf
Fix agent CLI config and workspace focus mode (#604)
* fix agent CLI config and workspace focus mode

* address CLI env review follow-ups
2026-05-06 16:06:56 +08:00
nhancdt2602
d1d63f9dae
Fix/error message persistence (#623)
* test(ProjectView): persists daemon errors on assistant messages

Signed-off-by: nhancdt2602 <nhancu2602@gmail.com>

* fix(ProjectView): persists daemon errors on assistant message

Signed-off-by: nhancdt2602 <nhancu2602@gmail.com>

* test(e2e): cover agent switch and persistence

Signed-off-by: nhancdt2602 <nhancu2602@gmail.com>

* chore(chat-event): handle falsy empty error detail

Signed-off-by: nhancdt2602 <nhancu2602@gmail.com>

---------

Signed-off-by: nhancdt2602 <nhancu2602@gmail.com>
2026-05-06 15:28:30 +08:00
zz
dd702c7254
fix(acp): normalize mcpServers to stdio shape for Kimi/Hermes ACP (#612)
Kimi CLI 1.35.0 expects MCP stdio servers to include 'type', 'name',
'command', 'args', and 'env' fields. Open Design was passing only
'name', 'command', and 'args', which caused session/new to return
JSON-RPC -32602 Invalid params when MCP discovery was enabled.

This change normalizes every MCP server descriptor to the full ACP
stdio shape before sending it over the wire.
2026-05-06 15:03:51 +08:00
Charles
165f8f70a3
docs(ko): sync Korean README with upstream/main + quality improvements (#619)
* docs(ko): sync Korean README with upstream/main + apply quality improvements

- Update CLI count: 10 → 15 (add Devin for Terminal, Kiro, Kilo, Mistral Vibe, DeepSeek TUI)
- Fix badge: agents-10 → agents-15
- "락인 없음" → "종속성 없음" (vendor lock-in meaning clarified)
- "pre-flight를 강제로 읽고" → "pre-flight 점검을 반드시 수행" (natural Korean)
- "5개 학파" / "5개의 엄선된" → "5가지" (Korean number classifier correction)
- "임대료" → "사용료" (API cost context)
- Update comparison table and roadmap: 10개 CLI → 15개 CLI

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs(ko): address PR #619 review feedback

P1: add 5 missing CLI rows to the supported-agents argv table
- Devin for Terminal (acp-json-rpc)
- Kiro CLI (acp-json-rpc)
- Kilo (acp-json-rpc)
- Mistral Vibe CLI (acp-json-rpc)
- DeepSeek TUI (plain)
- Update BYOK row to multi-provider /api/proxy/{anthropic,openai,azure,google}/stream

P2: "종속성 없음" → "벤더 종속 없음" (matches "none of the lock-in" intent)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Charles <charles@spoonlabs.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 14:04:29 +08:00
laihenyi
e8d6191d9e
docs(zh-TW): backport 4 missing H2 sections from English README (#586)
* docs(zh-TW): backport 4 missing H2 sections from English README

zh-TW had drifted from English by 4 sections. Backport with
Taiwan-specific terminology (per glossary in TRANSLATIONS.md):

- ## 跑專案 (Running the Project) — foreground/background lifecycle,
  desktop/electron commands, Other useful commands table
- ## 從 coding agent 端使用 Open Design (Use OD from your coding agent)
  — stdio MCP server flow, why MCP, install, security model
- ## 媒體生成 (Media generation) — image/video/audio model families,
  prompt gallery (43+39+11), gpt-image-2 / Seedance / HyperFrames tables
- ## 致謝 / Credits — html-ppt + guizang-ppt upstream attribution

Also extends the License section to mention html-ppt's bundled MIT
license (was already mentioning guizang-ppt only). Section IDs now
match English README exactly (27 H2 each).

* docs(zh-TW): address P3 review feedback on terminology

- 視訊模型 → 影片模型 (TRANSLATIONS.md zh-TW glossary maps video→影片)
- 目錄塊 → 目錄元件 (catalog blocks reads more naturally as 元件 in TW)
- 由他們的 CDN 回源 → 由 HeyGen 的 CDN 提供 (回源 is jargon, name is clearer)
- prompt → 產物路徑 → prompt → 輸出行為 (corrected mistranslation of
  "output behavior"; 路徑 incorrectly read as filesystem path)
2026-05-06 14:04:16 +08:00
Mohamed Abdallah
be1b3dae40
craft: add rtl-and-bidi so OD artifacts don't break for Arabic / Hebrew / Persian users (#595)
* feat(craft): add rtl-and-bidi + opt-ins on blog-post, docs-page, finance-report

Module 4 of 5 in the behavioral craft series proposed in #501. Modules
1 (state-coverage, #502) and 2 (animation-discipline, #515) merged.
Module 3 (accessibility-baseline, #587) open at time of authoring.

Differentiating niche per the corpus prior-art survey: zero existing
OSS RTL skill is Apache-2.0, framework-agnostic, and aligned with
UAX #9 rev 51. The closest comparators (idanlevi1/rtlify 5★, MIT;
skills-il/localization 7★, MIT) are LTR-web-skewed and don't cover
Flutter Directionality, RN I18nManager, Compose LocalLayoutDirection,
or iOS UIKit semanticContentAttribute / SwiftUI layoutDirection.

Three-loop adversarial review pass via Claude Opus 4.7 xhigh effort
(codex unavailable). Loop 1 caught five revisions (typography spin-out,
WebKit prose compression, mistakes-list trim 12→9, alreq letter-spacing
rename dropped, WebKit r94775 specific revision dropped). Loop 2 caught
one blocking SwiftUI 4 claim and three nits. Loop 3 said ship.

Skill opt-ins picked to avoid PR #587 merge surface: blog-post (long-form
text), docs-page (LTR code islands in RTL prose), finance-report
(numerals + IBAN + currency).

Refs #501.

* fix(craft): rtl-and-bidi review fixes (lefarcen 6 findings)

- P2 #1 WebKit #50949: bug is RESOLVED FIXED, not still open. Verified
  directly against bugs.webkit.org. Removed the broken-WebKit framing;
  the recommendation to prefer <bdi> over CSS now stands on UAX #9
  §2.7 ("prefer markup over CSS or control characters") rather than a
  WebKit bug. Source list updated to drop the dead reference.
- P2 #2 isolate vs embedding controls: U+202C PDF is the
  embedding/override terminator, not an isolate terminator. Split into
  two families: isolate controls (U+2066/2067/2068 + U+2069 PDI) for
  modern code, embedding/override controls (U+202A/202B/202D/202E +
  U+202C PDF) as legacy. Recommend isolates first.
- P2 #3 base direction and language: new section covering
  <html dir lang>, mixed-language subtrees, dir=auto for UGC. Without
  this, agents can follow every other rule and still ship an LTR
  document containing Arabic.
- P2 #4 phone/IBAN/card values: bare <bdi> is unreliable for
  weak/neutral character runs; updated must-mirror bullet and forms
  section to require <bdi dir="ltr">. Added common-mistake entry.
- P3 #1 native mobile budget: added a one-line opt-out hint at the
  top of the section so HTML-only skills know they can skim it. Full
  split into web/native files deferred — the table is 16 lines on a
  176-line file, the cost is bounded.
- P3 #2 lintability: restructured "common mistakes" into three groups
  — mechanically lintable, needs script detection, HTML semantics —
  with explicit exception language (chart axes, physical-object icons,
  platform-pinned UI). Avoids false positives in future linting.

Reviewed via Claude CLI Opus 4.7 xhigh effort (3 loops on the
original draft); these fixes are explicit reviewer responses with
WebKit Bugzilla state verified live.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(craft): rtl-and-bidi mrcfps round-2 precision (lang+dir, isolate picks)

Two non-blocking precision items:

- lang-without-dir scope: previous wording implied English never needs
  dir="ltr". True only at the document root in a default-LTR page.
  lang does not reset an inherited bidi base direction, so an
  <section lang="en"> inside an RTL ancestor still resolves RTL.
  Reworded to "lang without dir is fine at the document root in a
  default-LTR page; inside any opposite-direction ancestor, set both."
- Plain-text isolate picks: previous wording recommended U+2068 / U+2069
  generically. U+2068 is FSI (first-strong auto-detect) — wrong default
  for known-direction runs, especially weak/neutral-heavy values like
  phone, IBAN, card numbers (the same class this file forces to LTR in
  HTML). Split: LRI/PDI for known-LTR, RLI/PDI for known-RTL, FSI/PDI
  reserved for unknown direction. Added an explicit "don't default to
  FSI" callout.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(craft+skills): rtl-and-bidi mrcfps round-3 — skill-body conflicts + bidi semantic correction

P1 BLOCKING — skill-body physical-direction conflicts (mrcfps):

- skills/docs-page: "left nav" / "right-rail TOC" / "left-edge accent
  stripe" survive in skill body even with the rtl-and-bidi opt-in,
  because craft is injected ABOVE the skill body. An Arabic docs
  request would still see "Left nav" and emit physical-direction
  layout. Updated description, lay-out section, and self-check to
  inline-start / inline-end vocabulary; added a self-check bullet
  requiring logical CSS on rails and accent.

- skills/blog-post: pull-quote "accent rule on the left" updated to
  "accent rule on the inline-start edge" with a matching note about
  flipping under dir="rtl".

P1 craft semantic correction (mrcfps):

- HTML-semantics lint: previous wording equated <bdi dir="auto"> with
  unicode-bidi: plaintext. Not equivalent. <bdi> isolates an inline
  run from surrounding bidi resolution; unicode-bidi: plaintext
  changes how base direction is *determined* for each plaintext
  paragraph in a block. Different surfaces. Reworded the lint guidance
  to "prefer semantic isolation in HTML for inline runs; reach for
  unicode-bidi: plaintext only when that block-level paragraph
  behavior is explicitly required and tested" — and explicitly flagged
  that they are not drop-in equivalents to avoid future linters
  flagging valid CSS with a non-equivalent fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(craft): rtl-and-bidi mrcfps round-4 — split progress-bar from media scrubber

Non-blocking precision: prior must-mirror bullet lumped "progress-bar
fill" together with sliders, which would have flipped a video / audio
scrubber under dir="rtl" — directly conflicting with the must-not-mirror
rule for media playback controls (play/pause/FF/rewind represent tape
direction, not reading direction). The two cases collide on every audio
or video player.

- Must-mirror progress bars now scoped to "non-media" (download, upload,
  form-completion).
- Media scrubber / progress timeline added explicitly to the must-not-
  mirror media bullet.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 12:43:48 +08:00
Tom
5df04c29a3
feat(daemon): add model name to pi initial status and RPC abort on cancel (#618)
* feat(daemon): add model name to pi initial status and RPC abort on cancel

- Emit status:initializing with model name before pi responds so the UI
  shows 'pi · claude-sonnet-4-5' — matching Claude Code, Copilot, Gemini,
  and Cursor Agent model-name parity
- Replace raw SIGTERM with RPC abort command on cancel, giving pi a
  chance to clean up gracefully before SIGTERM fallback
- Wire run.acpSession onto the run object so cancel() can dispatch to
  session.abort() for pi and ACP adapters
- Add stdinOpen guard so sendCommand is a no-op after stdin closes
- Add 4 tests covering initializing status, abort wire format, and
  stdin-closed guard

* fix(daemon): gate stdout parser after abort to prevent post-cancel events

Once abort() sets finished=true, the stdout listener kept feeding
chunks into mapPiRpcEvent, so text_delta/tool/status events could
still be emitted during the PI_ABORT_GRACE_MS window. Add a finished
guard at the top of the parser callback so no agent events are
forwarded after abort, while still draining stdout cleanly.

Adds a test that aborts mid-session, then feeds message_update and
tool events, proving zero post-abort agent events are emitted.

* refactor(daemon): own SIGTERM fallback in cancel, rewrite abort tests as integration

- Move SIGTERM fallback from pi-rpc abort() to runs cancel() so the
  termination guarantee is centralized — a misbehaving session can't
  leave the child alive indefinitely (address lefarcen P3 on L130)
- Remove the setTimeout/SIGTERM from abort(); it now only sends the
  RPC abort command, termination is the caller's responsibility
- Rewrite initial-status and abort tests as integration tests that
  exercise attachPiRpcSession against mock child processes instead
  of duplicating private sendCommand/send helpers inline (address
  lefarcen P3 on L453 and L491)
- All 28 tests pass
2026-05-06 12:20:40 +08:00
nettee
8762f06297
Add i18n structure checks (#608) 2026-05-06 11:55:59 +08:00
lefarcen
f1290a0222
docs(readme): also surface help-wanted issues from first-PR link (#605)
GitHub's `/contribute` page only renders the `good first issue` label,
so 12 open `help wanted` issues never reach newcomers via that entry.
Switch the link to an issues search URL covering both labels (OR), so
both pools surface from one click. Wording is unchanged across all 10
README locales.
2026-05-06 10:52:35 +08:00
Kadu Maverick
2036ce0a8e
feat(web): add Cmd/Ctrl+P quick file switcher (#556)
* feat(web): add Cmd/Ctrl+P quick file switcher

A keyboard-driven file palette overlaid on the workspace. Press Cmd/Ctrl+P
anywhere in the project view; type to fuzzy-filter the file list, ↑/↓ to
navigate, Enter to open in a tab, Esc to dismiss. With an empty query the
palette surfaces recents (per-project, localStorage) followed by the rest
of the file list sorted by mtime.

Adds:
- apps/web/src/components/QuickSwitcher.tsx: palette UI and matcher
- apps/web/src/quickSwitcherRecents.ts: per-project recents store
- index.css: scoped .qs-* styles using existing design tokens
- i18n: 6 new keys translated across all 16 locale files

Wires into FileWorkspace's existing openFile() so recents and tab state
behave identically to opening from DesignFilesPanel. Capture-phase keydown
beats the browser's print dialog. No backend changes; uses the files prop
already passed to FileWorkspace.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(web): address QuickSwitcher review feedback

Three fixes from the PR review:

- z-index: bump .qs-overlay from 200 to 1500 so the palette renders in
  the modal tier (alongside prompt-template-modal-overlay) instead of
  behind context menus and popovers (which sit at 200).

- Arrow-key guard: skip setCursor when matches is empty. Without this,
  pressing ↓ on a no-results query set the cursor to -1, making the
  highlight selector miss every row on the next render.

- Tests: add 19 unit tests covering scoreMatch ranking tiers, render
  output (empty state / row count / kbd hints / placeholder), and the
  full recents lifecycle (cap at 6, dedupe-on-push, corrupt-JSON
  recovery, per-project scoping, quota-exceeded no-op). Vitest stays
  on the node env via a small in-memory localStorage stub.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

* fix(web): QuickSwitcher review — wrap, IME, platform gate

Three follow-ups from @mrcfps's review on #556:

- ArrowUp/ArrowDown now wrap at list bounds (last → first, first → last)
  via modulo arithmetic in a new pure helper `nextCursor(current, total,
  direction)`. Previously they clamped, which contradicted the wrap
  behavior the PR test plan promised. Pulled into a pure function so
  boundary cases are unit-testable without simulating keyboard events.

- Palette's onKeyDown now early-returns on `e.nativeEvent.isComposing`,
  so users typing CJK file names through an IME keep ↑/↓/Enter for
  candidate navigation instead of having them steered by the palette.
  The global Cmd/Ctrl+P opener already had the equivalent guard.

- Global keydown is now platform-gated: macOS responds only to metaKey,
  win/linux only to ctrlKey. Previously both fired everywhere, which
  meant Ctrl+P on macOS was stealing native readline "previous line" in
  text fields (and the chat composer).

Tests: +6 unit tests for `nextCursor` covering forward/backward wrap,
mid-list moves, empty list (no division-by-zero), and single-item
no-op. Suite now 258 passing (up from 252).

Verified live: ↓ from last row → first row; ↑ from first row → last
row, in a mocked-project Playwright harness.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 10:31:50 +08:00
ferasbusiness666
e8b63ecec1
feat: add resizable chat panel (#563) 2026-05-06 10:12:45 +08:00
github-actions[bot]
241846e1ef
Update docs/assets/github-metrics.svg - [Skip GitHub Action] (#592)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-05-06 09:21:39 +08:00
Mohamed Abdallah
b064637e3f
feat(craft): accessibility-baseline module + opt-ins on dashboard, hr-onboarding, mobile-onboarding (#587)
* feat(craft): add accessibility-baseline + opt-ins on dashboard, hr-onboarding, mobile-onboarding

Module 3 of 5 in the behavioral craft series proposed in #501. Modules 1 (state-coverage, #502) and 2 (animation-discipline, #515) merged earlier today.

The differentiator that survived the corpus review is native-mobile
parity. Existing OSS prior art (fecarrico/A11Y.md, awesome-copilot,
Community-Access) covers web ARIA well, none covers Flutter Semantics,
Compose semantics, iOS UIKit/SwiftUI, or RN labelling APIs.

Secondary differentiator: jurisdictional legal-floor calibration. EAA
references WCAG 2.1 (via EN 301 549 v3.2.1), not 2.2. ADA Title II
2026-04-24 deadline slipped to 2027-04-26 via 2026-04-20 IFR. Most
existing OSS a11y prior art doesn't track either accurately.

Three-loop adversarial review pass before push (codex unavailable, ran
via substitute agent). Loop 1 caught nine cuts plus four factual fixes
including a wrong Android Compose API name. Loop 2 verified and flagged
two more trims. Loop 3 said ship.

Anchored citations: WCAG 2.2 Understanding pages, ISO/IEC 40500:2025,
ADA Title II 2024 + 2026-04-20 IFR, EN 301 549 v3.2.1, WAI-ARIA 1.3 +
AccName 1.2 + Core AAM 1.2, WebAIM Million 2025, A11yn (arXiv 2510.13914),
APCA W3C silver branch.

Refs #501.

* fix(craft): accessibility-baseline review fixes (lefarcen + mrcfps)

Address all P1/P2/P3 findings:

- P1 (lefarcen): add "Keyboard operability and semantic structure" section covering tab reachability (2.1.1), activation keys, no keyboard trap (2.1.2), focus order (2.4.3), native-control-first, document language (3.1.1), heading hierarchy (1.3.1, 2.4.6), landmarks (1.3.1, 2.4.1), text alternatives (1.1.1)
- P2 (lefarcen): expand jurisdiction scope with US Section 508 (WCAG 2.0 AA), ADA Title III caveat, EU WAD reference
- P2 (lefarcen + mrcfps): rename contrast-table row to "Normal text below 18 pt regular / 14 pt bold" so the table matches the threshold rule
- P2 (mrcfps): correct "exclusive" → "inclusive" — exact 4.5:1 / 3:1 passes; the no-rounding rule is what makes 2.999:1 fail
- P2 (lefarcen): add "Prior art and scope" note differentiating from existing OSS a11y agent docs
- P3 (lefarcen): narrow APCA framing to "not part of WCAG/EN/ADA/Section 508" and clarify size/weight-dependent thresholds
- P3 (lefarcen): expand WCAG 2.5.8 exceptions list (Spacing, Equivalent, Inline, User Agent Control, Essential)
- Common-mistakes additions: Section 508/2.1 confusion, tabindex>0 anti-pattern, modal-focus-trap distinction from 2.1.2, heading-size vs level confusion

* fix(craft): accessibility-baseline mrcfps round-2 precision fixes

All three non-blocking precision items addressed:

- Update WebAIM Million benchmark from 2025 to 2026 (February 2026 crawl). Form labels: page-level 51% (was 48.2%), input-level 33.1% (was 34.2%) of 6.9M inputs (was 6.3M). ARIA: 59.1 errors on ARIA pages vs 42 on non-ARIA (was 57 vs 27); gap is ~17 in 2026, was 30 in 2025. ARIA usage 82.7% of pages (was 79.4%). Verified directly against webaim.org/projects/million/.
- Soften keyboard/semantic-structure intro: Level A items are still labeled Level A, but 2.4.6 Headings and Labels is correctly tagged AA, and the one-h1 / no-skipped-levels rules are now framed as OD craft conventions on top of WCAG's programmatic-structure floor (1.3.1).
- Tighten <a> activation note: bare <a> without href is not focusable, not a link, and not keyboard-operable. Use <a href="…"> for navigation or <button> for actions. Added a "common mistakes" entry to lock the rule.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 09:18:59 +08:00
iulian
14a73d948b
Fix packaged contracts runtime exports (#577)
* fix packaged contracts runtime exports

* fix(packaging): prepare contracts runtime exports on install
2026-05-06 09:11:35 +08:00
Yuhao Chen
b8adcd0670
docs: add Chinese (Simplified) QUICKSTART (#578)
Translate QUICKSTART.md to QUICKSTART.zh-CN.md and add the 简体中文
entry to the language nav in all existing translations (en / de / fr /
ja-JP / pt-BR).
2026-05-06 09:08:44 +08:00
StotheC
581baeebb7
docs(readme): document OD_DATA_DIR + migration from .od/ to Desktop app (#570)
* docs(readme): document OD_DATA_DIR + migration from .od/ to Desktop app

The "Move it elsewhere" row in the First-run state table still said the
path is hard-coded; OD_DATA_DIR (resolveDataDir in apps/daemon/src/server.ts)
has supported relocation since the runtime-data refactor. Replace the
"not supported yet" note with the actual env-var usage and resolution
semantics, and add OD_MEDIA_CONFIG_DIR for the narrower credentials
override.

Add a Migrating a pre-desktop-app `.od/` section so users who started in
the repo and later installed the packaged Desktop app know:

- the two writers target different roots (repo .od/ vs.
  ~/Library/Application Support/.../namespaces/<channel>/data on macOS,
  with the platform-equivalent paths on Windows and Linux),
- how to copy projects/SQLite/artifacts/media-config.json over after
  quitting the app cleanly,
- how to keep both writers on the same dir going forward via
  OD_DATA_DIR.

Documentation only; no code changes.

* docs(readme): address review feedback on .od/ migration section

Resolves the review on #570:

- chatgpt-codex P1 / mrcfps: replace the literal `<repo>` token in the
  copy command (Bash parses `<repo>` as input redirection, so the
  documented snippet would fail before any copy). Use a shell-safe
  `REPO=` variable in the example.
- chatgpt-codex P2 / mrcfps / lefarcen P2: correct the cross-platform
  Desktop data-root. The packaged runtime resolves
  `app.getPath("userData")/namespaces/<namespace>/data` (see
  apps/packaged/src/config.ts:106-107), and Electron's `userData`
  default on Linux is `$XDG_CONFIG_HOME` / `~/.config`, not
  `$XDG_DATA_HOME`. Replace the single macOS-only path with a per-OS
  table, plus a hint to inspect the packaged daemon log for the
  resolved `daemonDataRoot`.
- lefarcen P2: list platform-specific channel namespaces. The release
  workflows append `-win` and `-linux` suffixes (release-stable-win,
  release-beta-win, release-stable-linux, release-beta-linux); only
  macOS uses the bare `release-stable`/`release-beta` strings.
- lefarcen P1 (data corruption): demote the "share one data dir between
  repo dev-server and Desktop app" recommendation to an Advanced
  callout with an explicit warning that the two writers must never run
  at the same time. The daemon opens app.sqlite in WAL mode and writes
  uncoordinated project/artifact files, so concurrent use can corrupt
  SQLite or clobber artifacts.
- lefarcen P2 (downgrade risk): add a forward-only schema migration
  warning. apps/daemon/src/db.ts applies `CREATE TABLE IF NOT EXISTS` /
  `ALTER TABLE` without a version guard, so opening a migrated dir with
  an older repo checkout can leave the workspace inconsistent. Advise
  backing up app.sqlite* before the first launch.
- lefarcen P2 (failure-safety): replace the in-place `cp -R` with a
  rsync-into-sibling-then-rename pattern so a partial copy cannot leave
  the Desktop data dir in a half-populated state. Document the restore
  path from the .fresh-baseline-* backup.
- lefarcen P2 (replace vs merge): add a preflight `ls` of the Desktop's
  existing projects and a callout that this is a replace operation, so
  users with projects on both sides can stop and choose which is
  authoritative.

Documentation only.

* docs(readme): address second review round on .od/ migration section

Resolves the follow-up review on #570 from a72b35f:

- mrcfps (blocking): require stopping the repo dev-server too, not just
  the Desktop app, before copying. Without that the source `$REPO/.od/`
  may still receive SQLite/WAL writes mid-rsync, so the staged copy can
  be inconsistent even though the Desktop target is clean. The clean-
  state callout and the bash block both now name `pnpm tools-dev stop`
  alongside the Desktop quit step.

- lefarcen P2 (fail-fast gap): the rsync block was not actually fail-
  fast — a non-zero rsync exit would still let the subsequent `mv`
  promote a partial staged copy. Added `set -euo pipefail` at the top
  of the bash block plus an explicit `|| { echo …; exit 1; }` guard on
  the rsync line so a failed copy aborts before any swap.

- lefarcen P3 (wording): "Electron's userData path" overlapped with the
  per-OS table values, since `app.getPath("userData")` already appends
  the `Open Design` segment. Renamed the table column to "<appData>
  (Electron `appData` base)" and reworded the surrounding sentence so
  the path components compose unambiguously: `<appData>/Open Design/
  namespaces/<channel>/data/`.

Documentation only.

---------

Co-authored-by: StotheC90 <StotheC90@users.noreply.github.com>
2026-05-06 09:06:31 +08:00
lefarcen
c69dee74a5
fix(release): defer Linux artifact from 0.4.0 stable 2026-05-06 01:12:26 +08:00
ferasbusiness666
036e105b98
Add spanish readme (#552) 2026-05-06 00:54:02 +08:00
bojie.hbj
29e1ed5f28
fix: 修复设计文件列表行菜单被裁剪的问题 (#561) 2026-05-06 00:46:18 +08:00
Tom
6b2792b03a
fix(daemon): remove --no-session from pi adapter to persist session files (#557)
* fix(daemon): remove --no-session from pi adapter to persist session files

The pi agent was the only adapter explicitly passing `--no-session`
in its `buildArgs`, preventing pi from writing session files.
All other adapters either run in single-shot mode by design or use
the ACP JSON-RPC session lifecycle without suppressing persistence.

Removing `--no-session` lets `--mode rpc` retain its default behavior
of writing session state, which is needed for multi-prompt continuity
and matches the rest of the harness ecosystem.

* test(daemon): add pi buildArgs regression tests; fix docs for --no-session removal

- Adds test for pi.buildArgs base shape: returns ["--mode", "rpc"]
  and does not include --no-session (prevents regression).
- Adds test for --model and --thinking option passthrough.
- Updates pi-rpc.ts lifecycle comment to remove [--no-session].
- Updates README.md and all localized READMEs to reflect the
  corrected pi CLI invocation.
2026-05-06 00:26:09 +08:00
lefarcen
74f1a18b71
fix(tools-pack): replace corepack with npx in linux container build (#558) 2026-05-06 00:05:22 +08:00
Marc Chan
0953ab58a2
fix(web): todo card dark mode styling (#526)
* fix(web): improve todo card dark mode

* fix(web): address todo card contrast feedback

Generated-By: looper 0.5.5 (runner=fixer, agent=opencode)
2026-05-05 23:57:02 +08:00
lefarcen
963bbf2500
release: Open Design 0.4.0 (#454) 2026-05-05 23:39:40 +08:00
ChildhoodAndy
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.
2026-05-05 23:31:14 +08:00
soulme
6b7a40e5c3
Fix file tab wheel scrolling (#549) 2026-05-05 23:23:48 +08:00
AImaster888
14908e1aea
fix: typo in zh-TW README (#548) 2026-05-05 22:57:41 +08:00
Justin Gao
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.
2026-05-05 22:50:25 +08:00
laihenyi
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.
2026-05-05 22:25:17 +08:00
Mason
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>
2026-05-05 22:02:05 +08:00
Martin Atrin
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>
2026-05-05 21:09:20 +08:00
Violet
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.
2026-05-05 21:02:49 +08:00