fix: 修复文件管理器跨平台路径串台(Linux/Mac 风格路径在 Windows 下被拼成 C:/home/user/...)
- 新增 _resolve_cross_platform_path:Windows 下将 /home/<用户>/…、/Users/<用户>/…、/root/… 映射到当前用户家目录对应位置 - file_manager 全部 10 个操作的路径解析改用该归一化函数 - 更新 CHANGELOG v8.0.2 条目(覆盖 8.0.2 发行)
This commit is contained in:
1 parent
0aaca9c63d
commit
6f4fa5076f
2 files changed
+39
-10
No files matched your search
@@ -16,6 +16,10 @@
|
|||||||
- 上一版修复导致聊天界面完全看不到情话,改为:非 TTY 在请求开始输出一句随机情话(`💭` 前缀,只打一次、零残帧)
|
- 上一版修复导致聊天界面完全看不到情话,改为:非 TTY 在请求开始输出一句随机情话(`💭` 前缀,只打一次、零残帧)
|
||||||
- `love.txt` 读取时过滤 `http/https` 行,避免把反战标语 / 网址当情话甩出
|
- `love.txt` 读取时过滤 `http/https` 行,避免把反战标语 / 网址当情话甩出
|
||||||
- 真 TTY 逐帧情话 + spinner 动画、TUI 模式均不受影响
|
- 真 TTY 逐帧情话 + spinner 动画、TUI 模式均不受影响
|
||||||
|
- **修复文件管理器跨平台路径串台**(本次提交)
|
||||||
|
- 模型在 Windows 主机上常给出 Linux/Mac 风格绝对路径(如 `/home/user/Desktop`、`/Users/<谁>/Desktop`、`/root/Desktop`),`os.path.abspath` 在 Windows 下会错误地拼成 `C:\home\user\Desktop` 并报「路径不存在」
|
||||||
|
- 新增 `_resolve_cross_platform_path`:Windows 下把 `/home/<用户>/…`、`/Users/<用户>/…`、`/root/…` 统一映射到当前用户家目录对应位置(`~/Desktop` 等);Linux/Mac 下这些路径本身合法,原样保留
|
||||||
|
- `file_manager` 全部 10 个操作(list/read/write/append/copy/move/delete/search/info/mkdir)的路径解析均改用该归一化函数
|
||||||
|
|
||||||
### 🛠 工程
|
### 🛠 工程
|
||||||
|
|
||||||
|
|||||||
+35
-10
@@ -3,6 +3,7 @@
|
|||||||
聚焦文件系统操作,代码编辑交给 code_editor
|
聚焦文件系统操作,代码编辑交给 code_editor
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import json
|
import json
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
@@ -10,6 +11,30 @@ from datetime import datetime
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
|
|
||||||
|
# ── 跨平台路径归一化 ──────────────────────────────────────────────
|
||||||
|
# 模型常给出 Linux/Mac 风格绝对路径(如 /home/<user>/Desktop、
|
||||||
|
# /Users/<user>/Desktop、/root/Desktop)。在 Windows 下 os.path.abspath 会
|
||||||
|
# 错误地拼成 C:\home\user\Desktop。这里把这类路径映射到当前用户家目录
|
||||||
|
# 对应位置;Linux/Mac 下这些路径本身合法,原样保留。
|
||||||
|
_HOME_OR_USER_RE = re.compile(r'^/(?:home|Users)/[^/]+(/.*)?$')
|
||||||
|
_ROOT_RE = re.compile(r'^/root(/.*)?$')
|
||||||
|
|
||||||
|
|
||||||
|
def _resolve_cross_platform_path(path: str) -> str:
|
||||||
|
"""把模型给出的路径归一化到当前平台后再转绝对路径。"""
|
||||||
|
if os.name == 'nt' and path:
|
||||||
|
p = path.replace('\\', '/')
|
||||||
|
m = _HOME_OR_USER_RE.match(p)
|
||||||
|
if m:
|
||||||
|
rest = (m.group(1) or '').lstrip('/')
|
||||||
|
return os.path.join(os.path.expanduser('~'), rest)
|
||||||
|
m = _ROOT_RE.match(p)
|
||||||
|
if m:
|
||||||
|
rest = (m.group(1) or '').lstrip('/')
|
||||||
|
return os.path.join(os.path.expanduser('~'), rest)
|
||||||
|
return os.path.abspath(path)
|
||||||
|
|
||||||
# 添加项目根目录到 path
|
# 添加项目根目录到 path
|
||||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
from xcli_core.tool_result import ToolResult, ErrorCode
|
from xcli_core.tool_result import ToolResult, ErrorCode
|
||||||
@@ -158,7 +183,7 @@ class Liugin:
|
|||||||
path = args[i]
|
path = args[i]
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
path = os.path.abspath(path)
|
path = _resolve_cross_platform_path(path)
|
||||||
if not os.path.isdir(path):
|
if not os.path.isdir(path):
|
||||||
return ToolResult.not_found(f"目录: {path}")
|
return ToolResult.not_found(f"目录: {path}")
|
||||||
|
|
||||||
@@ -193,7 +218,7 @@ class Liugin:
|
|||||||
def _op_read(self, args: List[str]):
|
def _op_read(self, args: List[str]):
|
||||||
if not args:
|
if not args:
|
||||||
return ToolResult.missing("文件路径")
|
return ToolResult.missing("文件路径")
|
||||||
file_path = os.path.abspath(args[0])
|
file_path = _resolve_cross_platform_path(args[0])
|
||||||
max_lines = None
|
max_lines = None
|
||||||
i = 1
|
i = 1
|
||||||
while i < len(args):
|
while i < len(args):
|
||||||
@@ -235,7 +260,7 @@ class Liugin:
|
|||||||
def _op_write(self, args: List[str]):
|
def _op_write(self, args: List[str]):
|
||||||
if len(args) < 2:
|
if len(args) < 2:
|
||||||
return ToolResult.fail("格式: write <文件> -c <内容>", ErrorCode.MISSING_ARGS)
|
return ToolResult.fail("格式: write <文件> -c <内容>", ErrorCode.MISSING_ARGS)
|
||||||
fp = os.path.abspath(args[0])
|
fp = _resolve_cross_platform_path(args[0])
|
||||||
content = None
|
content = None
|
||||||
i = 1
|
i = 1
|
||||||
while i < len(args):
|
while i < len(args):
|
||||||
@@ -256,7 +281,7 @@ class Liugin:
|
|||||||
def _op_append(self, args: List[str]):
|
def _op_append(self, args: List[str]):
|
||||||
if len(args) < 2:
|
if len(args) < 2:
|
||||||
return ToolResult.fail("格式: append <文件> -c <内容>", ErrorCode.MISSING_ARGS)
|
return ToolResult.fail("格式: append <文件> -c <内容>", ErrorCode.MISSING_ARGS)
|
||||||
fp = os.path.abspath(args[0])
|
fp = _resolve_cross_platform_path(args[0])
|
||||||
content = None
|
content = None
|
||||||
i = 1
|
i = 1
|
||||||
while i < len(args):
|
while i < len(args):
|
||||||
@@ -278,7 +303,7 @@ class Liugin:
|
|||||||
def _op_copy(self, args: List[str]):
|
def _op_copy(self, args: List[str]):
|
||||||
if len(args) < 2:
|
if len(args) < 2:
|
||||||
return ToolResult.missing("源和目标路径")
|
return ToolResult.missing("源和目标路径")
|
||||||
src, dst = os.path.abspath(args[0]), os.path.abspath(args[1])
|
src, dst = _resolve_cross_platform_path(args[0]), _resolve_cross_platform_path(args[1])
|
||||||
if not os.path.exists(src):
|
if not os.path.exists(src):
|
||||||
return ToolResult.not_found(f"源: {src}")
|
return ToolResult.not_found(f"源: {src}")
|
||||||
os.makedirs(os.path.dirname(dst) or ".", exist_ok=True)
|
os.makedirs(os.path.dirname(dst) or ".", exist_ok=True)
|
||||||
@@ -291,7 +316,7 @@ class Liugin:
|
|||||||
def _op_move(self, args: List[str]):
|
def _op_move(self, args: List[str]):
|
||||||
if len(args) < 2:
|
if len(args) < 2:
|
||||||
return ToolResult.missing("源和目标路径")
|
return ToolResult.missing("源和目标路径")
|
||||||
src, dst = os.path.abspath(args[0]), os.path.abspath(args[1])
|
src, dst = _resolve_cross_platform_path(args[0]), _resolve_cross_platform_path(args[1])
|
||||||
if not os.path.exists(src):
|
if not os.path.exists(src):
|
||||||
return ToolResult.not_found(f"源: {src}")
|
return ToolResult.not_found(f"源: {src}")
|
||||||
os.makedirs(os.path.dirname(dst) or ".", exist_ok=True)
|
os.makedirs(os.path.dirname(dst) or ".", exist_ok=True)
|
||||||
@@ -301,7 +326,7 @@ class Liugin:
|
|||||||
def _op_delete(self, args: List[str]):
|
def _op_delete(self, args: List[str]):
|
||||||
if not args:
|
if not args:
|
||||||
return ToolResult.missing("路径")
|
return ToolResult.missing("路径")
|
||||||
path = os.path.abspath(args[0])
|
path = _resolve_cross_platform_path(args[0])
|
||||||
recursive = "-r" in args
|
recursive = "-r" in args
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
return ToolResult.not_found(f"路径: {path}")
|
return ToolResult.not_found(f"路径: {path}")
|
||||||
@@ -321,7 +346,7 @@ class Liugin:
|
|||||||
def _op_search(self, args: List[str]):
|
def _op_search(self, args: List[str]):
|
||||||
if not args:
|
if not args:
|
||||||
return ToolResult.missing("搜索目录")
|
return ToolResult.missing("搜索目录")
|
||||||
directory = os.path.abspath(args[0])
|
directory = _resolve_cross_platform_path(args[0])
|
||||||
pattern, content_search = None, None
|
pattern, content_search = None, None
|
||||||
i = 1
|
i = 1
|
||||||
while i < len(args):
|
while i < len(args):
|
||||||
@@ -363,7 +388,7 @@ class Liugin:
|
|||||||
def _op_info(self, args: List[str]):
|
def _op_info(self, args: List[str]):
|
||||||
if not args:
|
if not args:
|
||||||
return ToolResult.missing("路径")
|
return ToolResult.missing("路径")
|
||||||
path = os.path.abspath(args[0])
|
path = _resolve_cross_platform_path(args[0])
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
return ToolResult.not_found(f"路径: {path}")
|
return ToolResult.not_found(f"路径: {path}")
|
||||||
|
|
||||||
@@ -383,7 +408,7 @@ class Liugin:
|
|||||||
def _op_mkdir(self, args: List[str]):
|
def _op_mkdir(self, args: List[str]):
|
||||||
if not args:
|
if not args:
|
||||||
return ToolResult.missing("目录路径")
|
return ToolResult.missing("目录路径")
|
||||||
path = os.path.abspath(args[0])
|
path = _resolve_cross_platform_path(args[0])
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
return ToolResult.fail(f"已存在: {path}", ErrorCode.INVALID_ARGS)
|
return ToolResult.fail(f"已存在: {path}", ErrorCode.INVALID_ARGS)
|
||||||
os.makedirs(path, exist_ok=True)
|
os.makedirs(path, exist_ok=True)
|
||||||
|
|||||||
Reference in new issue
Block a user