From 2a05914150a2121b4bbe6638444971624eb7a856 Mon Sep 17 00:00:00 2001 From: jinliyl <6469360+jinliyl@users.noreply.github.com> Date: Thu, 13 Aug 2026 11:07:37 +0800 Subject: [PATCH] feat: distribute Studio as an optional package (#454) --- .github/workflows/pre-commit.yml | 2 +- .github/workflows/python-publish.yml | 25 ++- .github/workflows/unittest.yml | 2 +- .github/workflows/windows-smoke.yml | 2 +- README.md | 9 +- docs/en/contributing.md | 2 +- docs/en/framework.md | 8 +- docs/en/quick_start.md | 5 +- docs/zh/contributing.md | 2 +- docs/zh/framework.md | 5 +- docs/zh/quick_start.md | 5 +- packages/reme_ai_studio/README.md | 203 ++++++++++++++++++ packages/reme_ai_studio/pyproject.toml | 24 +++ .../src/reme_ai_studio/__init__.py | 11 + .../src/reme_ai_studio/static/.gitignore | 2 + pyproject.toml | 5 +- reme/utils/web_static.py | 23 +- scripts/package_studio.py | 58 +++++ tests/unit/test_http_web_workspace.py | 13 +- tests/unit/test_package_versions.py | 28 +++ website/README.md | 13 +- website/README_ZH.md | 13 +- 22 files changed, 426 insertions(+), 34 deletions(-) create mode 100644 packages/reme_ai_studio/README.md create mode 100644 packages/reme_ai_studio/pyproject.toml create mode 100644 packages/reme_ai_studio/src/reme_ai_studio/__init__.py create mode 100644 packages/reme_ai_studio/src/reme_ai_studio/static/.gitignore create mode 100644 scripts/package_studio.py create mode 100644 tests/unit/test_package_versions.py diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 7444fe65..191cbb95 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -23,7 +23,7 @@ jobs: pip install -U setuptools wheel - name: Install run: | - pip install -q -e ".[dev,core]" + pip install -q -e packages/reme_ai_studio -e ".[dev,core]" - name: Install pre-commit run: | pre-commit install diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 82a80a4a..8bb12ca7 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -29,30 +29,33 @@ jobs: node-version: '22' cache: npm cache-dependency-path: website/package-lock.json + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: '3.11' - name: Build web workspace working-directory: website run: | npm ci npm run build:static - rm -rf ../reme/web - mkdir -p ../reme/web - cp -R dist-static/. ../reme/web/ - - name: Set up Python - uses: actions/setup-python@v6 - with: - python-version: '3.11' + - name: Prepare Studio package + run: python scripts/package_studio.py - name: Install dependencies run: | python -m pip install --upgrade pip pip install setuptools wheel build - name: Build package - run: python -m build + run: | + python -m build --outdir dist + python -m build packages/reme_ai_studio --outdir dist - name: Test installation run: | - WHEEL="$(ls dist/*.whl)" - pip install "${WHEEL}[core]" + REME_WHEEL="$(pwd)/$(ls dist/reme_ai-[0-9]*.whl)" + python -m zipfile -l "${REME_WHEEL}" | (! grep 'reme/web/') + pip install --find-links "$(pwd)/dist" "${REME_WHEEL}[core]" python -c "import reme; print(reme.__version__)" - python -c "from importlib.resources import files; assert (files('reme') / 'web' / 'index.html').is_file()" + python -c "from reme_ai_studio import static_dir; assert (static_dir() / 'index.html').is_file()" + python -c "from reme.utils import resolve_web_static_dir; assert (resolve_web_static_dir() / 'index.html').is_file()" - name: Publish package to PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: diff --git a/.github/workflows/unittest.yml b/.github/workflows/unittest.yml index 0eb9e664..4fd5886e 100644 --- a/.github/workflows/unittest.yml +++ b/.github/workflows/unittest.yml @@ -32,7 +32,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip setuptools wheel - pip install -e ".[dev,core]" + pip install -e packages/reme_ai_studio -e ".[dev,core]" pip install coverage - name: Run unit tests diff --git a/.github/workflows/windows-smoke.yml b/.github/workflows/windows-smoke.yml index 8a1f787a..e72080a1 100644 --- a/.github/workflows/windows-smoke.yml +++ b/.github/workflows/windows-smoke.yml @@ -32,7 +32,7 @@ jobs: - name: Install package run: | python -m pip install --upgrade pip setuptools wheel - pip install -e ".[dev,core]" + pip install -e packages/reme_ai_studio -e ".[dev,core]" - name: Run version job run: reme start service.backend=cli job=version diff --git a/README.md b/README.md index a1449025..26e26741 100644 --- a/README.md +++ b/README.md @@ -86,12 +86,16 @@ Install from pip: pip install "reme-ai[core]" ``` +The base `reme-ai` package contains only the Python service and library. ReMe Studio is distributed separately and is +installed by the `web` and `core` extras. Use `pip install reme-ai` for embedded or headless integrations that do not +need the frontend, or `pip install "reme-ai[web]"` when Studio is needed without the other `core` integrations. + Install from source: ```bash git clone https://github.com/agentscope-ai/ReMe.git cd ReMe -pip install -e ".[core]" +pip install -e packages/reme_ai_studio -e ".[core]" ``` ### Environment Variables @@ -134,7 +138,8 @@ reme start service.port=8181 After startup, check the service status. If you use a custom port, replace `2333` in the URL below with that port. -When the web build is available, the HTTP service also serves **ReMe Studio** at . Studio can +When the `web` or `core` extra is installed, the HTTP service also serves **ReMe Studio** at +. Studio can browse, edit, and search the workspace, chat with the read-only workspace agent, and inspect the digest wikilink graph. Set `service.web_enabled=false` to disable it, or use `service.web_static_dir` / `REME_WEB_STATIC_DIR` to provide a custom static build. The Job API remains available when no web build is found. diff --git a/docs/en/contributing.md b/docs/en/contributing.md index 8671c292..44c8be25 100644 --- a/docs/en/contributing.md +++ b/docs/en/contributing.md @@ -39,7 +39,7 @@ The project requires Python 3.11 or later. A virtual environment is recommended: ```bash python -m venv .venv source .venv/bin/activate -pip install -e ".[dev,full]" +pip install -e packages/reme_ai_studio -e ".[dev,full]" pre-commit install ``` diff --git a/docs/en/framework.md b/docs/en/framework.md index 5774e734..d95cab1d 100644 --- a/docs/en/framework.md +++ b/docs/en/framework.md @@ -166,10 +166,10 @@ HTTP service behavior: | `enable_serve: false` | No endpoint is registered. | After registering Job endpoints, the HTTP service can also mount the ReMe Studio single-page application. The default is -`service.web_enabled=true`. Builds are resolved from `service.web_static_dir`, `REME_WEB_STATIC_DIR`, packaged -`reme/web`, and source-tree locations such as `website/dist-static`. If no `index.html` is found, only the frontend is -skipped and the Job API remains available. The Studio `GET` fallback does not replace existing `POST /` -routes. +`service.web_enabled=true`. Builds are resolved from `service.web_static_dir`, `REME_WEB_STATIC_DIR`, the optional +`reme-ai-studio` package installed by the `web` and `core` extras, and source-tree locations such as +`website/dist-static`. If no `index.html` is found, only the frontend is skipped and the Job API remains available. The +Studio `GET` fallback does not replace existing `POST /` routes. MCP service behavior: diff --git a/docs/en/quick_start.md b/docs/en/quick_start.md index 2bc7a806..d2791d89 100644 --- a/docs/en/quick_start.md +++ b/docs/en/quick_start.md @@ -15,7 +15,7 @@ Install from source: ```bash git clone https://github.com/agentscope-ai/ReMe.git cd ReMe -pip install -e ".[core]" +pip install -e packages/reme_ai_studio -e ".[core]" ``` Installing the `core` extra is recommended. The current code imports the AgentScope wrapper, and self-evolving memory @@ -56,7 +56,8 @@ reme help `reme help` lists server actions. Ordinary commands invoke server Jobs over HTTP. -When the package includes the web build, open for ReMe Studio. It uses the same service to +The base `reme-ai` package does not include frontend assets. Install `reme-ai[web]` or `reme-ai[core]`, then open + for ReMe Studio. It uses the same service to browse, edit, and search the workspace and inspect the digest wikilink graph. Disable it with `service.web_enabled=false`, or provide a custom build with `service.web_static_dir` / `REME_WEB_STATIC_DIR`. The Job API still starts if no web build is found. diff --git a/docs/zh/contributing.md b/docs/zh/contributing.md index 495db1f0..0e134e66 100644 --- a/docs/zh/contributing.md +++ b/docs/zh/contributing.md @@ -37,7 +37,7 @@ ReMe 的核心代码位于: ```bash python -m venv .venv source .venv/bin/activate -pip install -e ".[dev,full]" +pip install -e packages/reme_ai_studio -e ".[dev,full]" pre-commit install ``` diff --git a/docs/zh/framework.md b/docs/zh/framework.md index 7052f05e..6c17612d 100644 --- a/docs/zh/framework.md +++ b/docs/zh/framework.md @@ -161,8 +161,9 @@ HTTP service 行为: | `enable_serve: false` | 不注册 endpoint | HTTP service 还可以在所有 Job endpoint 注册完成后挂载 ReMe Studio 单页应用。默认 `service.web_enabled=true`;构建产物按 -`service.web_static_dir`、`REME_WEB_STATIC_DIR`、包内 `reme/web` 和源码树 `website/dist-static` 等候选位置解析。找不到 -`index.html` 时只跳过前端,Job API 仍然可用。Studio 的 `GET` fallback 不会覆盖已有的 `POST /`。 +`service.web_static_dir`、`REME_WEB_STATIC_DIR`、由 `web` 或 `core` extra 安装的可选 `reme-ai-studio` 包,以及源码树 +`website/dist-static` 等候选位置解析。找不到 `index.html` 时只跳过前端,Job API 仍然可用。Studio 的 `GET` fallback 不会覆盖 +已有的 `POST /`。 MCP service 行为: diff --git a/docs/zh/quick_start.md b/docs/zh/quick_start.md index afa0d5ef..e00688e1 100644 --- a/docs/zh/quick_start.md +++ b/docs/zh/quick_start.md @@ -15,7 +15,7 @@ pip install "reme-ai[core]" ```bash git clone https://github.com/agentscope-ai/ReMe.git cd ReMe -pip install -e ".[core]" +pip install -e packages/reme_ai_studio -e ".[core]" ``` `core` extra 建议安装:当前代码会导入 AgentScope wrapper,自进化记忆也依赖它。 @@ -55,7 +55,8 @@ reme help `reme help` 会列出服务端 action。普通命令会通过 HTTP 调用服务端 Job。 -如果安装包中包含 Web 构建产物,浏览器打开 即可进入 ReMe Studio,在同一服务中浏览、编辑和搜索 +基础 `reme-ai` 包不包含前端资源。安装 `reme-ai[web]` 或 `reme-ai[core]` 后,浏览器打开 + 即可进入 ReMe Studio,在同一服务中浏览、编辑和搜索 workspace,并查看 digest Wikilink 图。可用 `service.web_enabled=false` 关闭,或通过 `service.web_static_dir` / `REME_WEB_STATIC_DIR` 指定自定义静态目录;找不到构建产物时,Job API 仍会正常启动。 diff --git a/packages/reme_ai_studio/README.md b/packages/reme_ai_studio/README.md new file mode 100644 index 00000000..bda397ca --- /dev/null +++ b/packages/reme_ai_studio/README.md @@ -0,0 +1,203 @@ +# ReMe Studio + +English | [简体中文](#简体中文) + +ReMe Studio is the local web workspace for ReMe. It lets you browse and edit user-owned workspace files, explore memory +links, and chat with the ReMe Agent without moving durable memory into a separate application database. Search indexes, +graphs, and other derived metadata remain rebuildable from the source files. + +![ReMe Studio workspace](https://raw.githubusercontent.com/agentscope-ai/ReMe/main/website/public/og.jpg) + +## Installation + +Install Studio together with ReMe's optional integrations: + +```bash +pip install "reme-ai[core]" +``` + +For Studio without the other optional integrations, use `pip install "reme-ai[web]"`. The base `reme-ai` package is +headless and does not include the frontend assets. + +## Features + +- **Workspace browsing**: browse the full workspace or focus on journal and knowledge files through dedicated views. The + navigator refreshes as files change on disk. +- **Markdown editing and preview**: open multiple files in tabs, render Markdown front matter and GitHub Flavored + Markdown, edit with Monaco, save with optimistic modification-time checks, and download files locally. +- **Memory graph**: inspect indexed wikilinks under the `wiki`, `personal`, and + `procedure` knowledge roots, follow inbound and outbound links, and open the corresponding Markdown source. +- **Agent chat**: stream conversations with the read-only workspace Agent, see tool calls and token usage, and drag + workspace files into the conversation as references. +- **Service management**: inspect service and component memory usage, review the effective redacted configuration and + version, and rebuild derived indexes without modifying source memory files. +- **Personalization**: switch between English and Chinese, and use light, dark, or system appearance. + +## Requirements + +- Python 3.11 or newer with ReMe installed. +- A running ReMe HTTP service. Agent chat additionally requires a working Agent and model configuration. +- Node.js 22.13 or newer is required only when developing or building Studio from source. + +See the [repository README](https://github.com/agentscope-ai/ReMe#readme) for ReMe installation and backend configuration. + +## Development + +Start ReMe from the repository root, then run the frontend in another terminal: + +```bash +# Terminal 1, from the repository root +reme start + +# Terminal 2 +cd website +npm install +npm run dev +``` + +Open . The frontend connects to +`http://127.0.0.1:2333` by default. Override it when needed: + +```bash +NEXT_PUBLIC_REME_API_URL=http://127.0.0.1:8000 npm run dev +``` + +## ReMe-hosted static build + +ReMe can serve Studio from the same FastAPI process as its HTTP API. Build the static variant and restart ReMe: + +```bash +cd website +npm ci +npm run build:static +cd .. +reme start +``` + +Open . The static build uses same-origin requests by default. For standalone static development, +run `npm run dev:static` and set +`VITE_REME_API_URL` to the running ReMe service URL when necessary. + +The regular `npm run build` command remains the vinext/Sites deployment build; +`npm run build:static` creates `dist-static/` exclusively for FastAPI and Python package distribution. + +## Configuration + +The workspace hides dotfiles and dot-directories. It displays only Markdown and text files by default. Configure the +allowed extensions as a comma-separated list in `.env.local`: + +```bash +NEXT_PUBLIC_REME_WORKSPACE_EXTENSIONS=md,txt,mdx +``` + +The memory graph requires an index built by ReMe. Rebuilding the index from the Studio settings regenerates derived data +from workspace files and does not modify the source memory. + +## Checks + +```bash +npm run format:check +npm run lint +npm run build +npm run build:static +npm test +``` + +--- + +# 简体中文 + +[English](#reme-studio) | 简体中文 + +ReMe Studio 是 ReMe 的本地 Web 工作区。你可以在这里浏览和编辑自己拥有的工作区文件、探索记忆之间的联系,并与 ReMe Agent +对话,而无需将持久记忆迁移到独立的应用数据库中。搜索索引、图谱和其他派生元数据均可根据源文件重建。 + +![ReMe Studio 工作区](https://raw.githubusercontent.com/agentscope-ai/ReMe/main/website/public/og.jpg) + +## 安装 + +安装 Studio 和 ReMe 的可选集成功能: + +```bash +pip install "reme-ai[core]" +``` + +如果只需要 Studio,不需要其他可选集成,可以使用 `pip install "reme-ai[web]"`。基础 `reme-ai` 包以无界面模式分发, +不包含前端资源。 + +## 功能 + +- **浏览工作区**:浏览完整工作区,或通过独立视图聚焦日记和知识文件;磁盘中的文件发生变化后,导航器会自动刷新。 +- **Markdown 编辑与预览**:在多个标签页中打开文件,渲染 Markdown front matter 和 GitHub Flavored Markdown,使用 Monaco + 编辑器编辑,通过修改时间检查安全保存,并可将文件下载到本地。 +- **记忆图谱**:查看知识库 `wiki`、`personal` 和 `procedure` 目录中已索引的 wikilink,检查入链和出链,并从图谱打开对应的 + Markdown 源文件。 +- **Agent 对话**:与只读工作区 Agent 进行流式对话,查看工具调用和 token 用量,还可将工作区文件拖入对话作为引用。 +- **服务管理**:查看服务及组件的内存使用情况、当前生效的脱敏配置和版本,并在不修改记忆源文件的情况下重建派生索引。 +- **个性化设置**:切换中英文界面,并使用浅色、深色或跟随系统的外观。 + +## 环境要求 + +- Python 3.11 或更高版本,并已安装 ReMe。 +- 正在运行的 ReMe HTTP 服务。Agent 对话还需要可用的 Agent 和模型配置。 +- 只有从源码开发或构建 Studio 时才需要 Node.js 22.13 或更高版本。 + +ReMe 的安装和后端配置请参阅[仓库中文 README](https://github.com/agentscope-ai/ReMe/blob/main/README_ZH.md)。 + +## 本地开发 + +先在仓库根目录启动 ReMe,然后在另一个终端运行前端: + +```bash +# 终端 1:仓库根目录 +reme start + +# 终端 2 +cd website +npm install +npm run dev +``` + +打开 。前端默认连接 `http://127.0.0.1:2333`,需要时可覆盖该地址: + +```bash +NEXT_PUBLIC_REME_API_URL=http://127.0.0.1:8000 npm run dev +``` + +## 由 ReMe 托管的静态构建 + +ReMe 可以通过提供 HTTP API 的同一个 FastAPI 进程托管 Studio。构建静态版本并重启 ReMe: + +```bash +cd website +npm ci +npm run build:static +cd .. +reme start +``` + +打开 。静态构建默认使用同源请求。进行独立的静态开发时,运行 +`npm run dev:static`;如有需要,将 `VITE_REME_API_URL` 设置为正在运行的 ReMe 服务地址。 + +常规的 `npm run build` 命令仍用于 vinext/Sites 部署构建;`npm run build:static` 仅为 FastAPI 和 Python 包分发生成 +`dist-static/`。 + +## 配置 + +工作区会隐藏点文件和点目录,并且默认只显示 Markdown 和文本文件。可以在 `.env.local` 中通过逗号分隔的列表配置允许显示的扩展名: + +```bash +NEXT_PUBLIC_REME_WORKSPACE_EXTENSIONS=md,txt,mdx +``` + +记忆图谱依赖 ReMe 构建的索引。在 Studio 设置中重建索引时,只会根据工作区文件重新生成派生数据,不会修改记忆源文件。 + +## 检查 + +```bash +npm run format:check +npm run lint +npm run build +npm run build:static +npm test +``` diff --git a/packages/reme_ai_studio/pyproject.toml b/packages/reme_ai_studio/pyproject.toml new file mode 100644 index 00000000..8fe88424 --- /dev/null +++ b/packages/reme_ai_studio/pyproject.toml @@ -0,0 +1,24 @@ +[project] +name = "reme-ai-studio" +version = "0.4.1.6" +description = "Optional ReMe Studio static frontend." +readme = "README.md" +license = "Apache-2.0" +requires-python = ">=3.11" + +[project.urls] +Homepage = "https://github.com/agentscope-ai/ReMe/tree/main/website" +Documentation = "https://reme.agentscope.io" +Repository = "https://github.com/agentscope-ai/ReMe" + +[tool.setuptools] +package-dir = { "" = "src" } +packages = ["reme_ai_studio"] +include-package-data = false + +[tool.setuptools.package-data] +"reme_ai_studio" = ["static/**"] + +[build-system] +requires = ["setuptools>=45", "wheel"] +build-backend = "setuptools.build_meta" diff --git a/packages/reme_ai_studio/src/reme_ai_studio/__init__.py b/packages/reme_ai_studio/src/reme_ai_studio/__init__.py new file mode 100644 index 00000000..41ae36df --- /dev/null +++ b/packages/reme_ai_studio/src/reme_ai_studio/__init__.py @@ -0,0 +1,11 @@ +"""Static asset provider for the optional ReMe Studio frontend.""" + +from pathlib import Path + + +def static_dir() -> Path: + """Return the installed Studio static asset directory.""" + return Path(__file__).resolve().parent / "static" + + +__all__ = ["static_dir"] diff --git a/packages/reme_ai_studio/src/reme_ai_studio/static/.gitignore b/packages/reme_ai_studio/src/reme_ai_studio/static/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/packages/reme_ai_studio/src/reme_ai_studio/static/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/pyproject.toml b/pyproject.toml index 364a6106..f2c24e0e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,6 +42,9 @@ dependencies = [ ] [project.optional-dependencies] +web = [ + "reme-ai-studio==0.4.1.6", +] core = [ "agentscope==2.0.4.post1", "claude-agent-sdk>=0.2.126", @@ -55,6 +58,7 @@ core = [ "neo4j>=6.2.0", "networkx>=3.4.2", "polars>=1.43.0", + "reme-ai-studio==0.4.1.6", ] dev = [ "pre-commit>=4.6.1", @@ -80,7 +84,6 @@ include-package-data = true [tool.setuptools.package-data] "*" = ["py.typed", "**/*.yaml", "**/*.json"] -"reme" = ["web/**"] "reme.components.tokenizer" = ["stopwords"] [tool.setuptools.dynamic] diff --git a/reme/utils/web_static.py b/reme/utils/web_static.py index 97d38a3e..aa58f4b4 100644 --- a/reme/utils/web_static.py +++ b/reme/utils/web_static.py @@ -8,20 +8,39 @@ from pathlib import Path REME_WEB_STATIC_DIR = "REME_WEB_STATIC_DIR" +def _packaged_studio_dir() -> Path | None: + """Return the static directory supplied by the optional Studio package.""" + try: + from reme_ai_studio import static_dir + except ImportError: + return None + return static_dir() + + def resolve_web_static_dir(configured_dir: str | None = None) -> Path | None: """Return the first directory containing a built workspace ``index.html``.""" package_dir = Path(__file__).resolve().parent.parent repository_dir = package_dir.parent cwd = Path.cwd() - candidates = [ + explicit_candidates = [ configured_dir, os.getenv(REME_WEB_STATIC_DIR), + ] + for candidate in explicit_candidates: + if not candidate: + continue + path = Path(candidate).expanduser().resolve() + if path.is_dir() and (path / "index.html").is_file(): + return path + + fallback_candidates = [ + _packaged_studio_dir(), package_dir / "web", repository_dir / "website" / "dist-static", cwd / "website" / "dist-static", cwd / "web_dist", ] - for candidate in candidates: + for candidate in fallback_candidates: if not candidate: continue path = Path(candidate).expanduser().resolve() diff --git a/scripts/package_studio.py b/scripts/package_studio.py new file mode 100644 index 00000000..66ed4ca5 --- /dev/null +++ b/scripts/package_studio.py @@ -0,0 +1,58 @@ +"""Prepare the optional ReMe Studio Python distribution.""" + +from __future__ import annotations + +import argparse +import shutil +from pathlib import Path + +REPOSITORY_DIR = Path(__file__).resolve().parents[1] +WEBSITE_DIR = REPOSITORY_DIR / "website" +PACKAGE_DIR = REPOSITORY_DIR / "packages" / "reme_ai_studio" +STATIC_DIR = PACKAGE_DIR / "src" / "reme_ai_studio" / "static" + +_RAW_WEBSITE_URL = "https://raw.githubusercontent.com/agentscope-ai/ReMe/main/website" +_REPOSITORY_URL = "https://github.com/agentscope-ai/ReMe" + + +def build_readme() -> str: + """Compose the PyPI description from the English and Chinese Studio docs.""" + english = (WEBSITE_DIR / "README.md").read_text(encoding="utf-8") + chinese = (WEBSITE_DIR / "README_ZH.md").read_text(encoding="utf-8") + english = english.replace("English | [简体中文](./README_ZH.md)", "English | [简体中文](#简体中文)") + chinese = chinese.replace( + "# ReMe Studio\n\n[English](./README.md) | 简体中文", + "# 简体中文\n\n[English](#reme-studio) | 简体中文", + ) + for relative, absolute in { + "./public/og.jpg": f"{_RAW_WEBSITE_URL}/public/og.jpg", + "../README.md": f"{_REPOSITORY_URL}#readme", + "../README_ZH.md": f"{_REPOSITORY_URL}/blob/main/README_ZH.md", + }.items(): + english = english.replace(relative, absolute) + chinese = chinese.replace(relative, absolute) + return f"{english.rstrip()}\n\n---\n\n{chinese.rstrip()}\n" + + +def prepare_package(*, copy_static: bool = True) -> None: + """Generate the PyPI README and optionally stage the static build.""" + (PACKAGE_DIR / "README.md").write_text(build_readme(), encoding="utf-8") + if not copy_static: + return + source = WEBSITE_DIR / "dist-static" + if not (source / "index.html").is_file(): + raise FileNotFoundError(f"Studio static build is unavailable: {source}") + shutil.rmtree(STATIC_DIR, ignore_errors=True) + shutil.copytree(source, STATIC_DIR) + + +def main() -> None: + """Run the package preparation command.""" + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--readme-only", action="store_true", help="Generate only the PyPI README") + args = parser.parse_args() + prepare_package(copy_static=not args.readme_only) + + +if __name__ == "__main__": + main() diff --git a/tests/unit/test_http_web_workspace.py b/tests/unit/test_http_web_workspace.py index 96472a5b..891f943a 100644 --- a/tests/unit/test_http_web_workspace.py +++ b/tests/unit/test_http_web_workspace.py @@ -1,7 +1,8 @@ """HTTP service coverage for the optional bundled web workspace.""" +import sys from pathlib import Path -from types import SimpleNamespace +from types import ModuleType, SimpleNamespace import pytest from fastapi.testclient import TestClient @@ -100,3 +101,13 @@ def test_static_dir_configuration_precedes_environment(monkeypatch, tmp_path: Pa assert resolve_web_static_dir(str(configured)) == configured.resolve() assert resolve_web_static_dir() == environment.resolve() + + +def test_static_dir_uses_optional_studio_package(monkeypatch, tmp_path: Path) -> None: + """Use static assets supplied by the separately installed Studio wheel.""" + static_dir = _static_build(tmp_path / "studio") + studio = ModuleType("reme_ai_studio") + studio.static_dir = lambda: static_dir # type: ignore[attr-defined] + monkeypatch.setitem(sys.modules, "reme_ai_studio", studio) + + assert resolve_web_static_dir() == static_dir.resolve() diff --git a/tests/unit/test_package_versions.py b/tests/unit/test_package_versions.py new file mode 100644 index 00000000..fb5b9b94 --- /dev/null +++ b/tests/unit/test_package_versions.py @@ -0,0 +1,28 @@ +"""Keep the separately published distributions version-compatible.""" + +from pathlib import Path +import tomllib + +import reme +from scripts.package_studio import build_readme + + +def test_studio_package_and_extra_versions_match_reme() -> None: + """Require one version bump to update both wheels and their exact pin.""" + repository = Path(__file__).resolve().parents[2] + main_config = tomllib.loads((repository / "pyproject.toml").read_text(encoding="utf-8")) + studio_config = tomllib.loads( + (repository / "packages" / "reme_ai_studio" / "pyproject.toml").read_text(encoding="utf-8"), + ) + expected_dependency = f"reme-ai-studio=={reme.__version__}" + + assert studio_config["project"]["version"] == reme.__version__ + assert main_config["project"]["optional-dependencies"]["web"] == [expected_dependency] + assert expected_dependency in main_config["project"]["optional-dependencies"]["core"] + + +def test_studio_readme_is_generated_from_website_docs() -> None: + """Keep the packaged PyPI description synchronized with the source docs.""" + repository = Path(__file__).resolve().parents[2] + packaged_readme = repository / "packages" / "reme_ai_studio" / "README.md" + assert packaged_readme.read_text(encoding="utf-8") == build_readme() diff --git a/website/README.md b/website/README.md index 28f52f9d..d8fda46f 100644 --- a/website/README.md +++ b/website/README.md @@ -8,6 +8,17 @@ graphs, and other derived metadata remain rebuildable from the source files. ![ReMe Studio workspace](./public/og.jpg) +## Installation + +Install Studio together with ReMe's optional integrations: + +```bash +pip install "reme-ai[core]" +``` + +For Studio without the other optional integrations, use `pip install "reme-ai[web]"`. The base `reme-ai` package is +headless and does not include the frontend assets. + ## Features - **Workspace browsing**: browse the full workspace or focus on journal and knowledge files through dedicated views. The @@ -24,9 +35,9 @@ graphs, and other derived metadata remain rebuildable from the source files. ## Requirements -- Node.js 22.13 or newer. - Python 3.11 or newer with ReMe installed. - A running ReMe HTTP service. Agent chat additionally requires a working Agent and model configuration. +- Node.js 22.13 or newer is required only when developing or building Studio from source. See the [repository README](../README.md) for ReMe installation and backend configuration. diff --git a/website/README_ZH.md b/website/README_ZH.md index 75ec6054..c6f813ee 100644 --- a/website/README_ZH.md +++ b/website/README_ZH.md @@ -7,6 +7,17 @@ ReMe Studio 是 ReMe 的本地 Web 工作区。你可以在这里浏览和编辑 ![ReMe Studio 工作区](./public/og.jpg) +## 安装 + +安装 Studio 和 ReMe 的可选集成功能: + +```bash +pip install "reme-ai[core]" +``` + +如果只需要 Studio,不需要其他可选集成,可以使用 `pip install "reme-ai[web]"`。基础 `reme-ai` 包以无界面模式分发, +不包含前端资源。 + ## 功能 - **浏览工作区**:浏览完整工作区,或通过独立视图聚焦日记和知识文件;磁盘中的文件发生变化后,导航器会自动刷新。 @@ -20,9 +31,9 @@ ReMe Studio 是 ReMe 的本地 Web 工作区。你可以在这里浏览和编辑 ## 环境要求 -- Node.js 22.13 或更高版本。 - Python 3.11 或更高版本,并已安装 ReMe。 - 正在运行的 ReMe HTTP 服务。Agent 对话还需要可用的 Agent 和模型配置。 +- 只有从源码开发或构建 Studio 时才需要 Node.js 22.13 或更高版本。 ReMe 的安装和后端配置请参阅[仓库中文 README](../README_ZH.md)。