agentmomo 0.1.1 → 0.2.0

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.
@@ -0,0 +1,312 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (let key of __getOwnPropNames(from))
11
+ if (!__hasOwnProp.call(to, key) && key !== except)
12
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
13
+ }
14
+ return to;
15
+ };
16
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
17
+ // If the importer is in node compatibility mode or this is not an ESM
18
+ // file that has been converted to a CommonJS file using a Babel-
19
+ // compatible transform (i.e. "__esModule" has not been set), then set
20
+ // "default" to the CommonJS "module.exports" for node compatibility.
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+
25
+ // proxy/gemini-cli-hook.ts
26
+ var import_http = __toESM(require("http"), 1);
27
+ var import_fs = __toESM(require("fs"), 1);
28
+ var import_path = __toESM(require("path"), 1);
29
+ var AGENTMOMO_PORT = 9001;
30
+ var TIMEOUT_MS = 1500;
31
+ var LOG_FILE = import_path.default.join(
32
+ process.env.USERPROFILE ?? process.env.HOME ?? ".",
33
+ ".agentmomo-hook.log"
34
+ );
35
+ function readArg(name) {
36
+ const idx = process.argv.indexOf(name);
37
+ if (idx !== -1 && process.argv[idx + 1]) {
38
+ return process.argv[idx + 1].replace(/^["']+|["']+$/g, "");
39
+ }
40
+ return void 0;
41
+ }
42
+ var AGENTMOMO_API_KEY = readArg("--api-key") ?? process.env.AGENTMOMO_API_KEY ?? "";
43
+ function log(msg) {
44
+ try {
45
+ import_fs.default.appendFileSync(
46
+ LOG_FILE,
47
+ `[${(/* @__PURE__ */ new Date()).toISOString()}] [gemini] ${msg}
48
+ `
49
+ );
50
+ } catch {
51
+ }
52
+ }
53
+ function postEvent(body) {
54
+ const headers = {
55
+ "Content-Type": "application/json",
56
+ "Content-Length": Buffer.byteLength(body)
57
+ };
58
+ if (AGENTMOMO_API_KEY) {
59
+ headers.Authorization = `Bearer ${AGENTMOMO_API_KEY}`;
60
+ }
61
+ const req = import_http.default.request(
62
+ {
63
+ hostname: "localhost",
64
+ port: AGENTMOMO_PORT,
65
+ path: "/api/event",
66
+ method: "POST",
67
+ headers,
68
+ timeout: TIMEOUT_MS
69
+ },
70
+ (res) => {
71
+ if (res.statusCode && (res.statusCode < 200 || res.statusCode >= 300)) {
72
+ let responseBody = "";
73
+ res.on("data", (chunk) => {
74
+ responseBody += chunk.toString();
75
+ });
76
+ res.on("end", () => {
77
+ log(`POST /api/event failed ${res.statusCode}: ${responseBody}`);
78
+ });
79
+ } else {
80
+ res.resume();
81
+ }
82
+ }
83
+ );
84
+ req.on("error", (err) => {
85
+ log("POST error: " + err.message);
86
+ });
87
+ req.on("timeout", () => {
88
+ req.destroy();
89
+ });
90
+ req.write(body);
91
+ req.end();
92
+ }
93
+ function respond() {
94
+ process.stdout.write("{}\n");
95
+ }
96
+ var TOOL_ROLES = {
97
+ // Read / inspect
98
+ read_file: "reader",
99
+ read_many_files: "reader",
100
+ list_directory: "reader",
101
+ get_internal_docs: "reader",
102
+ // Write / mutate
103
+ write_file: "writer",
104
+ replace: "writer",
105
+ save_memory: "writer",
106
+ // Execute / shell / planning
107
+ run_shell_command: "runner",
108
+ complete_task: "runner",
109
+ enter_plan_mode: "runner",
110
+ exit_plan_mode: "runner",
111
+ write_todos: "runner",
112
+ ask_user: "runner",
113
+ activate_skill: "runner",
114
+ // Search / navigate
115
+ grep_search: "searcher",
116
+ glob: "searcher",
117
+ google_web_search: "searcher",
118
+ web_fetch: "searcher"
119
+ };
120
+ var ROLE_LABELS = {
121
+ reader: "Reader",
122
+ writer: "Writer",
123
+ runner: "Runner",
124
+ searcher: "Searcher"
125
+ };
126
+ function extractToolMessage(toolName, toolInput) {
127
+ const str = (v, max = 80) => typeof v === "string" && v.trim() ? v.trim().slice(0, max) : void 0;
128
+ switch (toolName) {
129
+ case "read_file":
130
+ case "read_many_files":
131
+ return str(toolInput["path"] ?? toolInput["paths"]) ? `Reading ${str(toolInput["path"] ?? toolInput["paths"])}` : void 0;
132
+ case "list_directory":
133
+ return str(toolInput["path"]) ? `Listing ${str(toolInput["path"])}` : void 0;
134
+ case "write_file":
135
+ return str(toolInput["path"]) ? `Writing ${str(toolInput["path"])}` : void 0;
136
+ case "replace":
137
+ return str(toolInput["path"]) ? `Editing ${str(toolInput["path"])}` : void 0;
138
+ case "run_shell_command": {
139
+ const cmd = str(toolInput["command"], 100);
140
+ return cmd ? `Running: ${cmd}` : void 0;
141
+ }
142
+ case "grep_search": {
143
+ const pat = str(toolInput["pattern"]);
144
+ const dir = str(toolInput["directory"] ?? toolInput["path"], 40);
145
+ return pat ? `Searching "${pat}"${dir ? ` in ${dir}` : ""}` : void 0;
146
+ }
147
+ case "google_web_search":
148
+ return str(toolInput["query"]) ? `Web search: ${str(toolInput["query"])}` : void 0;
149
+ case "web_fetch":
150
+ return str(toolInput["url"]) ? `Fetching ${str(toolInput["url"])}` : void 0;
151
+ case "save_memory":
152
+ return "Saving to memory";
153
+ case "write_todos":
154
+ return "Updating task list";
155
+ case "ask_user": {
156
+ const q = str(toolInput["question"], 80);
157
+ return q ? `Asking: ${q}` : void 0;
158
+ }
159
+ case "complete_task": {
160
+ const result = str(toolInput["result"], 80);
161
+ return result ? `Completing task: ${result}` : void 0;
162
+ }
163
+ default:
164
+ if (toolName.startsWith("mcp_")) {
165
+ return `Using ${toolName.replace(/^mcp_[^_]+_/, "").replace(/_/g, " ")}`;
166
+ }
167
+ return void 0;
168
+ }
169
+ }
170
+ function extractResultText(response) {
171
+ if (!response || typeof response !== "object") return void 0;
172
+ const obj = response;
173
+ for (const key of ["text", "content", "output", "result", "stdout"]) {
174
+ if (typeof obj[key] === "string" && obj[key].trim())
175
+ return obj[key].trim();
176
+ }
177
+ const llm = obj.llmContent;
178
+ if (typeof llm === "string" && llm.trim()) return llm.trim();
179
+ if (llm && typeof llm === "object") {
180
+ const llmObj = llm;
181
+ if (typeof llmObj.text === "string" && llmObj.text.trim())
182
+ return llmObj.text.trim();
183
+ if (Array.isArray(llmObj.parts)) {
184
+ const parts = llmObj.parts.map((p) => typeof p === "string" ? p : p?.text).filter((t) => typeof t === "string" && t.trim());
185
+ if (parts.length > 0) return parts.join("\n").trim() || void 0;
186
+ }
187
+ }
188
+ return void 0;
189
+ }
190
+ function getRole(toolName) {
191
+ if (TOOL_ROLES[toolName]) return TOOL_ROLES[toolName];
192
+ if (toolName.startsWith("mcp_")) {
193
+ const parts = toolName.split("_");
194
+ const suffix = parts[parts.length - 1];
195
+ if (suffix === "read" || suffix === "get" || suffix === "list")
196
+ return "reader";
197
+ if (suffix === "write" || suffix === "create" || suffix === "update" || suffix === "delete")
198
+ return "writer";
199
+ if (suffix === "search" || suffix === "find" || suffix === "query")
200
+ return "searcher";
201
+ }
202
+ return "runner";
203
+ }
204
+ process.stdin.setEncoding("utf-8");
205
+ var raw = "";
206
+ process.stdin.on("data", (chunk) => {
207
+ raw += chunk;
208
+ });
209
+ process.stdin.on("end", () => {
210
+ respond();
211
+ try {
212
+ const payload = JSON.parse(raw);
213
+ log(
214
+ `Received: hook_event_name=${payload.hook_event_name ?? "?"} tool_name=${payload.tool_name ?? "?"} session_id=${String(payload.session_id ?? "?").slice(0, 8)}`
215
+ );
216
+ const {
217
+ session_id = "unknown",
218
+ hook_event_name = "BeforeTool",
219
+ tool_name = "unknown",
220
+ tool_input,
221
+ tool_response,
222
+ cwd,
223
+ timestamp
224
+ } = payload;
225
+ if (hook_event_name === "SessionStart") {
226
+ const sessionShort2 = String(session_id).slice(0, 8);
227
+ const folderName2 = cwd ? import_path.default.basename(cwd) : "Gemini CLI";
228
+ const event2 = {
229
+ agentId: `gc-${sessionShort2}-runner`,
230
+ agentName: `${folderName2} \xB7 Runner`,
231
+ source: "gemini-cli",
232
+ event: "agent_register",
233
+ toolName: "",
234
+ timestamp: Date.now(),
235
+ requestId: `${session_id}-session-start-${Date.now()}`,
236
+ metadata: {
237
+ cwd: cwd ?? "unknown",
238
+ sessionId: session_id,
239
+ hookEvent: "SessionStart"
240
+ }
241
+ };
242
+ postEvent(JSON.stringify(event2));
243
+ return;
244
+ }
245
+ if (hook_event_name === "SessionEnd") {
246
+ const sessionShort2 = String(session_id).slice(0, 8);
247
+ const folderName2 = cwd ? import_path.default.basename(cwd) : "Gemini CLI";
248
+ const event2 = {
249
+ agentId: `gc-${sessionShort2}-runner`,
250
+ agentName: `${folderName2} \xB7 Runner`,
251
+ source: "gemini-cli",
252
+ event: "agent_heartbeat",
253
+ toolName: "",
254
+ timestamp: Date.now(),
255
+ requestId: `${session_id}-session-end-${Date.now()}`,
256
+ metadata: {
257
+ cwd: cwd ?? "unknown",
258
+ sessionId: session_id,
259
+ hookEvent: "SessionEnd"
260
+ }
261
+ };
262
+ postEvent(JSON.stringify(event2));
263
+ return;
264
+ }
265
+ const isAfter = hook_event_name === "AfterTool";
266
+ const hasError = isAfter && tool_response?.error;
267
+ const role = getRole(tool_name);
268
+ const sessionShort = String(session_id).slice(0, 8);
269
+ const agentId = `gc-${sessionShort}-${role}`;
270
+ const folderName = cwd ? import_path.default.basename(cwd) : "Gemini CLI";
271
+ const agentName = `${folderName} \xB7 ${ROLE_LABELS[role]}`;
272
+ let subAgentMeta;
273
+ if (tool_name === "complete_task" && tool_input) {
274
+ const result = tool_input["result"];
275
+ const subName = typeof result === "string" && result.trim() ? result.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 24) : "subagent";
276
+ const subAgentId = `gc-${sessionShort}-subagent-${subName}`;
277
+ subAgentMeta = { subAgentId, subAgentName: subName };
278
+ }
279
+ let eventType;
280
+ if (isAfter && hasError) {
281
+ eventType = "call_error";
282
+ } else if (isAfter) {
283
+ eventType = "call_end";
284
+ } else {
285
+ eventType = "call_start";
286
+ }
287
+ const resultText = isAfter ? extractResultText(tool_response) : void 0;
288
+ const event = {
289
+ agentId,
290
+ agentName,
291
+ source: "gemini-cli",
292
+ event: eventType,
293
+ toolName: tool_name,
294
+ arguments: tool_input ?? {},
295
+ timestamp: timestamp ? new Date(timestamp).getTime() : Date.now(),
296
+ requestId: `${session_id}-${tool_name}-${Date.now()}`,
297
+ ...hasError ? { error: String(tool_response.error) } : {},
298
+ // On BeforeTool: attach context hint; on AfterTool: attach tool result
299
+ ...!isAfter && tool_input ? { message: extractToolMessage(tool_name, tool_input) } : {},
300
+ ...isAfter && resultText ? { message: resultText } : {},
301
+ metadata: {
302
+ cwd: cwd ?? "unknown",
303
+ role,
304
+ sessionId: session_id,
305
+ ...subAgentMeta ?? {}
306
+ }
307
+ };
308
+ postEvent(JSON.stringify(event));
309
+ } catch (e) {
310
+ log("Error: " + (e?.message ?? e));
311
+ }
312
+ });
package/dist/index.html CHANGED
@@ -4,15 +4,15 @@
4
4
  <meta charset="UTF-8" />
5
5
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <title>AgentMomo — MCP Activity Visualizer</title>
7
+ <title>AgentMOMO— MCP Activity Visualizer</title>
8
8
  <link rel="preconnect" href="https://fonts.googleapis.com" />
9
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
10
10
  <link
11
11
  href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400..900&display=swap"
12
12
  rel="stylesheet"
13
13
  />
14
- <script type="module" crossorigin src="/assets/index-Cru_j148.js"></script>
15
- <link rel="stylesheet" crossorigin href="/assets/index-q7eACk3a.css">
14
+ <script type="module" crossorigin src="/assets/index-5pVyUNvu.js"></script>
15
+ <link rel="stylesheet" crossorigin href="/assets/index-BjOLTppo.css">
16
16
  </head>
17
17
  <body>
18
18
  <div id="root"></div>