@openclaw/line 2026.9.6 → 2026.9.7

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.
Files changed (77) hide show
  1. package/assets/icon.png +0 -0
  2. package/dist/.setup/{accounts-BBEFMYbY.mjs → accounts-DOiM8-y3.mjs} +1 -4
  3. package/dist/.setup/api-4RgpQmHW.mjs +3 -0
  4. package/dist/.setup/{api-D_06cuHl.mjs → api-w4QdlCCB.mjs} +2 -2
  5. package/dist/.setup/{card-command-710u8FBH.mjs → card-command-DYf4gnmI.mjs} +25 -33
  6. package/dist/.setup/{channel-kc3VRglA.mjs → channel-DN6Za8Vm.mjs} +789 -26
  7. package/dist/.setup/channel.runtime-bd5vGeSo.mjs +4 -0
  8. package/dist/.setup/{monitor-morJPcPd.mjs → monitor-C01hAm3f.mjs} +262 -333
  9. package/dist/.setup/monitor.runtime-DwH2zK48.mjs +2 -0
  10. package/dist/.setup/outbound.runtime-D_Gs99Dm.mjs +3 -0
  11. package/dist/.setup/probe.runtime-Cj08-BZ1.mjs +2 -0
  12. package/dist/.setup/runtime-V7yh9OeC.mjs +8 -0
  13. package/dist/.setup/{send-BmsHY4WC.mjs → send-DOY1WTxv.mjs} +7 -26
  14. package/dist/.setup/{send-retry-DbfiHBPd.mjs → send-retry-DV6I0muq.mjs} +104 -208
  15. package/dist/.setup/{setup-surface-CcfKJKtr.mjs → setup-surface-CbfkmkIS.mjs} +15 -4
  16. package/dist/.setup/{markdown-to-line-CRfEHFs0.mjs → template-messages-CxCnYsWN.mjs} +168 -189
  17. package/dist/api.js +2 -2
  18. package/dist/channel-plugin-api.js +1 -1
  19. package/dist/contract-api.js +1 -1
  20. package/dist/index.js +1 -1
  21. package/dist/runtime-api.js +2 -260
  22. package/dist/setup-api.js +1 -1
  23. package/dist/setup-entry.js +1 -1
  24. package/node_modules/@line/bot-sdk/node_modules/@types/node/README.md +1 -1
  25. package/node_modules/@line/bot-sdk/node_modules/@types/node/child_process.d.ts +1 -1
  26. package/node_modules/@line/bot-sdk/node_modules/@types/node/package.json +2 -2
  27. package/node_modules/typebox/build/compile/code.mjs +1 -2
  28. package/node_modules/typebox/build/compile/validator.mjs +5 -1
  29. package/node_modules/typebox/build/format/iri.mjs +16 -9
  30. package/node_modules/typebox/build/guard/emit.mjs +2 -2
  31. package/node_modules/typebox/build/guard/guard.d.mts +7 -5
  32. package/node_modules/typebox/build/guard/guard.mjs +14 -9
  33. package/node_modules/typebox/build/guard/index.mjs +6 -0
  34. package/node_modules/typebox/build/guard/unicode/unicode.d.mts +6 -0
  35. package/node_modules/typebox/build/guard/unicode/unicode.mjs +35 -0
  36. package/node_modules/typebox/build/guard/{string.mjs → unicode/unicode_segment.mjs} +16 -19
  37. package/node_modules/typebox/build/schema/build.mjs +2 -3
  38. package/node_modules/typebox/build/schema/engine/_pathing.d.mts +1 -0
  39. package/node_modules/typebox/build/schema/engine/_pathing.mjs +11 -0
  40. package/node_modules/typebox/build/schema/engine/_refine.mjs +13 -5
  41. package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +2 -1
  42. package/node_modules/typebox/build/schema/engine/dependencies.mjs +2 -1
  43. package/node_modules/typebox/build/schema/engine/dependentSchemas.mjs +2 -1
  44. package/node_modules/typebox/build/schema/engine/dynamicRef.d.mts +1 -1
  45. package/node_modules/typebox/build/schema/engine/dynamicRef.mjs +2 -2
  46. package/node_modules/typebox/build/schema/engine/format.mjs +9 -2
  47. package/node_modules/typebox/build/schema/engine/patternProperties.mjs +3 -2
  48. package/node_modules/typebox/build/schema/engine/properties.mjs +3 -2
  49. package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -1
  50. package/node_modules/typebox/build/schema/engine/recursiveRef.d.mts +1 -1
  51. package/node_modules/typebox/build/schema/engine/recursiveRef.mjs +2 -2
  52. package/node_modules/typebox/build/schema/engine/ref.d.mts +1 -1
  53. package/node_modules/typebox/build/schema/engine/ref.mjs +2 -2
  54. package/node_modules/typebox/build/schema/engine/schema.mjs +24 -24
  55. package/node_modules/typebox/build/schema/parse.mjs +3 -0
  56. package/node_modules/typebox/build/schema/pointer/pointer.d.mts +1 -6
  57. package/node_modules/typebox/build/schema/pointer/pointer.mjs +47 -64
  58. package/node_modules/typebox/build/system/settings/internal.d.mts +2 -0
  59. package/node_modules/typebox/build/system/settings/internal.mjs +20 -0
  60. package/node_modules/typebox/build/system/settings/settings.d.mts +11 -0
  61. package/node_modules/typebox/build/system/settings/settings.mjs +14 -0
  62. package/node_modules/typebox/build/type/extends/inference.d.mts +1 -1
  63. package/node_modules/typebox/build/type/extends/inference.mjs +15 -2
  64. package/node_modules/typebox/build/type/extends/tuple.d.mts +2 -1
  65. package/node_modules/typebox/build/type/extends/tuple.mjs +21 -1
  66. package/node_modules/typebox/build/value/parse/parse.mjs +10 -4
  67. package/node_modules/typebox/package.json +1 -1
  68. package/node_modules/typebox/readme.md +3 -1
  69. package/package.json +5 -5
  70. package/dist/.setup/account-helpers-BSUyZwLm.mjs +0 -12
  71. package/dist/.setup/api-RdEuQgW-.mjs +0 -3
  72. package/dist/.setup/channel.runtime-BtkeDELb.mjs +0 -4
  73. package/dist/.setup/monitor.runtime-BGhxYDKG.mjs +0 -2
  74. package/dist/.setup/outbound.runtime-QGvZy8Em.mjs +0 -3
  75. package/dist/.setup/probe.runtime-CMf8b-jB.mjs +0 -2
  76. package/dist/.setup/rich-messages-d8CmBVJj.mjs +0 -872
  77. /package/node_modules/typebox/build/guard/{string.d.mts → unicode/unicode_segment.d.mts} +0 -0
