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
+88
View File
@@ -20326,6 +20326,94 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/run/clipboard-files:
post:
tags:
- Run
summary: The files a file manager's Copy put on this machine's clipboard
operationId: runClipboardFiles
description: 'For a browser on this machine: the files the OS clipboard holds (Windows GetFileDropList, macOS NSPasteboard file URLs, Linux text/uri-list via wl-paste/xclip), each that exists here with its size (`null` for a folder), at most 100 — so a pasted copy is attached by its own path, with no upload and no size limit. The client uses a path only when name and size match the pasted file. 403 EREMOTE in server mode or for any non-loopback (or proxied) request.'
responses:
'200':
description: The clipboard's files; empty when it holds none or no reader is installed.
content:
application/json:
schema:
type: object
properties:
files:
type: array
items:
type: object
properties:
path:
type: string
size:
type: integer
nullable: true
dir:
type: boolean
'403':
description: EREMOTE.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/run/selected-files:
post:
tags:
- Run
summary: The files selected in this machine's file manager (what a drag carries)
operationId: runSelectedFiles
description: 'For a browser on this machine: the items selected in Explorer (every window, and the desktop) or Finder — a drag from the file manager carries exactly those — each that exists here with its size (`null` for a folder), at most 100, so a dropped file is attached by its own path with no upload and no size limit. Linux file managers publish no selection: always empty there. Nothing is searched for on disk. 403 EREMOTE in server mode or for any non-loopback (or proxied) request.'
responses:
'200':
description: The selected files; empty when none or no reader is available.
content:
application/json:
schema:
type: object
properties:
files:
type: array
items:
type: object
properties:
path:
type: string
size:
type: integer
nullable: true
dir:
type: boolean
'403':
description: EREMOTE.
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
/api/run/native-paste:
get:
tags:
- Run
summary: Whether a claude pane can read this machine's clipboard itself
operationId: runNativePaste
description: '`native`: local mode, a loopback request, and on Linux a reachable display plus `wl-paste` or `xclip` — then the terminal hands a pasted screenshot to `claude` as its image-paste key instead of uploading it. `key`: that chord on this machine — `alt+v` on Windows, `ctrl+v` elsewhere (Claude Code''s own bindings).'
responses:
'200':
description: The answer.
content:
application/json:
schema:
type: object
properties:
native:
type: boolean
key:
type: string
enum:
- ctrl+v
- alt+v
/api/run/interrupted:
get:
tags: