@masons/agent-network 0.6.18 → 0.6.20

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-setup.d.ts","sourceRoot":"","sources":["../src/channel-setup.ts"],"names":[],"mappings":"AAgBA,UAAU,wBAAwB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IAMnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAuBD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAKD,wBAAgB,6BAA6B,IAAI,wBAAwB,CAKxE;AAED,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,kBAAkB,CAAC,CAqC7B;AAED,wBAAgB,qBAAqB,IAAI,kBAAkB,GAAG,IAAI,CAejE;AAED,wBAAgB,yBAAyB,IAAI,kBAAkB,GAAG,IAAI,CAMrE;AAkED,wBAAgB,4BAA4B,IAAI,IAAI,CAGnD;AAED,eAAO,MAAM,oBAAoB,QAAqB,CAAC"}
1
+ {"version":3,"file":"channel-setup.d.ts","sourceRoot":"","sources":["../src/channel-setup.ts"],"names":[],"mappings":"AAiBA,UAAU,wBAAwB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IAMnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAuBD,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAKD,wBAAgB,6BAA6B,IAAI,wBAAwB,CAKxE;AAED,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,kBAAkB,CAAC,CAqC7B;AAED,wBAAgB,qBAAqB,IAAI,kBAAkB,GAAG,IAAI,CAejE;AAED,wBAAgB,yBAAyB,IAAI,kBAAkB,GAAG,IAAI,CAMrE;AAmED,wBAAgB,4BAA4B,IAAI,IAAI,CAGnD;AAED,eAAO,MAAM,oBAAoB,QAAqB,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import { readExistingConnectorUrl, writeCredentials, } from "./config.js";
2
2
  import { resolveConnectorUrlForSetup } from "./connector-url-boundary.js";
3
3
  import { beginBridgeHandoff, completeBridgeHandoff, DEFAULT_IDP_BASE_URL, HANDOFF_TIMEOUT_MS, SetupFlowError, } from "./handoff.js";
4
+ import { assertHandoffDeadlineActive } from "./handoff-deadline.js";
4
5
  import { DEFAULT_API_HOST } from "./platform-client.js";
5
6
  let pendingSetup = null;
6
7
  let lastSetupStatus = null;
@@ -91,7 +92,7 @@ async function completePendingSetup(record) {
91
92
  connectorUrl: record.connectorUrl,
92
93
  token: handoff.token,
93
94
  };
94
- await writeCredentials(creds, record.apiHost, record.idpBaseUrl, record.invitedBy);
95
+ await writeCredentials(creds, record.apiHost, record.idpBaseUrl, record.invitedBy, () => assertHandoffDeadlineActive(record.session.expiresAt));
95
96
  lastSetupStatus = {
96
97
  status: "completed",
97
98
  agentHandle: handoff.agent.handle,
package/dist/channel.d.ts CHANGED
@@ -1,8 +1,13 @@
1
- import type { ChannelPlugin } from "openclaw/plugin-sdk/channel-core";
1
+ import type { ChannelPlugin, PluginRuntime } from "openclaw/plugin-sdk/channel-core";
2
2
  import type { AgentNetworkAccount } from "./config-schema.js";
3
3
  export declare function getOwnerPassportAddress(): string | null;
4
4
  export declare function consumeIdentityLinkingNudge(): boolean;
5
5
  export declare function _setNudgePendingForTesting(value: boolean): void;
6
+ export declare function buildServicesRetainedRuntimeSessionKey(buildAgentSessionKey: PluginRuntime["channel"]["routing"]["buildAgentSessionKey"], params: {
7
+ agentId: string;
8
+ accountId: string;
9
+ messageRef: string;
10
+ }): string;
6
11
  declare function withAgentNetworkSilentReplyPolicy(cfg: Record<string, unknown>, servicesRetained?: boolean): Record<string, unknown>;
7
12
  export declare const _withAgentNetworkSilentReplyPolicyForTesting: typeof withAgentNetworkSilentReplyPolicy;
8
13
  export declare const agentNetworkChannel: ChannelPlugin<AgentNetworkAccount>;
@@ -1 +1 @@
1
- {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,aAAa,EAEd,MAAM,kCAAkC,CAAC;AAa1C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAsD9D,wBAAgB,uBAAuB,IAAI,MAAM,GAAG,IAAI,CAEvD;AAOD,wBAAgB,2BAA2B,IAAI,OAAO,CAIrD;AAGD,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAE/D;AAaD,iBAAS,iCAAiC,CACxC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,gBAAgB,UAAQ,GACvB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAuCzB;AAED,eAAO,MAAM,4CAA4C,0CACtB,CAAC;AAyiBpC,eAAO,MAAM,mBAAmB,EAAE,aAAa,CAAC,mBAAmB,CAoRlE,CAAC"}
1
+ {"version":3,"file":"channel.d.ts","sourceRoot":"","sources":["../src/channel.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,aAAa,EACb,aAAa,EACd,MAAM,kCAAkC,CAAC;AAa1C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAuD9D,wBAAgB,uBAAuB,IAAI,MAAM,GAAG,IAAI,CAEvD;AAOD,wBAAgB,2BAA2B,IAAI,OAAO,CAIrD;AAGD,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAE/D;AAeD,wBAAgB,sCAAsC,CACpD,oBAAoB,EAAE,aAAa,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,sBAAsB,CAAC,EACjF,MAAM,EAAE;IACN,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB,GACA,MAAM,CAiBR;AAED,iBAAS,iCAAiC,CACxC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,gBAAgB,UAAQ,GACvB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA8CzB;AAED,eAAO,MAAM,4CAA4C,0CACtB,CAAC;AAokBpC,eAAO,MAAM,mBAAmB,EAAE,aAAa,CAAC,mBAAmB,CAuRlE,CAAC"}
package/dist/channel.js CHANGED
@@ -1,4 +1,4 @@
1
- import { randomUUID } from "node:crypto";
1
+ import { createHash, randomUUID } from "node:crypto";
2
2
  import createDebug from "debug";
3
3
  import { clearConnectorClient, clearConversationManager, extractNetworkConfig, getDmScope, initConnectorClient, initConversationManager, initToolConfig, isIdentityLinksConfigured, requirePlatformConfig, requirePluginRuntime, } from "./config.js";
4
4
  import { ConnectorClient } from "./connector-client.js";
@@ -8,6 +8,7 @@ import { extractHandleFromAddress } from "./handle-utils.js";
8
8
  import { clearOwnerState, isOwnerAddress, markOwnerAddress, setCurrentTurnIsOwner, setCurrentTurnOwnerSignal, } from "./owner-session-state.js";
9
9
  import { ServicesRetainedRecipientConsumer, } from "./services-retained-recipient.js";
10
10
  import { isServicesRetainedReplyContext, runWithServicesRetainedReplyContext, } from "./services-retained-reply-context.js";
11
+ import { runWithServicesRetainedToolPolicy } from "./services-retained-tool-policy.js";
11
12
  import { createReplyTraceMetadata, ensureTraceMetadata, } from "./trace-metadata.js";
12
13
  import { setCurrentTurnSender, setCurrentTurnSenderAddress, } from "./turn-context.js";
13
14
  import { checkForUpdate } from "./update-check.js";
@@ -31,6 +32,22 @@ export function _setNudgePendingForTesting(value) {
31
32
  function isRecord(value) {
32
33
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
33
34
  }
35
+ const SERVICES_RETAINED_TOOL_ALLOW = ["masons_note_for_owner"];
36
+ export function buildServicesRetainedRuntimeSessionKey(buildAgentSessionKey, params) {
37
+ const messageRefDigest = createHash("sha256")
38
+ .update(params.messageRef, "utf8")
39
+ .digest("hex");
40
+ return buildAgentSessionKey({
41
+ agentId: params.agentId,
42
+ channel: "agent-network",
43
+ accountId: params.accountId,
44
+ peer: {
45
+ kind: "direct",
46
+ id: `services-retained-${messageRefDigest}`,
47
+ },
48
+ dmScope: "per-account-channel-peer",
49
+ });
50
+ }
34
51
  function withAgentNetworkSilentReplyPolicy(cfg, servicesRetained = false) {
35
52
  const surfaces = isRecord(cfg.surfaces) ? cfg.surfaces : {};
36
53
  const existingSurface = isRecord(surfaces["agent-network"])
@@ -43,9 +60,7 @@ function withAgentNetworkSilentReplyPolicy(cfg, servicesRetained = false) {
43
60
  ? existingSurface.silentReplyRewrite
44
61
  : {};
45
62
  const tools = isRecord(cfg.tools) ? cfg.tools : {};
46
- const deny = Array.isArray(tools.deny)
47
- ? tools.deny.filter((value) => typeof value === "string")
48
- : [];
63
+ const messages = isRecord(cfg.messages) ? cfg.messages : {};
49
64
  return {
50
65
  ...cfg,
51
66
  surfaces: {
@@ -63,9 +78,15 @@ function withAgentNetworkSilentReplyPolicy(cfg, servicesRetained = false) {
63
78
  },
64
79
  },
65
80
  ...(servicesRetained && {
81
+ messages: {
82
+ ...messages,
83
+ visibleReplies: "automatic",
84
+ },
66
85
  tools: {
67
86
  ...tools,
68
- deny: [...new Set([...deny, "message"])],
87
+ allow: [...SERVICES_RETAINED_TOOL_ALLOW],
88
+ alsoAllow: [],
89
+ toolSearch: false,
69
90
  },
70
91
  }),
71
92
  };
@@ -218,13 +239,23 @@ async function handleAddressedMessage(event, conversationManager, client, ctx, o
218
239
  accountId: ctx.accountId,
219
240
  peer: { kind: "direct", id: senderId },
220
241
  });
242
+ const runtimeSessionKey = options.servicesRetained
243
+ ? buildServicesRetainedRuntimeSessionKey(runtime.channel.routing.buildAgentSessionKey, {
244
+ agentId: route.agentId,
245
+ accountId: ctx.accountId,
246
+ messageRef: options.servicesRetained.messageRef,
247
+ })
248
+ : route.sessionKey;
221
249
  const msgCtx = runtime.channel.reply.finalizeInboundContext({
222
250
  Body: event.content,
223
251
  RawBody: event.content,
224
252
  CommandBody: event.content,
225
253
  From: senderId,
226
254
  To: senderId,
227
- SessionKey: route.sessionKey,
255
+ SessionKey: runtimeSessionKey,
256
+ ...(options.servicesRetained && {
257
+ RuntimePolicySessionKey: runtimeSessionKey,
258
+ }),
228
259
  AccountId: ctx.accountId,
229
260
  ChatType: "direct",
230
261
  SenderName: senderName,
@@ -262,8 +293,14 @@ async function handleAddressedMessage(event, conversationManager, client, ctx, o
262
293
  const dispatch = () => runtime.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
263
294
  ctx: msgCtx,
264
295
  cfg: withAgentNetworkSilentReplyPolicy(ctx.cfg, options.servicesRetained !== undefined),
296
+ toolsAllow: options.servicesRetained
297
+ ? SERVICES_RETAINED_TOOL_ALLOW
298
+ : undefined,
265
299
  dispatcherOptions: {
266
300
  deliver: async (payload) => {
301
+ if (options.servicesRetained && payload.isError) {
302
+ throw new Error("services_retained_runtime_policy_unavailable");
303
+ }
267
304
  const text = payload.text;
268
305
  if (!text)
269
306
  return;
@@ -299,7 +336,7 @@ async function handleAddressedMessage(event, conversationManager, client, ctx, o
299
336
  },
300
337
  });
301
338
  if (options.servicesRetained) {
302
- await runWithServicesRetainedReplyContext(dispatch);
339
+ await runWithServicesRetainedToolPolicy(runtimeSessionKey, () => runWithServicesRetainedReplyContext(dispatch));
303
340
  }
304
341
  else {
305
342
  await dispatch();
@@ -450,7 +487,10 @@ export const agentNetworkChannel = {
450
487
  runtimePeerId: SERVICES_RETAINED_INBOX_PEER,
451
488
  senderName: servicesRetainedSenderName(message),
452
489
  messageSid: `an:${message.envelope.message_ref}`,
453
- servicesRetained: { reply: message.reply },
490
+ servicesRetained: {
491
+ messageRef: message.envelope.message_ref,
492
+ reply: message.reply,
493
+ },
454
494
  }),
455
495
  });
456
496
  const state = {
@@ -1 +1 @@
1
- {"version":3,"file":"cli-setup.d.ts","sourceRoot":"","sources":["../src/cli-setup.ts"],"names":[],"mappings":"AAyFA,UAAU,eAAe;IACvB,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC9B,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChD,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAOD,UAAU,gBAAgB;IACxB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,eAAe,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAgFD,wBAAsB,KAAK,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmEhE"}
1
+ {"version":3,"file":"cli-setup.d.ts","sourceRoot":"","sources":["../src/cli-setup.ts"],"names":[],"mappings":"AA0FA,UAAU,eAAe;IACvB,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC9B,KAAK,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAChC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChD,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAOD,UAAU,gBAAgB;IACxB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,eAAe,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAwFD,wBAAsB,KAAK,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+EhE"}
package/dist/cli-setup.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { readExistingConnectorUrl, writeCredentials } from "./config.js";
2
2
  import { ConnectorUrlConfigurationError, resolveConnectorUrlForSetup, } from "./connector-url-boundary.js";
3
3
  import { beginBridgeHandoff, completeBridgeHandoff, DEFAULT_IDP_BASE_URL, SetupFlowError, } from "./handoff.js";
4
+ import { assertHandoffDeadlineActive } from "./handoff-deadline.js";
4
5
  import { DEFAULT_API_HOST, DEFAULT_CONNECTOR_URL, PlatformApiError, } from "./platform-client.js";
5
6
  async function serverBridgeHandoffFlow(apiHost, idpBaseUrl, runtime, channelInput) {
6
7
  const session = await beginBridgeHandoff({
@@ -16,16 +17,19 @@ async function serverBridgeHandoffFlow(apiHost, idpBaseUrl, runtime, channelInpu
16
17
  "Waiting for the runtime key to be issued and delivered…",
17
18
  "",
18
19
  ].join("\n"));
19
- return completeBridgeHandoff(session);
20
+ return {
21
+ handoff: await completeBridgeHandoff(session),
22
+ expiresAt: session.expiresAt,
23
+ };
20
24
  }
21
25
  export async function login(ctx) {
22
26
  const apiHost = typeof ctx.cfg.apiHost === "string" ? ctx.cfg.apiHost : DEFAULT_API_HOST;
23
27
  const idpBaseUrl = typeof ctx.cfg.idpBaseUrl === "string"
24
28
  ? ctx.cfg.idpBaseUrl
25
29
  : DEFAULT_IDP_BASE_URL;
26
- let handoff;
30
+ let completed;
27
31
  try {
28
- handoff = await serverBridgeHandoffFlow(apiHost, idpBaseUrl, ctx.runtime, ctx.channelInput);
32
+ completed = await serverBridgeHandoffFlow(apiHost, idpBaseUrl, ctx.runtime, ctx.channelInput);
29
33
  }
30
34
  catch (err) {
31
35
  if (err instanceof SetupFlowError) {
@@ -38,6 +42,7 @@ export async function login(ctx) {
38
42
  }
39
43
  throw err;
40
44
  }
45
+ const { handoff } = completed;
41
46
  const existingConnectorUrl = await readExistingConnectorUrl();
42
47
  const configuredConnectorUrl = typeof ctx.cfg.connectorUrl === "string" ? ctx.cfg.connectorUrl : undefined;
43
48
  let connectorUrl;
@@ -56,6 +61,15 @@ export async function login(ctx) {
56
61
  }
57
62
  throw err;
58
63
  }
59
- await writeCredentials({ connectorUrl, token: handoff.token }, apiHost, idpBaseUrl);
64
+ try {
65
+ await writeCredentials({ connectorUrl, token: handoff.token }, apiHost, idpBaseUrl, undefined, () => assertHandoffDeadlineActive(completed.expiresAt));
66
+ }
67
+ catch (err) {
68
+ if (err instanceof SetupFlowError) {
69
+ ctx.runtime.error(err.message);
70
+ return;
71
+ }
72
+ throw err;
73
+ }
60
74
  ctx.runtime.log(`✓ Connected as @${handoff.agent.handle}`);
61
75
  }
@@ -1,4 +1,4 @@
1
1
  export declare function getOpenClawHome(): string;
2
2
  export declare function readConfig(): Promise<Record<string, unknown>>;
3
- export declare function persistConfig(config: Record<string, unknown>): Promise<void>;
3
+ export declare function persistConfig(config: Record<string, unknown>, assertCanPersist?: () => void): Promise<void>;
4
4
  //# sourceMappingURL=config-fs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config-fs.d.ts","sourceRoot":"","sources":["../src/config-fs.ts"],"names":[],"mappings":"AAKA,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAMD,wBAAsB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAOnE;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAAC,IAAI,CAAC,CAIf"}
1
+ {"version":3,"file":"config-fs.d.ts","sourceRoot":"","sources":["../src/config-fs.ts"],"names":[],"mappings":"AAKA,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAMD,wBAAsB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAOnE;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,gBAAgB,CAAC,EAAE,MAAM,IAAI,GAC5B,OAAO,CAAC,IAAI,CAAC,CAKf"}
package/dist/config-fs.js CHANGED
@@ -16,8 +16,9 @@ export async function readConfig() {
16
16
  return {};
17
17
  }
18
18
  }
19
- export async function persistConfig(config) {
19
+ export async function persistConfig(config, assertCanPersist) {
20
20
  const configPath = getConfigPath();
21
21
  await mkdir(dirname(configPath), { recursive: true });
22
+ assertCanPersist?.();
22
23
  await writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
23
24
  }
package/dist/config.d.ts CHANGED
@@ -26,7 +26,7 @@ export interface NetworkCredentials {
26
26
  token: string;
27
27
  }
28
28
  export declare function readExistingConnectorUrl(): Promise<string | undefined>;
29
- export declare function writeCredentials(creds: NetworkCredentials, apiHost?: string, idpBaseUrl?: string, pendingTarget?: string): Promise<void>;
29
+ export declare function writeCredentials(creds: NetworkCredentials, apiHost?: string, idpBaseUrl?: string, pendingTarget?: string, assertCanPersist?: () => void): Promise<void>;
30
30
  export declare function writeTargetHandle(handle: string): Promise<void>;
31
31
  export declare function clearTargetHandle(): Promise<void>;
32
32
  export declare function markProfileNeeded(): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAoCjD,wBAAgB,uBAAuB,IAAI,MAAM,CAEhD;AAsBD,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC3B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAMhC;AAYD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAyCjE;AAuCD,wBAAgB,yBAAyB,IAAI,OAAO,CAEnD;AAWD,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAeD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAOjE;AAQD,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AAYD,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAE1E;AASD,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C;AAKD,wBAAgB,0BAA0B,IAAI,mBAAmB,CAOhE;AASD,wBAAgB,sBAAsB,IAAI,mBAAmB,GAAG,IAAI,CAEnE;AAgBD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAExD;AAKD,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAQD,wBAAgB,oBAAoB,IAAI,OAAO,CAO9C;AAcD,wBAAgB,qBAAqB,IAAI,oBAAoB,CAE5D;AAKD,wBAAgB,aAAa,IAAI,MAAM,CAKtC;AAKD,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAEhD;AASD,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AASD,wBAAgB,sBAAsB,IAAI,eAAe,CAOxD;AAyBD,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAQD,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAW5E;AAmBD,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,kBAAkB,EACzB,OAAO,CAAC,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,EACnB,aAAa,CAAC,EAAE,MAAM,GACrB,OAAO,CAAC,IAAI,CAAC,CA0Cf;AAUD,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMrE;AASD,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CASvD;AAYD,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAOvD;AAUD,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAOzD;AAwCD,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EAAE,GAChB,OAAO,CAAC,IAAI,CAAC,CAsBf;AAQD,wBAAsB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA4B1E;AAOD,MAAM,WAAW,YAAY;IAE3B,cAAc,EAAE,OAAO,CAAC;IAExB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAE7B,YAAY,EAAE,OAAO,CAAC;CACvB;AASD,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,YAAY,CAAC,CA2BhE;AAOD,wBAAgB,gBAAgB,IAAI,IAAI,CAWvC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAoCjD,wBAAgB,uBAAuB,IAAI,MAAM,CAEhD;AAsBD,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC3B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAMhC;AAYD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAyCjE;AAuCD,wBAAgB,yBAAyB,IAAI,OAAO,CAEnD;AAWD,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAeD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAOjE;AAQD,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AAYD,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAE1E;AASD,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C;AAKD,wBAAgB,0BAA0B,IAAI,mBAAmB,CAOhE;AASD,wBAAgB,sBAAsB,IAAI,mBAAmB,GAAG,IAAI,CAEnE;AAgBD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAExD;AAKD,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAQD,wBAAgB,oBAAoB,IAAI,OAAO,CAO9C;AAcD,wBAAgB,qBAAqB,IAAI,oBAAoB,CAE5D;AAKD,wBAAgB,aAAa,IAAI,MAAM,CAKtC;AAKD,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,IAAI,CAEhD;AASD,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AASD,wBAAgB,sBAAsB,IAAI,eAAe,CAOxD;AAyBD,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAQD,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAW5E;AAoBD,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,kBAAkB,EACzB,OAAO,CAAC,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,EACnB,aAAa,CAAC,EAAE,MAAM,EACtB,gBAAgB,CAAC,EAAE,MAAM,IAAI,GAC5B,OAAO,CAAC,IAAI,CAAC,CA0Cf;AAUD,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMrE;AASD,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CASvD;AAYD,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAOvD;AAUD,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAOzD;AAwCD,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EAAE,GAChB,OAAO,CAAC,IAAI,CAAC,CAsBf;AAQD,wBAAsB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA4B1E;AAOD,MAAM,WAAW,YAAY;IAE3B,cAAc,EAAE,OAAO,CAAC;IAExB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAE7B,YAAY,EAAE,OAAO,CAAC;CACvB;AASD,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,YAAY,CAAC,CA2BhE;AAOD,wBAAgB,gBAAgB,IAAI,IAAI,CAWvC"}
package/dist/config.js CHANGED
@@ -141,7 +141,7 @@ export async function readExistingConnectorUrl() {
141
141
  ? connectorUrl
142
142
  : undefined;
143
143
  }
144
- export async function writeCredentials(creds, apiHost, idpBaseUrl, pendingTarget) {
144
+ export async function writeCredentials(creds, apiHost, idpBaseUrl, pendingTarget, assertCanPersist) {
145
145
  const config = await readConfig();
146
146
  const section = ensureNetworkSection(config);
147
147
  section.enabled = true;
@@ -163,7 +163,7 @@ export async function writeCredentials(creds, apiHost, idpBaseUrl, pendingTarget
163
163
  if (pendingTarget) {
164
164
  section.pendingTarget = pendingTarget;
165
165
  }
166
- await persistConfig(config);
166
+ await persistConfig(config, assertCanPersist);
167
167
  storedApiKey = creds.token;
168
168
  if (pendingTarget) {
169
169
  storedPendingTarget = pendingTarget;
@@ -0,0 +1,4 @@
1
+ export declare class SetupFlowError extends Error {
2
+ }
3
+ export declare function assertHandoffDeadlineActive(expiresAt: number): void;
4
+ //# sourceMappingURL=handoff-deadline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handoff-deadline.d.ts","sourceRoot":"","sources":["../src/handoff-deadline.ts"],"names":[],"mappings":"AAAA,qBAAa,cAAe,SAAQ,KAAK;CAAG;AAG5C,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAMnE"}
@@ -0,0 +1,7 @@
1
+ export class SetupFlowError extends Error {
2
+ }
3
+ export function assertHandoffDeadlineActive(expiresAt) {
4
+ if (Date.now() >= expiresAt) {
5
+ throw new SetupFlowError("Handoff session expired before the runtime key was delivered. Re-run setup.");
6
+ }
7
+ }
package/dist/handoff.d.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  import { type KeyObject } from "node:crypto";
2
+ export { SetupFlowError } from "./handoff-deadline.js";
2
3
  export declare const DEFAULT_IDP_BASE_URL = "https://preview.masons.ai";
3
4
  export declare const HANDOFF_TIMEOUT_MS: number;
4
- export declare class SetupFlowError extends Error {
5
- }
6
5
  export interface BridgeHandoffResult {
7
6
  token: string;
8
7
  agent: {
@@ -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;AAerB,eAAO,MAAM,oBAAoB,8BAA8B,CAAC;AAiBhE,eAAO,MAAM,kBAAkB,QAAgB,CAAC;AAKhD,qBAAa,cAAe,SAAQ,KAAK;CAAG;AAY5C,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;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAOhB,UAAU,EAAE,SAAS,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAMD,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,oBAAoB,CAAC,CAsD/B;AAKD,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,mBAAmB,CAAC,CAmC9B"}
1
+ {"version":3,"file":"handoff.d.ts","sourceRoot":"","sources":["../src/handoff.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,SAAS,EAEf,MAAM,aAAa,CAAC;AAQrB,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAavD,eAAO,MAAM,oBAAoB,8BAA8B,CAAC;AAiBhE,eAAO,MAAM,kBAAkB,QAAiB,CAAC;AAejD,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;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAOhB,UAAU,EAAE,SAAS,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAMD,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,oBAAoB,CAAC,CAsD/B;AAKD,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,mBAAmB,CAAC,CAwC9B"}
package/dist/handoff.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import { createDecipheriv, constants as cryptoConstants, generateKeyPairSync, privateDecrypt, } from "node:crypto";
2
+ import { assertHandoffDeadlineActive, SetupFlowError, } from "./handoff-deadline.js";
2
3
  import { apiFetch, PlatformNetworkError } from "./platform-client.js";
4
+ export { SetupFlowError } from "./handoff-deadline.js";
3
5
  export const DEFAULT_IDP_BASE_URL = "https://preview.masons.ai";
4
6
  const HANDLE_REGEX = /^[a-z][a-z0-9_-]{2,14}$/;
5
- export const HANDOFF_TIMEOUT_MS = 5 * 60 * 1000;
7
+ export const HANDOFF_TIMEOUT_MS = 10 * 60 * 1000;
6
8
  const HANDOFF_POLL_INTERVAL_MS = 2000;
7
- export class SetupFlowError extends Error {
8
- }
9
9
  export async function beginBridgeHandoff(options) {
10
10
  const { publicKey, privateKey } = generateKeyPairSync("rsa", {
11
11
  modulusLength: 2048,
@@ -53,7 +53,7 @@ export async function beginBridgeHandoff(options) {
53
53
  };
54
54
  }
55
55
  export async function completeBridgeHandoff(session) {
56
- const envelope = await pollForCompletion(session.apiBase, session.sessionId);
56
+ const envelope = await pollForCompletion(session.apiBase, session.sessionId, session.expiresAt);
57
57
  let payload;
58
58
  try {
59
59
  payload = decryptBridgeEnvelope(session.privateKey, envelope);
@@ -62,6 +62,7 @@ export async function completeBridgeHandoff(session) {
62
62
  const message = err instanceof Error ? err.message : "unknown error";
63
63
  throw new SetupFlowError(`Handoff received but could not be decrypted (${message}). The link may have been tampered with — re-run setup. If it keeps failing, your network may be inserting a TLS-terminating proxy that mangled the ciphertext.`);
64
64
  }
65
+ assertHandoffDeadlineActive(session.expiresAt);
65
66
  if (typeof payload.token !== "string" ||
66
67
  !payload.token.startsWith("masons_rt_v1_") ||
67
68
  typeof payload.agent?.handle !== "string" ||
@@ -79,10 +80,9 @@ export async function completeBridgeHandoff(session) {
79
80
  },
80
81
  };
81
82
  }
82
- async function pollForCompletion(apiBase, sessionId) {
83
- const start = Date.now();
83
+ async function pollForCompletion(apiBase, sessionId, expiresAt) {
84
84
  let lastNetworkError;
85
- while (Date.now() - start < HANDOFF_TIMEOUT_MS) {
85
+ while (Date.now() < expiresAt) {
86
86
  let res;
87
87
  try {
88
88
  res = await apiFetch(`${apiBase}/v1/cli-handoff/${encodeURIComponent(sessionId)}/poll`, { method: "GET" });
@@ -90,28 +90,38 @@ async function pollForCompletion(apiBase, sessionId) {
90
90
  catch (err) {
91
91
  if (err instanceof PlatformNetworkError) {
92
92
  lastNetworkError = err;
93
- await sleep(HANDOFF_POLL_INTERVAL_MS);
93
+ await sleepBeforeNextPoll(expiresAt);
94
94
  continue;
95
95
  }
96
96
  throw err;
97
97
  }
98
+ if (Date.now() >= expiresAt)
99
+ break;
98
100
  if (res.status === 404) {
99
101
  throw new SetupFlowError("Handoff session expired before the runtime key was delivered. Re-run setup.");
100
102
  }
101
103
  if (!res.ok) {
102
- await sleep(HANDOFF_POLL_INTERVAL_MS);
104
+ await sleepBeforeNextPoll(expiresAt);
103
105
  continue;
104
106
  }
105
107
  const body = (await res.json());
108
+ if (Date.now() >= expiresAt)
109
+ break;
106
110
  if (body.status === "completed" && body.payload) {
107
111
  return body.payload;
108
112
  }
109
- await sleep(HANDOFF_POLL_INTERVAL_MS);
113
+ await sleepBeforeNextPoll(expiresAt);
110
114
  }
111
115
  throw new SetupFlowError(lastNetworkError
112
116
  ? `Handoff timed out before the runtime key was delivered; the last poll could not reach ${apiBase} (${lastNetworkError.message}). Re-run setup; if you're behind a proxy that blocks long-running fetches, retry on a different network.`
113
117
  : "Handoff timed out before the runtime key was delivered. Re-run setup; if you're behind a proxy that blocks long-running fetches, retry on a different network.");
114
118
  }
119
+ async function sleepBeforeNextPoll(expiresAt) {
120
+ const remainingMs = expiresAt - Date.now();
121
+ if (remainingMs <= 0)
122
+ return;
123
+ await sleep(Math.min(HANDOFF_POLL_INTERVAL_MS, remainingMs));
124
+ }
115
125
  function decryptBridgeEnvelope(privateKey, envelope) {
116
126
  const wrappedKey = Buffer.from(envelope.wrapped_key, "base64url");
117
127
  const iv = Buffer.from(envelope.iv, "base64url");
package/dist/plugin.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { evaluateServicesRetainedToolPolicy } from "./services-retained-tool-policy.js";
1
2
  export declare function buildInteractionContext(channelId: string | undefined, turnSender: string | null, turnSenderAddress: string | null, servicesRetained?: boolean): string | undefined;
2
3
  interface OpenClawPluginApi {
3
4
  runtime: unknown;
@@ -8,6 +9,11 @@ interface OpenClawPluginApi {
8
9
  optional?: boolean;
9
10
  name?: string;
10
11
  }): void;
12
+ registerTrustedToolPolicy(policy: {
13
+ id: string;
14
+ description: string;
15
+ evaluate: typeof evaluateServicesRetainedToolPolicy;
16
+ }): void;
11
17
  on(event: string, handler: (...args: unknown[]) => unknown): void;
12
18
  }
13
19
  declare const plugin: {
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAsFA,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,iBAAiB,EAAE,MAAM,GAAG,IAAI,EAChC,gBAAgB,UAAQ,GACvB,MAAM,GAAG,SAAS,CA+EpB;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,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,GAAG,IAAI,CAAC;CACnE;AAED,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAaI,iBAAiB;CA0YhC,CAAC;AAEF,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAuBA,OAAO,EACL,kCAAkC,EAEnC,MAAM,oCAAoC,CAAC;AAgE5C,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,iBAAiB,EAAE,MAAM,GAAG,IAAI,EAChC,gBAAgB,UAAQ,GACvB,MAAM,GAAG,SAAS,CA+EpB;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;AAED,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAaI,iBAAiB;CAiZhC,CAAC;AAEF,eAAe,MAAM,CAAC"}
package/dist/plugin.js CHANGED
@@ -7,6 +7,7 @@ import { ownerNotesQueue } from "./owner-notes.js";
7
7
  import { consumeCurrentTurnIsOwner, consumeCurrentTurnOwnerSignal, } from "./owner-session-state.js";
8
8
  import { sentMessageBuffer } from "./sent-message-buffer.js";
9
9
  import { isServicesRetainedReplyContext } from "./services-retained-reply-context.js";
10
+ import { evaluateServicesRetainedToolPolicy, SERVICES_RETAINED_TOOL_POLICY_ID, } from "./services-retained-tool-policy.js";
10
11
  import { registerTools } from "./tools.js";
11
12
  import { consumeCurrentTurnSender, consumeCurrentTurnSenderAddress, setCurrentTurnChannelId, setCurrentTurnIsOwnerForTools, setCurrentTurnOwnerSignalForTools, } from "./turn-context.js";
12
13
  import { getUpdateInfo } from "./update-check.js";
@@ -95,6 +96,11 @@ const plugin = {
95
96
  configSchema: pluginManifest.configSchema,
96
97
  register(api) {
97
98
  initPluginRuntime(api.runtime);
99
+ api.registerTrustedToolPolicy({
100
+ id: SERVICES_RETAINED_TOOL_POLICY_ID,
101
+ description: "Deny every tool except the owner note during Services-retained recipient turns.",
102
+ evaluate: evaluateServicesRetainedToolPolicy,
103
+ });
98
104
  registerTools(api);
99
105
  try {
100
106
  api.registerChannel({
@@ -0,0 +1,11 @@
1
+ export declare const SERVICES_RETAINED_TOOL_POLICY_ID = "agent-network-services-retained-turn-v1";
2
+ export declare function runWithServicesRetainedToolPolicy<T>(sessionKey: string, callback: () => Promise<T> | T): Promise<T>;
3
+ export declare function evaluateServicesRetainedToolPolicy(event: {
4
+ toolName: string;
5
+ }, ctx: {
6
+ sessionKey?: string;
7
+ }): {
8
+ allow: false;
9
+ reason: string;
10
+ } | undefined;
11
+ //# sourceMappingURL=services-retained-tool-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"services-retained-tool-policy.d.ts","sourceRoot":"","sources":["../src/services-retained-tool-policy.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,gCAAgC,4CACF,CAAC;AAE5C,wBAAsB,iCAAiC,CAAC,CAAC,EACvD,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,GAC7B,OAAO,CAAC,CAAC,CAAC,CAeZ;AAED,wBAAgB,kCAAkC,CAChD,KAAK,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,EAC3B,GAAG,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3B;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAY9C"}
@@ -0,0 +1,30 @@
1
+ const SERVICES_RETAINED_OWNER_NOTE_TOOL = "masons_note_for_owner";
2
+ const activeSessionRefCounts = new Map();
3
+ export const SERVICES_RETAINED_TOOL_POLICY_ID = "agent-network-services-retained-turn-v1";
4
+ export async function runWithServicesRetainedToolPolicy(sessionKey, callback) {
5
+ activeSessionRefCounts.set(sessionKey, (activeSessionRefCounts.get(sessionKey) ?? 0) + 1);
6
+ try {
7
+ return await callback();
8
+ }
9
+ finally {
10
+ const remaining = (activeSessionRefCounts.get(sessionKey) ?? 1) - 1;
11
+ if (remaining > 0) {
12
+ activeSessionRefCounts.set(sessionKey, remaining);
13
+ }
14
+ else {
15
+ activeSessionRefCounts.delete(sessionKey);
16
+ }
17
+ }
18
+ }
19
+ export function evaluateServicesRetainedToolPolicy(event, ctx) {
20
+ if (!ctx.sessionKey || !activeSessionRefCounts.has(ctx.sessionKey)) {
21
+ return undefined;
22
+ }
23
+ if (event.toolName === SERVICES_RETAINED_OWNER_NOTE_TOOL) {
24
+ return undefined;
25
+ }
26
+ return {
27
+ allow: false,
28
+ reason: "Services-retained recipient turns permit only the owner-note capability.",
29
+ };
30
+ }
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const PLUGIN_VERSION = "0.6.18";
1
+ export declare const PLUGIN_VERSION = "0.6.20";
2
2
  //# sourceMappingURL=version.d.ts.map
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const PLUGIN_VERSION = "0.6.18";
1
+ export const PLUGIN_VERSION = "0.6.20";
@@ -3,6 +3,7 @@
3
3
  "channels": ["agent-network"],
4
4
  "skills": ["skills/agent-network"],
5
5
  "contracts": {
6
+ "trustedToolPolicies": ["agent-network-services-retained-turn-v1"],
6
7
  "tools": [
7
8
  "masons_setup",
8
9
  "masons_update_profile",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@masons/agent-network",
3
- "version": "0.6.18",
3
+ "version": "0.6.20",
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)",
@@ -38,7 +38,7 @@
38
38
  ],
39
39
  "openclaw": {
40
40
  "compat": {
41
- "pluginApi": ">=2026.3.28"
41
+ "pluginApi": ">=2026.6.11"
42
42
  },
43
43
  "extensions": [
44
44
  "./dist/plugin.js"