feat: v2.8.0 — Artifacts uploads and plugin links, console tab combos, account avatars

- Artifacts hub: upload a file from the computer; make a skill by uploading a
  Markdown file, files, a folder or a .zip/.skill, or by writing it in the
  dialog; add plugins by picking from the list a marketplace link answers
  (POST /api/artifacts/plugin/inspect); Settings → AI tools → Artifacts Hub.
- Console tabs are combos of up to four split panes (ConsoleTabs, PaneGrid).
- Accounts: an own avatar (PUT/DELETE /api/me/avatar, raster only, ≤ 1 MB,
  <data dir>/avatars/), shown with name and role at the sidebar's foot and on
  the workspace owner groups (GET /api/users/:id/avatar, owner_avatar_at).
- Users page: per-user storage (GET /api/users/storage, measured in a worker)
  and account-pool spend/tokens per account (server/lib/pool-usage.js).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-14 17:21:33 +07:00
parent 8ed5018a2f
commit 7a88b74016
63 changed files with 3833 additions and 354 deletions
+39 -2
View File
@@ -35,7 +35,7 @@
"installs": "{{count}} installs",
"installed": "Installed to {{path}}",
"installedPlugin": "Installed {{name}} — start a new session (or /reload-plugins) to use it",
"rename": "Rename",
"rename": "Edit",
"delete": "Delete",
"deleteTitle": "Delete “{{title}}”?",
"deleteBody": "It is removed from your library and the Hub. Anything already installed from it stays installed.",
@@ -71,5 +71,42 @@
"files": "{{count}} files",
"close": "Close",
"fromSession": "From a session",
"form.saveEdit": "Save"
"form.saveEdit": "Save",
"skill.tab.upload": "Upload files",
"skill.tab.write": "Write new",
"skill.tab.existing": "From my skills",
"skill.name": "Skill name",
"skill.slugHint": "Installs as ~/.claude/skills/{{slug}}/ and runs as /{{slug}}",
"skill.slugBad": "Use letters, digits, '.', '_' or '-'",
"skill.description": "Description — when Claude should use this skill",
"skill.descriptionHint": "e.g. Use when writing release notes from the git log",
"skill.content": "Instructions (the body of SKILL.md)",
"skill.contentHint": "Write the steps Claude should follow. You can also paste a whole SKILL.md, frontmatter included.",
"skill.dropHint": "Drop a SKILL.md, any Markdown file, a skill folder, several files or a .zip/.skill here",
"skill.pickFiles": "Choose files",
"skill.pickFolder": "Choose folder",
"skill.clear": "Clear",
"skill.uploading": "Uploading…",
"skill.shape.none": "Nothing to upload",
"skill.shape.single-md": "This Markdown file becomes the skill's SKILL.md",
"skill.shape.archive": "An archive — it is unpacked; each folder with a SKILL.md becomes a skill",
"skill.shape.one": "One skill folder",
"skill.shape.many": "{{count}} skills — each is added on its own, named by its folder",
"skill.shape.no-skill-md": "No SKILL.md here — add one, or upload a single Markdown file",
"skill.manyHint": "Several skills: each keeps its own folder name and the description in its SKILL.md.",
"skill.addedMany": "Added {{count}} skills",
"plugin.link": "Marketplace link",
"plugin.linkHint": "A git repository with .claude-plugin/marketplace.json (https link, the forge's web link, or owner/repo for GitHub), or a link to a marketplace.json.",
"plugin.read": "Read plugins",
"plugin.reading": "Reading…",
"plugin.none": "This marketplace lists no plugins.",
"plugin.all": "Select all",
"plugin.have": "already added",
"plugin.addPicked": "Add {{count}} plugin(s)",
"plugin.addedMany": "Added {{count}} plugin(s)",
"plugin.manual": "Type name@marketplace by hand (ssh link, private repository…)",
"file.fromComputer": "From your computer (≤ 25 MB)",
"file.upload": "Upload",
"file.tooBig": "The file is larger than 25 MB.",
"file.fromWorkspace": "Or pin a document a workspace's sessions wrote"
}
+7 -1
View File
@@ -436,7 +436,13 @@
"tabs.settings": "Settings",
"tabs.closeSettings": "Close Settings",
"tabs.splitHint": "Ctrl/Cmd+click: open in a split · drag onto a pane to place it",
"panes.drag": "Drag to move this pane — onto another pane's edge to split there, onto its middle to swap",
"panes.drag": "Drag to move this pane — onto another pane's edge to split there, onto its middle to swap; hold it over another tab to open that tab",
"panes.drop.left": "Place on the left",
"panes.drop.right": "Place on the right",
"panes.drop.top": "Place on top",
"panes.drop.bottom": "Place below",
"panes.drop.swap": "Swap places",
"panes.drop.replace": "Show here — this pane moves to its own tab",
"panes.pick": "Show another session in this pane",
"panes.empty": "No session",
"panes.split.right": "Split right",
+7
View File
@@ -1267,6 +1267,13 @@
"appliesTo": "Applies to"
},
"account": {
"avatar": {
"change": "Change picture",
"remove": "Remove picture",
"saved": "Picture updated",
"removed": "Picture removed",
"tooBig": "The picture must be at most 1 MB"
},
"loadFailed": "Could not load your account: {{message}}",
"memberSince": "Member since",
"workspaces": "Workspaces",
+9 -1
View File
@@ -7,6 +7,11 @@
"sessions": "Sessions",
"last7d": "7 days",
"last30d": "30 days",
"storage": "Storage",
"storageHint": "{{files}} files · measured {{at}}",
"storagePartial": "at least — part of the folder could not be read in time",
"storageNone": "No home folder of their own",
"storageMeasuring": "Measuring…",
"disabled": "disabled",
"you": "you",
"tokens": "{{n}} tokens",
@@ -61,6 +66,8 @@
"deleted": "{{name}} was deleted."
},
"errors": {
"EBADIMAGE": "Only a PNG, JPEG, GIF or WebP picture",
"ETOOBIG": "The picture must be at most 1 MB",
"EREAUTH": "Your password is wrong.",
"ETOOMANY": "Too many wrong passwords. Try again in 15 minutes.",
"ESELF": "You cannot change your own role or disable yourself.",
@@ -128,7 +135,8 @@
"livePanes": "Live",
"quota": "Quota",
"spend": "5 hours",
"spend7d": "{{cost}} in 7 days",
"spend7d": "{{cost}} · {{tokens}} tokens in 7 days",
"tokens": "{{tokens}} tokens",
"added": "added {{at}}",
"expired": "expired",
"full": "full",
+39 -2
View File
@@ -35,7 +35,7 @@
"installs": "{{count}} lượt cài",
"installed": "Đã cài vào {{path}}",
"installedPlugin": "Đã cài {{name}} — mở phiên mới (hoặc /reload-plugins) để dùng",
"rename": "Đổi tên",
"rename": "Sửa",
"delete": "Xoá",
"deleteTitle": "Xoá “{{title}}”?",
"deleteBody": "Mục này bị gỡ khỏi thư viện của bạn và Hub. Những bản người khác đã cài vẫn giữ nguyên.",
@@ -71,5 +71,42 @@
"files": "{{count}} file",
"close": "Đóng",
"fromSession": "Từ một phiên",
"form.saveEdit": "Lưu"
"form.saveEdit": "Lưu",
"skill.tab.upload": "Tải file lên",
"skill.tab.write": "Viết mới",
"skill.tab.existing": "Từ skill có sẵn",
"skill.name": "Tên skill",
"skill.slugHint": "Cài vào ~/.claude/skills/{{slug}}/ và gọi bằng /{{slug}}",
"skill.slugBad": "Chỉ dùng chữ, số, '.', '_' hoặc '-'",
"skill.description": "Mô tả — khi nào Claude nên dùng skill này",
"skill.descriptionHint": "VD: Dùng khi viết release notes từ git log",
"skill.content": "Hướng dẫn (nội dung SKILL.md)",
"skill.contentHint": "Viết các bước Claude cần làm. Có thể dán nguyên một file SKILL.md, kể cả frontmatter.",
"skill.dropHint": "Kéo thả vào đây: SKILL.md, một file Markdown bất kỳ, thư mục skill, nhiều file hoặc file .zip/.skill",
"skill.pickFiles": "Chọn file",
"skill.pickFolder": "Chọn thư mục",
"skill.clear": "Bỏ chọn",
"skill.uploading": "Đang tải lên…",
"skill.shape.none": "Chưa có gì để tải lên",
"skill.shape.single-md": "File Markdown này sẽ thành SKILL.md của skill",
"skill.shape.archive": "File nén — sẽ được giải nén; mỗi thư mục có SKILL.md thành một skill",
"skill.shape.one": "Một thư mục skill",
"skill.shape.many": "{{count}} skill — mỗi skill được thêm riêng, đặt tên theo thư mục",
"skill.shape.no-skill-md": "Không có SKILL.md — thêm một file SKILL.md, hoặc chỉ tải lên một file Markdown",
"skill.manyHint": "Nhiều skill: mỗi skill giữ tên thư mục và mô tả trong SKILL.md của nó.",
"skill.addedMany": "Đã thêm {{count}} skill",
"plugin.link": "Link marketplace",
"plugin.linkHint": "Repo git có .claude-plugin/marketplace.json (link https, link trang web của repo, hoặc owner/repo với GitHub), hoặc link tới file marketplace.json.",
"plugin.read": "Đọc danh sách plugin",
"plugin.reading": "Đang đọc…",
"plugin.none": "Marketplace này không có plugin nào.",
"plugin.all": "Chọn tất cả",
"plugin.have": "đã thêm",
"plugin.addPicked": "Thêm {{count}} plugin",
"plugin.addedMany": "Đã thêm {{count}} plugin",
"plugin.manual": "Nhập tay name@marketplace (link ssh, repo riêng tư…)",
"file.fromComputer": "Từ máy tính (≤ 25 MB)",
"file.upload": "Tải lên",
"file.tooBig": "File lớn hơn 25 MB.",
"file.fromWorkspace": "Hoặc ghim tài liệu do các phiên của workspace đã ghi"
}
+7 -1
View File
@@ -436,7 +436,13 @@
"tabs.settings": "Cài đặt",
"tabs.closeSettings": "Đóng Cài đặt",
"tabs.splitHint": "Ctrl/Cmd+click: mở ở split · kéo thả vào một pane để đặt vị trí",
"panes.drag": "Kéo để di chuyển pane — thả vào cạnh pane khác để tách ở đó, vào giữa để đổi chỗ",
"panes.drag": "Kéo để di chuyển pane — thả vào cạnh pane khác để tách ở đó, vào giữa để đổi chỗ; giữ trên một tab khác để mở tab đó",
"panes.drop.left": "Đặt bên trái",
"panes.drop.right": "Đặt bên phải",
"panes.drop.top": "Đặt phía trên",
"panes.drop.bottom": "Đặt phía dưới",
"panes.drop.swap": "Đổi chỗ",
"panes.drop.replace": "Hiện ở đây — pane này sang tab riêng",
"panes.pick": "Hiện session khác trong pane này",
"panes.empty": "Không có session",
"panes.split.right": "Tách sang phải",
+7
View File
@@ -1267,6 +1267,13 @@
"appliesTo": "Áp dụng cho"
},
"account": {
"avatar": {
"change": "Đổi ảnh đại diện",
"remove": "Xoá ảnh đại diện",
"saved": "Đã cập nhật ảnh đại diện",
"removed": "Đã xoá ảnh đại diện",
"tooBig": "Ảnh tối đa 1 MB"
},
"loadFailed": "Không tải được tài khoản: {{message}}",
"memberSince": "Tham gia từ",
"workspaces": "Workspace",
+9 -1
View File
@@ -7,6 +7,11 @@
"sessions": "Phiên",
"last7d": "7 ngày",
"last30d": "30 ngày",
"storage": "Dung lượng",
"storageHint": "{{files}} tệp · đo lúc {{at}}",
"storagePartial": "ít nhất — một phần thư mục chưa đọc được kịp",
"storageNone": "Không có thư mục home riêng",
"storageMeasuring": "Đang đo…",
"disabled": "đã khoá",
"you": "bạn",
"tokens": "{{n}} token",
@@ -61,6 +66,8 @@
"deleted": "Đã xoá {{name}}."
},
"errors": {
"EBADIMAGE": "Chỉ nhận ảnh PNG, JPEG, GIF hoặc WebP",
"ETOOBIG": "Ảnh tối đa 1 MB",
"EREAUTH": "Mật khẩu của bạn không đúng.",
"ETOOMANY": "Nhập sai mật khẩu quá nhiều lần. Thử lại sau 15 phút.",
"ESELF": "Bạn không thể tự đổi vai trò hay tự khoá chính mình.",
@@ -128,7 +135,8 @@
"livePanes": "Đang chạy",
"quota": "Quota",
"spend": "5 giờ",
"spend7d": "{{cost}} trong 7 ngày",
"spend7d": "{{cost}} · {{tokens}} tokens trong 7 ngày",
"tokens": "{{tokens}} tokens",
"added": "thêm lúc {{at}}",
"expired": "hết hạn",
"full": "đầy",