@openclaw/clickclack 2026.8.1-beta.2 → 2026.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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-DjT-gmMe.js";
2
- import { a as setClickClackRuntime, i as getClickClackRuntime, n as buildClickClackTarget, r as parseClickClackTarget, t as clickClackPlugin } from "./channel-DaHgaTy1.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-1p34fBnm.js";
2
+ import { a as setClickClackRuntime, i as getClickClackRuntime, n as buildClickClackTarget, r as parseClickClackTarget, t as clickClackPlugin } from "./channel-Byi8SvFt.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-DjT-gmMe.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-1p34fBnm.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";
@@ -866,15 +867,16 @@ async function syncClickClackCommandMenu(params) {
866
867
  await params.client.setBotCommands(commands);
867
868
  } catch (error) {
868
869
  const status = errorStatus(error);
870
+ const messagePrefix = `[${params.accountId}] ClickClack command menu sync`;
869
871
  if (status === 403) {
870
- params.log?.warn?.("ClickClack command menu sync skipped: bot token lacks commands:write");
872
+ params.log?.warn?.(`${messagePrefix} skipped: ${formatErrorMessage(error)}; verify token/workspace command permissions or set commandMenu: false if menus are not needed`);
871
873
  return;
872
874
  }
873
875
  if (status === 404) {
874
- params.log?.debug?.("ClickClack command menu sync skipped: server does not support /api/bots/self/commands");
876
+ params.log?.debug?.(`${messagePrefix} skipped: server does not support /api/bots/self/commands`);
875
877
  return;
876
878
  }
877
- params.log?.warn?.(`ClickClack command menu sync failed: ${formatErrorMessage(error)}`);
879
+ params.log?.warn?.(`${messagePrefix} failed: ${formatErrorMessage(error)}`);
878
880
  }
879
881
  }
880
882
  //#endregion
@@ -1210,13 +1212,18 @@ async function sendClickClackMedia(params) {
1210
1212
  deliveryQueueId: params.deliveryQueueId,
1211
1213
  deliveryPartIndex: params.deliveryPartIndex
1212
1214
  });
1215
+ const { account, client } = createOutboundContext(params);
1216
+ const maxBytes = Math.min(resolveChannelMediaMaxBytes({
1217
+ cfg: params.cfg,
1218
+ accountId: account.accountId,
1219
+ resolveChannelLimitMb: () => account.config.mediaMaxMb
1220
+ }) ?? CLICKCLACK_MAX_UPLOAD_BYTES, CLICKCLACK_MAX_UPLOAD_BYTES);
1213
1221
  const preloadedMedia = nonces.upload ? void 0 : await loadOutboundMediaFromUrl(params.mediaUrl, {
1214
- maxBytes: CLICKCLACK_MAX_UPLOAD_BYTES,
1222
+ maxBytes,
1215
1223
  mediaAccess: params.mediaAccess,
1216
1224
  mediaLocalRoots: params.mediaLocalRoots,
1217
1225
  mediaReadFile: params.mediaReadFile
1218
1226
  });
1219
- const { account, client } = createOutboundContext(params);
1220
1227
  const workspaceId = await resolveWorkspaceId(client, account.workspace);
