@sfmc-bds/cli 0.2.0-beta.9 → 0.2.0

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 (128) hide show
  1. package/LICENSE +663 -0
  2. package/README.md +4 -5
  3. package/dist/bds-runtime-version.d.ts +3 -0
  4. package/dist/bds-runtime-version.d.ts.map +1 -0
  5. package/dist/bds-runtime-version.js +15 -0
  6. package/dist/bds-runtime-version.js.map +7 -0
  7. package/dist/command-surface.d.ts.map +1 -1
  8. package/dist/command-surface.js +3 -1
  9. package/dist/command-surface.js.map +2 -2
  10. package/dist/commands.d.ts +57 -4
  11. package/dist/commands.d.ts.map +1 -1
  12. package/dist/commands.js +78 -75
  13. package/dist/commands.js.map +2 -2
  14. package/dist/directory-picker.d.ts +27 -0
  15. package/dist/directory-picker.d.ts.map +1 -0
  16. package/dist/directory-picker.js +112 -0
  17. package/dist/directory-picker.js.map +7 -0
  18. package/dist/i18n/locales/en.d.ts +25 -1
  19. package/dist/i18n/locales/en.d.ts.map +1 -1
  20. package/dist/i18n/locales/en.js +25 -1
  21. package/dist/i18n/locales/en.js.map +2 -2
  22. package/dist/i18n/locales/zh-CN.d.ts.map +1 -1
  23. package/dist/i18n/locales/zh-CN.js +26 -2
  24. package/dist/i18n/locales/zh-CN.js.map +2 -2
  25. package/dist/interactive-prompts.d.ts +1 -2
  26. package/dist/interactive-prompts.d.ts.map +1 -1
  27. package/dist/interactive-prompts.js +12 -23
  28. package/dist/interactive-prompts.js.map +3 -3
  29. package/dist/llbot-launch.d.ts +3 -3
  30. package/dist/llbot-launch.js.map +1 -1
  31. package/dist/log-filter.d.ts +18 -2
  32. package/dist/log-filter.d.ts.map +1 -1
  33. package/dist/log-filter.js +54 -4
  34. package/dist/log-filter.js.map +2 -2
  35. package/dist/log-translator.d.ts +36 -0
  36. package/dist/log-translator.d.ts.map +1 -0
  37. package/dist/log-translator.js +279 -0
  38. package/dist/log-translator.js.map +7 -0
  39. package/dist/logs.d.ts +2 -0
  40. package/dist/logs.d.ts.map +1 -1
  41. package/dist/logs.js +24 -11
  42. package/dist/logs.js.map +2 -2
  43. package/dist/main.js +5 -0
  44. package/dist/main.js.map +2 -2
  45. package/dist/module-commands.d.ts.map +1 -1
  46. package/dist/module-commands.js +22 -8
  47. package/dist/module-commands.js.map +2 -2
  48. package/dist/module-fingerprint.d.ts.map +1 -1
  49. package/dist/module-fingerprint.js +1 -0
  50. package/dist/module-fingerprint.js.map +2 -2
  51. package/dist/module-pack-build.d.ts +14 -4
  52. package/dist/module-pack-build.d.ts.map +1 -1
  53. package/dist/module-pack-build.js +81 -108
  54. package/dist/module-pack-build.js.map +2 -2
  55. package/dist/module-toggle.d.ts +1 -1
  56. package/dist/module-toggle.d.ts.map +1 -1
  57. package/dist/module-toggle.js.map +1 -1
  58. package/dist/pack-lifecycle.d.ts +15 -1
  59. package/dist/pack-lifecycle.d.ts.map +1 -1
  60. package/dist/pack-lifecycle.js +242 -15
  61. package/dist/pack-lifecycle.js.map +2 -2
  62. package/dist/player-session.d.ts +13 -0
  63. package/dist/player-session.d.ts.map +1 -0
  64. package/dist/player-session.js +26 -0
  65. package/dist/player-session.js.map +7 -0
  66. package/dist/registry.d.ts +1 -1
  67. package/dist/registry.d.ts.map +1 -1
  68. package/dist/registry.js +4 -1
  69. package/dist/registry.js.map +2 -2
  70. package/dist/repl-windows/format-display.d.ts.map +1 -1
  71. package/dist/repl-windows/format-display.js +5 -1
  72. package/dist/repl-windows/format-display.js.map +2 -2
  73. package/dist/repl-windows/host.d.ts +6 -3
  74. package/dist/repl-windows/host.d.ts.map +1 -1
  75. package/dist/repl-windows/host.js +12 -6
  76. package/dist/repl-windows/host.js.map +2 -2
  77. package/dist/repl-windows/index.d.ts +1 -0
  78. package/dist/repl-windows/index.d.ts.map +1 -1
  79. package/dist/repl-windows/index.js +3 -0
  80. package/dist/repl-windows/index.js.map +2 -2
  81. package/dist/repl-windows/service-window.d.ts.map +1 -1
  82. package/dist/repl-windows/service-window.js +1 -0
  83. package/dist/repl-windows/service-window.js.map +2 -2
  84. package/dist/repl-windows/sfmc-window.d.ts +7 -0
  85. package/dist/repl-windows/sfmc-window.d.ts.map +1 -0
  86. package/dist/repl-windows/sfmc-window.js +28 -0
  87. package/dist/repl-windows/sfmc-window.js.map +7 -0
  88. package/dist/repl.d.ts.map +1 -1
  89. package/dist/repl.js +38 -13
  90. package/dist/repl.js.map +2 -2
  91. package/dist/runtime.d.ts +2 -2
  92. package/dist/runtime.d.ts.map +1 -1
  93. package/dist/runtime.js +15 -2
  94. package/dist/runtime.js.map +2 -2
  95. package/dist/send-target.d.ts +2 -0
  96. package/dist/send-target.d.ts.map +1 -1
  97. package/dist/send-target.js +6 -0
  98. package/dist/send-target.js.map +2 -2
  99. package/dist/services.d.ts +26 -1
  100. package/dist/services.d.ts.map +1 -1
  101. package/dist/services.js +179 -45
  102. package/dist/services.js.map +2 -2
  103. package/dist/sfmc-modules-root.d.ts.map +1 -1
  104. package/dist/sfmc-modules-root.js +6 -2
  105. package/dist/sfmc-modules-root.js.map +2 -2
  106. package/dist/ui-command.d.ts +6 -0
  107. package/dist/ui-command.d.ts.map +1 -0
  108. package/dist/ui-command.js +68 -0
  109. package/dist/ui-command.js.map +7 -0
  110. package/dist/wizard.d.ts.map +1 -1
  111. package/dist/wizard.js +36 -31
  112. package/dist/wizard.js.map +2 -2
  113. package/dist/world-packs.d.ts +2 -0
  114. package/dist/world-packs.d.ts.map +1 -1
  115. package/dist/world-packs.js +161 -18
  116. package/dist/world-packs.js.map +2 -2
  117. package/package.json +22 -15
  118. package/scripts/module-install/check-modules.mjs +178 -0
  119. package/scripts/module-install/fetch-module.mjs +1083 -0
  120. package/scripts/module-install/lib/catalog.mjs +96 -0
  121. package/scripts/module-install/lib/config-seeding.mjs +128 -0
  122. package/scripts/module-install/lib/io.mjs +37 -0
  123. package/scripts/module-install/lib/link-from.mjs +80 -0
  124. package/scripts/module-install/lib/lock.mjs +78 -0
  125. package/scripts/module-install/lib/npm-resolver.mjs +55 -0
  126. package/scripts/module-install/lib/packages.mjs +136 -0
  127. package/scripts/module-install/lib/paths.mjs +48 -0
  128. package/scripts/module-install/lib/registry-index.mjs +50 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/interactive-prompts.ts"],
