@openclaw/clickclack 2026.8.1-beta.3 → 2026.8.2

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
@@ -119,8 +119,8 @@ not have an account selector.
119
119
  Messages in the managed channel run in a stable side session under the same
120
120
  agent id as the attached main session. The plugin installs a scoped host grant
121
121
  for `sessions_history`, `session_status`, and `sessions_send` between that side
122
- session and its attached main session, so `tools.sessions.visibility` can stay
123
- at its safer default `tree`. A second host-side policy blocks session discovery
122
+ session and its attached main session, so `tools.sessions.visibility` can be set
123
+ explicitly to `tree` for narrower access than the agent-wide default. A second host-side policy blocks session discovery
124
124
  and alternate targets; the side-agent prompt is not the authorization boundary.
125
125
  The agent still needs those three tools in its effective tool allowlist.
126
126
 
package/dist/api.js CHANGED
@@ -1,3 +1,3 @@
1
- import { _ as DEFAULT_ACCOUNT_ID, b as resolveClickClackAccount, p as clickClackConfigSchema, u as createClickClackClient, v as listClickClackAccountIds, x as resolveDefaultClickClackAccountId, y as listEnabledClickClackAccounts } from "./setup-surface-BQ1Zyohu.js";
2
- import { a as setClickClackRuntime, i as getClickClackRuntime, n as buildClickClackTarget, r as parseClickClackTarget, t as clickClackPlugin } from "./channel-ChO3E9i2.js";
1
+ import { _ as DEFAULT_ACCOUNT_ID, b as resolveClickClackAccount, p as clickClackConfigSchema, u as createClickClackClient, v as listClickClackAccountIds, x as resolveDefaultClickClackAccountId, y as listEnabledClickClackAccounts } from "./setup-surface-k_ZLgpwc.js";
2
+ import { a as setClickClackRuntime, i as getClickClackRuntime, n as buildClickClackTarget, r as parseClickClackTarget, t as clickClackPlugin } from "./channel-84ZGfWxl.js";
3
3
  export { DEFAULT_ACCOUNT_ID, buildClickClackTarget, clickClackConfigSchema, clickClackPlugin, createClickClackClient, getClickClackRuntime, listClickClackAccountIds, listEnabledClickClackAccounts, parseClickClackTarget, resolveClickClackAccount, resolveDefaultClickClackAccountId, setClickClackRuntime };
@@ -1,10 +1,11 @@
1
- import { _ as DEFAULT_ACCOUNT_ID, b as resolveClickClackAccount, c as resolveWorkspaceId, f as normalizeClickClackCorrelationId, g as clickClackMeta, h as clickClackConfigAdapter, l as ClickClackHttpError, m as CLICKCLACK_CHANNEL_ID, n as clickClackSetupContract, p as clickClackConfigSchema, s as resolveChannelId, t as clickClackSetupWizard, u as createClickClackClient, y as listEnabledClickClackAccounts } from "./setup-surface-BQ1Zyohu.js";
1
+ import { _ as DEFAULT_ACCOUNT_ID, b as resolveClickClackAccount, c as resolveWorkspaceId, f as normalizeClickClackCorrelationId, g as clickClackMeta, h as clickClackConfigAdapter, l as ClickClackHttpError, m as CLICKCLACK_CHANNEL_ID, n as clickClackSetupContract, p as clickClackConfigSchema, s as resolveChannelId, t as clickClackSetupWizard, u as createClickClackClient, y as listEnabledClickClackAccounts } from "./setup-surface-k_ZLgpwc.js";
2
2
  import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-BKkzzjBA.js";
