@imenam/mcp-messenger 1.0.34 → 1.0.36

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/src/index.js CHANGED
@@ -3,27 +3,27 @@ import "dotenv/config";
3
3
  import { ConfigError } from "./config.js";
4
4
  import { logger } from "./logger.js";
5
5
  import { APP_VERSION } from "./version.js";
6
- const USAGE = `mcp-messenger v${APP_VERSION} — agent-to-agent mailbox
7
-
8
- Usage:
9
- mcp-messenger Start in MCP mode (stdio) — the agent-side client.
10
- mcp-messenger --server Start the mailbox server (HTTP API + web console).
11
- mcp-messenger --watch <mailbox>
12
- Print one line per incoming message, forever. Meant to be
13
- run by the agent's host as a background watcher, not by hand.
14
- mcp-messenger --claude-setup-mcp [--server-url <url>] [--api-key <key>] [--force]
15
- Write the messenger entry into ./.mcp.json.
16
- mcp-messenger --reset-password
17
- Give the web console account a new random password and
18
- close all its sessions. Run it on the server machine.
19
- mcp-messenger --version Print the version.
20
- mcp-messenger --help Print this help.
21
-
22
- MCP mode requires MESSENGER_SERVER_URL and MESSENGER_API_KEY (an API key created in the
23
- web console); each session gets its own mailbox unless MESSENGER_AGENT_ID pins a fixed
24
- address.
25
- Server mode reads MESSENGER_PORT and MESSENGER_DB_PATH and always listens on 127.0.0.1.
26
- At the first start it prints a setup code: open /ui/ to create the console account.
6
+ const USAGE = `mcp-messenger v${APP_VERSION} — agent-to-agent mailbox
7
+
8
+ Usage:
9
+ mcp-messenger Start in MCP mode (stdio) — the agent-side client.
10
+ mcp-messenger --server Start the mailbox server (HTTP API + web console).
11
+ mcp-messenger --watch <mailbox>
12
+ Print one line per incoming message, forever. Meant to be
13
+ run by the agent's host as a background watcher, not by hand.
14
+ mcp-messenger --claude-setup-mcp [--server-url <url>] [--api-key <key>] [--force]
15
+ Write the messenger entry into ./.mcp.json.
16
+ mcp-messenger --reset-password
17
+ Give the web console account a new random password and
18
+ close all its sessions. Run it on the server machine.
19
+ mcp-messenger --version Print the version.
20
+ mcp-messenger --help Print this help.
21
+
22
+ MCP mode requires MESSENGER_SERVER_URL and MESSENGER_API_KEY (an API key created in the
23
+ web console); each session gets its own mailbox unless MESSENGER_AGENT_ID pins a fixed
24
+ address.
25
+ Server mode reads MESSENGER_PORT and MESSENGER_DB_PATH and always listens on 127.0.0.1.
26
+ At the first start it prints a setup code: open /ui/ to create the console account.
27
27
  See .env.example for the full list.`;
28
28
  /** Valeur qui suit une option (`--api-key mk_…`), ou null si l'option est absente ou vide. */
29
29
  function optionValue(args, name) {
@@ -140,11 +140,10 @@ const keyCreateSchema = z
140
140
  const keyPatchSchema = z
141
141
  .object({
142
142
  name: z.string().trim().min(1).max(200).optional(),
143
+ agent_name: z.string().trim().min(1).max(200).optional(),
143
144
  agent_description: agentDescriptionSchema.optional(),
144
145
  })
145
- .refine((input) => input.name !== undefined || input.agent_description !== undefined, {
146
- message: "provide `name` and/or `agent_description`",
147
- });
146
+ .refine((input) => input.name !== undefined || input.agent_name !== undefined || input.agent_description !== undefined, { message: "provide `name`, `agent_name` and/or `agent_description`" });
148
147
  const keyExtendSchema = z.object({ days: lifetimeSchema });
149
148
  const adminThreadsSchema = z.object({
150
149
  search: z.string().trim().min(1).optional(),
@@ -527,6 +526,10 @@ export function createApp({ store, config, setup = new SetupGate(store.access) }
527
526
  const input = keyPatchSchema.parse(req.body ?? {});
528
527
  const id = String(req.params.id);
529
528
  let key = input.name !== undefined ? access.renameApiKey(id, input.name) : null;
529
+ if (input.agent_name !== undefined) {
530
+ key = access.setApiKeyAgentName(id, input.agent_name);
531
+ logger.info(`API key ${key.id} now bound to agent "${key.agent_name}"`);
532
+ }
530
533
  if (input.agent_description !== undefined)
531
534
  key = access.setApiKeyAgentDescription(id, input.agent_description);
532
535
  res.json({ key });
@@ -3265,6 +3265,7 @@ async function openKeyDetail(id) {
3265
3265
  function renderKeyDetail({ key, mailboxes }) {
3266
3266
  let renaming = false;
3267
3267
  let describing = false;
3268
+ let renamingAgent = false;
3268
3269
  let extendOpen = false;
3269
3270
  const error = node("p", "form-banner");
3270
3271
  error.hidden = true;
@@ -3385,7 +3386,7 @@ function renderKeyDetail({ key, mailboxes }) {
3385
3386
  for (const part of [].concat(value)) cell.appendChild(typeof part === "string" ? document.createTextNode(part) : part);
3386
3387
  list.appendChild(cell);
3387
3388
  };
3388
- add("Agent autorisé", keyAgent(key));
3389
+ add("Agent autorisé", key.agent_name ? agentNameCell() : keyAgent(key));
3389
3390
  if (key.agent_name) add("Description", descriptionCell());
3390
3391
  add("Créée", `${formatDay(key.created_at)}${key.created_by ? ` par ${key.created_by}` : ""}`);
3391
3392
  add(
@@ -3398,6 +3399,66 @@ function renderKeyDetail({ key, mailboxes }) {
3398
3399
  return list;
3399
3400
  }
3400
3401
 
3402
+ /**
3403
+ * Nom de l'agent, modifiable sur place : Entrée ou un clic ailleurs enregistre, Échap
3404
+ * annule. Le nouveau nom s'applique aussi aux boîtes déjà ouvertes avec la clé.
3405
+ */
3406
+ function agentNameCell() {
3407
+ if (!renamingAgent) {
3408
+ const edit = node("button", "btn btn--icon btn--ghost props-edit");
3409
+ edit.type = "button";
3410
+ edit.title = "Renommer l'agent";
3411
+ edit.setAttribute("aria-label", "Renommer l'agent autorisé");
3412
+ edit.appendChild(icon("pencil"));
3413
+ edit.addEventListener("click", () => {
3414
+ renamingAgent = true;
3415
+ render();
3416
+ });
3417
+ return [keyAgent(key), edit];
3418
+ }
3419
+ const input = textInput(key.agent_name, { autocomplete: "off", list: "key-detail-agent-names" });
3420
+ input.className = "inline-input inline-input--small";
3421
+ const datalist = node("datalist");
3422
+ datalist.id = "key-detail-agent-names";
3423
+ for (const name of knownAgentNames()) {
3424
+ const option = document.createElement("option");
3425
+ option.value = name;
3426
+ datalist.appendChild(option);
3427
+ }
3428
+ let saved = false;
3429
+ const save = async () => {
3430
+ if (saved) return;
3431
+ saved = true;
3432
+ const agentName = input.value.trim();
3433
+ if (!agentName || agentName === key.agent_name) {
3434
+ renamingAgent = false;
3435
+ render();
3436
+ return;
3437
+ }
3438
+ try {
3439
+ await patch(`/admin/keys/${encodeURIComponent(key.id)}`, { agent_name: agentName });
3440
+ await reload();
3441
+ } catch (failure) {
3442
+ saved = false;
3443
+ fail(failure);
3444
+ }
3445
+ };
3446
+ input.addEventListener("keydown", (event) => {
3447
+ if (event.key === "Enter") save();
3448
+ if (event.key === "Escape") {
3449
+ // Échap referme la saisie, pas le volet.
3450
+ event.preventDefault();
3451
+ event.stopPropagation();
3452
+ saved = true;
3453
+ renamingAgent = false;
3454
+ render();
3455
+ }
3456
+ });
3457
+ input.addEventListener("blur", save);
3458
+ setTimeout(() => input.focus(), 0);
3459
+ return [input, datalist];
3460
+ }
3461
+
3401
3462
  /** Description de l'agent, modifiable sur place : Entrée enregistre, Échap annule. */
3402
3463
  function descriptionCell() {
3403
3464
  if (!describing) {