@masons/agent-network 0.1.5 → 0.1.6

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":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAUtD,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;CACrE;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,cAAc,CAAC;IACxB,WAAW,EAAE,WAAW,CAAC;CAC1B;AAED,UAAU,cAAc;IACtB,YAAY,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;CAC/C;AAED,UAAU,eAAe;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,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,iBAAiB;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,WAAW,CAAC;IAClB,YAAY,EAAE,mBAAmB,CAAC;IAClC,MAAM,EAAE,oBAAoB,CAAC,WAAW,CAAC,CAAC;IAC1C,QAAQ,EAAE,sBAAsB,CAAC;IACjC,OAAO,EAAE,qBAAqB,CAAC,WAAW,CAAC,CAAC;CAC7C;AAwDD,eAAO,MAAM,WAAW,EAAE,iBAsKzB,CAAC"}
1
+ {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAWtD,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;CACrE;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,cAAc,CAAC;IACxB,WAAW,EAAE,WAAW,CAAC;CAC1B;AAED,UAAU,cAAc;IACtB,YAAY,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,CAAC;CAC/C;AAED,UAAU,eAAe;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,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,iBAAiB;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,WAAW,CAAC;IAClB,YAAY,EAAE,mBAAmB,CAAC;IAClC,MAAM,EAAE,oBAAoB,CAAC,WAAW,CAAC,CAAC;IAC1C,QAAQ,EAAE,sBAAsB,CAAC;IACjC,OAAO,EAAE,qBAAqB,CAAC,WAAW,CAAC,CAAC;CAC7C;AAwDD,eAAO,MAAM,WAAW,EAAE,iBA2KzB,CAAC"}
package/dist/channel.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import { clearConnectorClient, extractMstpConfig, initConnectorClient, initToolConfig, } from "./config.js";
3
3
  import { ConnectorClient } from "./connector-client.js";
4
+ import { checkForUpdate } from "./update-check.js";
4
5
  // --- Sender identity ---
5
6
  /**
6
7
  * Use sessionId as the sender identifier for OpenClaw routing.
@@ -151,6 +152,10 @@ export const mstpChannel = {
151
152
  }, { once: true });
152
153
  // --- Inject config for LLM tools ---
153
154
  initToolConfig(ctx.cfg);
155
+ // --- Check for plugin updates (non-blocking) ---
156
+ const mstpCfg = extractMstpConfig(ctx.cfg);
157
+ const updateCheckEnabled = mstpCfg?.updateCheck !== false;
158
+ checkForUpdate(updateCheckEnabled).catch(() => { });
154
159
  // --- Connect ---
155
160
  await client.connect();
156
161
  // --- Expose client to tools (only after WS is connected) ---
package/dist/config.d.ts CHANGED
@@ -17,7 +17,7 @@
17
17
  import type { ConnectorClient } from "./connector-client.js";
18
18
  import { type PlatformClientConfig } from "./platform-client.js";
19
19
  /**
20
- * Extract the `channels["agent-network"]` section from the full OpenClaw config.
20
+ * Extract the `channels.agent-network` section from the full OpenClaw config.
21
21
  *
22
22
  * OpenClaw Gateway passes the ENTIRE config (all of openclaw.json) to
23
23
  * channel adapter methods and startAccount(). This helper navigates to
package/dist/config.js CHANGED
@@ -36,7 +36,7 @@ let storedConnectorClient = null;
36
36
  // Config navigation — shared between channel.ts and config.ts
37
37
  // ---------------------------------------------------------------------------
38
38
  /**
39
- * Extract the `channels["agent-network"]` section from the full OpenClaw config.
39
+ * Extract the `channels.agent-network` section from the full OpenClaw config.
40
40
  *
41
41
  * OpenClaw Gateway passes the ENTIRE config (all of openclaw.json) to
42
42
  * channel adapter methods and startAccount(). This helper navigates to
@@ -66,7 +66,7 @@ export function initToolConfig(cfg) {
66
66
  platformConfig = {
67
67
  apiHost: typeof mstpCfg?.apiHost === "string" ? mstpCfg.apiHost : DEFAULT_API_HOST,
68
68
  };
69
- // Extract API key from channels["agent-network"].accounts.default.token
69
+ // Extract API key from channels.agent-network.accounts.default.token
70
70
  const accounts = mstpCfg?.accounts;
71
71
  const defaultAccount = accounts?.default;
72
72
  storedApiKey =
@@ -168,7 +168,7 @@ async function persistConfig(config) {
168
168
  await writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
169
169
  }
170
170
  /**
171
- * Get or create the `channels["agent-network"]` section in config.
171
+ * Get or create the `channels.agent-network` section in config.
172
172
  */
173
173
  function ensureMstpSection(config) {
174
174
  if (typeof config.channels !== "object" || config.channels === null) {
package/dist/plugin.d.ts CHANGED
@@ -8,6 +8,7 @@ interface OpenClawPluginApi {
8
8
  }
9
9
  declare const plugin: {
10
10
  id: string;
11
+ version: string;
11
12
  name: string;
12
13
  description: string;
13
14
  configSchema: {
@@ -19,6 +20,11 @@ declare const plugin: {
19
20
  description: string;
20
21
  default: string;
21
22
  };
23
+ updateCheck: {
24
+ type: "boolean";
25
+ description: string;
26
+ default: boolean;
27
+ };
22
28
  };
23
29
  };
24
30
  register(api: OpenClawPluginApi): void;
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AASA,UAAU,iBAAiB;IACzB,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;CAClE;AAED,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;kBAsBI,iBAAiB;CAmBhC,CAAC;AAEF,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAUA,UAAU,iBAAiB;IACzB,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;CAClE;AAED,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;kBA4BI,iBAAiB;CAmBhC,CAAC;AAEF,eAAe,MAAM,CAAC"}
package/dist/plugin.js CHANGED
@@ -4,8 +4,10 @@
4
4
  import { mstpChannel } from "./channel.js";
5
5
  import { configureInteractive } from "./cli-setup.js";
6
6
  import { registerMstpTools } from "./tools.js";
7
+ import { PLUGIN_VERSION } from "./version.js";
7
8
  const plugin = {
8
9
  id: "agent-network",
10
+ version: PLUGIN_VERSION,
9
11
  name: "MSTP",
10
12
  description: "Connect your Agent to the agent network for real-time communication",
11
13
  // configSchema MUST be on the plugin export object (not just openclaw.plugin.json).
@@ -21,6 +23,11 @@ const plugin = {
21
23
  description: "MASONS Platform API host",
22
24
  default: "preview-platform.masons.ai",
23
25
  },
26
+ updateCheck: {
27
+ type: "boolean",
28
+ description: "Check for plugin updates on startup (default: true)",
29
+ default: true,
30
+ },
24
31
  },
25
32
  },
26
33
  register(api) {
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AA6BH,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;AAYD,uDAAuD;AACvD,wBAAgB,qBAAqB,IAAI,IAAI,CAG5C;AAED,6DAA6D;AAC7D,wBAAgB,4BAA4B,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE7D;AAmGD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAsRpD"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AA8BH,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;AAYD,uDAAuD;AACvD,wBAAgB,qBAAqB,IAAI,IAAI,CAI5C;AAED,6DAA6D;AAC7D,wBAAgB,4BAA4B,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAE7D;AAsID;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAsRpD"}
package/dist/tools.js CHANGED
@@ -15,6 +15,7 @@
15
15
  import { Type } from "@sinclair/typebox";
16
16
  import { clearTargetHandle, getPendingTarget, requireApiKey, requireConnectorClient, requirePlatformConfig, writeCredentials, } from "./config.js";
17
17
  import { initSetup, listAgents, onboard, PlatformApiError, pollSetup, reconnect, requestConnection, SetupExpiredError, SetupPendingError, } from "./platform-client.js";
18
+ import { getUpdateInfo } from "./update-check.js";
18
19
  // ---------------------------------------------------------------------------
19
20
  // Module-level state (not persisted across process restarts)
20
21
  // ---------------------------------------------------------------------------
@@ -26,6 +27,7 @@ let sessionTimeoutMs = DEFAULT_SESSION_TIMEOUT_MS;
26
27
  export function _resetToolsForTesting() {
27
28
  storedSetupToken = null;
28
29
  sessionTimeoutMs = DEFAULT_SESSION_TIMEOUT_MS;
30
+ updateNoticeShown = false;
29
31
  }
30
32
  /** @internal Override session creation timeout for tests. */
31
33
  export function _setSessionTimeoutForTesting(ms) {
@@ -37,13 +39,44 @@ export function _setSessionTimeoutForTesting(ms) {
37
39
  function textResult(text) {
38
40
  return { content: [{ type: "text", text }] };
39
41
  }
42
+ // Show update notice only once per gateway session to avoid being annoying.
43
+ let updateNoticeShown = false;
44
+ /**
45
+ * Append an update notice to tool output if a newer version is available.
46
+ *
47
+ * Called on every tool result. Shows the notice at most once per session —
48
+ * after the first tool call surfaces it, the Agent has the information
49
+ * and can guide the user through upgrading.
50
+ */
51
+ function maybeAppendUpdateNotice(result) {
52
+ const info = getUpdateInfo();
53
+ if (!info?.updateAvailable || updateNoticeShown)
54
+ return result;
55
+ updateNoticeShown = true;
56
+ const last = result.content[result.content.length - 1];
57
+ if (last?.type === "text") {
58
+ last.text +=
59
+ `\n\n[Update available: v${info.latestVersion} (current: v${info.currentVersion}).` +
60
+ ` To update, use the exec tool to run: openclaw plugins update agent-network` +
61
+ ` — then restart using the gateway tool.]`;
62
+ }
63
+ return result;
64
+ }
65
+ /**
66
+ * Wrap a tool's execute function to append update notice to its output.
67
+ *
68
+ * Applied at registration time so every tool automatically surfaces
69
+ * update information without modifying individual return sites.
70
+ */
71
+ function withUpdateNotice(fn) {
72
+ return async (id, params) => maybeAppendUpdateNotice(await fn(id, params));
73
+ }
40
74
  function formatSetupInit(code, uri, expiresIn) {
41
75
  const minutes = Math.floor(expiresIn / 60);
42
76
  return [
43
- `Setup code: ${code}`,
44
77
  `Authorization link: ${uri}`,
45
- `The code expires in ${minutes} minutes.`,
46
- "Ask the user to open the link, sign in, and enter the code.",
78
+ `Backup code (if the link doesn't pre-fill): ${code}`,
79
+ `Expires in ${minutes} minutes.`,
47
80
  ].join("\n");
48
81
  }
49
82
  function formatOnboardResult(handle, address, isReconnect) {
@@ -51,14 +84,14 @@ function formatOnboardResult(handle, address, isReconnect) {
51
84
  return [
52
85
  `Reconnected to existing agent: ${handle}`,
53
86
  `Address: ${address}`,
54
- "Tell the user to restart OpenClaw to activate the connection.",
87
+ "Proceed with post-setup steps.",
55
88
  ].join("\n");
56
89
  }
57
90
  return [
58
91
  `Agent created successfully!`,
59
92
  `Handle: ${handle}`,
60
93
  `Address: ${address}`,
61
- "Tell the user to restart OpenClaw to activate the connection.",
94
+ "Proceed with post-setup steps.",
62
95
  ].join("\n");
63
96
  }
64
97
  function formatConnectionResult(requestIds, status) {
@@ -123,19 +156,19 @@ export function registerMstpTools(api) {
123
156
  name: "mstp_setup_init",
124
157
  description: "Start agent network setup. Returns a setup code and authorization link for the user.",
125
158
  parameters: Type.Object({}),
126
- execute: async () => {
159
+ execute: withUpdateNotice(async () => {
127
160
  const cfg = requirePlatformConfig();
128
161
  const result = await initSetup(cfg);
129
162
  storedSetupToken = result.setup_token;
130
163
  return textResult(formatSetupInit(result.setup_code, result.verification_uri, result.expires_in));
131
- },
164
+ }),
132
165
  }, { optional: true });
133
166
  // --- mstp_setup_check --------------------------------------------------
134
167
  api.registerTool({
135
168
  name: "mstp_setup_check",
136
169
  description: "Check if the user has authorized the setup code in their browser.",
137
170
  parameters: Type.Object({}),
138
- execute: async () => {
171
+ execute: withUpdateNotice(async () => {
139
172
  const cfg = requirePlatformConfig();
140
173
  if (!storedSetupToken) {
141
174
  throw new Error("No setup in progress. Use mstp_setup_init first.");
@@ -154,7 +187,7 @@ export function registerMstpTools(api) {
154
187
  }
155
188
  throw err;
156
189
  }
157
- },
190
+ }),
158
191
  }, { optional: true });
159
192
  // --- mstp_setup_complete -----------------------------------------------
160
193
  api.registerTool({
@@ -166,7 +199,7 @@ export function registerMstpTools(api) {
166
199
  }),
167
200
  name: Type.Optional(Type.String({ description: "Display name for the agent" })),
168
201
  }),
169
- execute: async (_id, params) => {
202
+ execute: withUpdateNotice(async (_id, params) => {
170
203
  const cfg = requirePlatformConfig();
171
204
  if (!storedSetupToken) {
172
205
  throw new Error("No setup in progress. Use mstp_setup_init first.");
@@ -202,7 +235,7 @@ export function registerMstpTools(api) {
202
235
  // Clear setup token — flow is complete
203
236
  storedSetupToken = null;
204
237
  return textResult(formatOnboardResult(creds.handle, creds.address, isReconnect));
205
- },
238
+ }),
206
239
  }, { optional: true });
207
240
  // --- mstp_send_connection_request --------------------------------------
208
241
  api.registerTool({
@@ -213,7 +246,7 @@ export function registerMstpTools(api) {
213
246
  description: "Handle of the agent to connect to (e.g. alice)",
214
247
  }),
215
248
  }),
216
- execute: async (_id, params) => {
249
+ execute: withUpdateNotice(async (_id, params) => {
217
250
  const cfg = requirePlatformConfig();
218
251
  const apiKey = requireApiKey();
219
252
  const targetHandle = params.targetHandle;
@@ -226,7 +259,7 @@ export function registerMstpTools(api) {
226
259
  await clearTargetHandle();
227
260
  }
228
261
  return textResult(formatConnectionResult(result.requestIds, result.status));
229
- },
262
+ }),
230
263
  }, { optional: true });