3
+ import { resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/account-helpers";
3
4
  import { parseDateStringTimestampMs } from "openclaw/plugin-sdk/number-runtime";
4
5
  import { mergePairLoopGuardConfig } from "openclaw/plugin-sdk/pair-loop-guard-runtime";
5
6
  import { readStringField } from "openclaw/plugin-sdk/string-coerce-runtime";
6
7
  import { buildChannelOutboundSessionRoute, buildThreadAwareOutboundSessionRoute, createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
7
- import { buildChannelProgressDraftLine, createMessageReceiptFromOutboundResults, defineChannelMessageAdapter, deriveDurableFinalDeliveryRequirements } from "openclaw/plugin-sdk/channel-outbound";
8
+ import { buildChannelProgressDraftLine, createChannelMessageReplyPipeline, createMessageReceiptFromOutboundResults, defineChannelMessageAdapter, deriveDurableFinalDeliveryRequirements } from "openclaw/plugin-sdk/channel-outbound";
8
9
  import { createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
9
10
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
10
11
  import { channelReadyPatch, channelStoppedPatch } from "openclaw/plugin-sdk/gateway-runtime";
@@ -500,7 +501,7 @@ const CLICKCLACK_MENTION_PATTERN = /(?:^|[^a-z0-9_@-])@([a-z0-9][a-z0-9_-]{1,31}
500
501
  function buildLocalMentionRegexes(params) {
501
502
  if (params.mentionPatterns.length === 0) return [];
502
503
  const cfg = params.cfg;
503
- return buildMentionRegexes({
504
+ const syntheticCfg = {
504
505
  ...cfg,
505
506
  messages: {
506
507
  ...cfg?.messages,
@@ -509,7 +510,8 @@ function buildLocalMentionRegexes(params) {
509
510
  mentionPatterns: params.mentionPatterns
510
511
  }
511
512
  }
512
- }, void 0, {
513
+ };
514
+ return buildMentionRegexes(syntheticCfg, void 0, {
513
515
  provider: "clickclack",
514
516
  conversationId: params.channelId
515
517
  });
@@ -1081,11 +1083,11 @@ function createClickClackActivityPublisher(params) {
1081
1083
  * Outbound ClickClack delivery helpers for channel messages, thread replies,
1082
1084
  * and direct messages.
1083
1085
  */
1084
- const CLICKCLACK_MAX_UPLOAD_BYTES = 64 * 1024 * 1024;
1086
+ const CLICKCLACK_MAX_UPLOAD_BYTES = 67108864;
1085
1087
  const CLICKCLACK_FORMAT_PROFILE = FormatCapabilityProfile.define({
1086
1088
  mechanism: "markdown",
1087
1089
  chunk: {
1088
- limit: 1024 * 1024,
1090
+ limit: 1048576,
1089
1091
  unit: "bytes"
1090
1092
  }
1091
1093
  });
@@ -1211,13 +1213,18 @@ async function sendClickClackMedia(params) {
1211
1213
  deliveryQueueId: params.deliveryQueueId,
1212
1214
  deliveryPartIndex: params.deliveryPartIndex
1213
1215
  });
1216
+ const { account, client } = createOutboundContext(params);
1217
+ const maxBytes = Math.min(resolveChannelMediaMaxBytes({
1218
+ cfg: params.cfg,
1219
+ accountId: account.accountId,
1220
+ resolveChannelLimitMb: () => account.config.mediaMaxMb
1221
+ }) ?? CLICKCLACK_MAX_UPLOAD_BYTES, CLICKCLACK_MAX_UPLOAD_BYTES);
1214
1222
  const preloadedMedia = nonces.upload ? void 0 : await loadOutboundMediaFromUrl(params.mediaUrl, {
1215
- maxBytes: CLICKCLACK_MAX_UPLOAD_BYTES,
1223
+ maxBytes,
1216
1224
  mediaAccess: params.mediaAccess,
1217
1225
  mediaLocalRoots: params.mediaLocalRoots,
1218
1226
  mediaReadFile: params.mediaReadFile
1219
1227
  });
1220
- const { account, client } = createOutboundContext(params);
1221
1228
  const workspaceId = await resolveWorkspaceId(client, account.workspace);
1222
1229
  const persistedUpload = nonces.upload ? await client.findUploadByNonce({
1223
1230
  workspaceId,
@@ -1228,7 +1235,7 @@ async function sendClickClackMedia(params) {
1228
1235
  let mediaFilename = preloadedMedia?.fileName?.trim();
1229
1236
  if (!upload) {
1230
1237
  const media = preloadedMedia ?? await loadOutboundMediaFromUrl(params.mediaUrl, {
1231
- maxBytes: CLICKCLACK_MAX_UPLOAD_BYTES,
1238
+ maxBytes,
1232
1239
  mediaAccess: params.mediaAccess,
1233
1240
  mediaLocalRoots: params.mediaLocalRoots,
1234
1241
  mediaReadFile: params.mediaReadFile
@@ -1592,7 +1599,7 @@ function resolveClickClackAgentRunId(messageId) {
1592
1599
  }
1593
1600
  async function dispatchModelReply(params) {
1594
1601
  const runtime = getClickClackRuntime();
1595
- const text = (await runtime.llm.complete({
1602
+ const result = await runtime.llm.complete({
1596
1603
  agentId: params.route.agentId,
1597
1604
  model: params.account.model,
1598
1605
  purpose: "clickclack bot reply",
@@ -1601,14 +1608,28 @@ async function dispatchModelReply(params) {
1601
1608
  role: "user",
1602
1609
  content: params.message.body
1603
1610
  }]
1604
- })).text.trim();
1605
- if (!text) {
1611
+ });
1612
+ const completion = result.text.trim();
1613
+ if (!completion) {
1606
1614
  runtime.logging.getChildLogger({
1607
1615
  plugin: "clickclack",
1608
1616
  feature: "model-reply"
1609
1617
  }).warn(`[${params.account.accountId}] ClickClack model reply produced no sendable text`);
1610
1618
  return;
1611
1619
  }
1620
+ const replyPipeline = createChannelMessageReplyPipeline({
1621
+ cfg: params.cfg,
1622
+ agentId: params.route.agentId,
1623
+ channel: CHANNEL_ID$1,
1624
+ accountId: params.account.accountId
1625
+ });
1626
+ replyPipeline.onModelSelected?.({
1627
+ provider: result.provider,
1628
+ model: result.model,
1629
+ thinkLevel: void 0
1630
+ });
1631
+ const responsePrefix = replyPipeline.resolveResponsePrefix?.();
1632
+ const text = responsePrefix && !completion.startsWith(responsePrefix) ? `${responsePrefix} ${completion}` : completion;
1612
1633
  await sendClickClackText({
1613
1634
  cfg: params.cfg,
1614
1635
  accountId: params.account.accountId,
@@ -1869,7 +1890,7 @@ function parseSocketEvent(data) {
1869
1890
  }
1870
1891
  async function processEvent(params) {
1871
1892
  if (params.event.type !== "message.created" && params.event.type !== "thread.reply_created") return;
1872
- if (payloadString(params.event, "author_id") === params.botUserId) return;
1893
+ if (params.abortSignal.aborted || payloadString(params.event, "author_id") === params.botUserId) return;
1873
1894
  const correlationId = eventCorrelationId(params.event);
1874
1895
  const message = await resolveEventMessage({
1875
1896
  client: correlationId ? createClickClackClient({
@@ -1883,12 +1904,13 @@ async function processEvent(params) {
1883
1904
  params.log?.warn?.(`[${params.account.accountId}] skipped unreadable ClickClack message before agent dispatch: type=${params.event.type} messageId=${payloadString(params.event, "message_id") || "unknown"}`);
1884
1905
  return;
1885
1906
  }
1886
- if (message.author_id === params.botUserId) return;
1907
+ if (params.abortSignal.aborted || message.author_id === params.botUserId) return;
1887
1908
  const access = await resolveClickClackInboundAccess({
1888
1909
  account: params.account,
1889
1910
  config: params.config,
1890
1911
  message
1891
1912
  });
1913
+ if (params.abortSignal.aborted) return;
1892
1914
  if (!access.shouldDispatch) {
1893
1915
  params.log?.info(`[${params.account.accountId}] skipped ClickClack message before agent dispatch: kind=${message.direct_conversation_id ? "dm" : "group"} requireMention=${access.requireMention ?? "unknown"} wasMentioned=${access.mentionFacts.wasMentioned} hasAnyMention=${access.mentionFacts.hasAnyMention ?? "unknown"} commandAuthorized=${access.commandAuthorized}`);
1894
1916
  return;
@@ -1938,6 +1960,7 @@ async function startClickClackGatewayAccount(ctx) {
1938
1960
  botHandle: me.handle
1939
1961
  };
1940
1962
  const processIncomingEvent = (event) => processEvent({
1963
+ abortSignal: ctx.abortSignal,
1941
1964
  account,
1942
1965
  config: ctx.cfg,
1943
1966
  client,
@@ -2017,6 +2040,7 @@ async function startClickClackGatewayAccount(ctx) {
2017
2040
  socket.on("message", (data) => {
2018
2041
  if (closing || settled) return;
2019
2042
  messageQueue = messageQueue.then(async () => {
2043
+ if (ctx.abortSignal.aborted) return;
2020
2044
  const event = parseSocketEvent(data);
2021
2045
  if (!event) {
2022
2046
  ctx.log?.warn?.(`[${account.accountId}] skipped malformed ClickClack websocket event`);
@@ -2180,21 +2204,22 @@ const clickClackPlugin = createChatChannelPlugin({
2180
2204
  },
2181
2205
  resolveOutboundSessionRoute: ({ cfg, agentId, accountId, target, replyToId, threadId, currentSessionKey }) => {
2182
2206
  const parsed = parseClickClackTarget(target);
2207
+ const baseRoute = buildChannelOutboundSessionRoute({
2208
+ cfg,
2209
+ agentId,
2210
+ channel: CHANNEL_ID,
2211
+ accountId,
2212
+ recipientSessionExact: parsed.kind === "dm",
2213
+ peer: {
2214
+ kind: parsed.chatType === "direct" ? "direct" : "channel",
2215
+ id: buildClickClackTarget(parsed)
2216
+ },
2217
+ chatType: parsed.chatType,
2218
+ from: `clickclack:${accountId ?? DEFAULT_ACCOUNT_ID}`,
2219
+ to: buildClickClackTarget(parsed)
2220
+ });
2183
2221
  return buildThreadAwareOutboundSessionRoute({
2184
- route: buildChannelOutboundSessionRoute({
2185
- cfg,
2186
- agentId,
2187
- channel: CHANNEL_ID,
2188
- accountId,
2189
- recipientSessionExact: parsed.kind === "dm",
2190
- peer: {
2191
- kind: parsed.chatType === "direct" ? "direct" : "channel",
2192
- id: buildClickClackTarget(parsed)
2193
- },
2194
- chatType: parsed.chatType,
2195
- from: `clickclack:${accountId ?? DEFAULT_ACCOUNT_ID}`,
2196
- to: buildClickClackTarget(parsed)
2197
- }),
2222
+ route: baseRoute,
2198
2223
  replyToId,
2199
2224
  threadId: threadId ?? (parsed.kind === "thread" ? parsed.id : void 0),
2200
2225
  currentSessionKey,
@@ -1,2 +1,2 @@
1
- import { t as clickClackPlugin } from "./channel-ChO3E9i2.js";
1
+ import { t as clickClackPlugin } from "./channel-84ZGfWxl.js";
2
2
  export { clickClackPlugin };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as registerClickClackDiscussions } from "./runtime-api-B0ChZLhm.js";
1
+ import { t as registerClickClackDiscussions } from "./runtime-api-6Kws_vrf.js";
2
2
  import { defineBundledChannelEntry } from "openclaw/plugin-sdk/channel-entry-contract";
3
3
  //#region extensions/clickclack/index.ts
4
4
  /**
@@ -1,10 +1,10 @@
1
- import { b as resolveClickClackAccount, d as isClickClackChannelNameConflict, l as ClickClackHttpError, u as createClickClackClient, v as listClickClackAccountIds } from "./setup-surface-BQ1Zyohu.js";
2
- import { C as slugifyDiscussionLabel, D as listPendingDiscussionOpens, E as clearPendingDiscussionOpen, O as recordPendingDiscussionOpen, S as resolveDiscussionLabel, T as clearDiscussionBindingGeneration, _ as getClickClackDiscussionBindingStore, b as fallbackDiscussionLabel, c as markClickClackDiscussionChannelIdentityRevoked, d as discussionInfoForBinding, f as normalizedServerBaseUrl, g as bindingMatchesActiveSessionIncarnation, h as attachBindingToCurrentActiveSession, k as reserveDiscussionBindingGeneration, l as markClickClackDiscussionChannelRevoked, o as clearClickClackDiscussionChannelRevoked, p as resolveDiscussionBindingAccount, s as isClickClackDiscussionChannelRevoked, u as discussionAccounts, v as discussionCredentialFingerprint, w as truncateDiscussionDisplayTitle, x as isDiscussionSessionKey, y as discussionExternalRef } from "./channel-ChO3E9i2.js";
1
+ import { b as resolveClickClackAccount, d as isClickClackChannelNameConflict, l as ClickClackHttpError, u as createClickClackClient, v as listClickClackAccountIds } from "./setup-surface-k_ZLgpwc.js";
2
+ import { C as slugifyDiscussionLabel, D as listPendingDiscussionOpens, E as clearPendingDiscussionOpen, O as recordPendingDiscussionOpen, S as resolveDiscussionLabel, T as clearDiscussionBindingGeneration, _ as getClickClackDiscussionBindingStore, b as fallbackDiscussionLabel, c as markClickClackDiscussionChannelIdentityRevoked, d as discussionInfoForBinding, f as normalizedServerBaseUrl, g as bindingMatchesActiveSessionIncarnation, h as attachBindingToCurrentActiveSession, k as reserveDiscussionBindingGeneration, l as markClickClackDiscussionChannelRevoked, o as clearClickClackDiscussionChannelRevoked, p as resolveDiscussionBindingAccount, s as isClickClackDiscussionChannelRevoked, u as discussionAccounts, v as discussionCredentialFingerprint, w as truncateDiscussionDisplayTitle, x as isDiscussionSessionKey, y as discussionExternalRef } from "./channel-84ZGfWxl.js";
3
3
  import "./api.js";
4
4
  import { randomUUID } from "node:crypto";
5
5
  import { buildControlUiSessionPath, registerSessionDiscussionProvider } from "openclaw/plugin-sdk/session-discussion";
6
6
  import { createSessionVisibilityChecker } from "openclaw/plugin-sdk/session-visibility";
7
- import { resolveSessionAgentId } from "openclaw/plugin-sdk/agent-scope-runtime";
7
+ import { resolveSessionAgentIdStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
8
8
  import { textResult } from "openclaw/plugin-sdk/tool-results";
9
9
  //#region extensions/clickclack/src/discussions/binding-retention.ts
10
10
  var DetachedDiscussionBindingRetention = class {
@@ -257,7 +257,7 @@ async function openClickClackDiscussionBinding(params) {
257
257
  if (listPendingDiscussionOpens(runtime).some((pending) => pending.sessionKey === sessionKey)) throw new Error("A previous ClickClack discussion open is still unresolved; restore its credential and retry");
258
258
  }
259
259
  const config = runtime.config.current();
260
- const agentId = resolveSessionAgentId({
260
+ const agentId = resolveSessionAgentIdStrict({
261
261
  config,
262
262
  sessionKey
263
263
  });
@@ -338,7 +338,7 @@ async function openClickClackDiscussionBinding(params) {
338
338
  }
339
339
  break;
340
340
  } catch (error) {
341
- if (isClickClackChannelNameConflict(error) && attempt < CHANNEL_NAME_MUTATION_ATTEMPTS$1 - 1) {
341
+ if (isClickClackChannelNameConflict(error) && attempt < 3) {
342
342
  channels = await client.channels(workspace.id);
343
343
  assertManagedChannelListContract(channels);
344
344
  continue;
@@ -442,7 +442,7 @@ async function openClickClackDiscussionBinding(params) {
442
442
  assertChannelPatch(currentChannel, latestManagedFields);
443
443
  break;
444
444
  } catch (error) {
445
- if (!isClickClackChannelNameConflict(error) || attempt === CHANNEL_NAME_MUTATION_ATTEMPTS$1 - 1) throw error;
445
+ if (!isClickClackChannelNameConflict(error) || attempt === 3) throw error;
446
446
  }
447
447
  }
448
448
  } catch (error) {
@@ -736,7 +736,7 @@ var ClickClackDiscussionService = class {
736
736
  assertChannelPatch(renamed, patch);
737
737
  return renamed;
738
738
  } catch (error) {
739
- if (!isClickClackChannelNameConflict(error) || attempt === CHANNEL_NAME_MUTATION_ATTEMPTS - 1) throw error;
739
+ if (!isClickClackChannelNameConflict(error) || attempt === 3) throw error;
740
740
  }
741
741
  }
742
742
  throw new Error("ClickClack discussion channel name retries were exhausted");
@@ -1,4 +1,4 @@
1
- import { b as resolveClickClackAccount, u as createClickClackClient } from "./setup-surface-BQ1Zyohu.js";
2
- import { a as setClickClackRuntime, r as parseClickClackTarget } from "./channel-ChO3E9i2.js";
3
- import { t as registerClickClackDiscussions } from "./runtime-api-B0ChZLhm.js";
1
+ import { b as resolveClickClackAccount, u as createClickClackClient } from "./setup-surface-k_ZLgpwc.js";
2
+ import { a as setClickClackRuntime, r as parseClickClackTarget } from "./channel-84ZGfWxl.js";
3
+ import { t as registerClickClackDiscussions } from "./runtime-api-6Kws_vrf.js";
4
4
  export { createClickClackClient, parseClickClackTarget, registerClickClackDiscussions, resolveClickClackAccount, setClickClackRuntime };
@@ -1,10 +1,10 @@
1
- import { a as isClickClackSetupLoopbackHost, i as buildClickClackSetupClaimUrl, o as requireClickClackSetupApiBaseUrl } from "./setup-surface-BQ1Zyohu.js";
1
+ import { a as isClickClackSetupLoopbackHost, i as buildClickClackSetupClaimUrl, o as requireClickClackSetupApiBaseUrl } from "./setup-surface-k_ZLgpwc.js";
2
2
  import { createProviderOperationDeadline, readProviderJsonResponse, readResponseTextLimited, resolveProviderOperationTimeoutMs } from "openclaw/plugin-sdk/provider-http";
3
3
  import { fetchWithSsrFGuard, resolvePinnedHostnameWithPolicy, ssrfPolicyFromHttpBaseUrlAllowedHostname } from "openclaw/plugin-sdk/ssrf-runtime";
4
4
  import { withTimeout } from "openclaw/plugin-sdk/text-utility-runtime";
5
5
  //#region extensions/clickclack/src/setup-claim.ts
6
- const CLICKCLACK_ERROR_BODY_LIMIT_BYTES = 8 * 1024;
7
- const CLICKCLACK_SETUP_CODE_CLAIM_JSON_LIMIT_BYTES = 64 * 1024;
6
+ const CLICKCLACK_ERROR_BODY_LIMIT_BYTES = 8192;
7
+ const CLICKCLACK_SETUP_CODE_CLAIM_JSON_LIMIT_BYTES = 65536;
8
8
  const CLICKCLACK_SETUP_CODE_CLAIM_TIMEOUT_MS = 3e4;
9
9
  var ClickClackSetupCodeClaimError = class extends Error {
10
10
  constructor(status, detail) {
@@ -1,4 +1,4 @@
1
- import { g as clickClackMeta, h as clickClackConfigAdapter, n as clickClackSetupContract, p as clickClackConfigSchema, t as clickClackSetupWizard } from "./setup-surface-BQ1Zyohu.js";
1
+ import { g as clickClackMeta, h as clickClackConfigAdapter, n as clickClackSetupContract, p as clickClackConfigSchema, t as clickClackSetupWizard } from "./setup-surface-k_ZLgpwc.js";
2
2
  //#region extensions/clickclack/src/channel.setup.ts
3
3
  const clickClackSetupPlugin = {
4
4
  id: "clickclack",
@@ -3,9 +3,9 @@ import { DEFAULT_ACCOUNT_ID, DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$2, normali
3
3
  import { resolveNormalizedAccountEntry } from "openclaw/plugin-sdk/account-resolution-runtime";
4
4
  import { resolveIntegerOption } from "openclaw/plugin-sdk/number-runtime";
5
5
  import { mergePairLoopGuardConfig } from "openclaw/plugin-sdk/pair-loop-guard-runtime";
6
- import { resolveDefaultSecretProviderAlias } from "openclaw/plugin-sdk/provider-auth";
7
6
  import { tryReadSecretFileSync } from "openclaw/plugin-sdk/secret-file-runtime";
8
7
  import { buildSecretInputSchema, normalizeSecretInputString, resolveSecretInputString } from "openclaw/plugin-sdk/secret-input";
8
+ import { canResolveEnvSecretRefInReadOnlyPath } from "openclaw/plugin-sdk/secret-ref-readonly";
9
9
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
10
10
  import { getChatChannelMeta } from "openclaw/plugin-sdk/channel-plugin-common";
11
11
  import { ChannelBotLoopProtectionSchema, buildChannelAllowBotsSchema, buildChannelConfigSchema, buildMultiAccountChannelSchema } from "openclaw/plugin-sdk/channel-config-schema";
@@ -121,11 +121,15 @@ function resolveClickClackToken(params) {
121
121
  };
122
122
  }
123
123
  if (resolved.status === "configured_unavailable" && resolved.ref.source === "env") {
124
- const providerConfig = params.cfg.secrets?.providers?.[resolved.ref.provider];
125
- if (providerConfig) {
124
+ if (!canResolveEnvSecretRefInReadOnlyPath({
125
+ cfg: params.cfg,
126
+ ...resolved.ref
127
+ })) {
128
+ const providerConfig = params.cfg.secrets?.providers?.[resolved.ref.provider];
129
+ if (!providerConfig) throw new Error(`Secret provider "${resolved.ref.provider}" is not configured (ref: env:${resolved.ref.provider}:${resolved.ref.id}).`);
126
130
  if (providerConfig.source !== "env") throw new Error(`Secret provider "${resolved.ref.provider}" has source "${providerConfig.source}" but ref requests "env".`);
127
- if (providerConfig.allowlist && !providerConfig.allowlist.includes(resolved.ref.id)) throw new Error(`Environment variable "${resolved.ref.id}" is not allowlisted in secrets.providers.${resolved.ref.provider}.allowlist.`);
128
- } else if (resolved.ref.provider !== resolveDefaultSecretProviderAlias({ secrets: params.cfg.secrets }, "env")) throw new Error(`Secret provider "${resolved.ref.provider}" is not configured (ref: env:${resolved.ref.provider}:${resolved.ref.id}).`);
131
+ throw new Error(`Environment variable "${resolved.ref.id}" is not allowlisted in secrets.providers.${resolved.ref.provider}.allowlist.`);
132
+ }
129
133
  const token = normalizeSecretInputString((params.env ?? process.env)[resolved.ref.id]);
130
134
  return {
131
135
  token: token ?? "",
@@ -246,6 +250,8 @@ const ClickClackAccountConfigSchema = z.object({
246
250
  name: z.string().optional(),
247
251
  enabled: z.boolean().optional(),
248
252
  configWrites: z.boolean().optional(),
253
+ mediaMaxMb: z.number().positive().optional(),
254
+ responsePrefix: z.string().optional(),
249
255
  baseUrl: z.string().url().optional(),
250
256
  apiBaseUrl: z.string().url().optional(),
251
257
  token: buildSecretInputSchema().optional(),
@@ -280,11 +286,12 @@ const ClickClackAccountConfigSchema = z.object({
280
286
  section: z.string().optional()
281
287
  }).strict().optional()
282
288
  }).strict();
289
+ const ClickClackConfigSchema = buildMultiAccountChannelSchema(ClickClackAccountConfigSchema.extend({ historyLimit: z.number().int().min(0).optional() }), { accountSchema: ClickClackAccountConfigSchema.partial() });
283
290
  /**
284
291
  * Config schema exported to core so `openclaw doctor` and config validation
285
292
  * understand both default and named ClickClack accounts.
286
293
  */
287
- const clickClackConfigSchema = buildChannelConfigSchema(buildMultiAccountChannelSchema(ClickClackAccountConfigSchema, { accountSchema: ClickClackAccountConfigSchema.partial() }));
294
+ const clickClackConfigSchema = buildChannelConfigSchema(ClickClackConfigSchema);
288
295
  //#endregion
289
296
  //#region extensions/clickclack/src/http-client.ts
290
297
  /**
@@ -303,11 +310,11 @@ function provenanceFields(provenance) {
303
310
  if (provenance?.runtime?.trim()) fields.author_runtime = provenance.runtime.trim();
304
311
  return fields;
305
312
  }
306
- const CLICKCLACK_ERROR_BODY_LIMIT_BYTES = 8 * 1024;
313
+ const CLICKCLACK_ERROR_BODY_LIMIT_BYTES = 8192;
307
314
  const CLICKCLACK_CORRELATION_ID_MAX_LENGTH = 128;
308
315
  const CLICKCLACK_CORRELATION_ID_PATTERN = /^[A-Za-z0-9._:-]+$/u;
309
316
  const CLICKCLACK_CORRELATION_ID_HEADER = "X-Correlation-ID";
310
- const CLICKCLACK_INBOUND_JSON_LIMIT_BYTES = 16 * 1024 * 1024;
317
+ const CLICKCLACK_INBOUND_JSON_LIMIT_BYTES = 16777216;
311
318
  const CLICKCLACK_WEBSOCKET_HANDSHAKE_TIMEOUT_MS = 3e4;
312
319
  const CLICKCLACK_EPHEMERAL_REQUEST_TIMEOUT_MS = 15e3;
313
320
  const CLICKCLACK_MESSAGE_PAGE_LIMIT = 200;
@@ -772,13 +779,14 @@ function formatClickClackSetupCodeClaimError(error) {
772
779
  }
773
780
  function applyClickClackSetupConfigPatch(params) {
774
781
  const accountId = normalizeAccountId(params.accountId);
782
+ const scopedConfig = accountId === DEFAULT_ACCOUNT_ID ? params.cfg : moveSingleAccountChannelSectionToDefaultAccount({
783
+ cfg: params.cfg,
784
+ channelKey: channel$1,
785
+ setupSurface: clickClackSetupAdapter
786
+ });
775
787
  return patchScopedAccountConfig({
776
788
  cfg: prepareScopedSetupConfig({
777
- cfg: accountId === DEFAULT_ACCOUNT_ID ? params.cfg : moveSingleAccountChannelSectionToDefaultAccount({
778
- cfg: params.cfg,
779
- channelKey: channel$1,
780
- setupSurface: clickClackSetupAdapter
781
- }),
789
+ cfg: scopedConfig,
782
790
  channelKey: channel$1,
783
791
  accountId,
784
792
  name: params.name,
@@ -813,7 +821,7 @@ const clickClackSetupAdapter = {
813
821
  const claimUrl = setup.exactClaimUrl && !privateApiBaseUrl ? setup.exactClaimUrl : buildClickClackSetupClaimUrl(privateApiBaseUrl ?? setup.baseUrl);
814
822
  let claim;
815
823
  try {
816
- const { claimClickClackSetupCode } = await import("./setup-claim--cdFCz2P.js");
824
+ const { claimClickClackSetupCode } = await import("./setup-claim-D3B51eQ0.js");
817
825
  claim = await claimClickClackSetupCode({
818
826
  claimUrl,
819
827
  code: setup.code,
@@ -167,7 +167,9 @@ class PerMessageDeflate {
167
167
  (typeof opts.serverMaxWindowBits === 'number' &&
168
168
  opts.serverMaxWindowBits > params.server_max_window_bits))) ||
169
169
  (typeof opts.clientMaxWindowBits === 'number' &&
170
- !params.client_max_window_bits)
170
+ (typeof params.client_max_window_bits === 'number'
171
+ ? opts.clientMaxWindowBits > params.client_max_window_bits
172
+ : !params.client_max_window_bits))
171
173
  ) {
172
174
  return false;
173
175
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ws",
3
- "version": "8.21.1",
3
+ "version": "8.21.3",
4
4
  "description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js",
5
5
  "keywords": [
6
6
  "HyBi",
@@ -24,6 +24,13 @@
24
24
  "configWrites": {
25
25
  "type": "boolean"
26
26
  },
27
+ "mediaMaxMb": {
28
+ "type": "number",
29
+ "exclusiveMinimum": 0
30
+ },
31
+ "responsePrefix": {
32
+ "type": "string"
33
+ },
27
34
  "baseUrl": {
28
35
  "type": "string",
29
36
  "format": "uri"
@@ -306,6 +313,11 @@
306
313
  },
307
314
  "additionalProperties": false
308
315
  },
316
+ "historyLimit": {
317
+ "type": "integer",
318
+ "minimum": 0,
319
+ "maximum": 9007199254740991
320
+ },
309
321
  "accounts": {
310
322
  "type": "object",
311
323
  "propertyNames": {
@@ -323,6 +335,13 @@
323
335
  "configWrites": {
324
336
  "type": "boolean"
325
337
  },
338
+ "mediaMaxMb": {
339
+ "type": "number",
340
+ "exclusiveMinimum": 0
341
+ },
342
+ "responsePrefix": {
343
+ "type": "string"
344
+ },
326
345
  "baseUrl": {
327
346
  "type": "string",
328
347
  "format": "uri"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/clickclack",
3
- "version": "2026.8.1-beta.3",
3
+ "version": "2026.8.2",
4
4
  "description": "OpenClaw ClickClack channel plugin",
5
5
  "type": "module",
6
6
  "exports": {
@@ -9,11 +9,11 @@
9
9
  "./runtime-api.js": "./dist/runtime-api.js"
10
10
  },
11
11
  "dependencies": {
12
- "ws": "8.21.1",
12
+ "ws": "8.21.3",
13
13
  "zod": "4.4.3"
14
14
  },
15
15
  "peerDependencies": {
16
- "openclaw": ">=2026.8.1-beta.3"
16
+ "openclaw": ">=2026.8.2"
17
17
  },
18
18
  "peerDependenciesMeta": {
19
19
  "openclaw": {
@@ -139,10 +139,10 @@
139
139
  "allowInvalidConfigRecovery": true
140
140
  },
141
141
  "compat": {
142
- "pluginApi": ">=2026.8.1-beta.3"
142
+ "pluginApi": ">=2026.8.2"
143
143
  },
144
144
  "build": {
145
- "openclawVersion": "2026.8.1-beta.3",
145
+ "openclawVersion": "2026.8.2",
146
146
  "bundledDist": false
147
147
  },
148
148
  "release": {