Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0335e0e6bc | |||
| 18614f378d | |||
| 63ed90ba05 |
@@ -9537,7 +9537,7 @@ exports[`screen snapshots > Settings 1`] = `
|
|||||||
<p
|
<p
|
||||||
class="text-[10px] text-status-warning/90 mt-1"
|
class="text-[10px] text-status-warning/90 mt-1"
|
||||||
>
|
>
|
||||||
UI build v1.5.5 (rebuild client to match)
|
UI build v1.5.6 (rebuild client to match)
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
|||||||
+3
-3
@@ -1,6 +1,6 @@
|
|||||||
# AgentHub — Plugin Marketplace
|
# AgentHub — Plugin Marketplace
|
||||||
|
|
||||||
Official Claude Code plugins for the Agent Monitor dashboard. The **`agenthub`** plugin _is_ the dashboard — hooks, server, `agenthub` CLI and MCP tools, no checkout required. On top of it, **10 focused plugins** extend Claude Code with skills, agents, slash commands, hooks, and CLI tools for deep analytics, cost guardrails, productivity automation, developer tools, AI-powered insights, session forensics, workflow/fleet intelligence, reliability & SLOs, config & memory governance, and dashboard connectivity.
|
Official Claude Code plugins for the Agent Monitor dashboard. The **`agenthub`** plugin _is_ the dashboard — hooks, server and the `agenthub` CLI, no checkout required. (It shipped an MCP server until `c7dbaf2`, which dropped it; the dashboard reads Claude Code's MCP configuration in the config explorer but no longer serves one.) On top of it, **10 focused plugins** extend Claude Code with skills, agents, slash commands, hooks, and CLI tools for deep analytics, cost guardrails, productivity automation, developer tools, AI-powered insights, session forensics, workflow/fleet intelligence, reliability & SLOs, config & memory governance, and dashboard connectivity.
|
||||||
|
|
||||||
Every plugin is powered by the local Agent Monitor REST API at `http://localhost:4820`. They are read-only advisors unless a skill explicitly documents a mutating endpoint (and those preview + confirm before acting).
|
Every plugin is powered by the local Agent Monitor REST API at `http://localhost:4820`. They are read-only advisors unless a skill explicitly documents a mutating endpoint (and those preview + confirm before acting).
|
||||||
|
|
||||||
@@ -134,7 +134,7 @@ waits on an install:
|
|||||||
4. **Install** — `npm install --omit=dev --ignore-scripts` into the runtime dir (never into the plugin cache, which is garbage-collected and replaced on every update). `--ignore-scripts` keeps the root `postinstall` from pulling the whole Vite client toolchain.
|
4. **Install** — `npm install --omit=dev --ignore-scripts` into the runtime dir (never into the plugin cache, which is garbage-collected and replaced on every update). `--ignore-scripts` keeps the root `postinstall` from pulling the whole Vite client toolchain.
|
||||||
5. **Legacy hook cleanup** — see above.
|
5. **Legacy hook cleanup** — see above.
|
||||||
6. **CLI** — write the `~/.local/bin/agenthub` launcher, never clobbering a `agenthub` the bootstrap did not write.
|
6. **CLI** — write the `~/.local/bin/agenthub` launcher, never clobbering a `agenthub` the bootstrap did not write.
|
||||||
7. **UI build** — `client/` is copied into the runtime dir and built there (`npm ci --include=dev`, falling back to `npm install --include=dev`, then `npm run build`), landing in `runtime/client-dist` — the same directory the server serves from. `--include=dev` is required, not tidy: the entire build toolchain (`vite`, `typescript`, `@vitejs/plugin-react`, `tailwindcss`, `@types/*`) is a devDependency, and npm reads an inherited `NODE_ENV=production` as `--omit=dev`. Every bootstrap descended from the running server carries that env — the self-update chain, and any `SessionStart` fired by a `claude` inside a tmux pane the server started — so without the flag the install drops `vite` and the build dies on missing types. Skipped when a bundle for the current version already exists; a failure here does not fail the bootstrap (API and MCP still work, and `/agenthub-open` can retry) but does mean `/run` 404s until it's fixed — and when a bundle from the PREVIOUS version is still on disk the failure is quieter still: the dashboard keeps serving the old UI against the new API, visible only as the Settings page's `UI build vX (rebuild client to match)` line.
|
7. **UI build** — `client/` is copied into the runtime dir and built there (`npm ci --include=dev`, falling back to `npm install --include=dev`, then `npm run build`), landing in `runtime/client-dist` — the same directory the server serves from. `--include=dev` is required, not tidy: the entire build toolchain (`vite`, `typescript`, `@vitejs/plugin-react`, `tailwindcss`, `@types/*`) is a devDependency, and npm reads an inherited `NODE_ENV=production` as `--omit=dev`. Every bootstrap descended from the running server carries that env — the self-update chain, and any `SessionStart` fired by a `claude` inside a tmux pane the server started — so without the flag the install drops `vite` and the build dies on missing types. Skipped when a bundle for the current version already exists; a failure here does not fail the bootstrap (the API still works, and `/agenthub-open` can retry) but does mean `/run` 404s until it's fixed — and when a bundle from the PREVIOUS version is still on disk the failure is quieter still: the dashboard keeps serving the old UI against the new API, visible only as the Settings page's `UI build vX (rebuild client to match)` line.
|
||||||
8. **Server** — on Linux with `systemd --user` available, install/refresh a
|
8. **Server** — on Linux with `systemd --user` available, install/refresh a
|
||||||
`agenthub.service` unit (see [Auto-start on boot](#auto-start-on-boot)) instead
|
`agenthub.service` unit (see [Auto-start on boot](#auto-start-on-boot)) instead
|
||||||
of a bare spawn, so the server is supervised and comes back after a reboot
|
of a bare spawn, so the server is supervised and comes back after a reboot
|
||||||
@@ -176,7 +176,7 @@ reboot, same as always.
|
|||||||
|
|
||||||
| Command | Does |
|
| Command | Does |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `/agenthub-doctor` | Node version, bootstrap state, runtime deps, server liveness, duplicate hooks, CLI launcher + PATH, **tmux** (`WARN` when absent — only the run console, `agenthub lanes shell` and session reloads need it), **skill plugins** (see below), MCP build freshness, UI bundle |
|
| `/agenthub-doctor` | Node version, bootstrap state, runtime deps, server liveness, duplicate hooks, CLI launcher + PATH, **tmux** (`WARN` when absent — only the run console, `agenthub lanes shell` and session reloads need it), **skill plugins** (see below), UI bundle |
|
||||||
| `/agenthub-update` | Pull the latest `agenthub` release via `claude plugin marketplace update` + `claude plugin update agenthub@<marketplace> -y`, then reinstall dependencies and restart the server (`plugin-bootstrap.js --force`). The plugin pull needs a manual `/reload-plugins` afterward to take effect in the current session — not scriptable from a command. |
|
| `/agenthub-update` | Pull the latest `agenthub` release via `claude plugin marketplace update` + `claude plugin update agenthub@<marketplace> -y`, then reinstall dependencies and restart the server (`plugin-bootstrap.js --force`). The plugin pull needs a manual `/reload-plugins` afterward to take effect in the current session — not scriptable from a command. |
|
||||||
| `/agenthub-open` | Rebuild the UI bundle and print the dashboard URL. Re-runs the bootstrap first when the server is down or still executing a plugin root that a mid-session `/plugin` update retired, so a fresh bundle never talks to an older server's routes |
|
| `/agenthub-open` | Rebuild the UI bundle and print the dashboard URL. Re-runs the bootstrap first when the server is down or still executing a plugin root that a mid-session `/plugin` update retired, so a fresh bundle never talks to an older server's routes |
|
||||||
| `/ship-full <requirement>` | Put the lane on the 16-node `ship-feature` template, then run `/agenthub:ship-feature-lane` **in this session**. The in-session twin of `agenthub ship-full` (which spawns its own `claude` from a terminal) |
|
| `/ship-full <requirement>` | Put the lane on the 16-node `ship-feature` template, then run `/agenthub:ship-feature-lane` **in this session**. The in-session twin of `agenthub ship-full` (which spawns its own `claude` from a terminal) |
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
openapi: 3.0.3
|
openapi: 3.0.3
|
||||||
info:
|
info:
|
||||||
title: Agent Dashboard for Claude Code API
|
title: Agent Dashboard for Claude Code API
|
||||||
version: 1.5.5
|
version: 1.5.6
|
||||||
description: HTTP API for real-time Claude Code session monitoring, agent lifecycle tracking, analytics, pricing, hooks ingestion, and workflow intelligence.
|
description: HTTP API for real-time Claude Code session monitoring, agent lifecycle tracking, analytics, pricing, hooks ingestion, and workflow intelligence.
|
||||||
contact:
|
contact:
|
||||||
name: Nguyễn Ngọc Trí Vĩ
|
name: Nguyễn Ngọc Trí Vĩ
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "agenthub",
|
"name": "agenthub",
|
||||||
"version": "1.5.5",
|
"version": "1.5.6",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "agenthub",
|
"name": "agenthub",
|
||||||
"version": "1.5.5",
|
"version": "1.5.6",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"license": "UNLICENSED",
|
"license": "UNLICENSED",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "agenthub",
|
"name": "agenthub",
|
||||||
"version": "1.5.5",
|
"version": "1.5.6",
|
||||||
"bin": {
|
"bin": {
|
||||||
"agenthub": "bin/agenthub.js"
|
"agenthub": "bin/agenthub.js"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -176,8 +176,15 @@ describe("getUpdatesStatus — plugin cache with no .git", () => {
|
|||||||
|
|
||||||
const s = await getUpdatesStatus(root, { latestRelease: release("v1.5.1") });
|
const s = await getUpdatesStatus(root, { latestRelease: release("v1.5.1") });
|
||||||
|
|
||||||
// The old behaviour: message set, everything else absent.
|
// The old behaviour: the not-a-git-clone message, everything else absent.
|
||||||
assert.equal(s.message, null, "must not fall through to the not-a-git-clone payload");
|
// Asserted on the message's CONTENT, not on it being null — a plugin
|
||||||
|
// install now carries its own sentence, and null was only ever a proxy for
|
||||||
|
// "did not fall through here".
|
||||||
|
assert.doesNotMatch(
|
||||||
|
s.message,
|
||||||
|
/not a git clone/i,
|
||||||
|
"must not fall through to the not-a-git-clone payload"
|
||||||
|
);
|
||||||
assert.equal(s.release_check, "ok", "the release layer must actually run");
|
assert.equal(s.release_check, "ok", "the release layer must actually run");
|
||||||
assert.equal(s.install_kind, "plugin");
|
assert.equal(s.install_kind, "plugin");
|
||||||
assert.equal(s.plugin_marketplace, "sg");
|
assert.equal(s.plugin_marketplace, "sg");
|
||||||
@@ -208,6 +215,31 @@ describe("getUpdatesStatus — plugin cache with no .git", () => {
|
|||||||
assert.ok(s.plugin_marketplace && s.plugin_name && s.repo_root);
|
assert.ok(s.plugin_marketplace && s.plugin_name && s.repo_root);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("carries a human-readable message in every outcome, never a null", async () => {
|
||||||
|
// `agenthub update-check` prints `message` as its headline. Null here made
|
||||||
|
// it print the literal "null" on every plugin-cache install — the one kind
|
||||||
|
// that has no commit count to fall back on.
|
||||||
|
const cases = [
|
||||||
|
[makePluginInstall("msg-newer").root, { latestRelease: release("v1.6.0") }, /v1\.6\.0/],
|
||||||
|
[makePluginInstall("msg-current").root, { latestRelease: release("v1.5.0") }, /newest/i],
|
||||||
|
[
|
||||||
|
makePluginInstall("msg-failed").root,
|
||||||
|
{ latestRelease: { ok: false, reason: "unreachable" } },
|
||||||
|
/unreachable/,
|
||||||
|
],
|
||||||
|
[
|
||||||
|
makePluginInstall("msg-noversion", { version: null }).root,
|
||||||
|
{ latestRelease: release("v1.6.0") },
|
||||||
|
/no version|cannot be compared/i,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
for (const [root, opts, expected] of cases) {
|
||||||
|
const s = await getUpdatesStatus(root, opts);
|
||||||
|
assert.equal(typeof s.message, "string", `message must be a string, got ${s.message}`);
|
||||||
|
assert.match(s.message, expected);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it("does not treat an older published release as an update", async () => {
|
it("does not treat an older published release as an update", async () => {
|
||||||
const { root } = makePluginInstall("older");
|
const { root } = makePluginInstall("older");
|
||||||
const s = await getUpdatesStatus(root, { latestRelease: release("v1.4.0") });
|
const s = await getUpdatesStatus(root, { latestRelease: release("v1.4.0") });
|
||||||
|
|||||||
@@ -402,7 +402,17 @@ async function pluginStatus(root, pluginInstall, options = {}) {
|
|||||||
`commands — "Update now" runs them for you and restarts the dashboard. An already-open ` +
|
`commands — "Update now" runs them for you and restarts the dashboard. An already-open ` +
|
||||||
`Claude Code session still needs '/reload-plugins' to pick up new skills and commands.`,
|
`Claude Code session still needs '/reload-plugins' to pick up new skills and commands.`,
|
||||||
manual_command: manualParts.join(" && "),
|
manual_command: manualParts.join(" && "),
|
||||||
message: null,
|
// A plugin install compares versions exactly like a checkout does, so it
|
||||||
|
// gets the same sentence. Left null, `agenthub update-check` printed the
|
||||||
|
// literal "null" as its headline on every plugin-cache install — the one
|
||||||
|
// install kind that cannot fall back to a commit count.
|
||||||
|
message: releaseIsNewer
|
||||||
|
? `Release ${release.tag} is available (this install reports ${localVersion || "no version"}).`
|
||||||
|
: comparable
|
||||||
|
? `Running the newest release (${release.tag}).`
|
||||||
|
: release.ok
|
||||||
|
? `This install reports no version, so it cannot be compared with release ${release.tag}.`
|
||||||
|
: `Could not read the latest release (${release.reason}); version comparison unavailable.`,
|
||||||
|
|
||||||
install_kind: "plugin",
|
install_kind: "plugin",
|
||||||
plugin_marketplace: pluginInstall.marketplace,
|
plugin_marketplace: pluginInstall.marketplace,
|
||||||
|
|||||||
Reference in New Issue
Block a user