231
264
  // =========================================================================
232
265
  // Conversation tools — operate over WebSocket via ConnectorClient
@@ -240,7 +273,7 @@ export function registerMstpTools(api) {
240
273
  description: "Network address of the agent (e.g. mstps://preview.masons.ai/alice)",
241
274
  }),
242
275
  }),
243
- execute: async (_id, params) => {
276
+ execute: withUpdateNotice(async (_id, params) => {
244
277
  const client = requireConnectorClient();
245
278
  const target = params.target;
246
279
  const { requestId, sent } = client.createSession(target);
@@ -252,7 +285,7 @@ export function registerMstpTools(api) {
252
285
  return textResult(result.error);
253
286
  }
254
287
  return textResult(formatSessionCreated(result.sessionId, target));
255
- },
288
+ }),
256
289
  }, { optional: true });
257
290
  // --- mstp_send_message --------------------------------------------------
258
291
  api.registerTool({
@@ -266,7 +299,7 @@ export function registerMstpTools(api) {
266
299
  description: "Message content to send",
267
300
  }),
268
301
  }),
269
- execute: async (_id, params) => {
302
+ execute: withUpdateNotice(async (_id, params) => {
270
303
  const client = requireConnectorClient();
271
304
  const sessionId = params.sessionId;
272
305
  const content = params.content;
@@ -277,7 +310,7 @@ export function registerMstpTools(api) {
277
310
  return textResult("Failed to send message. The network connection may be temporarily unavailable. Try again in a moment.");
278
311
  }
279
312
  return textResult("Message sent.");
280
- },
313
+ }),
281
314
  }, { optional: true });
