mirror of
https://github.com/nexu-io/open-design.git
synced 2026-10-27 09:51:12 +01:00
85d2e4893c138dc3bb6ea5941b2ec13f4a37658e
386
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
85d2e4893c |
fix(amr): recover expired cloud sessions (#6786)
* fix(amr): recover expired cloud sessions * fix(diagnostics): redact dynamic API routes * fix(daemon): honor settings in AMR diagnostics * fix(daemon): align workspace auth revisions * fix(web): gate expired cloud sessions on sign-in * fix(web): scope cloud sign-in gate to cloud execution * test(web): align cloud auth fixture * fix(web): recover transient run authority failures * test(daemon): expect retryable authority detail * test(e2e): align BYOK auth boundary * test(e2e): align expired cloud recovery flows |
||
|
|
e78bb22613 |
fix(daemon): inline shared pipeline atom bodies once across active-stage blocks (#6245)
The system-prompt composer rendered each pipeline stage's atoms independently, so an atom declared by multiple stages (od-default declares discovery-question-form in both task-type and discovery) had its full SKILL.md body inlined once per stage — duplicating ~70 lines in every default free-form Home run's system prompt. Add renderActiveStageBlocks to @open-design/contracts: it renders all stage blocks while inlining each atom body exactly once; a later stage that re-declares an atom keeps its subsection header but carries a one-line back-reference to the stage that inlined the body. Stage headers stay per spec §23.4. The server's activeStageBlocks build now goes through this builder, so any plugin sharing atoms across stages is handled at composition time. Fixes #6238 Co-authored-by: John Doe <johndoe@example.com> |
||
|
|
abbc7cbe3b |
feat(analytics): report the Share tab publish flow (publish_file / artifact_publish_result / copy_publish_link) (#6651)
* feat(analytics): report the Share tab publish flow
The 0.18.0 unified Share panel made 'Publish this file for everyone' the
primary sharing path, but the whole chain was untracked: no click event,
no outcome event, no copy-link event. This wires the three points:
- ui_click element 'publish_file' when the publish button is clicked
- artifact_publish_result (new event, mirroring the artifact_deploy_result
split) when a publish/unpublish attempt settles, with action/result/
error_code/publish_duration_ms
- ui_click element 'copy_publish_link' on the post-publish copy button
Both viewer copies (ReactComponentViewer, HtmlViewer) report the same
shape; ReactComponentViewer has no projectKind prop so it reports
project_kind null. Failure codes are stable analytics values
(workspace_identity_required | publish_failed), not i18n keys.
* fix(analytics): gate HtmlViewer publish tracking on workspaceActive and close the error_code type
- Wrap the new publish/copy-link/result emissions in HtmlViewer behind
fire*-style helpers that early-return on !workspaceActive, matching every
neighboring emission site; the publish/unpublish network calls stay
unconditional. ReactComponentViewer has no workspaceActive prop and is
unchanged.
- Declare TrackingPublishErrorCode as a closed two-value union in
contracts shared-enums, use it for ArtifactPublishResultProps.error_code,
and import it from publish-error-code.ts so the helper and contract
cannot drift.
- Extend the publish-tracking suite with unpublish success/failed cases and
a ReactComponentViewer case asserting project_kind: null.
Generated-By: looper 0.11.8 (runner=fixer, agent=claude-code)
* fix(analytics): report the real project kind from ReactComponentViewer publish events
ReactComponentViewer's publishTrackingIdentity() hard-coded
project_kind: null, so every publish_file, copy_publish_link, and
artifact_publish_result emitted for a React artifact lost project-kind
attribution — even though FileViewer requires Props.projectKind and had
the value in scope at the render site.
Thread projectKind into ReactComponentViewer and return it from
publishTrackingIdentity(), matching the HtmlViewer copy so both viewers
really do report the same shape.
The React-path test now asserts project_kind 'prototype' on both the
publish click and the publish result, and additionally covers the
copy_publish_link click that previously had no React-path assertion.
Generated-By: looper 0.11.8 (runner=fixer, agent=claude-code)
* fix(analytics): read the live workspaceActive ref when a publish settles
firePublishResult closed over the workspaceActive prop captured by the
render that created the click handler. A publish/unpublish request can
start while the HtmlViewer is active and settle after the user switches
tabs; the in-flight continuation still saw the render-time `true`, so a
retained (inert) viewer emitted artifact_publish_result anyway — exactly
what the gate added in
|
||
|
|
15c48e7001 |
fix(daemon): make run telemetry attempt-aware (#6598)
* fix(daemon): make run telemetry attempt-aware * fix(daemon): preserve terminal causes across restart Generated-By: looper 0.11.8 (runner=fixer, agent=codex) |
||
|
|
0460157e1e |
feat(analytics): observe conversation fork outcomes (#6707)
* feat(analytics): observe conversation fork outcomes * docs(daemon): note native session fork follow-up |
||
|
|
cf2cc74818 |
feat(media): route Open Design Cloud generation through Vela (#6500)
* feat(media): route Open Design Cloud generation through Vela Add Vela image and video adapters behind od media generate with trusted workspace attribution, multi-image support, video polling, and fail-closed behavior. Expose AMR-specific media defaults and pin the packaged Vela CLI used by the integration. * fix(nix): refresh pnpm dependency hashes Refresh the daemon and web fixed-output hashes after the bundled Vela CLI lockfile update. The values come from the failed Nix CI derivations. * chore(pack): bundle Vela CLI 0.0.31-test.0 0.0.29-test.0 is the build QA hit the 413 with: an agent that reads a generated image turns it into base64 for the next model request, and a 1.7 MB PNG became 2.13 MiB of attachment that the ingress in front of Link rejected. 0.0.31-test.0 configures OpenCode to downscale read images to 512px and cap them at 1 MiB of base64. Verified against this build: the same 1,678,735-byte PNG now reaches the model as a 512x288 attachment, 326,762 bytes of base64 -- 6.85x smaller -- and the model still describes the image correctly from it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VDg4zffeaNboRdhAh17evB * chore(pack): bundle Vela CLI 0.0.31-test.1 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VDg4zffeaNboRdhAh17evB * feat(media): request published aspect ratios from Vela The Vela image adapter refused every aspect but 1:1 and then sent no size at all, so the one shape it did accept was still whatever the provider defaulted to -- the guard proved nothing about the output. Vela now publishes (aspect_ratio, resolution) profiles per model and per request kind, and all five image models carry 1:1, 16:9, 9:16, 4:3, and 3:4. Resolve the pair from `vela media models --json` and pass --aspect-ratio and --resolution, which the CLI requires together. When one aspect ratio publishes several resolutions, prefer the model's default tier: asking for a shape should not quietly change quality or price. When the requested ratio is not published, fail with the ratios that are, before spawning a render. The lookup runs per request rather than from a cache. Vela owns which shapes a model can deliver, so a catalogue that gains or loses one has to take effect immediately, and one CLI call is nothing beside the generation behind it. The prompt contract already advertised these five ratios, so this closes the gap where the prompt promised what the adapter rejected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VDg4zffeaNboRdhAh17evB * fix(media): harden multimodal generation and delivery (#6607) * fix(media): harden multimodal generation and delivery Use daemon-authored artifact paths for created and modified outputs. Preserve media references through CLI staging and make Cloud model routing deterministic. Recover one transient post-tool continuation, surface useful generation progress, and pin the verified Vela CLI package. * fix(web): make produced rows keyboard accessible Expose the row-level open action to keyboard and assistive technology users while preserving the nested Open and Download controls. Cover Enter and Space activation in the component regression test. * build(nix): refresh pnpm dependency hashes Update the daemon and web fixed-output hashes after the bundled Vela CLI lockfile change. --------- Co-authored-by: Cheems <94773058+itscheems@users.noreply.github.com> * fix(media): keep image errors user-friendly and diagnosable * feat(media): forward quality and resolution to Vela images `od media generate` had no way to name an image quality tier or output resolution, so neither reached the Vela CLI. A user asking for "high quality, 1K" got whatever the model's default profile produced, with the request surviving only as prose inside the prompt. Thread both through the existing layers -- CLI flag whitelist, the generate route, generateMedia, MediaContext -- and append them to the `vela image gen|edit` argv. Unspecified stays unspecified. Tiers are priced more than an order of magnitude apart, so substituting a tier for a caller who named none would silently re-price every unqualified request; omitting `--quality` is what leaves the model's own default in charge. Resolution keeps its existing default-profile selection, because Vela's CLI refuses a resolution without an aspect ratio and an aspect ratio is always sent. Both values are validated against `vela media models` before spawning: quality is published per model (only gpt-image-2 is tiered today) and resolution must be published for the requested aspect. Failing here costs nothing, versus a round trip that ends in a provider rejection. Bump the bundled Vela CLI to 0.0.32, the first release whose `image gen`/`image edit` publish `--quality`. * feat(media): teach the agent to map a named size or tier onto the flags The forwarding change added `--quality` / `--resolution` and told the agent when NOT to send them, but never said what counts as the user asking. A request for "2k" came back as `16:9 2K · model default quality`: the size survived only as prose inside the prompt, where the provider never sees it. Name the mapping in both prompt copies, in one sentence each. The golden system-prompt matrix tracks total prompt length, so its two character counts move with the added text. * fix(media): match published Vela resolutions and tiers case-insensitively A real run asked for `--resolution 2k`. Vela publishes `2K`, the lookup compared the two exactly, and the request failed before reaching the provider; the agent read the supported value out of the error and retried ten seconds later with the shifted letter. Fold case on both sides when matching, and put the catalogue's own spelling on the wire rather than the caller's. No published value differs from another by case alone, so nothing becomes ambiguous, and a request that names a shape or tier the model genuinely lacks still fails the same way. --------- Co-authored-by: Cheems <94773058+itscheems@users.noreply.github.com> Co-authored-by: a1chzt <chizblank@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: open-design-crew[bot] <299007234+open-design-crew[bot]@users.noreply.github.com> |
||
|
|
1ca8620e9f |
feat(web): report preview iframe failures to PostHog (#6671)
* feat(web): report preview iframe failures * fix(web): preserve preview error stacks * fix(preview): scope and normalize observability bridge * fix(preview): ignore retained iframe diagnostics * fix(preview): consume early diagnostics once |
||
|
|
16a83e19d3 |
fix(web): improve Workspace failure diagnostics (#6666)
* fix(web): improve workspace failure diagnostics * fix(web): address workspace diagnostics review * fix(web): bound workspace analytics error codes |
||
|
|
2fb33fb282 |
fix(web): make project conversation forks reliable (#6673)
* fix(web): make conversation forks reliable * fix: preserve fallback fork boundary |
||
|
|
d1f5e1f2fb |
chore(release): bump main to 0.18.2 ahead of stable 0.18.1 (#6588)
Co-authored-by: open-design-release-bot[bot] <open-design-release-bot[bot]@users.noreply.github.com> |
||
|
|
8b3ec59cfe |
feat(campaign): DeepSeek V4 Flash free-week surfaces (landing + web + attribution) (#6507)
* feat(campaign): port DeepSeek V4 Flash free-week surfaces from #6450 1:1 port of the demo net diff (base feat/workspace-team) onto main. Landing home banner, landing pricing benefits, cloud-team-demo review page, in-app home modal, workbench badge, model-switcher benefit badge, and the campaign attribution/analytics pipeline. No behavior changes in this commit; agreed behavior fixes land separately. * fix(campaign): show the DeepSeek V4 Flash modal only on the active home view The dialog portals to document.body while EntryShell hides inactive entry views with display:none, so the campaign escaped the home view and interrupted projects/tasks/plugins routes. Thread EntryShell's existing isActive signal through HomeView into a new `active` prop: when inactive the modal neither opens nor renders (and closes without being marked seen, so returning to home while still unseen re-opens it). Requirement: 弹窗只在 #/home 展示,不在编辑器或其他工作流中打断用户。 * fix(campaign): fail closed when frequency-control storage is unreadable hasSeenCampaign() answered "unseen" when localStorage threw (private mode / storage disabled), so the modal re-opened on every Home mount even though markCampaignSeen() could never persist the dismissal. The campaign promise is one appearance per activity window — an unreadable store now counts as seen. * feat(campaign): make the paid 立即使用 CTA switch to DeepSeek V4 Flash for real 产品拍板 D5 + Demo 表格「点击立即使用模型切换为DSV4」: the paid modal CTA previously only clicked the composer chip open and highlighted it. Now it performs the actual switch — agent to Cloud (amr), model to deepseek-v4-flash — through EntryShell's onAgentChange/onAgentModelChange persistence pair (the same sink InlineModelSwitcher writes through), threaded HomeView → DeepSeekV4FlashCampaign as onUseCampaignModel. The chip keeps the data-campaign-highlight pulse as feedback but no longer opens the picker; the use_now analytics element is unchanged. * fix(campaign): carry metricsConsent + device id on the unpaid modal upgrade The unpaid modal's recordAmrEntry was the only campaign touchpoint that dropped metricsConsent — the workbench badge and the model-switcher upgrade already forward it — so the consent-gated AMR analytics mirror never fired and the plans URL missed od_device_id. Thread config.telemetry.metrics and config.installationId from EntryShell through HomeView into the modal, and stamp the URL via amrHandoffDeviceId + attributedAmrUrl(plansUrl, attribution, deviceId). * fix(campaign): make the campaign/campaignAudience/campaignUsage review params production-inert 产品拍板 D7 + 需求文档「该入口仅用于本地 Demo,不作为线上产品规则」: the review URL fixtures forced campaign surfaces for real users on released builds. Web: new isCampaignReviewAllowed() gate (NODE_ENV !== 'production', inlined at build time) now fronts isDeepSeekV4FlashCampaignReview, the campaignAudience override, the modal's shouldForceCampaignReview, and the switcher's campaignUsage read. Landing (Astro): inline scripts cannot see build-time constants, so the home banner, pricing page, and cloud-team-demo inject the verdict as data-campaign-review-allowed (__OD_LANDING_NOINDEX__: staging/PR previews true, production false) and preview activation now requires it. The [locale] wrappers re-render the same components, so they inherit the gate. * fix(landing): stamp campaign attribution only inside the activity window Pricing subscribe CTAs and the cloud-team-demo upgrade/pricing clicks minted __odRecordCampaignEntry with campaignId and stamped campaign_id on analytics props unconditionally, so clicks outside the fixed Aug 6-13 window were counted toward the campaign. Both surfaces now pass the campaign id and the campaign_id prop only while campaignActive is true; od_entry_* attribution itself is still recorded outside the window, just without the campaign stamp. Inbound first-touch od_campaign_id preservation in posthog-analytics.ts is untouched. * test(campaign): use undefined-safe access for window.open mock calls Strict TS (tsc -b) flags open.mock.calls[0][0] as possibly undefined in the modal spec added for the unpaid-upgrade consent behavior; go through String(...[0]?.[0]) instead. No behavioral change. * chore(campaign): drop demo-only artifacts before shipping Remove the cloud-team-demo static review page (fake team cards and prices, noindex but publicly reachable — review-only material that must not ship), its locale wrapper and test, and five unreferenced campaign poster PNGs left over from demo iterations. The team-modal campaign surfaces the page previewed live in the real Cloud plan-selection component (powerformer/vela#1379). * fix(campaign): make review URLs a pure UI projection with zero config writes Product boundary ruling: the client-side campaign change is a badge next to DeepSeek V4 Flash (auto-hides after the window) plus the modal CTA reusing the existing model-selection callbacks — selection behavior must not change. The demo's review fixtures violated that: an effect force- switched the persisted agent to AMR under ?campaignAudience=, and the model write-back effect persisted the review projection into the user's config. Both writes are removed; review URLs now project AMR + DeepSeek purely in the UI and leave persisted state untouched. This also roots out the CI heap OOM in InlineModelSwitcher.compact-model-click.test.tsx (run 31076791463): the stateful test wrapper re-rendered on every persisted write, looping the unconditional write-back forever. With review write-back gone the file completes in ~10s. The review-URL test now asserts the projection and that onAgentChange/onAgentModelChange are never called. * refactor(campaign): remove DeepSeek V4 Flash URL review backdoors Product decision: the ?campaign= / ?campaignAudience= / ?campaignUsage= review parameter mechanisms are deleted entirely. Campaign visibility is now decided only by the real activity window plus the real subscription audience, and pre-launch acceptance switches to a temporary startAt constant override instead of URL fixtures. web: - campaigns/deepseek-v4-flash.ts: drop review param constants, review gate, review detection, and the audience URL override; visibility and audience resolution take only `now` (plus plan/loggedIn); restricted presentation kept as a reserved branch for the backend usage-limit signal (no trigger wired yet) - DeepSeekV4FlashCampaign.tsx: drop the forced review open and the synthetic openedAt+7d countdown; the countdown always runs against the real endAtExclusive boundary - InlineModelSwitcher.tsx: drop campaignUsage URL read, audience override, review agent/model fixtures and the currentAgent/model review projection (incl. data-campaign-review); 已暂停 and 升级可用 badge branches stay as reserved presentation flags with no trigger - EntryShell.tsx / use-deepseek-v4-flash-campaign.ts: no more location.search plumbing; home-hero.css review-width rule removed landing-page: - index.astro / pricing/index.astro: preview branch removed (review params, review-allowed attribute, synthetic preview countdown); campaignActive follows the fixed window only - _lib/deepseek-v4-flash-campaign.ts: reviewParam field removed tests: review-only specs deleted; convertible specs rewritten as pure time-window assertions (clock pinned inside/outside the real window); new negative specs pin that no campaign surface reads URL parameters. * fix(campaign): device id on badge handoff + impressions on window-open transition Two review findings from PerishCode, both verified real: - EntryShell workbench-badge handoff called attributedAmrUrl without the device id, so opted-in clicks omitted od_device_id (confirmed in live browser acceptance: the modal URL carried it, the badge URL did not). Now derives it via amrHandoffDeviceId like the other two touchpoints; the source-contract assertion pins the three-arg call. - The pricing page emitted campaign impressions only during initial script execution, so a tab opened before startAt showed the surfaces at launch without any surface_view. Impressions now share the reveal loop's cadence with a one-time flag, covering both load-time and mid-session window-open transitions. * temp!: open the campaign window early for pre-launch acceptance — REVERT BEFORE MERGE startAt 2026-08-06T20:00 → 00:00 (+08:00) in both front-end constants so reviewers can see the real campaign state (true countdown, no review backdoors) on local runs and the PR preview today. endAtExclusive is untouched. This commit MUST be reverted before this PR enters the merge queue — merging it would launch the landing surfaces ahead of 20:00. * test(campaign): derive the start-instant countdown from the window constants Pins the assertion to endAtExclusive - startAt instead of a literal '7天 00:00:00', so the temporary pre-launch start-time override (and any future window change) cannot silently break the suite. * Revert "temp!: open the campaign window early for pre-launch acceptance — REVERT BEFORE MERGE" This reverts commit |
||
|
|
886bcc4db0 |
feat(web): streamline onboarding model source flow (#6475)
* feat(web): streamline onboarding model source flow * test(e2e): align onboarding coverage with cloud-first entry * test(e2e): isolate cloud status in non-auth specs * test(e2e): keep restoration focused on tab state * test(e2e): close cloud-first onboarding gaps * test(e2e): align runtime checks with cloud-first gate * ci(e2e): retire automations from P0 gate --------- Co-authored-by: Amy <1184569493@qq.com> |
||
|
|
99fc8a45bc |
Revert "feat(design-systems): add structured runtime contract (#6456)" (#6520)
This reverts commit
|
||
|
|
2b8aa8c457 |
feat(design-systems): add structured runtime contract (#6456)
* feat(design-systems): add structured runtime contract * chore: retrigger CI for PR 6456 --------- Co-authored-by: xiaoche-hub <298951296+xiaoche-hub@users.noreply.github.com> Co-authored-by: mrcfps <mrc@powerformer.com> |
||
|
|
d771c1ca5f |
feat(daemon): export execution diagnostics (#6433)
* feat(daemon): export execution diagnostics * fix(daemon): preserve observed execution diagnostics --------- Co-authored-by: bone3deep1962-collab <bone3deep1962@gmail.com> |
||
|
|
e6aeb38da6 |
feat(analytics): track recoverable task outcomes (#6411)
Co-authored-by: bone3deep1962-collab <bone3deep1962@gmail.com> |
||
|
+13 |
356c8c364f |
feat(workspace-team): team workspaces, shared resources, workspace-scoped billing, and the #5517 redesign (#6142)
* fix(web): scope plugin URL imports to workspace * test(web): cover billing interest remount lifecycle * feat(packaged): enable the workspace-team transport for test-profile builds The vela test backend now serves the workspace-team API, so a packaged build baked with the test AMR profile should drive team projects / collab / resource sharing there instead of leaving them dormant. Replace the single feature-test equality check with a profile -> vela web origin map so adding a backend is one entry, and keep every unlisted profile (prod above all) off. * test(daemon): cover billing catch-up after SSE reconnect * fix(collab): surface and start first materialization when opening a shared project QA P0: a brand-new member on a fresh install joins someone's workspace, opens a project from it, and sees no loading state and no files — content only appears on a SECOND open, much later. Two defects, both on the first `/collab/status` request that opening a shared project makes. 1. No pull is started. The daemon's self-materialization block was gated on `callerIsOwner`, so a non-owner member got the placeholder record registered and nothing else. The web's auto-pull is gated on `publishedVersion` advancing past its cursor, and a fresh daemon's first status response cannot carry a published head: `collab.publishedVersion()` reads an in-process map that has never been written, and the real hub head is fetched fire-and-forget into `headEnrichmentCache` for a LATER poll to consume. Materialization therefore arrived only whenever a proactive lane (hub push / reconnect catch-up / the 30s recovery floor) next fired — the "second open" the report describes. 2. No download state is shown. `useProjectCollab.downloadPending` — which picks DesignFilesPanel's "Syncing files from the team…" over its empty state and create-a-file CTAs — reads only `publishedVersion > cursor`, `contentTransferState`, and an in-flight pull. All three are blank on that first response, so the member was shown an empty project inviting them to start creating over content that was still on its way. The fix makes the placeholder stamp the load-bearing signal on both sides: - `materializePlaceholderOnOpen` (routes/collab-sync.ts) replaces the owner-only block: any viewer opening a shared project whose only local record is an unmaterialized placeholder starts its pull on that same request, through the same coalesced flow. The retracted-share heal in its catch stays owner-only — a member who hits the hub tombstone has merely lost access and must not unshare anyone's project. - `/collab/status` reports `awaitingFirstMaterialization`, a purely local, synchronous fact that needs no hub round-trip and is therefore available on the very first response. `od collab status` prints it too. - `localFilesAreNotTheContentYet` (useProjectCollab.ts) makes it always download-pending, bypassing the member-only `shouldAutoPull` gate: whether the local files are the content is a fact about the record, not about who may pull it, so the owner of an unmaterialized placeholder (the reinstall case, recvqzaDvUU6B3) stops seeing the same empty state too. Red evidence: all six new specs fail on origin/feat/workspace-team @ |
||
|
|
4d0376e437 |
fix(byok): restore local runtime configuration (#6356)
* fix(byok): restore local runtime configuration Return BYOK settings to the browser-local configuration path and pass credentials only to the active OpenCode child run. Remove the unpublished secure-profile migration, credential backends, API, CLI, contracts, and MCP exposure while retaining raw-secret rejection on external MCP calls. Validated with focused web and daemon suites, full web tests, workspace typecheck, guard, and diff checks. * test(e2e): align BYOK settings checks with local storage Update the settings UI contract after rolling BYOK credentials back to local app config storage. Assert the entered key is persisted, keep incomplete BYOK drafts from activating, and seed the Local CLI isolation case with a usable BYOK key. Validated with all seven P0 cases in settings-api-protocol.test.ts and the e2e TypeScript check. * fix(daemon): validate plugin request ids explicitly Use a field-specific canonical UUID/ULID validator for attributed request IDs and document that format in the MCP schema and server instructions. Invalid calls now identify requestId instead of incorrectly blaming pluginWorkflowId, while Codex can generate a valid ID on its first attempt. Validated with a red/green MCP observability regression test, daemon typecheck, repository guard, and a real Local Codex plugin smoke that completed in one start_run attempt. * test(pack): follow active PTY consumer in prebundle coverage Point the macOS prebundle boundary test at the Terminal runtime after the retired BYOK credential service was removed. This keeps native node-pty externalization covered without restoring legacy credential code. Validated with the focused mac-prebundle suite, the complete tools-pack suite, tools-pack typechecks, repository guard, and deleted-file reference scans. --------- Co-authored-by: Cheems <94773058+itscheems@users.noreply.github.com> |
||
|
|
ebcba704ef |
feat(prompts): introduce on-demand discovery in SP v2.0 (#6223)
* feat(prompts): introduce on-demand discovery in SP v2.0 * fix(prompts): prevent nested deck label overlap * fix(plugins): stabilize od-default task routing * fix: address prompt and deck audit regressions * fix(prompts): restore plan mode precedence * fix(daemon): accept all form answer headers --------- Co-authored-by: bone3deep1962-collab <bone3deep1962@gmail.com> |
||
|
|
9757b25279 |
fix(daemon): auto-mint assistantMessageId when clients omit pin (#6107)
* fix(daemon): auto-mint assistantMessageId when API clients omit it Web always supplies assistantMessageId. Headless/MCP/eval clients that already send conversationId but omit the pin left lastMessageId null and skipped multi-turn native session resume (missing_cursor). Mint the id server-side whenever a conversation is bound and the client did not, and seed the user message the same way the old MCP-only path did. * fix(daemon): validate conversation ownership before omit-pin seed Reorder project-ownership checks before minting assistantMessageId and seeding the user prompt so cross-project omit-pin requests cannot corrupt foreign chats. Make ChatRunCreateRequest.assistantMessageId optional and expose conversationId/assistantMessageId on McpRunCreateRequest with contract tests for the omit-pin shape. Generated-By: looper 0.11.1 (runner=fixer, agent=grok-build) * fix(daemon): reject missing conversation before omit-pin mint Return CONVERSATION_NOT_FOUND when a client supplies a stale or mistyped conversationId so omit-pin does not mint an unpersisted assistantMessageId and plugin snapshot resolve does not FK-crash with a 500. Generated-By: looper 0.11.1 (runner=fixer, agent=grok-build) * fix(daemon): seed latest turn and fallback-bound user prompts Prefer currentPrompt over full message transcripts when seeding omit-pin user turns, and still seed after conversationId fallback when the client already supplied assistantMessageId. Generated-By: looper 0.11.1 (runner=fixer, agent=grok-build) * fix(daemon): preserve attachments on omit-pin seeded user turns Copy request attachments and commentAttachments into the server-seeded user message so omit-pin/headless clients keep chips and annotation context after conversation reload. Generated-By: looper 0.11.1 (runner=fixer, agent=grok-build) * fix(daemon): treat empty currentPrompt as authoritative omit-pin seed Attachments-only ChatRequest turns send currentPrompt as '' while message is the flattened transcript. Prefer any string currentPrompt, including empty, so seeded user rows keep empty content and do not duplicate history. Generated-By: looper 0.11.1 (runner=fixer, agent=grok-build) * fix(daemon): seed turn metadata and bump project activity on omit-pin Persist sessionMode, runContext, and appliedPluginSnapshot on omit-pin seeded user turns so reload/retry keep applied context. Call updateProject after seed so listProjects reorders headless/API activity like PUT /messages. Generated-By: looper 0.11.1 (runner=fixer, agent=grok-build) * fix(daemon): require projectId for bound conversation ownership Reject POST /api/runs when conversationId is present but projectId is missing or non-string, so omit-pin cannot seed messages without owning project context. Cover both early and post-fallback ownership checks. Generated-By: looper 0.11.1 (runner=fixer, agent=grok-build) * fix(daemon): preserve slideIndex and BMP kind on omit-pin seeds Keep deck annotation slideIndex and classify .bmp as image when seeding user messages for clients that omit assistantMessageId. Generated-By: looper 0.11.1 (runner=fixer, agent=grok-build) * fix(daemon): seed empty message when omit-pin has attachments When currentPrompt is unset and message is empty, still seed the user turn if attachment metadata is present so chips/annotations survive reload. Generated-By: looper 0.11.1 (runner=fixer, agent=grok-build) * fix(daemon): seed omit-pin chat content from original request Plugin resolution may rewrite meta.message with a rendered scenario brief for the run; persist requestBody currentPrompt/message for the user turn so the internal brief is not shown as chat content. Generated-By: looper 0.11.1 (runner=fixer, agent=grok-build) |
||
|
|
8518ec847b |
fix(amr): recover late login failures and trace auth stages (#5986)
* fix(amr): recover late login failures and trace auth stages * fix(amr): preserve scoped cancel attempt IDs Generated-By: looper 0.11.1 (runner=fixer, agent=codex) * fix(amr): defer unsupported Vela auth stages Generated-By: looper 0.11.1 (runner=fixer, agent=codex) * fix(amr): narrow fallback telemetry to shipped Vela Generated-By: looper 0.11.1 (runner=fixer, agent=codex) * fix(amr): preserve live login after stale cancel Generated-By: looper 0.11.1 (runner=fixer, agent=codex) * fix(amr): preserve cancel during login startup Retain cancellation intent when a provisional cancel races the delayed canonical login response, then cancel the canonical attempt before polling can begin. Generated-By: looper 0.11.1 (runner=fixer, agent=codex) * fix(amr): rejoin newer login after startup cancel Generated-By: looper 0.11.1 (runner=fixer, agent=codex) * fix(amr): preserve cancel across web login starts Generated-By: looper 0.11.1 (runner=fixer, agent=codex) * fix(amr): retain cancel when status refresh fails Generated-By: looper 0.11.1 (runner=fixer, agent=codex) * fix(amr): cancel onboarding status preflight Treat cancellation before an auth attempt exists as a local preflight cancel so a delayed status response cannot start login.\n\nGenerated-By: looper 0.11.1 (runner=fixer, agent=codex) |
||
|
|
4f3a0b3c06 |
fix(daemon): continue stalled post-tool sessions (#6237)
* fix(daemon): continue stalled post-tool sessions * fix(daemon): separate post-tool continuation budget Generated-By: looper 0.11.1 (runner=fixer, agent=codex) * fix(daemon): preserve retry telemetry budget Generated-By: looper 0.11.1 (runner=fixer, agent=codex) * fix(daemon): align retry failure telemetry Generated-By: looper 0.11.1 (runner=fixer, agent=codex) |
||
|
|
809d45f27c |
feat(integrations): add the local Open Design Cloud flow for Codex (#6055)
* feat(daemon): expose Vela login through CLI and MCP * feat(mcp): add interactive local brief card * feat(packaged): bootstrap local MCP headlessly * feat(daemon): secure local BYOK credential profiles * feat(cli): manage secure BYOK profiles * feat(web): store BYOK keys in secure profiles * fix(runs): deduplicate cloud generation requests * feat(daemon): add end-to-end plugin observability * fix(pack): include native PTY runtime in desktop packages Lazy-load node-pty in the daemon so missing native binaries only disable Terminal and interactive Keychain operations instead of crashing startup. Ship and validate target prebuilds in macOS and Windows packages. Repair the macOS spawn helper before signing, and invalidate stale Windows packaging caches. Cover the packaged PTY path in macOS and Windows smoke tests. Require Vela CLI for every beta desktop build target. * fix(mcp): localize and stabilize plugin briefs Keep collect and confirm on one MCP Apps card, report intrinsic size changes, and remove the fragile widget-state fallback. Localize brief forms, summaries, status, and public errors from the current request or Host locale while preserving stable protocol ids and selections. Keep internal runtime identifiers out of user-facing MCP guidance. * fix(packaged): register live Studio URLs with daemon Register the packaged web sidecar loopback origin over namespace-scoped daemon IPC after dynamic binding. Invalidate install-info by the live web port and remove the second MCP URL cache so run and project responses use the current Studio address. Validate loopback origins and cover registration, rebind, and cache refresh. * fix(mcp): stabilize brief confirmation lifecycle Keep confirmed briefs locked after Host publication failures and retry only the cached follow-up message instead of confirming twice. Replace blank initialization with a compact loading state, accept immediate and delayed tool results, and bump the MCP Apps resource to v3 so Codex does not reuse the stale card. Add an executable JSDOM Host bridge harness covering double-submit, publication retry, delayed results, and repeated draft notifications. Validated with the full daemon suite, workspace typecheck, and guard. * fix(mcp): prevent brief app resize feedback loops Replace the self-observed intrinsic-height loop with deduplicated body measurements so Codex MCP app iframes do not repeatedly resize themselves and fail sandbox startup. Bump the brief resource URI to v4 to avoid cached v3 cards and cover the regression with the focused brief-app spec. Validated with daemon tests/build, workspace guard/typecheck, a verified beta DMG, and a direct packaged MCP resource smoke. * fix(mcp): use the final Open Design plugin identity Make open-design the only accepted external plugin ID across MCP tools, run attribution, artifact version origins, and telemetry. Rename the Brief MCP App resource to v5 and reject the unpublished old ID instead of aliasing it. Validated with 171 daemon tests, 5 web tests, daemon/web typechecks, and guard. * chore(pack): bump Vela CLI to 0.0.27 * chore(nix): refresh pnpm dependency hashes * fix(mcp): honor host and plugin request contracts Respect independently advertised MCP Apps capabilities and prefer the Codex-native follow-up bridge so confirmed briefs render as readable user turns instead of context-only messages. Bump the brief resource to v6 to invalidate stale cards.\n\nMark Vela login and account probes as open-world interactions, and require stable request IDs for attributed generation so lost responses cannot create a second logical run. * fix(cli): support keyless BYOK profiles Add an explicit --no-api-key save mode for local and self-hosted providers while keeping credential-bearing profiles stdin-only. Reject missing or conflicting credential modes and cover both paths in the CLI tests. * fix(pack): replace headless owner when desktop opens Advertise headless packaged runtimes as having no visible window, then shut them down before a normal desktop launch continues instead of treating SHOW as a successful focus. Validated with the focused packaged headless and launcher lifecycle tests (20 passed). * fix(pack): clean up failed headless startup Acquire the headless identity, sidecars, and IPC server through one failure-atomic lifecycle so later bootstrap errors close every previously acquired owner in reverse order. Cover MCP-install and web-identity publication failures; validated with 22 focused tests and the packaged typecheck. * fix(byok): remove raw provider request contract Expose only daemon-owned BYOK profile references from shared run types and the web transport, while retaining the daemon's fail-closed rejection for legacy or untyped raw credential payloads. Validated with 76 web provider tests plus web and contracts typechecks. * fix(daemon): preserve interrupted run idempotency Hydrate queued or running durable requests as DAEMON_RESTARTED failures before idempotency reuse, preserving the original request and workflow mappings instead of creating a second cloud operation. Share the restart transition with boot reconciliation and expose synthetic terminal events to reattaching clients. Validated with 48 focused tests and the daemon typecheck. * fix(byok): roll back failed credential metadata writes Snapshot secure-store values before mutation and compensate create, update, and delete operations when profile metadata cannot be persisted, preventing orphaned or lost credentials. Validated with nine focused credential-service tests and the daemon typecheck. * fix(web): reconcile selected BYOK profile metadata Treat the daemon's selected secure profile as authoritative for protocol, endpoint, model, and API version so CLI profile edits cannot leave the browser showing stale execution settings. Validated with 66 config tests and the web typecheck. * fix(byok): migrate legacy credentials before cleanup Import each supported legacy browser credential into a stable daemon-owned secure profile before removing plaintext copies. Keep the original browser record on secure-store or unsupported-provider failures and surface a Settings recovery path. Cover successful migration, duplicate projections, and injected secure-backend failure while preserving existing Bedrock downgrade behavior in memory. * fix(byok): secure Windows profiles with DPAPI Dispatch native Windows BYOK profiles to a CurrentUser DPAPI backend rooted under the resolved daemon data directory. Secrets enter PowerShell only through stdin, encrypted blobs stay separate from non-secret profile metadata, and API responses remain secret-free. Add platform dispatch coverage, a Windows-only real DPAPI round-trip test, and the packaged Windows smoke path for create, resolve, response-redaction, and delete behavior. * fix(web): preserve config writes during hydration * fix(byok): persist secure credentials across entry flows * test(byok): cover secure onboarding persistence --------- Co-authored-by: Cheems <94773058+itscheems@users.noreply.github.com> Co-authored-by: lefarcen <935902669@qq.com> |
||
|
|
af2a833506 |
fix(daemon): surface AMR OpenCode stall context (#6040)
* fix(daemon): surface AMR OpenCode stall context * fix(daemon): accept runtime-omitted OpenCode diagnostics Generated-By: looper 0.11.0 (runner=fixer, agent=codex) * fix(ci): make static gate runner-independent (#6039) --------- Co-authored-by: PerishFire <39043006+PerishCode@users.noreply.github.com> |
||
|
|
ad5a7d6ba1 |
Revert "feat(web): add guided inspiration and deliverable workflow (#5899)" (#6120)
This reverts commit
|
||
|
|
c3de4d5b95 | fix(daemon): classify model and timeout failures (#6103) | ||
|
|
340cbb9b94 |
feat(web): add guided inspiration and deliverable workflow (#5899)
* feat(cli): add project rename command to CLI Introduced a new command `od project rename <id> --name "<title>"` to allow users to rename existing projects. The command validates input and sends a PATCH request to update the project name in the backend. Updated CLI help documentation to include this new command. * feat(web): enhance InspirationPicker with reference-site shortcuts and selection chips Added functionality to the InspirationPicker component, allowing users to browse reference sites (e.g., Dribbble, Behance) directly from the picker. Implemented a selection chips feature that lists all current picks, enabling easy removal across different families. Updated styles for better visual representation of selected items. Enhanced internationalization support with new translations for the added features. * feat(web): enhance InspirationPicker with detailed previews and selection management Updated the InspirationPicker component to include a detailed preview feature for selected items, allowing users to view full documents directly from the picker. Implemented a "Selected" section that displays current picks with a remove option, improving user interaction. Adjusted styles for better visual consistency and added new translations for enhanced internationalization support. * fix(web): restore uploaded inspiration thumbs and drop preview elapsed Resolve locked inspiration-upload previews via the submitted path map so answered forms still show real images, and keep the floating preview status pill as a stage label only. * feat(web): implement TaskDeliverableCard for displaying task outputs Added a new TaskDeliverableCard component to showcase the primary deliverable and its associated outputs. This includes a preview feature for various file types, an actions menu for sharing and downloading, and improved styling for better user experience. Enhanced internationalization support with new translations for deliverable-related terms. Updated InspirationPicker to utilize the new deliverable ranking and searching functionalities. * fix(inspiration): unify design system previews and source priority * fix(web): align deliverable card regression coverage * test(web): scope question form assertions * fix(web): keep the deliverable card off failed and canceled runs The card's status label is an unconditional Done, so gating it on the shared terminal predicate let a failed or canceled run that wrote files present a partial artifact as delivered while the same message reported the error. Gate on the existing runSucceeded predicate instead; those turns fall back to the plain file ledger, so the files stay reachable without the false completion signal. * fix(daemon): serialize DESIGN.md font stacks through a strict font-family grammar extractFonts is deliberately permissive and its output was interpolated verbatim into the generated <style> raw text, so a Body font value like "Karla</style><img src=…>" could close the style element and inject active markup into every auto-loaded card iframe. sanitizeFontStack now rebuilds each stack from validated family names only (quoted names, unquoted generic/system keywords), dropping anything else and falling back to the trusted default stack; both the full preview and the compact card renderer route every font interpolation through it. Card and preview fixtures with a </style> payload pin the boundary. * fix(daemon): ground additional inspiration systems in the run prompt The picker's extra design-system picks reached the agent as ids on a metadata line only, so a user-authored system contributed none of its colors, fonts, or rules. The daemon now resolves each additional id through the same DESIGN.md reader chain as the primary (workspace file first, then registry), bounds the result (3 systems, 6000 chars each), and composes an 'Additional inspiration systems' section with explicit primary-wins precedence. Prompt tests pin a unique secondary token reaching the composed prompt, both at the composer seam and end-to-end through the chat route with bento's #FAD4C0. * test(e2e): stabilize preview comment click * test(web): update runtime override history expectation --------- Co-authored-by: Amy <1184569493@qq.com> |
||
|
|
b99a9fdc3d |
feat(manual-edit): add direct manipulation and reliable history (#5890)
* feat(web): manual edit v2 direct manipulation (v2.2–v2.4) Selection overlay with action bar and drag/resize handles, floating text toolbar with range-format highlight (queryCommandState round trip), Manus color picker, image replace/crop/paste/drop, element copy/duplicate/delete, and the systematized in-place content pipeline: every element-scoped patch now reconciles the live iframe DOM from the saved source over od-edit-apply-dom (replace/insert-after/append-child/prepend-child/remove) with positional identity restamping, so commits, undo and redo never reload the canvas, never flash, and never move the scroll position. Frozen-source reloads remain only as a scroll-capturing fallback. Includes the Chromium Home/End double-booking fix, the dblclick word-selection guard, and light targets-broadcast dedupe. * test(web): manual edit v2 unit and e2e coverage Bridge (in-place apply ops, positional restamp, selection format state, Home/End consumption, dblclick selection guard), source-patches (insert readback, restore descriptors, sanitization), gestures/shortcuts/color units, and host-level FileViewer suites proving content commits mutate the canvas without a srcDoc reload, hand selection to inserted elements, and record labeled manual versions for undo/redo. Also realigns the manual-edit-history and srcdoc-reload-races helpers with the v2.1 opt-in inspector two-step flow. * docs(specs): manual edit v2 architecture spec Six-layer map (identity/chrome/style/content/history/external-sync), core invariants (DOM equals saved source without reloads; positional identity restamps on structural change; every save is a labeled manual version), patch-kind application matrix, performance contract, and the v2.1–v2.4 revision log including the real-browser verification round. * fix(tools-dev): fail fast when a sidecar process dies during startup wait waitForDaemonRuntime/waitForWebRuntime now accept a liveness probe for the spawned pid, so a crashed daemon/web process surfaces immediately instead of burning the full startup timeout. * fix(web): edit brand-kit pages in place — no reload flash, no scroll jump Brand-kit targets carry runtime-annotated ids with no markup of their own in the saved source (edits persist into the payload / runtime overrides), so the in-place readback came up empty and every commit fell back to a srcDoc reload — the flash-and-jump-to-top the user hit when editing text after an image. New od-edit-apply-dom op 'apply-content' mirrors the patch fields (text/href/src/alt/html/attributes, on*/data-od-* filtered) onto the live element instead, and set-outer-html reuses replace with the patch html. The reload fallback's scroll restore also gains a clamped-only retry ladder (600–4000ms) so async-rendering pages (brand kit renders after load) no longer land at the top when a reload is genuinely needed. * refactor(FileViewer): unify manual edit history management and enhance undo/redo functionality This update introduces a consistent approach to managing manual edit history and undo/redo stacks by utilizing refs to mirror state. The new `updateManualEditHistoryStack` and `updateManualEditUndoneStack` functions ensure that the state remains in sync with the refs, preventing stale data issues during undo/redo operations. Additionally, the handling of in-session undo (Cmd+Z) has been improved to escalate to the host's global history when no local changes remain, ensuring a seamless user experience. Tests have been added to verify the correct behavior of these features. * feat(manual-edit): enhance manual edit functionality with space scaling and improved gesture handling This update introduces a new `ManualEditSpaceScale` interface to manage the scaling between viewport pixels and CSS pixels, ensuring accurate positioning during manual edits. The `manualEditMovePreviewTransform` and `manualEditResizeStyles` functions have been updated to utilize this scaling, improving the precision of drag and resize gestures. Additionally, the `ManualEditSelectionOverlay` component now maintains pointer capture during gestures to prevent interaction issues with nested iframes. Tests have been added to verify the correct behavior of these enhancements, ensuring a smoother user experience in manual editing scenarios. * feat(FileViewer): add localized toasts for image upload process in manual edit This update enhances the manual editing experience by introducing localized toast notifications for the image upload process. New messages for uploading, processing, and successful addition of images have been added to the i18n files. The `insertManualEditImage` function now manages these notifications, providing users with real-time feedback during image uploads. Additionally, tests have been implemented to ensure the correct display of these toasts across different locales. * fix(manual-edit): drag whole image to move + lock selection frame to element box (#5888) Two direct-manipulation fixes reported from real prototype/landing/deck edits: 1. Move by dragging the image body, not only the top pill. Adds a full-interior moveBody surface inside the selection frame that starts the same undoable move gesture; scoped to image targets so text/link bodies keep click-to-edit. Rendered under the resize handles so edges still resize. 2. Keep the selection frame locked to the element during resize. The frame previously drew the gesture-intent x/width and only adopted the iframe's measured y/height, so an element that re-centers, caps at max-width, or reflows on width change left the frame drifting horizontally off the picture. adoptMeasuredExtent now takes the full measured rect and displayRect follows it, so the chrome always wraps the element. Adds ManualEditSelectionOverlay tests for body-drag move and measured-box frame sync; records the change as spec v2.5. Co-authored-by: Claude <noreply@anthropic.com> * test(web): stabilize manual edit browser validation * fix(manual-edit): address structural edit review blockers * fix(manual-edit): preserve runtime formatting and restore order * fix(manual-edit): flush toolbar styles before navigation * fix(manual-edit): preserve runtime target identity * fix(manual-edit): serialize saves and image handoff * fix(manual-edit): clear stale runtime clipboard * fix(manual-edit): scrub rich text identities * fix(manual-edit): save inspector text after formatting * fix(manual-edit): action-bar boundary avoidance, select-without-reflow, image paste shortcut (#5892) Three edit-mode canvas fixes from user feedback: 1. Action bar no longer covers the element frame/handles. A small or edge-hugging element previously had its move pill and resize handles hidden under the floating action bar (clamped to the top), so it could not be moved or resized. New pure helper manualEditActionBarTop places the bar above the frame, flips it below when the element hugs the top edge, and keeps it inside the canvas; horizontal clamping already handles the side edges. Adds a data-placement attribute. 2. Selecting a text element no longer makes it jump/grow. The bridge fused 'select' and 'enter inline edit' into one click, and making a deck text box contenteditable releases its line-clamp/height cap so it visibly reflows larger the instant it is selected. The first click now only selects (no contenteditable, no reflow); editing begins on a second click of the already-selected element or a double-click — matching how images/containers already select. 3. A selected image/container can be pasted with Cmd/Ctrl+V. The native paste event only fires while an editable element holds the caret, which never happens for non-text selections, so the shortcut did nothing for images. The bridge keydown handler now forwards od-edit-paste-request for a selected non-editable element (paired with the existing Cmd/Ctrl+C copy). Updates the 14 inline-edit bridge tests to enter edit via double-click and adds coverage for all three fixes; recorded as spec v2.6. Co-authored-by: Claude <noreply@anthropic.com> * fix(manual-edit): image corner scaling, nowrap unlock on resize, restore image paste Three edit-mode canvas fixes from user feedback: 1. Images get four corner anchors that scale aspect-locked from any corner, anchored at the opposite corner (new resize-nw/ne/sw/se gesture kinds). The dominant pointer axis drives the scale, the floor binds the larger dimension, and corner gestures skip snapping so the ratio never breaks. Corner resizes persist width AND height (space-scale corrected) plus the offsets that keep the anchored corner fixed. 2. Resizing an element with white-space: nowrap (or pre) now unlocks wrapping (normal / pre-wrap) alongside the width — a narrowed heading previously stayed on one line and overflowed its own new box. ManualEditStyles and the bridge style props gain whiteSpace. 3. Image paste works again. The v2.6 Cmd/Ctrl+V keydown branch called preventDefault, which suppresses the native paste event — the only place clipboard image bytes are readable — so pasting an image did nothing. The shortcut now arms a 150ms one-shot element-paste fallback instead; any real paste event disarms it and routes image vs element itself, so the two channels never double-fire. Adds gesture/overlay/bridge coverage for all three; recorded as spec v2.7. * fix(manual-edit): replay runtime history in place * fix(brands): reject scraped CSS junk font families before token emission An extraction can capture CSS source text instead of a real font family (e.g. Tailwind v4's `--theme(--default-font-family` from aliyun.com). Interpolated raw into the kit's `--brand-font-family`, the unbalanced parenthesis swallows every later :root declaration, so the component kit renders unstyled (UA serif, collapsed buttons) while earlier color tokens still work. isRenderableFontFamily() now guards both emission seams: the seed's fontStack (kit/variables/artifacts token block) and brandFontAssets' display-family stack (h1-h3 face). Junk families drop out and the renderable fallbacks + system stack take over. * fix(manual-edit): replay runtime-only style history from the persisted override rule Runtime-only brand-kit targets persist set-style patches in the style[data-od-manual-edit-runtime-overrides] rule, not as element inline styles. The in-place history replay read inline styles only, so redo of a runtime style change replayed empty values while reporting success — the file held the redone style while the canvas stayed on the undone one. readManualEditSavedStyles() now reads a target's persisted styles wherever they live (inline attribute for source-backed nodes, the runtime override rule otherwise), and the set-style history branch replays through it. The same inline-only read also made reconcileManualEditStyleSave() treat every runtime style save as "target vanished" — erroring, dropping the selection, and reloading the canvas — so it now consults hasManualEditRuntimeStyleOverride() before taking that path. Regressions: source-patches unit coverage for the saved-styles read and the override predicate, plus a FileViewer spec that styles a runtime target, undoes and redoes it without any srcdoc change, and asserts the redo preview carries the persisted value (red on the previous head). * fix(manual-edit): merge partial runtime style patches into the persisted rule Successive debounced toolbar autosaves send only the touched property, but setRuntimeStyleOverride() rebuilt the target's override rule solely from the incoming patch, so a runtime-only brand-kit target lost its earlier saved declarations (fontSize save, then color save -> font-size silently dropped). Persistence now merges the incoming patch into the existing rule declarations, treating empty incoming values as deletions and removing the rule once its last declaration is deleted. --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
7787556cf1 |
fix(daemon): full ACP tool transcript and richer usage telemetry (#6057)
* fix(daemon): full ACP tool transcript and richer usage telemetry Map all ACP tool_call frames to canonical tool_use/tool_result for run.events, PostHog run_finished, and Langfuse spans. Preserve artifact_count via Write/Edit normalization, tighten path extraction, forward truncated results, and emit real tool startedAt. Enrich usage scanning (thought_tokens, anthropic vs openai cache semantics), canonical tool-family PostHog props, analytics recovery finish snapshot, and shared content-tool redaction. * fix(daemon): prefer ACP kind over noncanonical tool names Normalize recognized ACP kinds (e.g. kind:read + name:read_file → Read) before emitting tool transcripts so Langfuse content-tool redaction matches canonical families and does not leak file contents. Generated-By: looper 0.11.0 (runner=fixer, agent=grok-build) * fix(daemon): fail-closed redaction for unknown ACP tool payloads Generated-By: looper 0.11.0 (runner=fixer, agent=grok-build) * fix(daemon): flush open ACP tools as errors on session fail When a session dies mid-tool (timeout, exit, RPC error), emit pending tool_use/tool_result pairs with isError so transcripts stay complete. Generated-By: looper 0.11.0 (runner=fixer, agent=grok-build) * fix(daemon): redact ACP Bash stdout in tool transcripts Execute tools can dump private files (e.g. cat .env); replace Bash tool_result content with a length summary before the canonical transcript ships so Langfuse cannot receive raw execute output. Generated-By: looper 0.11.0 (runner=fixer, agent=grok-build) * fix(daemon): redact Linux home paths in Langfuse Bash tool spans Extend local-path masking for ACP Bash partial redaction to cover /home and /root (not only /Users and Windows Users), so Linux home paths do not leak into Langfuse tool inputs when content telemetry is on. Generated-By: looper 0.11.0 (runner=fixer, agent=grok-build) * fix(daemon): redact custom ACP tool names before Langfuse telemetry Sanitize path/token-like kind:other tool names at transcript emit and canonicalize non-allowlisted names for Langfuse span labels, toolName metadata, and redaction placeholders so untrusted custom names cannot leak even when content telemetry is off. Generated-By: looper 0.11.0 (runner=fixer, agent=grok-build) * test(e2e): force-click unstable comment targets in preview iframe UI P0 project-workspace timed out on comment attachment when Playwright kept waiting for hero-title stability under auto-fit zoom / bridge inject. Click once visible with force so the critical flow stays reliable. Generated-By: looper 0.11.0 (runner=fixer, agent=grok-build) * fix(daemon): merge partial usage frames in reverse analytics scan Keep provider_usage for thought/cache-only trailing usage events while continuing the reverse scan to the latest primary input/output/total record so run_finished and Langfuse do not drop complete token counts. Generated-By: looper 0.11.0 (runner=fixer, agent=grok-build) * fix(daemon): flush open ACP tools before AMR no-output fail Clean-flush pending non-think tools on successful session/prompt before evaluating emittedConcreteToolEvent so missing terminal tool_call_update does not mark a productive run as acp_no_visible_output. Generated-By: looper 0.11.0 (runner=fixer, agent=grok-build) * fix(daemon): merge partial primary usage and flush tools on ACP abort Require both input and output before ending the reverse usage scan so output-only or input-only trailing frames still merge earlier counters. Flush deferred open ACP tools as errored on abort so user-canceled runs keep complete tool transcripts for Langfuse/PostHog. Generated-By: looper 0.11.0 (runner=fixer, agent=grok-build) * fix(daemon): hash path-like ACP toolCallIds before telemetry Adapters can embed user paths in toolCallId (e.g. read:/home/alice/.env). Hash those values at tool_use/tool_result emit so Langfuse span ids and metadata.toolCallId cannot leak secrets, while keeping the raw id as the local frame-correlation map key. Generated-By: looper 0.11.0 (runner=fixer, agent=grok-build) * fix(daemon): always hash ACP adapter toolCallIds for telemetry Identifier-shaped secrets (sk-proj-*, ghp_*, JWTs) passed the prior allowlist because they contain no path characters. Hash every non-empty adapter toolCallId before tool_use/tool_result emission so Langfuse span ids and metadata.toolCallId cannot leak tokens. Generated-By: looper 0.11.0 (runner=fixer, agent=grok-build) * fix(daemon): keep reverse usage scan open for missing cache fields When a newer usage frame already has input+output but omits cache counters, continue scanning older frames so cache_read/cache_creation still merge into run_finished and Langfuse. Generated-By: looper 0.11.0 (runner=fixer, agent=grok-build) * fix(daemon): retain flushed ACP tool IDs against late terminals Keep acpToolRunEventState entries after flushOpenAcpTools so a racy tool_call_update cannot recreate the same id and emit a second tool_use/tool_result pair after timeout, abort, or prompt flush. Generated-By: looper 0.11.0 (runner=fixer, agent=grok-build) * fix(daemon): block kind:other Bash-like tool names Custom ACP tools with kind:other must not emit Bash/shell/execute/terminal names, which would unlock Langfuse partial redaction and leak rawInput. Generated-By: looper 0.11.0 (runner=fixer, agent=grok-build) * fix(daemon): fail closed on Bash names without execute kind ACP tools missing kind must not preserve name/title Bash labels that unlock Langfuse partial redaction; only recognized execute-family kinds may emit Bash. Generated-By: looper 0.11.0 (runner=fixer, agent=grok-build) |
||
|
|
ca4ecf0bf2 |
chore(release): bump main to 0.16.1 ahead of stable 0.16.0 (#6000)
Co-authored-by: open-design-release-bot[bot] <open-design-release-bot[bot]@users.noreply.github.com> |
||
|
|
2337932714 |
feat: expose GPT-5.5 Fast service tier (#4287)
* feat: support Codex service tiers * fix: forward service tiers through MCP runs * fix: clear default service tier selections * fix: preserve service tier on model option updates * fix: preserve service tier without explicit model * fix: preserve service tier in connection tests * test: stabilize API empty stream UI check * fix: preserve codex service tier labels * fix: preserve service tier without saved model * fix: address service tier review follow-ups * fix: pin legacy chat assistant rows before start * fix: accept bare model catalog responses |
||
|
|
2e377a5152 |
name every packaged startup failure instead of bucketing it as unknown (#5956)
* name every packaged startup failure instead of bucketing it as unknown
The weekly `packaged_runtime_failed` alert is dominated by failures the event
had enough evidence to name and reported as opaque anyway. Triaging a 7d window
turned up three places where the emitter threw away a cause it was already
holding:
- 62 devices died with the daemon log tail read successfully, but
`parseDaemonLogTail` only ever matched `ERR_*`. A daemon that threw anything
else (SQLite corruption, EPERM, a plain throw) reported error_code=null AND
missing_module=null with its reason printed in the tail we had just read.
- 21 devices hit win32 CreateProcess failures. Node puts the real cause on the
error's `code`/`errno`/`syscall`; the event sent `.message` only, so
`spawn UNKNOWN` was indistinguishable from any other opaque failure.
- 149 devices produced an Error with an empty `.message` and no `.stack`. Every
free-form field went null, leaving residue that could not even be counted
apart from "no error at all".
So: parse the sidecar's own fatal line as a backstop when `ERR_*` misses, carry
the errno triplet off the thrown object, classify a rejected spawn as its own
`spawn-failed` kind rather than `unknown`, and guarantee a thrown error never
serializes to error_message=null — an unnamed leftover is now a named, countable
bucket.
Classification-only; the failures themselves are unchanged. Every test input is
a verbatim field payload from the alert window.
* reduce syscall to its operation token before sending it
Review catch, and a real leak. Node does not guarantee `syscall` holds only the
operation name: spawning a missing binary sets it to the whole invocation.
Verified against real Node —
spawn('/Users/elian/nonexistent/bin/thing')
→ syscall === 'spawn /Users/elian/nonexistent/bin/thing'
Forwarding that verbatim would have put the local username and install path
into an event that is retained even for opted-out users, while every other path
this module sends goes through scrubUserPaths.
Keep the first token — the operation is the whole analytic value, and the path
is already available (scrubbed) via error_message — then scrub what survives
and cap it, as a second line of defence. `code` is capped too.
This also fixes a classification miss the same review implies: the spawn-failed
branch compared the RAW syscall to 'spawn', so a spawn error carrying a path
never matched and fell through to `unknown` — the exact bucket this PR exists
to drain.
|
||
|
|
1226773663 |
feat(daemon): route completed-run telemetry through Vela (#5666)
* feat(daemon): route completed-run telemetry through Vela * fix(daemon): migrate test telemetry relay domain * feat(daemon): send Vela feedback scores with completed-run telemetry Map score-create into the Vela envelope and use the same Vela sink for thumbs feedback, binding scores via the client run id instead of skipping them when account-aware telemetry is selected. * fix(daemon): skip anonymous fallback for Vela feedback auth errors Score-only feedback batches must stay on the account-scoped Vela path. When Vela returns 401/403, fail the delivery instead of posting to the anonymous relay, which has no matching trace for those scores. Generated-By: looper 0.11.0-beta.1 (runner=fixer, agent=grok-build) |
||
|
|
d1372da029 |
fix(daemon): reconcile run terminals after restart (#5817)
* reconcile run terminals after restart * fix(daemon): preserve replayed failure taxonomy Reclassify analytics-incomplete terminal failures from their persisted state and events while keeping the interrupted template exclusive to daemon-restart recovery. Generated-By: looper 0.11.0 (runner=fixer, agent=codex) * fix(daemon): preserve repaired errors and skip completed logs The repair path previously collapsed every failed message to restart copy and hydrated event logs before checking completed telemetry checkpoints. Use durable recovery metadata for status detail and gate log reads on outstanding PostHog or Langfuse work. Generated-By: looper 0.11.0 (runner=fixer, agent=codex) |
||
|
|
6fb644a57d |
feat(analytics): report conversation turn index (#5917)
Co-authored-by: bone3deep1962-collab <bone3deep1962@gmail.com> |
||
|
|
4e8db9a9b7 | add runtime version and retry provenance (#5814) | ||
|
|
ef35a08e24 |
feat(daemon): E-lite root-cause telemetry for inactivity_timeout attribution (#5775)
* feat(daemon): E-lite root-cause telemetry for inactivity_timeout attribution Add four run_finished fields that separate WHY a stalled run died, which the coarse `last_observed_phase` (WHICH phase) cannot: - approval_requested: an ACP approval/permission gate fired. Only the ACP path is daemon-observable (stream/CLI runtimes pass a skip-permissions flag so no gate fires); surfaced via an acp_approval_request diagnostic and folded in by summarizeRunDiagnosticsForAnalytics. - stdin_backpressure: the prompt write to the child's stdin was queued because the OS pipe buffer was full (the child was not draining stdin) — the corroborating signal for a stdin_write-phase stall. - tool_result_sent: a tool_result came back for the run's LAST tool_use. A stall with tool_call_seen && !tool_result_sent is the tool-result-not-delivered root cause. - last_progress_age_ms: age of the last agent activity at finish (the inactivity-watchdog clock). Near the ceiling on a stall, ~0 on a clean finish. Contract fields on RunFinishedProps; daemon populates two off the run object (stdin_backpressure, last_progress_age_ms) and derives two from run.events in the diagnostics summarizer (tool_result_sent, approval_requested). * fix(daemon): pair tool_result_sent by id so parallel tools attribute correctly Review catch (nettee/Looper): the first cut flipped `tool_result_sent` to true on any tool_result after a tool_use, so a multi-tool turn like tool_use(A), tool_use(B), tool_result(A) reported delivered even though B was still outstanding — bucketing multi-tool stalls as "provider stalled after delivery" instead of "tool result not delivered". Now paired by id (`tool_use.id` <-> `tool_result.toolUseId`, the same pairing summarizeRunTimingAnalytics uses): `tool_result_sent` is true only when EVERY committed tool_use received a matching tool_result (outstanding set empty). Tests cover the reviewer's regression case plus parallel all-resolved and sequential-last-outstanding. * fix(daemon): count-pair id-less tool events so degraded stalls aren't "delivered" Second review catch (nettee/Looper): id-based pairing alone still fell through to `tool_result_sent: true` when a runtime emits a tool_use with a null id, because those were counted in `sawAnyToolUse` but never tracked as outstanding. That is not hypothetical — `agent-protocol/pi-rpc/events.ts` and `copilot-stream.ts` both emit `toolCallId ?? null` for tool_use.id AND tool_result.toolUseId on degraded provider events, so an unpaired id-less tool call would mask exactly the stall this metric attributes. Id-less tool events are now paired by count alongside the id-keyed set: `tool_result_sent` requires both an empty outstanding-id set and at least as many id-less results as id-less uses. Tests cover an unpaired id-less stall and an id-less pair that did resolve. * fix(daemon): capture stdin backpressure on the default text-input path Third review catch (nettee/Looper): `stdin_backpressure` never recorded anything for non-`stream-json` runtimes. `child.stdin.end(composed, ...)` returns the stream rather than a boolean, and `writableNeedDrain` is already back to false by the time it returns — even for a chunk that `write(chunk)` would have rejected. Claude is the only runtime on the stream-json path, so the field was permanently false on exactly the runs whose `stdin_write` stalls it exists to attribute. The write and the close are now issued separately through `writePromptAndEndStdin`, which returns the boolean the OS pipe actually gave us. Extracted into chat-run-lifecycle.ts so it is unit-testable: tests cover the backpressured write, the accepted write, and the flush callback still firing (the `stdin_write_end` lifecycle mark). Verified red against the previous behavior. |
||
|
|
c9e622d0a9 |
fix(daemon): ship baseline OpenCode for Windows and stop retrying AVX2 illegal-instruction crashes (#5733)
* Classify AVX2 illegal-instruction agent crashes as cpu_unsupported and stop retrying them The Windows opencode.exe bundled with the AMR runtime is a Bun build that requires AVX2. On CPUs without it (Intel Atom/Celeron/Pentium N-series through 2021) the binary dies with STATUS_ILLEGAL_INSTRUCTION before readiness; vela surfaces an ACP fatal, the daemon classified it as a retryable fatal_rpc_error, and the automatic retry deterministically failed again. 88 of 105 pre-readiness Windows crash traces in Langfuse are this single failure. The crash text (Bun 'Illegal instruction' banner with a no_avx2 CPU feature line, or the raw 0xC000001D / decimal 3221225501 exit status) now classifies as process_exit/cpu_unsupported ahead of the fatal_rpc_error close-reason promotion, is never auto-retried, and renders a dedicated error card telling the user to update Open Design instead of a dead Retry button. * Bump @powerformer/vela-cli to 0.0.23 so packaged Windows builds bundle the baseline (non-AVX2) OpenCode The 0.0.23 win32-x64 platform package compiles the OpenCode fork with --target=windows-x64-baseline, so the bundled opencode.exe no longer requires AVX2 and starts on Intel Atom/Celeron/Pentium N-series CPUs. Verified in vela CI: the build log shows the baseline target and the new post-publish smoke job boots the published bundle's opencode.exe on a real Windows runner (powerformer/vela#838). * Refresh Nix pnpm deps hashes for the vela-cli 0.0.23 lockfile change * Add the abort-after-panic (exit status 3) production shape to cpu_unsupported specs A user on an AVX-but-no-AVX2 CPU (Sandy/Ivy Bridge era) hit the same illegal-instruction crash, but Bun panicked during its own panic handler and abort()ed, so vela reported exit status 3 instead of STATUS_ILLEGAL_INSTRUCTION. The stderr banner (no_avx2 / Illegal instruction) is the only signal; encode the real Langfuse trace shape so the classifier keeps catching it. * Bump @powerformer/vela-cli to 0.0.25 so packaged Windows builds bundle the baseline (non-AVX2) OpenCode 0.0.25 is the first stable cut after powerformer/vela#838 merged: its win32-x64 package compiles the OpenCode fork with --target=windows-x64-baseline (verified in the release CI log), the post-publish smoke boots the published bundle on a real Windows runner, and the lockfile regenerator now pins the baseline asset so a routine version bump cannot silently flip back. 0.0.24 predated that merge and still shipped the AVX2 build. * Tighten cpu_unsupported to precise signals only (no bare 'Illegal instruction') Review is right that a bare illegal-instruction line is too broad: an unrelated SIGILL on an AVX2-capable machine (runtime bug, corrupted jump) would be mislabeled 'Processor not supported' and lose its retry. Bun's crash banner always prints the CPU-feature line, so machines actually missing AVX2 are identified by no_avx2; the bare Windows STATUS_ILLEGAL_INSTRUCTION renderings (0xC000001D / 3221225501) stay because those runs carry no banner at all. Generic illegal-instruction banners without no_avx2 return to process_crashed / fatal_rpc_error, locked by a new negative spec. * Refresh Nix pnpm deps hashes for the vela-cli 0.0.25 lockfile change * Gate raw STATUS_ILLEGAL_INSTRUCTION on the bundled-opencode startup context |
||
|
|
d3e091e157 | fix(daemon): classify deterministic failures and preserve retry attribution (#5882) | ||
|
|
30a4c284c6 |
feat(web): extend visual style catalog to visual artifacts (#5746)
* feat(web): extend visual style catalog to visual artifacts * feat(web): expand visual style catalog * Simplify chat execution disclosures * test: cover collapsed file disclosures * refactor(web): consolidate chat task activity * fix(web): show small file outputs inline * fix(web): separate file outputs from reads * fix(web): collapse completed todo cards * refactor(web): compact completed todo lists * fix(web): make completed todos expandable * fix(web): keep four output files visible * refactor(web): clarify chat activity timeline * fix(web): make file output disclosure interactive * feat(web): emphasize chat run states * style(web): simplify chat run status colors * style(web): remove chat run status icons * feat(web): stream one chat activity at a time * style(web): align chat completion row * Revert "style(web): align chat completion row" This reverts commit |
||
|
|
888d35ce96 |
feat(desktop): add macOS check for updates flow (#5789)
* feat(desktop): add macOS check for updates flow * fix(web): refine update dialog layout * fix(web): refine update-ready copy * fix(web): refine updater dialog states * fix(desktop): map preflight denials to active-run copy, skip menu rebuild on progress ticks Address review feedback on PR #5789: UpdaterPopup and Settings About now surface the active-runs-blocked/active-runs-unknown restart-safety denial as user copy instead of a generic failure, and the app-menu preflight response no longer publishes a synthetic error onto the shared updater status channel. The mac app-menu rebuild now compares a stable derived menu-item key so download progress ticks stop triggering a full Menu.setApplicationMenu rebuild. --------- Co-authored-by: bone3deep1962-collab <bone3deep1962@gmail.com> Co-authored-by: NJUHua <113895241+NJUHua@users.noreply.github.com> |
||
|
|
2192a7f6b9 |
fix incomplete BYOK configuration preflight (#5745)
* fix BYOK configuration preflight * fix(web): short-circuit non-BYOK run preflight Local-agent test fixtures omit BYOK-only fields, but provider resolution read model before rejecting non-BYOK protocols. Return before touching those fields and keep the pending-prompt API fixture explicitly valid. Generated-By: looper 0.10.4 (runner=fixer, agent=codex) * fix(web): persist committed BYOK key clears Treat a blank active-provider key as draft-only while it is being edited, then persist the clear once the field is committed. This preserves incomplete replacement drafts while invalidating saved account-scoped model state. Generated-By: looper 0.10.4 (runner=fixer, agent=codex) * test(web): align BYOK draft expectations Keep incomplete model discovery edits in the provider-scoped draft while the active configuration remains unchanged, and expect the current DeepSeek preset default. Generated-By: looper 0.10.4 (runner=fixer, agent=codex) |
||
|
|
4ddfc6e447 | fix(media): retry transient image generation responses (#5702) | ||
|
|
e49d1abc42 |
fix: resolve media-backed memory extraction keys (#5767)
* fix: resolve media-backed memory extraction keys Generated-By: looper 0.0.0-dev (runner=worker, agent=codex) * fix: refine unsupported memory provider detection |
||
|
|
6bee94be03 |
fix(deploy): honor target preview/production for Cloudflare Pages (#4483) (#4576)
* fix(deploy): honour target for Cloudflare Pages branch and URL selection (#4483) - deployToCloudflarePages: add optional target ('preview'|'production', default 'production') - Branch derivation: preview→'preview', production/omitted→'main' - URL selection: preview uses per-deploy alias; production uses production root - routes/deploy.ts: read target from request body (default 'production'), pass to deployToCloudflarePages, persist actual target (not hardcoded 'preview') - db.ts normalizeDeployment: read target from DB row instead of hardcoding 'preview' - contracts: widen target fields to 'preview'|'production'; add target to DeployProjectFileRequest * test(deploy): type FormData branch capture as string | undefined (#4483) The Phase-1 branch-capture objects were typed `{ branch?: string }` but assigned `string | undefined`, which fails `tsc` under `exactOptionalPropertyTypes`. Type the field as `branch: string | undefined` so the daemon typecheck gate passes; assertions are unchanged. * fix(deploy): reject invalid deploy target with HTTP 400 (#4576) The deploy route coerced any non-'preview' target to 'production', so a malformed value (typo, empty string, wrong case) silently published to the production Cloudflare branch instead of a gated preview. Validate the supplied target up front and return 400 for anything outside preview|production; an omitted target still defaults to production (non-breaking). Addresses review feedback on #4576 / #4483. * feat(deploy): add `od deploy` CLI subcommand with --target (#4483) Land the CLI surface for the preview/production deploy capability so it is not API-only. `od deploy <projectId> --file <name> [--target preview| production] [--provider vercel-self|cloudflare-pages] [--cf-zone-id] [--cf-zone-name] [--cf-domain-prefix] [--json] [--daemon-url]` POSTs to the same `/api/projects/:id/deploy` endpoint the web UI uses, with local validation of `--target` before any request (omitted target = no key, server defaults to production). Addresses the surface-closure review feedback on #4576 by shipping the embeddability (CLI) surface alongside the API contract. The human web-UI preview/production selector remains tracked as a follow-up in #4577. Tests: apps/daemon/tests/cli-deploy.test.ts (11 cases, written test-first). * feat(deploy): add web UI target selector for Cloudflare Pages deploys Closes the web-UI surface gap PerishCode flagged on #4576: deploy target (preview/production) had HTTP + od CLI support but no way to choose it from the deploy modal. Adds a target <select> to the Cloudflare Pages deploy panel, defaulted to Preview, threaded through deployProjectFile's new optional target argument and forwarded in the deploy POST body. References #4576. * fix(deploy): reject vercel-self target=production instead of silently deploying preview POST /api/projects/:id/deploy resolved the requested target but only threaded it into deployToCloudflarePages(); deployToVercel() never received it and always behaved as preview. A caller explicitly requesting target=production against the Vercel provider was silently deployed as preview with no error (Codex P2 finding on PR #4576). Real Vercel production-target support is out of scope for this PR, so reject the explicit request with 400 BAD_REQUEST instead. The guard gates on the raw requested value, not the resolved target, so an omitted target (which defaults to 'production' for Cloudflare Pages parity) keeps deploying Vercel as preview exactly as before. * fix(web): default Cloudflare Pages deploy target to production The deploy target selector defaulted to 'preview', both in its initial useState and when syncing from the (currently placeholder, always-'preview') GET /api/deploy/config response. A user who opened the Cloudflare Pages deploy modal and clicked Deploy without touching the selector silently deployed to preview instead of production, contradicting the daemon's documented default for an omitted target and pre-PR behavior. Default both sites to 'production'; explicit user selection of either target is untouched. FileViewer.deploy-target.test.tsx covers the default and both explicit selections. Fixes #4483 |
||
|
|
265aa51630 |
feat(web): make Studio discovery visual and inline (#5496)
* feat(web): make Studio discovery visual and inline Move clarification forms into the chat flow, add artifact-aware visual style choices, and keep follow-up actions hidden until discovery is complete. * feat(web): keep clarification entirely in chat Remove the legacy Questions workspace tab, preserve discovery analytics in the inline form, and keep Skip, Submit, and answered summaries in one conversation flow. * docs: split Studio Chat input and response work Frame visual discovery as the input-side initiative and record response aggregation as a separately reviewed follow-up so the current PR stays bounded. * docs: reorganize Studio Chat experience plans Separate the overall journey, visual discovery, and response architecture so each scope can be reviewed and delivered independently. * docs: define first-artifact satisfaction prompt Limit the feedback prompt to the first successful previewable artifact so it gathers a useful signal without interrupting every iteration. * docs: keep Studio Chat plans independent Preserve the existing discovery proposal as one document and keep response architecture as a separate review surface without an extra master layer. * fix(web): preserve inline discovery behavior Keep visual direction single-select while restoring custom input, optional auto-continue, analytics, and current end-to-end coverage for the inline flow. * fix(web): preserve files when skipping discovery step * fix(web): exclude skipped file answers * fix(web): align inline discovery with slim prompt Preserve the latest discovery contract while keeping inline forms, uploads, drafts, and schema-driven visual selections consistent after the rebase. * feat(web): add style catalog preview images * fix(web): clarify discovery form completion * fix(web): preserve question form context * fix(web): time out unanswered question forms * test(web): cover inline question form next steps * fix(web): roll back partial inline uploads * ci: trigger validation after rebase * fix(web): unlock blocked inline question submits * fix(web): retain previewless visual answers * fix(web): load visual style previews from R2 * fix(web): clean blocked inline uploads * test(web): expect R2 style preview assets * feat(web): show full visual style catalog * fix(web): keep inline question answers consistent --------- Co-authored-by: xiaoche-hub <298951296+xiaoche-hub@users.noreply.github.com> |
||
|
|
66e4061274 |
fix(memory): retire chat auto-extraction and clean up its artifacts (#5708)
- chatExtractionEnabled now defaults OFF (explicit opt-in only); it gates the regex pack, chat-form profile capture, and LLM extractor together while leaving memory injection untouched - add a one-time boot migration (memory-cleanup.ts) that deletes regex-pack artifacts by name+template fingerprint, prunes user_profile to the canonical field set the settings editor writes, and forces the legacy config flag off once; marker-gated so a conscious re-opt-in sticks - persist writer provenance (frontmatter source:) on every new entry so future audits can tell auto-extracted facts from hand-written ones - LLM-extracted entries are deliberately kept: on-disk they are indistinguishable from hand-written prose, and they are the least harmful of the retired pipelines' output Co-authored-by: NJUHua <113895241+NJUHua@users.noreply.github.com> |
||
|
|
a219a933eb |
fix(memory): forward BYOK chat model through /api/memory/extract (#5177)
* fix: forward BYOK chat model to memory extraction (#5162) Root cause: Two issues preventing non-OpenAI BYOK providers (e.g. MiniMax) from working with memory-llm extraction: 1. Web side (ProjectView.tsx): The BYOK chatProvider snapshot sent to /api/memory/extract was missing the `model` field. Without it, pickProvider() fell through to PROVIDER_DEFAULTS.openai.model ('gpt-4o-mini'), which doesn't exist on non-OpenAI endpoints. 2. Daemon route (memory.ts): The /api/memory/extract POST handler did not extract body.chatModel, unlike every other memory route. Even when the web side passes a model, it was silently dropped. Changes: - ProjectView.tsx: Add `model: byokOpenCodeProvider.model` to the BYOK chatProvider snapshot so pickProvider() can use the user's actual chat model (e.g. 'MiniMax-M3'). - routes/memory.ts: Read `body.chatModel` and forward it to extractWithLLM options, matching the pattern used by all other memory routes. Testing: typecheck passes for apps/web (affected packages). The daemon typecheck requires pre-built @open-design/release which is a separate toolchain concern. * fix(contracts): add model field to ByokChatProviderConfig for BYOK memory extraction (#5177) The web-side memory snapshot was reading byokOpenCodeProvider.model but the BYOK config contract had no model property, causing a compile-time type error. Add an optional model field so the daemon can forward the user's chat-model picker choice to memory extraction. * fix(byok): copy config.model into byokOpenCodeProvider snapshot Address review comment on PR #5177: byokOpenCodeProviderFromConfig() did not copy config.model into the returned ByokChatProviderConfig, so byokChatProvider.model serialized as undefined and /api/memory/extract fell back to the hardcoded default (gpt-4o-mini) for OpenAI-compatible BYOK endpoints like MiniMax. Threading config.model through ensures the chat-selected model reaches memory extraction. Reviewed-by: mrcfps (review comments on ProjectView.tsx:5049) * test: add model field to BYOK payload expectations in web workspace tests * fix(daemon): forward BYOK chatProvider to post-turn memory extraction The daemon close handler creates memoryOptions for pickProvider() but never forwarded the per-call BYOK provider snapshot ('byokProvider' from the chat request body). This meant post-turn LLM memory extraction always fell through to environment/default provider detection instead of using the user's selected BYOK provider and endpoint. Added 'chatProvider: byokProvider ?? null' to the memoryOptions object so pickProvider() can run 'Same as chat' extraction against the user's actual provider/config, matching the behavior of the pre-turn /api/memory/extract path. Addresses reviewer feedback on PR #5177 (fix #5162). * fix(daemon): normalize byokProvider shape for post-turn memory extraction (#5177) The close handler forwarded byokProvider ({ protocol, ... }) directly as chatProvider, but memory-llm.pickProvider expects { provider, ... } with provider being a PROVIDER_DEFAULTS key. Now we map protocol → provider the same way the web pre-turn path does (ProjectView.tsx L5894). * fix(daemon): support keyless BYOK endpoints in post-turn memory extraction (#5177) Three-part fix for keyless BYOK (local vLLM / Ollama / openai-compatible servers with requiresApiKey=false): 1. server.ts normalization: thread requiresApiKey through to the memoryChatProvider snapshot so pickProvider() can distinguish keyless endpoints from missing-provider cases. 2. memory-llm pickProvider() BYOK gate: relax the apiKey guard so endpoints explicitly marked with requiresApiKey=false enter the BYOK branch instead of falling through to env/media-config fallbacks (which would route to unrelated OpenAI credentials / gpt-4o-mini). 3. memory-llm callOpenAI(): conditionally emit Authorization header only when apiKey is non-empty, preventing empty Bearer from being sent to keyless local servers that would reject it. |
||
|
|
c67048516c |
fix(web): polish preview status action (#5696)
* fix(web): polish preview status action * fix(web): keep preview failure hint passive --------- Co-authored-by: xiaoche-hub <298951296+xiaoche-hub@users.noreply.github.com> |
||
|
|
167db9de20 |
feat(web): add preview delivery status feedback (#5557)
* feat(web): add preview delivery status feedback
* fix(web): keep delivery retry in chat
* feat(web): stage preview delivery progress
* refine(web): clarify preview delivery stages
* fix(web): preserve preview delivery feedback
* fix(web): address preview delivery review
* refine(web): keep preview delivery status passive
* Revert "refine(web): keep preview delivery status passive"
This reverts commit
|