koishi-plugin-dew-bot 1.0.254 → 1.0.255

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.
@@ -0,0 +1,7 @@
1
+ Generation tool: built-in image_gen
2
+
3
+ Use case: stylized-concept.
4
+ Asset type: one square raster placeholder icon for a Chinese fantasy RPG inventory, shared by bloodline items, pet eggs and follower contracts until their own artwork is available.
5
+ Primary request: create exactly ONE neutral placeholder illustration, a single mysterious life seal: a simple rounded jade-gray magical core with an abstract curled life-flame motif, subtly enclosed by a soft ink halo. It should suggest unrevealed life and a sealed bond without depicting a specific bloodline, creature or character.
6
+ Style/medium: elegant Chinese ink and pale watercolor on warm off-white rice paper, matching refined fantasy game item artwork. Calm, restrained light; strong, simple silhouette. One centered subject, occupying about 65–70% of the square, large clear forms, clean low-contrast background and generous safe margins.
7
+ Constraints: opaque square background; remains legible at 24×24 pixels; one standalone icon, not an icon sheet or UI screenshot. No text, no letters, no numbers, no question mark, no watermark, no UI frame, no quality badge, no character, no weapon, no armor, no detailed scene, no tiny intricate decorations.
package/lib/index.js CHANGED
@@ -980,6 +980,12 @@ function compactListLabel(value) {
980
980
  return /[📖📚]/u.test(label) ? label.replace(/技能书(?=$|×\d+(?:\.\d+)?(?:||$)||)/g, "") : label;
981
981
  }
982
982
  __name(compactListLabel, "compactListLabel");