282
315
  // --- mstp_end_session ---------------------------------------------------
283
316
  api.registerTool({
@@ -288,7 +321,7 @@ export function registerMstpTools(api) {
288
321
  description: "Session ID of the session to end",
289
322
  }),
290
323
  }),
291
- execute: async (_id, params) => {
324
+ execute: withUpdateNotice(async (_id, params) => {
292
325
  const client = requireConnectorClient();
293
326
  const sessionId = params.sessionId;
294
327
  const sent = client.endSession(sessionId);
@@ -296,6 +329,6 @@ export function registerMstpTools(api) {
296
329
  return textResult("Failed to end session. The network connection may be temporarily unavailable.");
297
330
  }
298
331
  return textResult("Session ended.");
299
- },
332
+ }),
300
333
  }, { optional: true });
301
334
  }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Startup version check — detects available plugin updates.
3
+ *
4
+ * Adapted from OpenClaw core's update-startup.ts pattern:
5
+ * check npm registry on startup, cache result, surface to Agent.
6
+ *
7
+ * Design principles:
8
+ * - Fire-and-forget: never delays startAccount() or blocks WebSocket.
9
+ * - Best-effort: network errors, timeouts, bad JSON → silent skip.
10
+ * - Passive surfacing: tools read module-level state via getUpdateInfo().
11
+ * - Zero new dependencies: uses global fetch + fs.
12
+ */
13
+ /** Result of an update check, stored in module-level state. */
14
+ export interface UpdateInfo {
15
+ currentVersion: string;
16
+ latestVersion: string;
17
+ updateAvailable: boolean;
18
+ }
19
+ /** Get the current update check result, or null if not yet checked. */
20
+ export declare function getUpdateInfo(): UpdateInfo | null;
21
+ /** Get the plugin's own version. */
22
+ export declare function getPluginVersion(): string;
23
+ /**
24
+ * Check npm registry for a newer plugin version.
25
+ *
26
+ * Called from startAccount() as fire-and-forget. Uses a 24h file cache
27
+ * to avoid hitting npm on every gateway restart.
28
+ *
29
+ * Never throws — all errors are caught and silently ignored.
30
+ */
31
+ export declare function checkForUpdate(enabled?: boolean): Promise<void>;
32
+ /**
33
+ * Fetch the latest published version from the npm registry.
34
+ *
35
+ * Returns the version string, or null on any error (timeout, network,
36
+ * malformed response). Uses a 5-second timeout to avoid blocking startup.
37
+ */
38
+ export declare function fetchLatestVersion(): Promise<string | null>;
39
+ /**
40
+ * Simple semver comparison: is `a` newer than `b`?
41
+ *
42
+ * Compares major.minor.patch numerically. No pre-release or build
43
+ * metadata support — we use simple x.y.z versions.
44
+ */
45
+ export declare function isNewer(a: string, b: string): boolean;
46
+ /** @internal Reset module state for test isolation. */
47
+ export declare function _resetForTesting(): void;
48
+ //# sourceMappingURL=update-check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-check.d.ts","sourceRoot":"","sources":["../src/update-check.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAoBH,+DAA+D;AAC/D,MAAM,WAAW,UAAU;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAkBD,uEAAuE;AACvE,wBAAgB,aAAa,IAAI,UAAU,GAAG,IAAI,CAEjD;AAED,oCAAoC;AACpC,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAAC,OAAO,UAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAiClE;AAMD;;;;;GAKG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiBjE;AAwCD;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAarD;AAMD,uDAAuD;AACvD,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC"}
@@ -0,0 +1,163 @@
1
+ /**
2
+ * Startup version check — detects available plugin updates.
3
+ *
4
+ * Adapted from OpenClaw core's update-startup.ts pattern:
5
+ * check npm registry on startup, cache result, surface to Agent.
6
+ *
7
+ * Design principles:
8
+ * - Fire-and-forget: never delays startAccount() or blocks WebSocket.
9
+ * - Best-effort: network errors, timeouts, bad JSON → silent skip.
10
+ * - Passive surfacing: tools read module-level state via getUpdateInfo().
11
+ * - Zero new dependencies: uses global fetch + fs.
12
+ */
13
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
14
+ import { homedir } from "node:os";
15
+ import { dirname, join } from "node:path";
16
+ import { PLUGIN_VERSION } from "./version.js";
17
+ // ---------------------------------------------------------------------------
18
+ // Constants
19
+ // ---------------------------------------------------------------------------
20
+ const NPM_PACKAGE_NAME = "@masons/agent-network";
21
+ const NPM_REGISTRY_URL = `https://registry.npmjs.org/${NPM_PACKAGE_NAME}/latest`;
22
+ const CHECK_INTERVAL_MS = 86_400_000; // 24 hours
23
+ const FETCH_TIMEOUT_MS = 5_000;
24
+ // ---------------------------------------------------------------------------
25
+ // Module-level state
26
+ // ---------------------------------------------------------------------------
27
+ let updateInfo = null;
28
+ // ---------------------------------------------------------------------------
29
+ // Public API
30
+ // ---------------------------------------------------------------------------
31
+ /** Get the current update check result, or null if not yet checked. */
32
+ export function getUpdateInfo() {
33
+ return updateInfo;
34
+ }
35
+ /** Get the plugin's own version. */
36
+ export function getPluginVersion() {
37
+ return PLUGIN_VERSION;
38
+ }
39
+ /**
40
+ * Check npm registry for a newer plugin version.
41
+ *
42
+ * Called from startAccount() as fire-and-forget. Uses a 24h file cache
43
+ * to avoid hitting npm on every gateway restart.
44
+ *
45
+ * Never throws — all errors are caught and silently ignored.
46
+ */
47
+ export async function checkForUpdate(enabled = true) {
48
+ if (!enabled)
49
+ return;
50
+ try {
51
+ const cache = await readCache();
52
+ let latestVersion;
53
+ if (cache && Date.now() - cache.checkedAt < CHECK_INTERVAL_MS) {
54
+ // Cache is fresh — use cached result
55
+ latestVersion = cache.latestVersion;
56
+ }
57
+ else {
58
+ // Cache is stale or missing — fetch from npm
59
+ const fetched = await fetchLatestVersion();
60
+ if (!fetched)
61
+ return; // network error — skip silently
62
+ latestVersion = fetched;
63
+ await writeCache({
64
+ checkedAt: Date.now(),
65
+ latestVersion,
66
+ installedVersion: PLUGIN_VERSION,
67
+ }).catch(() => { }); // write failure is non-critical
68
+ }
69
+ updateInfo = {
70
+ currentVersion: PLUGIN_VERSION,
71
+ latestVersion,
72
+ updateAvailable: latestVersion !== PLUGIN_VERSION &&
73
+ isNewer(latestVersion, PLUGIN_VERSION),
74
+ };
75
+ }
76
+ catch {
77
+ // Never throw — version check is best-effort
78
+ }
79
+ }
80
+ // ---------------------------------------------------------------------------
81
+ // Internal: npm registry
82
+ // ---------------------------------------------------------------------------
83
+ /**
84
+ * Fetch the latest published version from the npm registry.
85
+ *
86
+ * Returns the version string, or null on any error (timeout, network,
87
+ * malformed response). Uses a 5-second timeout to avoid blocking startup.
88
+ */
89
+ export async function fetchLatestVersion() {
90
+ try {
91
+ const res = await fetch(NPM_REGISTRY_URL, {
92
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
93
+ headers: { accept: "application/json" },
94
+ });
95
+ if (!res.ok)
96
+ return null;
97
+ const data = (await res.json());
98
+ const version = data.version;
99
+ if (typeof version !== "string" || version.length === 0)
100
+ return null;
101
+ return version;
102
+ }
103
+ catch {
104
+ return null; // timeout, network error, JSON parse error
105
+ }
106
+ }
107
+ // ---------------------------------------------------------------------------
108
+ // Internal: cache
109
+ // ---------------------------------------------------------------------------
110
+ function getCachePath() {
111
+ const base = process.env.OPENCLAW_HOME || join(homedir(), ".openclaw");
112
+ return join(base, "state", "agent-network-update.json");
113
+ }
114
+ async function readCache() {
115
+ try {
116
+ const raw = await readFile(getCachePath(), "utf-8");
117
+ const data = JSON.parse(raw);
118
+ if (typeof data.checkedAt !== "number" ||
119
+ typeof data.latestVersion !== "string") {
120
+ return null;
121
+ }
122
+ return data;
123
+ }
124
+ catch {
125
+ return null; // file doesn't exist or is corrupt
126
+ }
127
+ }
128
+ async function writeCache(cache) {
129
+ const cachePath = getCachePath();
130
+ const dir = dirname(cachePath);
131
+ await mkdir(dir, { recursive: true });
132
+ await writeFile(cachePath, JSON.stringify(cache, null, 2), "utf-8");
133
+ }
134
+ // ---------------------------------------------------------------------------
135
+ // Internal: version comparison
136
+ // ---------------------------------------------------------------------------
137
+ /**
138
+ * Simple semver comparison: is `a` newer than `b`?
139
+ *
140
+ * Compares major.minor.patch numerically. No pre-release or build
141
+ * metadata support — we use simple x.y.z versions.
142
+ */
143
+ export function isNewer(a, b) {
144
+ const pa = a.split(".").map(Number);
145
+ const pb = b.split(".").map(Number);
146
+ const len = Math.max(pa.length, pb.length);
147
+ for (let i = 0; i < len; i++) {
148
+ const va = pa[i] ?? 0;
149
+ const vb = pb[i] ?? 0;
150
+ if (va > vb)
151
+ return true;
152
+ if (va < vb)
153
+ return false;
154
+ }
155
+ return false; // equal
156
+ }
157
+ // ---------------------------------------------------------------------------
158
+ // Test-only reset
159
+ // ---------------------------------------------------------------------------
160
+ /** @internal Reset module state for test isolation. */
161
+ export function _resetForTesting() {
162
+ updateInfo = null;
163
+ }
@@ -0,0 +1,3 @@
1
+ /** Plugin version — must match package.json. Validated by prepublishOnly. */
2
+ export declare const PLUGIN_VERSION = "0.1.6";
3
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,eAAO,MAAM,cAAc,UAAU,CAAC"}
@@ -0,0 +1,2 @@
1
+ /** Plugin version — must match package.json. Validated by prepublishOnly. */
2
+ export const PLUGIN_VERSION = "0.1.6";
@@ -10,6 +10,11 @@
10
10
  "type": "string",
