* fix sharing to keep file publication independent of team visibility (OPEND-3855)
* fix(comments): synchronize current file lifetimes across members and shares
OPEND-3870 / OPEND-3871. Stack on published OPEND-3855 dependency; preserve reviewed source tree exactly. Local validation does not establish PostgreSQL or native acceptance.
* refactor sharing to one explicit policy path (OPEND-3855)
* fix(collab): adapt comment sync to converged project lifecycle
* test: isolate metadata snapshots from the trailing identity directive
* fix(collab): preserve nested publication and pulled file authority
* fix: align collaboration consumers with explicit project visibility
Carry trusted catalog roots through content receivers and suppress stale Team rows after explicit privacy changes. Read shared design-system brand assets from their resource snapshots. Align stopped-publication ordering and protocol/browser fixtures with the existing contracts.
* fix(collab): preserve relay identity and retire captured file batches atomically
* test: await explicit comment preparation and independent UI states
Complete the existing source-version consent and real frame-readiness flow before opening the comment sidebar. Bind the response waiter to the UI actions so failures retain their real cause. Await the independently loaded account callout and assert exact catalog-bound materialization wiring.
* test: expect private policy when unsharing a team project
Await the explicit visibility-private command instead of deleting the retained root registration. Assert that remove was not invoked and preserve all member quarantine, directory and file-read privacy checks.
* fix(collab): retain the actual native root during mirror materialization
* fix(collab): fail closed on unbound active share identity
* fix(collab): retire comment lifetimes after local mutation commits
* fix(collab): commit local artifact invalidation with working-root changes
* fix(collab): reconcile committed root retirement without stopping new links
* test(collab): align CI fixtures with admitted file identities and receipts
* test(collab): model receipt-backed root file admission in the shared hub
* test(collab): distinguish bound and unbound publication recovery
* fix sharing to keep file publication independent of team visibility (OPEND-3855)
* refactor sharing to one explicit policy path (OPEND-3855)
* test: isolate metadata snapshots from the trailing identity directive
* fix: align collaboration consumers with explicit project visibility
Carry trusted catalog roots through content receivers and suppress stale Team rows after explicit privacy changes. Read shared design-system brand assets from their resource snapshots. Align stopped-publication ordering and protocol/browser fixtures with the existing contracts.
* test: await explicit comment preparation and independent UI states
Complete the existing source-version consent and real frame-readiness flow before opening the comment sidebar. Bind the response waiter to the UI actions so failures retain their real cause. Await the independently loaded account callout and assert exact catalog-bound materialization wiring.
* test: expect private policy when unsharing a team project
Await the explicit visibility-private command instead of deleting the retained root registration. Assert that remove was not invoked and preserve all member quarantine, directory and file-read privacy checks.
* fix(od-next): restore production follow-up host instructions
Compose production host instructions with the same fresh key persisted on the run, including native resume, cold-start input, and UI locale. Keep the instructions independent of retired model state declarations and exclude the nonce-bearing text from internal continuation retry identity.
Verify optional suggestions, message persistence, and repeated preparation through the real server and run registry. Validated with main red specs, focused regression tests, guard, and the workspace typecheck.
* test(od-next): preserve production test entry points
Keep the existing production test header and fixture setup while sharing host-protocol assertions with a separate suggestions case. This avoids adding a conflict with the pending agent rollout tests.
Validated with the focused real-server regressions, guard, and the full workspace typecheck.
* fix(cms): fence offline replay across revocation and process death
* feat(cms): define paginated Test catalog and immutable runtime context
* fix(cms): synchronize Test and Production host presentation lifecycles
* test(cms): retain cross-host lifecycle and browser acceptance regressions
* fix(cms): retain request tickets through body classification
---------
Co-authored-by: heggria <bshengtao@gmail.com>
Co-authored-by: ivy-tinggg <986810707@qq.com>
* feat: add Motion Design skill and OD Next task route
* fix(web): rename motion design entry and place it second
* fix(web): reconcile motion design catalog consumers
* feat(web): add motion design templates to Home and Community
Five motion design example templates (3D procedural island, explainer,
product launch, showreel, data story), chosen by community reach, under the
Home motion-design chip and a new Community "Motion design" type.
Each template follows the bundled example layout: an OD-generated
example.html with its runtime libraries under assets/, an HTML preview baked
by the existing preview pipeline, and a SKILL.md that carries example.html
as the reference when the card is picked on the OD Next motion-design route.
Home cards ship curated copy for every UI locale. Motion templates stay off
the Video and HyperFrames chips.
* fix(skills): keep motion-design procedural layers visible in video export
The MP4 exporter seeks timelines with callbacks suppressed
(renderSeek(t, { suppressEvents: true })), so content drawn only from a GSAP
onUpdate callback is missing from exported video. Recommend a per-frame draw
loop that reads the timeline clock, and state that visible content must not
depend on timeline callbacks. The OD Next task asset is re-synced with
scripts/sync-motion-design-skill.ts.
* fix(motion): preserve reference assets and exported animation frames
* feat(skills): integrate curated motion helpers with complete runtime files
* feat(skills): add Huashu, Oil Motion and Motion.Lab adapters
* test: classify animate design guidance in narration guard
* feat(motion): refine five community templates and portable previews
* fix(motion): refine launch transitions and center gallery previews
* fix: allow free-form briefs on automatic motion task route
* feat(motion): add template soundtracks and audio export
* fix(motion): require rendered MP4 alongside editable video source
* test(motion): align strategy activation expectation with package version
* fix: scope motion delivery and make editable sources playable
* fix(motion): bundle source dependencies and valid closing protocol
* feat(motion): rebuild the five templates on the most-viewed community posts
Re-select topics by single-post views in the latest awesome-opus-5.5-video
snapshot and anchor each template to the top eligible post of its genre:
camera-focus explainer, showreel, product launch, procedural island and a
new wordless animated short that replaces the data story.
All five example.html files are hand-authored canvas/Three.js films drawn by
one render(t) from the GSAP master timeline, so preview, scrubbing and MP4
export produce identical frames. Each ships an original procedural
soundtrack, updated SKILL.md and 19-locale copy; Home order follows reach.
* fix(plugins): load bundled fonts in plugin previews
Plugin previews blocked every bundled font: the preview CSP had no font-src,
and relative url() references inside inline <style> blocks kept pointing at
the preview URL instead of the plugin folder. Allow same-origin fonts, map
inline-style url() references through the existing asset route (escapes,
absolute and data: URLs stay untouched), and serve font files with font
MIME types.
* feat(community): make motion template Use match the Home example pick
Community 「做同款」 on a motion design template now binds it as that type's
own example card, carrying the type's project metadata, so the run takes the
same OD Next motion-design route as a pick from Home's motion design list and
delivers the MP4 together with the editable source. Other task types keep
the existing plugin-pinning hand-off.
Community use clicks now record use_source (card | detail_modal) and
use_action (use | use_with_query); the details modal Use is tracked for the
first time. The Home hand-off no longer records a second community_gallery
click for uses Community already tracked.
* fix(plugins): count the five motion templates in the official registry metadata
* fix(media): keep HyperFrames audio filters compatible with FFmpeg 4.1
CI's bundled Linux FFmpeg 4.1 rejects adelay all=1 and amix normalize=0.
Make each track stereo and delay both channels explicitly, skip amix for a
single track, and undo amix averaging with a gain for several tracks.
* fix(motion): keep template previews bakeable on slow CI renderers
CI's software-GL baker skipped the 3D island (preview readiness timeout):
under slow frames GSAP lag smoothing slowed the timeline, so the 8 s
poster frame never arrived within the baker's 15 s wait. Play every
template on the wall clock and move the island poster to 6 s. With
simulated 300 ms frames all five now report ready within 10 s.
* feat(motion): add the kinetic typography template
Template selection now follows the motion design spec's four content types
(brand and product films, kinetic typography, explainer animation, procedural
art). Kinetic typography takes the fifth slot, replacing the animated short.
The new template is a 15-second, 120 BPM type film with an original
soundtrack and 19-locale copy.
* fix(motion): let the project motion player fit template stages
Inside a project the motion source player wraps the composition, fits it and
adds its own controls. The templates also scaled their stage, so editable
sources from Remix and Community use rendered at a fraction of the preview.
Templates now keep their own fit and controls only outside that player.
* feat(motion): restage the 3D island as a midday lagoon
The island moves from golden hour to a bright tropical midday closer to its
anchor post: a shader lagoon coloured by a baked depth map with ripples,
shallow-water shimmer and shore foam, a wide white-sand beach, palms and
instanced bushes, a village with a pier, soft sun shadows and a lower
camera path. The CPU wave mesh is gone, so frames cost no more than before.
Copy is updated in all 19 locales.
* fix(motion): keep each soundtrack inside the composition root
A Community use regenerated the island source tail and dropped the root
<audio> element, so its MP4 had no sound. Templates now place the element
inside the composition root next to the stage.
* docs(motion): state the template selection rule as complete works
* fix(motion): enforce video clocks and bound content verification
* feat(motion): replace the motion templates with remakes of viral posts
The five Motion design templates are now frame-faithful remakes of viral
motion posts, so each preview shows the look users came for: the 15-second
motion designer showreel, a high-energy motion reel (copy set in English), a
one-shape UI motion piece, a pixel-art wizard and a 20-second electric-blue
tech reel. Each ships open-licensed fonts, an original soundtrack, the
creator's published prompt where one exists, and credits its source post.
The explainer, product launch, 3D island and kinetic type templates are
removed. Tests follow the new set; a backward-seek check now covers hidden
WebGL layers.
* feat(motion): feature The Future Is Already Here first and start preview sound with the film
* chore: ensure PR CI
* fix(motion): match The Future Is Already Here controls and reorder the motion templates
* fix(motion): make the one-shape UI preview controls legible
* fix(motion): hide The Future Is Already Here controls inside the project player
* fix(motion): plan suitable sound and synchronize source audio playback
* feat(motion): keep remake soundtracks by default and fade exported audio where it stops
* test(motion): cover audible source controls in Chromium
* fix(test): use explicit ESM imports in audio player regression
* fix(motion): align preview track discovery with video export
* feat(motion): autoplay looping HTML without a player bar
* fix(test): consume the built motion playback contract
* docs(motion): state explicit soundtrack rules for make-same and the music line in replies
* chore(motion): version the audible looping delivery profile
* docs(motion): let template sound rules lead the general policy and freeze the audio contract
* fix(motion): scope autoplay to declared video motion sources
* fix(motion): reject audible MP4s under an explicit silent contract
* docs(motion): drop the routine music note from make-same replies
* test(motion): align delivery regressions with looping source playback
* fix(motion): isolate preview and audio export from legacy HyperFrames
* test(motion): retain the existing desktop legacy audio limitation
* fix(motion): suspend audio when previews leave the active workspace
* feat(motion): replace two motion templates with a product promo and a visual lesson; sign the showreel as Open Design
* feat(motion): give the showreel the Open Design palette and a full-size stacked wordmark
* feat(motion): give the product promo a livelier mascot girl
* refactor(motion): rebuild The Future Is Already Here as readable, editable scene code
* fix(motion): pick gallery cover frames that survive the baker's capture delay
* feat(motion): sharpen the showreel opener, depth, truchet and end card
* feat(motion): make the product promo mascot talk, add a speaking score and the flow pop
* feat(motion): give the visual lesson the original's paper-collage texture
* fix(motion): bundle gallery covers for fresh branch checkouts
* feat(motion): feature and refine Bring Ideas to Life
Adapt the paper story around OpenDesign capabilities, with short rounded hands, clearer timing, continuous paper actions, and a larger audience invitation. Feature it first in Motion and synchronize localized names, metadata, cover, guidance, and regressions.
Keep product promo audio music-only with sparse percussion.
* fix(motion): stabilize artifact cards and capture declared covers
* fix(web): share creation type order with community
* test(motion): exercise audio controls through project UI lifecycle
* fix(motion): scope live cover behavior to actual video sources
* test(motion): use real HEAD responses in cover regressions
---------
Co-authored-by: bone3deep1962-collab <bone3deep1962@gmail.com>
Co-authored-by: William <zhouhaoran@refly.ai>
Co-authored-by: open-design-crew[bot] <4197780+open-design-crew[bot]@users.noreply.github.com>
Co-authored-by: NJUHua <113895241+NJUHua@users.noreply.github.com>
Co-authored-by: Amy <1184569493@qq.com>
* fix(od-next): continue plans with keyed markers and honor explicit deliverables
* fix(od-next): retire output contracts and hand off continued tasks
* fix(od-next): record round settlement and recover production cold
* fix(od-next): resume marker sessions with context deltas
* fix(od-next): separate completion facts and honor plan-only intent
* fix(od-next): preserve physical failures and legacy chat compatibility
* test(web): align run recovery fixtures and await campaign mount
* fix(od-next): tolerate terminal production marker formatting
* fix(od-next): unblock follow-ups after a stop or unreadable history (#8423)
Treat a previous task this build cannot read as absent so the follow-up starts a new task, and stop counting a Run with a pending cancel as holding its conversation. Add end-to-end coverage for the marker continuation flow and restore the remote Workspace directory gate cases.
* docs: clarify focused local validation
Keep local daemon and web validation scoped to affected files and integration boundaries. Reserve full suites for PR CI unless the user explicitly requests them.
* fix(web): scope folded task completion to its final run
Keep the final physical Run key and conclusion together when OD Next history is folded or accumulated live. Reuse the existing predecessor offsets while retaining the full display history and remaining Todo snapshot.
Add regression coverage for completed and unfinished production, live continuation, multiple Runs, legacy history, wrong and quoted markers, question handoff, and failed or canceled Runs.
Validated the parent regression before the fix, 165 focused Web tests, workspace typecheck, and guard.
* fix(od-next): compact historical context without restricting clarification
Reuse confirmed artifact summaries for old assistant history, preserve cross-agent plans and original requests, and represent earlier questionnaires as neutral historical information without inferring answers.
Keep user replies, skips, changed answers, unpersisted bodies, examples, and unfamiliar content intact. Do not add question repetition checks, output gates, repair rounds, or limits on clarification.
Validated red regressions, shared context and Web provider tests, focused handoff/resume/cold-production coverage, real server and fake CLI input, workspace typecheck, and guard. The repeated-question server fixture remains successful.
---------
Co-authored-by: bone3deep1962-collab <bone3deep1962@gmail.com>
Co-authored-by: Cheems <hihicheems@gmail.com>
Co-authored-by: Cheems <94773058+itscheems@users.noreply.github.com>
Long macOS temporary-directory paths can push private sidecar sockets beyond the 103-byte pathname limit and crash startup. Fall back to /tmp only for oversized macOS paths, preserving the full digest and UID isolation. Add byte-boundary, identity, platform-compatibility, and native macOS IPC regression coverage.
The bundled OpenCode is a Bun binary and Bun requires Windows 10 1809
(build 17763). On older builds it exits with STATUS_ENTRYPOINT_NOT_FOUND
(0xc0000139) before readiness, which was classified as a retryable
fatal_rpc_error and shown as a generic failure. Classify it as a
non-retryable os_unsupported when the host build is below 17763 and show
a card telling the user to update Windows.
* fix(daemon): keep ACP turns succeeded when the daemon force-closes the agent
After a clean ACP end_turn the daemon waits 500ms and then terminates the
agent. On Windows a child killed by pid reports exit code 1 with no signal,
so the close classifier (which only forgave SIGTERM or code 130) marked
the completed turn failed with exit_nonzero and suppressed retry. In the
last 7 days this hit 143 AMR runs from 65 Windows users on 0.24.1; every
sampled bundle (76/76) had already returned stopReason end_turn.
Treat any exit as succeeded once the daemon itself began shutting down a
cleanly completed ACP attempt.
* fix(daemon): only forgive a completed ACP exit the daemon itself caused
Review follow-up. terminateProcessTree waits gracefulWaitMs before it
signals anything, so a vela that exits 1 on its own during that wait
used to count as a daemon shutdown and was reclassified as succeeded.
terminateProcessTree now takes onChildSignal, called just before the
first signal to a direct child that is still alive (POSIX group,
pid-less and Windows pid-tree paths). server.ts sets
acpCompletionShutdownRequested from it for the completed-turn
termination only, so a non-zero exit during the grace wait stays failed.
* fix(daemon): report a daemon close only after the signal was delivered
Review follow-up. `onChildSignal` ran before the stop helpers dispatched
anything. If that dispatch then failed (a non-ESRCH error from the Windows
stop path) or found the child already gone (ESRCH), the flag was still set,
and a child that later exited 1 on its own was reported as succeeded.
- platform: `stopProcesses` takes `onSignal`, called for each PID a signal
was actually delivered to. ESRCH and thrown dispatches are not reported.
- runs: the completion-shutdown callback fires once, after the first
delivered signal to the still-owned direct child, on the Windows pid-tree,
POSIX group and pid-less paths alike.
* fix(od-next): recover planning replies that repeat the runtime state block
OD Next treats a reply with more than one open-design-runtime-state block
as non-repairable, so the task ends before anything is produced. On AMR
0.24.1 that surfaced as OD_NEXT_CONTINUATION_FAILED ("The parsed response
was not eligible for contract repair.") on 16 design-mode prototype runs
from 15 users in the last 7 days, 15 of them with no artifact. Most of the
daemon logs we could read show `Expected at most one
open-design-runtime-state block, received 2.`
- Collapse runtime state blocks that carry the same JSON value (key order
aside) into one declaration and record a normalization.
- Let disagreeing runtime state blocks take the existing one-time
serialization repair. Nothing has been written at this point. When every
block agrees on executionIntent, that intent counts as the reply's
explicit intent for the repair gate; otherwise the gate stays closed.
- Plan Contract duplicates still fail closed.
* fix(od-next): send agreed-produce duplicate runtime states straight to repair
Review follow-up. A duplicate Runtime State reply has no strict runtimeState,
so requiresStrategyIntentResolution treated a new task's intent as missing
and spent an intent-resolution turn before the serialization repair: two
provider turns where one was promised.
When every duplicate block declares `produce`, the intent is already
explicit, so the automatic continuation now claims the contract repair Run
directly. An agreed `plan_only` still takes the intent-resolution turn,
because only that turn can complete a planning-only task; the repair gate
would block it.
* test(od-next): cover duplicate runtime states that go through intent resolution
On AMR 0.24.1, 19 of 20 duplicate runtime-state failures asked the intent
supplement first. The model answered produce with one clean block, then the
original reply, still carrying the duplicate, was refused with "The parsed
response was not eligible for contract repair." This path already repairs
on this branch; the test fails with that exact error on the parent commit.
* fix(od-next): let the supplement complete a duplicate-state planning-only task
A planning reply whose two Runtime State blocks both declare plan_only goes
through intent resolution, but the source keeps no state of its own, so the
validated plan_only reply could not be copied anywhere and the task was blocked
on the duplicate. When the duplicate is the source's only defect, the
supplement's schema-validated plan_only state now completes the task and the
source Plan Contract is kept. Any other source defect stays fail-closed.
* fix(od-next): bound prototype SVG icon geometry
* fix(od-next): classify prototype SVGs by role, not canvas size
The icon contract listed example glyphs on each side but gave no rule for
anything outside those lists, so a logo inside a button or a deliberately
large UI glyph had to be guessed. State the basis: classify by the role the
SVG plays, not by canvas size or the presence of a viewBox.
---------
Co-authored-by: bone3deep1962-collab <bone3deep1962@gmail.com>
* fix(web): align export and update-check error copy with product (OPEND-2849)
- S26a: a generic export failure now shows the product title + body
("导出失败" / "本次导出未完成,请重新尝试。") through the same Toast
message + details shape as S26c. fileViewer.exportFailed is split into
fileViewer.exportFailedTitle / fileViewer.exportFailedDescription in all
19 locales; the old key is removed.
- S31b: drop the sentence-final period from the title line of
updater.dialogCheckFailed (zh-CN and 17 other locales; th had none).
* fix(web): never surface raw exporter errors on export failure (OPEND-2849)
Product copy S26: an export failure shows the S26a title + body by default;
only an already-localized, user-facing reason may replace it. Raw exporter
strings (HTTP status lines, renderer/daemon errors, internal exceptions)
no longer reach the toast.
- New export-failure-toast module: LocalizedExportError marks errors whose
message comes from an i18n key; exportFailureToast passes only those
through and falls back to S26a for everything else.
- Localized reasons now thrown as LocalizedExportError: PPTX daemon
unreachable / PPTX not available, version image capture failed.
- Image export catch-all uses the same rule instead of echoing err.message.
- The original error object is unchanged, so console.warn and
exportErrorCode analytics still see the raw message.
* fix(web): align disk-write failure and browser-open hint copy with product (OPEND-2849)
- chat.runError.localStorageFailureMessage now matches the product supplement
row 13 verbatim in zh-CN ("…请确认有足够的剩余空间后,再重新尝试。"); the
old "permission to save to the current folder" clause is dropped and all
19 locales are retranslated to the new meaning.
- settings.amrActivationBrowserFailed (S32 browser not opened): half-width
comma replaced by a full-width one in zh-CN and zh-TW; wording unchanged.
* fix(web): align S03/S04/S06/S09a/S15/S24/S28a/S31c/S32a error copy with product (OPEND-2849)
zh-CN copied verbatim from the product error-copy doc; all 19 locales translated.
- S04 pre-send signed out (balance gate dialog): "Open Design 尚未登录" + body.
- S06 pre-send insufficient allowance: owner dialog "可用额度不足" + body (no
balance figure); member dialog "团队额度不足" + body. Benefits list and
buttons unchanged.
- S15 mid-run allowance exhausted: the turn-anchored upgrade card's $0 state
shows title + body, personal vs. member chosen by the billing audience
ProjectView already resolves. Low-balance tier, amount and Upgrade button
unchanged; the pre-send tail card keeps "现在无法开始新任务".
- S24a unfinished todos: "任务尚未完成" + "本次任务仍有 {n} 项内容未完成。" with the
real unfinished count; S24c user stop: "任务已停止" + body. Buttons kept.
- S03 / S28a Home send failures: the optimistic create's rollback toast (the
surface users actually see) and HomeView's inline block now map
AMR_AUTH_REQUIRED to S03 and transport failures to S28a, as title + body.
- S31c update download failed (updater error code download-failed): update
dialog shows "更新下载未完成" + body; Settings status shows the title.
- S32a browser not opened during sign-in: title + body via one shared
component for the three sign-in surfaces; the sign-in page link is kept.
- S09a rate-limit auto retry: run_retry_attempted now carries
failure_category in the SSE contract; a rate_limit retry row reads
"模型服务请求繁忙" + body, other retries keep "正在重试".
When two local processes race to refresh the same stored OAuth credential,
the agent aborts its refresh and reports the condition as transient:
Failed to refresh OAuth token: another Claude Code process is refreshing
it or exited mid-refresh. This is usually transient; retry in a minute...
The classifier had no branch for this text, so it fell to the generic
process-exit fallback as `exit_nonzero`, which `transientSuppressedReason`
refuses for `process_exit` with `non_retryable_category`. The safe-retry
path was suppressed and the run died on a dead-end failure card, for a
condition that clears as soon as the contending holder releases the lock.
Name it `credential_refresh_contention` and wire it the way
`session_resume_expired` already is: classified at `session_init` as
retryable with `user_action: 'retry'`, and added to the `process_exit`
transient allowlist.
The branch is claimed ahead of the auth verdicts on purpose. The message
ends "...or sign in again", and `auth` is fixed at `retryable: false` /
`user_action: 'login'` — reaching it would prescribe re-authenticating a
credential that never expired. The detector is anchored on the contention
itself rather than on the word "refresh", so a genuinely spent or replayed
refresh token keeps its non-retryable auth verdict; a test pins that
direction.
Retry is safe without further gating: the failure is raised before a
request is sent, so nothing streamed, no tool ran and no artifact was
written, leaving the side-effect gates in `decideSafeRunRetry` satisfied.
Referenced .html/.htm files (iframes, frames) are now walked like the entry:
their references resolve against their own directory at any depth, so their
stylesheets, images and child pages ship and missing/invalid ones are
reported. Share mode rewrites their root-absolute references relative to
their own directory and maps references to the entry to the published
index.html; standalone deploy keeps their bytes.
Parsing is deduped on each file's real path, which bounds the walk even with
in-project symlink loops (x -> .) and also fixes the existing unbounded CSS
@import recursion through such links.
A reference to an existing root index.html while sharing another page no
longer overwrites the entry: the plan records the conflict (referrer file,
attribute, line, suggested free name) and deploy refuses it with 409
ENTRY_INDEX_CONFLICT carrying a copy-to-agent fix prompt.
* fix(diagnostics): collect the AMR run's runtime log records (OPEND-3498)
AMR incidents never carried AMR-side evidence. The collector looked for
OpenCode logs under <dataDir>/amr/opencode-home, but Vela drops the
OPENCODE_TEST_HOME it receives and runs OpenCode under per-conversation homes
in $AMR_HOME/opencode-sessions, so nothing was listed and no note explained
the gap. $AMR_HOME/logs/agent-runtime.jsonl was never listed either.
- Take the incident run's records from agent-runtime.jsonl, plus those of the
OpenCode sessions it owns until another run takes a session over, so other
runs' records never enter the bundle.
- Report a missing runtime log, a missing run id and the not-yet-located
session logs as explicit collection notes, and keep those reasons instead
of a consent verdict.
- Give sources that appear after opting in a boundary at their current size
on start, so a newly listed shared log is not omitted forever.
Locating the per-conversation OpenCode session logs is left for a follow-up.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(diagnostics): keep a rotated log's baseline when extending the fence
On Windows the packaged launcher rotates latest.log to previous.log at every
start. extend() saw previous.log as an unbaselined path and recorded a
boundary at its current size, so the rotated log's bytes written after the
real boundary were dropped as consent_boundary. Found in a packaged Windows
run: the daemon log written after opting in was missing from the bundle.
Skip files that share a baselined creation time; the fence decides their
boundary from that baseline. Skipping only defers to apply() and never
admits bytes by itself.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* fix(diagnostics): stop repeating API failures from flooding automatic uploads
Stable 0.24.1 devices uploaded thousands of diagnostic incidents a day from
one deterministic failure: GET /api/runs answering 400 PROJECT_SCOPE_REQUIRED.
- Key API-failure incidents by failure signature per hour instead of the
per-request id, so a polling caller yields one incident per hour.
- Drop earlier "[diagnostics] incident delivered" receipt lines from
automatic bundles; on busy devices they filled the daemon log tail.
- Desktop pet task center: stop interval polling once the daemon requires a
project scope, and stop restarting the poller on every 1.5s config reload.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(diagnostics): filter receipts before allocating the log tail budget
Scan automatic text logs backward with bounded buffers, preserving complete lines and consent offsets before applying the retained byte limit. Cover receipt suffixes larger than 4 MiB and filtered-tail boundary cases.
Generated-By: looper 0.13.0 (runner=fixer, agent=codex)
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The daemon no longer builds the public share address from a hardcoded or
per-channel Viewer origin. AMR reports it: `vela share publish|bind|resume|
project-status --json` carry `url` (https://<share origin>/artifact/{projectId}/{slug})
for an active binding, or `link: {status: "unavailable", code}`.
Link rule, one place (resolvePublicShareLink): an explicit
OD_SHARE_VIEWER_URL(S) override wins (a present invalid override is
unavailable, never a fallback); otherwise the AMR address, accepted only when
it is byte-for-byte the canonical HTTPS root-origin address of this project
and slug; otherwise unavailable, passing AMR's code
(PUBLIC_SHARE_WEB_URL_UNAVAILABLE / PUBLIC_SHARE_IDENTITY_INVALID) through.
A rejected address is logged without echoing it.
The verified AMR address is persisted with the publication and refreshed on
publish, foreground bind/resume, the background binding retry and every
publish-public status read, without rotating the publication witness. When
the status read fails, GET falls back to the persisted link marked
`stale: true` (not for a queued stop); a stored legacy console URL fails
re-verification and stays hidden until the next online read replaces it.
Packaged daemons no longer get a per-channel Viewer origin and tools-dev has
no default; an explicit launch override is still forwarded. `od project share`
prints the same link, a stale notice on stderr, and says when an alias has no
Viewer address.
A share-page comment resolved at cloud seq 10 reverted to open after a daemon
restart: the legacy pull cursor is in memory, so the restarted daemon replays
from seq 0, and the merge stamped Date.now() on the share-page create (which
carries no updatedAt), making the replayed create look newest.
Each preview_comments row now records the highest cloud revision seq it
reflects (cloud_revision_seq) and the seq space it came from
(cloud_revision_stream: relay team + member stream epoch). An incoming
revision at or below that seq in the same stream is a replay and never
overwrites the row. Unseen revisions keep updatedAt last-writer-wins when they
carry an updatedAt; one without updatedAt applies in seq order and is stored
with its createdAt, never the local clock. pin_seq is untouched.
Publishing a public link for a private project in a team workspace registers
it in the team catalog, but only the later background reconcile marked the
local row team-visible. Until then the row was personal in a team workspace,
which is neither Team- nor personal-relayable: the publish backfill was
cancelled (BACKFILL_DELIVERY_DISCARDED) and comments written right after
publishing were never queued.
- publish-public marks the creator's private row team-visible right after
catalog registration, before the publication transaction enqueues the
backfill (decision 67 #11); the response carries madeTeamVisible.
- The relay re-queues a personal record as Team relay once its creator's
project turned team-visible, and defers (bounded) a personal record in a
team workspace whose publication is still current instead of cancelling it.
- A cloud seq is never adopted as pin_seq when another confirmed row of the
file already holds it, which produced two pins numbered 1.
Public share links come from OD_SHARE_VIEWER_URL(S) (HTTPS root origin)
as https://<viewer>/artifact/{projectId}/{slug}; the console origin is
no longer a fallback. GET publish-public derives the URL from the
resolver instead of the stored row, so pre-upgrade console URLs are
never echoed, and reports link unavailable plus the slug when no Viewer
origin is configured. Remotely stopped rows are not live. Manual-revoke
recovery data carries projectId and a nullable url. od project share
prints the slug in the unavailable state. Test fixtures move from
OD_VELA_WEB_URL to OD_SHARE_VIEWER_URL.
- S0: signed-out description uses the design copy via its own key; the
publish-failure message keeps its original text.
- S5: update notice reads 「文件有新改动,访问者看到的还是上一版。」.
- K2/K5: the failed-sync notice drops the 「分享已发布」 title and uses the
design copy; terminal variants keep their own wording.
- K1: first-publication sync shows 「同步已有评论 · N 条」. The backfill
state carries optional total/synced from the daemon's backfill members
table, driving a determinate bar when progress is known; older daemons
fall back to the previous copy and the indeterminate sweep.
- Refresh the PR screenshot of the Share popup comment-sync state.
- Share panel: remove every yellow warning; show the public link row above
the copy button in published states; oversized shares stay blocked and
explain why in the red error row.
- Global toast for update success/failure and residual stop failure, with
final design icons and copy; share panel buttons match the design.
- Comment sync: K1 turns the primary action into the sync progress bar, K4
shows a busy "正在同步评论…" button, K5 retry is red.
- Deployment menu layers above the share popover; export-complete guide
rebuilt to the final design.
- Share bridge pin label accepts exactly one letter so a CJK author's
initial can label their pin.
- Update ui-audit capture specs for the intended copy/structure changes.
* feat(billing): support Coding Plan usage and wallet fallback
* fix(web): keep AMR send off billing preflight
Workspace send no longer waits on advisory vela billing preflight; recovery still requests it. Realign zero-wallet P0 oracles and the credits-card wallet label.
Generated-By: looper 0.15.0 (runner=fixer, agent=omp)
* fix(billing): serialize recovery preflight and bound hung vela
Skip overlapping AmrBalanceDialog recovery ticks and stop the watch after
ten minutes even if a preflight is still pending. Give vela billing
preflight a 60s runVelaCommand timeout so a hung CLI cannot pin recovery.
Generated-By: looper 0.15.0 (runner=fixer, agent=omp)
* fix(web): restore coding plan text contrast in billing card
* feat(web): render Coding Plan windows and Go tier in the credits panel
- CodingPlanUsage renders one row per preflight window (name, used %,
remaining USD, reset countdown + absolute time) with loading/unavailable
states; refreshes once on mount and once at resetsAt (no 30s polling,
setTimeout delay clamped to the 32-bit limit).
- Pure model in coding-plan-usage-model.ts; creditsPerUsd comes from
`vela billing summary` through WorkspaceBillingSummary and falls back to
10,000 only when the backend omits it.
- PlanWordmark/EntryNavRail accept the `go` tier (placeholder wordmark,
design asset still pending).
- i18n: 7 new billing keys + entry.billingTierGo across all 19 locales;
real translations for the #8339 keys; drop unused codingPlanNone /
codingPlanRemaining.
- CLI wording: unstarted window reads "not started yet".
* build(pack): pin vela-cli 0.1.4-test.0 and gate on billing preflight
The packaged client needs `vela billing preflight` for the Coding Plan
window rows. Bump the bundled CLI to the npm `test` prerelease that ships
it and add a third capability gate in tools-pack: a CLI without the
subcommand prints the parent `billing` help and exits 0, so the gate
checks the help markers (preflight, --workspace-id, --model, --format)
instead of the exit code.
TEMPORARY: replace 0.1.4-test.0 with the stable 0.1.4 once it is
released; do not merge with a `test` prerelease pinned.
* fix(web): make Coding Plan rows legible on the inverted credits card
The credits card is a hard-coded #202020/#fafafa inverted surface, but
CodingPlanUsage.module.css read page-level --text-* / --bg-fill-* tokens,
so on the card the window names rendered #202020 on #202020 (1.00:1) and
the stat/reset lines sat below WCAG AA. Derive every colour from
currentColor instead (name 100%, stat 72%, reset/note 60%, separator ~50%,
track 36%, exhausted = --red mixed toward currentColor); measured in Chrome:
name 15.6:1, stat 8.7:1, reset 6.4:1, track 3.2:1, exhausted 6.5:1.
Keep the stat on one line (nowrap) and let the name ellipsize instead of
wrapping "60% / used" onto two lines; drop the block's 12px side padding so
it aligns with the card's own rows.
Also add a minutes tier to the reset countdown: the last hour before a
window resets used to show no countdown at all. New key
billing.codingPlanResetsInMinutes in all 19 locales.
* feat(web): rebuild the plan panel 1:1 from design PR #8364
Replace the improvised Coding Plan block with the design's panel, measured
against docs/ui-previews/plan-panels/index.html in Chrome (computed styles
and a 4x pixel diff of the Plus specimen):
- Header: tier name + 16px wordmark, 升级 pill (管理 on the top tier).
- One row 「7天额度免费用 · 已用 N% ›」 (7-day window only; rounded percent;
100% when spent, no red state) over a 5px #b1f38b track, then the
separator and the 「钱包余额 · US$x.xx ›」 row. No headings, window names,
remaining USD, reset time, note or unavailable line.
- Team workspaces keep the pre-existing card unchanged (all team_* tiers);
the quota row renders only for personal workspaces.
- Free personal workspace: no quota row, but the header sells 升级 like the
design (a personal workspace needs no billing permission; an account B
reports without a plan upgrades as free).
- Top-right pill shows the wordmark only, no balance.
- Wallet always reads US$ regardless of locale (product ruling 2026-09-23).
- zh-CN tier names follow the design: 免费版 / 标准版 / 专业版 / 旗舰版.
- Drop the dead billing.codingPlan* keys and model helpers; add
billing.codingPlanWeeklyAllowance and entry.creditsManage in 19 locales.
* feat(web): show 管理 on personal Max per design PR #8364
The design's Max card sells 管理 (console auto-recharge settings) where
every other tier sells 升级; product ruled on 2026-09-23 to follow the
design for personal Max too, superseding the earlier "personal tiers are
always upgradeable" ruling. The gate now asks isMaxPlanTier and 管理 wins
over 升级 when both would show.
* feat(web): route the plan card's three entries per product ruling
2026-09-23 ruling on the card's landings: 升级 opens the console's pricing
dialog (billing=plan, unchanged), the allowance row opens the console
dashboard (unchanged), the wallet row asks for the manual top-up dialog
(new billing=recharge intent; B does not honor it yet and degrades to the
dashboard), and 管理 on Max opens the plain dashboard instead of the
auto-recharge dialog.
* fix(web): align personal plan cards with v2 design and scoped loading
* fix(web): center plan wordmarks inside the top-right pill
* fix(web): reuse shared billing cache for plan hover cards
* test(web): match personal billing preflight in avatar fixture
* fix(billing): require usable quota evidence for funding recovery
* test(billing): cover scoped preflight and quota event refresh end to end
* feat(daemon): relay scoped coding plan usage events and health
* fix(billing): refresh quota caches from scoped realtime events
* test(daemon): accept capability query on mock event stream
---------
Co-authored-by: lefarcen <935902669@qq.com>
* fix(packaged): let a macOS headless runtime become the desktop in place
When Codex starts Open Design headlessly through MCP, macOS treats that
windowless process as the running app. Opening the app from the Dock,
Finder, Launchpad or `open -a` then only reactivates it, so no launcher
runs and no window ever appears (OPEND-3426).
On macOS the headless runtime now runs the desktop path with its window
deferred, and restores the window in the same process when the user
opens the app: through `activate`/`open-url` paired with the app becoming
active, or through SHOW from a newer launcher that sees a `restorable`
owner. The daemon, its port and connected MCP clients stay. A new outer
hands headless launches to the active payload and marks the launch as
managed; payloads started by older outers keep today's behavior.
Managed MCP registrations carry absolute sidecar endpoints for every mode
of the namespace, so the MCP process finds the daemon whichever mode owns
it, waits for a running owner instead of reopening it, and cold-starts
only when nothing runs. The daemon refreshes an existing Codex
registration on start and never installs one. A write interrupted by a
service restart now says it may or may not have been applied.
* fix(daemon): scope Codex refresh to its managed install
Require the existing registration's managed discovery marker to match before refreshing it, so local, stable, and prerelease installs cannot take over the global name from one another. Cover the unrelated-owner path without invoking a config mutation.\n\nGenerated-By: looper 0.11.2 (runner=fixer, agent=codex)
* fix(daemon): prove Codex registration ownership by data root and app
Tighten the ownership check from d2d47a5f8e. Matching the discovery
endpoints alone still let a copy of the app that reuses the installed
namespace take over the registration (the endpoints depend only on
channel, namespace and source), and it could never refresh a
registration written before the managed contract, which has no
discovery value and still names a payload version that cleanup removes.
Read the existing registration and rewrite it only when it serves the
same daemon data root and bootstraps the same installed app; the managed
marker is ignored so a pre-managed registration of this install still
counts. Anything else, including a registration that cannot be read, is
left untouched.
---------
Co-authored-by: Looper <looper@noreply.github.com>
Brings in #8402 (publish/deploy failure classification). Conflicts were
resolved so the share-based publish flow keeps its behavior and gains the
additive telemetry:
- collab-sync.ts: publish/unpublish keep publicFileMutationHandler and the
share publish/stop pipeline; they gain startedAt/requestId, stage tracking
(push -> snapshot [share publish] -> persist), classified `failure` on the
502 responses and the structured failure log line. The compensated
persistence failure also carries { stage: 'persist', reason: 'internal' }.
The unused readVelaControlApiContext import stays removed.
- FileViewer.tsx: publish progress timer and per-attempt request id both kept.
- Tests: the upstream failure-detail tests are ported to the share flow
(store stubs gain getRevision/deleteIfRevisionMatches; unpublish failure is
driven through `share stop`; the empty `resource snapshot` case has no
equivalent on this flow and is dropped). The deploy failure test reaches the
provider through Share -> More sharing options, as the share panel requires.