d8ab85029504ecc43e3908c3de14ffe27064a6fa
13 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a9c71cd905 |
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. |
||
|
|
ca821008e2 |
perf: v2.5.10 — ready for 10+ concurrent users, leaner locally
Measured on a copy of a real 1.2 GB / 253K-event database, 10 simulated browsers + 10 hooks/s for 90 s: event-loop delay p99 1239 ms → 32 ms (max 2.0 s → 94 ms), 266 failed requests → 0, 74 → 111 requests/s served, server RSS 633 → 346 MB. Entry bundle 975 KB raw → 394 KB (106 KB brotli). Server - /api/analytics: the events-table scans run in the read worker (scoped-stats eventAggregates, read-pool job analyticsEvents); runRead takes maxAgeMs — analytics 10 s, /api/workflows 30 s — keyed by the args - /api/workflows/skill-usage: +event_type and a tool_name range instead of LIKE, so it uses idx_events_tool (784 ms → a few ms) - idx_events_session_type_tool (session_id, event_type, tool_name, created_at) replaces idx_events_session_type: covering reads for session stats, the hook dedupes and the import resume point (1.2 s → 20 ms); 64 MB cache_size and 256 MB mmap_size on both connections - WAL: the server sets wal_autocheckpoint = 0 and checkpoints PASSIVE every DASHBOARD_WAL_CHECKPOINT_MS (5 s) from the read worker's own writable connection; a failed checkpoint restores the automatic one (hook COMMIT p95 109 ms → 15 ms at 100 hooks/s) - tmux: one list-sessions answers a whole GET /api/lanes and the heal beat (liveSessions), shared for 1 s and cleared by this process's new/kill — GET /api/run's sync spawns had blocked 60 s of a 90 s run; the heal beat skips tmux when nothing runs; attach options chained into 2 spawns - hooks: TurnDuration/APIError deduped against one read per hook instead of a query per transcript entry (23 ms/hook on a 763-turn session); one lane scan per hook; hourly upserts skip rows that did not grow; frames are sent after the transaction commits (and after the pane binding); new_event carries its row id; a split pane's (slot 1–9) hooks no longer rebind the lane's session_id - watchdog liveness probe runs ps asynchronously; transcript newline scan via indexOf; startup subagent backfill fingerprints the files it already checked - pty attach: backpressure (pause past 1 MB unsent, resume under 256 KB) - static: hashed assets served from their pre-compressed .br/.gz sibling Client - hidden tabs neither refetch on WS events nor poll (useLiveRefresh, panes, lane cards, git header, changes panel, settings); no per-tab hourly /updates/check (the server already checks) - refetch storms throttled (workspace tree/session list 3 s, /api/run only on a run-key change, notification pane lookup only when shown); WS reconnect jitter; terminal retry backoff 1.5 → 30 s, stops on 1008 - heavier throttles for aggregates (15 s) and detail views; Monitor keepIfSame; GET in-flight dedupe in request() - lazy Dashboard/History, xterm (with the first terminal), lane modals, Sagi (only while enabled); only the active locale loads; Workspace chunk prefetched on a /workspace deep link - Sagi: no work while disabled, pupil via CSS variables, memo avatar - build: .br/.gz siblings, sourcemap hidden; service worker no longer caches /assets/ (cache v3 drops the old one) Tests: scripts/test-server.js drops the GIT_DIR-family variables a hook exports, so a suite run from a linked worktree's pre-commit can no longer commit into the real repository or set core.bare. Docs: ARCHITECTURE, DATABASE, API, DEPLOYMENT, client README, docs/plans/perf/README.md (audit, checklist, results). |
||
|
|
4aae61297f |
feat: analytics parity — tool cost, date ranges, budgets, query explorer, replay, snapshots (v2.4.0)
Analytics parity phases 2–7 (docs/plans/analytics-parity/), built on
|
||
|
|
6c605849d8 |
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. |
||
|
|
198fbb7980 |
fix: event-loop freezes, plugin-install boot crash, tmux attach/scrollbar, Codex transcripts
- GET /api/workflows: one LEAD() window pass in a read worker (read-pool.js, workflow-stats.js); idx_events_session restored, idx_events_tool added - compat-sqlite gains function/pluck/readonly so a plugin install without a better-sqlite3 build boots again; antigravity-usage uses db.js's Database - install-hooks adds no checkout hooks while the agenthub plugin is enabled (events were doubled) - terminal attach runs the live tmux server's own binary; the pane scrollbar gets a visible 2-column style, and claude panes start with CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN=1 so tmux keeps history to scroll - Codex sessions' conversation in GET /api/sessions/:id/transcript - Codex/Antigravity sessions claimed by their workspace without hooks - UI-audit follow-ups, docs and OpenAPI |
||
|
|
969b06253c |
feat: per-tool settings, persistent settings file, Codex and Antigravity sessions, tokens and hooks (#40 B, C1, C2, D)
Part B: Model Pricing, Hook Configuration and CLAUDE_HOME move from Settings → Dashboard to the Claude Code tab's AgentHub sub-tab (ClaudeAgentHubSettings.tsx); CODEX_HOME is editable in Codex → AgentHub. A home that is or contains the OS home is refused (EBADHOME). Settings persistence: dashboard-saved settings go to ~/.config/agenthub/settings.env (AGENTHUB_SETTINGS_FILE), outside the plugin cache an update wipes. Load order: real env > the checkout's .env > that file. The first CLAUDE_HOME change pins DASHBOARD_DATA_DIR so the DB stays put. C1: codex-usage.js reads Codex rollout journals into sessions (new column tool) and token_usage, tracked per file in codex_rollouts; forks deduped by total vector, sub-agent threads folded into the root; pricing-sync also prices OpenAI models; PricingSettings with a vendor filter. C2: codex-hooks.js installs AgentHub's hooks into $CODEX_HOME/hooks.json on a click, through a stable forwarder; Codex trust is never written. The hook route creates tool='codex' sessions and folds sub-agent hooks into the root. D: antigravity-usage.js reads agy's per-conversation SQLite files (tokens from ModelUsageStats) into tool='antigravity' sessions; antigravity-hooks.js installs the named hook `agenthub` (PreInvocation, PostToolUse, Stop — never PreToolUse) into ~/.gemini/config/hooks.json; Settings → Antigravity tab; Gemini pricing. Whole-change review fixes: sameOriginGuard on both home PUTs, routers.missing on a CLAUDE_HOME change, reset-pricing scope, GET /api/sessions?tool=, clear-data covering the new tables, Codex child-thread events moving no status, hooks owning status only while current, EFOREIGN for a forwarder that is not ours, agy quiet window and turn rules, AGENTHUB_SETTINGS_FILE honoured from .env. Docs, OpenAPI and the CLAUDE.md marker updated. Server 2141, client 779. |
||
|
|
952e8584f0 |
feat: per-change-block hunk actions (#50), codex lanes without a pipeline, macOS LaunchAgent
- git (#50): stage-hunk/discard-hunk take an optional `block` — one run of consecutive +/- lines inside an @@ hunk. `onlyBlock` (server/lib/git-diff.js) cuts git's fresh hunk down to it, folding the other blocks into the side being checked; LaneDiffView hangs one review bar per block (unified + split) and its arrows walk blocks. - git exclude: entries AgentHub writes for a lane go to the COMMON git dir with the lane's path prefix (server/lib/git-exclude.js, used by router-apply and lane-mcp) — a linked worktree's own info/exclude is never read by git, and a subdir lane has no .git. MCP sync no longer fails with ENOTDIR on a worktree lane or creates a stray .git in a non-repo lane. - codex lanes carry no pipeline: codex-ingest mirrors only idle/running, codex-nudge is removed, agents install writes nothing for codex, the Workspace hides stage/pipeline/feature pickers/PipelineMap for them, and every server start clears leftover codex stage data and the old AGENTS.md stage block. - Changes panel: a whole file opens for reading and enters the editor on a click on its text (caret at the clicked line), not automatically. - macOS: LaunchAgent start-at-login (scripts/launchd-service.js, picked by scripts/service-manager.js). - Adds the AgentHub introduction slides and their image-embedding script. |
||
|
|
de8d1079e0 |
fix(bootstrap): never stop the dashboard from inside its own systemd cgroup
A plugin self-update took the dashboard down and left it down. The chain
ran correctly up to the point where the bootstrap SIGTERMs the server it is
replacing — and that server was systemd-managed, with the bootstrap running
as its descendant, i.e. inside its cgroup. Two failures fired at once:
* the server exits 0, and `Restart=on-failure` reads a clean exit as
"meant to stop", so systemd did not bring it back;
* `KillMode=control-group` reaped the bootstrap itself, mid-run, before it
could repoint the unit at the new plugin root or write state.json.
Evidence from the incident: bootstrap.log ends at "stopped the server
started from the previous plugin version" with no systemd line after it,
.bootstrap.lock survived with a dead pid, state.json still named the
previous version, and the unit's ExecStart still pointed at the old cache
dir. The same truncation is visible on three earlier updates — those only
recovered because a later SessionStart bootstrapped again.
systemd-service.js now splits install into writeUserService (repoints the
unit, starts nothing) and restartUserService (--no-block). The bootstrap
skips the manual stop whenever a unit of ours owns the server, and defers
the restart past writeState and releaseLock, so being killed by its own
request costs nothing. The unit is Restart=always: a graceful SIGTERM from
anything must no longer read as "leave it stopped".
installUserService keeps its old semantics for `agenthub service install`,
which runs from a user's shell and is not in the cgroup.
|
||
|
|
d4b949a6f4 |
docs(deployment): list git and tmux beside node in the prerequisites
The only prerequisites block that still said node+npm alone. |
||
|
|
61cc37ba32 |
chore: remove unused surfaces (VS Code extension, statusline, landing assets, Docker)
The repo shipped five install/publish surfaces that nothing in the project builds, tests or documents as supported any more. Each one carried its own stale docs, and the Docker/Podman path additionally described a Dockerfile whose COPY of statusline/ would have broken the build the moment that directory went away. Removed: vscode-extension/ (16 files, marketplace extension for an ID we do not own); statusline/ (3 files, standalone CLI statusline); the repo-root landing/wiki PWA assets (sw.js, manifest.json, robots.txt, sitemap.xml, og-image.svg, favicon.svg, fonts/ - 17 files for pages that no longer exist); .superpowers/ (4 files of scratch brainstorm state, already covered by .gitignore:55); and the container publish path (Dockerfile, docker-compose.yml, .dockerignore, 5 Makefile targets, 2 npm scripts). Kept deliberately - these are about the USER's containers, not ours: scripts/install-hooks.js container detection and AGENTHUB_ALLOW_CONTAINER_HOOKS (issue #193), server/lib/lane-detect.js docker-compose service detection, server/data/profile-templates/postgres-compose/, server/lib/stage-detect.js 'docker push' detection, the host.docker.internal Prometheus notes, the Config Explorer's reads of the user's own ~/.claude/statusline.py, and .devcontainer/ (its docker-in-docker feature is dropped since it existed only to build the removed Dockerfile). Docs follow the code: ARCHITECTURE.md loses the VS Code, statusline and container sections plus two dead TOC anchors, and its PWA section is rewritten from three PWAs to one; INSTALL.md, SETUP.md, docs/DEPLOYMENT.md, server/README.md, client/README.md, docs/README.md, docs/HOOKS.md and docs/DATABASE.md drop the same. The Makefile target count in ARCHITECTURE.md is corrected 25 -> 17 (it was already stale). |
||
|
|
c7dbaf2d9f |
refactor: finish the AgentHub rename and drop the MCP server
Two leftovers from the rebrand, done together because they touch the same docs and manifests. **Data directory.** `agent-dashboard` could not simply be renamed in the source: it names a real directory holding the live SQLite database. Startup now moves it once, via `migrateLegacyDataDir()` in `server/lib/claude-home.js` — a same-filesystem rename, so it is instant even at multiple gigabytes and cannot leave two divergent copies. `getDataDir()` stays PURE and resolves to the legacy path until the move happens; the first version of this put the rename inside the getter, which meant `npm run test:server` relocated the developer's real database as a side effect. The call sits behind `require.main === module` and ahead of the router requires, because those pull in db.js, which opens SQLite at module load. A failed rename is silent and the old directory keeps being used: an unfashionable directory name beats a blank database beside an unreachable one. Same treatment for the port-discovery file (`.agent-dashboard.json` → `.agenthub.json`, old one dropped on write). Not renamed on purpose: the Sagi localStorage keys (renaming silently resets everyone's prefs) and the PWA manifest `id` (changing it orphans an installed app). **MCP server.** 4 tool calls in 46 days across 577,132 events, against 4,556 lines of TypeScript, a 2 MB committed build artifact, and a pre-commit guard that had already blocked commits twice. Deleted: `mcp/`, the maintainer skills and `mcp-reviewer` agent, the build check, `plugins/agenthub/.mcp.json`, `docs/MCP.md`, 12 npm scripts, 5 Makefile targets, and every doc section describing it. Kept, because they are unrelated things sharing the name: the Config Explorer's MCP tab and its API, per-lane Playwright MCP, the agenthub-config plugin's MCP audit, and the historical `mcp__plugin_agenthub_*` events that analytics must keep attributing. Verified: server 1432/1432, client 459/459, tsc clean, prettier clean. Both directions of the migration proven — a sandbox-HOME test run leaves the legacy directory untouched, and a real boot moves it with its contents intact. |
||
|
|
fd7f57929c |
fix(lanes): auto-detect and report stage for codex lanes (issue 11)
A lane on the 16-node `ship-feature` template showed an untouched pipeline
map and never declared a stage. Four independent causes, fixed at their
shared choke points:
1. Codex emits no hooks, so `touchLaneFromHook` — the only caller of
`stage-detect.detect()`, and correctly pinned to `claude` — could never
see a `codex` lane. New `server/lib/codex-ingest.js` tails Codex's own
rollout journals (`$CODEX_HOME/sessions/**/rollout-*.jsonl`), maps its
tool calls onto the hook-shaped `{tool_name, tool_input}` the matcher
already understands, and feeds the existing detect path plus an
idle/running status mirror under the same guard hooks use. Polled every
`DASHBOARD_CODEX_POLL_MS` ms (default 15000, `0` disables).
2. `resolveLaneArg` matched on cwd alone, so with a claude and a codex lane
at one directory (the composite `idx_lanes_cwd_tool`) a `ccam stage`
call could drive the sibling lane's card. It now resolves by
`--lane` → `CCAM_LANE_ID` → `--tool`/harness marker → owning lane, and
errors naming both candidates rather than picking one. Every pane the
dashboard starts carries `CCAM_LANE_ID` (`tmux new-session -e`, or an
assignment prefix when typing into a live shell pane).
3. `recordDetection`'s declared-wins veto had no exit: a lane left at the
pipeline's last node rejected every detection for the rest of its life.
A declaration on the LAST node no longer vetoes — the pipeline is over
there, so a later detection is new work. Nothing else is relaxed, and
detection still never writes `stage` nor renders `done`.
4. The run console pre-filled the pipeline's Claude slash command into
codex panes, which Codex reads as prose — so the skill that would have
called `ccam stage` never ran. Claude lanes only now.
A codex lane's *declared* stage still depends on the session calling
`ccam stage`; `AGENTS.md` is the only lever CCAM has, so it now says so.
Verified: server 1345/1345, client 441/441, and end-to-end against a real
codex lane row (detected_stage/detected_signal set, declared stage
untouched, no node rendered done).
|
||
|
|
57dc91585d |
feat: Claude Code Monitor — lanes, pipelines and a merged workspace
Internal SmartGift build of a Claude Code monitoring dashboard. Lanes: a durable unit of parallel agent work, one per working directory, tracked across session restarts. Managed lanes are git worktrees the dashboard provisions and can reset or remove behind a three-check destroy guard and a counted preflight; adopted lanes are directories you already own and are never destroyable. Pipelines: a lane moves through pipeline stages. A stage the agent declares with evidence renders green; a stage inferred from the tool-event stream renders dashed amber and never counts as done. Detection is forward-only within a 30-minute window, and never writes the declared stage. Workspace: one page at /run with a lane grid, the selected lane's pipeline, and a full Claude console behind a disclosure. |