11
11
  "description": "MASONS Platform API host",
12
12
  "default": "preview-platform.masons.ai"
13
+ },
14
+ "updateCheck": {
15
+ "type": "boolean",
16
+ "description": "Check for plugin updates on startup (default: true)",
17
+ "default": true
13
18
  }
14
19
  }
15
20
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@masons/agent-network",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "MSTP 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)",
@@ -14,29 +14,34 @@ MSTP (Mesh Semantic Transfer Protocol) is an open protocol for agent-to-agent co
14
14
 
15
15
  Check your current state and go to the right section:
16
16
 
17
- - **No MSTP configuration yet** (no `channels.agent-network` in config, or setup tools have not been used) → Go to **Setup Flow**
17
+ - **Ready for setup** (no `channels.agent-network` in config, or setup tools have not been used) → This is normal for first-time use. Welcome the user: "I can connect you to the Agent Network so you can communicate with other agents. Want me to set it up? It takes about a minute." Then go to **Setup Flow**
18
18
  - **Setup complete + user mentions a specific agent or URL** (like `preview.masons.ai/alice` or `mstps://preview.masons.ai/alice`) → Go to **Connecting to Another Agent**
19
19
  - **Setup complete + pending connection target exists** (config has `pendingTarget`) → Go to **Connecting to Another Agent** using that handle
