agent-comms 8.0.5 → 8.0.7
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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +1 -1
- package/dist/bridges/cc-peer/front-controller.d.ts +6 -3
- package/dist/bridges/cc-peer/front-controller.d.ts.map +1 -1
- package/dist/bridges/cc-peer/front-controller.js +4 -3
- package/dist/bridges/cc-peer/front-controller.js.map +1 -1
- package/dist/bridges/cc-peer/front-relay.d.ts +4 -3
- package/dist/bridges/cc-peer/front-relay.d.ts.map +1 -1
- package/dist/bridges/cc-peer/front-relay.js +17 -8
- package/dist/bridges/cc-peer/front-relay.js.map +1 -1
- package/dist/bridges/cc-peer/reply-aliases.d.ts +24 -7
- package/dist/bridges/cc-peer/reply-aliases.d.ts.map +1 -1
- package/dist/bridges/cc-peer/reply-aliases.js +25 -13
- package/dist/bridges/cc-peer/reply-aliases.js.map +1 -1
- package/dist/test/cc-peer-alias-reply-routing.integration.test.d.ts +5 -0
- package/dist/test/cc-peer-alias-reply-routing.integration.test.d.ts.map +1 -0
- package/dist/test/cc-peer-alias-reply-routing.integration.test.js +153 -0
- package/dist/test/cc-peer-alias-reply-routing.integration.test.js.map +1 -0
- package/dist/test/cc-peer-front-controller.unit.test.js +40 -4
- package/dist/test/cc-peer-front-controller.unit.test.js.map +1 -1
- package/dist/test/cc-peer-front-relay.unit.test.js +136 -8
- package/dist/test/cc-peer-front-relay.unit.test.js.map +1 -1
- package/dist/test/cc-peer-reply-aliases.unit.test.js +65 -16
- package/dist/test/cc-peer-reply-aliases.unit.test.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/ExaDev/agent-comms)
|
|
4
4
|
[](https://www.npmjs.com/package/agent-comms)
|
|
5
|
-
[](https://github.com/ExaDev/agent-comms/releases/tag/v8.0.7)
|
|
6
6
|
[](https://github.com/ExaDev/agent-comms/actions)
|
|
7
7
|
|
|
8
8
|
Cross-harness communication mesh for LLM agents: rooms, DMs, presence, and visibility over TCP with zero filesystem dependencies.
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { type CcPeerRosterEntryLike } from "./front.js";
|
|
7
7
|
import type { IdentitySlot } from "../../core/identity-store.js";
|
|
8
|
+
import type { ReplyContext } from "./reply-aliases.js";
|
|
8
9
|
/** The minimum shape a fronted-session record must carry so CcPeerFront can track and route to it, regardless of whatever real MeshStore/CommsTool state a concrete implementation (front-runtime.ts) attaches alongside these fields. */
|
|
9
10
|
export interface FrontedSessionRecord {
|
|
10
11
|
readonly pid: number;
|
|
@@ -16,8 +17,8 @@ export interface FrontedSessionRecord {
|
|
|
16
17
|
fromName?: string;
|
|
17
18
|
body: string;
|
|
18
19
|
}>) => void;
|
|
19
|
-
/** Routes a reply arriving on one of this session's own reply aliases into
|
|
20
|
-
readonly handleAliasReply: (correspondentId: string, message: Readonly<{
|
|
20
|
+
/** Routes a reply arriving on one of this session's own reply aliases back into the mesh, sent as this session's own device-id (agent-comms#158) — the session-to-mesh direction for lazy per-correspondent aliases. A dm context sends a mesh DM addressed to the correspondent that alias stands for; a room context instead posts back into the room the aliased message was itself sent in, since a reply to a room message must return to that room rather than becoming a private DM to its sender (agent-comms#289). Only called once handleAliasMessage has already resolved the alias to a known correspondent and context; a stale alias goes to notifyStaleAlias instead. */
|
|
21
|
+
readonly handleAliasReply: (correspondentId: string, context: Readonly<ReplyContext>, message: Readonly<{
|
|
21
22
|
from?: string;
|
|
22
23
|
fromName?: string;
|
|
23
24
|
body: string;
|
|
@@ -28,6 +29,8 @@ export interface FrontedSessionRecord {
|
|
|
28
29
|
/** The narrow slice of ReplyAliasDirectory (reply-aliases.ts) CcPeerFront needs to resolve an inbound alias message's own correspondent -- narrowed rather than importing the class directly so front-controller.ts stays free of any construction concern, matching probeSlotOwner's own injected-function convention. */
|
|
29
30
|
export interface CcPeerFrontAliasDirectory {
|
|
30
31
|
correspondentFor: (aliasName: string) => string | undefined;
|
|
32
|
+
/** The reply context (dm vs. a named room) a previously-minted alias name currently carries — reply-aliases.ts's ReplyAliasDirectory.contextFor in production. Always defined whenever correspondentFor is, since both are set together by the directory's own ensure(); treated as a stale alias when either is missing. */
|
|
33
|
+
contextFor: (aliasName: string) => ReplyContext | undefined;
|
|
31
34
|
}
|
|
32
35
|
export interface CcPeerFrontDeps<TRecord extends FrontedSessionRecord> {
|
|
33
36
|
/** Enumerates the current local cc-peer roster. Rejects propagate to onError rather than throwing out of the poll timer. */
|
|
@@ -62,7 +65,7 @@ export declare class CcPeerFront<TRecord extends FrontedSessionRecord> {
|
|
|
62
65
|
fromName?: string;
|
|
63
66
|
body: string;
|
|
64
67
|
}>): void;
|
|
65
|
-
/** Routes a reply arriving on a shared reply alias to whichever fronted session actually sent it
|
|
68
|
+
/** Routes a reply arriving on a shared reply alias to whichever fronted session actually sent it — matched the same way as handleInboundMessage, by the envelope's own socket-path convention. A message matching no fronted session is silently dropped, same as handleInboundMessage: there is nowhere for it to go, and we cannot safely address an error back to a session we do not control. Once the sending session is identified, the alias directory resolves which correspondent this reply is for and the reply context (dm vs. room) it should return to; an alias the directory no longer knows about, or whose context is missing, is reported back into the session as a stale-alias error rather than silently dropped, per agent-comms#158. */
|
|
66
69
|
handleAliasMessage(message: Readonly<{
|
|
67
70
|
alias: string;
|
|
68
71
|
from?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"front-controller.d.ts","sourceRoot":"","sources":["../../../src/bridges/cc-peer/front-controller.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAGL,KAAK,qBAAqB,EAC3B,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"front-controller.d.ts","sourceRoot":"","sources":["../../../src/bridges/cc-peer/front-controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -42,17 +42,18 @@ export class CcPeerFront {
|
|
|
42
42
|
const record = matchInboundMessageSession(this.fronted.values(), message);
|
|
43
43
|
record?.handleInbound(message);
|
|
44
44
|
}
|
|
45
|
-
/** Routes a reply arriving on a shared reply alias to whichever fronted session actually sent it
|
|
45
|
+
/** Routes a reply arriving on a shared reply alias to whichever fronted session actually sent it — matched the same way as handleInboundMessage, by the envelope's own socket-path convention. A message matching no fronted session is silently dropped, same as handleInboundMessage: there is nowhere for it to go, and we cannot safely address an error back to a session we do not control. Once the sending session is identified, the alias directory resolves which correspondent this reply is for and the reply context (dm vs. room) it should return to; an alias the directory no longer knows about, or whose context is missing, is reported back into the session as a stale-alias error rather than silently dropped, per agent-comms#158. */
|
|
46
46
|
handleAliasMessage(message) {
|
|
47
47
|
const record = matchInboundMessageSession(this.fronted.values(), message);
|
|
48
48
|
if (!record)
|
|
49
49
|
return;
|
|
50
50
|
const correspondentId = this.deps.aliasDirectory.correspondentFor(message.alias);
|
|
51
|
-
|
|
51
|
+
const context = this.deps.aliasDirectory.contextFor(message.alias);
|
|
52
|
+
if (correspondentId === undefined || context === undefined) {
|
|
52
53
|
record.notifyStaleAlias(message.alias);
|
|
53
54
|
return;
|
|
54
55
|
}
|
|
55
|
-
record.handleAliasReply(correspondentId, message);
|
|
56
|
+
record.handleAliasReply(correspondentId, context, message);
|
|
56
57
|
}
|
|
57
58
|
async tick() {
|
|
58
59
|
let roster;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"front-controller.js","sourceRoot":"","sources":["../../../src/bridges/cc-peer/front-controller.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,qBAAqB,EACrB,0BAA0B,GAE3B,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"front-controller.js","sourceRoot":"","sources":["../../../src/bridges/cc-peer/front-controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,7 @@ import type { DeliveryEvent } from "../../core/types.js";
|
|
|
8
8
|
import { type FrontedSessionRecord } from "./front-controller.js";
|
|
9
9
|
import type { CcPeerRosterEntryLike } from "./front.js";
|
|
10
10
|
import type { CcPeerRef } from "./bridge.js";
|
|
11
|
+
import { type ReplyContext } from "./reply-aliases.js";
|
|
11
12
|
/** The narrow slice of MeshStore a fronted session's own record needs -- onDelivery to wire the mesh-to-session direction, setAgentOffline/shutdown for detachFrontedSession's own teardown. */
|
|
12
13
|
export interface FrontRelayStore {
|
|
13
14
|
onDelivery: ((agentId: string, event: DeliveryEvent) => void | Promise<void>) | undefined;
|
|
@@ -26,9 +27,9 @@ export interface FrontRelayAliasPool {
|
|
|
26
27
|
msgId: string;
|
|
27
28
|
}>;
|
|
28
29
|
}
|
|
29
|
-
/** The narrow slice of ReplyAliasDirectory (reply-aliases.ts) this relay needs to mint/recall the alias name for one correspondent on the mesh-to-session direction. */
|
|
30
|
+
/** The narrow slice of ReplyAliasDirectory (reply-aliases.ts) this relay needs to mint/recall the alias name for one correspondent, and record its current reply context, on the mesh-to-session direction. */
|
|
30
31
|
export interface FrontRelayAliasDirectory {
|
|
31
|
-
ensure: (correspondentId: string) => string;
|
|
32
|
+
ensure: (correspondentId: string, context: ReplyContext) => string;
|
|
32
33
|
}
|
|
33
34
|
export interface FrontedRelayRecord extends FrontedSessionRecord {
|
|
34
35
|
agentId: string;
|
|
@@ -50,7 +51,7 @@ export interface BuildFrontedSessionRecordDeps {
|
|
|
50
51
|
onError?: ((error: Error) => void) | undefined;
|
|
51
52
|
}
|
|
52
53
|
/**
|
|
53
|
-
* Wires both relay directions for one fronted session and returns the record CcPeerFront tracks it under. Mesh-to-session: store.onDelivery sends the formatted event to this session's own pid. An event with a single originating correspondent (a dm or room_message, per
|
|
54
|
+
* Wires both relay directions for one fronted session and returns the record CcPeerFront tracks it under. Mesh-to-session: store.onDelivery sends the formatted event to this session's own pid. An event with a single originating correspondent (a dm or room_message, per replyTargetForEvent) is sent from that correspondent's own reply alias, so the sender the session sees, and therefore replies to, is the correspondent rather than the front (agent-comms#284); every other event, having no one repliable behind it, is sent from the front's shared peer. Session-to-mesh: the returned handleInbound (called by the front's shared "message" listener once it's matched this record by socket path) posts the message into this session's own project room, exactly as wireCcPeerBridge's own peer.on("message") handler does for the one-shot bridge command; handleAliasReply (called once CcPeerFront has resolved an inbound alias message to its correspondent and reply context) sends a mesh DM to that correspondent when the context is a dm, or posts back into the originating room when the context is a room — a reply to a room message no longer always becomes a private DM to its sender (agent-comms#289); notifyStaleAlias delivers a clear error back into the session for a reply on an alias the directory no longer recognises. All three mesh actions report a refusal back into the session rather than discarding it, so a reply the mesh would not carry is visible where it was written.
|
|
54
55
|
*/
|
|
55
56
|
export declare function buildFrontedSessionRecord(deps: Readonly<BuildFrontedSessionRecordDeps>): FrontedRelayRecord;
|
|
56
57
|
/** Tears a fronted session's record down: marks its agent offline (a courtesy to peers watching its presence), then shuts its mesh store down. There is no identity lock to release -- attach() never took one (loadIdentityForFront's whole point), so a real bridge for this slot can already have claimed it by the time this runs. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"front-relay.d.ts","sourceRoot":"","sources":["../../../src/bridges/cc-peer/front-relay.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAe,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAW,KAAK,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,KAAK,EAAwB,SAAS,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"front-relay.d.ts","sourceRoot":"","sources":["../../../src/bridges/cc-peer/front-relay.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,EAAe,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAW,KAAK,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,KAAK,EAAwB,SAAS,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE5E,gMAAgM;AAChM,MAAM,WAAW,eAAe;IAC9B,UAAU,EACN,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,GACjE,SAAS,CAAC;IACd,eAAe,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/C,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/B;AAED,mQAAmQ;AACnQ,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,CACJ,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC,EAC3B,IAAI,EAAE,MAAM,KACT,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjC;AAED,+YAA+Y;AAC/Y,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,CACJ,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,QAAQ,CAAC,SAAS,CAAC,EAC3B,IAAI,EAAE,MAAM,KACT,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACjC;AAED,+MAA+M;AAC/M,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,CAAC,eAAe,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,KAAK,MAAM,CAAC;CACpE;AAED,MAAM,WAAW,kBAAmB,SAAQ,oBAAoB;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,eAAe,CAAC;CACxB;AAED,MAAM,WAAW,6BAA6B;IAC5C,KAAK,EAAE,QAAQ,CAAC,qBAAqB,CAAC,CAAC;IACvC,iHAAiH;IACjH,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,eAAe,CAAC;IACvB,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAChC,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,EAAE,mBAAmB,CAAC;IAC/B,cAAc,EAAE,wBAAwB,CAAC;IACzC,kRAAkR;IAClR,OAAO,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CAChD;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,QAAQ,CAAC,6BAA6B,CAAC,GAC5C,kBAAkB,CA0GpB;AAED,0UAA0U;AAC1U,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,kBAAkB,EAAE,SAAS,GAAG,OAAO,CAAC,CAAC,GAC9D,OAAO,CAAC,IAAI,CAAC,CAGf"}
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
import { buildAction } from "../../core/bridge.js";
|
|
7
7
|
import { answerJoinRequest, formatCcPeerDelivery, parseApprovalCommand, } from "./approval-commands.js";
|
|
8
8
|
import { toError } from "./front-controller.js";
|
|
9
|
-
import {
|
|
9
|
+
import { replyTargetForEvent } from "./reply-aliases.js";
|
|
10
10
|
/**
|
|
11
|
-
* Wires both relay directions for one fronted session and returns the record CcPeerFront tracks it under. Mesh-to-session: store.onDelivery sends the formatted event to this session's own pid. An event with a single originating correspondent (a dm or room_message, per
|
|
11
|
+
* Wires both relay directions for one fronted session and returns the record CcPeerFront tracks it under. Mesh-to-session: store.onDelivery sends the formatted event to this session's own pid. An event with a single originating correspondent (a dm or room_message, per replyTargetForEvent) is sent from that correspondent's own reply alias, so the sender the session sees, and therefore replies to, is the correspondent rather than the front (agent-comms#284); every other event, having no one repliable behind it, is sent from the front's shared peer. Session-to-mesh: the returned handleInbound (called by the front's shared "message" listener once it's matched this record by socket path) posts the message into this session's own project room, exactly as wireCcPeerBridge's own peer.on("message") handler does for the one-shot bridge command; handleAliasReply (called once CcPeerFront has resolved an inbound alias message to its correspondent and reply context) sends a mesh DM to that correspondent when the context is a dm, or posts back into the originating room when the context is a room — a reply to a room message no longer always becomes a private DM to its sender (agent-comms#289); notifyStaleAlias delivers a clear error back into the session for a reply on an alias the directory no longer recognises. All three mesh actions report a refusal back into the session rather than discarding it, so a reply the mesh would not carry is visible where it was written.
|
|
12
12
|
*/
|
|
13
13
|
export function buildFrontedSessionRecord(deps) {
|
|
14
14
|
const { entry, peerName, agentId, roomId, store, tool, peer, aliasPool, aliasDirectory, onError, } = deps;
|
|
@@ -28,20 +28,20 @@ export function buildFrontedSessionRecord(deps) {
|
|
|
28
28
|
};
|
|
29
29
|
store.onDelivery = async (_targetId, event) => {
|
|
30
30
|
const body = formatCcPeerDelivery(event, peerName);
|
|
31
|
-
const
|
|
32
|
-
if (
|
|
31
|
+
const target = replyTargetForEvent(event);
|
|
32
|
+
if (target === undefined) {
|
|
33
33
|
await sendToSession(body);
|
|
34
34
|
return;
|
|
35
35
|
}
|
|
36
|
-
const aliasName = aliasDirectory.ensure(correspondentId);
|
|
36
|
+
const aliasName = aliasDirectory.ensure(target.correspondentId, target.context);
|
|
37
37
|
try {
|
|
38
|
-
// Sent from the correspondent's own alias, not from the front's shared peer, so the session's native reply-to-sender lands on that alias and handleAliasReply routes it back to this correspondent. A hint naming the alias is deliberately not appended: the reply target is now the sender the session already replies to, and a model is free to ignore a hint (agent-comms#284).
|
|
38
|
+
// Sent from the correspondent's own alias, not from the front's shared peer, so the session's native reply-to-sender lands on that alias and handleAliasReply routes it back to this correspondent's dm channel, or back into the room, per the alias's own recorded context. A hint naming the alias is deliberately not appended: the reply target is now the sender the session already replies to, and a model is free to ignore a hint (agent-comms#284).
|
|
39
39
|
await aliasPool.send(aliasName, { pid: entry.pid }, body);
|
|
40
40
|
}
|
|
41
41
|
catch (error) {
|
|
42
42
|
// Re-sending from the front's shared peer with a plain body would put the session back in exactly the failure this alias delivery exists to remove: its reply would reach the front, be posted into the project room, and never arrive. Deliver the content, say plainly that a reply cannot get back, and report the failure on the front's own error channel.
|
|
43
43
|
onError?.(toError(error));
|
|
44
|
-
await sendToSession(`${body}\n(Cannot reply: ${correspondentId}'s reply peer could not be started, so a reply to this message goes to this session's project room instead.)`);
|
|
44
|
+
await sendToSession(`${body}\n(Cannot reply: ${target.correspondentId}'s reply peer could not be started, so a reply to this message goes to this session's project room instead.)`);
|
|
45
45
|
}
|
|
46
46
|
};
|
|
47
47
|
return {
|
|
@@ -66,7 +66,16 @@ export function buildFrontedSessionRecord(deps) {
|
|
|
66
66
|
});
|
|
67
67
|
void runForSession(action, `Not posted to ${roomId}`);
|
|
68
68
|
},
|
|
69
|
-
handleAliasReply: (correspondentId, message) => {
|
|
69
|
+
handleAliasReply: (correspondentId, context, message) => {
|
|
70
|
+
if (context.kind === "room") {
|
|
71
|
+
const action = buildAction({
|
|
72
|
+
action: "send",
|
|
73
|
+
room: context.room,
|
|
74
|
+
content: message.body,
|
|
75
|
+
});
|
|
76
|
+
void runForSession(action, `Reply to ${context.room} not delivered`);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
70
79
|
const action = buildAction({
|
|
71
80
|
action: "dm",
|
|
72
81
|
target: correspondentId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"front-relay.js","sourceRoot":"","sources":["../../../src/bridges/cc-peer/front-relay.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EAAE,OAAO,EAA6B,MAAM,uBAAuB,CAAC;AAG3E,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"front-relay.js","sourceRoot":"","sources":["../../../src/bridges/cc-peer/front-relay.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,22 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Lazy per-correspondent reply aliases for the default cc-peer front (agent-comms#158)
|
|
2
|
+
* Lazy per-correspondent reply aliases for the default cc-peer front (agent-comms#158) — pure alias-name derivation and the in-memory correspondent↔alias directory the front consults on both the mesh-to-session direction (materialise an alias so the session can address a reply to it) and the session-to-mesh direction (translate a reply arriving on an alias back into the correspondent it stands for and where that reply should go).
|
|
3
3
|
*
|
|
4
|
-
* Deliberately not persisted: aliases are ephemeral by design, lost on restart and re-materialised by the next inbound message from that correspondent (see the issue body's "Rejected alternatives" for why a directory of every mesh agent is not minted upfront). Kept free of any real cc-peer/AliasPool construction, exactly like front.ts's pure decision logic
|
|
4
|
+
* Deliberately not persisted: aliases are ephemeral by design, lost on restart and re-materialised by the next inbound message from that correspondent (see the issue body's "Rejected alternatives" for why a directory of every mesh agent is not minted upfront). Kept free of any real cc-peer/AliasPool construction, exactly like front.ts's pure decision logic — front-relay.ts and front-controller.ts consult this directory, and front-runtime.ts supplies the real AliasPool the alias names get materialised against.
|
|
5
5
|
*/
|
|
6
6
|
import type { DeliveryEvent } from "../../core/types.js";
|
|
7
7
|
/** Derives the cc-peer peer name a correspondent's reply alias registers under. Deterministic and side-effect-free: the same correspondent id always derives the same name, so ReplyAliasDirectory only needs to remember the mapping, not invent a fresh name per call. */
|
|
8
8
|
export declare function deriveAliasName(correspondentId: string): string;
|
|
9
|
-
/**
|
|
10
|
-
export
|
|
9
|
+
/** Where a reply arriving on a correspondent's alias should go back to: a DM straight to that correspondent, or a post back into the room the message that produced the alias was itself sent in. A room's own reply-aliased message always names the room it came from, so a reply lands in the same room rather than always falling back to a DM (agent-comms#289). */
|
|
10
|
+
export type ReplyContext = {
|
|
11
|
+
readonly kind: "dm";
|
|
12
|
+
} | {
|
|
13
|
+
readonly kind: "room";
|
|
14
|
+
readonly room: string;
|
|
15
|
+
};
|
|
16
|
+
/** The mesh correspondent and reply context a DeliveryEvent carries, for the event types with a single, repliable-to sender — undefined for every other event type (room membership/status/capability events describe something happening, not a message from one correspondent worth aliasing). */
|
|
17
|
+
export interface ReplyTarget {
|
|
18
|
+
readonly correspondentId: string;
|
|
19
|
+
readonly context: ReplyContext;
|
|
20
|
+
}
|
|
21
|
+
/** Resolves a DeliveryEvent's own reply target, or undefined when the event has no single originating correspondent. A dm event's reply target is always another dm; a room_message event's reply target is the room the message was posted in, since that is what a reply to it should return to, not the sender's own dm channel (agent-comms#289). */
|
|
22
|
+
export declare function replyTargetForEvent(event: Readonly<DeliveryEvent>): ReplyTarget | undefined;
|
|
11
23
|
/**
|
|
12
|
-
* Bounded, in-memory, bijective map between the cc-peer peer names materialised for a front's reply aliases and the mesh correspondent id each one stands for. Bounded by real correspondents, per the issue's own "Rejected alternatives": a name is only ever minted by ensure(), which the front calls solely on genuine inbound contact from that correspondent
|
|
24
|
+
* Bounded, in-memory, bijective map between the cc-peer peer names materialised for a front's reply aliases and the mesh correspondent id each one stands for, plus the reply context (dm vs. room) each alias currently carries. Bounded by real correspondents, per the issue's own "Rejected alternatives": a name is only ever minted by ensure(), which the front calls solely on genuine inbound contact from that correspondent — nothing pre-populates this directory with the wider mesh roster.
|
|
25
|
+
*
|
|
26
|
+
* A single correspondent id can reach a fronted session two different ways — a direct dm, and a message posted in a room they share with the session — and both share the same alias, since the alias scheme is keyed on the correspondent alone (agent-comms#158). ensure() therefore always records the context of the *most recent* event sent from that alias: a session's reply always continues whatever conversation it was last shown on that alias, so the context that matters is the one behind the last message it actually saw, not whichever context first minted the name.
|
|
13
27
|
*/
|
|
14
28
|
export declare class ReplyAliasDirectory {
|
|
15
29
|
private readonly nameToCorrespondent;
|
|
16
30
|
private readonly correspondentToName;
|
|
17
|
-
|
|
18
|
-
|
|
31
|
+
private readonly nameToContext;
|
|
32
|
+
/** Returns the alias name for a correspondent, deriving and recording it the first time this correspondent is seen, and records `context` as that alias's current reply target regardless of whether the alias was just minted or already existed. Idempotent on the name itself: a correspondent already known always gets back its existing name, so a session's reply target stays stable across repeated inbound contact within the same front lifetime; the context, however, is refreshed on every call. */
|
|
33
|
+
ensure(correspondentId: string, context: ReplyContext): string;
|
|
19
34
|
/** The correspondent a previously-minted alias name stands for, or undefined for a name this directory never minted (or no longer remembers, e.g. after a front restart cleared it) -- the front's own signal to treat an inbound reply as addressed to a stale alias rather than a known correspondent. */
|
|
20
35
|
correspondentFor(aliasName: string): string | undefined;
|
|
36
|
+
/** The reply context a previously-minted alias name currently carries (dm or a named room), or undefined for a name this directory never minted. Always defined whenever correspondentFor(aliasName) is, since both are set together by ensure(). */
|
|
37
|
+
contextFor(aliasName: string): ReplyContext | undefined;
|
|
21
38
|
}
|
|
22
39
|
//# sourceMappingURL=reply-aliases.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reply-aliases.d.ts","sourceRoot":"","sources":["../../../src/bridges/cc-peer/reply-aliases.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAQzD,4QAA4Q;AAC5Q,wBAAgB,eAAe,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,
|
|
1
|
+
{"version":3,"file":"reply-aliases.d.ts","sourceRoot":"","sources":["../../../src/bridges/cc-peer/reply-aliases.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAQzD,4QAA4Q;AAC5Q,wBAAgB,eAAe,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,yWAAyW;AACzW,MAAM,MAAM,YAAY,GACtB;IAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7E,oSAAoS;AACpS,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;CAChC;AAED,yVAAyV;AACzV,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,QAAQ,CAAC,aAAa,CAAC,GAC7B,WAAW,GAAG,SAAS,CAwBzB;AAED;;;;GAIG;AACH,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAA6B;IACjE,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAA6B;IACjE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAmC;IAEjE,kfAAkf;IAClf,MAAM,CAAC,eAAe,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,MAAM;IAW9D,4SAA4S;IAC5S,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIvD,qPAAqP;IACrP,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;CAGxD"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Lazy per-correspondent reply aliases for the default cc-peer front (agent-comms#158)
|
|
2
|
+
* Lazy per-correspondent reply aliases for the default cc-peer front (agent-comms#158) — pure alias-name derivation and the in-memory correspondent↔alias directory the front consults on both the mesh-to-session direction (materialise an alias so the session can address a reply to it) and the session-to-mesh direction (translate a reply arriving on an alias back into the correspondent it stands for and where that reply should go).
|
|
3
3
|
*
|
|
4
|
-
* Deliberately not persisted: aliases are ephemeral by design, lost on restart and re-materialised by the next inbound message from that correspondent (see the issue body's "Rejected alternatives" for why a directory of every mesh agent is not minted upfront). Kept free of any real cc-peer/AliasPool construction, exactly like front.ts's pure decision logic
|
|
4
|
+
* Deliberately not persisted: aliases are ephemeral by design, lost on restart and re-materialised by the next inbound message from that correspondent (see the issue body's "Rejected alternatives" for why a directory of every mesh agent is not minted upfront). Kept free of any real cc-peer/AliasPool construction, exactly like front.ts's pure decision logic — front-relay.ts and front-controller.ts consult this directory, and front-runtime.ts supplies the real AliasPool the alias names get materialised against.
|
|
5
5
|
*/
|
|
6
6
|
/** How many leading hex characters of a correspondent's device-id go into its alias name -- 48 bits of a SHA-256 hash, chosen purely for a short, readable cc-peer peer name; cc-peer's own registry name field has no length or format restriction beyond non-empty (see AliasStartCommandSchema in cc-peer's alias-ipc schema), so this is a readability choice, not a protocol requirement. */
|
|
7
7
|
const ALIAS_ID_LENGTH = 12;
|
|
@@ -11,12 +11,16 @@ const ALIAS_NAME_PREFIX = "mesh-";
|
|
|
11
11
|
export function deriveAliasName(correspondentId) {
|
|
12
12
|
return `${ALIAS_NAME_PREFIX}${correspondentId.slice(0, ALIAS_ID_LENGTH)}`;
|
|
13
13
|
}
|
|
14
|
-
/**
|
|
15
|
-
export function
|
|
14
|
+
/** Resolves a DeliveryEvent's own reply target, or undefined when the event has no single originating correspondent. A dm event's reply target is always another dm; a room_message event's reply target is the room the message was posted in, since that is what a reply to it should return to, not the sender's own dm channel (agent-comms#289). */
|
|
15
|
+
export function replyTargetForEvent(event) {
|
|
16
16
|
switch (event.type) {
|
|
17
17
|
case "dm":
|
|
18
|
+
return { correspondentId: event.message.from, context: { kind: "dm" } };
|
|
18
19
|
case "room_message":
|
|
19
|
-
return
|
|
20
|
+
return {
|
|
21
|
+
correspondentId: event.message.from,
|
|
22
|
+
context: { kind: "room", room: event.message.room },
|
|
23
|
+
};
|
|
20
24
|
case "room_invite":
|
|
21
25
|
case "member_joined":
|
|
22
26
|
case "member_left":
|
|
@@ -34,24 +38,32 @@ export function correspondentForEvent(event) {
|
|
|
34
38
|
}
|
|
35
39
|
}
|
|
36
40
|
/**
|
|
37
|
-
* Bounded, in-memory, bijective map between the cc-peer peer names materialised for a front's reply aliases and the mesh correspondent id each one stands for. Bounded by real correspondents, per the issue's own "Rejected alternatives": a name is only ever minted by ensure(), which the front calls solely on genuine inbound contact from that correspondent
|
|
41
|
+
* Bounded, in-memory, bijective map between the cc-peer peer names materialised for a front's reply aliases and the mesh correspondent id each one stands for, plus the reply context (dm vs. room) each alias currently carries. Bounded by real correspondents, per the issue's own "Rejected alternatives": a name is only ever minted by ensure(), which the front calls solely on genuine inbound contact from that correspondent — nothing pre-populates this directory with the wider mesh roster.
|
|
42
|
+
*
|
|
43
|
+
* A single correspondent id can reach a fronted session two different ways — a direct dm, and a message posted in a room they share with the session — and both share the same alias, since the alias scheme is keyed on the correspondent alone (agent-comms#158). ensure() therefore always records the context of the *most recent* event sent from that alias: a session's reply always continues whatever conversation it was last shown on that alias, so the context that matters is the one behind the last message it actually saw, not whichever context first minted the name.
|
|
38
44
|
*/
|
|
39
45
|
export class ReplyAliasDirectory {
|
|
40
46
|
nameToCorrespondent = new Map();
|
|
41
47
|
correspondentToName = new Map();
|
|
42
|
-
|
|
43
|
-
|
|
48
|
+
nameToContext = new Map();
|
|
49
|
+
/** Returns the alias name for a correspondent, deriving and recording it the first time this correspondent is seen, and records `context` as that alias's current reply target regardless of whether the alias was just minted or already existed. Idempotent on the name itself: a correspondent already known always gets back its existing name, so a session's reply target stays stable across repeated inbound contact within the same front lifetime; the context, however, is refreshed on every call. */
|
|
50
|
+
ensure(correspondentId, context) {
|
|
44
51
|
const existing = this.correspondentToName.get(correspondentId);
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
52
|
+
const name = existing ?? deriveAliasName(correspondentId);
|
|
53
|
+
if (existing === undefined) {
|
|
54
|
+
this.correspondentToName.set(correspondentId, name);
|
|
55
|
+
this.nameToCorrespondent.set(name, correspondentId);
|
|
56
|
+
}
|
|
57
|
+
this.nameToContext.set(name, context);
|
|
50
58
|
return name;
|
|
51
59
|
}
|
|
52
60
|
/** The correspondent a previously-minted alias name stands for, or undefined for a name this directory never minted (or no longer remembers, e.g. after a front restart cleared it) -- the front's own signal to treat an inbound reply as addressed to a stale alias rather than a known correspondent. */
|
|
53
61
|
correspondentFor(aliasName) {
|
|
54
62
|
return this.nameToCorrespondent.get(aliasName);
|
|
55
63
|
}
|
|
64
|
+
/** The reply context a previously-minted alias name currently carries (dm or a named room), or undefined for a name this directory never minted. Always defined whenever correspondentFor(aliasName) is, since both are set together by ensure(). */
|
|
65
|
+
contextFor(aliasName) {
|
|
66
|
+
return this.nameToContext.get(aliasName);
|
|
67
|
+
}
|
|
56
68
|
}
|
|
57
69
|
//# sourceMappingURL=reply-aliases.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reply-aliases.js","sourceRoot":"","sources":["../../../src/bridges/cc-peer/reply-aliases.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,kYAAkY;AAClY,MAAM,eAAe,GAAG,EAAE,CAAC;AAE3B,+OAA+O;AAC/O,MAAM,iBAAiB,GAAG,OAAO,CAAC;AAElC,4QAA4Q;AAC5Q,MAAM,UAAU,eAAe,CAAC,eAAuB;IACrD,OAAO,GAAG,iBAAiB,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC,EAAE,CAAC;AAC5E,CAAC;
|
|
1
|
+
{"version":3,"file":"reply-aliases.js","sourceRoot":"","sources":["../../../src/bridges/cc-peer/reply-aliases.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,kYAAkY;AAClY,MAAM,eAAe,GAAG,EAAE,CAAC;AAE3B,+OAA+O;AAC/O,MAAM,iBAAiB,GAAG,OAAO,CAAC;AAElC,4QAA4Q;AAC5Q,MAAM,UAAU,eAAe,CAAC,eAAuB;IACrD,OAAO,GAAG,iBAAiB,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC,EAAE,CAAC;AAC5E,CAAC;AAYD,yVAAyV;AACzV,MAAM,UAAU,mBAAmB,CACjC,KAA8B;IAE9B,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,IAAI;YACP,OAAO,EAAE,eAAe,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC;QAC1E,KAAK,cAAc;YACjB,OAAO;gBACL,eAAe,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI;gBACnC,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE;aACpD,CAAC;QACJ,KAAK,aAAa,CAAC;QACnB,KAAK,eAAe,CAAC;QACrB,KAAK,aAAa,CAAC;QACnB,KAAK,cAAc,CAAC;QACpB,KAAK,eAAe,CAAC;QACrB,KAAK,iBAAiB,CAAC;QACvB,KAAK,iBAAiB,CAAC;QACvB,KAAK,cAAc,CAAC;QACpB,KAAK,oBAAoB,CAAC;QAC1B,KAAK,oBAAoB,CAAC;QAC1B,KAAK,mBAAmB;YACtB,OAAO,SAAS,CAAC;QACnB;YACE,OAAO,KAAqB,CAAC;IACjC,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,OAAO,mBAAmB;IACb,mBAAmB,GAAG,IAAI,GAAG,EAAkB,CAAC;IAChD,mBAAmB,GAAG,IAAI,GAAG,EAAkB,CAAC;IAChD,aAAa,GAAG,IAAI,GAAG,EAAwB,CAAC;IAEjE,kfAAkf;IAClf,MAAM,CAAC,eAAuB,EAAE,OAAqB;QACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QAC/D,MAAM,IAAI,GAAG,QAAQ,IAAI,eAAe,CAAC,eAAe,CAAC,CAAC;QAC1D,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;YACpD,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACtC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,4SAA4S;IAC5S,gBAAgB,CAAC,SAAiB;QAChC,OAAO,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACjD,CAAC;IAED,qPAAqP;IACrP,UAAU,CAAC,SAAiB;QAC1B,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC3C,CAAC;CACF"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration coverage for the fronted cc-peer session's own reply-alias routing (agent-comms#289): a real MeshStore/CommsTool pair fronted by buildFrontedSessionRecord, wired to a real ReplyAliasDirectory rather than a stub, proving a reply to a room message posts back into the room it came from — not a DM to its sender — while a reply to a genuine DM still becomes a DM. Both paths share the same per-correspondent alias (reply-aliases.ts), so both need real coverage, not just the one that was broken.
|
|
3
|
+
*/
|
|
4
|
+
export {};
|
|
5
|
+
//# sourceMappingURL=cc-peer-alias-reply-routing.integration.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cc-peer-alias-reply-routing.integration.test.d.ts","sourceRoot":"","sources":["../../src/test/cc-peer-alias-reply-routing.integration.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration coverage for the fronted cc-peer session's own reply-alias routing (agent-comms#289): a real MeshStore/CommsTool pair fronted by buildFrontedSessionRecord, wired to a real ReplyAliasDirectory rather than a stub, proving a reply to a room message posts back into the room it came from — not a DM to its sender — while a reply to a genuine DM still becomes a DM. Both paths share the same per-correspondent alias (reply-aliases.ts), so both need real coverage, not just the one that was broken.
|
|
3
|
+
*/
|
|
4
|
+
import { test, expect } from "vitest";
|
|
5
|
+
import { MeshStore } from "../core/mesh-store.js";
|
|
6
|
+
import { CommsTool } from "../core/tool.js";
|
|
7
|
+
import { buildFrontedSessionRecord } from "../bridges/cc-peer/front-relay.js";
|
|
8
|
+
import { ReplyAliasDirectory } from "../bridges/cc-peer/reply-aliases.js";
|
|
9
|
+
import { waitFor, wireTestTransport } from "./test-transport.js";
|
|
10
|
+
let nextPort = 27_500;
|
|
11
|
+
function freshPort() {
|
|
12
|
+
nextPort += 1;
|
|
13
|
+
return nextPort;
|
|
14
|
+
}
|
|
15
|
+
const PEER_NAME = "agent-comms-front";
|
|
16
|
+
const SESSION_PID = 4343;
|
|
17
|
+
async function registered(port, name) {
|
|
18
|
+
const store = new MeshStore({ coordinatorPort: port });
|
|
19
|
+
await wireTestTransport(store);
|
|
20
|
+
await store.init();
|
|
21
|
+
await store.registerAgent({
|
|
22
|
+
name,
|
|
23
|
+
harness: "test",
|
|
24
|
+
cwd: `/test/${name}`,
|
|
25
|
+
pid: process.pid,
|
|
26
|
+
visibility: "visible",
|
|
27
|
+
tags: [],
|
|
28
|
+
});
|
|
29
|
+
return store;
|
|
30
|
+
}
|
|
31
|
+
/** Builds a fronted session record for `fronted`, backed by a real ReplyAliasDirectory, with a fake cc-peer peer/alias pool standing in for the session's own process — the same DI seam cc-peer-front-relay.unit.test.ts and cc-peer-fronted-approval.integration.test.ts already use, just with the real alias-context bookkeeping this test exists to exercise. */
|
|
32
|
+
function frontFor(fronted, cwd) {
|
|
33
|
+
const toSession = [];
|
|
34
|
+
const toSessionFromAlias = [];
|
|
35
|
+
const aliasDirectory = new ReplyAliasDirectory();
|
|
36
|
+
const record = buildFrontedSessionRecord({
|
|
37
|
+
entry: {
|
|
38
|
+
pid: SESSION_PID,
|
|
39
|
+
cwd,
|
|
40
|
+
version: "2.1.278",
|
|
41
|
+
messagingSocketPath: "/tmp/cc-socks/fronted.sock",
|
|
42
|
+
},
|
|
43
|
+
peerName: PEER_NAME,
|
|
44
|
+
agentId: fronted.peerId,
|
|
45
|
+
roomId: "unused",
|
|
46
|
+
store: fronted,
|
|
47
|
+
tool: new CommsTool(fronted),
|
|
48
|
+
peer: {
|
|
49
|
+
send: async (_target, body) => {
|
|
50
|
+
toSession.push(body);
|
|
51
|
+
return Promise.resolve({ msgId: "m" });
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
aliasPool: {
|
|
55
|
+
send: async (alias, _target, body) => {
|
|
56
|
+
toSessionFromAlias.push({ alias, body });
|
|
57
|
+
return Promise.resolve({ msgId: "m" });
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
aliasDirectory,
|
|
61
|
+
});
|
|
62
|
+
return { toSession, toSessionFromAlias, aliasDirectory, record };
|
|
63
|
+
}
|
|
64
|
+
test("a fronted session's reply to a room message posts back into that room, not a DM to its sender (agent-comms#289)", async () => {
|
|
65
|
+
const port = freshPort();
|
|
66
|
+
const sender = await registered(port, "room-sender");
|
|
67
|
+
const fronted = await registered(port, "room-fronted");
|
|
68
|
+
await waitFor(() => sender.serialise().agents[fronted.peerId] !== undefined, "the sender sees the fronted agent");
|
|
69
|
+
const room = await fronted.createRoom({
|
|
70
|
+
name: "shared-room",
|
|
71
|
+
type: "public",
|
|
72
|
+
owner: fronted.peerId,
|
|
73
|
+
description: "",
|
|
74
|
+
});
|
|
75
|
+
const joinPromise = sender.joinRoom(room.id, sender.peerId);
|
|
76
|
+
await waitFor(() => fronted
|
|
77
|
+
.listPendingRoomJoins()
|
|
78
|
+
.some((p) => p.roomPath === room.id && p.requesterId === sender.peerId), "the fronted agent to see the sender's pending join request");
|
|
79
|
+
fronted.acceptRoomJoin(room.id, sender.peerId);
|
|
80
|
+
await joinPromise;
|
|
81
|
+
const { toSessionFromAlias, aliasDirectory, record } = frontFor(fronted, "/test/room-fronted");
|
|
82
|
+
const senderDeliveries = [];
|
|
83
|
+
sender.onDelivery = (_agentId, event) => {
|
|
84
|
+
senderDeliveries.push(event);
|
|
85
|
+
};
|
|
86
|
+
await sender.sendRoomMessage(room.id, sender.peerId, "hello from the room");
|
|
87
|
+
await waitFor(() => toSessionFromAlias.length > 0, "the room message arrives at the fronted session from an alias");
|
|
88
|
+
const delivered = toSessionFromAlias[0];
|
|
89
|
+
if (delivered === undefined)
|
|
90
|
+
throw new Error("expected an alias delivery");
|
|
91
|
+
expect(delivered.body).toContain("hello from the room");
|
|
92
|
+
// Resolve the alias exactly as CcPeerFront.handleAliasMessage does: the correspondent and reply context the real directory recorded when this alias was minted/used, not a value this test invents.
|
|
93
|
+
const correspondentId = aliasDirectory.correspondentFor(delivered.alias);
|
|
94
|
+
const context = aliasDirectory.contextFor(delivered.alias);
|
|
95
|
+
if (correspondentId === undefined || context === undefined) {
|
|
96
|
+
throw new Error("expected the alias to resolve to a correspondent and context");
|
|
97
|
+
}
|
|
98
|
+
expect(context).toEqual({ kind: "room", room: room.id });
|
|
99
|
+
senderDeliveries.length = 0;
|
|
100
|
+
record.handleAliasReply(correspondentId, context, {
|
|
101
|
+
body: "reply from the fronted session",
|
|
102
|
+
});
|
|
103
|
+
await waitFor(() => senderDeliveries.some((event) => event.type === "room_message" &&
|
|
104
|
+
event.message.content === "reply from the fronted session"), "the sender receives the reply as a room message");
|
|
105
|
+
// Never delivered as a DM instead.
|
|
106
|
+
expect(senderDeliveries.some((event) => event.type === "dm")).toBe(false);
|
|
107
|
+
await fronted.shutdown();
|
|
108
|
+
await sender.shutdown();
|
|
109
|
+
});
|
|
110
|
+
test("a fronted session's reply to a genuine DM still becomes a DM, through the same alias mechanism (agent-comms#289)", async () => {
|
|
111
|
+
const port = freshPort();
|
|
112
|
+
const sender = await registered(port, "dm-sender");
|
|
113
|
+
const fronted = await registered(port, "dm-fronted");
|
|
114
|
+
await waitFor(() => sender.serialise().agents[fronted.peerId] !== undefined, "the sender sees the fronted agent");
|
|
115
|
+
const { toSession, toSessionFromAlias, aliasDirectory, record } = frontFor(fronted, "/test/dm-fronted");
|
|
116
|
+
const dmAccessPromise = sender.requestDmAccess(fronted.peerId);
|
|
117
|
+
await waitFor(() => toSession.some((body) => body.includes("accept ")), "the fronted session is told a dm request is waiting");
|
|
118
|
+
const instruction = toSession.find((body) => body.includes("accept "));
|
|
119
|
+
const command = instruction
|
|
120
|
+
?.split("\n")
|
|
121
|
+
.find((line) => line.startsWith("accept "));
|
|
122
|
+
if (command === undefined)
|
|
123
|
+
throw new Error("expected an accept command");
|
|
124
|
+
record.handleInbound({
|
|
125
|
+
from: `uds:${record.messagingSocketPath}`,
|
|
126
|
+
body: command,
|
|
127
|
+
});
|
|
128
|
+
await dmAccessPromise;
|
|
129
|
+
const senderDeliveries = [];
|
|
130
|
+
sender.onDelivery = (_agentId, event) => {
|
|
131
|
+
senderDeliveries.push(event);
|
|
132
|
+
};
|
|
133
|
+
await sender.sendDm(sender.peerId, fronted.peerId, "hello session");
|
|
134
|
+
await waitFor(() => toSessionFromAlias.length > 0, "the dm arrives at the fronted session from an alias");
|
|
135
|
+
const delivered = toSessionFromAlias[0];
|
|
136
|
+
if (delivered === undefined)
|
|
137
|
+
throw new Error("expected an alias delivery");
|
|
138
|
+
expect(delivered.body).toContain("hello session");
|
|
139
|
+
const correspondentId = aliasDirectory.correspondentFor(delivered.alias);
|
|
140
|
+
const context = aliasDirectory.contextFor(delivered.alias);
|
|
141
|
+
if (correspondentId === undefined || context === undefined) {
|
|
142
|
+
throw new Error("expected the alias to resolve to a correspondent and context");
|
|
143
|
+
}
|
|
144
|
+
expect(context).toEqual({ kind: "dm" });
|
|
145
|
+
expect(correspondentId).toBe(sender.peerId);
|
|
146
|
+
record.handleAliasReply(correspondentId, context, {
|
|
147
|
+
body: "reply as a real dm",
|
|
148
|
+
});
|
|
149
|
+
await waitFor(() => senderDeliveries.some((event) => event.type === "dm" && event.message.content === "reply as a real dm"), "the sender receives the reply as a dm");
|
|
150
|
+
await fronted.shutdown();
|
|
151
|
+
await sender.shutdown();
|
|
152
|
+
});
|
|
153
|
+
//# sourceMappingURL=cc-peer-alias-reply-routing.integration.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cc-peer-alias-reply-routing.integration.test.js","sourceRoot":"","sources":["../../src/test/cc-peer-alias-reply-routing.integration.test.ts"],"names":[],"mappings":"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"}
|