mirror of
https://github.com/lobehub/lobehub.git
synced 2026-09-20 04:56:13 +08:00
feat/start-topic-from-folder
171 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
c5ec20abab |
✨ feat(docker): run self-hosted Compose chats in Gateway Mode by default (#19583)
* ✨ feat(docker): run self-hosted Compose chats in Gateway Mode by default - Add the lobehub-gateway service to docker-compose and wire the lobe service to it; AGENT_GATEWAY_INTERNAL_URL keeps server pushes on the Compose network while browsers use AGENT_GATEWAY_URL. - S3_INTERNAL_ENDPOINT routes the server's own S3 requests to rustfs:9000 while presigned URLs keep the browser-facing S3_ENDPOINT, which local mode sets to localhost and the container cannot reach. - setup.sh generates a per-deployment JWKS_KEY and gateway token and writes the gateway URL for each deploy mode; the .env template drops the public JWKS key. - Warn loudly at container startup when an upgraded stack lacks the gateway settings or still uses the public example JWKS_KEY, and document the upgrade. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 🔒 fix(docker): pass only the public JWK to the gateway container The gateway only needs the public half of JWKS_KEY to verify browser sessions, but it received the full private key set, so anyone able to read the gateway environment could sign tokens LobeHub trusts. setup.sh now also writes JWKS_PUBLIC_KEY (the same key without d/p/q/dp/dq/qi), Compose passes only that to the gateway, and the startup check warns when it is missing, still contains private fields, or does not match JWKS_KEY. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
40f8f469cf |
🐛 fix(docker): make the one-click Docker Compose install start on the released image (#19590)
- Apply a bucket CORS rule in rustfs-init so browser uploads to RustFS through presigned URLs are not blocked by the preflight. - Preload pg_cron and pg_stat_statements alongside pg_search, matching the ParadeDB image default. Its first-start bootstrap creates pg_cron under set -e, so preloading only pg_search aborted initialization, restarted the container and failed the first docker compose up with an unhealthy database. - Probe PostgreSQL health over TCP with a start period. During initialization the image runs a temporary socket-only server, so the socket probe passed early and LobeHub's migrations failed with ECONNREFUSED until it had restarted repeatedly. - setup.sh downloads templates from lobehub/lobehub main, uses curl with a wget fallback, and detects the host IP on macOS where hostname -I is missing. Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
41ce61b35d | ⚡️ perf(search): skip ineligible message indexing with versioned capture (#19537) | ||
|
|
ef6e3b1fe5 |
✨ feat(desktop): add built-in completion sound choices (#19480)
* ✨ feat(desktop): add built-in completion sound choices Ship three more synthesized chimes next to the marimba default (glass bell, soft tone, xylophone) and let the notification settings pick one from a select; importing a sound now lives inside that select and picking a built-in drops the imported pack. The generator script renders every built-in from one instrument × motif table; the default output stays byte-identical. Dev builds no longer compute the renderer main hash unless OTA is forced, since the lockfile pin check only matters for packaged builds. Claude-Session: https://claude.ai/code/session_01Rf3vs7eC8jwF75kohcS3Ye * ♻️ refactor(desktop): synthesize completion sounds at build time Move the chime renderer out of a one-off script into a Vite plugin that writes the WAVs under the renderer public dir and the banner AIFF under the desktop resources on every dev/build start, and stop tracking the audio binaries. Output is byte-identical to the files that were checked in; a test pins the default chime's hash. Claude-Session: https://claude.ai/code/session_01Rf3vs7eC8jwF75kohcS3Ye |
||
|
|
13ada65ad9 | ✨ feat(fts-search): safe per-entity Elasticsearch mapping migrations (#19186) | ||
|
|
ac000cc0a6 |
✨ feat(desktop): add chat completion sound settings (#19280)
* ✨ feat(desktop): add chat completion sound settings Split completion feedback by window focus so the two sound sources can never overlap: the foreground plays an in-app chime (off by default, own volume and importable audio), while the background leaves the sound to the notification banner. The main process owns the focus decision and the renderer only plays when the banner was skipped or refused. The banner can carry either the macOS default sound or LobeHub's own chime. UNNotificationSound resolves a name only against ~/Library/Sounds and only in AIFF, so the chime is installed there on demand rather than bundled. Claude-Session: https://claude.ai/code/session_01SaZzuGjGHqADBxhWn4HjUa * ✅ test: mock completion sound in agent run specs |
||
|
|
38bd08df1d | 🐛 fix(ci): keep desktop canary OTA progressing (#19112) | ||
|
|
011f947cf7 |
👷 ci(share,workbench): upload PR previews to sibling -preview Workers (#19103)
* 👷 ci(share,workbench): upload PR previews to sibling -preview Workers Cloudflare rolls back only to the 100 most recently uploaded versions of a script, and PR preview uploads landed on the production scripts, so a busy day pushed every real deployment out of the rollback window. Previews now go to lobehub-share-preview and lobehub-workbench-preview; the preview aliases move with them (pr<N>-lobehub-share-preview...). Claude-Session: https://claude.ai/code/session_01BKMAksDxdePWPW4kgr9KpM * 📝 docs(split-micro-app): previews upload to a sibling -preview Worker Claude-Session: https://claude.ai/code/session_01BKMAksDxdePWPW4kgr9KpM * 👷 ci(share,workbench): stamp actor, commit and run on every Worker version Cloudflare records only the API token's owner as a version's author, so a deploy from CI or a laptop was unattributable. wrangler deploy and PR preview uploads now carry --tag <sha7> and --message "<actor> <repo>@<sha7> run <id>" (local deploys: "<git email> local@<sha7>"), which 鳥居番's Deploys page already shows per version. Claude-Session: https://claude.ai/code/session_01BKMAksDxdePWPW4kgr9KpM * 📝 docs(split-micro-app): 鳥居番 Deploys page has Releases and Previews tabs Claude-Session: https://claude.ai/code/session_01BKMAksDxdePWPW4kgr9KpM * 📝 docs(split-micro-app): releases and previews live on the target's Worker card Claude-Session: https://claude.ai/code/session_01BKMAksDxdePWPW4kgr9KpM * 📝 docs(split-micro-app): Set override writes the staging config directly Claude-Session: https://claude.ai/code/session_01BKMAksDxdePWPW4kgr9KpM |
||
|
|
330c12a760 | ✨ feat(self-host): add optional Elasticsearch to Docker Compose (#19028) | ||
|
|
321bfe8623 | ⚡ perf: accelerate and harden Elasticsearch reindex recovery (#18902) | ||
|
|
d74e897191 | ✨ feat: add Elasticsearch full-text search provider (#18807) | ||
|
|
4dc26d48ef |
✨ feat(goal): add process control UI and server-driven execution (#18762)
* ✨ feat(goal): add the process-control surface to the Goal detail page Move the prototyped process-control UI into the product: the frontier list (what can move now), the exploration map on react-flow, the findings list and a per-node activity feed. Data comes from one `goal.graph` read. The server has no frontier projection, no per-node attempt roll-up and no artifact hydration, so the client reproduces the coordinator's own selection rule and derives the attempt ledger from the `goal_events` trail. Anything that cannot be derived honestly is omitted rather than invented. A Goal Graph goal has no carrier task, so the detail route falls back to a graph-only page when the identifier resolves to no task. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ♻️ refactor(goal): make the Goal Graph the only goal model A goal used to be a `goals` row bound to one carrier task, driven by an outer loop in the verify settle path. That was the early attempt; the Goal Graph supersedes it — the graph owns the decomposition and dispatches a Task per Work node, each with its own acceptance contract, and stops on a decision gate when a Work runs out of attempts. Server - `GoalModel.list` is goal-centric: it reads `goals` and derives the roll-up (work done/total, findings, pending gates, cost) from the graph, so a goal without a carrier task is no longer invisible. - Delete the task-carried outer loop: `verify/goalLoop`, `verify/goalBudget`, the goal branches in `settle` / `acceptanceService` / `planInstantiation`, and the goal binding in `TaskService.createTask` and `task.create`. - `/goal` now creates a Goal Graph and advances it once; the coordinator creates the responsible task and its verifier. - New `goal.delete`; `task.deleteGoal`, `hasGoal` filters and `TaskItem.goal` are gone with the flow that needed them. Client - Goal list, detail, home rail and the conversation card read the graph. - The goal detail route is keyed by the `goals` row id. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 🐛 fix(goal): read the attempt ledger from real attempt boundaries Found while driving a goal end to end: the frontier row of a running task showed no clock, and a finished task's attempts were labelled from a bookkeeping event. `goal_events` writes `updated` for housekeeping too ("Attached Work version …"), and every `updated` was closing the open attempt. That ended the live attempt one event early — so `startedAt` was never set and the running clock disappeared — and stamped the housekeeping reason onto the previous attempt. Only `activated` now opens an attempt, and only a boundary closes it: the next `activated` (the coordinator started another attempt, so this one did not deliver) or a terminal event. A Work parked at a decision gate leaves its attempt open, since the gate is written as `updated`, so the node's own status closes it. A gate row also showed an empty ledger, because attempts live on the Work and the row is the decision node. The gate now carries the Work it was opened for and renders that Work's ledger — which is the case the user is deciding. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 💄 style(goal): quiet the exploration map and make one press run the goal Review feedback on the acceptance round, item by item. The map was shouting the same thing in three places at once — a pill floating on the card's outline, an emphasis border, and a drop shadow — which left no room for the edges routed around it: - cards go flat; state becomes a dot plus a word on the header's trailing edge, where the "you took part" mark now sits too; - edges become bezier curves instead of right-angled steps; - the frontier emphasis border is gone. It was drawing a heavy outline around a *completed* card, which is the wrong signal entirely; selection keeps a single light border; - inline, the map is a picture: no zoom controls, no pan, no zoom. Fullscreen is where it becomes navigable. The advance button ran a single coordinator tick. That is an implementation unit, not one a person cares about — dispatching a work takes two ticks, so one press usually looked like it did nothing. It now advances until the goal is achieved, needs a decision, or has nothing ready, the way `lh goal run` does. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ✨ feat(goal): drive goals from the server instead of a client tick loop A Goal Graph only moved while something kept calling `goal.tick` — a browser loop or `lh goal run`. Close the tab and a long-horizon goal stopped, which is the opposite of what "long-horizon" is supposed to mean. Goals now advance on their own, event-first with a sweep behind it: - `advanceGoal` runs the coordinator until it is waiting on something that is not another tick. `waiting_external` is a stop, not a poll: a Work Task is executing, and that task's own settle is the next event. - Something that may have unblocked a goal queues an advance — creating it, resolving a decision gate, resuming it, raising a budget, and a Work Task settling in the verify path. - `/api/workflows/goal/sweep` is the safety net a purely event-driven chain needs: it picks up goals with no fresh active Work and no pending gate, so a dropped queue message, a runner that died mid-dispatch, or a Work that outlived its operation lease cannot strand a goal forever. - The scheduler mirrors `taskScheduler`: QStash in queue mode, in-process timers for dev and desktop, so both exercise the same runner. The page's advance button hands off to the server in one call rather than holding a tick loop open, and `goal.advance` is the nudge for "don't wait for the next event". The loop that used to live in the browser now lives where it can keep running without one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 🐛 fix(goal): actually queue the advance when a goal is created The create procedure was the one enqueue site that never landed, so a goal sat in `planning` until something else poked it — the exact failure the automatic driver exists to remove. Caught by running a goal end to end with no client attached: creation published nothing to the queue. A dispatch failure is now logged loudly rather than only through `debug`. This is the only thing that makes a goal move on its own; when it breaks, the symptom is goals that quietly stop, which is close to impossible to attribute from the outside. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ♻️ refactor(goal): import Text/Tag/ActionIcon from base-ui The base-ui migration (#18729) landed on canary while this branch was open, so the Goal process-control components still pulled the deprecated antd wrappers. Move them over and drop the acceptance imports the Goal detail page no longer uses. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 🐛 fix(goal): close the gaps the review found in the graph-only migration Seven problems, all from making the Goal Graph the only goal model: The create modal still showed a visibility control whose value went nowhere, so a goal marked private dispatched Work Tasks that fell back to the assignee agent's visibility and published its output to the workspace. Visibility now rides on the goal's `config` — no new column — and the coordinator stamps every task it creates. Goals from the earlier task-carried flow have no `goal_nodes`, and the new goal-centric list returned them alongside graph goals: a goal page with no work, no frontier and no way forward. They stay out of both the list and the sweep's work list until something backfills them. `task.create` no longer accepts a `goal`, but Zod was stripping the field rather than rejecting it, so a released client would report that a goal started when only an ordinary task existed. It now fails with a message that says to reload. The sweep is the safety net for an event-driven chain, and self-hosted deployments only ever provisioned the task dispatcher schedule, so nothing called it. `startServer.js` now registers both. Two advances can overlap — an event hook, a manual nudge, the sweep — and `runTask` decides whether a run is in flight by reading topics before creating one, so both could dispatch the same Work and bill it twice. The coordinator claims the task with a conditional status update first, and releases it if the dispatch throws. Deleting a goal cascaded its graph away while leaving its Work Tasks and their agent operations running, spending budget with nothing left on screen to stop them. Deletion now cancels running topics and pauses those tasks first. Project goal cards had no `aid` in the route, so every card on the project Goals page rendered as a link that did nothing. They fall back to the goal's own agent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 🐛 fix(goal): stop a public goal on a private agent from wedging its Work Two problems with the visibility the previous commit added. `GoalService.create` still declared its own narrower config type, so the shared `GoalConfig` field did not type-check on the server — which the CI type-check caught and the runtime tests could not. Forwarding an explicit `public` to `createTask` also buys nothing: it is what the service derives anyway, and stating it outright trips the "a public task can never run on a private agent" invariant, leaving the Work throwing on every tick. Only `private` — the value that actually has to be preserved — is passed through now. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 🐛 fix(goal): keep the page live, claim recovery retries, close terminal goals Three more from the review, all consequences of the server now driving goals. The graph snapshot only revalidated on focus. That was fine when the client ticked the goal itself and refreshed after every step; now the server advances it, so an open page sat on its first snapshot — a spinner still turning on a goal that had already finished. It polls while the goal is in a status the server can move, and stops for `review`, `paused` and the terminal ones, where the next change comes from a person and their action refreshes it anyway. The dispatch claim added in the previous commit only covered starting a backlog Work. `WorkRecoveryCoordinator.recover` spawns its own run for the two automatic-retry paths, so overlapping advances could still each pay for an attempt. The claim now lives in `recover`, where the spawn is. Both callers hand it a task row read before they paused it, so it compares against what the row says now — and treats an already-`running` task as someone else's claim rather than its own. The goal page still offered Advance and Add Task on an achieved, failed or canceled goal. The coordinator returns immediately for those, so Advance reported nothing happened and a Work added there stayed `proposed` with no way to run it. Those controls are gone once a goal is closed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 🐛 fix(goal): stop the client racing the queued driver, free orphaned claims Three more from the review. Creating a goal queued an advance on the server and then fired a single tick from the client. A tick is one step: the one that binds the Work's task, not the one that starts it. If that tick won the node claim, the queued driver saw the claim, reported `waiting_external` and stopped — leaving the task in backlog with nobody to start it until the sweep noticed. Both creation paths now run the full driver, so whichever one claims the Work carries it through to starting it and the loser stops harmlessly. The dispatch claim is taken just before `runTask` creates the task's topic. A worker that died in that sliver left the task `running` with no operation behind it, and `recoverAbandonedWork` returned immediately because there was nothing to reclaim — so every later advance reported `waiting_external` and the Work never ran again. A claim with no run behind it is now handed back once it is older than the operation lease, which is also long enough that a run about to start is never mistaken for an abandoned one. The Advance tooltip still told users graph goals have no server-side driver and only move while a client advances them — the opposite of what this branch implements, and an invitation to sit on the page pressing the button. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 🐛 fix(goal): scope private goals, and stop attempts capping the whole graph Five more from the review. A goal marked private only made its Work Tasks private. The goal row itself has no visibility column, so workspace scoping alone left its requirement, its graph, its findings and its whole event log readable by every member — the one thing the private toggle exists to prevent. `buildGoalScopeWhere` now enforces the stored `config.visibility` on every goal and graph read. A real column that `buildWorkspaceWhere` can take directly is the better long-term shape; this holds the guarantee without a migration. The creation form's only iteration field means "attempts on one Work", and it was also being sent as `maxRounds` — which the coordinator counts across every Work in the graph. With the default of three, three finished tasks exhausted the budget and a fourth never started despite having run nothing. The two limits are separate now, and the same conflation is gone from both `/goal` paths. `null` in that field is the manifest's documented "no user-specified cap", but it was folded into the default of three, so clearing it quietly capped the goal anyway. It now leaves the setting off and lets the recovery policy default apply. Raising the budget of a goal the budget had stopped left it `paused`, and `tick` refuses to move a paused goal — so the advance this mutation queues returned immediately and the user had to find Resume as a second gesture. A goal whose budget was actually binding is reopened; one somebody paused deliberately is left alone. Goals created from a project page have no responsible agent, so the earlier `goal.agentId` fallback was still empty and every card there was a dead link. They route to a bare `/goal/:goalId`, mirroring how tasks already fall back to `/task/:taskId`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 🔒 fix(goal): gate goal deletion and inherit a private agent's visibility Four more from the review. Deleting a goal only checked that the caller holds `agent:update` in the workspace — which says a member may change goals, not whose. Any member could delete a colleague's goal and cascade its whole graph away. It now asserts the same creator-or-workspace-owner rule that task deletion already applies. `/goal` runs as an agent and never states a visibility, so a goal created by a private agent was workspace-public even though the task it dispatched was inferred private. `GoalService.create` derives it from the responsible agent the way `createTask` does, which covers both the client executor and the server runtime instead of asking each to remember. Deleting a goal cancelled its running work but swallowed a cancellation failure. If the runtime or a device gateway was unreachable the graph was deleted anyway, leaving an operation spending with nothing left that could stop it. That failure now aborts the deletion and says why. The bare `/goal/:goalId` route rendered only a title, and the actions menu it omitted is the only place a goal can be deleted — so a goal created from a project could never be removed. The menu is no longer nested under the agent breadcrumb, and both it and the post-delete destination fall back to the project scope. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 🐛 fix(goal): park unmovable goals and keep a failed kickoff from looking unsaved Two more from the review. A goal with no Work — or whose every remaining Work is blocked with nothing running to unblock it — can only ever report `no_progress`, but it stayed `running`. The sweep takes the newest stalled goals up to a limit, so enough of these permanently occupy that window and every older stalled goal stops being swept at all. They are now parked the same way a goal waiting on a decision gate is: the row says what it is, and the scan moves on to goals that can actually move. Creating a goal through `/goal` reported a kickoff failure as `GoalCreateFailed` even though the goal was already committed — so the agent, told nothing was created, would create a second one and both would do the same paid work. Once creation succeeds the goal id is always reported; a failure to start it now says so and points out that the server will pick it up. Both the client executor and the server runtime had the same boundary. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * 🐛 fix(goal): queue the advance for goals created by the server runtime The previous commit stopped reporting a failed kickoff as a failed creation, telling the agent the server would pick the goal up instead. That is true for `/goal` from a client, which goes through the `goal.create` route, but the server-side tool runtime calls `GoalService.create` directly and nothing scheduled anything. Outside queue mode there is no local timer for the goal and no recurring sweep either, so a kickoff failure left it stranded in `planning` while the agent had been told not to create it again. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ⚡️ perf(goal): stop every goal card refetching the whole graph each second The card's timer drove both the elapsed clock and a full graph revalidation, from when the client had to keep a goal moving itself. The store already polls the snapshot while the goal is one the server can move, so this was a second, five-times-faster copy of that: ten cards in a conversation pulled the whole node and event history six hundred times a minute. Worse, a card whose fetch had failed had no status to read, resolved as unsettled, and kept asking forever. The timer now only ticks the clock. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * ⏪️ revert(goal): drop the goal visibility control Goals do not carry a privacy promise for now, so the whole mechanism comes out rather than sitting half-wired: the `config.visibility` field, the creation input that set it, the agent-derived default, the stamp the coordinator put on each Work Task, and the `buildGoalScopeWhere` predicate that enforced it on reads. Goal and graph reads are back to plain workspace scoping. The chooser goes with it. Leaving the control on the creation form while nothing acts on it is exactly the state this branch was reported for: a user marks a goal private and it is not. Deleting a goal still requires being its creator or a workspace owner — that is about who may destroy someone else's work, not about who may read it, and it matches what tasks already enforce. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Arvin Xu <arvin.x@lobehub.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
1bd6c6c56c | 🐛 fix(desktop): stop bundling web SPA artifacts into the renderer dist (#18644) | ||
|
|
2df9829a5e |
✨ feat(share): extract share pages into a standalone SSR micro app (#18496)
* ✨ feat(share): extract share pages into a standalone SSR micro app `/share/t/:id` and `/share/page/:id` were client-only routes inside the main SPA, so a shared link opened on a blank shell and link previews carried the generic app card. They now live in `apps/share`, built the same way as `apps/workbench`: a React Router framework-mode app that server-renders on a Cloudflare Worker for cloud, plus a plain SPA build that Next serves for self-hosted deployments. What the server renders is the shell, the hero and a complete meta set — title, description and the OG/Twitter card — resolved from the route loader through a per-request tRPC client. The conversation and page-viewer stacks stay on the client: `clientOnly()` gates them and, in the SSR environment, a resolver stub cuts every `*.client` module out of the worker graph entirely. Gating the render alone does not help, because the dynamic import still pulls the graph into the bundle. Keeping that worker deployable took three more cuts, each found by tracing the module graph rather than guessing: - `@/store/user` is stubbed for SSR — `GroupAvatar` reads the viewer profile, and the store drags the model catalog and every provider behind it (39MB→19MB) - `shiki` and `shiki/wasm` are stubbed for SSR — the `@lobehub/ui` barrel reads the bundled-language catalog at module scope, registering ~400 grammars for a highlighter the server never runs (19MB→7.6MB, 1.78MB gzip) - SSR i18n resolves only the namespaces the shell renders; the generic loader would register every locale x namespace pair as a worker chunk The conversation list keeps its `headerSlot` while it shows the skeleton. It returned early before, so mounting the list to fetch blanked a title the server had already rendered. `/share` is removed from the desktop and mobile routers and rewritten by the Next middleware to `/spa-share/<locale>/…`, mirroring how `/verify` reaches workbench. The cloud worker is published from lobehub-cloud, which builds this same app against its business overlay, so this repo ships no deploy workflow for it. * 🐛 fix(share): preload the error namespace so the boundary renders translated The root ErrorBoundary reaches for the `error` namespace, which SSR did not bundle, so a failed share page rendered `error.title error.desc error.retry` verbatim. Fetching it on demand does not fix that case: a chunk-load failure is exactly when the client can never load the dictionary to correct itself. * 🐛 fix(share): drop the dev template fetch that served the main SPA The handler asked the main Vite server for `/index.share.html`, which does not exist at the repo root. Vite answers that with the HTML fallback — 200, main SPA shell — so `/share/*` in `bun run dev` silently booted an app that no longer has those routes. Share is developed against its own Vite server, so the branch goes rather than the file being added. `spaDevShells.test.ts` guards both directions: every remaining dev template must exist at the root and point at its own app entry, and share must not reintroduce one. * 📝 docs(skill): record the cloud-overlay split in split-micro-app Share is the second micro app and the first whose rendering code lives in the lobehub-cloud business overlay, so the skill needed the ownership rules that decides which repo builds and deploys, and the Vite 8 tsconfig-nearest-importer landmine that makes an overlay build ship the open-source fallback with a green build. Also folds in what the extraction turned up: the full Docker chain, the dev shell that answers 200 with the wrong app, shiki and @lobehub/ui bundle cuts, the error namespace, hydration and virtualized-prefill rules, the asset prefix convention, and the prod promote gate. |
||
|
|
1001a58a22 |
✨ feat(workbench): React Router framework mode SSR on Cloudflare Workers (#18473)
* ♻️ refactor(spa): extract verify/acceptance into apps/workbench Move the Workbench SPA into apps/workbench and serve /verify and /acceptance from that runtime for every web UA. The main SPA no longer registers those page routes, so they drop out of its bundle. * 🔧 chore(docker): wire the workbench workspace into image builds Copy apps/workbench/package.json before pnpm i so Docker can resolve the extracted SPA. Keep generateSpaTemplates optional for Cloud, and require the HTML only when WORKBENCH_REQUIRED=1 (build:docker). * ♻️ refactor(workbench): hard-navigate only from markdown entity links Keep Link and useWorkspaceAwareNavigate in-router. Markdown verify, acceptance, and mobile agent-doc links document-navigate. Drop the __WORKBENCH__ Vite define; Electron still skips hard-nav for portals. * ♻️ refactor(verify): slot-inject origin conversation and decouple shared components * 🐛 fix(i18n): make vite glob loaders independent of the vite root * ✨ feat(workbench): React Router framework mode SSR on Cloudflare Workers * 🐛 fix(verify): render viewer-timezone timestamps only after hydration * 💚 ci(workbench): deploy with affected detection and PR build verification * 📝 docs(skills): micro-app split and gateway routing playbook * 🐛 fix(workbench): track app/lib swallowed by the root lib/ ignore rules * ✨ feat(workbench): signed-in acceptance list sidebar on detail pages * 🐛 fix(workbench): survive shared-origin gateway quirks in client navigation * 💄 style(workbench): surface error detail on the boundary page * 💄 style(workbench): adopt the shared ErrorCapture page for the root boundary * 💄 style(verify): drop the app-home back arrow from the acceptance list panel * 🔧 chore(workbench): persist only error logs in wrangler observability * 📝 docs(skills): record Docker vs Cloud hosting for micro apps OSS Docker still builds and serves the SPA in-image. Cloud Next must not build, rewrite, or CDN-upload it — gateway routes to the Worker. * 💄 style(workbench): pin the acceptance logo while the list panel slides * 🐛 fix(workbench): only show the acceptance sidebar when signed in * 🐛 fix(verify): drop namespace prefix on bound verify translations |
||
|
|
a608bd3f1d |
🐛 fix(python-interpreter): run the worker as classic, and publish workers where a page can load them (#18277)
* 🐛 fix(python-interpreter): construct the worker as classic, not a module The worker was constructed with `type: 'module'` while the bundler emits it as an IIFE, so the declared type never matched the output. It also loads Pyodide through `importScripts`, and a module worker rejects that call: TypeError: Failed to execute 'importScripts' on 'WorkerGlobalScope': Module scripts don't support importScripts(). The failure lands inside `init()`, so nothing surfaces until the interpreter is first used — construction succeeds and the tool then fails on its first real call. Verified end to end in a browser against the built worker: Pyodide loads, `print("hello from", sys.platform)` writes `hello from emscripten`, and `6*7` returns 42. * ✨ feat(build): publish web workers to the public root `new Worker(url)` only accepts a same-origin script — no CORS header lifts that, unlike a crossorigin script tag. So once the SPA's assets move to an asset host, workers are the one thing that has to stay behind, served from the page's own origin. The build emits them into `app-workers/`, but `copyDirs` is an allowlist and did not carry the directory across, so the files reached neither `public/` nor the asset upload and the emitted URL resolved to nothing. Copy them to `public/app-workers/` rather than into each SPA directory: the files are byte-identical across variants, so one path keeps one copy and gives the origin a single prefix to recognise. |
||
|
|
5287fe849f |
✨ feat: add standalone workbench SPA target (#17786)
* ✨ feat: add standalone workbench SPA target * ⚡️ perf(verify): stabilize acceptance callbacks to keep CheckList memoized * 🔧 chore(docker): copy workbench SPA assets into the runtime image Mirror the existing public/_spa copy for public/_spa-workbench so the workbench bundle is present in the runtime image regardless of Next.js output file tracing. |
||
|
|
71532e1ba7 |
🐛 fix: ship devtools chunks in production and stop DevDock load failure crashing the app (#17814)
* 🐛 fix: ship devtools chunks in production and stop DevDock load failure crashing the app * 🐛 fix: stop paired chunk-error events from looping the auto-reload A failed dynamic import surfaces as vite:preloadError, the rethrown unhandledrejection and the router ErrorBoundary render, all carrying the same Error. notifyChunkError now dedupes by error identity and keeps the sessionStorage reload guard monotonic, so a persistently missing chunk stops at the toast instead of reloading forever. |
||
|
|
c3a51ec26b |
🐛 fix(workspace): sync library visibility with its content and stop phantom agent-config saves (#17715)
fix: common workspace and bot issues |
||
|
|
93213a51fb |
⚡️ perf: make SPA startup demand-aware (#17577)
* ⚡️ perf(vite): make route chunk warmup demand-aware * ⚡️ perf(spa): preload routes through shared lazy loaders * ⬆️ chore(deps): align UI editor and Shiki versions * ⚡️ perf(pwa): cache lazy code on demand * ⚡️ perf(spa): reduce initial JavaScript dependency closure * ⚡️ perf(desktop): simplify renderer startup * ⚡️ perf: refine imperative modal loading boundaries * 🐛 fix(ci): restore production SPA startup * ♻️ refactor: share deferred PWA cache rules * 🐛 fix(ci): execute SPA copy entry with Node |
||
|
|
f945c00d50 | ♻️ refactor(lint): clean up eslint-disable directives (#17206) | ||
|
|
a84caf7156 |
♻️ refactor(dev): resolve dev ports in orchestrator and inject via env (#16641)
* ♻️ refactor(dev): resolve dev ports in orchestrator and inject via env * 🐛 fix(dev): probe loopback addresses in free-port scan * 🔥 chore(dev): drop devStartupSequence tests |
||
|
|
872604cc6a |
🐛 fix(auth-spa): clean stale SPA assets before auth build (#16310)
* 🐛 fix(auth-spa): clean stale SPA assets before auth build * 🐛 fix(auth-spa): copy favicon assets |
||
|
|
5862a3ead8 |
🌐 chore: translate non-English comments to English in scripts (#16000)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
4595f86e41 | ✨ feat: use Market task template recommendations (#15558) | ||
|
|
4a11ed9887 |
♻️ refactor(auth): migrate auth pages to a standalone lightweight SPA (#15689)
* ✨ feat(oidc): add interaction details endpoint * ✨ feat(auth-spa): scaffold standalone auth SPA shell and build pipeline * 🐛 fix(auth-spa): address review findings in AuthShell copies * ✨ feat(auth-spa): add spa-auth html route handler * ♻️ refactor(auth-spa): migrate simple auth pages into auth SPA * 🔒 fix(auth-spa): validate locale segment in spa-auth route * ♻️ refactor(auth-spa): move verify-im route to main SPA * 🔒 fix(auth-spa): sanitize callbackUrl, fix signup form wiring, add router error element * ♻️ refactor(auth-spa): migrate oauth pages into auth SPA * 🐛 fix(auth-spa): address oauth migration review findings * ♻️ refactor(auth): route auth pages to standalone SPA and drop Next auth tree * 🔒 fix(auth): validate locale before middleware rewrite * 🔥 chore(auth-spa): drop unused messenger i18n namespace from auth shell * ⚡️ perf(build): share one react vendor bundle across web/mobile/auth SPA builds Build react core (react, react-dom, react-dom/client, react/jsx-runtime) once as a self-contained ESM bundle under /_spa/vendor-shared, then mark those specifiers external in every SPA build and map them via rolldown output.paths to the same hashed URLs, so the auth page warms the main app's react cache. react-router-dom stays per-build: apps use ~19K of it after tree shaking while a shared bundle must export all 252K. Also split auth i18n namespaces into per-locale chunks, keep locale runtime helpers out of the default locale chunk, and group packages/const into app-const so vendor-ai-runtime no longer captures it. * ♻️ refactor(spa): extract shared SPA html serving helpers Both the main SPA and auth SPA route handlers duplicated the Vite dev asset rewriting, analytics config assembly and html template rendering. Move them into src/server/spaHtml.ts; the desktop umami block becomes an opt-in flag only the main SPA enables. * 🐛 fix(auth-spa): bundle default locale resources and disable i18n suspense to fix signin mount loop * ✨ feat(auth-spa): wrap auth shell with BusinessAuthProvider slot * 👷 build(spa): support custom vite dev origin and mark SPA entries side-effectful * 🔥 chore: drop dead /welcome entry from nextjsOnlyRoutes * 🐛 fix(auth-spa): forward referral to signup and fix error boundary dark-mode contrast * ♻️ refactor(spa): lift NextThemeProvider above RouterProvider so route error boundaries are theme-aware * update |
||
|
|
35b6bc55b8 |
🐛 fix: workspace error (#15701)
feat: support workspace (page author, copyTo/transferTo, notifications, i18n & fixes) Squashed 13 commits from fix/workspace-error for clean rebase onto main's submodule base. |
||
|
|
365dd1ff64 |
⚡️ perf(build): remove sitemap generation to cut static export time (#15702)
* ⚡️ perf(build): remove sitemap generation to cut static export time
The sitemap accounted for 772 of 827 prerendered pages, each fetching
marketplace data at build time. Static generation drops from 28.2s to
0.3s and total next build from ~59s to ~32s.
* Redirect legacy sitemap URLs to the landing site
* Redirect sitemap index to landing sitemap
|
||
|
|
5dfb6fc288 |
chore: clean [LOBE-XXX] code annotations (2026-06-10) (#15623)
chore: clean up [LOBE-XXX] code annotations (2026-06-10) Remove LOBE-XXX markers from comments and URLs across 7 files: - apps/cli/hetero.ts & hetero.test.ts: Remove LOBE-10157 markers, keep context - apps/server/ModelRuntime: Remove LOBE-10056, keep PK migration note - packages/database/rbac.ts: Remove LOBE-9193, keep API doc - scripts/codemodWorkspaceNav.ts: Remove LOBE-9024 from description - parse.ts & parse.test.ts: Replace LOBE-10141/LOBE-123 with generic IDs Co-authored-by: lobehub-bot <lobehub-bot@users.noreply.github.com> |
||
|
|
a5f16c1184 | 🐛 fix: import button from ui root (#15599) | ||
|
|
1a4005c7b9 |
♻️ refactor: extract server into apps/server + root namespaces into packages (#14949)
* ♻️ refactor(server-deps): extract envs/trpc/config/locales/business-server into packages * ♻️ refactor: relocate src/server backend modules to apps/server package Rebuilt on current canary: git mv the 8 server subtrees (services, routers, modules, globalConfig, utils, runtimeConfig, workflows, featureFlags) into @lobechat/server, with @/server/* dual-path alias, database vitest aliases, and instrumentation import fixup. * 📝 docs(skills): update src/server path refs to apps/server/src after relocation |
||
|
|
ccb33fa48c |
✨ feat: workspace backend service slice (#15560)
Backend-only slice of the workspace feature (server routers/services, database models with workspaceId threading, openapi middleware, business/server stubs, const/types). Excludes all UI (features/routes/store/hooks). Deploys dark behind the workspace feature flag. Includes open-source stub fixes: workspaceCreds router stub, ChargeParams workspaceId, usage.ts null-coalesce, DBMessageItem.workspaceId. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
25635ddb38 |
✨ feat(task): auto-ensure qstash schedule for task system (#14771)
* ✨ feat(task): auto-ensure qstash schedule
chore: cleanup code
chore: cleanup code
chore: cleanup code
* chore: migrate qstash init workflow to startServer
chore: migrate qstash init workflow to startServer
* fix: set default QSTASH_URL to eu region, same as SDK
fix: set default QSTASH_URL to eu region, same as SDK
|
||
|
|
42487663b9 |
🐛 fix(scripts): kill dev child processes on parent shutdown (#15246)
Detach next/vite children into their own process group so process.kill(-pid) reaps the whole tree (npm -> vite, etc.). Forward SIGHUP, escalate to SIGKILL after a timeout, and add uncaughtException / 'exit' fallbacks to avoid leaving orphan processes when the dev startup script is killed. |
||
|
|
ddb5794826 |
chore: clean up LOBE-XXX code annotations (#15135)
* chore: clean up LOBE-XXX annotations from codebase comments - Remove 【LOBE-XXX】 bracket markers - Remove LOBE-XXXX references from inline comments - Clean up test descriptions containing LOBE identifiers - Preserve linear.app URLs and code-level regex patterns - Generated: 2026-05-23 02:30:09 * 🐛 fix(tests): restore () in arrow callbacks broken by annotation cleanup The LOBE-XXX annotation cleanup script over-matched `(LOBE-XXXX', () =>` and stripped the callback `()`, leaving invalid syntax like `describe(..., => {` and `it(..., async => {` across 24 test files. This caused parse failures in Test Packages, Test Desktop App, Test Database lint, and Test App shard runs. Restoring `()` / `async ()` unblocks the suites while keeping the ticket-text cleanup intact. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 🐛 fix(hintFormat-test): restore label + ellipsis in stripMarkdownLinks fixture The annotation cleanup stripped `LOBE-8516` from a markdown-link's *label* (`[LOBE-8516](/task/T-1)` → `[](/task/T-1)`), which then survived `stripMarkdownLinks` because the pattern requires non-empty link text — the test expected the link to disappear and asserted equality on a LOBE-free output. The same line also lost a `.` from the trailing `...` indicator in both input and expected strings. Substitute a neutral Chinese label (`发布计划`) so the link continues to exercise the multi-link substitution path, and restore the full `...` ellipsis. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Arvin Xu <arvinxx@lobehub.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
0911c2a94c |
♻️ refactor: load models through model bank slot (#14877)
* ♻️ refactor: load models through model bank slot * ♻️ refactor: remove static LobeHub model cards * ♻️ refactor: share OpenAI image parameters * 🐛 fix: load async LobeHub model config in server paths * 🐛 fix: repair model bank CI follow-ups * 🐛 fix: avoid repeated model bank fallback loads * 🐛 fix: resolve business model config import in browser * 🐛 fix: align Nano Banana 2 resolution default * ♻️ refactor: move model loader slot under client * ✅ test: move model bank aiModels spec out of build entries * 🐛 fix: use business model config for mixed provider parsing * ♻️ refactor: consolidate model bank provider utilities * 🐛 fix: preserve Nano Banana 2 raw resolution * 🐛 fix: avoid generated locale sync for raw resolution * 🌐 style: add Nano Banana 2 resolution locales * 🌐 style: add online LobeHub model locales * 🐛 fix: guard optional model provider loaders * 🐛 fix: prevent sitemap build from hanging * 🐛 fix: clear sitemap timeout after model load |
||
|
|
67cd059340 | 🔨 chore: replace husky with native git hooks (#14941) | ||
|
|
7b61b9526f | ✨ feat: align self-iteration builtin tool with shared runtime and inspector patterns (#14827) | ||
|
|
4ebd8f7f7c |
♻️ refactor(onboarding): extract language and privacy as shared prefix steps (#14538)
* ♻️ refactor(onboarding): extract language and privacy as shared prefix steps Move the language-selection and privacy/telemetry consent out of the classic flow into a shared prefix that runs at /onboarding before branching into either the agent or classic experience. Welcome decoration is merged with language selection on a single screen, dropping the total step count by one. Shared-prefix completion is derived from raw stored settings (s.settings.general.responseLanguage and telemetry), so no new schema fields are introduced and existing consumers that rely on the merged-default telemetry value are unaffected. Branch routing remains automatic (feature flag + isDesktop check) and is now encapsulated in deriveOnboardingBranchPath. Both branch routes guard against entering before the shared prefix is complete. MAX_ONBOARDING_STEPS drops from 5 to 3 (FullName, Interests, ProSettings). * ♻️ refactor(onboarding): use original Telemetry + ResponseLanguage as shared steps Revert the merged welcome+language design. The shared prefix now reuses the original two classic steps as-is: - Step 1: TelemetryStep (welcome decoration + privacy/telemetry consent) - Step 2: ResponseLanguageStep (language selection) Also suppress the mode-switch + skip footer on the bare /onboarding path so it only appears once the user has entered the agent or classic branch. * 🐛 fix(onboarding): persist shared-prefix step in URL to survive locale-triggered remounts Use react-router's useSearchParams to keep the active shared step in the URL (?step=2). Local useState was lost when switching language for the first time because i18next's first-time resource load triggers a remount up the tree; the URL param survives any remount. * 🐛 fix(onboarding): unblock branch redirect when user accepts default telemetry Derive commonStepsCompleted from responseLanguage alone. setSettings strips fields whose value matches DEFAULT_COMMON_SETTINGS, so accepting the default telemetry: true left s.settings.general.telemetry undefined and the derive selector never flipped to true — the redirect to the branch never fired. Step 2 (language) implies step 1 was completed because the flow is sequential, so checking responseLanguage alone is sufficient and robust against the default-strip behavior. * 🐛 fix(onboarding): redirect after step 2 by deriving completion from responseLanguage only setSettings strips fields that match defaultSettings, so writing telemetry=true (the default) never persists to s.settings.general. That made commonStepsCompleted permanently false even after the user finished both steps, blocking the redirect to the branch flow. Drop telemetry from the derive check. Step 1 completion is already tracked via the URL ?step=2 marker; step 2 completion is the only event that needs to flip commonStepsCompleted, signalled by writing responseLanguage (which always differs from the default since DEFAULT_COMMON_SETTINGS has no responseLanguage entry). * 🔨 chore(scripts): add reset-onboarding script for redoing the flow Takes an email, clears users.onboarding, agent_onboarding, full_name, interests and removes responseLanguage + telemetry from user_settings.general so the user re-enters the shared-prefix onboarding from step 1. Usage: pnpm workflow:reset-onboarding <email> bunx tsx scripts/resetOnboarding/index.ts <email> * 🐛 fix(signup): add refs for email and password inputs to improve focus handling Signed-off-by: Innei <tukon479@gmail.com> * 🐛 fix(onboarding): skip responseLanguage auto-fill while onboarding is in progress useInitUserState's onSuccess callback auto-fills general.responseLanguage from navigator.language whenever the field is missing. For new users this fired immediately after signup, which made commonStepsCompleted (which derives from responseLanguage being set) flip to true on first load, and CommonOnboardingPage's early-redirect skipped past the shared prefix straight into /onboarding/agent. Gate the auto-fill on onboarding.finishedAt or agentOnboarding.finishedAt being set, so legacy users who finished onboarding without responseLanguage still get the safety-net detection, but in-progress users keep the field undefined until they explicitly choose it on the language step. * 🐛 fix(onboarding): refresh welcome message locale until conversation starts ensureWelcomeMessage previously only created the welcome on first call and skipped on subsequent ones, leaving stale welcomes locked to the locale that was active when the topic was first created. After the shared-prefix refactor users pick their language earlier than they used to, so the welcome that was generated during the auto-detect phase never gets re-translated. Now the welcome content is rewritten in-place to match the current responseLanguage as long as no user reply has been recorded yet (message count <= 1). Once the conversation has started, the welcome is left as part of the chat history. * 🐛 fix(onboarding): update welcome message handling to render client-side and avoid persisting during onboarding Signed-off-by: Innei <tukon479@gmail.com> * Refactor onboarding user profile handling: remove responseLanguage field - Removed responseLanguage from SaveUserQuestionInput and related schemas. - Updated onboarding logic to no longer save or request responseLanguage. - Adjusted related components and services to reflect the removal of responseLanguage. - Enhanced user info handling to include displayName and fullName from OAuth. - Updated tests to align with the new onboarding structure. Signed-off-by: Innei <tukon479@gmail.com> * refactor(onboarding): update locale handling to use i18n's resolved language Signed-off-by: Innei <tukon479@gmail.com> * 🐛 fix(onboarding): remap legacy 5-step classic currentStep on shared-prefix mount Mid-flow legacy users with persisted currentStep authored under the old 5-step classic flow (Telemetry, FullName, Interests, Language, ProSettings) would silently skip required profile steps after the renumbering: old step 2 (FullName) rendered Interests, old step 3 (Interests) rendered ProSettings. Apply a one-time remap (2->1, 3->2, >=4->MAX) when Common mounts, gated by isUserStateInit and onboarding.finishedAt absence so it fires only for in-flight legacy users. Idempotent for new-schema values. * refactor(onboarding): implement AGENT_ONBOARDING_ENABLED master switch for onboarding flow Signed-off-by: Innei <tukon479@gmail.com> * refactor(onboarding): standardize AGENT_ONBOARDING_ENABLED naming in tests Signed-off-by: Innei <tukon479@gmail.com> --------- Signed-off-by: Innei <tukon479@gmail.com> |
||
|
|
70e7e441b2 |
🔨 chore: premerge Task detail page UI (#13653)
* ✨ feat: add AgentTaskList component on agent welcome page (LOBE-6597) - AgentTaskList with TaskListHeader, TaskItem, and styles - Embedded in AgentWelcome below ToolAuthAlert - Each task rendered as independent rounded card with status badge - Status: green filled circle (Done), blue circle (In progress) - Card width matches chat input (960px) - i18n keys for taskList.title and taskList.viewAll - Fix updateReview type to use TRPC-inferred type Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ✨ feat: add Tasks page at /agent/:aid/tasks with route, breadcrumb, and view toggle (LOBE-6597) - Register tasks route in both desktopRouter.config.tsx and .desktop.tsx - Thin route page at src/routes/(main)/agent/tasks/index.tsx - Feature components in src/features/AgentTasks/: page, breadcrumb, header with list/kanban toggle, full task list - Wire up "View All Tasks" navigation from AgentTaskList welcome card - Add i18n keys (taskList.activeTasks, taskList.breadcrumb.task) and generate translations via pnpm i18n Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ✨ feat: add Task detail page at /agent/:aid/tasks/:taskId (LOBE-6597) - Register :taskId child route in both desktopRouter configs - TaskDetailPage with auto-save hint, breadcrumb, and scrollable content - TaskDetailHeader: editable title (borderless Input), Run/Pause button, status/priority tags, delete - TaskInstruction: click-to-edit Markdown with debounced auto-save - TaskSubtasks: sub-issues list with status badges - TaskActivities: timeline with topic/brief/comment icons - TaskItem now navigates to detail page instead of just setting activeTaskId - Add taskDetail.* i18n keys with generated translations Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ✨ feat: add TaskModelConfig, TaskScheduleConfig, and refine Task detail UI (LOBE-6597) Add model/provider selector and periodic execution config to Task detail page. Refine TaskDetailHeader, TaskInstruction with auto-save and i18n support. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ✨ feat: refine Task detail UI with Linear-style design (LOBE-6597) - Redesign SubTasks with collapsible header, progress circle, hover + click navigation - Redesign Activities with agent avatar, comment input box, and Linear-style layout - Add TaskParentBar showing parent task relationship with sibling navigation popover - Add delete confirmation modal using App.useApp().modal.confirm - Move ModelSelect to separate row below action bar - Fix zustand selector recreation in ActivityItem - Replace hardcoded colors with cssVar tokens Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ✨ feat: add Properties panel, parent link hover, activity icon, and lifecycle save status (LOBE-6597) - Add TaskProperties sidebar with collapsible status/priority dropdowns - Parent bar: clickable parent link with hover, sibling navigation popover on progress - Activity title: add BotMessageSquare icon - Fix lifecycle actions not updating taskSaveStatus (saving/saved indicator) - Filter status dropdown to only user-selectable states (backlog/completed/canceled) - Add test task creation script for dev Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ✨ feat: add recursive tree view for subtasks with Linear-style connecting lines (LOBE-6597) - Add buildTaskTree utility to convert flat getTaskTree API response into nested tree - Implement SubtaskTreeItem recursive component with CSS connecting lines (├─ and └─) - Fetch full task tree via taskService.getTaskTree for nested subtask display - Show loading spinner during tree fetch, fallback to flat list on error - Remove padding-inline from AgentTaskList container Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * 🐛 fix: address PR review — delete redirect, debounce cleanup, schedule resync (LOBE-6597) - Redirect to task list after successful delete (P1) - Clean up instruction debounce timer on unmount/task switch to prevent stale writes (P1) - Resync TaskScheduleConfig local state when active task changes (P2) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ♻️ refactor: use backend nested subtasks directly, remove buildTaskTree (LOBE-6597) Backend now returns nested subtasks in task.detail (LOBE-6814). Remove buildTaskTree utility, getTaskTree API call, and loading state. Use TaskDetailSubtask from @lobechat/types instead of local interface. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ⚡ perf: add optimistic update and save status for model config change (LOBE-6597) updateTaskModelConfig now immediately reflects new model/provider in UI via optimistic store dispatch, and tracks taskSaveStatus (saving/saved). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ⚡ perf: skip redundant refreshTaskDetail on successful model config update (LOBE-6597) Optimistic update is trusted on success — no need for full detail re-fetch. Aligns with updateTask pattern. Refresh kept only in error path for revert. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ✨ feat: use backend author info for activities, fix AgentTaskList after AgentHome refactor (LOBE-6597) - Activity: use act.author (TaskDetailActivityAuthor) from backend instead of agentMap lookup (LOBE-7013) - AgentTaskList: fix agentId from useParams instead of useAgentStore.activeAgentId (was undefined) - AgentHome: integrate AgentTaskList into new AgentHome layout (replaces old AgentWelcome) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ✨ feat: show participant avatars on task cards, use backend author for activities (LOBE-6597) - TaskItem: display up to 3 participant avatars next to task title (LOBE-6805) - Activity: use act.author from backend instead of agentMap lookup (LOBE-7013) - AgentHome: integrate AgentTaskList into new AgentHome layout - Revert AgentTaskList/TaskItem agentId back to useAgentStore (works correctly when mounted) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ♻️ refactor: fix type safety, memoize participants filter, extract avatar styles (LOBE-6597) - Use TaskParticipant type instead of `any` in filter/map - Compute displayParticipants once with useMemo (was filtering twice per render) - Move avatar overlap styles to CSS classes (was inline objects per render) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * 🔇 chore: hide kanban view toggle until implemented (LOBE-6597) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ♻️ refactor: export TaskStatus/TaskPriority/TaskActivityType from @lobechat/types (LOBE-6597) Replace hardcoded string/number types with shared type aliases: - TaskStatus: 'backlog' | 'canceled' | 'completed' | 'failed' | 'paused' | 'running' - TaskPriority: 0 | 1 | 2 | 3 | 4 - TaskActivityType: 'brief' | 'comment' | 'topic' Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * style: update * style: update * style: update * style: update * style: update * style: update * style: update * style: update * style: update * style: update * ✨ feat: add Daily Brief module to homepage (#13851) * ✨ feat: add Daily Brief module to homepage Add a Daily Brief section below the chat input on the homepage that displays unresolved briefs from the Agent Tasks system. Users can resolve, comment, and provide feedback directly from the brief cards. - Service: BriefService with listUnresolved, resolve, markRead, addComment - Store: Independent Zustand store (src/store/brief/) with SWR data fetching - Components: BriefCard, BriefCardActions (dynamic action buttons), BriefCardSummary (Markdown with expand/collapse), CommentInput (@lobehub/editor) - Three action types: resolve (closes brief), comment (resolve with text), link (safe URL navigation with protocol validation) - Fixed feedback button: adds task comment without resolving the brief - Inline success state ("Feedback sent") with 1.5s auto-restore - i18n: zh-CN + en-US translations - Tests: 21 tests across service, store selectors, and components - CLI: Register task and brief commands for local development Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ✨ feat: add agent avatars to Daily Brief cards Display stacked agent avatars next to brief card titles using the new `agents` data from Arvin's enriched listUnresolved API (#13489). - Add AgentAvatarInfo type and agents field to BriefItem - Render overlapping circular avatars (20px, -6px overlap) - Use cssVar.colorBgContainer for border (dark mode compatible) - Extract avatar style to function to avoid inline object creation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ♻️ refactor: clean up Daily Brief components - Extract duplicate success state JSX into reusable SuccessTag component - Remove redundant comments that describe what code does - Use DEFAULT_AVATAR from @lobechat/const instead of hardcoded emoji Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * 🐛 fix: address PR review feedback for Daily Brief - Use cssVar.colorBgBase instead of hardcoded #fff for primary button text color (dark mode contrast fix) - Add submitting state to CommentInput to prevent duplicate submissions (disable buttons + show loading during async submit) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * 🌐 chore: generate i18n translations for Daily Brief Run pnpm i18n to generate translations for all 18 locales. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ♻️ refactor: use shared BriefType from @lobechat/types Export BriefType union from packages/types and use it in BRIEF_TYPE_COLOR and BRIEF_TYPE_ICON records for compile-time key validation. Adding a new brief type now requires updating the shared type, and TypeScript will flag missing mappings. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * style: update * style: update * style: update --------- Co-authored-by: Tsuki <976499226@qq.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * style: update * style: update * style: update * style: update * fix: stopPropagation * fix: i18n * 🐛 fix: wire comment inputs to editor instance so Send actually submits CommentInput in AgentTasks and DailyBrief used antd TextArea inside @lobehub/editor's ChatInput while reading content via editor.getDocument('markdown'). The TextArea was never connected to the editor instance, so getDocument always returned empty and handleSubmit short-circuited silently — Send appeared to do nothing (no network request fired). Replace the TextArea with <Editor editor={editor} type="text" variant="chat" /> so useEditor() actually drives the editable surface. Keep plain-text behavior via markdownOption={false} + enablePasteMarkdown={false}, and bind Cmd/Ctrl+Enter submit via onPressEnter. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * 🐛 fix: use participant.title after TaskParticipant schema rename (#13877) PR #13877 renamed TaskParticipant.name → .title and added .backgroundColor. Our branch's UI code (AgentAvatars, listViewOptions, TaskList group header, Breadcrumb) was already written against the new schema, but TaskProperties still read firstParticipant?.name — update the last remaining call site so the type matches post-rebase. backgroundColor is already plumbed through everywhere it applies within #13877's scope; TaskActivities' TaskDetailActivityAuthor is a separate type untouched by the PR and kept as-is. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * 🐛 fix: resolve type-check errors exposed after canary rebase canary upgraded react-i18next to a version with typed i18n keys and tightened @lobehub/editor's SendButton + IEditor APIs. Rebase pulled these in, surfacing latent type errors in LOBE-6597 code. - CommentInput: use editor.cleanDocument() (IEditor's actual API; clearContent never existed). - TaskActivities / TaskLatestActivity / TaskTriggerTag: type t as TFunction<'chat'> so typed i18n accepts the known-literal keys used inside module-level helpers. - TaskPriorityTag / TaskStatusTag / listViewOptions: add defaultValue: '' to dynamic-key t() calls (template literals and Record lookups) to match the broad-key i18n overload. - BriefCardActions: swap unusable <SendButton> (no children, no iconPlacement) for <Button>; add defaultValue to the dynamic brief-action key lookup; drop stale @ts-ignore. - DailyBrief/CommentInput: drop unsupported children on SendButton; keep label via title attribute. - Recents/Item: type TYPE_ICON_MAP as Partial<Record<...>> so 'task' (rendered via TaskStatusIcon elsewhere) is a safe absent key. - brief/slices/list/action: cast briefService.listUnresolved() result back to BriefItem[] (TRPC serialization widens BriefType to string). - AgentTasks/TasksHeader: delete dead file — no importers and its ./style module was removed by an earlier refactor. Also ran pnpm install to materialize the newly-extracted @lobechat/agent-gateway-client workspace package (canary #13866), clearing ~7 "cannot find module" errors. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ♻️ refactor(builtin-tool-task): polish task tool paths (#13869) * ✨ feat: navigate to task detail when clicking brief card header Clicking the header row of a Daily Brief card (icon + title + time + agent avatars) now jumps straight to the associated task, using the brief's task-tree agent (with activeAgent / inbox as fallback). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ✨ feat: show parent task ids as clickable breadcrumb trail Walk the cached parent chain from taskDetailMap and insert each ancestor's identifier as a link between the "任务" entry and the current task name in the task detail breadcrumb. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ✨ feat: add cross-agent /tasks page with View All Tasks on Daily Brief - Register `/tasks` route in desktop (web + Electron) and mobile router configs - `useFetchTaskList` supports `allAgents` mode via options object API to fetch tasks without agent filter; backend already supports optional assigneeAgentId - `Breadcrumb` accepts optional `agentId`, renders "All tasks" crumb when absent - `AgentTaskItem` navigation uses `task.assigneeAgentId` so clicks work from the cross-agent page (falls back to `activeAgentId` for unassigned tasks) - Extract `useScenarioEnabledTools` hook to share layout effect between `/tasks/_layout` and `/agent/:aid/tasks/_layout` Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ♻️ refactor: use assigneeAgentId for task avatar instead of participants array Replace AgentAvatars (took participants[]) with AssigneeAvatar (takes agentId, resolves meta from agent store). This correctly represents that a task is assigned to a single agent via assigneeAgentId/detail.agentId. - New AssigneeAvatar component reads agent meta from agent store by ID - TaskProperties reads activeTaskAgentId from task detail store - listViewOptions uses task.assigneeAgentId directly for groupBy/sort - Extract shared isInboxAgentId helper to eliminate 4x inline duplication - Group headers resolve agent title at render time via AssigneeLabel component Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * 🐛 fix: enable vertical scrolling on cross-agent tasks page Add overflowY and flex to WideScreenContainer wrapper so the task list can scroll when content exceeds viewport height. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ✨ feat: add re-assign task agent with popover selector - Add AssigneeAgentSelector component with Popover agent list - Extract useAgentDisplayMeta hook for consistent agent name/avatar resolution - Fix optimistic update mapping assigneeAgentId → agentId in task store - Disable reassignment for running tasks with tooltip hint - Integrate selector into task list and task detail property panel Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ✨ feat: reuse BriefCard in task detail activities & fix raw-id navigation Render brief-type activities as full BriefCard (same as homepage) instead of plain tree rows. Decouple BriefCardActions from useBriefStore for actions lookup so it can be reused across pages. Fix infinite loading when navigating to task detail via raw DB id (task_xxx) by storing detail under both the identifier and the raw id key in taskDetailMap. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ✨ feat: add TopicCard component for task detail activities Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ✨ feat: allow re-running completed tasks with dedicated button Completed tasks now show a "Re-run" button (with rotate icon) instead of hiding the action. The backend already supported this — only the frontend selector gate needed updating. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ✨ feat: add create task modal with markdown editor Add a "+" button on the tasks list page that opens a Linear-style modal for manually creating tasks. The modal features a title input, a markdown editor (EditorCanvas), and a bottom toolbar with priority and assignee selectors. Existing tag components (TaskStatusTag, TaskPriorityTag, AssigneeAgentSelector) are extended with an `onChange` controlled mode so they can be used in creation context where no task exists yet. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * 🐛 fix: suppress spurious updateTask on Task Detail page load EditorDataMode was missing the contentChangeLockRef pattern that DocumentIdMode already uses, causing Lexical's registerUpdateListener to treat programmatic content hydration as a user edit and fire onContentChange → updateTask on every page visit. - Add contentChangeLockRef + lockIdRef staleness guard - Extract loadContentWithLock to deduplicate lock/load/unlock logic - Pass contentChangeLockRef to InternalEditor - Remove unreachable dead code in loadEditorContent Closes LOBE-7362 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * ✨ feat: task detail comment CRUD and various UX improvements Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 🐛 fix: move canceled status group to the end of task list Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 💄 style: polish task detail layout, title, and run button - Title switched to auto-sizing TextArea so long names wrap (like Linear) - Reduce title font-size from 32px to 24px and tighten paddings - Make "运行任务" button small-sized to match the denser header - Add 120px bottom padding for end-of-content scroll breathing room - Default EditorCanvas paddingBottom trimmed from 64 to 32 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 💄 style: refine task assignee, priority, and comment input - Assignee block uses filled variant in dark mode for better contrast - Urgent priority (level 1) renders in orange for quick scanning - Comment input keeps SendButton slot reserved to prevent layout shift Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ✨ feat: task detail — inline subtasks, automation mode, chronological activity - Inline subtask creation under a task via CreateTaskInlineEntry (parentTaskId/autoFocus/onCollapse/placeholder), refreshes parent on create - Track agent-created tasks via createdByAgentId through service, router, types, and the builtin task executor - Replace scheduler Segmented-only UI with an Enable switch + heartbeat/ schedule mode; persist via automationMode on the task - Sort detail activities oldest → newest for a natural timeline reading - Reducer patches nested subtask entries on updateTaskDetail so in-place edits reflect in the parent's subtask tree Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 💄 style: render activate-tool chips as rounded pills Switch inspector tool chips from monospace code tags to filled rounded pills with ellipsis overflow, making multi-tool rows scan better in tight headers. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 🐛 fix: keep finished tool call out of loading state while siblings run The message-level isAssistantMessageBusy flag stays true while sibling tool calls are still running. Without guarding on this tool's own result, a finished tool would flip back to "loading". Now a tool that has a real result or error is never shown as calling. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 💄 style: use small Segmented in schedule config popover Keeps the automation mode switcher visually aligned with the denser popover controls. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ✨ feat: agent profile hover card on task activity author - Extract shared AgentProfileCard + unified AgentProfilePopup (click / hover) with lazy agent fetch; move out of group sidebar path. - Wire activity author avatar + name to a hover card; brighten title on hover; keep a small "agent" tag on the author row. - Show inline skeletons (description + footer stats) while loading. - Enrich subtask payload with assignee agent info for cleaner UI. * ✨ feat: open task topic chat in side drawer Click a topic row in the task detail activities to open a right-side drawer showing the topic's full chat history. Messages stream in live via the existing agent gateway pipeline (gateway events land in chatStore.dbMessagesMap keyed by the topic context), so a running topic refreshes its drawer in real time without a dedicated subscription. Reuses the Conversation feature (ConversationProvider + ChatList) with an isolated context (agentId + topicId + isolatedTopic), so the drawer never touches the global active topic and multiple panels coexist cleanly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 💄 style: outline activate-tool chip with subtle border Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ✨ feat: show topic handoff summary on activity card Pull `handoff.summary` through the task service into TaskDetailActivity and render it under the title in TopicCard so completed topics surface what was accomplished without opening the drawer. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 🎸 chore: gate agent task feature behind agent_task flag Hide every client-side entry point to the Agent Task feature when the `agent_task` flag (default `isDev`, off in prod) is disabled: - Sidebar: task tab in the agent sidebar nav - Routes: `/agent/:aid/tasks/*` and `/tasks/*` layouts redirect to `/` when the flag is off (mobile router reuses the same layout) - Home Recents: filter out `type='task'` items in both the list and the "all recents" drawer - Daily Brief: skip fetch + hide the entire panel (all briefs link to tasks) Backend TRPC / lifecycle stays on — the feature is already live for CLI usage. Flag name mirrors `agent_onboarding` for consistency. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * 🐛 fix: prioritize includeTriggers in topic queries * 🐛 fix: normalize task detail activity payloads * ✨ feat: add Kanban board view for task list with drag-and-drop LOBE-7493 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * 💄 style: shorten schedule tag labels & fix time width in task cards Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * update i18n * 💄 style: hide task tool from user selectors * 💄 style: hide task skill from user selectors --------- Co-authored-by: canisminor1990 <i@canisminor.cc> Co-authored-by: YuTengjing <ytj2713151713@gmail.com> Co-authored-by: Arvin Xu <arvinx@foxmail.com> |
||
|
|
31d76ccb90 |
⬆️ chore: upgrade Vite to 8.0.0 (#12720)
* ⬆️ chore(vite): migrate SPA build pipeline to Vite 8 * 🔧 chore(vite): patch inspector tooling and stabilize rolldown output * 🐛 fix(vite): apply Vite 8 follow-up fixes and dev proxy polish * 🩹 chore(vite): drop oversized code-inspector core patch * 🐛 fix(desktop): support vite 8 electron build * 🐛 fix(desktop): declare mac permissions types ambiently * 🐛 fix(desktop): externalize mac permissions in main build |
||
|
|
f804d0fc7c |
🌐 chore: translate non-English comments to English in scripts (#13690)
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
f6314cc673 |
♻️ refactor: serve Vite SPA static assets under /_spa (#13409)
Made-with: Cursor |
||
|
|
53c5708c9f |
🔨 chore: improve start up scripts (#13318)
update scripts |
||
|
|
dd192eda3e |
✨ feat: bot support custom markdown render and context injection (#13294)
* feat: support bot mardown format * feat: support custom markdownRender and bot context inject * feat: support custom PORT * feat: telegram support html render * feat: slack support markdown render * chore: feishu and lark don't handle markdown for now |
||
|
|
c087134953 |
✨ feat(desktop): unify canary with stable app name/icon, add channel tag in About (#12881)
- Use same app name (LobeHub) and icon as stable for canary builds - Add build channel tag in Settings > About for non-stable channels (Canary, Nightly, Beta) - Add getBuildChannel IPC to expose build-time channel for display Made-with: Cursor |
||
|
|
0dd0d11731 |
👷 build(ci): fix changelog auto-generation in release workflow (#12763)
After auto-tag-release.yml was introduced, semantic-release in release.yml stopped working because the tag already exists when it runs. This caused CHANGELOG.md to never be updated. Fix: move changelog generation into auto-tag-release.yml with a custom script that parses git log and generates gitmoji-formatted entries, matching the existing CHANGELOG.md format. Remove the broken semantic-release step from release.yml. |
||
|
|
9cb0560ebf |
✨ feat(desktop): unified update channel switching with S3 distribution (#12644)
* ✨ feat(desktop): add update channel settings for desktop app * 🔧 chore(desktop): update test scripts for multi-channel update flow - Support stable/nightly/canary channel structure in generate-manifest.sh - Add --all-channels flag for generating manifests across all channels - Dual-mode run-test.sh: packaged (full updater) and --dev (UI only) - Fix package:mac:local to skip signing for local builds - Document Squirrel.Mac signature validation limitation * 🔧 chore(desktop): update local app update configuration - Change provider from GitHub to Generic for local testing. - Update local server URL and cache directory settings. - Revise comments for clarity on usage and configuration. Signed-off-by: Innei <tukon479@gmail.com> * 🐛 fix(desktop): fix update channel switch race condition and downgrade flag - P1: Use generation counter to discard stale check results when channel is switched mid-flight. Pending recheck is scheduled after current check completes instead of forcing concurrent checks. - P2: Explicitly reset allowDowngrade=false on non-downgrade transitions to prevent stale downgrade permission from persisting. - Fix GitHub fallback repo name (lobe-chat -> lobehub). * 🔧 chore(settings): remove dynamic import for Beta component from componentMap - Eliminated the dynamic import for the Beta settings tab, streamlining the component map. Signed-off-by: Innei <tukon479@gmail.com> * 🔧 chore(settings): simplify UpdateChannel component structure - Refactored the UpdateChannel component to streamline the Select component usage by removing unnecessary nested children. Signed-off-by: Innei <tukon479@gmail.com> * update * 🐛 fix(desktop): strip channel suffix from UPDATE_SERVER_URL before appending channel The UPDATE_SERVER_URL secret may already contain a channel path (e.g., /stable). Previously, the code unconditionally appended /{channel}, resulting in double paths like /stable/stable/stable-mac.yml. Now both electron-builder.mjs and UpdaterManager strip any trailing channel suffix before re-appending the correct channel, supporting both legacy URLs (with channel) and clean base URLs. * update * update * redesign ui - Added `getUpdaterState` method to `UpdaterManager` for retrieving current update status. - Introduced `UpdaterState` type to encapsulate update progress, stage, and error messages. - Updated UI components to reflect update states, including checking, downloading, and latest version notifications. - Enhanced menu items for macOS and Windows to display appropriate update statuses. - Localized new update messages in English and Chinese. This improves user experience by providing real-time feedback during the update process. Signed-off-by: Innei <tukon479@gmail.com> * Enhance UpdaterManager tests and mock implementations - Updated tests for UpdaterManager to reflect changes in broadcasting update states, including 'checking', 'downloading', and 'error' stages. - Modified mock implementations in macOS and Windows test files to include `getUpdaterState` and `installNow` methods for better state management. - Improved test coverage for update availability and download processes. These changes ensure more accurate testing of the update flow and enhance the overall reliability of the UpdaterManager functionality. Signed-off-by: Innei <tukon479@gmail.com> --------- Signed-off-by: Innei <tukon479@gmail.com> |
||
|
|
1cf0257326 |
fix: scripts support win32 (#12613)
Co-authored-by: Innei <tukon479@gmail.com> |
||
|
|
d68acec58e |
✨ feat: support Discord IM bot intergration (#12517)
* clean fix tools calling results improve display support discord bot finish bot integration * improve next config * support queue callback mode * support queue callback mode * improve error * fix build * support serverless gateway * support serverless gateway * support serverless enable * improve ui * improve ui * add credentials config * improve and refactor data working * update config * fix integration * fix types * fix types * fix types * fix types * move files * fix update * fix update * fix update |