From 7c5556add3eee61842ff7ebed7be35336934752d Mon Sep 17 00:00:00 2001 From: liukewia Date: Wed, 26 Aug 2026 17:50:15 +0800 Subject: [PATCH 1/6] chore: bump harness-browser to 0.7.6 Co-authored-by: Cursor --- pyproject.toml | 2 +- uv.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c64d3f0f..04b34153 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,7 @@ dependencies = [ "acme>=5.6.0", "josepy>=2.2.0", "boto3>=1.40.61", - "harness-browser>=0.7.5", + "harness-browser>=0.7.6", "playwright>=1.40", "psycopg[binary]>=3.2", "langgraph-checkpoint-postgres>=2.0", diff --git a/uv.lock b/uv.lock index 53819ab0..98ea5b90 100644 --- a/uv.lock +++ b/uv.lock @@ -1293,7 +1293,7 @@ wheels = [ [[package]] name = "harness-browser" -version = "0.7.5" +version = "0.7.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, @@ -1301,9 +1301,9 @@ dependencies = [ { name = "pydantic" }, { name = "websockets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/98/e2/fd855aac21ff8cb75dd49a3ad804de9a94d668fcb5299c31a73f8db3c23e/harness_browser-0.7.5.tar.gz", hash = "sha256:ab3dd40d830c896da881132745c8a3c3de04dd24cfef9923d97a1ab58c9d3ae8", size = 326189, upload-time = "2026-08-12T11:18:54.865Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e1/0c/1abe8206743dfbdb017ae77b2820359ac066941853ac726bcc6d76800509/harness_browser-0.7.6.tar.gz", hash = "sha256:1a40f849813899bf04168926cafa677cdda6c49617e57d26eff975b929539aa0", size = 329380, upload-time = "2026-08-26T09:35:56.964Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2e/57/d170b7ace2342a3c3a813f4d341320861e638b6bfd6e808b0bef169513a0/harness_browser-0.7.5-py3-none-any.whl", hash = "sha256:ed3bb6fe5fe452d37aacce4b730c14b12d6bd3266b11a0c9056f116e0f2a0a97", size = 92581, upload-time = "2026-08-12T11:18:52.971Z" }, + { url = "https://files.pythonhosted.org/packages/2c/7f/b81b2c3f14bb69843501873947703d1d3d0f5471fbda87ca3ffea45abf33/harness_browser-0.7.6-py3-none-any.whl", hash = "sha256:4c533301fe7b052bc30cd176600f19d5ffa122857856a766de3d10560c54f58e", size = 95146, upload-time = "2026-08-26T09:35:55.034Z" }, ] [[package]] @@ -2548,7 +2548,7 @@ requires-dist = [ { name = "edge-tts", specifier = ">=6.1" }, { name = "fastapi", specifier = ">=0.110" }, { name = "fastembed", marker = "extra == 'local-embedding'", specifier = ">=0.4" }, - { name = "harness-browser", specifier = ">=0.7.5" }, + { name = "harness-browser", specifier = ">=0.7.6" }, { name = "harness-gateway", specifier = ">=0.9.3" }, { name = "harness-memory", specifier = ">=0.9.7" }, { name = "httpx", marker = "extra == 'dev'", specifier = ">=0.27" }, From c38b512a5cff65af19402dad304cc2fd9c9a10d6 Mon Sep 17 00:00:00 2001 From: jubaoliang Date: Wed, 26 Aug 2026 10:53:45 +0000 Subject: [PATCH 2/6] fix: gate update UI by permission and speed up local tests Hide check-for-updates entry points unless the user has the update module permission, show compact offloads under .octop/conversation_history, and add pytest-xdist / test-fast with isolated HOME for parallel runs. Co-authored-by: Cursor --- CHANGELOG.md | 9 +++ Makefile | 11 +++- .../src/components/AppVersionBadge/index.tsx | 9 +-- dashboard/src/components/AvatarDropdown.tsx | 25 +++++---- .../components/CurrentVersionBadge/index.tsx | 11 ++-- pyproject.toml | 8 ++- src/octop/infra/backend/resolver.py | 12 ++-- .../infra/gateway/slash/handlers/composite.py | 10 +++- tests/conftest.py | 55 +++++++++++++++++-- tests/unit/gateway/test_slash_compact.py | 31 +++++++++++ tests/unit/infra/setup/test_service.py | 11 +++- uv.lock | 34 ++++++++++-- 12 files changed, 182 insertions(+), 44 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 594bbbf9..5565d4d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,15 @@ ## [Unreleased] +### 修复 + +- 无「应用更新」权限时隐藏检查更新入口(按权限而非 admin 角色) +- `/compact` 卸载路径展示兼容 `.octop/conversation_history/` + +### 其他 + +- 测试:`pytest-xdist` 并行、`make test-fast`、`slow` 标记与隔离 HOME + ## [0.9.27] - 2026-08-26 ### 新增 diff --git a/Makefile b/Makefile index 37ac43ee..cdf862e8 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,8 @@ UV := $(shell command -v uv 2>/dev/null) RUN := $(if $(UV),uv run,) PYTHON := $(if $(UV),uv run python,python3) PIP := $(if $(UV),uv pip,python3 -m pip) +# Parallel workers for make test / make test-fast (override: make test PYTEST_JOBS=4) +PYTEST_JOBS ?= auto # ─── Help ──────────────────────────────────────────────────────────────────── @@ -219,8 +221,13 @@ typecheck: .PHONY: test test: - @echo "[test] pytest (not live)..." - $(RUN) pytest -m "not live" + @echo "[test] pytest (not live, -n $(PYTEST_JOBS))..." + $(RUN) pytest -n $(PYTEST_JOBS) -m "not live" + +.PHONY: test-fast +test-fast: + @echo "[test-fast] pytest (not live, not slow, -n $(PYTEST_JOBS))..." + $(RUN) pytest -n $(PYTEST_JOBS) -m "not live and not slow" .PHONY: test-live test-live: diff --git a/dashboard/src/components/AppVersionBadge/index.tsx b/dashboard/src/components/AppVersionBadge/index.tsx index 5e4d85cc..d9e6b821 100644 --- a/dashboard/src/components/AppVersionBadge/index.tsx +++ b/dashboard/src/components/AppVersionBadge/index.tsx @@ -3,7 +3,8 @@ import { useNavigate } from "react-router-dom"; import { Tooltip } from "antd"; import { ArrowUpCircle } from "lucide-react"; import { useUpdateStatus } from "../../hooks/useUpdateStatus"; -import { useUserRole } from "../../hooks/useUserRole"; +import { useCurrentUser } from "../../hooks/useCurrentUser"; +import { userCan } from "../../utils/permissions"; import styles from "./index.module.less"; interface AppVersionBadgeProps { @@ -13,11 +14,11 @@ interface AppVersionBadgeProps { export default function AppVersionBadge({ isMobile }: AppVersionBadgeProps) { const { t } = useTranslation(); const navigate = useNavigate(); - const role = useUserRole(); + const user = useCurrentUser(); const { status, hasUpdate } = useUpdateStatus(); - const isAdmin = role === "admin"; - if (!status?.current_version || !hasUpdate || !isAdmin) return null; + const canUpdate = userCan(user, "update"); + if (!status?.current_version || !hasUpdate || !canUpdate) return null; const tooltip = t("header.versionUpdateAvailable", { current: status.current_version, diff --git a/dashboard/src/components/AvatarDropdown.tsx b/dashboard/src/components/AvatarDropdown.tsx index 1102cbfa..145fa30d 100644 --- a/dashboard/src/components/AvatarDropdown.tsx +++ b/dashboard/src/components/AvatarDropdown.tsx @@ -43,6 +43,7 @@ import PaletteSwitcher from "./PaletteSwitcher"; import type { OctopUser } from "../api/modules/auth"; import { useLayoutMode } from "../context/LayoutModeContext"; import type { LayoutMode } from "../layouts/layoutModeStorage"; +import { userCan } from "../utils/permissions"; import styles from "./AvatarDropdown.module.less"; const GITHUB_URL = "https://github.com/TencentCloud/Octop"; @@ -259,17 +260,19 @@ export default function AvatarDropdown({ {t("account.changePassword")} - + {userCan(user, "update") && ( + + )} diff --git a/dashboard/src/components/CurrentVersionBadge/index.tsx b/dashboard/src/components/CurrentVersionBadge/index.tsx index 3dbab8a4..e6f8e59a 100644 --- a/dashboard/src/components/CurrentVersionBadge/index.tsx +++ b/dashboard/src/components/CurrentVersionBadge/index.tsx @@ -2,7 +2,8 @@ import { useTranslation } from "react-i18next"; import { useNavigate } from "react-router-dom"; import { Tooltip } from "antd"; import { useUpdateStatus } from "../../hooks/useUpdateStatus"; -import { useUserRole } from "../../hooks/useUserRole"; +import { useCurrentUser } from "../../hooks/useCurrentUser"; +import { userCan } from "../../utils/permissions"; import styles from "./index.module.less"; interface CurrentVersionBadgeProps { @@ -14,19 +15,19 @@ export default function CurrentVersionBadge({ }: CurrentVersionBadgeProps) { const { t } = useTranslation(); const navigate = useNavigate(); - const role = useUserRole(); + const user = useCurrentUser(); const { status } = useUpdateStatus(); const version = status?.current_version; if (!version) return null; - const isAdmin = role === "admin"; - const tooltip = isAdmin + const canUpdate = userCan(user, "update"); + const tooltip = canUpdate ? t("header.currentVersionAdmin", { version }) : t("header.currentVersion", { version }); const label = `v${version}`; - if (isAdmin) { + if (canUpdate) { return (