@openclaw/nextcloud-talk 2026.7.2-beta.7 → 2026.8.1-beta.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/dist/api.js CHANGED
@@ -1,2 +1,2 @@
1
- import { t as nextcloudTalkPlugin } from "./channel-B9yquEb1.js";
1
+ import { t as nextcloudTalkPlugin } from "./channel-CojgyJSq.js";
2
2
  export { nextcloudTalkPlugin };
@@ -1,6 +1,6 @@
1
1
  import { a as fetchWithSsrFGuard, c as resolveDefaultGroupPolicy, i as deliverFormattedTextWithAttachments, l as warnMissingProviderGroupPolicyFallbackOnce, o as logInboundDrop, r as createChannelPairingController, s as resolveAllowlistProviderRuntimeGroupPolicy, t as GROUP_POLICY_BLOCKED_LABEL, u as getNextcloudTalkRuntime } from "./runtime-api-BKsxTw4J.js";
2
- import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-fNhK1wag.js";
3
- import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-DGgvfVqm.js";
2
+ import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-Bda_xc6V.js";
3
+ import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-Bvm0PmP3.js";
4
4
  import { createAccountListHelpers, describeWebhookAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
5
5
  import { createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
6
6
  import { createLoggedPairingApprovalNotifier, createPairingPrefixStripper } from "openclaw/plugin-sdk/channel-pairing";
@@ -8,7 +8,7 @@ import { createAllowlistProviderRouteAllowlistWarningCollector, resolveScopeRequ
8
8
  import { buildWebhookChannelStatusSummary, createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
9
9
  import { FormatCapabilityProfile, convertMarkdownTables, renderMarkdownWithMarkers, sanitizeAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking";
10
10
  import { createChannelApprovalAuth } from "openclaw/plugin-sdk/approval-auth-runtime";
11
- import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
11
+ import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries, readNonEmptyStringPreservingWhitespace } from "openclaw/plugin-sdk/string-coerce-runtime";
12
12
  import { DEFAULT_ACCOUNT_ID, hasConfiguredAccountValue, normalizeAccountId, resolveAccountWithDefaultFallback } from "openclaw/plugin-sdk/account-core";
13
13
  import { isTruthyEnvValue } from "openclaw/plugin-sdk/runtime-env";
14
14
  import { tryReadSecretFileSync } from "openclaw/plugin-sdk/secret-file-runtime";
@@ -16,7 +16,7 @@ import { buildSecretInputSchema, hasConfiguredSecretInput, normalizeResolvedSecr
16
16
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
17
17
  import { parseStrictNonNegativeInteger, parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
18
18
  import { readProviderJsonResponse, readResponseTextLimited } from "openclaw/plugin-sdk/provider-http";
19
- import { buildChannelInboundEventContext, resolveChannelInboundRouteEnvelope } from "openclaw/plugin-sdk/channel-inbound";
19
+ import { resolveChannelInboundRouteEnvelope } from "openclaw/plugin-sdk/channel-inbound";
20
20
  import { bindIngressLifecycleToReplyOptions, createAccountStatusSink, createChannelIngressMonitor, createMessageReceiptFromOutboundResults, defineChannelMessageAdapter, resolveChannelStreamingBlockEnabled, runPassiveAccountLifecycle } from "openclaw/plugin-sdk/channel-outbound";
21
21
  import { ssrfPolicyFromPrivateNetworkOptIn, ssrfPolicyFromPrivateNetworkOptIn as ssrfPolicyFromPrivateNetworkOptIn$1 } from "openclaw/plugin-sdk/ssrf-runtime";
22
22
  import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
@@ -34,6 +34,7 @@ import os from "node:os";
34
34
  import path from "node:path";
35
35
  import { migratePersistentDedupeLegacyJsonFile, resolvePersistentDedupePluginStateNamespace } from "openclaw/plugin-sdk/persistent-dedupe";
36
36
  import { resolveStateDir } from "openclaw/plugin-sdk/state-paths";
37
+ import { channelReadyPatch } from "openclaw/plugin-sdk/gateway-runtime";
37
38
  import { channelIngressRoutes, resolveStableChannelMessageIngress } from "openclaw/plugin-sdk/channel-ingress-runtime";
38
39
  import { buildChannelKeyCandidates, normalizeChannelSlug, resolveChannelEntryMatchWithFallback } from "openclaw/plugin-sdk/channel-targets";
39
40
  import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
@@ -395,6 +396,7 @@ dangerouslyAllowPrivateNetwork: z.boolean().optional() }).strict().optional();
395
396
  const NextcloudTalkConfigSchema = buildMultiAccountChannelSchema(z.object({
396
397
  name: z.string().optional(),
397
398
  enabled: z.boolean().optional(),
399
+ configWrites: z.boolean().optional(),
398
400
  markdown: MarkdownConfigSchema,
399
401
  baseUrl: z.string().optional(),
400
402
  botSecret: buildSecretInputSchema().optional(),
@@ -593,10 +595,6 @@ function cacheRoomInfo(key, value) {
593
595
  roomCache.set(key, value);
594
596
  pruneMapToMaxSize(roomCache, ROOM_CACHE_MAX_ENTRIES);
595
597
  }
596
- function coerceRoomType(value) {
597
- if (typeof value === "number" && Number.isSafeInteger(value) && value > 0) return value;
598
- return parseStrictPositiveInteger(value);
599
- }
600
598
  function resolveRoomKindFromType(type) {
601
599
  if (!type) return;
602
600
  if (type === 1 || type === 5 || type === 6) return "direct";
@@ -648,7 +646,7 @@ async function resolveNextcloudTalkRoomKind(params) {
648
646
  runtime?.log?.(`nextcloud-talk: room lookup failed (${response.status}) token=${roomToken}`);
649
647
  return;
650
648
  }
651
- const kind = resolveRoomKindFromType(coerceRoomType((await readProviderJsonResponse(response, "Nextcloud Talk room info failed")).ocs?.data?.type));
649
+ const kind = resolveRoomKindFromType(parseStrictPositiveInteger((await readProviderJsonResponse(response, "Nextcloud Talk room info failed")).ocs?.data?.type));
652
650
  cacheRoomInfo(key, {
653
651
  fetchedAt: Date.now(),
654
652
  kind
@@ -987,7 +985,7 @@ async function handleNextcloudTalkInbound(params) {
987
985
  const allowFrom = normalizeStringEntries(account.config.allowFrom);
988
986
  const outerGroupAllowFrom = account.config.groupAllowFrom?.length ? normalizeStringEntries(account.config.groupAllowFrom) : allowFrom;
989
987
  const roomAllowFrom = normalizeStringEntries(roomConfig?.allowFrom);
990
- const resolveAccess = async (wasMentioned) => await resolveStableChannelMessageIngress({
988
+ const resolveAccess = async (wasMentioned, contextBinding) => await resolveStableChannelMessageIngress({
991
989
  channelId: CHANNEL_ID,
992
990
  accountId: account.accountId,
993
991
  identity: {
@@ -1003,6 +1001,7 @@ async function handleNextcloudTalkInbound(params) {
1003
1001
  kind: isGroup ? "group" : "direct",
1004
1002
  id: isGroup ? roomToken : senderId
1005
1003
  },
1004
+ contextBinding,
1006
1005
  route: roomRoutes({
1007
1006
  isGroup,
1008
1007
  groupPolicy,
@@ -1090,11 +1089,6 @@ async function handleNextcloudTalkInbound(params) {
1090
1089
  }
1091
1090
  const mentionRegexes = core.channel.mentions.buildMentionRegexes(config);
1092
1091
  const wasMentioned = mentionRegexes.length ? core.channel.mentions.matchesMentionPatterns(rawBody, mentionRegexes) : false;
1093
- if (isGroup) access = await resolveAccess(wasMentioned);
1094
- if (isGroup && access.activationAccess.shouldSkip) {
1095
- runtime.log?.(`nextcloud-talk: drop room ${roomToken} (no mention)`);
1096
- return;
1097
- }
1098
1092
  const { route, buildEnvelope } = resolveChannelInboundRouteEnvelope({
1099
1093
  cfg: config,
1100
1094
  channel: CHANNEL_ID,
@@ -1104,6 +1098,16 @@ async function handleNextcloudTalkInbound(params) {
1104
1098
  id: isGroup ? roomToken : senderId
1105
1099
  }
1106
1100
  });
1101
+ access = await resolveAccess(isGroup ? wasMentioned : void 0, {
1102
+ agentId: route.agentId,
1103
+ sessionKey: route.sessionKey,
1104
+ messageId: message.messageId,
1105
+ inboundEventKind: "user_request"
1106
+ });
1107
+ if (access.ingress.admission !== "dispatch") {
1108
+ runtime.log?.(isGroup && access.activationAccess.shouldSkip ? `nextcloud-talk: drop room ${roomToken} (no mention)` : `nextcloud-talk: drop ${isGroup ? "room" : "DM"} ${roomToken} (authorization changed)`);
1109
+ return;
1110
+ }
1107
1111
  const fromLabel = isGroup ? `room:${roomName || roomToken}` : senderName || `user:${senderId}`;
1108
1112
  const body = buildEnvelope({
1109
1113
  channel: "Nextcloud Talk",
@@ -1113,7 +1117,8 @@ async function handleNextcloudTalkInbound(params) {
1113
1117
  });
1114
1118
  const groupSystemPrompt = normalizeOptionalString(roomConfig?.systemPrompt);
1115
1119
  const blockStreamingEnabled = resolveChannelStreamingBlockEnabled(account.config);
1116
- const ctxPayload = buildChannelInboundEventContext({
1120
+ const ctxPayload = core.channel.inbound.buildContext({
1121
+ channelIngress: access,
1117
1122
  channel: CHANNEL_ID,
1118
1123
  accountId: route.accountId,
1119
1124
  messageId: message.messageId,
@@ -1125,7 +1130,7 @@ async function handleNextcloudTalkInbound(params) {
1125
1130
  },
1126
1131
  conversation: {
1127
1132
  kind: isGroup ? "group" : "direct",
1128
- id: roomToken,
1133
+ id: isGroup ? roomToken : senderId,
1129
1134
  label: fromLabel
1130
1135
  },
1131
1136
  route: {
@@ -1276,10 +1281,6 @@ const WEBHOOK_ERRORS = {
1276
1281
  payloadTooLarge: "Payload too large",
1277
1282
  internalServerError: "Internal server error"
1278
1283
  };
1279
- function formatError(err) {
1280
- if (err instanceof Error) return err.message;
1281
- return typeof err === "string" ? err : JSON.stringify(err);
1282
- }
1283
1284
  function writeJsonResponse(res, status, body) {
1284
1285
  if (body) {
1285
1286
  res.writeHead(status, { "Content-Type": "application/json" });
@@ -1388,7 +1389,7 @@ function createNextcloudTalkWebhookServer(opts) {
1388
1389
  writeWebhookError(res, 400, WEBHOOK_ERRORS.invalidPayloadFormat);
1389
1390
  return;
1390
1391
  }
1391
- const error = err instanceof Error ? err : new Error(formatError(err));
1392
+ const error = err instanceof Error ? err : new Error(formatErrorMessage(err));
1392
1393
  onError?.(error);
1393
1394
  writeWebhookError(res, 500, WEBHOOK_ERRORS.internalServerError);
1394
1395
  }
@@ -1536,12 +1537,12 @@ function createNextcloudTalkWebhookSpool(options) {
1536
1537
  await options.deliver(message, lifecycle);
1537
1538
  },
1538
1539
  pollIntervalMs: options.pollIntervalMs ?? NEXTCLOUD_TALK_INGRESS_POLL_INTERVAL_MS,
1539
- waitForDeliveryIdleBeforeRepump: true,
1540
1540
  retention: {
1541
1541
  completedMaxEntries: 1e4,
1542
1542
  failedMaxEntries: 1e4
1543
1543
  },
1544
1544
  drain: {
1545
+ startLimit: 32,
1545
1546
  resolveNonRetryableFailure,
1546
1547
  ...options.adoptionStallTimeoutMs === void 0 ? {} : { adoptionStallTimeoutMs: options.adoptionStallTimeoutMs },
1547
1548
  onLog: (message) => options.runtime.log?.(`nextcloud-talk ${message}`)
@@ -1672,6 +1673,7 @@ async function monitorNextcloudTalkProvider(opts) {
1672
1673
  await stop();
1673
1674
  return { stop };
1674
1675
  }
1676
+ opts.statusSink?.(channelReadyPatch());
1675
1677
  const publicUrl = account.config.webhookPublicUrl ?? `http://${host === "0.0.0.0" ? "localhost" : host}:${port}${path}`;
1676
1678
  logger.info(`[nextcloud-talk:${account.accountId}] webhook listening on ${publicUrl}`);
1677
1679
  return { stop };
@@ -1857,9 +1859,6 @@ function resolveNextcloudTalkOutboundSessionRoute(params) {
1857
1859
  //#region extensions/nextcloud-talk/src/setup-core.ts
1858
1860
  const t$1 = createSetupTranslator$1();
1859
1861
  const channel$1 = "nextcloud-talk";
1860
- function readOptionalString(value) {
1861
- return typeof value === "string" && value.length > 0 ? value : void 0;
1862
- }
1863
1862
  function normalizeNextcloudTalkBaseUrl(value) {
1864
1863
  return value?.trim().replace(/\/+$/, "") ?? "";
1865
1864
  }
@@ -1924,46 +1923,6 @@ const nextcloudTalkDmPolicy = createChannelDmPolicy({
1924
1923
  applyPatch: ({ cfg, account, patch }) => setNextcloudTalkAccountConfig(cfg, account.accountId, patch),
1925
1924
  promptAllowFrom: promptNextcloudTalkAllowFromForAccount
1926
1925
  });
1927
- const nextcloudTalkSetupAdapter = {
1928
- singleAccountKeysToMove: ["rooms"],
1929
- resolveAccountId: ({ accountId }) => normalizeAccountId$1(accountId),
1930
- prepareAccountConfigInput: ({ input }) => {
1931
- const setupInput = input;
1932
- return {
1933
- ...setupInput,
1934
- baseUrl: setupInput.baseUrl ?? readOptionalString(setupInput.url),
1935
- secret: setupInput.secret ?? readOptionalString(setupInput.token) ?? readOptionalString(setupInput.password),
1936
- secretFile: setupInput.secretFile ?? readOptionalString(setupInput.tokenFile)
1937
- };
1938
- },
1939
- applyAccountName: ({ cfg, accountId, name }) => applyAccountNameToChannelSection({
1940
- cfg,
1941
- channelKey: channel$1,
1942
- accountId,
1943
- name
1944
- }),
1945
- validateInput: createSetupInputPresenceValidator({
1946
- defaultAccountOnlyEnvError: "NEXTCLOUD_TALK_BOT_SECRET can only be used for the default account.",
1947
- validate: ({ input }) => {
1948
- const setupInput = input;
1949
- if (!setupInput.useEnv && !setupInput.secret && !setupInput.secretFile) return "Nextcloud Talk requires bot secret or --secret-file (or --use-env).";
1950
- if (!setupInput.baseUrl) return "Nextcloud Talk requires --base-url.";
1951
- return null;
1952
- }
1953
- }),
1954
- applyAccountConfig: ({ cfg, accountId, input }) => {
1955
- const setupInput = input;
1956
- return setNextcloudTalkAccountConfig(applyAccountNameToChannelSection({
1957
- cfg,
1958
- channelKey: channel$1,
1959
- accountId,
1960
- name: setupInput.name
1961
- }), accountId, {
1962
- baseUrl: normalizeNextcloudTalkBaseUrl(setupInput.baseUrl),
1963
- ...setupInput.useEnv ? {} : setupInput.secretFile ? { botSecretFile: setupInput.secretFile } : setupInput.secret ? { botSecret: setupInput.secret } : {}
1964
- }, setupInput.useEnv ? ["botSecret", "botSecretFile"] : void 0);
1965
- }
1966
- };
1967
1926
  const nextcloudTalkSetupContract = defineChannelSetupContract({
1968
1927
  fields: {
1969
1928
  baseUrl: {
@@ -2025,10 +1984,53 @@ const nextcloudTalkSetupContract = defineChannelSetupContract({
2025
1984
  cli: {
2026
1985
  flags: "--use-env",
2027
1986
  description: "Use Nextcloud Talk environment credentials"
2028
- }
1987
+ },
1988
+ envVars: ["NEXTCLOUD_TALK_BOT_SECRET"]
2029
1989
  }
2030
1990
  },
2031
- legacyAdapter: nextcloudTalkSetupAdapter
1991
+ legacyAdapter: {
1992
+ singleAccountKeysToMove: ["rooms"],
1993
+ resolveAccountId: ({ accountId }) => normalizeAccountId$1(accountId),
1994
+ prepareAccountConfigInput: ({ input }) => {
1995
+ const setupInput = input;
1996
+ return {
1997
+ ...setupInput,
1998
+ baseUrl: setupInput.baseUrl ?? readNonEmptyStringPreservingWhitespace(setupInput.url),
1999
+ secret: setupInput.secret ?? readNonEmptyStringPreservingWhitespace(setupInput.token) ?? readNonEmptyStringPreservingWhitespace(setupInput.password),
2000
+ secretFile: setupInput.secretFile ?? readNonEmptyStringPreservingWhitespace(setupInput.tokenFile)
2001
+ };
2002
+ },
2003
+ applyAccountName: ({ cfg, accountId, name }) => applyAccountNameToChannelSection({
2004
+ cfg,
2005
+ channelKey: channel$1,
2006
+ accountId,
2007
+ name
2008
+ }),
2009
+ validateInput: createSetupInputPresenceValidator({
2010
+ defaultAccountOnlyEnvError: "NEXTCLOUD_TALK_BOT_SECRET can only be used for the default account.",
2011
+ validate: ({ input }) => {
2012
+ const setupInput = input;
2013
+ if (!setupInput.useEnv && !setupInput.secret && !setupInput.secretFile) return "Nextcloud Talk requires bot secret or --secret-file (or --use-env).";
2014
+ const normalizedBaseUrl = normalizeNextcloudTalkBaseUrl(setupInput.baseUrl);
2015
+ if (!normalizedBaseUrl) return "Nextcloud Talk requires --base-url.";
2016
+ const baseUrlError = validateNextcloudTalkBaseUrl(normalizedBaseUrl);
2017
+ if (baseUrlError) return baseUrlError;
2018
+ return null;
2019
+ }
2020
+ }),
2021
+ applyAccountConfig: ({ cfg, accountId, input }) => {
2022
+ const setupInput = input;
2023
+ return setNextcloudTalkAccountConfig(applyAccountNameToChannelSection({
2024
+ cfg,
2025
+ channelKey: channel$1,
2026
+ accountId,
2027
+ name: setupInput.name
2028
+ }), accountId, {
2029
+ baseUrl: normalizeNextcloudTalkBaseUrl(setupInput.baseUrl),
2030
+ ...setupInput.useEnv ? {} : setupInput.secretFile ? { botSecretFile: setupInput.secretFile } : setupInput.secret ? { botSecret: setupInput.secret } : {}
2031
+ }, setupInput.useEnv ? ["botSecret", "botSecretFile"] : void 0);
2032
+ }
2033
+ }
2032
2034
  });
2033
2035
  //#endregion
2034
2036
  //#region extensions/nextcloud-talk/src/setup-surface.ts
@@ -2232,6 +2234,7 @@ const nextcloudTalkPlugin = createChatChannelPlugin({
2232
2234
  "nc"
2233
2235
  ],
2234
2236
  normalizeTarget: normalizeNextcloudTalkMessagingTarget,
2237
+ inferTargetChatType: ({ to }) => normalizeNextcloudTalkMessagingTarget(to) ? "group" : void 0,
2235
2238
  resolveOutboundSessionRoute: (params) => resolveNextcloudTalkOutboundSessionRoute(params),
2236
2239
  targetResolver: {
2237
2240
  looksLikeId: looksLikeNextcloudTalkTargetId,
@@ -2242,7 +2245,6 @@ const nextcloudTalkPlugin = createChatChannelPlugin({
2242
2245
  secretTargetRegistryEntries,
2243
2246
  collectRuntimeConfigAssignments
2244
2247
  },
2245
- setup: nextcloudTalkSetupAdapter,
2246
2248
  setupContract: nextcloudTalkSetupContract,
2247
2249
  status: createComputedAccountStatusAdapter({
2248
2250
  defaultRuntime: createDefaultChannelRuntimeState(DEFAULT_ACCOUNT_ID$2),
@@ -1,2 +1,2 @@
1
- import { t as nextcloudTalkPlugin } from "./channel-B9yquEb1.js";
1
+ import { t as nextcloudTalkPlugin } from "./channel-CojgyJSq.js";
2
2
  export { nextcloudTalkPlugin };
@@ -1,5 +1,4 @@
1
- import { createLegacyPrivateNetworkDoctorContract } from "openclaw/plugin-sdk/ssrf-runtime";
2
- import { defineChannelAliasMigration } from "openclaw/plugin-sdk/runtime-doctor";
1
+ import { createLegacyPrivateNetworkDoctorContract, defineChannelAliasMigration } from "openclaw/plugin-sdk/runtime-doctor-migrations";
3
2
  //#region extensions/nextcloud-talk/src/doctor-contract.ts
4
3
  const networkContract = createLegacyPrivateNetworkDoctorContract({ channelKey: "nextcloud-talk" });
5
4
  const streamingAliasMigration = defineChannelAliasMigration({
@@ -1,2 +1,2 @@
1
- import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-fNhK1wag.js";
1
+ import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-Bda_xc6V.js";
2
2
  export { legacyConfigRules, normalizeCompatibilityConfig };
@@ -0,0 +1,15 @@
1
+ import { createSimpleChannelSecretContract } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
2
+ //#region extensions/nextcloud-talk/src/secret-contract.ts
3
+ const channelSecrets = createSimpleChannelSecretContract({
4
+ channelKey: "nextcloud-talk",
5
+ label: "Nextcloud Talk",
6
+ accountFields: ["apiPassword", "botSecret"],
7
+ channelFields: ["apiPassword", "botSecret"],
8
+ mode: {
9
+ kind: "surface-inheritance",
10
+ collectionFields: ["botSecret", "apiPassword"]
11
+ }
12
+ });
13
+ const { secretTargetRegistryEntries, collectRuntimeConfigAssignments } = channelSecrets;
14
+ //#endregion
15
+ export { collectRuntimeConfigAssignments as n, secretTargetRegistryEntries as r, channelSecrets as t };
@@ -1,2 +1,2 @@
1
- import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries, t as channelSecrets } from "./secret-contract-DGgvfVqm.js";
1
+ import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries, t as channelSecrets } from "./secret-contract-Bvm0PmP3.js";
2
2
  export { channelSecrets, collectRuntimeConfigAssignments, secretTargetRegistryEntries };
@@ -1,5 +1,8 @@
1
1
  {
2
2
  "id": "nextcloud-talk",
3
+ "doctorContract": {
4
+ "configRepair": true
5
+ },
3
6
  "name": "Nextcloud Talk",
4
7
  "description": "OpenClaw Nextcloud Talk channel plugin for conversations.",
5
8
  "icon": "https://cdn.simpleicons.org/nextcloud",
@@ -26,6 +29,9 @@
26
29
  "enabled": {
27
30
  "type": "boolean"
28
31
  },
32
+ "configWrites": {
33
+ "type": "boolean"
34
+ },
29
35
  "markdown": {
30
36
  "type": "object",
31
37
  "properties": {
@@ -74,6 +80,29 @@
74
80
  ],
75
81
  "additionalProperties": false
76
82
  },
83
+ {
84
+ "type": "object",
85
+ "properties": {
86
+ "source": {
87
+ "type": "string",
88
+ "const": "store"
89
+ },
90
+ "provider": {
91
+ "type": "string",
92
+ "pattern": "^[a-z][a-z0-9_-]{0,63}$"
93
+ },
94
+ "id": {
95
+ "type": "string",
96
+ "pattern": "^[A-Z][A-Z0-9_]{0,127}$"
97
+ }
98
+ },
99
+ "required": [
100
+ "source",
101
+ "provider",
102
+ "id"
103
+ ],
104
+ "additionalProperties": false
105
+ },
77
106
  {
78
107
  "type": "object",
79
108
  "properties": {
@@ -158,6 +187,29 @@
158
187
  ],
159
188
  "additionalProperties": false
160
189
  },
190
+ {
191
+ "type": "object",
192
+ "properties": {
193
+ "source": {
194
+ "type": "string",
195
+ "const": "store"
196
+ },
197
+ "provider": {
198
+ "type": "string",
199
+ "pattern": "^[a-z][a-z0-9_-]{0,63}$"
200
+ },
201
+ "id": {
202
+ "type": "string",
203
+ "pattern": "^[A-Z][A-Z0-9_]{0,127}$"
204
+ }
205
+ },
206
+ "required": [
207
+ "source",
208
+ "provider",
209
+ "id"
210
+ ],
211
+ "additionalProperties": false
212
+ },
161
213
  {
162
214
  "type": "object",
163
215
  "properties": {
@@ -424,6 +476,9 @@
424
476
  "enabled": {
425
477
  "type": "boolean"
426
478
  },
479
+ "configWrites": {
480
+ "type": "boolean"
481
+ },
427
482
  "markdown": {
428
483
  "type": "object",
429
484
  "properties": {
@@ -472,6 +527,29 @@
472
527
  ],
473
528
  "additionalProperties": false
474
529
  },
530
+ {
531
+ "type": "object",
532
+ "properties": {
533
+ "source": {
534
+ "type": "string",
535
+ "const": "store"
536
+ },
537
+ "provider": {
538
+ "type": "string",
539
+ "pattern": "^[a-z][a-z0-9_-]{0,63}$"
540
+ },
541
+ "id": {
542
+ "type": "string",
543
+ "pattern": "^[A-Z][A-Z0-9_]{0,127}$"
544
+ }
545
+ },
546
+ "required": [
547
+ "source",
548
+ "provider",
549
+ "id"
550
+ ],
551
+ "additionalProperties": false
552
+ },
475
553
  {
476
554
  "type": "object",
477
555
  "properties": {
@@ -556,6 +634,29 @@
556
634
  ],
557
635
  "additionalProperties": false
558
636
  },
637
+ {
638
+ "type": "object",
639
+ "properties": {
640
+ "source": {
641
+ "type": "string",
642
+ "const": "store"
643
+ },
644
+ "provider": {
645
+ "type": "string",
646
+ "pattern": "^[a-z][a-z0-9_-]{0,63}$"
647
+ },
648
+ "id": {
649
+ "type": "string",
650
+ "pattern": "^[A-Z][A-Z0-9_]{0,127}$"
651
+ }
652
+ },
653
+ "required": [
654
+ "source",
655
+ "provider",
656
+ "id"
657
+ ],
658
+ "additionalProperties": false
659
+ },
559
660
  {
560
661
  "type": "object",
561
662
  "properties": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/nextcloud-talk",
3
- "version": "2026.7.2-beta.7",
3
+ "version": "2026.8.1-beta.2",
4
4
  "description": "OpenClaw Nextcloud Talk channel plugin for conversations.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "type": "module",
10
10
  "peerDependencies": {
11
- "openclaw": ">=2026.7.2-beta.7"
11
+ "openclaw": ">=2026.8.1-beta.2"
12
12
  },
13
13
  "peerDependenciesMeta": {
14
14
  "openclaw": {
@@ -113,7 +113,10 @@
113
113
  "cli": {
114
114
  "flags": "--use-env",
115
115
  "description": "Use Nextcloud Talk environment credentials"
116
- }
116
+ },
117
+ "envVars": [
118
+ "NEXTCLOUD_TALK_BOT_SECRET"
119
+ ]
117
120
  }
118
121
  ]
119
122
  }
@@ -124,10 +127,10 @@
124
127
  "minHostVersion": ">=2026.4.10"
125
128
  },
126
129
  "compat": {
127
- "pluginApi": ">=2026.7.2-beta.7"
130
+ "pluginApi": ">=2026.8.1-beta.2"
128
131
  },
129
132
  "build": {
130
- "openclawVersion": "2026.7.2-beta.7"
133
+ "openclawVersion": "2026.8.1-beta.2"
131
134
  },
132
135
  "release": {
133
136
  "publishToClawHub": true,
@@ -1,45 +0,0 @@
1
- import { collectConditionalChannelFieldAssignments, createChannelSecretTargetRegistryEntries, getChannelSurface, hasOwnProperty } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
2
- //#region extensions/nextcloud-talk/src/secret-contract.ts
3
- const secretTargetRegistryEntries = createChannelSecretTargetRegistryEntries({
4
- channelKey: "nextcloud-talk",
5
- account: ["apiPassword", "botSecret"],
6
- channel: ["apiPassword", "botSecret"]
7
- });
8
- function collectRuntimeConfigAssignments(params) {
9
- const resolved = getChannelSurface(params.config, "nextcloud-talk");
10
- if (!resolved) return;
11
- const { channel: nextcloudTalk, surface } = resolved;
12
- const inheritsField = (field) => ({ account, enabled }) => enabled && !hasOwnProperty(account, field);
13
- collectConditionalChannelFieldAssignments({
14
- channelKey: "nextcloud-talk",
15
- field: "botSecret",
16
- channel: nextcloudTalk,
17
- surface,
18
- defaults: params.defaults,
19
- context: params.context,
20
- topLevelActiveWithoutAccounts: true,
21
- topLevelInheritedAccountActive: inheritsField("botSecret"),
22
- accountActive: ({ enabled }) => enabled,
23
- topInactiveReason: "no enabled Nextcloud Talk surface inherits this top-level botSecret.",
24
- accountInactiveReason: "Nextcloud Talk account is disabled."
25
- });
26
- collectConditionalChannelFieldAssignments({
27
- channelKey: "nextcloud-talk",
28
- field: "apiPassword",
29
- channel: nextcloudTalk,
30
- surface,
31
- defaults: params.defaults,
32
- context: params.context,
33
- topLevelActiveWithoutAccounts: true,
34
- topLevelInheritedAccountActive: inheritsField("apiPassword"),
35
- accountActive: ({ enabled }) => enabled,
36
- topInactiveReason: "no enabled Nextcloud Talk surface inherits this top-level apiPassword.",
37
- accountInactiveReason: "Nextcloud Talk account is disabled."
38
- });
39
- }
40
- const channelSecrets = {
41
- secretTargetRegistryEntries,
42
- collectRuntimeConfigAssignments
43
- };
44
- //#endregion
45
- export { collectRuntimeConfigAssignments as n, secretTargetRegistryEntries as r, channelSecrets as t };