4
- "sourcesContent": ["import { isCancel, select, text } from \"@clack/prompts\";\nimport { execFileSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { t } from \"./i18n/index.js\";\n\n/** \u4E0E init \u5411\u5BFC\u4E00\u81F4\uFF1A\u6587\u672C\u8F93\u5165\u6216\u7CFB\u7EDF\u6587\u4EF6\u5939\u9009\u62E9\u5668\u3002 */\nexport async function pickDirectory(message: string, defaultDirectory: string): Promise<string> {\n const method = await select({\n message,\n options: [\n { value: \"text\", label: t(\"prompt.enterPath\"), hint: defaultDirectory },\n { value: \"browse\", label: t(\"prompt.browse\"), hint: t(\"prompt.browseHint\") },\n ],\n });\n if (isCancel(method)) return defaultDirectory;\n if (method === \"browse\") return pickDirectoryDialog(message, defaultDirectory) ?? defaultDirectory;\n\n const selected = await text({ message, initialValue: defaultDirectory });\n return isCancel(selected) || !selected ? defaultDirectory : selected;\n}\n\n/** Windows \u6587\u4EF6\u5939\u9009\u62E9\u5668\uFF1B\u975E Windows \u6216\u5931\u8D25\u65F6\u8FD4\u56DE null\u3002 */\nexport function pickDirectoryDialog(title: string, defaultDirectory: string): string | null {\n if (process.platform !== \"win32\") return null;\n const escape = (value: string): string => value.replace(/'/g, \"''\");\n const script = [\n \"Add-Type -AssemblyName System.Windows.Forms\",\n \"$dialog = New-Object System.Windows.Forms.FolderBrowserDialog\",\n `$dialog.Description = '${escape(title)}'`,\n `$dialog.SelectedPath = '${escape(defaultDirectory)}'`,\n \"if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { Write-Output $dialog.SelectedPath }\",\n ].join(\"; \");\n\n try {\n const output = execFileSync(\"powershell.exe\", [\"-NoProfile\", \"-STA\", \"-Command\", script], {\n encoding: \"utf-8\",\n timeout: 30_000,\n windowsHide: true,\n });\n return output.trim() || null;\n } catch {\n return null;\n }\n}\n\nexport function ensureDirectory(directory: string): boolean {\n try {\n fs.mkdirSync(directory, { recursive: true });\n return fs.statSync(directory).isDirectory();\n } catch {\n return false;\n }\n}\n\n/** \u5C06\u7528\u6237\u8F93\u5165\u89C4\u8303\u4E3A\u7EDD\u5BF9\u8DEF\u5F84\uFF08\u517C\u5BB9\u542B # \u7684 Windows \u8DEF\u5F84\uFF09\u3002 */\nexport function resolveUserPath(input: string, base = process.cwd()): string {\n return path.resolve(base, input.trim());\n}\n"],
5
- "mappings": "AAAA,SAAS,UAAU,QAAQ,YAAY;AACvC,SAAS,oBAAoB;AAC7B,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,SAAS;AAGlB,eAAsB,cAAc,SAAiB,kBAA2C;AAC9F,QAAM,SAAS,MAAM,OAAO;AAAA,IAC1B;AAAA,IACA,SAAS;AAAA,MACP,EAAE,OAAO,QAAQ,OAAO,EAAE,kBAAkB,GAAG,MAAM,iBAAiB;AAAA,MACtE,EAAE,OAAO,UAAU,OAAO,EAAE,eAAe,GAAG,MAAM,EAAE,mBAAmB,EAAE;AAAA,IAC7E;AAAA,EACF,CAAC;AACD,MAAI,SAAS,MAAM,EAAG,QAAO;AAC7B,MAAI,WAAW,SAAU,QAAO,oBAAoB,SAAS,gBAAgB,KAAK;AAElF,QAAM,WAAW,MAAM,KAAK,EAAE,SAAS,cAAc,iBAAiB,CAAC;AACvE,SAAO,SAAS,QAAQ,KAAK,CAAC,WAAW,mBAAmB;AAC9D;AAGO,SAAS,oBAAoB,OAAe,kBAAyC;AAC1F,MAAI,QAAQ,aAAa,QAAS,QAAO;AACzC,QAAM,SAAS,CAAC,UAA0B,MAAM,QAAQ,MAAM,IAAI;AAClE,QAAM,SAAS;AAAA,IACb;AAAA,IACA;AAAA,IACA,0BAA0B,OAAO,KAAK,CAAC;AAAA,IACvC,2BAA2B,OAAO,gBAAgB,CAAC;AAAA,IACnD;AAAA,EACF,EAAE,KAAK,IAAI;AAEX,MAAI;AACF,UAAM,SAAS,aAAa,kBAAkB,CAAC,cAAc,QAAQ,YAAY,MAAM,GAAG;AAAA,MACxF,UAAU;AAAA,MACV,SAAS;AAAA,MACT,aAAa;AAAA,IACf,CAAC;AACD,WAAO,OAAO,KAAK,KAAK;AAAA,EAC1B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,gBAAgB,WAA4B;AAC1D,MAAI;AACF,OAAG,UAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAC3C,WAAO,GAAG,SAAS,SAAS,EAAE,YAAY;AAAA,EAC5C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGO,SAAS,gBAAgB,OAAe,OAAO,QAAQ,IAAI,GAAW;AAC3E,SAAO,KAAK,QAAQ,MAAM,MAAM,KAAK,CAAC;AACxC;",
6
- "names": []
4
+ "sourcesContent": ["import { isCancel, select, text } from \"@clack/prompts\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { pickDirectoryDialog as runNativeDirectoryPicker } from \"./directory-picker.js\";\nimport { t } from \"./i18n/index.js\";\n\n/** \u4E0E init \u5411\u5BFC\u4E00\u81F4\uFF1A\u6587\u672C\u8F93\u5165\u6216\u7CFB\u7EDF\u6587\u4EF6\u5939\u9009\u62E9\u5668\u3002 */\nexport async function pickDirectory(message: string, defaultDirectory: string): Promise<string> {\n const method = await select({\n message,\n options: [\n { value: \"text\", label: t(\"prompt.enterPath\"), hint: defaultDirectory },\n { value: \"browse\", label: t(\"prompt.browse\"), hint: t(\"prompt.browseHint\") },\n ],\n });\n if (isCancel(method)) return defaultDirectory;\n\n if (method === \"browse\") {\n const result = runNativeDirectoryPicker(message, defaultDirectory);\n if (result.status === \"selected\") return result.path;\n if (result.status === \"cancelled\") return defaultDirectory;\n\n const selected = await text({\n message: `${message} \u2014 ${t(\"prompt.browseUnavailable\")}`,\n initialValue: defaultDirectory,\n });\n return isCancel(selected) || !selected ? defaultDirectory : selected;\n }\n\n const selected = await text({ message, initialValue: defaultDirectory });\n return isCancel(selected) || !selected ? defaultDirectory : selected;\n}\n\nexport { pickDirectoryDialog, type DirectoryPickerResult } from \"./directory-picker.js\";\n\nexport function ensureDirectory(directory: string): boolean {\n try {\n fs.mkdirSync(directory, { recursive: true });\n return fs.statSync(directory).isDirectory();\n } catch {\n return false;\n }\n}\n\n/** \u5C06\u7528\u6237\u8F93\u5165\u89C4\u8303\u4E3A\u7EDD\u5BF9\u8DEF\u5F84\uFF08\u517C\u5BB9\u542B # \u7684 Windows \u8DEF\u5F84\uFF09\u3002 */\nexport function resolveUserPath(input: string, base = process.cwd()): string {\n return path.resolve(base, input.trim());\n}\n"],
5
+ "mappings": "AAAA,SAAS,UAAU,QAAQ,YAAY;AACvC,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,uBAAuB,gCAAgC;AAChE,SAAS,SAAS;AAGlB,eAAsB,cAAc,SAAiB,kBAA2C;AAC9F,QAAM,SAAS,MAAM,OAAO;AAAA,IAC1B;AAAA,IACA,SAAS;AAAA,MACP,EAAE,OAAO,QAAQ,OAAO,EAAE,kBAAkB,GAAG,MAAM,iBAAiB;AAAA,MACtE,EAAE,OAAO,UAAU,OAAO,EAAE,eAAe,GAAG,MAAM,EAAE,mBAAmB,EAAE;AAAA,IAC7E;AAAA,EACF,CAAC;AACD,MAAI,SAAS,MAAM,EAAG,QAAO;AAE7B,MAAI,WAAW,UAAU;AACvB,UAAM,SAAS,yBAAyB,SAAS,gBAAgB;AACjE,QAAI,OAAO,WAAW,WAAY,QAAO,OAAO;AAChD,QAAI,OAAO,WAAW,YAAa,QAAO;AAE1C,UAAMA,YAAW,MAAM,KAAK;AAAA,MAC1B,SAAS,GAAG,OAAO,WAAM,EAAE,0BAA0B,CAAC;AAAA,MACtD,cAAc;AAAA,IAChB,CAAC;AACD,WAAO,SAASA,SAAQ,KAAK,CAACA,YAAW,mBAAmBA;AAAA,EAC9D;AAEA,QAAM,WAAW,MAAM,KAAK,EAAE,SAAS,cAAc,iBAAiB,CAAC;AACvE,SAAO,SAAS,QAAQ,KAAK,CAAC,WAAW,mBAAmB;AAC9D;AAEA,SAAS,2BAAuD;AAEzD,SAAS,gBAAgB,WAA4B;AAC1D,MAAI;AACF,OAAG,UAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAC3C,WAAO,GAAG,SAAS,SAAS,EAAE,YAAY;AAAA,EAC5C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGO,SAAS,gBAAgB,OAAe,OAAO,QAAQ,IAAI,GAAW;AAC3E,SAAO,KAAK,QAAQ,MAAM,MAAM,KAAK,CAAC;AACxC;",
6
+ "names": ["selected"]
7
7
  }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * llbot-launch.ts — 解析 LLBot 可执行文件与工作目录