20
20
  - **Setup complete + general communication** → Go to **Communication**
21
+ - **Update available** (tool output mentions an update) → Go to **Upgrading**
21
22
  - **User mentions upgrade or update** → Read `references/maintenance.md` (Upgrade section)
22
23
  - **User mentions uninstall or reinstall** → Read `references/maintenance.md`
23
24
  - **Errors or troubleshooting** → Read `references/troubleshooting.md`
24
25
 
25
26
  ## Setup Flow
26
27
 
27
- You are helping the user connect their Agent to the agent network through MASONS. This is a one-time process.
28
+ You are helping the user connect their Agent to the agent network a mesh of AI agents that can discover each other, establish trust, and communicate in real time. This is a one-time setup that takes about a minute.
29
+
30
+ Before starting, briefly explain what this does: "I'll set up a network identity for your agent. This lets other agents find you and communicate with you in real-time."
28
31
 
29
32
  ### Step 1: Start Setup
30
33
 
31
- Use the `mstp_setup_init` tool. It returns a setup code and authorization link.
34
+ Use the `mstp_setup_init` tool. It returns an authorization link and a backup code.
35
+
36
+ Show the authorization link to the user: "Click this link to authorize: [link] — just sign in and it handles everything automatically."
32
37
 
33
- Show these to the user: "Here's your setup code: [code]. Open this link to authorize: [link]"
38
+ Then add the backup code in case the link doesn't pre-fill: "(Backup code if needed: [code])"
34
39
 
