fix_commit_5dfe60ed_utf8.mjs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import { readFileSync, writeFileSync, existsSync } from 'node:fs';
  2. import { execSync } from 'node:child_process';
  3. import { dirname, join } from 'node:path';
  4. import { fileURLToPath } from 'node:url';
  5. const scriptDir = dirname(fileURLToPath(import.meta.url));
  6. const root = join(scriptDir, '../../..');
  7. const svc = join(root, 'java/fs-service/src/main/java/com/fs/company/service/workflow');
  8. const srcDir = join(scriptDir, 'lobster_utf8_sources');
  9. const commitFiles = execSync('git show --name-only --pretty=format: 5dfe60ed', { cwd: root })
  10. .toString('utf8')
  11. .split(/\r?\n/)
  12. .filter(Boolean);
  13. function u(s) {
  14. return s.replace(/\\u([0-9a-fA-F]{4})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)));
  15. }
  16. function writeUtf8(path, content) {
  17. let text = content.replace(/\r\n/g, '\n');
  18. if (text.charCodeAt(0) === 0xfeff) {
  19. text = text.slice(1);
  20. }
  21. writeFileSync(path, text, 'utf8');
  22. }
  23. function decodeFile(rel) {
  24. const path = join(root, rel);
  25. if (!existsSync(path)) return;
  26. const raw = readFileSync(path, 'utf8');
  27. const decoded = u(raw);
  28. if (decoded === raw && !raw.charCodeAt(0)) return;
  29. writeUtf8(path, decoded);
  30. const count = (raw.match(/\\u[0-9a-fA-F]{4}/g) || []).length;
  31. if (count > 0) {
  32. console.log('decoded', rel, `(${count} escapes)`);
  33. }
  34. }
  35. function stripBom(rel) {
  36. const path = join(root, rel);
  37. if (!existsSync(path)) return;
  38. const raw = readFileSync(path);
  39. if (raw.length >= 3 && raw[0] === 0xef && raw[1] === 0xbb && raw[2] === 0xbf) {
  40. writeFileSync(path, raw.slice(3), 'utf8');
  41. console.log('stripped BOM', rel);
  42. }
  43. }
  44. function copySource(name, subdir) {
  45. const rel = subdir ? `${subdir}/${name}` : name;
  46. writeUtf8(join(svc, rel), readFileSync(join(srcDir, name), 'utf8'));
  47. console.log('restored source', name);
  48. }
  49. const sqlPatches = [
  50. {
  51. rel: 'java/fs-agent/src/main/resources/db/migration/tenant/V20260726_01__drop_lobster_evolution_token_menus.sql',
  52. header: u(`-- \u5220\u9664\u300cAI\u8fdb\u5316\u5f15\u64ce\u300d(29939) \u4e0e\u300cToken\u6d88\u8017\u7edf\u8ba1\u300d(29937)
  53. -- AI\u8fdb\u5316\u5f15\u64ce\u529f\u80fd\u5df2\u7531\u540e\u53f0 EvolutionScheduler +\u300c\u8bdd\u672f\u4f18\u5316\u5ba1\u6838\u300d\u627f\u63a5
  54. -- Token\u6d88\u8017\u7edf\u8ba1\u83dc\u5355\u4e0b\u7ebf\uff0c\u7edf\u8ba1\u80fd\u529b\u4fdd\u7559\u5728\u8ba1\u8d39/\u6d41\u6c34\u4fa7
  55. `),
  56. },
  57. {
  58. rel: 'java/fs-agent/src/main/resources/db/migration/tenant/V20260728_01__lobster_udd_admin_menus.sql',
  59. header: u(`-- \u79df\u6237\u7ba1\u7406\u7aef\uff08sys_menu\uff09\u589e\u52a0\uff1a\u884c\u4e1a\u8bed\u6599\u77e9\u9635\u3001\u6df1\u5ea6\u5bf9\u8bdd\u8c03\u8bd5
  60. -- \u4ec5\u7ba1\u7406\u7aef\u53ef\u89c1\uff0c\u4e0d\u540c\u6b65\u5230 company_menu\uff08\u9500\u552e\u7aef\uff09
  61. `),
  62. },
  63. {
  64. rel: 'java/sql/master/V20260726_01__drop_lobster_evolution_token_menus_master.sql',
  65. header: u(`-- \u4e3b\u5e93\uff1a\u5220\u9664\u300cAI\u8fdb\u5316\u5f15\u64ce\u300d(29939) \u4e0e\u300cToken\u6d88\u8017\u7edf\u8ba1\u300d(29937)
  66. `),
  67. },
  68. {
  69. rel: 'java/sql/master/V20260728_01__lobster_udd_admin_menus_master.sql',
  70. header: u(`-- \u4e3b\u5e93\u65b0\u79df\u6237\u6a21\u677f tenant_sys_menu\uff1a\u884c\u4e1a\u8bed\u6599\u77e9\u9635\u3001\u6df1\u5ea6\u5bf9\u8bdd\u8c03\u8bd5\uff08\u4ec5\u7ba1\u7406\u7aef\u6a21\u677f\uff0c\u4e0d\u5199 tenant_company_menu\uff09
  71. `),
  72. },
  73. ];
  74. for (const { rel, header } of sqlPatches) {
  75. const path = join(root, rel);
  76. if (!existsSync(path)) continue;
  77. let text = readFileSync(path, 'utf8').replace(/\r\n/g, '\n');
  78. const bodyStart = text.indexOf('\n\n');
  79. const body = bodyStart >= 0 ? text.slice(bodyStart + 1) : text.replace(/^[^\n]*\n?/, '');
  80. writeUtf8(path, header + '\n' + body.replace(/^\n+/, ''));
  81. console.log('sql header fixed', rel);
  82. }
  83. {
  84. const rel = 'java/sql/lobster_menu_canonical_init.sql';
  85. const path = join(root, rel);
  86. let text = readFileSync(path, 'utf8').replace(/\r\n/g, '\n');
  87. text = text
  88. .replace(u('-- \u9f99\u8679\u5f15\u64ce\u83dc\u5355'), u('-- \u9f99\u867e\u5f15\u64ce\u83dc\u5355'))
  89. .replace(/^-- A\.3.*$/mu, u('-- A.3 \u91cd\u5efa sys_menu\uff08UNHEX \u4fdd\u8bc1\u4e2d\u6587\u540d\u79f0\uff09'))
  90. .replace(/^-- A\.4.*$/mu, u('-- A.4 \u540c\u6b65 company_menu\uff08\u9500\u552e\u7aef\u5b50\u96c6\uff09'))
  91. .replace(/^-- A\.5.*$/mu, u('-- A.5 \u8865\u5168\u89d2\u8272\u6388\u6743'))
  92. .replace(/^-- PART B.*tenant_sys_menu.*$/mu, u('-- PART B \uff1a\u9010\u79df\u6237 tenant_sys_menu + tenant_company_menu\uff08\u6a21\u677f\u5e93\u6267\u884c\uff09'));
  93. writeUtf8(path, text);
  94. console.log('sql fixed', rel);
  95. }
  96. for (const rel of commitFiles) {
  97. if (/\.(java|js)$/.test(rel)) {
  98. decodeFile(rel);
  99. }
  100. stripBom(rel);
  101. }
  102. for (const name of [
  103. 'LobsterOutboundQualityGate.java',
  104. 'ProductKnowledgeBoundaryPolicy.java',
  105. 'TenantProductClaimSemanticAnalyzer.java',
  106. 'LobsterProactiveGreetingService.java',
  107. 'LobsterMessageTemplateRenderer.java',
  108. 'GeneralKnowledgeDialoguePolicy.java',
  109. 'CustomerFacingMessageSplitter.java',
  110. ]) {
  111. copySource(name, name.startsWith('General') || name.startsWith('Customer') ? 'deepdialogue' : 'execution');
  112. }
  113. console.log('fix commit 5dfe60ed utf8 done');