@masons/agent-network 0.4.17 → 0.4.19

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.
@@ -1 +1 @@
1
- {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAsB9D,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,UAAU,oBAAoB,CAAC,CAAC;IAC9B,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EAAE,CAAC;IACvD,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC;IACpE,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;IACjE,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;CAC/D;AAED,UAAU,sBAAsB;IAC9B,EAAE,EAAE,OAAO,CAAC;CACb;AAED,UAAU,sBAAsB;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,sBAAsB;IAC9B,YAAY,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC9C,QAAQ,CAAC,CAAC,GAAG,EAAE,sBAAsB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;CACzE;AAED,UAAU,qBAAqB,CAAC,CAAC,GAAG,OAAO;IACzC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,WAAW,CAAC;CAC1B;AAsDD,UAAU,qBAAqB,CAAC,CAAC,GAAG,OAAO;IACzC,YAAY,CAAC,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/D,WAAW,CAAC,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5D;AAED,UAAU,yBAAyB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,WAAW,CAAC;IAClB,YAAY,EAAE,mBAAmB,CAAC;IAClC,MAAM,EAAE,oBAAoB,CAAC,mBAAmB,CAAC,CAAC;IAClD,QAAQ,EAAE,sBAAsB,CAAC;IACjC,OAAO,EAAE,qBAAqB,CAAC,mBAAmB,CAAC,CAAC;CACrD;AA+ND,eAAO,MAAM,mBAAmB,EAAE,yBAoNjC,CAAC"}
1
+ {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAuB9D,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,UAAU,oBAAoB,CAAC,CAAC;IAC9B,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EAAE,CAAC;IACvD,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC;IACpE,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;IACjE,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC;CAC/D;AAED,UAAU,sBAAsB;IAC9B,EAAE,EAAE,OAAO,CAAC;CACb;AAED,UAAU,sBAAsB;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,sBAAsB;IAC9B,YAAY,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC9C,QAAQ,CAAC,CAAC,GAAG,EAAE,sBAAsB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;CACzE;AAED,UAAU,qBAAqB,CAAC,CAAC,GAAG,OAAO;IACzC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,CAAC,CAAC;IACX,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,WAAW,CAAC;CAC1B;AAsDD,UAAU,qBAAqB,CAAC,CAAC,GAAG,OAAO;IACzC,YAAY,CAAC,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/D,WAAW,CAAC,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5D;AAED,UAAU,yBAAyB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,WAAW,CAAC;IAClB,YAAY,EAAE,mBAAmB,CAAC;IAClC,MAAM,EAAE,oBAAoB,CAAC,mBAAmB,CAAC,CAAC;IAClD,QAAQ,EAAE,sBAAsB,CAAC;IACjC,OAAO,EAAE,qBAAqB,CAAC,mBAAmB,CAAC,CAAC;CACrD;AA+ND,eAAO,MAAM,mBAAmB,EAAE,yBAqNjC,CAAC"}
package/dist/channel.js CHANGED
@@ -3,6 +3,7 @@ import createDebug from "debug";
3
3
  import { clearConnectorClient, clearConversationManager, extractNetworkConfig, initConnectorClient, initConversationManager, initToolConfig, requirePluginRuntime, } from "./config.js";
4
4
  import { ConnectorClient } from "./connector-client.js";
5
5
  import { ConversationManager } from "./conversation-manager.js";
6
+ import { clearEnvironmentContext } from "./environment-context.js";
6
7
  import { extractHandleFromAddress } from "./handle-utils.js";
7
8
  import { clearOwnerState, isOwnerAddress, markOwnerAddress, setCurrentTurnIsOwner, } from "./owner-session-state.js";
8
9
  import { setCurrentTurnSender } from "./turn-context.js";
@@ -283,9 +284,10 @@ export const agentNetworkChannel = {
283
284
  dbg("delivery_pending → ACK sent count=%d upTo=%s", event.count, event.upTo);
284
285
  });
285
286
  // --- Disconnect ---
286
- // On disconnect, all owner addresses are invalid — clear owner state.
287
+ // On disconnect, all session state is invalid — clear owner + environment.
287
288
  client.on("disconnected", () => {
288
289
  clearOwnerState();
290
+ clearEnvironmentContext();
289
291
  });
290
292
  // --- Error handling ---
291
293
  // Must register before connect() — unhandled "error" events crash the process.
package/dist/config.d.ts CHANGED
@@ -38,6 +38,15 @@ export declare function extractNetworkConfig(cfg: Record<string, unknown>): Reco
38
38
  * Ensures tools always read the Host's current config values.
39
39
  */
40
40
  export declare function initToolConfig(cfg: Record<string, unknown>): void;
41
+ /** Whether session.identityLinks has an agent-network entry. */
42
+ export declare function isIdentityLinksConfigured(): boolean;
43
+ /**
44
+ * Mark the identity link hint as shown for this session.
45
+ * Prevents repeated injection on every owner turn.
46
+ */
47
+ export declare function markIdentityLinkHintShown(): void;
48
+ /** Whether the identity link hint has been shown this session. */
49
+ export declare function isIdentityLinkHintShown(): boolean;
41
50
  /**
42
51
  * Inject the live ConnectorClient after WebSocket connection is established.
43
52
  *
@@ -183,6 +192,20 @@ export declare function markProfileNeeded(): Promise<void>;
183
192
  * (connection request / accept) take effect immediately without a restart.
184
193
  */
185
194
  export declare function markProfileComplete(): Promise<void>;
195
+ /**
196
+ * Write cross-channel identity links to `config.session.identityLinks`.
197
+ *
198
+ * Merges a new canonical identity group into the existing identityLinks
199
+ * map. Never overwrites other canonical groups.
200
+ *
201
+ * This writes to `session.*` (Gateway-level), not `channels.agent-network.*`.
202
+ * Justified because cross-channel identity is inherently a Gateway concern,
203
+ * and the Gateway provides the full config to plugins via `ctx.cfg`.
204
+ *
205
+ * Follows the same readConfig → merge → persistConfig pattern as
206
+ * writeCredentials() and writeTargetHandle().
207
+ */
208
+ export declare function writeIdentityLinks(canonical: string, entries: string[]): Promise<void>;
186
209
  /** Pending state detected from config file — used for restart continuity. */
187
210
  export interface PendingState {
188
211
  /** Whether valid credentials exist (connectorUrl + token) */
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,sBAAsB,CAAC;AAuB9B;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,CAEhD;AAcD;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC3B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAMhC;AAMD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAwBjE;AAMD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAOjE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AAMD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAE1E;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C;AAED;;GAEG;AACH,wBAAgB,0BAA0B,IAAI,mBAAmB,CAOhE;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,IAAI,mBAAmB,GAAG,IAAI,CAEnE;AAMD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAExD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAO9C;AAMD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,IAAI,oBAAoB,CAE5D;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAKtC;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAEhD;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,IAAI,eAAe,CAOxD;AAMD,+EAA+E;AAC/E,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAgDD,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,kBAAkB,EACzB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CA4Bf;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMrE;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CASvD;AAMD;;;;;GAKG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAOvD;AAED;;;;;;;GAOG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAOzD;AAMD,6EAA6E;AAC7E,MAAM,WAAW,YAAY;IAC3B,6DAA6D;IAC7D,cAAc,EAAE,OAAO,CAAC;IACxB,wDAAwD;IACxD,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,4EAA4E;IAC5E,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,YAAY,CAAC,CA2BhE;AAMD,uDAAuD;AACvD,wBAAgB,gBAAgB,IAAI,IAAI,CASvC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
package/dist/config.js CHANGED
@@ -31,6 +31,9 @@ let platformConfig = { apiHost: DEFAULT_API_HOST };
31
31
  let storedApiKey = null;
32
32
  let storedPendingTarget = null;
33
33
  let storedNeedsProfile = false;
34
+ // Cross-channel identity state (from cfg.session — set by initToolConfig)
35
+ let storedIdentityLinksConfigured = false;
36
+ let identityLinkHintShown = false;
34
37
  // State cache generation — incremented when config-modifying functions write
35
38
  // to disk (writeCredentials, clearTargetHandle, markProfileNeeded, markProfileComplete).
36
39
  // before_prompt_build compares its cached generation to this value; mismatch
@@ -95,6 +98,54 @@ export function initToolConfig(cfg) {
95
98
  ? networkCfg.pendingTarget
96
99
  : null;
97
100
  storedNeedsProfile = networkCfg?.needsProfile === true;
101
+ // --- Cross-channel identity state (cfg.session, not cfg.channels) ---
102
+ // Read Gateway-level session.identityLinks to detect if the owner's
103
+ // agent-network identity is linked to other channels. Used by
104
+ // before_prompt_build to inject a one-time configuration hint.
105
+ storedIdentityLinksConfigured = hasAgentNetworkIdentityLink(cfg);
106
+ identityLinkHintShown = false; // Reset on startup / hot-reload
107
+ }
108
+ // ---------------------------------------------------------------------------
109
+ // Cross-channel identity detection
110
+ // ---------------------------------------------------------------------------
111
+ /**
112
+ * Check if any `session.identityLinks` entry includes an agent-network peerId.
113
+ *
114
+ * Scans all canonical identity groups for entries containing
115
+ * `"agent-network:"` prefix, which indicates the owner's agent-network
116
+ * identity has been linked to another channel.
117
+ *
118
+ * Reads `cfg.session.identityLinks` — this is Gateway-level config,
119
+ * not channel-level. Legitimate because Gateway passes the full config
120
+ * via `ctx.cfg` to `startAccount()`.
121
+ */
122
+ function hasAgentNetworkIdentityLink(cfg) {
123
+ const session = cfg.session;
124
+ const links = session?.identityLinks;
125
+ if (!links)
126
+ return false;
127
+ for (const entries of Object.values(links)) {
128
+ if (Array.isArray(entries) &&
129
+ entries.some((e) => typeof e === "string" && e.startsWith("agent-network:"))) {
130
+ return true;
131
+ }
132
+ }
133
+ return false;
134
+ }
135
+ /** Whether session.identityLinks has an agent-network entry. */
136
+ export function isIdentityLinksConfigured() {
137
+ return storedIdentityLinksConfigured;
138
+ }
139
+ /**
140
+ * Mark the identity link hint as shown for this session.
141
+ * Prevents repeated injection on every owner turn.
142
+ */
143
+ export function markIdentityLinkHintShown() {
144
+ identityLinkHintShown = true;
145
+ }
146
+ /** Whether the identity link hint has been shown this session. */
147
+ export function isIdentityLinkHintShown() {
148
+ return identityLinkHintShown;
98
149
  }
99
150
  // ---------------------------------------------------------------------------
100
151
  // ConnectorClient injection (called by startAccount() after connect)
@@ -385,6 +436,49 @@ export async function markProfileComplete() {
385
436
  storedNeedsProfile = false;
386
437
  stateCacheGeneration++;
387
438
  }
439
+ // ---------------------------------------------------------------------------
440
+ // Cross-channel identity link write (writes to config.session, not config.channels)
441
+ // ---------------------------------------------------------------------------
442
+ /**
443
+ * Get or create the top-level `session` section in config.
444
+ *
445
+ * Unlike `ensureNetworkSection()` which targets `channels.agent-network`,
446
+ * this targets `config.session` — a Gateway-level config section.
447
+ * Used only by `writeIdentityLinks()`.
448
+ */
449
+ function ensureSessionSection(config) {
450
+ if (typeof config.session !== "object" || config.session === null) {
451
+ config.session = {};
452
+ }
453
+ return config.session;
454
+ }
455
+ /**
456
+ * Write cross-channel identity links to `config.session.identityLinks`.
457
+ *
458
+ * Merges a new canonical identity group into the existing identityLinks
459
+ * map. Never overwrites other canonical groups.
460
+ *
461
+ * This writes to `session.*` (Gateway-level), not `channels.agent-network.*`.
462
+ * Justified because cross-channel identity is inherently a Gateway concern,
463
+ * and the Gateway provides the full config to plugins via `ctx.cfg`.
464
+ *
465
+ * Follows the same readConfig → merge → persistConfig pattern as
466
+ * writeCredentials() and writeTargetHandle().
467
+ */
468
+ export async function writeIdentityLinks(canonical, entries) {
469
+ const config = await readConfig();
470
+ const session = ensureSessionSection(config);
471
+ // Merge into existing identityLinks (never overwrite other groups)
472
+ const existing = typeof session.identityLinks === "object" && session.identityLinks !== null
473
+ ? session.identityLinks
474
+ : {};
475
+ existing[canonical] = entries;
476
+ session.identityLinks = existing;
477
+ await persistConfig(config);
478
+ // Update module-level state — same exception pattern as writeCredentials
479
+ storedIdentityLinksConfigured = true;
480
+ stateCacheGeneration++;
481
+ }
388
482
  /**
389
483
  * Detect pending state by reading config file directly.
390
484
  *
@@ -420,6 +514,8 @@ export function _resetForTesting() {
420
514
  storedApiKey = null;
421
515
  storedPendingTarget = null;
422
516
  storedNeedsProfile = false;
517
+ storedIdentityLinksConfigured = false;
518
+ identityLinkHintShown = false;
423
519
  storedConnectorClient = null;
424
520
  storedConversationManager = null;
425
521
  storedPluginRuntime = null;
@@ -1 +1 @@
1
- {"version":3,"file":"connector-client.d.ts","sourceRoot":"","sources":["../src/connector-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"connector-client.d.ts","sourceRoot":"","sources":["../src/connector-client.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@ import { randomUUID } from "node:crypto";
2
2
  import { EventEmitter } from "node:events";
3
3
  import createDebug from "debug";
4
4
  import WebSocket from "ws";
5
+ import { setEnvironmentContext } from "./environment-context.js";
5
6
  import { CURRENT_PROTOCOL_VERSION, isAddressedMessage, isDeliveryPending, isRegisterAck, isSendAck, isStructuredError, REGISTER_ACK_TIMEOUT_MS, SEND_ACK_TIMEOUT_MS, } from "./types.js";
6
7
  import { PLUGIN_VERSION } from "./version.js";
7
8
  const dbg = createDebug("agent-network:connector");
@@ -231,6 +232,9 @@ export class ConnectorClient extends EventEmitter {
231
232
  if (ack.protocolVersion !== CURRENT_PROTOCOL_VERSION) {
232
233
  dbg("WARN: server negotiated protocolVersion=%d, expected=%d", ack.protocolVersion, CURRENT_PROTOCOL_VERSION);
233
234
  }
235
+ // Store agent + owner identity from enriched REGISTER_ACK (#969).
236
+ // Old Connectors omit these fields — setEnvironmentContext handles undefined.
237
+ setEnvironmentContext(ack.agent, ack.owner);
234
238
  this.backoffMs = BACKOFF_INITIAL_MS;
235
239
  this.alreadyConnectedRetries = 0;
236
240
  this.resolveRegister();
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Agent Environment Context — self-identity and owner identity.
3
+ *
4
+ * Populated from REGISTER_ACK when the Connector includes agent/owner fields
5
+ * (#969). Connection-scoped: cleared on disconnect, refreshed on reconnect.
6
+ *
7
+ * Module-level singleton — shared between connector-client.ts (write) and
8
+ * plugin.ts (read). Follows the same pattern as owner-session-state.ts.
9
+ *
10
+ * **Trust model**: Identity is Connector-asserted, not cryptographically
11
+ * verified. The Plugin trusts the Connector because they communicate over an
12
+ * authenticated WebSocket channel. A self-hosted Connector could assert
13
+ * arbitrary identity — this is the same trust level as the `from` field on
14
+ * MESSAGE_RECEIVED. Do not build security-critical logic on these values.
15
+ */
16
+ export interface AgentIdentity {
17
+ handle: string;
18
+ name?: string;
19
+ }
20
+ export interface OwnerIdentity {
21
+ handle: string;
22
+ displayName?: string;
23
+ }
24
+ /**
25
+ * Store agent and owner identity from an enriched REGISTER_ACK.
26
+ *
27
+ * Either parameter may be undefined (old Connector, or agent without
28
+ * a bound owner). Undefined values leave the corresponding state as null.
29
+ */
30
+ export declare function setEnvironmentContext(agent?: {
31
+ handle: string;
32
+ name?: string;
33
+ }, owner?: {
34
+ handle: string;
35
+ displayName?: string;
36
+ }): void;
37
+ export declare function getAgentIdentity(): AgentIdentity | null;
38
+ export declare function getOwnerIdentity(): OwnerIdentity | null;
39
+ /** Convenience: get the owner's handle for interaction tagging. */
40
+ export declare function getOwnerHandle(): string | null;
41
+ /** Clear all environment context (connection lost — identity invalid). */
42
+ export declare function clearEnvironmentContext(): void;
43
+ /** @internal Reset module state for test isolation. */
44
+ export declare function _resetForTesting(): void;
45
+ //# sourceMappingURL=environment-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environment-context.d.ts","sourceRoot":"","sources":["../src/environment-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAMH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAaD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,CAAC,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EACzC,KAAK,CAAC,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/C,IAAI,CAkBN;AAMD,wBAAgB,gBAAgB,IAAI,aAAa,GAAG,IAAI,CAEvD;AAED,wBAAgB,gBAAgB,IAAI,aAAa,GAAG,IAAI,CAEvD;AAED,mEAAmE;AACnE,wBAAgB,cAAc,IAAI,MAAM,GAAG,IAAI,CAE9C;AAMD,0EAA0E;AAC1E,wBAAgB,uBAAuB,IAAI,IAAI,CAG9C;AAMD,uDAAuD;AACvD,wBAAgB,gBAAgB,IAAI,IAAI,CAGvC"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Agent Environment Context — self-identity and owner identity.
3
+ *
4
+ * Populated from REGISTER_ACK when the Connector includes agent/owner fields
5
+ * (#969). Connection-scoped: cleared on disconnect, refreshed on reconnect.
6
+ *
7
+ * Module-level singleton — shared between connector-client.ts (write) and
8
+ * plugin.ts (read). Follows the same pattern as owner-session-state.ts.
9
+ *
10
+ * **Trust model**: Identity is Connector-asserted, not cryptographically
11
+ * verified. The Plugin trusts the Connector because they communicate over an
12
+ * authenticated WebSocket channel. A self-hosted Connector could assert
13
+ * arbitrary identity — this is the same trust level as the `from` field on
14
+ * MESSAGE_RECEIVED. Do not build security-critical logic on these values.
15
+ */
16
+ // ---------------------------------------------------------------------------
17
+ // State
18
+ // ---------------------------------------------------------------------------
19
+ let agentIdentity = null;
20
+ let ownerIdentity = null;
21
+ // ---------------------------------------------------------------------------
22
+ // Write API (called from connector-client.ts on REGISTER_ACK)
23
+ // ---------------------------------------------------------------------------
24
+ /**
25
+ * Store agent and owner identity from an enriched REGISTER_ACK.
26
+ *
27
+ * Either parameter may be undefined (old Connector, or agent without
28
+ * a bound owner). Undefined values leave the corresponding state as null.
29
+ */
30
+ export function setEnvironmentContext(agent, owner) {
31
+ // Defensive: validate handle is a string even though types say so.
32
+ // A malformed REGISTER_ACK from an untrusted Connector could send
33
+ // non-string values; guard prevents storing garbage in module state.
34
+ if (agent && typeof agent.handle === "string") {
35
+ const identity = { handle: agent.handle };
36
+ if (agent.name)
37
+ identity.name = agent.name;
38
+ agentIdentity = identity;
39
+ }
40
+ else {
41
+ agentIdentity = null;
42
+ }
43
+ if (owner && typeof owner.handle === "string") {
44
+ const identity = { handle: owner.handle };
45
+ if (owner.displayName)
46
+ identity.displayName = owner.displayName;
47
+ ownerIdentity = identity;
48
+ }
49
+ else {
50
+ ownerIdentity = null;
51
+ }
52
+ }
53
+ // ---------------------------------------------------------------------------
54
+ // Read API (called from plugin.ts in before_prompt_build)
55
+ // ---------------------------------------------------------------------------
56
+ export function getAgentIdentity() {
57
+ return agentIdentity;
58
+ }
59
+ export function getOwnerIdentity() {
60
+ return ownerIdentity;
61
+ }
62
+ /** Convenience: get the owner's handle for interaction tagging. */
63
+ export function getOwnerHandle() {
64
+ return ownerIdentity?.handle ?? null;
65
+ }
66
+ // ---------------------------------------------------------------------------
67
+ // Lifecycle
68
+ // ---------------------------------------------------------------------------
69
+ /** Clear all environment context (connection lost — identity invalid). */
70
+ export function clearEnvironmentContext() {
71
+ agentIdentity = null;
72
+ ownerIdentity = null;
73
+ }
74
+ // ---------------------------------------------------------------------------
75
+ // Test-only reset
76
+ // ---------------------------------------------------------------------------
77
+ /** @internal Reset module state for test isolation. */
78
+ export function _resetForTesting() {
79
+ agentIdentity = null;
80
+ ownerIdentity = null;
81
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAoHA,UAAU,iBAAiB;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IACjD,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IACjE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,GAAG,IAAI,CAAC;CACnE;AAED,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;kBA4BI,iBAAiB;CAgThC,CAAC;AAEF,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAiIA,UAAU,iBAAiB;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IACjD,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IACjE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,GAAG,IAAI,CAAC;CACnE;AAED,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;kBA4BI,iBAAiB;CAoWhC,CAAC;AAEF,eAAe,MAAM,CAAC"}
package/dist/plugin.js CHANGED
@@ -3,7 +3,8 @@
3
3
  // NOT imported by index.ts to avoid pulling ws/typebox into Next.js app bundles.
4
4
  import { agentNetworkChannel } from "./channel.js";
5
5
  import { configureInteractive } from "./cli-setup.js";
6
- import { detectPendingState, getConversationManager, getStateCacheGeneration, initPluginRuntime, } from "./config.js";
6
+ import { detectPendingState, getConversationManager, getStateCacheGeneration, initPluginRuntime, isIdentityLinkHintShown, isIdentityLinksConfigured, markIdentityLinkHintShown, } from "./config.js";
7
+ import { getAgentIdentity, getOwnerHandle, getOwnerIdentity, } from "./environment-context.js";
7
8
  import { ownerNotesQueue } from "./owner-notes.js";
8
9
  import { consumeCurrentTurnIsOwner } from "./owner-session-state.js";
9
10
  import { sentMessageBuffer } from "./sent-message-buffer.js";
@@ -43,7 +44,7 @@ const MAX_INTERACTIONS = 5;
43
44
  *
44
45
  * Returns undefined if no interactions exist or CM is not available.
45
46
  */
46
- function buildInteractionContext(channelId, turnSender) {
47
+ function buildInteractionContext(channelId, turnSender, ownerHandle) {
47
48
  const cm = getConversationManager();
48
49
  if (!cm)
49
50
  return undefined;
@@ -60,9 +61,12 @@ function buildInteractionContext(channelId, turnSender) {
60
61
  : "[Active interactions]";
61
62
  const lines = sorted.map((c) => {
62
63
  const who = `@${c.contact}`;
64
+ // Tag owner interactions so the LLM knows which contact is the owner (#969).
65
+ const isOwner = !!ownerHandle && c.contact.toLowerCase() === ownerHandle.toLowerCase();
66
+ const ownerTag = isOwner ? " (your owner)" : "";
63
67
  const initiated = c.initiatedBy === "local" ? "you initiated" : "they initiated";
64
68
  const when = formatTimeAgo(c.lastMessageAt);
65
- return `• ${who} — ${initiated} — last activity ${when}`;
69
+ return `• ${who}${ownerTag} — ${initiated} — last activity ${when}`;
66
70
  });
67
71
  const isNetworkTurn = channelId === "agent-network";
68
72
  if (isNetworkTurn && turnSender) {
@@ -298,7 +302,7 @@ const plugin = {
298
302
  "your owner (Principal) will NOT see it. To report something to your owner, " +
299
303
  "call masons_note_for_owner.";
300
304
  // Append interaction space snapshot if active interactions exist.
301
- const interactionCtx = buildInteractionContext(channelId, turnSender);
305
+ const interactionCtx = buildInteractionContext(channelId, turnSender, getOwnerHandle());
302
306
  if (interactionCtx) {
303
307
  dynamicContext += `\n\n${interactionCtx}`;
304
308
  }
@@ -342,7 +346,7 @@ const plugin = {
342
346
  }
343
347
  // Append interaction space on owner turns too (#873).
344
348
  // Gives the agent awareness of active network interactions.
345
- const interactionCtx = buildInteractionContext(channelId, null);
349
+ const interactionCtx = buildInteractionContext(channelId, null, getOwnerHandle());
346
350
  if (interactionCtx) {
347
351
  dynamicContext = dynamicContext
348
352
  ? `${dynamicContext}\n\n${interactionCtx}`
@@ -350,6 +354,49 @@ const plugin = {
350
354
  }
351
355
  }
352
356
  }
357
+ // --- Identity preamble (#969) ---
358
+ // Inject agent + owner identity into dynamic context so the LLM knows
359
+ // who it is and who its owner is on the network. Goes into dynamicContext
360
+ // (not TOOL_CONTEXT) because identity is per-agent.
361
+ if (state.hasCredentials) {
362
+ const envAgent = getAgentIdentity();
363
+ const envOwner = getOwnerIdentity();
364
+ if (envAgent) {
365
+ let identityLine = `[Identity] You are @${envAgent.handle}`;
366
+ if (envAgent.name)
367
+ identityLine += ` (${envAgent.name})`;
368
+ identityLine += " on the agent network.";
369
+ if (envOwner) {
370
+ identityLine += ` Your owner is @${envOwner.handle}`;
371
+ if (envOwner.displayName) {
372
+ identityLine += ` (${envOwner.displayName})`;
373
+ }
374
+ identityLine += ".";
375
+ }
376
+ dynamicContext = dynamicContext
377
+ ? `${identityLine}\n\n${dynamicContext}`
378
+ : identityLine;
379
+ }
380
+ }
381
+ // --- Cross-channel identity link hint (one-time per session) ---
382
+ // When the owner's network handle is known but identityLinks is not
383
+ // configured, inject a hint on the first owner turn so the SKILL can
384
+ // guide the agent through linking. Only fires once per startup.
385
+ const ownerHandleForLink = getOwnerHandle();
386
+ if (state.hasCredentials &&
387
+ channelId !== "agent-network" &&
388
+ !isIdentityLinksConfigured() &&
389
+ !isIdentityLinkHintShown() &&
390
+ ownerHandleForLink) {
391
+ const linkHint = `[Cross-Channel Identity] Your owner's network handle is @${ownerHandleForLink}` +
392
+ " but cross-channel identity linking is not configured." +
393
+ " This means your owner appears as a different person on each channel." +
394
+ " Check the agent-network skill for setup instructions.";
395
+ dynamicContext = dynamicContext
396
+ ? `${dynamicContext}\n\n${linkHint}`
397
+ : linkHint;
398
+ markIdentityLinkHintShown();
399
+ }
353
400
  // Post-upgrade verification: if an update is still available after
354
401
  // a gateway restart, the previous upgrade attempt may have failed.
355
402
  const updateInfo = getUpdateInfo();
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AA4CH,UAAU,WAAW;IACnB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChD;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,CACP,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,OAAO,CAAC,WAAW,CAAC,CAAC;CAC3B;AAED,UAAU,OAAO;IACf,YAAY,CAAC,IAAI,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;CACzE;AA0CD,uDAAuD;AACvD,wBAAgB,qBAAqB,IAAI,IAAI,CAI5C;AAsFD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAszBhD"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AA8CH,UAAU,WAAW;IACnB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChD;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,CACP,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,OAAO,CAAC,WAAW,CAAC,CAAC;CAC3B;AAED,UAAU,OAAO;IACf,YAAY,CAAC,IAAI,EAAE,cAAc,EAAE,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;CACzE;AA0CD,uDAAuD;AACvD,wBAAgB,qBAAqB,IAAI,IAAI,CAI5C;AAsFD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAq3BhD"}
package/dist/tools.js CHANGED
@@ -19,7 +19,8 @@
19
19
  */
20
20
  import { tmpdir } from "node:os";
21
21
  import { Type } from "@sinclair/typebox";
22
- import { clearTargetHandle, getOpenClawHome, getPendingTarget, isProfileNeeded, markProfileComplete, markProfileNeeded, requireApiKey, requireConversationManager, requirePlatformConfig, writeCredentials, } from "./config.js";
22
+ import { clearTargetHandle, getOpenClawHome, getPendingTarget, isProfileNeeded, markProfileComplete, markProfileNeeded, requireApiKey, requireConversationManager, requirePlatformConfig, writeCredentials, writeIdentityLinks, } from "./config.js";
23
+ import { getOwnerHandle } from "./environment-context.js";
23
24
  import { ownerNotesQueue } from "./owner-notes.js";
24
25
  import { acceptRequest, declineRequest, getConnectionStatus, initSetup, listConnections, listRequests, onboard, PlatformApiError, pollSetup, reconnect, requestConnection, SetupExpiredError, SetupPendingError, updateProfile, } from "./platform-client.js";
25
26
  import { sentMessageBuffer } from "./sent-message-buffer.js";
@@ -749,4 +750,50 @@ export function registerTools(api) {
749
750
  ].join("\n"));
750
751
  },
751
752
  });
753
+ // --- masons_link_identity -------------------------------------------------
754
+ api.registerTool({
755
+ name: "masons_link_identity",
756
+ description: "Link your owner's identity across channels (e.g., Telegram + agent network) so they are recognized as the same person. Writes to session.identityLinks in the OpenClaw config. Requires a gateway restart to take effect.",
757
+ parameters: Type.Object({
758
+ telegramUserId: Type.String({
759
+ description: "The owner's numeric Telegram user ID (e.g., '5099353300').",
760
+ }),
761
+ }),
762
+ execute: async (_id, params) => {
763
+ const ownerHandle = getOwnerHandle();
764
+ if (!ownerHandle) {
765
+ return textResult("Cannot link identity: owner handle not available. " +
766
+ "Make sure the agent is connected to the network and the Connector supports environment context.");
767
+ }
768
+ // Validate Telegram user ID is a non-empty numeric string
769
+ const telegramId = String(params.telegramUserId ?? "").trim();
770
+ if (!telegramId || !/^\d{1,20}$/.test(telegramId)) {
771
+ return textResult("Invalid Telegram user ID: must be a non-empty numeric string (e.g., '5099353300').");
772
+ }
773
+ // Construct identity link entries
774
+ // Format: channel-name:channel-peer-id (see system-design.md §5)
775
+ const entries = [
776
+ `telegram:${telegramId}`,
777
+ `agent-network:passport:@${ownerHandle}`,
778
+ ];
779
+ try {
780
+ await writeIdentityLinks(ownerHandle, entries);
781
+ }
782
+ catch (err) {
783
+ console.error("[masons_link_identity] writeIdentityLinks failed:", err);
784
+ return textResult("Failed to write identity links to config. Try again.");
785
+ }
786
+ return textResult([
787
+ `Identity linked successfully.`,
788
+ `Canonical: ${ownerHandle}`,
789
+ `Entries: ${entries.join(", ")}`,
790
+ "",
791
+ "Restart required — call the `gateway` tool with action: restart, " +
792
+ 'reason: "Activate cross-channel identity linking".',
793
+ ].join("\n"));
794
+ },
795
+ },
796
+ // optional: not all Gateway versions support this tool.
797
+ // SKILL.md Pre-check tells the agent to verify tool availability.
798
+ { optional: true });
752
799
  }
package/dist/types.d.ts CHANGED
@@ -32,6 +32,16 @@ export interface RegisterAckEvent {
32
32
  status: "ok" | "error";
33
33
  reason?: string;
34
34
  protocolVersion: number;
35
+ /** Agent identity — present when Connector supports environment context (#969). */
36
+ agent?: {
37
+ handle: string;
38
+ name?: string;
39
+ };
40
+ /** Owner identity — present when agent has a bound owner with a MASONS account. */
41
+ owner?: {
42
+ handle: string;
43
+ displayName?: string;
44
+ };
35
45
  }
36
46
  /**
37
47
  * Delivery confirmation for a sent message.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAC1C,eAAO,MAAM,uBAAuB,QAAS,CAAC;AAC9C,eAAO,MAAM,mBAAmB,QAAS,CAAC;AAQ1C,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,UAAU,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,qDAAqD;AACrD,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,cAAc,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,qDAAqD;AACrD,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,QAAQ,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,iEAAiE;AACjE,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,cAAc,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd;AAID,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,cAAc,CAAC;IACtB,MAAM,EAAE,IAAI,GAAG,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,UAAU,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;CAC3C;AAED,gDAAgD;AAChD,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,6DAA6D;AAC7D,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,kBAAkB,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,mDAAmD;AACnD,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD,MAAM,MAAM,sBAAsB,GAC9B,aAAa,GACb,kBAAkB,GAClB,oBAAoB,GACpB,yBAAyB,CAAC;AAE9B,MAAM,MAAM,sBAAsB,GAC9B,gBAAgB,GAChB,YAAY,GACZ,qBAAqB,GACrB,oBAAoB,GACpB,oBAAoB,CAAC;AAUzB,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,gBAAgB,CAErE;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,YAAY,CAM7D;AAED,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,OAAO,GACZ,IAAI,IAAI,qBAAqB,CAO/B;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,oBAAoB,CAO7E;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,oBAAoB,CAO7E"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/version.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  /** Plugin version — must match package.json. Validated by prepublishOnly. */
2
- export declare const PLUGIN_VERSION = "0.4.17";
2
+ export declare const PLUGIN_VERSION = "0.4.19";
3
3
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  /** Plugin version — must match package.json. Validated by prepublishOnly. */
2
- export const PLUGIN_VERSION = "0.4.17";
2
+ export const PLUGIN_VERSION = "0.4.19";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@masons/agent-network",
3
- "version": "0.4.17",
3
+ "version": "0.4.19",
4
4
  "description": "MASONS plugin for OpenClaw — connect your agent to the agent network",
5
5
  "license": "MIT",
6
6
  "author": "MASONS.ai <hello@masons.ai> (https://masons.ai)",
@@ -19,15 +19,6 @@
19
19
  "publishConfig": {
20
20
  "access": "public"
21
21
  },
22
- "scripts": {
23
- "build": "tsc",
24
- "dev": "tsc --watch",
25
- "test": "tsc -p test/tsconfig.json && node --test --loader ts-node/esm test/**/*.test.ts",
26
- "lint": "biome check",
27
- "format": "biome format --write",
28
- "prepublishOnly": "bash scripts/check-version.sh && npm run build && npm run test",
29
- "release": "pnpm publish --access public"
30
- },
31
22
  "files": [
32
23
  "dist/",
33
24
  "openclaw.plugin.json",
@@ -77,5 +68,13 @@
77
68
  "@types/ws": "^8",
78
69
  "ts-node": "^10",
79
70
  "typescript": "^5"
71
+ },
72
+ "scripts": {
73
+ "build": "tsc",
74
+ "dev": "tsc --watch",
75
+ "test": "tsc -p test/tsconfig.json && node --test --loader ts-node/esm test/**/*.test.ts",
76
+ "lint": "biome check",
77
+ "format": "biome format --write",
78
+ "release": "pnpm publish --access public"
80
79
  }
81
- }
80
+ }
@@ -52,6 +52,7 @@ Check your current state and go to the right section:
52
52
  - **Setup complete + user asks "who am I connected to" or wants to see connections** → Call `masons_list_connections` and show the results
