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
+33 -1
View File
@@ -1023,6 +1023,13 @@ export function gitTarget(
return session ? { lane: laneId, session } : laneId;
}
/** A file the dashboard machine's file manager holds, by its own path. */
export interface FileManagerFile {
path: string;
size: number | null;
dir: boolean;
}
export const api = {
// ───────────────────────── Server mode login (routes/auth.js) ─────────────────────────
auth: {
@@ -2152,7 +2159,9 @@ export const api = {
*
* @returns {@link CostResult} — the aggregate cost breakdown across sessions.
*/
totalCost: (opts: { lane?: number; date?: string; tool?: string; range?: DateRange } = {}) => {
totalCost: (
opts: { lane?: number; date?: string; tool?: string; range?: DateRange; mine?: boolean } = {}
) => {
// Scope the aggregate to the active data-scope, exactly like the sessions /
// stats / analytics endpoints — otherwise switching the Data scope selector
// left the Dashboard "total cost" showing the un-narrowed global total.
@@ -2162,6 +2171,8 @@ export const api = {
// `date` (local YYYY-MM-DD): only that day's usage, breakdown included.
if (opts.date) qs.set("date", opts.date);
if (opts.tool) qs.set("tool", opts.tool);
// `mine`: only the caller's own sessions, even for an admin/analyst (server mode).
if (opts.mine) qs.set("mine", "1");
// `range`: total, breakdown and by_tool for those local days only.
applyRange(qs, opts.range);
applyScope(qs);
@@ -3350,6 +3361,27 @@ export const api = {
method: "POST",
body: JSON.stringify({ paths }),
}),
/** POST /api/run/clipboard-files — the files a file manager's Copy put on
* the dashboard machine's clipboard, by their own paths (`size` null for a
* folder); 403 EREMOTE unless local mode and a loopback browser. */
clipboardFiles: () =>
request<{ files: FileManagerFile[] }>("/run/clipboard-files", {
method: "POST",
body: "{}",
}),
/** POST /api/run/selected-files — the files selected in that machine's
* file manager (Explorer, Finder): what a drag from it carries. Same
* shape and refusal as `clipboardFiles`. */
selectedFiles: () =>
request<{ files: FileManagerFile[] }>("/run/selected-files", {
method: "POST",
body: "{}",
}),
/** GET /api/run/native-paste — whether a `claude` pane can read this
* machine's clipboard itself (a reader installed, a display reachable);
* false for a remote browser and in server mode. `key`: the chord
* `claude` reads an image with on that machine (Alt+V on Windows). */
nativePaste: () => request<{ native: boolean; key?: "ctrl+v" | "alt+v" }>("/run/native-paste"),
/** POST /api/run - start (or adopt, if already live) a lane's terminal run. */
start: (args: RunStartArgs) =>
request<RunHandle>("/run", { method: "POST", body: JSON.stringify(args) }),