@imenam/mcp-messenger 1.0.30 → 1.0.31
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 +764 -727
- package/dist/src/cli/watch.d.ts +3 -1
- package/dist/src/cli/watch.js +12 -2
- package/dist/src/client/messenger-client.d.ts +5 -1
- package/dist/src/client/messenger-client.js +5 -0
- package/dist/src/core/store.d.ts +23 -1
- package/dist/src/core/store.js +305 -211
- package/dist/src/core/types.d.ts +24 -0
- package/dist/src/mcp/start.js +25 -22
- package/dist/src/mcp/tools.js +45 -7
- package/dist/src/server/app.js +41 -10
- package/dist/src/server/ui/app.js +839 -7
- package/dist/src/server/ui/index.html +59 -0
- package/dist/src/server/ui/styles.css +687 -0
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +16 -2
- package/package.json +2 -2
package/dist/src/core/types.d.ts
CHANGED
|
@@ -35,6 +35,30 @@ export interface AgentDirectoryEntry extends Agent {
|
|
|
35
35
|
/** Plus récent de la dernière connexion et de la dernière livraison ; null si aucune. */
|
|
36
36
|
last_activity_at: string | null;
|
|
37
37
|
}
|
|
38
|
+
/** Une des deux boîtes d'une liaison, et le moment où son agent en a pris connaissance. */
|
|
39
|
+
export interface LinkEnd {
|
|
40
|
+
mailbox: string;
|
|
41
|
+
/** null tant que l'agent de cette boîte n'a pas lu la liaison (`whoami`, `list_links`, `list_agents`). */
|
|
42
|
+
seen_at: string | null;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Liaison posée depuis la console entre deux boîtes : chacune connaît l'autre comme
|
|
46
|
+
* correspondante désignée, sans que les agents aient à échanger d'adresse.
|
|
47
|
+
*/
|
|
48
|
+
export interface MailboxLink {
|
|
49
|
+
link_id: string;
|
|
50
|
+
/** Motif transmis aux deux agents. */
|
|
51
|
+
note: string | null;
|
|
52
|
+
created_at: string;
|
|
53
|
+
mailboxes: [LinkEnd, LinkEnd];
|
|
54
|
+
}
|
|
55
|
+
/** Liaison vue depuis l'une de ses deux boîtes : la fiche de la boîte d'en face. */
|
|
56
|
+
export interface LinkedMailbox {
|
|
57
|
+
link_id: string;
|
|
58
|
+
note: string | null;
|
|
59
|
+
created_at: string;
|
|
60
|
+
correspondent: Agent;
|
|
61
|
+
}
|
|
38
62
|
/** Pièce jointe telle qu'elle voyage avec un message : ses métadonnées, sans son contenu. */
|
|
39
63
|
export interface AttachmentInfo {
|
|
40
64
|
attachment_id: string;
|
package/dist/src/mcp/start.js
CHANGED
|
@@ -18,28 +18,31 @@ import { TOOLS, callTool } from "./tools.js";
|
|
|
18
18
|
* recopier une adresse dans le corps d'un message (le serveur la pose déjà, la copie ment
|
|
19
19
|
* dès qu'elle vieillit). Les dire ici, c'est les dire avant l'erreur.
|
|
20
20
|
*/
|
|
21
|
-
const INSTRUCTIONS = `mcp-messenger gives this session a mailbox and lets it exchange messages with other agent sessions.
|
|
22
|
-
|
|
23
|
-
Two words, two different things, used consistently by every tool here:
|
|
24
|
-
- a **mailbox** is an address (\`box_…\`). It identifies exactly one session, and it is what you write to.
|
|
25
|
-
- an **agent name** is the project a session works for. It is a label, never an address, and every session of that project carries it.
|
|
26
|
-
|
|
27
|
-
Who you are, and who the others are — read this before writing to anyone:
|
|
28
|
-
- A session is identified by its mailbox address, and by nothing else. \`whoami\` gives you yours.
|
|
29
|
-
- The agent name (e.g. "Ai Corrector Dev") comes from the configuration and says which project the agent works on. It is NOT unique: every session started from that configuration carries it.
|
|
30
|
-
- \`list_agents\` groups mailboxes under their agent name: one group per project, one line per session. A group holding several lines is several live sessions of that project, each with its own address — pick one of those addresses, never the group name.
|
|
31
|
-
- One of those groups may carry the same agent name as yours. Recognising your own agent name there does not mean you are looking at yourself — those are other sessions of the same project, each a different agent with its own mailbox. Compare addresses, never names.
|
|
32
|
-
- Your own mailbox is never listed in \`list_agents\`: every address you see there belongs to someone else.
|
|
33
|
-
|
|
34
|
-
Resuming earlier work:
|
|
35
|
-
- A resumed session usually keeps the mailbox it had: the address, the threads and the unread messages come back on their own. \`whoami\` says so when it happens.
|
|
36
|
-
- When it cannot be decided automatically, \`whoami\` lists the mailboxes left by a stopped session of this project. If you are continuing that work, call \`attach_to_mailbox\` with the right address.
|
|
37
|
-
- If a \`box_…\` address appears earlier in your own context, from a previous part of this conversation, that is your mailbox from before: attach to it rather than writing from a fresh one, so your correspondents keep reaching you at the address they know.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
-
|
|
41
|
-
|
|
42
|
-
|
|
21
|
+
const INSTRUCTIONS = `mcp-messenger gives this session a mailbox and lets it exchange messages with other agent sessions.
|
|
22
|
+
|
|
23
|
+
Two words, two different things, used consistently by every tool here:
|
|
24
|
+
- a **mailbox** is an address (\`box_…\`). It identifies exactly one session, and it is what you write to.
|
|
25
|
+
- an **agent name** is the project a session works for. It is a label, never an address, and every session of that project carries it.
|
|
26
|
+
|
|
27
|
+
Who you are, and who the others are — read this before writing to anyone:
|
|
28
|
+
- A session is identified by its mailbox address, and by nothing else. \`whoami\` gives you yours.
|
|
29
|
+
- The agent name (e.g. "Ai Corrector Dev") comes from the configuration and says which project the agent works on. It is NOT unique: every session started from that configuration carries it.
|
|
30
|
+
- \`list_agents\` groups mailboxes under their agent name: one group per project, one line per session. A group holding several lines is several live sessions of that project, each with its own address — pick one of those addresses, never the group name.
|
|
31
|
+
- One of those groups may carry the same agent name as yours. Recognising your own agent name there does not mean you are looking at yourself — those are other sessions of the same project, each a different agent with its own mailbox. Compare addresses, never names.
|
|
32
|
+
- Your own mailbox is never listed in \`list_agents\`: every address you see there belongs to someone else.
|
|
33
|
+
|
|
34
|
+
Resuming earlier work:
|
|
35
|
+
- A resumed session usually keeps the mailbox it had: the address, the threads and the unread messages come back on their own. \`whoami\` says so when it happens.
|
|
36
|
+
- When it cannot be decided automatically, \`whoami\` lists the mailboxes left by a stopped session of this project. If you are continuing that work, call \`attach_to_mailbox\` with the right address.
|
|
37
|
+
- If a \`box_…\` address appears earlier in your own context, from a previous part of this conversation, that is your mailbox from before: attach to it rather than writing from a fresh one, so your correspondents keep reaching you at the address they know.
|
|
38
|
+
|
|
39
|
+
Linked mailboxes:
|
|
40
|
+
- The user can link this mailbox to others from the web console: those are the correspondents you are meant to work with. \`whoami\` and \`list_links\` list them, and the notification watcher announces each new link as it arrives.
|
|
41
|
+
|
|
42
|
+
Writing:
|
|
43
|
+
- One message goes to exactly one mailbox, and never to your own. To reach several correspondents, send each one its own message.
|
|
44
|
+
- Never write a mailbox address in the body of a message. The server attaches the sender and the recipient to every message, and the reader sees them: an address copied by hand adds nothing and misleads as soon as it is stale or mistaken.
|
|
45
|
+
- Call \`enable_notifications\` once at the start of the session and arm the watcher it hands you. Until then, no incoming message reaches you.
|
|
43
46
|
- The host stops that watcher after 30 minutes at most. Each time it tells you the watcher expired, re-arm it at once with the same Monitor call; otherwise notifications stop for good.`;
|
|
44
47
|
/** Serveur MCP prêt à être branché sur n'importe quel transport (stdio en production, mémoire en test). */
|
|
45
48
|
export function createMcpServer(client) {
|
package/dist/src/mcp/tools.js
CHANGED
|
@@ -107,6 +107,11 @@ export const TOOLS = [
|
|
|
107
107
|
additionalProperties: false,
|
|
108
108
|
},
|
|
109
109
|
},
|
|
110
|
+
{
|
|
111
|
+
name: "list_links",
|
|
112
|
+
description: "List the mailboxes the user has linked to this one from the web console, newest first: these are the correspondents you are meant to work with, with the reason the user gave. Write to them with send_message, using the address listed here. Links arrive while you work — the notification watcher announces each new one — and whoami lists them too.",
|
|
113
|
+
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
114
|
+
},
|
|
110
115
|
{
|
|
111
116
|
name: "list_agents",
|
|
112
117
|
description: "List the mailboxes known to the server, grouped by agent name — one group per project, one line per session mailbox inside it, most recently active first. An agent name is shared by every session of the same project, so a group with several lines means several live sessions, each with its own mailbox address. Your own mailbox is never listed — you cannot write to yourself. Use it to find the mailbox address you want to write to; pass agent_name to expand a group whose sessions were not all listed.",
|
|
@@ -396,6 +401,7 @@ export async function callTool(client, name, rawArgs) {
|
|
|
396
401
|
const health = await client.health().catch(() => null);
|
|
397
402
|
const folders = stats.folders.map((f) => ` ${f.name.padEnd(12)} ${f.total} message(s), ${f.unread} unread`);
|
|
398
403
|
const self = await client.getAgent(client.agentId).catch(() => null);
|
|
404
|
+
const links = await client.listLinks();
|
|
399
405
|
const lines = [
|
|
400
406
|
`Mailbox address: ${client.agentId}`,
|
|
401
407
|
// Personne n'a besoin qu'on la lui envoie : l'annuaire la donne, et chaque message
|
|
@@ -411,6 +417,7 @@ export async function callTool(client, name, rawArgs) {
|
|
|
411
417
|
self?.display_name
|
|
412
418
|
? `Mailbox name: ${self.display_name}`
|
|
413
419
|
: "Mailbox name: none — call rename_mailbox so the user can tell this session apart from the others.",
|
|
420
|
+
...linkLines(links),
|
|
414
421
|
];
|
|
415
422
|
if (client.isAttachedElsewhere) {
|
|
416
423
|
lines.push(`Attached to another mailbox. This session's own mailbox is ${client.sessionAgentId}.`);
|
|
@@ -491,13 +498,27 @@ export async function callTool(client, name, rawArgs) {
|
|
|
491
498
|
return `No thread in this mailbox${scope} matching these filters.`;
|
|
492
499
|
return [`${threads.length} thread(s)${scope}:`, "", ...threads.map(formatThread)].join("\n");
|
|
493
500
|
}
|
|
501
|
+
case "list_links": {
|
|
502
|
+
const links = await client.listLinks();
|
|
503
|
+
if (links.length === 0) {
|
|
504
|
+
return "No mailbox is linked to this one yet. The user links mailboxes from the web console; the notification watcher announces each new link.";
|
|
505
|
+
}
|
|
506
|
+
return [
|
|
507
|
+
`${links.length} mailbox(es) linked to this one by the user, newest first:`,
|
|
508
|
+
"",
|
|
509
|
+
...links.map(formatLink),
|
|
510
|
+
"",
|
|
511
|
+
"Write to them with send_message, using the address shown. Do not repeat the address in the message body.",
|
|
512
|
+
].join("\n");
|
|
513
|
+
}
|
|
494
514
|
case "list_agents": {
|
|
495
515
|
const input = schemas.list_agents.parse(args);
|
|
496
516
|
const agents = await client.listAgents();
|
|
497
517
|
if (agents.length === 0)
|
|
498
518
|
return "No other mailbox on this server yet.";
|
|
519
|
+
const linked = new Set((await client.listLinks()).map((link) => link.correspondent.id));
|
|
499
520
|
const groups = groupByAgentName(agents);
|
|
500
|
-
return input.agent_name ? formatAgentGroup(groups, input.agent_name) : formatDirectory(groups);
|
|
521
|
+
return input.agent_name ? formatAgentGroup(groups, input.agent_name, linked) : formatDirectory(groups, linked);
|
|
501
522
|
}
|
|
502
523
|
case "send_message": {
|
|
503
524
|
const input = schemas.send_message.parse(args);
|
|
@@ -744,9 +765,9 @@ function groupByAgentName(agents) {
|
|
|
744
765
|
return [...groups.values()];
|
|
745
766
|
}
|
|
746
767
|
/** `boîte — nom · activité` : une ligne par session, l'adresse en tête car c'est elle qu'on copie. */
|
|
747
|
-
function formatMailboxLine(agent) {
|
|
768
|
+
function formatMailboxLine(agent, linked) {
|
|
748
769
|
const seen = agent.last_activity_at ? `last active ${agent.last_activity_at}` : "never active";
|
|
749
|
-
const flags = agent.registered ? "" : " · never connected"
|
|
770
|
+
const flags = `${agent.registered ? "" : " · never connected"}${linked.has(agent.id) ? " · linked to you" : ""}`;
|
|
750
771
|
return ` • ${agent.id} — ${agent.display_name ?? "no mailbox name"} · ${seen}${flags}`;
|
|
751
772
|
}
|
|
752
773
|
/**
|
|
@@ -763,7 +784,7 @@ const DIRECTORY_FOOTER = [
|
|
|
763
784
|
"is never listed here. Always write to a mailbox address taken from this list, never to a name.",
|
|
764
785
|
"To see what you have already exchanged with one of them, call list_threads with its address in with_mailbox.",
|
|
765
786
|
];
|
|
766
|
-
function formatDirectory(groups) {
|
|
787
|
+
function formatDirectory(groups, linked) {
|
|
767
788
|
const mailboxes = groups.reduce((total, group) => total + group.mailboxes.length, 0);
|
|
768
789
|
const blocks = groups.map((group) => {
|
|
769
790
|
const sessions = group.mailboxes.length;
|
|
@@ -773,7 +794,7 @@ function formatDirectory(groups) {
|
|
|
773
794
|
// Un agent à sessions nombreuses ne doit pas noyer les autres : les plus récentes
|
|
774
795
|
// suffisent à écrire, `agent_name` donne le reste à qui en a besoin.
|
|
775
796
|
const shown = sessions > SESSIONS_SHOWN_PER_AGENT ? group.mailboxes.slice(0, 3) : group.mailboxes;
|
|
776
|
-
lines.push(...shown.map(formatMailboxLine));
|
|
797
|
+
lines.push(...shown.map((agent) => formatMailboxLine(agent, linked)));
|
|
777
798
|
if (shown.length < sessions) {
|
|
778
799
|
lines.push(` … ${sessions - shown.length} more session(s) — list_agents with agent_name: "${group.name}" lists them all.`);
|
|
779
800
|
}
|
|
@@ -789,7 +810,7 @@ function formatDirectory(groups) {
|
|
|
789
810
|
].join("\n");
|
|
790
811
|
}
|
|
791
812
|
/** Toutes les sessions d'un agent, décrites une par une : le second niveau de l'annuaire. */
|
|
792
|
-
function formatAgentGroup(groups, requested) {
|
|
813
|
+
function formatAgentGroup(groups, requested, linked) {
|
|
793
814
|
const wanted = requested.trim().toLowerCase();
|
|
794
815
|
const group = groups.find((g) => g.name.toLowerCase() === wanted);
|
|
795
816
|
if (!group) {
|
|
@@ -802,7 +823,7 @@ function formatAgentGroup(groups, requested) {
|
|
|
802
823
|
`• ${agent.id}`,
|
|
803
824
|
` Mailbox: ${agent.display_name ?? "not named — this session never said what it works on"}`,
|
|
804
825
|
agent.description ? ` ${agent.description}` : null,
|
|
805
|
-
` ${seen}${agent.registered ? "" : " · never connected"}`,
|
|
826
|
+
` ${seen}${agent.registered ? "" : " · never connected"}${linked.has(agent.id) ? " · linked to you" : ""}`,
|
|
806
827
|
]
|
|
807
828
|
.filter(Boolean)
|
|
808
829
|
.join("\n");
|
|
@@ -862,6 +883,23 @@ function resumeLines(client) {
|
|
|
862
883
|
}
|
|
863
884
|
return lines;
|
|
864
885
|
}
|
|
886
|
+
/** Ce que `whoami` dit des liaisons posées par l'utilisateur sur cette boîte. */
|
|
887
|
+
function linkLines(links) {
|
|
888
|
+
if (links.length === 0) {
|
|
889
|
+
return ["Linked mailboxes: none yet — the user links mailboxes from the web console."];
|
|
890
|
+
}
|
|
891
|
+
return [
|
|
892
|
+
"Linked mailboxes — correspondents the user designated for this session:",
|
|
893
|
+
...links.map((link) => ` ${formatLink(link)}`),
|
|
894
|
+
" ↳ write to them with send_message; list_links details them.",
|
|
895
|
+
];
|
|
896
|
+
}
|
|
897
|
+
/** `• adresse — Agent · Boîte · liée le … — motif` */
|
|
898
|
+
function formatLink(link) {
|
|
899
|
+
const names = formatAgentNames(link.correspondent) || "unnamed mailbox";
|
|
900
|
+
const note = link.note ? ` — ${link.note}` : "";
|
|
901
|
+
return `• ${link.correspondent.id} — ${names} · linked ${link.created_at}${note}`;
|
|
902
|
+
}
|
|
865
903
|
/** `titre (id)`, ou l'id seul tant que le fil n'a pas été nommé. */
|
|
866
904
|
function formatThreadRef(title, threadId) {
|
|
867
905
|
return title ? `${title} (${threadId})` : threadId;
|
package/dist/src/server/app.js
CHANGED
|
@@ -133,6 +133,10 @@ const purgeSchema = z
|
|
|
133
133
|
.refine((input) => [input.before, input.created_before, input.empty].filter((value) => value !== undefined).length === 1, {
|
|
134
134
|
message: "provide exactly one of `before` (inactive since that date), `created_before` (created before that date) or `empty: true`",
|
|
135
135
|
});
|
|
136
|
+
const linkSchema = z.object({
|
|
137
|
+
mailboxes: z.tuple([agentIdSchema, agentIdSchema]),
|
|
138
|
+
note: z.string().trim().max(500).nullish(),
|
|
139
|
+
});
|
|
136
140
|
const adminListSchema = z.object({
|
|
137
141
|
search: z.string().trim().min(1).optional(),
|
|
138
142
|
agent: z.string().trim().min(1).optional(),
|
|
@@ -209,7 +213,7 @@ export function createApp({ store, config }) {
|
|
|
209
213
|
app.get("/", (_req, res) => {
|
|
210
214
|
res.redirect("/ui/");
|
|
211
215
|
});
|
|
212
|
-
// --- Supervision (lecture,
|
|
216
|
+
// --- Supervision (lecture, liaisons et nettoyages de boîtes) -------------
|
|
213
217
|
// Montée avant la porte d'entrée : son contrôle est au moins aussi strict (session de
|
|
214
218
|
// console ou jeton admin), et la session par cookie n'est reconnue nulle part ailleurs.
|
|
215
219
|
const admin = express.Router();
|
|
@@ -281,7 +285,7 @@ export function createApp({ store, config }) {
|
|
|
281
285
|
res.json({ mailboxes: store.emptyMailboxes() });
|
|
282
286
|
});
|
|
283
287
|
/**
|
|
284
|
-
*
|
|
288
|
+
* Suppression en lot : elle détruit.
|
|
285
289
|
*
|
|
286
290
|
* Deux garde-fous, parce qu'un nettoyage ne se rattrape pas : le critère est redemandé
|
|
287
291
|
* avec les adresses, et le serveur refuse toute adresse qui n'y répond plus au moment
|
|
@@ -331,6 +335,21 @@ export function createApp({ store, config }) {
|
|
|
331
335
|
logger.warn(`admin delete: mailbox ${id} deleted (${removed.messages} message(s) erased)`);
|
|
332
336
|
res.json({ mailbox: id, ...removed });
|
|
333
337
|
});
|
|
338
|
+
admin.get("/links", (_req, res) => {
|
|
339
|
+
res.json({ links: store.listLinks() });
|
|
340
|
+
});
|
|
341
|
+
admin.post("/links", (req, res) => {
|
|
342
|
+
const input = linkSchema.parse(req.body ?? {});
|
|
343
|
+
const link = store.createLink(input.mailboxes[0], input.mailboxes[1], input.note ?? null);
|
|
344
|
+
logger.info(`admin link ${link.link_id}: ${link.mailboxes[0].mailbox} <-> ${link.mailboxes[1].mailbox}`);
|
|
345
|
+
res.status(201).json({ link });
|
|
346
|
+
});
|
|
347
|
+
admin.delete("/links/:id", (req, res) => {
|
|
348
|
+
const linkId = String(req.params.id);
|
|
349
|
+
store.deleteLink(linkId);
|
|
350
|
+
logger.info(`admin unlink ${linkId}`);
|
|
351
|
+
res.json({ link_id: linkId });
|
|
352
|
+
});
|
|
334
353
|
app.use("/admin", admin);
|
|
335
354
|
// Porte d'entrée de tout le reste : aucune requête n'est servie sans jeton valide. Le
|
|
336
355
|
// contrôle par route (identité de l'agent) vient ensuite.
|
|
@@ -388,6 +407,10 @@ export function createApp({ store, config }) {
|
|
|
388
407
|
throw new MessengerError(`mailbox not found: ${req.params.id}`, 404);
|
|
389
408
|
res.json({ agent });
|
|
390
409
|
});
|
|
410
|
+
// Lire ses liaisons, c'est en prendre connaissance : la console l'affiche comme reçue.
|
|
411
|
+
api.get("/links", (req, res) => {
|
|
412
|
+
res.json({ links: store.linksFor(req.agentId, { markSeen: true }) });
|
|
413
|
+
});
|
|
391
414
|
api.get("/mailbox", (req, res) => {
|
|
392
415
|
res.json({ ...store.stats(req.agentId), watcher: watchers.status(req.agentId) });
|
|
393
416
|
});
|
|
@@ -460,7 +483,8 @@ export function createApp({ store, config }) {
|
|
|
460
483
|
});
|
|
461
484
|
// Attente longue : seuls les messages arrivés APRÈS le début de l'attente réveillent
|
|
462
485
|
// l'appelant ; les non-lus déjà présents sont ignorés (sinon l'outil rendrait la main
|
|
463
|
-
// immédiatement tant que la boîte n'est pas vidée).
|
|
486
|
+
// immédiatement tant que la boîte n'est pas vidée). Un veilleur est aussi réveillé par
|
|
487
|
+
// une liaison posée sur sa boîte.
|
|
464
488
|
api.get("/wait", (req, res) => {
|
|
465
489
|
const { timeout_seconds, folder, watcher } = waitQuerySchema.parse(req.query);
|
|
466
490
|
const agentId = req.agentId;
|
|
@@ -471,11 +495,15 @@ export function createApp({ store, config }) {
|
|
|
471
495
|
// Le relâchement doit couvrir les trois sorties possibles : message, expiration,
|
|
472
496
|
// client parti. Un compteur qui ne redescend pas ferait croire à un veilleur éternel.
|
|
473
497
|
const releaseWatcher = watcher ? watchers.begin(agentId) : () => { };
|
|
474
|
-
const
|
|
498
|
+
const stop = () => {
|
|
475
499
|
clearTimeout(timer);
|
|
476
500
|
store.off("message", onMessage);
|
|
477
|
-
|
|
501
|
+
store.off("link", onLink);
|
|
502
|
+
req.off("close", stop);
|
|
478
503
|
releaseWatcher();
|
|
504
|
+
};
|
|
505
|
+
const done = (payload) => {
|
|
506
|
+
stop();
|
|
479
507
|
if (!res.headersSent)
|
|
480
508
|
res.json(payload);
|
|
481
509
|
};
|
|
@@ -488,14 +516,17 @@ export function createApp({ store, config }) {
|
|
|
488
516
|
return;
|
|
489
517
|
done({ timed_out: false, message: store.getMessage(agentId, event.message_id, false) });
|
|
490
518
|
};
|
|
491
|
-
const
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
519
|
+
const onLink = (event) => {
|
|
520
|
+
if (event.agent_id !== agentId)
|
|
521
|
+
return;
|
|
522
|
+
const [link] = store.linksFor(agentId, { linkId: event.link_id });
|
|
523
|
+
done({ timed_out: false, message: null, link });
|
|
495
524
|
};
|
|
496
525
|
const timer = setTimeout(() => done({ timed_out: true, message: null }), timeoutSeconds * 1000);
|
|
497
526
|
store.on("message", onMessage);
|
|
498
|
-
|
|
527
|
+
if (watcher)
|
|
528
|
+
store.on("link", onLink);
|
|
529
|
+
req.once("close", stop);
|
|
499
530
|
});
|
|
500
531
|
app.use("/api", api);
|
|
501
532
|
// --- Erreurs --------------------------------------------------------------
|