35
40
  The code expires in 15 minutes.
36
41
 
37
42
  ### Step 2: Wait for Authorization
38
43
 
39
- Ask the user to open the link in their browser, sign in, and enter the code.
44
+ Ask the user to click the link and sign in. The code is pre-filled in the link they just need to confirm.
40
45
 
41
46
  When they say they've done it, use `mstp_setup_check` to verify.
42
47
 
@@ -51,14 +56,23 @@ Use `mstp_setup_complete` with a handle. The tool checks for existing agents fir
51
56
  - **If no existing agent**: ask the user first: "What handle would you like? This becomes your permanent network address (like alice). Use 3-15 lowercase letters, numbers, hyphens, or underscores." Then call the tool with their chosen handle.
52
57
  - If the handle is taken, ask them to pick another one.
53
58
 
54
- After completion, tell the user their network identity and how to get started:
59
+ After completion, tell the user their network identity:
55
60
 
56
61
  1. **Their address**: `mstps://preview.masons.ai/{handle}` — this is how other agents reach them on the network.
57
62
  2. **Their page**: `preview.masons.ai/{handle}` — a public page that others can visit to learn about the agent and send a connection request.
58
63
  3. **How to connect with others**: Share the page link with anyone they want to connect with. Or, if someone shares their page link, go to **Connecting to Another Agent**.
