Compare commits

..

1 Commits

Author SHA1 Message Date
Innei 37214c27e8 ♻️ 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.
2026-06-08 23:48:34 +08:00
1184 changed files with 492 additions and 2698 deletions
-75
View File
@@ -1,75 +0,0 @@
name: Release CLI
permissions:
contents: write
on:
push:
tags:
- 'v*.*.*'
workflow_dispatch:
inputs:
tag:
description: 'Tag name for the release (e.g. v0.1.0)'
required: true
default: 'v0.0.0'
jobs:
build:
name: Build ${{ matrix.target }}
runs-on: ${{ matrix.os }}
# skip pre-release tags (containing '-') on auto-trigger; always run on workflow_dispatch
if: ${{ github.event_name == 'workflow_dispatch' || !contains(github.ref_name, '-') }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: lobe-linux-x64
- os: macos-latest
target: lobe-macos-arm64
steps:
- uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build binary
run: |
mkdir -p dist
bun build ./apps/cli/src/index.ts --compile --minify --outfile ./dist/${{ matrix.target }}
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.target }}
path: ./dist/${{ matrix.target }}
release:
name: Upload to Release
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: ./dist
- name: Upload to GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }}
files: |
./dist/lobe-linux-x64/lobe-linux-x64
./dist/lobe-macos-arm64/lobe-macos-arm64
./apps/cli/install.sh
-78
View File
@@ -1,78 +0,0 @@
#!/bin/sh
set -e
REPO="lobehub/lobe-chat"
BIN_NAME="lh"
# Detect OS
case "$(uname -s)" in
Linux) OS="linux" ;;
Darwin) OS="macos" ;;
*)
printf 'Error: Unsupported OS: %s\n' "$(uname -s)" >&2
exit 1
;;
esac
# Detect architecture
case "$(uname -m)" in
x86_64) ARCH="x64" ;;
aarch64|arm64) ARCH="arm64" ;;
*)
printf 'Error: Unsupported architecture: %s\n' "$(uname -m)" >&2
exit 1
;;
esac
BINARY="lobe-${OS}-${ARCH}"
URL="https://github.com/${REPO}/releases/latest/download/${BINARY}"
printf 'Detected: %s/%s\n' "$OS" "$ARCH"
printf 'Downloading %s...\n' "$BINARY"
TMP="$(mktemp)"
trap 'rm -f "$TMP"' EXIT
if command -v curl >/dev/null 2>&1; then
curl -fsSL "$URL" -o "$TMP"
elif command -v wget >/dev/null 2>&1; then
wget -qO "$TMP" "$URL"
else
printf 'Error: curl or wget is required\n' >&2
exit 1
fi
chmod +x "$TMP"
# Choose install directory: prefer /usr/local/bin, fall back to ~/.local/bin
USE_SUDO=0
if [ -w "/usr/local/bin" ]; then
INSTALL_DIR="/usr/local/bin"
elif command -v sudo >/dev/null 2>&1 && sudo -n true 2>/dev/null; then
INSTALL_DIR="/usr/local/bin"
USE_SUDO=1
else
INSTALL_DIR="${HOME}/.local/bin"
mkdir -p "$INSTALL_DIR"
printf 'Note: No sudo access. Installing to %s\n' "$INSTALL_DIR"
printf 'Add the following to your shell profile if needed:\n'
printf ' export PATH="%s:$PATH"\n' "$INSTALL_DIR"
fi
# Install binary and create symlinks
if [ "$USE_SUDO" = "1" ]; then
sudo cp "$TMP" "${INSTALL_DIR}/${BIN_NAME}"
sudo chmod +x "${INSTALL_DIR}/${BIN_NAME}"
sudo ln -sf "${INSTALL_DIR}/${BIN_NAME}" "${INSTALL_DIR}/lobe"
sudo ln -sf "${INSTALL_DIR}/${BIN_NAME}" "${INSTALL_DIR}/lobehub"
else
cp "$TMP" "${INSTALL_DIR}/${BIN_NAME}"
chmod +x "${INSTALL_DIR}/${BIN_NAME}"
ln -sf "${INSTALL_DIR}/${BIN_NAME}" "${INSTALL_DIR}/lobe"
ln -sf "${INSTALL_DIR}/${BIN_NAME}" "${INSTALL_DIR}/lobehub"
fi
printf '\nInstalled successfully!\n'
printf ' Binary: %s/%s\n' "$INSTALL_DIR" "$BIN_NAME"
printf ' Symlinks: lobe, lobehub -> lh\n\n'
"${INSTALL_DIR}/${BIN_NAME}" --version
-1
View File
@@ -125,7 +125,6 @@
"node-mac-permissions"
],
"overrides": {
"node-gyp": "^12.4.0",
"react": "19.2.4",
"react-dom": "19.2.4",
"vitest": "3.2.4"
@@ -16,7 +16,6 @@ import type {
InitWorkspaceParams,
KillCommandParams,
ListLocalFileParams,
ListProjectSkillsParams,
LocalReadFileParams,
LocalReadFilesParams,
LocalSearchFilesParams,
@@ -408,10 +407,6 @@ export default class GatewayConnectionCtr extends ControllerModule {
return this.localFileCtr.getProjectFileIndex(params as { scope?: string });
}
case 'listProjectSkills': {
return this.workspaceCtr.listProjectSkills(params as ListProjectSkillsParams);
}
case 'getGitBranchDiff': {
return this.gitCtr.getGitBranchDiff(params as { baseRef?: string; path: string });
}
@@ -440,14 +440,8 @@ describe('HeterogeneousAgentCtr', () => {
expect(command).toBe('codex');
expect(cliArgs).not.toContain(prompt);
expect(cliArgs).toEqual(
expect.arrayContaining([
'exec',
'--json',
'--skip-git-repo-check',
'--dangerously-bypass-approvals-and-sandbox',
]),
expect.arrayContaining(['exec', '--json', '--skip-git-repo-check', '--full-auto']),
);
expect(cliArgs).not.toContain('--full-auto');
expect(cliArgs).not.toContain('-');
expect(writes).toEqual([prompt]);
});
@@ -1,11 +1,13 @@
import {
CODEX_DEFAULT_EXECUTION_ARGS,
CODEX_EXECUTION_MODE_FLAGS,
CODEX_REQUIRED_ARGS,
} from '@lobechat/heterogeneous-agents/spawn';
import type { HeterogeneousAgentBuildPlanParams, HeterogeneousAgentDriver } from '../types';
const CODEX_REQUIRED_ARGS = ['--json', '--skip-git-repo-check'] as const;
const CODEX_AUTO_EXECUTION_FLAGS = [
'--full-auto',
'--dangerously-bypass-approvals-and-sandbox',
'--sandbox',
'-s',
] as const;
const hasAnyFlag = (args: string[], flags: readonly string[]) =>
args.some((arg) => flags.includes(arg as (typeof flags)[number]));
@@ -16,11 +18,9 @@ const buildCodexOptionArgs = async ({
}: Pick<HeterogeneousAgentBuildPlanParams, 'args' | 'helpers' | 'imageList'>) => {
const imagePaths = await helpers.resolveCliImagePaths(imageList);
const imageArgs = imagePaths.flatMap((filePath) => ['--image', filePath]);
const executionModeArgs = hasAnyFlag(args, CODEX_EXECUTION_MODE_FLAGS)
? []
: [...CODEX_DEFAULT_EXECUTION_ARGS];
const autoExecutionArgs = hasAnyFlag(args, CODEX_AUTO_EXECUTION_FLAGS) ? [] : ['--full-auto'];
return [...CODEX_REQUIRED_ARGS, ...executionModeArgs, ...args, ...imageArgs];
return [...CODEX_REQUIRED_ARGS, ...autoExecutionArgs, ...args, ...imageArgs];
};
export const codexDriver: HeterogeneousAgentDriver = {
+8
View File
@@ -0,0 +1,8 @@
{
"name": "@lobechat/server",
"version": "0.0.0",
"private": true,
"scripts": {
"type-check": "tsc --noEmit"
}
}
@@ -790,23 +790,6 @@ export const createRuntimeExecutors = (
// {{sandbox_enabled}} — mirrors client-side check for lobe-cloud-sandbox.
const sandboxEnabled = String(resolved.enabledToolIds.includes('lobe-cloud-sandbox'));
// {{sandbox_uploaded_files}} — lists the topic/session files that are
// synced into the sandbox upload dir, so the agent knows they exist.
// Mirrors the bootstrap query in SandboxMiddlewareService.
let sandboxUploadedFiles = '';
if (sandboxEnabled === 'true' && ctx.serverDB && ctx.userId && lobehubSkillTopicId) {
try {
const { FileModel } = await import('@/database/models/file');
const { formatUploadedFilesPrompt } =
await import('@lobechat/builtin-tool-cloud-sandbox');
const fileModel = new FileModel(ctx.serverDB, ctx.userId);
const uploadedFiles = await fileModel.findFilesToInitInSandbox(lobehubSkillTopicId);
sandboxUploadedFiles = formatUploadedFilesPrompt(uploadedFiles);
} catch (error) {
log('Failed to resolve files for {{sandbox_uploaded_files}} substitution: %O', error);
}
}
// {{session_date}} — current date formatted for user's timezone.
const sessionDate = new Intl.DateTimeFormat('en-US', {
day: 'numeric',
@@ -896,7 +879,6 @@ export const createRuntimeExecutors = (
session_date: sessionDate,
// Creds tool variables
sandbox_enabled: sandboxEnabled,
sandbox_uploaded_files: sandboxUploadedFiles,
CREDS_LIST: credsListStr,
KLAVIS_SERVICES_LIST: klavisServicesListStr,
// Memory tool variables
@@ -3763,9 +3763,9 @@ describe('RuntimeExecutors', () => {
// Import real implementations directly from source (bypassing the @lobechat/model-runtime mock)
const { consumeStreamUntilDone: realConsume } =
await import('../../../../../packages/model-runtime/src/utils/consumeStream');
await import('../../../../../../packages/model-runtime/src/utils/consumeStream');
const { createCallbacksTransformer } =
await import('../../../../../packages/model-runtime/src/core/streams/protocol');
await import('../../../../../../packages/model-runtime/src/core/streams/protocol');
// Use real consumeStreamUntilDone so the stream is actually consumed
vi.mocked(consumeStreamUntilDone).mockImplementation(realConsume);
@@ -188,7 +188,6 @@ describe('AssistantStore', () => {
global.fetch = vi.fn().mockRejectedValue(new Error('something else'));
const store = new AssistantStore();
vi.spyOn(console, 'error').mockImplementation(() => {});
await expect(store.getAgentIndex()).rejects.toThrow('something else');

Some files were not shown because too many files have changed in this diff Show More