feat: v2.7.7 — File Explorer on workspaces and the user's home, clone with per-user git identity

- File Explorer (Files in the sidebar, /files; also from a workspace's Files
  tab, portalled so no panel clips it), laid out like GNOME Files: places
  (Home, workspaces, Trash), Back/Forward/Up, path bar, search, icon grid with
  image thumbnails or list, labelled New/Upload, selection action bar, hidden
  files behind Ctrl+H, right-click menus and the usual keys.
  Make, rename, move, copy (within a workspace, between workspaces, home ↔
  workspace), delete into a per-account trash restorable for 7 days, streamed
  upload of files and whole folders (≤ 500 MB a batch, Replace / Keep both /
  Skip on a taken name), download a file or a zip of anything.
  server/lib/file-explorer.js, /api/lanes/:id/fs/*, /api/homes/:who/fs/*.
- The user's home: every dot entry at its top stays hidden and refused
  (also via a symlink, download, zip or as a copy source); an admin may view
  other users' homes read-only, audited.
- write-as learns move/copy (re-run `sudo agenthub server install-system`).
- Hardening: a write to a workspace re-checks its owner by the live role;
  S3 keeps its server.conf if the file stops reading and a tmux call never
  falls back to the host's server; the AI Proxy gateway marks what it relays
  and the dashboard refuses it; a NUL in a pane's argv/env is refused.
- OpenAPI for the new routes (server/openapi-extra/files.js); docs (API,
  SERVER-MODE, CLAUDE.md) updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-14 14:17:39 +07:00
parent b441f32949
commit e94038481e
38 changed files with 5961 additions and 27 deletions
+85 -1
View File
@@ -522,5 +522,89 @@
"changes.historyWholeBranch": "Whole branch",
"changes.annotate": "Annotate",
"changes.noBlame": "Nothing to annotate: this file has no committed history yet",
"changes.notCommitted": "Not committed yet"
"changes.notCommitted": "Not committed yet",
"fx.title": "Files",
"fx.workspace": "Workspace",
"fx.files": "Files",
"fx.trash": "Trash",
"fx.close": "Close",
"fx.up": "Parent folder",
"fx.refresh": "Refresh",
"fx.newFolder": "New folder",
"fx.newFile": "New file",
"fx.uploadFiles": "Upload files",
"fx.uploadFolder": "Upload a folder",
"fx.download": "Download",
"fx.downloadZip": "Download as zip",
"fx.rename": "Rename",
"fx.copy": "Copy",
"fx.cut": "Cut",
"fx.paste": "Paste",
"fx.pasteInto": "Paste into this folder",
"fx.pasteFrom": "Paste {{count}} item(s) from {{workspace}}",
"fx.delete": "Move to Trash",
"fx.open": "Open",
"fx.location": "Location",
"fx.name": "Name",
"fx.size": "Size",
"fx.modified": "Modified",
"fx.empty": "This folder is empty — drop files here to upload.",
"fx.itemsCount": "{{count}} item(s)",
"fx.selectedCount": "{{count}} selected",
"fx.dropHint": "Drag files or folders here to upload · drag onto a folder to move (Ctrl: copy)",
"fx.uploading": "Uploading {{done}}/{{total}}…",
"fx.uploaded": "Uploaded {{count}} file(s).",
"fx.uploadFailed": "Could not upload {{name}}: {{message}}",
"fx.tooBig": "{{size}} is more than one upload may carry ({{max}}). Upload fewer files at a time.",
"fx.trashed": "Moved {{count}} item(s) to the Trash.",
"fx.copiedDone": "Copied {{count}} item(s) — open a folder (or another workspace) and Paste.",
"fx.cutDone": "Cut {{count}} item(s) — open a folder (or another workspace) and Paste.",
"fx.pasted": "Pasted.",
"fx.crossOnlyWorkspace": "These items can only be pasted where they came from (a session worktree, an extra folder, or between two homes).",
"fx.needsUpgrade": "This needs the updated server helper — ask an admin to run `sudo agenthub server install-system` once.",
"fx.conflictTitle": "Already there",
"fx.conflictBody": "This name is taken in the destination: {{names}}",
"fx.conflictAll": "Do this for every remaining file",
"fx.cancel": "Cancel",
"fx.skip": "Skip",
"fx.keepBoth": "Keep both",
"fx.replace": "Replace",
"fx.trashHint": "Deleted files and folders, restorable for 7 days.",
"fx.emptyTrash": "Empty Trash",
"fx.restore": "Restore",
"fx.purge": "Delete forever",
"fx.restored": "Restored.",
"fx.trashEmpty": "The Trash is empty.",
"changes.openExplorer": "Open File Explorer — manage, upload and download files",
"changes.openInExplorer": "Open in File Explorer",
"fx.places": "Workspaces",
"fx.back": "Back",
"fx.forward": "Forward",
"fx.search": "Search (Ctrl+F)",
"fx.searchHere": "Search this folder…",
"fx.viewAs": "View as",
"fx.gridView": "Icons",
"fx.listView": "List",
"fx.new": "New",
"fx.upload": "Upload",
"fx.more": "More",
"fx.selectAll": "Select all",
"fx.showHidden": "Show hidden files (Ctrl+H)",
"fx.untitledFolder": "New folder",
"fx.untitledFile": "untitled.txt",
"fx.copyPath": "Copy path",
"fx.clearSelection": "Clear selection",
"fx.noMatch": "Nothing here matches.",
"fx.loading": "Loading…",
"fx.dropHere": "Drop to upload into {{folder}}",
"fx.nameField": "Name",
"fx.from": "From",
"fx.deletedAt": "Deleted",
"fx.unavailable": "The file manager is not available on this dashboard yet — it needs a restart after the update.",
"fx.noWorkspace": "There is no workspace yet. Add one first, then its files show here.",
"fx.myHome": "Home",
"fx.userHomes": "Users' homes",
"fx.readOnlyHome": "Another user's home — view and download only",
"fx.readOnly": "Read-only",
"fx.readOnlyHint": "This is another user's home: you can view, copy and download, not change it."
}
+2 -1
View File
@@ -85,5 +85,6 @@
"closeMenu": "Close menu",
"sidebar": "Sidebar",
"now": "now",
"users": "Users"
"users": "Users",
"files": "Files"
}
+85 -1
View File
@@ -522,5 +522,89 @@
"changes.historyWholeBranch": "Cả nhánh",
"changes.annotate": "Annotate",
"changes.noBlame": "Không có gì để annotate: file này chưa có lịch sử commit",
"changes.notCommitted": "Chưa commit"
"changes.notCommitted": "Chưa commit",
"fx.title": "Quản lý file",
"fx.workspace": "Workspace",
"fx.files": "File",
"fx.trash": "Thùng rác",
"fx.close": "Đóng",
"fx.up": "Thư mục cha",
"fx.refresh": "Làm mới",
"fx.newFolder": "Thư mục mới",
"fx.newFile": "File mới",
"fx.uploadFiles": "Tải file lên",
"fx.uploadFolder": "Tải cả thư mục lên",
"fx.download": "Tải về",
"fx.downloadZip": "Tải về dạng zip",
"fx.rename": "Đổi tên",
"fx.copy": "Sao chép",
"fx.cut": "Cắt",
"fx.paste": "Dán",
"fx.pasteInto": "Dán vào thư mục này",
"fx.pasteFrom": "Dán {{count}} mục từ {{workspace}}",
"fx.delete": "Chuyển vào Thùng rác",
"fx.open": "Mở",
"fx.location": "Vị trí",
"fx.name": "Tên",
"fx.size": "Dung lượng",
"fx.modified": "Sửa lần cuối",
"fx.empty": "Thư mục trống — thả file vào đây để tải lên.",
"fx.itemsCount": "{{count}} mục",
"fx.selectedCount": "Đã chọn {{count}}",
"fx.dropHint": "Kéo file hoặc thư mục vào đây để tải lên · kéo vào một thư mục để di chuyển (Ctrl: sao chép)",
"fx.uploading": "Đang tải lên {{done}}/{{total}}…",
"fx.uploaded": "Đã tải lên {{count}} file.",
"fx.uploadFailed": "Không tải lên được {{name}}: {{message}}",
"fx.tooBig": "{{size}} vượt quá giới hạn một lần tải lên ({{max}}). Hãy tải ít file hơn mỗi lần.",
"fx.trashed": "Đã chuyển {{count}} mục vào Thùng rác.",
"fx.copiedDone": "Đã sao chép {{count}} mục — mở thư mục (hoặc workspace khác) rồi Dán.",
"fx.cutDone": "Đã cắt {{count}} mục — mở thư mục (hoặc workspace khác) rồi Dán.",
"fx.pasted": "Đã dán.",
"fx.crossOnlyWorkspace": "Các mục này chỉ dán được ở nơi chúng được lấy ra (worktree của session, thư mục phụ, hoặc giữa hai home).",
"fx.needsUpgrade": "Cần cập nhật helper của server — nhờ admin chạy `sudo agenthub server install-system` một lần.",
"fx.conflictTitle": "Đã có sẵn",
"fx.conflictBody": "Tên này đã có ở nơi đến: {{names}}",
"fx.conflictAll": "Áp dụng cho tất cả file còn lại",
"fx.cancel": "Huỷ",
"fx.skip": "Bỏ qua",
"fx.keepBoth": "Giữ cả hai",
"fx.replace": "Thay thế",
"fx.trashHint": "File và thư mục đã xoá, khôi phục được trong 7 ngày.",
"fx.emptyTrash": "Dọn sạch Thùng rác",
"fx.restore": "Khôi phục",
"fx.purge": "Xoá vĩnh viễn",
"fx.restored": "Đã khôi phục.",
"fx.trashEmpty": "Thùng rác trống.",
"changes.openExplorer": "Mở Quản lý file — quản lý, tải lên và tải về file",
"changes.openInExplorer": "Mở trong Quản lý file",
"fx.places": "Workspace",
"fx.back": "Quay lại",
"fx.forward": "Tiến tới",
"fx.search": "Tìm (Ctrl+F)",
"fx.searchHere": "Tìm trong thư mục này…",
"fx.viewAs": "Kiểu xem",
"fx.gridView": "Biểu tượng",
"fx.listView": "Danh sách",
"fx.new": "Mới",
"fx.upload": "Tải lên",
"fx.more": "Thêm",
"fx.selectAll": "Chọn tất cả",
"fx.showHidden": "Hiện file ẩn (Ctrl+H)",
"fx.untitledFolder": "Thư mục mới",
"fx.untitledFile": "chua-dat-ten.txt",
"fx.copyPath": "Sao chép đường dẫn",
"fx.clearSelection": "Bỏ chọn",
"fx.noMatch": "Không có mục nào khớp.",
"fx.loading": "Đang tải…",
"fx.dropHere": "Thả để tải lên vào {{folder}}",
"fx.nameField": "Tên",
"fx.from": "Từ",
"fx.deletedAt": "Ngày xoá",
"fx.unavailable": "Dashboard này chưa có trình quản lý file — cần khởi động lại sau khi cập nhật.",
"fx.noWorkspace": "Chưa có workspace nào. Hãy thêm một workspace, file của nó sẽ hiện ở đây.",
"fx.myHome": "Thư mục home",
"fx.userHomes": "Home của các user",
"fx.readOnlyHome": "Home của user khác — chỉ xem và tải về",
"fx.readOnly": "Chỉ đọc",
"fx.readOnlyHint": "Đây là home của user khác: bạn chỉ xem, sao chép và tải về được, không sửa được."
}
+2 -1
View File
@@ -85,5 +85,6 @@
"closeMenu": "Đóng menu",
"sidebar": "Thanh bên",
"now": "bây giờ",
"users": "Người dùng"
"users": "Người dùng",
"files": "Quản lý file"
}