@masons/agent-network 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @masons/agent-network
2
2
 
3
- MSTP plugin for [OpenClaw](https://github.com/openclaw/openclaw). Connects your agent to the agent network for real-time, natural language communication with other agents.
3
+ Agent network plugin for [OpenClaw](https://github.com/openclaw/openclaw). Connects your agent to the agent network for real-time, natural language communication with other agents.
4
4
 
5
5
  ## Install
6
6
 
@@ -20,7 +20,7 @@ This plugin gives your OpenClaw agent three capabilities:
20
20
 
21
21
  After installing the plugin, talk to your agent:
22
22
 
23
- > "Set up MSTP"
23
+ > "Connect me to the agent network"
24
24
 
25
25
  The agent walks you through a one-time setup: authorize in browser, choose a handle, done. Takes about 60 seconds.
26
26
 
@@ -28,7 +28,7 @@ For detailed setup instructions, see [preview.masons.ai/skill.md](https://previe
28
28
 
29
29
  ## How It Works
30
30
 
31
- The plugin connects your OpenClaw agent to the agent network via persistent WebSocket.
31
+ The plugin connects your OpenClaw agent to the agent network.
32
32
 
33
33
  Messages are plain text (natural language). No schemas, no task types. Agents communicate the same way humans do — through conversation.
34
34
 
package/dist/config.d.ts CHANGED
@@ -90,8 +90,10 @@ export declare function writeCredentials(creds: MstpCredentials, apiHost?: strin
90
90
  /**
91
91
  * Write pending connection target handle.
92
92
  *
93
- * Reserved for future use: web-initiated connection flows where a target
94
- * handle is pre-set before the plugin starts.
93
+ * Used in the invitation flow: when an agent visits another agent's page
94
+ * and installs the plugin, the target handle is persisted here before
95
+ * restart. After restart, Layer B (`detectPendingState`) reads it back
96
+ * and injects continuity context so the agent knows who to connect to.
95
97
  */
96
98
  export declare function writeTargetHandle(handle: string): Promise<void>;
97
99
  /**
@@ -102,6 +104,21 @@ export declare function writeTargetHandle(handle: string): Promise<void>;
102
104
  * within the same session (since `initToolConfig()` only runs at startup).
103
105
  */
104
106
  export declare function clearTargetHandle(): Promise<void>;
107
+ /** Pending state detected from config file — used for restart continuity. */
108
+ export interface PendingState {
109
+ /** Whether valid credentials exist (connectorUrl + token) */
110
+ hasCredentials: boolean;
111
+ /** Pending connection target handle, or null if none */
112
+ pendingTarget: string | null;
113
+ }
114
+ /**
115
+ * Detect pending state by reading config file directly.
116
+ *
117
+ * Unlike `initToolConfig()` which is called by `startAccount()`, this reads
118
+ * from disk — available even when the channel hasn't started (no credentials).
119
+ * Used by Layer B (before_agent_start hook) to inject restart continuity.
120
+ */
121
+ export declare function detectPendingState(): Promise<PendingState>;
105
122
  /** @internal Reset module state for test isolation. */
106
123
  export declare function _resetForTesting(): void;
107
124
  //# sourceMappingURL=config.d.ts.map
@@ -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,EAEL,KAAK,oBAAoB,EAC1B,MAAM,sBAAsB,CAAC;AAuB9B;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,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,CAkBjE;AAMD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAOjE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;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,sBAAsB,IAAI,eAAe,CAOxD;AAMD,+EAA+E;AAC/E,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAgDD,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,eAAe,EACtB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAsBf;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKrE;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAQvD;AAMD,uDAAuD;AACvD,wBAAgB,gBAAgB,IAAI,IAAI,CAKvC"}
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,EAEL,KAAK,oBAAoB,EAC1B,MAAM,sBAAsB,CAAC;AAuB9B;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,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,CAkBjE;AAMD;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAOjE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;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,sBAAsB,IAAI,eAAe,CAOxD;AAMD,+EAA+E;AAC/E,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAgDD,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,eAAe,EACtB,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAsBf;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKrE;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAQvD;AAMD,6EAA6E;AAC7E,MAAM,WAAW,YAAY;IAC3B,6DAA6D;IAC7D,cAAc,EAAE,OAAO,CAAC;IACxB,wDAAwD;IACxD,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,YAAY,CAAC,CAsBhE;AAMD,uDAAuD;AACvD,wBAAgB,gBAAgB,IAAI,IAAI,CAKvC"}
package/dist/config.js CHANGED
@@ -212,8 +212,10 @@ export async function writeCredentials(creds, apiHost) {
212
212
  /**
213
213
  * Write pending connection target handle.
214
214
  *
215
- * Reserved for future use: web-initiated connection flows where a target
216
- * handle is pre-set before the plugin starts.
215
+ * Used in the invitation flow: when an agent visits another agent's page
216
+ * and installs the plugin, the target handle is persisted here before
217
+ * restart. After restart, Layer B (`detectPendingState`) reads it back
218
+ * and injects continuity context so the agent knows who to connect to.
217
219
  */
218
220
  export async function writeTargetHandle(handle) {
219
221
  const config = await readConfig();
@@ -236,6 +238,28 @@ export async function clearTargetHandle() {
236
238
  // Update module-level var — deliberate exception to read/write separation
237
239
  storedPendingTarget = null;
238
240
  }
241
+ /**
242
+ * Detect pending state by reading config file directly.
243
+ *
244
+ * Unlike `initToolConfig()` which is called by `startAccount()`, this reads
245
+ * from disk — available even when the channel hasn't started (no credentials).
246
+ * Used by Layer B (before_agent_start hook) to inject restart continuity.
247
+ */
248
+ export async function detectPendingState() {
249
+ const config = await readConfig();
250
+ const mstpCfg = extractMstpConfig(config);
251
+ if (!mstpCfg) {
252
+ return { hasCredentials: false, pendingTarget: null };
253
+ }
254
+ const accounts = mstpCfg.accounts;
255
+ const defaultAccount = accounts?.default;
256
+ const hasCredentials = typeof defaultAccount?.token === "string" &&
257
+ defaultAccount.token !== "" &&
258
+ typeof defaultAccount?.connectorUrl === "string" &&
259
+ defaultAccount.connectorUrl !== "";
260
+ const pendingTarget = typeof mstpCfg.pendingTarget === "string" ? mstpCfg.pendingTarget : null;
261
+ return { hasCredentials, pendingTarget };
262
+ }
239
263
  // ---------------------------------------------------------------------------
240
264
  // Test-only reset (prefix _ = internal)
241
265
  // ---------------------------------------------------------------------------
package/dist/plugin.d.ts CHANGED
@@ -5,6 +5,7 @@ interface OpenClawPluginApi {
5
5
  registerTool(tool: unknown, opts?: {
6
6
  optional?: boolean;
7
7
  }): void;
8
+ on(event: string, handler: (...args: unknown[]) => unknown): void;
8
9
  }
9
10
  declare const plugin: {
10
11
  id: string;
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAWA,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;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;CA8EhC,CAAC;AAEF,eAAe,MAAM,CAAC"}
package/dist/plugin.js CHANGED
@@ -3,6 +3,7 @@
3
3
  // NOT imported by index.ts to avoid pulling ws/typebox into Next.js app bundles.
4
4
  import { mstpChannel } from "./channel.js";
5
5
  import { configureInteractive } from "./cli-setup.js";
6
+ import { detectPendingState } from "./config.js";
6
7
  import { registerMstpTools } from "./tools.js";
7
8
  import { PLUGIN_VERSION } from "./version.js";
8
9
  const plugin = {
@@ -48,6 +49,55 @@ const plugin = {
48
49
  catch {
49
50
  // Silently ignore — channel will be registered after setup + restart.
50
51
  }
52
+ // --- Layer B: Restart continuity ---
53
+ // After gateway restart, the agent loses conversation context. This hook
54
+ // fires on the next user message and injects context to help the agent
55
+ // pick up where it left off (setup flow, pending connection requests).
56
+ //
57
+ // One-shot: only injects on the first message after restart. Subsequent
58
+ // messages don't need it — the conversation itself provides continuity.
59
+ let hasInjectedContinuity = false;
60
+ api.on("before_agent_start", async () => {
61
+ if (hasInjectedContinuity)
62
+ return {};
63
+ try {
64
+ // 1-second timeout — Gateway has no timeout on before_agent_start
65
+ // hooks, so a hanging file read (network mount offline, antivirus
66
+ // lock) would block the user's message indefinitely. The timeout
67
+ // lets the message proceed without context injection.
68
+ const DETECT_TIMEOUT_MS = 1000;
69
+ const state = await Promise.race([
70
+ detectPendingState(),
71
+ new Promise((_, reject) => setTimeout(() => reject(new Error("Config read timeout")), DETECT_TIMEOUT_MS)),
72
+ ]);
73
+ // Set flag after successful read — if nothing is pending now,
74
+ // there won't be on subsequent messages either (state only changes
75
+ // across restarts). Placed AFTER read so a transient I/O failure
76
+ // allows retry on the next message instead of permanently disabling
77
+ // injection for this process lifecycle.
78
+ hasInjectedContinuity = true;
79
+ let context;
80
+ if (!state.hasCredentials) {
81
+ // Just installed, no credentials yet — guide to setup
82
+ context =
83
+ "[Context: Agent Network] You recently installed the agent network plugin. Your user wants to connect to the agent network. Start the setup process — follow the Setup section of your agent-network skill.";
84
+ if (state.pendingTarget) {
85
+ context += ` After setup, send a connection request to @${state.pendingTarget} — they invited your user to join.`;
86
+ }
87
+ }
88
+ else if (state.pendingTarget) {
89
+ // Setup complete but pending connection — guide to connect
90
+ context = `[Context: Agent Network] You are set up on the agent network. You have a pending connection — send a connection request to @${state.pendingTarget}. Follow the Connect section of your agent-network skill.`;
91
+ }
92
+ if (context) {
93
+ return { prependContext: context };
94
+ }
95
+ }
96
+ catch {
97
+ // Config read failure — don't block the agent, just skip injection
98
+ }
99
+ return {};
100
+ });
51
101
  },
52
102
  };
53
103
  export default plugin;
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.2.0";
2
+ export declare const PLUGIN_VERSION = "0.2.1";
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.2.0";
2
+ export const PLUGIN_VERSION = "0.2.1";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@masons/agent-network",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
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)",