@openclaw/line 2026.9.1-beta.1 → 2026.9.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/account-helpers-BSUyZwLm.js +12 -0
- package/dist/{accounts-BqEVsDoB.js → accounts-BBEFMYbY.js} +2 -1
- package/dist/api.js +2 -2
- package/dist/card-command-pwvE48Wb.js +252 -0
- package/dist/{channel-CsQLcrsA.js → channel-BJvELOIg.js} +111 -380
- package/dist/channel-plugin-api.js +1 -1
- package/dist/channel.runtime-CZOszXXj.js +4 -0
- package/dist/contract-api.js +1 -1
- package/dist/doctor-contract-api.js +141 -0
- package/dist/index.js +5 -17
- package/dist/{markdown-to-line-BmZ4hhfC.js → markdown-to-line-B-sj-7II.js} +22 -23
- package/dist/{monitor-Bd9XDV1i.js → monitor-m9h5osFz.js} +339 -237
- package/dist/monitor.runtime-C90LL-P3.js +2 -0
- package/dist/outbound.runtime-CGqyJ-Ug.js +3 -0
- package/dist/probe.runtime-CbtMgU4s.js +2 -0
- package/dist/rich-messages-DY1AGKAJ.js +742 -0
- package/dist/runtime-api.js +14 -15
- package/dist/{send-Dce0m539.js → send-CQQxpxPp.js} +142 -112
- package/dist/{send-receipt-CCPTalf9.js → send-retry-ChpfJ-LM.js} +326 -86
- package/dist/setup-api.js +1 -1
- package/dist/{setup-surface-W0Dbgu58.js → setup-surface-CDlgkTKi.js} +47 -39
- package/dist/webhook-spool-contract-1rY8OJw8.js +59 -0
- package/node_modules/typebox/build/format/email.mjs +1 -1
- package/node_modules/typebox/build/format/idna/idn-hostname.mjs +19 -1
- package/node_modules/typebox/build/format/json_pointer.d.mts +2 -2
- package/node_modules/typebox/build/format/json_pointer.mjs +2 -2
- package/node_modules/typebox/build/format/json_pointer_uri_fragment.d.mts +2 -2
- package/node_modules/typebox/build/format/json_pointer_uri_fragment.mjs +2 -2
- package/node_modules/typebox/build/format/relative_json_pointer.d.mts +2 -2
- package/node_modules/typebox/build/format/relative_json_pointer.mjs +2 -2
- package/node_modules/typebox/build/system/memory/assign.mjs +2 -1
- package/node_modules/typebox/build/system/memory/create.mjs +3 -4
- package/node_modules/typebox/build/system/memory/discard.mjs +2 -2
- package/node_modules/typebox/build/system/memory/freeze.d.mts +4 -0
- package/node_modules/typebox/build/system/memory/freeze.mjs +6 -0
- package/node_modules/typebox/build/system/memory/update.mjs +3 -2
- package/node_modules/typebox/package.json +1 -1
- package/openclaw.plugin.json +16 -3
- package/package.json +5 -5
- package/dist/card-command-CmU47gD9.js +0 -230
- package/dist/channel.runtime-B83x7k_i.js +0 -4
- package/dist/media-control-cards-CksNB8Wk.js +0 -474
- package/dist/monitor.runtime-BCCa6qTX.js +0 -2
- package/dist/outbound.runtime-D4w0-Gkc.js +0 -3
- package/dist/probe-CM03wo6r.js +0 -28
- package/dist/probe.runtime-D13ZtXsd.js +0 -2
|
@@ -1,25 +1,24 @@
|
|
|
1
|
-
import { i as resolveLineAccount, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./accounts-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { i as resolveLineAccount, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./accounts-BBEFMYbY.js";
|
|
2
|
+
import { t as hasLineCredentials } from "./account-helpers-BSUyZwLm.js";
|
|
3
|
+
import { _ as LineChannelConfigSchema, a as renderLineCard, d as resolveExactLineGroupConfigKey, h as getLineRuntime, n as createLineQuickReply, o as renderLinePresentation, p as resolveLineGroupLookupIds, r as lineMessageActions, t as LINE_PRESENTATION_CAPABILITIES, u as buildLineQuickReplyFallbackText } from "./rich-messages-DY1AGKAJ.js";
|
|
4
|
+
import { s as createLineSendReceipt, t as explainLineRefusal, w as buildLineMediaMessage } from "./send-retry-ChpfJ-LM.js";
|
|
5
|
+
import { r as lineSetupContract, t as lineSetupWizard } from "./setup-surface-CDlgkTKi.js";
|
|
5
6
|
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
6
7
|
import { buildDmGroupAccountAllowlistAdapter, createFlatAllowlistOverrideResolver } from "openclaw/plugin-sdk/allowlist-config-edit";
|
|
7
8
|
import { buildChannelOutboundSessionRoute, createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
|
|
8
9
|
import { createPairingPrefixStripper } from "openclaw/plugin-sdk/channel-pairing";
|
|
9
10
|
import { buildChannelGroupsScopeTree, createRestrictSendersChannelSecurity, resolveScopeRequireMention } from "openclaw/plugin-sdk/channel-policy";
|
|
10
|
-
import {
|
|
11
|
+
import { createChannelDirectoryAdapter, createResolvedDirectoryEntriesLister } from "openclaw/plugin-sdk/directory-runtime";
|
|
11
12
|
import { describeWebhookAccountSnapshot } from "openclaw/plugin-sdk/account-helpers";
|
|
12
13
|
import { DEFAULT_ACCOUNT_ID } from "openclaw/plugin-sdk/account-id";
|
|
13
|
-
import { createScopedChannelConfigAdapter } from "openclaw/plugin-sdk/channel-config-helpers";
|
|
14
|
-
import {
|
|
14
|
+
import { clearAccountFieldsFromConfigSection, createScopedChannelConfigAdapter } from "openclaw/plugin-sdk/channel-config-helpers";
|
|
15
|
+
import { normalizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
15
16
|
import { createAccountStatusSink, defineChannelMessageAdapter, listMessageReceiptPlatformIds } from "openclaw/plugin-sdk/channel-outbound";
|
|
16
|
-
import {
|
|
17
|
-
import { createChannelPartialDeliveryError } from "openclaw/plugin-sdk/channel-inbound";
|
|
17
|
+
import { createChannelPartialDeliveryError, isChannelPartialDeliveryError } from "openclaw/plugin-sdk/channel-inbound";
|
|
18
18
|
import { createAttachedChannelResultAdapter, createEmptyChannelResult } from "openclaw/plugin-sdk/channel-send-result";
|
|
19
|
+
import { PlatformMessageNotDispatchedError } from "openclaw/plugin-sdk/error-runtime";
|
|
19
20
|
import { resolveOutboundMediaUrls } from "openclaw/plugin-sdk/reply-payload";
|
|
20
21
|
import { sanitizeAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking";
|
|
21
|
-
import { resolveMessagePresentationButtonAction, resolveMessagePresentationOptionAction } from "openclaw/plugin-sdk/interactive-runtime";
|
|
22
|
-
import { Type } from "typebox";
|
|
23
22
|
import { buildTokenChannelStatusSummary, createComputedAccountStatusAdapter, createDefaultChannelRuntimeState, createDependentCredentialStatusIssueCollector } from "openclaw/plugin-sdk/status-helpers";
|
|
24
23
|
//#region extensions/line/src/bindings.ts
|
|
25
24
|
function normalizeLineConversationId(raw) {
|
|
@@ -120,8 +119,8 @@ const lineChannelPluginCommon = {
|
|
|
120
119
|
};
|
|
121
120
|
//#endregion
|
|
122
121
|
//#region extensions/line/src/gateway.ts
|
|
123
|
-
const loadLineProbeRuntime$1 = createLazyRuntimeModule(() => import("./probe.runtime-
|
|
124
|
-
const loadLineMonitorRuntime = createLazyRuntimeModule(() => import("./monitor.runtime-
|
|
122
|
+
const loadLineProbeRuntime$1 = createLazyRuntimeModule(() => import("./probe.runtime-CbtMgU4s.js"));
|
|
123
|
+
const loadLineMonitorRuntime = createLazyRuntimeModule(() => import("./monitor.runtime-C90LL-P3.js"));
|
|
125
124
|
const lineGatewayAdapter = {
|
|
126
125
|
startAccount: async (ctx) => {
|
|
127
126
|
const account = ctx.account;
|
|
@@ -157,22 +156,9 @@ const lineGatewayAdapter = {
|
|
|
157
156
|
},
|
|
158
157
|
logoutAccount: async ({ accountId, cfg }) => {
|
|
159
158
|
const envToken = process.env.LINE_CHANNEL_ACCESS_TOKEN?.trim() ?? "";
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
let changed = false;
|
|
164
|
-
if (accountId === DEFAULT_ACCOUNT_ID) {
|
|
165
|
-
if (nextLine.channelAccessToken || nextLine.channelSecret || nextLine.tokenFile || nextLine.secretFile) {
|
|
166
|
-
delete nextLine.channelAccessToken;
|
|
167
|
-
delete nextLine.channelSecret;
|
|
168
|
-
delete nextLine.tokenFile;
|
|
169
|
-
delete nextLine.secretFile;
|
|
170
|
-
cleared = true;
|
|
171
|
-
changed = true;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
const accountCleanup = clearAccountEntryFields({
|
|
175
|
-
accounts: nextLine.accounts,
|
|
159
|
+
const { nextConfig, changed, cleared } = clearAccountFieldsFromConfigSection({
|
|
160
|
+
cfg,
|
|
161
|
+
sectionKey: "line",
|
|
176
162
|
accountId,
|
|
177
163
|
fields: [
|
|
178
164
|
"channelAccessToken",
|
|
@@ -182,30 +168,12 @@ const lineGatewayAdapter = {
|
|
|
182
168
|
],
|
|
183
169
|
markClearedOnFieldPresence: true
|
|
184
170
|
});
|
|
185
|
-
if (
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
else delete nextLine.accounts;
|
|
190
|
-
}
|
|
191
|
-
if (changed) {
|
|
192
|
-
if (Object.keys(nextLine).length > 0) nextCfg.channels = {
|
|
193
|
-
...nextCfg.channels,
|
|
194
|
-
line: nextLine
|
|
195
|
-
};
|
|
196
|
-
else {
|
|
197
|
-
const nextChannels = { ...nextCfg.channels };
|
|
198
|
-
delete nextChannels.line;
|
|
199
|
-
if (Object.keys(nextChannels).length > 0) nextCfg.channels = nextChannels;
|
|
200
|
-
else delete nextCfg.channels;
|
|
201
|
-
}
|
|
202
|
-
await getLineRuntime().config.replaceConfigFile({
|
|
203
|
-
nextConfig: nextCfg,
|
|
204
|
-
afterWrite: { mode: "auto" }
|
|
205
|
-
});
|
|
206
|
-
}
|
|
171
|
+
if (changed) await getLineRuntime().config.replaceConfigFile({
|
|
172
|
+
nextConfig,
|
|
173
|
+
afterWrite: { mode: "auto" }
|
|
174
|
+
});
|
|
207
175
|
const loggedOut = resolveLineAccount({
|
|
208
|
-
cfg:
|
|
176
|
+
cfg: nextConfig,
|
|
209
177
|
accountId
|
|
210
178
|
}).tokenSource === "none";
|
|
211
179
|
return {
|
|
@@ -242,252 +210,8 @@ function inferLineTargetChatType(target) {
|
|
|
242
210
|
return /^[CR][a-f0-9]{32}$/i.test(normalized) ? "group" : void 0;
|
|
243
211
|
}
|
|
244
212
|
//#endregion
|
|
245
|
-
//#region extensions/line/src/rich-messages.ts
|
|
246
|
-
const nonempty = () => Type.String({ minLength: 1 });
|
|
247
|
-
const closed = (properties) => Type.Object(properties, { additionalProperties: false });
|
|
248
|
-
const lineCardSchema = Type.Union([
|
|
249
|
-
closed({
|
|
250
|
-
type: Type.Literal("media_player"),
|
|
251
|
-
title: nonempty(),
|
|
252
|
-
artist: Type.Optional(nonempty()),
|
|
253
|
-
source: Type.Optional(nonempty()),
|
|
254
|
-
imageUrl: Type.Optional(Type.String({ pattern: "^https://" })),
|
|
255
|
-
status: Type.Optional(Type.Union([Type.Literal("playing"), Type.Literal("paused")]))
|
|
256
|
-
}),
|
|
257
|
-
closed({
|
|
258
|
-
type: Type.Literal("event"),
|
|
259
|
-
title: nonempty(),
|
|
260
|
-
date: nonempty(),
|
|
261
|
-
time: Type.Optional(nonempty()),
|
|
262
|
-
location: Type.Optional(nonempty()),
|
|
263
|
-
description: Type.Optional(nonempty())
|
|
264
|
-
}),
|
|
265
|
-
closed({
|
|
266
|
-
type: Type.Literal("agenda"),
|
|
267
|
-
title: nonempty(),
|
|
268
|
-
events: Type.Array(closed({
|
|
269
|
-
title: nonempty(),
|
|
270
|
-
time: Type.Optional(nonempty()),
|
|
271
|
-
location: Type.Optional(nonempty())
|
|
272
|
-
}), {
|
|
273
|
-
minItems: 1,
|
|
274
|
-
maxItems: 6
|
|
275
|
-
})
|
|
276
|
-
}),
|
|
277
|
-
closed({
|
|
278
|
-
type: Type.Literal("device"),
|
|
279
|
-
name: nonempty(),
|
|
280
|
-
deviceType: Type.Optional(nonempty()),
|
|
281
|
-
status: Type.Optional(nonempty()),
|
|
282
|
-
controls: Type.Optional(Type.Array(closed({
|
|
283
|
-
label: nonempty(),
|
|
284
|
-
action: nonempty()
|
|
285
|
-
}), { maxItems: 6 }))
|
|
286
|
-
}),
|
|
287
|
-
closed({
|
|
288
|
-
type: Type.Literal("appletv_remote"),
|
|
289
|
-
name: Type.Optional(nonempty()),
|
|
290
|
-
status: Type.Optional(nonempty())
|
|
291
|
-
})
|
|
292
|
-
]);
|
|
293
|
-
const lineChannelDataSchema = Type.Optional(closed({ line: closed({
|
|
294
|
-
location: Type.Optional(closed({
|
|
295
|
-
title: nonempty(),
|
|
296
|
-
address: nonempty(),
|
|
297
|
-
latitude: Type.Number({
|
|
298
|
-
minimum: -90,
|
|
299
|
-
maximum: 90
|
|
300
|
-
}),
|
|
301
|
-
longitude: Type.Number({
|
|
302
|
-
minimum: -180,
|
|
303
|
-
maximum: 180
|
|
304
|
-
})
|
|
305
|
-
})),
|
|
306
|
-
card: Type.Optional(lineCardSchema),
|
|
307
|
-
mediaKind: Type.Optional(Type.Union([
|
|
308
|
-
Type.Literal("image"),
|
|
309
|
-
Type.Literal("video"),
|
|
310
|
-
Type.Literal("audio")
|
|
311
|
-
])),
|
|
312
|
-
previewImageUrl: Type.Optional(Type.String({ pattern: "^https://" })),
|
|
313
|
-
durationMs: Type.Optional(Type.Integer({ minimum: 1 })),
|
|
314
|
-
trackingId: Type.Optional(nonempty())
|
|
315
|
-
}) }));
|
|
316
|
-
const lineMessageActions = {
|
|
317
|
-
describeMessageTool: ({ cfg, accountId }) => {
|
|
318
|
-
const account = resolveLineAccount({
|
|
319
|
-
cfg,
|
|
320
|
-
accountId: accountId ?? void 0
|
|
321
|
-
});
|
|
322
|
-
return account.enabled && hasLineCredentials(account) ? {
|
|
323
|
-
actions: ["send"],
|
|
324
|
-
capabilities: ["presentation"],
|
|
325
|
-
schema: {
|
|
326
|
-
actions: ["send"],
|
|
327
|
-
properties: { channelData: lineChannelDataSchema }
|
|
328
|
-
}
|
|
329
|
-
} : {
|
|
330
|
-
actions: [],
|
|
331
|
-
capabilities: [],
|
|
332
|
-
schema: null
|
|
333
|
-
};
|
|
334
|
-
},
|
|
335
|
-
prepareSendPayload: ({ payload }) => payload
|
|
336
|
-
};
|
|
337
|
-
const LINE_PRESENTATION_CAPABILITIES = {
|
|
338
|
-
supported: true,
|
|
339
|
-
buttons: true,
|
|
340
|
-
selects: true,
|
|
341
|
-
context: true,
|
|
342
|
-
limits: {
|
|
343
|
-
actions: {
|
|
344
|
-
maxActions: 4,
|
|
345
|
-
maxActionsPerRow: 1,
|
|
346
|
-
maxRows: 4,
|
|
347
|
-
maxLabelLength: 40
|
|
348
|
-
},
|
|
349
|
-
selects: {
|
|
350
|
-
maxOptions: 13,
|
|
351
|
-
maxLabelLength: 20,
|
|
352
|
-
maxValueBytes: 300
|
|
353
|
-
},
|
|
354
|
-
text: { markdownDialect: "plain" }
|
|
355
|
-
}
|
|
356
|
-
};
|
|
357
|
-
function toLineAction(button) {
|
|
358
|
-
const normalized = resolveMessagePresentationButtonAction(button);
|
|
359
|
-
const { label } = button;
|
|
360
|
-
if (normalized?.type === "command") return {
|
|
361
|
-
type: "message",
|
|
362
|
-
label,
|
|
363
|
-
text: normalized.command
|
|
364
|
-
};
|
|
365
|
-
if (normalized?.type === "callback") return {
|
|
366
|
-
type: "postback",
|
|
367
|
-
label,
|
|
368
|
-
data: normalized.value,
|
|
369
|
-
displayText: label
|
|
370
|
-
};
|
|
371
|
-
if (normalized?.type === "url") return {
|
|
372
|
-
type: "uri",
|
|
373
|
-
label,
|
|
374
|
-
uri: normalized.url
|
|
375
|
-
};
|
|
376
|
-
if (normalized?.type === "web-app" && normalized.url) return {
|
|
377
|
-
type: "uri",
|
|
378
|
-
label,
|
|
379
|
-
uri: normalized.url
|
|
380
|
-
};
|
|
381
|
-
}
|
|
382
|
-
function renderLinePresentation(payload, presentation) {
|
|
383
|
-
const buttons = presentation.blocks.flatMap((block) => block.type === "buttons" ? block.buttons : []);
|
|
384
|
-
const buttonActions = buttons.map(toLineAction);
|
|
385
|
-
const options = presentation.blocks.flatMap((block) => block.type === "select" ? block.options : []);
|
|
386
|
-
const quickReplyItems = options.flatMap((option) => {
|
|
387
|
-
const action = resolveMessagePresentationOptionAction(option);
|
|
388
|
-
return action?.type === "command" || action?.type === "callback" ? [{
|
|
389
|
-
label: option.label,
|
|
390
|
-
action
|
|
391
|
-
}] : [];
|
|
392
|
-
});
|
|
393
|
-
if (buttons.length > 0 && buttonActions.some((action) => !action) || quickReplyItems.length !== options.length || buttons.length === 0 && options.length === 0) return null;
|
|
394
|
-
const lineData = isRecord(payload.channelData?.line) ? payload.channelData.line : {};
|
|
395
|
-
const text = presentation.blocks.flatMap((block) => block.type === "text" || block.type === "context" ? [block.text] : []).join("\n");
|
|
396
|
-
const title = presentation.title || "Choose an option";
|
|
397
|
-
const flexMessage = buttonActions.length > 0 ? {
|
|
398
|
-
altText: title,
|
|
399
|
-
contents: createActionCard(title, text || "Choose an option.", buttons.map((button, index) => ({
|
|
400
|
-
label: button.label,
|
|
401
|
-
action: buttonActions[index]
|
|
402
|
-
})))
|
|
403
|
-
} : void 0;
|
|
404
|
-
return {
|
|
405
|
-
...payload,
|
|
406
|
-
channelData: {
|
|
407
|
-
...payload.channelData,
|
|
408
|
-
line: {
|
|
409
|
-
...lineData,
|
|
410
|
-
...flexMessage ? { flexMessage } : {},
|
|
411
|
-
quickReplyItems
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
};
|
|
415
|
-
}
|
|
416
|
-
const toSlug = (value) => normalizeLowercaseStringOrEmpty(value).replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "") || "device";
|
|
417
|
-
const lineActionData = (action, device) => `line.action=${encodeURIComponent(action)}&line.device=${encodeURIComponent(device)}`;
|
|
418
|
-
function renderLineCard(card) {
|
|
419
|
-
if (card.type === "media_player") {
|
|
420
|
-
const device = toSlug(card.source || card.title);
|
|
421
|
-
return {
|
|
422
|
-
altText: `🎵 ${card.title}${card.artist ? ` - ${card.artist}` : ""}`,
|
|
423
|
-
contents: createMediaPlayerCard({
|
|
424
|
-
title: card.title,
|
|
425
|
-
subtitle: card.artist,
|
|
426
|
-
source: card.source,
|
|
427
|
-
imageUrl: card.imageUrl,
|
|
428
|
-
isPlaying: card.status ? card.status === "playing" : void 0,
|
|
429
|
-
controls: Object.fromEntries([
|
|
430
|
-
"previous",
|
|
431
|
-
"play",
|
|
432
|
-
"pause",
|
|
433
|
-
"next"
|
|
434
|
-
].map((action) => [action, { data: lineActionData(action, device) }]))
|
|
435
|
-
})
|
|
436
|
-
};
|
|
437
|
-
}
|
|
438
|
-
if (card.type === "event") return {
|
|
439
|
-
altText: `📅 ${card.title} - ${card.date}${card.time ? ` ${card.time}` : ""}`,
|
|
440
|
-
contents: createEventCard(card)
|
|
441
|
-
};
|
|
442
|
-
if (card.type === "agenda") return {
|
|
443
|
-
altText: `📋 ${card.title} (${card.events.length} events)`,
|
|
444
|
-
contents: createAgendaCard(card)
|
|
445
|
-
};
|
|
446
|
-
const device = toSlug(card.type === "device" ? card.name : card.name || "apple_tv");
|
|
447
|
-
if (card.type === "device") return {
|
|
448
|
-
altText: `📱 ${card.name}${card.status ? `: ${card.status}` : ""}`,
|
|
449
|
-
contents: createDeviceControlCard({
|
|
450
|
-
deviceName: card.name,
|
|
451
|
-
deviceType: card.deviceType,
|
|
452
|
-
status: card.status,
|
|
453
|
-
controls: (card.controls ?? []).map((control) => ({
|
|
454
|
-
label: control.label,
|
|
455
|
-
data: lineActionData(control.action, device)
|
|
456
|
-
}))
|
|
457
|
-
})
|
|
458
|
-
};
|
|
459
|
-
const actionData = {
|
|
460
|
-
up: lineActionData("up", device),
|
|
461
|
-
down: lineActionData("down", device),
|
|
462
|
-
left: lineActionData("left", device),
|
|
463
|
-
right: lineActionData("right", device),
|
|
464
|
-
select: lineActionData("select", device),
|
|
465
|
-
menu: lineActionData("menu", device),
|
|
466
|
-
home: lineActionData("home", device),
|
|
467
|
-
play: lineActionData("play", device),
|
|
468
|
-
pause: lineActionData("pause", device),
|
|
469
|
-
volumeUp: lineActionData("volume_up", device),
|
|
470
|
-
volumeDown: lineActionData("volume_down", device),
|
|
471
|
-
mute: lineActionData("mute", device)
|
|
472
|
-
};
|
|
473
|
-
return {
|
|
474
|
-
altText: `📺 ${card.name || "Apple TV"} Remote`,
|
|
475
|
-
contents: createAppleTvRemoteCard({
|
|
476
|
-
deviceName: card.name || "Apple TV",
|
|
477
|
-
status: card.status,
|
|
478
|
-
actionData
|
|
479
|
-
})
|
|
480
|
-
};
|
|
481
|
-
}
|
|
482
|
-
function createLineQuickReply(items) {
|
|
483
|
-
return { items: items.slice(0, 13).map((item) => ({
|
|
484
|
-
type: "action",
|
|
485
|
-
action: item.action.type === "command" ? messageAction(item.label, item.action.command) : postbackAction(item.label, item.action.value, item.label)
|
|
486
|
-
})) };
|
|
487
|
-
}
|
|
488
|
-
//#endregion
|
|
489
213
|
//#region extensions/line/src/outbound.ts
|
|
490
|
-
const loadLineOutboundRuntime = createLazyRuntimeModule(() => import("./outbound.runtime-
|
|
214
|
+
const loadLineOutboundRuntime = createLazyRuntimeModule(() => import("./outbound.runtime-CGqyJ-Ug.js"));
|
|
491
215
|
const lineOutboundAdapter = {
|
|
492
216
|
deliveryMode: "direct",
|
|
493
217
|
chunker: (text, limit) => getLineRuntime().channel.text.chunkMarkdownText(text, limit),
|
|
@@ -513,9 +237,27 @@ const lineOutboundAdapter = {
|
|
|
513
237
|
const sendLocation = lineRuntime?.pushLocationMessage ?? outboundRuntime.pushLocationMessage;
|
|
514
238
|
const sendQuickReplies = lineRuntime?.pushTextMessageWithQuickReplies ?? outboundRuntime.pushTextMessageWithQuickReplies;
|
|
515
239
|
const buildTemplate = lineRuntime?.buildTemplateMessageFromPayload ?? outboundRuntime.buildTemplateMessageFromPayload;
|
|
240
|
+
const sendOptions = {
|
|
241
|
+
verbose: false,
|
|
242
|
+
cfg,
|
|
243
|
+
accountId: accountId ?? void 0
|
|
244
|
+
};
|
|
516
245
|
let lastResult = null;
|
|
517
246
|
const recordResult = async (resultPromise) => {
|
|
518
|
-
|
|
247
|
+
let result;
|
|
248
|
+
try {
|
|
249
|
+
result = await resultPromise;
|
|
250
|
+
} catch (error) {
|
|
251
|
+
const refusal = lastResult !== null || isChannelPartialDeliveryError(error) ? void 0 : await explainLineRefusal({
|
|
252
|
+
error,
|
|
253
|
+
cfg,
|
|
254
|
+
accountId
|
|
255
|
+
});
|
|
256
|
+
throw refusal?.retryable !== void 0 ? new PlatformMessageNotDispatchedError(refusal.reason, {
|
|
257
|
+
cause: error,
|
|
258
|
+
retryable: refusal.retryable
|
|
259
|
+
}) : error;
|
|
260
|
+
}
|
|
519
261
|
lastResult = result;
|
|
520
262
|
try {
|
|
521
263
|
await onDeliveryResult?.(createEmptyChannelResult("line", { ...result }));
|
|
@@ -537,11 +279,7 @@ const lineOutboundAdapter = {
|
|
|
537
279
|
if (messages.length === 0) return;
|
|
538
280
|
for (let i = 0; i < messages.length; i += 5) {
|
|
539
281
|
const batch = messages.slice(i, i + 5);
|
|
540
|
-
await recordResult(sendBatch(to, batch,
|
|
541
|
-
verbose: false,
|
|
542
|
-
cfg,
|
|
543
|
-
accountId: accountId ?? void 0
|
|
544
|
-
}));
|
|
282
|
+
await recordResult(sendBatch(to, batch, sendOptions));
|
|
545
283
|
}
|
|
546
284
|
};
|
|
547
285
|
const sendTextWithQuickReply = async (text) => {
|
|
@@ -553,11 +291,7 @@ const lineOutboundAdapter = {
|
|
|
553
291
|
}]);
|
|
554
292
|
return;
|
|
555
293
|
}
|
|
556
|
-
await recordResult(sendQuickReplies(to, text, quickReplies,
|
|
557
|
-
verbose: false,
|
|
558
|
-
cfg,
|
|
559
|
-
accountId: accountId ?? void 0
|
|
560
|
-
}));
|
|
294
|
+
await recordResult(sendQuickReplies(to, text, quickReplies, sendOptions));
|
|
561
295
|
};
|
|
562
296
|
const processed = payload.text ? outboundRuntime.processLineMessage(payload.text) : {
|
|
563
297
|
text: "",
|
|
@@ -570,9 +304,8 @@ const lineOutboundAdapter = {
|
|
|
570
304
|
})));
|
|
571
305
|
const chunks = orderedMessages ? orderedMessages.flatMap((message) => message.type === "text" ? [message.text] : []) : processed.text ? runtime.channel.text.chunkMarkdownText(processed.text, chunkLimit) : [];
|
|
572
306
|
const mediaUrls = resolveOutboundMediaUrls(payload);
|
|
573
|
-
const useLineSpecificMedia = hasLineSpecificMediaOptions(lineData);
|
|
574
307
|
const mediaOptions = {
|
|
575
|
-
mediaKind:
|
|
308
|
+
mediaKind: lineData.mediaKind,
|
|
576
309
|
previewImageUrl: lineData.previewImageUrl,
|
|
577
310
|
durationMs: lineData.durationMs,
|
|
578
311
|
trackingId: lineData.trackingId
|
|
@@ -582,82 +315,40 @@ const lineOutboundAdapter = {
|
|
|
582
315
|
for (const url of mediaUrls) {
|
|
583
316
|
const trimmed = url?.trim();
|
|
584
317
|
if (!trimmed) continue;
|
|
585
|
-
if (!useLineSpecificMedia) {
|
|
586
|
-
await recordResult((lineRuntime?.sendMessageLine ?? outboundRuntime.sendMessageLine)(to, "", {
|
|
587
|
-
verbose: false,
|
|
588
|
-
mediaUrl: trimmed,
|
|
589
|
-
cfg,
|
|
590
|
-
accountId: accountId ?? void 0
|
|
591
|
-
}));
|
|
592
|
-
continue;
|
|
593
|
-
}
|
|
594
|
-
const resolved = await resolveLineOutboundMedia(trimmed, mediaOptions);
|
|
595
318
|
await recordResult((lineRuntime?.sendMessageLine ?? outboundRuntime.sendMessageLine)(to, "", {
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
previewImageUrl: resolved.previewImageUrl,
|
|
600
|
-
durationMs: resolved.durationMs,
|
|
601
|
-
trackingId: resolved.trackingId,
|
|
602
|
-
cfg,
|
|
603
|
-
accountId: accountId ?? void 0
|
|
319
|
+
...sendOptions,
|
|
320
|
+
...mediaOptions,
|
|
321
|
+
mediaUrl: trimmed
|
|
604
322
|
}));
|
|
605
323
|
}
|
|
606
324
|
};
|
|
607
325
|
if (!shouldSendQuickRepliesInline) {
|
|
608
326
|
if (lineData.flexMessage) {
|
|
609
327
|
const flexContents = lineData.flexMessage.contents;
|
|
610
|
-
await recordResult(sendFlex(to, lineData.flexMessage.altText, flexContents,
|
|
611
|
-
verbose: false,
|
|
612
|
-
cfg,
|
|
613
|
-
accountId: accountId ?? void 0
|
|
614
|
-
}));
|
|
328
|
+
await recordResult(sendFlex(to, lineData.flexMessage.altText, flexContents, sendOptions));
|
|
615
329
|
}
|
|
616
330
|
if (lineData.templateMessage) {
|
|
617
331
|
const template = buildTemplate(lineData.templateMessage);
|
|
618
|
-
if (template) await recordResult(sendTemplate(to, template,
|
|
619
|
-
verbose: false,
|
|
620
|
-
cfg,
|
|
621
|
-
accountId: accountId ?? void 0
|
|
622
|
-
}));
|
|
332
|
+
if (template) await recordResult(sendTemplate(to, template, sendOptions));
|
|
623
333
|
}
|
|
624
|
-
if (location) await recordResult(sendLocation(to, location,
|
|
625
|
-
|
|
626
|
-
cfg,
|
|
627
|
-
accountId: accountId ?? void 0
|
|
628
|
-
}));
|
|
629
|
-
if (!orderedMessages) for (const flexMsg of processed.flexMessages) await recordResult(sendFlex(to, flexMsg.altText, flexMsg.contents, {
|
|
630
|
-
verbose: false,
|
|
631
|
-
cfg,
|
|
632
|
-
accountId: accountId ?? void 0
|
|
633
|
-
}));
|
|
334
|
+
if (location) await recordResult(sendLocation(to, location, sendOptions));
|
|
335
|
+
if (!orderedMessages) for (const flexMsg of processed.flexMessages) await recordResult(sendFlex(to, flexMsg.altText, flexMsg.contents, sendOptions));
|
|
634
336
|
}
|
|
635
337
|
const sendMediaAfterText = !(hasQuickReplies && chunks.length > 0);
|
|
636
338
|
if (mediaUrls.length > 0 && !shouldSendQuickRepliesInline && !sendMediaAfterText) await sendMediaMessages();
|
|
637
339
|
if (orderedMessages && !shouldSendQuickRepliesInline) for (const [index, message] of orderedMessages.entries()) {
|
|
638
340
|
const isLast = index === orderedMessages.length - 1;
|
|
639
|
-
if (message.type === "flex")
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
}));
|
|
648
|
-
else if (isLast && hasQuickReplies) await sendTextWithQuickReply(message.text);
|
|
649
|
-
else await recordResult(sendText(to, message.text, {
|
|
650
|
-
verbose: false,
|
|
651
|
-
cfg,
|
|
652
|
-
accountId: accountId ?? void 0
|
|
653
|
-
}));
|
|
341
|
+
if (message.type === "flex") {
|
|
342
|
+
if (isLast && quickReply) await sendMessageBatch([{
|
|
343
|
+
...message,
|
|
344
|
+
quickReply
|
|
345
|
+
}]);
|
|
346
|
+
else await recordResult(sendFlex(to, message.altText, message.contents, sendOptions));
|
|
347
|
+
} else if (isLast && hasQuickReplies) await sendTextWithQuickReply(message.text);
|
|
348
|
+
else await recordResult(sendText(to, message.text, sendOptions));
|
|
654
349
|
}
|
|
655
350
|
else if (chunks.length > 0) for (const [i, chunk] of chunks.entries()) if (i === chunks.length - 1 && hasQuickReplies) await sendTextWithQuickReply(chunk);
|
|
656
|
-
else await recordResult(sendText(to, chunk,
|
|
657
|
-
verbose: false,
|
|
658
|
-
cfg,
|
|
659
|
-
accountId: accountId ?? void 0
|
|
660
|
-
}));
|
|
351
|
+
else await recordResult(sendText(to, chunk, sendOptions));
|
|
661
352
|
else if (shouldSendQuickRepliesInline) {
|
|
662
353
|
const quickReplyMessages = [];
|
|
663
354
|
if (lineData.flexMessage) quickReplyMessages.push(outboundRuntime.createFlexMessage(lineData.flexMessage.altText, lineData.flexMessage.contents));
|
|
@@ -757,7 +448,7 @@ const lineMessageAdapter = defineChannelMessageAdapter({
|
|
|
757
448
|
});
|
|
758
449
|
//#endregion
|
|
759
450
|
//#region extensions/line/src/status.ts
|
|
760
|
-
const loadLineProbeRuntime = createLazyRuntimeModule(() => import("./probe.runtime-
|
|
451
|
+
const loadLineProbeRuntime = createLazyRuntimeModule(() => import("./probe.runtime-CbtMgU4s.js"));
|
|
761
452
|
const collectLineStatusIssues = createDependentCredentialStatusIssueCollector({
|
|
762
453
|
channel: "line",
|
|
763
454
|
dependencySourceKey: "tokenSource",
|
|
@@ -769,7 +460,7 @@ const lineStatusAdapter = createComputedAccountStatusAdapter({
|
|
|
769
460
|
collectStatusIssues: collectLineStatusIssues,
|
|
770
461
|
buildChannelSummary: ({ snapshot }) => buildTokenChannelStatusSummary(snapshot),
|
|
771
462
|
probeAccount: async ({ account, timeoutMs }) => await (await loadLineProbeRuntime()).probeLineBot(account.channelAccessToken, timeoutMs),
|
|
772
|
-
resolveAccountSnapshot: ({ account }) => ({
|
|
463
|
+
resolveAccountSnapshot: ({ account, probe }) => ({
|
|
773
464
|
accountId: account.accountId,
|
|
774
465
|
name: account.name,
|
|
775
466
|
enabled: account.enabled,
|
|
@@ -779,13 +470,14 @@ const lineStatusAdapter = createComputedAccountStatusAdapter({
|
|
|
779
470
|
signingSecretSource: account.signingSecretSource,
|
|
780
471
|
tokenStatus: account.tokenStatus,
|
|
781
472
|
signingSecretStatus: account.signingSecretStatus,
|
|
782
|
-
mode: "webhook"
|
|
473
|
+
mode: "webhook",
|
|
474
|
+
...probe?.quota ? { quota: probe.quota } : {}
|
|
783
475
|
}
|
|
784
476
|
})
|
|
785
477
|
});
|
|
786
478
|
//#endregion
|
|
787
479
|
//#region extensions/line/src/channel.ts
|
|
788
|
-
const loadLineChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime-
|
|
480
|
+
const loadLineChannelRuntime = createLazyRuntimeModule(() => import("./channel.runtime-CZOszXXj.js"));
|
|
789
481
|
const lineSecurityAdapter = createRestrictSendersChannelSecurity({
|
|
790
482
|
channelKey: "line",
|
|
791
483
|
resolveDmPolicy: (account) => account.config.dmPolicy,
|
|
@@ -801,6 +493,10 @@ const lineSecurityAdapter = createRestrictSendersChannelSecurity({
|
|
|
801
493
|
approveHint: "openclaw pairing approve line <code>",
|
|
802
494
|
normalizeDmEntry: (raw) => raw.replace(/^line:(?:user:)?/i, "")
|
|
803
495
|
});
|
|
496
|
+
function normalizeLineDirectoryId(entry, kind) {
|
|
497
|
+
const id = normalizeLineMessagingTarget(entry);
|
|
498
|
+
return id && inferLineTargetChatType(id) === kind ? id : null;
|
|
499
|
+
}
|
|
804
500
|
const linePlugin = createChatChannelPlugin({
|
|
805
501
|
base: {
|
|
806
502
|
id: "line",
|
|
@@ -862,21 +558,56 @@ const linePlugin = createChatChannelPlugin({
|
|
|
862
558
|
hint: "<userId|groupId|roomId>"
|
|
863
559
|
}
|
|
864
560
|
},
|
|
865
|
-
directory:
|
|
561
|
+
directory: createChannelDirectoryAdapter({
|
|
562
|
+
listPeers: createResolvedDirectoryEntriesLister({
|
|
563
|
+
kind: "user",
|
|
564
|
+
resolveAccount: (cfg, accountId) => resolveLineAccount({
|
|
565
|
+
cfg,
|
|
566
|
+
accountId: accountId ?? void 0
|
|
567
|
+
}),
|
|
568
|
+
resolveSources: ({ config }) => [
|
|
569
|
+
config.allowFrom ?? [],
|
|
570
|
+
config.groupAllowFrom ?? [],
|
|
571
|
+
...Object.values(config.groups ?? {}).map((group) => group?.allowFrom ?? [])
|
|
572
|
+
],
|
|
573
|
+
normalizeId: (entry) => normalizeLineDirectoryId(entry, "direct")
|
|
574
|
+
}),
|
|
575
|
+
listGroups: createResolvedDirectoryEntriesLister({
|
|
576
|
+
kind: "group",
|
|
577
|
+
resolveAccount: (cfg, accountId) => resolveLineAccount({
|
|
578
|
+
cfg,
|
|
579
|
+
accountId: accountId ?? void 0
|
|
580
|
+
}),
|
|
581
|
+
resolveSources: ({ config }) => [Object.keys(config.groups ?? {})],
|
|
582
|
+
normalizeId: (entry) => normalizeLineDirectoryId(resolveLineGroupLookupIds(entry)[0] ?? "", "group")
|
|
583
|
+
})
|
|
584
|
+
}),
|
|
866
585
|
setupContract: lineSetupContract,
|
|
867
586
|
status: lineStatusAdapter,
|
|
868
587
|
gateway: lineGatewayAdapter,
|
|
588
|
+
heartbeat: { sendTyping: async ({ cfg, to, accountId }) => {
|
|
589
|
+
const chatId = normalizeLineMessagingTarget(to);
|
|
590
|
+
if (!chatId || inferLineTargetChatType(chatId) !== "direct") return;
|
|
591
|
+
const { showLoadingAnimation } = await loadLineChannelRuntime();
|
|
592
|
+
await showLoadingAnimation(chatId, {
|
|
593
|
+
cfg,
|
|
594
|
+
accountId: accountId ?? void 0
|
|
595
|
+
});
|
|
596
|
+
} },
|
|
869
597
|
message: lineMessageAdapter,
|
|
870
598
|
actions: lineMessageActions,
|
|
871
599
|
bindings: lineBindingsAdapter,
|
|
872
600
|
conversationBindings: { defaultTopLevelPlacement: "current" },
|
|
873
|
-
agentPrompt: {
|
|
874
|
-
"",
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
601
|
+
agentPrompt: {
|
|
602
|
+
messageToolCapabilities: () => ["inlineButtons"],
|
|
603
|
+
messageToolHints: () => [
|
|
604
|
+
"",
|
|
605
|
+
"### LINE structured output",
|
|
606
|
+
"Use `presentation.blocks` for buttons, yes/no choices, and selectable options; LINE maps them to Flex controls or quick replies.",
|
|
607
|
+
"Use `channelData.line.location` for a location pin and `channelData.line.card` for one LINE-specific card. Supported card types are `media_player`, `event`, `agenda`, `device`, and `appletv_remote`.",
|
|
608
|
+
"Send rich output with the structured message fields. Double-bracket marker text has no special meaning."
|
|
609
|
+
]
|
|
610
|
+
}
|
|
880
611
|
},
|
|
881
612
|
pairing: { text: {
|
|
882
613
|
idLabel: "lineUserId",
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as linePlugin } from "./channel-
|
|
1
|
+
import { t as linePlugin } from "./channel-BJvELOIg.js";
|
|
2
2
|
export { linePlugin };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { a as probeLineBot } from "./send-retry-ChpfJ-LM.js";
|
|
2
|
+
import { t as monitorLineProvider } from "./monitor-m9h5osFz.js";
|
|
3
|
+
import { _ as showLoadingAnimation, d as pushMessageLine } from "./send-CQQxpxPp.js";
|
|
4
|
+
export { monitorLineProvider, probeLineBot, pushMessageLine, showLoadingAnimation };
|
package/dist/contract-api.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as resolveLineAccount, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./accounts-
|
|
1
|
+
import { i as resolveLineAccount, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./accounts-BBEFMYbY.js";
|
|
2
2
|
export { listLineAccountIds, resolveDefaultLineAccountId, resolveLineAccount };
|