1221
1228
  const persistedUpload = nonces.upload ? await client.findUploadByNonce({
1222
1229
  workspaceId,
@@ -1227,7 +1234,7 @@ async function sendClickClackMedia(params) {
1227
1234
  let mediaFilename = preloadedMedia?.fileName?.trim();
1228
1235
  if (!upload) {
1229
1236
  const media = preloadedMedia ?? await loadOutboundMediaFromUrl(params.mediaUrl, {
1230
- maxBytes: CLICKCLACK_MAX_UPLOAD_BYTES,
1237
+ maxBytes,
1231
1238
  mediaAccess: params.mediaAccess,
1232
1239
  mediaLocalRoots: params.mediaLocalRoots,
1233
1240
  mediaReadFile: params.mediaReadFile
@@ -1591,7 +1598,7 @@ function resolveClickClackAgentRunId(messageId) {
1591
1598
  }
1592
1599
  async function dispatchModelReply(params) {
1593
1600
  const runtime = getClickClackRuntime();
1594
- const text = (await runtime.llm.complete({
1601
+ const result = await runtime.llm.complete({
1595
1602
  agentId: params.route.agentId,
1596
1603
  model: params.account.model,
1597
1604
  purpose: "clickclack bot reply",
@@ -1600,14 +1607,28 @@ async function dispatchModelReply(params) {
1600
1607
  role: "user",
1601
1608
  content: params.message.body
1602
1609
  }]
1603
- })).text.trim();
1604
- if (!text) {
1610
+ });
1611
+ const completion = result.text.trim();
1612
+ if (!completion) {
1605
1613
  runtime.logging.getChildLogger({
1606
1614
  plugin: "clickclack",
1607
1615
  feature: "model-reply"
1608
1616
  }).warn(`[${params.account.accountId}] ClickClack model reply produced no sendable text`);
1609
1617
  return;
1610
1618
  }
1619
+ const replyPipeline = createChannelMessageReplyPipeline({
1620
+ cfg: params.cfg,
1621
+ agentId: params.route.agentId,
1622
+ channel: CHANNEL_ID$1,
1623
+ accountId: params.account.accountId
1624
+ });
1625
+ replyPipeline.onModelSelected?.({
1626
+ provider: result.provider,
1627
+ model: result.model,
1628
+ thinkLevel: void 0
1629
+ });
1630
+ const responsePrefix = replyPipeline.resolveResponsePrefix?.();
1631
+ const text = responsePrefix && !completion.startsWith(responsePrefix) ? `${responsePrefix} ${completion}` : completion;
1611
1632
  await sendClickClackText({
1612
1633
  cfg: params.cfg,
1613
1634
  accountId: params.account.accountId,
@@ -1868,7 +1889,7 @@ function parseSocketEvent(data) {
1868
1889
  }
1869
1890
  async function processEvent(params) {
1870
1891
  if (params.event.type !== "message.created" && params.event.type !== "thread.reply_created") return;
1871
- if (payloadString(params.event, "author_id") === params.botUserId) return;
1892
+ if (params.abortSignal.aborted || payloadString(params.event, "author_id") === params.botUserId) return;
1872
1893
  const correlationId = eventCorrelationId(params.event);
1873
1894
  const message = await resolveEventMessage({
1874
1895
  client: correlationId ? createClickClackClient({
@@ -1882,12 +1903,13 @@ async function processEvent(params) {
1882
1903
  params.log?.warn?.(`[${params.account.accountId}] skipped unreadable ClickClack message before agent dispatch: type=${params.event.type} messageId=${payloadString(params.event, "message_id") || "unknown"}`);
1883
1904
  return;
1884
1905
  }
1885
- if (message.author_id === params.botUserId) return;
1906
+ if (params.abortSignal.aborted || message.author_id === params.botUserId) return;
1886
1907
  const access = await resolveClickClackInboundAccess({
1887
1908
  account: params.account,
1888
1909
  config: params.config,
1889
1910
  message
1890
1911
  });
1912
+ if (params.abortSignal.aborted) return;
1891
1913
  if (!access.shouldDispatch) {
1892
1914
  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}`);
1893
1915
  return;
@@ -1937,6 +1959,7 @@ async function startClickClackGatewayAccount(ctx) {
1937
1959
  botHandle: me.handle
1938
1960
  };
1939
1961
  const processIncomingEvent = (event) => processEvent({
1962
+ abortSignal: ctx.abortSignal,
1940
1963
  account,
1941
1964
  config: ctx.cfg,
1942
1965
  client,
@@ -1948,7 +1971,8 @@ async function startClickClackGatewayAccount(ctx) {
1948
1971
  if (account.commandMenu) await syncClickClackCommandMenu({
1949
1972
  cfg: ctx.cfg,
1950
1973
  client,
1951
- log: ctx.log
1974
+ log: ctx.log,
1975
+ accountId: account.accountId
1952
1976
  });
1953
1977
  ctx.setStatus({
1954
1978
  accountId: account.accountId,
@@ -2015,6 +2039,7 @@ async function startClickClackGatewayAccount(ctx) {
2015
2039
  socket.on("message", (data) => {
2016
2040
  if (closing || settled) return;
2017
2041
  messageQueue = messageQueue.then(async () => {
2042
+ if (ctx.abortSignal.aborted) return;
2018
2043
  const event = parseSocketEvent(data);
2019
2044
  if (!event) {
2020
2045
  ctx.log?.warn?.(`[${account.accountId}] skipped malformed ClickClack websocket event`);
@@ -2156,6 +2181,7 @@ const clickClackPlugin = createChatChannelPlugin({
2156
2181
  capabilities: {
2157
2182
  chatTypes: ["direct", "group"],
2158
2183
  threads: true,
2184
+ media: true,
2159
2185
  blockStreaming: true
2160
2186
  },
2161
2187
  reload: { configPrefixes: ["channels.clickclack"] },
@@ -2222,7 +2248,11 @@ const clickClackPlugin = createChatChannelPlugin({
2222
2248
  name: account.name,
2223
2249
  enabled: account.enabled,
2224
2250
  configured: account.configured,
2225
- baseUrl: account.baseUrl
2251
+ extra: {
2252
+ baseUrl: account.baseUrl,
2253
+ tokenSource: account.tokenSource,
2254
+ tokenStatus: account.tokenStatus
2255
+ }
2226
2256
  })
2227
2257
  }),
2228
2258
  gateway: { startAccount: startClickClackGatewayAccount },
@@ -1,2 +1,2 @@
1
- import { t as clickClackPlugin } from "./channel-DaHgaTy1.js";
1
+ import { t as clickClackPlugin } from "./channel-Byi8SvFt.js";
2
2
  export { clickClackPlugin };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as registerClickClackDiscussions } from "./runtime-api-CPL3m5AD.js";
1
+ import { t as registerClickClackDiscussions } from "./runtime-api-DynyiJBy.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-DjT-gmMe.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-DaHgaTy1.js";
1
+ import { b as resolveClickClackAccount, d as isClickClackChannelNameConflict, l as ClickClackHttpError, u as createClickClackClient, v as listClickClackAccountIds } from "./setup-surface-1p34fBnm.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-Byi8SvFt.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
  });
@@ -1,4 +1,4 @@
1
- import { b as resolveClickClackAccount, u as createClickClackClient } from "./setup-surface-DjT-gmMe.js";
2
- import { a as setClickClackRuntime, r as parseClickClackTarget } from "./channel-DaHgaTy1.js";
3
- import { t as registerClickClackDiscussions } from "./runtime-api-CPL3m5AD.js";
1
+ import { b as resolveClickClackAccount, u as createClickClackClient } from "./setup-surface-1p34fBnm.js";
2
+ import { a as setClickClackRuntime, r as parseClickClackTarget } from "./channel-Byi8SvFt.js";
3
+ import { t as registerClickClackDiscussions } from "./runtime-api-DynyiJBy.js";
4
4
  export { createClickClackClient, parseClickClackTarget, registerClickClackDiscussions, resolveClickClackAccount, setClickClackRuntime };
@@ -1,4 +1,4 @@
1
- import { a as isClickClackSetupLoopbackHost, i as buildClickClackSetupClaimUrl, o as requireClickClackSetupApiBaseUrl } from "./setup-surface-DjT-gmMe.js";
1
+ import { a as isClickClackSetupLoopbackHost, i as buildClickClackSetupClaimUrl, o as requireClickClackSetupApiBaseUrl } from "./setup-surface-1p34fBnm.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";
@@ -1,4 +1,4 @@
1
- import { g as clickClackMeta, h as clickClackConfigAdapter, n as clickClackSetupContract, p as clickClackConfigSchema, t as clickClackSetupWizard } from "./setup-surface-DjT-gmMe.js";
1
+ import { g as clickClackMeta, h as clickClackConfigAdapter, n as clickClackSetupContract, p as clickClackConfigSchema, t as clickClackSetupWizard } from "./setup-surface-1p34fBnm.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
- import { buildSecretInputSchema, normalizeResolvedSecretInputString, normalizeSecretInputString, resolveSecretInputString } from "openclaw/plugin-sdk/secret-input";
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";
@@ -87,7 +87,20 @@ function resolveClickClackAccountConfig(cfg, accountId) {
87
87
  }
88
88
  function resolveClickClackToken(params) {
89
89
  const tokenFile = params.tokenFile?.trim();
90
- if (tokenFile) return tryReadSecretFileSync(tokenFile, params.accountId === DEFAULT_ACCOUNT_ID$2 ? "channels.clickclack.tokenFile" : `channels.clickclack.accounts.${params.accountId}.tokenFile`, { rejectSymlink: true }) ?? "";
90
+ if (tokenFile) {
91
+ const accountTokenFile = resolveNormalizedAccountEntry(params.cfg.channels?.clickclack?.accounts, params.accountId, normalizeAccountId)?.tokenFile?.trim();
92
+ const result = tryReadSecretFileSync(tokenFile, "ClickClack bot token", { rejectSymlink: true }, { configPath: accountTokenFile ? `channels.clickclack.accounts.${params.accountId}.tokenFile` : "channels.clickclack.tokenFile" });
93
+ return result.status === "available" ? {
94
+ token: result.value,
95
+ tokenSource: "tokenFile",
96
+ tokenStatus: "available"
97
+ } : {
98
+ token: "",
99
+ tokenSource: "tokenFile",
100
+ tokenStatus: "configured_unavailable",
101
+ credentialDiagnostics: [result.diagnostic]
102
+ };
103
+ }
91
104
  const resolved = resolveSecretInputString({
92
105
  value: params.value,
93
106
  path: params.accountId === DEFAULT_ACCOUNT_ID$2 ? "channels.clickclack.token" : `channels.clickclack.accounts.${params.accountId}.token`,
@@ -95,21 +108,46 @@ function resolveClickClackToken(params) {
95
108
  mode: "inspect"
96
109
  });
97
110
  if (resolved.status !== "available") {
98
- if (resolved.status === "missing" && params.accountId === DEFAULT_ACCOUNT_ID$2) return normalizeSecretInputString((params.env ?? process.env).CLICKCLACK_BOT_TOKEN) ?? "";
111
+ if (resolved.status === "missing" && params.accountId === DEFAULT_ACCOUNT_ID$2) {
112
+ const token = normalizeSecretInputString((params.env ?? process.env).CLICKCLACK_BOT_TOKEN);
113
+ return token ? {
114
+ token,
115
+ tokenSource: "env",
116
+ tokenStatus: "available"
117
+ } : {
118
+ token: "",
119
+ tokenSource: "none",
120
+ tokenStatus: "missing"
121
+ };
122
+ }
99
123
  if (resolved.status === "configured_unavailable" && resolved.ref.source === "env") {
100
- const providerConfig = params.cfg.secrets?.providers?.[resolved.ref.provider];
101
- 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}).`);
102
130
  if (providerConfig.source !== "env") throw new Error(`Secret provider "${resolved.ref.provider}" has source "${providerConfig.source}" but ref requests "env".`);
103
- 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.`);
104
- } 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}).`);
105
- return normalizeSecretInputString((params.env ?? process.env)[resolved.ref.id]) ?? "";
131
+ throw new Error(`Environment variable "${resolved.ref.id}" is not allowlisted in secrets.providers.${resolved.ref.provider}.allowlist.`);
132
+ }
133
+ const token = normalizeSecretInputString((params.env ?? process.env)[resolved.ref.id]);
134
+ return {
135
+ token: token ?? "",
136
+ tokenSource: "config",
137
+ tokenStatus: token ? "available" : "configured_unavailable"
138
+ };
106
139
  }
107
- return "";
140
+ return {
141
+ token: "",
142
+ tokenSource: resolved.status === "missing" ? "none" : "config",
143
+ tokenStatus: resolved.status
144
+ };
108
145
  }
109
- return normalizeResolvedSecretInputString({
110
- value: resolved.value,
111
- path: "channels.clickclack.token"
112
- }) ?? "";
146
+ return {
147
+ token: resolved.value,
148
+ tokenSource: "config",
149
+ tokenStatus: "available"
150
+ };
113
151
  }
114
152
  /**
115
153
  * Builds the normalized account snapshot used by gateway, outbound delivery,
@@ -134,10 +172,10 @@ function resolveClickClackAccount(params) {
134
172
  return {
135
173
  accountId,
136
174
  enabled,
137
- configured: Boolean(baseUrl && token && workspace),
175
+ configured: Boolean(baseUrl && token.tokenStatus !== "missing" && workspace),
138
176
  name: normalizeOptionalString(merged.name),
139
177
  baseUrl,
140
- token,
178
+ ...token,
141
179
  workspace,
142
180
  botUserId: normalizeOptionalString(merged.botUserId),
143
181
  agentId: normalizeOptionalString(merged.agentId),
@@ -212,6 +250,8 @@ const ClickClackAccountConfigSchema = z.object({
212
250
  name: z.string().optional(),
213
251
  enabled: z.boolean().optional(),
214
252
  configWrites: z.boolean().optional(),
253
+ mediaMaxMb: z.number().positive().optional(),
254
+ responsePrefix: z.string().optional(),
215
255
  baseUrl: z.string().url().optional(),
216
256
  apiBaseUrl: z.string().url().optional(),
217
257
  token: buildSecretInputSchema().optional(),
@@ -250,7 +290,7 @@ const ClickClackAccountConfigSchema = z.object({
250
290
  * Config schema exported to core so `openclaw doctor` and config validation
251
291
  * understand both default and named ClickClack accounts.
252
292
  */
253
- const clickClackConfigSchema = buildChannelConfigSchema(buildMultiAccountChannelSchema(ClickClackAccountConfigSchema, { accountSchema: ClickClackAccountConfigSchema.partial() }));
293
+ const clickClackConfigSchema = buildChannelConfigSchema(buildMultiAccountChannelSchema(ClickClackAccountConfigSchema.extend({ historyLimit: z.number().int().min(0).optional() }), { accountSchema: ClickClackAccountConfigSchema.partial() }));
254
294
  //#endregion
255
295
  //#region extensions/clickclack/src/http-client.ts
256
296
  /**
@@ -482,7 +522,7 @@ function createClickClackClient(options) {
482
522
  },
483
523
  createUpload: async (params) => {
484
524
  const form = new FormData();
485
- const bytes = new Uint8Array(params.buffer);
525
+ const bytes = params.buffer.buffer instanceof ArrayBuffer ? new Uint8Array(params.buffer.buffer, params.buffer.byteOffset, params.buffer.byteLength) : Uint8Array.from(params.buffer);
486
526
  form.append("file", new Blob([bytes], { type: params.contentType }), params.filename);
487
527
  const query = new URLSearchParams({ workspace_id: params.workspaceId });
488
528
  if (params.nonce) query.set("nonce", params.nonce);
@@ -779,7 +819,7 @@ const clickClackSetupAdapter = {
779
819
  const claimUrl = setup.exactClaimUrl && !privateApiBaseUrl ? setup.exactClaimUrl : buildClickClackSetupClaimUrl(privateApiBaseUrl ?? setup.baseUrl);
780
820
  let claim;
781
821
  try {
782
- const { claimClickClackSetupCode } = await import("./setup-claim-CQjgPGxU.js");
822
+ const { claimClickClackSetupCode } = await import("./setup-claim-D_6JQdu5.js");
783
823
  claim = await claimClickClackSetupCode({
784
824
  claimUrl,
785
825
  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.2",
3
+ "version": "2026.8.1",
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.2"
16
+ "openclaw": ">=2026.8.1"
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.2"
142
+ "pluginApi": ">=2026.8.1"
143
143
  },
144
144
  "build": {
145
- "openclawVersion": "2026.8.1-beta.2",
145
+ "openclawVersion": "2026.8.1",
146
146
  "bundledDist": false
147
147
  },
148
148
  "release": {