3
3
  *
4
- * 历史向导曾把 llbot_path 写成「目录」;schema 语义是可执行文件。
4
+ * 历史向导曾把 llbot.path 写成「目录」;schema 语义是可执行文件。
5
5
  * 此处兼容二者,避免 spawn 目录导致 ENOENT。
6
6
  */
7
7
  export declare function defaultLlbotDir(platform?: NodeJS.Platform): string;
@@ -13,8 +13,8 @@ export type LlbotLaunch = {
13
13
  cwd: string;
14
14
  };
15
15
  /**
16
- * @param pathRaw qq_config.llbot_path(可为 exe 或目录)
17
- * @param cwdRaw qq_config.llbot_cwd(目录;可空)
16
+ * @param pathRaw qq_config.llbot.path(可为 exe 或目录)
17
+ * @param cwdRaw qq_config.llbot.cwd(目录;可空)
18
18
  */
19
19
  export declare function resolveLlbotLaunch(pathRaw: unknown, cwdRaw: unknown): LlbotLaunch;
20
20
  //# sourceMappingURL=llbot-launch.d.ts.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/llbot-launch.ts"],
4
- "sourcesContent": ["/**\n * llbot-launch.ts \u2014 \u89E3\u6790 LLBot \u53EF\u6267\u884C\u6587\u4EF6\u4E0E\u5DE5\u4F5C\u76EE\u5F55\n *\n * \u5386\u53F2\u5411\u5BFC\u66FE\u628A llbot_path \u5199\u6210\u300C\u76EE\u5F55\u300D\uFF1Bschema \u8BED\u4E49\u662F\u53EF\u6267\u884C\u6587\u4EF6\u3002\n * \u6B64\u5904\u517C\u5BB9\u4E8C\u8005\uFF0C\u907F\u514D spawn \u76EE\u5F55\u5BFC\u81F4 ENOENT\u3002\n */\n\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nexport function defaultLlbotDir(platform = process.platform): string {\n return platform === \"win32\" ? \"D:\\\\LLBot-CLI-win-x64\" : path.join(os.homedir(), \"LLBot\");\n}\n\nexport function llbotExeName(platform = process.platform): string {\n return platform === \"win32\" ? \"llbot.exe\" : \"llbot\";\n}\n\nexport type LlbotLaunch = {\n /** spawn \u7528\u7684\u53EF\u6267\u884C\u6587\u4EF6\u7EDD\u5BF9/\u89C4\u8303\u5316\u8DEF\u5F84 */\n exe: string;\n /** \u5DE5\u4F5C\u76EE\u5F55 */\n cwd: string;\n};\n\n/**\n * @param pathRaw qq_config.llbot_path\uFF08\u53EF\u4E3A exe \u6216\u76EE\u5F55\uFF09\n * @param cwdRaw qq_config.llbot_cwd\uFF08\u76EE\u5F55\uFF1B\u53EF\u7A7A\uFF09\n */\nexport function resolveLlbotLaunch(pathRaw: unknown, cwdRaw: unknown): LlbotLaunch {\n const exeName = llbotExeName();\n const raw = String(pathRaw ?? \"\").trim();\n const cwdHint = String(cwdRaw ?? \"\").trim();\n\n const looksLikeDir = (p: string): boolean => {\n try {\n if (fs.existsSync(p) && fs.statSync(p).isDirectory()) return true;\n } catch {\n /* ignore */\n }\n // \u5C1A\u4E0D\u5B58\u5728\u65F6\uFF1A\u65E0\u6269\u5C55\u540D\u4E14\u4E0D\u4EE5 exe \u540D\u7ED3\u5C3E \u2192 \u6309\u76EE\u5F55\u5904\u7406\n const base = path.basename(p);\n if (/^llbot(\\.exe)?$/i.test(base)) return false;\n return !path.extname(p);\n };\n\n if (!raw) {\n const cwd = cwdHint || defaultLlbotDir();\n return { exe: path.join(cwd, exeName), cwd };\n }\n\n if (looksLikeDir(raw)) {\n const cwd = raw;\n return { exe: path.join(cwd, exeName), cwd: cwdHint || cwd };\n }\n\n // \u660E\u786E\u662F\u53EF\u6267\u884C\u6587\u4EF6\u8DEF\u5F84\n const exe = raw;\n const cwd = cwdHint || path.dirname(exe) || defaultLlbotDir();\n return { exe, cwd };\n}\n"],
4
+ "sourcesContent": ["/**\n * llbot-launch.ts \u2014 \u89E3\u6790 LLBot \u53EF\u6267\u884C\u6587\u4EF6\u4E0E\u5DE5\u4F5C\u76EE\u5F55\n *\n * \u5386\u53F2\u5411\u5BFC\u66FE\u628A llbot.path \u5199\u6210\u300C\u76EE\u5F55\u300D\uFF1Bschema \u8BED\u4E49\u662F\u53EF\u6267\u884C\u6587\u4EF6\u3002\n * \u6B64\u5904\u517C\u5BB9\u4E8C\u8005\uFF0C\u907F\u514D spawn \u76EE\u5F55\u5BFC\u81F4 ENOENT\u3002\n */\n\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nexport function defaultLlbotDir(platform = process.platform): string {\n return platform === \"win32\" ? \"D:\\\\LLBot-CLI-win-x64\" : path.join(os.homedir(), \"LLBot\");\n}\n\nexport function llbotExeName(platform = process.platform): string {\n return platform === \"win32\" ? \"llbot.exe\" : \"llbot\";\n}\n\nexport type LlbotLaunch = {\n /** spawn \u7528\u7684\u53EF\u6267\u884C\u6587\u4EF6\u7EDD\u5BF9/\u89C4\u8303\u5316\u8DEF\u5F84 */\n exe: string;\n /** \u5DE5\u4F5C\u76EE\u5F55 */\n cwd: string;\n};\n\n/**\n * @param pathRaw qq_config.llbot.path\uFF08\u53EF\u4E3A exe \u6216\u76EE\u5F55\uFF09\n * @param cwdRaw qq_config.llbot.cwd\uFF08\u76EE\u5F55\uFF1B\u53EF\u7A7A\uFF09\n */\nexport function resolveLlbotLaunch(pathRaw: unknown, cwdRaw: unknown): LlbotLaunch {\n const exeName = llbotExeName();\n const raw = String(pathRaw ?? \"\").trim();\n const cwdHint = String(cwdRaw ?? \"\").trim();\n\n const looksLikeDir = (p: string): boolean => {\n try {\n if (fs.existsSync(p) && fs.statSync(p).isDirectory()) return true;\n } catch {\n /* ignore */\n }\n // \u5C1A\u4E0D\u5B58\u5728\u65F6\uFF1A\u65E0\u6269\u5C55\u540D\u4E14\u4E0D\u4EE5 exe \u540D\u7ED3\u5C3E \u2192 \u6309\u76EE\u5F55\u5904\u7406\n const base = path.basename(p);\n if (/^llbot(\\.exe)?$/i.test(base)) return false;\n return !path.extname(p);\n };\n\n if (!raw) {\n const cwd = cwdHint || defaultLlbotDir();\n return { exe: path.join(cwd, exeName), cwd };\n }\n\n if (looksLikeDir(raw)) {\n const cwd = raw;\n return { exe: path.join(cwd, exeName), cwd: cwdHint || cwd };\n }\n\n // \u660E\u786E\u662F\u53EF\u6267\u884C\u6587\u4EF6\u8DEF\u5F84\n const exe = raw;\n const cwd = cwdHint || path.dirname(exe) || defaultLlbotDir();\n return { exe, cwd };\n}\n"],
5
5
  "mappings": "AAOA,OAAO,QAAQ;AACf,OAAO,QAAQ;AACf,OAAO,UAAU;AAEV,SAAS,gBAAgB,WAAW,QAAQ,UAAkB;AACnE,SAAO,aAAa,UAAU,0BAA0B,KAAK,KAAK,GAAG,QAAQ,GAAG,OAAO;AACzF;AAEO,SAAS,aAAa,WAAW,QAAQ,UAAkB;AAChE,SAAO,aAAa,UAAU,cAAc;AAC9C;AAaO,SAAS,mBAAmB,SAAkB,QAA8B;AACjF,QAAM,UAAU,aAAa;AAC7B,QAAM,MAAM,OAAO,WAAW,EAAE,EAAE,KAAK;AACvC,QAAM,UAAU,OAAO,UAAU,EAAE,EAAE,KAAK;AAE1C,QAAM,eAAe,CAAC,MAAuB;AAC3C,QAAI;AACF,UAAI,GAAG,WAAW,CAAC,KAAK,GAAG,SAAS,CAAC,EAAE,YAAY,EAAG,QAAO;AAAA,IAC/D,QAAQ;AAAA,IAER;AAEA,UAAM,OAAO,KAAK,SAAS,CAAC;AAC5B,QAAI,mBAAmB,KAAK,IAAI,EAAG,QAAO;AAC1C,WAAO,CAAC,KAAK,QAAQ,CAAC;AAAA,EACxB;AAEA,MAAI,CAAC,KAAK;AACR,UAAMA,OAAM,WAAW,gBAAgB;AACvC,WAAO,EAAE,KAAK,KAAK,KAAKA,MAAK,OAAO,GAAG,KAAAA,KAAI;AAAA,EAC7C;AAEA,MAAI,aAAa,GAAG,GAAG;AACrB,UAAMA,OAAM;AACZ,WAAO,EAAE,KAAK,KAAK,KAAKA,MAAK,OAAO,GAAG,KAAK,WAAWA,KAAI;AAAA,EAC7D;AAGA,QAAM,MAAM;AACZ,QAAM,MAAM,WAAW,KAAK,QAAQ,GAAG,KAAK,gBAAgB;AAC5D,SAAO,EAAE,KAAK,IAAI;AACpB;",
