Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/app/service/agent/core/opfs_helpers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
// OPFS 工作区公共辅助函数
// 供 opfs_tools、agent_dom 等模块复用

export const WORKSPACE_ROOT = "agents/workspace";
export const WORKSPACE_PATH = ["agents", "workspace"] as const;
export const WORKSPACE_ROOT = WORKSPACE_PATH.join("/");

export function isWorkspacePath(path: readonly string[]): boolean {
return (
path.every((part) => part.length > 0 && part !== "." && part !== "..") &&
WORKSPACE_PATH.every((part, index) => path[index] === part)
);
}

/** Strip leading `/`, reject `..` segments */
export function sanitizePath(raw: string): string {
Expand Down
7 changes: 7 additions & 0 deletions src/locales/de-DE/agent.json
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,13 @@
"opfs_type_text": "Text",
"opfs_type_binary": "Binär",
"opfs_root": "Stammverzeichnis",
"opfs_read_only": "Dieses Verzeichnis ist schreibgeschützt. Änderungen sind nur in agents/workspace und darunter möglich.",
"opfs_rename": "Umbenennen",
"opfs_move": "Verschieben",
"opfs_rename_placeholder": "Neuer Datei- oder Verzeichnisname",
"opfs_move_destination_placeholder": "Zielverzeichnis (z. B. agents/workspace)",
"opfs_rename_success": "Erfolgreich umbenannt",
"opfs_move_success": "Erfolgreich verschoben",
"dom_permission_title": "Das Skript fordert DOM-Zugriff an",
"dom_permission_describe": "Dieses Skript fordert die Fähigkeit an, das DOM der Webseite zu lesen und zu manipulieren (Klicken, Formulare ausfüllen, Navigation, Screenshot usw.). Erlauben Sie nur vertrauenswürdigen Skripten.",
"dom_permission_content": "Agent DOM-Operationen",
Expand Down
7 changes: 7 additions & 0 deletions src/locales/en-US/agent.json
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,13 @@
"opfs_type_text": "Text",
"opfs_type_binary": "Binary",
"opfs_root": "Root",
"opfs_read_only": "This directory is read-only. Changes are allowed only in agents/workspace and its subdirectories.",
"opfs_rename": "Rename",
"opfs_move": "Move",
"opfs_rename_placeholder": "New file or folder name",
"opfs_move_destination_placeholder": "Destination directory (for example, agents/workspace)",
"opfs_rename_success": "Renamed successfully",
"opfs_move_success": "Moved successfully",
"dom_permission_title": "The script is requesting DOM operation access",
"dom_permission_describe": "This script requests the ability to read and manipulate web page DOM (click, fill forms, navigate, screenshot, etc.). Only grant access to trusted scripts.",
"dom_permission_content": "Agent DOM Operations",
Expand Down
7 changes: 7 additions & 0 deletions src/locales/ja-JP/agent.json
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,13 @@
"opfs_type_text": "テキスト",
"opfs_type_binary": "バイナリ",
"opfs_root": "ルート",
"opfs_read_only": "このディレクトリは読み取り専用です。変更できるのは agents/workspace とその配下だけです。",
"opfs_rename": "名前を変更",
"opfs_move": "移動",
"opfs_rename_placeholder": "新しいファイルまたはディレクトリ名",
"opfs_move_destination_placeholder": "移動先ディレクトリ(例: agents/workspace)",
"opfs_rename_success": "名前を変更しました",
"opfs_move_success": "移動しました",
"dom_permission_title": "スクリプトが DOM 操作アクセスをリクエストしています",
"dom_permission_describe": "このスクリプトはウェブページの DOM を読み取り操作する能力(クリック、フォーム入力、ナビゲーション、スクリーンショットなど)をリクエストしています。信頼できるスクリプトにのみ許可してください。",
"dom_permission_content": "Agent DOM 操作",
Expand Down
7 changes: 7 additions & 0 deletions src/locales/ru-RU/agent.json
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,13 @@
"opfs_type_text": "Текст",
"opfs_type_binary": "Двоичный",
"opfs_root": "Корень",
"opfs_read_only": "Этот каталог доступен только для чтения. Изменения разрешены только в agents/workspace и его подкаталогах.",
"opfs_rename": "Переименовать",
"opfs_move": "Переместить",
"opfs_rename_placeholder": "Новое имя файла или папки",
"opfs_move_destination_placeholder": "Каталог назначения (например, agents/workspace)",
"opfs_rename_success": "Успешно переименовано",
"opfs_move_success": "Успешно перемещено",
"dom_permission_title": "Скрипт запрашивает доступ к операциям DOM",
"dom_permission_describe": "Этот скрипт запрашивает возможность читать и управлять DOM веб-страницы (клик, заполнение форм, навигация, скриншот и т.д.). Разрешайте только доверенным скриптам.",
"dom_permission_content": "Agent DOM операции",
Expand Down
7 changes: 7 additions & 0 deletions src/locales/tr-TR/agent.json
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,13 @@
"opfs_type_text": "Metin",
"opfs_type_binary": "İkili",
"opfs_root": "Kök",
"opfs_read_only": "Bu dizin salt okunurdur. Değişikliklere yalnızca agents/workspace ve alt dizinlerinde izin verilir.",
"opfs_rename": "Yeniden adlandır",
"opfs_move": "Taşı",
"opfs_rename_placeholder": "Yeni dosya veya klasör adı",
"opfs_move_destination_placeholder": "Hedef dizin (örneğin agents/workspace)",
"opfs_rename_success": "Yeniden adlandırıldı",
"opfs_move_success": "Taşındı",
"dom_permission_title": "Betik DOM işlem erişimi istiyor",
"dom_permission_describe": "Bu betik web sayfası DOM'unu okuma ve değiştirme yetkisi istiyor (tıklama, form doldurma, gezinme, ekran görüntüsü vb.). Yalnızca güvendiğiniz betiklere erişim verin.",
"dom_permission_content": "Agent DOM İşlemleri",
Expand Down
7 changes: 7 additions & 0 deletions src/locales/vi-VN/agent.json
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,13 @@
"opfs_type_text": "Văn bản",
"opfs_type_binary": "Nhị phân",
"opfs_root": "Gốc",
"opfs_read_only": "Thư mục này chỉ đọc. Chỉ agents/workspace và các thư mục con cho phép thay đổi.",
"opfs_rename": "Đổi tên",
"opfs_move": "Di chuyển",
"opfs_rename_placeholder": "Tên tệp hoặc thư mục mới",
"opfs_move_destination_placeholder": "Thư mục đích (ví dụ: agents/workspace)",
"opfs_rename_success": "Đã đổi tên",
"opfs_move_success": "Đã di chuyển",
"dom_permission_title": "Script yêu cầu quyền thao tác DOM",
"dom_permission_describe": "Script này yêu cầu khả năng đọc và thao tác DOM trang web (nhấp chuột, điền biểu mẫu, điều hướng, chụp ảnh màn hình, v.v.). Chỉ cấp quyền cho các script đáng tin cậy.",
"dom_permission_content": "Agent DOM thao tác",
Expand Down
7 changes: 7 additions & 0 deletions src/locales/zh-CN/agent.json
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,13 @@
"opfs_type_image": "图片",
"opfs_type_text": "文本",
"opfs_type_binary": "二进制",
"opfs_read_only": "此目录为只读目录。仅 agents/workspace 及其子目录允许修改。",
"opfs_rename": "重命名",
"opfs_move": "移动",
"opfs_rename_placeholder": "新的文件或目录名称",
"opfs_move_destination_placeholder": "目标目录(例如 agents/workspace)",
"opfs_rename_success": "重命名成功",
"opfs_move_success": "移动成功",
"dom_permission_title": "脚本请求 DOM 操作权限",
"dom_permission_describe": "此脚本请求读取和操作网页 DOM 的能力(点击、填写表单、导航、截图等)。请仅对可信脚本授权。",
"dom_permission_content": "Agent DOM 操作",
Expand Down
7 changes: 7 additions & 0 deletions src/locales/zh-TW/agent.json
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,13 @@
"opfs_type_text": "文字",
"opfs_type_binary": "二進位",
"opfs_root": "根目錄",
"opfs_read_only": "此資料夾為唯讀。只有 agents/workspace 及其子資料夾允許修改。",
"opfs_rename": "重新命名",
"opfs_move": "移動",
"opfs_rename_placeholder": "新的檔案或資料夾名稱",
"opfs_move_destination_placeholder": "目的資料夾(例如 agents/workspace)",
"opfs_rename_success": "重新命名成功",
"opfs_move_success": "移動成功",
"dom_permission_title": "腳本請求 DOM 操作權限",
"dom_permission_describe": "此腳本請求讀取和操作網頁 DOM 的能力(點擊、填寫表單、導航、截圖等)。請僅對可信腳本授權。",
"dom_permission_content": "Agent DOM 操作",
Expand Down
32 changes: 22 additions & 10 deletions src/pages/options/routes/Agent/OPFS/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@ describe("AgentOPFS 页面", () => {
expect(screen.getByText("subdir")).toBeInTheDocument();
});

it("系统目录浏览时只提供读取和下载,不提供修改操作", async () => {
render(<AgentOPFS />);
expect(await screen.findByText("file1.txt")).toBeInTheDocument();
expect(screen.queryByTestId("opfs-upload")).not.toBeInTheDocument();
expect(screen.queryByTestId("delete-file1.txt")).not.toBeInTheDocument();
expect(screen.getByTestId("opfs-read-only-notice")).toBeInTheDocument();
});

it("点击目录进入并更新面包屑", async () => {
render(<AgentOPFS />);
expect(await screen.findByTestId("entry-subdir")).toBeInTheDocument();
Expand All @@ -109,8 +117,12 @@ describe("AgentOPFS 页面", () => {
});

it("选择文件后写入当前目录并刷新展示", async () => {
const workspace = dirHandle("workspace");
root = dirHandle("root", { agents: dirHandle("agents", { workspace }) });
(navigator.storage.getDirectory as any).mockResolvedValue(root);
render(<AgentOPFS />);
expect(await screen.findByText("file1.txt")).toBeInTheDocument();
fireEvent.click(await screen.findByTestId("entry-agents"));
fireEvent.click(await screen.findByTestId("entry-workspace"));
const input = screen.getByTestId("opfs-upload-input") as HTMLInputElement;
const file = new File(["uploaded-content"], "report.json", { type: "application/json" });
fireEvent.change(input, { target: { files: [file] } });
Expand All @@ -123,8 +135,8 @@ describe("AgentOPFS 页面", () => {
const closeGate = new Promise<void>((resolve) => {
releaseClose = resolve;
});
root = dirHandle("root", { "file1.txt": fileHandle("file1.txt", "hi") });
root.getFileHandle = async (n: string) => ({
const workspace = dirHandle("workspace", { "file1.txt": fileHandle("file1.txt", "hi") });
workspace.getFileHandle = async (n: string) => ({
kind: "file",
name: n,
async createWritable() {
Expand All @@ -136,9 +148,12 @@ describe("AgentOPFS 页面", () => {
};
},
});
root = dirHandle("root", { agents: dirHandle("agents", { workspace }) });
(navigator.storage.getDirectory as any).mockResolvedValue(root);

render(<AgentOPFS />);
fireEvent.click(await screen.findByTestId("entry-agents"));
fireEvent.click(await screen.findByTestId("entry-workspace"));
expect(await screen.findByText("file1.txt")).toBeInTheDocument();

const upload = screen.getByTestId("opfs-upload");
Expand Down Expand Up @@ -174,12 +189,9 @@ describe("AgentOPFS 页面", () => {
mockedUseIsMobile.mockReturnValue(true);
render(<AgentOPFS />);
expect(await screen.findByText("file1.txt")).toBeInTheDocument();
const upload = screen.getByTestId("opfs-upload");
const refresh = screen.getByTestId("opfs-refresh");
// 图标按钮:有可访问名,但没有可见文本节点
expect(upload).toHaveAccessibleName();
expect(upload.textContent).toBe("");
expect(refresh.textContent).toBe("");
expect(screen.queryByTestId("opfs-upload")).not.toBeInTheDocument();
// 页内标题存在(以 test-id 断言,不耦合译文)
expect(screen.getByTestId("opfs-mobile-title")).toBeInTheDocument();
});
Expand All @@ -191,15 +203,15 @@ describe("AgentOPFS 页面", () => {
// AgentPageHeader 的副标题与带文案的桌面按钮均不应出现:说明 64px 页头未渲染
expect(screen.queryByText("Origin Private File System · Agent 私有存储")).not.toBeInTheDocument();
expect(screen.queryByTestId("opfs-refresh")?.textContent).not.toContain("刷新");
expect(screen.queryByTestId("opfs-upload")?.textContent).not.toContain("上传");
expect(screen.queryByTestId("opfs-upload")).not.toBeInTheDocument();
});

it("桌面端渲染 64px 页头(含副标题与带文案的刷新/上传按钮)", async () => {
it("桌面端渲染 64px 页头并在系统目录隐藏上传按钮", async () => {
mockedUseIsMobile.mockReturnValue(false);
render(<AgentOPFS />);
expect(await screen.findByText("file1.txt")).toBeInTheDocument();
expect(screen.getByText("Origin Private File System · Agent 私有存储")).toBeInTheDocument();
expect(screen.getByTestId("opfs-refresh")).toHaveTextContent("刷新");
expect(screen.getByTestId("opfs-upload")).toHaveTextContent("上传");
expect(screen.queryByTestId("opfs-upload")).not.toBeInTheDocument();
});
});
Loading
Loading