Commit Graph

37 Commits

Author SHA1 Message Date
Innei 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
2026-09-12 21:54:05 +08:00
Innei 2933b9fcc5 ⚡️ perf(desktop): show the main window on first paint, compile cache, dev progress (#19429)
* ⚡️ perf(desktop): show the main window on the loading screen's first paint

`ready-to-show` only fires with the `load` event for the desktop entry, which
lands ~250ms after the static loading screen has actually painted. The preload
now reports that first paint (double rAF after `#loading-screen` enters the
DOM) and the main process shows the window on whichever signal arrives first.

Measured on the packaged app (warm start, window creation = 0): window visible
at +140ms instead of +370ms, with the loading screen already painted.

Claude-Session: https://claude.ai/code/session_012z4cpfrWDXZDtNgT4uJKoS

* ⚡️ perf(desktop): enable the V8 compile cache for the main process bundle

Injected as an entry banner because rolldown hoists chunk requires above any
statement in the entry source, so `main-app` would otherwise load uncached.
Main bundle load 55ms → 37ms warm; exec → main.js ~10ms faster on a
packaged build.

Claude-Session: https://claude.ai/code/session_012z4cpfrWDXZDtNgT4uJKoS

* ✨ feat(desktop): show Vite transform progress on the dev loading screens

A cold `bun run dev` sits on the loading logo for 10s+ while Vite transforms
thousands of modules. A serve-only plugin streams the transform count and the
current file over the HMR socket, and an injected client renders it at the
bottom of the window for as long as any boot placeholder (`#loading-screen`,
`#boot-shell`, `#app-shell-fallback`) is on screen.

Claude-Session: https://claude.ai/code/session_012z4cpfrWDXZDtNgT4uJKoS
2026-09-11 15:50:00 +08:00
Innei 6329f97e14 🐛 fix(vite): stop assuming node_modules sits at the repo root (#19325)
* 🐛 fix(vite): resolve the editor provider without assuming node_modules layout

GlobalProvider/Editor.tsx reached @lobehub/editor's provider through a
relative `../../../node_modules/...` path, which assumes node_modules sits at
the repo root. Business-overlay desktop builds mount this repo as the overlay
root's `lobehub/` submodule, so the install hoists to the parent directory and
the path does not exist — every desktop platform failed with UNRESOLVED_IMPORT.

The provider subpath is not in the package's export map, so it still cannot be
imported on its own; the dev-only resolver now runs in builds too and derives
the provider file from the resolved package entry, wherever it lives.

Claude-Session: https://claude.ai/code/session_01LNsSw6SDv3UEGNfBEwPa8S

* 🐛 fix(vite): resolve the @lobehub/ui barrel through the package

The barrel parser reached the package's `es` directory through
`../../../node_modules/@lobehub/ui/es`, which assumes node_modules sits at the
repo root — the same assumption that broke the desktop build. Business-overlay
share builds hoist the install above this checkout, where that path does not
exist and `realpathSync` throws before the plugin can load.

Resolving the package entry instead finds it wherever it is installed. The
plugin is not loaded on the desktop platform, so this never surfaced there.

Claude-Session: https://claude.ai/code/session_01LNsSw6SDv3UEGNfBEwPa8S

* ♻️ refactor(vite): take the editor provider entry @lobehub/editor now exports

@lobehub/editor 4.27.0 exports `./react/EditorProvider`, so the provider no
longer has to be reached by file path and the build-time resolver and its
ambient shim can go. The dev redirect stays: Vite prebundles the provider entry
separately from `@lobehub/editor/react`, which the editors use, and the app
would end up with two EditorContexts.

Claude-Session: https://claude.ai/code/session_01LNsSw6SDv3UEGNfBEwPa8S

* 🐛 fix(desktop): let pnpm find the business-const stub

pnpm does not match the `./stubs/business-const` workspace entry, so an OSS
install from apps/desktop fails to resolve `@lobechat/business-const` — the
package the stub exists to provide — and the desktop build cannot be run
locally at all. Cloud builds resolve the real package from the overlay, and
the renderer redirects the module to `@cloud/business-const` either way.

Claude-Session: https://claude.ai/code/session_01LNsSw6SDv3UEGNfBEwPa8S
2026-09-09 14:54:22 +08:00
Innei a5e74a9eb4 ⚡️ perf(spa): cut the editor runtime, ajv and database models from the boot path (#19294)
* ⚡️ perf(spa): cut the editor runtime, ajv and database models from the boot path

Four package-level import edges put ~1.5 MB raw on the first screen:

- GlobalProvider/Editor.tsx imported @lobehub/editor/react, and rolldown does
  not shake that entry down to EditorProvider, so lexical, yjs and fuse landed
  in the entry chunk. The provider is reached by path until the package
  exposes a provider-only entry.
- @lobechat/types re-exported the ajv-backed AgentGraphSchema through the
  barrel that every store touches; it now lives on the
  @lobechat/types/agent/graph subpath and the agent barrel re-exports types
  only.
- @lobechat/context-engine's root barrel dragged the database models barrel
  (drizzle) in through AgentDocumentInjector; the app reaches the
  ./agent-document subpath and the injector reads loadPolicy directly.
- packages/locales bundled locales/en-US/*.json on top of the default
  sources it mirrors; the overlay now applies only in development.

Web production build: first-screen gzip 2299 KB -> 1968 KB.

Claude-Session: https://claude.ai/code/session_01QKr8CsFLYmrgqbRTSipTNH

* 🐛 fix(vite): keep one EditorContext in dev for the path-imported provider

Claude-Session: https://claude.ai/code/session_01QKr8CsFLYmrgqbRTSipTNH

* 🐛 fix(locales): refresh consumers after the dev English overlay lands

Claude-Session: https://claude.ai/code/session_01QKr8CsFLYmrgqbRTSipTNH
2026-09-09 02:45:25 +08:00
Innei db663d7077 ⚡️ perf(spa): keep first-screen and lazy modules in separate chunks (#19288)
Every manual rolldown group gets a $initial-tagged variant so first-screen
modules never share a chunk with lazy ones, an app-initial catch-all folds
the rest of the entry's static graph into one chunk, and dependency capture
stops being recursive so lazy groups cannot drag first-screen modules into a
chunk the entry then has to preload.

Web production build: 71 eager chunks / 2299 KB gzip -> 10 / 2162 KB.

Claude-Session: https://claude.ai/code/session_01QKr8CsFLYmrgqbRTSipTNH
2026-09-09 00:32:32 +08:00
Innei ba3e528e4b 🐛 fix(vite): preserve precompiled style composition order (#19162)
* 🐛 fix(user-panel): make the popover padding override order-independent

`classNames.content` maps to the base-ui viewport, whose padding is set with
`padding-block` / `padding-inline` longhands. The shorthand `padding: 0` only
won because dev-mode module order inserted it last; production chunking flips
that and the 12px padding comes back.

Claude-Session: https://claude.ai/code/session_0136deq4gr2Pbe1cEYJHi1v8

* 🐛 fix(vite): preserve precompiled style composition order
2026-09-05 15:38:16 +08:00
Innei 94d06945e1 ⚡️ perf(vite): precompile pure createStaticStyles at build time (#19066)
Run pure cssVar/responsive createStaticStyles callbacks through antd-style
at build time and ship the stylis output as pre-split rules. The runtime
helper only calls sheet.insert and exposes a lazy `&`-form getter on
cache.registered so cx merging and `${styles.x}` composition keep emotion
semantics. Covers src/packages and @lobehub/ui dist; impure callbacks stay
on the runtime path. Legacy vendor prefixes are dropped except the -webkit-
ones Safari still needs.

Claude-Session: https://claude.ai/code/session_01LWpHcuigdH4EcPsNEKP6He
2026-09-04 20:23:06 +08:00
Innei 0877876478 ⚡️ perf(spa): fold first-screen @lobehub/ui members into vendor-ui-core (#19062)
Claude-Session: https://claude.ai/code/session_013sk2z4PpPbcLRMASm3DST3
2026-09-03 16:26:00 +08:00
Innei b03d467345 🐛 fix(vite): forward memberless @lobehub/ui barrel imports as a namespace (#19059)
Claude-Session: https://claude.ai/code/session_013sk2z4PpPbcLRMASm3DST3
2026-09-03 03:31:05 +08:00
Innei fabe719a18 ⚡️ perf(spa): gate the first-screen import graph and shrink it 41% (#19033)
* 👷 ci(perf): gate the first-screen static import graph

Total dist size cannot see a lazy chunk being pulled back into the entry's
sync graph. Walk static imports from each SPA entry, gzip the reachable
chunks, and fail a PR when the total grows past the threshold or a chunk
name that was lazy in the canary baseline now sits on the first-screen path.

Claude-Session: https://claude.ai/code/session_01C2wPWhzukH4pniaLy6vkhD

* ⚡️ perf(spa): keep heavy @lobehub/ui members out of the first-screen chunk

Rolldown assigns chunks by static reachability, so the @lobehub/ui barrel
promoted shiki, katex, elkjs, emoji-mart and @pierre/diffs into the entry
chunk as soon as any lazy route used Markdown, Mermaid or EmojiPicker.
Rewrite the ui barrels to deep imports (same approach as lobeIconImports),
stop the tool store from importing the Claude Code render registry, lazy-load
ProfileSetupModal and the error-page Highlighter, and add a boot-path lint
rule for the known heavy members. Desktop entry graph: 3.84 MB -> 2.26 MB gz.

Claude-Session: https://claude.ai/code/session_01C2wPWhzukH4pniaLy6vkhD

* 🐛 fix(vite): resolve bare barrel specifiers from the @lobehub/ui package itself

The virtual proxy re-exported `ErrorBoundary` from "react-error-boundary",
a dependency of @lobehub/ui that pnpm does not hoist to the app root, so the
auth build failed in CI. Resolve such specifiers with the barrel's real path
as the importer.

Claude-Session: https://claude.ai/code/session_01QP9qfw629JNyNeNCwizuHY

* 👷 ci(perf): run the size gates on feature-branch pushes too

skip-duplicate-actions cancels the pull_request run of same-repo PRs in favour
of the push run, and the push run skipped every gate step, so neither the web
dist gate nor the entry-graph gate ever checked a same-repo PR. Gate on a
SIZE_GATE_ENABLED flag that is true for PRs and for pushes to non-release
branches, and resolve the PR number from the commit when commenting.

Claude-Session: https://claude.ai/code/session_01QP9qfw629JNyNeNCwizuHY
2026-09-02 20:54:05 +08:00
LiJian c5caffe684 💄 style: brand the loading screen and LobeHub provider card via the business slot (#18638)
* ✨ feat: brand the static loading screen for custom-branding deployments

The SPA entry html hardcodes the LobeHub wordmark SVG in #loading-brand,
so white-label deployments flash the LobeHub logo before the bundle
boots. Add a transformIndexHtml plugin that swaps it for BRANDING_NAME
(from the business-const slot) when custom branding is active; no-op for
default branding.

* 🐛 fix: expose dependency-free ./branding subpath for config-time imports

Importing the business-const package root from vite.config context fails
under Node's type-stripping loader (the barrel uses extensionless
relative imports). Expose branding.ts — a dependency-free leaf — as a
'./branding' subpath and deep-import it from the loading-screen plugin.
branding.ts must stay import-free for this to keep working.

* 💄 style: brand the LobeHub provider card via the business branding slot

Custom-branding distributions (BRANDING_NAME override) get their own
provider display name and drop the LobeHub marketing copy/links; OSS and
cloud keep the exact previous card.

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

* 🐛 fix: address codex review on the branding slot PR

- Import BRANDING_NAME from the business-const package root instead of
  the ./branding subpath in modelProviders/lobehub.ts: this file runs at
  normal app runtime, not vite-config time, so it never needed the
  dependency-free leaf — and the root export is what every override
  (including apps/desktop/stubs/business-const) already provides, so no
  companion change is needed there.
- Guard every `t(id.description, { defaultValue: description })` call
  against a falsy description before invoking t() at all, across Header,
  RelatedModels/Item, Related/Item, RelatedProviders/Item, ActionButton
  (share meta), and ProviderGrid/Card. Without the guard, a provider whose
  description was removed (LobeHub under custom branding) still displayed
  the old text for any locale whose already-translated providers.json
  hadn't been regenerated, since i18next only falls back to defaultValue
  when the key is missing, not when it's stale.
- Wire openSettings into ProviderConfig's fallback Button so the primary
  Config CTA still does something when both url and modelsUrl are empty
  (custom branding drops both) — it silently had no onClick before.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-24 15:43:18 +08:00
Innei 67058d0f96 ✨ feat(desktop): support macOS communication notifications with agent avatars (#18441)
* ✨ feat(desktop): support macOS communication notifications with agent avatars

* 🐛 fix(desktop): load mac notifications addon when wrapper is inlined into the main bundle

* ♻️ refactor(desktop): auto-discover first-party native addons via shared napi loader

* 👷 ci(desktop): prepare macOS provisioning profile in desktop build workflows

* 🐛 fix(desktop): timeout stalled avatars and bound notification cache

* 🐛 fix(desktop): resolve TS2454 in notification avatar cache eviction

* 🐛 fix(desktop): skip mac notification native rebuild on Windows

* ♻️ refactor(desktop): resolve mac NotificationCtr via os file overlay
2026-08-19 14:24:51 +08:00
AmAzing- 705df95283 🐛 fix(vite): dedupe editor context runtime (#18261) 2026-08-13 20:03:56 +08:00
YuTengjing d81495521a 🐛 fix: narrow Vite SPA watcher scope (#17693) 2026-07-29 15:36:35 +08:00
Innei 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
2026-07-29 15:00:26 +08:00
Innei dfbd8ae6ac ✨ feat: enable authorized runtime DevDock (#17652)
* ✨ feat: enable authorized runtime DevDock

* ✨ feat: require explicit DevDock unlock gesture

* 🐛 fix: scope DevDock access to selected workspaces

* ✨ feat: redesign DevDock bar with pinnable items and overflow menu

* 🐛 fix: always mount DevDock in dev builds

* 🐛 fix: reject boolean toggles on array-only feature flags

* 📝 docs: extend acceptance living log

* 🐛 fix: gate scroll-debug overlays by the DevDock mount rule

* 💄 style: hint the DevDock gesture cursor only for eligible users
2026-07-28 19:06:08 +08:00
YuTengjing fa7da885e5 ✨ feat(auth): confirm agreement before continuing (#17190)
* ✨ feat(auth): confirm agreement before continuing

* 🐛 fix(auth): keep agreement visible for social sign-in

* 💄 style(auth): open legal links in new tabs

* 💄 style(auth): show visited legal links

* 💄 style(auth): preserve agreement link underline

* 💄 style(auth): distinguish visited legal links

* 🐛 fix(auth): confirm agreement before social sign-in
2026-07-15 00:30:02 +08:00
Innei 40db39ac95 🔧 chore: gate react-scan behind REACT_SCAN env flag (#16847) 2026-07-07 21:48:47 +08:00
Innei f22185716a ⬆️ chore(deps): upgrade react-router to v8 (#16029)
- Bump react-router-dom 7.13 → react-router 8.0
- Codemod 'react-router-dom' → 'react-router' across 275 sites
- Pin RouterProvider to 'react-router/dom' in 5 SPA entries
- Bump react/react-dom to 19.2.7 (v8 minimum)
- Update vite manualChunks + optimizeDeps include
- Update vi.mock string literals in test files
2026-06-19 16:31:01 +08:00
Innei 2746a4b454 🐛 fix(locale): align dayjs locale imports (#15896) 2026-06-16 01:10:21 +08:00
LiJian 866af8d2f0 ✨ feat(composio): add Composio integration layer as Klavis replacement (#15461)
* ✨ feat(composio): add Composio integration layer as Klavis replacement

- Add @composio/core SDK client factory (src/libs/composio)
- Add COMPOSIO_API_KEY server config + enableComposio flag
- Add COMPOSIO_APP_TYPES const with 21 curated apps (appSlug-based)
- Add lambda/composio tRPC router (createConnection, deleteConnection, getConnection, updateComposioPlugin)
- Add tools/composio tRPC router (executeAction, listActions, getActions)
- Add ComposioService with executeComposioTool + getComposioManifests
- Add composioStore Zustand slice (7 files: types, initialState, action, selectors, index, test)
- Wire composioStore into ToolStore state and action tree
- Add composioStoreSelectors to tool selectors index
- Add handleComposioInstall to AgentManagerRuntime
- Extend CustomPluginParams with composio field
- Add enableComposio to GlobalServerConfig types

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

* 🔥 refactor(klavis): remove Klavis integration and migrate all references to Composio

- Delete all Klavis source files (libs, config, const, routers, services, store, UI components)
- Rename KlavisX components to ComposioX equivalents
- Replace all Klavis store selectors, types, and action names with Composio counterparts
- Fix authConfigId to be server-side managed (auto-fetch/create from Composio API)
- Update DB customParams.klavis → customParams.composio throughout
- Fix ToolSource type: 'klavis' → 'composio'
- Fix TaskTemplateSkillSource: 'klavis' → 'composio'
- Fix RecommendedSkillType.Klavis → RecommendedSkillType.Composio
- Remove klavis npm package dependency
- Update builtin-tool-creds: connectKlavisService → connectComposioService
- Update RuntimeExecutors: KLAVIS_SERVICES_LIST → COMPOSIO_SERVICES_LIST
- All Composio-related type errors: 0 remaining

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

* 🐛 fix(composio): complete the klavis→composio migration and wire the OAuth callback

The composio branch had renamed the klavis modules but left consumers
half-migrated, so the OAuth connect link did not work end-to-end. Finish it:

- Add the missing OAuth callback route `/api/composio/oauth/callback` (Composio
  uses managed auth, so it only lands the user back and closes the popup; the
  opener then polls getConnection and syncs tools). Allowlist it as a public
  cross-site redirect landing in the proxy define-config.
- Remove leftover `import { type Klavis } from 'composio'` (non-existent package)
  and type the prop as `string`.
- Fix undefined `oauthUrl` → `redirectUrl` in every OAuth popup opener.
- Map `serverName` to `appSlug` (API) / `label` (display); unify every
  createComposioConnection call to `{ appSlug, identifier, label }`.
- Compare against the `ComposioServerStatus` enum instead of the `'ACTIVE'`
  string literal.
- Use the renamed store fields `composioServers` / `isComposioServersInit`.
- executeComposioTool: `toolName` → `toolSlug`.
- Rename onboarding `KlavisServerItem.tsx` → `ComposioServerItem.tsx` to match
  its import.

* 🐛 fix(composio): use connectedAccounts.link for Composio-managed OAuth

`connectedAccounts.initiate` is no longer supported for Composio-managed OAuth
auth configs (HTTP 400), which broke connecting apps like Gmail. Switch to
`connectedAccounts.link` (POST /api/v3/connected_accounts/link) — same
`{ callbackUrl }` options and `{ id, redirectUrl }` result, so it is a drop-in.

Also treat Composio's `status=failed` callback query param as a failed
authorization in the OAuth callback page.

* 🐛 fix(composio): correct tool sync, execution, callback build, and list dedup

Four fixes found while testing the Composio integration end-to-end:

- listActions: use `getRawComposioTools` (raw defs with slug/inputParameters)
  instead of `tools.get()` (provider-wrapped, name/params under `.function`).
  The wrapped shape left every synced tool with an empty name, so they all
  collapsed to `${identifier}____` and the LLM rejected the request with
  "Tool names must be unique."
- tools.execute: pass `dangerouslySkipVersionCheck: true` (manual execution
  otherwise throws ComposioToolVersionRequiredError when the toolkit version
  resolves to "latest"). Applied to both the executeAction router and the
  ComposioService used by the agent runtime.
- OAuth callback route: escape only `<`/`>`/`&` for the inline-script payload;
  the previous regex embedded literal U+2028/U+2029 line separators which broke
  the regex literal at build time ("Unterminated regular expression").
- installed-plugin selectors: filter out `customParams.composio` (was still
  checking the old `customParams.klavis`), so a connected Composio app no longer
  shows up twice in the skill picker / tool discovery list.

* ✨ feat(composio): pin auth config id per toolkit via env

Add `COMPOSIO_AUTH_CONFIG_IDS` (JSON map of `identifier -> authConfigId`) so a
pre-created Composio auth config (e.g. a custom/white-label OAuth app set up in
the dashboard) can be used directly per toolkit. `createConnection` now resolves
the pinned auth config first, then falls back to discovering an existing one for
the toolkit (matched case-insensitively), and only auto-creates a
Composio-managed config when nothing is configured.

* 🐛 fix(composio): update plugin invoke test to composio + sort tool initialState imports

- action.test.ts: the action was renamed invokeKlavisTypePlugin → invokeComposioTypePlugin
  (Klavis is being removed); update the test to call the composio action and drop
  the klavis-era naming/mock field.
- store/tool/initialState.ts: order the composioStore import before connector to
  satisfy simple-import-sort/imports.

* 🐛 fix(composio): stop client deleting remote connections by static allowlist

useFetchUserComposioConnections no longer deletes remote connections/plugins
for identifiers outside the compile-time COMPOSIO_APP_TYPES list — an outdated
client bundle would silently destroy a legitimate connection. Unknown
identifiers are now only hidden locally.

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

* 🐛 fix(composio): resolve connectedAccountId server-side in executeAction

executeAction now takes `identifier` and looks up the connectedAccountId from
the caller's own user-scoped plugin record (PluginModel), instead of trusting a
connectedAccountId supplied by the client — which would let a user drive
another user's connection. Callers (callComposioTool, composioExecutor) pass
identifier accordingly.

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

* 🐛 fix(composio): enable plugin only after OAuth succeeds

Move enablePluginForAgent into the ACTIVE and post-auth-success branches so a
cancelled/timed-out authorization no longer leaves an enabled-but-unauthorized
Composio tool on the agent.

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

* 🔥 fix(composio): drop dead OAuth callback postMessage

The lobe-composio-oauth postMessage had no consumer — the OAuth wait uses
polling + window.closed detection. Remove it and its escaping helpers.

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

* 🐛 fix(composio): resolve type-check errors after canary merge

- Guard authConfigId to a definite string before persisting/returning it
  (createConnection), fixing the string|undefined assignment in both the
  server router and the composio store server object.
- Replace leftover KLAVIS_SERVER_TYPES with COMPOSIO_APP_TYPES in AgentTool.
- Update SkillAuthRow test to a composio source/provider (klavis is removed
  from TaskTemplateSkillSource).

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

* ♻️ refactor(composio): remove leftover klavis naming after migration

Klavis is deprecated and fully replaced by Composio. The migration kept the
underlying composio wiring but left klavis-named identifiers, comments, prompt
tags, i18n keys, and files throughout. Sweep them to composio:

- Code identifiers/comments across ~70 files (isKlavisEnabled→isComposioEnabled,
  allKlavisServers→allComposioServers, klavisManifests→composioManifests, etc.)
- LLM prompt tags (<klavis_tools>→<composio_tools>, KLAVIS_SERVICES_LIST→
  COMPOSIO_SERVICES_LIST) — kept consistent across definition and substitution
- i18n keys tools.klavis.*→tools.composio.* + user-facing "Klavis"→"Composio"
  brand strings, in default setting.ts and all locale setting.json files
- Rename useKlavisOAuth→useComposioOAuth, useKlavisServerActions→
  useComposioServerActions (+ imports)
- klavis.ai homepage URLs → composio.dev
- Remove the dead `klavis` npm peerDependency; swap .env.example Klavis section
  for Composio; update product docs

Changelog history left untouched. Pure rename — no behavior change.

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

* 🐛 fix(composio): remove duplicate composio key in CustomPluginParams

The klavis→composio rename collapsed the deprecated klavis param block onto
the live composio one, producing a duplicate `composio` property. The klavis
shape (instanceId/serverName/serverUrl/isAuthenticated) is dead — no code reads
it — so drop it and keep the live composio shape.

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

* 🐛 fix(composio): let pending/errored connections re-authorize or be deleted

A Composio connection link (lk_...) expires after a while. Previously a
pending/errored row only offered to reopen the stored — now expired —
redirectUrl, and the delete action existed only for ACTIVE connections, so an
expired link left the tool permanently stuck: unauthenticatable and
unremovable.

- Add reauthorizeComposioConnection store action: best-effort delete the stale
  connection, then mint a fresh link (replaces the record in place)
- Settings skill item + chat toolbar item: PENDING/ERROR now render a ··· menu
  with Re-authorize (fresh link) and Delete
- Onboarding: pending/errored row click re-mints a fresh link instead of
  reopening the stale one
- i18n: add tools.composio.reauthorize (en-US + zh-CN)

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

* 🐛 fix(composio): return auth link instead of opening popup from agent

connectComposioService runs from the agent's response, which carries no user
gesture, so window.open was blocked by the browser and the flow always failed
with "Authorization was cancelled or timed out". Instead of opening the popup
ourselves, return the authorization redirectUrl in the tool result so the agent
can surface a clickable link — the user's click is a real gesture and completes
the OAuth normally. Drops the now-unused popup/poll helper.

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

* 💄 fix(composio): match pending toolbar item to sibling authorize affordance

The ··· dropdown I added to the chat-toolbar Composio item was a bare icon
(inconsistent color/size with the app's standard menus), its popup was
mis-anchored/offset, and replacing the visible "authorize" cue with a ···
made an un-authorized (pending) row look connected.

Match the sibling LobehubSkillServerItem instead: render a clickable
"Re-authorize" text + external-link icon for PENDING/ERROR. Clicking re-mints a
fresh link (the prior one may have expired) and opens it. No dropdown, so no
offset; the explicit affordance makes it clear the row still needs auth. Delete
stays on the settings page (siblings have no inline delete here either).

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

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 11:53:48 +08:00
Innei 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
2026-06-13 16:15:04 +08:00
Innei 302755057e ⚡️ perf(vite): prewarm more route chunks (#15142) 2026-05-25 16:48:55 +08:00
Innei 8cd03c8013 ⚡️ perf: warm route chunks after idle (#15109)
* ⚡️ perf: warm route chunks after idle

* 🐛 fix: normalize platform route chunk ids

* ⚡️ perf: refine route chunk preloading

* 🔧 chore: keep desktop renderer preload unchanged

* ⚡️ perf: skip renderer chunks in route warmup

* ⚡️ perf: preload agent route dynamic chunks

* ⚡️ perf: align route preload deployment urls

* ⚡️ perf: coalesce stable vendor chunks

* ⚡️ perf: group shared data runtime chunks

* ⚡️ perf: group model runtime chunks

* ⚡️ perf: trim initial route preloads

* ⚡️ perf: limit idle route micro preloads

* ⚡️ perf: strip tiny html modulepreloads

* ⚡️ perf: prune redundant route chunk imports

* ⚡️ perf: enable rolldown devtools

* ⚡️ perf: gate vite devtools output

* ⚡️ perf: optimize react-scan integration and update global types

Signed-off-by: Innei <tukon479@gmail.com>

* ⚡️ perf: support cloud route chunk preload

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-05-23 01:00:53 +08:00
Innei e00c299d1c 🐛 fix(onboarding): resolve agent route loading stall and branch redirect (#14795)
* 🐛 fix(onboarding): refresh branch config before redirect

* 🐛 fix(onboarding): refresh agent route flag before branch guard

* 🐛 fix(onboarding): simplify agent branch guard

* 🐛 fix(onboarding): eliminate agent route loading stall

- Make AgentModel.getBuiltinAgent idempotent under concurrent callers.
  The web-onboarding builtin agent was inserted by both the bootstrap
  query and the standalone useInitBuiltinAgent SWR in parallel; the
  insert loser hit agents_slug_user_id_unique and SWR sat in its ~5s
  error-retry window before the row could be read.
- Prefetch /onboarding/agent and /onboarding/classic chunks while the
  shared-prefix steps are visible, so the branch redirect no longer
  pays a cold chunk load.

* 🐛 fix(onboarding): skip prefetch under test and complete fixture

- Add `__TEST__` Vite define so renderer code can branch on Vitest runs
  (set true in vitest.config.mts, false in sharedRendererDefine).
- Guard the shared-prefix chunk prefetch with `if (__TEST__) return`.
  Otherwise the fire-and-forget `import('@/routes/onboarding/agent')`
  resolves after the test asserts and tries to load builtin-agents,
  which the test's partial `vi.mock('@lobechat/const')` doesn't supply
  (`DEFAULT_MODEL` missing), surfacing as 25 unhandled rejections.
- Fix `extract.runtime.test.ts` fixture to include the new required
  `agentBenchmarkLoCoMo` field on `MemoryExtractionPrivateConfig`,
  added in 20267fc77c.
2026-05-15 01:19:37 +08:00
Innei 4e31a33599 🐛 fix: strip manifest link in Vite dev to silence 404 warning (#14079)
Dev server does not serve /manifest.webmanifest, which causes a console
404 in the browser. Add a shared dev-only Vite plugin that removes the
<link rel="manifest"> tag via transformIndexHtml for web/mobile/desktop.
2026-04-23 15:10:00 +08:00
Innei 9c5831ac54 🐛 fix(vite): exclude .html from code-inspector to fix Vite 8 bundledDev (#14053)
* 🐛 fix(vite): exclude .html from code-inspector to fix bundledDev

* 🔥 chore: remove @code-inspector/vite patch, fixed via exclude config
2026-04-22 20:43:24 +08:00
Innei 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
2026-04-22 19:59:38 +08:00
Innei b845ba4476 🔨 chore(vite): support direct markdown imports (#13216)
✨ feat(vite): support markdown imports
2026-03-24 14:33:57 +08:00
Innei b2122a5224 ♻️ refactor: replace per-message useNewScreen with centralized useConversationSpacer (#13042)
* ♻️ refactor: replace per-message useNewScreen with centralized useConversationSpacer

Replace the old per-message min-height approach with a single spacer element appended to the virtual list, simplifying scroll-to-top UX when user sends a new message.

* 🔧 refactor: streamline handleSendButton logic and enhance editor focus behavior

Removed redundant editor null check and added double requestAnimationFrame calls to ensure the editor is focused after sending a message.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-03-17 21:19:58 +08:00
Innei 4438b559e6 ✨ feat: add slash action tags, topic reference tool, and command bus system (#12860)
* ✨ feat: add slash action tags in chat input

Made-with: Cursor

* ✨ feat: enhance editor with new slash actions and localization updates

- Added new slash actions: change tone, condense, expand, polish, rewrite, summarize, and translate.
- Updated localization files for English and Chinese to include new action tags and slash commands.
- Removed deprecated useSlashItems component and integrated its functionality directly into InputEditor.

Signed-off-by: Innei <tukon479@gmail.com>

* ✨ feat: add slash placement configuration to chat input components

- Introduced `slashPlacement` prop to `ChatInputProvider`, `StoreUpdater`, and `InputEditor` for customizable slash menu positioning.
- Updated initial state to include `slashPlacement` with default value 'top'.
- Adjusted `ChatInput` and `InputArea` components to utilize the new `slashPlacement` prop.

This enhancement allows for better control over the user interface in chat input interactions.

Signed-off-by: Innei <tukon479@gmail.com>

* ✨ feat: implement command bus for slash action tags processing

Add command bus system to parse and execute slash commands (compact context,
new topic). Refactor action tag categories from ai/prompt to command/skill.
Add useEnabledSkills hook for dynamic skill registration.

* feat: compress command

Signed-off-by: Innei <tukon479@gmail.com>

* refactor: compress

Signed-off-by: Innei <tukon479@gmail.com>

* fix: skill inject

* ✨ feat: slash action tags with context engine integration

Made-with: Cursor

* ✨ feat: add topic reference builtin tool and server runtime

Made-with: Cursor

* ✨ feat: add topic mention items and update ReferTopic integration

Made-with: Cursor

* 🐛 fix: preserve editorData through assistant-group edit flow and update RichTextMessage reactively

- EditState now forwards editorData from EditorModal to modifyMessageContent
- modifyMessageContent accepts and passes editorData to updateMessageContent
- RichTextMessage uses useEditor + effect to update document on content change instead of key-based remount
- Refactored RichTextMessage plugins to use shared createChatInputRichPlugins()

* ✨ feat(context-engine): add metadata types and update processors/providers

Made-with: Cursor

* ✨ feat(chat-input): add slash action tags and restore failed input state

* 🔧 chore: update package dependencies and enhance Vite configuration

- Changed @lobehub/ui dependency to a specific package URL.
- Added multiple SPA entry points and layout files to the Vite warmup configuration.
- Removed unused monorepo packages from sharedOptimizeDeps and added various dayjs locales for better localization support.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update @lobehub/ui dependency to version 5.4.0 in package.json

Signed-off-by: Innei <tukon479@gmail.com>

* 🐛 fix: correct SkillsApiName.runSkill to activateSkill and update trimmed content assertions

* 🐛 fix: resolve type errors in context-engine tests and InputEditor slashPlacement

* 🐛 fix: update runSkill to activateSkill in conversationLifecycle test

* 🐛 fix: avoid regex backtracking in placeholder parser

* ✨ feat(localization): add action tags and tooltips for slash commands across multiple languages

Signed-off-by: Innei <tukon479@gmail.com>

* 🐛 fix: preserve file attachments when /newTopic has no text content

* cleanup

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-03-13 22:17:36 +08:00
Innei 5e468cd850 ✨ feat(agent-browser): add browser automation skill and tool detection (#12858)
* ✨ feat(tool-detectors): add browser automation support and refactor tool detector categories

- Introduced browser automation detectors to the tool detector manager.
- Updated tool categories to include 'browser-automation'.
- Refactored imports to use type imports where applicable for better clarity.
- Cleaned up unnecessary comments in tool filters.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: add browser automation tool detection UI

* 🔧 chore: update react-scan version and enhance agent-browser documentation

- Updated `react-scan` dependency from version 0.4.3 to 0.5.3 in package.json.
- Improved documentation in `content.ts` for the agent-browser, clarifying command usage and workflows.
- Added development mode flag `__DEV__` in sharedRendererConfig for better environment handling.
- Integrated `scan` functionality in `initialize.ts` to enable scanning in development mode.
- Updated global type definitions to include `__DEV__` constant for clarity.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore(builtin-skills): add dependency and refactor skill filtering logic

- Added `@lobechat/const` as a dependency in package.json.
- Introduced a new function `shouldEnableBuiltinSkill` to determine if a skill should be enabled based on the environment.
- Refactored the `builtinSkills` export to filter skills using the new logic.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore(builtin-skills): refactor skill management and add filtering logic

- Removed unnecessary dependency from package.json.
- Simplified skill filtering logic by introducing `filterBuiltinSkills` and `shouldEnableBuiltinSkill` functions.
- Updated various components to utilize the new filtering logic for managing builtin skills based on the environment.

Signed-off-by: Innei <tukon479@gmail.com>

* ✨ feat(builtin-skills): introduce new skill APIs and refactor manifest structure

- Added new APIs for skill management: `runSkillApi`, `readReferenceApi`, and `exportFileApi` to enhance functionality.
- Created a base manifest file (`manifest.base.ts`) to centralize API definitions.
- Updated the desktop manifest (`manifest.desktop.ts`) to utilize the new base APIs.
- Refactored existing manifest to streamline API integration and improve maintainability.
- Introduced a detailed system prompt for better user guidance on skill usage.

Signed-off-by: Innei <tukon479@gmail.com>

* ✨ feat: desktop skill runtime, skill store inspectors, and tool UI updates

Made-with: Cursor

* ✨ feat: enhance skill import functionality and testing

- Updated `importFromUrl` method in `SkillImporter` to accept additional options for identifier and source.
- Modified `importFromMarket` in `agentSkillsRouter` to utilize the new options for better tracking of skill imports.
- Added integration tests to ensure stable behavior when re-importing skills from the market, verifying that identifiers remain consistent across imports.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update .gitignore and package.json dependencies

- Added 'bin' to .gitignore to exclude binary files from version control.
- Included 'fflate' as a new dependency in package.json to support file compression in the application.
- Updated writeFile method in LocalFileCtr to handle file content as Uint8Array for improved type safety.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update package.json dependencies

- Removed 'fflate' from dependencies and added it to devDependencies for better organization.
- Ensured proper formatting by adding a newline at the end of the file.

Signed-off-by: Innei <tukon479@gmail.com>

* ✨ feat: add agent-browser download script and integrate binary handling

- Introduced a new script to download the `agent-browser` binary, ensuring it is available for the application.
- Updated `electron-builder.mjs` to include the binary in the build process.
- Modified `dir.ts` to define the binary directory path based on the packaging state.
- Enhanced the `App` class to set environment variables for the agent-browser integration.

Signed-off-by: Innei <tukon479@gmail.com>

* ✨ feat: add DevTools toggle to Linux and Windows menus

- Introduced a new menu item for toggling DevTools with the F12 accelerator key in both Linux and Windows menu implementations.
- Added a separator for better organization of the view submenu items.

Signed-off-by: Innei <tukon479@gmail.com>

* ✨ feat: integrate agent-browser binary download into build process

- Added functionality to download the `agent-browser` binary during the build process in `electron-builder.mjs`.
- Enhanced the download script with detailed logging for better visibility of the download status and errors.
- Updated the `App` class to log the binary directory path for improved debugging.
- Reintroduced the `AuthRequiredModal` in the layout for desktop users.

Signed-off-by: Innei <tukon479@gmail.com>

* fix: mock binary directory path in tests

- Added a mock for the binary directory path in the App tests to facilitate testing of the agent-browser integration.
- This change enhances the test environment by providing a consistent path for the binary during test execution.

Signed-off-by: Innei <tukon479@gmail.com>

* 🐛 fix: improve authorization notification handling

- Updated the `notifyAuthorizationRequired` method to implement trailing-edge debounce, ensuring that rapid 401 responses are coalesced and the IPC event is sent after the burst settles.
- Refactored the notification logic to enhance clarity and maintainability.

✨ feat: add desktop onboarding redirect

- Introduced a `useEffect` hook in `StoreInitialization` to redirect users to the `/desktop-onboarding` page if onboarding is not completed, ensuring a smoother user experience on fresh installs.

Signed-off-by: Innei <tukon479@gmail.com>

* 🐛 fix(desktop): hide Agent Browser skill on Windows

Made-with: Cursor

* 🔧 chore: update memory limits for build processes

- Increased the `NODE_OPTIONS` memory limit for both `build:next` and `build:spa` scripts from 6144 to 7168, optimizing build performance and resource management.

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-03-10 16:13:33 +08:00
Innei 07997b44a5 🐛 fix: skew plugin (#12669)
* fix: skew plugin

Signed-off-by: Innei <tukon479@gmail.com>

* refactor(vite): enhance vercelSkewProtection to handle static imports and improve coverage

- Added handling for static import/export declarations to ensure correct deployment links.
- Updated coverage documentation to reflect new handling for static imports and additional cases.
- Adjusted comment numbering for clarity in the processing steps.

Signed-off-by: Innei <tukon479@gmail.com>

* fix: dev proxy

Signed-off-by: Innei <tukon479@gmail.com>

* refactor(AssistantGroup): streamline contentId handling in GroupMessage component

- Simplified the logic for determining contentId by directly using lastAssistantMsg?.id.
- Moved the creation and generation state checks to follow the contentId assignment for better clarity.

Signed-off-by: Innei <tukon479@gmail.com>

* ♻️ refactor: remove chunk error reload retry, keep notification only

Made-with: Cursor

* fix: inject

Signed-off-by: Innei <tukon479@gmail.com>

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-03-04 21:47:31 +08:00
LiJian bf5d6ce2f8 🐛 fix: updown the old lobehub plugins (#12674)
* fix: updown the old lobehub plugins

* fix: update test.ts
2026-03-04 18:05:43 +08:00
Innei 58fb45d251 🐛 fix: add unsaved changes guard to prevent data loss on navigation (#12332)
* 🐛 fix: add unsaved changes guard to prevent data loss on navigation

Migrate from BrowserRouter to createBrowserRouter (data router API) to enable
route-level navigation blocking. Add UnsavedChangesGuard component that uses
useBlocker to prevent leaving editor pages with unsaved changes, auto-saving
before navigation. Remove legacy renderRoutes/RouteConfig dead code.

Fixes LOBE-4973

* 🔧 chore: remove unused ESLint suppressions for welcome.ts

Cleaned up eslint-suppressions.json by removing suppressions related to sort-keys-fix and typescript-sort-keys for welcome.ts, as they are no longer needed.

Signed-off-by: Innei <tukon479@gmail.com>

* ⚡ perf: skip JSON snapshot on selection-only Lexical updates

Reintroduce dirtyElements/dirtyLeaves guard before editor.getDocument('json')
and deep-equality check, avoiding O(document-size) work on caret/selection
updates that do not mutate content.

* 🔧 test: update UnsavedChangesGuard tests to use message.destroy instead of message.success

Signed-off-by: Innei <tukon479@gmail.com>

* fix: dayjs init

- Moved dayjs plugin extensions (relativeTime, utc, isToday, isYesterday) to src/initialize.ts for centralized initialization.
- Removed redundant extensions from individual components to prevent duplicate calls.
- Updated locale loading logic in Locale.tsx to ensure correct dayjs locale handling.

This change improves performance by ensuring dayjs plugins are only extended once during application initialization.

Signed-off-by: Innei <tukon479@gmail.com>

* refactor: update router configuration to use RouteObject type

- Changed the type of desktopRoutes from RouteConfig[] to RouteObject[] for better compatibility with react-router-dom.
- Removed the RouteConfig interface from the router utility file to streamline the codebase.

This refactor enhances the router's integration with the latest routing library standards.

Signed-off-by: Innei <tukon479@gmail.com>

* feat: enhance Vite configuration and chunk management

- Added a function to suppress Vite's default URL print in the server configuration.
- Updated chunk file naming strategy in sharedRollupOutput to organize output files into specific directories based on chunk type (i18n, vendor, assets).
- Removed redundant dayjs chunk handling logic to streamline the manualChunks function.

These changes improve the clarity of the build output and enhance the server's configuration options.

Signed-off-by: Innei <tukon479@gmail.com>

* ✨ feat: add collapsible error stack with __CI__ default expand

- Add Collapse + Highlighter for error stack in Error component
- Define __CI__ in Vite (sharedRendererDefine) based on process.env.CI
- Add __CI__ to global.d.ts
- Add error.stack i18n to all 18 locales

Made-with: Cursor

* chore: update build:spa:copy script to handle multiple asset directories

- Modified the build:spa:copy script in package.json to iterate over multiple directories (assets, i18n, vendor) for both desktop and mobile builds, improving the asset copying process.

This change enhances the build process by ensuring all relevant directories are copied correctly.

Signed-off-by: Innei <tukon479@gmail.com>

* 🐛 fix: mark initialize.ts as sideEffects to prevent tree-shaking

sideEffects: false caused Rollup to drop the side-effect-only import
of initialize.ts, removing dayjs.extend(relativeTime) and enableMapSet()
from the production bundle.

---------

Signed-off-by: Innei <tukon479@gmail.com>
2026-03-03 18:50:57 +08:00
Innei 5f2f49a26e ✨ feat(vite): add env restart keys plugin for selective .env restart (#12561)
Add a Vite plugin that prevents server restart on every .env file change,
only restarting when whitelisted env keys actually change their values.
2026-03-01 20:58:05 +08:00
Innei 687b36c81c ♻️ refactor: migrate frontend from Next.js App Router to Vite SPA (#12404)
* init plan

* 📝 docs: update SPA plan for dev mode Worker cross-origin handling

- Clarified the handling of Worker cross-origin issues in dev mode, emphasizing the need for `workerPatch` to wrap cross-origin URLs as blob URLs.
- Enhanced the explanation of the dev mode's resource URL rewriting process for better understanding.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 refactor: Phase 1 - 环境变量整治

- Fix Pyodide env var mismatch (NEXT_PUBLIC_PYPI_INDEX_URL → pythonEnv.NEXT_PUBLIC_PYODIDE_PIP_INDEX_URL)
- Consolidate python.ts to use pythonEnv instead of direct process.env
- Remove NEXT_PUBLIC_ prefix from server-side MARKET_BASE_URL (5 files)

* 🏗️ chore: Phase 2 - Vite 工程搭建

- Add vite.config.ts with dual build (desktop/mobile via MOBILE env)
- Add index.html SPA template with __SERVER_CONFIG__ placeholder
- Add entry.desktop.tsx and entry.mobile.tsx SPA entry points
- Add dev:spa, dev:spa:mobile, build:spa, build:spa:copy scripts
- Install @vitejs/plugin-react and linkedom

* ♻️ refactor: Phase 3 - 第一方包 Next.js 解耦

- Replace next/link with <a> in builtin-tool-web-browsing (4 files, external links)
- Replace next/image with <img> in builtin-tool-agent-builder/InstallPlugin.tsx
- Add Vite import.meta.env compat for isDesktop in const/version.ts, builtin-tool-gtd, builtin-tool-group-management

* ♻️ refactor: Phase 4a - Auth 页面改用直接 next/navigation 和 next/link

- 9 auth files: @/libs/next/navigation → next/navigation
- 5 auth files: @/libs/next/Link → next/link
- Auth pages remain in Next.js App Router, need direct Next.js imports

* ♻️ refactor: Phase 4b - Next.js 抽象层替换为 react-router-dom/vanilla React

- navigation.ts: useRouter/usePathname/useSearchParams/useParams → react-router-dom
- navigation.ts: redirect/notFound → custom error throws
- navigation.ts: useServerInsertedHTML → no-op for SPA
- Link.tsx: next/link → react-router-dom Link adapter (href→to, external→<a>)
- Image.tsx: next/image → <img> wrapper with fill/style support
- dynamic.tsx: next/dynamic → React.lazy + Suspense wrapper

* ✨ feat: Phase 5 - 新建 SPAGlobalProvider

- Create SPAServerConfig type (analyticsConfig, clientEnv, theme, featureFlags, locale)
- Add window.__SERVER_CONFIG__ and __MOBILE__ to global.d.ts
- Create SPAGlobalProvider (client-only Provider tree mirroring GlobalProvider)
- Includes AuthProvider for user session support
- Update entry.desktop.tsx and entry.mobile.tsx to wrap with SPAGlobalProvider

* ♻️ refactor: add SPA catch-all route handler with Vite dev proxy

- Create (spa)/[[...path]]/route.ts for serving SPA HTML
- Dev mode: proxy Vite dev server, rewrite asset URLs, inject Worker patch
- Prod mode: read pre-built HTML templates
- Build SPAServerConfig with analytics, theme, clientEnv, featureFlags
- Update middleware to pass SPA routes through to catch-all

* ♻️ refactor: skip auth checks for SPA routes in middleware

SPA pages are all public (no sensitive data in HTML).
Auth is handled client-side by SPAGlobalProvider's AuthProvider.
Only Next.js auth routes and API endpoints go through session checks.

* ♻️ refactor: replace Next.js-specific analytics with vanilla JS

- Google.tsx: replace @next/third-parties/google with direct gtag script
- ReactScan.tsx: replace react-scan/monitoring/next with generic script
- Desktop.tsx: replace next/script with native script injection

* ♻️ refactor: migrate @t3-oss/env-nextjs to @t3-oss/env-core

Replace framework-specific env validation with framework-agnostic version.
Add clientPrefix where client schemas exist.

* ♻️ refactor: replace next-mdx-remote/rsc with react-markdown

Use client-side react-markdown for MDX rendering instead of
Next.js RSC-dependent next-mdx-remote.

* 🔧 chore: update build scripts and Dockerfile for SPA integration

- build:docker now includes SPA build + copy steps
- dev defaults to Vite SPA, dev:next for Next.js backend
- Dockerfile copies public/spa/ assets for production
- Add public/spa/ to .gitignore (build artifact)

* 🗑️ chore: remove old Next.js route segment files and serwist PWA

- Delete [variants] page.tsx, error.tsx, not-found.tsx, loading.tsx
- Delete root loading.tsx and empty [[...path]] directory
- Delete unused loaders directory
- Remove @serwist/next PWA wrapper from Next.js config

* plan2

* ✨ feat: add locale detection script to index.html for SPA dev mode

* ♻️ refactor: remove locale and theme from SPAServerConfig

* ✨ feat: add [locale] segment with force-static and SEO meta generation

* ♻️ refactor: remove theme/locale reads from SPAGlobalProvider

* ✨ feat: set vite base to /spa/ for production builds

* ✨ feat: auto-generate spaHtmlTemplates from vite build output

* 🔧 chore: register dev:next task in turbo.json for parallel dev startup

* ♻️ refactor: rename (spa) route group to spa segment, rewrite SPA routes via middleware

* ✨ feat: add Vite-compatible i18n/locale modules with import.meta.glob and resolve aliases

* 🔧 fix: use custom Vite plugin for module redirects instead of resolve.alias

* very important

* build

* 🔧 chore: update build scripts and clean up Vite configuration by removing unused plugin and code

Signed-off-by: Innei <tukon479@gmail.com>

* 🗑️ refactor: remove all electron modifier scripts

Modifiers are no longer needed with Vite SPA renderer build.

* ✨ feat: add Vite renderer entry to electron-vite config

Add renderer build configuration to electron-vite, replacing the old
Next.js shadow workspace build flow. Delete buildNextApp.mts and
moveNextExports.ts, update package.json scripts accordingly.

* ✨ feat: add .desktop suffix files for eager i18n loading

Create 4 .desktop files that use import.meta.glob({ eager: true })
for synchronous locale access in Electron desktop builds, replacing
the async lazy-loading used in web SPA builds.

* 🔧 refactor: adapt Electron main process for Vite renderer

Replace nextExportDir with rendererDir, update protocol from
app://next to app://renderer, simplify file resolution to SPA
fallback pattern, update _next/ asset paths to /assets/.

* 🔧 chore: update electron-builder files config for Vite renderer

Replace dist/next references with dist/renderer, remove Next.js
specific exclusion rules no longer applicable to Vite output.

* 🗑️ chore: remove @ast-grep/napi dependency

No longer needed after removing electron modifier scripts.

* 🔧 refactor: unify isDesktop to __ELECTRON__ compile-time constant

Remove NEXT_PUBLIC_IS_DESKTOP_APP and VITE_IS_DESKTOP_APP env vars.
Unify isDesktop in @lobechat/const using __ELECTRON__ defined by Vite.
Re-export from builtin-tool packages. Scripts use DESKTOP_BUILD.

* update

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 refactor: use electron-vite ELECTRON_RENDERER_URL instead of hardcoded port 3015

Replace hardcoded http://localhost:3015 with process.env.ELECTRON_RENDERER_URL
injected by electron-vite dev server. Clean up stale Next.js references.

* 🐛 fix: use local renderer-entry shim to resolve Vite root path issue

HTML entry ../../src/entry.desktop.tsx resolves to /src/entry.desktop.tsx
in URL space, which Vite cannot find within apps/desktop/ root. Add a
local shim that imports across root via module resolver instead.

* 🔧 refactor: extract shared renderer Vite config into sharedRendererConfig

Deduplicate plugins (nodeModuleStub, platformResolve, tsconfigPaths) and
define (__MOBILE__, __ELECTRON__, process.env) between root vite.config.ts
and electron.vite.config.ts renderer section.

* 🔧 refactor: move all renderer plugins and optimizeDeps into shared config

sharedRendererPlugins now includes react, codeInspectorPlugin alongside
nodeModuleStub, platformResolve, tsconfigPaths. Add sharedOptimizeDeps
for pre-bundling list. Both root and electron configs consume shared only.

* 🐛 fix: set electron renderer root to monorepo root for correct glob resolution

import.meta.glob with absolute paths (e.g. /node_modules/antd/...) resolved
within apps/desktop/ instead of monorepo root. Change renderer root to ROOT_DIR,
add electronDesktopHtmlPlugin middleware to rewrite / to /apps/desktop/index.html,
and remove the now-unnecessary renderer-entry.ts shim.

* desktop vite !!

Signed-off-by: Innei <tukon479@gmail.com>

* sync import !!

Signed-off-by: Innei <tukon479@gmail.com>

* clean ci!!

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 refactor: update SPA path structure and clean up dependencies

- Changed the path in .gitignore and related files from [locale] to [variants] for SPA templates.
- Updated index.html to set body height to 100%.
- Cleaned up package.json by removing unused dependencies and reorganizing devDependencies.
- Refactored RendererUrlManager to use a constant for SPA entry HTML path.
- Removed obsolete route.ts file from the SPA structure.
- Adjusted proxy configuration to reflect the new SPA path structure.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update build script to include mobile SPA build

- Modified the build script in package.json to add the mobile SPA build step.
- Ensured the build process accommodates both desktop and mobile SPA versions.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update build scripts and improve file encoding consistency

- Modified the build script in package.json to ensure the SPA copy step runs after the build.
- Updated file encoding in generateSpaTemplates.mts from 'utf-8' to 'utf8' for consistency.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 fix: correct Blob import syntax and update global server config type

- Fixed the Blob import syntax in route.ts to ensure proper module loading.
- Updated the global server configuration type in global.d.ts for improved type safety.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 test: update RendererUrlManager test to reflect new file path

- Modified the mock implementation in RendererUrlManager.test.ts to check for the updated file path '/mock/export/out/apps/desktop/index.html'.
- Adjusted the expected resolved path in the test to match the new structure.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 refactor: remove catch-all example file and update imports

- Deleted the catch-all example file `catch-all.eg.ts` to streamline the codebase.
- Updated import paths in `ClientResponsiveLayout.tsx` and `ClientResponsiveContent/index.tsx` to use the new dynamic import location.
- Added type declarations for HTML templates in `spaHtmlTemplates.d.ts`.
- Adjusted `tsconfig.json` to include the updated file structure.
- Enhanced type definitions in `global.d.ts` and fixed locale loading in `locale.vite.ts`.

Signed-off-by: Innei <tukon479@gmail.com>

* e2e

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: remove unused build script for Vercel deployment

- Deleted the `build:vercel` script from package.json to streamline the build process.
- Ensured the remaining build scripts are organized and relevant.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 config: update Vite build input for mobile support

- Changed the build input path in vite.config.ts to conditionally use 'index.mobile.html' for mobile builds, enhancing support for mobile SPA versions.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 feat: add compatibility checks for import maps and cascade layers

- Implemented functions to check for browser support of import maps and CSS cascade layers.
- Redirected users to a compatibility page if their browser does not support the required features.
- Updated the build script in package.json to use the experimental analyze command for better performance.

Signed-off-by: Innei <tukon479@gmail.com>

* chore: rename

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 feat: refactor authentication layout and introduce global providers

- Created a new `RootLayout` component to streamline the layout structure.
- Removed the old layout file for variants and integrated necessary features into the new layout.
- Added `AuthGlobalProvider` to manage authentication context and server configurations.
- Introduced language and theme selection components for enhanced user experience.
- Updated various components to utilize the new context and improve modularity.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 config: exclude build artifacts from serverless functions

- Updated the `next.config.ts` to exclude SPA, desktop, and mobile build artifacts from serverless functions.
- Added paths for `public/spa/**`, `dist/**`, `apps/desktop/build/**`, and `packages/database/migrations/**` to the exclusion list.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 config: refine exclusion of build artifacts from serverless functions

- Updated `next.config.ts` to specify exclusion paths for desktop and mobile build artifacts.
- Changed exclusions from `dist/**` and `apps/desktop/build/**` to `dist/desktop/**`, `dist/mobile/**`, and `apps/desktop/**` for better clarity and organization.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 fix: update BrowserRouter basename for local development

- Modified the `ClientRouter` component to conditionally set the `basename` of `BrowserRouter` based on the `__DEBUG_PROXY__` variable, improving local development experience.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 feat: implement mobile SPA workflow and S3 asset management

- Added a new workflow for building and uploading mobile SPA assets to S3, including environment variable configurations in `.env.example`.
- Updated `package.json` to include a new script for the mobile SPA workflow.
- Enhanced the Vite configuration to support dynamic CDN base paths.
- Refactored the template generation script to handle mobile HTML templates more effectively.
- Introduced new modules for uploading assets to S3 and generating mobile HTML templates.

Signed-off-by: Innei <tukon479@gmail.com>

* 🐛 fix: extract origin from MOBILE_S3_PUBLIC_DOMAIN to prevent double key prefix

* 🔧 fix: update mobile HTML template to use the latest asset versions

- Modified the mobile HTML template to reference the updated JavaScript asset version for improved functionality.
- Ensured consistency in the template structure while maintaining existing styles and scripts.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update dependencies and refine service worker integration

- Removed outdated dependencies related to Serwist from package.json and tsconfig.json.
- Added vite-plugin-pwa to enhance PWA capabilities in the Vite configuration.
- Updated service worker registration logic in the PWA installation component.
- Introduced a new local development proxy route for debugging purposes.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: refactor development scripts and remove Turbo configuration

- Updated the `dev` script in `package.json` to use a new startup sequence script for improved development workflow.
- Removed the outdated `turbo.json` configuration file as it is no longer needed.
- Introduced `devStartupSequence.mts` to manage the startup of Next.js and Vite processes concurrently.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 feat: update entry points and introduce debug proxy for local development

- Changed the main entry point in `index.html` from `entry.desktop.tsx` to `entry.web.tsx` for improved web compatibility.
- Added an `initialize.ts` file to enable `immer`'s `enableMapSet` functionality.
- Introduced a new `__DEBUG_PROXY__` variable in global types to support local development proxy features.
- Implemented a debug proxy route to facilitate local development with dynamic HTML injection and script handling.
- Removed outdated mobile routing components to streamline the codebase.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 refactor: replace BrowserRouter with RouterProvider for improved routing

- Updated entry points for desktop, mobile, and web to utilize RouterProvider and createAppRouter for better routing management.
- Removed the deprecated renderRoutes function in favor of a more streamlined router configuration.
- Enhanced router setup to support error boundaries and dynamic routing.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 refactor: remove direct access handling for SPA routes in proxy configuration

- Eliminated the handling of direct access to pre-rendered SPA pages in the proxy configuration.
- Simplified the request processing logic by removing checks for SPA routes, streamlining the middleware response flow.

Signed-off-by: Innei <tukon479@gmail.com>

* update

* 🔧 refactor: enhance Worker instantiation logic in mobile HTML template

* 🐛 fix: remove duplicate waitForPageWorkspaceReady calls in page CRUD e2e steps

* 🔧 refactor: simplify createTracePayload function by using btoa for base64 encoding

* 🔧 refactor: specify locales in import.meta.glob for dayjs and antd

* 🔧 refactor: replace Node.js Buffer with web-compatible btoa for base64 encoding in file upload

* 🐛 fix: disable consistent-type-imports rule for mdx files to prevent eslint crash

* 🔧 refactor: add height style to root div for consistent layout

* 🔧 refactor: replace btoa with Buffer for base64 encoding in trace and file upload handling

* 🔧 refactor: extract nextjsOnlyRoutes to a separate file for better organization

* 🔧 refactor: enable Immer MapSet plugin in tests for better state management

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 refactor: integrate sharedRollupOutput configuration and increase cache size for better performance

Signed-off-by: Innei <tukon479@gmail.com>

* 🗑️ chore: remove obsolete desktop.routes.test.ts file as it is no longer needed

Signed-off-by: Innei <tukon479@gmail.com>

* 🐛 fix: use cross-env for env vars in npm scripts (Windows CI)

Co-authored-by: Cursor <cursoragent@cursor.com>

* 🔧 chore: update Dockerfile for web-only build and adjust npm scripts to use pnpm

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: enhance Dockerfile prebuild process with environment checks and add new dependencies

- Updated Dockerfile to include environment checks before removing desktop-only code.
- Added new dependencies in package.json: @aws-sdk/client-bedrock-runtime, @opentelemetry/auto-instrumentations-node, @opentelemetry/resources, @opentelemetry/sdk-metrics, and ajv.
- Configured Rollup to exclude @aws-sdk/client-bedrock-runtime from the SPA bundle.
- Introduced dockerPrebuild.mts script for environment variable validation and information logging.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: enhance Vite and Electron configurations with environment loading and trace encoding improvements

- Updated Vite and Electron configurations to load environment variables using loadEnv.
- Modified trace encoding in utils to use TextEncoder for better compatibility.
- Adjusted sharedRendererConfig to expose only necessary public environment variables.

Signed-off-by: Innei <tukon479@gmail.com>

* 🗑️ chore: remove plans directory (migrated to discussion)

* ♻️ refactor: inject NEXT_PUBLIC_* env per key in Vite define

Co-authored-by: Cursor <cursoragent@cursor.com>

* ✨ feat: add loading screen with animation to enhance user experience

- Introduced a loading screen with a brand logo and animations for better visual feedback during loading times.
- Implemented CSS styles for the loading screen and animations in index.html.
- Removed the loading screen from the DOM once the layout is ready using useLayoutEffect in SPAGlobalProvider.

Signed-off-by: Innei <tukon479@gmail.com>

* 🗑️ chore: remove unnecessary external dependency from Vite configuration

- Eliminated the external dependency '@aws-sdk/client-bedrock-runtime' from the Vite configuration to streamline the build process for the SPA bundle.

Signed-off-by: Innei <tukon479@gmail.com>

* ✨ feat: add web app manifest link in index.html and enable PWA support in Vite configuration

- Added a link to the web app manifest in index.html to enhance PWA capabilities.
- Enabled manifest support in Vite configuration for improved service worker functionality.

Signed-off-by: Innei <tukon479@gmail.com>

* 🔧 chore: update link rel attributes for improved SEO and consistency

- Modified link rel attributes in multiple components to remove 'noreferrer' and standardize to 'nofollow'.
- Adjusted imports in PageContent components for better organization.

Signed-off-by: Innei <tukon479@gmail.com>

* update provider

* ✨ feat: enhance loading experience and update package dependencies

- Added a loading screen with animations and a brand logo in index.html for improved user feedback during loading times.
- Introduced CSS styles for the loading screen and animations.
- Updated package.json files across multiple packages to include "@lobechat/const" as a dependency.

Signed-off-by: Innei <tukon479@gmail.com>

* fix: update proxy

Signed-off-by: Innei <tukon479@gmail.com>

* 🗑️ chore: remove GlobalLayout and Locale components

- Deleted GlobalLayout and Locale components from the GlobalProvider directory to streamline the codebase.
- This removal is part of a refactor to simplify the layout structure and improve maintainability.

Signed-off-by: Innei <tukon479@gmail.com>

* chore: clean up console logs and improve component structure

- Removed unnecessary console log statements from AgentForkTag components in both agent and community directories to enhance code cleanliness.
- Refactored UserAgentList component for better readability by restructuring the useUserDetailContext hook and adjusting the layout of Flexbox components.

Signed-off-by: Innei <tukon479@gmail.com>

* chore: remove console log from MemoryAnalysis component

* chore: update mobile HTML template with new asset links

- Replaced the previous asset links in the mobile HTML template with updated versions to ensure the latest resources are utilized.
- Adjusted the link rel attributes for module preloading to enhance performance and loading efficiency.

Signed-off-by: Innei <tukon479@gmail.com>

* fix: correct variable assignment in createClientTaskThread integration test

- Updated the assignment of the second parent message in the createClientTaskThread integration test to improve clarity and ensure proper data handling.
- Changed the variable name from 'secondParentMsg' to 'inserted' for better context before extracting the first message from the inserted results.

Signed-off-by: Innei <tukon479@gmail.com>

* refactor: simplify authentication check in define-config

- Removed the dependency on the isDesktop variable in the authentication check to streamline the logic.
- Enhanced the clarity of the redirection process for protected routes by focusing solely on the isLoggedIn status.

Signed-off-by: Innei <tukon479@gmail.com>

* ✨ feat(dev): enhance local development setup with debug proxy instructions

- Added detailed instructions for starting the development environment in CLAUDE.md, including commands for SPA and full-stack modes.
- Updated README.md and README.zh-CN.md to reflect new commands and the debug proxy URL for local development.
- Introduced a Vite plugin to print the debug proxy URL upon server start, facilitating easier local development against the production backend.
- Corrected the debug proxy route in entry.web.tsx and define-config.ts for consistency.

This improves the developer experience by providing clear guidance and tools for local development.

Signed-off-by: Innei <tukon479@gmail.com>

* optimize perf

* optimize perf

* optimize perf

* remove speedy plugin

* add dayjs vendor

* Revert "remove speedy plugin"

This reverts commit bf986afeb1.

---------

Signed-off-by: Innei <tukon479@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-28 00:01:01 +08:00