agentmomo 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.js CHANGED
@@ -47464,6 +47464,7 @@ var CLAUDE_CONFIG_PATH = process.env.APPDATA ? path3.join(process.env.APPDATA, "
47464
47464
  var AGENTSMOMO_DIST_DIR = process.env.AGENTSMOMO_DIST_DIR;
47465
47465
  var WRAPPER_JS = AGENTSMOMO_DIST_DIR ? path3.join(AGENTSMOMO_DIST_DIR, "stdio-wrapper.js") : path3.join(process.cwd(), "proxy", "dist", "stdio-wrapper.js");
47466
47466
  var HOOK_JS = AGENTSMOMO_DIST_DIR ? path3.join(AGENTSMOMO_DIST_DIR, "claude-code-hook.cjs") : path3.join(process.cwd(), "proxy", "dist", "claude-code-hook.cjs");
47467
+ var GEMINI_HOOK_JS = AGENTSMOMO_DIST_DIR ? path3.join(AGENTSMOMO_DIST_DIR, "gemini-cli-hook.cjs") : path3.join(process.cwd(), "proxy", "dist", "gemini-cli-hook.cjs");
47467
47468
  function projectSettingsPath(projectPath) {
47468
47469
  return path3.join(projectPath, ".claude", "settings.json");
47469
47470
  }
@@ -47622,11 +47623,112 @@ app.post("/api/event", requireAuth, async (req, res) => {
47622
47623
  };
47623
47624
  broadcast(subEvent);
47624
47625
  }
47626
+ if (event.event === "call_start" && event.source === "gemini-cli" && event.toolName === "complete_task" && event.metadata?.subAgentId && typeof event.metadata.subAgentId === "string") {
47627
+ const subAgentId = event.metadata.subAgentId;
47628
+ const subAgentName = event.metadata.subAgentName ?? subAgentId;
47629
+ const folderPart = typeof event.metadata.cwd === "string" ? path3.basename(event.metadata.cwd) : "Gemini CLI";
47630
+ const subEvent = {
47631
+ agentId: subAgentId,
47632
+ agentName: `${folderPart} \xB7 ${subAgentName}`,
47633
+ source: "gemini-cli-subagent",
47634
+ event: "agent_register",
47635
+ toolName: "",
47636
+ timestamp: event.timestamp,
47637
+ requestId: `${event.requestId}-sub-register`,
47638
+ parentId: event.agentId,
47639
+ isSubAgent: true,
47640
+ metadata: event.metadata
47641
+ };
47642
+ broadcast(subEvent);
47643
+ }
47625
47644
  res.json({ ok: true });
47626
47645
  });
47627
47646
  app.get("/api/health", (_req, res) => {
47628
47647
  res.json({ status: "ok", agents: getAllAgents().length });
47629
47648
  });
