@openclaw/line 2026.7.2-beta.4 → 2026.7.2-beta.5

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/index.js CHANGED
@@ -4,7 +4,7 @@ import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
4
4
  function createLineCardCommandLoader(api) {
5
5
  return createLazyRuntimeModule(async () => {
6
6
  let registered = null;
7
- const { registerLineCardCommand } = await import("./card-command-Ch0TwcDW.js");
7
+ const { registerLineCardCommand } = await import("./card-command-BEMIm8D8.js");
8
8
  registerLineCardCommand({
9
9
  ...api,
10
10
  registerCommand(command) {
@@ -1,6 +1,6 @@
1
- import { i as resolveLineAccount } from "./accounts-BUBOoW5Q.js";
1
+ import { i as resolveLineAccount } from "./accounts-CSH5sk8U.js";
2
2
  import { a as validateLineMediaUrl, t as createLineSendReceipt } from "./send-receipt-CY2ey8XH.js";
3
- import { a as messageAction, o as postbackAction, s as uriAction, u as createReceiptCard } from "./flex-templates-KiKaVYgi.js";
3
+ import { _ as postbackAction, g as normalizeLineMessageActions, h as normalizeLineAction, m as messageAction, o as createReceiptCard, v as uriAction } from "./flex-templates-DVy_wog4.js";
4
4
  import { markdownToIRWithMeta, stripMarkdown, stripMarkdown as stripMarkdown$1 } from "openclaw/plugin-sdk/text-chunking";
5
5
  import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
6
6
  import { logVerbose } from "openclaw/plugin-sdk/runtime-env";
@@ -54,6 +54,19 @@ function formatProductCarouselText(description, price) {
54
54
  const descriptionText = truncateTemplateText(description, Math.max(0, COMPACT_TEMPLATE_TEXT_LIMIT - priceText.length - 1));
55
55
  return descriptionText ? `${descriptionText}\n${priceText}` : priceText;
56
56
  }
57
+ function normalizeCarouselColumnActions(column) {
58
+ return {
59
+ ...column,
60
+ actions: column.actions.map((action) => normalizeLineAction(action)),
61
+ defaultAction: column.defaultAction === void 0 ? void 0 : normalizeLineAction(column.defaultAction)
62
+ };
63
+ }
64
+ function normalizeImageCarouselColumnAction(column) {
65
+ return {
66
+ ...column,
67
+ action: normalizeLineAction(column.action, 12)
68
+ };
69
+ }
57
70
  /**
58
71
  * Create a confirm template (yes/no style dialog)
59
72
  */
@@ -61,7 +74,7 @@ function createConfirmTemplate(text, confirmAction, cancelAction, altText) {
61
74
  const template = {
62
75
  type: "confirm",
63
76
  text: truncateTemplateText(text, 240),
64
- actions: [confirmAction, cancelAction]
77
+ actions: [normalizeLineAction(confirmAction), normalizeLineAction(cancelAction)]
65
78
  };
66
79
  return {
67
80
  type: "template",
@@ -83,12 +96,12 @@ function createButtonTemplate(title, text, actions, options) {
83
96
  type: "buttons",
84
97
  ...normalizedTitle ? { title: truncateTemplateText(normalizedTitle, 40) } : {},
85
98
  text: truncateTemplateText(text, textLimit),
86
- actions: actions.slice(0, 4),
99
+ actions: actions.slice(0, 4).map((action) => normalizeLineAction(action)),
87
100
  thumbnailImageUrl: options?.thumbnailImageUrl,
88
101
  imageAspectRatio: options?.imageAspectRatio ?? "rectangle",
89
102
  imageSize: options?.imageSize ?? "cover",
90
103
  imageBackgroundColor: options?.imageBackgroundColor,
91
- defaultAction: options?.defaultAction
104
+ defaultAction: options?.defaultAction === void 0 ? void 0 : normalizeLineAction(options.defaultAction)
92
105
  };
93
106
  return {
94
107
  type: "template",
@@ -102,7 +115,7 @@ function createButtonTemplate(title, text, actions, options) {
102
115
  function createTemplateCarousel(columns, options) {
103
116
  const template = {
104
117
  type: "carousel",
105
- columns: columns.slice(0, 10),
118
+ columns: columns.slice(0, 10).map(normalizeCarouselColumnActions),
106
119
  imageAspectRatio: options?.imageAspectRatio ?? "rectangle",
107
120
  imageSize: options?.imageSize ?? "cover"
108
121
  };
@@ -123,10 +136,10 @@ function createCarouselColumn(params) {
123
136
  return {
124
137
  title: truncateOptionalTemplateText(params.title, 40),
125
138
  text: truncateTemplateText(params.text, textLimit),
126
- actions: params.actions.slice(0, 3),
139
+ actions: params.actions.slice(0, 3).map((action) => normalizeLineAction(action)),
127
140
  thumbnailImageUrl: params.thumbnailImageUrl,
128
141
  imageBackgroundColor: params.imageBackgroundColor,
129
- defaultAction: params.defaultAction
142
+ defaultAction: params.defaultAction === void 0 ? void 0 : normalizeLineAction(params.defaultAction)
130
143
  };
131
144
  }
132
145
  /**
@@ -135,7 +148,7 @@ function createCarouselColumn(params) {
135
148
  function createImageCarousel(columns, altText) {
136
149
  const template = {
137
150
  type: "image_carousel",
138
- columns: columns.slice(0, 10)
151
+ columns: columns.slice(0, 10).map(normalizeImageCarouselColumnAction)
139
152
  };
140
153
  return {
141
154
  type: "template",
@@ -149,7 +162,7 @@ function createImageCarousel(columns, altText) {
149
162
  function createImageCarouselColumn(imageUrl, action) {
150
163
  return {
151
164
  imageUrl,
152
- action
165
+ action: normalizeLineAction(action, 12)
153
166
  };
154
167
  }
155
168
  /**
@@ -331,9 +344,10 @@ function resolveLineReceiptKind(messages) {
331
344
  async function pushLineMessages(to, messages, opts, behavior = {}) {
332
345
  if (messages.length === 0) throw new Error("Message must be non-empty for LINE sends");
333
346
  const { account, client, chatId } = createLinePushContext(to, opts);
347
+ const normalizedMessages = messages.map(normalizeLineMessageActions);
334
348
  const pushRequest = client.pushMessage({
335
349
  to: chatId,
336
- messages
350
+ messages: normalizedMessages
337
351
  });
338
352
  if (behavior.errorContext) await pushRequest.catch((err) => {
339
353
  logLineHttpError(err, behavior.errorContext);
@@ -355,9 +369,10 @@ async function pushLineMessages(to, messages, opts, behavior = {}) {
355
369
  }
356
370
  async function replyLineMessages(replyToken, messages, opts, behavior = {}) {
357
371
  const { account, client } = createLineMessagingClient(opts);
372
+ const normalizedMessages = messages.map(normalizeLineMessageActions);
358
373
  await client.replyMessage({
359
374
  replyToken,
360
- messages
375
+ messages: normalizedMessages
361
376
  });
362
377
  recordLineOutboundActivity(account.accountId);
363
378
  if (opts.verbose) logVerbose(behavior.verboseMessage?.(messages.length) ?? `line: replied with ${messages.length} messages`);
@@ -1,7 +1,7 @@
1
- import { i as resolveLineAccount, r as resolveDefaultLineAccountId } from "./accounts-BUBOoW5Q.js";
1
+ import { i as resolveLineAccount, r as resolveDefaultLineAccountId } from "./accounts-CSH5sk8U.js";
2
2
  import { a as resolveLineGroupConfigEntry, n as getLineRuntime, t as buildLineQuickReplyFallbackText } from "./quick-reply-fallback-D86FwAfr.js";
3
3
  import { n as buildLineMediaMessage, r as hasLineSpecificMediaOptions } from "./send-receipt-CY2ey8XH.js";
4
- import { E as buildTemplateMessageFromPayload, S as replyMessageLine, i as processLineMessage, l as createLocationMessage, p as getUserDisplayName, s as createFlexMessage, u as createQuickReplyItems, v as pushMessageLine, w as showLoadingAnimation, y as pushMessagesLine } from "./markdown-to-line-DWIdzBfy.js";
4
+ import { E as buildTemplateMessageFromPayload, S as replyMessageLine, i as processLineMessage, l as createLocationMessage, p as getUserDisplayName, s as createFlexMessage, u as createQuickReplyItems, v as pushMessageLine, w as showLoadingAnimation, y as pushMessagesLine } from "./markdown-to-line-Dn00k1bq.js";
5
5
  import { createChannelPairingChallengeIssuer } from "openclaw/plugin-sdk/channel-pairing";
6
6
  import { normalizeOptionalString, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
7
7
  import { DEFAULT_INGRESS_ADOPTION_STALL_MS, DEFAULT_INGRESS_RETRY_MAX_ATTEMPTS, bindIngressLifecycleToReplyOptions, createChannelIngressMonitor } from "openclaw/plugin-sdk/channel-outbound";
@@ -17,7 +17,7 @@ import { createNonExitingRuntime, danger, logVerbose, shouldLogVerbose, waitForA
17
17
  import { fetchWithRuntimeDispatcherOrMockedGlobal } from "openclaw/plugin-sdk/runtime-fetch";
18
18
  import { HTTPFetchError } from "@line/bot-sdk";
19
19
  import { recordChannelActivity } from "openclaw/plugin-sdk/channel-activity-runtime";
20
- import { buildMentionRegexes, formatInboundEnvelope, formatInboundMediaUnavailableText, formatLocationText, hasFinalInboundReplyDispatch, matchesMentionPatterns, resolveInboundSessionEnvelopeContext, toInboundMediaFacts, toLocationContext } from "openclaw/plugin-sdk/channel-inbound";
20
+ import { buildChannelInboundEventContext, buildMentionRegexes, formatInboundEnvelope, formatInboundMediaUnavailableText, formatLocationText, hasFinalInboundReplyDispatch, matchesMentionPatterns, resolveInboundSessionEnvelopeContext, toInboundMediaFacts, toLocationContext } from "openclaw/plugin-sdk/channel-inbound";
21
21
  import { chunkMarkdownText } from "openclaw/plugin-sdk/reply-runtime";
22
22
  import { isRequestBodyLimitError, normalizePluginHttpPath, normalizeWebhookPath, registerWebhookTargetWithPluginRoute, requestBodyErrorToText, resolveSingleWebhookTarget } from "openclaw/plugin-sdk/webhook-ingress";
23
23
  import { beginWebhookRequestPipelineOrReject, createWebhookInFlightLimiter, isRequestBodyLimitError as isRequestBodyLimitError$1, readRequestBodyWithLimit, requestBodyErrorToText as requestBodyErrorToText$1, runDetachedWebhookWork } from "openclaw/plugin-sdk/webhook-request-guards";
@@ -28,7 +28,6 @@ import { hasControlCommand } from "openclaw/plugin-sdk/command-auth-native";
28
28
  import { ensureConfiguredBindingRouteReady, readChannelAllowFromStore, resolveConfiguredBindingRoute, resolvePairingIdLabel, resolvePinnedMainDmOwnerFromAllowlist, resolveRuntimeConversationBindingRoute, upsertChannelPairingRequest } from "openclaw/plugin-sdk/conversation-runtime";
29
29
  import { resolveAgentRoute, resolveInboundLastRouteSessionKey } from "openclaw/plugin-sdk/routing";
30
30
  import { resolveAllowlistProviderRuntimeGroupPolicy, resolveDefaultGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce } from "openclaw/plugin-sdk/runtime-group-policy";
31
- import { finalizeInboundContext } from "openclaw/plugin-sdk/reply-dispatch-runtime";
32
31
  import crypto from "node:crypto";
33
32
  import { safeEqualSecret } from "openclaw/plugin-sdk/security-runtime";
34
33
  //#region extensions/line/src/bot-access.ts
@@ -441,33 +440,11 @@ function extractNativeMediaKind(message) {
441
440
  default: return;
442
441
  }
443
442
  }
444
- function resolveLineConversationLabel(params) {
445
- return params.isGroup ? params.groupId ? `group:${params.groupId}` : params.roomId ? `room:${params.roomId}` : "unknown-group" : params.senderLabel;
446
- }
447
- function resolveLineAddresses(params) {
448
- const fromAddress = params.isGroup ? params.groupId ? `line:group:${params.groupId}` : params.roomId ? `line:room:${params.roomId}` : `line:${params.peerId}` : `line:${params.userId ?? params.peerId}`;
449
- return {
450
- fromAddress,
451
- toAddress: params.isGroup ? fromAddress : `line:${params.userId ?? params.peerId}`,
452
- originatingTo: params.isGroup ? fromAddress : `line:${params.userId ?? params.peerId}`
453
- };
454
- }
455
443
  async function finalizeLineInboundContext(params) {
456
- const { fromAddress, toAddress, originatingTo } = resolveLineAddresses({
457
- isGroup: params.source.isGroup,
458
- groupId: params.source.groupId,
459
- roomId: params.source.roomId,
460
- userId: params.source.userId,
461
- peerId: params.source.peerId
462
- });
463
444
  const senderId = params.source.userId ?? "unknown";
464
445
  const senderLabel = params.source.userId ? `user:${params.source.userId}` : "unknown";
465
- const conversationLabel = resolveLineConversationLabel({
466
- isGroup: params.source.isGroup,
467
- groupId: params.source.groupId,
468
- roomId: params.source.roomId,
469
- senderLabel
470
- });
446
+ const conversationLabel = params.source.isGroup ? params.source.groupId ? `group:${params.source.groupId}` : params.source.roomId ? `room:${params.source.roomId}` : "unknown-group" : senderLabel;
447
+ const address = params.source.groupId ? `line:group:${params.source.groupId}` : params.source.roomId ? `line:room:${params.source.roomId}` : `line:${params.source.userId ?? params.source.peerId}`;
471
448
  const { storePath, envelopeOptions, previousTimestamp } = resolveInboundSessionEnvelopeContext({
472
449
  cfg: params.cfg,
473
450
  agentId: params.route.agentId,
@@ -485,34 +462,45 @@ async function finalizeLineInboundContext(params) {
485
462
  previousTimestamp,
486
463
  envelope: envelopeOptions
487
464
  });
488
- const ctxPayload = finalizeInboundContext({
489
- Body: body,
490
- BodyForAgent: agentBody,
491
- RawBody: params.rawBody,
492
- CommandBody: params.rawBody,
493
- From: fromAddress,
494
- To: toAddress,
495
- SessionKey: params.route.sessionKey,
496
- DmScope: params.route.dmScope,
497
- AccountId: params.route.accountId,
498
- ChatType: params.source.isGroup ? "group" : "direct",
499
- ConversationLabel: conversationLabel,
500
- GroupSubject: params.source.isGroup ? params.source.groupId ?? params.source.roomId : void 0,
501
- SenderId: senderId,
502
- Provider: "line",
503
- Surface: "line",
504
- MessageSid: params.messageSid,
505
- Timestamp: params.timestamp,
465
+ const ctxPayload = buildChannelInboundEventContext({
466
+ channel: "line",
467
+ accountId: params.route.accountId,
468
+ messageId: params.messageSid,
469
+ timestamp: params.timestamp,
470
+ from: address,
471
+ sender: { id: senderId },
472
+ conversation: {
473
+ kind: params.source.isGroup ? "group" : "direct",
474
+ id: params.source.peerId,
475
+ label: conversationLabel
476
+ },
477
+ route: {
478
+ agentId: params.route.agentId,
479
+ dmScope: params.route.dmScope,
480
+ accountId: params.route.accountId,
481
+ routeSessionKey: params.route.sessionKey
482
+ },
483
+ reply: {
484
+ to: address,
485
+ originatingTo: address
486
+ },
487
+ message: {
488
+ body,
489
+ bodyForAgent: agentBody,
490
+ rawBody: params.rawBody,
491
+ commandBody: params.rawBody,
492
+ inboundHistory: params.inboundHistory
493
+ },
494
+ access: { commands: { authorized: params.commandAuthorized } },
506
495
  media,
507
- ...params.locationContext,
508
- CommandAuthorized: params.commandAuthorized,
509
- OriginatingChannel: "line",
510
- OriginatingTo: originatingTo,
511
- GroupSystemPrompt: params.source.isGroup ? normalizeOptionalString(resolveLineGroupConfigEntry(params.account.config.groups, {
512
- groupId: params.source.groupId,
513
- roomId: params.source.roomId
514
- })?.systemPrompt) : void 0,
515
- InboundHistory: params.inboundHistory
496
+ extra: {
497
+ ...params.locationContext,
498
+ GroupSubject: params.source.isGroup ? params.source.groupId ?? params.source.roomId : void 0,
499
+ GroupSystemPrompt: params.source.isGroup ? normalizeOptionalString(resolveLineGroupConfigEntry(params.account.config.groups, {
500
+ groupId: params.source.groupId,
501
+ roomId: params.source.roomId
502
+ })?.systemPrompt) : void 0
503
+ }
516
504
  });
517
505
  const pinnedMainDmOwner = !params.source.isGroup ? resolvePinnedMainDmOwnerFromAllowlist({
518
506
  dmScope: params.cfg.session?.dmScope,
@@ -0,0 +1,2 @@
1
+ import { t as monitorLineProvider } from "./monitor-DzFU5UPV.js";
2
+ export { monitorLineProvider };
@@ -1,2 +1,2 @@
1
- import { C as sendMessageLine, E as buildTemplateMessageFromPayload, _ as pushLocationMessage, b as pushTemplateMessage, h as pushFlexMessage, i as processLineMessage, u as createQuickReplyItems, v as pushMessageLine, x as pushTextMessageWithQuickReplies, y as pushMessagesLine } from "./markdown-to-line-DWIdzBfy.js";
1
+ import { C as sendMessageLine, E as buildTemplateMessageFromPayload, _ as pushLocationMessage, b as pushTemplateMessage, h as pushFlexMessage, i as processLineMessage, u as createQuickReplyItems, v as pushMessageLine, x as pushTextMessageWithQuickReplies, y as pushMessagesLine } from "./markdown-to-line-Dn00k1bq.js";
2
2
  export { buildTemplateMessageFromPayload, createQuickReplyItems, processLineMessage, pushFlexMessage, pushLocationMessage, pushMessageLine, pushMessagesLine, pushTemplateMessage, pushTextMessageWithQuickReplies, sendMessageLine };
@@ -1,4 +1,4 @@
1
- import { withTimeout } from "openclaw/plugin-sdk/text-utility-runtime";
1
+ import { runChannelProbe } from "openclaw/plugin-sdk/text-utility-runtime";
2
2
  import { messagingApi } from "@line/bot-sdk";
3
3
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
4
4
  //#region extensions/line/src/probe.ts
@@ -8,8 +8,8 @@ async function probeLineBot(channelAccessToken, timeoutMs = 5e3) {
8
8
  error: "Channel access token not configured"
9
9
  };
10
10
  const client = new messagingApi.MessagingApiClient({ channelAccessToken: channelAccessToken.trim() });
11
- try {
12
- const profile = await withTimeout(client.getBotInfo(), timeoutMs);
11
+ return await runChannelProbe(timeoutMs, async () => {
12
+ const profile = await client.getBotInfo();
13
13
  return {
14
14
  ok: true,
15
15
  bot: {
@@ -19,12 +19,10 @@ async function probeLineBot(channelAccessToken, timeoutMs = 5e3) {
19
19
  pictureUrl: profile.pictureUrl
20
20
  }
21
21
  };
22
- } catch (err) {
23
- return {
24
- ok: false,
25
- error: formatErrorMessage(err)
26
- };
27
- }
22
+ }, (error) => ({
23
+ ok: false,
24
+ error: formatErrorMessage(error)
25
+ }));
28
26
  }
29
27
  //#endregion
30
28
  export { probeLineBot as t };
@@ -0,0 +1,2 @@
1
+ import { t as probeLineBot } from "./probe-CM03wo6r.js";
2
+ export { probeLineBot };
@@ -1,4 +1,4 @@
1
- import { c as createAgendaCard, l as createEventCard, n as createDeviceControlCard, r as createMediaPlayerCard, t as createAppleTvRemoteCard } from "./flex-templates-KiKaVYgi.js";
1
+ import { a as createEventCard, i as createAgendaCard, n as createDeviceControlCard, r as createMediaPlayerCard, t as createAppleTvRemoteCard } from "./flex-templates-DVy_wog4.js";
2
2
  import { normalizeLowercaseStringOrEmpty, normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
3
3
  import { DmPolicySchema, GroupPolicySchema, buildChannelConfigSchema, buildGroupEntrySchema, buildMultiAccountChannelSchema, requireOpenAllowFrom } from "openclaw/plugin-sdk/channel-config-schema";
4
4
  import { requireChannelOpenAllowFrom } from "openclaw/plugin-sdk/extension-shared";
@@ -1,18 +1,17 @@
1
- import { i as resolveLineAccount, n as normalizeAccountId, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./accounts-BUBOoW5Q.js";
1
+ import { i as resolveLineAccount, n as normalizeAccountId, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./accounts-CSH5sk8U.js";
2
2
  import { a as resolveLineGroupConfigEntry, i as resolveExactLineGroupConfigKey, o as resolveLineGroupLookupIds, r as setLineRuntime, s as resolveLineGroupsConfig } from "./quick-reply-fallback-D86FwAfr.js";
3
- import { i as LineConfigSchema, n as parseLineDirectives, r as LineChannelConfigSchema, t as hasLineDirectives } from "./reply-payload-transform-d57WYHFm.js";
4
- import { a as messageAction, c as createAgendaCard, i as datetimePickerAction, l as createEventCard, n as createDeviceControlCard, o as postbackAction, r as createMediaPlayerCard, s as uriAction, t as createAppleTvRemoteCard, u as createReceiptCard } from "./flex-templates-KiKaVYgi.js";
5
- import { a as createListCard, i as createInfoCard, n as createCarousel, o as createNotificationBubble, r as createImageCard, t as createActionCard } from "./basic-cards-Rb-Ow7LN.js";
6
- import { A as createConfirmTemplate, C as sendMessageLine, D as createButtonMenu, E as buildTemplateMessageFromPayload, F as createTemplateCarousel, I as createYesNoConfirm, L as toFlexMessage, M as createImageCarouselColumn, N as createLinkMenu, O as createButtonTemplate, P as createProductCarousel, S as replyMessageLine, T as resolveLineChannelAccessToken, _ as pushLocationMessage, a as stripMarkdown, b as pushTemplateMessage, c as createImageMessage, d as createTextMessageWithQuickReplies, f as createVideoMessage, g as pushImageMessage, h as pushFlexMessage, i as processLineMessage, j as createImageCarousel, k as createCarouselColumn, l as createLocationMessage, m as getUserProfile, n as convertTableToFlexBubble, o as createAudioMessage, p as getUserDisplayName, r as hasMarkdownToConvert, s as createFlexMessage, t as convertCodeBlockToFlexBubble, u as createQuickReplyItems, v as pushMessageLine, w as showLoadingAnimation, x as pushTextMessageWithQuickReplies, y as pushMessagesLine } from "./markdown-to-line-DWIdzBfy.js";
7
- import { a as validateLineSignature, c as normalizeAllowFrom, i as parseLineWebhookBody, n as createLineNodeWebhookHandler, o as downloadLineMedia, r as readLineWebhookRequestBody, s as firstDefined, t as monitorLineProvider } from "./monitor-BinAXvIY.js";
8
- import { t as probeLineBot } from "./probe-BslD77tJ.js";
3
+ import { i as LineConfigSchema, n as parseLineDirectives, r as LineChannelConfigSchema, t as hasLineDirectives } from "./reply-payload-transform-BRM2fRvK.js";
4
+ import { _ as postbackAction, a as createEventCard, c as createCarousel, d as createListCard, f as createNotificationBubble, i as createAgendaCard, l as createImageCard, m as messageAction, n as createDeviceControlCard, o as createReceiptCard, p as datetimePickerAction, r as createMediaPlayerCard, s as createActionCard, t as createAppleTvRemoteCard, u as createInfoCard, v as uriAction } from "./flex-templates-DVy_wog4.js";
5
+ import { A as createConfirmTemplate, C as sendMessageLine, D as createButtonMenu, E as buildTemplateMessageFromPayload, F as createTemplateCarousel, I as createYesNoConfirm, L as toFlexMessage, M as createImageCarouselColumn, N as createLinkMenu, O as createButtonTemplate, P as createProductCarousel, S as replyMessageLine, T as resolveLineChannelAccessToken, _ as pushLocationMessage, a as stripMarkdown, b as pushTemplateMessage, c as createImageMessage, d as createTextMessageWithQuickReplies, f as createVideoMessage, g as pushImageMessage, h as pushFlexMessage, i as processLineMessage, j as createImageCarousel, k as createCarouselColumn, l as createLocationMessage, m as getUserProfile, n as convertTableToFlexBubble, o as createAudioMessage, p as getUserDisplayName, r as hasMarkdownToConvert, s as createFlexMessage, t as convertCodeBlockToFlexBubble, u as createQuickReplyItems, v as pushMessageLine, w as showLoadingAnimation, x as pushTextMessageWithQuickReplies, y as pushMessagesLine } from "./markdown-to-line-Dn00k1bq.js";
6
+ import { a as validateLineSignature, c as normalizeAllowFrom, i as parseLineWebhookBody, n as createLineNodeWebhookHandler, o as downloadLineMedia, r as readLineWebhookRequestBody, s as firstDefined, t as monitorLineProvider } from "./monitor-DzFU5UPV.js";
7
+ import { t as probeLineBot } from "./probe-CM03wo6r.js";
9
8
  import { clearAccountEntryFields } from "openclaw/plugin-sdk/core";
10
9
  import { buildChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-schema";
11
10
  import { DEFAULT_ACCOUNT_ID, formatDocsLink, setSetupChannelEnabled, splitSetupEntries } from "openclaw/plugin-sdk/setup";
12
11
  import { buildComputedAccountStatusSnapshot, buildTokenChannelStatusSummary } from "openclaw/plugin-sdk/status-helpers";
13
12
  import { danger, logVerbose } from "openclaw/plugin-sdk/runtime-env";
14
13
  import { messagingApi } from "@line/bot-sdk";
15
- import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/agent-media-payload";
14
+ import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-local-roots";
16
15
  import { mimeTypeFromFilePath } from "openclaw/plugin-sdk/media-mime";
17
16
  import { loadWebMediaRaw } from "openclaw/plugin-sdk/web-media";
18
17
  //#region extensions/line/src/webhook.ts
package/dist/setup-api.js CHANGED
@@ -1,2 +1,2 @@
1
- import { n as lineSetupAdapter, t as lineSetupWizard } from "./setup-surface-Bili5gWy.js";
1
+ import { n as lineSetupAdapter, t as lineSetupWizard } from "./setup-surface-BHQOSD8R.js";
2
2
  export { lineSetupAdapter, lineSetupWizard };
@@ -1,7 +1,8 @@
1
- import { i as resolveLineAccount, n as normalizeAccountId, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./accounts-BUBOoW5Q.js";
1
+ import { i as resolveLineAccount, n as normalizeAccountId, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./accounts-CSH5sk8U.js";
2
2
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
3
3
  import { defineChannelSetupContract } from "openclaw/plugin-sdk/channel-setup";
4
- import { DEFAULT_ACCOUNT_ID, createAllowFromSection, createSetupInputPresenceValidator, createSetupTranslator, createStandardChannelSetupStatus, defineTokenCredential, formatDocsLink, mergeAllowFromEntries, setSetupChannelEnabled, splitSetupEntries } from "openclaw/plugin-sdk/setup";
4
+ import { DEFAULT_ACCOUNT_ID, createAllowFromSection, createPromptParsedAllowFromForAccount, createSetupInputPresenceValidator, createSetupTranslator, createStandardChannelSetupStatus, defineTokenCredential, formatDocsLink, parseSetupEntriesWithParser, patchScopedAccountConfig, setSetupChannelEnabled, splitSetupEntries } from "openclaw/plugin-sdk/setup";
5
+ import { createChannelDmPolicy } from "openclaw/plugin-sdk/channel-dm-policy";
5
6
  //#region extensions/line/src/account-helpers.ts
6
7
  function hasLineCredentials(account) {
7
8
  if (account.tokenStatus && account.signingSecretStatus) return account.tokenStatus !== "missing" && account.signingSecretStatus !== "missing";
@@ -15,44 +16,19 @@ function parseLineAllowFromId(raw) {
15
16
  //#endregion
16
17
  //#region extensions/line/src/setup-core.ts
17
18
  function patchLineAccountConfig(params) {
18
- const accountId = normalizeAccountId(params.accountId);
19
- const lineConfig = params.cfg.channels?.line ?? {};
20
- const clearFields = params.clearFields ?? [];
21
- if (accountId === DEFAULT_ACCOUNT_ID) {
22
- const nextLine = { ...lineConfig };
23
- for (const field of clearFields) delete nextLine[field];
24
- return {
25
- ...params.cfg,
26
- channels: {
27
- ...params.cfg.channels,
28
- line: {
29
- ...nextLine,
30
- ...params.enabled ? { enabled: true } : {},
31
- ...params.patch
32
- }
33
- }
34
- };
35
- }
36
- const nextAccount = { ...lineConfig.accounts?.[accountId] };
37
- for (const field of clearFields) delete nextAccount[field];
38
- return {
39
- ...params.cfg,
40
- channels: {
41
- ...params.cfg.channels,
42
- line: {
43
- ...lineConfig,
44
- ...params.enabled ? { enabled: true } : {},
45
- accounts: {
46
- ...lineConfig.accounts,
47
- [accountId]: {
48
- ...nextAccount,
49
- ...params.enabled ? { enabled: true } : {},
50
- ...params.patch
51
- }
52
- }
53
- }
54
- }
55
- };
19
+ return patchScopedAccountConfig({
20
+ cfg: params.cfg,
21
+ channelKey: "line",
22
+ accountId: params.accountId,
23
+ patch: params.patch,
24
+ accountPatch: {
25
+ ...params.enabled ? { enabled: true } : {},
26
+ ...params.patch
27
+ },
28
+ ...params.clearFields ? { clearFields: params.clearFields } : {},
29
+ ensureChannelEnabled: Boolean(params.enabled),
30
+ ensureAccountEnabled: false
31
+ });
56
32
  }
57
33
  function isLineConfigured(cfg, accountId) {
58
34
  return hasLineCredentials(resolveLineAccount({
@@ -183,36 +159,42 @@ const LINE_ALLOW_FROM_HELP_LINES = [
183
159
  t("wizard.line.multipleEntries"),
184
160
  t("wizard.channels.docs", { link: formatDocsLink("/channels/line", "channels/line") })
185
161
  ];
186
- const lineDmPolicy = {
162
+ const lineDmPolicy = createChannelDmPolicy({
187
163
  label: "LINE",
188
164
  channel,
189
- policyKey: "channels.line.dmPolicy",
190
- allowFromKey: "channels.line.allowFrom",
191
- resolveConfigKeys: (cfg, accountId) => (accountId ?? resolveDefaultLineAccountId(cfg)) !== DEFAULT_ACCOUNT_ID ? {
192
- policyKey: `channels.line.accounts.${accountId ?? resolveDefaultLineAccountId(cfg)}.dmPolicy`,
193
- allowFromKey: `channels.line.accounts.${accountId ?? resolveDefaultLineAccountId(cfg)}.allowFrom`
194
- } : {
195
- policyKey: "channels.line.dmPolicy",
196
- allowFromKey: "channels.line.allowFrom"
197
- },
198
- getCurrent: (cfg, accountId) => resolveLineAccount({
165
+ resolveAccount: (cfg, accountId) => resolveLineAccount({
199
166
  cfg,
200
167
  accountId: accountId ?? resolveDefaultLineAccountId(cfg)
201
- }).config.dmPolicy ?? "pairing",
202
- setPolicy: (cfg, policy, accountId) => patchLineAccountConfig({
168
+ }),
169
+ applyPatch: ({ cfg, account, patch }) => patchLineAccountConfig({
203
170
  cfg,
204
- accountId: accountId ?? resolveDefaultLineAccountId(cfg),
171
+ accountId: account.accountId,
205
172
  enabled: true,
206
- patch: policy === "open" ? {
207
- dmPolicy: "open",
208
- allowFrom: mergeAllowFromEntries(resolveLineAccount({
209
- cfg,
210
- accountId: accountId ?? resolveDefaultLineAccountId(cfg)
211
- }).config.allowFrom, ["*"])
212
- } : { dmPolicy: policy },
213
- clearFields: policy === "pairing" || policy === "disabled" ? ["allowFrom"] : void 0
173
+ patch,
174
+ clearFields: patch.dmPolicy === "pairing" || patch.dmPolicy === "disabled" ? ["allowFrom"] : void 0
175
+ }),
176
+ promptAllowFrom: createPromptParsedAllowFromForAccount({
177
+ defaultAccountId: resolveDefaultLineAccountId,
178
+ noteTitle: t("wizard.line.allowlistTitle"),
179
+ noteLines: LINE_ALLOW_FROM_HELP_LINES,
180
+ message: t("wizard.line.allowFromPrompt"),
181
+ placeholder: "U1234567890abcdef1234567890abcdef",
182
+ parseEntries: (raw) => parseSetupEntriesWithParser(raw, (entry) => {
183
+ const id = parseLineAllowFromId(entry);
184
+ return id ? { value: id } : { error: t("wizard.line.allowFromInvalid") };
185
+ }),
186
+ getExistingAllowFrom: ({ cfg, accountId }) => resolveLineAccount({
187
+ cfg,
188
+ accountId
189
+ }).config.allowFrom ?? [],
190
+ applyAllowFrom: ({ cfg, accountId, allowFrom }) => patchLineAccountConfig({
191
+ cfg,
192
+ accountId,
193
+ enabled: true,
194
+ patch: { allowFrom }
195
+ })
214
196
  })
215
- };
197
+ });
216
198
  const lineSetupWizard = {
217
199
  channel,
218
200
  status: createStandardChannelSetupStatus({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/line",
3
- "version": "2026.7.2-beta.4",
3
+ "version": "2026.7.2-beta.5",
4
4
  "description": "OpenClaw LINE channel plugin for LINE Bot API chats.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -12,7 +12,7 @@
12
12
  "zod": "4.4.3"
13
13
  },
14
14
  "peerDependencies": {
15
- "openclaw": ">=2026.7.2-beta.4"
15
+ "openclaw": ">=2026.7.2-beta.5"
16
16
  },
17
17
  "peerDependenciesMeta": {
18
18
  "openclaw": {
@@ -107,10 +107,10 @@
107
107
  "minHostVersion": ">=2026.4.10"
108
108
  },
109
109
  "compat": {
110
- "pluginApi": ">=2026.7.2-beta.4"
110
+ "pluginApi": ">=2026.7.2-beta.5"
111
111
  },
112
112
  "build": {
113
- "openclawVersion": "2026.7.2-beta.4"
113
+ "openclawVersion": "2026.7.2-beta.5"
114
114
  },
115
115
  "release": {
116
116
  "publishToClawHub": true,
@@ -124,7 +124,6 @@
124
124
  "files": [
125
125
  "dist/**",
126
126
  "openclaw.plugin.json",
127
- "npm-shrinkwrap.json",
128
127
  "README.md"
129
128
  ],
130
129
  "bundledDependencies": [