Skip to content

Commit 56e0192

Browse files
authored
Merge branch 'AstrBotDevs:master' into master
2 parents d5fb9f9 + dd716e6 commit 56e0192

5 files changed

Lines changed: 358 additions & 41 deletions

File tree

astrbot/core/pipeline/result_decorate/stage.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,9 @@ async def process(
289289
),
290290
)
291291
else:
292-
result.chain.insert(0, Plain(f"🤔 思考: {reasoning_content}\n"))
292+
result.chain.insert(
293+
0, Plain(f"🤔 思考: {reasoning_content}\n\n────\n")
294+
)
293295

294296
if should_tts and tts_provider:
295297
new_chain = []

astrbot/core/star/updator.py

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import os
2-
import shutil
32
import zipfile
43

54
from astrbot.core import logger
65
from astrbot.core.utils.astrbot_path import get_astrbot_plugin_path
7-
from astrbot.core.utils.io import ensure_dir, on_error, remove_dir
6+
from astrbot.core.utils.io import ensure_dir, remove_dir
87

98
from ..star.star import StarMetadata
109
from ..updator import RepoZipUpdator
@@ -72,28 +71,9 @@ async def update(
7271

7372
def unzip_file(self, zip_path: str, target_dir: str) -> None:
7473
ensure_dir(target_dir)
75-
update_dir = ""
7674
logger.info(f"Extracting archive: {zip_path}")
7775
with zipfile.ZipFile(zip_path, "r") as z:
78-
update_dir = z.namelist()[0]
76+
update_dir = self._resolve_archive_root_dir(z.namelist())
7977
z.extractall(target_dir)
8078

81-
files = os.listdir(os.path.join(target_dir, update_dir))
82-
for f in files:
83-
if os.path.isdir(os.path.join(target_dir, update_dir, f)):
84-
if os.path.exists(os.path.join(target_dir, f)):
85-
shutil.rmtree(os.path.join(target_dir, f), onerror=on_error)
86-
elif os.path.exists(os.path.join(target_dir, f)):
87-
os.remove(os.path.join(target_dir, f))
88-
shutil.move(os.path.join(target_dir, update_dir, f), target_dir)
89-
90-
try:
91-
logger.info(
92-
f"Removing temporary files: {zip_path} and {os.path.join(target_dir, update_dir)}",
93-
)
94-
shutil.rmtree(os.path.join(target_dir, update_dir), onerror=on_error)
95-
os.remove(zip_path)
96-
except BaseException:
97-
logger.warning(
98-
f"Failed to remove update files; you can manually delete {zip_path} and {os.path.join(target_dir, update_dir)}",
99-
)
79+
self._finalize_extracted_archive(zip_path, target_dir, update_dir)

astrbot/core/utils/io.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,9 +289,23 @@ async def download_dashboard(
289289
)
290290
except BaseException as _:
291291
if latest:
292-
dashboard_release_url = "https://github.com/AstrBotDevs/AstrBot/releases/latest/download/dist.zip"
292+
# Resolve latest release tag from GitHub API to construct correct asset URL
293+
ssl_context = ssl.create_default_context(cafile=certifi.where())
294+
async with aiohttp.ClientSession(
295+
connector=aiohttp.TCPConnector(ssl=ssl_context),
296+
trust_env=True,
297+
) as session:
298+
async with session.get(
299+
"https://api.github.com/repos/AstrBotDevs/AstrBot/releases/latest",
300+
timeout=30,
301+
headers={"Accept": "application/vnd.github+json"},
302+
) as api_resp:
303+
api_resp.raise_for_status()
304+
release_data = await api_resp.json()
305+
tag = release_data["tag_name"]
293306
else:
294-
dashboard_release_url = f"https://github.com/AstrBotDevs/AstrBot/releases/download/{version}/dist.zip"
307+
tag = version
308+
dashboard_release_url = f"https://github.com/AstrBotDevs/AstrBot/releases/download/{tag}/AstrBot-{tag}-dashboard.zip"
295309
if proxy:
296310
dashboard_release_url = f"{proxy}/{dashboard_release_url}"
297311
await download_file(

astrbot/core/zip_updator.py

Lines changed: 72 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -234,30 +234,87 @@ def parse_github_url(self, url: str):
234234
def unzip_file(self, zip_path: str, target_dir: str) -> None:
235235
"""解压缩文件, 并将压缩包内**第一个**文件夹内的文件移动到 target_dir"""
236236
ensure_dir(target_dir)
237-
update_dir = ""
238237
with zipfile.ZipFile(zip_path, "r") as z:
239-
update_dir = z.namelist()[0]
238+
update_dir = self._resolve_archive_root_dir(z.namelist())
240239
z.extractall(target_dir)
241240
logger.debug(f"解压文件完成: {zip_path}")
242241

243-
files = os.listdir(os.path.join(target_dir, update_dir))
242+
self._finalize_extracted_archive(zip_path, target_dir, update_dir)
243+
244+
@staticmethod
245+
def _resolve_archive_root_dir(entries: list[str]) -> str:
246+
normalized_entries = [os.path.normpath(entry) for entry in entries]
247+
portable_entries = [entry.replace("\\", "/") for entry in normalized_entries]
248+
root_candidates: list[str] = []
249+
250+
for raw_entry, normalized_entry, portable_entry in zip(
251+
entries, normalized_entries, portable_entries
252+
):
253+
if normalized_entry == ".":
254+
continue
255+
256+
has_children = any(
257+
other_entry != portable_entry
258+
and other_entry.startswith(f"{portable_entry}/")
259+
for other_entry in portable_entries
260+
)
261+
if raw_entry.endswith(("/", "\\")) or has_children:
262+
root_candidates.append(normalized_entry)
263+
continue
264+
265+
parent_portable, _, _ = portable_entry.rpartition("/")
266+
if not parent_portable:
267+
return ""
268+
root_candidates.append(parent_portable.replace("/", os.sep))
269+
270+
if not root_candidates:
271+
return ""
272+
return os.path.commonpath(root_candidates)
273+
274+
def _finalize_extracted_archive(
275+
self,
276+
zip_path: str,
277+
target_dir: str,
278+
update_dir: str,
279+
) -> None:
280+
target_root_path = os.path.normpath(target_dir)
281+
282+
def _join_under_root(root: str, *parts: str) -> str:
283+
path = os.path.normpath(os.path.join(root, *parts))
284+
try:
285+
if os.path.commonpath([root, path]) != root:
286+
raise ValueError("path escapes root directory")
287+
except ValueError as exc:
288+
raise ValueError("path escapes root directory") from exc
289+
return path
290+
291+
if not update_dir:
292+
try:
293+
os.remove(zip_path)
294+
except Exception:
295+
logger.warning(f"删除更新文件失败,可以手动删除 {zip_path}")
296+
return
297+
298+
update_root_path = _join_under_root(target_root_path, update_dir)
299+
300+
files = os.listdir(update_root_path)
244301
for f in files:
245-
if os.path.isdir(os.path.join(target_dir, update_dir, f)):
246-
if os.path.exists(os.path.join(target_dir, f)):
247-
shutil.rmtree(os.path.join(target_dir, f), onerror=on_error)
248-
elif os.path.exists(os.path.join(target_dir, f)):
249-
os.remove(os.path.join(target_dir, f))
250-
shutil.move(os.path.join(target_dir, update_dir, f), target_dir)
302+
update_item_path = _join_under_root(update_root_path, f)
303+
target_item_path = _join_under_root(target_root_path, f)
304+
if os.path.isdir(update_item_path):
305+
if os.path.exists(target_item_path):
306+
shutil.rmtree(target_item_path, onerror=on_error)
307+
elif os.path.exists(target_item_path):
308+
os.remove(target_item_path)
309+
shutil.move(update_item_path, target_root_path)
251310

252311
try:
253-
logger.debug(
254-
f"删除临时更新文件: {zip_path}{os.path.join(target_dir, update_dir)}",
255-
)
256-
shutil.rmtree(os.path.join(target_dir, update_dir), onerror=on_error)
312+
logger.debug(f"删除临时更新文件: {zip_path}{update_root_path}")
313+
shutil.rmtree(update_root_path, onerror=on_error)
257314
os.remove(zip_path)
258-
except BaseException:
315+
except Exception:
259316
logger.warning(
260-
f"删除更新文件失败,可以手动删除 {zip_path}{os.path.join(target_dir, update_dir)}",
317+
f"删除更新文件失败,可以手动删除 {zip_path}{update_root_path}"
261318
)
262319

263320
def format_name(self, name: str) -> str:

0 commit comments

Comments
 (0)