47649
+ app.get("/.well-known/agent.json", (_req, res) => {
47650
+ res.json({
47651
+ name: "agentmomo",
47652
+ description: "3D visualization dashboard for AI coding agents. Monitor active agents, view real-time activity, and manage the dashboard.",
47653
+ url: `http://localhost:${PORT}`,
47654
+ version: "1.0.0",
47655
+ capabilities: {
47656
+ streaming: false,
47657
+ pushNotifications: false
47658
+ },
47659
+ skills: [
47660
+ {
47661
+ id: "list-agents",
47662
+ name: "List Agents",
47663
+ description: "Get all active agents and their current states (idle, working, break, error, offline)"
47664
+ },
47665
+ {
47666
+ id: "get-activity",
47667
+ name: "Get Activity",
47668
+ description: "Get server health status and agent count"
47669
+ },
47670
+ {
47671
+ id: "reset-dashboard",
47672
+ name: "Reset Dashboard",
47673
+ description: "Clear all agents from the visualization dashboard"
47674
+ }
47675
+ ],
47676
+ defaultInputModes: ["text/plain"],
47677
+ defaultOutputModes: ["application/json"]
47678
+ });
47679
+ });
47680
+ app.post("/a2a/tasks/send", import_express2.default.json(), (req, res) => {
47681
+ const { message } = req.body ?? {};
47682
+ if (!message || !message.parts || !Array.isArray(message.parts)) {
47683
+ res.status(400).json({ error: "Invalid A2A task message" });
47684
+ return;
47685
+ }
47686
+ const textParts = message.parts.filter((p) => !p.type || p.type === "text").map((p) => p.text ?? "").join(" ").toLowerCase();
47687
+ let result;
47688
+ if (textParts.includes("reset") || textParts.includes("clear")) {
47689
+ clearAllAgents();
47690
+ broadcast({
47691
+ agentId: "__system__",
47692
+ agentName: "system",
47693
+ source: "manual",
47694
+ event: "agent_register",
47695
+ toolName: "",
47696
+ timestamp: Date.now(),
47697
+ requestId: "a2a-clear"
47698
+ });
47699
+ result = { action: "reset", success: true, message: "Dashboard cleared" };
47700
+ } else if (textParts.includes("list") || textParts.includes("agents") || textParts.includes("status")) {
47701
+ const agents2 = getAllAgents();
47702
+ result = {
47703
+ action: "list-agents",
47704
+ count: agents2.length,
47705
+ agents: agents2.map((a) => ({
47706
+ id: a.id,
47707
+ name: a.name,
47708
+ source: a.source,
47709
+ state: a.state,
47710
+ currentTool: a.currentTool,
47711
+ totalCalls: a.totalCalls,
47712
+ totalErrors: a.totalErrors
47713
+ }))
47714
+ };
47715
+ } else {
47716
+ result = {
47717
+ action: "health",
47718
+ status: "ok",
47719
+ agents: getAllAgents().length
47720
+ };
47721
+ }
47722
+ res.json({
47723
+ id: req.body.id ?? `a2a-${Date.now()}`,
47724
+ status: { state: "completed" },
47725
+ artifacts: [
47726
+ {
47727
+ parts: [{ type: "text", text: JSON.stringify(result, null, 2) }]
47728
+ }
47729
+ ]
47730
+ });
47731
+ });
47630
47732
  app.post(
47631
47733
  "/api/payments/create-checkout-session",
47632
47734
  requireAuth,
@@ -48113,7 +48215,7 @@ app.post("/api/claude-code-config", (req, res) => {
48113
48215
  if (!cfg.hooks) cfg.hooks = {};
48114
48216
  const hookCommandParts = [`node "${HOOK_JS.replace(/\\/g, "/")}"`];
48115
48217
  if (apiKey && typeof apiKey === "string" && apiKey.startsWith("amk_")) {
48116
- hookCommandParts.push(`--api-key "${apiKey}"`);
48218
+ hookCommandParts.push(`--api-key ${apiKey}`);
48117
48219
  }
48118
48220
  const hookEntry = {
48119
48221
  type: "command",
@@ -48161,6 +48263,107 @@ app.post("/api/build-hook", (_req, res) => {
48161
48263
  }
48162
48264
  );
48163
48265
  });
48266
+ function geminiSettingsPath(projectPath) {
48267
+ return path3.join(projectPath, ".gemini", "settings.json");
48268
+ }
48269
+ app.get("/api/gemini-cli-config", (req, res) => {
48270
+ const projectPath = req.query.project || process.cwd();
48271
+ const configPath = geminiSettingsPath(projectPath);
48272
+ const hookBuilt = fs2.existsSync(GEMINI_HOOK_JS);
48273
+ const configExists = fs2.existsSync(configPath);
48274
+ let config2 = null;
48275
+ let hooksInstalled = false;
48276
+ if (configExists) {
48277
+ try {
48278
+ config2 = JSON.parse(fs2.readFileSync(configPath, "utf-8"));
48279
+ const before = config2?.hooks?.BeforeTool ?? [];
48280
+ hooksInstalled = before.some(
48281
+ (entry) => entry.hooks?.some(
48282
+ (h) => String(h.command ?? "").includes("gemini-cli-hook")
48283
+ )
48284
+ );
48285
+ } catch {
48286
+ config2 = null;
48287
+ }
48288
+ }
48289
+ res.json({
48290
+ configPath,
48291
+ projectPath,
48292
+ exists: configExists,
48293
+ config: config2,
48294
+ hooksInstalled,
48295
+ hookPath: GEMINI_HOOK_JS,
48296
+ hookBuilt
48297
+ });
48298
+ });
48299
+ app.post("/api/gemini-cli-config", (req, res) => {
48300
+ const {
48301
+ action,
48302
+ projectPath: pp,
48303
+ apiKey
48304
+ } = req.body;
48305
+ const projectPath = pp || process.cwd();
48306
+ const configPath = geminiSettingsPath(projectPath);
48307
+ try {
48308
+ const configDir = path3.dirname(configPath);
48309
+ if (!fs2.existsSync(configDir)) fs2.mkdirSync(configDir, { recursive: true });
48310
+ let cfg = {};
48311
+ if (fs2.existsSync(configPath)) {
48312
+ cfg = JSON.parse(fs2.readFileSync(configPath, "utf-8"));
48313
+ }
48314
+ if (!cfg.hooks) cfg.hooks = {};
48315
+ const hookCommandParts = [`node "${GEMINI_HOOK_JS.replace(/\\/g, "/")}"`];
48316
+ if (apiKey && typeof apiKey === "string" && apiKey.startsWith("amk_")) {
48317
+ hookCommandParts.push(`--api-key ${apiKey}`);
48318
+ }
48319
+ const hookEntry = {
48320
+ name: "agentmomo",
48321
+ type: "command",
48322
+ command: hookCommandParts.join(" "),
48323
+ timeout: 2e3
48324
+ };
48325
+ const matcher = { matcher: ".*", hooks: [hookEntry] };
48326
+ const sessionMatcher = { matcher: ".*", hooks: [hookEntry] };
48327
+ if (action === "install") {
48328
+ cfg.hooks.BeforeTool = [matcher];
48329
+ cfg.hooks.AfterTool = [matcher];
48330
+ cfg.hooks.SessionStart = [sessionMatcher];
48331
+ if (!cfg.experimental) cfg.experimental = {};
48332
+ cfg.experimental.enableAgents = true;
48333
+ } else {
48334
+ const strip = (arr) => (arr ?? []).filter(
48335
+ (e) => !e.hooks?.some(
48336
+ (h) => String(h.command ?? "").includes("gemini-cli-hook")
48337
+ )
48338
+ );
48339
+ cfg.hooks.BeforeTool = strip(cfg.hooks.BeforeTool ?? []);
48340
+ cfg.hooks.AfterTool = strip(cfg.hooks.AfterTool ?? []);
48341
+ cfg.hooks.SessionStart = strip(cfg.hooks.SessionStart ?? []);
48342
+ if (!cfg.hooks.BeforeTool.length) delete cfg.hooks.BeforeTool;
48343
+ if (!cfg.hooks.AfterTool.length) delete cfg.hooks.AfterTool;
48344
+ if (!cfg.hooks.SessionStart.length) delete cfg.hooks.SessionStart;
48345
+ if (!Object.keys(cfg.hooks).length) delete cfg.hooks;
48346
+ }
48347
+ fs2.writeFileSync(configPath, JSON.stringify(cfg, null, 2), "utf-8");
48348
+ res.json({ ok: true, configPath });
48349
+ } catch (err) {
48350
+ res.status(500).json({ error: err.message });
48351
+ }
48352
+ });
48353
+ app.post("/api/build-gemini-hook", (_req, res) => {
48354
+ if (AGENTSMOMO_DIST_DIR) {
48355
+ res.json({ ok: true });
48356
+ return;
48357
+ }
48358
+ exec(
48359
+ `npx esbuild proxy/gemini-cli-hook.ts --bundle --platform=node --format=cjs --outfile=proxy/dist/gemini-cli-hook.cjs`,
48360
+ { cwd: process.cwd() },
48361
+ (err, _stdout, stderr) => {
48362
+ if (err) res.status(500).json({ error: stderr || err.message });
48363
+ else res.json({ ok: true });
48364
+ }
48365
+ );
48366
+ });
48164
48367
  app.get("/api/subagents", (req, res) => {
48165
48368
  const projectPath = req.query.project || process.cwd();
48166
48369
  const agentsDir = path3.join(projectPath, ".claude", "agents");
@@ -48216,7 +48419,7 @@ if (config.httpProxy.targets.length > 0) {
48216
48419
  if (fs2.existsSync(INDEX_HTML)) {
48217
48420
  app.use(import_express2.default.static(DIST_DIR));
48218
48421
  app.get("*", (req, res, next) => {
48219
- if (req.path.startsWith("/api") || req.path.startsWith("/proxy") || req.path.startsWith("/ws")) {
48422
+ if (req.path.startsWith("/api") || req.path.startsWith("/proxy") || req.path.startsWith("/ws") || req.path.startsWith("/.well-known") || req.path.startsWith("/a2a")) {
48220
48423
  next();
48221
48424
  return;
48222
48425
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentmomo",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "3D visualization of MCP agent activity — watch your AI tools work in a virtual office",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,9 +18,10 @@
18
18
  "start": "tsx proxy/server.ts",
19
19
  "build:wrapper": "npx esbuild proxy/stdio-wrapper.ts --bundle --platform=node --format=esm --outfile=proxy/dist/stdio-wrapper.js",
20
20
  "build:hook": "npx esbuild proxy/claude-code-hook.ts --bundle --platform=node --format=cjs --outfile=proxy/dist/claude-code-hook.cjs",
21
+ "build:gemini-hook": "npx esbuild proxy/gemini-cli-hook.ts --bundle --platform=node --format=cjs --outfile=proxy/dist/gemini-cli-hook.cjs",
21
22
  "build:server": "npx esbuild proxy/server.ts --bundle --platform=node --format=esm --outfile=dist/server.js",
22
23
  "build:cli": "npx esbuild bin/cli.ts --bundle --platform=node --format=esm --banner:js=\"#!/usr/bin/env node\" --outfile=dist/cli.js",
23
- "build:npm": "npm run build && npm run build:server && npm run build:cli && npx esbuild proxy/stdio-wrapper.ts --bundle --platform=node --format=esm --outfile=dist/stdio-wrapper.js && npx esbuild proxy/claude-code-hook.ts --bundle --platform=node --format=cjs --outfile=dist/claude-code-hook.cjs",
24
+ "build:npm": "npm run build && npm run build:server && npm run build:cli && npx esbuild proxy/stdio-wrapper.ts --bundle --platform=node --format=esm --outfile=dist/stdio-wrapper.js && npx esbuild proxy/claude-code-hook.ts --bundle --platform=node --format=cjs --outfile=dist/claude-code-hook.cjs && npx esbuild proxy/gemini-cli-hook.ts --bundle --platform=node --format=cjs --outfile=dist/gemini-cli-hook.cjs",
24
25
  "preview": "vite preview"
25
26
  },
26
27
  "dependencies": {
@@ -32,6 +33,7 @@
32
33
  "@radix-ui/react-dialog": "^1.1.15",
33
34
  "@radix-ui/react-dropdown-menu": "^2.1.16",
34
35
  "@radix-ui/react-scroll-area": "^1.2.10",
36
+ "@radix-ui/react-select": "^2.2.6",
35
37
  "@radix-ui/react-separator": "^1.1.8",
36
38
  "@radix-ui/react-slider": "^1.3.6",
37
39
  "@radix-ui/react-slot": "^1.2.4",