6
6
  "names": ["cwd"]
7
7
  }
@@ -8,11 +8,15 @@ export interface LogFilterRule {
8
8
  contains?: string;
9
9
  /** JS RegExp 源;支持前缀 (?i) 表示忽略大小写 */
10
10
  regex?: string;
11
+ /** 命中规则时的替换/翻译文本模板,支持 $1, $2 等正则捕获变量 */
12
+ replace?: string;
11
13
  }
12
14
  export interface LogFilterConfig {
13
15
  enabled: boolean;
14
16
  mode: LogFilterMode;
15
17
  applyTo: LogFilterApplyTo;
18
+ /** 是否开启 BDS 原版与常用日志本地化翻译(缺省为 true) */
19
+ translate?: boolean;
16
20
  rules: LogFilterRule[];
17
21
  }
18
22
  export type LogFilterEntry = {
@@ -28,11 +32,13 @@ type CompiledRule = {
28
32
  levels?: Set<string>;
29
33
  contains?: string;
30
34
  regex?: RegExp;
35
+ replace?: string;
31
36
  };
32
- type CompiledFilter = {
37
+ export type CompiledFilter = {
33
38
  enabled: boolean;
34
39
  mode: LogFilterMode;
35
40
  applyTo: LogFilterApplyTo;
41
+ translate: boolean;
36
42
  rules: CompiledRule[];
37
43
  mtimeMs: number;
38
44
  };
@@ -54,16 +60,26 @@ export declare function entryMatchesAnyRule(entry: LogFilterEntry, rules: Compil
54
60
  export declare function shouldDropForDisplay(entry: LogFilterEntry, filter: CompiledFilter): boolean;
55
61
  /** 是否应跳过落盘(仅 applyTo=all 时与 display 一致) */
56
62
  export declare function shouldDropForDisk(entry: LogFilterEntry, filter: CompiledFilter): boolean;
63
+ /**
64
+ * 对日志条目应用转换/本地化翻译:
65
+ * 1. 优先匹配 rules 中带有 replace 的自定义规则(支持 $1, $2 捕获组)
66
+ * 2. 若未被自定义规则替换且启用了 translate(且 source 为 bds),调用内建 BDS 翻译引擎
67
+ */
68
+ export declare function transformLogEntry(entry: LogFilterEntry, filter?: CompiledFilter, locale?: string): {
69
+ entry: LogFilterEntry;
70
+ transformed: boolean;
71
+ };
57
72
  /** 测试用:清空缓存 */
58
73
  export declare function resetLogFilterCacheForTests(): void;
59
74
  /**
60
75
  * 纯函数判定(不读盘):供单测与调用方表驱动。
61
76
  * dropDisplay / dropDisk 语义与 pushLog 一致。
62
77
  */
63
- export declare function evaluateLogFilter(entry: LogFilterEntry, cfg: LogFilterConfig): {
78
+ export declare function evaluateLogFilter(entry: LogFilterEntry, cfg: LogFilterConfig, locale?: string): {
64
79
  dropDisplay: boolean;
65
80
  dropDisk: boolean;
66
81
  matched: boolean;
82
+ transformedEntry: LogFilterEntry;
67
83
  };
68
84
  export {};
69
85
  //# sourceMappingURL=log-filter.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"log-filter.d.ts","sourceRoot":"","sources":["../src/log-filter.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAKnD,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,CAAC;AAC5C,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,KAAK,CAAC;AAEjD,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,EAAE,gBAAgB,CAAC;IAC1B,KAAK,EAAE,aAAa,EAAE,CAAC;CACxB;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,QAAQ,CAAC;CACjB,CAAC;AASF,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED,qFAAqF;AACrF,wBAAgB,yBAAyB,IAAI,MAAM,CAGlD;AAED,KAAK,YAAY,GAAG;IAClB,OAAO,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACtB,MAAM,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,KAAK,cAAc,GAAG;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,EAAE,gBAAgB,CAAC;IAC1B,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAIF,2CAA2C;AAC3C,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAYhE;AAiDD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAAG,cAAc,CA8BvF;AAED,uBAAuB;AACvB,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,cAAc,GAAG,OAAO,CAMnF;AAED,uBAAuB;AACvB,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,OAAO,CAGzF;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAK3F;AAED,2CAA2C;AAC3C,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAGxF;AAED,eAAe;AACf,wBAAgB,2BAA2B,IAAI,IAAI,CAElD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,cAAc,EACrB,GAAG,EAAE,eAAe,GACnB;IAAE,WAAW,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAa/D"}
1
+ {"version":3,"file":"log-filter.d.ts","sourceRoot":"","sources":["../src/log-filter.ts"],"names":[],"mappings":"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"}
@@ -2,10 +2,13 @@ import { ensureSchemaConfig, readJson, stripConfigMeta } from "@sfmc-bds/sdk/nod
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import { ROOT } from "./runtime.js";
5
+ import { applyRuleReplacement, translateBdsLog } from "./log-translator.js";
6
+ import { getLocale } from "./i18n/index.js";
5
7
  const DEFAULTS = {
6
8
  enabled: false,
7
9
  mode: "drop",
8
10
  applyTo: "display",
11
+ translate: true,
9
12
  rules: []
10
13
  };
11
14
  function logFilterConfigPath() {
@@ -33,7 +36,7 @@ function compileRules(rules, onBadRegex) {
33
36
  const out = [];
34
37
  for (const r of rules) {
35
38
  if (r.enabled === false) continue;
36
- const hasAny = r.sources && r.sources.length > 0 || r.levels && r.levels.length > 0 || typeof r.contains === "string" && r.contains.length > 0 || typeof r.regex === "string" && r.regex.length > 0;
39
+ const hasAny = r.sources && r.sources.length > 0 || r.levels && r.levels.length > 0 || typeof r.contains === "string" && r.contains.length > 0 || typeof r.regex === "string" && r.regex.length > 0 || typeof r.replace === "string" && r.replace.length > 0;
37
40
  if (!hasAny) continue;
38
41
  const compiled = {};
39
42
  if (r.sources && r.sources.length > 0) {
@@ -53,6 +56,9 @@ function compileRules(rules, onBadRegex) {
53
56
  }
54
57
  compiled.regex = re;
55
58
  }
59
+ if (typeof r.replace === "string") {
60
+ compiled.replace = r.replace;
61
+ }
56
62
  out.push(compiled);
57
63
  }
58
64
  return out;
@@ -61,11 +67,13 @@ function normalizeConfig(raw) {
61
67
  const stripped = stripConfigMeta(raw);
62
68
  const mode = stripped.mode === "keep" ? "keep" : "drop";
63
69
  const applyTo = stripped.applyTo === "all" ? "all" : "display";
70
+ const translate = stripped.translate !== void 0 ? Boolean(stripped.translate) : true;
64
71
  const rules = Array.isArray(stripped.rules) ? stripped.rules : [];
65
72
  return {
66
73
  enabled: Boolean(stripped.enabled),
67
74
  mode,
68
75
  applyTo,
76
+ translate,
69
77
  rules
70
78
  };
71
79
  }
@@ -92,6 +100,7 @@ function getCompiledLogFilter(onBadRegex) {
92
100
  enabled: cfg.enabled,
93
101
  mode: cfg.mode,
94
102
  applyTo: cfg.applyTo,
103
+ translate: cfg.translate ?? true,
95
104
  rules,
96
105
  mtimeMs
97
106
  };
@@ -118,21 +127,61 @@ function shouldDropForDisk(entry, filter) {
118
127
  if (filter.applyTo !== "all") return false;
119
128
  return shouldDropForDisplay(entry, filter);
120
129
  }
130
+ function transformLogEntry(entry, filter, locale) {
131
+ if (filter && filter.rules.length > 0) {
132
+ for (const rule of filter.rules) {
133
+ if (rule.replace && ruleMatchesEntry(rule, entry)) {
134
+ let newText = entry.text;
135
+ if (rule.regex) {
136
+ newText = applyRuleReplacement(entry.text, rule.regex, rule.replace);
137
+ } else if (rule.contains) {
138
+ newText = entry.text.replaceAll(rule.contains, rule.replace);
139
+ } else {
140
+ newText = rule.replace;
141
+ }
142
+ return {
143
+ entry: { ...entry, text: newText },
144
+ transformed: true
145
+ };
146
+ }
147
+ }
148
+ }
149
+ const translateEnabled = filter ? filter.translate : true;
150
+ if (translateEnabled && entry.source.toLowerCase() === "bds") {
151
+ let loc;
152
+ try {
153
+ loc = locale ?? getLocale();
154
+ } catch {
155
+ loc = locale ?? "zh-CN";
156
+ }
157
+ const res = translateBdsLog(entry.text, loc);
158
+ if (res.translated) {
159
+ return {
160
+ entry: { ...entry, text: res.text },
161
+ transformed: true
162
+ };
163
+ }
164
+ }
165
+ return { entry, transformed: false };
166
+ }
121
167
  function resetLogFilterCacheForTests() {
122
168
  cache = null;
123
169
  }
124
- function evaluateLogFilter(entry, cfg) {
170
+ function evaluateLogFilter(entry, cfg, locale) {
125
171
  const compiled = {
126
172
  enabled: cfg.enabled,
127
173
  mode: cfg.mode,
128
174
  applyTo: cfg.applyTo,
175
+ translate: cfg.translate ?? true,
129
176
  rules: compileRules(cfg.rules),
130
177
  mtimeMs: 0
131
178
  };
179
+ const transformRes = transformLogEntry(entry, compiled, locale);
132
180
  return {
133
181
  matched: entryMatchesAnyRule(entry, compiled.rules),
134
182
  dropDisplay: shouldDropForDisplay(entry, compiled),
135
- dropDisk: shouldDropForDisk(entry, compiled)
183
+ dropDisk: shouldDropForDisk(entry, compiled),
184
+ transformedEntry: transformRes.entry
136
185
  };
137
186
  }
138
187
  export {
@@ -145,6 +194,7 @@ export {
145
194
  resetLogFilterCacheForTests,
146
195
  ruleMatchesEntry,
147
196
  shouldDropForDisk,
148
- shouldDropForDisplay
197
+ shouldDropForDisplay,
198
+ transformLogEntry
149
199
  };
150
200
  //# sourceMappingURL=log-filter.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/log-filter.ts"],
4
- "sourcesContent": ["/**\n * log-filter.ts \u2014 configs/log-filter.json \u52A0\u8F7D\u4E0E\u5339\u914D\uFF08\u7EAF\u5224\u5B9A + \u70ED\u8BFB\u7F13\u5B58\uFF09\n */\nimport { ensureSchemaConfig, readJson, stripConfigMeta } from \"@sfmc-bds/sdk/node/config\";\nimport type { LogLevel } from \"@sfmc-bds/sdk/logs\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { ROOT } from \"./runtime.js\";\n\nexport type LogFilterMode = \"drop\" | \"keep\";\nexport type LogFilterApplyTo = \"display\" | \"all\";\n\nexport interface LogFilterRule {\n enabled?: boolean;\n sources?: string[];\n levels?: LogLevel[];\n contains?: string;\n /** JS RegExp \u6E90\uFF1B\u652F\u6301\u524D\u7F00 (?i) \u8868\u793A\u5FFD\u7565\u5927\u5C0F\u5199 */\n regex?: string;\n}\n\nexport interface LogFilterConfig {\n enabled: boolean;\n mode: LogFilterMode;\n applyTo: LogFilterApplyTo;\n rules: LogFilterRule[];\n}\n\nexport type LogFilterEntry = {\n text: string;\n source: string;\n level: LogLevel;\n};\n\nconst DEFAULTS: LogFilterConfig = {\n enabled: false,\n mode: \"drop\",\n applyTo: \"display\",\n rules: [],\n};\n\nexport function logFilterConfigPath(): string {\n return path.join(ROOT, \"configs\", \"log-filter.json\");\n}\n\n/** \u786E\u4FDD configs/log-filter.json \u5B58\u5728\uFF08\u59D4\u6258 SDK ensureSchemaConfig\uFF0C\u7981\u6B62\u624B\u5199 withConfigSchema\uFF09 */\nexport function ensureLogFilterConfigFile(): string {\n ensureSchemaConfig(ROOT, \"log-filter.json\", \"log_filter\", { ...DEFAULTS } as Record<string, unknown>);\n return logFilterConfigPath();\n}\n\ntype CompiledRule = {\n sources?: Set<string>;\n levels?: Set<string>;\n contains?: string;\n regex?: RegExp;\n};\n\ntype CompiledFilter = {\n enabled: boolean;\n mode: LogFilterMode;\n applyTo: LogFilterApplyTo;\n rules: CompiledRule[];\n mtimeMs: number;\n};\n\nlet cache: CompiledFilter | null = null;\n\n/** \u5C06 (?i) \u524D\u7F00\u8F6C\u4E3A RegExp i \u65D7\u6807\uFF08JS \u65E0\u5185\u8054 (?i)\uFF09 */\nexport function compileLogFilterRegex(src: string): RegExp | null {\n let pattern = String(src ?? \"\");\n let flags = \"\";\n if (pattern.startsWith(\"(?i)\")) {\n pattern = pattern.slice(4);\n flags = \"i\";\n }\n try {\n return new RegExp(pattern, flags);\n } catch {\n return null;\n }\n}\n\nfunction compileRules(rules: LogFilterRule[], onBadRegex?: (src: string) => void): CompiledRule[] {\n const out: CompiledRule[] = [];\n for (const r of rules) {\n if (r.enabled === false) continue;\n const hasAny =\n (r.sources && r.sources.length > 0) ||\n (r.levels && r.levels.length > 0) ||\n (typeof r.contains === \"string\" && r.contains.length > 0) ||\n (typeof r.regex === \"string\" && r.regex.length > 0);\n if (!hasAny) continue;\n\n const compiled: CompiledRule = {};\n if (r.sources && r.sources.length > 0) {\n compiled.sources = new Set(r.sources.map((s) => s.toLowerCase()));\n }\n if (r.levels && r.levels.length > 0) {\n compiled.levels = new Set(r.levels.map((l) => l.toLowerCase()));\n }\n if (typeof r.contains === \"string\" && r.contains.length > 0) {\n compiled.contains = r.contains;\n }\n if (typeof r.regex === \"string\" && r.regex.length > 0) {\n const re = compileLogFilterRegex(r.regex);\n if (!re) {\n onBadRegex?.(r.regex);\n continue;\n }\n compiled.regex = re;\n }\n out.push(compiled);\n }\n return out;\n}\n\nfunction normalizeConfig(raw: Record<string, unknown>): LogFilterConfig {\n const stripped = stripConfigMeta(raw);\n const mode = stripped.mode === \"keep\" ? \"keep\" : \"drop\";\n const applyTo = stripped.applyTo === \"all\" ? \"all\" : \"display\";\n const rules = Array.isArray(stripped.rules) ? (stripped.rules as LogFilterRule[]) : [];\n return {\n enabled: Boolean(stripped.enabled),\n mode,\n applyTo,\n rules,\n };\n}\n\n/**\n * \u52A0\u8F7D\u5E76\u7F16\u8BD1\u8FC7\u6EE4\u914D\u7F6E\uFF08\u6309\u6587\u4EF6 mtime \u70ED\u8BFB\uFF09\u3002\n * onBadRegex\uFF1A\u6B63\u5219\u975E\u6CD5\u65F6\u56DE\u8C03\uFF08\u7531 logs \u5C42\u6253 warn\uFF0C\u907F\u514D\u5FAA\u73AF\u4F9D\u8D56\uFF09\u3002\n */\nexport function getCompiledLogFilter(onBadRegex?: (src: string) => void): CompiledFilter {\n const p = ensureLogFilterConfigFile();\n let mtimeMs = 0;\n try {\n mtimeMs = fs.statSync(p).mtimeMs;\n } catch {\n mtimeMs = 0;\n }\n if (cache && cache.mtimeMs === mtimeMs) return cache;\n\n let cfg = { ...DEFAULTS };\n const raw = readJson<Record<string, unknown>>(p);\n if (raw) {\n try {\n cfg = normalizeConfig(raw);\n } catch {\n cfg = { ...DEFAULTS };\n }\n }\n\n const rules = compileRules(cfg.rules, onBadRegex);\n\n cache = {\n enabled: cfg.enabled,\n mode: cfg.mode,\n applyTo: cfg.applyTo,\n rules,\n mtimeMs,\n };\n return cache;\n}\n\n/** \u5355\u6761\u89C4\u5219\u662F\u5426\u547D\u4E2D\uFF08\u540C\u6761 AND\uFF09 */\nexport function ruleMatchesEntry(rule: CompiledRule, entry: LogFilterEntry): boolean {\n if (rule.sources && !rule.sources.has(entry.source.toLowerCase())) return false;\n if (rule.levels && !rule.levels.has(entry.level.toLowerCase())) return false;\n if (rule.contains != null && !entry.text.includes(rule.contains)) return false;\n if (rule.regex && !rule.regex.test(entry.text)) return false;\n return true;\n}\n\n/** \u4EFB\u4E00\u89C4\u5219\u547D\u4E2D\u5373\u4E3A matched */\nexport function entryMatchesAnyRule(entry: LogFilterEntry, rules: CompiledRule[]): boolean {\n if (rules.length === 0) return false;\n return rules.some((r) => ruleMatchesEntry(r, entry));\n}\n\n/**\n * \u662F\u5426\u5E94\u4E22\u5F03\u8BE5\u6761\uFF08\u5BF9\u5C55\u793A/\u5185\u5B58\u800C\u8A00\uFF09\u3002\n * enabled=false \u2192 \u4E0D\u4E22\uFF1Bkeep \u6A21\u5F0F\u672A\u5339\u914D \u2192 \u4E22\uFF1Bdrop \u6A21\u5F0F\u5339\u914D \u2192 \u4E22\u3002\n */\nexport function shouldDropForDisplay(entry: LogFilterEntry, filter: CompiledFilter): boolean {\n if (!filter.enabled) return false;\n const matched = entryMatchesAnyRule(entry, filter.rules);\n if (filter.mode === \"keep\") return !matched;\n return matched;\n}\n\n/** \u662F\u5426\u5E94\u8DF3\u8FC7\u843D\u76D8\uFF08\u4EC5 applyTo=all \u65F6\u4E0E display \u4E00\u81F4\uFF09 */\nexport function shouldDropForDisk(entry: LogFilterEntry, filter: CompiledFilter): boolean {\n if (filter.applyTo !== \"all\") return false;\n return shouldDropForDisplay(entry, filter);\n}\n\n/** \u6D4B\u8BD5\u7528\uFF1A\u6E05\u7A7A\u7F13\u5B58 */\nexport function resetLogFilterCacheForTests(): void {\n cache = null;\n}\n\n/**\n * \u7EAF\u51FD\u6570\u5224\u5B9A\uFF08\u4E0D\u8BFB\u76D8\uFF09\uFF1A\u4F9B\u5355\u6D4B\u4E0E\u8C03\u7528\u65B9\u8868\u9A71\u52A8\u3002\n * dropDisplay / dropDisk \u8BED\u4E49\u4E0E pushLog \u4E00\u81F4\u3002\n */\nexport function evaluateLogFilter(\n entry: LogFilterEntry,\n cfg: LogFilterConfig\n): { dropDisplay: boolean; dropDisk: boolean; matched: boolean } {\n const compiled = {\n enabled: cfg.enabled,\n mode: cfg.mode,\n applyTo: cfg.applyTo,\n rules: compileRules(cfg.rules),\n mtimeMs: 0,\n };\n return {\n matched: entryMatchesAnyRule(entry, compiled.rules),\n dropDisplay: shouldDropForDisplay(entry, compiled),\n dropDisk: shouldDropForDisk(entry, compiled),\n };\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * log-filter.ts \u2014 configs/log-filter.json \u52A0\u8F7D\u4E0E\u5339\u914D\uFF08\u7EAF\u5224\u5B9A + \u70ED\u8BFB\u7F13\u5B58\uFF09\n */\nimport { ensureSchemaConfig, readJson, stripConfigMeta } from \"@sfmc-bds/sdk/node/config\";\nimport type { LogLevel } from \"@sfmc-bds/sdk/logs\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { ROOT } from \"./runtime.js\";\nimport { applyRuleReplacement, translateBdsLog } from \"./log-translator.js\";\nimport { getLocale } from \"./i18n/index.js\";\n\nexport type LogFilterMode = \"drop\" | \"keep\";\nexport type LogFilterApplyTo = \"display\" | \"all\";\n\nexport interface LogFilterRule {\n enabled?: boolean;\n sources?: string[];\n levels?: LogLevel[];\n contains?: string;\n /** JS RegExp \u6E90\uFF1B\u652F\u6301\u524D\u7F00 (?i) \u8868\u793A\u5FFD\u7565\u5927\u5C0F\u5199 */\n regex?: string;\n /** \u547D\u4E2D\u89C4\u5219\u65F6\u7684\u66FF\u6362/\u7FFB\u8BD1\u6587\u672C\u6A21\u677F\uFF0C\u652F\u6301 $1, $2 \u7B49\u6B63\u5219\u6355\u83B7\u53D8\u91CF */\n replace?: string;\n}\n\nexport interface LogFilterConfig {\n enabled: boolean;\n mode: LogFilterMode;\n applyTo: LogFilterApplyTo;\n /** \u662F\u5426\u5F00\u542F BDS \u539F\u7248\u4E0E\u5E38\u7528\u65E5\u5FD7\u672C\u5730\u5316\u7FFB\u8BD1\uFF08\u7F3A\u7701\u4E3A true\uFF09 */\n translate?: boolean;\n rules: LogFilterRule[];\n}\n\nexport type LogFilterEntry = {\n text: string;\n source: string;\n level: LogLevel;\n};\n\nconst DEFAULTS: LogFilterConfig = {\n enabled: false,\n mode: \"drop\",\n applyTo: \"display\",\n translate: true,\n rules: [],\n};\n\nexport function logFilterConfigPath(): string {\n return path.join(ROOT, \"configs\", \"log-filter.json\");\n}\n\n/** \u786E\u4FDD configs/log-filter.json \u5B58\u5728\uFF08\u59D4\u6258 SDK ensureSchemaConfig\uFF0C\u7981\u6B62\u624B\u5199 withConfigSchema\uFF09 */\nexport function ensureLogFilterConfigFile(): string {\n ensureSchemaConfig(ROOT, \"log-filter.json\", \"log_filter\", { ...DEFAULTS } as Record<string, unknown>);\n return logFilterConfigPath();\n}\n\ntype CompiledRule = {\n sources?: Set<string>;\n levels?: Set<string>;\n contains?: string;\n regex?: RegExp;\n replace?: string;\n};\n\nexport type CompiledFilter = {\n enabled: boolean;\n mode: LogFilterMode;\n applyTo: LogFilterApplyTo;\n translate: boolean;\n rules: CompiledRule[];\n mtimeMs: number;\n};\n\nlet cache: CompiledFilter | null = null;\n\n/** \u5C06 (?i) \u524D\u7F00\u8F6C\u4E3A RegExp i \u65D7\u6807\uFF08JS \u65E0\u5185\u8054 (?i)\uFF09 */\nexport function compileLogFilterRegex(src: string): RegExp | null {\n let pattern = String(src ?? \"\");\n let flags = \"\";\n if (pattern.startsWith(\"(?i)\")) {\n pattern = pattern.slice(4);\n flags = \"i\";\n }\n try {\n return new RegExp(pattern, flags);\n } catch {\n return null;\n }\n}\n\nfunction compileRules(rules: LogFilterRule[], onBadRegex?: (src: string) => void): CompiledRule[] {\n const out: CompiledRule[] = [];\n for (const r of rules) {\n if (r.enabled === false) continue;\n const hasAny =\n (r.sources && r.sources.length > 0) ||\n (r.levels && r.levels.length > 0) ||\n (typeof r.contains === \"string\" && r.contains.length > 0) ||\n (typeof r.regex === \"string\" && r.regex.length > 0) ||\n (typeof r.replace === \"string\" && r.replace.length > 0);\n if (!hasAny) continue;\n\n const compiled: CompiledRule = {};\n if (r.sources && r.sources.length > 0) {\n compiled.sources = new Set(r.sources.map((s) => s.toLowerCase()));\n }\n if (r.levels && r.levels.length > 0) {\n compiled.levels = new Set(r.levels.map((l) => l.toLowerCase()));\n }\n if (typeof r.contains === \"string\" && r.contains.length > 0) {\n compiled.contains = r.contains;\n }\n if (typeof r.regex === \"string\" && r.regex.length > 0) {\n const re = compileLogFilterRegex(r.regex);\n if (!re) {\n onBadRegex?.(r.regex);\n continue;\n }\n compiled.regex = re;\n }\n if (typeof r.replace === \"string\") {\n compiled.replace = r.replace;\n }\n out.push(compiled);\n }\n return out;\n}\n\nfunction normalizeConfig(raw: Record<string, unknown>): LogFilterConfig {\n const stripped = stripConfigMeta(raw);\n const mode = stripped.mode === \"keep\" ? \"keep\" : \"drop\";\n const applyTo = stripped.applyTo === \"all\" ? \"all\" : \"display\";\n const translate = stripped.translate !== undefined ? Boolean(stripped.translate) : true;\n const rules = Array.isArray(stripped.rules) ? (stripped.rules as LogFilterRule[]) : [];\n return {\n enabled: Boolean(stripped.enabled),\n mode,\n applyTo,\n translate,\n rules,\n };\n}\n\n/**\n * \u52A0\u8F7D\u5E76\u7F16\u8BD1\u8FC7\u6EE4\u914D\u7F6E\uFF08\u6309\u6587\u4EF6 mtime \u70ED\u8BFB\uFF09\u3002\n * onBadRegex\uFF1A\u6B63\u5219\u975E\u6CD5\u65F6\u56DE\u8C03\uFF08\u7531 logs \u5C42\u6253 warn\uFF0C\u907F\u514D\u5FAA\u73AF\u4F9D\u8D56\uFF09\u3002\n */\nexport function getCompiledLogFilter(onBadRegex?: (src: string) => void): CompiledFilter {\n const p = ensureLogFilterConfigFile();\n let mtimeMs = 0;\n try {\n mtimeMs = fs.statSync(p).mtimeMs;\n } catch {\n mtimeMs = 0;\n }\n if (cache && cache.mtimeMs === mtimeMs) return cache;\n\n let cfg = { ...DEFAULTS };\n const raw = readJson<Record<string, unknown>>(p);\n if (raw) {\n try {\n cfg = normalizeConfig(raw);\n } catch {\n cfg = { ...DEFAULTS };\n }\n }\n\n const rules = compileRules(cfg.rules, onBadRegex);\n\n cache = {\n enabled: cfg.enabled,\n mode: cfg.mode,\n applyTo: cfg.applyTo,\n translate: cfg.translate ?? true,\n rules,\n mtimeMs,\n };\n return cache;\n}\n\n/** \u5355\u6761\u89C4\u5219\u662F\u5426\u547D\u4E2D\uFF08\u540C\u6761 AND\uFF09 */\nexport function ruleMatchesEntry(rule: CompiledRule, entry: LogFilterEntry): boolean {\n if (rule.sources && !rule.sources.has(entry.source.toLowerCase())) return false;\n if (rule.levels && !rule.levels.has(entry.level.toLowerCase())) return false;\n if (rule.contains != null && !entry.text.includes(rule.contains)) return false;\n if (rule.regex && !rule.regex.test(entry.text)) return false;\n return true;\n}\n\n/** \u4EFB\u4E00\u89C4\u5219\u547D\u4E2D\u5373\u4E3A matched */\nexport function entryMatchesAnyRule(entry: LogFilterEntry, rules: CompiledRule[]): boolean {\n if (rules.length === 0) return false;\n return rules.some((r) => ruleMatchesEntry(r, entry));\n}\n\n/**\n * \u662F\u5426\u5E94\u4E22\u5F03\u8BE5\u6761\uFF08\u5BF9\u5C55\u793A/\u5185\u5B58\u800C\u8A00\uFF09\u3002\n * enabled=false \u2192 \u4E0D\u4E22\uFF1Bkeep \u6A21\u5F0F\u672A\u5339\u914D \u2192 \u4E22\uFF1Bdrop \u6A21\u5F0F\u5339\u914D \u2192 \u4E22\u3002\n */\nexport function shouldDropForDisplay(entry: LogFilterEntry, filter: CompiledFilter): boolean {\n if (!filter.enabled) return false;\n const matched = entryMatchesAnyRule(entry, filter.rules);\n if (filter.mode === \"keep\") return !matched;\n return matched;\n}\n\n/** \u662F\u5426\u5E94\u8DF3\u8FC7\u843D\u76D8\uFF08\u4EC5 applyTo=all \u65F6\u4E0E display \u4E00\u81F4\uFF09 */\nexport function shouldDropForDisk(entry: LogFilterEntry, filter: CompiledFilter): boolean {\n if (filter.applyTo !== \"all\") return false;\n return shouldDropForDisplay(entry, filter);\n}\n\n/**\n * \u5BF9\u65E5\u5FD7\u6761\u76EE\u5E94\u7528\u8F6C\u6362/\u672C\u5730\u5316\u7FFB\u8BD1\uFF1A\n * 1. \u4F18\u5148\u5339\u914D rules \u4E2D\u5E26\u6709 replace \u7684\u81EA\u5B9A\u4E49\u89C4\u5219\uFF08\u652F\u6301 $1, $2 \u6355\u83B7\u7EC4\uFF09\n * 2. \u82E5\u672A\u88AB\u81EA\u5B9A\u4E49\u89C4\u5219\u66FF\u6362\u4E14\u542F\u7528\u4E86 translate\uFF08\u4E14 source \u4E3A bds\uFF09\uFF0C\u8C03\u7528\u5185\u5EFA BDS \u7FFB\u8BD1\u5F15\u64CE\n */\nexport function transformLogEntry(\n entry: LogFilterEntry,\n filter?: CompiledFilter,\n locale?: string\n): { entry: LogFilterEntry; transformed: boolean } {\n // 1. \u81EA\u5B9A\u4E49\u89C4\u5219 replace \u66FF\u6362\u4F18\u5148\n if (filter && filter.rules.length > 0) {\n for (const rule of filter.rules) {\n if (rule.replace && ruleMatchesEntry(rule, entry)) {\n let newText = entry.text;\n if (rule.regex) {\n newText = applyRuleReplacement(entry.text, rule.regex, rule.replace);\n } else if (rule.contains) {\n newText = entry.text.replaceAll(rule.contains, rule.replace);\n } else {\n newText = rule.replace;\n }\n return {\n entry: { ...entry, text: newText },\n transformed: true,\n };\n }\n }\n }\n\n // 2. \u5185\u7F6E BDS \u539F\u7248\u65E5\u5FD7\u672C\u5730\u5316\u7FFB\u8BD1\n const translateEnabled = filter ? filter.translate : true;\n if (translateEnabled && entry.source.toLowerCase() === \"bds\") {\n let loc: string;\n try {\n loc = locale ?? getLocale();\n } catch {\n loc = locale ?? \"zh-CN\";\n }\n const res = translateBdsLog(entry.text, loc);\n if (res.translated) {\n return {\n entry: { ...entry, text: res.text },\n transformed: true,\n };\n }\n }\n\n return { entry, transformed: false };\n}\n\n/** \u6D4B\u8BD5\u7528\uFF1A\u6E05\u7A7A\u7F13\u5B58 */\nexport function resetLogFilterCacheForTests(): void {\n cache = null;\n}\n\n/**\n * \u7EAF\u51FD\u6570\u5224\u5B9A\uFF08\u4E0D\u8BFB\u76D8\uFF09\uFF1A\u4F9B\u5355\u6D4B\u4E0E\u8C03\u7528\u65B9\u8868\u9A71\u52A8\u3002\n * dropDisplay / dropDisk \u8BED\u4E49\u4E0E pushLog \u4E00\u81F4\u3002\n */\nexport function evaluateLogFilter(\n entry: LogFilterEntry,\n cfg: LogFilterConfig,\n locale?: string\n): {\n dropDisplay: boolean;\n dropDisk: boolean;\n matched: boolean;\n transformedEntry: LogFilterEntry;\n} {\n const compiled: CompiledFilter = {\n enabled: cfg.enabled,\n mode: cfg.mode,\n applyTo: cfg.applyTo,\n translate: cfg.translate ?? true,\n rules: compileRules(cfg.rules),\n mtimeMs: 0,\n };\n const transformRes = transformLogEntry(entry, compiled, locale);\n return {\n matched: entryMatchesAnyRule(entry, compiled.rules),\n dropDisplay: shouldDropForDisplay(entry, compiled),\n dropDisk: shouldDropForDisk(entry, compiled),\n transformedEntry: transformRes.entry,\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * log-translator.ts — BDS 原版日志本地化翻译与友好转换引擎
3
+ *
4
+ * 将 Minecraft 基岩版专用服务端 (BDS) 引擎输出的晦涩英文日志
5
+ * (如 Beta APIs 阻断、方块形态超限、包缺失、配方失效、语法错误等)
6
+ * 转换为服主与开发者易懂的本地化语言日志。
7
+ */
8
+ export interface TranslationRule {
9
+ id: string;
10
+ pattern: RegExp;
11
+ translations: {
12
+ "zh-CN": string;
13
+ [locale: string]: string;
14
+ };
15
+ }
16
+ /**
17
+ * 内置常见 BDS 原版日志翻译字典
18
+ */
19
+ export declare const BUILTIN_BDS_TRANSLATIONS: TranslationRule[];
20
+ /**
21
+ * 将正则匹配结果套入含 $1, $2 等占位符的模板字符串
22
+ */
23
+ export declare function interpolateRegexTemplate(match: RegExpMatchArray, template: string): string;
24
+ /**
25
+ * 应用规则正则替换模板
26
+ */
27
+ export declare function applyRuleReplacement(text: string, regex: RegExp, replaceTemplate: string): string;
28
+ /**
29
+ * 翻译单条 BDS 日志文本(纯函数)
30
+ */
31
+ export declare function translateBdsLog(text: string, locale?: string): {
32
+ translated: boolean;
33
+ text: string;
34
+ ruleId?: string;
35
+ };
36
+ //# sourceMappingURL=log-translator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-translator.d.ts","sourceRoot":"","sources":["../src/log-translator.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE;QACZ,OAAO,EAAE,MAAM,CAAC;QAChB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;KAC1B,CAAC;CACH;AAED;;GAEG;AACH,eAAO,MAAM,wBAAwB,EAAE,eAAe,EA+OrD,CAAC;AAEF;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAQ1F;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,CAIjG;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,MAAgB,GACvB;IAAE,UAAU,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAqBxD"}