feat: workspace aliases, tab groups of split panes, native path picker (v2.1.0)

- /api/workspaces and `agenthub workspace(s)` / `--workspace` as aliases of
  /api/lanes and `agenthub lanes` / `--lane`; old names print one stderr note.
  REPL `help lanes|workspace|workspaces` resolves through the aliases.
- A workspace holds up to ten sessions (slots 0-9); every console tab is a
  group of 1-4 split panes (PaneGroups, agenthub.workspace.paneLayout);
  parseGroups keeps the stored active tab when an earlier one is dropped.
- Browse button beside path fields: POST /api/lanes/pick-path opens the OS
  picker on the server's desktop — loopback only and no forwarding header
  (EREMOTE), a display failure is ENODIALOG not a Cancel, the dialog is
  killed when the request closes, a folder field falls back to the in-app
  browser on any failure.
- Changes rail counts chip, image viewer (/git/raw), status bar session
  counts and per-day cost (`date=` on /api/pricing/cost).
- /agenthub-open and /agenthub-doctor run from the INSTALLED build
  (supersededBy), doctor offers fixes behind two confirmations; plugin-open
  treats a locked bootstrap as non-fatal.
- New-terminal shell waits for the first attach (issue #55).
- repo-onboarding / debug-live-issue skills removed.
- OpenAPI: pick-path, lane/date on /pricing/cost, tool on /run/history,
  /api/workspaces mount.
This commit is contained in:
2026-10-06 11:31:26 +07:00
parent c067abc68f
commit 6c605849d8
104 changed files with 3478 additions and 1396 deletions
+98 -2
View File
@@ -3,7 +3,7 @@
openapi: 3.0.3
info:
title: Agent Dashboard for Claude Code API
version: 2.0.1
version: 2.1.0
description: HTTP API for real-time Claude Code session monitoring, agent lifecycle tracking, analytics, pricing, hooks ingestion, and workflow intelligence.
contact:
name: Nguyễn Ngọc Trí Vĩ
@@ -57,7 +57,7 @@ tags:
- name: Run
description: Spawn and supervise Claude Code runs from the dashboard (headless or interactive conversation), stream output over WebSocket, and manage run history
- name: Lanes
description: Durable parallel-work lanes and dashboard-managed git worktrees
description: Durable parallel-work workspaces (called lanes in the API) and dashboard-managed git worktrees. Every /api/lanes route is also mounted at /api/workspaces — the same handlers, the user-facing name.
- name: Push
description: Web Push notification subscriptions and broadcast (VAPID); also fires native Electron notifications when hosted in the desktop app
- name: AI Tools
@@ -6022,6 +6022,21 @@ paths:
type: string
description: Comma-separated data-source ids to include (local history is `local`; remote SSH machines use their `remote_sources.id`). Omit for all sources. Narrows the aggregate cost to the given origins.
example: local
- name: lane
in: query
required: false
schema:
type: integer
description: Only the sessions this workspace owns — the same rule as GET /api/sessions?lane=. 400 INVALID_INPUT when not an id.
example: 5
- name: date
in: query
required: false
schema:
type: string
format: date
description: 'Only that local day (YYYY-MM-DD, in `tz_offset`''s timezone): the total and breakdown count the tokens spent that day. 400 INVALID_INPUT for any other shape.'
example: '2026-10-06'
responses:
'200':
description: Cost result
@@ -10574,6 +10589,13 @@ paths:
type: integer
description: Return only the runs started through this lane (POST /api/lanes/{id}/start). Omit for every run; runs spawned from POST /api/run carry no lane and are excluded whenever this is set.
example: 5
- name: tool
in: query
required: false
schema:
type: string
description: Return only the runs of this AI Tools id — `shell` for a plain terminal tab (the sidebar's recently closed Terminal tabs).
example: shell
responses:
'200':
description: Run history, most recent first
@@ -10946,6 +10968,48 @@ paths:
error:
code: ENOTFOUND
message: run not found
/api/lanes/pick-path:
post:
tags:
- Lanes
summary: Open the OS's own folder/file picker on the server's desktop
description: 'Shows zenity/kdialog (Linux), osascript (macOS) or a WinForms dialog (Windows) on the SERVER''s desktop and waits for the user (up to 10 minutes; closed when the request goes away). Only for a browser on the same machine: a non-loopback client, or a request carrying X-Forwarded-For/Forwarded, gets EREMOTE and should fall back to GET /api/lanes/browse. One dialog at a time. Nothing from the request reaches argv but the starting folder, resolved to an existing absolute directory first.'
operationId: pickLanePath
requestBody:
content:
application/json:
schema:
type: object
properties:
kind:
type: string
enum:
- dir
- file
default: dir
start:
type: string
description: Folder (or file) to open the dialog at.
responses:
'200':
description: '`{path}` — the chosen absolute path — or `{cancelled: true}`.'
content:
application/json:
schema:
type: object
properties:
path:
type: string
cancelled:
type: boolean
'403':
description: EBADORIGIN (not same-origin) or EREMOTE (not a local browser).
'409':
description: EBUSY — a picker is already open.
'500':
description: EDIALOG — the dialog program failed.
'501':
description: ENODIALOG — no desktop session or no dialog program.
/api/lanes/ensure:
post:
tags:
@@ -11415,6 +11479,38 @@ paths:
description: ESECRET — `.claude/settings.local.json` (the AI Router key) is refused at every rev, at any depth, and under any path that resolves to it (a symlinked `.claude`).
'404':
description: Lane not found.
/api/lanes/{id}/git/raw:
get:
tags:
- Lanes
summary: One image file's bytes at a revision
description: 'For the viewer''s <img>. Same path, rev and secret guards as /git/file, plus an extension allowlist (png, jpg, jpeg, gif, webp, avif, bmp, ico, svg) that sets the Content-Type, and a 20 MB cap. Served with `Content-Security-Policy: …; sandbox` and `X-Content-Type-Options: nosniff`, so an SVG opened from this URL runs no script. Read-only, no same-origin guard.'
operationId: readLaneImage
parameters:
- name: id
in: path
required: true
schema:
type: integer
- name: path
in: query
required: true
schema:
type: string
- name: rev
in: query
schema:
type: string
default: work
responses:
'200':
description: The image bytes, typed by extension.
'400':
description: EBADPATH, EBADREV, ENOFILE, ENOTIMAGE or ETOOBIG.
'403':
description: ESECRET.
'404':
description: Lane not found.
/api/lanes/{id}/git/ls:
get:
tags: