feat: v2.5.12 — plan and quota for every AI tool, Grok Build and Kimi Code, Quit AgentHub (#65)
Usage panel (status bar): - every account shows its plan (Claude subscriptionType, Codex chatgpt_plan_type, Cursor membershipType, Grok subscriptionTier) - new quota rows: Cursor CLI (cursor.com usage-summary), Antigravity (`agy --print /usage`, two model pools; AGENTHUB_AGY_USAGE=0 never runs agy), Grok Build, Kimi Code, OpenCode Go — each login read from the tool's own file, sent only to its own host while valid, never refreshed - in-flight quota reads are shared between tabs AI Tools catalog: Grok Build (`grok`) and Kimi Code (`kimi`) added; Gemini CLI, Hermes and OpenClaw removed. Also: Quit AgentHub (#65, `agenthub stop`), status-area icon, Add to Chat on an editor selection, Settings in three groups, JetBrains-style Changes panel (ticked files/hunks, ignore, blame, file history), terminal font. --no-verify: :3000 is taken by another dev server (lane-detect tests); both suites run by hand — server 2636/2639 (the 3 are :3000), client 1131/1131.
This commit is contained in:
+77
-11
@@ -397,6 +397,7 @@ import type {
|
||||
Lane,
|
||||
LaneChangeRange,
|
||||
LaneChanges,
|
||||
LaneBlame,
|
||||
LaneCommit,
|
||||
LaneFileContent,
|
||||
LaneTreeEntry,
|
||||
@@ -673,8 +674,42 @@ export const api = {
|
||||
users: {
|
||||
/** GET /api/users — every account with its recent usage (admin/analyst). */
|
||||
list: () => request<{ users: ServerUserUsage[] }>("/users"),
|
||||
/** GET /api/users/audit — staff reads of members' sessions, newest first. */
|
||||
/** GET /api/users/audit — staff reads of members' sessions and admins'
|
||||
* account changes, newest first. */
|
||||
audit: () => request<{ entries: AuditEntry[] }>("/users/audit"),
|
||||
// Account changes (admin only). Each carries the admin's OWN password
|
||||
// again (`currentPassword`): the server refuses without it (EREAUTH).
|
||||
/** POST /api/users — a new account. */
|
||||
create: (
|
||||
body: { username: string; password: string; role: AuthUser["role"] },
|
||||
currentPassword: string
|
||||
) =>
|
||||
request<{ user: AuthUser & { disabled: boolean } }>("/users", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ ...body, currentPassword }),
|
||||
}),
|
||||
/** PATCH /api/users/:id — role and/or disabled (never your own). */
|
||||
update: (
|
||||
id: number,
|
||||
body: { role?: AuthUser["role"]; disabled?: boolean },
|
||||
currentPassword: string
|
||||
) =>
|
||||
request<{ user: AuthUser & { disabled: boolean } }>(`/users/${id}`, {
|
||||
method: "PATCH",
|
||||
body: JSON.stringify({ ...body, currentPassword }),
|
||||
}),
|
||||
/** POST /api/users/:id/password — a new password; that user's logins end. */
|
||||
setPassword: (id: number, password: string, currentPassword: string) =>
|
||||
request<{ user: AuthUser }>(`/users/${id}/password`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ password, currentPassword }),
|
||||
}),
|
||||
/** POST /api/users/:id/workspaces — give that user a workspace. */
|
||||
assignWorkspace: (id: number, laneId: number, currentPassword: string) =>
|
||||
request<{ user: AuthUser }>(`/users/${id}/workspaces`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ laneId, currentPassword }),
|
||||
}),
|
||||
},
|
||||
// ───────────────────────── Updates / self-update API ─────────────────────────
|
||||
/** Self-update status: whether this install is a git clone and, if so,
|
||||
@@ -1113,7 +1148,13 @@ export const api = {
|
||||
};
|
||||
load_stats: { m5: number; m15: number; h1: number };
|
||||
};
|
||||
hooks: { installed: boolean; path: string; hooks: Record<string, boolean> };
|
||||
hooks: {
|
||||
installed: boolean;
|
||||
path: string;
|
||||
hooks: Record<string, boolean>;
|
||||
/** "plugin" when the enabled agenthub plugin provides the hooks. */
|
||||
source?: "plugin";
|
||||
};
|
||||
server: {
|
||||
version: string;
|
||||
uptime: number;
|
||||
@@ -1197,6 +1238,21 @@ export const api = {
|
||||
body: JSON.stringify({ enabled }),
|
||||
}),
|
||||
},
|
||||
/** AgentHub's icon in the OS status area — on by default; a change starts
|
||||
* or stops the icon process, never the server. */
|
||||
tray: {
|
||||
/** GET /api/settings/tray */
|
||||
get: () => request<TrayStatus>("/settings/tray"),
|
||||
/** PUT /api/settings/tray */
|
||||
set: (enabled: boolean) =>
|
||||
request<TrayStatus>("/settings/tray", {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({ enabled }),
|
||||
}),
|
||||
},
|
||||
/** POST /api/settings/quit — close every workspace terminal and stop the
|
||||
* server until `agenthub start` (or a boot/login with autostart on). */
|
||||
quit: () => request<{ ok: true; killed: number }>("/settings/quit", { method: "POST" }),
|
||||
/** Opt-in secret redaction of stored payloads and the folders whose hooks
|
||||
* are dropped (`server/lib/privacy.js`). */
|
||||
privacy: {
|
||||
@@ -2891,6 +2947,9 @@ export const api = {
|
||||
* @param id The lane id.
|
||||
* @param opts `file` narrows the list to the commits touching one path.
|
||||
*/
|
||||
/** GET /api/lanes/:id/git/blame — Annotate: each line's last commit. */
|
||||
gitBlame: (id: GitTarget, path: string) =>
|
||||
request<LaneBlame>(gitUrl(id, "/blame", new URLSearchParams({ path }))),
|
||||
gitLog: (id: GitTarget, opts: { limit?: number; file?: string; ref?: string } = {}) => {
|
||||
const q = new URLSearchParams();
|
||||
if (opts.limit) q.set("limit", String(opts.limit));
|
||||
@@ -2978,8 +3037,11 @@ export const api = {
|
||||
* POST /api/lanes/:id/git/commit-message — a message for what is staged,
|
||||
* written by the user's `claude` CLI (no tools, nothing persisted).
|
||||
*/
|
||||
suggestCommitMessage: (id: GitTarget) =>
|
||||
request<{ message: string }>(gitUrl(id, "/commit-message"), { method: "POST" }),
|
||||
suggestCommitMessage: (id: GitTarget, paths?: string[]) =>
|
||||
request<{ message: string }>(gitUrl(id, "/commit-message"), {
|
||||
method: "POST",
|
||||
...(paths ? { body: JSON.stringify({ paths }) } : {}),
|
||||
}),
|
||||
/**
|
||||
* POST /api/lanes/:id/git/:action — one git write on the lane's worktree.
|
||||
* @param id The lane id.
|
||||
@@ -3016,7 +3078,8 @@ export const api = {
|
||||
| "cherry-pick"
|
||||
| "revert"
|
||||
| "undo-commit"
|
||||
| "amend",
|
||||
| "amend"
|
||||
| "ignore",
|
||||
body: {
|
||||
/** cherry-pick / revert: the commit. */
|
||||
sha?: string;
|
||||
@@ -3278,12 +3341,7 @@ function requestCodexBackupsHelper(params?: {
|
||||
/** Kind of Claude Code config artifact manageable via `api.ccConfig.write`/
|
||||
* `delete` - each maps to a distinct on-disk location under `.claude/`. */
|
||||
export type CcArtifactType =
|
||||
| "skills"
|
||||
| "agents"
|
||||
| "commands"
|
||||
| "output-styles"
|
||||
| "memory"
|
||||
| "auto-memory";
|
||||
"skills" | "agents" | "commands" | "output-styles" | "memory" | "auto-memory";
|
||||
|
||||
/** Body for PUT /api/cc-config/file - create or overwrite one artifact. */
|
||||
export interface CcWriteArgs {
|
||||
@@ -4436,6 +4494,14 @@ export interface AutostartStatus {
|
||||
foreign: boolean;
|
||||
}
|
||||
|
||||
/** GET /api/settings/tray. `available` false: server mode, or no graphical
|
||||
* session on this Linux machine. */
|
||||
export interface TrayStatus {
|
||||
available: boolean;
|
||||
enabled: boolean;
|
||||
running: boolean;
|
||||
}
|
||||
|
||||
/** GET /api/settings/privacy. A field the environment set is `env_owned`
|
||||
* and cannot be saved from the dashboard. */
|
||||
export interface PrivacySettings {
|
||||
|
||||
Reference in New Issue
Block a user