@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.
Files changed (46) hide show
  1. package/dist/account-helpers-BSUyZwLm.js +12 -0
  2. package/dist/{accounts-BqEVsDoB.js → accounts-BBEFMYbY.js} +2 -1
  3. package/dist/api.js +2 -2
  4. package/dist/card-command-pwvE48Wb.js +252 -0
  5. package/dist/{channel-CsQLcrsA.js → channel-BJvELOIg.js} +111 -380
  6. package/dist/channel-plugin-api.js +1 -1
  7. package/dist/channel.runtime-CZOszXXj.js +4 -0
  8. package/dist/contract-api.js +1 -1
  9. package/dist/doctor-contract-api.js +141 -0
  10. package/dist/index.js +5 -17
  11. package/dist/{markdown-to-line-BmZ4hhfC.js → markdown-to-line-B-sj-7II.js} +22 -23
  12. package/dist/{monitor-Bd9XDV1i.js → monitor-m9h5osFz.js} +339 -237
  13. package/dist/monitor.runtime-C90LL-P3.js +2 -0
  14. package/dist/outbound.runtime-CGqyJ-Ug.js +3 -0
  15. package/dist/probe.runtime-CbtMgU4s.js +2 -0
  16. package/dist/rich-messages-DY1AGKAJ.js +742 -0
  17. package/dist/runtime-api.js +14 -15
  18. package/dist/{send-Dce0m539.js → send-CQQxpxPp.js} +142 -112
  19. package/dist/{send-receipt-CCPTalf9.js → send-retry-ChpfJ-LM.js} +326 -86
  20. package/dist/setup-api.js +1 -1
  21. package/dist/{setup-surface-W0Dbgu58.js → setup-surface-CDlgkTKi.js} +47 -39
  22. package/dist/webhook-spool-contract-1rY8OJw8.js +59 -0
  23. package/node_modules/typebox/build/format/email.mjs +1 -1
  24. package/node_modules/typebox/build/format/idna/idn-hostname.mjs +19 -1
  25. package/node_modules/typebox/build/format/json_pointer.d.mts +2 -2
  26. package/node_modules/typebox/build/format/json_pointer.mjs +2 -2
  27. package/node_modules/typebox/build/format/json_pointer_uri_fragment.d.mts +2 -2
  28. package/node_modules/typebox/build/format/json_pointer_uri_fragment.mjs +2 -2
  29. package/node_modules/typebox/build/format/relative_json_pointer.d.mts +2 -2
  30. package/node_modules/typebox/build/format/relative_json_pointer.mjs +2 -2
  31. package/node_modules/typebox/build/system/memory/assign.mjs +2 -1
  32. package/node_modules/typebox/build/system/memory/create.mjs +3 -4
  33. package/node_modules/typebox/build/system/memory/discard.mjs +2 -2
  34. package/node_modules/typebox/build/system/memory/freeze.d.mts +4 -0
  35. package/node_modules/typebox/build/system/memory/freeze.mjs +6 -0
  36. package/node_modules/typebox/build/system/memory/update.mjs +3 -2
  37. package/node_modules/typebox/package.json +1 -1
  38. package/openclaw.plugin.json +16 -3
  39. package/package.json +5 -5
  40. package/dist/card-command-CmU47gD9.js +0 -230
  41. package/dist/channel.runtime-B83x7k_i.js +0 -4
  42. package/dist/media-control-cards-CksNB8Wk.js +0 -474
  43. package/dist/monitor.runtime-BCCa6qTX.js +0 -2
  44. package/dist/outbound.runtime-D4w0-Gkc.js +0 -3
  45. package/dist/probe-CM03wo6r.js +0 -28
  46. package/dist/probe.runtime-D13ZtXsd.js +0 -2
@@ -0,0 +1,12 @@
1
+ //#region extensions/line/src/account-helpers.ts
2
+ function hasLineCredentials(account) {
3
+ if (account.tokenStatus && account.signingSecretStatus) return account.tokenStatus !== "missing" && account.signingSecretStatus !== "missing";
4
+ return Boolean(account.channelAccessToken?.trim() && account.channelSecret?.trim());
5
+ }
6
+ function parseLineAllowFromId(raw) {
7
+ const trimmed = raw.trim().replace(/^line:(?:user:)?/i, "");
8
+ if (!/^U[a-f0-9]{32}$/i.test(trimmed)) return null;
9
+ return trimmed;
10
+ }
11
+ //#endregion
12
+ export { parseLineAllowFromId as n, hasLineCredentials as t };
@@ -16,7 +16,8 @@ function resolveLineCredential(params) {
16
16
  };