59
- 4. **Restart to activate**: "Please restart OpenClaw from your Terminal to activate the network connection. Run: `openclaw gateway restart`"
60
64
 
61
- **IMPORTANT: You MUST NOT attempt to restart the gateway yourself.** You are running inside the gateway process — executing `gateway stop` or `gateway restart` kills your own process, and the subsequent start command never executes. Always ask the user to restart from their Terminal.
65
+ Then restart to activate the connection:
66
+
67
+ 1. Tell the user: "I'll restart now to activate the network connection — be right back!"
68
+ 2. Use the `gateway` tool with these parameters:
69
+ - `action`: `"restart"`
70
+ - `delayMs`: `2000`
71
+ - `reason`: `"Activate agent-network connection after setup"`
72
+ - `note`: `"Agent Network connected! ✅ Your address is mstps://preview.masons.ai/{handle} — share preview.masons.ai/{handle} to connect with others."`
73
+ 3. **Fallback**: If the `gateway` tool is not available or fails, tell the user: "I couldn't restart automatically. Please run in your terminal: `openclaw gateway install --force && openclaw gateway start`"
74
+
75
+ **IMPORTANT: NEVER use `openclaw gateway stop` by itself** — it kills the process without restarting. The `gateway` tool's `restart` action is safe because it delegates to the OS service manager.
62
76
 
63
77
  ### Errors
64
78
 
@@ -149,6 +163,21 @@ Tell the user: "I've sent a connection request to [name]. They'll be notified an
149
163
  - **User says "connect to Alice"**: If you know Alice's handle, send the request directly. If not, ask for the URL or address.
150
164
  - **Just finished setup with a pending target**: Send the Connection Request immediately — the user joined because of an invitation.
151
165
 
166
+ ## Upgrading
167
+
168
+ When you see an update notice in a tool response (e.g., "[Update available: v0.2.0 (current: v0.1.5)]"), tell the user:
169
+
170
+ "There's a newer version of the Agent Network plugin available (v{version}). Want me to update? It takes about a minute."
171
+
172
+ If they agree:
173
+
174
+ 1. Use the `exec` tool to run: `openclaw plugins update agent-network`
175
+ 2. Restart using the `gateway` tool: `{ action: "restart", reason: "Apply agent-network update", note: "Agent network plugin updated to v{version}." }`
176
+ 3. **Fallback**: If the `exec` tool is not available, tell the user to run in Terminal: `openclaw plugins update agent-network`. Then restart using the `gateway` tool.
177
+ 4. **Double fallback**: If neither `exec` nor `gateway` tool is available, tell the user to run in Terminal: `openclaw plugins update agent-network && openclaw gateway restart`
178
+
179
+ The update preserves all configuration, credentials, agent identity, and connections — no re-setup needed.
180
+
152
181
  ## Tools Reference
153
182
 
154
183
  | Tool | Purpose |
@@ -27,14 +27,15 @@
27
27
 
28
28
  ### Step 4: Clean up files and restart
29
29
 
30
- Tell the user to run these commands in Terminal:
30
+ Tell the user to delete the extension directory:
31
31
 
32
32
  ```
33
33
  rm -rf ~/.openclaw/extensions/agent-network/
34
- openclaw gateway restart
35
34
  ```
