feat: account pool per tool with groups and a Cursor pool; update runs in the background

- The update dialog can be closed while an update applies: it keeps running,
  the page still reloads itself when the new server is up, and a failure
  re-opens the dialog with its error.
- Account pool card: one tab per AI tool (Claude Code, Codex, Cursor CLI,
  Oh My Pi, and every other installed tool, which says it has no pool),
  accounts as cards with 5-hour and weekly quota shown as what is LEFT plus
  their reset times, and the saved profiles of Settings → AI tools →
  Profiles as cards with "Share to pool".
- Cursor account pool (server/lib/cursor-pool.js): Cursor API keys handed to
  a cursor-agent pane only through tmux -e CURSOR_API_KEY;
  `agenthub accounts add <name> --tool cursor`.
- Pool groups (server/lib/pool-groups.js, /api/accounts/groups): a group's
  members run only on its accounts of each tool, a user in no group on the
  accounts no group lists, a pin still wins. account_pins loses its tool
  CHECK (rebuilt, pins kept); three new tables.
- Oh My Pi login sharing can be switched from its pool tab too.
This commit is contained in:
2026-10-22 17:02:08 +07:00
parent 44426faf16
commit 685eb748e8
30 changed files with 2891 additions and 299 deletions
+4 -1
View File
@@ -488,6 +488,8 @@ function spawnRun(args) {
entry.launcher === "codex" && !proxyProfile
? require("./codex-pool").forSpawn(require("./run-as").accountForLane(laneId), laneOwner)
: null;
// Cursor's pool is API keys only (cursor-pool.js): CURSOR_API_KEY through `-e`.
const cursorPool = tool === "cursor" ? require("./cursor-pool").forSpawn(laneOwner) : null;
const paneCred = require("./auth").newPaneToken();
// A member's omp on the host's shared omp login (omp-share.js): its
// models.yml points at the loopback gateway, with a key already listed there.
@@ -611,7 +613,7 @@ function spawnRun(args) {
resumeSessionId: resumeSessionId || null,
worktree: worktree === true || inWorktree === true,
proxy: proxyProfile ? proxyProfile.name : null,
account: (poolAccount || codexPool)?.name ?? null,
account: (poolAccount || codexPool || cursorPool)?.name ?? null,
paneTokenHash: paneCred ? paneCred.hash : null,
prompt: initialPrompt || "",
status: "running",
@@ -668,6 +670,7 @@ function spawnRun(args) {
// this process only. Through tmux `-e`, never typed into the pane.
...(poolAccount ? poolAccount.env : {}),
...(codexPool ? codexPool.env : {}),
...(cursorPool ? cursorPool.env : {}),
...(ompShare ? ompShare.env : {}),
// Server mode: the CLI, MCP server and statusline in this pane act as the
// workspace's owner with it (server/lib/auth.js userFromPaneToken).