17
17
  const file = config?.[fileKey];
18
18
  if (file?.trim()) {
19
- const result = tryReadSecretFileSync(file, "LINE credential file", { rejectSymlink: true }, { configPath: `channels.line.${index === 0 ? `accounts.${accountId}.` : ""}${fileKey}` });
19
+ const scope = index === 0 ? `accounts.${accountId}.` : "";
20
+ const result = tryReadSecretFileSync(file, "LINE credential file", { rejectSymlink: true }, { configPath: `channels.line.${scope}${fileKey}` });
20
21
  return result.status === "available" ? {
21
22
  value: result.value,
22
23
  source: "file",
package/dist/api.js CHANGED
@@ -1,5 +1,5 @@
1
- import { n as lineChannelPluginCommon, t as linePlugin } from "./channel-CsQLcrsA.js";
2
- import { r as lineSetupContract, t as lineSetupWizard } from "./setup-surface-W0Dbgu58.js";
1
+ import { n as lineChannelPluginCommon, t as linePlugin } from "./channel-BJvELOIg.js";
2
+ import { r as lineSetupContract, t as lineSetupWizard } from "./setup-surface-CDlgkTKi.js";
3
3
  //#region extensions/line/src/channel.setup.ts
4
4
  const lineSetupPlugin = {
5
5
  id: "line",
@@ -0,0 +1,252 @@
1
+ import { d as createActionCard, f as createImageCard, m as createListCard, p as createInfoCard, u as createReceiptCard } from "./send-retry-ChpfJ-LM.js";
2
+ import { t as createFlexMessage } from "./send-CQQxpxPp.js";
3
+ import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
4
+ import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
5
+ //#region extensions/line/src/card-command.ts
6
+ const CARD_USAGE = `Usage: /card <type> "title" "body" [options]
7
+
8
+ Types:
9
+ info "Title" "Body" ["Footer"]
10
+ image "Title" "Caption" --url <image-url>
11
+ action "Title" "Body" --actions "Btn1|url1,Btn2|text2"
12
+ list "Title" "Item1|Desc1,Item2|Desc2"
13
+ receipt "Title" "Item1:$10,Item2:$20" --total "$30"
14
+ confirm "Question?" --yes "Yes|data" --no "No|data"
15
+ buttons "Title" "Text" --actions "Btn1|url1,Btn2|data2"
16
+
17
+ Escape a separator that belongs to the data with a backslash: \\, \\|, or \\:
18
+
19
+ Examples:
20
+ /card info "Welcome" "Thanks for joining!"
21
+ /card image "Product" "Check it out" --url https://example.com/img.jpg
22
+ /card action "Menu" "Choose an option" --actions "Order|/order,Help|/help"
23
+ /card action "Links" "Pick one" --actions "Open|https://example.com/a\\,b"`;
24
+ function buildLineReply(lineData) {
25
+ return { channelData: { line: lineData } };
26
+ }
27
+ function buildLineFlexReply(altText, contents) {
28
+ const message = createFlexMessage(altText, contents);
29
+ return buildLineReply({ flexMessage: {
30
+ altText: message.altText,
31
+ contents: message.contents
32
+ } });
33
+ }
34
+ /**
35
+ * Split a card option value on its unescaped separators.
36
+ *
37
+ * Each pass consumes escapes for its own separator and preserves every other
38
+ * backslash. This lets nested comma, pipe, and colon passes stay independent.
39
+ */
40
+ function splitCardValue(value, separator) {
41
+ const parts = [];
42
+ let current = "";
43
+ for (let index = 0; index < value.length; index += 1) {
44
+ const char = value[index];
45
+ if (char === "\\" && value[index + 1] === separator) {
46
+ current += separator;
47
+ index += 1;
48
+ continue;
49
+ }
50
+ if (char === separator) {
51
+ parts.push(current);
52
+ current = "";
53
+ continue;
54
+ }
55
+ current += char;
56
+ }
57
+ parts.push(current);
58
+ return parts;
59
+ }
60
+ /** Split a "Label|data" pair, keeping escaped separators inside either side. */
61
+ function splitCardPair(part) {
62
+ const [label = "", data] = splitCardValue(part, "|").map((piece) => piece.trim());
63
+ return [label, data];
64
+ }
65
+ /**
66
+ * Parse action string format: "Label|data,Label2|data2"
67
+ * Data can be a URL (uri action) or plain text (message action) or key=value (postback)
68
+ */
69
+ function parseActions(actionsStr) {
70
+ if (!actionsStr) return [];
71
+ const results = [];
72
+ for (const part of splitCardValue(actionsStr, ",")) {
73
+ const [label, data] = splitCardPair(part);
74
+ if (!label) continue;
75
+ const actionData = data || label;
76
+ const action = actionData.startsWith("http://") || actionData.startsWith("https://") ? {
77
+ type: "uri",
78
+ label,
79
+ uri: actionData
80
+ } : actionData.includes("=") ? {
81
+ type: "postback",
82
+ label,
83
+ data: actionData,
84
+ displayText: label
85
+ } : {
86
+ type: "message",
87
+ label,
88
+ text: actionData
89
+ };
90
+ results.push({
91
+ label,
92
+ action
93
+ });
94
+ }
95
+ return results;
96
+ }
97
+ /**
98
+ * Parse list items format: "Item1|Subtitle1,Item2|Subtitle2"
99
+ */
100
+ function parseListItems(itemsStr) {
101
+ return splitCardValue(itemsStr, ",").map((part) => {
102
+ const [title, subtitle] = splitCardPair(part);
103
+ return {
104
+ title,
105
+ subtitle
106
+ };
107
+ }).filter((item) => item.title);
108
+ }
109
+ /**
110
+ * Parse receipt items format: "Item1:$10,Item2:$20"
111
+ */
112
+ function parseReceiptItems(itemsStr) {
113
+ return splitCardValue(itemsStr, ",").map((part) => {
114
+ const segments = splitCardValue(part, ":");
115
+ const value = segments.length > 1 ? segments.pop() : void 0;
116
+ return {
117
+ name: segments.join(":").trim(),
118
+ value: value?.trim() ?? ""
119
+ };
120
+ }).filter((item) => item.name);
121
+ }
122
+ /**
123
+ * Parse quoted arguments from command string
124
+ * Supports: /card type "arg1" "arg2" "arg3" --flag value
125
+ */
126
+ function parseCardArgs(argsStrInput) {
127
+ let argsStr = argsStrInput;
128
+ const result = {
129
+ type: "",
130
+ args: [],
131
+ flags: {}
132
+ };
133
+ const typeMatch = argsStr.match(/^(\w+)/);
134
+ if (typeMatch) {
135
+ result.type = normalizeLowercaseStringOrEmpty(typeMatch[1]);
136
+ argsStr = argsStr.slice(typeMatch[0].length).trim();
137
+ }
138
+ const quotedRegex = /"([^"]*?)"/g;
139
+ let match;
140
+ while ((match = quotedRegex.exec(argsStr)) !== null) result.args.push(expectDefined(match[1], "quoted card argument capture") || void 0);
141
+ const flagRegex = /--(\w+)\s+(?:"([^"]*?)"|(\S+))/g;
142
+ while ((match = flagRegex.exec(argsStr)) !== null) {
143
+ const key = expectDefined(match[1], "card flag name capture");
144
+ result.flags[key] = expectDefined(match[2] ?? match[3], "card flag value capture");
145
+ }
146
+ return result;
147
+ }
148
+ async function handleLineCardCommand(argsInput) {
149
+ const argsStr = argsInput?.trim() ?? "";
150
+ if (!argsStr) return { text: CARD_USAGE };
151
+ const { type, args, flags } = parseCardArgs(argsStr);
152
+ if (!type) return { text: CARD_USAGE };
153
+ try {
154
+ switch (type) {
155
+ case "info": {
156
+ const [title = "Info", body = "", footer] = args;
157
+ const bubble = createInfoCard(title, body, footer);
158
+ return buildLineFlexReply(body ? `${title}: ${body}` : title, bubble);
159
+ }
160
+ case "image": {
161
+ const [title = "Image", caption = ""] = args;
162
+ const imageUrl = flags.url || flags.image;
163
+ if (!imageUrl) return { text: "Error: Image card requires --url <image-url>" };
164
+ const bubble = createImageCard(imageUrl, title, caption);
165
+ return buildLineFlexReply(`${title}: ${caption}`, bubble);
166
+ }
167
+ case "action": {
168
+ const [title = "Actions", body = ""] = args;
169
+ const actions = parseActions(flags.actions);
170
+ if (actions.length === 0) return { text: "Error: Action card requires --actions \"Label1|data1,Label2|data2\"" };
171
+ const bubble = createActionCard(title, body, actions, { imageUrl: flags.url || flags.image });
172
+ return buildLineFlexReply(body ? `${title}: ${body}` : title, bubble);
173
+ }
174
+ case "list": {
175
+ const [title = "List", itemsStr = ""] = args;
176
+ const items = parseListItems(itemsStr || flags.items || "");
177
+ if (items.length === 0) return { text: "Error: List card requires items. Usage: /card list \"Title\" \"Item1|Desc1,Item2|Desc2\"" };
178
+ const bubble = createListCard(title, items);
179
+ return buildLineFlexReply(`${title}: ${items.map((item) => item.title).join(", ")}`, bubble);
180
+ }
181
+ case "receipt": {
182
+ const [title = "Receipt", itemsStr = ""] = args;
183
+ const items = parseReceiptItems(itemsStr || flags.items || "");
184
+ const total = flags.total ? {
185
+ label: "Total",
186
+ value: flags.total
187
+ } : void 0;
188
+ const footer = flags.footer;
189
+ if (items.length === 0) return { text: "Error: Receipt card requires items. Usage: /card receipt \"Title\" \"Item1:$10,Item2:$20\" --total \"$30\"" };
190
+ const bubble = createReceiptCard({
191
+ title,
192
+ items,
193
+ total,
194
+ footer
195
+ });
196
+ return buildLineFlexReply(`${title}: ${items.map((item) => `${item.name} ${item.value}`).join(", ")}`, bubble);
197
+ }
198
+ case "confirm": {
199
+ const [question = "Confirm?"] = args;
200
+ const yesStr = flags.yes || "Yes|yes";
201
+ const noStr = flags.no || "No|no";
202
+ const [yesLabel, yesData] = splitCardPair(yesStr);
203
+ const [noLabel, noData] = splitCardPair(noStr);
204
+ return buildLineReply({ templateMessage: {
205
+ type: "confirm",
206
+ text: question,
207
+ confirmLabel: yesLabel || "Yes",
208
+ confirmData: yesData || "yes",
209
+ cancelLabel: noLabel || "No",
210
+ cancelData: noData || "no",
211
+ altText: question
212
+ } });
213
+ }
214
+ case "buttons": {
215
+ const [title = "Menu", text = "Choose an option"] = args;
216
+ const actionParts = parseActions(flags.actions || "");
217
+ if (actionParts.length === 0) return { text: "Error: Buttons card requires --actions \"Label1|data1,Label2|data2\"" };
218
+ const templateActions = actionParts.map((a) => {
219
+ const action = a.action;
220
+ const label = action.label ?? a.label;
221
+ if (action.type === "uri") return {
222
+ type: "uri",
223
+ label,
224
+ uri: action.uri
225
+ };
226
+ if (action.type === "postback") return {
227
+ type: "postback",
228
+ label,
229
+ data: action.data
230
+ };
231
+ return {
232
+ type: "message",
233
+ label,
234
+ data: action.text
235
+ };
236
+ });
237
+ return buildLineReply({ templateMessage: {
238
+ type: "buttons",
239
+ title,
240
+ text,
241
+ thumbnailImageUrl: flags.url || flags.image,
242
+ actions: templateActions
243
+ } });
244
+ }
245
+ default: return { text: `Unknown card type: "${type}". Available types: info, image, action, list, receipt, confirm, buttons` };
246
+ }
247
+ } catch (err) {
248
+ return { text: `Error creating card: ${String(err)}` };
249
+ }
250
+ }
251
+ //#endregion
252
+ export { handleLineCardCommand };