Commit Graph

303 Commits

Author SHA1 Message Date
Innei ffaa7d2a1c 🐛 fix(nav-panel): keep the Home sidebar scroll offset across route round trips (#19441)
* 🐛 fix(nav-panel): keep the Home sidebar scroll offset across route round trips

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

* ✅ test: scope sidebar e2e locators to visible elements and drop flaky parse timing assertion

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

* ✅ test(e2e): wait for a visible search control before typing in the sidebar

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

* 👷 ci(size-gate): record resolved dependency versions and report drift against the baseline

Claude-Session: https://claude.ai/code/session_01ARGf412bndxNwVrxYxQBEa
2026-09-12 00:01:23 +08:00
AmAzing- 3bb887ca4c 🐛 fix(ci): restore release metadata sync and dispatch on main (#19424)
Co-authored-by: lobehubbot <i@lobehub.com>
2026-09-11 14:57:59 +08:00
Innei aba9e8150c 👷 build: migrate the test suite to vitest 5 (#19355)
* 👷 build: upgrade vitest to 5.0.0

Bump vitest and @vitest/coverage-v8 to 5.0.0 and migrate the configs for Vitest 4/5: drop the removed coverage.all option and replace poolOptions.forks.singleFork with maxWorkers/isolate.

* 👷 build: shim jest-dom matcher types for vitest 5

Vitest 5 exposes Assertion<R, T> and no longer reads the jest.Matchers augmentation that @testing-library/jest-dom ships, so its matchers vanish from expect(). Re-declare them on the Vitest interface, and replace the removed describe.sequential with { concurrent: false }.

* 👷 build: migrate the test suite to vitest 5

Vitest 5 (and @vitest/coverage-v8) replaces the esbuild dep optimizer with Rolldown, removed environmentMatchGlobs/coverage.all/poolOptions, forwards `new` to mock implementations, requires top-level vi.mock, and no longer resets automocks in restoreAllMocks. Migrate the root config to app/server projects with Rolldown optimizer options, shim the jest-dom matchers on Assertion<R, T>, and update the affected tests (constructor mocks, hoisted mocks, awaited assertions, explicit mock types, per-test mock defaults).

* 👷 build: make the openapi knowledge-base FileService mock constructable

tests/ was outside the per-area sweep; vitest 5 forwards `new` to the mock implementation, so the arrow implementation threw "is not a constructor".

* 👷 build: point the CI blob-report artifacts at the vitest 5 output dir

Vitest 5 writes blob reports to .vitest/blob instead of .vitest-reports, so the sharded jobs uploaded nothing and the merge jobs failed with ENOENT. Track the new directory in .gitignore too.

* 👷 build: refresh the desktop lockfile for vitest 5

apps/desktop/pnpm-lock.yaml is committed and the desktop build action installs with --frozen-lockfile, so the vitest/override change has to be reflected in it.

* 👷 build: keep the pre-vitest-4 coverage exclusions explicit

Vitest 4+ ships an empty coverageConfigDefaults.exclude, so configs that spread it silently lost the default exclusions (node_modules, dist, *.config.*) and counted more files. Inline the previous list.

* 🎨 style: format the migrated vitest configs

* 👷 build: keep canary's new class mocks constructable under vitest 5

exploreGraph/dispatchAuthorization/scopedDevices (canary #19375, #19352) mock classes with arrow implementations; vitest 5 constructs the implementation when the mock is newed, so the arrows throw 'is not a constructor'.
2026-09-10 22:18:49 +08:00
Innei 9357042766 🐛 fix(desktop): derive renderer OTA compatibility from source inputs (#19351)
* 🐛 fix(desktop): derive renderer OTA compatibility from source inputs

* 🐛 fix(desktop): set up Node before validating S3 releases

* 🐛 fix(desktop): report OTA decisions and preserve diagnostics
2026-09-09 23:52:33 +08:00
Innei b65aae96b6 👷 build: migrate workspace to pnpm 12 (#19324)
* 👷 build: migrate workspace to pnpm 12

pnpm 12 no longer reads the package.json "pnpm" field, only honours auth and registry keys from .npmrc, and requires allowBuilds instead of onlyBuiltDependencies. Move every project setting into pnpm-workspace.yaml and keep the previously effective overrides and build allowlist.

* 👷 build: resolve desktop and cli workspaces on pnpm 12

pnpm 12 no longer accepts './'-prefixed workspace package globs, so the desktop stub path is now relative without the prefix. Migrate the remaining package.json "pnpm" fields into the desktop and cli pnpm-workspace.yaml files.

* 👷 build: list protobufjs in the desktop build allowlist

pnpm 12 fails the install with ERR_PNPM_IGNORED_BUILDS when a script-bearing dependency is missing from allowBuilds. protobufjs only appears in the desktop graph on Linux, so it was absent from the previous allowlist.

* 👷 build: relink root workspace members before the desktop typecheck

pnpm 12 writes broken relative symlinks for workspace members that live outside the desktop workspace root (../../packages/*), so tsgo cannot resolve sibling packages from source. Installing the root workspace after the desktop install rewrites those links correctly.
2026-09-09 19:43:11 +08:00
YuTengjing 13ada65ad9 ✨ feat(fts-search): safe per-entity Elasticsearch mapping migrations (#19186) 2026-09-09 09:03:40 +08:00
Innei 8bf9734dfb ✨ feat(task-dock): promote the upload dock into an app-level task dock (#19146)
* ✨ feat(task-dock): promote the upload dock into an app-level task dock

Background work of every kind now shares one dock instead of the
uploads-only one mounted inside the resource manager.

- `features/TaskDock` renders a `DockTask[]` collected from producer
  hooks; producers own their copy, actions and results.
- One task renders as a result card, two or more as a panel grouped by
  producer. The shape follows the task count and waits 400ms before
  shrinking so a burst of dismissals cannot morph it repeatedly.
- A finished task with nothing to hand back clears itself after 3s; one
  that left a result waits for the user, and a failure always does.
- File uploads keep their store untouched and are adapted into tasks;
  `business/client/features/DockTasks` lets a distribution add its own.
- Mounted in `SPAGlobalProvider`, so the dock outlives the page that
  started the work.

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

* 🐛 fix(task-dock): batch a producer's cancel-all and label the expand toggle

- `DockTask.groupCancel` lets a producer cancel its whole set in one
  operation. Walking `cancel` per task turned a folder upload's batched
  cancel into one full-list update per file.
- The header toggle said "Collapse" while collapsed, i.e. the opposite of
  what it does.

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

* 🐛 fix(task-dock): lazy-load the dock and turn the size gate into a review

The dock pulled the upload/file chunks into the first-screen static
graph; it now loads through `lazy()` like the other global hosts.

The web and ASAR size gates no longer fail their jobs. A failing gate
submits a REQUEST_CHANGES review from github-actions that links the
report comment, updates it while still failing, and dismisses it once
the gate passes again.

Claude-Session: https://claude.ai/code/session_01BBCjqExuP6Ux5PRVJbU2ru
2026-09-04 23:40:24 +08:00
Innei 38bd08df1d 🐛 fix(ci): keep desktop canary OTA progressing (#19112) 2026-09-04 19:16:17 +08:00
Innei 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
2026-09-04 02:53:34 +08:00
Innei 546cc8354e 🐛 fix(ci): select size baselines from tested lineage (#19052) 2026-09-03 01:29:50 +08:00
Innei df001d13ba 🐛 fix(ci): support perf commits in desktop canary trigger (#19046) 2026-09-02 22:18:56 +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
Innei 82acc9f2d7 🐛 fix(desktop): hash renderer OTA main bundles (#18799)
* 🐛 fix(desktop): hash renderer OTA main bundles

* 🐛 fix(desktop): hash externalized runtime modules in mainHash

Externalized main-process modules (electron-log, font-list, native addons
and their dependency trees) never reach the emitted bundles, so a renderer
OTA patch could be gated against an installed binary whose external runtime
module had changed.

Each platform now contributes an `externals` digest: name@version for
registry packages, plus full source content for workspace packages whose
version never bumps.

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

* ♻️ refactor(desktop): unify update notification info

* test: avoid building main hash bundles in unit test
2026-08-30 21:38:00 +08:00
Innei c3a11cfcfc 👷 ci: upgrade pnpm setup action to v6 (#18777) 2026-08-28 15:16:50 +08:00
Innei 9e750585fc 👷 ci(share): add PR-time verify workflow for the share micro app (#18757)
* 👷 ci(share): add PR-time verify workflow for the share micro app

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

* 👷 ci(share): build same-repo PR previews with the cloud overlay

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

* 📝 docs(skill): record dual-repo share verify and skeleton layout parity

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

* 👷 ci(share): keep overlay naming neutral in public workflow

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

* 👷 ci(share): reuse the existing overlay token secret

Claude-Session: https://claude.ai/code/session_01TQcoZnDo12NGCxWZDJpciZ
2026-08-28 01:04:14 +08:00
Innei 2325c093c6 👷 ci(desktop): read the overlay repository from a variable instead of hardcoding (#18759)
Claude-Session: https://claude.ai/code/session_01TQcoZnDo12NGCxWZDJpciZ
2026-08-28 00:56:08 +08:00
Innei 3f039d795b ♻️ refactor(desktop): migrate renderer OTA to V2 packs (#18745)
* ♻️ refactor(desktop): migrate renderer OTA to V2 packs

* ⚡️ perf(desktop): decode renderer packs asynchronously
2026-08-27 17:50:49 +08:00
Innei 0643d3b39f ♻️ refactor(desktop): scope renderer OTA by release version (#18724) 2026-08-26 23:21:57 +08:00
Innei 63deb07494 🐛 fix(ci): dispatch renderer OTA before desktop releases (#18716) 2026-08-26 20:05:49 +08:00
Innei 2fd9cfb970 ✨ feat(desktop): gzip renderer OTA CAS and keep r0 plus last-2 deltas (#18694)
* ✨ feat(desktop): gzip renderer OTA CAS and keep r0 plus last-2 deltas

Tree-diff with zstd --patch-from instead of re-downloading the full renderer,
gzip the original CAS objects, and generate deltas from the packaged r0 tree
plus the two most recent patch versions.

* ♻️ refactor(desktop): simplify renderer OTA lineage

* 🐛 fix(ci): publish renderer base after r0
2026-08-26 15:26:11 +08:00
Innei c66135277e 🐛 fix(ci): strip checkout extraheader when resolving cloud revision (#18686)
actions/checkout persist-credentials extraheader would send GITHUB_TOKEN
and 404 the private cloud repo on git ls-remote.
2026-08-25 21:57:37 +08:00
Innei 19f910750c ✨ feat(desktop): renderer OTA hot update without app restart (#18648)
* ✨ feat(desktop): renderer OTA hot update without app restart

* 🐛 fix(desktop): address renderer OTA review findings

- compute mainHash only from committed files and include src/common
- inject UPDATE_SERVER_URL into beta builds so OTA is enabled
- validate all MPA entry htmls at staging, not just index.html
- use async fs for renderer tree hashing/staging off the main event loop

* ♻️ refactor(desktop): validate renderer OTA manifest with zod + zod-compiler

* 🐛 fix(desktop): pin renderer OTA build lineage

* 🐛 fix(desktop): isolate renderer OTA lineages
2026-08-24 23:39:03 +08:00
Innei 2d6de14094 ci(workbench): upload a preview version per PR instead of a dry run (#18592)
* ✨ feat(workbench): upload a preview version per PR instead of a dry run

A PR could only prove the bundle compiled and fit under the size guard; the
first request any workbench bundle ever served was production traffic. The
build now stamps the preview version's own workers.dev origin as the asset
base and uploads a real version, which takes no production traffic and can be
pointed at from the gateway's staging config to walk the whole chain.

Fork PRs keep the dry run: they have no secrets to upload with.

* ✨ feat(workbench): post the preview URL as a PR comment

The step summary is a page nobody opens. Matched on a marker rather than
`gh pr comment --edit-last`: other workflows here comment as the same bot,
so editing the actor's last comment would rewrite one of theirs.
2026-08-22 21:37:24 +08:00
Innei 1477aa2ca7 💚 ci(workbench): upload CDN assets to R2 before deploying the worker (#18492)
CI was building the worker and wrangler-deploying without `bun run deploy`,
so hashed `/workbench/` assets never reached R2. Run the full deploy script
and inject the shared `ASSET_S3_*` web-assets credentials.
2026-08-19 18:44:11 +08:00
Innei 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
2026-08-19 18:21:00 +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
Rdmclin2 e869088121 ✨ feat(sdk): add @lobehub/sdk generated from the OpenAPI spec (#17980)
* ✨ feat(sdk): add @lobehub/sdk generated from the OpenAPI spec

Resource-style TypeScript SDK (lobehub.agents.list()) generated from
packages/openapi/openapi.yml via @hey-api/openapi-ts: instantiable LobeHub
root class, 14 resource groups, inlined HTTP runtime (zero npm deps), and a
byte-level drift check (bun scripts/generate-sdk.ts --check) that runs in
local tests and the release workflow only — regular PR CI is not gated.
Publishing is automated by release-sdk.yml on canary pushes touching
packages/sdk/** (plus manual dispatch), versioned 1.0.<UTC timestamp>.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* 🐛 fix(sdk): rename misleading messages.deleteAll to deleteMany

DELETE /api/v1/messages requires a non-empty messageIds array — it deletes
a selected batch, not all messages.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* 🔨 chore(sdk): make .mjs output deterministic and document SSE streaming

fixedExtension: true pins tsdown output to .mjs/.d.mts regardless of
package.json type, matching the exports the release workflow writes.
README documents parseAs: 'stream' for responses.create with stream: true.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* 🐛 fix(sdk): preserve per-call HeadersInit values on write methods

The generated write methods spread options.headers into an object literal,
which drops Headers instances and corrupts tuple arrays. generate-sdk.ts now
rewrites the spread to the client's mergeHeaders (normalizing tuple arrays
via new Headers) in both generate and --check modes, with a regression test
covering both HeadersInit shapes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* 🐛 fix(sdk): normalize HeadersInit at the root and keep form-data Content-Type deletion

Follow-ups to the header-spread rewrite: (1) mergeHeaders itself now
normalizes tuple-array HeadersInit (client defaults and read-method calls
previously degraded to numeric keys); (2) write methods merge into a plain
object instead of a Headers instance, so the 'Content-Type': null sentinel
on form-data methods survives to the final client merge and can delete a
client-default Content-Type. Regression tests cover both paths.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* 🐛 fix(sdk): satisfy repo-wide type-check for generator script and upload test

Resolve the defineConfig thenable before spreading/passing to createClient,
and drop fields not present in the files.create body schema from the
form-data regression test. The package tsconfig only covers src/**, so these
scripts/test typings were first caught by the repo-wide type-check in CI.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 18:23:39 -07:00
Innei df629b17ee 👷 ci: add bundle size gate for web dist and desktop asar (#17970)
* 👷 ci: add bundle size gate for web dist and desktop asar

- measure web dist (dist/desktop|auth|workbench) in e2e workflow builds
- measure app.asar in desktop builds (pr-build-desktop, release-desktop-canary)
- baseline stored as workflow artifacts from latest successful canary runs
- PR runs compare against baseline and fail when increase > max(3%, 512KB)
- upsert PR comment with per-entry size report

* 👷 ci: address codex review on size gate

- add result-encoding: string to baseline finder steps (raw run id,
  empty-string check works, graceful degrade no longer broken)
- emit a visible skipped section when baseline/current report is missing
  instead of the misleading comment fallback
- per-gate comment identifiers (web / asar) so e2e and desktop workflows
  no longer overwrite each other's PR comment
2026-08-06 22:31:29 +08:00
AmAzing- 1fc482cc0c ♻️ refactor(ci): simplify MCP marketplace issue bot to single CLI redirect (#17816) 2026-08-03 21:44:39 +08:00
YuTengjing b2bb1ee823 🐛 fix: resolve multiple high-frequency Windows feedback issues around shell execution (#17576) 2026-07-29 12:42:00 +08:00
Arvin Xu f8365500c2 ♻️ refactor(desktop): compile against the real @lobechat/types, drop the types stub (#17436)
* ♻️ refactor(desktop): compile against the real @lobechat/types, drop the types stub

Follow-up to #17424: close the remaining isolated-workspace gaps and delete
apps/desktop/stubs/types.

- push the last two @/ imports out of packages/types: MCPErrorType now lives
  with the shared MCP plugin types (src/libs/mcp re-exports it), and
  IFeatureFlagsState is an explicit type in serverConfig.ts that app-config's
  mapFeatureFlagsEnvToState is pinned to via its return-type annotation
- move ModelProviderKey next to the ModelProvider enum in model-bank, removing
  the types → model-runtime type edge
- load packages/const/src/global.d.ts from version.ts (type-only import) so
  __ELECTRON__ exists without the app's ambient declarations
- mirror ENABLE_BUSINESS_FEATURES into the desktop business-const stub
- make model-runtime compile under the desktop tsconfig (strict:false):
  relative import in volcengine, typed runtime-map lookup instead of
  @ts-expect-error, explicit AsyncIterator<T> in convertIterableToStream,
  ternary spreads in google createVideo, unknown-bridged ThinkingConfig cast
- add StrictOnly<T> guard helper: zod 4 inference needs strictNullChecks, so
  satisfies-guards in understanding.ts / userMemory/tools.ts stay strict in
  the root project and relax to any for non-strict consumers

Desktop isolated workspace: 15 type errors → 0, stub deleted.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* 👷 ci(desktop): type-check the isolated workspace in the desktop quality job

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-22 12:00:59 +08:00
AmAzing- ec8aec806d 🐛 fix(desktop): use embedded CLI for gateway agent runs (#17379) 2026-07-20 19:37:14 +08:00
Innei 53d6925329 ✅ test(e2e): cover OIDC device flow (#17188) 2026-07-14 21:51:36 +08:00
AmAzing- 1be0ad970c 🐛 fix: preserve MCP publishing feedback triage (#16631) 2026-07-02 18:45:38 +08:00
YuTengjing e20b0757bc ✨ feat(chat-input): nudge sandbox users to switch to local (#16520)
* ✨ feat(chat-input): nudge sandbox users to switch to local

When a desktop user has the cloud sandbox selected as the execution
target, show an inline notice above the input with a one-click "switch
to local" action. Sandbox is ephemeral, so local runs are faster and
can access the user's files.

- Rename CurrentModelNotice -> ChatInputNotice; the resolver now returns
  { key, type, action } so it can carry both warning (model) and info
  (sandbox) notices in a single slot, model warnings taking priority.
- Extract useSelectExecutionTarget so the device switcher and the notice
  share the local device-id resolution.

* 💄 style(chat-input): fix sandbox notice action spacing and alignment

Antd's alert section defaults to flex: 1, pushing the action button to
the far edge; the message line-height override targeted the wrong
class (.ant-alert-message instead of .ant-alert-title) so it never
applied; and @lobehub/ui's root style top-aligns children instead of
centering. Also bump the switch-to-local button to a primary type so
it reads as the notice's clear call to action.

* ✅ test(chat-input): add coverage for useSelectExecutionTarget

Cover boundDeviceId resolution order (cached gateway id -> async
fallback -> keep stale value on failure) and the heterogeneous-agent
guard that skips switching to local when no device can be resolved.

* 🐛 fix(chat-input): type ChatInputNotice key as literal union

t(notice.key) failed tsgo type-check (TS2345) since the feature's
original commit — key: string is too loose for i18next's typed
TFunction overloads, which require a literal key from the resources
union rather than plain string.

* ♻️ refactor(chat-input): derive ChatInputNotice type from resolveChatInputNotice

Replaces the hand-maintained ChatInputNotice interface with a type
derived from resolveChatInputNotice's actual return values (ReturnType +
`as const`). The manual interface had already drifted out of sync with
the implementation once (key: string vs. the literal keys actually
returned), causing a tsgo failure; deriving the type removes that
drift risk and tightens the union to only the key/type/action
combinations that can actually occur.

* 🐛 fix(chat): compare Immer draft via current() before deep-equal

fast-deep-equal comparing a live Immer draft proxy against a plain
merged object is fragile — its result depends on Immer's internal
Proxy trap implementation, which changed between immer 11.1.8 and
11.1.9 and made these no-op checks spuriously report a change.

* 👷 ci: shard Test Server into 2 jobs

Mirror Test App's shard+blob-report+merge pattern so server tests
run in parallel instead of one long single job.
2026-07-01 21:21:42 +08:00
Arvin Xu 3e133cbbd8 ✅ test(e2e): parallelize semantic e2e validation (#16452)
* ✅ test(e2e): speed up semantic agent smoke path

* ✅ test(e2e): run semantic suite in parallel
2026-06-30 10:08:11 +08:00
AmAzing- b52b991812 ✨ feat(ci): auto-handle MCP marketplace submission issues (#16282)
* ✨ feat(ci): auto-handle MCP marketplace submission issues

Adds a workflow + script that auto-triages "Add my MCP server to the marketplace" issues, now that listing is self-service via @lobehub/market-cli.

- Local/installable servers (npx/npm/uvx/pip/docker/stdio): post a CLI redirect comment (with the submitter's repo filled in) and close as not_planned; the comment invites reopen if mis-closed.
- Remote-only servers (URL/SSE/streamable-http, no install): cannot use the CLI, so label mcp:remote and leave open for manual review.
- Guardrails: skip marketplace pipeline/listing bugs and publishing-CLI feedback.
- Silence the triage @-mention for these listing requests (marketplace bugs and product feature requests still get mentioned).

* 🔨 chore(ci): convert invalid top-level workflow description keys to comments

Top-level `description` is not part of the GitHub Actions workflow schema (it is only valid nested under workflow_call/workflow_dispatch inputs), so editors flag "Property description is not allowed". Convert these doc strings to # comments to clear the lint while keeping the text. No runtime change.

* 🐛 fix(ci): harden MCP delivery detection per review

- A bare `stdio` mention no longer outranks a remote signal, so a remote server that says "Transport: SSE, not stdio" is classified remote (labeled mcp:remote) instead of being closed with the local CLI redirect.
- Recognize a bare endpoint URL (`URL:`/`Endpoint:` + non-GitHub https) as a remote reference, so URL-only submissions with no repo are labeled mcp:remote instead of falling through to normal triage.

Precedence is now: remote-only > strong install (npx/npm/uvx/pip/docker/command) > remote signal > lone stdio mention.
2026-06-25 17:14:50 +08:00
R3pl4c3r 8ab5ec5364 🐛 chore(workflow): fix Upstream Sync workflow running error (#15706)
fix(workflow): fix Upstream Sync workflow running error
2026-06-13 01:29:44 +08:00
Innei dbc8d76c8d ✨ feat(desktop): restore cloud desktop builds (#15666) 2026-06-11 19:14:26 +08:00
Arvin Xu 97e4e345d1 🔨 chore(codecov): update coverage grouping (#15650)
🔨 chore: update codecov coverage grouping
2026-06-11 14:40:06 +08:00
cokeSEE1 c609a60f0e 🔨 chore(ci): bump outdated action versions to latest (#15655)
- actions/checkout@v4 -> @v6 in issue-auto-comments.yml
  (last remaining @v4 usage; all other 48 uses are already @v6)
- actions/github-script@v7 -> @v8 in release-desktop-canary.yml
  (last remaining @v7 usage; all other 4 uses are already @v8)

Co-authored-by: 章岚 <zhanglan@datagrand.com>
2026-06-11 09:54:53 +08:00
renovate[bot] 06bf82f3e0 Update dependency node to v24.16.0 (#14621) 2026-06-11 09:24:21 +08:00
Innei 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
2026-06-09 18:09:26 +08:00
AmAzing- 54e1b59ce6 ✨ feat(agent-management): paginate searchAgent with real totals + wire 8 packages into CI (#15448)
* ✨ feat(agent-management): paginate searchAgent with real totals and cap notice

The searchAgent tool silently clamped limit to 20 with no pagination and
reported totalCount as the returned page size, so models (and users) could
never discover agents beyond the 20 most recently updated ones.

- AgentModel: extract shared where builder, add countAgents (same
  conditions as queryAgents)
- lambda router + client agent service: expose countAgents
- server tool runtime & AgentManagerRuntime: pass offset through, report
  real totals (workspace + marketplace), emit explicit notes when the
  requested limit is capped and when more pages exist, explain
  out-of-range offsets instead of claiming no matches
- manifest: add offset param, document pagination
- agent-manager-runtime: add vitest config + test scripts (suite was
  previously unrunnable), repair stale store mocks

* 👷 build(ci): wire 8 tested packages into the package test workflow

An audit found 8 packages carrying test:coverage scripts that were never
added to the CI PACKAGES allowlist, so their suites never ran:

- agent-gateway-client, device-gateway-client, device-identity,
  eval-dataset-parser: already green, added as-is
- eval-rubric, fetch-sse: had no package-level vitest config, so vitest
  fell back to the root config whose setup/aliases break outside src/ —
  added minimal configs
- heterogeneous-agents: one assertion drifted (labels registry gained
  amp/hermes/openclaw/opencode) with nobody noticing — updated
- agent-manager-runtime: wired in the previous commit

All 8 verified locally with the exact CI command
(bun run --filter <pkg> test:coverage).

* ✅ test(agent-management): cover searchAgent error path and market totalCount fallback

Codecov flagged 3 uncovered lines in the patch: the searchAgents catch
block (2 misses) and the totalCount ?? items.length fallback (1 partial).
Add the missing failure-path and fallback tests on both execution paths
(client AgentManagerRuntime + server tool runtime).
2026-06-04 10:52:25 +08:00
Arvin Xu 651d1a203a Revert "✨ feat(desktop): support cloud desktop builds (#14498)"
This reverts commit 0c5ccc8770.
2026-05-28 10:40:59 +08:00
Innei 0c5ccc8770 ✨ feat(desktop): support cloud desktop builds (#14498)
* ✨ feat(desktop): support cloud desktop builds

* 🐛 fix: open payment navigations externally in desktop
2026-05-27 16:22:48 +08:00
Innei f685d5c217 ✨ feat(agent-explorer): support multi-select delete in document tree (#15125)
* ✨ feat(agent-explorer): support multi-select delete in document tree

- Right-click on a multi-selected row deletes the whole selection; dedupe descendants when an ancestor folder is also selected
- Reserve chevron slot in SkillsList rows so atomic and bundled skills align
- Centralize EMPTY_ARRAY (typed `never[]`, frozen) in @lobechat/const

* ♻️ refactor: migrate delete confirm dialog from antd modal to confirmModal

* ✅ test: stabilize bun vitest environment

* 🔧 ci: avoid authenticated checkout for PR tests
2026-05-23 16:44:00 +08:00
Arvin Xu 500a02bd88 🔒 chore: remove compromised actions-cool/issues-helper@v3 (#14956)
* fix: remove compromised actions-cool/issues-helper@v3

* fix: remove actions-cool/issues-helper

* fix: pin actions-cool/issues-helper to safe commit SHA in sync.yml
2026-05-19 11:42:01 +08:00
YuTengjing 7e514ac3e3 🐛 fix: use JSON object for video image reference (#14900) 2026-05-18 00:55:29 +08:00
YuTengjing b5d7696dbd ✨ feat: add visual understanding tool (#14378) 2026-05-02 22:18:50 +08:00