fix: per-user Today, native paste and drop on a local machine

- Today's spend in the status bar and the Claude Code statusline is the
  caller's own (`GET /api/pricing/cost?mine=1`, scope.ownSessionWhere), not
  every user's sum for an admin or analyst.
- A screenshot pasted into a local claude pane is sent as Claude Code's own
  image-paste key: Alt+V on Windows (Ctrl+V did nothing there), ^V elsewhere,
  and only when the machine can read its clipboard (wl-paste/xclip + a
  display on Linux), else it is uploaded (GET /api/run/native-paste {key}).
- A file manager's files pasted or dropped on a local browser go in by their
  own paths, read from the OS clipboard or the file manager's selection
  (server/lib/file-manager.js, POST /api/run/clipboard-files and
  /selected-files): no upload, no size limit. A copied image file is pasted
  by path, text that comes with a picture of it (spreadsheet cells) is
  pasted as text, Windows paths go in as `C:/…` mentions.
- Tab titles for Snapshot, Artifacts, Files and Administration.
- An npm tool AgentHub installed under ~/.local is updated there, not by its
  own updater into npm's global prefix.
This commit is contained in:
2026-10-26 11:18:05 +07:00
parent c59e196e41
commit f2f1cd9b6c
33 changed files with 1046 additions and 60 deletions
+15 -5
View File
@@ -36,7 +36,19 @@ const ownerFor = (req) => (req?.user ? req.user.id : null);
* unrestricted. `col` is the session id expression, `laneCol` its lane id.
*/
function sessionWhere(req, col = "id", laneCol = "lane_id") {
const uid = memberId(req);
return ownedSessionWhere(memberId(req), col, laneCol);
}
/**
* `sessionWhere` for the requesting user's OWN sessions, whatever their role —
* a personal figure (the status bar's Today) that must not be every user's sum
* for an admin or analyst. "1" in local mode, where there is no user.
*/
function ownSessionWhere(req, col = "id", laneCol = "lane_id") {
return ownedSessionWhere(req?.user ? req.user.id : null, col, laneCol);
}
function ownedSessionWhere(uid, col, laneCol) {
if (uid == null) return { where: "1", params: [] };
return {
where: `(${laneCol} IN (SELECT id FROM lanes WHERE owner_id = ?)
@@ -155,10 +167,7 @@ const PATH_RULES = [
[/^\/workflows\/runs\/([^/]+)/i, (req, m) => canSeeRowSession(req, "workflows", m[1], "run_id")],
[/^\/alerts\/([^/]+)\/ack/i, (req, m) => canSeeRowSession(req, "alert_events", m[1])],
// `/artifacts/<id>…`: the owner's, or a shared one (server/lib/artifacts.js).
[
/^\/artifacts\/(\d+)(?:\/|$)/i,
(req, m) => require("./artifacts").canSeeId(req, m[1]),
],
[/^\/artifacts\/(\d+)(?:\/|$)/i, (req, m) => require("./artifacts").canSeeId(req, m[1])],
[
/^\/snapshots\/([^/]+)$/i,
(req, m) => req.method !== "DELETE" || canSeeRowSession(req, "session_snapshots", m[1]),
@@ -449,6 +458,7 @@ module.exports = {
memberId,
ownerFor,
sessionWhere,
ownSessionWhere,
bySessionWhere,
laneWhere,
canSeeLane,