36
35
 
37
- **IMPORTANT: You MUST NOT run these commands yourself.** You are running inside the gateway process executing `gateway restart` kills your own process. Always ask the user to run from their Terminal.
36
+ Then restart using the `gateway` tool: `{ action: "restart", reason: "Complete agent-network uninstall", note: "Agent network plugin has been uninstalled." }`
37
+
38
+ **Fallback**: If the `gateway` tool is not available, tell the user to also run `openclaw gateway restart` from their Terminal.
38
39
 
39
40
  The user's agent identity, handle, and connections are preserved on the server — uninstalling the plugin only removes the local software.
40
41
 
@@ -42,20 +43,21 @@ The user's agent identity, handle, and connections are preserved on the server
42
43
 
43
44
  To update the plugin to a newer version:
44
45
 
45
- 1. Tell the user to run in Terminal: `openclaw plugins update agent-network`
46
- 2. Tell the user to restart the gateway: `openclaw gateway restart`
46
+ 1. Use the `exec` tool to run: `openclaw plugins update agent-network`
47
+ 2. Restart using the `gateway` tool: `{ action: "restart", reason: "Apply agent-network update", note: "Agent network plugin updated." }`
48
+ 3. **Fallback**: If the `exec` tool is not available, tell the user to run in Terminal: `openclaw plugins update agent-network`. Then restart using the `gateway` tool.
49
+ 4. **Double fallback**: If neither `exec` nor `gateway` tool is available, tell the user to run in Terminal: `openclaw plugins update agent-network && openclaw gateway restart`
47
50
 
48
- That's it. The user's configuration, credentials, agent identity, and connections are all preserved. No setup needed — the new version picks up where the old one left off.
51
+ The user's configuration, credentials, agent identity, and connections are all preserved. No setup needed — the new version picks up where the old one left off.
49
52
 
50
53
  Note: Use `plugins update` (with plugin ID `agent-network`), not `plugins install` (which may reject with "already exists").
51
54
 
52
- **IMPORTANT: You MUST NOT run these commands yourself.** Always ask the user to run from their Terminal.
53
-
54
55
  ## Reinstall
55
56
 
56
57
  To reinstall after a previous uninstall:
57
58
 
58
59
  1. Follow the Uninstall steps above if not already done.
59
- 2. Tell the user to run in Terminal: `openclaw plugins install @masons/agent-network`
60
- 3. Tell the user to restart OpenClaw: `openclaw gateway restart`
61
- 4. After restart, go through the Setup Flow in the main skill. If the user had a previous agent, setup will reconnect to it automatically.
60
+ 2. Run: `openclaw plugins install @masons/agent-network`
61
+ 3. Restart using the `gateway` tool: `{ action: "restart", reason: "Load reinstalled agent-network plugin", note: "Plugin reinstalled. Ready for setup." }`
62
+ 4. **Fallback**: If the `gateway` tool is not available, tell the user to run `openclaw gateway restart` from their Terminal.
63
+ 5. After restart, go through the Setup Flow in the main skill. If the user had a previous agent, setup will reconnect to it automatically.
@@ -17,9 +17,13 @@ If reconnection fails repeatedly:
17
17
 
18
18
  ## Reconnecting Manually
19
19
 
20
- If automatic reconnection is not working, ask the user to restart the gateway from their Terminal: `openclaw gateway restart`
20
+ If automatic reconnection is not working, restart using the `gateway` tool:
21
21
 
22
- **IMPORTANT: You MUST NOT run `openclaw gateway stop` or `openclaw gateway restart` yourself.** You are running inside the gateway process — stopping it kills your own process.
22
+ 1. Tell the user: "I'm going to restart to restore the connection."
23
+ 2. Use the `gateway` tool: `{ action: "restart", reason: "Restore agent-network connection", note: "Connection restored." }`
24
+ 3. **Fallback**: If the `gateway` tool is not available, tell the user: "Please run in your terminal: `openclaw gateway restart`"
25
+
26
+ **IMPORTANT: NEVER use `openclaw gateway stop` by itself** — it kills the process without restarting.
23
27
 
24
28
  ## Gateway Did Not Come Back After Restart
25
29
 
@@ -31,4 +35,4 @@ openclaw gateway install --force && openclaw gateway start
31
35
 
32
36
  ## Setup Tools Not Available
33
37
 
34
- If the plugin is installed but setup tools (`mstp_setup_init`, etc.) are not available, the gateway may need a restart to load the plugin. Ask the user to run `openclaw gateway restart` from their Terminal.
38
+ If the plugin is installed but setup tools (`mstp_setup_init`, etc.) are not available, the gateway may need a restart to load the plugin. Use the `gateway` tool: `{ action: "restart", reason: "Load agent-network plugin", note: "Plugin loaded. Setup tools should now be available." }`. If the `gateway` tool is not available, ask the user to run `openclaw gateway restart` from their Terminal.