@openclaw/nextcloud-talk 2026.7.1 → 2026.7.2-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-BMKRTDSP.js";
1
+ import { t as nextcloudTalkPlugin } from "./channel-BSnehBf6.js";
2
2
  export { nextcloudTalkPlugin };
@@ -1,47 +1,47 @@
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-BY7I5-v9.js";
3
- import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-CsCJ-vOP.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";
4
4
  import { 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";
7
- import { createAllowlistProviderRouteAllowlistWarningCollector } from "openclaw/plugin-sdk/channel-policy";
7
+ import { createAllowlistProviderRouteAllowlistWarningCollector, resolveScopeRequireMention, resolveScopeToolsPolicy } from "openclaw/plugin-sdk/channel-policy";
8
8
  import { buildWebhookChannelStatusSummary, createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
9
+ import { convertMarkdownTables, sanitizeAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking";
10
+ import { createChannelApprovalAuth } from "openclaw/plugin-sdk/approval-auth-runtime";
11
+ import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
9
12
  import { DEFAULT_ACCOUNT_ID, createAccountListHelpers, hasConfiguredAccountValue, normalizeAccountId, resolveAccountWithDefaultFallback, resolveMergedAccountConfig } from "openclaw/plugin-sdk/account-core";
10
13
  import { tryReadSecretFileSync } from "openclaw/plugin-sdk/secret-file-runtime";
11
- import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
12
14
  import { buildSecretInputSchema, hasConfiguredSecretInput, normalizeResolvedSecretInputString } from "openclaw/plugin-sdk/secret-input";
13
- import { createResolvedApproverActionAuthAdapter, resolveApprovalApprovers } from "openclaw/plugin-sdk/approval-auth-runtime";
14
15
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
15
16
  import { parseStrictNonNegativeInteger, parseStrictPositiveInteger } from "openclaw/plugin-sdk/number-runtime";
16
17
  import { readProviderJsonResponse, readResponseTextLimited } from "openclaw/plugin-sdk/provider-http";
17
- import { createAccountStatusSink, createMessageReceiptFromOutboundResults, defineChannelMessageAdapter } from "openclaw/plugin-sdk/channel-outbound";
18
+ import { createAccountStatusSink, createMessageReceiptFromOutboundResults, defineChannelMessageAdapter, resolveChannelStreamingBlockEnabled } from "openclaw/plugin-sdk/channel-outbound";
18
19
  import { ssrfPolicyFromPrivateNetworkOptIn, ssrfPolicyFromPrivateNetworkOptIn as ssrfPolicyFromPrivateNetworkOptIn$1 } from "openclaw/plugin-sdk/ssrf-runtime";
19
- import { readFileSync } from "node:fs";
20
20
  import { requireRuntimeConfig } from "openclaw/plugin-sdk/plugin-config-runtime";
21
21
  import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
22
- import { convertMarkdownTables } from "openclaw/plugin-sdk/text-chunking";
23
- import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
22
+ import { createHmac, randomBytes } from "node:crypto";
23
+ import { fileExists, safeEqualSecret } from "openclaw/plugin-sdk/security-runtime";
24
24
  import { clearAccountEntryFields } from "openclaw/plugin-sdk/channel-plugin-common";
25
25
  import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$2 } from "openclaw/plugin-sdk/account-id";
26
- import { DmPolicySchema, GroupPolicySchema, MarkdownConfigSchema, ReplyRuntimeConfigSchemaShape, ToolPolicySchema, buildChannelConfigSchema, requireOpenAllowFrom } from "openclaw/plugin-sdk/channel-config-schema";
26
+ import { DmPolicySchema, GroupPolicySchema, MarkdownConfigSchema, ReplyRuntimeConfigSchemaShape, buildChannelConfigSchema, buildGroupEntrySchema, buildMultiAccountChannelSchema, requireOpenAllowFrom } from "openclaw/plugin-sdk/channel-config-schema";
27
27
  import { formatAllowFromLowercase } from "openclaw/plugin-sdk/allow-from";
28
28
  import { adaptScopedAccountAccessor, createScopedChannelConfigAdapter, createScopedDmSecurityResolver } from "openclaw/plugin-sdk/channel-config-helpers";
29
29
  import { requireChannelOpenAllowFrom, resolveLoggerBackedRuntime, runStoppablePassiveMonitor, safeParseJsonWithSchema } from "openclaw/plugin-sdk/extension-shared";
30
30
  import { z } from "zod";
31
- import fs from "node:fs/promises";
32
31
  import os from "node:os";
33
32
  import path from "node:path";
34
- import { createClaimableDedupe, migratePersistentDedupeLegacyJsonFile } from "openclaw/plugin-sdk/persistent-dedupe";
33
+ import { createChannelReplayGuard, migratePersistentDedupeLegacyJsonFile } from "openclaw/plugin-sdk/persistent-dedupe";
35
34
  import { resolveStateDir } from "openclaw/plugin-sdk/state-paths";
36
35
  import { channelIngressRoutes, resolveStableChannelMessageIngress } from "openclaw/plugin-sdk/channel-ingress-runtime";
37
36
  import { resolveInboundRouteEnvelopeBuilderWithRuntime } from "openclaw/plugin-sdk/inbound-envelope";
38
- import { buildChannelKeyCandidates, normalizeChannelSlug, resolveChannelEntryMatchWithFallback, resolveNestedAllowlistDecision } from "openclaw/plugin-sdk/channel-targets";
37
+ import { buildChannelKeyCandidates, normalizeChannelSlug, resolveChannelEntryMatchWithFallback } from "openclaw/plugin-sdk/channel-targets";
39
38
  import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
39
+ import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
40
40
  import { createServer } from "node:http";
41
41
  import { WEBHOOK_RATE_LIMIT_DEFAULTS, createAuthRateLimiter, isRequestBodyLimitError, readRequestBodyWithLimit, requestBodyErrorToText } from "openclaw/plugin-sdk/webhook-ingress";
42
42
  import { jsonResult, readStringParam, resolveReactionMessageId } from "openclaw/plugin-sdk/channel-actions";
43
43
  import { DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$1, buildOutboundBaseSessionKey, normalizeAccountId as normalizeAccountId$1 } from "openclaw/plugin-sdk/routing";
44
- import { applyAccountNameToChannelSection, createSetupTranslator, createStandardChannelSetupStatus, formatDocsLink, patchScopedAccountConfig, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup";
44
+ import { applyAccountNameToChannelSection, baseUrlTextInput, createSetupTranslator, createStandardChannelSetupStatus, defineTokenCredential, formatDocsLink, patchScopedAccountConfig, setSetupChannelEnabled } from "openclaw/plugin-sdk/setup";
45
45
  import { createSetupInputPresenceValidator, createSetupTranslator as createSetupTranslator$1, mergeAllowFromEntries, promptParsedAllowFromForAccount, resolveSetupAccountId } from "openclaw/plugin-sdk/setup-runtime";
46
46
  import { formatDocsLink as formatDocsLink$1 } from "openclaw/plugin-sdk/setup-tools";
47
47
  //#region extensions/nextcloud-talk/src/accounts.ts
@@ -139,19 +139,16 @@ function resolveNextcloudTalkAccount(params) {
139
139
  function normalizeNextcloudTalkApproverId(value) {
140
140
  return normalizeOptionalLowercaseString(String(value).trim().replace(/^(nextcloud-talk|nc-talk|nc):/i, ""));
141
141
  }
142
- const nextcloudTalkApprovalAuth = createResolvedApproverActionAuthAdapter({
142
+ const nextcloudTalkApprovalAuth = createChannelApprovalAuth({
143
143
  channelLabel: "Nextcloud Talk",
144
- resolveApprovers: ({ cfg, accountId }) => {
145
- return resolveApprovalApprovers({
146
- allowFrom: resolveNextcloudTalkAccount({
147
- cfg,
148
- accountId
149
- }).config.allowFrom,
150
- normalizeApprover: normalizeNextcloudTalkApproverId
151
- });
144
+ resolveInputs: ({ cfg, accountId }) => {
145
+ return { allowFrom: resolveNextcloudTalkAccount({
146
+ cfg,
147
+ accountId
148
+ }).config.allowFrom };
152
149
  },
153
- normalizeSenderId: (value) => normalizeNextcloudTalkApproverId(value)
154
- });
150
+ normalizeApprover: normalizeNextcloudTalkApproverId
151
+ }).approvalAuth;
155
152
  //#endregion
156
153
  //#region extensions/nextcloud-talk/src/api-credentials.ts
157
154
  function resolveNextcloudTalkApiCredentials(params) {
@@ -167,10 +164,10 @@ function resolveNextcloudTalkApiCredentials(params) {
167
164
  };
168
165
  if (!params.apiPasswordFile) return;
169
166
  try {
170
- const filePassword = readFileSync(params.apiPasswordFile, "utf-8").trim();
171
- return filePassword ? {
167
+ const fileValue = tryReadSecretFileSync(params.apiPasswordFile, "Nextcloud Talk API password", { rejectHardlinks: false });
168
+ return fileValue ? {
172
169
  apiUser,
173
- apiPassword: filePassword
170
+ apiPassword: fileValue
174
171
  } : void 0;
175
172
  } catch {
176
173
  return;
@@ -188,16 +185,7 @@ const BACKEND_HEADER = "x-nextcloud-talk-backend";
188
185
  function verifyNextcloudTalkSignature(params) {
189
186
  const { signature, random, body, secret } = params;
190
187
  if (!signature || !random || !secret) return false;
191
- const expected = createHmac("sha256", secret).update(random + body).digest("hex");
192
- const expectedBuf = Buffer.from(expected, "utf8");
193
- const signatureBuf = Buffer.from(signature, "utf8");
194
- const maxLen = Math.max(expectedBuf.length, signatureBuf.length);
195
- const paddedExpected = Buffer.alloc(maxLen);
196
- const paddedSignature = Buffer.alloc(maxLen);
197
- expectedBuf.copy(paddedExpected);
198
- signatureBuf.copy(paddedSignature);
199
- const timingResult = timingSafeEqual(paddedExpected, paddedSignature);
200
- return expectedBuf.length === signatureBuf.length && timingResult;
188
+ return safeEqualSecret(signature, createHmac("sha256", secret).update(random + body).digest("hex"));
201
189
  }
202
190
  /**
203
191
  * Extract webhook headers from an incoming request.
@@ -372,18 +360,11 @@ const nextcloudTalkPairingTextAdapter = {
372
360
  };
373
361
  //#endregion
374
362
  //#region extensions/nextcloud-talk/src/config-schema.ts
375
- const NextcloudTalkRoomSchema = z.object({
376
- requireMention: z.boolean().optional(),
377
- tools: ToolPolicySchema,
378
- skills: z.array(z.string()).optional(),
379
- enabled: z.boolean().optional(),
380
- allowFrom: z.array(z.string()).optional(),
381
- systemPrompt: z.string().optional()
382
- }).strict();
363
+ const NextcloudTalkRoomSchema = buildGroupEntrySchema({ allowFrom: z.array(z.string()).optional() }).omit({ toolsBySender: true });
383
364
  const NextcloudTalkNetworkSchema = z.object({
384
365
  /** Dangerous opt-in for self-hosted Nextcloud Talk on trusted private/internal hosts. */
385
366
  dangerouslyAllowPrivateNetwork: z.boolean().optional() }).strict().optional();
386
- const NextcloudTalkAccountSchemaBase = z.object({
367
+ const NextcloudTalkConfigSchema = buildMultiAccountChannelSchema(z.object({
387
368
  name: z.string().optional(),
388
369
  enabled: z.boolean().optional(),
389
370
  markdown: MarkdownConfigSchema,
@@ -405,27 +386,17 @@ const NextcloudTalkAccountSchemaBase = z.object({
405
386
  /** Network policy overrides for self-hosted Nextcloud Talk on trusted private/internal hosts. */
406
387
  network: NextcloudTalkNetworkSchema,
407
388
  ...ReplyRuntimeConfigSchemaShape
408
- }).strict();
409
- const NextcloudTalkAccountSchema = NextcloudTalkAccountSchemaBase.superRefine((value, ctx) => {
410
- requireChannelOpenAllowFrom({
411
- channel: "nextcloud-talk",
412
- policy: value.dmPolicy,
413
- allowFrom: value.allowFrom,
414
- ctx,
415
- requireOpenAllowFrom
416
- });
417
- });
418
- const NextcloudTalkConfigSchema = NextcloudTalkAccountSchemaBase.extend({
419
- accounts: z.record(z.string(), NextcloudTalkAccountSchema.optional()).optional(),
420
- defaultAccount: z.string().optional()
421
- }).superRefine((value, ctx) => {
422
- requireChannelOpenAllowFrom({
423
- channel: "nextcloud-talk",
424
- policy: value.dmPolicy,
425
- allowFrom: value.allowFrom,
426
- ctx,
427
- requireOpenAllowFrom
428
- });
389
+ }).strict(), {
390
+ optionalAccount: true,
391
+ refine: (value, ctx) => {
392
+ requireChannelOpenAllowFrom({
393
+ channel: "nextcloud-talk",
394
+ policy: value.dmPolicy,
395
+ allowFrom: value.allowFrom,
396
+ ctx,
397
+ requireOpenAllowFrom
398
+ });
399
+ }
429
400
  });
430
401
  //#endregion
431
402
  //#region extensions/nextcloud-talk/src/replay-guard.ts
@@ -434,7 +405,7 @@ const NEXTCLOUD_TALK_REPLAY_DEDUPE_NAMESPACE_PREFIX = "replay-dedupe";
434
405
  const DEFAULT_REPLAY_TTL_MS = 1440 * 60 * 1e3;
435
406
  const DEFAULT_MEMORY_MAX_SIZE = 1e3;
436
407
  const DEFAULT_STATE_MAX_ENTRIES = 1e4;
437
- function buildReplayKey(params) {
408
+ function buildNextcloudTalkReplayKey(params) {
438
409
  const roomToken = params.roomToken.trim();
439
410
  const messageId = params.messageId.trim();
440
411
  if (!roomToken || !messageId) return null;
@@ -446,55 +417,21 @@ function createNextcloudTalkReplayGuard(options) {
446
417
  ttlMs: options.ttlMs ?? DEFAULT_REPLAY_TTL_MS,
447
418
  memoryMaxSize: options.memoryMaxSize ?? DEFAULT_MEMORY_MAX_SIZE
448
419
  };
449
- const dedupe = createClaimableDedupe(stateDir ? {
450
- ...baseOptions,
451
- pluginId: NEXTCLOUD_TALK_PLUGIN_ID,
452
- namespacePrefix: NEXTCLOUD_TALK_REPLAY_DEDUPE_NAMESPACE_PREFIX,
453
- stateMaxEntries: options.stateMaxEntries ?? options.fileMaxEntries ?? DEFAULT_STATE_MAX_ENTRIES,
454
- env: {
455
- ...process.env,
456
- OPENCLAW_STATE_DIR: stateDir
457
- },
458
- onDiskError: options.onDiskError
459
- } : baseOptions);
460
- return {
461
- claimMessage: async ({ accountId, roomToken, messageId }) => {
462
- const replayKey = buildReplayKey({
463
- roomToken,
464
- messageId
465
- });
466
- if (!replayKey) return "invalid";
467
- return (await dedupe.claim(replayKey, { namespace: accountId })).kind;
468
- },
469
- commitMessage: async ({ accountId, roomToken, messageId }) => {
470
- const replayKey = buildReplayKey({
471
- roomToken,
472
- messageId
473
- });
474
- if (!replayKey) return true;
475
- return await dedupe.commit(replayKey, { namespace: accountId });
476
- },
477
- releaseMessage: ({ accountId, roomToken, messageId, error }) => {
478
- const replayKey = buildReplayKey({
479
- roomToken,
480
- messageId
481
- });
482
- if (!replayKey) return;
483
- dedupe.release(replayKey, {
484
- namespace: accountId,
485
- error
486
- });
487
- },
488
- shouldProcessMessage: async ({ accountId, roomToken, messageId }) => {
489
- const replayKey = buildReplayKey({
490
- roomToken,
491
- messageId
492
- });
493
- if (!replayKey) return true;
494
- if ((await dedupe.claim(replayKey, { namespace: accountId })).kind !== "claimed") return false;
495
- return await dedupe.commit(replayKey, { namespace: accountId });
496
- }
497
- };
420
+ return createChannelReplayGuard({
421
+ dedupe: stateDir ? {
422
+ ...baseOptions,
423
+ pluginId: NEXTCLOUD_TALK_PLUGIN_ID,
424
+ namespacePrefix: NEXTCLOUD_TALK_REPLAY_DEDUPE_NAMESPACE_PREFIX,
425
+ stateMaxEntries: options.stateMaxEntries ?? options.fileMaxEntries ?? DEFAULT_STATE_MAX_ENTRIES,
426
+ env: {
427
+ ...process.env,
428
+ OPENCLAW_STATE_DIR: stateDir
429
+ },
430
+ onDiskError: options.onDiskError
431
+ } : baseOptions,
432
+ buildReplayKey: buildNextcloudTalkReplayKey,
433
+ namespace: (event) => event.accountId
434
+ });
498
435
  }
499
436
  //#endregion
500
437
  //#region extensions/nextcloud-talk/src/doctor.ts
@@ -505,14 +442,6 @@ function sanitizeLegacyReplaySegment(value) {
505
442
  if (!trimmed) return "default";
506
443
  return trimmed.replace(/[^a-zA-Z0-9_-]/g, "_");
507
444
  }
508
- async function fileExists(filePath) {
509
- try {
510
- await fs.access(filePath);
511
- return true;
512
- } catch {
513
- return false;
514
- }
515
- }
516
445
  async function collectNextcloudTalkBotResponseWarnings(params) {
517
446
  const warnings = [];
518
447
  for (const accountId of listNextcloudTalkAccountIds(params.cfg)) {
@@ -537,7 +466,7 @@ async function repairNextcloudTalkReplayDedupeState(params) {
537
466
  const replayDir = path.join(stateDir, "nextcloud-talk", "replay-dedupe");
538
467
  for (const accountId of listNextcloudTalkAccountIds(params.cfg)) {
539
468
  const legacyPath = path.join(replayDir, `${sanitizeLegacyReplaySegment(accountId)}.json`);
540
- if (!await fileExists(legacyPath)) continue;
469
+ if (!fileExists(legacyPath)) continue;
541
470
  try {
542
471
  const result = await migratePersistentDedupeLegacyJsonFile({
543
472
  filePath: legacyPath,
@@ -592,12 +521,11 @@ function resolveNextcloudTalkAllowlistMatch(params) {
592
521
  matchSource: "wildcard"
593
522
  };
594
523
  const senderId = normalizeNextcloudTalkAllowEntry(params.senderId);
595
- if (allowFrom.includes(senderId)) return {
524
+ return allowFrom.includes(senderId) ? {
596
525
  allowed: true,
597
526
  matchKey: senderId,
598
527
  matchSource: "id"
599
- };
600
- return { allowed: false };
528
+ } : { allowed: false };
601
529
  }
602
530
  function resolveNextcloudTalkRoomMatch(params) {
603
531
  const rooms = params.rooms ?? {};
@@ -609,12 +537,7 @@ function resolveNextcloudTalkRoomMatch(params) {
609
537
  normalizeKey: normalizeChannelSlug
610
538
  });
611
539
  const roomConfig = match.entry;
612
- const allowed = resolveNestedAllowlistDecision({
613
- outerConfigured: allowlistConfigured,
614
- outerMatched: Boolean(roomConfig),
615
- innerConfigured: false,
616
- innerMatched: false
617
- });
540
+ const allowed = !allowlistConfigured || Boolean(roomConfig);
618
541
  return {
619
542
  roomConfig,
620
543
  wildcardConfig: match.wildcardEntry,
@@ -625,25 +548,52 @@ function resolveNextcloudTalkRoomMatch(params) {
625
548
  };
626
549
  }
627
550
  function resolveNextcloudTalkGroupToolPolicy(params) {
628
- const cfg = params.cfg;
629
551
  const roomToken = params.groupId?.trim();
630
552
  if (!roomToken) return;
631
- const match = resolveNextcloudTalkRoomMatch({
632
- rooms: cfg.channels?.["nextcloud-talk"]?.rooms,
633
- roomToken
553
+ const { tree, toolsPath } = buildNextcloudTalkRoomScope(resolveNextcloudTalkAccount({
554
+ cfg: params.cfg,
555
+ accountId: params.accountId
556
+ }).config.rooms, roomToken);
557
+ return resolveScopeToolsPolicy({
558
+ tree,
559
+ path: toolsPath
634
560
  });
635
- return match.roomConfig?.tools ?? match.wildcardConfig?.tools;
636
561
  }
637
- function resolveNextcloudTalkRequireMention(params) {
638
- if (typeof params.roomConfig?.requireMention === "boolean") return params.roomConfig.requireMention;
639
- if (typeof params.wildcardConfig?.requireMention === "boolean") return params.wildcardConfig.requireMention;
640
- return true;
562
+ function buildNextcloudTalkRoomScope(rooms, roomToken) {
563
+ const { "*": defaults, ...scopes } = rooms ?? {};
564
+ const tree = {
565
+ defaults,
566
+ scopes
567
+ };
568
+ const exactPath = Object.hasOwn(scopes, roomToken) ? [roomToken] : [];
569
+ const toolsMatch = resolveChannelEntryMatchWithFallback({
570
+ entries: scopes,
571
+ keys: buildChannelKeyCandidates(roomToken),
572
+ normalizeKey: normalizeChannelSlug
573
+ });
574
+ return {
575
+ tree,
576
+ exactPath,
577
+ toolsPath: toolsMatch.matchKey ? [toolsMatch.matchKey] : []
578
+ };
579
+ }
580
+ function resolveNextcloudTalkGroupRequireMention(params) {
581
+ if (!params.groupId) return true;
582
+ const { tree, exactPath } = buildNextcloudTalkRoomScope(resolveNextcloudTalkAccount({
583
+ cfg: params.cfg,
584
+ accountId: params.accountId
585
+ }).config.rooms, params.groupId);
586
+ return resolveScopeRequireMention({
587
+ tree,
588
+ path: exactPath
589
+ });
641
590
  }
642
591
  //#endregion
643
592
  //#region extensions/nextcloud-talk/src/room-info.ts
644
593
  const ROOM_CACHE_TTL_MS = 300 * 1e3;
645
594
  const ROOM_CACHE_ERROR_TTL_MS = 30 * 1e3;
646
595
  const ROOM_CACHE_MAX_ENTRIES = 1e3;
596
+ const NEXTCLOUD_TALK_ROOM_INFO_TIMEOUT_MS = 3e4;
647
597
  const roomCache = /* @__PURE__ */ new Map();
648
598
  function resolveRoomCacheKey(params) {
649
599
  return `${params.accountId}:${params.roomToken}`;
@@ -695,7 +645,8 @@ async function resolveNextcloudTalkRoomKind(params) {
695
645
  }
696
646
  },
697
647
  auditContext: "nextcloud-talk.room-info",
698
- policy: ssrfPolicyFromPrivateNetworkOptIn(account.config)
648
+ policy: ssrfPolicyFromPrivateNetworkOptIn(account.config),
649
+ timeoutMs: params.timeoutMs ?? NEXTCLOUD_TALK_ROOM_INFO_TIMEOUT_MS
699
650
  });
700
651
  try {
701
652
  if (!response.ok) {
@@ -730,10 +681,10 @@ function stripNextcloudTalkTargetPrefix(raw) {
730
681
  const trimmed = raw.trim();
731
682
  if (!trimmed) return;
732
683
  let normalized = trimmed;
733
- if (normalized.startsWith("nextcloud-talk:")) normalized = normalized.slice(15).trim();
734
- else if (normalized.startsWith("nc-talk:")) normalized = normalized.slice(8).trim();
735
- else if (normalized.startsWith("nc:")) normalized = normalized.slice(3).trim();
736
- if (normalized.startsWith("room:")) normalized = normalized.slice(5).trim();
684
+ if (/^nextcloud-talk:/i.test(normalized)) normalized = normalized.slice(15).trim();
685
+ else if (/^nc-talk:/i.test(normalized)) normalized = normalized.slice(8).trim();
686
+ else if (/^nc:/i.test(normalized)) normalized = normalized.slice(3).trim();
687
+ if (/^room:/i.test(normalized)) normalized = normalized.slice(5).trim();
737
688
  if (!normalized) return;
738
689
  return normalized;
739
690
  }
@@ -744,17 +695,18 @@ function normalizeNextcloudTalkMessagingTarget(raw) {
744
695
  function looksLikeNextcloudTalkTargetId(raw) {
745
696
  const trimmed = raw.trim();
746
697
  if (!trimmed) return false;
747
- if (/^(nextcloud-talk|nc-talk|nc):/i.test(trimmed)) return true;
698
+ if (/^(nextcloud-talk|nc-talk|nc|room):/i.test(trimmed)) return true;
748
699
  return /^[a-z0-9]{8,}$/i.test(trimmed);
749
700
  }
750
701
  //#endregion
751
702
  //#region extensions/nextcloud-talk/src/send.ts
752
703
  const NEXTCLOUD_TALK_ERROR_SNIPPET_MAX_BYTES = 8 * 1024;
753
704
  const NEXTCLOUD_TALK_ERROR_SNIPPET_MAX_CHARS = 200;
705
+ const NEXTCLOUD_TALK_SEND_TIMEOUT_MS = 3e4;
754
706
  /** Collapses whitespace and caps an error-body prefix to a short, log-safe snippet. */
755
707
  function collapseErrorSnippet(text) {
756
708
  const collapsed = text.replace(/\s+/g, " ").trim();
757
- if (collapsed.length > NEXTCLOUD_TALK_ERROR_SNIPPET_MAX_CHARS) return `${collapsed.slice(0, NEXTCLOUD_TALK_ERROR_SNIPPET_MAX_CHARS)}…`;
709
+ if (collapsed.length > NEXTCLOUD_TALK_ERROR_SNIPPET_MAX_CHARS) return `${truncateUtf16Safe(collapsed, NEXTCLOUD_TALK_ERROR_SNIPPET_MAX_CHARS)}…`;
758
710
  return collapsed;
759
711
  }
760
712
  /** Reads a bounded, collapsed error-body snippet without buffering hostile responses. */
@@ -850,7 +802,8 @@ async function sendMessageNextcloudTalk(to, text, opts) {
850
802
  body: bodyStr
851
803
  },
852
804
  auditContext: "nextcloud-talk-send",
853
- policy: ssrfPolicyFromPrivateNetworkOptIn$1(account.config)
805
+ policy: ssrfPolicyFromPrivateNetworkOptIn$1(account.config),
806
+ timeoutMs: opts.timeoutMs ?? NEXTCLOUD_TALK_SEND_TIMEOUT_MS
854
807
  });
855
808
  try {
856
809
  if (!response.ok) {
@@ -908,7 +861,8 @@ async function sendReactionNextcloudTalk(roomToken, messageId, reaction, opts) {
908
861
  body
909
862
  },
910
863
  auditContext: "nextcloud-talk-reaction",
911
- policy: ssrfPolicyFromPrivateNetworkOptIn$1(account.config)
864
+ policy: ssrfPolicyFromPrivateNetworkOptIn$1(account.config),
865
+ timeoutMs: opts.timeoutMs ?? NEXTCLOUD_TALK_SEND_TIMEOUT_MS
912
866
  });
913
867
  try {
914
868
  if (!response.ok) {
@@ -959,7 +913,7 @@ function roomRoutes(params) {
959
913
  }
960
914
  async function deliverNextcloudTalkReply(params) {
961
915
  const { cfg, payload, roomToken, accountId, statusSink } = params;
962
- await deliverFormattedTextWithAttachments({
916
+ return { visibleReplySent: await deliverFormattedTextWithAttachments({
963
917
  payload,
964
918
  send: async ({ text, replyToId }) => {
965
919
  await sendMessageNextcloudTalk(roomToken, text, {
@@ -969,7 +923,7 @@ async function deliverNextcloudTalkReply(params) {
969
923
  });
970
924
  statusSink?.({ lastOutboundAt: Date.now() });
971
925
  }
972
- });
926
+ }) };
973
927
  }
974
928
  async function handleNextcloudTalkInbound(params) {
975
929
  const { message, account, config, runtime, statusSink } = params;
@@ -1002,9 +956,10 @@ async function handleNextcloudTalkInbound(params) {
1002
956
  surface: CHANNEL_ID
1003
957
  });
1004
958
  const hasControlCommand = core.channel.text.hasControlCommand(rawBody, config);
1005
- const shouldRequireMention = isGroup ? resolveNextcloudTalkRequireMention({
1006
- roomConfig,
1007
- wildcardConfig: roomMatch.wildcardConfig
959
+ const shouldRequireMention = isGroup ? resolveNextcloudTalkGroupRequireMention({
960
+ cfg: config,
961
+ accountId: account.accountId,
962
+ groupId: roomToken
1008
963
  }) : false;
1009
964
  const { groupPolicy, providerMissingFallbackApplied } = resolveAllowlistProviderRuntimeGroupPolicy({
1010
965
  providerConfigPresent: (config.channels?.[CHANNEL_ID] ?? void 0) !== void 0,
@@ -1141,6 +1096,7 @@ async function handleNextcloudTalkInbound(params) {
1141
1096
  body: rawBody
1142
1097
  });
1143
1098
  const groupSystemPrompt = normalizeOptionalString(roomConfig?.systemPrompt);
1099
+ const blockStreamingEnabled = resolveChannelStreamingBlockEnabled(account.config);
1144
1100
  const ctxPayload = core.channel.reply.finalizeInboundContext({
1145
1101
  Body: body,
1146
1102
  BodyForAgent: rawBody,
@@ -1176,8 +1132,12 @@ async function handleNextcloudTalkInbound(params) {
1176
1132
  recordInboundSession: core.channel.session.recordInboundSession,
1177
1133
  dispatchReplyWithBufferedBlockDispatcher: core.channel.reply.dispatchReplyWithBufferedBlockDispatcher,
1178
1134
  delivery: {
1135
+ preparePayload: (payload) => payload.text === void 0 ? payload : {
1136
+ ...payload,
1137
+ text: sanitizeAssistantVisibleText(payload.text)
1138
+ },
1179
1139
  deliver: async (payload) => {
1180
- await deliverNextcloudTalkReply({
1140
+ return await deliverNextcloudTalkReply({
1181
1141
  cfg: config,
1182
1142
  payload,
1183
1143
  roomToken,
@@ -1192,7 +1152,7 @@ async function handleNextcloudTalkInbound(params) {
1192
1152
  replyPipeline: {},
1193
1153
  replyOptions: {
1194
1154
  skillFilter: roomConfig?.skills,
1195
- disableBlockStreaming: typeof account.config.blockStreaming === "boolean" ? !account.config.blockStreaming : void 0
1155
+ disableBlockStreaming: typeof blockStreamingEnabled === "boolean" ? !blockStreamingEnabled : void 0
1196
1156
  },
1197
1157
  record: { onRecordError: (err) => {
1198
1158
  runtime.error?.(`nextcloud-talk: failed updating session meta: ${String(err)}`);
@@ -1242,40 +1202,12 @@ const WEBHOOK_ERRORS = {
1242
1202
  payloadTooLarge: "Payload too large",
1243
1203
  internalServerError: "Internal server error"
1244
1204
  };
1245
- var NextcloudTalkRetryableWebhookError = class extends Error {
1246
- constructor(message, options) {
1247
- super(message, options);
1248
- this.name = "NextcloudTalkRetryableWebhookError";
1249
- }
1250
- };
1251
1205
  async function processNextcloudTalkReplayGuardedMessage(params) {
1252
- if (await params.replayGuard.claimMessage({
1206
+ return (await params.replayGuard.processGuarded({
1253
1207
  accountId: params.accountId,
1254
1208
  roomToken: params.message.roomToken,
1255
1209
  messageId: params.message.messageId
1256
- }) !== "claimed") return "duplicate";
1257
- try {
1258
- await params.handleMessage();
1259
- await params.replayGuard.commitMessage({
1260
- accountId: params.accountId,
1261
- roomToken: params.message.roomToken,
1262
- messageId: params.message.messageId
1263
- });
1264
- return "processed";
1265
- } catch (error) {
1266
- if (error instanceof NextcloudTalkRetryableWebhookError) params.replayGuard.releaseMessage({
1267
- accountId: params.accountId,
1268
- roomToken: params.message.roomToken,
1269
- messageId: params.message.messageId,
1270
- error
1271
- });
1272
- else await params.replayGuard.commitMessage({
1273
- accountId: params.accountId,
1274
- roomToken: params.message.roomToken,
1275
- messageId: params.message.messageId
1276
- });
1277
- throw error;
1278
- }
1210
+ }, params.handleMessage, { onError: "commit" })).kind === "processed" ? "processed" : "duplicate";
1279
1211
  }
1280
1212
  function formatError(err) {
1281
1213
  if (err instanceof Error) return err.message;
@@ -1651,7 +1583,7 @@ const nextcloudTalkMessageActions = {
1651
1583
  if (!hasConfiguredAccount(cfg, accountId)) return null;
1652
1584
  return { actions: ["send", "react"] };
1653
1585
  },
1654
- supportsAction: ({ action }) => action !== "send",
1586
+ supportsAction: ({ action }) => action === "react",
1655
1587
  handleAction: async ({ action, params, cfg, accountId, toolContext }) => {
1656
1588
  if (action === "send") throw new Error("Send should be handled by outbound, not actions handler.");
1657
1589
  if (action === "react") {
@@ -1938,8 +1870,10 @@ const nextcloudTalkSetupWizard = {
1938
1870
  [CONFIGURE_API_FLAG]: "1"
1939
1871
  } };
1940
1872
  },
1941
- credentials: [{
1873
+ credentials: [defineTokenCredential({
1942
1874
  inputKey: "token",
1875
+ configKey: "botSecret",
1876
+ configuredFields: ["botSecret", "botSecretFile"],
1943
1877
  providerHint: channel,
1944
1878
  credentialLabel: t("wizard.nextcloudTalk.botSecret"),
1945
1879
  preferredEnvVar: "NEXTCLOUD_TALK_BOT_SECRET",
@@ -1947,61 +1881,56 @@ const nextcloudTalkSetupWizard = {
1947
1881
  keepPrompt: t("wizard.nextcloudTalk.botSecretKeep"),
1948
1882
  inputPrompt: t("wizard.nextcloudTalk.botSecretInput"),
1949
1883
  allowEnv: ({ accountId }) => accountId === DEFAULT_ACCOUNT_ID$1,
1950
- inspect: ({ cfg, accountId }) => {
1951
- const resolvedAccount = resolveNextcloudTalkAccount({
1952
- cfg,
1953
- accountId
1954
- });
1955
- return {
1956
- accountConfigured: Boolean(resolvedAccount.secret && resolvedAccount.baseUrl),
1957
- hasConfiguredValue: Boolean(hasConfiguredSecretInput(resolvedAccount.config.botSecret) || resolvedAccount.config.botSecretFile),
1958
- resolvedValue: resolvedAccount.secret || void 0,
1959
- envValue: accountId === DEFAULT_ACCOUNT_ID$1 ? normalizeOptionalString(process.env.NEXTCLOUD_TALK_BOT_SECRET) : void 0
1960
- };
1884
+ resolveAccount: ({ cfg, accountId }) => resolveNextcloudTalkAccount({
1885
+ cfg,
1886
+ accountId
1887
+ }),
1888
+ accountConfigured: (account) => Boolean(account.secret && account.baseUrl),
1889
+ hasConfiguredValue: (account) => Boolean(hasConfiguredSecretInput(account.config.botSecret) || account.config.botSecretFile),
1890
+ resolvedValue: (account) => account.secret || void 0,
1891
+ envValue: ({ accountId }) => accountId === DEFAULT_ACCOUNT_ID$1 ? normalizeOptionalString(process.env.NEXTCLOUD_TALK_BOT_SECRET) : void 0,
1892
+ patchAccount: ({ cfg, accountId, patch, clearFields }) => {
1893
+ return setNextcloudTalkAccountConfig(clearNextcloudTalkAccountFields(cfg, accountId, clearFields), accountId, patch);
1961
1894
  },
1962
- applyUseEnv: async (params) => {
1963
- const resolvedAccount = resolveNextcloudTalkAccount({
1964
- cfg: params.cfg,
1965
- accountId: params.accountId
1966
- });
1967
- return setNextcloudTalkAccountConfig(clearNextcloudTalkAccountFields(params.cfg, params.accountId, ["botSecret", "botSecretFile"]), params.accountId, { baseUrl: resolvedAccount.baseUrl });
1895
+ useEnv: {
1896
+ clearFields: ["botSecret", "botSecretFile"],
1897
+ patch: (account) => ({ baseUrl: account.baseUrl })
1968
1898
  },
1969
- applySet: async (params) => setNextcloudTalkAccountConfig(clearNextcloudTalkAccountFields(params.cfg, params.accountId, ["botSecret", "botSecretFile"]), params.accountId, { botSecret: params.value })
1970
- }, {
1899
+ set: { clearFields: ["botSecret", "botSecretFile"] }
1900
+ }), defineTokenCredential({
1971
1901
  inputKey: "password",
1902
+ configKey: "apiPassword",
1903
+ configuredFields: ["apiPassword", "apiPasswordFile"],
1972
1904
  providerHint: "nextcloud-talk-api",
1973
1905
  credentialLabel: t("wizard.nextcloudTalk.apiPassword"),
1974
1906
  preferredEnvVar: "NEXTCLOUD_TALK_API_PASSWORD",
1975
1907
  envPrompt: "",
1976
1908
  keepPrompt: t("wizard.nextcloudTalk.apiPasswordKeep"),
1977
1909
  inputPrompt: t("wizard.nextcloudTalk.apiPasswordInput"),
1978
- inspect: ({ cfg, accountId }) => {
1979
- const resolvedAccount = resolveNextcloudTalkAccount({
1980
- cfg,
1981
- accountId
1982
- });
1983
- const apiUser = resolvedAccount.config.apiUser?.trim();
1984
- const apiPasswordConfigured = Boolean(hasConfiguredSecretInput(resolvedAccount.config.apiPassword) || resolvedAccount.config.apiPasswordFile);
1985
- return {
1986
- accountConfigured: Boolean(apiUser && apiPasswordConfigured),
1987
- hasConfiguredValue: apiPasswordConfigured
1988
- };
1989
- },
1910
+ resolveAccount: ({ cfg, accountId }) => resolveNextcloudTalkAccount({
1911
+ cfg,
1912
+ accountId
1913
+ }),
1914
+ accountConfigured: (account) => Boolean(account.config.apiUser?.trim() && (hasConfiguredSecretInput(account.config.apiPassword) || account.config.apiPasswordFile)),
1915
+ hasConfiguredValue: (account) => Boolean(hasConfiguredSecretInput(account.config.apiPassword) || account.config.apiPasswordFile),
1990
1916
  shouldPrompt: ({ credentialValues }) => credentialValues[CONFIGURE_API_FLAG] === "1",
1991
- applySet: async (params) => setNextcloudTalkAccountConfig(clearNextcloudTalkAccountFields(params.cfg, params.accountId, ["apiPassword", "apiPasswordFile"]), params.accountId, { apiPassword: params.value })
1992
- }],
1993
- textInputs: [{
1917
+ patchAccount: ({ cfg, accountId, patch, clearFields }) => setNextcloudTalkAccountConfig(clearNextcloudTalkAccountFields(cfg, accountId, clearFields), accountId, patch),
1918
+ set: { clearFields: ["apiPassword", "apiPasswordFile"] }
1919
+ })],
1920
+ textInputs: [baseUrlTextInput({
1994
1921
  inputKey: "httpUrl",
1922
+ configKey: "baseUrl",
1995
1923
  message: t("wizard.nextcloudTalk.instanceUrlPrompt"),
1996
- currentValue: ({ cfg, accountId }) => resolveNextcloudTalkAccount({
1924
+ resolveAccount: ({ cfg, accountId }) => resolveNextcloudTalkAccount({
1997
1925
  cfg,
1998
1926
  accountId
1999
- }).baseUrl || void 0,
1927
+ }),
1928
+ currentValue: (account) => account.baseUrl || void 0,
2000
1929
  shouldPrompt: ({ currentValue }) => !currentValue,
2001
- validate: ({ value }) => validateNextcloudTalkBaseUrl(value),
2002
- normalizeValue: ({ value }) => normalizeNextcloudTalkBaseUrl(value),
2003
- applySet: async (params) => setNextcloudTalkAccountConfig(params.cfg, params.accountId, { baseUrl: params.value })
2004
- }, {
1930
+ validate: validateNextcloudTalkBaseUrl,
1931
+ normalize: normalizeNextcloudTalkBaseUrl,
1932
+ patchAccount: ({ cfg, accountId, patch }) => setNextcloudTalkAccountConfig(cfg, accountId, patch)
1933
+ }), {
2005
1934
  inputKey: "userId",
2006
1935
  message: t("wizard.nextcloudTalk.apiUserPrompt"),
2007
1936
  currentValue: ({ cfg, accountId }) => resolveNextcloudTalkAccount({
@@ -2076,18 +2005,7 @@ const nextcloudTalkPlugin = createChatChannelPlugin({
2076
2005
  approvalCapability: nextcloudTalkApprovalAuth,
2077
2006
  doctor: nextcloudTalkDoctor,
2078
2007
  groups: {
2079
- resolveRequireMention: ({ cfg, accountId, groupId }) => {
2080
- const rooms = resolveNextcloudTalkAccount({
2081
- cfg,
2082
- accountId
2083
- }).config.rooms;
2084
- if (!rooms || !groupId) return true;
2085
- const roomConfig = rooms[groupId];
2086
- if (roomConfig?.requireMention !== void 0) return roomConfig.requireMention;
2087
- const wildcardConfig = rooms["*"];
2088
- if (wildcardConfig?.requireMention !== void 0) return wildcardConfig.requireMention;
2089
- return true;
2090
- },
2008
+ resolveRequireMention: resolveNextcloudTalkGroupRequireMention,
2091
2009
  resolveToolPolicy: resolveNextcloudTalkGroupToolPolicy
2092
2010
  },
2093
2011
  messaging: {
@@ -2155,7 +2073,8 @@ const nextcloudTalkPlugin = createChatChannelPlugin({
2155
2073
  deliveryMode: "direct",
2156
2074
  chunker: (text, limit) => getNextcloudTalkRuntime().channel.text.chunkMarkdownText(text, limit),
2157
2075
  chunkerMode: "markdown",
2158
- textChunkLimit: 4e3
2076
+ textChunkLimit: 4e3,
2077
+ sanitizeText: ({ text }) => sanitizeAssistantVisibleText(text)
2159
2078
  },
2160
2079
  attachedResults: {
2161
2080
  channel: "nextcloud-talk",
@@ -1,2 +1,2 @@
1
- import { t as nextcloudTalkPlugin } from "./channel-BMKRTDSP.js";
1
+ import { t as nextcloudTalkPlugin } from "./channel-BSnehBf6.js";
2
2
  export { nextcloudTalkPlugin };
@@ -1,2 +1,2 @@
1
- import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-BY7I5-v9.js";
1
+ import { n as normalizeCompatibilityConfig, t as legacyConfigRules } from "./doctor-contract-fNhK1wag.js";
2
2
  export { legacyConfigRules, normalizeCompatibilityConfig };
@@ -0,0 +1,22 @@
1
+ import { createLegacyPrivateNetworkDoctorContract } from "openclaw/plugin-sdk/ssrf-runtime";
2
+ import { defineChannelAliasMigration } from "openclaw/plugin-sdk/runtime-doctor";
3
+ //#region extensions/nextcloud-talk/src/doctor-contract.ts
4
+ const networkContract = createLegacyPrivateNetworkDoctorContract({ channelKey: "nextcloud-talk" });
5
+ const streamingAliasMigration = defineChannelAliasMigration({
6
+ channelId: "nextcloud-talk",
7
+ streaming: {
8
+ defaultMode: "partial",
9
+ deliveryOnly: true
10
+ },
11
+ accountStreamingReplacesRoot: true
12
+ });
13
+ const legacyConfigRules = [...networkContract.legacyConfigRules, ...streamingAliasMigration.legacyConfigRules];
14
+ function normalizeCompatibilityConfig({ cfg }) {
15
+ const network = networkContract.normalizeCompatibilityConfig({ cfg });
16
+ return streamingAliasMigration.normalizeChannelConfig({
17
+ cfg: network.config,
18
+ changes: network.changes
19
+ });
20
+ }
21
+ //#endregion
22
+ export { normalizeCompatibilityConfig as n, legacyConfigRules as t };
@@ -1,51 +1,10 @@
1
- import { collectConditionalChannelFieldAssignments, getChannelSurface, hasOwnProperty } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
1
+ import { collectConditionalChannelFieldAssignments, createChannelSecretTargetRegistryEntries, getChannelSurface, hasOwnProperty } from "openclaw/plugin-sdk/channel-secret-basic-runtime";
2
2
  //#region extensions/nextcloud-talk/src/secret-contract.ts
3
- const secretTargetRegistryEntries = [
4
- {
5
- id: "channels.nextcloud-talk.accounts.*.apiPassword",
6
- targetType: "channels.nextcloud-talk.accounts.*.apiPassword",
7
- configFile: "openclaw.json",
8
- pathPattern: "channels.nextcloud-talk.accounts.*.apiPassword",
9
- secretShape: "secret_input",
10
- expectedResolvedValue: "string",
11
- includeInPlan: true,
12
- includeInConfigure: true,
13
- includeInAudit: true
14
- },
15
- {
16
- id: "channels.nextcloud-talk.accounts.*.botSecret",
17
- targetType: "channels.nextcloud-talk.accounts.*.botSecret",
18
- configFile: "openclaw.json",
19
- pathPattern: "channels.nextcloud-talk.accounts.*.botSecret",
20
- secretShape: "secret_input",
21
- expectedResolvedValue: "string",
22
- includeInPlan: true,
23
- includeInConfigure: true,
24
- includeInAudit: true
25
- },
26
- {
27
- id: "channels.nextcloud-talk.apiPassword",
28
- targetType: "channels.nextcloud-talk.apiPassword",
29
- configFile: "openclaw.json",
30
- pathPattern: "channels.nextcloud-talk.apiPassword",
31
- secretShape: "secret_input",
32
- expectedResolvedValue: "string",
33
- includeInPlan: true,
34
- includeInConfigure: true,
35
- includeInAudit: true
36
- },
37
- {
38
- id: "channels.nextcloud-talk.botSecret",
39
- targetType: "channels.nextcloud-talk.botSecret",
40
- configFile: "openclaw.json",
41
- pathPattern: "channels.nextcloud-talk.botSecret",
42
- secretShape: "secret_input",
43
- expectedResolvedValue: "string",
44
- includeInPlan: true,
45
- includeInConfigure: true,
46
- includeInAudit: true
47
- }
48
- ];
3
+ const secretTargetRegistryEntries = createChannelSecretTargetRegistryEntries({
4
+ channelKey: "nextcloud-talk",
5
+ account: ["apiPassword", "botSecret"],
6
+ channel: ["apiPassword", "botSecret"]
7
+ });
49
8
  function collectRuntimeConfigAssignments(params) {
50
9
  const resolved = getChannelSurface(params.config, "nextcloud-talk");
51
10
  if (!resolved) return;
@@ -1,2 +1,2 @@
1
- import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries, t as channelSecrets } from "./secret-contract-CsCJ-vOP.js";
1
+ import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries, t as channelSecrets } from "./secret-contract-DGgvfVqm.js";
2
2
  export { channelSecrets, collectRuntimeConfigAssignments, secretTargetRegistryEntries };
@@ -1,17 +1,17 @@
1
1
  {
2
2
  "name": "@openclaw/nextcloud-talk",
3
- "version": "2026.7.1",
3
+ "version": "2026.7.2-beta.2",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@openclaw/nextcloud-talk",
9
- "version": "2026.7.1",
9
+ "version": "2026.7.2-beta.2",
10
10
  "dependencies": {
11
11
  "zod": "4.4.3"
12
12
  },
13
13
  "peerDependencies": {
14
- "openclaw": ">=2026.7.1"
14
+ "openclaw": ">=2026.7.2-beta.2"
15
15
  },
16
16
  "peerDependenciesMeta": {
17
17
  "openclaw": {
@@ -366,33 +366,45 @@
366
366
  "exclusiveMinimum": 0,
367
367
  "maximum": 9007199254740991
368
368
  },
369
- "chunkMode": {
370
- "type": "string",
371
- "enum": [
372
- "length",
373
- "newline"
374
- ]
375
- },
376
- "blockStreaming": {
377
- "type": "boolean"
378
- },
379
- "blockStreamingCoalesce": {
369
+ "streaming": {
380
370
  "type": "object",
381
371
  "properties": {
382
- "minChars": {
383
- "type": "integer",
384
- "exclusiveMinimum": 0,
385
- "maximum": 9007199254740991
386
- },
387
- "maxChars": {
388
- "type": "integer",
389
- "exclusiveMinimum": 0,
390
- "maximum": 9007199254740991
372
+ "chunkMode": {
373
+ "type": "string",
374
+ "enum": [
375
+ "length",
376
+ "newline"
377
+ ]
391
378
  },
392
- "idleMs": {
393
- "type": "integer",
394
- "minimum": 0,
395
- "maximum": 9007199254740991
379
+ "block": {
380
+ "type": "object",
381
+ "properties": {
382
+ "enabled": {
383
+ "type": "boolean"
384
+ },
385
+ "coalesce": {
386
+ "type": "object",
387
+ "properties": {
388
+ "minChars": {
389
+ "type": "integer",
390
+ "exclusiveMinimum": 0,
391
+ "maximum": 9007199254740991
392
+ },
393
+ "maxChars": {
394
+ "type": "integer",
395
+ "exclusiveMinimum": 0,
396
+ "maximum": 9007199254740991
397
+ },
398
+ "idleMs": {
399
+ "type": "integer",
400
+ "minimum": 0,
401
+ "maximum": 9007199254740991
402
+ }
403
+ },
404
+ "additionalProperties": false
405
+ }
406
+ },
407
+ "additionalProperties": false
396
408
  }
397
409
  },
398
410
  "additionalProperties": false
@@ -752,33 +764,45 @@
752
764
  "exclusiveMinimum": 0,
753
765
  "maximum": 9007199254740991
754
766
  },
755
- "chunkMode": {
756
- "type": "string",
757
- "enum": [
758
- "length",
759
- "newline"
760
- ]
761
- },
762
- "blockStreaming": {
763
- "type": "boolean"
764
- },
765
- "blockStreamingCoalesce": {
767
+ "streaming": {
766
768
  "type": "object",
767
769
  "properties": {
768
- "minChars": {
769
- "type": "integer",
770
- "exclusiveMinimum": 0,
771
- "maximum": 9007199254740991
772
- },
773
- "maxChars": {
774
- "type": "integer",
775
- "exclusiveMinimum": 0,
776
- "maximum": 9007199254740991
770
+ "chunkMode": {
771
+ "type": "string",
772
+ "enum": [
773
+ "length",
774
+ "newline"
775
+ ]
777
776
  },
778
- "idleMs": {
779
- "type": "integer",
780
- "minimum": 0,
781
- "maximum": 9007199254740991
777
+ "block": {
778
+ "type": "object",
779
+ "properties": {
780
+ "enabled": {
781
+ "type": "boolean"
782
+ },
783
+ "coalesce": {
784
+ "type": "object",
785
+ "properties": {
786
+ "minChars": {
787
+ "type": "integer",
788
+ "exclusiveMinimum": 0,
789
+ "maximum": 9007199254740991
790
+ },
791
+ "maxChars": {
792
+ "type": "integer",
793
+ "exclusiveMinimum": 0,
794
+ "maximum": 9007199254740991
795
+ },
796
+ "idleMs": {
797
+ "type": "integer",
798
+ "minimum": 0,
799
+ "maximum": 9007199254740991
800
+ }
801
+ },
802
+ "additionalProperties": false
803
+ }
804
+ },
805
+ "additionalProperties": false
782
806
  }
783
807
  },
784
808
  "additionalProperties": false
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/nextcloud-talk",
3
- "version": "2026.7.1",
3
+ "version": "2026.7.2-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.1"
11
+ "openclaw": ">=2026.7.2-beta.2"
12
12
  },
13
13
  "peerDependenciesMeta": {
14
14
  "openclaw": {
@@ -40,10 +40,10 @@
40
40
  "minHostVersion": ">=2026.4.10"
41
41
  },
42
42
  "compat": {
43
- "pluginApi": ">=2026.7.1"
43
+ "pluginApi": ">=2026.7.2-beta.2"
44
44
  },
45
45
  "build": {
46
- "openclawVersion": "2026.7.1"
46
+ "openclawVersion": "2026.7.2-beta.2"
47
47
  },
48
48
  "release": {
49
49
  "publishToClawHub": true,
@@ -1,7 +0,0 @@
1
- import { createLegacyPrivateNetworkDoctorContract } from "openclaw/plugin-sdk/ssrf-runtime";
2
- //#region extensions/nextcloud-talk/src/doctor-contract.ts
3
- const contract = createLegacyPrivateNetworkDoctorContract({ channelKey: "nextcloud-talk" });
4
- const legacyConfigRules = contract.legacyConfigRules;
5
- const normalizeCompatibilityConfig = contract.normalizeCompatibilityConfig;
6
- //#endregion
7
- export { normalizeCompatibilityConfig as n, legacyConfigRules as t };