@@ -1,183 +1,5 @@
1
- import { C as toFlexMessage, S as fitsLineFlexBubble, _ as normalizeLineAction, g as messageAction, u as createReceiptCard, x as uriAction, y as postbackAction } from "./send-retry-DbfiHBPd.mjs";
2
- import { markdownToIRWithMeta, stripMarkdown, stripMarkdown as stripMarkdown$1 } from "openclaw/plugin-sdk/text-chunking";
3
- import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
4
- //#region extensions/line/src/template-messages.ts
5
- const COMPACT_TEMPLATE_TEXT_LIMIT = 60;
6
- const TEMPLATE_ALT_TEXT_LIMIT = 1500;
7
- const graphemeSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
8
- function buildTemplatePayloadAction(action) {
9
- if (action.type === "uri" && action.uri) return uriAction(action.label, action.uri);
10
- if (action.type === "postback" && action.data) return postbackAction(action.label, action.data, action.label);
11
- return messageAction(action.label, action.data ?? action.label);
12
- }
13
- function resolveTemplateTextLimit(params) {
14
- return params.title !== void 0 || params.thumbnailImageUrl !== void 0 ? COMPACT_TEMPLATE_TEXT_LIMIT : params.textOnlyLimit;
15
- }
16
- function truncateTemplateText(text, limit) {
17
- let result = "";
18
- for (const { segment } of graphemeSegmenter.segment(text)) {
19
- if (result.length + segment.length > limit) {
20
- if (!result) for (const codePoint of segment) {
21
- if (result.length + codePoint.length > limit) break;
22
- result += codePoint;
23
- }
24
- break;
25
- }
26
- result += segment;
27
- }
28
- return result;
29
- }
30
- function truncateOptionalTemplateText(value, limit) {
31
- return value === void 0 ? void 0 : truncateTemplateText(value, limit);
32
- }
33
- function resolveTemplateAltText(value, fallback) {
34
- return truncateTemplateText(value ?? fallback, TEMPLATE_ALT_TEXT_LIMIT);
35
- }
36
- function normalizeCarouselColumn(column) {
37
- return {
38
- ...column,
39
- title: column.title || void 0,
40
- actions: column.actions.map((action) => normalizeLineAction(action)).filter((action) => action.label !== void 0 && action.label !== "").slice(0, 3),
41
- defaultAction: column.defaultAction === void 0 ? void 0 : normalizeLineAction(column.defaultAction)
42
- };
43
- }
44
- function describeCarouselColumn(column) {
45
- const body = column.title ? `${column.title}: ${column.text}` : column.text;
46
- const labels = column.actions.map((action) => action.label).filter((label) => label !== void 0 && label !== "");
47
- return labels.length > 0 ? `${body} (${labels.join(" / ")})` : body;
48
- }
49
- function normalizeCarousel(columns, altText) {
50
- const normalized = columns.slice(0, 10).map(normalizeCarouselColumn);
51
- const first = normalized[0];
52
- if (!(!first || normalized.some((column) => column.text === "" || column.actions.length === 0 || column.title === void 0 !== (first.title === void 0) || column.actions.length !== first.actions.length))) return {
53
- kind: "template",
54
- columns: normalized
55
- };
56
- const text = [...altText ? [truncateTemplateText(altText, TEMPLATE_ALT_TEXT_LIMIT)] : [], ...normalized.map(describeCarouselColumn).filter((line) => line !== "")].join("\n");
57
- return text ? {
58
- kind: "text",
59
- text
60
- } : { kind: "empty" };
61
- }
62
- function createCarouselMessage(columns, options) {
63
- const template = {
64
- type: "carousel",
65
- columns,
66
- imageAspectRatio: options?.imageAspectRatio ?? "rectangle",
67
- imageSize: options?.imageSize ?? "cover"
68
- };
69
- return {
70
- type: "template",
71
- altText: resolveTemplateAltText(options?.altText, "View carousel"),
72
- template
73
- };
74
- }
75
- /**
76
- * Create a confirm template (yes/no style dialog)
77
- */
78
- function createConfirmTemplate(text, confirmAction, cancelAction, altText) {
79
- const template = {
80
- type: "confirm",
81
- text: truncateTemplateText(text, 240),
82
- actions: [normalizeLineAction(confirmAction), normalizeLineAction(cancelAction)]
83
- };
84
- return {
85
- type: "template",
86
- altText: resolveTemplateAltText(altText, text),
87
- template
88
- };
89
- }
90
- /**
91
- * Create a button template with title, text, and action buttons
92
- */
93
- function createButtonTemplate(title, text, actions, options) {
94
- const normalizedTitle = title || void 0;
95
- const textLimit = resolveTemplateTextLimit({
96
- title: normalizedTitle,
97
- thumbnailImageUrl: options?.thumbnailImageUrl,
98
- textOnlyLimit: 160
99
- });
100
- const template = {
101
- type: "buttons",
102
- ...normalizedTitle ? { title: truncateTemplateText(normalizedTitle, 40) } : {},
103
- text: truncateTemplateText(text, textLimit),
104
- actions: actions.slice(0, 4).map((action) => normalizeLineAction(action)),
105
- thumbnailImageUrl: options?.thumbnailImageUrl,
106
- imageAspectRatio: options?.imageAspectRatio ?? "rectangle",
107
- imageSize: options?.imageSize ?? "cover",
108
- imageBackgroundColor: options?.imageBackgroundColor,
109
- defaultAction: options?.defaultAction === void 0 ? void 0 : normalizeLineAction(options.defaultAction)
110
- };
111
- return {
112
- type: "template",
113
- altText: resolveTemplateAltText(options?.altText, normalizedTitle ? `${normalizedTitle}: ${text}` : text),
114
- template
115
- };
116
- }
117
- /**
118
- * Create a carousel template with multiple columns
119
- */
120
- function createTemplateCarousel(columns, options) {
121
- const outcome = normalizeCarousel(columns, options?.altText);
122
- if (outcome.kind !== "template") throw new Error(outcome.kind === "empty" ? "LINE carousel has no deliverable text or action labels." : "LINE carousel columns violate provider consistency requirements.");
123
- return createCarouselMessage(outcome.columns, options);
124
- }
125
- /**
126
- * Create a carousel column for use with createTemplateCarousel
127
- */
128
- function createCarouselColumn(params) {
129
- const normalizedTitle = params.title || void 0;
130
- const textLimit = resolveTemplateTextLimit({
131
- ...params,
132
- title: normalizedTitle,
133
- textOnlyLimit: 120
134
- });
135
- return {
136
- title: truncateOptionalTemplateText(normalizedTitle, 40),
137
- text: truncateTemplateText(params.text, textLimit),
138
- actions: params.actions.map((action) => normalizeLineAction(action)).filter((action) => action.label !== void 0 && action.label !== "").slice(0, 3),
139
- thumbnailImageUrl: params.thumbnailImageUrl,
140
- imageBackgroundColor: params.imageBackgroundColor,
141
- defaultAction: params.defaultAction === void 0 ? void 0 : normalizeLineAction(params.defaultAction)
142
- };
143
- }
144
- /**
145
- * Convert a TemplateMessagePayload from ReplyPayload to a LINE TemplateMessage
146
- */
147
- function buildTemplateMessageFromPayload(payload) {
148
- switch (payload.type) {
149
- case "confirm": {
150
- const confirmAction = payload.confirmData.startsWith("http") ? uriAction(payload.confirmLabel, payload.confirmData) : payload.confirmData.includes("=") ? postbackAction(payload.confirmLabel, payload.confirmData, payload.confirmLabel) : messageAction(payload.confirmLabel, payload.confirmData);
151
- const cancelAction = payload.cancelData.startsWith("http") ? uriAction(payload.cancelLabel, payload.cancelData) : payload.cancelData.includes("=") ? postbackAction(payload.cancelLabel, payload.cancelData, payload.cancelLabel) : messageAction(payload.cancelLabel, payload.cancelData);
152
- return createConfirmTemplate(payload.text, confirmAction, cancelAction, payload.altText);
153
- }
154
- case "buttons": {
155
- const actions = payload.actions.slice(0, 4).map((action) => buildTemplatePayloadAction(action));
156
- return createButtonTemplate(payload.title, payload.text, actions, {
157
- thumbnailImageUrl: payload.thumbnailImageUrl,
158
- altText: payload.altText
159
- });
160
- }
161
- case "carousel": {
162
- const outcome = normalizeCarousel(payload.columns.map((col) => {
163
- const colActions = col.actions.map((action) => buildTemplatePayloadAction(action));
164
- return createCarouselColumn({
165
- title: col.title,
166
- text: col.text,
167
- thumbnailImageUrl: col.thumbnailImageUrl,
168
- actions: colActions
169
- });
170
- }), payload.altText);
171
- if (outcome.kind === "empty") return null;
172
- return outcome.kind === "text" ? {
173
- type: "text",
174
- text: outcome.text
175
- } : createCarouselMessage(outcome.columns, { altText: payload.altText });
176
- }
177
- default: return null;
178
- }
179
- }
180
- //#endregion
1
+ import { C as toFlexMessage, S as fitsLineFlexBubble, _ as normalizeLineAction, g as messageAction, u as createReceiptCard, x as uriAction, y as postbackAction } from "./send-retry-DV6I0muq.mjs";
2
+ import { markdownToIRWithMeta, stripMarkdown } from "openclaw/plugin-sdk/text-chunking";
181
3
  //#region extensions/line/src/markdown-to-line.ts
