Commit Graph
109 Commits
Author SHA1 Message Date
yinjialuandGitHub e94acc2702 add cross-app import boundary check to pnpm guard (#4069)
* feat(guard): enforce the cross-app import boundary in pnpm guard

Adds a cross-app import check that scans apps/* sources for imports
reaching into another app (relative paths, @open-design/<app> package
specifiers, or apps/-rooted paths) and fails pnpm guard with the
offending file:line. The web/daemon integration boundary (HTTP APIs +
packages/contracts) was previously enforced only by human review.

The deliberate packaged -> desktop ./main export is allowlisted with a
documented reason; further exceptions must be added the same way.

* fix(guard): harden cross-app import scanning

Generated-By: looper 0.9.6 (runner=fixer, agent=codex)

* fix(guard): fail on unreadable app manifests

Generated-By: looper 0.9.6 (runner=fixer, agent=codex)

* fix(guard): reject unnamed app manifests

Generated-By: looper 0.9.6 (runner=fixer, agent=codex)

* fix(guard): catch require.resolve app imports

Generated-By: looper 0.9.6 (runner=fixer, agent=codex)

* fix(guard): detect createRequire app imports

Generated-By: looper 0.9.6 (runner=fixer, agent=codex)

* fix(guard): catch CommonJS node module createRequire

Generated-By: looper 0.9.6 (runner=fixer, agent=codex)
2026-06-10 11:40:31 +00:00
6869b1208b fix(plugins-home): correct deck/scroll preview capture + smoother gallery playback (#4044)
* fix(bake): classify deck-vs-scroll by viewport, real-wheel pan, motion config

Systematic audit of all 126 baked previews surfaced three capture bugs:

- 2 vertical pages misread as decks (the input probe wheel-scrolled them and the
  scroll-driven animation looked like a slide change), so they got walked
  sideways. Classify by viewport height instead: a fixed-viewport page is a deck,
  a vertically-scrollable page is a landing page (pan it) even with a horizontal
  marquee/carousel sub-component.
- 9 scroll-hijack landing pages (custom/transform scroll) that window.scrollTo
  can't move, so the pan was static. Pan those with REAL wheel events
  (page.mouse.wheel), which drive the page's own scroll handler.
- single-screen pages now hold (static) instead of being forced down a deck path.

Plus an opt-in override: authors can declare od.preview.motion ('scroll' | 'deck'
| 'static') and the bake honors it, auto-detecting only when it's absent. Schema
+ plugins-spec document the field. (Also strips a stray NUL byte from the hash
line that made the file read as binary.) BAKE_VERSION -> 4 re-bakes everything.

* perf(plugins-home): only decode visible gallery clips + stream first frame

Two cheap wins for the baked gallery videos:

- Decouple mount from play. The tile mounts the <video> across the wider inView
  margin (so scroll-in/hover never remounts + reloads), but only PLAYS while
  truly visible — off-screen tiles in the mount margin hold their poster frame
  paused instead of all running a simultaneous decode. Adds a 0-margin visible
  observer in PreviewSurface alongside the existing near one.
- preload=metadata instead of auto: paints the first frame off the +faststart
  header instead of eagerly buffering the whole clip up front, so tiles show fast
  and don't saturate the network. The idle hold buffers the pan before hover.

* perf(plugins-home): keep baked clips mounted across a scroll window

Scrolling a tile out of view and back re-showed a load even though the clip
bytes are HTTP-cached (R2 immutable): the <video> unmounted at the tight 120px
margin, so scroll-back remounted a fresh element that re-fetches metadata and
re-decodes the first frame. Add a wide keep-mounted observer (~1500/1800px) so a
clip stays mounted for a few screens — instant scroll-back — while iframes keep
the tight margin and play stays gated to the truly-visible zone (paused, not
unmounted, off screen).

* fix(bake,contracts): probe scroll mechanism before recording; validate motion

Address review:
- Move the window.scrollTo probe before Page.startScreencast so its scrollTo
  160 -> 0 jump isn't baked into the head of the pan as a visible lurch.
- Type od.preview.motion in the Zod PluginManifestSchema (enum scroll|deck|
  static) so an invalid value fails doctor/install instead of silently parsing
  via passthrough and being ignored by the bake; add contract test coverage.

* fix(bake): auto-detect single-screen fixed pages as static, not deck

A fixed-viewport page is only a deck if an input actually advances it; probe the
driver during auto-detect and fall back to 'static' (default viewport + a hold)
when nothing moves it, instead of routing every non-scrollable page through the
deck path where walkSlides(null) just held at the deck-sized capture. Extracted
the arrow/wheel probe into probeDeckDriver(). Verified: a waitlist page now bakes
a 2.5s static hold, guizang still walks, acreage still pans.

---------

Co-authored-by: audit <a@b.c>
2026-06-10 05:43:50 +00:00
9b06b6df78 perf(bake): bound the deck slide-walk so huge-DOM decks don't run long (#4029)
A deck that renders every slide side-by-side in one giant rail
(#deck{width:10000vw}) has thousands of DOM nodes. deckSignal called
getBoundingClientRect + getComputedStyle on ALL of them to fingerprint the
current slide, which is O(n) layout reads — fast locally but ~3s/scan in CI,
dragging guizang's walk (and its clip) out to 21.7s while every other deck
stayed <=10s.

Cap deckSignal's scan to the first 600 elements (the slide rail/track is a
structural node near the top of the DOM, so this still detects slide changes —
verified guizang still walks to its later slides), and add an 8s wall-time
backstop on the walk so a clip can never run long even if signal reads are slow.
BAKE_VERSION -> 3 re-bakes everything.

Co-authored-by: audit <a@b.c>
2026-06-10 01:53:12 +00:00
31cf0e0f0a fix(plugins-home): deck slide-tour bakes, CJK font fix, framing + reveal height (#4020)
* fix(plugins-home): anchor baked preset previews to the hero top

The example-prompt preset tiles render wider than the gallery's 1.31:1 baked
clip, so object-fit:cover was cropping the hero headline out of the vertical
middle. Anchor the preset video/poster to the top so the hero stays in frame.
Scoped to the preset cards; the Community grid (which matches the clip aspect)
is untouched.

* fix(plugins-home): bake decks as slide tours, fix CJK font tofu, unclip reveal

Three gallery-preview fixes found reviewing the baked Community gallery:

- Decks (fixed-viewport PPT/slideshow pages driven by arrow/wheel, not scroll)
  were vertically panned like tall landing pages — capturing ~20s of a dead
  WebGL background at the wrong 1.31 aspect (the page's compact responsive
  variant, hero headline gone). The bake now detects them (page no taller than
  the viewport), re-renders at 16:9, and walks their slides (arrow keys, falling
  back to wheel then a "next" control, detected by a structural slide signal)
  for a slide-tour the gallery loops on hover. BAKE_VERSION -> 2 re-bakes all.
- CJK-heavy templates baked tofu boxes: they pull Noto Serif/Sans SC from Google
  Fonts with display=swap and the CI runner had no CJK fallback. The bake job now
  installs fonts-noto-cjk + emoji, and the bake double-awaits fonts.ready around a
  force-load so a late-registered display face isn't captured as its fallback.
- The Home templates reveal clipped its last rows: a fixed max-height:6000px
  ceiling + overflow:hidden, but the gallery is ~7300px and grows. Switched to the
  repo's canonical grid-template-rows 0fr->1fr auto-height pattern (inner wrapper
  owns the overflow) so it expands to the gallery's natural height.

* fix(bake): probe-detect deck nav + capture at the 1.31 tile aspect

Refines the deck path after live review:

- Detection was scrollHeight-based, so a deck whose DOM stacks slides
  vertically got misread as a scroll page and vertically panned. Now PROBE the
  navigation: press the arrow key, then nudge the wheel, and use whichever
  actually moves a slide (deckSignal ignores the WebGL background); only a page
  that neither navigates nor fits the viewport keeps the linear pan.
- Captured decks at 16:9, which object-fit:cover then side-cropped in the 1.31
  tile (hero edges cut). Decks collapse to a compact variant at the normal 1440
  width, NOT at the 1.31 aspect — so capture at 1.31 (1760x1344, wide enough to
  clear the breakpoint): full layout AND a clip that fills the tile, no crop.

---------

Co-authored-by: audit <a@b.c>
2026-06-09 19:04:46 +00:00
c2d16727cd feat(plugins-home): content-hashed preview filenames + immutable CDN caching (#4007)
Baked clips are served from R2 behind Cloudflare's CDN (cf-cache-status: HIT).
Previously a re-bake overwrote the same key (example-x.mp4), so the edge kept
serving the stale clip until its TTL expired. Name each clip
example-x.<contentHash>.mp4 instead: a content change ships a NEW URL the
manifest points at, the old edge entry is simply no longer referenced, and the
upload sets Cache-Control: public, max-age=31536000, immutable so the CDN can
cache each clip forever.

Co-authored-by: audit <a@b.c>
2026-06-09 14:12:05 +00:00
d0f350e825 feat(plugins-home): pre-baked hover-pan preview clips for the gallery (#3994)
* feat(plugins-home): pre-baked hover-pan preview clips for the gallery

The Community gallery renders every html plugin as a live, scaled
example.html iframe that animates + auto-pans on hover. That is
GPU-expensive at scale (each tile is its own out-of-process document
re-compositing a tall page) and renders inconsistently for tricky pages
(WebGL noise, video backgrounds, lazy content).

Pre-render each preview to a tiny H.264 clip + first-frame poster:

- scripts/bake-plugin-previews.mjs: headless-Chrome screencast of a
  [hold@top in-place animation][linear pan top->bottom] capture, waiting
  on fonts + <img> + CSS background-images + <video> backgrounds first,
  then ffmpeg -> CFR H.264 mp4 + poster.jpg + manifest.json. Velocity is
  pre-computed from page height so the pan always finishes within ~10s.
  Runtime deps (puppeteer-core / Chrome / ffmpeg) stay out of package.json
  and are provided by the CI environment.
- daemon: serves <out> at /api/plugin-previews and attaches the clip to a
  plugin record under od.bakedPreview (a SEPARATE field — the detail modal
  still reads od.preview and opens the live, interactive page).
- web: inferPluginPreview(record, { preferBaked: true }) lets gallery tiles
  opt into the clip; MediaSurface loops the in-place [0, holdMs] span while
  idle and plays the pan on hover, one always-mounted <video> (no black
  flash), looped frame-accurately via requestVideoFrameCallback, with no
  native controls. Plugins without a bake keep the live-iframe fallback.

CI upload to R2 + the post-merge/nightly bake workflow (with content-hash
skip) and the daemon on-demand path land in follow-ups.

* feat(plugins-home): content-hash skip so unchanged plugins reuse their baked clip

The bake now hashes each plugin's preview HTML + a BAKE_VERSION and stores it
in the manifest. Re-running skips any plugin whose hash is unchanged (no render,
no re-encode, and the CI step re-uploads nothing) — editing the page or bumping
BAKE_VERSION invalidates it. Verified: a second pass over already-baked plugins
reuses all of them in ~1s instead of re-rendering.

* feat(plugins-home): point baked-preview URLs at R2 in production

bakedPreviewBlock now builds its poster/video URLs from
OD_PLUGIN_PREVIEWS_BASE_URL (the R2 public origin) when set, falling back to
the daemon's own /api/plugin-previews static route for local dev. The CI bake
uploads the clips to R2 and the deployed daemon points at them there.

* feat(plugins-home): CI workflow to bake + publish plugin previews

Adds .github/workflows/bake-plugin-previews.yml: post-merge (paths:
plugins/_official) + nightly + manual. Each run starts the daemon, bakes ALL
plugins (the content-hash skip makes that cheap — only changed pages re-render,
PREVIEW_REMOTE trusts the manifest hash since CI clips live on R2 not on disk),
`aws s3 cp`s the new clips to R2 (no --delete, so untouched clips stay), and
commits the refreshed manifest back to main.

- The daemon now reads the checked-in manifest from data/plugin-previews/ by
  default (binaries stay on R2; OD_PLUGIN_PREVIEWS_DIR still overrides locally),
  seeded here with an empty manifest so every plugin starts on the live-iframe
  fallback until the first bake lands.

Verification needs a real CI run (R2 secrets + a daemon in CI); the bake script,
hash skip, daemon injection, and web display are all already verified locally.

* ci(plugin-previews): open a reviewed PR for the manifest instead of pushing to main

Protected main can't take a direct push, and the manifest is version-pinned
(ships with the build), so the bake now opens a PR with the refreshed
data/plugin-previews/manifest.json and requests review from @lefarcen rather
than committing straight to main. Only fires when a plugin actually changed.

* ci(plugin-previews): fix invalid YAML — single-line PR body (@ in body broke the literal block)

* ci(plugin-previews): TEMP branch trigger + debug guards (limit 3, skip publish off-main)

* ci(plugin-previews): install puppeteer-core via pnpm (npm chokes on workspace:*)

* ci(plugin-previews): correct R2 secrets (repository-assets bucket) + TEMP branch publish test

* ci(plugin-previews): revert temp branch-debug toggles (workflow verified in CI)

* fix(plugins-home): gate bakedPreview on a fetchable source + fix workflow shellcheck

Review feedback (nettee):
- bakedPreviewBlock now only attaches a baked preview when a remote origin
  (OD_PLUGIN_PREVIEWS_BASE_URL) is set OR the clip files exist on disk. A
  deployment reading the checked-in manifest without the base URL set would
  otherwise emit /api/plugin-previews URLs that 404 (binaries live on R2),
  breaking tiles instead of falling back to the live iframe.
- workflow: `for _` instead of unused `for i` (SC2034) and split the CHROME
  declare/export (SC2155) so the actionlint gate passes.

* fix(plugins-home): log manifest load failures instead of swallowing them

Review feedback (nettee, non-blocking): loadManifest() caught every read/parse
error and returned {}, so a malformed manifest would silently disable all baked
previews with no trace. Warn so it's diagnosable.

* feat(plugins-home): use baked previews on the example-prompt preset tiles too

The HomeHero '示例提示词' preset tiles render the same plugin previews via
PreviewSurface; pass preferBaked so they get the cheap poster + hover-pan clip
instead of a live iframe, matching the gallery.

* ci(plugin-previews): grant pull-requests: write so the manifest PR step can open its PR

Review feedback (nettee): the permissions block only set contents: write, so
pull-requests defaulted to none and gh pr create would 403 on the first run that
changes the manifest.

---------

Co-authored-by: audit <a@b.c>
2026-06-09 13:14:54 +00:00
PerishFireandGitHub f9433a7a07 release: harden packaged launcher validation (#3995)
* Unify release metadata publishing

* Allow empty release asset suffix

* Harden beta-s release publishing

* Clean beta Windows release namespace

* Clean Windows launcher namespace

* Retry transient mac notarization uploads

* Control mac notarization upload mode

* Notarize release mac DMGs after build

* Harden release mac DMG notarization retries

* Make beta-s mac updates payload-first

* Bake mac updater metadata URL

* Add unsafe DMG install helper

* Fix beta-s feed and About version

* Improve release validation observability

* Build launcher proto before packaging

* Notarize release-stable mac artifacts

* Enable mac notarization in tools-pack

* test: update packaged release workflow assertions
2026-06-09 11:50:01 +00:00
7231c891f8 Allow release-stable preflight dry runs (#3857)
* Allow release stable preflight dry runs

* Fix stable dry-run nightly branch validation

Generated-By: looper 0.9.5 (runner=fixer, agent=codex)

---------

Co-authored-by: Looper <looper@noreply.github.com>
2026-06-08 04:46:02 +00:00
e2dc6423cd design-systems: guard component manifest token references (#3834)
Co-authored-by: chaoxiaoche <chaoxiaoche@chaoxiaochedeMacBook-Pro.local>
2026-06-07 12:46:16 +00:00
a2809ea336 design-systems: backfill 2.0 package batch 09 (#3791)
* design-systems: backfill 2.0 package batch 09

* fix: repair design token source references

* fix: update latest design token source references

* fix: tighten design token source validation

---------

Co-authored-by: chaoxiaoche <chaoxiaoche@chaoxiaochedeMacBook-Pro.local>
2026-06-07 10:17:03 +00:00
a3a222c6c0 fix: small UX/correctness fixes (composer, media settings, run status, nav tabs) (#3814)
* fix(web): drop the border around the composer "+" trigger

The base button{} rule applied a 1px border to the ComposerPlusMenu
trigger, leaving a visible box around the home composer's "+" icon. Make
the trigger transparent (border + background) with a subtle hover, so it
reads as a plain icon button consistent with the project composer.

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

* feat(web): defer media generation settings to in-task AI questions

HyperFrames / Image / Video / Audio composer modes no longer surface
inline pre-flight dropdowns (aspect ratio, duration, model, resolution,
audio kind). Image/Video keep only the design-system picker; HyperFrames
and Audio keep none. Those settings are now asked for by the agent during
the run via the existing question-form / AskUserQuestion flow, mirroring
how Prototype and Slide deck already defer their settings.

- footerInputNamesForChip: image/video -> ['designSystem'], hyperframes/
  audio -> [].
- metadataForHomeMediaComposer no longer seeds imageAspect/videoAspect/
  videoLength/audioKind/audioDuration; only kind (+ the hyperframes-html
  route discriminator) and any picked prompt template.
- queryTemplateForSurface drops the {{ratio}}/{{duration}}/{{model}}/
  {{resolution}}/{{voice}} slots from the prompt body.
- system.ts: image now prints "(unknown - ask: ...)" for model/aspect
  instead of silently defaulting, so the agent asks (video/audio already
  did).

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

* fix(daemon): don't mark a run failed when it produced an artifact

classifyChatRunCloseStatus decided run status purely from the process
exit (code/signal/turnCompletedCleanly) and never checked whether the run
actually produced an artifact. A non-zero exit during teardown (e.g. a
SessionEnd hook) after the deliverable was already written showed a red
"failed" card for work that succeeded.

Add an artifact-aware carve-out: a non-zero NORMAL exit (real exit code,
never a signal) that produced a confirmed artifact this run is classified
succeeded. Gated on code != null && code !== 0 so a signal kill
(OOM / external kill / container shutdown) is never flipped, preserving
the existing guard. The signal comes from scanRunEventsForRetrySideEffects
(artifactWriteSeen || liveArtifactSeen).

Also add a one-shot backfill script (pnpm backfill:failed-runs) that
repairs existing rows: failed runs whose project dir contains an
*.artifact.json are corrected to succeeded.

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

* fix(web): persist the entry nav-rail expanded state

The rail's open/collapsed state lived only in EntryShell's useState, so it
reset to collapsed whenever EntryShell remounted — e.g. returning to home
after visiting a project, or a reload. Persist it to localStorage
(SSR-guarded read/write; App is loaded with ssr:false so there's no
hydration mismatch) so the rail keeps its state across navigation and
reloads.

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

* fix(web): collapse all entry sections into the single leftmost tab

Clicking a sidebar section (Projects / Automation / Design systems /
Plugins / Integrations) opened a second workspace tab instead of reusing
the leftmost one. Treat the leftmost tab as a single entry-tab singleton
(any view) rather than a Home-view singleton: navigating to any entry view
switches that one tab's view in place, and its label follows the view.
Project / marketplace tabs are unchanged and still open to the right.

- syncStateToRoute: any kind:'home' route reuses the entry tab found by
  kind alone and updates its view; project-route guard broadened so
  opening a project from any entry view appends rather than replaces.
- normalizeTabsState: dedup / must-exist / leftmost-pin invariants keyed
  by kind==='entry' instead of view==='home'.
- The non-closable / pinned / drag-pin / new-tab-reuse sites switch from
  view==='home' to kind==='entry'.

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

* fix(scripts): correlate backfill repair to the run that produced the artifact

The failed-runs backfill was scoped only by projectId: a single
*.artifact.json anywhere under <dataDir>/projects/<id> flipped every
failed message row in that project to succeeded. Project dirs are
long-lived and accumulate sidecars from unrelated runs, so one
successful artifact reclassified unrelated real failures — an
irreversible data-integrity bug once run without --dry-run.

Now a row is repaired only when the failed message's own
produced_files_json lists a file whose <name>.artifact.json sidecar
still exists on disk, mirroring the daemon's artifactProducedThisRun
carve-out. Path-traversal/absolute refs are rejected.

Generated-By: looper 0.8.1 (runner=fixer, agent=claude-code)

* fix(web): strip deferred media defaults from the forwarded run inputs

Hiding the media footer pills (model / ratio / resolution / duration /
audioType / voice) stopped them rendering but did not stop their seeded
defaults from reaching the run. buildHomeMediaComposer still seeds
`ratio: 16:9`, `duration: 5`, `audioType: speech`, etc., and submit()
forwarded submittedActive.inputs as pluginInputs after stripping only
fidelity / slideCount / speakerNotes — so an Image/Video/Audio/HyperFrames
run arrived with baked-in defaults and the first-turn AskUserQuestion
discovery flow had nothing left to ask.

Extend ARTIFACT_FOOTER_FIELD_NAMES to cover the deferred media fields, and
split submit() into apply-inputs vs forwarded-inputs: the plugin is still
(re)applied with the full inputs (od-media-generation validates `subject`),
while only the stripped set is forwarded to onSubmit. Computing
inputsEqual against the apply-inputs avoids a spurious re-apply round-trip
on submit. subject / style / aspect / mediaKind are intentionally kept.

Red spec: tests/components/HomeView.media-options.test.tsx "strips deferred
media settings from the forwarded pluginInputs" — red on the pre-fix
branch (pluginInputs.model === doubao-seedance-2-0-260128), green here.

Generated-By: looper 0.8.1 (runner=fixer, agent=claude-code)

* fix(web): assert prototype fidelity deferral on the forwarded run inputs

The deferred-media-defaults change re-applies the plugin with its full
inputs (hyperframes needs `model` to pick its pipeline, od-media-generation
needs `subject`), so the prototype apply call now legitimately carries
`fidelity`. HomeView.prefill's "binds the Home rail Prototype chip" case
still asserted `fidelity` was absent from the apply-call body, which is the
wrong surface — the deferral invariant is that `fidelity` must not reach the
run, not that it is stripped before apply.

Move the assertion onto the forwarded `pluginInputs` from onSubmit, where the
deferral actually holds, and note in HomeView why hyperframes keeps `model`
at apply time. No source behavior change.

Generated-By: looper 0.8.1 (runner=fixer, agent=claude-code)

* fix(web): strip deferred media defaults from the run-facing snapshot too

Stripping the deferred footer/media fields from onSubmit.pluginInputs was
not enough: submit() still re-applied the plugin from the FULL inputs and
forwarded that snapshot's id as appliedPluginSnapshotId. The daemon renders
`## Plugin inputs` verbatim from snapshot.inputs (server.ts pluginPromptBlock,
packages/contracts plugin-block.ts) and tells the agent not to re-ask about
anything listed there, so an Image/Video/Audio/HyperFrames run still arrived
with `ratio: 16:9` / `duration: 5` / `model: …` baked into the prompt and the
first-turn AskUserQuestion discovery flow stayed suppressed.

Resolve the run-facing snapshot from the deferral-stripped inputs and compare
inputsEqual against the cached snapshot's inputs so the strip forces a fresh
apply. Stripping only removes non-required fields (subject / style / aspect /
mediaKind survive, and no scenario plugin requires a stripped field), so the
od-media-generation apply still validates.

Regression at the prompt/run boundary: tests/components/HomeView.media-options
"resolves the run-facing snapshot from inputs with the deferred media settings
stripped" asserts the apply-call body that yields appliedPluginSnapshotId (the
source of snapshot.inputs) carries no deferred field while subject survives.

Generated-By: looper 0.8.1 (runner=fixer, agent=claude-code)

---------

Co-authored-by: qiongyu1999 <2694684348@qq.com>
Co-authored-by: Claude Opus 4 <noreply@anthropic.com>
2026-06-07 08:35:31 +00:00
7a1ad1a438 feat(packaged): add launcher payload updates (#3812)
* feat(packaged): add launcher payload runtime

* ci: focus launcher payload windows smoke

* ci: publish beta mac x64 launcher payload

* test(e2e): harden payload updater smoke

* fix(pack): inject launch config for installed windows smoke

* fix(daemon): allow packaged payload resource roots

* fix(updater): relaunch after payload update

* test(e2e): refresh windows updater UI status

* test(e2e): ensure windows smoke reaches main shell

* test(e2e): skip onboarding before windows updater smoke

* fix(updater): detach windows payload relaunch helper

* test(e2e): run payload smoke without updater dry run

* fix(desktop): relaunch windows payload updates on quit

* fix(updater): preserve installed payload relaunch target

* fix(updater): require launcher target for payload updates

Generated-By: looper 0.9.5 (runner=fixer, agent=codex)

* test(e2e): align mac x64 artifact mode assertion

* test(e2e): canonicalize launcher relaunch root

* fix(updater): validate launcher payload config before activation

Generated-By: looper 0.9.5 (runner=fixer, agent=codex)

* fix(updater): require live launcher target for payload updates

Generated-By: looper 0.9.5 (runner=fixer, agent=codex)

---------

Co-authored-by: Looper <looper@noreply.github.com>
2026-06-07 07:38:57 +00:00
b3b5bbeced design-systems: backfill 2.0 package batch 01 (#3781)
* design-systems: backfill 2.0 package batch 01

* fix: repair design-system token audit references

* fix: update design token source references

---------

Co-authored-by: chaoxiaoche <chaoxiaoche@chaoxiaochedeMacBook-Pro.local>
2026-06-06 14:49:28 +00:00
67a8d7cc8e Add derived design-system token outputs (#3734)
* Add derived design system token outputs

* Harden derived design token output guards

---------

Co-authored-by: chaoxiaoche <chaoxiaoche@chaoxiaochedeMacBook-Pro.local>
2026-06-05 11:33:22 +00:00
2df76ee0c9 Improve design system token import contract (#3719)
Co-authored-by: chaoxiaoche <chaoxiaoche@chaoxiaochedeMacBook-Pro.local>
2026-06-05 07:12:40 +00:00
8f6cdaaba1 Harden release-beta-s self-hosted beta lane (#3641)
* Fix Windows smoke launcher payload layout

* Harden release-beta-s runner probe

* Use cmd shell for release-beta-s probe

* Add win beta build script for self-hosted lane

* Keep release-beta-s checkout lightweight

* Use explicit local beta version for release-beta-s

* Install dependencies in beta build script

* Repair Electron dist before Windows beta build

* Add release-beta-s timings and diagnostics

* Polish release-beta-s observability guardrails

* Trace tools-pack cache materialization

* Reuse materialized workspace build cache

* Trace Windows packaging segments

* Trace Windows archive process details

* Reuse installer unpacked materialization

* Preserve reusable Windows unpacked projection

* Add fast smoke telemetry for self-hosted beta

* Cache Windows archive outputs for beta lane

* Tighten fast Windows smoke lane

* Scope Windows beta artifact reporting by target

* Clean stale Windows target artifacts

* Wire Windows Authenticode signing

* Expose self-hosted beta validation modes

* Add core Windows smoke profile

* Decouple core smoke from updater fixture version

* Trace Windows smoke lifecycle steps

* Skip unpacked materialization on NSIS cache hit

* Add Nexu S3 beta publisher

* Harden self-hosted Windows beta lane

* Use Windows PowerShell for publish probe

* Run publish probe via repo script

* Require explicit self-hosted S3 public origin

* Run real installer acceptance for external feeds

* Skip ready-prompt checks for external feeds

* Relax optional self-hosted update inputs

* Tolerate BOM in self-hosted publish probe

* Converge self-hosted beta metadata and signing flow

* Run self-hosted beta metadata prep on the runner lane

* Use Windows PowerShell for self-hosted beta metadata checks

* Bypass execution policy in self-hosted beta metadata checks

* Split self-hosted beta metadata publish

* Suppress mc output in beta publish helpers

* Split Windows NSIS payload cache layers

* Require fresh tool dist metadata

* Preserve Windows overlay payload paths

* Default beta-s gate to core

* Optimize win beta packaging reuse

* simplify windows full smoke lifecycle

* preserve onboarding state after windows upgrade smoke

* fix windows tools-pack test portability

* recover stale tools-pack locks

* Allow auto signing fallback for beta builds

* Add self-hosted beta mac arm64 lane

* Quote self-hosted signing choices

* Run self-hosted beta metadata on mac lane

* Use shallow metadata checkout on self-hosted beta

* Use sparse beta metadata checkout

* Make mac release profile bash-compatible

* Allow file sparse metadata checkout

* Isolate self-hosted metadata checkout

* Clear sparse skip-worktree before mac build

* Isolate self-hosted mac build checkout

* Run self-hosted beta publish without aws cli

* Use unsigned beta prefix for mixed platform publish

* Sparse checkout self-hosted beta publish

* Publish mac beta platform before metadata

* Pass mac publish release profile

* Probe mac signing keychain import

* Expand mac signing preflight variants

* Use sudo keychain helper for self-hosted mac signing

* Route self-hosted mac codesign through sudo wrapper

* Normalize mac signing identity name

* Harden self-hosted mac notarization

* Optimize self-hosted mac release cache

* Fix mac signing helper cleanup

* Retry transient mac notarization uploads

* Keep mac notarization fail-fast

* Reduce mac symlink diagnostics noise

* Normalize self-hosted beta platform inputs

* chore: bump beta base version to 0.9.1

* chore: tune release tools-pack cache retention

* test: add temporary cache validation marker

* chore: key windows nsis base payload by content

* Revert "test: add temporary cache validation marker"

This reverts commit e8487bfd3e.

* chore: probe windows nsis payload cache before materializing

* chore: align self-hosted beta smoke modes

* chore: skip mac smoke report upload when disabled

* chore: default self-hosted beta to publish both platforms

* chore: make beta signing modes explicit

* Add release report artifacts and metatool metadata

* Fix Windows release report zip publishing

* Remove artifact handoff from release beta self-hosted lane

* Fix release beta merge follow-ups

* Fix release beta install regressions

* Restore web build dependencies

* Route Windows beta downloads through mirrors

* Use PowerShell 7 for Windows beta lane

* Fix release beta preflight gates

Generated-By: looper 0.9.4 (runner=fixer, agent=codex)

* Fix Windows beta smoke update reuse

Generated-By: looper 0.9.4 (runner=fixer, agent=codex)

* Fix release beta review follow-ups

* Refresh Nix pnpm dependency hashes

Generated-By: looper 0.9.4 (runner=fixer, agent=codex)

* Fix Windows signtool fallback resolution

* Reject stale beta platform manifests

* Validate beta platform manifest run identity

Generated-By: looper 0.9.4 (runner=fixer, agent=codex)

* Validate beta manifest commit identity

Generated-By: looper 0.9.4 (runner=fixer, agent=codex)

* Allow beta metadata publish reruns

Generated-By: looper 0.9.4 (runner=fixer, agent=codex)

* Build tools-pack fully in beta Windows bootstrap

Generated-By: looper 0.9.4 (runner=fixer, agent=codex)

* Emit r2 metadata for Windows beta publish

Generated-By: looper 0.9.4 (runner=fixer, agent=codex)

* Stabilize beta publish browser test

Generated-By: looper 0.9.4 (runner=fixer, agent=codex)

* Stabilize Windows beta metadata smoke test

Generated-By: looper 0.9.4 (runner=fixer, agent=codex)

* Restore multi-platform Vela CLI package

* Refresh Nix pnpm dependency hashes

Generated-By: looper 0.9.5 (runner=fixer, agent=codex)

---------

Co-authored-by: Looper <looper@noreply.github.com>
2026-06-05 03:00:55 +00:00
7403dc681e refactor: move daemon routes into routes dir (#3568)
* refactor: move daemon routes into routes dir

* fix: restore components typecheck dependencies

* fix: update host tools route test import

Generated-By: looper 0.9.4 (runner=fixer, agent=codex)

* fix: restore review follow-up patches

* fix: tighten daemon route typing

---------

Co-authored-by: Looper <looper@noreply.github.com>
2026-06-04 07:39:18 +00:00
67077fd36f chore(docs): move translated docs into docs/i18n/ (#3621)
* chore(docs): move translated docs into docs/i18n/

Collect the translated README/QUICKSTART/CONTRIBUTING/MAINTAINERS files
(including the Korean set) into docs/i18n/, leaving only the English sources
in the repo root so the GitHub project home page file list stays clean.
Rewrite internal links for the new layout (../../ for repo-root resources,
sibling filenames between translations), update both switcher conventions,
the i18n-check mixed-layout support, the contributors-wall workflow globs,
TRANSLATIONS.md guidance, and drop now-dead root translation paths from the
fork-PR docs allowlist.

* fix(docs): correct root-relative links in Korean contribution guide

Prefix repo-root targets (scripts/sync-design-systems.ts, TRANSLATIONS.md,
package.json, .github/pull_request_template.md) with ../../ so they resolve
from the new docs/i18n/ depth; sibling translated docs stay bare.

Generated-By: looper 0.8.1 (runner=fixer, agent=claude-code)

---------

Co-authored-by: qiongyu1999 <2694684348@qq.com>
2026-06-04 06:55:16 +00:00
Thinh NguyenandGitHub 30f58ce824 fix: update anthropics/skills upstream URLs to use skills/ subdirectory (#3548) 2026-06-04 03:58:27 +00:00
Tom HuangGitHubopen-design-bot[bot] <282769551+open-design-bot[bot]@users.noreply.github.com>qiongyu1999Siri-Ray
c6722d2671 feat: Lexical composer, interactive terminals, comment attachments & browser reference board (#3516)
* feat(daemon): add interactive terminal support with node-pty

- Introduced a new terminal service to manage interactive terminal sessions.
- Added routes for creating, streaming, and managing terminal sessions in the daemon.
- Integrated terminal functionality into the CLI, allowing users to open interactive shells.
- Updated project routes to support conversation seeding for side chats.
- Enhanced the web application to include terminal tab functionality and UI components.

This feature enables users to interact with a terminal directly within the application, enhancing the overall user experience and providing a more integrated development environment.

* feat(web): implement embedded browser module in Design Files workspace

- Added a `+` icon to the Design Files tab for opening a new Browser module.
- The Browser module supports navigation features including back, forward, refresh, and address input.
- Integrated a curated list of design reference URLs for user convenience.
- Implemented browser data clearing functionality via IPC.
- Enhanced desktop runtime to support embedded browser with appropriate security measures.
- Added tests for browser functionality and URL handling.

This commit establishes a new workspace for browsing and referencing design resources directly within the application, improving user experience and accessibility to design tools.

* refactor(web): enhance add tab menu functionality in FileWorkspace

- Updated the add tab button to toggle the visibility of the menu with improved accessibility attributes.
- Refactored the add menu to be portaled to the document body for better positioning and visibility.
- Adjusted CSS styles for the add menu to use fixed positioning and increased z-index for proper layering.
- Minor CSS adjustments in entry layout for consistent padding.

These changes improve the user experience when adding new modules in the FileWorkspace, ensuring the add menu is more accessible and visually consistent.

* feat(daemon): introduce session mode for conversations

- Added a new `session_mode` column to the `conversations` table with a default value of 'design'.
- Implemented logic to handle `session_mode` in conversation creation, updates, and retrieval.
- Enhanced the API to support `session_mode` in conversation requests, allowing for 'chat' or 'design' modes.
- Updated the web application to include a session mode toggle, enabling users to switch between chat and design modes seamlessly.
- Adjusted system prompts to reflect the current session mode, providing context-aware responses.

This feature enhances the user experience by allowing for more flexible conversation management, catering to different interaction styles.

* feat(web): enhance navigation and settings functionality in DesignBrowserPanel and EntryShell

- Introduced a navigation stack in DesignBrowserPanel to manage back and forward navigation states.
- Updated the browser navigation logic to handle URL history and improve user experience.
- Added a settings menu in EntryShell for quick access to language and appearance options.
- Implemented CSS styles for the new settings menu, ensuring a consistent and user-friendly interface.
- Enhanced tests for navigation functionality and settings menu interactions.

These changes improve the overall usability of the application by streamlining navigation and providing easy access to settings.

* feat(daemon): enhance conversation session mode handling

- Added a new `mode` flag to CLI commands for project and conversation creation, allowing users to specify 'design' or 'chat' modes.
- Implemented `normalizeChatSessionModeFlag` function to validate and normalize session mode inputs.
- Updated project routes to handle session mode during conversation creation and updates.
- Enhanced web components to support session mode changes, including new props and handlers for managing session modes in conversations.
- Adjusted UI elements to reflect the current session mode, improving user experience and interaction flexibility.

This update provides a more robust framework for managing conversation modes, catering to diverse user needs and enhancing overall functionality.

* feat(web): enhance HandoffButton and DesignBrowserPanel with improved functionality and styling

- Updated HandoffButton to support framework-specific CLI prompts and improved local project path handling.
- Enhanced DesignBrowserPanel to manage browser history with favicon support and improved address display.
- Introduced new utility functions for formatting addresses and extracting hostnames.
- Refactored CSS styles for better layout and responsiveness across components.
- Added tests for new functionalities in HandoffButton and DesignBrowserPanel, ensuring robust behavior.

These changes improve user experience by streamlining the handoff process and enhancing the design browsing capabilities within the application.

* feat(web): enhance HandoffButton and ProjectView with improved instructions handling and UI updates

- Updated HandoffButton to include a tabbed interface for switching between editor and CLI options, enhancing user experience.
- Added support for opening the AMR website directly from the HandoffButton.
- Refactored ProjectView to implement a modal for custom instructions, allowing users to edit and review instructions more intuitively.
- Improved CSS styles for project instructions modal and handoff menu, ensuring better layout and responsiveness.
- Added keyboard accessibility for closing the instructions modal with the Escape key.

These changes streamline the handoff process and improve the usability of custom instructions within the application.

* feat(daemon): add social share functionality and project folder management

- Introduced new `share` command in CLI for building localized social-share targets for Open Design projects.
- Implemented `printShareUsage` and `runShare` functions to handle share requests and display usage instructions.
- Added API routes for social sharing, allowing users to create shareable links for projects.
- Enhanced project routes with new endpoints for listing and creating project folders, improving project organization.
- Updated relevant files and tests to support new functionalities, ensuring robust behavior.

These changes enhance user experience by facilitating social sharing and better project management within the application.

* feat(web): enhance DesignBrowserPanel and DesignFilesPanel with improved address formatting and drag-and-drop functionality

- Refactored `formatAddressDisplay` to utilize a new `formatAddressDisplayParts` function, separating URL and title handling for better clarity.
- Updated `DesignFilesPanel` to improve drag-and-drop interactions, including enhanced directory navigation and file management features.
- Adjusted CSS styles for better visual consistency and responsiveness across components.
- Added tests for new functionalities in `DesignBrowserPanel` and `DesignFilesPanel`, ensuring robust behavior.

These changes improve user experience by streamlining address formatting and enhancing file management capabilities within the application.

* feat(web): enhance DesignBrowserPanel and DesignFilesPanel with new reference categories and improved folder creation

- Added new reference categories in DesignBrowserPanel, including 'Inspiration', 'Real Interfaces', 'Color', 'Typography', and more, each with curated design resources.
- Improved folder creation logic in DesignFilesPanel to suggest names based on existing folders, enhancing user experience.
- Updated CSS styles for better layout and responsiveness across components, particularly in control rows and search functionalities.
- Added tests for new reference categories and folder creation features, ensuring robust functionality.

These changes enrich the design resource catalog and streamline folder management, improving overall usability within the application.

* feat(web): implement reference icon functionality and enhance social share features

- Replaced favicon URL generation with a new `referenceIconUrl` function to provide reliable icons for curated design sites, improving visual consistency in the DesignBrowserPanel.
- Updated the FileViewer component to enhance social share functionality, including clearer messaging for protected deployments and improved UI for sharing links.
- Added CSS styles to support new visual states for social share components, ensuring better user experience.
- Expanded tests for the new `referenceIconUrl` function and social share interactions, ensuring robust functionality.

These changes enhance the design resource presentation and improve the sharing experience within the application.

* feat(web): enhance DesignFilesPanel and FileViewer with improved folder management and social share functionality

- Added optimistic folder path management in DesignFilesPanel to improve user experience during folder creation.
- Updated social share logic in FileViewer to handle protected deployments more effectively, ensuring clearer messaging and UI updates.
- Refactored CSS styles for better layout and responsiveness in both components, enhancing overall usability.
- Expanded tests for new folder management features and social share interactions, ensuring robust functionality.

These changes streamline folder management and enhance the social sharing experience within the application.

* feat(daemon): enhance project tab management with new state handling

- Updated database schema to include a new `state_json` column in the `tabs_state` table for improved project tab state management.
- Implemented functions to normalize and parse project tab states, including handling browser workspace tabs.
- Modified `listTabs` and `setTabs` functions to utilize the new state management features, allowing for better tracking of active tabs and saved states.
- Refactored related types in the contracts and web applications to support the new tab state structure.

These changes improve the functionality and user experience of managing project tabs within the application.

* feat(web): enhance project tab management and browser tab functionality

- Updated project routes and server logic to include `browserTabs` in the request body, improving tab state management.
- Implemented validation for `browserTabs` to ensure it is an array, enhancing error handling.
- Refactored `setTabs` function to accommodate the new structure for managing tabs, including browser-specific tabs.
- Added tests for browser tab state persistence and management in the new `project-tabs-state.test.ts` file, ensuring robust functionality.

These changes improve the user experience by providing better management and persistence of project and browser tabs within the application.

* feat(web): enhance ProjectView with improved chat send management and UI updates

- Added support for queue-only chat sends, allowing for better handling of messages during busy conversations.
- Refactored chat send functions to improve state management and persistence of queued messages.
- Updated CSS styles in the DesignFilesPanel for better layout and responsiveness, including search control enhancements.
- Expanded tests for new chat send functionalities and search interactions, ensuring robust behavior.

These changes improve the user experience by streamlining chat interactions and enhancing the overall design file management interface.

* feat(web): improve project tab state management and caching

- Enhanced the `loadTabs` function to utilize cached tab states, improving performance and user experience during data fetching.
- Implemented `normalizeTabsState` and caching functions to manage tab states effectively, including validation and error handling.
- Updated `writeCachedTabs` to ensure the latest state is stored in local storage, facilitating better persistence of tab information.
- Modified `listTabs` in the daemon to include `updatedAt` in the state retrieval, allowing for more accurate tracking of tab updates.

These changes streamline tab management and enhance the overall responsiveness of the application.

* feat(web): integrate Lexical for enhanced text composition and mention handling

- Added Lexical as a dependency to improve text composition capabilities within the chat interface.
- Implemented mention functionality with the creation of `MentionNode` and related serialization/deserialization logic for inline mentions.
- Enhanced `ChatComposer` and `ChatPane` components to support queue-only message sending and improved state management for queued messages.
- Updated `DesignBrowserPanel` and `PreviewDrawOverlay` to incorporate new features for capturing and annotating browser snapshots.
- Refactored various components to streamline interactions and improve user experience during chat and design tasks.

These changes significantly enhance the text editing experience and provide better management of chat interactions, improving overall usability in the application.

* feat(workspace): integrate terminal viewer and enhance chat functionality

- Added a new terminal viewer component with customizable themes and improved styling for better user experience.
- Integrated terminal functionality into the workspace, allowing users to interact with a terminal directly within the application.
- Updated chat components to support active conversation states, enabling seamless message handling and interaction.
- Refactored chat-related props and state management to enhance performance and maintainability.
- Removed deprecated file tree explorer components to streamline the workspace interface.

This update enhances the overall functionality of the workspace, providing users with a more integrated and responsive environment for both terminal and chat interactions.

* feat(workspace): enhance chat and session mode functionality

- Introduced a new `+` launcher in the workspace for easy access to project files and new tabs, including Side Chat and Terminal.
- Added Side Chat functionality that allows users to create context-aware conversations based on existing chats.
- Implemented a new terminal tab type for interactive terminal sessions using `node-pty`, enabling users to run shell commands directly within the workspace.
- Enhanced chat functionality with a new session mode toggle, allowing users to switch between 'design' and 'chat' modes seamlessly.
- Added a feature to copy chat responses as markdown to the clipboard, improving usability and sharing capabilities.
- Updated various components and styles to support these new features, ensuring a cohesive user experience.

This update significantly improves the workspace's interactivity and usability, providing users with more tools for collaboration and development.

* feat(workspace): enhance session mode toggle and chat functionality

- Improved the SessionModeToggle component to include localized guidance cards that provide context-aware descriptions for each mode.
- Updated the UI to display a popover with mode descriptions when hovering over options, enhancing user understanding of the available modes.
- Added a new copy button in the AssistantMessage footer to allow users to copy responses as raw Markdown, improving usability for external documentation.
- Enhanced localization support by updating i18n keys and translations for various languages, ensuring consistent user experience across different locales.
- Refactored styles for the session mode toggle and associated components to improve layout and responsiveness.

This update significantly enhances the user experience by providing clearer guidance and improved functionality in chat interactions.

* feat(styles): enhance session mode toggle styling for improved visibility

- Added new CSS rules to ensure the session mode toggle popover and hover cards are displayed correctly with increased z-index and visibility.
- Updated styles for various chat components to maintain consistent positioning and overflow behavior when session mode elements are present.
- Improved overall layout responsiveness for chat interactions, enhancing user experience during mode transitions.

This update refines the visual presentation of session mode toggles, ensuring they are more accessible and user-friendly.

* feat(web): finish Lexical composer input with atomic mention pills

* fix(web): make browser reference board scroll with a pinned toolbar

The browser tab's default Reference Board (.db-start) is wrapped by
PreviewDrawOverlay's position:absolute container, which is not a flex
parent — so .db-start's flex:1 1 auto never bounded its height and the
board grew to its content height instead of scrolling (and the sticky
.db-reference-toolbar could not pin). Fill the overlay with height:100%
like the .db-webview/.db-fallback siblings already do, restoring scroll
and the sticky toolbar.

* test(daemon): expect updatedAt in persisted tab state round-trip

listTabs() returns the tabs_state row's updatedAt timestamp on the
saved-state path, but these two toEqual assertions predated that field
and failed strictly. Match the real shape with expect.any(Number).

* feat(chat): enhance ChatComposer with session mode management and UI improvements

- Introduced a new `sessionMode` prop to the ChatComposer, allowing users to switch between different session modes (e.g., 'design').
- Added a SessionModeToggle component for improved user interaction and visibility of session options.
- Updated the ToolsTab type to reflect the removal of the pet option, streamlining the tools available in the composer.
- Refactored styles to enhance the visibility and positioning of session mode elements, ensuring a better user experience during mode transitions.
- Improved the handling of draft state and user interactions within the composer, enhancing overall functionality.

These changes significantly improve the ChatComposer's usability and flexibility, providing users with clearer options and a more responsive interface.

* feat(chat): implement caret floating layer for mention and slash popovers

- Introduced a new `CaretFloatingLayer` component to manage the positioning of mention and slash command popovers relative to the caret.
- Enhanced `ChatComposer` to utilize the caret rectangle for accurate popover placement, improving user experience during text input.
- Updated `LexicalComposerInput` to pass caret position data to the trigger handling logic, allowing for dynamic popover adjustments.
- Refactored styles for popovers to ensure consistent appearance and behavior, including improved animations and responsiveness.
- Added accessibility features to mention and slash popovers, enhancing usability for keyboard navigation.

These changes significantly improve the interaction model for mentions and commands within the chat interface, providing a more intuitive and responsive user experience.

* feat(chat): update mention tab order and improve search functionality

- Reordered the mention tab sections in the ChatComposer to prioritize 'Design files' over other categories, enhancing user experience during mentions.
- Updated the search prompt to reflect the new tab order, ensuring clarity in search functionality.
- Enhanced the mention selection logic to accommodate the new tab structure, allowing for a more intuitive navigation experience.
- Added tests to verify the correct display and functionality of the updated mention tabs and search behavior.

These changes significantly improve the usability of the mention feature within the chat interface, making it easier for users to find and select relevant items.

* feat(chat): enhance context management in ChatComposer and HomeHero

- Added functionality to manage MCP servers and connectors within the ChatComposer, allowing users to remove these contexts seamlessly.
- Updated the HomeHero component to support the selection and removal of MCP servers and connectors, improving context handling in user interactions.
- Enhanced the search prompt to include files, ensuring users can search across all relevant categories.
- Refactored related components and styles for better integration and user experience.
- Added tests to verify the correct functionality of the new context management features.

These changes significantly improve the usability of context features in the chat interface, making it easier for users to manage their interactions effectively.

* feat(chat): enhance message handling with session mode and plugin snapshot support

- Added new columns to the database schema for `session_mode` and `applied_plugin_snapshot_json` to support enhanced message context.
- Updated the `upsertMessage` and `listMessages` functions to handle the new fields, ensuring messages can store and retrieve session mode and plugin snapshot data.
- Enhanced the `ChatComposer` to manage and send the applied plugin snapshot as part of the message context, improving user interaction with plugins.
- Introduced a new `MessageSessionModeChip` component to visually represent the session mode in the chat interface.
- Updated styles for better presentation of session mode and plugin context within messages, enhancing user experience.

These changes significantly improve the context management capabilities in the chat interface, allowing for richer interactions and better tracking of session-specific data.

* feat(chat): add annotation handling and UI improvements in ChatComposer and PreviewDrawOverlay

- Implemented functionality to stage draw annotations into the composer input without sending, enhancing user interaction.
- Added a new button in the PreviewDrawOverlay to allow users to append notes to the input, improving workflow flexibility.
- Updated the ChatComposer tests to verify the correct staging of annotations and their integration into the input.
- Enhanced internationalization support by adding new translation keys for annotation actions across multiple languages.

These changes significantly improve the user experience by providing more intuitive annotation handling and better integration within the chat interface.

* feat(capture): implement page capture functionality and enhance folder management dialogs

- Added new capture functionality to allow users to take snapshots of the current page, improving user interaction with visual content.
- Introduced in-app dialogs for folder creation and moving files, replacing the unsupported window.prompt in the Electron desktop host, enhancing usability across platforms.
- Updated the DesignFilesPanel to support these new dialogs, ensuring a seamless experience for managing project files.
- Enhanced internationalization support by adding new translation keys for folder management actions across multiple languages.

These changes significantly improve the user experience by providing intuitive capture options and streamlined file management within the application.

* feat(projects): implement folder deletion and enhance project file management

- Added a new API endpoint to delete project folders, improving the file management capabilities within the application.
- Introduced utility functions for ensuring project subdirectories and safely deleting folders, enhancing the robustness of folder operations.
- Updated the DesignFilesPanel and FileWorkspace components to support folder deletion actions, providing users with a more intuitive interface for managing project files.
- Enhanced internationalization support by adding new translation keys for folder management actions.

These changes significantly improve the user experience by streamlining folder management and providing clearer options for users to organize their projects effectively.

* feat(composer): enhance BoardComposerPopover with image attachment functionality

- Added support for attaching images to comments, allowing users to upload and preview images directly within the composer.
- Implemented new handlers for image input changes and clipboard pasting, improving the user experience for image uploads.
- Updated the component's props to include image-related callbacks and state management for attached images.
- Enhanced styles for image thumbnails and removal buttons, ensuring a cohesive design with the existing comment popover interface.

These changes significantly improve the functionality of the BoardComposerPopover, providing users with a more interactive and visually rich commenting experience.

* feat(file-viewer): enhance comment attachment functionality with image support

- Updated the `onSendBoardCommentAttachments` prop to accept an additional `images` parameter, allowing for image attachments alongside comments.
- Introduced state management for handling attached images, including functions to add and remove images, and to generate previews.
- Implemented a modal for previewing attached images, improving user interaction when managing comment attachments.
- Updated the `FileWorkspace` component to reflect changes in the props, ensuring consistency across components.

These enhancements significantly improve the commenting experience by enabling users to attach and preview images directly within the file viewer.

* feat(home-hero, project-view, styles): enhance functionality and user experience

- Updated the HomeHero component to prevent unnecessary state changes during programmatic updates, improving user interaction with prompts.
- Enhanced the ProjectView component to support image attachments alongside comments, allowing for a more versatile commenting experience.
- Implemented a new image upload process that queues tasks efficiently, ensuring smooth handling of comment attachments.
- Added CSS to reserve scrollbar space in design files, preventing layout shifts when scrollbars appear, thus enhancing visual stability.

These changes collectively improve the user experience by streamlining interactions and ensuring consistent UI behavior across components.

* feat(preview-comments, chat): enhance comment functionality with attachment support

- Added support for `attachments_json` in the `preview_comments` table, allowing users to attach files to comments.
- Updated relevant functions to handle attachments, including `upsertPreviewComment` and `listPreviewComments`, ensuring attachments are properly managed and displayed.
- Enhanced the `CommentSidePanel` to render attached files, providing users with a visual representation of their attachments.
- Improved the `BoardComposerPopover` and `ChatPane` components to support image attachments, including drag-and-drop functionality for reordering queued sends.

These changes significantly enhance the commenting experience by enabling users to attach and manage files directly within the chat interface, improving overall usability and interaction.

* refactor(comment-attachments): rename attachment normalization functions for clarity

- Updated the `normalizeCommentAttachments` function to `normalizePreviewCommentAttachments` for better context in handling preview comment attachments.
- Adjusted the `upsertPreviewComment` and `normalizePreviewComment` functions to utilize the renamed attachment normalization function.
- Added tests to ensure that image attachments are correctly saved and retrieved, addressing a regression issue with attachment persistence.

These changes enhance code clarity and maintainability while ensuring the functionality for handling comment attachments remains robust.

* feat(comment-attachments): enhance comment submission with image and note validation

- Updated the `upsertPreviewComment` function to require either a text note or at least one image attachment for comment submission, improving validation logic.
- Modified the `BoardComposerPopover` to allow saving comments with only images, enhancing user experience by simplifying the commenting process.
- Adjusted the `FileViewer` to support saving comments with image-only notes, ensuring consistency across components.
- Improved styles in the chat and home hero components for better visual representation of attachments and comments.

These changes collectively enhance the commenting functionality, providing users with more flexibility in how they submit comments while ensuring robust validation.

* feat(project-view): implement auto-start for queued chat sends

- Replaced the `startingQueuedChatSendIdRef` with a state variable `queuedAutoStartBlocked` to manage the auto-start behavior of queued chat sends.
- Updated the `useEffect` to ensure that queued sends are processed one at a time after the active conversation completes, enhancing the chat experience.
- Added a test to verify that queued sends auto-start correctly after the active run finishes, ensuring reliable functionality.

These changes improve the handling of queued chat messages, providing a smoother user experience during conversations.

* feat(project-view): refine auto-start logic for queued chat sends

- Replaced the state variable `queuedAutoStartBlocked` with a reference `startingQueuedChatSendIdRef` to manage the auto-start behavior of queued chat sends more effectively.
- Updated the `useEffect` to ensure that queued sends are processed sequentially, improving the handling of chat messages during active conversations.
- Introduced a new state variable `queuedAutoStartTick` to track the auto-start process, enhancing the responsiveness of the chat interface.

These changes improve the reliability and user experience of the chat functionality by ensuring queued messages are handled smoothly and efficiently.

* feat(comment-attachments): improve attachment handling in preview comments

- Updated the `upsertPreviewComment` function to merge existing and incoming attachments, ensuring that image attachments are preserved when updating comments without new files.
- Introduced a new helper function, `mergePreviewCommentAttachments`, to handle the merging of attachments without duplicates, enhancing the robustness of attachment management.
- Added tests to verify the correct merging of attachments and the preservation of existing attachments during comment updates, improving overall functionality and user experience.

These changes enhance the commenting system by providing better management of image attachments, ensuring users can update comments seamlessly while retaining their attached images.

* feat(BoardComposerPopover): enhance popover positioning and measurement

- Updated the `popoverAnchorStyle` function to incorporate viewport scroll positions, ensuring the popover remains within visible bounds.
- Introduced a new `PopoverSize` type to manage measured dimensions, improving the accuracy of popover placement.
- Implemented a `useLayoutEffect` to dynamically measure the popover size and adjust its position accordingly, enhancing user experience during interactions.
- Added tests to verify that the popover correctly adjusts its position based on target and viewport dimensions, ensuring it remains fully visible.

These changes improve the usability of the BoardComposerPopover by ensuring it is properly positioned within the viewport, enhancing the overall commenting experience.

* feat(comment-attachments): enhance image attachment handling in comments

- Updated the `normalizeCommentAttachments` function to include image attachments in the comment payload, allowing comments to be submitted with only images.
- Introduced a fallback message for comments that consist solely of image attachments, improving user guidance.
- Enhanced the `renderCommentAttachmentHint` function to display image attachment details, ensuring users are informed about attached images.
- Added tests to verify that image attachments are preserved in comment submissions and correctly rendered in hints, improving overall functionality and user experience.

These changes enhance the commenting system by providing better support for image-only comments, ensuring users can effectively utilize image attachments in their interactions.

* feat(comment-attachments): refine comment context handling and enhance drag-and-drop functionality

- Updated the `normalizeCommentAttachments` function to conditionally omit comment text when the context is set to 'query', improving clarity in comment submissions.
- Enhanced the `renderCommentAttachmentHint` function to only display comments when not in 'query' context, ensuring a cleaner output.
- Implemented drag-and-drop functionality in the `CommentSidePanel` for reordering comments, improving user interaction and organization of comments.
- Added tests to verify the correct handling of comment context and the functionality of the drag-and-drop feature, ensuring robust performance.

These changes enhance the commenting system by providing clearer context management and improved usability through drag-and-drop capabilities.

* feat(FileViewer, ProjectView): enhance comment attachment handling and status updates

- Updated the `FileViewer` component to manage the state of sent comment IDs, ensuring that active previews are correctly updated after sending comments.
- Refined the `ProjectView` component to filter out comment attachments from the board-batch source and update their status to 'applying' during processing, improving user feedback on attachment handling.
- Introduced logic to handle the removal of sent comment IDs from the preview, enhancing the overall user experience when managing comments and attachments.

These changes improve the functionality and responsiveness of the commenting system, providing clearer feedback and better management of comment attachments.

* feat(conversation-forking): introduce message-based conversation forking

- Added the ability to fork conversations from a specific message, enhancing the chat experience by allowing users to create new conversations that inherit context up to a chosen point.
- Updated the CLI commands and help documentation to reflect the new `--fork-after` option, which specifies the message ID to stop copying from.
- Enhanced the backend to handle the new forking logic, ensuring that only messages up to the specified ID are included in the new conversation.
- Implemented tests to verify the forking functionality, ensuring robust performance and correct behavior when forking conversations.

These changes improve the flexibility of conversation management, allowing users to create tailored discussions based on previous interactions.

* feat(terminal-service): enhance session output management and memory handling

- Introduced new parameters for managing session output, including `maxBufferBytes`, `exitTailBytes`, `flushIntervalMs`, and `flushThresholdBytes`, to optimize memory usage and performance.
- Implemented a `trimBuffer` function to efficiently evict old events based on byte and count limits, improving memory management during active sessions.
- Added logic to coalesce buffered PTY output into single `data` events, reducing the frequency of event emissions and enhancing performance during high-throughput scenarios.
- Updated session event structure to include `byteLength`, allowing for better tracking of output size and memory usage.

These changes improve the efficiency and responsiveness of terminal sessions, ensuring better resource management and user experience.

* feat(workspace-context): enhance project attachment handling and workspace context management

- Introduced `formatProjectAttachmentHint` function to render project attachments in a user-visible order, improving clarity for users referencing attachments.
- Added `normalizeWorkspaceContextItems` function to standardize workspace context items, ensuring consistent handling of various context types.
- Updated `mergeRunContextSelections` to include workspace items, enhancing the context management during chat interactions.
- Enhanced `renderRunContextPrompt` to display active workspace context, providing users with better visibility of their current workspace state.
- Implemented tests for new functions to ensure robust functionality and correct behavior in handling project attachments and workspace contexts.

These changes improve the user experience by providing clearer context and better management of project attachments within the application.

* feat(database, chat): enhance message and conversation data structure

- Added `run_context_json` to the `messages` table schema to store contextual information for each message.
- Updated migration logic to include the new `run_context_json` field and ensure backward compatibility.
- Enhanced conversation retrieval to include `messageCount`, providing better insights into the number of messages per conversation.
- Improved attachment handling in the `ChatComposer` component by introducing ordering logic for attachments, ensuring a consistent user experience.
- Refactored `SessionModeToggle` to simplify state management and improve tooltip visibility.

These changes enhance data management and user interaction within the chat application, providing clearer context and improved functionality.

* feat(attachment-handling): improve attachment sorting and context management

- Introduced `sortAttachmentsByUserOrder` function to ensure attachments are displayed in a user-defined order, enhancing clarity and usability.
- Updated `historyWithApiAttachmentContext` to utilize the new sorting function, improving the context provided with message histories.
- Refactored `buildAnthropicMessageContent` to apply sorting for image attachments, ensuring consistent handling across different message types.

These changes enhance the user experience by providing better organization and visibility of attachments within the chat application.

* feat(chat): enhance conversation listing and loading states

- Improved the SQL query for listing conversations to include message counts, providing better insights into conversation activity.
- Added loading states to the ChatPane component, enhancing user experience during data fetching.
- Implemented a search feature in the conversation history, allowing users to filter conversations by title for easier navigation.
- Updated styles for loading indicators and conversation list to improve visual feedback during loading states.

These changes enhance the usability and responsiveness of the chat interface, providing users with clearer context and improved interaction capabilities.

* feat(chat): optimize suggestion filtering and enhance design system integration

- Refactored suggestion filtering in the ChatComposer component to utilize `useMemo`, improving performance by memoizing results based on dependencies.
- Added new props in ChatPane for handling plugin and design system details, enhancing the integration of these features within the chat interface.
- Updated the FileWorkspace component to manage tab states for design system and browser tabs, improving user navigation and context management.
- Introduced modals for displaying plugin and design system details in the ProjectView, enhancing user experience by providing contextual information.

These changes improve the efficiency of suggestion handling and enhance the overall user experience in managing plugins and design systems within the chat application.

* fix(chat): adjust styling and layout for improved chat interface

- Reduced the conversation row height in ChatPane for better alignment with design specifications.
- Updated CSS styles across various components to enhance layout consistency, including adjustments to margins, padding, and flex properties.
- Improved visual feedback and responsiveness in chat elements, ensuring a more cohesive user experience.

These changes refine the chat interface, making it more visually appealing and user-friendly.

* feat(comments): implement structural equality checks for comment snapshots

- Added `commentSnapshotOverlayEqual` and `commentSnapshotEqual` functions to compare comment snapshots based on their structural properties, improving performance by avoiding unnecessary state updates in the `FileViewer` component.
- Updated `HtmlViewer` to utilize these equality checks, optimizing the handling of live comment targets during pointer movements and hover events.
- Enhanced the overall responsiveness of the comment system by preventing redundant re-renders when comment snapshots remain unchanged.

These changes enhance the efficiency of comment handling and improve user experience in the commenting interface.

* feat(chat): enhance comment attachment sorting and order management

- Introduced `sortChatCommentAttachmentsByOrder` function to ensure comment attachments are displayed in a user-defined order, improving clarity and usability.
- Updated the `currentCommentAttachments` function to utilize the new sorting logic, enhancing the organization of attachments.
- Adjusted the order assignment for visual attachments to ensure consistent handling based on existing attachment orders.

These changes improve the user experience by providing better organization and visibility of comment attachments within the chat application.

* feat(chat): enhance queued send strip with overflow handling and styling improvements

- Added overflow handling to the queued send strip, allowing for better visibility of additional queued items when the list exceeds the visible limit.
- Updated CSS styles for the chat components, including adjustments to layout, padding, and font sizes to improve overall aesthetics and usability.
- Refactored the structure of the queued send row to utilize a grid layout, enhancing alignment and responsiveness of the elements within the chat interface.

These changes improve the user experience by providing clearer visibility of queued messages and a more polished interface.

* feat(database): add index for created_at and enhance comment retrieval

- Introduced a new index on `preview_comments` for `created_at` to optimize query performance when retrieving comments.
- Updated the `listPreviewComments` function to order results by `created_at` and `rowid`, improving the organization of displayed comments.
- Enhanced the test suite to verify the injection of the new URL preview selection bridge and its functionality in various scenarios.

These changes improve the efficiency of comment retrieval and enhance the user experience in the commenting interface.

* feat(tooltip): implement tooltip system for enhanced user guidance

- Introduced a new `TooltipLayer` component to manage tooltip display across the application, improving user interaction by providing contextual information on hover and focus.
- Updated various components to utilize the tooltip system, including buttons and icons, ensuring consistent tooltip behavior and styling.
- Enhanced CSS styles for tooltips, improving visibility and responsiveness, while maintaining a cohesive design across the application.

These changes enhance the user experience by providing clearer guidance and improving the overall usability of interactive elements.

* feat(tooltip): enhance tooltip integration across components

- Updated various components to include tooltip functionality, improving user guidance with contextual information on hover and focus.
- Added `data-tooltip` and `data-tooltip-placement` attributes to buttons and interactive elements for consistent tooltip behavior.
- Enhanced CSS styles to ensure tooltips are displayed correctly and responsively, maintaining a cohesive design across the application.

These changes improve the overall user experience by providing clearer guidance and enhancing the usability of interactive elements.

* feat(project-view): refactor comment handling and enhance tooltip positioning

- Introduced `mergeSavedPreviewComment` function to streamline the management of preview comments, improving clarity and maintainability.
- Updated `ProjectView` to utilize the new comment merging function, enhancing the efficiency of comment updates.
- Refactored `TooltipLayer` to use x and y coordinates for positioning, improving tooltip display accuracy and responsiveness.
- Enhanced CSS styles for tooltips, ensuring better visibility and layout consistency across the application.

These changes improve the user experience by providing more efficient comment handling and refined tooltip interactions.

* feat(design-files): enhance workspace hint and file handling in project context

- Introduced `formatDesignFilesWorkspaceHint` function to provide a detailed overview of the current Design Files workspace, including folder and file listings.
- Added limits for the number of folders and files displayed to improve clarity and prevent overwhelming users with excessive information.
- Updated the `startServer` function to integrate the new workspace hint, ensuring that the context of existing project files and folders is communicated effectively.
- Enhanced tests for the new workspace hint functionality to ensure accurate representation of project context.

These changes improve user experience by providing clearer insights into the Design Files workspace and facilitating better project management.

* feat(composer): atomic @mention keyboard navigation and deletion

* feat(database): add attachments_json field to comments and enhance migration logic

- Introduced `attachments_json` field in the database schema for comments to support attachment storage.
- Updated migration functions to include the new field, ensuring existing data is properly migrated.
- Refactored related SQL queries to accommodate the new field, improving data handling for comments.

These changes enhance the comment functionality by allowing attachments to be stored and retrieved effectively.

* chore(nix): refresh pnpm deps hash

* feat(chat-composer): implement design toolbox for enhanced design actions

- Added a new design toolbox feature to the ChatComposer, allowing users to access various design actions such as 'auto-match', 'motion', and 'visual-polish'.
- Introduced a state management system for the design toolbox, including hooks for opening and closing the toolbox.
- Enhanced the user interface with new components and styles for the design toolbox, improving accessibility and usability.
- Implemented functionality to apply design actions directly from the toolbox, streamlining the design workflow.
- Added tests to ensure the correct behavior of the design toolbox and its interactions within the ChatComposer.

These changes significantly enhance the design capabilities within the ChatComposer, providing users with a more efficient and intuitive design experience.

* feat(chat-composer): enhance design toolbox resource management

- Expanded the design toolbox functionality in ChatComposer to include a comprehensive resource index, allowing for better organization and retrieval of skills, plugins, MCP servers, templates, connectors, and project files.
- Introduced new types and interfaces to support the expanded resource management, improving type safety and clarity in the codebase.
- Updated the design toolbox action descriptions and search functionality to reflect the new resource capabilities, enhancing user experience.
- Added tests to validate the new resource indexing and search features, ensuring robust functionality.

These enhancements significantly improve the design workflow by providing users with a more organized and efficient way to access various design resources.

* feat(workspace): enhance workspace context management and UI integration

- Introduced a new function `renderWorkspaceContextToolHints` to provide contextual hints based on the type of workspace items (browser, terminal, files, live artifacts).
- Updated `ChatComposer`, `ChatPane`, and `FileWorkspace` components to support and display workspace context items, improving user interaction and accessibility.
- Enhanced the `QuickSwitcher` and `TabLauncherMenu` components to include workspace context items in search results, allowing users to navigate between tabs and files more efficiently.
- Added new translations and updated existing ones to reflect the inclusion of workspace tabs in the user interface.

These enhancements significantly improve the usability and functionality of the workspace, providing users with better context and navigation options.

* test(e2e): assert Lexical composer content with toHaveText, not toHaveValue

The chat composer and home hero input are now Lexical contenteditable
editors, not native form controls, so Playwright's toHaveValue (form-only)
fails with "Not an input element". Switch all chat-composer-input and
home-hero-input content assertions to toHaveText, and assert multi-line
soft-break cases with separate toContainText checks since the editor's
textContent collapses the newline (the newline reaching the sent payload
is already covered by downstream message/payload assertions).

* chore(nix): refresh pnpm deps hash

* chore(nix): refresh pnpm deps hash

* test(e2e): open settings through the entry settings menu

The home settings entry is now a menu (EntrySettingsMenu): clicking the
gear opens a popover whose "Settings" item opens the full execution-mode
dialog. Update the three specs that assumed a single click opened the
dialog directly to go through the menu trigger + open-details item.

* test(web): drive HomeView context picker through the Lexical helper

The home hero input is a Lexical contenteditable, so fireEvent.change /
reading .value throws "element does not have a value setter". Switch the
MCP+connector first-turn-context spec to setHomeHeroPrompt / homeHeroPromptText
like the rest of the file already does.

* Fix PR review blockers

* Update Nix pnpm deps hash

* Enhance project folder routes with error handling and tests

- Added checks for project existence in GET, POST, and DELETE folder routes, returning a 404 error if the project is not found.
- Updated tests to verify 404 responses for unknown project IDs in folder operations.
- Improved folder metadata handling in project routes.
- Refactored the TabLauncherMenu component for better UI structure and scrolling behavior.
- Adjusted styles for the TabLauncherMenu to improve usability and visual consistency.

* Update ProjectView component and enhance design toolbox localization

- Modified the ProjectView component to include workspacePanelTrack in chat panel width adjustments.
- Updated localization files to add new keys and translations for the design toolbox in English, Simplified Chinese, and Traditional Chinese.
- Enhanced user experience by providing comprehensive tooltips and prompts for design toolbox actions.

* Add browser use prompt launcher

* Cover browser use prompt launcher

* Add design toolbox badge translations

* Refactor ChatComposer and DesignBrowserPanel components

- Removed the design system picker from the ChatComposer component and integrated it into the StagedRunContexts for better context handling.
- Updated the DesignBrowserPanel to include a new function for determining viewport icons and modified the browser use categories to reflect changes in action prompts and titles.
- Enhanced the HandoffButton component with a new feature to copy the project path to the clipboard, improving user experience.
- Added new styles for search input and empty states in design files, enhancing the UI consistency across components.

* Enhance ChatPane and DesignBrowserPanel components with new features and styles

- Added scroll handling features to the ChatPane component, including scrollable state management and improved user experience during chat interactions.
- Updated the DesignBrowserPanel to include new localization keys and improved category titles for better clarity in the browser use prompt.
- Enhanced styles for chat log scrolling behavior, providing a more intuitive interface for users.
- Implemented keyboard shortcuts for tab navigation in the WorkspaceTabsBar, improving accessibility and user efficiency.

* Fix web workspace test hang

* Update styles and functionality for workspace tabs and chat components

- Adjusted CSS for the MAC_WINDOW_CHROME to improve spacing and margins for better layout.
- Enhanced the ChatComposer component to ensure proper tab order and mention handling, improving user experience.
- Implemented keyboard shortcuts for navigating workspace tabs, allowing for more efficient tab management.
- Updated localization strings for clarity in search prompts across multiple languages.
- Improved the HandoffButton component's UI for better visibility and interaction when copying project paths.

* Update visual settings flow

* Refresh Nix pnpm deps hashes

---------

Co-authored-by: open-design-bot[bot] <282769551+open-design-bot[bot]@users.noreply.github.com>
Co-authored-by: qiongyu1999 <2694684348@qq.com>
Co-authored-by: Siri-Ray <2667192167@qq.com>
2026-06-03 15:46:22 +00:00
AmyandGitHub 8fefebbbaf test(e2e): add priority tiers and main UI alerts (#3574)
* test(e2e): add priority tiers and stabilize p0 coverage

* test(e2e): align restoration artifact reopen path

* test(e2e): stabilize p1 workspace flows

* ci(e2e): run extended UI on main and notify failures

* fix(e2e): repair priority preflight checks

Generated-By: looper 0.9.2 (runner=fixer, agent=codex)

* fix(e2e): restore AMR login pill coverage

Generated-By: looper 0.9.2 (runner=fixer, agent=codex)

* fix(e2e): add full UI test script

Generated-By: looper 0.9.2 (runner=fixer, agent=codex)

* fix(e2e): remove disallowed ui script

Generated-By: looper 0.9.2 (runner=fixer, agent=codex)

* fix(e2e): allow full UI script in guard

Generated-By: looper 0.9.2 (runner=fixer, agent=codex)
2026-06-03 12:08:06 +00:00
Marc ChanGitHubopen-design-bot[bot] <282769551+open-design-bot[bot]@users.noreply.github.com>
b6105a8cab refactor(web): extract shared UI primitives (#2879)
* refactor(web): extract shared UI primitives

* fix(web): include components in packaged builds

* fix(nix): refresh daemon pnpm deps hash

* fix(components): trim unused primitive exports

Generated-By: looper 0.9.0 (runner=fixer, agent=opencode)

* refactor(components): split primitives into modules

* fix(web): restore finalize cancel link

Generated-By: looper 0.9.0 (runner=fixer, agent=opencode)

* docs: prefer shared web components

* refactor(web): migrate easy primitives

* fix(web): preserve migrated control styling

* fix(nix): refresh daemon pnpm deps hash

Generated-By: looper 0.9.1 (runner=fixer, agent=opencode)

* fix(web): keep Continue in CLI action styling

Generated-By: looper 0.9.1 (runner=fixer, agent=opencode)

* fix(web): keep finalize action styling

Generated-By: looper 0.9.1 (runner=fixer, agent=opencode)

* chore(nix): refresh pnpm deps hash

* fix(web): preserve MCP row label styling

Generated-By: looper 0.9.1 (runner=fixer, agent=opencode)

* fix(web): resolve ChatComposer merge conflict

Generated-By: looper 0.9.2 (runner=fixer, agent=opencode)

* fix(e2e): stop leaked tools-dev runtime before retry

Generated-By: looper 0.9.2 (runner=fixer, agent=opencode)

* ci: include packages/components in change scopes

Generated-By: looper 0.9.2 (runner=fixer, agent=opencode)

* fix(pack): include components in linux internal packages

Generated-By: looper 0.9.2 (runner=fixer, agent=opencode)

* fix(pack): ship components package in packed installs

Generated-By: looper 0.9.2 (runner=fixer, agent=opencode)

* fix(pack): align win app test with internal packages

Generated-By: looper 0.9.2 (runner=fixer, agent=opencode)

* fix(components): use global visually hidden class

Generated-By: looper 0.9.2 (runner=fixer, agent=opencode)

* fix(components): add development export for source builds

Generated-By: looper 0.9.2 (runner=fixer, agent=opencode)

* fix(components): restore selected custom select state

Generated-By: looper 0.9.2 (runner=fixer, agent=opencode)

* fix(tools-pack): rebuild components for packaged web builds

Generated-By: looper 0.9.2 (runner=fixer, agent=opencode)

* test(tools-pack): cover components workspace artifacts

Generated-By: looper 0.9.2 (runner=fixer, agent=opencode)

* fix(ci): include components in tools-pack scope

Generated-By: looper 0.9.2 (runner=fixer, agent=opencode)

---------

Co-authored-by: open-design-bot[bot] <282769551+open-design-bot[bot]@users.noreply.github.com>
2026-06-03 03:22:29 +00:00
Denis RedozubovandGitHub 3da33f92a1 Harden sandbox orchestration daemon chokepoints (#3420)
* Harden sandbox orchestration chokepoints

* Cover web app public copy in neutrality guard
2026-06-02 07:33:12 +00:00
kamiandGitHub 333a62cda6 fix: link od bin after fresh install (#2069)
* fix: link od bin after fresh install

* test: lock root od bin shim path

* test: cover root workspace deps in postinstall scan

* chore(nix): refresh pnpm deps hash
2026-05-31 04:36:49 +00:00
da19ff3ca0 feat(mocks): replay-based mock CLIs for 14 of OD's supported agents (opencode/codex/claude/gemini/cursor-agent/deepseek/qwen/grok + ACP family devin/hermes/kilo/kimi/kiro/vibe) (#3241)
* feat(mocks): replay-based mock CLIs for opencode/claude/codex/deepseek/qwen/grok

Drops in a `mocks/` top-level dir that pretends to be the real agent
CLIs by streaming pre-recorded sessions in each CLI's native stdout
protocol. Zero LLM tokens.

## Use cases

- **E2E tests** in `apps/daemon/tests/` — exercise the full chat-server
  pipeline against a known trace, assert UI events / artifacts.
- **Self-validation during dev** — iterate on `claude-stream.ts` /
  `json-event-stream.ts` parser changes without burning provider budget.
- **Regression harness** — replay the same trace before and after a
  charter / parser change; diff the daemon events the UI surfaces.
- **Demo / onboarding** — show what a 17-tool claude editing session
  looks like end-to-end, offline.

## How

- 6 bash wrappers (`mocks/bin/`) shadow the real CLIs when PATH-overlaid.
- `mocks/mock-agent.mjs` reads `mocks/recordings/<trace>.jsonl`, picks
  one via env var (`SYNCLO_EXPLORE_MOCK_TRACE` / `_POOL` /
  `_BY_PROMPT_HASH`), streams the trace in the requested format.
- Each format renderer matches the EXACT JSON shape the OD daemon
  parser expects, verified line-by-line against
  `apps/daemon/src/{json-event-stream,claude-stream}.ts`:

  | CLI                       | streamFormat              | parser source                              |
  | ------------------------- | ------------------------- | ------------------------------------------ |
  | `opencode`                | `json-event-stream`       | `handleOpenCodeEvent`                      |
  | `codex`                   | `json-event-stream`       | `handleCodexEvent`                         |
  | `claude`                  | `claude-stream-json`      | `createClaudeStreamHandler`                |
  | `deepseek` `qwen` `grok`  | `plain`                   | `server.ts` (raw stdout)                   |

## Quick start

```bash
export PATH="$PWD/mocks/bin:$PATH"
export SYNCLO_EXPLORE_MOCK_TRACE=04097377   # 8-char prefix OK
export SYNCLO_EXPLORE_MOCK_NO_DELAY=1

echo "any prompt" | opencode run
echo "any prompt" | claude -p --output-format=stream-json
echo "any prompt" | codex exec
```

The mock binary announces the picked trace id on stderr:
`[mock-opencode] picked 04097377… via fixed`.

Recording selection (env, in priority order):
- `SYNCLO_EXPLORE_MOCK_TRACE=<id>` — fixed (prefix OK)
- `SYNCLO_EXPLORE_MOCK_BY_PROMPT_HASH=1` + stdin prompt — `sha256(prompt) % N`
- `SYNCLO_EXPLORE_MOCK_POOL=<tag>` — random within `agent:claude` /
  `skill:agent-browser` / `outcome:failed` / etc.
- (default) uniform random
- `SYNCLO_EXPLORE_MOCK_SEED=<str>` — reproducible "random"
- `SYNCLO_EXPLORE_MOCK_NO_DELAY=1` — skip inter-event waits

## Dataset

179 anonymized Langfuse traces from this project's own production
telemetry:

- 9 agents: claude 57 · opencode 41 · codex 38 · gemini 25 ·
  cursor-agent 11 · qwen 2 · copilot 2 · deepseek 2 · antigravity 1
- outcomes: succeeded 144 · failed 35
- skills: default 71 · ad-creative 50 · algorithmic-art 30 ·
  agent-browser 22 · video-hyperframes 2 · plus magazine-web-ppt /
  brainstorming / data-report / penpot-flutter-design-source 1 each
- 124 multi-turn (sessions with ≥2 turns)
- 18 produce `<artifact>` output
- ~4.5 MB on disk total

Anonymization: `/Users/<name>/` → `${HOME}/`,
`C:\Users\<name>\` → `%USERPROFILE%\`, project UUIDs →
stable `proj-001`, `proj-002`, …. Tool input/output payloads
preserved verbatim (templated UI, no cell-level PII).

## Smoke test

`bash mocks/scripts/smoke-test.sh` — 6 checks across all 6 agents.
All pass on this branch (verified locally):

```
  ✓ opencode first event = step_start
  ✓ codex first event = thread.started
  ✓ claude first event = system
  ✓ deepseek emitted plain text (144 chars on first line)
  ✓ qwen emitted plain text (144 chars on first line)
  ✓ grok emitted plain text (144 chars on first line)
All mock CLIs working. ✅
```

## Adding more recordings

The exporter that produced this set lives in
[nexu-io/agent-pr-explore](https://github.com/nexu-io/agent-pr-explore)
(see `cli/src/local/orchestrator/langfuse-import.ts` + the `local
langfuse-import` CLI command). Operators with the Langfuse keys can pull
more by tag / outcome / artifact / multi-turn filter, then run
`local recordings anonymize --out-dir ~/Documents/open-design/mocks/recordings`.
`mocks/README.md` has the full instructions.

## Out of scope (follow-ups)

- **ACP agents** (`devin`, `hermes`, `kilo`, `kimi`, `kiro`, `vibe`) need
  a JSON-RPC server on stdio rather than a one-shot stream — separate
  `format-acp.mjs` module not yet written.
- **Per-agent json-event-stream variants** (`cursor-agent`, `gemini`,
  `qoder`, `copilot`, `pi`) currently fall back to the `plain` renderer;
  their parsers are in `apps/daemon/src/json-event-stream.ts` and follow
  the same template as `format-codex.mjs`.

## AGENTS.md updates

- Added `mocks/` to the top-level content directories listing
- Added a Validation strategy bullet pointing here for agent-stream /
  parser changes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

* fix(mocks): add opencode-cli/kiro-cli/vibe-acp bin aliases and unref ACP timeout

- Add mocks/bin/opencode-cli, kiro-cli, vibe-acp wrappers for the primary
  RuntimeAgentDef bin names OD resolves before any fallback. Without these,
  a PATH-overlaid OD daemon run bypasses the mock entirely (opencode-cli,
  kiro-cli) or cannot find the mock at all (vibe-acp, which has no fallback).
- Include opencode-cli, kiro-cli, vibe-acp in the smoke-test ACP/JSON loop
  so coverage is verified end-to-end.
- Call .unref() on the 30s safety timeout in format-acp.mjs so a completed
  ACP session exits promptly instead of waiting the full 30 seconds.

Generated-By: looper 0.9.2 (runner=fixer, agent=claude-code)

* feat(mocks): add vela (AMR) — login / models / ACP with strict set_model gate

Extends mocks/ to cover OD's own AMR runtime. `vela` is the bin name
`apps/daemon/src/runtimes/defs/amr.ts` specifies (`bin: 'vela'`,
`streamFormat: 'acp-json-rpc'`). It's richer than the generic ACP
agents — covers full login + models + chat-session lifecycle.

### What vela does (mirrored from apps/daemon/tests/fixtures/fake-vela.mjs)

1. `vela login` — writes ~/.amr/config.json with a fake profile (controlKey,
   runtimeKey, user{email,name,plan}, profile-specific apiUrl/linkUrl).
   The on-disk projection is what OD's daemon login route + AmrLoginPill
   poller read; production goes through device-auth, the mock skips
   straight to the file write.

2. `vela models` — prints the production-shaped public model catalog as
   newline-separated `public_model_*    vela` lines. Override via
   FAKE_VELA_MODELS env.

3. `vela agent run --runtime opencode` — ACP JSON-RPC server with three
   vela-specific protocol extensions:

   a. `initialize` response carries `agentCapabilities`
      (`promptCapabilities.embeddedContext`) + `models`
      (`currentModelId` + `availableModels`).
   b. `session/new` response carries the same `models` block.
   c. **Strict set_model gate**: `session/prompt` is rejected with
      JSON-RPC -32602 ("session/set_model must be called before
      session/prompt") UNLESS `session/set_model` (or
      `session/set_config_option`) has been called for the current
      sessionId. Mirrors real vela 0.0.1 contract; catches regressions
      in `attachAcpSession` that silently skip set_model.

### Error injection envs (in sync with fake-vela.mjs)

  FAKE_VELA_SESSION_ID            - sessionId returned by session/new
  FAKE_VELA_TEXT                  - override assistant text
  FAKE_VELA_THOUGHT               - optional thought_chunk before text
  FAKE_VELA_SESSION_NEW_ERROR     - fail session/new
  FAKE_VELA_SET_MODEL_ERROR       - fail session/set_model
  FAKE_VELA_PROMPT_ERROR          - fail session/prompt
  FAKE_VELA_REQUIRE_SET_MODEL='0' - disable the strict gate (legacy)
  FAKE_VELA_LOGIN_USER_EMAIL      - email written into config profile
  FAKE_VELA_LOGIN_USER_PLAN       - plan written into config profile
  FAKE_VELA_LOGIN_DELAY_MS        - sleep before write (test in-flight)
  FAKE_VELA_LOGIN_FAIL            - print + exit 1
  FAKE_VELA_MODELS                - override models stdout
  VELA_PROFILE                    - profile slot (prod | test | local)

### Components

`mocks/lib/format-vela.mjs` (~205 LOC)
  - Full ACP server with vela protocol extensions
  - Strict set_model gate
  - Error injection plumbing

`mocks/lib/vela-subcommands.mjs` (~90 LOC)
  - runVelaLogin() — writes ~/.amr/config.json
  - runVelaModels() — prints catalog

`mocks/bin/vela` — dispatcher wrapper. Forwards `vela <subcmd>` to
mock-agent.mjs which routes to login/models or falls through to ACP.

`mocks/mock-agent.mjs` — parseArgs now collects positionals so the vela
dispatcher can read subcommand from there; switch case added for vela.

`mocks/scripts/smoke-test.sh` — +4 assertions:
  vela models prints ≥10 catalog lines
  vela login writes ~/.amr/config.json with the requested email
  vela agent run ACP roundtrip (initialize+models+set_model+stream+result)
  vela strict set_model gate rejects prompt without prior set_model

### Verified locally

  ✓ vela models printed 15 catalog lines
  ✓ vela login wrote ~/.amr/config.json with profile.prod.user.email
  ✓ vela agent run ACP roundtrip (initialize+models, set_model accepted, prompt streamed)
  ✓ vela strict set_model gate rejects session/prompt without prior set_model

All 21 smoke checks pass (up from 17 with previous P3 ACP commit).

### AGENTS.md + README updates

  AGENTS.md — mention `vela (AMR — vela CLI)` alongside ACP agents in
  the directory listing entry.
  mocks/README.md — protocol table row + dedicated vela section with
  subcommand contract, strict gate explanation, env-injection cheat
  sheet. Mock-tree listing updated.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

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

* fix(mocks): honor REPORT_FILE env when --report-file flag not given

Harnesses that spawn the mock without translating their report-path
contract to the mock's CLI flag (notably nexu-io/agent-pr-explore's
orchestrator, which passes REPORT_FILE as env per the existing
opencode/claude/codex agent launchers) wouldn't get a report file
written, so the harness's "agent exit 0 but produced no report"
check would always fire and mark mock runs as failure even though the
stdout stream was complete.

Fix: in mock-agent.mjs parseArgs, fall through to process.env.REPORT_FILE
when --report-file wasn't provided on argv. Each format renderer already
accepts opts.reportFile and writes the recording's final assistant text
to it (`format-*.mjs` already had this — only the wiring was missing).

Verified: synclo-explore run with `mock=true, mock_trace=04097377`
against the opencode wrapper now produces a plan.md with the recording's
17-tool claude editing session report. ~1.5s per run vs ~70s real opencode.

* mocks: move recordings to Cloudflare R2; PR→main→Action upload path

The 179-recording corpus (~4.5 MB raw, ~280 KB after compression) has
been moved off git into Cloudflare R2 at the bucket open-design-mocks
under recordings/v1/. The repo now ships:

- mocks/manifest.json — the canonical catalog (renamed from
  recordings/index.json) with sha256 + storage hints; consumers
  fetch this to discover what exists, then pull individual jsonl
  files on demand
- mocks/scripts/fetch-recordings.sh — parallel, sha256-verified,
  idempotent puller for the public r2.dev URL
- mocks/scripts/add-recording.sh — local maintainer helper that
  validates a new .jsonl and copies it into recordings-staging/
  (no R2 calls; no credentials needed)
- mocks/scripts/upload-to-r2.mjs — called only by the CI workflow
- mocks/scripts/lib/manifest-utils.mjs — shared sha256/meta/
  rebuild-histograms logic, used by both add-recording (preview)
  and upload-to-r2 (actual write) so the entry shape never drifts
- .github/workflows/sync-mocks-to-r2.yml — fires on push to main
  when mocks/recordings-staging/ changes; uploads to R2, updates
  manifest, commits cleanup back; serialized via concurrency group

Trust model: R2 write credentials (CLOUDFLARE_API_TOKEN,
CLOUDFLARE_ACCOUNT_ID) are repo secrets; nobody can push from a
laptop. Read stays public via the r2.dev URL.

Why not pnpm install integration: contributors who do not touch
agent code do not pay the fetch cost. Fetch happens on first
smoke-test run (auto-fallback) or when a mock spawn needs data.

Repo size: -4.55 MB net (delete 179 jsonl, +280 KB manifest +
scripts). Smoke test (21 checks) still green against the fetched
corpus.

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

* mocks: scope R2 write token to a dedicated secret name

Use CLOUDFLARE_R2_MOCKS_TOKEN (instead of reusing the shared
CLOUDFLARE_API_TOKEN that landing-page-*.yml uses for Pages deploys)
so the R2 write capability can be scoped to just the
open-design-mocks bucket without bleeding extra capability into the
Pages workflows.

Also hardcode the powerformer CF account_id directly in the workflow
(account IDs are not secret and the shared CLOUDFLARE_ACCOUNT_ID
secret may point at a different account).

Workflow now fails fast with an actionable error message + dashboard
link if the secret is unset.

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

* mocks: switch R2 sync to S3-compat API (wrangler getMemberships gate)

wrangler 4.x calls /memberships before any r2 action, requiring
user:read scope. R2 "Object Read & Write" tokens deliberately lack
that scope (defense in depth — a leaked token should not enumerate
account-level resources). The workflow now uses the aws CLI talking
straight to the R2 S3-compatible endpoint with SigV4, no membership
lookup.

Secret rotation: CLOUDFLARE_R2_MOCKS_TOKEN (Bearer) is replaced by
CLOUDFLARE_R2_MOCKS_AK / CLOUDFLARE_R2_MOCKS_SK (matching the
existing CLOUDFLARE_R2_RELEASES_AK/SK naming convention). End-to-end
tested locally: PUT recording → manifest rebuild → manifest PUT →
staging cleanup all green.

aws CLI is pre-installed on ubuntu-latest, so no install step.

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

* mocks: scrub synclo namespace; use OD_MOCKS_* env prefix throughout

These mocks were copy-pasted from synclo-explore, where they
originated, and inherited the SYNCLO_EXPLORE_MOCK_* env-var
convention. That brand-bleed is not appropriate in OD: rename the
public env surface to OD_MOCKS_* (matching OD-native prefixes like
OD_MOCKS_CACHE_DIR, OD_TRACE_R2_UPLOAD, OD_EXPECT_TIMEOUT_SECONDS).

Renames:
  SYNCLO_EXPLORE_MOCK_TRACE             → OD_MOCKS_TRACE
  SYNCLO_EXPLORE_MOCK_BY_PROMPT_HASH    → OD_MOCKS_BY_PROMPT_HASH
  SYNCLO_EXPLORE_MOCK_POOL              → OD_MOCKS_POOL
  SYNCLO_EXPLORE_MOCK_SEED              → OD_MOCKS_SEED
  SYNCLO_EXPLORE_MOCK_NO_DELAY          → OD_MOCKS_NO_DELAY
  SYNCLO_EXPLORE_MOCK_RECORDINGS_DIR    → OD_MOCKS_RECORDINGS_DIR
  SYNCLO_EXPLORE_MOCK_SMOKE_TRACE       → OD_MOCKS_SMOKE_TRACE
  SYNCLO_OD_MOCKS_I_KNOW_WHAT_IM_DOING  → OD_MOCKS_ALLOW_LOCAL_UPLOAD

Also drop the inline harvester usage from README. The harvester is an
external CLI in nexu-io/agent-pr-explore — its README is the right
place for langfuse-import flags, anonymization options, etc. OD only
documents its own staging→PR→Action workflow.

Smoke test (21 checks) still green; OD_MOCKS_TRACE end-to-end
verified to route correctly.

Consumers of the OLD env names (notably the orchestrator in
nexu-io/agent-pr-explore) need a matching rename. No back-compat
shim here — the explore side has zero external users today and a
one-line follow-up is cleaner than a permanent deprecation layer.

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

* AGENTS.md: align mock env names with mocks/ rename (SYNCLO_* → OD_MOCKS_*)

Missed in the prior commit (a30b868a) — only grepped mocks/ subdir.

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

* mocks: drop staging dir + GH Action; back to local-script upload

The staging-dir + Action design (added earlier in this PR) had a flaw
the user caught: new recordings briefly entered the repo on their way
through staging, leaving them in git history forever even after the
Action cleanup commit removed them from HEAD. That defeats the whole
point of moving recordings to R2.

Replace with the simpler local-maintainer flow:

  bash mocks/scripts/upload-recording.sh /path/to/<trace>.jsonl
  # → validates, wrangler r2 put, updates manifest.json, wrangler r2 put manifest
  git add mocks/manifest.json && git commit && git push
  # → only the ~200B manifest delta enters git

The wrangler-OAuth gate replaces the CI secret + Action duo. For a
solo / small maintainer team this collapses the trust chain down to
"do you have wrangler login to the powerformer account?" — no GH
secrets to rotate, no concurrency window to worry about, no
inevitable repo-history bloat.

Deletes:
- .github/workflows/sync-mocks-to-r2.yml
- mocks/scripts/upload-to-r2.mjs   (CI-only)
- mocks/scripts/add-recording.sh   (staging helper, now obsolete)
- mocks/recordings-staging/        (empty dir, never to be repopulated)

Adds:
- mocks/scripts/upload-recording.sh

Kept:
- mocks/scripts/fetch-recordings.sh
- mocks/scripts/lib/manifest-utils.mjs (still used by upload-recording.sh)
- mocks/manifest.json (committed; the only mocks artifact in git)

End-to-end tested locally: re-upload an existing recording is
idempotent, manifest math is stable, fetch + smoke test still green.

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

* mocks: address review — guard allowlist + safe ~/.amr + loud OD_MOCKS_TRACE typo

Three concrete issues raised across recent Siri-Ray (Looper) review
threads on #3241:

1. scripts/guard.ts only allowlisted mocks/lib/ + mocks/mock-agent.mjs,
   leaving mocks/scripts/lib/manifest-utils.mjs outside the residual-
   JS guard. Result: Preflight fail on every push. Extend the allowlist
   to mocks/scripts/ — same precedent as the lib/ entry directly above.

2. mocks/scripts/smoke-test.sh moved the caller real ~/.amr to
   ~/.amr-smoke-backup, ran vela login (which writes a fake config),
   then rm -rf the .amr and restored the backup. Two failure modes:
   crash mid-run loses the user real config, and re-running before
   restore overwrites the backup with the fake login. Fix: sandbox
   vela login into a mktemp -d HOME via env (HOME=$amr_sandbox vela
   login). Never touches the real ~/.amr at all. trap cleans up.

3. mocks/lib/recording-picker.mjs silently fell through to
   prompt-hash → pool → random when OD_MOCKS_TRACE was set but did
   not match any recording (typo, prefix too short, corpus not
   fetched). Tests using a pinned trace would silently get a
   different trace, hiding regressions. Fix: throw an explicit error
   with the failing value + a pointer at fetch-recordings.sh.

Verified locally: pnpm guard prints "Residual JavaScript check
passed", smoke-test still 21/21, ~/.amr mtime unchanged after run,
typo on OD_MOCKS_TRACE now produces "mock-agent: OD_MOCKS_TRACE=...
set but no matching recording in <dir>" on stderr.

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

* fetch-recordings: detect empty filter result before line-counting

printf '%s\n' on an empty string emits a single empty line, so the
previous TOTAL=$(printf ... | grep -c "") math returned 1 on an
empty $ENTRIES_TSV — a typo like `--agent no-such-agent` printed
"Fetching up to 1 recordings", downloaded zero, and exited 0
("ready"). Check `-z $ENTRIES_TSV` first.

Reproduced + fix verified per the reviewer thread.

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

* mocks: address mrcfps review — goldens + provenance + contract check

Three durability improvements suggested in the PR #3241 top-level
review:

## 1. Golden daemon-event snapshots (mocks/golden/*.events.json + apps/daemon/tests/mocks-golden.test.ts)

Smoke-test verified that mocks RUN; that catches crashes but not a
parser change that semantically reshapes the events the daemon emits.

Commit the daemon-event sequence for 3 representative traces:
- claude  314d6833 — median-complexity agent-browser session
- codex   dcdff3b3 — 14-tool refactor
- opencode 9a9522ec — 7-tool data-report

apps/daemon/tests/mocks-golden.test.ts spawns the mock, feeds stdout
through the real createClaudeStreamHandler / createJsonEventStreamHandler,
normalizes per-spawn volatile fields (only sessionId today, only on
claude), and deep-equals against the committed snapshot. A parser
regression fails the test loudly.

After an intentional parser change, regenerate:

  MOCKS_GOLDEN_UPDATE=1 pnpm --filter @open-design/daemon test mocks-golden
  git diff mocks/golden/
  # eyeball; commit if shapes match intent

## 2. Provenance fields on every manifest entry (mocks/scripts/lib/manifest-utils.mjs + mocks/manifest.json)

Augment inspectRecording() to write:

  captured_at         — ISO 8601 from existing meta.timestamp
  cli_version         — null until harvester writes it
  protocol_version    — null until harvester writes it
  anonymization_version — null until harvester writes it

captured_at is now populated for all 179 existing entries from the
meta event the harvester already emits. The harvester in
nexu-io/agent-pr-explore is the next step for cli_version /
protocol_version / anonymization_version — once those are
populated, consumers can detect when a recording is older than ~1
minor version behind the live CLI and flag for re-harvest.

No matrix of (cli_version × agent) recordings — that explodes
maintenance. Just metadata per recording so trust decay is visible.

## 3. Real-CLI contract check (mocks/scripts/contract-check.sh + docs/MOCKS-CONTRACT-CHECK.md)

Mocks catch parser regressions against recordings; they do NOT
catch recordings drifting away from the live agent CLI as that CLI
evolves. The contract check spawns the real CLI alongside the mock
with a fixed deterministic prompt + diffs top-level event-type
distributions.

Deliberately human-driven, not cron-scheduled:
- costs real LLM tokens per invocation
- requires real CLI auth
- maintainer reads the output, not a regex

Suggested triggers per doc: real-CLI release notes mentioning
"output format" / "stream" / "JSON" / "events"; before a parser
refactor; ad-hoc when something looks off.

## Coverage note

README updated to position mocks as "deterministic protocol/parser
coverage" (not "e2e replacement") per mrcfps framing.

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

* fix(mocks-golden test): drop import of non-exported ParserKind

Use plain string (the type alias is `string` anyway) — Preflight
typecheck on a31fa71a failed:

  tests/mocks-golden.test.ts(29,8): error TS2459: Module
  "../src/json-event-stream.js" declares "ParserKind" locally, but
  it is not exported.

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

* recording-picker: structured OD_MOCKS_POOL + hard-fail no-match

Siri-Ray review: \`OD_MOCKS_POOL=outcome:failed\` was documented as a
supported selection knob, but the matcher only checked tags and
\`meta.agent\` — so the negative-path pool found 0 candidates and
silently fell through to global random, validating against any
recording instead of a failed trace.

Fix:
- Parse \`<dim>:<value>\` shape and route each dim to the right meta
  field: \`outcome\` → \`meta.outcome\`, \`agent\` → \`meta.agent\`,
  \`skill\` → \`tags[]\`. Bare values still fall back to tag substring.
- If the env was set and matched nothing, throw with the failing
  value and a jq one-liner for inspection. Same loud-fail policy as
  OD_MOCKS_TRACE — silent fallback was the original bug.

Verified locally: outcome:failed, agent:codex, skill:agent-browser
all route correctly; outcome:nonsense throws the explicit error.

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

* contract-check.sh: fix lost $PROMPT in mock invocation

Siri-Ray review on e576074a: the mock side wrapped its pipeline in
`bash -c "printf %s \"\$PROMPT\" | ..."` — but $PROMPT was a parent
shell variable, not exported, so the child bash expanded it to an
empty string. Result: the contract check sent the real prompt to the
real CLI and an empty string to the mock, defeating the
same-input invariant the whole script rests on. Also let the mock
randomly select a different trace whenever a maintainer happens to
have OD_MOCKS_BY_PROMPT_HASH=1 in their env.

Fix: drop the inner bash -c entirely; use a subshell that scopes the
PATH overlay and pipes printf into the PATH-resolved mock binary
directly. The subshell limits the PATH change without var-passing.

Verified locally: with prompt-A the mock picks trace 54ec02ee via
hash; prompt-B → 2667e851 via hash; empty prompt (old broken
behavior) → random — confirms the prompt is now actually reaching
the mock under PATH overlay.

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-29 07:17:20 +00:00
lefarcenGitHuba1chztAmyMasonCaprikaopen-design-bot[bot] <282769551+open-design-bot[bot]@users.noreply.github.com>
df8a0faff6 feat(runtimes): register AMR (vela) as an ACP stdio agent (#2355)
* feat(runtimes): register AMR (vela) as an ACP stdio agent

AMR is the vela CLI's ACP runtime mode. `vela agent run --runtime opencode`
speaks ACP JSON-RPC over stdio (see vela's
`specs/current/runtime/manual-agent-run-openrouter.md`); per
`docs/new-agent-runtime-acp.md` we expose it through the same `streamFormat:
'acp-json-rpc'` transport that already powers Hermes, Devin, Kimi, etc.

The new `defs/amr.ts` is the entire wiring — `buildArgs` returns
`['agent', 'run', '--runtime', 'opencode']`, `fetchModels` reuses
`detectAcpModels`, and the fallback list seeds the OpenRouter ids vela's
e2e baseline uses. `executables.ts`/`app-config.ts`/`metadata.ts` get the
matching `VELA_BIN`/`VELA_LINK_URL`/`VELA_RUNTIME_KEY`/`VELA_OPENCODE_BIN`
allowlist + install/docs URLs, so users can configure the per-agent env in
Settings without leaking into other adapters.

Coverage: `tests/fixtures/fake-vela.mjs` is a minimal ACP stub that returns
the documented `initialize` / `session/new` / `session/set_model` /
`session/prompt` shapes; `tests/amr-acp-integration.test.ts` spawns it via
`child_process.spawn` and drives a full turn through `attachAcpSession` and
`detectAcpModels`, so the ACP transport contract for AMR is end-to-end
verified locally even before a real `vela` binary is installed.

Validated:
- pnpm guard
- pnpm typecheck (all workspace projects)
- pnpm --filter @open-design/daemon test (2881/2881)

Deferred: real OpenRouter-backed turn through a built `vela` binary —
the runtime def needs no changes for that path, only `VELA_RUNTIME_KEY`
and `VELA_LINK_URL` in env (or Settings).

* fix(runtimes/amr): pin a concrete default model and bare openai ids

End-to-end validation against a freshly-built `vela` (nexu-io/vela@main)
+ OpenRouter surfaced two contract details the first AMR runtime def
got wrong:

1. vela rejects `session/prompt` with `session/set_model must be called
   before session/prompt`. attachAcpSession in apps/daemon/src/acp.ts
   skips set_model whenever the picked model is the synthetic 'default'
   id, so AMR's fallback list must NOT include DEFAULT_MODEL_OPTION. The
   def now ships a concrete `gpt-5.4-mini` as both `fetchModels`'
   default option and `fallbackModels[0]`, which makes attachAcpSession
   always send a real `session/set_model` for AMR turns.

2. `vela --runtime opencode` auto-prepends `openai/` to whatever modelId
   it forwards to opencode's openai provider. With OpenRouter-style ids
   like `openai/gpt-5.4-mini`, opencode receives the double-prefixed
   `openai/openai/gpt-5.4-mini` and replies `ProviderModelNotFoundError`.
   The new fallback list ships the bare ids opencode's openai registry
   actually knows about (gpt-5.4, gpt-5.4-mini, gpt-5.4-fast, etc.).

Stub + tests:
- tests/fixtures/fake-vela.mjs now enforces the set_model gate the same
  way real vela does, so a regression that silently goes back to
  model: 'default' would surface as a fatal error in tests instead of a
  hidden production failure.
- tests/amr-acp-integration.test.ts pins both contracts: no 'default' /
  no 'openai/' prefix in fallbackModels, and a negative case that
  asserts session/prompt fails when no model is set.

Adds `apps/daemon/scripts/verify-amr-real-vela.mjs` — a small dev-time
runner that drives `attachAcpSession` against a real `vela` binary and
prints the daemon's chat events, so future protocol drift can be checked
against an actual OpenRouter call.

Verified locally: `vela agent run --runtime opencode` + OpenRouter
returns the prompted string ("AMR-E2E-PASS") through the full daemon
pipeline; daemon test suite stays 2883/2883.

* fix(runtimes/amr): substitute concrete model when chat run sends 'default'

A plugin-driven AMR run from the UI surfaced a real-world hole in the
prior commit:

  json-rpc id 3: session/set_model must be called before session/prompt

The Default-design-router plugin (and any caller that doesn't pin a
real model) sends `model: 'default'` straight through, which the AMR
runtime def cannot accept — vela rejects `session/prompt` without
`session/set_model` and attachAcpSession skips set_model whenever
model === 'default'. Just leaving DEFAULT_MODEL_OPTION out of the
adapter's `fallbackModels` is not enough: the chat-run handler in
server.ts still forwarded 'default' verbatim.

This adds `resolveModelForAgent(def, resolved, env?)` as the
single source of truth for the substitution:

  1. If the caller picked a real id, pass it through.
  2. Else, if `def.defaultModelEnvVar` is set and the daemon process
     env has a non-empty value for it, return that (operator escape
     hatch — see below).
  3. Else, if the def's `fallbackModels` does NOT contain a 'default'
     id, return `fallbackModels[0].id`.
  4. Else, return the original value (the historic shape — defs that
     list 'default' themselves are untouched).

AMR sets `defaultModelEnvVar: 'VELA_DEFAULT_MODEL'`, so when
opencode's openai-provider registry deprecates `gpt-5.4-mini`
upstream, an operator can swap the fallback id without a code change
by exporting `VELA_DEFAULT_MODEL=gpt-5.5` before launching tools-dev
/ od. Worth noting the env var must live in the daemon's `process.env`
(Settings-UI per-agent env values only reach the spawned child, not
the daemon's resolver) — the new field's docblock spells this out.

Coverage:
- `tests/runtimes/resolve-model.test.ts` — 8 unit tests covering all
  four resolver branches plus the env-override happy path / fallback /
  ignore-when-user-picked-a-real-id case.
- `pnpm --filter @open-design/daemon typecheck` clean.

* chore(runtimes/amr): move AMR to the top of the base agent list

So `AMR (vela)` shows up first in the agent picker / status views,
ahead of claude / codex. Pure ordering change; no behavior delta.

* feat(amr): Sign-in / Sign-out button on the AMR Settings card

The first half of the AMR work assumed the operator would set
VELA_RUNTIME_KEY / VELA_LINK_URL on the daemon process and never
surfaced login state to users. This adds the missing UX so a fresh
install can drive the full path from Settings:

  - GET  /api/integrations/vela/status   reads ~/.vela/config.json
    for the active profile and returns { loggedIn, profile, user }
    (without leaking the runtime/control keys themselves).
  - POST /api/integrations/vela/login    spawns `vela login` once
    (409 if one is already in flight). The vela CLI opens the user's
    browser to the device-authorization page itself — Open Design
    only needs to kick the subprocess off.
  - POST /api/integrations/vela/logout   removes ~/.vela/config.json
    so the next status read returns logged-out.

`AmrAgentCard` is a dedicated agent-card component for AMR because
the existing `<button>` row can't host an interactive sub-control
(nested interactive elements). It polls /status after a login click
until the daemon reports loggedIn=true (or 5 minutes elapse), and
exposes a Sign-out action on hover. Other adapters (claude, codex,
hermes, …) keep their existing `<button>` card.

i18n: 8 new keys (settings.amrLogin / Logout / LoggingIn / etc.)
added to en + zh-CN. Other locales spread `en` and inherit the
English copy until translations land.

Coverage:
- `tests/integrations/vela.test.ts` pins the config.json reader
  against a tmp HOME — including the negative case where a profile
  has user info but no runtimeKey (still logged-out), and the
  secret-leak guard ("rt-secret-*" must not appear in the projection
  payload).
- `tests/components/AmrAgentCard.test.tsx` covers all four UI
  states (logged-out, logging-in, logged-in, logging-out) plus the
  click-propagation invariant the divergent card was built to keep.

`pnpm --filter @open-design/daemon test` 2901 / 2901 passing.
`pnpm --filter @open-design/web test` 1719 / 1719 passing.
`pnpm typecheck` + `pnpm guard` clean.

Dev script side-effects: `apps/daemon/scripts/verify-amr-real-vela.mjs`
no longer requires both VELA_RUNTIME_KEY and VELA_LINK_URL — if
VELA_PROFILE is set, the vela CLI is allowed to resolve credentials
from `~/.vela/config.json`. Added the two AMR `.mjs` fixtures to
`scripts/guard.ts` allowlist with the executable-fixture / dev-runner
rationale.

* fix(connection-test): substitute model for AMR before attachAcpSession

The chat-run path in server.ts already routes the requested model through
`resolveModelForAgent` so AMR / vela (whose CLI demands an explicit
`session/set_model` before `session/prompt`) gets the def's first
concrete fallback id when the chat run ships `model: 'default'`.
`connectionTest.ts` was wiring `attachAcpSession({ ..., model: model ?? null })`
directly, which made the Test Connection button on the AMR Settings
card deadlock with the same `session/set_model must be called before
session/prompt` error the chat-run path already handles — surfaced as a
permanent "Testing connection…" spinner in the UI.

Reuse the same helper here so Test Connection mirrors chat-run behavior.

* test(amr): three-layer end-to-end coverage for the AMR login + turn flow

The PR up to this point shipped runtime + UI code with unit-level Vitest
coverage. This commit adds the cross-layer regression net the live demo
relied on:

1. apps/daemon/tests/integrations/vela.routes.test.ts (HTTP, Vitest)
   Spins up the real daemon Express app via `startServer({port:0,...})`,
   persists `agentCliEnv.amr.VELA_BIN = <fake>` into app-config.json,
   and exercises every /api/integrations/vela/* endpoint against the
   extended fake-vela stub:
     - status reads ~/.vela/config.json under various states
     - login spawns the fake, waits for config.json to appear, returns
       pid + startedAt + profile
     - 409 already-running guard with the stub's delay knob
     - logout removes the file (idempotent)
     - secrets (runtimeKey / controlKey) never leak in the projection
     - login → status round-trip flips loggedIn=false → true

2. e2e/tests/amr/turn.test.ts (tools-dev orchestrated, Vitest)
   Boots a namespaced daemon + web pair through `createSmokeSuite`,
   inlines a self-contained fake `vela` binary that handles BOTH
   `vela login` (writes ~/.vela/config.json) and
   `vela agent run --runtime opencode` (ACP stdio with the
   `session/set_model must precede session/prompt` gate the real binary
   enforces), then drives a complete /api/runs lifecycle for
   `agentId: 'amr', model: 'default'` and asserts the assistant message
   captures the fake's streamed text. This is the test that would have
   surfaced today's plugin-default-model regression (the `set_model
   before prompt` error) at PR time instead of demo time.

3. e2e/ui/amr-login-pill.test.ts (Playwright)
   Mocks /api/agents + /api/integrations/vela/{status,login,logout}
   to drive the Settings AMR card through the full Sign in → Signed in
   → Sign out cycle. Pins the AmrLoginPill polling contract and the
   aria-label semantics (the pill's accessible name is "Sign out" once
   logged in, regardless of which label the hover-state text shows).

fake-vela.mjs extensions:
   - Handles `vela login` argv by writing
     ~/.vela/config.json for the active VELA_PROFILE and exiting 0 —
     mirrors real vela's on-disk side-effect without the device-auth
     loop.
   - FAKE_VELA_LOGIN_DELAY_MS knob so route tests can observe the
     in-flight state of the spawn lifecycle.
   - FAKE_VELA_LOGIN_USER_EMAIL / _USER_PLAN to assert the surfaced
     user fields end-to-end.

Validated:
   - `pnpm guard` + `pnpm typecheck` (all workspace projects)
   - `pnpm --filter @open-design/daemon test`: 2998 / 2998 passing,
     including the new 8-test integration suite.
   - `cd e2e && pnpm test tests/amr`: 1 / 1 passing.
   - `cd e2e && pnpm exec playwright test ui/amr-login-pill.test.ts`:
     1 / 1 passing (6.7s).

* feat(amr): package native cli and refine login ui

* feat(amr): wire vela cli beta packaging

* docs(amr): document vela ci packaging review

* docs(amr): refine vela ci integration review

* fix(ci): refresh nix pnpm dependency hashes

* fix(pack): clean up Vela CLI packaging

* fix(pack): bundle Vela CLI support files

* fix(amr): recover login attempts from stale auth state

* test: expand AMR and automations coverage

* fix(amr): address review follow-ups

* test(web): align tasks fixtures with contracts

* fix(daemon): type wildcard route params

* fix(ci): refresh PR merge validation

* fix(amr): clear env credentials on logout

* feat(settings): inline local CLI model configuration

* fix(amr): recognize daemon env credentials

* [codex] Fix Vela companion packaging (#2979)

* Fix Vela companion packaging

* Update Nix pnpm dependency hashes

* [codex] Surface AMR account failures (#2980)

* fix: surface AMR account failures

* fix: cover AMR recovery error guidance

* chore: bump beta base version to 0.8.1 (#2990)

* Fix AMR profile and packaged runtime review issues

* Detect packaged AMR OpenCode companion tree

* feat(web): polish AMR frontend flows

* Polish AMR onboarding card

* fix: read AMR login state from dot-amr config (#3048)

* test: tighten AMR credential and packaging coverage

* test: restore AMR executable test env helper

* [codex] Fix packaged mac Dock identity and AMR label (#3076)

* Fix packaged mac sidecar Dock identity

* Rename AMR assistant label

* Fix AMR live models and dot-amr login state (#3073)

* fix: read AMR login state from dot-amr config

* fix: load live AMR models before runs

* fix: point AMR onboarding link to production wallet

* fix: address AMR model review feedback

* fix: persist live AMR model fallback

* [codex] Fix AMR link catalog model ids (#3088)

* Fix packaged mac sidecar Dock identity

* Rename AMR assistant label

* Fix AMR link catalog model ids

* Fix AMR model normalization typecheck

* Use live AMR model for default runs

* fix: polish AMR runtime settings UI

* Accelerate AMR startup defaults (#3092)

* Surface AMR insufficient balance wallet URL (#3099)

* fix(web): polish onboarding controls (#3112)

* fix(web): show CLI scan loading state

* Avoid duplicate AMR wallet recharge links (#3117)

* Avoid duplicate AMR wallet recharge links

* Use Vela CLI 0.0.3 test package

* chore(nix): refresh pnpm deps hash

* Fix AMR wallet guidance display

---------

Co-authored-by: open-design-bot[bot] <282769551+open-design-bot[bot]@users.noreply.github.com>

* chore(pack): pin Vela CLI 0.0.3-test.1 (#3127)

* chore(nix): refresh pnpm deps hash

* chore(pack): pin Vela CLI 0.0.3

* chore(nix): refresh pnpm deps hash

* fix(web): suppress AMR exit 130 fallback (#3136)

* feat(web): nudge users to hosted AMR on model/auth/quota failures (#3083)

* feat(web): nudge users to hosted AMR on model/auth/quota failures

When a non-AMR agent run fails with an auth / quota / upstream model
error, surface an inline nudge under the error pill linking to Open
Design's hosted AMR gateway (https://open-design.ai/amr). The nudge
fires `surface_view` (element=run_failed_toast) on impression and
`ui_click` (element=go_amr) on the link.

Also teach the daemon to classify CLI-agent auth/quota/upstream failures
(Claude Code, codex, ...) into specific API error codes
(AGENT_AUTH_REQUIRED / RATE_LIMITED / UPSTREAM_UNAVAILABLE) instead of
the generic AGENT_EXECUTION_FAILED, so both the error message and the
nudge key off accurate codes. AMR's own runs are excluded from the
nudge — they keep the dedicated sign-in / recharge affordances.

* feat(web): rework failed-run AMR guidance into per-case error UI

Replace the single inline nudge with a per-case failed-run experience
driven by the run's error code + agent:

- The error card is now neutral gray (was red) and always carries a
  retry button; it is driven by the persisted per-message error event so
  it survives a reload.
- Non-AMR agent hitting a model/auth/quota wall: a theme-color promotion
  card under the error card offers "switch to AMR & retry" — switches the
  run to AMR, opens Settings on the AMR card, and auto-retries once the
  account signs in (ProjectView polls vela login status, independent of
  the Settings pill lifecycle, with success / 5-min-timeout / unmount
  exits).
- AMR agent unauthorized: clearer copy + an "authorize & retry" button.
- AMR agent out of balance: clearer copy + a "top up" button to the AMR
  wallet, with manual retry.
- Settings AMR card: when opened from the nudge, it scrolls into view and
  pulses, and an authorize-button coachmark (a fake hand cursor that
  rises in and dismisses on hover) points at the sign-in control when not
  yet authorized.

analytics: surface_view (run_failed_toast) on the promotion card and
ui_click (go_amr) on its action are retained. i18n adds chat.amrCard.*
and chat.amrError.* (en / zh-CN / zh-TW translated; other locales fall
back to en) and drops the old chat.amrErrorGuidance keys.

* fix(daemon): require status context for numeric service-failure codes

Per review on #3083: the model-service classifier matched bare HTTP
status numbers (`500`, `502`, `429`, `401`), so ordinary CLI output like
`line 500`, `read 502 bytes`, or `exit code 401` could be misclassified
as a provider outage / auth wall and wrongly surface the AMR nudge. Now
a status number only counts when it carries explicit context (`HTTP 500`,
`status 503`, `code: 401`, `502 Bad Gateway`); textual provider phrases
(overloaded, bad gateway, service unavailable, rate limit, …) are
unchanged. Adds fixtures proving unrelated numeric output stays null.

* fix(web): keep error pill for failed runs ChatPane's card doesn't cover

Per review on #3083: the per-message gray error pill was suppressed for
every persisted error status event, but ChatPane only renders the
replacement top-level error card for `retryableAssistantMessage` (the
last failed assistant). So a failed turn that is no longer last (after a
follow-up) or an older failed run in history showed neither the pill nor
the card — its error detail vanished, undercutting reload/history
survival. ChatPane now passes `errorCardOwnerId` (the assistant id whose
error the card represents); AssistantMessage suppresses only that one
pill and keeps rendering StatusPill for all other error events.

* fix(daemon): don't treat a process exit code as an HTTP status

Follow-up to review on #3083: the status-context helper accepted a bare
`code` prefix, so `exit code 401` / `process exited with code 429` still
matched and got classified as AGENT_AUTH_REQUIRED / RATE_LIMITED (the
very `exit code 401` case the comment calls out as noise). `code` now
only counts when qualified (`status code` / `error code` / `response
code`) or punctuation-bound (`code: 401`); bare `exit code N` no longer
matches. Adds fixtures for exit-code lines returning null.

* chore(web): translate AMR card / error keys for 16 remaining locales

PR #3083 added 10 new `chat.amrCard.*` / `chat.amrError.*` keys but only
provided en/zh-CN/zh-TW translations; the other 16 locales fell back to
English. Translate the card title/body, three chips, primary CTA, and
the AMR self-error (auth / balance) messages and buttons for ar, de,
es-ES, fa, fr, hu, id, it, ja, ko, pl, pt-BR, ru, th, tr, uk.

* fix(amr): address review feedback on #2355

Targeted fixes for the unresolved review threads on #2355. Each fix
includes / updates a focused test.

- runtimes/executables.ts: `packagedVelaOpenCodeCompanionTree` now
  verifies the inner `opencode` executable exists + is runnable, not
  just the directory. This closes the false-positive availability path
  that let `detectAgents()` surface AMR as available even when the
  packaged companion was empty / partially copied (mrcfps, 4 threads).

- runtimes/executables.ts: `resolveAmrOpenCodeExecutable` now prefers
  the bundled `<OD_RESOURCE_ROOT>/bin/libexec/opencode/opencode` over a
  stale `opencode` on the user's PATH, so packaged AMR builds can't be
  hijacked by a global installation.

- web/EntryShell.tsx: when the Local CLI scan returns an available
  agent and the previously-selected agent is AMR, switch the selection
  to the first available local agent so the runtime and persisted
  agent agree before Continue.

- server.ts (model-probe branch): for AMR, check `readVelaLoginStatus`
  BEFORE rejecting on an empty live-model catalog — a signed-out user
  was getting `AMR_MODEL_UNAVAILABLE` ("choose a model") instead of
  the correct `AMR_AUTH_REQUIRED` (sign-in affordance).

- server.ts (default model fallback): if the user asked for the AMR
  agent default and the cached id is no longer in the FRESH catalog,
  fall back to `liveModels[0]` from the probe instead of rejecting the
  run as `AMR_MODEL_UNAVAILABLE`.

- integrations/vela.ts: route `vela login` through
  `createCommandInvocation` so an npm/Node-style `vela.cmd` / `.bat`
  shim on Windows gets the correct `cmd.exe /d /s /c …` wrapping with
  verbatim args (matches `execAgentFile` / chat-run spawning).

- tools/pack/src/linux.ts: in containerized Linux builds, bind-mount
  the host directory of `OPEN_DESIGN_VELA_CLI_BIN` and rewrite the env
  to the container-side path. The host path was being passed in as-is
  even though the default container only mounts /project, /tools-pack
  and cache/home — `copyOptionalVelaCliBinary` saw a missing path.

Deferred (out of scope for this PR):
- `od amr status/login/logout/cancel` CLI subcommands (AGENTS.md
  UI/CLI dual-track rule, server.ts:5763) — sizable surface; tracked
  for a separate focused PR.
- Strict `--require-vela-cli` for Windows + mac-x64 beta builds:
  prematurely blocked — `@powerformer/vela-cli` only publishes the
  `darwin-arm64` platform binary today; adding the flag elsewhere
  would fail the builds. Revisit once win/x64/linux binaries ship.

* fix(amr): hoist sendAmrAccountFailure above the AMR catalog preflight (TDZ)

The new signed-out AMR branch in the catalog preflight at server.ts:10875
calls `sendAmrAccountFailure(...)` to emit AMR_AUTH_REQUIRED, but the
const declaration sat ~100 lines below at the outer function scope. Because
`const` is TDZ-aware, that branch would have thrown `ReferenceError:
Cannot access 'sendAmrAccountFailure' before initialization` for the
exact users it tries to help — defeating the original intent.

Hoist the helper to just above the AMR preflight block so it's available
to every AMR code path in this function. Behavior elsewhere is unchanged.

Also rerun the daemon test suite: `launch.test.ts > resolveAgentLaunch
uses packaged built-in Vela for AMR` was creating the
`<resourceRoot>/bin/libexec/opencode/` companion *directory* only, but
this PR's earlier tightening of `packagedVelaOpenCodeCompanionTree`
also requires the inner `opencode` executable. Add it to that fixture
to match the new contract; the test was a sibling of the executables /
env-and-detection fixtures already updated in 13fc4f4.

Addresses #2355 review (mrcfps, 2026-05-28).

* feat(web): add hover cancel for AMR login (#3158)

* feat(web): add hover cancel for AMR login

* fix(web): don't bounce AmrLoginPill back to 'Signing in…' after local cancel

Both codex-connector (P2) and looper (CHANGES_REQUESTED) on this PR
flagged the same race in the new local-cancel path: `handleCancelLogin`
dispatches `notifyAmrLoginStatusChanged('login-canceled')` immediately
after `/login/cancel` returns, but the `AMR_LOGIN_STATUS_EVENT` listener
unconditionally re-enters `refresh()` and then restarts polling
whenever `/api/integrations/vela/status` still reports
`loginInFlight: true`.

That is a real race because the daemon's `cancelVelaLogin()` only sends
SIGTERM (escalating to SIGKILL after `LOGIN_CANCEL_KILL_GRACE_MS` =
2000 ms) and keeps the child in `activeLoginProcs` until it actually
exits — so the first `/status` read after a successful cancel can
legally still come back as in-flight. Under that window the pill flips
back to 'Signing in…' and can later surface the timeout/error path even
though the user already canceled, defeating the behavior promised in
the PR description.

Fix the listener instead of every dispatch site: in the
`login-canceled` branch, after the local reset (stopPolling +
setPending(null) + clear refs), optimistically mark every subscribed
pill instance as not-in-flight (`setStatus((c) => c ? { ...c,
loginInFlight: false } : c)`) and `return` — skip the
refresh-and-reconcile branch below entirely. The next explicit refresh
(component mount, user interaction, or a `status-changed` event) will
pick up the daemon's confirmed state once the child has actually
exited.

Add a focused regression test that holds `/api/integrations/vela/status`
at `loginInFlight: true` even after a successful `/login/cancel`,
asserting that the pill stays at the Canceled → Authorize sequence and
never bounces back to 'Signing in…'. This test fails on the pre-fix
listener and passes on the new behavior; existing
'cancels an in-flight AMR sign-in…' and 'reconciles late AMR browser
completion to Signed in after local cancel' tests continue to pass.

Addresses review feedback on #3158 (chatgpt-codex-connector, nettee).

---------

Co-authored-by: lefarcen <935902669@qq.com>

---------

Co-authored-by: a1chzt <chizblank@gmail.com>
Co-authored-by: Amy <1184569493@qq.com>
Co-authored-by: Mason <jinmeihong0201@gmail.com>
Co-authored-by: Caprika <56862773+alchemistklk@users.noreply.github.com>
Co-authored-by: open-design-bot[bot] <282769551+open-design-bot[bot]@users.noreply.github.com>
2026-05-28 05:09:55 +00:00
Marc ChanandGitHub 125dcd0174 fix(ci): run fork visual reports from trusted code (#2935)
* fix: run fork visual reports from trusted code

* fix: auto-approve strict web visual capture

* fix: address visual report review feedback

Generated-By: looper 0.9.1 (runner=fixer, agent=opencode)

* fix: propagate visual report storage failures

Generated-By: looper 0.9.1 (runner=fixer, agent=opencode)

* fix: validate PR screenshots before upload

Generated-By: looper 0.9.1 (runner=fixer, agent=opencode)

* fix: validate visual PR identity before comment

* fix: harden fork visual report validation

Generated-By: looper 0.9.1 (runner=fixer, agent=opencode)

* fix: address remaining fork visual report review feedback

Generated-By: looper 0.9.1 (runner=fixer, agent=opencode)

* fix: handle stale fork visual report lookup

Generated-By: looper 0.9.1 (runner=fixer, agent=opencode)

* fix: allow stale fork visual report fallback

Generated-By: looper 0.9.1 (runner=fixer, agent=opencode)
2026-05-26 06:17:04 +00:00
JiannanyaandGitHub f4af51d550 fix(skills): update d3-visualization skill upstream to snow-d3 and expand skill metadata (#1981)
* update d3 visualization skill

* update d3 skill info

* fix(skills/d3): align seed triggers and clone path with SKILL.md

- Add 'd3 scroll' to the d3-visualization triggers array in
  seed-curated-design-skills.ts so it matches the 16 triggers
  already present in skills/d3-visualization/SKILL.md.
- Change `git clone` target from `.` to `skills/snow-d3` so
  the install command produces the path described by the prose.
2026-05-25 10:58:23 +00:00
PerishFireandGitHub 34165ff189 chore: retire tools-pr (#2867) 2026-05-25 05:15:04 +00:00
Marc ChanandGitHub e70d5bdd3f fix(ci): disambiguate fork PR workflow auto-approval (#2857)
Fork PR workflow runs can arrive without GitHub PR associations, which left ci and visual checks stuck awaiting manual approval even for allowlisted changes. Fall back to a single open PR match on head repo/ref/SHA so the approver stays conservative while still unblocking low-risk fork PR workflows.
2026-05-25 03:44:33 +00:00
587f6de46d fix: restore Atelier Zero deck plugin prompt (#2822)
Co-authored-by: icc <iccccccccccccc@users.noreply.github.com>
2026-05-24 14:20:25 +00:00
Marc ChanandGitHub a04c2c8f3f fix(ci): broaden fork PR workflow auto-approval (#2788) 2026-05-23 13:00:43 +08:00
lefarcen c14baf07d3 Merge origin/main into release/v0.8.0
PR #2461 sync prep — resolves 14 conflicts merging 84 main-side commits
on top of 58 release-side commits accumulated during the 0.8.0 cycle.

Resolution summary:

Take main (theirs) where main carried deliberate forward progress:
- apps/web/src/components/PluginCard.tsx — 7 hunks, i18n migration:
  hardcoded English aria-labels/titles replaced with t() calls keyed
  on pluginCard.* (all 8 keys verified present in en.ts).
- apps/web/src/components/TasksView.tsx — 1 hunk, source-ingestion
  feature: sortedRoutines (newest-first), sourceIngestionTemplates,
  patchSourceForm, submitSourceIngestion. activeCount/pausedCount
  semantics preserved (now keyed on sortedRoutines, count unchanged).
- e2e/ui/app.test.ts — new node:fs/promises + tmpdir + path + @/timeouts
  imports needed by main-side test helpers.
- e2e/ui/settings-local-cli-codex-fallback.test.ts — menu-dismissal
  helper block added by main.

Keep both sides where each added a different field to the same object
literal:
- apps/web/src/components/ProjectView.tsx (locale + analyticsHints
  spread).
- apps/web/src/components/DesignSystemFlow.tsx (locale + analyticsHints).

Take release (ours) where release carried deliberate work that ships
0.8.0:
- CHANGELOG.md — release-side 0.8.0 entry + PR link refs; main's
  Unreleased section was the same body of work, now finalized.
- apps/landing-page/public/{apple-touch-icon,favicon}.png +
  apps/web/public/app-icon.svg — release-side visual refresh assets
  consistent with 0.8.0 stable ship.
- tools/pack/src/linux.ts — packageVersion const required by line 466;
  taking main's empty line would build-error.
- e2e/ui/project-management-flows.test.ts +
  e2e/ui/settings-api-protocol.test.ts +
  e2e/ui/settings-memory-routines.test.ts — release-side release-smoke
  hardening (shangxinyu1 + PerishFire) takes precedence on overlap.

Closes-issue / unblocks: PR #2461 sync release/v0.8.0 → main.
2026-05-23 12:17:18 +08:00
Marc ChanandGitHub 6592d638ce ci: gate fork PR workflow auto-approval (#2683)
* ci: gate fork PR workflow auto-approval

* ci: rename fork PR approval workflow

* ci: normalize fork workflow paths

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* fix(ci): match action_required workflow runs

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* fix(ci): denylist tool config paths

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* fix(ci): retry action_required workflow lookup

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* fix(ci): restrict fork workflow approvals to target PR

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* fix(ci): keep polling fork workflow approvals

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* fix(ci): revalidate fork workflow approvals before approving

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* fix(ci): poll longer for first fork approval run

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* fix(ci): make fork approval poll budget configurable

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* fix(ci): drop stale fork approval runs

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* fix(ci): deny dotted tsconfig variants in fork approvals

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* fix(ci): run fork approval regression in guard

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* fix(ci): refresh Nix pnpm deps hash

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* test(web): mock useI18n in reattach restore test

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* fix(ci): accept status-only fork approvals

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* fix(ci): rerun fork approval on retarget

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* fix(ci): ignore base tip churn in PR association

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* fix(ci): broaden pending approval run fetch

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* fix(ci): skip non-retarget fork approval edits

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* fix(ci): checkout visual comment workflow head

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* fix(ci): paginate workflow approval run lookup

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* fix(ci): harden fork workflow follow-ups

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* fix(ci): honor full post-appearance settling window

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* fix(ci): validate manual visual comment checkout

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)
2026-05-23 11:48:36 +08:00
Marc ChanandGitHub a5b47c5f76 fix(ci): narrow workflow scope and reuse setup steps (#2708)
* fix(ci): narrow workflow scope and reuse setup steps

* fix(ci): narrow workflow scope and reuse setup steps

Repair Nix fixed-output hashes for the filtered daemon and web source trees.

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* fix(ci): narrow workflow scope and reuse setup steps

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* fix(ci): narrow workflow scope and reuse setup steps

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)

* fix(ci): repair daemon and nix checks

Generated-By: looper 0.0.0-dev (runner=fixer, agent=opencode)
2026-05-22 18:58:53 +08:00
PerishFireandGitHub b4e94b0534 Harden packaged updater downloads and install handoff (#2677)
* Add managed download package for updater resumes

* fix(download): clear stale pid locks

* test(e2e): harden windows updater resume smoke

* feat(updater): make update downloads silent in ui

* fix(updater): keep install handoff prompt visible

* fix(ci): build platform before download in postinstall
2026-05-22 15:44:28 +08:00
PerishFireandGitHub 526c7f7c26 Fix packaged auto-update release validation (#2565)
* fix: tighten packaged updater flow

* test: prune noisy extended ui coverage

* fix: hide unpublished release artifacts

* test: validate release updater channels

* fix: align prerelease release namespaces
2026-05-21 18:15:53 +08:00
Marc ChanandGitHub 10192dcc52 fix(ci): catch nix hash drift before merge (#2530)
* fix(ci): catch nix hash drift before merge

* fix(nix): add pnpm hash refresh helper

* chore(nix): drop redundant hash alias

* fix(nix): raise update-hash output buffer

Generated-By: looper 0.8.1 (runner=fixer, agent=opencode)

* fix(nix): handle current pnpm deps hash

Generated-By: looper 0.8.1 (runner=fixer, agent=opencode)

* fix(nix): reject non-mismatch hash updates

Generated-By: looper 0.8.1 (runner=fixer, agent=opencode)
2026-05-21 16:08:13 +08:00
8193981511 Keep PR 2400 changes without folder pickers (#2462)
* feat(daemon): add project working directory management and editor hand-off functionality

- Introduced new flags for project commands to manage working directories, including `--working-dir` and `--dir`.
- Implemented API routes for listing available editors and opening projects in selected editors.
- Added a hand-off button in the ChatPane header to facilitate opening project folders in local applications.
- Enhanced the HomeHero component to include working directory and design system settings, improving user experience in project creation.
- Created HomeHeroSettingsChips component for inline management of working directory and design system selection.

* feat(chat): implement voice transcription proxy and enhance UI components

- Added a new API route for voice transcription using OpenAI's `/audio/transcriptions` endpoint, allowing users to send audio blobs directly for transcription.
- Integrated multer for handling audio file uploads in memory, ensuring efficient processing without disk storage.
- Updated the HomeHero component to include example prompt suggestions for plugins, enhancing user interaction.
- Introduced the EditorIcon component to visually represent different editors in the hand-off menu, improving the user experience.
- Refined the HandoffButton component to utilize the new EditorIcon, providing a more cohesive interface for selecting editors.
- Enhanced CSS styles for various components to improve layout and responsiveness, including adjustments to tab and button sizes for better usability.

* style(workspace-shell): enhance layout and overflow handling

- Updated CSS for .workspace-shell to ensure full viewport width and height, with proper overflow management.
- Adjusted grid layout to prevent content overflow and maintain responsiveness.
- Modified styles for .workspace-tabs-chrome to improve width handling and prevent overflow issues.

* refactor(chat): remove voice transcription proxy and related components

- Deleted the voice transcription proxy implementation, including the associated API route and multer configuration.
- Removed the MicButton component from the ChatComposer and HomeHero components to streamline the UI.
- Updated HomeHero to include example suggestions without the voice input functionality.
- Adjusted CSS styles for various components to maintain layout consistency after the removal of the MicButton.

* feat(daemon): implement minting of HMAC tokens for working directory management

- Added a new function `mintImportTokenFromCurrentSecret` to generate HMAC tokens bound to a specified base directory, enhancing security for working directory operations.
- Updated the `desktop-auth.ts` file to include the new token minting functionality, which returns structured errors when the desktop auth secret is cleared.
- Introduced new IPC message types for minting import tokens in the sidecar protocol, allowing seamless integration with the daemon's working directory management.
- Enhanced the `WorkingDirPill` component to utilize the new token minting flow for secure directory selection in desktop builds.
- Updated CSS styles for the HomeHero component to accommodate new example suggestion features and maintain layout consistency.

* fix(HomeView): import HOME_HERO_CHIPS constant for improved chip management

- Updated the HomeView component to import the HOME_HERO_CHIPS constant from the chips module, enhancing the management of hero chips within the component.

* feat(daemon): implement mintImportTokenViaSidecar for secure working directory management

- Introduced the `mintImportTokenViaSidecar` function to facilitate the minting of HMAC tokens for desktop-import operations via the daemon's sidecar IPC. This allows CLI commands to bypass authentication when the desktop-auth gate is active.
- Updated the CLI to utilize the new token minting function when setting the working directory, ensuring secure access to trust-gated API endpoints.
- Enhanced the sidecar server to handle minting requests and return structured error messages for improved user feedback.
- Added tests to validate the new token minting functionality and its integration with the working directory management process.
- Refactored related components to support the new token flow, improving overall security and user experience.

* feat(HomeHero): enhance UI components and styles for improved user experience

- Updated HomeHero component to replace active dot indicators with Plug icons for better visual representation of active plugins.
- Adjusted CSS styles for various elements, including padding and dimensions, to enhance layout consistency and responsiveness.
- Introduced new styles for active type icons and improved hover effects for buttons.
- Updated HomeHeroSettingsChips to change button titles and icons for clarity.
- Added tests to ensure proper rendering and functionality of updated components.

* feat(ProjectDesignSystemPicker): enhance design system selection with preview functionality

- Updated the ProjectDesignSystemPicker component to include a preview feature for design systems, allowing users to see a preview of the selected design system.
- Implemented hover functionality to update the preview based on the hovered design system.
- Added fullscreen preview capability for a more immersive experience.
- Enhanced CSS styles for the design system picker to improve layout and responsiveness.
- Introduced tests to validate the new preview functionality and ensure proper interaction within the component.

* feat: refactor project metadata handling and enhance design system picker

- Updated the default scenario plugin ID retrieval to use project metadata, improving the logic for determining the appropriate plugin based on project intent.
- Enhanced the ProjectDesignSystemPicker and related components to support localized design system summaries and categories, improving user experience.
- Introduced new translations for working directory and design system picker components, ensuring better accessibility and usability across different locales.
- Added a new 'live-artifact' project type to the HomeHero chips, expanding the functionality for users creating refreshable artifacts.
- Updated tests to validate the new project metadata handling and design system picker functionalities.

* feat: enhance localization and styling for design system components

- Added French translations for working directory and design system picker components, improving accessibility for French-speaking users.
- Updated CSS styles for the pet task item to ensure consistent padding and layout.
- Introduced a new test suite for HomeHeroSettingsChips to validate localization and design system selection functionality.
- Enhanced ProjectDesignSystemPicker tests to ensure proper localization and interaction with design system categories.

* fix: update .gitignore to include all claude-sessions directories and remove specific session files

- Modified .gitignore to ensure all claude-sessions directories are ignored by using a wildcard pattern.
- Deleted two specific claude-sessions markdown files to clean up unnecessary session data.

* fix: repair home automation ci regressions

* fix: stabilize artifact consistency e2e

* Remove folder picker changes from PR 2400

---------

Co-authored-by: pftom <1043269994@qq.com>
Co-authored-by: qiongyu1999 <2694684348@qq.com>
2026-05-20 22:07:30 +08:00
Marc ChanandGitHub f294ab4915 chore(ci): add visual regression PR workflow (#2372)
* Add visual regression PR workflow

* Allow manual visual PR comments

* Post visual comments for same-repo PRs

* fix(ci): surface R2 lookup failures in visual report

Generated-By: looper 0.8.1 (runner=fixer, agent=opencode)

* Align visual workflow names
2026-05-20 15:05:59 +08:00
lefarcenandGitHub 80d305858b feat(diagnostics): add one-click log export from Settings → About (#798)
* feat(diagnostics): add one-click log export from Settings → About

Adds a new "Export diagnostics" entry under the About section that bundles
daemon/web/desktop logs, machine info, and recent macOS crash reports into
a zip the user can share when reporting issues.

- Browser hits a new daemon HTTP endpoint and triggers a download.
- Electron uses an IPC bridge with the native save dialog and reveals the
  saved file in Finder/Explorer; the Help menu also exposes it as a
  fallback when the daemon is unresponsive.

Packaging + redaction lives in a new @open-design/diagnostics package so
both surfaces share it. Sensitive JSON keys, URL query secrets, and the
current user's home path are redacted before packaging.

* build(nix): include packages/diagnostics in daemon build targets

The Nix daemon derivation builds workspace siblings in dependency order
before compiling apps/daemon. Without @open-design/diagnostics in that
list, the daemon TypeScript build fails inside the Nix sandbox with
`Cannot find module '@open-design/diagnostics'` because pnpm install
only creates the symlink — the dist output that the package.json
exports point at isn't produced until each sibling's build script runs.

* build(tools-pack): include @open-design/diagnostics in packaged INTERNAL_PACKAGES

Without this, packaged win/mac/linux builds fail with `npm error 404` when
the post-build `npm install --omit=dev --no-package-lock` step in the
assembled app tries to resolve `@open-design/diagnostics@0.2.0` from the
public npm registry. The package is workspace-private, so it has to be
tarballed via `pnpm pack` and file:-referenced from the assembled
package.json like every other internal workspace dep that daemon/desktop
depend on.

Also wires the package's `pnpm --filter ... build` into the pre-pack
workspace build step so the dist/ exists before pnpm pack runs, and
updates the two test fixtures (`win-app.test.ts`, `workspace-build.test.ts`)
that mirror INTERNAL_PACKAGES.

The diagnostics package itself is repinned to exact dependency versions
already used elsewhere in the workspace (`jszip 3.10.1`, `@types/node
20.19.39`, `esbuild 0.28.0`, `typescript 5.9.3`, `vitest 4.1.6`) so it
passes the new `pnpm guard` exact-version rule and produces a minimal
lockfile diff vs main (additions only, no resolution-string churn).

* fix(diagnostics): include `~` in bearer-token redaction char class

RFC 6750 token68 syntax allows `~`, so tokens like `Authorization: Bearer
abcd~efgh` were only partially matched by `HTTP_AUTH_SCHEME_RE`. The
regex stopped at the first `~`, leaving the tail (`~efgh`) un-redacted in
the exported diagnostics zip — a clear leak since this feature explicitly
generates support bundles for external sharing.

Add `~` to the character class and a regression test.

* fix(diagnostics): only collect renderer.log from desktop

`buildSidecarLogSources` unconditionally added `logs/${app}/renderer.log`
for daemon/web/desktop, but only the desktop runtime writes a renderer
log (see apps/desktop/src/main/runtime.ts) — daemon and web are pure
Node services with no Electron renderer. Every export therefore produced
missing-file placeholders and manifest warnings for the two phantom
paths, polluting the bundle.

Gate the renderer.log source on APP_KEYS.DESKTOP so the daemon-side
collector matches the desktop-side collector in apps/desktop/src/main/
diagnostics.ts:63.

* fix(diagnostics): mirror desktop-side renderer.log gate

The previous fix only updated the daemon-side `buildSidecarLogSources`
in `apps/daemon/src/diagnostics-export.ts`. The desktop-side collector
at `apps/desktop/src/main/diagnostics.ts` had an identical copy of the
same bug that I overlooked: it also unconditionally added
`logs/${appKey}/renderer.log` for daemon/web/desktop, producing
missing-file placeholders + manifest warnings for the two phantom paths
on every desktop-initiated export.

Apply the same `appKey === APP_KEYS.DESKTOP` gate here so both export
entry points (browser via daemon HTTP, Electron via native save dialog)
emit the same clean manifest.

* feat(diagnostics): add `od diagnostics export` CLI subcommand

AGENTS.md's dual-track capability-exposure contract requires every
user-facing feature to ship on both the web UI and the `od` CLI. The
diagnostics export was only reachable through Settings → About and the
desktop Help menu; this commit closes the loop with an `od diagnostics
export [<path>] [--json]` subcommand registered in SUBCOMMAND_MAP.

The CLI is a thin shell over the existing GET /api/diagnostics/export
endpoint — same zip output, same redaction, same crash-report scope.
Defaults to writing `open-design-diagnostics-<timestamp>.zip` in the
current directory; `--output <path>` or a positional arg overrides.
`--json` prints `{path, sizeBytes}` for shell pipelines.

Use cases this unlocks:
- A CI script can `od diagnostics export ~/artifacts/bundle.zip` after
  a failed run.
- Bug reporters on headless boxes can grab a bundle without booting
  the web UI.
- `od doctor` follow-ups can collect a full snapshot when a probe fails.

* fix(diagnostics): surface non-sidecar launch in manifest warnings

`buildSidecarLogSources()` returns `[]` when the daemon has no sidecar
runtime context, which is the standard `od` (plain) launch path —
`runDaemonCliStartup()` -> `startDaemonRuntime()` does not pass a
runtime. Settings → About and the new `od diagnostics export` previously
reported success but produced a bundle with only the summary JSONs, so
operators could not tell "no logs because plain launch" from "no logs
because something genuinely broke."

- Extend `DiagnosticsContext` with an optional upstream `warnings:
  string[]` that `buildManifest` merges into the manifest warnings.
- Emit STANDALONE_LAUNCH_WARNING from the daemon handler when
  `options.runtime == null`. The warning names the limitation and
  points the user at the sidecar entry points that DO capture logs.
- Add a regression spec at `apps/daemon/tests/diagnostics-export.test.ts`
  that drives the handler with `runtime: null` and asserts the warning
  surfaces in `summary/manifest.json` (and that `files` is empty so a
  user reading the bundle does not confuse "no log sources" with
  "missing files").
2026-05-20 09:10:51 +08:00
PerishFireandGitHub 2c128e0e91 refactor desktop host bridge (#2246) 2026-05-19 18:27:05 +08:00
6a08dfe111 Add design system package quality guard (#2224)
* Add design system import manifest schema

* Generate hybrid design system imports

* Read design system usage and cached manifests

* Add design system pull-file tool

* Show design system package evidence

* Wire design system import semantics

* Add design system package quality guard

---------

Co-authored-by: chaoxiaoche <chaoxiaoche@chaoxiaochedeMacBook-Pro.local>
2026-05-19 16:53:29 +08:00
PerishFireandGitHub bd48c597b0 chore: pin dependency versions and harden CI caches (#2189)
* chore: pin dependency versions

* ci: enforce pinned dependency specs

* ci: fix pnpm executable invocation
2026-05-19 13:58:27 +08:00
PerishFireandGitHub 4424f08be0 [codex] Add packaged desktop auto-update (#1375)
* Add packaged desktop auto-update

* Handle counted beta nightly update versions

* Refresh desktop auto-update branch for main

* Serialize desktop updater operations

* Refresh auto-update branch for packaged paths
2026-05-19 11:20:05 +08:00
f7eb82d7a5 feat(design-systems): import design system projects (#2112)
* feat(design-systems): define project manifest contract

* feat(design-systems): add default project manifest

* feat(daemon): consume design system manifests

* feat(design-systems): import local project systems

* feat(design-systems): import from github repositories

---------

Co-authored-by: chaoxiaoche <chaoxiaoche@chaoxiaochedeMacBook-Pro.local>
2026-05-18 20:20:38 +08:00
1f66c53203 feat(daemon): consume component manifests (#2053)
* feat(design-systems): extract component manifests

* feat(daemon): consume component manifests

---------

Co-authored-by: chaoxiaoche <chaoxiaoche@chaoxiaochedeMacBook-Pro.local>
2026-05-18 16:50:52 +08:00
46a64edce3 feat(design-systems): extract component manifests (#2051)
Co-authored-by: chaoxiaoche <chaoxiaoche@chaoxiaochedeMacBook-Pro.local>
2026-05-18 16:48:59 +08:00
d1a2f9f07e chore(design-systems): report component fixture coverage (#2049)
Co-authored-by: chaoxiaoche <chaoxiaoche@chaoxiaochedeMacBook-Pro.local>
2026-05-18 16:47:34 +08:00
asim48-ctrlandGitHub 08d6bc73ac Clarify ui-ux-pro-max catalog scope (#1960) 2026-05-18 14:02:33 +08:00