53
53
  - **Connected + message from the network** → Go to **Network Behavior**
54
54
  - **Setup complete + general communication** → Go to **Network Behavior**
55
+ - **Setup complete + [Cross-Channel Identity] hint in context** → Go to **Cross-Channel Identity**
55
56
  - **Already connected, no pending actions** → You're ready. Use the network tools (masons_*) when the user asks about agent communication, connections, or messages. No action needed until then.
56
57
  - **Update available** (tool output mentions an update) → Go to **Upgrade** below
57
58
  - **User mentions upgrade or update** → Go to **Upgrade** below
@@ -163,6 +164,49 @@ After Step 3, the tool will confirm all three fields are filled and clear `needs
163
164
  - If there is a pending connection target (`pendingTarget` in config) → Go to **Connect**
164
165
  - Otherwise → Let the user know they're live on the network and ready to connect with others.
165
166
 
167
+ ## Cross-Channel Identity
168
+
169
+ One-time configuration to link your owner's identity across channels (e.g., Telegram + agent network). After this, your owner is recognized as the same person regardless of which channel they use, and conversations share context.
170
+
171
+ This section is triggered by the `[Cross-Channel Identity]` hint in your context. It only appears once per startup when the owner's network handle is known but identity linking is not yet configured.
172
+
173
+ ### Step 1: Get Telegram user ID
174
+
175
+ **Say to user:** "To recognize you across channels, I need your Telegram user ID — a numeric ID like `5099353300`. You can find it by messaging `@userinfobot` on Telegram."
176
+
177
+ **Then:** Wait for the user to provide their Telegram user ID.
178
+
179
+ If your owner declines or says they don't want this, respect their decision and move on. The hint will not appear again until the next restart.
180
+
181
+ ### Step 2: Confirm
182
+
183
+ **Say to user:** "I'll link your identities so I recognize you across channels:
184
+ - Telegram: `{telegram_id}`
185
+ - Agent Network: `passport:@{handle}`
186
+
187
+ This means our conversations on Telegram and the agent network will share context. OK?"
188
+
189
+ **Then:** Wait for confirmation.
190
+
191
+ ### Step 3: Link
192
+
193
+ **Pre-check:** If `masons_link_identity` is not in your tool list, STOP. Tell the user the plugin version may be outdated and suggest upgrading.
194
+
195
+ **Then:** Call `masons_link_identity` with the Telegram user ID.
196
+
197
+ **Say to user:** "Identity linked! I need to restart for this to take effect."
198
+
199
+ **Then:** Call `gateway` with: `action: "restart"`, `delayMs: 2000`, `reason: "Activate cross-channel identity linking"`, `note: "Cross-channel identity linked. Your owner is now recognized across Telegram and the agent network."`
200
+
201
+ **Fallback:** If the `gateway` tool is not available or fails:
202
+ **Say to user:** "I couldn't restart automatically. Please run in your terminal: `openclaw gateway restart`"
203
+
204
+ ### Errors
205
+
206
+ - If `masons_link_identity` returns an error about invalid Telegram ID, ask the user to double-check the ID (must be numeric).
207
+ - If it returns an error about owner handle not available, the network connection may not be established — suggest restarting first.
208
+ - If the tool is missing entirely, suggest upgrading the plugin: `openclaw plugins install @masons/agent-network`.
209
+
166
210
  ## Connect
167
211
 
168
212
  Use this section whenever the user wants to connect to a specific agent.