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
+72 -32
View File
@@ -1,41 +1,81 @@
---
description: Diagnose a plugin-installed AgentHub — Node, npm, disk, bootstrap, server, hooks, CLI, systemd, tmux, UI build
description: Diagnose a plugin-installed AgentHub — Node, npm, disk, bootstrap, server, hooks, CLI, systemd, tmux, UI build — and offer to fix what it finds
---
Run the diagnostic and report what it found. Do not fix anything unless the user
asks.
## 1. Diagnose
Every command here runs from the plugin build that is installed NOW (`ROOT`):
a session not restarted after an update still names the old build in
`${CLAUDE_PLUGIN_ROOT}`, which would warn about itself forever. The shell does
not keep `ROOT` between commands, so each command block below resolves it
again:
```bash
node "${CLAUDE_PLUGIN_ROOT}/scripts/plugin-doctor.js"
ROOT=$(node -e 'console.log(require(process.argv[1]).supersededBy() || "")' \
"${CLAUDE_PLUGIN_ROOT}/scripts/plugin-bootstrap.js")
ROOT="${ROOT:-${CLAUDE_PLUGIN_ROOT}}"
node "$ROOT/scripts/plugin-doctor.js"
```
Print the output verbatim, then add at most three lines of guidance based on the
`FAIL` and `WARN` rows:
Print the output verbatim. If every row is `OK`, stop there — no summary of
things that passed.
- `FAIL Node` → the installed Node is too old for `node:sqlite`; the server
cannot start until Node is upgraded.
- `FAIL Hooks` → duplicate hook entries double every token and cost figure.
Starting a new Claude Code session removes them automatically (the bootstrap
backs the file up as `settings.json.agenthub-bak` first).
- `FAIL Server` → run `/agenthub-update`, then check
`~/.claude/agenthub/runtime/bootstrap.log` and `server.log`.
- `FAIL Runtime deps` → the install is incomplete, not merely absent. Delete
`~/.claude/agenthub/runtime/node_modules` before running `/agenthub-update`;
reinstalling over the broken tree is what let it survive.
- `FAIL npm` or `FAIL Disk` → nothing else in the report can be trusted until
these are fixed; both silently truncate installs.
- `WARN agenthub CLI` → print the exact `export PATH=...` line from the output.
- `WARN systemd` → when it says the unit names a **previous plugin version**,
the dashboard is running now but will NOT come back after a reboot. Starting
a new Claude Code session repairs it; print the `--force` command from the
output as the immediate fix. "installed but not running" just needs
`systemctl --user start agenthub`.
- `WARN tmux` → only the run console, `agenthub lanes shell` and the
session-reload keystrokes are affected; monitoring, workspaces and the CLI are not.
Print the install command from the output. If the row says `ok` but Start Run
still fails, the server has a different PATH than this check — ask it directly
with `curl -s localhost:4820/api/run/tmux`.
- `WARN Dashboard UI` → run `/agenthub-open` to build the bundle. When the row
quotes a build error, report that error — it is the actual problem.
## 2. Offer to fix
No preamble, no summary of things that passed.
If any row is `FAIL` or `WARN`, say in one line per row what is wrong (use the
guide below), then ask with `AskUserQuestion`: **"Tự động sửa các lỗi trên?"**
(answer in the user's language) — options "Có, cho tôi xem danh sách việc sẽ
làm" and "Không". On "Không", stop.
## 3. Show the plan, get approval
Build the plan from the table below: only the rows that are not `OK`, in the
table's order, each with the EXACT command you will run. Merge duplicates — one
`plugin-bootstrap.js --force` covers every row marked *bootstrap*. Rows marked
*report only* go in a separate "cannot fix automatically" list. Print the plan
as a numbered list, then ask with `AskUserQuestion`: **"Thực hiện các bước
trên?"** — "Đồng ý" / "Không". Do nothing until the user agrees.
Detect what the commands need before printing them: the OS (`uname -s`), the
package manager (`apt-get`, `dnf`, `pacman`, `brew`), a Node version manager
(`nvm`, `fnm`, `volta` — check with `command -v` or `~/.nvm/nvm.sh`), the
user's shell rc file from `$SHELL`, and whether `sudo -n true` works.
| Row | Fix |
|---|---|
| `FAIL Node` / `FAIL npm` | Install Node ≥ 22.5 (it ships npm). Prefer the user's version manager (`nvm install 22 && nvm alias default 22`, `fnm install 22 && fnm default 22`, `volta install node@22`); else `brew install node` (macOS) or the distro's package (`sudo apt-get install -y nodejs` only when it is ≥ 22.5 — otherwise propose nvm). Then run the *bootstrap* step with THAT node's absolute path, since the `agenthub` CLI launcher pins the node that ran the bootstrap. |
| `FAIL Disk` | *Report only.* Show what is large (`du -sh "<Data dir>"/* 2>/dev/null`, the `Data dir` row's path); never delete user data. |
| `FAIL Runtime deps` | `rm -rf "<Data dir>/runtime/node_modules"` (the `Data dir` row's path), then *bootstrap* — reinstalling over the broken tree is what lets it survive. |
| `WARN Runtime deps`, `WARN Bootstrap`, `FAIL Server`, `FAIL Hooks`, `WARN agenthub CLI` "no launcher", `WARN systemd` "previous plugin version" | *bootstrap* (it reinstalls deps, removes the duplicate hook entries after backing up `settings.json` as `settings.json.agenthub-bak`, rewrites the CLI launcher and the unit, and restarts the server). |
| `WARN agenthub CLI` "not on PATH" | Append the exact `export PATH=...` line from the row to the shell rc file — only if that file does not already contain it. |
| `WARN systemd` "not running" | `systemctl --user start agenthub` (Linux) / `agenthub service install` (macOS LaunchAgent). |
| `WARN systemd` "not written by AgentHub" | *Report only* — it is the user's unit. |
| `WARN tmux` "not found" | `sudo apt-get install -y tmux` / `sudo dnf install -y tmux` / `sudo pacman -S --noconfirm tmux` / `brew install tmux`. |
| `WARN tmux` older than 3.7 | macOS: `brew upgrade tmux`. Linux: *report only* — building tmux from source is the user's call; quote the row's instructions. |
| `WARN tmux` "running tmux server is" | *Report only* — it clears once every tmux session has closed. Never run `tmux kill-server`. |
| `WARN Dashboard UI` | the *bootstrap* step's `ROOT` lines, then `node "$ROOT/scripts/plugin-open.js" --force`, as ONE command — skip it when this doctor run was started by `/agenthub-open` (it re-runs the build itself). |
The *bootstrap* step, run as ONE command so `ROOT` survives (it runs from the
plugin build that is installed now — an older build's bootstrap refuses):
```bash
ROOT=$(node -e 'console.log(require(process.argv[1]).supersededBy() || "")' \
"${CLAUDE_PLUGIN_ROOT}/scripts/plugin-bootstrap.js")
ROOT="${ROOT:-${CLAUDE_PLUGIN_ROOT}}"
node "$ROOT/scripts/plugin-bootstrap.js" --force
```
## 4. Fix, then verify
Run the approved steps in order, one at a time, and stop at the first one that
fails: quote its decisive error line (for the bootstrap, from
`<Data dir>/runtime/bootstrap.log`) and ask how to continue.
- Run nothing that is not in the approved plan. If a step turns out to need
something else, ask again first.
- A `sudo` command when `sudo -n true` failed cannot be typed from here: ask
the user to run it themselves as `! <command>`, wait, then continue.
- A shell rc change only reaches new terminals — say so.
Finish by running the diagnosis again (step 1's command, `ROOT` lines included) and printing it verbatim, then at most
three lines on what is still not `OK` and why.
+20 -4
View File
@@ -1,14 +1,23 @@
---
description: Rebuild the dashboard UI and print its URL
description: Rebuild the dashboard UI and print its URL — runs the doctor when it fails
---
Rebuild the dashboard bundle, then print the URL. Always forces a rebuild so a
stale bundle (e.g. after a fix commit landed but the bootstrap's build predates
it) never serves silently. Also finishes the build if the bootstrap's own
attempt failed (check `~/.claude/agenthub/runtime/client-build.log`).
attempt failed (check `client-build.log` in the runtime dir — `<data dir>/runtime`,
by default `~/.claude/agenthub/runtime`).
Run it from the plugin build that is installed NOW, as ONE command so `ROOT`
survives — a session not restarted after an update still names the old build
in `${CLAUDE_PLUGIN_ROOT}`, whose bootstrap refuses to run (`superseded`) and
whose client would be built over the new one:
```bash
node "${CLAUDE_PLUGIN_ROOT}/scripts/plugin-open.js" --force
ROOT=$(node -e 'console.log(require(process.argv[1]).supersededBy() || "")' \
"${CLAUDE_PLUGIN_ROOT}/scripts/plugin-bootstrap.js")
ROOT="${ROOT:-${CLAUDE_PLUGIN_ROOT}}"
node "$ROOT/scripts/plugin-open.js" --force
```
Install + build takes a few minutes if the client toolchain isn't already
@@ -19,7 +28,14 @@ re-runs bootstrap first and prints `Server restarted on the current plugin
version.` (without it, the fresh bundle would call routes that old server
never had).
Then help the user open it:
**If it exits non-zero** (a failed build, or a bootstrap that did not bring the
server up): quote its error line, say you are running the doctor, then read
`$ROOT/plugins/agenthub/commands/agenthub-doctor.md` (the `ROOT` resolved above)
and follow it from step 1 — diagnose, offer to fix, show the plan, fix only what
the user approves. After the fixes, run the `plugin-open.js --force` command
above once more; if it fails again, report its error and stop.
On success, help the user open the URL:
```bash
uname -s
+21 -19
View File
@@ -23,29 +23,31 @@ else
fi
```
That downloads the new version into `~/.claude/plugins/cache/` but does not
take effect in *this* session — Claude Code only re-resolves `${CLAUDE_PLUGIN_ROOT}`
on `/reload-plugins` (a REPL-only action, not scriptable from a command). Say
so plainly: **tell the user to run `/reload-plugins` now**, then either
re-run `/agenthub-update` (this time the bootstrap step below runs against the new
version) or just start a new session — `plugin-bootstrap.js` compares the
recorded state against the current plugin version on every `SessionStart` and
rebuilds automatically if they differ.
Then, whether or not a plugin update was just pulled, refresh the runtime
against whatever `${CLAUDE_PLUGIN_ROOT}` currently resolves to. This stops the
running dashboard server before starting the new one. Say so, then run:
That downloads the new version into a NEW directory under
`~/.claude/plugins/cache/`, while `${CLAUDE_PLUGIN_ROOT}` in this session still
names the old one — and the old build's bootstrap refuses to run once a newer
build is installed (`supersededBy`). So refresh the runtime from the build that
is installed now: the new directory when one was just pulled, else this one.
This stops the running dashboard server before starting the new one. Say so,
then run:
```bash
node "${CLAUDE_PLUGIN_ROOT}/scripts/plugin-bootstrap.js" --force
ROOT=$(node -e 'console.log(require(process.argv[1]).supersededBy() || "")' \
"${CLAUDE_PLUGIN_ROOT}/scripts/plugin-bootstrap.js")
ROOT="${ROOT:-${CLAUDE_PLUGIN_ROOT}}"
echo "Refreshing the AgentHub runtime from $ROOT"
node "$ROOT/scripts/plugin-bootstrap.js" --force
node "$ROOT/scripts/plugin-doctor.js"
```
It runs in the foreground and can take a few minutes on a cold cache. When it
finishes, verify:
Run it as ONE command (the shell does not keep `ROOT` between commands). The
bootstrap runs in the foreground and can take a few minutes on a cold cache;
the doctor that follows verifies the result.
```bash
node "${CLAUDE_PLUGIN_ROOT}/scripts/plugin-doctor.js"
```
If a new version was pulled, tell the user the dashboard already runs it, but
this Claude Code session still loads the old plugin's commands and skills until
they run `/reload-plugins` or start a new session.
Report the final state in a few lines. If the bootstrap failed, quote the
decisive line from `~/.claude/agenthub/runtime/bootstrap.log`.
decisive line from `bootstrap.log` in the runtime dir (`<Data dir>/runtime` —
the doctor's `Data dir` row; by default `~/.claude/agenthub/runtime`).