983
+ function renderEntryArtwork(address) {
984
+ if (!artworkIdentity(address)) return "";
985
+ const url = new URL(address).href.replace(/[()]/g, (character) => "%" + character.charCodeAt(0).toString(16).toUpperCase());
986
+ return `![图标 #24px #24px](${url}) `;
987
+ }
988
+ __name(renderEntryArtwork, "renderEntryArtwork");
983
989
  function inlineCommandUrl(command) {
984
990
  const encoded = encodeURIComponent(command).replace(/[!'()*]/g, (character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`);
985
991
  return `mqqapi://aio/inlinecmd?command=${encoded}&enter=true&reply=false`;
@@ -1106,6 +1112,7 @@ __name(renderInventoryFilters, "renderInventoryFilters");
1106
1112
  function renderQQInventoryMarkdown(data, showGreeting) {
1107
1113
  const nav = data.pageNav;
1108
1114
  const entryCommands = new Map(nav.entries?.map((entry) => [entry.lineIndex, entry.viewCommand]) ?? []);
1115
+ const entryArtwork = new Map(nav.entries?.map((entry) => [entry.lineIndex, renderEntryArtwork(entry.artworkUrl)]) ?? []);
1109
1116
  const sections = [];
1110
1117
  const items = [];
1111
1118
  const flushItems = /* @__PURE__ */ __name(() => {
@@ -1116,7 +1123,7 @@ function renderQQInventoryMarkdown(data, showGreeting) {
1116
1123
  const command = entryCommands.get(lineIndex);
1117
1124
  if (item.type === 1 /* line */ && command) {
1118
1125
  const label = compactListLabel(item.content.replace(/^\[\d+\]\s*/, ""));
1119
- items.push(`[${escapeMarkdown(label)}](${inlineCommandUrl(command)})`);
1126
+ items.push((entryArtwork.get(lineIndex) ?? "") + `[${escapeMarkdown(label)}](${inlineCommandUrl(command)})`);
1120
1127
  continue;
1121
1128
  }
1122
1129
  flushItems();
@@ -1144,6 +1151,7 @@ function renderQQPageMarkdown(data, showGreeting) {
1144
1151
  const nav = data.pageNav;
1145
1152
  const entryCommands = new Map(nav?.entries?.map((entry) => [entry.lineIndex, entry.viewCommand]) ?? []);
1146
1153
  const labeledEntries = new Map(nav?.entries?.filter((entry) => entry.label !== void 0).map((entry) => [entry.lineIndex, entry]) ?? []);
1154
+ const entryArtwork = new Map(nav?.entries?.map((entry) => [entry.lineIndex, renderEntryArtwork(entry.artworkUrl)]) ?? []);
1147
1155
  const listPattern = /^\[(\d+)\]\s*([^\r\n]+)$/;
1148
1156
  const pagePattern = /^第\s*\d+\s*\/\s*\d+\s*页(?:\s*[||]\s*共\s*(\d+)\s*([项条]))?$/;
1149
1157
  const title = data.line.find((item) => item.type === 0 /* title */);
@@ -1183,7 +1191,7 @@ function renderQQPageMarkdown(data, showGreeting) {
1183
1191
  if (labeledEntry) {
1184
1192
  flushList();
1185
1193
  flushRewards();
1186
- bodyLines.push(`[${escapeMarkdown(labeledEntry.label)}](${inlineCommandUrl(labeledEntry.viewCommand)})` + (labeledEntry.description ? " " + escapeMarkdown(labeledEntry.description) : ""));
1194
+ bodyLines.push((entryArtwork.get(lineIndex) ?? "") + `[${escapeMarkdown(labeledEntry.label)}](${inlineCommandUrl(labeledEntry.viewCommand)})` + (labeledEntry.description ? " " + escapeMarkdown(labeledEntry.description) : ""));
1187
1195
  break;
1188
1196
  }
1189
1197
  if (item.reward) {
@@ -1201,7 +1209,7 @@ function renderQQPageMarkdown(data, showGreeting) {
1201
1209
  const content = compactListLabel(listEntry[2]);
1202
1210
  const label = escapeMarkdown(content);
1203
1211
  const name2 = command2 ? `[${label}](${inlineCommandUrl(command2)})` : renderInlineCommands(content);
1204
- listLines.push(`${listEntry[1]}. ${name2}`);
1212
+ listLines.push(`${listEntry[1]}. ${entryArtwork.get(lineIndex) ?? ""}${name2}`);
1205
1213
  break;
1206
1214
  }
1207
1215
  flushList();
@@ -1222,7 +1230,7 @@ function renderQQPageMarkdown(data, showGreeting) {
1222
1230
  break;
1223
1231
  }
1224
1232
  const command = entryCommands.get(lineIndex);
1225
- bodyLines.push(command ? `[${escapeMarkdown(compactListLabel(item.content))}](${inlineCommandUrl(command)})` : renderInlineCommands(item.content));
1233
+ bodyLines.push(command ? (entryArtwork.get(lineIndex) ?? "") + `[${escapeMarkdown(compactListLabel(item.content))}](${inlineCommandUrl(command)})` : renderInlineCommands(item.content));
1226
1234
  break;
1227
1235
  }
1228
1236
  case 2 /* error */:
@@ -1632,7 +1640,7 @@ var import_tsrpc = require("tsrpc");
1632
1640
 
1633
1641
  // src/shared/bot/serviceProto.ts
1634
1642
  var serviceProto = {
1635
- "version": 21,
1643
+ "version": 22,
1636
1644
  "services": [
1637
1645
  {
1638
1646
  "id": 0,
@@ -2534,6 +2542,14 @@ var serviceProto = {
2534
2542
  "type": "String"
2535
2543
  },
2536
2544
  "optional": true
2545
+ },
2546
+ {
2547
+ "id": 4,
2548
+ "name": "artworkUrl",
2549
+ "type": {
2550
+ "type": "String"
2551
+ },
2552
+ "optional": true
2537
2553
  }
2538
2554
  ]
2539
2555
  }
@@ -134,9 +134,11 @@ export interface PageNavData {
134
134
  entries?: Array<{
135
135
  lineIndex: number;
136
136
  viewCommand: string;
137
- /** 提供时仅此名称可点击,说明作为普通文字展示;省略时沿用整行链接。 */
137
+ /** 菜单入口名称;提供时仅此文字可点击,说明作为普通文本显示。 */
138
138
  label?: string;
139
139
  description?: string;
140
+ /** 列表名称前的小图;使用已保存插画的临时 HTTPS 链接。 */
141
+ artworkUrl?: string;
140
142
  }>;
141
143
  /** 按完整实时列表提供筛选入口;空数组表示没有可用类型。 */
142
144
  filters?: Array<{
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-dew-bot",
3
3
  "description": "基于《无限恐怖》小说改编的 RPG 机器人。踏入主神空间,与伙伴迎接轮回试炼,书写属于你的无限冒险。",
4
- "version": "1.0.254",
4
+ "version": "1.0.255",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
@@ -3,6 +3,7 @@ import { MessageType, type IMessage, type PageNavData } from '../../shared/face'
3
3
  import type { MsgMessage } from '../../shared/bot/MsgMessage'
4
4
  import { compactDisplayText, escapeMarkdown, renderQQTitle } from './qqMarkdownHelpers'
5
5
  import { isRewardMessage, renderRewardLine, renderRewardTitle } from './qqRewardMessage'
6
+ import { artworkIdentity } from '../skillArtwork'
6
7
 
7
8
  export { escapeMarkdown, renderQQTitle } from './qqMarkdownHelpers'
8
9
 
@@ -35,6 +36,14 @@ function compactListLabel(value: string): string {
35
36
  : label
36
37
  }
37
38
 
39
+ /** QQ Markdown uses dimensions in the image label; keep the existing COS URL policy. */
40
+ function renderEntryArtwork(address?: string): string {
41
+ if (!artworkIdentity(address)) return ''
42
+ const url = new URL(address!).href.replace(/[()]/g, character =>
43
+ '%' + character.charCodeAt(0).toString(16).toUpperCase())
44
+ return `![图标 #24px #24px](${url}) `
45
+ }
46
+
38
47
  export function inlineCommandUrl(command: string): string {
39
48
  // encodeURIComponent leaves parentheses unescaped, which would close the
40
49
  // surrounding Markdown link if an item ID ever contained one.
@@ -179,6 +188,7 @@ function renderInventoryFilters(nav: PageNavData): string {
179
188
  function renderQQInventoryMarkdown(data: IMessage, showGreeting: boolean): string {
180
189
  const nav = data.pageNav!
181
190
  const entryCommands = new Map(nav.entries?.map(entry => [entry.lineIndex, entry.viewCommand]) ?? [])
191
+ const entryArtwork = new Map(nav.entries?.map(entry => [entry.lineIndex, renderEntryArtwork(entry.artworkUrl)]) ?? [])
182
192
  const sections: string[] = []
183
193
  const items: string[] = []
184
194
  const flushItems = () => {
@@ -189,7 +199,7 @@ function renderQQInventoryMarkdown(data: IMessage, showGreeting: boolean): strin
189
199
  const command = entryCommands.get(lineIndex)
190
200
  if (item.type === MessageType.line && command) {
191
201
  const label = compactListLabel(item.content.replace(/^\[\d+\]\s*/, ''))
192
- items.push(`[${escapeMarkdown(label)}](${inlineCommandUrl(command)})`)
202
+ items.push((entryArtwork.get(lineIndex) ?? '') + `[${escapeMarkdown(label)}](${inlineCommandUrl(command)})`)
193
203
  continue
194
204
  }
195
205
  flushItems()
@@ -225,6 +235,7 @@ export function renderQQPageMarkdown(data: IMessage, showGreeting: boolean): str
225
235
  const entryCommands = new Map(nav?.entries?.map(entry => [entry.lineIndex, entry.viewCommand]) ?? [])
226
236
  const labeledEntries = new Map(nav?.entries?.filter(entry => entry.label !== undefined)
227
237
  .map(entry => [entry.lineIndex, entry]) ?? [])
238
+ const entryArtwork = new Map(nav?.entries?.map(entry => [entry.lineIndex, renderEntryArtwork(entry.artworkUrl)]) ?? [])
228
239
  const listPattern = /^\[(\d+)\]\s*([^\r\n]+)$/
229
240
  const pagePattern = /^第\s*\d+\s*\/\s*\d+\s*页(?:\s*[||]\s*共\s*(\d+)\s*([项条]))?$/
230
241
  const title = data.line.find(item => item.type === MessageType.title)
@@ -261,7 +272,7 @@ export function renderQQPageMarkdown(data: IMessage, showGreeting: boolean): str
261
272
  if (labeledEntry) {
262
273
  flushList()
263
274
  flushRewards()
264
- bodyLines.push(`[${escapeMarkdown(labeledEntry.label!)}](${inlineCommandUrl(labeledEntry.viewCommand)})`
275
+ bodyLines.push((entryArtwork.get(lineIndex) ?? '') + `[${escapeMarkdown(labeledEntry.label!)}](${inlineCommandUrl(labeledEntry.viewCommand)})`
265
276
  + (labeledEntry.description ? ' ' + escapeMarkdown(labeledEntry.description) : ''))
266
277
  break
267
278
  }
@@ -283,7 +294,7 @@ export function renderQQPageMarkdown(data: IMessage, showGreeting: boolean): str
283
294
  ? `[${label}](${inlineCommandUrl(command)})`
284
295
  : renderInlineCommands(content)
285
296
  // Keep the numeric marker as Markdown syntax; escape only the item text.
286
- listLines.push(`${listEntry[1]}. ${name}`)
297
+ listLines.push(`${listEntry[1]}. ${entryArtwork.get(lineIndex) ?? ''}${name}`)
287
298
  break
288
299
  }
289
300
  flushList()
@@ -307,7 +318,7 @@ export function renderQQPageMarkdown(data: IMessage, showGreeting: boolean): str
307
318
  }
308
319
  const command = entryCommands.get(lineIndex)
309
320
  bodyLines.push(command
310
- ? `[${escapeMarkdown(compactListLabel(item.content))}](${inlineCommandUrl(command)})`
321
+ ? (entryArtwork.get(lineIndex) ?? '') + `[${escapeMarkdown(compactListLabel(item.content))}](${inlineCommandUrl(command)})`
311
322
  : renderInlineCommands(item.content))
312
323
  break
313
324
  }
@@ -20,7 +20,7 @@ export interface ServiceType {
20
20
  }
21
21
 
22
22
  export const serviceProto: ServiceProto<ServiceType> = {
23
- "version": 21,
23
+ "version": 22,
24
24
  "services": [
25
25
  {
26
26
  "id": 0,
@@ -922,6 +922,14 @@ export const serviceProto: ServiceProto<ServiceType> = {
922
922
  "type": "String"
923
923
  },
924
924
  "optional": true
925
+ },
926
+ {
927
+ "id": 4,
928
+ "name": "artworkUrl",
929
+ "type": {
930
+ "type": "String"
931
+ },
932
+ "optional": true
925
933
  }
926
934
  ]
927
935
  }
@@ -111,9 +111,11 @@ export interface PageNavData {
111
111
  entries?: Array<{
112
112
  lineIndex: number;
113
113
  viewCommand: string;
114
- /** 提供时仅此名称可点击,说明作为普通文字展示;省略时沿用整行链接。 */
114
+ /** 菜单入口名称;提供时仅此文字可点击,说明作为普通文本显示。 */
115
115
  label?: string;
116
116
  description?: string;
117
+ /** 列表名称前的小图;使用已保存插画的临时 HTTPS 链接。 */
118
+ artworkUrl?: string;
117
119
  }>;
118
120
  /** 按完整实时列表提供筛选入口;空数组表示没有可用类型。 */
119
121
  filters?: Array<{ name: string; emoji?: string; command: string }>;