182
4
  const LINE_MARKDOWN_OPTIONS = {
183
5
  assistantTranscriptRoleHeaders: true,
@@ -450,8 +272,6 @@ function convertTableToFlexBubble(table) {
450
272
  }
451
273
  /** Convert a code block to a LINE Flex Message bubble. */
452
274
  function convertCodeBlockToFlexBubble(block) {
453
- const titleText = block.language ? `Code (${block.language})` : "Code";
454
- const displayCode = block.code.length > LINE_FLEX_CODE_CARD_MAX_CHARS ? `${truncateUtf16Safe(block.code, LINE_FLEX_CODE_CARD_MAX_CHARS)}\n...` : block.code;
455
275
  return {
456
276
  type: "bubble",
457
277
  body: {
@@ -459,7 +279,7 @@ function convertCodeBlockToFlexBubble(block) {
459
279
  layout: "vertical",
460
280
  contents: [{
461
281
  type: "text",
462
- text: titleText,
282
+ text: block.language ? `Code (${block.language})` : "Code",
463
283
  weight: "bold",
464
284
  size: "sm",
465
285
  color: "#666666"
@@ -468,7 +288,7 @@ function convertCodeBlockToFlexBubble(block) {
468
288
  layout: "vertical",
469
289
  contents: [{
470
290
  type: "text",
471
- text: displayCode,
291
+ text: block.code,
472
292
  size: "xs",
473
293
  color: "#333333",
474
294
  wrap: true
@@ -524,10 +344,169 @@ function processLineMessage(text) {
524
344
  ...plainTextInsertions.length > 0 ? { segments } : {}
525
345
  };
526
346
  }
527
- /** Check if text contains markdown that needs conversion. */
528
- function hasMarkdownToConvert(text) {
529
- const { ir, tables } = parseLineMarkdown(text);
530
- return tables.length > 0 || ir.styles.length > 0 || ir.links.length > 0 || /<\/?u>/i.test(ir.text) || ir.text !== text.trimEnd();
347
+ //#endregion
348
+ //#region extensions/line/src/template-messages.ts
349
+ const COMPACT_TEMPLATE_TEXT_LIMIT = 60;
350
+ const TEMPLATE_ALT_TEXT_LIMIT = 1500;
351
+ const graphemeSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
352
+ function buildTemplatePayloadAction(action) {
353
+ if (action.type === "uri" && action.uri) return uriAction(action.label, action.uri);
354
+ if (action.type === "postback" && action.data) return postbackAction(action.label, action.data, action.label);
355
+ return messageAction(action.label, action.data ?? action.label);
356
+ }
357
+ function buildInferredTemplateAction(label, data) {
358
+ return data.startsWith("http") ? uriAction(label, data) : data.includes("=") ? postbackAction(label, data, label) : messageAction(label, data);
359
+ }
360
+ function resolveTemplateTextLimit(params) {
361
+ return params.title !== void 0 || params.thumbnailImageUrl !== void 0 ? COMPACT_TEMPLATE_TEXT_LIMIT : params.textOnlyLimit;
362
+ }
363
+ function truncateTemplateText(text, limit) {
364
+ let result = "";
365
+ for (const { segment } of graphemeSegmenter.segment(text)) {
366
+ if (result.length + segment.length > limit) {
367
+ if (!result) for (const codePoint of segment) {
368
+ if (result.length + codePoint.length > limit) break;
369
+ result += codePoint;
370
+ }
371
+ break;
372
+ }
373
+ result += segment;
374
+ }
375
+ return result;
376
+ }
377
+ function truncateOptionalTemplateText(value, limit) {
378
+ return value === void 0 ? void 0 : truncateTemplateText(value, limit);
379
+ }
380
+ function resolveTemplateAltText(value, fallback) {
381
+ return truncateTemplateText(value ?? fallback, TEMPLATE_ALT_TEXT_LIMIT);
382
+ }
383
+ function normalizeCarouselColumn(column) {
384
+ return {
385
+ ...column,
386
+ title: column.title || void 0,
387
+ actions: column.actions.map((action) => normalizeLineAction(action)).filter((action) => action.label !== void 0 && action.label !== "").slice(0, 3),
388
+ defaultAction: column.defaultAction === void 0 ? void 0 : normalizeLineAction(column.defaultAction)
389
+ };
390
+ }
391
+ function describeCarouselColumn(column) {
392
+ const body = column.title ? `${column.title}: ${column.text}` : column.text;
393
+ const labels = column.actions.map((action) => action.label).filter((label) => label !== void 0 && label !== "");
394
+ return labels.length > 0 ? `${body} (${labels.join(" / ")})` : body;
395
+ }
396
+ function normalizeCarousel(columns, altText) {
397
+ const normalized = columns.slice(0, 10).map(normalizeCarouselColumn);
398
+ const first = normalized[0];
399
+ if (!(!first || normalized.some((column) => column.text === "" || column.actions.length === 0 || column.title === void 0 !== (first.title === void 0) || column.actions.length !== first.actions.length))) return {
400
+ kind: "template",
401
+ columns: normalized
402
+ };
403
+ const text = [...altText ? [truncateTemplateText(altText, TEMPLATE_ALT_TEXT_LIMIT)] : [], ...normalized.map(describeCarouselColumn).filter((line) => line !== "")].join("\n");
404
+ return text ? {
405
+ kind: "text",
406
+ text
407
+ } : { kind: "empty" };
408
+ }
409
+ function createCarouselMessage(columns, options) {
410
+ const template = {
411
+ type: "carousel",
412
+ columns,
413
+ imageAspectRatio: options?.imageAspectRatio ?? "rectangle",
414
+ imageSize: options?.imageSize ?? "cover"
415
+ };
416
+ return {
417
+ type: "template",
418
+ altText: resolveTemplateAltText(options?.altText, "View carousel"),
419
+ template
420
+ };
421
+ }
422
+ /**
423
+ * Create a confirm template (yes/no style dialog)
424
+ */
425
+ function createConfirmTemplate(text, confirmAction, cancelAction, altText) {
426
+ const template = {
427
+ type: "confirm",
428
+ text: truncateTemplateText(text, 240),
429
+ actions: [normalizeLineAction(confirmAction), normalizeLineAction(cancelAction)]
430
+ };
431
+ return {
432
+ type: "template",
433
+ altText: resolveTemplateAltText(altText, text),
434
+ template
435
+ };
436
+ }
437
+ /**
438
+ * Create a button template with title, text, and action buttons
439
+ */
440
+ function createButtonTemplate(title, text, actions, options) {
441
+ const normalizedTitle = title || void 0;
442
+ const textLimit = resolveTemplateTextLimit({
443
+ title: normalizedTitle,
444
+ thumbnailImageUrl: options?.thumbnailImageUrl,
445
+ textOnlyLimit: 160
446
+ });
447
+ const template = {
448
+ type: "buttons",
449
+ ...normalizedTitle ? { title: truncateTemplateText(normalizedTitle, 40) } : {},
450
+ text: truncateTemplateText(text, textLimit),
451
+ actions: actions.slice(0, 4).map((action) => normalizeLineAction(action)),
452
+ thumbnailImageUrl: options?.thumbnailImageUrl,
453
+ imageAspectRatio: options?.imageAspectRatio ?? "rectangle",
454
+ imageSize: options?.imageSize ?? "cover",
455
+ imageBackgroundColor: options?.imageBackgroundColor,
456
+ defaultAction: options?.defaultAction === void 0 ? void 0 : normalizeLineAction(options.defaultAction)
457
+ };
458
+ return {
459
+ type: "template",
460
+ altText: resolveTemplateAltText(options?.altText, normalizedTitle ? `${normalizedTitle}: ${text}` : text),
461
+ template
462
+ };
463
+ }
464
+ function createCarouselColumn(params) {
465
+ const normalizedTitle = params.title || void 0;
466
+ const textLimit = resolveTemplateTextLimit({
467
+ ...params,
468
+ title: normalizedTitle,
469
+ textOnlyLimit: 120
470
+ });
471
+ return normalizeCarouselColumn({
472
+ title: truncateOptionalTemplateText(normalizedTitle, 40),
473
+ text: truncateTemplateText(params.text, textLimit),
474
+ actions: params.actions,
475
+ thumbnailImageUrl: params.thumbnailImageUrl,
476
+ imageBackgroundColor: params.imageBackgroundColor,
477
+ defaultAction: params.defaultAction
478
+ });
479
+ }
480
+ /**
481
+ * Convert a TemplateMessagePayload from ReplyPayload to a LINE TemplateMessage
482
+ */
483
+ function buildTemplateMessageFromPayload(payload) {
484
+ switch (payload.type) {
485
+ case "confirm": return createConfirmTemplate(payload.text, buildInferredTemplateAction(payload.confirmLabel, payload.confirmData), buildInferredTemplateAction(payload.cancelLabel, payload.cancelData), payload.altText);
486
+ case "buttons": {
487
+ const actions = payload.actions.slice(0, 4).map(buildTemplatePayloadAction);
488
+ return createButtonTemplate(payload.title, payload.text, actions, {
489
+ thumbnailImageUrl: payload.thumbnailImageUrl,
490
+ altText: payload.altText
491
+ });
492
+ }
493
+ case "carousel": {
494
+ const outcome = normalizeCarousel(payload.columns.map((col) => {
495
+ return createCarouselColumn({
496
+ title: col.title,
497
+ text: col.text,
498
+ thumbnailImageUrl: col.thumbnailImageUrl,
499
+ actions: col.actions.map(buildTemplatePayloadAction)
500
+ });
501
+ }), payload.altText);
502
+ if (outcome.kind === "empty") return null;
503
+ return outcome.kind === "text" ? {
504
+ type: "text",
505
+ text: outcome.text
506
+ } : createCarouselMessage(outcome.columns, { altText: payload.altText });
507
+ }
508
+ default: return null;
509
+ }
531
510
  }
532
511
  //#endregion
533
- export { buildTemplateMessageFromPayload as a, createConfirmTemplate as c, stripMarkdown$1 as i, createTemplateCarousel as l, hasMarkdownToConvert as n, createButtonTemplate as o, processLineMessage as r, createCarouselColumn as s, convertCodeBlockToFlexBubble as t };
512
+ export { processLineMessage as n, buildTemplateMessageFromPayload as t };
package/dist/api.js CHANGED
@@ -1,3 +1,3 @@
1
- import { t as linePlugin } from "./.setup/channel-kc3VRglA.mjs";
2
- import { t as lineSetupPlugin } from "./.setup/api-D_06cuHl.mjs";
1
+ import { t as linePlugin } from "./.setup/channel-DN6Za8Vm.mjs";
2
+ import { t as lineSetupPlugin } from "./.setup/api-w4QdlCCB.mjs";
3
3
  export { linePlugin, lineSetupPlugin };
@@ -1,2 +1,2 @@
1
- import { t as linePlugin } from "./.setup/channel-kc3VRglA.mjs";
1
+ import { t as linePlugin } from "./.setup/channel-DN6Za8Vm.mjs";
2
2
  export { linePlugin };
@@ -1,2 +1,2 @@
1
- import { i as resolveLineAccount, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./.setup/accounts-BBEFMYbY.mjs";
1
+ import { n as resolveDefaultLineAccountId, r as resolveLineAccount, t as listLineAccountIds } from "./.setup/accounts-DOiM8-y3.mjs";
2
2
  export { listLineAccountIds, resolveDefaultLineAccountId, resolveLineAccount };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { defineBundledChannelEntry } from "openclaw/plugin-sdk/channel-entry-contract";
2
2
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
3
3
  //#region extensions/line/index.ts
4
- const loadLineCardCommand = createLazyRuntimeModule(() => import("./.setup/card-command-710u8FBH.mjs"));
4
+ const loadLineCardCommand = createLazyRuntimeModule(() => import("./.setup/card-command-DYf4gnmI.mjs"));
5
5
  var line_default = defineBundledChannelEntry({
6
6
  id: "line",
7
7
  name: "LINE",
@@ -1,260 +1,2 @@
1
- import { i as resolveLineAccount, n as normalizeAccountId, r as resolveDefaultLineAccountId, t as listLineAccountIds } from "./.setup/accounts-BBEFMYbY.mjs";
2
- import { C as LineConfigSchema, S as LineChannelConfigSchema, _ as resolveLineGroupLookupIds, b as normalizeAllowFrom, d as createMediaPlayerCard, g as resolveLineGroupConfigEntry, h as resolveExactLineGroupConfigKey, l as createAppleTvRemoteCard, m as setLineRuntime, u as createDeviceControlCard, v as resolveLineGroupsConfig, y as firstDefined } from "./.setup/rich-messages-d8CmBVJj.mjs";
3
- import { C as toFlexMessage, M as createAudioMessage, N as createImageMessage, P as createVideoMessage, a as probeLineBot, c as createAgendaCard, d as createActionCard, f as createImageCard, g as messageAction, h as datetimePickerAction, l as createEventCard, m as createListCard, o as resolveLineChannelAccessToken, p as createInfoCard, u as createReceiptCard, x as uriAction, y as postbackAction } from "./.setup/send-retry-DbfiHBPd.mjs";
4
- import { a as resolveLineWebhookPath, i as parseLineWebhookBody, n as createLineNodeWebhookHandler, o as validateLineSignature, r as readLineWebhookRequestBody, s as downloadLineMedia, t as monitorLineProvider } from "./.setup/monitor-morJPcPd.mjs";
5
- import { a as buildTemplateMessageFromPayload, c as createConfirmTemplate, i as stripMarkdown, l as createTemplateCarousel, n as hasMarkdownToConvert, o as createButtonTemplate, r as processLineMessage, s as createCarouselColumn, t as convertCodeBlockToFlexBubble } from "./.setup/markdown-to-line-CRfEHFs0.mjs";
6
- import { _ as showLoadingAnimation, c as pushFlexMessage, d as pushMessageLine, f as pushMessagesLine, g as sendMessageLine, h as replyMessageLine, i as createTextMessageWithQuickReplies, l as pushImageMessage, m as pushTextMessageWithQuickReplies, n as createLocationMessage, o as getUserDisplayName, p as pushTemplateMessage, r as createQuickReplyItems, s as getUserProfile, t as createFlexMessage, u as pushLocationMessage } from "./.setup/send-BmsHY4WC.mjs";
7
- import { buildChannelConfigSchema } from "openclaw/plugin-sdk/channel-config-schema";
8
- import { buildComputedAccountStatusSnapshot, buildTokenChannelStatusSummary } from "openclaw/plugin-sdk/status-helpers";
9
- import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
10
- import { mimeTypeFromFilePath } from "openclaw/plugin-sdk/media-mime";
11
- import { danger, logVerbose } from "openclaw/plugin-sdk/runtime-env";
12
- import { messagingApi } from "@line/bot-sdk";
13
- import { DEFAULT_ACCOUNT_ID, formatDocsLink, setSetupChannelEnabled, splitSetupEntries } from "openclaw/plugin-sdk/setup";
14
- import { clearAccountEntryFields } from "openclaw/plugin-sdk/core";
15
- import { bufferToBlobPart } from "openclaw/plugin-sdk/blob-runtime";
16
- import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-local-roots";
17
- import { loadWebMediaRaw } from "openclaw/plugin-sdk/web-media";
18
- //#region extensions/line/src/webhook.ts
19
- const LINE_WEBHOOK_MAX_RAW_BODY_BYTES = 65536;
20
- function readRawBody(req) {
21
- const rawBody = req.rawBody ?? (typeof req.body === "string" || Buffer.isBuffer(req.body) ? req.body : null);
22
- if (!rawBody) return null;
23
- return Buffer.isBuffer(rawBody) ? rawBody.toString("utf-8") : rawBody;
24
- }
25
- function parseWebhookBody(rawBody) {
26
- if (!rawBody) return null;
27
- return parseLineWebhookBody(rawBody);
28
- }
29
- function createLineWebhookMiddleware(options) {
30
- const { channelSecret, onEvents, runtime } = options;
31
- return async (req, res, _next) => {
32
- try {
33
- const signature = req.headers["x-line-signature"];
34
- if (!signature || typeof signature !== "string") {
35
- res.status(400).json({ error: "Missing X-Line-Signature header" });
36
- return;
37
- }
38
- const rawBody = readRawBody(req);
39
- if (!rawBody) {
40
- res.status(400).json({ error: "Missing raw request body for signature verification" });
41
- return;
42
- }
43
- if (Buffer.byteLength(rawBody, "utf-8") > LINE_WEBHOOK_MAX_RAW_BODY_BYTES) {
44
- res.status(413).json({ error: "Payload too large" });
45
- return;
46
- }
47
- if (!validateLineSignature(rawBody, signature, channelSecret)) {
48
- logVerbose("line: webhook signature validation failed");
49
- res.status(401).json({ error: "Invalid signature" });
50
- return;
51
- }
52
- const body = parseWebhookBody(rawBody);
53
- if (!body) {
54
- res.status(400).json({ error: "Invalid webhook payload" });
55
- return;
56
- }
57
- if (body.events && body.events.length > 0) {
58
- logVerbose(`line: received ${body.events.length} webhook events`);
59
- await onEvents(body);
60
- }
61
- res.status(200).json({ status: "ok" });
62
- } catch (err) {
63
- runtime?.error?.(danger(`line webhook error: ${formatErrorMessage(err)}`));
64
- if (!res.headersSent) res.status(500).json({ error: "Internal server error" });
65
- }
66
- };
67
- }
68
- function startLineWebhook(options) {
69
- const channelSecret = typeof options.channelSecret === "string" ? options.channelSecret.trim() : "";
70
- if (!channelSecret) throw new Error("LINE webhook mode requires a non-empty channel secret. Set channels.line.channelSecret in your config.");
71
- return {
72
- path: resolveLineWebhookPath(options.path),
73
- handler: createLineWebhookMiddleware({
74
- channelSecret,
75
- onEvents: options.onEvents,
76
- runtime: options.runtime
77
- })
78
- };
79
- }
80
- //#endregion
81
- //#region extensions/line/src/rich-menu.ts
82
- const graphemeSegmenter = new Intl.Segmenter(void 0, { granularity: "grapheme" });
83
- function getClient(opts) {
84
- const account = resolveLineAccount({
85
- cfg: opts.cfg,
86
- accountId: opts.accountId
87
- });
88
- const token = resolveLineChannelAccessToken(opts.channelAccessToken, account);
89
- return new messagingApi.MessagingApiClient({ channelAccessToken: token });
90
- }
91
- function getBlobClient(opts) {
92
- const account = resolveLineAccount({
93
- cfg: opts.cfg,
94
- accountId: opts.accountId
95
- });
96
- const token = resolveLineChannelAccessToken(opts.channelAccessToken, account);
97
- return new messagingApi.MessagingApiBlobClient({ channelAccessToken: token });
98
- }
99
- function truncateGraphemes(input, maxLength) {
100
- let result = "";
101
- let count = 0;
102
- for (const { segment } of graphemeSegmenter.segment(input)) {
103
- if (count >= maxLength) break;
104
- result += segment;
105
- count += 1;
106
- }
107
- return result;
108
- }
109
- async function createRichMenu(menu, opts) {
110
- const client = getClient(opts);
111
- const richMenuRequest = {
112
- size: menu.size,
113
- selected: menu.selected ?? false,
114
- name: truncateGraphemes(menu.name, 300),
115
- chatBarText: truncateGraphemes(menu.chatBarText, 14),
116
- areas: menu.areas
117
- };
118
- const response = await client.createRichMenu(richMenuRequest);
119
- if (opts.verbose) logVerbose(`line: created rich menu ${response.richMenuId}`);
120
- return response.richMenuId;
121
- }
122
- async function uploadRichMenuImage(richMenuId, imagePath, opts) {
123
- const blobClient = getBlobClient(opts);
124
- const media = await loadWebMediaRaw(imagePath, { localRoots: opts.mediaLocalRoots ?? getAgentScopedMediaLocalRoots(opts.cfg) });
125
- const contentType = media.contentType === "image/png" || media.contentType === "image/jpeg" ? media.contentType : mimeTypeFromFilePath(imagePath) === "image/png" ? "image/png" : "image/jpeg";
126
- const blob = new Blob([bufferToBlobPart(media.buffer)], { type: contentType });
127
- await blobClient.setRichMenuImage(richMenuId, blob);
128
- if (opts.verbose) logVerbose(`line: uploaded image to rich menu ${richMenuId}`);
129
- }
130
- async function setDefaultRichMenu(richMenuId, opts) {
131
- await getClient(opts).setDefaultRichMenu(richMenuId);
132
- if (opts.verbose) logVerbose(`line: set default rich menu to ${richMenuId}`);
133
- }
134
- async function cancelDefaultRichMenu(opts) {
135
- await getClient(opts).cancelDefaultRichMenu();
136
- if (opts.verbose) logVerbose("line: cancelled default rich menu");
137
- }
138
- async function getDefaultRichMenuId(opts) {
139
- const client = getClient(opts);
140
- try {
141
- return (await client.getDefaultRichMenuId()).richMenuId ?? null;
142
- } catch {
143
- return null;
144
- }
145
- }
146
- async function getRichMenuIdOfUser(userId, opts) {
147
- const client = getClient(opts);
148
- try {
149
- return (await client.getRichMenuIdOfUser(userId)).richMenuId ?? null;
150
- } catch {
151
- return null;
152
- }
153
- }
154
- async function getRichMenuList(opts) {
155
- return (await getClient(opts).getRichMenuList()).richmenus ?? [];
156
- }
157
- async function getRichMenu(richMenuId, opts) {
158
- const client = getClient(opts);
159
- try {
160
- return await client.getRichMenu(richMenuId);
161
- } catch {
162
- return null;
163
- }
164
- }
165
- async function deleteRichMenu(richMenuId, opts) {
166
- await getClient(opts).deleteRichMenu(richMenuId);
167
- if (opts.verbose) logVerbose(`line: deleted rich menu ${richMenuId}`);
168
- }
169
- async function createRichMenuAlias(richMenuId, aliasId, opts) {
170
- await getClient(opts).createRichMenuAlias({
171
- richMenuId,
172
- richMenuAliasId: aliasId
173
- });
174
- if (opts.verbose) logVerbose(`line: created alias ${aliasId} for rich menu ${richMenuId}`);
175
- }
176
- async function deleteRichMenuAlias(aliasId, opts) {
177
- await getClient(opts).deleteRichMenuAlias(aliasId);
178
- if (opts.verbose) logVerbose(`line: deleted alias ${aliasId}`);
179
- }
180
- function createGridLayout(height, actions) {
181
- const colWidth = Math.floor(2500 / 3);
182
- const rowHeight = Math.floor(height / 2);
183
- return [
184
- {
185
- bounds: {
186
- x: 0,
187
- y: 0,
188
- width: colWidth,
189
- height: rowHeight
190
- },
191
- action: actions[0]
192
- },
193
- {
194
- bounds: {
195
- x: colWidth,
196
- y: 0,
197
- width: colWidth,
198
- height: rowHeight
199
- },
200
- action: actions[1]
201
- },
202
- {
203
- bounds: {
204
- x: colWidth * 2,
205
- y: 0,
206
- width: colWidth,
207
- height: rowHeight
208
- },
209
- action: actions[2]
210
- },
211
- {
212
- bounds: {
213
- x: 0,
214
- y: rowHeight,
215
- width: colWidth,
216
- height: rowHeight
217
- },
218
- action: actions[3]
219
- },
220
- {
221
- bounds: {
222
- x: colWidth,
223
- y: rowHeight,
224
- width: colWidth,
225
- height: rowHeight
226
- },
227
- action: actions[4]
228
- },
229
- {
230
- bounds: {
231
- x: colWidth * 2,
232
- y: rowHeight,
233
- width: colWidth,
234
- height: rowHeight
235
- },
236
- action: actions[5]
237
- }
238
- ];
239
- }
240
- function createDefaultMenuConfig() {
241
- return {
242
- size: {
243
- width: 2500,
244
- height: 843
245
- },
246
- selected: false,
247
- name: "Default Menu",
248
- chatBarText: "Menu",
249
- areas: createGridLayout(843, [
250
- messageAction("Help", "/help"),
251
- messageAction("Status", "/status"),
252
- messageAction("Settings", "/settings"),
253
- messageAction("About", "/about"),
254
- messageAction("Feedback", "/feedback"),
255
- messageAction("Contact", "/contact")
256
- ])
257
- };
258
- }
259
- //#endregion
260
- export { DEFAULT_ACCOUNT_ID, LineChannelConfigSchema, LineConfigSchema, buildChannelConfigSchema, buildComputedAccountStatusSnapshot, buildTemplateMessageFromPayload, buildTokenChannelStatusSummary, cancelDefaultRichMenu, clearAccountEntryFields, convertCodeBlockToFlexBubble, createActionCard, createAgendaCard, createAppleTvRemoteCard, createAudioMessage, createButtonTemplate, createCarouselColumn, createConfirmTemplate, createDefaultMenuConfig, createDeviceControlCard, createEventCard, createFlexMessage, createGridLayout, createImageCard, createImageMessage, createInfoCard, createLineNodeWebhookHandler, createLineWebhookMiddleware, createListCard, createLocationMessage, createMediaPlayerCard, createQuickReplyItems, createReceiptCard, createRichMenu, createRichMenuAlias, createTemplateCarousel, createTextMessageWithQuickReplies, createVideoMessage, datetimePickerAction, deleteRichMenu, deleteRichMenuAlias, downloadLineMedia, firstDefined, formatDocsLink, getDefaultRichMenuId, getRichMenu, getRichMenuIdOfUser, getRichMenuList, getUserDisplayName, getUserProfile, hasMarkdownToConvert, listLineAccountIds, messageAction, monitorLineProvider, normalizeAccountId, normalizeAllowFrom, parseLineWebhookBody, postbackAction, probeLineBot, processLineMessage, pushFlexMessage, pushImageMessage, pushLocationMessage, pushMessageLine, pushMessagesLine, pushTemplateMessage, pushTextMessageWithQuickReplies, readLineWebhookRequestBody, replyMessageLine, resolveDefaultLineAccountId, resolveExactLineGroupConfigKey, resolveLineAccount, resolveLineChannelAccessToken, resolveLineGroupConfigEntry, resolveLineGroupLookupIds, resolveLineGroupsConfig, sendMessageLine, setDefaultRichMenu, setLineRuntime, setSetupChannelEnabled, showLoadingAnimation, splitSetupEntries, startLineWebhook, stripMarkdown, toFlexMessage, uploadRichMenuImage, uriAction, validateLineSignature };
1
+ import { n as setLineRuntime } from "./.setup/runtime-V7yh9OeC.mjs";
2
+ export { setLineRuntime };
package/dist/setup-api.js CHANGED
@@ -1,2 +1,2 @@
1
- import { n as lineSetupAdapter, t as lineSetupWizard } from "./.setup/setup-surface-CcfKJKtr.mjs";
1
+ import { n as lineSetupAdapter, t as lineSetupWizard } from "./.setup/setup-surface-CbfkmkIS.mjs";
2
2
  export { lineSetupAdapter, lineSetupWizard };