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.
- package/README.md +8 -6
- package/dist/assets/index-5pVyUNvu.js +5574 -0
- package/dist/assets/index-BjOLTppo.css +1 -0
- package/dist/claude-code-hook.cjs +66 -0
- package/dist/cli.js +2 -0
- package/dist/codex-cli-hook.cjs +415 -0
- package/dist/gemini-cli-hook.cjs +312 -0
- package/dist/index.html +3 -3
- package/dist/server.js +8252 -26
- package/package.json +31 -2
- package/dist/assets/index-Cru_j148.js +0 -5346
- package/dist/assets/index-q7eACk3a.css +0 -1
|
@@ -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>
|
|
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-
|
|
15
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
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>
|