koishi-plugin-noah 2.3.8 → 2.4.1

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/lib/index.cjs CHANGED
@@ -1115,8 +1115,8 @@ function registerApiRoutes(ctx, apiCtx) {
1115
1115
  "/noah/api/resolve",
1116
1116
  "/noah/api/health"
1117
1117
  ];
1118
- for (const path3 of apiPaths) {
1119
- ctx.server.all(path3, async (kctx, next) => {
1118
+ for (const path4 of apiPaths) {
1119
+ ctx.server.all(path4, async (kctx, next) => {
1120
1120
  setCors(kctx);
1121
1121
  if (kctx.method === "OPTIONS") {
1122
1122
  kctx.status = 204;
@@ -1253,20 +1253,35 @@ function registerApiRoutes(ctx, apiCtx) {
1253
1253
  const payload = authenticate(kctx);
1254
1254
  if (!payload) return unauthorized(kctx);
1255
1255
  const body = kctx.request.body;
1256
- if (!body?.type || !body?.name) return badRequest(kctx, "type and name are required");
1256
+ if (!body?.type) return badRequest(kctx, "type is required");
1257
1257
  if (!serverValues.includes(body.type)) {
1258
1258
  return badRequest(
1259
1259
  kctx,
1260
1260
  `Invalid server type. Must be one of: ${serverValues.join(", ")}`
1261
1261
  );
1262
1262
  }
1263
+ const serverType = body.type;
1264
+ let baseUrl;
1265
+ let serverName;
1266
+ if (serverType === "mao") {
1267
+ baseUrl = ctx.globalConfig.maoServerUrl;
1268
+ serverName = body.name || "MaoMaNi";
1269
+ } else if (serverType === "official") {
1270
+ baseUrl = ctx.globalConfig.official_support_url;
1271
+ serverName = body.name || "Official";
1272
+ } else {
1273
+ if (!body.baseUrl) return badRequest(kctx, "baseUrl is required for asphyxia servers");
1274
+ if (!body.name) return badRequest(kctx, "name is required for asphyxia servers");
1275
+ baseUrl = body.baseUrl;
1276
+ serverName = body.name;
1277
+ }
1263
1278
  const serverService = new ServerService(ctx);
1264
1279
  const userService = new UserService(ctx);
1265
1280
  const server2 = await serverService.createServerForUser(
1266
1281
  {
1267
- type: body.type,
1268
- name: body.name,
1269
- baseUrl: body.baseUrl ?? "",
1282
+ type: serverType,
1283
+ name: serverName,
1284
+ baseUrl,
1270
1285
  pcbid: body.pcbid,
1271
1286
  supportedGames: []
1272
1287
  },
@@ -2384,7 +2399,9 @@ __name(addServer, "addServer");
2384
2399
 
2385
2400
  // src/core/commands/settings.ts
2386
2401
  function settings(ctx, apiCtx) {
2387
- ctx.command("settings", { slash: true }).alias("设置").userFields(["id"]).action(async ({ session }) => {
2402
+ ctx.command("settings", { slash: true }).alias("设置", "setting").userFields(["id"]).channelFields(["id"]).action(async ({ session }) => {
2403
+ const atGuild = session.guildId != null;
2404
+ if (atGuild) return session.text(".dm-only");
2388
2405
  const { secret, tokenTtl, frontendUrl } = apiCtx;
2389
2406
  const token = createToken(session.user.id, secret, tokenTtl);
2390
2407
  const url = frontendUrl ? `${frontendUrl}?token=${token}` : `Token: ${token}`;
@@ -2653,10 +2670,10 @@ __name(apply4, "apply");
2653
2670
  var en_US_default2 = { _config: { $desc: "Core Module Settings", adminUsers: "**Plugin Admin** User ID (use inspect command to get)", guildNameCards: "**Group Card** Name List", maoServerUrl: "**Mao Server** URL address", official_support_url: "**Official Support** URL address", tokenTtl: "**Settings Panel** Link expiry time (seconds)", frontendUrl: "**Settings Panel** Frontend URL (/settings will generate a full link when set)", corsOrigin: "**Settings Panel** CORS allowed origin (set to frontend domain in production)" }, selector: { "card-not-found": "<p>You haven't bound a card yet, go bind one first~</p>", "server-not-found": "<p>No available servers, add one yourself~</p>", "menu-select": "<p>Please select the card you want to use:</p>\n{card_list}\n<p>q. Quit</p>", "server-menu-select": "<p>Please select the server you want to use:</p>\n{server_list}\n<p>q. Quit</p>", "invalid-select": "<p>No such option!</p>", quit: "<p>Quit!</p>", "default-card": "Default", "default-server": "Default" }, commands: { maintain: { description: "Switch to maintenance mode", messages: { "no-auth": "<p>You don't have permission to use this feature~</p>", start: "<p>Entering maintenance mode</p>", "success-start": "<p>Successfully switched to maintenance mode</p>", stop: "<p>Exiting maintenance mode</p>", "success-stop": "<p>Successfully exited maintenance mode</p>" } }, timeout: "Noah didn't wait for your reply, please try again!", help: { description: "Show Noah help information", messages: { content: "<p>Guide:</p>\n<p>https://docs.logthm.cn/noah</p>", "qq-extra": "<p>Having issues? Join group 723977027 to give feedback~</p>" } }, locale: { description: "Set language", messages: { "no-auth": "<p>Only group admins can use this feature~</p>", "invalid-select": "<p>No such option!</p>", quit: "<p>Quit!</p>", "reset-channel": "<p>Reset successfully!</p>", "reset-user": "<p>Reset successfully!</p>", success: "<p>Set successfully!</p>", "set-channel": "<p>Select the default language for group chats:</p>\n<p>1. 简体中文</p>\n<p>2. English</p>\n<p>q. Quit</p>", "set-user": "<p>Select the language you use:</p>\n<p>1. 中文</p>\n<p>2. English</p>\n<p>q. Quit</p>" } }, link: { description: "Link account to another platform", options: { remove: "Unlink" }, messages: { "generated-1": `<p>The Link command can be used to link user data across multiple platforms. During the linking process, the original platform's user data is fully preserved, while the target platform's user data is overwritten.</p>
2654
2671
  <p>Please make sure the current platform is your target platform and send the following text to the bot on the original platform within 5 minutes:</p>
2655
2672
  <p>{0}</p>
2656
- <p>Once linked, you can use "link -r" to unlink at any time.</p>`, "generated-2": "<p>Token verified! Now proceeding to the second step.</p>\n<p>Please send the following text to the bot on the target platform within 5 minutes:</p>\n<p>{0}</p>\n<p>Note: The current platform is your original platform. User data here will overwrite the target platform's data.</p>", "self-1": "<p>Please enter this on the original platform.</p>", "self-2": "<p>Please enter this on the target platform.</p>", success: "<p>Account linked successfully!</p>", "remove-success": "<p>Account unlinked successfully!</p>", "remove-original": "<p>Cannot unlink: this is your original account.</p>" } }, bind: { description: "Bind card", messages: { prompt: "<p>Please enter your card number:</p>", "convert-access-failed": "<p>Failed to convert Access Code, please use 16-digit card code instead.</p>", "invalid-code": "<p>The card number is incorrect, if you don't remember it, go to the arcade to check it~</p>", name: "<p>Received! Please give this card a name, no spaces allowed:</p>", "invalid-name": "<p>No spaces allowed! Please try again o(一︿一+)o</p>", success: "<p>Bound successfully, your card information is as follows:</p>\n<p>[{cardName}]</p>\n<p>{cardCode}</p>" } }, card: { description: "Manage cards", options: { detail: "Show detailed card information" }, messages: { "invalid-code": "<p>The card number is incorrect, if you don't remember it, go to the arcade to check it~</p>", "invalid-select": "<p>No such option!</p>", "lookup-error": "Lookup failed: {message}", "lookup-error-unknown": "Lookup failed: unknown error", "menu-select": "<p>[Card Management]</p>\n{card_list}\n<p>0. Add new card</p>\n<p>Please enter the serial number:</p>", menu: "<p>[{name}]</p>\n<p>1. Set as default card</p>\n<p>2. View or modify card number</p>\n<p>3. Delete the card</p>\n<p>4. Rename the card</p>\n<p>5. Bind the card to a specified server</p>\n<p>0. Return to card selection</p>\n<p>Please enter the serial number:</p>", "menu-has-bound-server": "<p>[{name}]</p>\n<p>Bound server: {defaultServerName}</p>\n<p>1. Set as default card</p>\n<p>2. View or modify card number</p>\n<p>3. Delete the card</p>\n<p>4. Rename the card</p>\n<p>5. Bind the card to a specified server</p>\n<p>0. Return to card selection</p>\n<p>Please enter the serial number:</p>", "menu-1-success": "<p>Set successfully!</p>", "menu-1-error-duplicate": "<p>The selected card is the same as the old default card!</p>", "menu-2-prompt": "<p>Card number: {code}</p>\n<p>Please enter the new card number:</p>\n<p>Enter 0 to return</p>", "menu-2-success": "<p>Modified successfully!</p>", "menu-2-error-invalid-code": "<p>The card number is incorrect, if you don't remember it, go to the arcade to check it~</p>", "menu-3-success": "<p>Deleted successfully!</p>", "menu-4-prompt": "<p>Enter a new name, no spaces allowed:</p>", "menu-4-error-invalid-name": "<p>No spaces allowed! Please try again o(一︿一+)o</p>", "menu-4-success": "<p>Modified successfully!</p>", "menu-5": "{server_list}\n<p>Please enter the serial number:</p>", "menu-5-success": "<p>Set successfully!</p>", "menu-5-error-duplicate": "<p>The selected server is the same as the old default server!</p>" } }, server: { description: "Manage servers", messages: { "no-channel": "<p>Please use this feature in group chats~</p>", "invalid-select": "<p>No such option!</p>", "no-auth": "<p>Only group admins can use this feature~</p>", "admin-menu-select": "<p>[Group server management]</p>\n{server_list}\n<p>0. Add new server</p>\n<p>Please enter the serial number:</p>", "menu-select": "<p>[Server management]</p>\n{server_list}\n<p>0. Add new server</p>\n<p>Please enter the serial number:</p>", menu: "<p>[{name}]</p>\n<p>Type: {type}</p>\n<p>1. Set as default server</p>\n<p>2. View or modify url</p>\n<p>3. Delete the server</p>\n<p>4. Rename the server</p>\n<p>0. Return to server selection</p>\n<p>Please enter the serial number:</p>", "menu-1-success": "<p>Set successfully!</p>", "menu-1-error-duplicate": "<p>The selected server is the same as the old default server!</p>", "menu-2-prompt": "<p>The server's url: {baseUrl}</p>\n<p>Please enter the new server url:</p>\n<p>Enter 0 to return</p>", "menu-2-success": "<p>Modified successfully!</p>", "menu-2-invalid-url": "<p>Invalid URL format! Please enter a valid url address.</p>", "menu-2-too-many-attempts": "<p>Too many attempts. Operation cancelled.</p>", "menu-3-success": "<p>Deleted successfully!</p>", "menu-4-prompt": "<p>Enter a new name, no spaces allowed:</p>", "menu-4-error-invalid-name": "<p>No spaces allowed! Please try again o(一︿一+)o</p>", "menu-4-success": "<p>Modified successfully!</p>", "add-type": "<p>Please select the server type:</p>\n{server_type_list}", "add-url": "<p>Please enter the server url:</p>", "add-invalid-url": "<p>Invalid URL format! Please enter a valid url address.</p>", "add-too-many-attempts": "<p>Too many attempts. Operation cancelled.</p>", "add-name": "<p>Received! Please give the server a name, no spaces allowed:</p>", "add-invalid-name": "<p>No spaces allowed! Please try again o(一︿一+)o</p>", "add-success": "<p>Added successfully, the server information is as follows:</p>\n<p>[{serverName}]</p>\n<p>Type: {serverType}</p>" } }, settings: { description: "Get settings panel link", messages: { success: "<p>Open the settings panel via the link below:</p>\n<p>{url}</p>\n<p>This link expires in {minutes} minutes. Do not share it.</p>" } } } };
2673
+ <p>Once linked, you can use "link -r" to unlink at any time.</p>`, "generated-2": "<p>Token verified! Now proceeding to the second step.</p>\n<p>Please send the following text to the bot on the target platform within 5 minutes:</p>\n<p>{0}</p>\n<p>Note: The current platform is your original platform. User data here will overwrite the target platform's data.</p>", "self-1": "<p>Please enter this on the original platform.</p>", "self-2": "<p>Please enter this on the target platform.</p>", success: "<p>Account linked successfully!</p>", "remove-success": "<p>Account unlinked successfully!</p>", "remove-original": "<p>Cannot unlink: this is your original account.</p>" } }, bind: { description: "Bind card", messages: { prompt: "<p>Please enter your card number:</p>", "convert-access-failed": "<p>Failed to convert Access Code, please use 16-digit card code instead.</p>", "invalid-code": "<p>The card number is incorrect, if you don't remember it, go to the arcade to check it~</p>", name: "<p>Received! Please give this card a name, no spaces allowed:</p>", "invalid-name": "<p>No spaces allowed! Please try again o(一︿一+)o</p>", success: "<p>Bound successfully, your card information is as follows:</p>\n<p>[{cardName}]</p>\n<p>{cardCode}</p>" } }, card: { description: "Manage cards", options: { detail: "Show detailed card information" }, messages: { "invalid-code": "<p>The card number is incorrect, if you don't remember it, go to the arcade to check it~</p>", "invalid-select": "<p>No such option!</p>", "lookup-error": "Lookup failed: {message}", "lookup-error-unknown": "Lookup failed: unknown error", "menu-select": "<p>[Card Management]</p>\n{card_list}\n<p>0. Add new card</p>\n<p>Please enter the serial number:</p>", menu: "<p>[{name}]</p>\n<p>1. Set as default card</p>\n<p>2. View or modify card number</p>\n<p>3. Delete the card</p>\n<p>4. Rename the card</p>\n<p>5. Bind the card to a specified server</p>\n<p>0. Return to card selection</p>\n<p>Please enter the serial number:</p>", "menu-has-bound-server": "<p>[{name}]</p>\n<p>Bound server: {defaultServerName}</p>\n<p>1. Set as default card</p>\n<p>2. View or modify card number</p>\n<p>3. Delete the card</p>\n<p>4. Rename the card</p>\n<p>5. Bind the card to a specified server</p>\n<p>0. Return to card selection</p>\n<p>Please enter the serial number:</p>", "menu-1-success": "<p>Set successfully!</p>", "menu-1-error-duplicate": "<p>The selected card is the same as the old default card!</p>", "menu-2-prompt": "<p>Card number: {code}</p>\n<p>Please enter the new card number:</p>\n<p>Enter 0 to return</p>", "menu-2-success": "<p>Modified successfully!</p>", "menu-2-error-invalid-code": "<p>The card number is incorrect, if you don't remember it, go to the arcade to check it~</p>", "menu-3-success": "<p>Deleted successfully!</p>", "menu-4-prompt": "<p>Enter a new name, no spaces allowed:</p>", "menu-4-error-invalid-name": "<p>No spaces allowed! Please try again o(一︿一+)o</p>", "menu-4-success": "<p>Modified successfully!</p>", "menu-5": "{server_list}\n<p>Please enter the serial number:</p>", "menu-5-success": "<p>Set successfully!</p>", "menu-5-error-duplicate": "<p>The selected server is the same as the old default server!</p>" } }, server: { description: "Manage servers", messages: { "no-channel": "<p>Please use this feature in group chats~</p>", "invalid-select": "<p>No such option!</p>", "no-auth": "<p>Only group admins can use this feature~</p>", "admin-menu-select": "<p>[Group server management]</p>\n{server_list}\n<p>0. Add new server</p>\n<p>Please enter the serial number:</p>", "menu-select": "<p>[Server management]</p>\n{server_list}\n<p>0. Add new server</p>\n<p>Please enter the serial number:</p>", menu: "<p>[{name}]</p>\n<p>Type: {type}</p>\n<p>1. Set as default server</p>\n<p>2. View or modify url</p>\n<p>3. Delete the server</p>\n<p>4. Rename the server</p>\n<p>0. Return to server selection</p>\n<p>Please enter the serial number:</p>", "menu-1-success": "<p>Set successfully!</p>", "menu-1-error-duplicate": "<p>The selected server is the same as the old default server!</p>", "menu-2-prompt": "<p>The server's url: {baseUrl}</p>\n<p>Please enter the new server url:</p>\n<p>Enter 0 to return</p>", "menu-2-success": "<p>Modified successfully!</p>", "menu-2-invalid-url": "<p>Invalid URL format! Please enter a valid url address.</p>", "menu-2-too-many-attempts": "<p>Too many attempts. Operation cancelled.</p>", "menu-3-success": "<p>Deleted successfully!</p>", "menu-4-prompt": "<p>Enter a new name, no spaces allowed:</p>", "menu-4-error-invalid-name": "<p>No spaces allowed! Please try again o(一︿一+)o</p>", "menu-4-success": "<p>Modified successfully!</p>", "add-type": "<p>Please select the server type:</p>\n{server_type_list}", "add-url": "<p>Please enter the server url:</p>", "add-invalid-url": "<p>Invalid URL format! Please enter a valid url address.</p>", "add-too-many-attempts": "<p>Too many attempts. Operation cancelled.</p>", "add-name": "<p>Received! Please give the server a name, no spaces allowed:</p>", "add-invalid-name": "<p>No spaces allowed! Please try again o(一︿一+)o</p>", "add-success": "<p>Added successfully, the server information is as follows:</p>\n<p>[{serverName}]</p>\n<p>Type: {serverType}</p>" } }, settings: { description: "Get settings panel link", messages: { "dm-only": "Please use this command in a direct message.", success: "<p>Open the settings panel via the link below:</p>\n<p>{url}</p>\n<p>This link expires in {minutes} minutes. Do not share it.</p>" } } } };
2657
2674
 
2658
2675
  // src/core/locales/zh-CN.yml
2659
- var zh_CN_default2 = { _config: { $desc: "Core 模块设置", adminUsers: "**插件管理员** 的用户id (使用 inspect 指令获取)", guildNameCards: "**群聊卡片** 的名称列表", tokenTtl: "**设置面板** 链接有效期(秒)", frontendUrl: "**设置面板** 前端地址(配置后 /settings 会生成完整链接)", corsOrigin: "**设置面板** CORS 允许来源(生产环境请设为前端域名)", maoServerUrl: "**猫网服务器** 的 URL 地址", official_support_url: "**官方支持** 的 URL 地址" }, selector: { "card-not-found": "<p>你还没绑卡,去绑个卡再来吧~</p>", "server-not-found": "<p>没有可用的服务器哦,自己添加一个吧~</p>", "menu-select": "<p>请选择你要使用的卡片:</p>\n{card_list}\n<p>q. 退出</p>", "server-menu-select": "<p>请选择你要使用的服务器:</p>\n{server_list}\n<p>q. 退出</p>", "invalid-select": "<p>没有该选项!</p>", quit: "<p>已退出~</p>", "default-card": "默认卡片", "default-server": "默认服务器" }, commands: { maintain: { description: "切换到维护模式", messages: { "no-auth": "<p>你没有权限使用本功能哦~</p>", start: "<p>正在进入维护模式</p>", "success-start": "<p>成功切换到维护模式</p>", stop: "<p>正在退出维护模式</p>", "success-stop": "<p>成功退出维护模式</p>" } }, timeout: "Noah 没等到你的回复,请重试!", help: { description: "显示 Noah 帮助信息", messages: { content: "<p>使用文档:</p>\n<p>https://docs.logthm.cn/noah</p>", "qq-extra": "<p>遇到问题了?加群 723977027 反馈~</p>" } }, locale: { description: "设置语言", messages: { "no-auth": "<p>只有群管理员能使用本功能哦~</p>", "invalid-select": "<p>没有该选项!</p>", quit: "<p>已退出~</p>", "reset-channel": "<p>重置成功!</p>", "reset-user": "<p>重置成功!</p>", success: "<p>设置成功!</p>", "set-channel": "<p>选择群聊默认使用的语言:</p>\n<p>1. 简体中文</p>\n<p>2. English</p>\n<p>q. 退出</p>", "set-user": "<p>选择你使用的语言:</p>\n<p>1. 简体中文</p>\n<p>2. English</p>\n<p>q. 退出</p>" } }, link: { description: "关联账号到其他平台", options: { remove: "解除关联" }, messages: { "generated-1": "<p>Link 指令可用于在多个平台间关联用户数据。关联过程中,原始平台的用户数据将完全保留,而目标平台的用户数据将被原始平台的数据所覆盖。</p>\n<p>请确认当前平台是你的目标平台,并在 5 分钟内使用你的账号在原始平台内向机器人发送以下文本:</p>\n<p>{0}</p>\n<p>关联完成后,你可以随时使用「link -r」来解除关联。</p>", "generated-2": "<p>令牌核验成功!下面将进行第二步操作。</p>\n<p>请在 5 分钟内使用你的账号在目标平台内向机器人发送以下文本:</p>\n<p>{0}</p>\n<p>注意:当前平台是你的原始平台,这里的用户数据将覆盖目标平台的数据。</p>", "self-1": "<p>请前往原始平台输入。</p>", "self-2": "<p>请前往目标平台输入。</p>", success: "<p>账号关联成功!</p>", "remove-success": "<p>账号解除关联成功!</p>", "remove-original": "<p>无法解除关联:这是你的原始账号。</p>" } }, bind: { description: "绑定卡片", messages: { prompt: "<p>请输入你的卡号:</p>", "convert-access-failed": "<p>转换 Access Code 失败,请使用 16 位卡号进行绑定。</p>", "invalid-code": "<p>卡号不对哟,不记得的话去机台刷一下吧~</p>", name: "<p>收到!为这张卡取一个名字吧,不要带空格哦:</p>", "invalid-name": "<p>名字不要带空格!重来重来 o(一︿一+)o</p>", success: "<p>绑好啦,你的卡片信息如下:</p>\n<p>[{cardName}]</p>\n<p>{cardCode}</p>" } }, card: { description: "管理卡片", options: { detail: "显示卡片详细信息" }, messages: { "invalid-code": "<p>卡号不对哟,不记得的话去机台刷一下吧~</p>", "invalid-select": "<p>没有该选项!</p>", quit: "<p>已退出~</p>", "lookup-error": "查询失败: {message}", "lookup-error-unknown": "查询失败: 未知错误", "menu-select": "<p>[卡片管理]</p>\n{card_list}\n<p>0. 添加新卡片</p>\n<p>q. 退出菜单</p>\n<p>请输入序号:</p>", menu: "<p>[{name}]</p>\n<p>1. 设为默认卡片</p>\n<p>2. 查看或修改卡号</p>\n<p>3. 删除该卡</p>\n<p>4. 重命名该卡片</p>\n<p>5. 将卡片与指定服务器绑定</p>\n<p>0. 返回卡片选择</p>\n<p>q. 退出菜单</p>\n<p>请输入序号:</p>", "menu-has-bound-server": "<p>[{name}]</p>\n<p>已绑定服务器:{defaultServerName}</p>\n<p>1. 设为默认卡片</p>\n<p>2. 查看或修改卡号</p>\n<p>3. 删除该卡</p>\n<p>4. 重命名该卡片</p>\n<p>5. 将卡片与指定服务器绑定</p>\n<p>0. 返回卡片选择</p>\n<p>q. 退出菜单</p>\n<p>请输入序号:</p>", "menu-1-success": "<p>设置成功!</p>", "menu-1-error-duplicate": "<p>选择的卡片与旧的默认卡片相同!</p>", "menu-2-prompt": "<p>卡号:{code}</p>\n<p>请输入新的卡号:</p>\n<p>0. 返回</p>\n<p>q. 退出</p>", "menu-2-success": "<p>修改成功!</p>", "menu-2-error-invalid-code": "<p>卡号不对哟,不记得的话去机台刷一下吧~</p>", "menu-3-success": "<p>已删除!</p>", "menu-4-prompt": "<p>输入一个新名字,不要带空格哦:</p>\n<p>q. 退出</p>", "menu-4-error-invalid-name": "<p>名字不要带空格!重来重来 o(一︿一+)o</p>", "menu-4-success": "<p>修改成功!</p>", "menu-5": "<p>请选择一个服务器:</p>\n{server_list}\n<p>q. 退出</p>", "menu-5-success": "<p>设置成功!</p>", "menu-5-error-duplicate": "<p>选择的服务器与旧的默认服务器相同!</p>" } }, server: { description: "管理服务器", messages: { "no-channel": "<p>请在群聊中使用本功能哦~</p>", "invalid-select": "<p>没有该选项!</p>", "no-auth": "<p>只有群管理员能使用本功能哦~</p>", quit: "<p>已退出~</p>", "admin-menu-select": "<p>[群聊服务器管理]</p>\n{server_list}\n<p>0. 添加新服务器</p>\n<p>q. 退出菜单</p>\n<p>请输入序号:</p>", "menu-select": "<p>[服务器管理]</p>\n{server_list}\n<p>0. 添加新服务器</p>\n<p>q. 退出菜单</p>\n<p>请输入序号:</p>", menu: "<p>[{name}]</p>\n<p>类型:{type}</p>\n<p>1. 设为默认服务器</p>\n<p>2. 查看或修改 url</p>\n<p>3. 删除该服务器</p>\n<p>4. 重命名该服务器</p>\n<p>0. 返回服务器选择</p>\n<p>q. 退出菜单</p>\n<p>请输入序号:</p>", "menu-1-success": "<p>设置成功!</p>", "menu-1-error-duplicate": "<p>选择的服务器与旧的默认服务器相同!</p>", "menu-2-prompt": "<p>该服务器的 url:{baseUrl}</p>\n<p>请输入新的服务器 url:</p>\n<p>0. 返回</p>\n<p>q. 退出</p>", "menu-2-success": "<p>修改成功!</p>", "menu-2-invalid-url": "<p>URL 格式不正确!请输入有效的 url 地址。</p>", "menu-2-too-many-attempts": "<p>尝试次数过多,操作已取消。</p>", "menu-3-success": "<p>已删除!</p>", "menu-4-prompt": "<p>输入一个新名字,不要带空格哦:</p>\n<p>0. 返回</p>\n<p>q. 退出</p>", "menu-4-error-invalid-name": "<p>名字不要带空格!重来重来 o(一︿一+)o</p>", "menu-4-success": "<p>修改成功!</p>", "add-type": "<p>请选择服务器的类型:</p>\n{server_type_list}\n<p>q. 退出</p>", "add-url": "<p>请输入服务器的 url:</p>\n<p>q. 退出</p>", "add-invalid-url": "<p>URL 格式不正确!请输入有效的 url 地址。</p>", "add-too-many-attempts": "<p>尝试次数过多,操作已取消。</p>", "add-name": "<p>收到!为服务器取一个名字吧,不要带空格哦:</p>\n<p>q. 退出</p>", "add-invalid-name": "<p>名字不要带空格!重来重来 o(一︿一+)o</p>", "add-success": "<p>添加成功啦,服务器信息如下:</p>\n<p>[{serverName}]</p>\n<p>类型:{serverType}</p>" } }, settings: { description: "获取设置面板链接", messages: { success: "<p>点击下方链接打开设置面板:</p>\n<p>{url}</p>\n<p>链接有效期 {minutes} 分钟,请勿分享给他人。</p>" } } } };
2676
+ var zh_CN_default2 = { _config: { $desc: "Core 模块设置", adminUsers: "**插件管理员** 的用户id (使用 inspect 指令获取)", guildNameCards: "**群聊卡片** 的名称列表", tokenTtl: "**设置面板** 链接有效期(秒)", frontendUrl: "**设置面板** 前端地址(配置后 /settings 会生成完整链接)", corsOrigin: "**设置面板** CORS 允许来源(生产环境请设为前端域名)", maoServerUrl: "**猫网服务器** 的 URL 地址", official_support_url: "**官方支持** 的 URL 地址" }, selector: { "card-not-found": "<p>你还没绑卡,去绑个卡再来吧~</p>", "server-not-found": "<p>没有可用的服务器哦,自己添加一个吧~</p>", "menu-select": "<p>请选择你要使用的卡片:</p>\n{card_list}\n<p>q. 退出</p>", "server-menu-select": "<p>请选择你要使用的服务器:</p>\n{server_list}\n<p>q. 退出</p>", "invalid-select": "<p>没有该选项!</p>", quit: "<p>已退出~</p>", "default-card": "默认卡片", "default-server": "默认服务器" }, commands: { maintain: { description: "切换到维护模式", messages: { "no-auth": "<p>你没有权限使用本功能哦~</p>", start: "<p>正在进入维护模式</p>", "success-start": "<p>成功切换到维护模式</p>", stop: "<p>正在退出维护模式</p>", "success-stop": "<p>成功退出维护模式</p>" } }, timeout: "Noah 没等到你的回复,请重试!", help: { description: "显示 Noah 帮助信息", messages: { content: "<p>使用文档:</p>\n<p>https://docs.logthm.cn/noah</p>", "qq-extra": "<p>遇到问题了?加群 723977027 反馈~</p>" } }, locale: { description: "设置语言", messages: { "no-auth": "<p>只有群管理员能使用本功能哦~</p>", "invalid-select": "<p>没有该选项!</p>", quit: "<p>已退出~</p>", "reset-channel": "<p>重置成功!</p>", "reset-user": "<p>重置成功!</p>", success: "<p>设置成功!</p>", "set-channel": "<p>选择群聊默认使用的语言:</p>\n<p>1. 简体中文</p>\n<p>2. English</p>\n<p>q. 退出</p>", "set-user": "<p>选择你使用的语言:</p>\n<p>1. 简体中文</p>\n<p>2. English</p>\n<p>q. 退出</p>" } }, link: { description: "关联账号到其他平台", options: { remove: "解除关联" }, messages: { "generated-1": "<p>Link 指令可用于在多个平台间关联用户数据。关联过程中,原始平台的用户数据将完全保留,而目标平台的用户数据将被原始平台的数据所覆盖。</p>\n<p>请确认当前平台是你的目标平台,并在 5 分钟内使用你的账号在原始平台内向机器人发送以下文本:</p>\n<p>{0}</p>\n<p>关联完成后,你可以随时使用「link -r」来解除关联。</p>", "generated-2": "<p>令牌核验成功!下面将进行第二步操作。</p>\n<p>请在 5 分钟内使用你的账号在目标平台内向机器人发送以下文本:</p>\n<p>{0}</p>\n<p>注意:当前平台是你的原始平台,这里的用户数据将覆盖目标平台的数据。</p>", "self-1": "<p>请前往原始平台输入。</p>", "self-2": "<p>请前往目标平台输入。</p>", success: "<p>账号关联成功!</p>", "remove-success": "<p>账号解除关联成功!</p>", "remove-original": "<p>无法解除关联:这是你的原始账号。</p>" } }, bind: { description: "绑定卡片", messages: { prompt: "<p>请输入你的卡号:</p>", "convert-access-failed": "<p>转换 Access Code 失败,请使用 16 位卡号进行绑定。</p>", "invalid-code": "<p>卡号不对哟,不记得的话去机台刷一下吧~</p>", name: "<p>收到!为这张卡取一个名字吧,不要带空格哦:</p>", "invalid-name": "<p>名字不要带空格!重来重来 o(一︿一+)o</p>", success: "<p>绑好啦,你的卡片信息如下:</p>\n<p>[{cardName}]</p>\n<p>{cardCode}</p>" } }, card: { description: "管理卡片", options: { detail: "显示卡片详细信息" }, messages: { "invalid-code": "<p>卡号不对哟,不记得的话去机台刷一下吧~</p>", "invalid-select": "<p>没有该选项!</p>", quit: "<p>已退出~</p>", "lookup-error": "查询失败: {message}", "lookup-error-unknown": "查询失败: 未知错误", "menu-select": "<p>[卡片管理]</p>\n{card_list}\n<p>0. 添加新卡片</p>\n<p>q. 退出菜单</p>\n<p>请输入序号:</p>", menu: "<p>[{name}]</p>\n<p>1. 设为默认卡片</p>\n<p>2. 查看或修改卡号</p>\n<p>3. 删除该卡</p>\n<p>4. 重命名该卡片</p>\n<p>5. 将卡片与指定服务器绑定</p>\n<p>0. 返回卡片选择</p>\n<p>q. 退出菜单</p>\n<p>请输入序号:</p>", "menu-has-bound-server": "<p>[{name}]</p>\n<p>已绑定服务器:{defaultServerName}</p>\n<p>1. 设为默认卡片</p>\n<p>2. 查看或修改卡号</p>\n<p>3. 删除该卡</p>\n<p>4. 重命名该卡片</p>\n<p>5. 将卡片与指定服务器绑定</p>\n<p>0. 返回卡片选择</p>\n<p>q. 退出菜单</p>\n<p>请输入序号:</p>", "menu-1-success": "<p>设置成功!</p>", "menu-1-error-duplicate": "<p>选择的卡片与旧的默认卡片相同!</p>", "menu-2-prompt": "<p>卡号:{code}</p>\n<p>请输入新的卡号:</p>\n<p>0. 返回</p>\n<p>q. 退出</p>", "menu-2-success": "<p>修改成功!</p>", "menu-2-error-invalid-code": "<p>卡号不对哟,不记得的话去机台刷一下吧~</p>", "menu-3-success": "<p>已删除!</p>", "menu-4-prompt": "<p>输入一个新名字,不要带空格哦:</p>\n<p>q. 退出</p>", "menu-4-error-invalid-name": "<p>名字不要带空格!重来重来 o(一︿一+)o</p>", "menu-4-success": "<p>修改成功!</p>", "menu-5": "<p>请选择一个服务器:</p>\n{server_list}\n<p>q. 退出</p>", "menu-5-success": "<p>设置成功!</p>", "menu-5-error-duplicate": "<p>选择的服务器与旧的默认服务器相同!</p>" } }, server: { description: "管理服务器", messages: { "no-channel": "<p>请在群聊中使用本功能哦~</p>", "invalid-select": "<p>没有该选项!</p>", "no-auth": "<p>只有群管理员能使用本功能哦~</p>", quit: "<p>已退出~</p>", "admin-menu-select": "<p>[群聊服务器管理]</p>\n{server_list}\n<p>0. 添加新服务器</p>\n<p>q. 退出菜单</p>\n<p>请输入序号:</p>", "menu-select": "<p>[服务器管理]</p>\n{server_list}\n<p>0. 添加新服务器</p>\n<p>q. 退出菜单</p>\n<p>请输入序号:</p>", menu: "<p>[{name}]</p>\n<p>类型:{type}</p>\n<p>1. 设为默认服务器</p>\n<p>2. 查看或修改 url</p>\n<p>3. 删除该服务器</p>\n<p>4. 重命名该服务器</p>\n<p>0. 返回服务器选择</p>\n<p>q. 退出菜单</p>\n<p>请输入序号:</p>", "menu-1-success": "<p>设置成功!</p>", "menu-1-error-duplicate": "<p>选择的服务器与旧的默认服务器相同!</p>", "menu-2-prompt": "<p>该服务器的 url:{baseUrl}</p>\n<p>请输入新的服务器 url:</p>\n<p>0. 返回</p>\n<p>q. 退出</p>", "menu-2-success": "<p>修改成功!</p>", "menu-2-invalid-url": "<p>URL 格式不正确!请输入有效的 url 地址。</p>", "menu-2-too-many-attempts": "<p>尝试次数过多,操作已取消。</p>", "menu-3-success": "<p>已删除!</p>", "menu-4-prompt": "<p>输入一个新名字,不要带空格哦:</p>\n<p>0. 返回</p>\n<p>q. 退出</p>", "menu-4-error-invalid-name": "<p>名字不要带空格!重来重来 o(一︿一+)o</p>", "menu-4-success": "<p>修改成功!</p>", "add-type": "<p>请选择服务器的类型:</p>\n{server_type_list}\n<p>q. 退出</p>", "add-url": "<p>请输入服务器的 url:</p>\n<p>q. 退出</p>", "add-invalid-url": "<p>URL 格式不正确!请输入有效的 url 地址。</p>", "add-too-many-attempts": "<p>尝试次数过多,操作已取消。</p>", "add-name": "<p>收到!为服务器取一个名字吧,不要带空格哦:</p>\n<p>q. 退出</p>", "add-invalid-name": "<p>名字不要带空格!重来重来 o(一︿一+)o</p>", "add-success": "<p>添加成功啦,服务器信息如下:</p>\n<p>[{serverName}]</p>\n<p>类型:{serverType}</p>" } }, settings: { description: "获取设置面板链接", messages: { "dm-only": "请在私聊中使用此命令。", success: "<p>点击下方链接打开设置面板:</p>\n<p>{url}</p>\n<p>链接有效期 {minutes} 分钟,请勿分享给他人。</p>" } } } };
2660
2677
 
2661
2678
  // src/core/index.ts
2662
2679
  var name5 = "Noah-Core";
@@ -3314,8 +3331,8 @@ var SDVXDrawer = class extends BaseDrawer {
3314
3331
  ["Fredoka One", "fonts/FredokaOne.ttf"]
3315
3332
  ];
3316
3333
  for (const [name15, file] of fonts) {
3317
- const path3 = getAssetPath(this.ctx, file);
3318
- if (fs2.existsSync(path3)) FontLibrary.use(name15, path3);
3334
+ const path4 = getAssetPath(this.ctx, file);
3335
+ if (fs2.existsSync(path4)) FontLibrary.use(name15, path4);
3319
3336
  }
3320
3337
  this.fontsLoaded = true;
3321
3338
  }
@@ -3421,20 +3438,20 @@ var SDVXDrawer = class extends BaseDrawer {
3421
3438
  ctx.save();
3422
3439
  ctx.translate(556, 17);
3423
3440
  ctx.beginPath();
3424
- const r = 16, w = 100, h11 = 200, x0 = 0, y0 = 0;
3441
+ const r = 16, w = 100, h12 = 200, x0 = 0, y0 = 0;
3425
3442
  ctx.moveTo(x0 + r, y0);
3426
3443
  ctx.lineTo(x0 + w - r, y0);
3427
3444
  ctx.arcTo(x0 + w, y0, x0 + w, y0 + r, r);
3428
- ctx.lineTo(x0 + w, y0 + h11 - r);
3429
- ctx.arcTo(x0 + w, y0 + h11, x0 + w - r, y0 + h11, r);
3430
- ctx.lineTo(x0 + r, y0 + h11);
3431
- ctx.arcTo(x0, y0 + h11, x0, y0 + h11 - r, r);
3445
+ ctx.lineTo(x0 + w, y0 + h12 - r);
3446
+ ctx.arcTo(x0 + w, y0 + h12, x0 + w - r, y0 + h12, r);
3447
+ ctx.lineTo(x0 + r, y0 + h12);
3448
+ ctx.arcTo(x0, y0 + h12, x0, y0 + h12 - r, r);
3432
3449
  ctx.lineTo(x0, y0 + r);
3433
3450
  ctx.arcTo(x0, y0, x0 + r, y0, r);
3434
3451
  ctx.closePath();
3435
3452
  const circleRadius = 14;
3436
3453
  const circleX = x0 + w;
3437
- const circleY = y0 + h11 / 2;
3454
+ const circleY = y0 + h12 / 2;
3438
3455
  ctx.moveTo(circleX + circleRadius, circleY);
3439
3456
  ctx.arc(circleX, circleY, circleRadius, 0, Math.PI * 2, true);
3440
3457
  ctx.clip();
@@ -4263,154 +4280,20 @@ __name(apply6, "apply");
4263
4280
  var poke_exports = {};
4264
4281
  __export(poke_exports, {
4265
4282
  apply: () => apply7,
4283
+ logger: () => logger3,
4266
4284
  name: () => name7
4267
4285
  });
4268
- var fs3 = __toESM(require("fs"), 1);
4269
- var path2 = __toESM(require("path"), 1);
4270
- var import_koishi8 = require("koishi");
4271
-
4272
- // src/fun/poke/locales/en-US.yml
4273
- var en_US_default3 = { _config: { $desc: "Poke Module Settings", interval: "最小触发间隔(毫秒)", warning: "频繁触发是否发送警告", prompt: "警告内容", messages: { $desc: "消息内容", content: "消息内容", weight: "权重" } }, commands: { poke: { description: "poke" } } };
4274
-
4275
- // src/fun/poke/locales/zh-CN.yml
4276
- var zh_CN_default3 = { _config: { $desc: "Poke 模块设置", interval: "最小触发间隔(毫秒)", warning: "频繁触发是否发送警告", prompt: { $desc: "警告内容", content: "消息", weight: "权重" }, messages: { $desc: "消息内容", content: "消息", weight: "权重" } }, commands: { poke: { description: "戳一戳" } } };
4286
+ var import_koishi10 = require("koishi");
4277
4287
 
4278
- // src/fun/poke/index.ts
4279
- var name7 = "Noah-Poke";
4280
- function apply7(ctx, config) {
4281
- ;
4282
- [
4283
- ["en-US", en_US_default3],
4284
- ["zh-CN", zh_CN_default3]
4285
- ].forEach(([lang, file]) => ctx.i18n.define(lang, file));
4286
- const cache = /* @__PURE__ */ new Map();
4287
- const pokeConfig2 = config.poke;
4288
- const IMAGE_EXTENSIONS = [".png", ".jpg", ".jpeg", ".gif", ".webp"];
4289
- function isImageFile(filename) {
4290
- const ext = path2.extname(filename).toLowerCase();
4291
- return IMAGE_EXTENSIONS.includes(ext);
4292
- }
4293
- __name(isImageFile, "isImageFile");
4294
- function getMimeType(filename) {
4295
- const ext = path2.extname(filename).toLowerCase();
4296
- switch (ext) {
4297
- case ".png":
4298
- return "image/png";
4299
- case ".jpg":
4300
- case ".jpeg":
4301
- return "image/jpeg";
4302
- case ".gif":
4303
- return "image/gif";
4304
- case ".webp":
4305
- return "image/webp";
4306
- default:
4307
- return "image/png";
4308
- }
4309
- }
4310
- __name(getMimeType, "getMimeType");
4311
- function findMatchingAudio(imagePath) {
4312
- try {
4313
- const dir = path2.dirname(imagePath);
4314
- const filename = path2.basename(imagePath);
4315
- const match = filename.match(/_(\d+)\.(png|jpg|jpeg|gif|webp)$/i);
4316
- if (!match) {
4317
- return null;
4318
- }
4319
- const imageNumber = match[1];
4320
- const audioNumber = parseInt(imageNumber, 10).toString();
4321
- const files = fs3.readdirSync(dir);
4322
- const audioFile = files.find((file) => {
4323
- return file.endsWith(`-${audioNumber}.mp3`);
4324
- });
4325
- return audioFile ? path2.join(dir, audioFile) : null;
4326
- } catch {
4327
- return null;
4328
- }
4329
- }
4330
- __name(findMatchingAudio, "findMatchingAudio");
4331
- async function sendRandomNoahStamp(ctx2, session, voiceOnly = false) {
4332
- try {
4333
- const stampsPath = getAssetPath(ctx2, "stamps/noah_stamp");
4334
- const stampDirs = fs3.readdirSync(stampsPath).filter((dir) => dir.startsWith("stamp_"));
4335
- if (stampDirs.length === 0) {
4336
- await session.sendQueued("No stamps found!");
4337
- return;
4338
- }
4339
- const allStamps = [];
4340
- for (const dir of stampDirs) {
4341
- const stampDirPath = path2.join(stampsPath, dir);
4342
- const stampFiles = fs3.readdirSync(stampDirPath).filter((file) => file.startsWith(dir) && isImageFile(file));
4343
- stampFiles.forEach((file) => {
4344
- allStamps.push({
4345
- path: path2.join(stampDirPath, file),
4346
- dirName: dir
4347
- });
4348
- });
4349
- }
4350
- if (allStamps.length === 0) {
4351
- await session.sendQueued("No stamps found in any directory!");
4352
- return;
4353
- }
4354
- let availableStamps = allStamps;
4355
- if (voiceOnly) {
4356
- availableStamps = allStamps.filter((stamp) => {
4357
- const audioPath2 = findMatchingAudio(stamp.path);
4358
- return audioPath2 && fs3.existsSync(audioPath2);
4359
- });
4360
- if (availableStamps.length === 0) {
4361
- await session.sendQueued("No stamps with voice found!");
4362
- return;
4363
- }
4364
- }
4365
- const randomStamp = availableStamps[Math.floor(Math.random() * availableStamps.length)];
4366
- ctx2.logger("Noah-Poke").debug(`Selected stamp from ${randomStamp.dirName}`);
4367
- if (!fs3.existsSync(randomStamp.path)) {
4368
- await session.sendQueued("Selected stamp not found!");
4369
- return;
4370
- }
4371
- const imageBuffer = fs3.readFileSync(randomStamp.path);
4372
- const audioPath = findMatchingAudio(randomStamp.path);
4373
- await session.sendQueued(import_koishi8.h.image(imageBuffer, getMimeType(randomStamp.path)));
4374
- if (audioPath && fs3.existsSync(audioPath)) {
4375
- ctx2.logger("Noah-Poke").debug(`Found matching audio: ${path2.basename(audioPath)}`);
4376
- const audioBuffer = fs3.readFileSync(audioPath);
4377
- await session.sendQueued(import_koishi8.h.audio(audioBuffer, "audio/mpeg"));
4378
- }
4379
- } catch (error) {
4380
- ctx2.logger("Noah-Poke").error(`Error sending noah stamp: ${error.message}`);
4381
- await session.sendQueued("Failed to send noah stamp.");
4382
- }
4383
- }
4384
- __name(sendRandomNoahStamp, "sendRandomNoahStamp");
4385
- async function sendRandomChatStamp(ctx2) {
4386
- try {
4387
- const stampsPath = getAssetPath(ctx2, "stamps/chat_stamp");
4388
- const stampFiles = fs3.readdirSync(stampsPath).filter((file) => isImageFile(file));
4389
- if (stampFiles.length === 0) {
4390
- return "No chat stamps found!";
4391
- }
4392
- const randomStamp = stampFiles[Math.floor(Math.random() * stampFiles.length)];
4393
- const stampPath = path2.join(stampsPath, randomStamp);
4394
- if (!fs3.existsSync(stampPath)) {
4395
- return "Selected stamp not found!";
4396
- }
4397
- const imageBuffer = fs3.readFileSync(stampPath);
4398
- return import_koishi8.h.image(imageBuffer, getMimeType(stampPath));
4399
- } catch (error) {
4400
- ctx2.logger("Noah-Poke").error(`Error sending chat stamp: ${error.message}`);
4401
- return "Failed to send chat stamp.";
4402
- }
4403
- }
4404
- __name(sendRandomChatStamp, "sendRandomChatStamp");
4405
- ctx.command("stamp").option("type", "-t [type]").option("voice", "-v", { fallback: false }).action(async ({ session, options }) => {
4406
- if (options.type == "noah") {
4407
- await sendRandomNoahStamp(ctx, session, options.voice);
4408
- } else if (options.type == "chat") {
4409
- return sendRandomChatStamp(ctx);
4410
- } else {
4411
- return sendRandomChatStamp(ctx);
4412
- }
4413
- });
4288
+ // src/fun/poke/commands/poke.ts
4289
+ function parsePlatform(target) {
4290
+ const index = target.indexOf(":");
4291
+ const platform = target.slice(0, index);
4292
+ const id = target.slice(index + 1);
4293
+ return [platform, id];
4294
+ }
4295
+ __name(parsePlatform, "parsePlatform");
4296
+ function registerPokeCommand(ctx) {
4414
4297
  ctx.platform("onebot").command("poke [target:user]").action(async ({ session }, target) => {
4415
4298
  if (!session.onebot) {
4416
4299
  return;
@@ -4418,7 +4301,7 @@ function apply7(ctx, config) {
4418
4301
  const params = { user_id: session.userId };
4419
4302
  if (target) {
4420
4303
  const [platform, id] = parsePlatform(target);
4421
- if (platform != "onebot") {
4304
+ if (platform !== "onebot") {
4422
4305
  return;
4423
4306
  }
4424
4307
  params.user_id = id;
@@ -4426,66 +4309,292 @@ function apply7(ctx, config) {
4426
4309
  if (session.isDirect) {
4427
4310
  await session.onebot._request("friend_poke", params);
4428
4311
  } else {
4429
- params["group_id"] = session.guildId;
4312
+ params.group_id = session.guildId;
4430
4313
  await session.onebot._request("group_poke", params);
4431
4314
  }
4432
4315
  });
4433
- ctx.platform("onebot").on("notice", async (session) => {
4434
- if (session.subtype != "poke") {
4316
+ }
4317
+ __name(registerPokeCommand, "registerPokeCommand");
4318
+
4319
+ // src/fun/poke/utils/stamp.ts
4320
+ var fs4 = __toESM(require("fs"), 1);
4321
+ var path3 = __toESM(require("path"), 1);
4322
+ var import_koishi8 = require("koishi");
4323
+
4324
+ // src/fun/poke/utils/file.ts
4325
+ var fs3 = __toESM(require("fs"), 1);
4326
+ var path2 = __toESM(require("path"), 1);
4327
+
4328
+ // src/fun/poke/constants.ts
4329
+ var IMAGE_EXTENSIONS = [".png", ".jpg", ".jpeg", ".gif", ".webp"];
4330
+ var MIME_MAP = {
4331
+ ".png": "image/png",
4332
+ ".jpg": "image/jpeg",
4333
+ ".jpeg": "image/jpeg",
4334
+ ".gif": "image/gif",
4335
+ ".webp": "image/webp"
4336
+ };
4337
+ var DEFAULT_MIME = "image/png";
4338
+ var DEFAULT_LOCALE = "zh-CN";
4339
+ var TIP_POOL = {
4340
+ "zh-CN": [
4341
+ "你知道吗: 《FIN4LE ~終止線の彼方へ~》在发布 337 天后才出现首个 PUC。",
4342
+ "你知道吗: Near 是双子中的姐姐哟~",
4343
+ "你知道吗: Noah 是双子中的妹妹哟~",
4344
+ "你知道吗: 可以看刘海方向来区分 Near 和 Noah。",
4345
+ "你知道吗: Near 和 Noah 就读于ボルテ学園初等部。",
4346
+ "你知道吗: 元气满满的是姐姐 Near,文静的是妹妹 Noah。",
4347
+ "你知道吗: Near 和 Noah 的兔子鞋是烈风刀送给她们的。",
4348
+ "你知道吗: Near 和 Noah 都会飞哟~",
4349
+ "你知道吗: Near 和 Noah 初登场于 BOOTH 代歌曲《freaky freak》。",
4350
+ "你知道吗: Near 和 Noah 的 CV 为 日高里菜。",
4351
+ "你知道吗: Near 和 Noah 的身高是 140 cm。",
4352
+ "你知道吗: Near 和 Noah 的生日是 6 月 10 日。"
4353
+ ],
4354
+ "en-US": [
4355
+ "Do you know: FIN4LE ~終止線の彼方へ~ took 337 days to get its first PUC.",
4356
+ "Do you know: Near is the older sister of the twin.",
4357
+ "Do you know: Noah is the younger sister of the twin.",
4358
+ "Do you know: You can tell Near and Noah apart by their hair direction.",
4359
+ "Do you know: Near and Noah attend ボルテ学園初等部.",
4360
+ "Do you know: The energetic Near is the older sister, while the quiet Noah is the younger sister.",
4361
+ "Do you know: Near and Noah received their rabbit shoes from 烈风刀.",
4362
+ "Do you know: Near and Noah can fly.",
4363
+ 'Do you know: Near and Noah made their debut in the BOOTH song "freaky freak".',
4364
+ "Do you know: Near and Noah's CV is 日高里菜.",
4365
+ "Do you know: Near and Noah's height is 140 cm.",
4366
+ "Do you know: Near and Noah's birthday is June 10th."
4367
+ ]
4368
+ };
4369
+
4370
+ // src/fun/poke/utils/file.ts
4371
+ function isImageFile(filename) {
4372
+ const ext = path2.extname(filename).toLowerCase();
4373
+ return IMAGE_EXTENSIONS.includes(ext);
4374
+ }
4375
+ __name(isImageFile, "isImageFile");
4376
+ function getMimeType(filename) {
4377
+ const ext = path2.extname(filename).toLowerCase();
4378
+ return MIME_MAP[ext] ?? DEFAULT_MIME;
4379
+ }
4380
+ __name(getMimeType, "getMimeType");
4381
+ function findMatchingAudio(imagePath) {
4382
+ try {
4383
+ const dir = path2.dirname(imagePath);
4384
+ const filename = path2.basename(imagePath);
4385
+ const match = filename.match(/_(\d+)\.(png|jpg|jpeg|gif|webp)$/i);
4386
+ if (!match) {
4387
+ return null;
4388
+ }
4389
+ const audioNumber = parseInt(match[1], 10).toString();
4390
+ const files = fs3.readdirSync(dir);
4391
+ const audioFile = files.find((file) => file.endsWith(`-${audioNumber}.mp3`));
4392
+ return audioFile ? path2.join(dir, audioFile) : null;
4393
+ } catch {
4394
+ return null;
4395
+ }
4396
+ }
4397
+ __name(findMatchingAudio, "findMatchingAudio");
4398
+
4399
+ // src/fun/poke/utils/random.ts
4400
+ function randomMessage(items) {
4401
+ if (items.length === 0) {
4402
+ return void 0;
4403
+ }
4404
+ const totalWeight = items.reduce((sum2, cur) => sum2 + cur.weight, 0);
4405
+ const random = Math.random() * totalWeight;
4406
+ let sum = 0;
4407
+ for (const item of items) {
4408
+ sum += item.weight;
4409
+ if (random < sum) return item;
4410
+ }
4411
+ return items[items.length - 1];
4412
+ }
4413
+ __name(randomMessage, "randomMessage");
4414
+ function pickRandom(items) {
4415
+ if (items.length === 0) {
4416
+ return void 0;
4417
+ }
4418
+ return items[Math.floor(Math.random() * items.length)];
4419
+ }
4420
+ __name(pickRandom, "pickRandom");
4421
+
4422
+ // src/fun/poke/utils/stamp.ts
4423
+ var LOGGER_NAME = "Noah-Poke";
4424
+ function collectNoahStamps(stampsPath) {
4425
+ const stampDirs = fs4.readdirSync(stampsPath).filter((dir) => dir.startsWith("stamp_"));
4426
+ const allStamps = [];
4427
+ for (const dir of stampDirs) {
4428
+ const stampDirPath = path3.join(stampsPath, dir);
4429
+ const stampFiles = fs4.readdirSync(stampDirPath).filter((file) => file.startsWith(dir) && isImageFile(file));
4430
+ stampFiles.forEach((file) => {
4431
+ allStamps.push({ path: path3.join(stampDirPath, file), dirName: dir });
4432
+ });
4433
+ }
4434
+ return allStamps;
4435
+ }
4436
+ __name(collectNoahStamps, "collectNoahStamps");
4437
+ async function sendRandomNoahStamp(ctx, session, voiceOnly = false) {
4438
+ const logger6 = ctx.logger(LOGGER_NAME);
4439
+ try {
4440
+ const stampsPath = getAssetPath(ctx, "stamps/noah_stamp");
4441
+ const allStamps = collectNoahStamps(stampsPath);
4442
+ if (allStamps.length === 0) {
4443
+ await session.sendQueued("No stamps found!");
4444
+ return;
4445
+ }
4446
+ const availableStamps = voiceOnly ? allStamps.filter((stamp) => {
4447
+ const audioPath2 = findMatchingAudio(stamp.path);
4448
+ return audioPath2 && fs4.existsSync(audioPath2);
4449
+ }) : allStamps;
4450
+ if (availableStamps.length === 0) {
4451
+ await session.sendQueued("No stamps with voice found!");
4452
+ return;
4453
+ }
4454
+ const randomStamp = pickRandom(availableStamps);
4455
+ logger6.debug(`Selected stamp from ${randomStamp.dirName}`);
4456
+ if (!fs4.existsSync(randomStamp.path)) {
4457
+ await session.sendQueued("Selected stamp not found!");
4458
+ return;
4459
+ }
4460
+ const imageBuffer = fs4.readFileSync(randomStamp.path);
4461
+ await session.sendQueued(import_koishi8.h.image(imageBuffer, getMimeType(randomStamp.path)));
4462
+ const audioPath = findMatchingAudio(randomStamp.path);
4463
+ if (audioPath && fs4.existsSync(audioPath)) {
4464
+ logger6.debug(`Found matching audio: ${path3.basename(audioPath)}`);
4465
+ const audioBuffer = fs4.readFileSync(audioPath);
4466
+ await session.sendQueued(import_koishi8.h.audio(audioBuffer, "audio/mpeg"));
4467
+ }
4468
+ } catch (error) {
4469
+ logger6.error(`Error sending noah stamp: ${error.message}`);
4470
+ await session.sendQueued("Failed to send noah stamp.");
4471
+ }
4472
+ }
4473
+ __name(sendRandomNoahStamp, "sendRandomNoahStamp");
4474
+ function getRandomChatStamp(ctx) {
4475
+ const logger6 = ctx.logger(LOGGER_NAME);
4476
+ try {
4477
+ const stampsPath = getAssetPath(ctx, "stamps/chat_stamp");
4478
+ const stampFiles = fs4.readdirSync(stampsPath).filter((file) => isImageFile(file));
4479
+ if (stampFiles.length === 0) {
4480
+ return "No chat stamps found!";
4481
+ }
4482
+ const randomStamp = pickRandom(stampFiles);
4483
+ const stampPath = path3.join(stampsPath, randomStamp);
4484
+ if (!fs4.existsSync(stampPath)) {
4485
+ return "Selected stamp not found!";
4486
+ }
4487
+ const imageBuffer = fs4.readFileSync(stampPath);
4488
+ return import_koishi8.h.image(imageBuffer, getMimeType(stampPath));
4489
+ } catch (error) {
4490
+ logger6.error(`Error sending chat stamp: ${error.message}`);
4491
+ return "Failed to send chat stamp.";
4492
+ }
4493
+ }
4494
+ __name(getRandomChatStamp, "getRandomChatStamp");
4495
+
4496
+ // src/fun/poke/commands/stamp.ts
4497
+ function registerStampCommand(ctx) {
4498
+ ctx.command("stamp").option("type", "-t [type]").option("voice", "-v", { fallback: false }).action(async ({ session, options }) => {
4499
+ if (options.type === "noah") {
4500
+ await sendRandomNoahStamp(ctx, session, options.voice);
4435
4501
  return;
4436
4502
  }
4437
- if (session.targetId != session.selfId) {
4503
+ return getRandomChatStamp(ctx);
4504
+ });
4505
+ }
4506
+ __name(registerStampCommand, "registerStampCommand");
4507
+
4508
+ // src/fun/poke/events/notice.ts
4509
+ var import_koishi9 = require("koishi");
4510
+
4511
+ // src/fun/poke/utils/tip.ts
4512
+ async function pickTip(session) {
4513
+ const user = await session.observeUser(["locales"]);
4514
+ const locales = user.locales ?? [];
4515
+ for (const locale2 of locales) {
4516
+ const tips = TIP_POOL[locale2];
4517
+ if (tips && tips.length > 0) {
4518
+ return pickRandom(tips);
4519
+ }
4520
+ }
4521
+ return pickRandom(TIP_POOL[DEFAULT_LOCALE] ?? []);
4522
+ }
4523
+ __name(pickTip, "pickTip");
4524
+
4525
+ // src/fun/poke/events/notice.ts
4526
+ function registerPokeNotice(ctx, config, cache) {
4527
+ ctx.platform("onebot").on("notice", async (session) => {
4528
+ if (session.subtype !== "poke" || session.targetId !== session.selfId) {
4438
4529
  return;
4439
4530
  }
4440
- if (pokeConfig2.interval > 0 && cache.has(session.userId)) {
4531
+ if (config.interval > 0 && cache.has(session.userId)) {
4441
4532
  const ts = cache.get(session.userId);
4442
- if (session.timestamp - ts < pokeConfig2.interval) {
4443
- if (pokeConfig2.warning) {
4444
- const msg = randomMessage(pokeConfig2.prompt);
4445
- const content = import_koishi8.h.parse(msg, session);
4446
- session.sendQueued(content);
4533
+ if (session.timestamp - ts < config.interval) {
4534
+ if (config.warning) {
4535
+ const msg2 = randomMessage(config.prompt);
4536
+ if (msg2) {
4537
+ await session.sendQueued(import_koishi9.h.parse(msg2.content, session));
4538
+ }
4447
4539
  }
4448
4540
  return;
4449
4541
  }
4450
4542
  }
4451
4543
  cache.set(session.userId, session.timestamp);
4452
- if (pokeConfig2.messages.length > 0) {
4453
- const msg = randomMessage(pokeConfig2.messages);
4454
- const content = import_koishi8.h.parse(msg, session);
4455
- await session.sendQueued(content);
4544
+ if (config.messages.length === 0) {
4545
+ return;
4546
+ }
4547
+ const msg = randomMessage(config.messages);
4548
+ if (!msg) {
4549
+ return;
4550
+ }
4551
+ if (msg.type === "noah") {
4552
+ await sendRandomNoahStamp(ctx, session);
4553
+ } else if (msg.type === "chat") {
4554
+ await session.sendQueued(getRandomChatStamp(ctx));
4555
+ } else {
4556
+ const tip = await pickTip(session);
4557
+ if (tip) {
4558
+ await session.sendQueued(import_koishi9.h.parse(tip, session));
4559
+ }
4456
4560
  }
4457
4561
  });
4458
4562
  }
4459
- __name(apply7, "apply");
4460
- function randomMessage(messages) {
4461
- const totalWeight = messages.reduce((sum2, cur) => sum2 + cur.weight, 0);
4462
- const random = Math.random() * totalWeight;
4463
- let sum = 0;
4464
- for (const message of messages) {
4465
- sum += message.weight;
4466
- if (random < sum) return message.content;
4467
- }
4468
- }
4469
- __name(randomMessage, "randomMessage");
4470
- function parsePlatform(target) {
4471
- const index = target.indexOf(":");
4472
- const platform = target.slice(0, index);
4473
- const id = target.slice(index + 1);
4474
- return [platform, id];
4563
+ __name(registerPokeNotice, "registerPokeNotice");
4564
+
4565
+ // src/fun/poke/locales/en-US.yml
4566
+ var en_US_default3 = { _config: { $desc: "Poke Module Settings", interval: "最小触发间隔(毫秒)", warning: "频繁触发是否发送警告", prompt: "警告内容", messages: { $desc: "消息内容", type: "Type (text=random tip / noah=voice stamp / chat=chat stamp)", weight: "权重" } }, commands: { poke: { description: "poke" } } };
4567
+
4568
+ // src/fun/poke/locales/zh-CN.yml
4569
+ var zh_CN_default3 = { _config: { $desc: "Poke 模块设置", interval: "最小触发间隔(毫秒)", warning: "频繁触发是否发送警告", prompt: { $desc: "警告内容", content: "消息", weight: "权重" }, messages: { $desc: "消息内容", type: "类型(text=随机提示 / noah=语音表情 / chat=聊天表情)", weight: "权重" } }, commands: { poke: { description: "戳一戳" } } };
4570
+
4571
+ // src/fun/poke/index.ts
4572
+ var name7 = "Noah-Poke";
4573
+ var logger3 = new import_koishi10.Logger("Noah-Poke");
4574
+ function apply7(ctx, config) {
4575
+ ;
4576
+ [
4577
+ ["en-US", en_US_default3],
4578
+ ["zh-CN", zh_CN_default3]
4579
+ ].forEach(([lang, file]) => ctx.i18n.define(lang, file));
4580
+ const cache = /* @__PURE__ */ new Map();
4581
+ registerStampCommand(ctx);
4582
+ registerPokeCommand(ctx);
4583
+ registerPokeNotice(ctx, config.poke, cache);
4475
4584
  }
4476
- __name(parsePlatform, "parsePlatform");
4585
+ __name(apply7, "apply");
4477
4586
 
4478
4587
  // src/games/general/index.ts
4479
4588
  var general_exports = {};
4480
4589
  __export(general_exports, {
4481
4590
  apply: () => apply8,
4482
- logger: () => logger3,
4591
+ logger: () => logger4,
4483
4592
  name: () => name8
4484
4593
  });
4485
- var import_koishi10 = require("koishi");
4594
+ var import_koishi12 = require("koishi");
4486
4595
 
4487
4596
  // src/games/general/events/quote.ts
4488
- var import_koishi9 = require("koishi");
4597
+ var import_koishi11 = require("koishi");
4489
4598
 
4490
4599
  // src/games/general/utils/codeReader.ts
4491
4600
  async function readCode128(ctx, barcodeApiUrl, imageUrl) {
@@ -4511,8 +4620,8 @@ __name(readCode128, "readCode128");
4511
4620
  function quote(ctx, config) {
4512
4621
  ctx.on("message", async (session) => {
4513
4622
  if (session.quote && session.quote.user.id === session.selfId) {
4514
- const images = await import_koishi9.h.select(session.quote.elements, "img");
4515
- const textElements = await import_koishi9.h.select(session.elements, "text");
4623
+ const images = await import_koishi11.h.select(session.quote.elements, "img");
4624
+ const textElements = await import_koishi11.h.select(session.elements, "text");
4516
4625
  const allText = textElements.map((el) => el.attrs?.content || "").join(" ");
4517
4626
  if (images.length === 1) {
4518
4627
  const imageUrl = images[0].attrs.src;
@@ -4538,7 +4647,7 @@ __name(quote, "quote");
4538
4647
 
4539
4648
  // src/games/general/index.ts
4540
4649
  var name8 = "Noah-General";
4541
- var logger3 = new import_koishi10.Logger("Noah-General");
4650
+ var logger4 = new import_koishi12.Logger("Noah-General");
4542
4651
  async function apply8(ctx, config) {
4543
4652
  quote(ctx, config.general);
4544
4653
  }
@@ -4549,10 +4658,10 @@ var sdvx_exports = {};
4549
4658
  __export(sdvx_exports, {
4550
4659
  apply: () => apply13,
4551
4660
  inject: () => inject3,
4552
- logger: () => logger4,
4661
+ logger: () => logger5,
4553
4662
  name: () => name13
4554
4663
  });
4555
- var import_koishi19 = require("koishi");
4664
+ var import_koishi21 = require("koishi");
4556
4665
 
4557
4666
  // src/servers/index.ts
4558
4667
  var servers_exports = {};
@@ -4564,7 +4673,7 @@ __export(servers_exports, {
4564
4673
  });
4565
4674
 
4566
4675
  // src/servers/Asphyxia/index.ts
4567
- var import_koishi11 = require("koishi");
4676
+ var import_koishi13 = require("koishi");
4568
4677
  var Asphyxia = class {
4569
4678
  static {
4570
4679
  __name(this, "Asphyxia");
@@ -4572,11 +4681,11 @@ var Asphyxia = class {
4572
4681
  name = "asphyxia";
4573
4682
  supportedGames = ["sdvx", "iidx"];
4574
4683
  gameServices = {};
4575
- logger = new import_koishi11.Logger("Noah-Asphyxia");
4684
+ logger = new import_koishi13.Logger("Noah-Asphyxia");
4576
4685
  };
4577
4686
 
4578
4687
  // src/servers/Mao/index.ts
4579
- var import_koishi12 = require("koishi");
4688
+ var import_koishi14 = require("koishi");
4580
4689
  var Mao = class {
4581
4690
  static {
4582
4691
  __name(this, "Mao");
@@ -4584,11 +4693,11 @@ var Mao = class {
4584
4693
  name = "mao";
4585
4694
  supportedGames = ["sdvx"];
4586
4695
  gameServices = {};
4587
- logger = new import_koishi12.Logger("Noah-Mao");
4696
+ logger = new import_koishi14.Logger("Noah-Mao");
4588
4697
  };
4589
4698
 
4590
4699
  // src/servers/Official/index.ts
4591
- var import_koishi13 = require("koishi");
4700
+ var import_koishi15 = require("koishi");
4592
4701
  var Official = class {
4593
4702
  static {
4594
4703
  __name(this, "Official");
@@ -4596,7 +4705,7 @@ var Official = class {
4596
4705
  name = "official";
4597
4706
  supportedGames = ["sdvx"];
4598
4707
  gameServices = {};
4599
- logger = new import_koishi13.Logger("Noah-Official");
4708
+ logger = new import_koishi15.Logger("Noah-Official");
4600
4709
  };
4601
4710
 
4602
4711
  // src/servers/ServerFactory.ts
@@ -4964,13 +5073,13 @@ var AsphyxiaSDVXService = class _AsphyxiaSDVXService {
4964
5073
  logger;
4965
5074
  config;
4966
5075
  cachedModel = null;
4967
- constructor(logger5, config) {
4968
- this.logger = logger5;
5076
+ constructor(logger6, config) {
5077
+ this.logger = logger6;
4969
5078
  this.config = config;
4970
5079
  }
4971
- static getInstance(logger5, config) {
5080
+ static getInstance(logger6, config) {
4972
5081
  if (!_AsphyxiaSDVXService.instance) {
4973
- _AsphyxiaSDVXService.instance = new _AsphyxiaSDVXService(logger5, config);
5082
+ _AsphyxiaSDVXService.instance = new _AsphyxiaSDVXService(logger6, config);
4974
5083
  }
4975
5084
  return _AsphyxiaSDVXService.instance;
4976
5085
  }
@@ -5117,12 +5226,12 @@ var MaoSDVXService = class _MaoSDVXService {
5117
5226
  }
5118
5227
  static instance;
5119
5228
  logger;
5120
- constructor(logger5) {
5121
- this.logger = logger5;
5229
+ constructor(logger6) {
5230
+ this.logger = logger6;
5122
5231
  }
5123
- static getInstance(logger5) {
5232
+ static getInstance(logger6) {
5124
5233
  if (!_MaoSDVXService.instance) {
5125
- _MaoSDVXService.instance = new _MaoSDVXService(logger5);
5234
+ _MaoSDVXService.instance = new _MaoSDVXService(logger6);
5126
5235
  }
5127
5236
  return _MaoSDVXService.instance;
5128
5237
  }
@@ -5467,12 +5576,12 @@ var OfficialSDVXService = class _OfficialSDVXService {
5467
5576
  }
5468
5577
  static instance;
5469
5578
  logger;
5470
- constructor(logger5) {
5471
- this.logger = logger5;
5579
+ constructor(logger6) {
5580
+ this.logger = logger6;
5472
5581
  }
5473
- static getInstance(logger5) {
5582
+ static getInstance(logger6) {
5474
5583
  if (!_OfficialSDVXService.instance) {
5475
- _OfficialSDVXService.instance = new _OfficialSDVXService(logger5);
5584
+ _OfficialSDVXService.instance = new _OfficialSDVXService(logger6);
5476
5585
  }
5477
5586
  return _OfficialSDVXService.instance;
5478
5587
  }
@@ -5577,15 +5686,15 @@ var OfficialSDVXService = class _OfficialSDVXService {
5577
5686
  };
5578
5687
 
5579
5688
  // src/games/sdvx/adapters/index.ts
5580
- function registerSDVXAdapters(logger5, config) {
5689
+ function registerSDVXAdapters(logger6, config) {
5581
5690
  const serverManager = ServerManager.getInstance();
5582
5691
  serverManager.registerGameService(
5583
5692
  "asphyxia",
5584
5693
  "sdvx",
5585
- AsphyxiaSDVXService.getInstance(logger5, config)
5694
+ AsphyxiaSDVXService.getInstance(logger6, config)
5586
5695
  );
5587
- serverManager.registerGameService("mao", "sdvx", MaoSDVXService.getInstance(logger5));
5588
- serverManager.registerGameService("official", "sdvx", OfficialSDVXService.getInstance(logger5));
5696
+ serverManager.registerGameService("mao", "sdvx", MaoSDVXService.getInstance(logger6));
5697
+ serverManager.registerGameService("official", "sdvx", OfficialSDVXService.getInstance(logger6));
5589
5698
  }
5590
5699
  __name(registerSDVXAdapters, "registerSDVXAdapters");
5591
5700
 
@@ -5597,7 +5706,7 @@ __export(command_exports2, {
5597
5706
  });
5598
5707
 
5599
5708
  // src/games/sdvx/commands/calculate.ts
5600
- var import_koishi14 = require("koishi");
5709
+ var import_koishi16 = require("koishi");
5601
5710
 
5602
5711
  // src/games/sdvx/utils/param-parser.ts
5603
5712
  function parseNumberWithSuffix(str) {
@@ -6116,7 +6225,7 @@ function parseQueryInput(input) {
6116
6225
  __name(parseQueryInput, "parseQueryInput");
6117
6226
 
6118
6227
  // src/games/sdvx/commands/calculate.ts
6119
- function calculate(ctx, config, logger5) {
6228
+ function calculate(ctx, config, logger6) {
6120
6229
  ctx.command("sdvx.calculate <query:text>").alias("sdvx.cal").action(async ({ session, options }, query) => {
6121
6230
  try {
6122
6231
  let queryInput = query;
@@ -6150,7 +6259,7 @@ function calculate(ctx, config, logger5) {
6150
6259
  lossless: true
6151
6260
  }
6152
6261
  );
6153
- return import_koishi14.h.image(imageBuffer, "image/png");
6262
+ return import_koishi16.h.image(imageBuffer, "image/png");
6154
6263
  } catch (error) {
6155
6264
  ctx.logger("SDVX-Calculate").warn(error);
6156
6265
  return session.text(".error");
@@ -6160,7 +6269,7 @@ function calculate(ctx, config, logger5) {
6160
6269
  __name(calculate, "calculate");
6161
6270
 
6162
6271
  // src/games/sdvx/commands/chart.ts
6163
- var import_koishi15 = require("koishi");
6272
+ var import_koishi17 = require("koishi");
6164
6273
  function mapArrangementToken(tok) {
6165
6274
  const t = tok.toLowerCase();
6166
6275
  if (t === "ran" || t === "random") return "random";
@@ -6243,7 +6352,7 @@ function getHighestDifstr(diffs) {
6243
6352
  return diffs[diffs.length - 1].difstr;
6244
6353
  }
6245
6354
  __name(getHighestDifstr, "getHighestDifstr");
6246
- function chart(ctx, config, logger5) {
6355
+ function chart(ctx, config, logger6) {
6247
6356
  ctx.command("sdvx.chart [query:text]").alias("sdvx.c").action(async ({ session }, query) => {
6248
6357
  if (!query) {
6249
6358
  await session.send(session.text(".prompt"));
@@ -6306,7 +6415,7 @@ function chart(ctx, config, logger5) {
6306
6415
  const res = await ctx.http.post(`${config.sdvx_data_url}/chart`, payload, {
6307
6416
  headers: { "Content-Type": "application/json" }
6308
6417
  });
6309
- return import_koishi15.h.image(res, "image/png");
6418
+ return import_koishi17.h.image(res, "image/png");
6310
6419
  } else {
6311
6420
  const {
6312
6421
  diffStr: parsedDiff,
@@ -6322,7 +6431,7 @@ function chart(ctx, config, logger5) {
6322
6431
  const picked = musicInfo[0];
6323
6432
  const music_id = Number(picked?.id);
6324
6433
  if (!Number.isFinite(music_id)) {
6325
- logger5.warn("search result missing id", picked);
6434
+ logger6.warn("search result missing id", picked);
6326
6435
  return session.text(".error");
6327
6436
  }
6328
6437
  let difstr = null;
@@ -6356,10 +6465,10 @@ function chart(ctx, config, logger5) {
6356
6465
  const res = await ctx.http.post(`${config.sdvx_data_url}/chart`, payload, {
6357
6466
  headers: { "Content-Type": "application/json" }
6358
6467
  });
6359
- return import_koishi15.h.image(res, "image/png");
6468
+ return import_koishi17.h.image(res, "image/png");
6360
6469
  }
6361
6470
  } catch (err) {
6362
- logger5.warn(err);
6471
+ logger6.warn(err);
6363
6472
  return session.text(".error");
6364
6473
  }
6365
6474
  });
@@ -6367,7 +6476,7 @@ function chart(ctx, config, logger5) {
6367
6476
  __name(chart, "chart");
6368
6477
 
6369
6478
  // src/core/utils/selector.ts
6370
- var import_koishi16 = require("koishi");
6479
+ var import_koishi18 = require("koishi");
6371
6480
  async function selectCard(session, cardService, uid) {
6372
6481
  const userCards = await cardService.getCardsByUid(uid);
6373
6482
  if (userCards.length === 0) {
@@ -6383,7 +6492,7 @@ async function selectCard(session, cardService, uid) {
6383
6492
  cardListMsg += `<p>${i + 1}. ${userCards[i].name}</p>`;
6384
6493
  }
6385
6494
  }
6386
- const msg = import_koishi16.h.unescape(session.text("selector.menu-select", { card_list: cardListMsg }));
6495
+ const msg = import_koishi18.h.unescape(session.text("selector.menu-select", { card_list: cardListMsg }));
6387
6496
  await session.send(msg);
6388
6497
  const select = await session.prompt();
6389
6498
  if (!select) return { ok: false, message: session.text("commands.timeout") };
@@ -6411,7 +6520,7 @@ async function selectServer(session, serverService, uid, channelId) {
6411
6520
  serverListMsg += `<p>${i + 1}. ${servers[i].name} (${servers[i].type})</p>`;
6412
6521
  }
6413
6522
  }
6414
- const msg = import_koishi16.h.unescape(
6523
+ const msg = import_koishi18.h.unescape(
6415
6524
  session.text("selector.server-menu-select", { server_list: serverListMsg })
6416
6525
  );
6417
6526
  await session.send(msg);
@@ -6548,7 +6657,7 @@ var ScoreService = class _ScoreService {
6548
6657
  };
6549
6658
 
6550
6659
  // src/games/sdvx/commands/radar.ts
6551
- function radar(ctx, config, logger5) {
6660
+ function radar(ctx, config, logger6) {
6552
6661
  ctx.command("sdvx.radar").userFields(["defaultCardId", "defaultServerId", "id"]).channelFields(["defaultServerId", "id"]).option("card", "-c").option("server", "-s").action(async ({ session, options }) => {
6553
6662
  const atGuild = session.guildId != null;
6554
6663
  const cardService = new CardService(ctx);
@@ -6614,7 +6723,7 @@ function radar(ctx, config, logger5) {
6614
6723
  one_hand: radarResult.one_hand.toFixed(2)
6615
6724
  });
6616
6725
  } catch (error) {
6617
- logger5.warn(error);
6726
+ logger6.warn(error);
6618
6727
  return session.text(".error");
6619
6728
  }
6620
6729
  });
@@ -6622,8 +6731,8 @@ function radar(ctx, config, logger5) {
6622
6731
  __name(radar, "radar");
6623
6732
 
6624
6733
  // src/games/sdvx/commands/recent.ts
6625
- var import_koishi17 = require("koishi");
6626
- function recent(ctx, config, logger5) {
6734
+ var import_koishi19 = require("koishi");
6735
+ function recent(ctx, config, logger6) {
6627
6736
  ctx.command("sdvx.recent [count:number]").alias("sdvx.r").userFields(["defaultCardId", "defaultServerId", "id"]).channelFields(["defaultServerId", "id"]).option("lossless", "-l").option("card", "-c").option("server", "-s").action(async ({ session, options }, count) => {
6628
6737
  const atGuild = session.guildId != null;
6629
6738
  if (!count) count = 1;
@@ -6693,11 +6802,11 @@ function recent(ctx, config, logger5) {
6693
6802
  }
6694
6803
  );
6695
6804
  if (options.lossless) {
6696
- return import_koishi17.h.image(imageBuffer, "image/png");
6805
+ return import_koishi19.h.image(imageBuffer, "image/png");
6697
6806
  }
6698
- return import_koishi17.h.image(imageBuffer, "image/jpg");
6807
+ return import_koishi19.h.image(imageBuffer, "image/jpg");
6699
6808
  } catch (error) {
6700
- logger5.warn(error);
6809
+ logger6.warn(error);
6701
6810
  return session.text(".error");
6702
6811
  }
6703
6812
  });
@@ -6705,7 +6814,7 @@ function recent(ctx, config, logger5) {
6705
6814
  __name(recent, "recent");
6706
6815
 
6707
6816
  // src/games/sdvx/commands/sync.ts
6708
- function sync(ctx, config, logger5) {
6817
+ function sync(ctx, config, logger6) {
6709
6818
  ctx.command("sdvx.sync").userFields(["id"]).channelFields(["id"]).action(async ({ session }) => {
6710
6819
  const serverService = new ServerService(ctx);
6711
6820
  const cardService = new CardService(ctx);
@@ -6780,7 +6889,7 @@ function sync(ctx, config, logger5) {
6780
6889
  const maoSdvxService = serverManager.getGameService("mao", "sdvx");
6781
6890
  const maoVerifyUrl = "https://maomani.cn";
6782
6891
  if (!maoSdvxService || typeof maoSdvxService.verifyPin !== "function") {
6783
- logger5.warn("Mao SDVX service does not support PIN verification");
6892
+ logger6.warn("Mao SDVX service does not support PIN verification");
6784
6893
  return session.text(".pin-verify-error");
6785
6894
  }
6786
6895
  const existingPin = await ctx.database.get("sdvx_pin_verified", {
@@ -6801,7 +6910,7 @@ function sync(ctx, config, logger5) {
6801
6910
  pinVerified = true;
6802
6911
  }
6803
6912
  } catch (error) {
6804
- logger5.warn(error);
6913
+ logger6.warn(error);
6805
6914
  }
6806
6915
  }
6807
6916
  if (!pinVerified) {
@@ -6837,7 +6946,7 @@ function sync(ctx, config, logger5) {
6837
6946
  })
6838
6947
  );
6839
6948
  } catch (error) {
6840
- logger5.warn(error);
6949
+ logger6.warn(error);
6841
6950
  await session.send(session.text(".pin-verify-error"));
6842
6951
  }
6843
6952
  }
@@ -6859,7 +6968,7 @@ function sync(ctx, config, logger5) {
6859
6968
  config
6860
6969
  );
6861
6970
  } catch (error) {
6862
- logger5.warn(error);
6971
+ logger6.warn(error);
6863
6972
  return session.text(".fetch-error");
6864
6973
  }
6865
6974
  if (!scoreList || scoreList.length === 0) {
@@ -6881,11 +6990,11 @@ function sync(ctx, config, logger5) {
6881
6990
  scoreList
6882
6991
  );
6883
6992
  if (!ok) {
6884
- logger5.warn("Mao SDVX uploadScore returned falsy result");
6993
+ logger6.warn("Mao SDVX uploadScore returned falsy result");
6885
6994
  return session.text(".sync-failed");
6886
6995
  }
6887
6996
  } catch (error) {
6888
- logger5.warn(error);
6997
+ logger6.warn(error);
6889
6998
  return session.text(".sync-error");
6890
6999
  }
6891
7000
  return session.text(".selected-summary", {
@@ -6900,8 +7009,8 @@ function sync(ctx, config, logger5) {
6900
7009
  __name(sync, "sync");
6901
7010
 
6902
7011
  // src/games/sdvx/commands/vf.ts
6903
- var fs4 = __toESM(require("fs"), 1);
6904
- var import_koishi18 = require("koishi");
7012
+ var fs5 = __toESM(require("fs"), 1);
7013
+ var import_koishi20 = require("koishi");
6905
7014
 
6906
7015
  // src/games/sdvx/utils/filter.ts
6907
7016
  function parseFilterQuery(query) {
@@ -6954,7 +7063,7 @@ function parseFilterQuery(query) {
6954
7063
  __name(parseFilterQuery, "parseFilterQuery");
6955
7064
 
6956
7065
  // src/games/sdvx/commands/vf.ts
6957
- function vf(ctx, config, logger5) {
7066
+ function vf(ctx, config, logger6) {
6958
7067
  ctx.command("vf").userFields(["defaultCardId", "defaultServerId", "id"]).channelFields(["defaultServerId", "id"]).option("lossless", "-l").option("card", "-c").option("server", "-s").option("filter", "-f <query:text>").action(async ({ session, options }) => {
6959
7068
  const atGuild = session.guildId != null;
6960
7069
  const cardService = new CardService(ctx);
@@ -7029,9 +7138,9 @@ function vf(ctx, config, logger5) {
7029
7138
  }
7030
7139
  );
7031
7140
  if (options.lossless) {
7032
- session.send(import_koishi18.h.file(imageBuffer, "image/png"));
7141
+ session.send(import_koishi20.h.file(imageBuffer, "image/png"));
7033
7142
  } else {
7034
- session.send(import_koishi18.h.image(imageBuffer, "image/jpg"));
7143
+ session.send(import_koishi20.h.image(imageBuffer, "image/jpg"));
7035
7144
  }
7036
7145
  const sortedScores = [...best50ScoreList].sort((a, b) => b.extra.volforce - a.extra.volforce).slice(0, 50);
7037
7146
  const total = sortedScores.reduce((sum, score) => sum + score.extra.volforce, 0);
@@ -7058,20 +7167,20 @@ function vf(ctx, config, logger5) {
7058
7167
  ctx,
7059
7168
  "stamps/noah_stamp/stamp_0385/stamp_0385_02.png"
7060
7169
  );
7061
- if (fs4.existsSync(audioPath)) {
7062
- const audioBuffer = fs4.readFileSync(audioPath);
7063
- session.send(import_koishi18.h.audio(audioBuffer, "audio/mpeg"));
7170
+ if (fs5.existsSync(audioPath)) {
7171
+ const audioBuffer = fs5.readFileSync(audioPath);
7172
+ session.send(import_koishi20.h.audio(audioBuffer, "audio/mpeg"));
7064
7173
  }
7065
- if (fs4.existsSync(imagePath)) {
7066
- const imageBuffer2 = fs4.readFileSync(imagePath);
7067
- session.send(import_koishi18.h.image(imageBuffer2, "image/png"));
7174
+ if (fs5.existsSync(imagePath)) {
7175
+ const imageBuffer2 = fs5.readFileSync(imagePath);
7176
+ session.send(import_koishi20.h.image(imageBuffer2, "image/png"));
7068
7177
  }
7069
7178
  } catch (error) {
7070
- logger5.warn(`Failed to send celebration files: ${error.message}`);
7179
+ logger6.warn(`Failed to send celebration files: ${error.message}`);
7071
7180
  }
7072
7181
  }
7073
7182
  } catch (error) {
7074
- logger5.warn(error);
7183
+ logger6.warn(error);
7075
7184
  return session.text(".error");
7076
7185
  }
7077
7186
  return;
@@ -7083,12 +7192,12 @@ __name(vf, "vf");
7083
7192
  var name10 = "command";
7084
7193
  function apply10(ctx, config) {
7085
7194
  ctx.command("sdvx").alias("s");
7086
- vf(ctx, config, logger4);
7087
- recent(ctx, config, logger4);
7088
- chart(ctx, config, logger4);
7089
- calculate(ctx, config, logger4);
7090
- sync(ctx, config, logger4);
7091
- radar(ctx, config, logger4);
7195
+ vf(ctx, config, logger5);
7196
+ recent(ctx, config, logger5);
7197
+ chart(ctx, config, logger5);
7198
+ calculate(ctx, config, logger5);
7199
+ sync(ctx, config, logger5);
7200
+ radar(ctx, config, logger5);
7092
7201
  }
7093
7202
  __name(apply10, "apply");
7094
7203
 
@@ -7136,14 +7245,14 @@ var zh_CN_default4 = { _config: { $desc: "SDVX 模块设置", sdvx_data_url: "<p
7136
7245
  // src/games/sdvx/index.ts
7137
7246
  var name13 = "Noah-SDVX";
7138
7247
  var inject3 = ["database", "globalConfig"];
7139
- var logger4 = new import_koishi19.Logger("Noah-SDVX");
7248
+ var logger5 = new import_koishi21.Logger("Noah-SDVX");
7140
7249
  async function apply13(ctx, config) {
7141
7250
  ;
7142
7251
  [
7143
7252
  ["en-US", en_US_default4],
7144
7253
  ["zh-CN", zh_CN_default4]
7145
7254
  ].forEach(([lang, file]) => ctx.i18n.define(lang, file));
7146
- registerSDVXAdapters(logger4, config.sdvx);
7255
+ registerSDVXAdapters(logger5, config.sdvx);
7147
7256
  ctx.plugin(database_exports2, config.sdvx);
7148
7257
  ctx.plugin(command_exports2, config.sdvx);
7149
7258
  ctx.plugin(event_exports2, config.sdvx);
@@ -7151,50 +7260,50 @@ async function apply13(ctx, config) {
7151
7260
  __name(apply13, "apply");
7152
7261
 
7153
7262
  // src/config.ts
7154
- var import_koishi27 = require("koishi");
7263
+ var import_koishi29 = require("koishi");
7155
7264
 
7156
7265
  // src/asset/config.ts
7157
- var import_koishi20 = require("koishi");
7158
- var assetConfig = import_koishi20.Schema.object({
7159
- data_path: import_koishi20.Schema.string().default("noah_assets"),
7160
- auto_update: import_koishi20.Schema.boolean().default(true),
7161
- update_url: import_koishi20.Schema.string().default("https://github.com/logthm/noah/releases/latest/download/"),
7162
- update_interval: import_koishi20.Schema.number().default(24 * 60 * 60 * 1e3),
7266
+ var import_koishi22 = require("koishi");
7267
+ var assetConfig = import_koishi22.Schema.object({
7268
+ data_path: import_koishi22.Schema.string().default("noah_assets"),
7269
+ auto_update: import_koishi22.Schema.boolean().default(true),
7270
+ update_url: import_koishi22.Schema.string().default("https://github.com/logthm/noah/releases/latest/download/"),
7271
+ update_interval: import_koishi22.Schema.number().default(24 * 60 * 60 * 1e3),
7163
7272
  // 24 hours in milliseconds
7164
- github_token: import_koishi20.Schema.string().description("GitHub token for accessing private repositories").role("secret")
7273
+ github_token: import_koishi22.Schema.string().description("GitHub token for accessing private repositories").role("secret")
7165
7274
  }).i18n({
7166
7275
  "en-US": en_US_default._config,
7167
7276
  "zh-CN": zh_CN_default._config
7168
7277
  });
7169
7278
 
7170
7279
  // src/core/config.ts
7171
- var import_koishi21 = require("koishi");
7172
- var coreConfig = import_koishi21.Schema.object({
7173
- adminUsers: import_koishi21.Schema.array(String).role("table"),
7174
- guildNameCards: import_koishi21.Schema.array(String).role("table").default(["Noah | /help 获取食用指南"]),
7175
- tokenTtl: import_koishi21.Schema.number().default(1800),
7176
- frontendUrl: import_koishi21.Schema.string().default(""),
7177
- corsOrigin: import_koishi21.Schema.string().default("*")
7280
+ var import_koishi23 = require("koishi");
7281
+ var coreConfig = import_koishi23.Schema.object({
7282
+ adminUsers: import_koishi23.Schema.array(String).role("table"),
7283
+ guildNameCards: import_koishi23.Schema.array(String).role("table").default(["Noah | /help 获取食用指南"]),
7284
+ tokenTtl: import_koishi23.Schema.number().default(1800),
7285
+ frontendUrl: import_koishi23.Schema.string().default(""),
7286
+ corsOrigin: import_koishi23.Schema.string().default("*")
7178
7287
  }).i18n({
7179
7288
  "en-US": en_US_default2._config,
7180
7289
  "zh-CN": zh_CN_default2._config
7181
7290
  });
7182
7291
 
7183
7292
  // src/fun/poke/config.ts
7184
- var import_koishi22 = require("koishi");
7185
- var pokeConfig = import_koishi22.Schema.object({
7186
- interval: import_koishi22.Schema.number().default(1e3).step(100),
7187
- warning: import_koishi22.Schema.boolean().default(false),
7188
- prompt: import_koishi22.Schema.array(
7189
- import_koishi22.Schema.object({
7190
- content: import_koishi22.Schema.string().required(),
7191
- weight: import_koishi22.Schema.number().min(0).max(100).default(50)
7293
+ var import_koishi24 = require("koishi");
7294
+ var pokeConfig = import_koishi24.Schema.object({
7295
+ interval: import_koishi24.Schema.number().default(1e3).step(100),
7296
+ warning: import_koishi24.Schema.boolean().default(false),
7297
+ prompt: import_koishi24.Schema.array(
7298
+ import_koishi24.Schema.object({
7299
+ content: import_koishi24.Schema.string().required(),
7300
+ weight: import_koishi24.Schema.number().min(0).max(100).default(50)
7192
7301
  })
7193
7302
  ).role("table"),
7194
- messages: import_koishi22.Schema.array(
7195
- import_koishi22.Schema.object({
7196
- content: import_koishi22.Schema.string().required(),
7197
- weight: import_koishi22.Schema.number().min(0).max(100).default(50)
7303
+ messages: import_koishi24.Schema.array(
7304
+ import_koishi24.Schema.object({
7305
+ type: import_koishi24.Schema.union(["text", "noah", "chat"]).default("text"),
7306
+ weight: import_koishi24.Schema.number().min(0).max(100).default(50)
7198
7307
  })
7199
7308
  ).role("table")
7200
7309
  }).i18n({
@@ -7203,7 +7312,7 @@ var pokeConfig = import_koishi22.Schema.object({
7203
7312
  });
7204
7313
 
7205
7314
  // src/games/general/config.ts
7206
- var import_koishi23 = require("koishi");
7315
+ var import_koishi25 = require("koishi");
7207
7316
 
7208
7317
  // src/games/general/locales/en-US.yml
7209
7318
  var en_US_default5 = { _config: { $desc: "General Module Settings", barcode_api_url: "<p>The URL of the barcode API</p>" } };
@@ -7212,33 +7321,33 @@ var en_US_default5 = { _config: { $desc: "General Module Settings", barcode_api_
7212
7321
  var zh_CN_default5 = { _config: { $desc: "通用工具模块设置", barcode_api_url: "<p>条形码 API 地址</p>" } };
7213
7322
 
7214
7323
  // src/games/general/config.ts
7215
- var generalConfig = import_koishi23.Schema.object({
7216
- barcode_api_url: import_koishi23.Schema.string().required()
7324
+ var generalConfig = import_koishi25.Schema.object({
7325
+ barcode_api_url: import_koishi25.Schema.string().required()
7217
7326
  }).i18n({
7218
7327
  "en-US": en_US_default5._config,
7219
7328
  "zh-CN": zh_CN_default5._config
7220
7329
  });
7221
7330
 
7222
7331
  // src/games/sdvx/config.ts
7223
- var import_koishi24 = require("koishi");
7224
- var sdvxConfig = import_koishi24.Schema.object({
7225
- sdvx_data_url: import_koishi24.Schema.string().required(),
7226
- sdvx_search_url: import_koishi24.Schema.string().required()
7332
+ var import_koishi26 = require("koishi");
7333
+ var sdvxConfig = import_koishi26.Schema.object({
7334
+ sdvx_data_url: import_koishi26.Schema.string().required(),
7335
+ sdvx_search_url: import_koishi26.Schema.string().required()
7227
7336
  }).i18n({
7228
7337
  "en-US": en_US_default4._config,
7229
7338
  "zh-CN": zh_CN_default4._config
7230
7339
  });
7231
7340
 
7232
7341
  // src/global/config.ts
7233
- var import_koishi25 = require("koishi");
7234
- var globalConfig = import_koishi25.Schema.object({
7235
- official_support_url: import_koishi25.Schema.string().default("https://noah.logthm.com"),
7236
- maoServerUrl: import_koishi25.Schema.string().default("http://maomani.cn:577"),
7237
- maoApiKey: import_koishi25.Schema.string().role("secret").default("")
7342
+ var import_koishi27 = require("koishi");
7343
+ var globalConfig = import_koishi27.Schema.object({
7344
+ official_support_url: import_koishi27.Schema.string().default("https://noah.logthm.com"),
7345
+ maoServerUrl: import_koishi27.Schema.string().default("http://maomani.cn:577"),
7346
+ maoApiKey: import_koishi27.Schema.string().role("secret").default("")
7238
7347
  });
7239
7348
 
7240
7349
  // src/slash/config.ts
7241
- var import_koishi26 = require("koishi");
7350
+ var import_koishi28 = require("koishi");
7242
7351
 
7243
7352
  // src/slash/locales/en-US.yml
7244
7353
  var en_US_default6 = { _config: { $desc: "Slash Module Settings", test_guilds: "**Guilds To Sync**", auto_sync_on_start: "**Auto Sync on Connect**" } };
@@ -7247,16 +7356,16 @@ var en_US_default6 = { _config: { $desc: "Slash Module Settings", test_guilds: "
7247
7356
  var zh_CN_default6 = { _config: { $desc: "Slash 模块设置", test_guilds: "**默认同步 Guild 列表**", auto_sync_on_start: "**连接后自动同步**" } };
7248
7357
 
7249
7358
  // src/slash/config.ts
7250
- var slashConfig = import_koishi26.Schema.object({
7251
- test_guilds: import_koishi26.Schema.array(String).default([]),
7252
- auto_sync_on_start: import_koishi26.Schema.boolean().default(true)
7359
+ var slashConfig = import_koishi28.Schema.object({
7360
+ test_guilds: import_koishi28.Schema.array(String).default([]),
7361
+ auto_sync_on_start: import_koishi28.Schema.boolean().default(true)
7253
7362
  }).i18n({
7254
7363
  "en-US": en_US_default6._config,
7255
7364
  "zh-CN": zh_CN_default6._config
7256
7365
  });
7257
7366
 
7258
7367
  // src/config.ts
7259
- var Config = import_koishi27.Schema.object({
7368
+ var Config = import_koishi29.Schema.object({
7260
7369
  global: globalConfig,
7261
7370
  core: coreConfig,
7262
7371
  sdvx: sdvxConfig,