@masons/agent-network 0.6.24 → 0.6.26
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/dist/channel-setup.d.ts +3 -2
- package/dist/channel-setup.d.ts.map +1 -1
- package/dist/channel-setup.js +177 -76
- package/dist/connector-client.d.ts.map +1 -1
- package/dist/connector-client.js +4 -2
- package/dist/handoff.d.ts +13 -0
- package/dist/handoff.d.ts.map +1 -1
- package/dist/handoff.js +42 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +6 -4
- package/dist/tools.d.ts +0 -1
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +55 -42
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/skills/agent-network/SKILL.md +11 -10
package/dist/channel-setup.d.ts
CHANGED
|
@@ -4,9 +4,10 @@ interface StartChannelSetupOptions {
|
|
|
4
4
|
idpBaseUrl: string;
|
|
5
5
|
idpBaseUrlIsDefault?: boolean;
|
|
6
6
|
invitedBy?: string;
|
|
7
|
+
startOver?: boolean;
|
|
7
8
|
}
|
|
8
9
|
export interface ChannelSetupResult {
|
|
9
|
-
status: "pending" | "completed" | "expired" | "failed";
|
|
10
|
+
status: "pending" | "completed" | "linked" | "expired" | "failed";
|
|
10
11
|
handoffUrl?: string;
|
|
11
12
|
expiresAt?: number;
|
|
12
13
|
message?: string;
|
|
@@ -14,7 +15,7 @@ export interface ChannelSetupResult {
|
|
|
14
15
|
export declare function getDefaultChannelSetupOptions(): StartChannelSetupOptions;
|
|
15
16
|
export declare function startOrGetChannelSetup(options: StartChannelSetupOptions): Promise<ChannelSetupResult>;
|
|
16
17
|
export declare function getChannelSetupStatus(): ChannelSetupResult | null;
|
|
17
|
-
export declare function
|
|
18
|
+
export declare function getReportableSetupStatus(): ChannelSetupResult | null;
|
|
18
19
|
export declare function _resetChannelSetupForTesting(): void;
|
|
19
20
|
export declare const CHANNEL_SETUP_TTL_MS: number;
|
|
20
21
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel-setup.d.ts","sourceRoot":"","sources":["../src/channel-setup.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"channel-setup.d.ts","sourceRoot":"","sources":["../src/channel-setup.ts"],"names":[],"mappings":"AA+BA,UAAU,wBAAwB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IAEnB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAM9B,SAAS,CAAC,EAAE,MAAM,CAAC;IAOnB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AA4CD,MAAM,WAAW,kBAAkB;IAKjC,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IAClE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AA4BD,wBAAgB,6BAA6B,IAAI,wBAAwB,CAKxE;AAWD,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,kBAAkB,CAAC,CAqB7B;AAyDD,wBAAgB,qBAAqB,IAAI,kBAAkB,GAAG,IAAI,CAQjE;AAaD,wBAAgB,wBAAwB,IAAI,kBAAkB,GAAG,IAAI,CAOpE;AAgOD,wBAAgB,4BAA4B,IAAI,IAAI,CAInD;AAED,eAAO,MAAM,oBAAoB,QAAqB,CAAC"}
|
package/dist/channel-setup.js
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
import createDebug from "debug";
|
|
2
|
-
import { readExistingConnectorUrl } from "./config.js";
|
|
2
|
+
import { hasApiKey, readExistingConnectorUrl, requireApiKey, requirePlatformConfig, } from "./config.js";
|
|
3
3
|
import { resolveConnectorUrlForSetup } from "./connector-url-boundary.js";
|
|
4
|
-
import { beginBridgeHandoff, completeBridgeHandoff, DEFAULT_IDP_BASE_URL, HANDOFF_TIMEOUT_MS, SetupFlowError, } from "./handoff.js";
|
|
4
|
+
import { beginBridgeHandoff, collectBridgeHandoffOnce, completeBridgeHandoff, DEFAULT_IDP_BASE_URL, HANDOFF_TIMEOUT_MS, SetupFlowError, } from "./handoff.js";
|
|
5
5
|
import { acceptBridgeHandoff } from "./handoff-acceptance.js";
|
|
6
|
-
import {
|
|
6
|
+
import { classifyIdentityError, formatCanonicalNode, } from "./identity-format.js";
|
|
7
|
+
import { DEFAULT_API_HOST, getIdentity, } from "./platform-client.js";
|
|
7
8
|
const dbg = createDebug("agent-network:channel-setup");
|
|
9
|
+
const GENERIC_EXPIRY_MESSAGE = "The previous Link URL expired before the browser handoff completed.";
|
|
10
|
+
const GONE_MESSAGE = "That Link session is no longer on the handoff bridge — it expired, or its runtime key was already delivered — so it cannot complete.";
|
|
11
|
+
const SUPERSEDED_MESSAGE = "A newer Link session replaced this one while it was completing, so the runtime key that session delivered was discarded. Nothing changed — this runtime still uses the credential it had before.";
|
|
12
|
+
const DURABLE_BINDING_NOTE = [
|
|
13
|
+
"This result reflects the current binding — the runtime key this Runtime holds, confirmed with the network just now.",
|
|
14
|
+
"To re-link or change Node, call masons_link with start_over: true.",
|
|
15
|
+
].join("\n");
|
|
8
16
|
let pendingSetup = null;
|
|
9
17
|
let lastSetupStatus = null;
|
|
18
|
+
let setupSeq = 0;
|
|
19
|
+
let lastRecordedSeq = 0;
|
|
10
20
|
export function getDefaultChannelSetupOptions() {
|
|
11
21
|
return {
|
|
12
22
|
apiHost: DEFAULT_API_HOST,
|
|
@@ -14,50 +24,52 @@ export function getDefaultChannelSetupOptions() {
|
|
|
14
24
|
};
|
|
15
25
|
}
|
|
16
26
|
export async function startOrGetChannelSetup(options) {
|
|
27
|
+
if (options.startOver)
|
|
28
|
+
return await startNewSession(options);
|
|
17
29
|
const active = getActivePendingSetup();
|
|
18
30
|
if (active) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
expiresAt: active.session.expiresAt,
|
|
23
|
-
};
|
|
31
|
+
const collected = await collectActiveSetup(active);
|
|
32
|
+
if (collected)
|
|
33
|
+
return collected;
|
|
24
34
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
35
|
+
const reportable = getReportableSetupStatus();
|
|
36
|
+
if (reportable)
|
|
37
|
+
return reportable;
|
|
38
|
+
const live = getActivePendingSetup();
|
|
39
|
+
if (live)
|
|
40
|
+
return pendingResult(live);
|
|
41
|
+
const durable = await reportDurableBinding(options);
|
|
42
|
+
if (durable)
|
|
43
|
+
return durable;
|
|
44
|
+
return await startNewSession(options);
|
|
45
|
+
}
|
|
46
|
+
async function reportDurableBinding(options) {
|
|
47
|
+
if (!hasApiKey())
|
|
48
|
+
return null;
|
|
49
|
+
let node;
|
|
50
|
+
try {
|
|
51
|
+
node = await getIdentity(requirePlatformConfig(), requireApiKey());
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
if (classifyIdentityError(err) === null)
|
|
55
|
+
throw err;
|
|
56
|
+
dbg("the stored runtime key could not be verified before minting: %O", err);
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
if (node === null)
|
|
60
|
+
return null;
|
|
61
|
+
const lines = [formatCanonicalNode("Linked", node), DURABLE_BINDING_NOTE];
|
|
62
|
+
if (options.invitedBy)
|
|
63
|
+
lines.push(invitationFollowThrough(options.invitedBy));
|
|
64
|
+
return { status: "linked", message: lines.join("\n") };
|
|
65
|
+
}
|
|
66
|
+
function invitationFollowThrough(invitedBy) {
|
|
67
|
+
return `This call carried an invitation from @${invitedBy}. The binding above already stands, so nothing was recorded to act on later — propose the connection now with masons_send_connection_request to @${invitedBy}.`;
|
|
51
68
|
}
|
|
52
69
|
export function getChannelSetupStatus() {
|
|
53
70
|
const active = getActivePendingSetup();
|
|
54
|
-
if (active)
|
|
55
|
-
return
|
|
56
|
-
status: "pending",
|
|
57
|
-
handoffUrl: active.session.handoffUrl,
|
|
58
|
-
expiresAt: active.session.expiresAt,
|
|
59
|
-
};
|
|
60
|
-
}
|
|
71
|
+
if (active)
|
|
72
|
+
return pendingResult(active);
|
|
61
73
|
if (!lastSetupStatus)
|
|
62
74
|
return null;
|
|
63
75
|
return {
|
|
@@ -65,31 +77,76 @@ export function getChannelSetupStatus() {
|
|
|
65
77
|
message: lastSetupStatus.message,
|
|
66
78
|
};
|
|
67
79
|
}
|
|
68
|
-
export function
|
|
69
|
-
const
|
|
70
|
-
if (
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
80
|
+
export function getReportableSetupStatus() {
|
|
81
|
+
const recorded = lastSetupStatus;
|
|
82
|
+
if (!recorded)
|
|
83
|
+
return null;
|
|
84
|
+
if (pendingSetup?.seq === recorded.seq)
|
|
85
|
+
return null;
|
|
86
|
+
if (recorded.status === "completed")
|
|
87
|
+
return reportStatus(recorded);
|
|
88
|
+
if (!recorded.reported)
|
|
89
|
+
return reportStatus(recorded);
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
function pendingResult(record) {
|
|
93
|
+
return {
|
|
94
|
+
status: "pending",
|
|
95
|
+
handoffUrl: record.session.handoffUrl,
|
|
96
|
+
expiresAt: record.session.expiresAt,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function reportStatus(status) {
|
|
100
|
+
status.reported = true;
|
|
101
|
+
return { status: status.status, message: status.message };
|
|
102
|
+
}
|
|
103
|
+
function storedResult(stored) {
|
|
104
|
+
return stored ? reportStatus(stored) : null;
|
|
74
105
|
}
|
|
75
106
|
function getActivePendingSetup() {
|
|
76
107
|
if (!pendingSetup)
|
|
77
108
|
return null;
|
|
78
109
|
if (Date.now() < pendingSetup.session.expiresAt)
|
|
79
110
|
return pendingSetup;
|
|
80
|
-
|
|
81
|
-
status: "expired",
|
|
82
|
-
message: "The previous Link URL expired before the browser handoff completed.",
|
|
83
|
-
finishedAt: Date.now(),
|
|
84
|
-
};
|
|
111
|
+
const lapsed = pendingSetup;
|
|
85
112
|
pendingSetup = null;
|
|
113
|
+
recordSetupStatus(lapsed, "expired", GENERIC_EXPIRY_MESSAGE, false);
|
|
86
114
|
return null;
|
|
87
115
|
}
|
|
88
|
-
async function
|
|
116
|
+
async function collectActiveSetup(record) {
|
|
117
|
+
let collection;
|
|
118
|
+
try {
|
|
119
|
+
collection = await collectBridgeHandoffOnce(record.session);
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
dbg("owner-invoked collection could not reach the bridge: %O", err);
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
switch (collection.outcome) {
|
|
126
|
+
case "delivered":
|
|
127
|
+
return storedResult(await acceptCollectedHandoff(record, collection.handoff));
|
|
128
|
+
case "spoiled":
|
|
129
|
+
return storedResult(settle(record, isExpiryError(collection.error) ? "expired" : "failed", collection.error.message));
|
|
130
|
+
case "gone":
|
|
131
|
+
return storedResult(collectGoneSession(record));
|
|
132
|
+
default:
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function collectGoneSession(record) {
|
|
137
|
+
if (!record.collected)
|
|
138
|
+
return settle(record, "expired", GONE_MESSAGE);
|
|
139
|
+
const settled = lastSetupStatus;
|
|
140
|
+
if (settled?.seq === record.seq && settled.settled)
|
|
141
|
+
return settled;
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
async function acceptCollectedHandoff(record, handoff) {
|
|
145
|
+
record.collected = true;
|
|
146
|
+
if (pendingSetup !== record) {
|
|
147
|
+
return recordSetupStatus(record, "failed", SUPERSEDED_MESSAGE, true);
|
|
148
|
+
}
|
|
89
149
|
try {
|
|
90
|
-
const handoff = await completeBridgeHandoff(record.session);
|
|
91
|
-
if (pendingSetup !== record)
|
|
92
|
-
return;
|
|
93
150
|
const receipt = await acceptBridgeHandoff({
|
|
94
151
|
handoff,
|
|
95
152
|
apiHost: record.apiHost,
|
|
@@ -98,31 +155,74 @@ async function completePendingSetup(record) {
|
|
|
98
155
|
pendingTarget: record.invitedBy,
|
|
99
156
|
expiresAt: record.session.expiresAt,
|
|
100
157
|
});
|
|
101
|
-
|
|
102
|
-
status: "completed",
|
|
103
|
-
message: receipt,
|
|
104
|
-
finishedAt: Date.now(),
|
|
105
|
-
};
|
|
158
|
+
return settle(record, "completed", receipt);
|
|
106
159
|
}
|
|
107
160
|
catch (err) {
|
|
108
|
-
|
|
109
|
-
return;
|
|
110
|
-
lastSetupStatus = {
|
|
111
|
-
status: isExpiryError(err) ? "expired" : "failed",
|
|
112
|
-
message: safeSetupErrorMessage(err),
|
|
113
|
-
finishedAt: Date.now(),
|
|
114
|
-
};
|
|
161
|
+
return settle(record, isExpiryError(err) ? "expired" : "failed", safeSetupErrorMessage(err));
|
|
115
162
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
163
|
+
}
|
|
164
|
+
function settle(record, status, message) {
|
|
165
|
+
if (pendingSetup === record)
|
|
166
|
+
pendingSetup = null;
|
|
167
|
+
return recordSetupStatus(record, status, message, true);
|
|
168
|
+
}
|
|
169
|
+
async function startNewSession(options) {
|
|
170
|
+
const existingConnectorUrl = await readExistingConnectorUrl();
|
|
171
|
+
const connectorUrl = resolveConnectorUrlForSetup({
|
|
172
|
+
apiHost: options.apiHost,
|
|
173
|
+
existingConnectorUrl,
|
|
174
|
+
configuredConnectorUrl: options.connectorUrl,
|
|
175
|
+
});
|
|
176
|
+
const session = await beginBridgeHandoff({
|
|
177
|
+
apiHost: options.apiHost,
|
|
178
|
+
idpBaseUrl: options.idpBaseUrl,
|
|
179
|
+
idpBaseUrlIsDefault: options.idpBaseUrlIsDefault,
|
|
180
|
+
});
|
|
181
|
+
const record = {
|
|
182
|
+
seq: ++setupSeq,
|
|
183
|
+
session,
|
|
184
|
+
apiHost: options.apiHost,
|
|
185
|
+
connectorUrl,
|
|
186
|
+
idpBaseUrl: options.idpBaseUrl,
|
|
187
|
+
invitedBy: options.invitedBy,
|
|
188
|
+
collected: false,
|
|
189
|
+
};
|
|
190
|
+
pendingSetup = record;
|
|
191
|
+
lastSetupStatus = null;
|
|
192
|
+
void completePendingSetup(record);
|
|
193
|
+
return pendingResult(record);
|
|
194
|
+
}
|
|
195
|
+
async function completePendingSetup(record) {
|
|
196
|
+
let handoff;
|
|
197
|
+
try {
|
|
198
|
+
handoff = await completeBridgeHandoff(record.session);
|
|
199
|
+
}
|
|
200
|
+
catch (err) {
|
|
201
|
+
recordSetupStatus(record, isExpiryError(err) ? "expired" : "failed", safeSetupErrorMessage(err), false);
|
|
202
|
+
return;
|
|
120
203
|
}
|
|
204
|
+
await acceptCollectedHandoff(record, handoff);
|
|
121
205
|
}
|
|
122
|
-
function
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
206
|
+
function recordSetupStatus(record, status, message, settled) {
|
|
207
|
+
const next = {
|
|
208
|
+
seq: record.seq,
|
|
209
|
+
status,
|
|
210
|
+
message,
|
|
211
|
+
reported: false,
|
|
212
|
+
settled,
|
|
213
|
+
};
|
|
214
|
+
if (!canRecord(next))
|
|
215
|
+
return null;
|
|
216
|
+
lastSetupStatus = next;
|
|
217
|
+
lastRecordedSeq = next.seq;
|
|
218
|
+
return next;
|
|
219
|
+
}
|
|
220
|
+
function canRecord(next) {
|
|
221
|
+
if (next.seq !== lastRecordedSeq)
|
|
222
|
+
return next.seq > lastRecordedSeq;
|
|
223
|
+
if (!lastSetupStatus)
|
|
224
|
+
return false;
|
|
225
|
+
return next.settled && !lastSetupStatus.settled;
|
|
126
226
|
}
|
|
127
227
|
function isExpiryError(err) {
|
|
128
228
|
if (!(err instanceof SetupFlowError))
|
|
@@ -138,5 +238,6 @@ function safeSetupErrorMessage(err) {
|
|
|
138
238
|
export function _resetChannelSetupForTesting() {
|
|
139
239
|
pendingSetup = null;
|
|
140
240
|
lastSetupStatus = null;
|
|
241
|
+
lastRecordedSeq = 0;
|
|
141
242
|
}
|
|
142
243
|
export const CHANNEL_SETUP_TTL_MS = HANDOFF_TIMEOUT_MS;
|
|
@@ -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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"}
|
package/dist/connector-client.js
CHANGED
|
@@ -476,8 +476,10 @@ export class ConnectorClient extends EventEmitter {
|
|
|
476
476
|
this.registration = { state: "replaced" };
|
|
477
477
|
const msg = "This agent was claimed by another Runtime " +
|
|
478
478
|
"(this Runtime disconnected). " +
|
|
479
|
-
"
|
|
480
|
-
"
|
|
479
|
+
"To drive this agent from here again, ask the owner to call " +
|
|
480
|
+
"masons_link with start_over: true in this conversation; as a last " +
|
|
481
|
+
"resort, `openclaw channels login --channel agent-network` in a " +
|
|
482
|
+
"terminal does the same.";
|
|
481
483
|
this.emit("error", new Error(msg));
|
|
482
484
|
if (wasRegistering) {
|
|
483
485
|
this.rejectRegister(new Error(msg));
|
package/dist/handoff.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type KeyObject } from "node:crypto";
|
|
2
|
+
import { SetupFlowError } from "./handoff-deadline.js";
|
|
2
3
|
export { SetupFlowError } from "./handoff-deadline.js";
|
|
3
4
|
export declare const DEFAULT_IDP_BASE_URL = "https://preview.masons.ai";
|
|
4
5
|
export declare const HANDOFF_TIMEOUT_MS: number;
|
|
@@ -24,4 +25,16 @@ export interface BeginBridgeHandoffOptions {
|
|
|
24
25
|
}
|
|
25
26
|
export declare function beginBridgeHandoff(options: BeginBridgeHandoffOptions): Promise<BridgeHandoffSession>;
|
|
26
27
|
export declare function completeBridgeHandoff(session: BridgeHandoffSession): Promise<BridgeHandoffResult>;
|
|
28
|
+
export type BridgeCollection = {
|
|
29
|
+
outcome: "pending";
|
|
30
|
+
} | {
|
|
31
|
+
outcome: "gone";
|
|
32
|
+
} | {
|
|
33
|
+
outcome: "delivered";
|
|
34
|
+
handoff: BridgeHandoffResult;
|
|
35
|
+
} | {
|
|
36
|
+
outcome: "spoiled";
|
|
37
|
+
error: SetupFlowError;
|
|
38
|
+
};
|
|
39
|
+
export declare function collectBridgeHandoffOnce(session: BridgeHandoffSession): Promise<BridgeCollection>;
|
|
27
40
|
//# sourceMappingURL=handoff.d.ts.map
|
package/dist/handoff.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handoff.d.ts","sourceRoot":"","sources":["../src/handoff.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,SAAS,EAEf,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"handoff.d.ts","sourceRoot":"","sources":["../src/handoff.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,SAAS,EAEf,MAAM,aAAa,CAAC;AAErB,OAAO,EAEL,cAAc,EACf,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAavD,eAAO,MAAM,oBAAoB,8BAA8B,CAAC;AAWhE,eAAO,MAAM,kBAAkB,QAAiB,CAAC;AA0BjD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1D;AAQD,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAElB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAUhB,UAAU,EAAE,SAAS,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IAMnB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAMD,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,oBAAoB,CAAC,CAiE/B;AAKD,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,mBAAmB,CAAC,CAO9B;AAUD,MAAM,MAAM,gBAAgB,GACxB;IAAE,OAAO,EAAE,SAAS,CAAA;CAAE,GACtB;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,GACnB;IAAE,OAAO,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,mBAAmB,CAAA;CAAE,GACtD;IAAE,OAAO,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,cAAc,CAAA;CAAE,CAAC;AASlD,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,gBAAgB,CAAC,CA8B3B"}
|
package/dist/handoff.js
CHANGED
|
@@ -55,6 +55,44 @@ export async function beginBridgeHandoff(options) {
|
|
|
55
55
|
}
|
|
56
56
|
export async function completeBridgeHandoff(session) {
|
|
57
57
|
const envelope = await pollForCompletion(session.apiBase, session.sessionId, session.expiresAt);
|
|
58
|
+
return readBridgeEnvelope(session, envelope);
|
|
59
|
+
}
|
|
60
|
+
export async function collectBridgeHandoffOnce(session) {
|
|
61
|
+
assertHandoffDeadlineActive(session.expiresAt);
|
|
62
|
+
const res = await apiFetch(pollUrl(session.apiBase, session.sessionId), {
|
|
63
|
+
method: "GET",
|
|
64
|
+
});
|
|
65
|
+
if (res.status === 404)
|
|
66
|
+
return { outcome: "gone" };
|
|
67
|
+
if (!res.ok)
|
|
68
|
+
return { outcome: "pending" };
|
|
69
|
+
let body;
|
|
70
|
+
try {
|
|
71
|
+
body = (await res.json());
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
return { outcome: "spoiled", error: unreadableDelivery(err) };
|
|
75
|
+
}
|
|
76
|
+
if (body.status !== "completed" || !body.payload)
|
|
77
|
+
return { outcome: "pending" };
|
|
78
|
+
try {
|
|
79
|
+
return {
|
|
80
|
+
outcome: "delivered",
|
|
81
|
+
handoff: readBridgeEnvelope(session, body.payload),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
return {
|
|
86
|
+
outcome: "spoiled",
|
|
87
|
+
error: err instanceof SetupFlowError ? err : unreadableDelivery(err),
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function unreadableDelivery(err) {
|
|
92
|
+
const detail = err instanceof Error ? err.message : "unknown error";
|
|
93
|
+
return new SetupFlowError(`The handoff bridge released this Link's runtime key but the response could not be read (${detail}), so the key was lost with it.`);
|
|
94
|
+
}
|
|
95
|
+
function readBridgeEnvelope(session, envelope) {
|
|
58
96
|
let payload;
|
|
59
97
|
try {
|
|
60
98
|
payload = decryptBridgeEnvelope(session.privateKey, envelope);
|
|
@@ -81,12 +119,15 @@ export async function completeBridgeHandoff(session) {
|
|
|
81
119
|
},
|
|
82
120
|
};
|
|
83
121
|
}
|
|
122
|
+
function pollUrl(apiBase, sessionId) {
|
|
123
|
+
return `${apiBase}/v1/cli-handoff/${encodeURIComponent(sessionId)}/poll`;
|
|
124
|
+
}
|
|
84
125
|
async function pollForCompletion(apiBase, sessionId, expiresAt) {
|
|
85
126
|
let lastNetworkError;
|
|
86
127
|
while (Date.now() < expiresAt) {
|
|
87
128
|
let res;
|
|
88
129
|
try {
|
|
89
|
-
res = await apiFetch(
|
|
130
|
+
res = await apiFetch(pollUrl(apiBase, sessionId), { method: "GET" });
|
|
90
131
|
}
|
|
91
132
|
catch (err) {
|
|
92
133
|
if (err instanceof PlatformNetworkError) {
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAUrE,OAAO,EACL,kCAAkC,EAEnC,MAAM,oCAAoC,CAAC;AA8D5C,wBAAgB,uBAAuB,CACrC,eAAe,EAAE,MAAM,GAAG,SAAS,EACnC,iBAAiB,EAAE,MAAM,GAAG,IAAI,EAChC,mBAAmB,GAAE,mBAAmB,GAAG,IAA+B,GACzE,MAAM,GAAG,SAAS,CA6EpB;AAKD,UAAU,iBAAiB;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IACjD,YAAY,CACV,IAAI,EAAE,OAAO,EACb,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAC3C,IAAI,CAAC;IACR,yBAAyB,CAAC,MAAM,EAAE;QAChC,EAAE,EAAE,MAAM,CAAC;QACX,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,OAAO,kCAAkC,CAAC;KACrD,GAAG,IAAI,CAAC;IACT,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,GAAG,IAAI,CAAC;CACnE;AAqCD,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAaI,iBAAiB;
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAUrE,OAAO,EACL,kCAAkC,EAEnC,MAAM,oCAAoC,CAAC;AA8D5C,wBAAgB,uBAAuB,CACrC,eAAe,EAAE,MAAM,GAAG,SAAS,EACnC,iBAAiB,EAAE,MAAM,GAAG,IAAI,EAChC,mBAAmB,GAAE,mBAAmB,GAAG,IAA+B,GACzE,MAAM,GAAG,SAAS,CA6EpB;AAKD,UAAU,iBAAiB;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,CAAC,IAAI,EAAE;QAAE,MAAM,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IACjD,YAAY,CACV,IAAI,EAAE,OAAO,EACb,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAC3C,IAAI,CAAC;IACR,yBAAyB,CAAC,MAAM,EAAE;QAChC,EAAE,EAAE,MAAM,CAAC;QACX,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,OAAO,kCAAkC,CAAC;KACrD,GAAG,IAAI,CAAC;IACT,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,GAAG,IAAI,CAAC;CACnE;AAqCD,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAaI,iBAAiB;CAsahC,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
package/dist/plugin.js
CHANGED
|
@@ -194,10 +194,12 @@ const plugin = {
|
|
|
194
194
|
if (!state.hasCredentials) {
|
|
195
195
|
dynamicContext =
|
|
196
196
|
"[Context: Agent Network] You recently installed the agent network plugin " +
|
|
197
|
-
"but it is not yet authorized.
|
|
198
|
-
"OpenClaw owner, call masons_link to
|
|
199
|
-
"
|
|
200
|
-
"
|
|
197
|
+
"but it is not yet authorized. Link finishes in this conversation: if your " +
|
|
198
|
+
"current channel sender is the verified OpenClaw owner, call masons_link to " +
|
|
199
|
+
"generate a MASONS handoff URL here. If owner authority is unavailable here, " +
|
|
200
|
+
"ask the owner to start Link from a channel their OpenClaw is configured for; " +
|
|
201
|
+
"only as a last resort, `openclaw channels login --channel agent-network` in a " +
|
|
202
|
+
"terminal. Browser sign-in handles " +
|
|
201
203
|
"agent selection or creation. After the Link completes, OpenClaw will reload and " +
|
|
202
204
|
"the agent network tools will become available.";
|
|
203
205
|
if (state.pendingTarget) {
|
package/dist/tools.d.ts
CHANGED
|
@@ -26,7 +26,6 @@ interface ToolApi {
|
|
|
26
26
|
}): void;
|
|
27
27
|
}
|
|
28
28
|
export declare function _resetToolsForTesting(): void;
|
|
29
|
-
export declare function terminalSetupInstructions(): string;
|
|
30
29
|
export declare function ownerRefusalText(reason: "known-non-owner" | "ambiguous"): string;
|
|
31
30
|
export declare function formatChannelSetupResult(result: ChannelSetupResult): string;
|
|
32
31
|
export declare function registerTools(api: ToolApi): void;
|
package/dist/tools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAuBA,OAAO,EAEL,KAAK,kBAAkB,
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAuBA,OAAO,EAEL,KAAK,kBAAkB,EAGxB,MAAM,oBAAoB,CAAC;AA0D5B,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,WAAW;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,KAAK,WAAW,GAAG,CAAC,GAAG,EAAE,WAAW,KAAK,cAAc,GAAG,IAAI,GAAG,SAAS,CAAC;AAE3E,UAAU,OAAO;IACf,YAAY,CACV,IAAI,EAAE,cAAc,GAAG,WAAW,EAWlC,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,GAC7D,IAAI,CAAC;CACT;AAkED,wBAAgB,qBAAqB,IAAI,IAAI,CAG5C;AAkYD,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,iBAAiB,GAAG,WAAW,GACtC,MAAM,CAqBR;AAGD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAyC3E;AA+CD,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAqoChD"}
|
package/dist/tools.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
2
|
import pluginManifest from "../openclaw.plugin.json" with { type: "json" };
|
|
3
3
|
import { getOwnerPassportAddress } from "./channel.js";
|
|
4
|
-
import { _resetChannelSetupForTesting,
|
|
4
|
+
import { _resetChannelSetupForTesting, getDefaultChannelSetupOptions, startOrGetChannelSetup, } from "./channel-setup.js";
|
|
5
5
|
import { clearTargetHandle, extractNetworkConfig, getConnectorClient, getDmScope, getPendingTarget, hasApiKey, isProfileNeeded, markProfileComplete, removeIdentityLinks, requireApiKey, requireConversationManager, requirePlatformConfig, writeIdentityLinks, } from "./config.js";
|
|
6
6
|
import { getOwnerHandle } from "./environment-context.js";
|
|
7
7
|
import { classifyIdentityError, formatCanonicalNode, formatKindLabel, } from "./identity-format.js";
|
|
@@ -142,17 +142,19 @@ function formatRegistration(outcome) {
|
|
|
142
142
|
return "none";
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
|
+
function formatChannelStateLines(client) {
|
|
146
|
+
return [
|
|
147
|
+
`Gateway channel: ${client ? client.getChannelState() : "not established"}`,
|
|
148
|
+
`Registration (this connection): ${formatRegistration(client ? client.getRegistration() : { state: "none" })}`,
|
|
149
|
+
];
|
|
150
|
+
}
|
|
145
151
|
function formatReadinessSection() {
|
|
146
152
|
const credentialsLine = hasApiKey()
|
|
147
153
|
? "Credentials: configured"
|
|
148
154
|
: "Credentials: not configured";
|
|
149
|
-
const client = getConnectorClient();
|
|
150
|
-
const channel = client ? client.getChannelState() : "not established";
|
|
151
|
-
const registration = formatRegistration(client ? client.getRegistration() : { state: "none" });
|
|
152
155
|
return [
|
|
153
156
|
credentialsLine,
|
|
154
|
-
|
|
155
|
-
`Registration (this connection): ${registration}`,
|
|
157
|
+
...formatChannelStateLines(getConnectorClient()),
|
|
156
158
|
].join("\n");
|
|
157
159
|
}
|
|
158
160
|
async function resolveIdentitySection() {
|
|
@@ -222,24 +224,6 @@ function toRecord(value) {
|
|
|
222
224
|
function stringValue(value) {
|
|
223
225
|
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
224
226
|
}
|
|
225
|
-
export function terminalSetupInstructions() {
|
|
226
|
-
return [
|
|
227
|
-
"Run this in the terminal where OpenClaw is installed:",
|
|
228
|
-
"",
|
|
229
|
-
" openclaw channels login --channel agent-network",
|
|
230
|
-
"",
|
|
231
|
-
"It will:",
|
|
232
|
-
" 1. Display a MASONS handoff URL.",
|
|
233
|
-
" 2. Open it in your browser and sign in.",
|
|
234
|
-
" 3. Pick an existing agent or create a new one.",
|
|
235
|
-
" 4. Return to the terminal after the encrypted handoff completes.",
|
|
236
|
-
" 5. Persist credentials to openclaw.json. OpenClaw reloads the channel.",
|
|
237
|
-
"",
|
|
238
|
-
"Note: on an already-linked install this is a Relink — choosing another Node here changes",
|
|
239
|
-
"which Node this OpenClaw install drives. Each install holds its own runtime key, so",
|
|
240
|
-
"relinking updates this OpenClaw install's credentials.",
|
|
241
|
-
].join("\n");
|
|
242
|
-
}
|
|
243
227
|
export function ownerRefusalText(reason) {
|
|
244
228
|
if (reason === "known-non-owner") {
|
|
245
229
|
return [
|
|
@@ -269,6 +253,7 @@ export function formatChannelSetupResult(result) {
|
|
|
269
253
|
result.handoffUrl,
|
|
270
254
|
"",
|
|
271
255
|
"Open this link in your browser, sign in, choose an agent, then come back here.",
|
|
256
|
+
"This Link is still open, so asking me again returns this same URL, not a new one — open the one above.",
|
|
272
257
|
"After browser sign-in and agent selection, OpenClaw will receive the encrypted handoff, persist the runtime key locally, and reload the channel.",
|
|
273
258
|
"This URL is sensitive Link material; only the OpenClaw owner should open it.",
|
|
274
259
|
].join("\n");
|
|
@@ -278,24 +263,40 @@ export function formatChannelSetupResult(result) {
|
|
|
278
263
|
result.message ?? "Agent Network Link completed.",
|
|
279
264
|
"",
|
|
280
265
|
"HTTP tools may work before the Gateway WebSocket is connected.",
|
|
281
|
-
|
|
266
|
+
GATEWAY_RESTART_ACTION,
|
|
267
|
+
"This result stands until the owner asks to start over: to re-link or change Node, call masons_link with start_over: true.",
|
|
282
268
|
].join("\n");
|
|
283
269
|
}
|
|
270
|
+
if (result.status === "linked") {
|
|
271
|
+
const receipt = result.message ?? "This Runtime is linked to an Agent Node.";
|
|
272
|
+
return [receipt, ...formatRealtimeGap()].join("\n");
|
|
273
|
+
}
|
|
284
274
|
if (result.status === "expired") {
|
|
285
275
|
return [
|
|
286
276
|
result.message ?? "The previous Link URL expired.",
|
|
287
|
-
"Ask again to generate a fresh owner-only Link URL, or use the terminal fallback:",
|
|
288
277
|
"",
|
|
289
|
-
|
|
278
|
+
LINK_RETRY_GUIDANCE,
|
|
290
279
|
].join("\n");
|
|
291
280
|
}
|
|
292
281
|
return [
|
|
293
282
|
result.message ?? "Agent Network Link failed.",
|
|
294
|
-
"Ask again to retry, or use the terminal fallback:",
|
|
295
283
|
"",
|
|
296
|
-
|
|
284
|
+
LINK_RETRY_GUIDANCE,
|
|
297
285
|
].join("\n");
|
|
298
286
|
}
|
|
287
|
+
const GATEWAY_RESTART_ACTION = 'If the gateway tool is available, call it with action "restart" and reason "Activate Agent Network after Link". If not, ask the user to run `openclaw gateway restart`.';
|
|
288
|
+
function formatRealtimeGap() {
|
|
289
|
+
const client = getConnectorClient();
|
|
290
|
+
if (client?.getChannelState() === "connected" &&
|
|
291
|
+
client.getRegistration().state === "accepted") {
|
|
292
|
+
return [];
|
|
293
|
+
}
|
|
294
|
+
return ["", ...formatChannelStateLines(client), GATEWAY_RESTART_ACTION];
|
|
295
|
+
}
|
|
296
|
+
const LINK_RETRY_GUIDANCE = [
|
|
297
|
+
"Call masons_link again in this conversation — the whole flow finishes here.",
|
|
298
|
+
"Last resort, only if that keeps failing: the owner can run `openclaw channels login --channel agent-network` in a terminal.",
|
|
299
|
+
].join("\n");
|
|
299
300
|
export function registerTools(api) {
|
|
300
301
|
api.registerTool((ctx = {}) => ({
|
|
301
302
|
name: "masons_link",
|
|
@@ -306,7 +307,12 @@ export function registerTools(api) {
|
|
|
306
307
|
"Agent Network tools fail with a 'no credentials' error, or when the",
|
|
307
308
|
"runtime owner wants a different MASONS agent driven by OpenClaw.",
|
|
308
309
|
"On a Runtime that is already linked, present this to the user as",
|
|
309
|
-
"Relink / Change Node — the same capability, not a second one.",
|
|
310
|
+
"Relink / Change Node — the same capability, not a second one. After a",
|
|
311
|
+
"Link has completed in this process, pass start_over: true to re-link",
|
|
312
|
+
"or link a different Node; a plain call re-reports the completed one.",
|
|
313
|
+
"To check on a Link in progress (after the owner opens the URL), call",
|
|
314
|
+
"with NO arguments — start_over would discard the pending Link and",
|
|
315
|
+
"issue a fresh URL instead of confirming the one the owner completed.",
|
|
310
316
|
"",
|
|
311
317
|
"Not to be confused with masons_link_identity: this tool binds a",
|
|
312
318
|
"Runtime to a Node. masons_link_identity aliases your owner's identity",
|
|
@@ -319,7 +325,9 @@ export function registerTools(api) {
|
|
|
319
325
|
"This tool returns a browser handoff URL on the channel where you are",
|
|
320
326
|
"running. The user opens it, signs in, picks an agent, and the encrypted",
|
|
321
327
|
"handoff completes in the background. After completion, restart the",
|
|
322
|
-
"gateway to activate realtime messaging.",
|
|
328
|
+
"gateway to activate realtime messaging. When this Runtime already",
|
|
329
|
+
"holds a verified binding and no Link is pending, it reports that",
|
|
330
|
+
"standing binding instead of issuing a URL.",
|
|
323
331
|
"",
|
|
324
332
|
"If the user is reaching this agent through the MASONS network as a",
|
|
325
333
|
"visitor (not the agent's owner), this tool refuses with an explanation",
|
|
@@ -333,6 +341,13 @@ export function registerTools(api) {
|
|
|
333
341
|
"the plugin records this as a pending connection target so the " +
|
|
334
342
|
"agent can propose a connection request automatically.",
|
|
335
343
|
})),
|
|
344
|
+
start_over: Type.Optional(Type.Boolean({
|
|
345
|
+
description: "Discard whatever this Runtime is holding — a Link still in " +
|
|
346
|
+
"progress, a Link that already completed, or a binding already " +
|
|
347
|
+
"on disk — and issue a fresh Link URL. Without it a repeat call " +
|
|
348
|
+
"re-reports what stands, which after a Gateway restart is the " +
|
|
349
|
+
"standing binding rather than the completed result.",
|
|
350
|
+
})),
|
|
336
351
|
}),
|
|
337
352
|
execute: async (_id, params) => {
|
|
338
353
|
const authority = resolveSetupAuthority();
|
|
@@ -342,15 +357,13 @@ export function registerTools(api) {
|
|
|
342
357
|
const invitedBy = typeof params.invitedBy === "string" && params.invitedBy.length > 0
|
|
343
358
|
? params.invitedBy
|
|
344
359
|
: undefined;
|
|
345
|
-
const existing = consumeChannelSetupStatus();
|
|
346
360
|
let result;
|
|
347
361
|
try {
|
|
348
|
-
result =
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
});
|
|
362
|
+
result = await startOrGetChannelSetup({
|
|
363
|
+
...getSetupOptionsFromToolContext(ctx),
|
|
364
|
+
invitedBy,
|
|
365
|
+
startOver: params.start_over === true,
|
|
366
|
+
});
|
|
354
367
|
}
|
|
355
368
|
catch (err) {
|
|
356
369
|
result = {
|
|
@@ -416,7 +429,7 @@ export function registerTools(api) {
|
|
|
416
429
|
catch (err) {
|
|
417
430
|
if (err instanceof PlatformApiError) {
|
|
418
431
|
if (err.status === 401) {
|
|
419
|
-
return textResult("Authentication failed. The runtime key may be invalid. Ask the
|
|
432
|
+
return textResult("Authentication failed. The runtime key may be invalid. Ask the owner to re-link here: call masons_link with start_over: true.");
|
|
420
433
|
}
|
|
421
434
|
if (err.status === 422) {
|
|
422
435
|
return textResult(`Validation error: ${err.message}`);
|
|
@@ -497,7 +510,7 @@ export function registerTools(api) {
|
|
|
497
510
|
: "This Services deployment does not serve the connection-request endpoint. Nothing was sent.");
|
|
498
511
|
}
|
|
499
512
|
if (err.status === 401) {
|
|
500
|
-
return textResult("Authentication failed. The runtime key may be invalid. Ask the
|
|
513
|
+
return textResult("Authentication failed. The runtime key may be invalid. Ask the owner to re-link here: call masons_link with start_over: true.");
|
|
501
514
|
}
|
|
502
515
|
return textResult(`Connection request failed: ${err.message}`);
|
|
503
516
|
}
|
|
@@ -581,7 +594,7 @@ export function registerTools(api) {
|
|
|
581
594
|
catch (err) {
|
|
582
595
|
if (err instanceof PlatformApiError) {
|
|
583
596
|
if (err.status === 401) {
|
|
584
|
-
return textResult("Authentication failed. The runtime key may be invalid. Ask the
|
|
597
|
+
return textResult("Authentication failed. The runtime key may be invalid. Ask the owner to re-link here: call masons_link with start_over: true.");
|
|
585
598
|
}
|
|
586
599
|
if (err.status === 404) {
|
|
587
600
|
return textResult("This Services deployment does not serve the packaged connection-request endpoint. Nothing was read.");
|
|
@@ -769,7 +782,7 @@ export function registerTools(api) {
|
|
|
769
782
|
catch (err) {
|
|
770
783
|
if (err instanceof PlatformApiError) {
|
|
771
784
|
if (err.status === 401) {
|
|
772
|
-
return textResult("Authentication failed. The runtime key may be invalid. Ask the
|
|
785
|
+
return textResult("Authentication failed. The runtime key may be invalid. Ask the owner to re-link here: call masons_link with start_over: true.");
|
|
773
786
|
}
|
|
774
787
|
return textResult(`Failed to list connections: ${err.message}`);
|
|
775
788
|
}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const PLUGIN_VERSION = "0.6.
|
|
1
|
+
export declare const PLUGIN_VERSION = "0.6.26";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const PLUGIN_VERSION = "0.6.
|
|
1
|
+
export const PLUGIN_VERSION = "0.6.26";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@masons/agent-network",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.26",
|
|
4
4
|
"description": "MASONS Agent Network — OpenClaw channel plugin for connecting agent runtimes to the Agent Network over MSTP.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "MASONS.ai <hello@masons.ai> (https://masons.ai)",
|
|
@@ -71,7 +71,7 @@ Check your current state and go to the right section:
|
|
|
71
71
|
|
|
72
72
|
## Link
|
|
73
73
|
|
|
74
|
-
Binding this runtime to an agent Node takes about a minute. Link
|
|
74
|
+
Binding this runtime to an agent Node takes about a minute. Link runs from an owner-verified channel through an encrypted browser handoff, and it finishes **in this conversation** — never send the owner to a terminal as your first move. Terminal login is the last resort, for when owner authority is unavailable here or Link keeps failing here.
|
|
75
75
|
|
|
76
76
|
On a runtime that is already linked, this same flow is a **Relink / Change Node** — tell the user that, and use the same tool. There is no second capability.
|
|
77
77
|
|
|
@@ -83,11 +83,7 @@ On a runtime that is already linked, this same flow is a **Relink / Change Node*
|
|
|
83
83
|
|
|
84
84
|
If the current sender is verified as the OpenClaw owner, the tool returns a MASONS handoff URL. Share the URL as ordinary chat text, on its own line, without wrapping it in backticks or a code block. Never ask for or display runtime keys, ciphertext payloads, decrypted token metadata, private key material, or debug output that looks credential-like.
|
|
85
85
|
|
|
86
|
-
If owner authority is missing, false, or ambiguous, the tool
|
|
87
|
-
|
|
88
|
-
```sh
|
|
89
|
-
openclaw channels login --channel agent-network
|
|
90
|
-
```
|
|
86
|
+
If owner authority is missing, false, or ambiguous, the tool refuses and explains why — relay that text. Where it names `openclaw channels login --channel agent-network`, that is the last resort for an owner with no channel their OpenClaw is configured for; try such a channel first.
|
|
91
87
|
|
|
92
88
|
### Step 2: User Completes Browser Handoff
|
|
93
89
|
|
|
@@ -97,7 +93,9 @@ The browser handoff page lets the owner sign in, select or create an agent, and
|
|
|
97
93
|
|
|
98
94
|
After completion:
|
|
99
95
|
|
|
100
|
-
1. Call `masons_link` again to check whether the encrypted handoff completed.
|
|
96
|
+
1. Call `masons_link` again to check whether the encrypted handoff completed. This call collects the owner's browser selection itself, so a step they already finished is confirmed here rather than costing a second browser walk. While the Link is still open the same call returns the SAME URL — pass it on, do not describe it as a new one.
|
|
97
|
+
- Some Hosts restart the Gateway the moment the runtime key is written, so a restart right after the owner says they finished is EXPECTED here — it is the success signal, not a fault.
|
|
98
|
+
- The restarted process confirms the Link as a **Linked** receipt (the present binding) instead of an **Accepted** one (the acceptance moment). Both mean the Link succeeded: relay it and move on, never re-issue a URL.
|
|
101
99
|
2. If `masons_link` reports the Link completed, restart the Gateway to activate realtime messaging:
|
|
102
100
|
- Prefer the host `gateway` tool with `action`: `"restart"` and `reason`: `"Activate Agent Network after Link"`.
|
|
103
101
|
- If the `gateway` tool is unavailable, tell the user to run `openclaw gateway restart`.
|
|
@@ -110,10 +108,13 @@ After completion:
|
|
|
110
108
|
|
|
111
109
|
### Errors
|
|
112
110
|
|
|
113
|
-
- If
|
|
114
|
-
- If
|
|
111
|
+
- If `masons_link` reports the Link expired or failed, that session is over: call `masons_link` again in this conversation. On a Runtime that still holds a working binding that call reports the standing binding, so add `start_over: true` to get a fresh URL. Do not offer the terminal on a first failure.
|
|
112
|
+
- If `masons_link` reports the Link completed or Linked and the user wants to re-link or change Node, call it with `start_over: true` — a plain call re-reports the current binding.
|
|
113
|
+
- Only after Link has failed here repeatedly, name `openclaw channels login --channel agent-network` as the last resort, and say so.
|
|
114
|
+
- If any other tool returns an error, explain it simply and suggest next steps.
|
|
115
|
+
- If the CLI says a handle is rejected or taken, ask the user to retry and choose a different handle.
|
|
115
116
|
- If network errors, suggest checking internet connection.
|
|
116
|
-
- If the tools still report no runtime key after
|
|
117
|
+
- If the tools still report no runtime key after a completed Link, read `references/troubleshooting.md`.
|
|
117
118
|
|
|
118
119
|
## Profile
|
|
119
120
|
|