prts-terrarchive 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 (287) hide show
  1. package/GAME_ASSETS.md +26 -0
  2. package/LICENSE +21 -0
  3. package/README.en.md +274 -0
  4. package/README.md +423 -0
  5. package/THIRD_PARTY_NOTICES.md +61 -0
  6. package/bin/bake-rhine-details.mjs +34 -0
  7. package/bin/install.js +273 -0
  8. package/bin/pack-map-assets.mjs +110 -0
  9. package/bin/preview-rhine.mjs +71 -0
  10. package/bin/rhine-detail-baker.ts +84 -0
  11. package/contracts/cloud_tools_v1.schema.json +243 -0
  12. package/contracts/corpus_i18n_v1.schema.json +179 -0
  13. package/contracts/corpus_tools_v1.schema.json +1801 -0
  14. package/cordis.patch.yml +32 -0
  15. package/docs/endfield-official-i18n.md +103 -0
  16. package/lib/client.js +3912 -0
  17. package/lib/endfield-map/map.js.br +0 -0
  18. package/lib/endfield-map/map.js.gz +0 -0
  19. package/lib/endfield-map/resources/map-00b0d0744a1b4404.json.br +0 -0
  20. package/lib/endfield-map/resources/map-00b0d0744a1b4404.json.gz +0 -0
  21. package/lib/endfield-map/resources/map-01616f534aaaeca1.png +0 -0
  22. package/lib/endfield-map/resources/map-1562e0dff4be3d23.png +0 -0
  23. package/lib/endfield-map/resources/map-160fe040f080f6a3.png +0 -0
  24. package/lib/endfield-map/resources/map-17b9d8be25dc2b39.json.br +0 -0
  25. package/lib/endfield-map/resources/map-17b9d8be25dc2b39.json.gz +0 -0
  26. package/lib/endfield-map/resources/map-1c4245c4e8b80c43.json.br +0 -0
  27. package/lib/endfield-map/resources/map-1c4245c4e8b80c43.json.gz +0 -0
  28. package/lib/endfield-map/resources/map-1d30baaaef3e29cc.png +0 -0
  29. package/lib/endfield-map/resources/map-21a61386af79cd12.json.br +0 -0
  30. package/lib/endfield-map/resources/map-21a61386af79cd12.json.gz +0 -0
  31. package/lib/endfield-map/resources/map-24b920b8dab49b44.json.br +0 -0
  32. package/lib/endfield-map/resources/map-24b920b8dab49b44.json.gz +0 -0
  33. package/lib/endfield-map/resources/map-26caf8d71247abb7.png +0 -0
  34. package/lib/endfield-map/resources/map-2729942c89545e73.json.br +0 -0
  35. package/lib/endfield-map/resources/map-2729942c89545e73.json.gz +0 -0
  36. package/lib/endfield-map/resources/map-29063a9802f67014.json.br +0 -0
  37. package/lib/endfield-map/resources/map-29063a9802f67014.json.gz +0 -0
  38. package/lib/endfield-map/resources/map-2f35d09a3ab60a63.json.br +0 -0
  39. package/lib/endfield-map/resources/map-2f35d09a3ab60a63.json.gz +0 -0
  40. package/lib/endfield-map/resources/map-2f98a873da81425e.json.br +0 -0
  41. package/lib/endfield-map/resources/map-2f98a873da81425e.json.gz +0 -0
  42. package/lib/endfield-map/resources/map-3ab978ae44190f80.json.br +0 -0
  43. package/lib/endfield-map/resources/map-3ab978ae44190f80.json.gz +0 -0
  44. package/lib/endfield-map/resources/map-3b62c80d14208902.json.br +0 -0
  45. package/lib/endfield-map/resources/map-3b62c80d14208902.json.gz +0 -0
  46. package/lib/endfield-map/resources/map-3d486e887ae121ac.png +0 -0
  47. package/lib/endfield-map/resources/map-418dc4865608fce5.png +0 -0
  48. package/lib/endfield-map/resources/map-4366b84607335f76.json.br +0 -0
  49. package/lib/endfield-map/resources/map-4366b84607335f76.json.gz +0 -0
  50. package/lib/endfield-map/resources/map-4371259d3ab7aac7.png +0 -0
  51. package/lib/endfield-map/resources/map-48dcc0fd55e13f7f.png +0 -0
  52. package/lib/endfield-map/resources/map-4aabda0e41197570.json.br +0 -0
  53. package/lib/endfield-map/resources/map-4aabda0e41197570.json.gz +0 -0
  54. package/lib/endfield-map/resources/map-505f5687b287043c.json.br +0 -0
  55. package/lib/endfield-map/resources/map-505f5687b287043c.json.gz +0 -0
  56. package/lib/endfield-map/resources/map-5177e9d1d46f47e2.png +0 -0
  57. package/lib/endfield-map/resources/map-51baeb59b7f8c28d.png +0 -0
  58. package/lib/endfield-map/resources/map-549561b46e621874.png +0 -0
  59. package/lib/endfield-map/resources/map-56c6a0bef799c8dc.json.br +0 -0
  60. package/lib/endfield-map/resources/map-56c6a0bef799c8dc.json.gz +0 -0
  61. package/lib/endfield-map/resources/map-5a6963909423b674.png +0 -0
  62. package/lib/endfield-map/resources/map-5a9c533c0552d7b7.png +0 -0
  63. package/lib/endfield-map/resources/map-5d20ae9ffa9a02b0.png +0 -0
  64. package/lib/endfield-map/resources/map-626c8847393f60bf.png +0 -0
  65. package/lib/endfield-map/resources/map-63d43cbec3bed3b8.png +0 -0
  66. package/lib/endfield-map/resources/map-661b6ec56e722574.png +0 -0
  67. package/lib/endfield-map/resources/map-6ddd384eca190828.png +0 -0
  68. package/lib/endfield-map/resources/map-6fc1aa9144f8156c.json.br +0 -0
  69. package/lib/endfield-map/resources/map-6fc1aa9144f8156c.json.gz +0 -0
  70. package/lib/endfield-map/resources/map-738ebaa002c33cfc.png +0 -0
  71. package/lib/endfield-map/resources/map-758c13be6085ec07.json.br +0 -0
  72. package/lib/endfield-map/resources/map-758c13be6085ec07.json.gz +0 -0
  73. package/lib/endfield-map/resources/map-78929f26d6844509.png +0 -0
  74. package/lib/endfield-map/resources/map-7f09c142950a0f74.png +0 -0
  75. package/lib/endfield-map/resources/map-8385e11f39e1a51c.json.br +0 -0
  76. package/lib/endfield-map/resources/map-8385e11f39e1a51c.json.gz +0 -0
  77. package/lib/endfield-map/resources/map-881343926a568f27.json.br +0 -0
  78. package/lib/endfield-map/resources/map-881343926a568f27.json.gz +0 -0
  79. package/lib/endfield-map/resources/map-8d1ade3f01d952b0.png +0 -0
  80. package/lib/endfield-map/resources/map-8fef3495bb7ed60f.png +0 -0
  81. package/lib/endfield-map/resources/map-907a7ecf8a0ce352.png +0 -0
  82. package/lib/endfield-map/resources/map-9113d5951c4db903.json.br +0 -0
  83. package/lib/endfield-map/resources/map-9113d5951c4db903.json.gz +0 -0
  84. package/lib/endfield-map/resources/map-94ad6634436224e3.json.br +0 -0
  85. package/lib/endfield-map/resources/map-94ad6634436224e3.json.gz +0 -0
  86. package/lib/endfield-map/resources/map-99722e61da5f3e53.png +0 -0
  87. package/lib/endfield-map/resources/map-9be9596cc059abe3.png +0 -0
  88. package/lib/endfield-map/resources/map-a4db9a4763e47fbf.png +0 -0
  89. package/lib/endfield-map/resources/map-a4e8ef07159997e7.json.br +0 -0
  90. package/lib/endfield-map/resources/map-a4e8ef07159997e7.json.gz +0 -0
  91. package/lib/endfield-map/resources/map-ab35d06875ee418f.png +0 -0
  92. package/lib/endfield-map/resources/map-ac51bb3e7623cd8b.png +0 -0
  93. package/lib/endfield-map/resources/map-ac830a66296bc83a.png +0 -0
  94. package/lib/endfield-map/resources/map-b3fd04209718e55e.json.br +0 -0
  95. package/lib/endfield-map/resources/map-b3fd04209718e55e.json.gz +0 -0
  96. package/lib/endfield-map/resources/map-b8164f1af7c5d895.png +0 -0
  97. package/lib/endfield-map/resources/map-b8cde93b965384d8.json.br +0 -0
  98. package/lib/endfield-map/resources/map-b8cde93b965384d8.json.gz +0 -0
  99. package/lib/endfield-map/resources/map-b8e48511502e0e8d.json.br +0 -0
  100. package/lib/endfield-map/resources/map-b8e48511502e0e8d.json.gz +0 -0
  101. package/lib/endfield-map/resources/map-bfc58277d5ba649d.png +0 -0
  102. package/lib/endfield-map/resources/map-c013f82048c6891a.png +0 -0
  103. package/lib/endfield-map/resources/map-c49c947841ae4ab5.json.br +0 -0
  104. package/lib/endfield-map/resources/map-c49c947841ae4ab5.json.gz +0 -0
  105. package/lib/endfield-map/resources/map-c4d1b1c6d6706c81.json.br +0 -0
  106. package/lib/endfield-map/resources/map-c4d1b1c6d6706c81.json.gz +0 -0
  107. package/lib/endfield-map/resources/map-c607f8b4c8ad8967.png +0 -0
  108. package/lib/endfield-map/resources/map-c6f20276b8781326.json.br +0 -0
  109. package/lib/endfield-map/resources/map-c6f20276b8781326.json.gz +0 -0
  110. package/lib/endfield-map/resources/map-d51adf5952af1e8e.png +0 -0
  111. package/lib/endfield-map/resources/map-d695eface22f8b74.json.br +0 -0
  112. package/lib/endfield-map/resources/map-d695eface22f8b74.json.gz +0 -0
  113. package/lib/endfield-map/resources/map-db11d394456a7465.png +0 -0
  114. package/lib/endfield-map/resources/map-dcc4d218581e3dc6.png +0 -0
  115. package/lib/endfield-map/resources/map-ddd43dbb8ab8a4e3.json.br +0 -0
  116. package/lib/endfield-map/resources/map-ddd43dbb8ab8a4e3.json.gz +0 -0
  117. package/lib/endfield-map/resources/map-defe5db7dabf748a.png +0 -0
  118. package/lib/endfield-map/resources/map-e1aeb833e22520aa.json.br +0 -0
  119. package/lib/endfield-map/resources/map-e1aeb833e22520aa.json.gz +0 -0
  120. package/lib/endfield-map/resources/map-e25ee9af6e493500.png +0 -0
  121. package/lib/endfield-map/resources/map-e3824082cd6f747d.json.br +0 -0
  122. package/lib/endfield-map/resources/map-e3824082cd6f747d.json.gz +0 -0
  123. package/lib/endfield-map/resources/map-e694a91e630b1bd6.png +0 -0
  124. package/lib/endfield-map/resources/map-eaa93af79d12a87d.png +0 -0
  125. package/lib/endfield-map/resources/map-ec9575ee65d7766f.json.br +0 -0
  126. package/lib/endfield-map/resources/map-ec9575ee65d7766f.json.gz +0 -0
  127. package/lib/endfield-map/resources/map-ede421a329dc78a4.png +0 -0
  128. package/lib/endfield-map/resources/map-eff3bce8f6888fc5.json.br +0 -0
  129. package/lib/endfield-map/resources/map-eff3bce8f6888fc5.json.gz +0 -0
  130. package/lib/endfield-map/resources/map-fb5f4a59a181452c.png +0 -0
  131. package/lib/endfield-map/resources/map-fdeaa17eeba90d8e.json.br +0 -0
  132. package/lib/endfield-map/resources/map-fdeaa17eeba90d8e.json.gz +0 -0
  133. package/lib/rhine/assets/archive-assembly.glb +0 -0
  134. package/lib/rhine/assets/archive-cassette.glb +0 -0
  135. package/lib/rhine/fonts/MiSans-Bold.woff2 +0 -0
  136. package/lib/rhine/fonts/MiSans-Demibold.woff2 +0 -0
  137. package/lib/rhine/fonts/MiSans-Light.woff2 +0 -0
  138. package/lib/rhine/fonts/MiSans-Regular.woff2 +0 -0
  139. package/lib/rhine/fonts/MiSans-license.pdf +0 -0
  140. package/lib/rhine/fonts/NOTICE.txt +6 -0
  141. package/lib/rhine/licenses/RhineLabUI-MIT.txt +21 -0
  142. package/lib/rhine/licenses/entities-BSD-2-Clause.txt +11 -0
  143. package/lib/rhine/licenses/linkify-it-MIT.txt +22 -0
  144. package/lib/rhine/licenses/markdown-it-MIT.txt +22 -0
  145. package/lib/rhine/licenses/mdurl-MIT.txt +45 -0
  146. package/lib/rhine/licenses/punycode.js-MIT.txt +20 -0
  147. package/lib/rhine/licenses/rolling-number-MIT.txt +21 -0
  148. package/lib/rhine/licenses/three-MIT.txt +21 -0
  149. package/lib/rhine/licenses/uc.micro-MIT.txt +20 -0
  150. package/lib/rhine/rhine.css +1 -0
  151. package/lib/rhine/rhine.js +5106 -0
  152. package/lib/skins/common.css +31 -0
  153. package/lib/skins/endfield-aic.css +141 -0
  154. package/lib/skins/prts-agent.css +136 -0
  155. package/lib/skins/rhine-lab.css +70 -0
  156. package/package.json +112 -0
  157. package/presets/definition.js +26 -0
  158. package/presets/prts/agent.cordis.yml +25 -0
  159. package/presets/prts/preset.yml +3 -0
  160. package/presets/register.js +86 -0
  161. package/resources/entity-routing.json +21 -0
  162. package/skills/prts-investigation/SKILL.md +121 -0
  163. package/skills/prts-retrieval/SKILL.md +35 -0
  164. package/skills/prts-retrieval/references/cloud-tools.md +13 -0
  165. package/skills/prts-retrieval/references/diagnostics.md +15 -0
  166. package/skills/prts-retrieval/references/local-tools.md +24 -0
  167. package/skills/prts-retrieval/references/module-arknights.md +23 -0
  168. package/skills/prts-retrieval/references/module-dual.md +15 -0
  169. package/skills/prts-retrieval/references/module-endfield.md +21 -0
  170. package/skills/prts-retrieval/references/retrieval-process.md +44 -0
  171. package/skills/prts-retrieval/references/retrieval-recipes-dual.md +34 -0
  172. package/skills/prts-retrieval/references/retrieval-recipes-endfield.md +37 -0
  173. package/skills/prts-retrieval/references/retrieval-recipes.md +39 -0
  174. package/skills/prts-retrieval/references/tools-runtime.md +48 -0
  175. package/skills/prts-retrieval/references/wiki-schema.md +38 -0
  176. package/src/archive-presentation.js +287 -0
  177. package/src/cloud-projection.js +124 -0
  178. package/src/cloud.js +498 -0
  179. package/src/entity-recognizer.js +311 -0
  180. package/src/entity-routing.js +82 -0
  181. package/src/evidence-state.js +332 -0
  182. package/src/i18n.js +365 -0
  183. package/src/index.js +1261 -0
  184. package/src/installer.js +1362 -0
  185. package/src/investigation-review.js +87 -0
  186. package/src/investigation-store.js +579 -0
  187. package/src/investigation-tools.js +113 -0
  188. package/src/localization-format.js +23 -0
  189. package/src/manual-search.js +103 -0
  190. package/src/read.js +1097 -0
  191. package/src/release-compatibility.js +73 -0
  192. package/src/release-watch.js +40 -0
  193. package/src/search-projection.js +139 -0
  194. package/src/search.js +1522 -0
  195. package/src/skill.js +98 -0
  196. package/src/source-map.js +348 -0
  197. package/src/state.js +314 -0
  198. package/src/store.js +1569 -0
  199. package/src/timeline.js +386 -0
  200. package/src/ui.js +1353 -0
  201. package/src/wiki.js +111 -0
  202. package/tsconfig.rhine.json +15 -0
  203. package/ui/rhine/archive-navigation-limit.ts +31 -0
  204. package/ui/rhine/archive-rack.ts +83 -0
  205. package/ui/rhine/assets/evidence-observatory.webp +0 -0
  206. package/ui/rhine/board-plane-transform.ts +24 -0
  207. package/ui/rhine/catalogue.ts +72 -0
  208. package/ui/rhine/deferred-preparation.ts +146 -0
  209. package/ui/rhine/evidence-board-controls.css +22 -0
  210. package/ui/rhine/evidence-board-history.ts +73 -0
  211. package/ui/rhine/evidence-board-model.ts +189 -0
  212. package/ui/rhine/evidence-board-panel.ts +762 -0
  213. package/ui/rhine/evidence-board-scene.ts +548 -0
  214. package/ui/rhine/evidence-board.css +191 -0
  215. package/ui/rhine/evidence-card-art.ts +470 -0
  216. package/ui/rhine/evidence-card-style.ts +17 -0
  217. package/ui/rhine/evidence-inbox-scene.ts +43 -0
  218. package/ui/rhine/evidence-inbox.css +29 -0
  219. package/ui/rhine/evidence-inbox.ts +104 -0
  220. package/ui/rhine/index.ts +12 -0
  221. package/ui/rhine/interaction.css +20 -0
  222. package/ui/rhine/investigation-board-plane.ts +5 -0
  223. package/ui/rhine/investigation-board.css +34 -0
  224. package/ui/rhine/investigation-board.ts +348 -0
  225. package/ui/rhine/investigation-edits.ts +46 -0
  226. package/ui/rhine/investigation-layout.ts +29 -0
  227. package/ui/rhine/label-prefetch.ts +34 -0
  228. package/ui/rhine/looping-title.ts +40 -0
  229. package/ui/rhine/manual-search.css +41 -0
  230. package/ui/rhine/manual-search.ts +89 -0
  231. package/ui/rhine/original/appearance.ts +180 -0
  232. package/ui/rhine/original/archive-label.ts +84 -0
  233. package/ui/rhine/original/archive-lighting.ts +39 -0
  234. package/ui/rhine/original/archive-loop.ts +82 -0
  235. package/ui/rhine/original/archive-refill.ts +64 -0
  236. package/ui/rhine/original/array-detail-data.ts +2 -0
  237. package/ui/rhine/original/array-detail.ts +41 -0
  238. package/ui/rhine/original/array-interior.ts +411 -0
  239. package/ui/rhine/original/array-occlusion.ts +166 -0
  240. package/ui/rhine/original/array-shell.ts +38 -0
  241. package/ui/rhine/original/array-visibility.ts +309 -0
  242. package/ui/rhine/original/asset-url.ts +4 -0
  243. package/ui/rhine/original/brand.ts +12 -0
  244. package/ui/rhine/original/cassette-lod.ts +81 -0
  245. package/ui/rhine/original/data.ts +21 -0
  246. package/ui/rhine/original/decryption.ts +185 -0
  247. package/ui/rhine/original/detail-signature.ts +18 -0
  248. package/ui/rhine/original/glass-reveal.ts +45 -0
  249. package/ui/rhine/original/internal-optics.ts +70 -0
  250. package/ui/rhine/original/label-renderer.ts +119 -0
  251. package/ui/rhine/original/label-textures.ts +117 -0
  252. package/ui/rhine/original/model-viewer.ts +658 -0
  253. package/ui/rhine/original/motion.ts +116 -0
  254. package/ui/rhine/original/opaque-backfaces.ts +64 -0
  255. package/ui/rhine/original/program-preparation.ts +111 -0
  256. package/ui/rhine/original/quality-renderer.ts +97 -0
  257. package/ui/rhine/original/quality-settings.ts +111 -0
  258. package/ui/rhine/original/render-quality.ts +163 -0
  259. package/ui/rhine/original/scene.ts +2051 -0
  260. package/ui/rhine/original/shelf-interior.ts +142 -0
  261. package/ui/rhine/original/ui-transitions.ts +111 -0
  262. package/ui/rhine/original/viewer-camera.ts +92 -0
  263. package/ui/rhine/original/viewport-layout.ts +41 -0
  264. package/ui/rhine/original-ui.css +2334 -0
  265. package/ui/rhine/readability.css +46 -0
  266. package/ui/rhine/reading-object.ts +96 -0
  267. package/ui/rhine/reading-origin.ts +28 -0
  268. package/ui/rhine/reading-room.css +55 -0
  269. package/ui/rhine/report-markdown.ts +98 -0
  270. package/ui/rhine/scene-edge-navigation.ts +84 -0
  271. package/ui/rhine/scene.ts +1726 -0
  272. package/ui/rhine/shelf-layout.ts +38 -0
  273. package/ui/rhine/snapshot-update-gate.ts +22 -0
  274. package/ui/rhine/source-reading.ts +15 -0
  275. package/ui/rhine/source-selection.css +164 -0
  276. package/ui/rhine/temporary-performance-observers.ts +163 -0
  277. package/ui/rhine/temporary-performance-panel.ts +124 -0
  278. package/ui/rhine/temporary-performance.css +19 -0
  279. package/ui/rhine/temporary-performance.ts +552 -0
  280. package/ui/rhine/temporary-render-diagnostics.ts +105 -0
  281. package/ui/rhine/tool-activity.ts +69 -0
  282. package/ui/rhine/types.ts +219 -0
  283. package/ui/rhine/visible-scene-hit.ts +13 -0
  284. package/ui/rhine/workbench.css +818 -0
  285. package/ui/rhine/workbench.ts +2245 -0
  286. package/ui/rhine/workspace-travel.ts +32 -0
  287. package/vite.rhine.config.ts +19 -0
@@ -0,0 +1,73 @@
1
+ import { createRequire } from 'node:module'
2
+
3
+ const packageMetadata = createRequire(import.meta.url)('../package.json')
4
+
5
+ export const AGENT_VERSION = packageMetadata.version
6
+
7
+ function parseIdentifierList(value, { prerelease = false } = {}) {
8
+ if (value === '') return null
9
+ const identifiers = value.split('.')
10
+ if (identifiers.some((identifier) => !/^[0-9A-Za-z-]+$/u.test(identifier)
11
+ || (prerelease && /^\d+$/u.test(identifier)
12
+ && identifier.length > 1 && identifier.startsWith('0')))) return null
13
+ return identifiers
14
+ }
15
+
16
+ /** Parse one strict Semantic Version 2.0.0 value without numeric precision loss. */
17
+ export function parseSemver(value) {
18
+ if (typeof value !== 'string' || value.length === 0 || value.length > 256
19
+ || value.trim() !== value) return null
20
+ const plus = value.indexOf('+')
21
+ if (plus !== -1 && value.indexOf('+', plus + 1) !== -1) return null
22
+ const coreAndPrerelease = plus === -1 ? value : value.slice(0, plus)
23
+ const buildText = plus === -1 ? null : value.slice(plus + 1)
24
+ const dash = coreAndPrerelease.indexOf('-')
25
+ const core = dash === -1 ? coreAndPrerelease : coreAndPrerelease.slice(0, dash)
26
+ const prereleaseText = dash === -1 ? null : coreAndPrerelease.slice(dash + 1)
27
+ const match = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/u.exec(core)
28
+ const prerelease = prereleaseText == null
29
+ ? [] : parseIdentifierList(prereleaseText, { prerelease: true })
30
+ const build = buildText == null ? [] : parseIdentifierList(buildText)
31
+ if (!match || prerelease == null || build == null) return null
32
+ return Object.freeze({ raw: value, core: Object.freeze(match.slice(1)),
33
+ prerelease: Object.freeze(prerelease), build: Object.freeze(build) })
34
+ }
35
+
36
+ function compareNumericIdentifiers(left, right) {
37
+ if (left.length !== right.length) return left.length < right.length ? -1 : 1
38
+ return left === right ? 0 : left < right ? -1 : 1
39
+ }
40
+
41
+ /** Compare strict SemVer values. Build metadata intentionally has no precedence. */
42
+ export function compareSemver(leftValue, rightValue) {
43
+ const left = parseSemver(leftValue)
44
+ const right = parseSemver(rightValue)
45
+ if (!left || !right) throw new TypeError('版本必须是有效的 Semantic Version 2.0.0')
46
+ for (let index = 0; index < 3; index += 1) {
47
+ const compared = compareNumericIdentifiers(left.core[index], right.core[index])
48
+ if (compared) return compared
49
+ }
50
+ if (!left.prerelease.length || !right.prerelease.length) {
51
+ if (left.prerelease.length === right.prerelease.length) return 0
52
+ return left.prerelease.length ? -1 : 1
53
+ }
54
+ const count = Math.max(left.prerelease.length, right.prerelease.length)
55
+ for (let index = 0; index < count; index += 1) {
56
+ const leftIdentifier = left.prerelease[index]
57
+ const rightIdentifier = right.prerelease[index]
58
+ if (leftIdentifier == null || rightIdentifier == null) {
59
+ return leftIdentifier == null ? -1 : 1
60
+ }
61
+ const leftNumeric = /^\d+$/u.test(leftIdentifier)
62
+ const rightNumeric = /^\d+$/u.test(rightIdentifier)
63
+ if (leftNumeric && rightNumeric) {
64
+ const compared = compareNumericIdentifiers(leftIdentifier, rightIdentifier)
65
+ if (compared) return compared
66
+ } else if (leftNumeric !== rightNumeric) {
67
+ return leftNumeric ? -1 : 1
68
+ } else if (leftIdentifier !== rightIdentifier) {
69
+ return leftIdentifier < rightIdentifier ? -1 : 1
70
+ }
71
+ }
72
+ return 0
73
+ }
@@ -0,0 +1,40 @@
1
+ import fs from 'node:fs'
2
+ import { basename, dirname, join } from 'node:path'
3
+
4
+ const WATCH_RESOURCE_ERRORS = new Set(['ENOSPC', 'EMFILE', 'ENFILE'])
5
+
6
+ /** Watch one file across atomic replacements, polling when native watcher resources are exhausted. */
7
+ export function watchFileChanges(path, onChange, { onFallback, onError } = {}) {
8
+ let closed = false
9
+ const notify = () => { if (!closed) onChange() }
10
+ let stop
11
+ try {
12
+ const watcher = fs.watch(dirname(path), { persistent: false }, (_event, filename) => {
13
+ if (filename == null || String(filename) === basename(path)) notify()
14
+ })
15
+ if (onError) watcher.on('error', (error) => { if (!closed) onError(error) })
16
+ stop = () => watcher.close()
17
+ } catch (error) {
18
+ if (!WATCH_RESOURCE_ERRORS.has(error?.code)) throw error
19
+ const listener = (current, previous) => {
20
+ // watchFile reports an initial missing file with two empty stats.
21
+ if (current.nlink === 0 && previous.nlink === 0) return
22
+ notify()
23
+ }
24
+ fs.watchFile(path, { persistent: false, interval: 1000 }, listener)
25
+ stop = () => fs.unwatchFile(path, listener)
26
+ onFallback?.(error)
27
+ }
28
+ return {
29
+ close() {
30
+ if (closed) return
31
+ closed = true
32
+ stop()
33
+ },
34
+ }
35
+ }
36
+
37
+ /** Watch the active release pointer without requiring native watcher capacity. */
38
+ export function watchCurrentRelease(releasesDir, onChange, options) {
39
+ return watchFileChanges(join(releasesDir, 'current.json'), onChange, options)
40
+ }
@@ -0,0 +1,139 @@
1
+ /** 将 public canonical corpus_search 结果渲染成紧凑的 grep 风格文本。 */
2
+
3
+ const RESOURCE_LABELS = Object.freeze({
4
+ original_story: '官方剧情原文', archive: '官方档案库', knowledge: '审校资料',
5
+ wiki: '整理性 Wiki', character_story: '角色剧情',
6
+ entity_profile: '实体资料', reference: '引用资料', timeline: '时间线',
7
+ story: '官方剧情原文', operator_record: '干员密录原文',
8
+ character_profile: '官方角色档案', character_module: '官方模组文案',
9
+ character_voice: '官方干员语音', character_skin: '官方时装文案',
10
+ character_wiki: '整理性角色 Wiki', story_wiki: '整理性活动/密录 Wiki',
11
+ character_activity_wiki: '整理性角色×活动 Wiki', terra_journey: '大地巡旅',
12
+ entity_profile: '实体资料', reference: '引用资料',
13
+ })
14
+
15
+ const EVIDENCE_LABELS = Object.freeze({
16
+ official_canonical: '官方原文', official_structured: '官方结构化资料',
17
+ wiki_curated: '整理性 Wiki', derived_summary: '整理性总结',
18
+ derived_timeline: '整理性时间线', entity_projection: '实体关联入口', catalog: '资料目录',
19
+ })
20
+
21
+ function renderLine(line) {
22
+ const marker = line.role === 'match' ? '>' : line.role === 'constraint' ? '+' : ' '
23
+ const number = line.line == null ? '' : String(line.line).padStart(4, ' ')
24
+ const speaker = line.speaker ? `${line.speaker}:` : ''
25
+ return `${marker} ${number} ${speaker}${line.rendered_text ?? line.text}${line.truncated ? '(本行已截断)' : ''}`.trimEnd()
26
+ }
27
+
28
+ function normalizeText(value) {
29
+ return String(value ?? '').normalize('NFKC').replace(/\s+/gu, ' ').trim()
30
+ }
31
+
32
+ function highlightLiteral(text, query) {
33
+ const needle = normalizeText(query)
34
+ if (!needle) return text
35
+ const haystack = text.toLocaleLowerCase()
36
+ const loweredNeedle = needle.toLocaleLowerCase()
37
+ const parts = []
38
+ let cursor = 0
39
+ let offset = haystack.indexOf(loweredNeedle)
40
+ while (offset >= 0) {
41
+ parts.push(text.slice(cursor, offset), `【${text.slice(offset, offset + needle.length)}】`)
42
+ cursor = offset + needle.length
43
+ offset = haystack.indexOf(loweredNeedle, cursor)
44
+ }
45
+ return parts.length ? `${parts.join('')}${text.slice(cursor)}` : text
46
+ }
47
+
48
+ function highlightRegex(text, query) {
49
+ try {
50
+ const regex = new RegExp(query, 'giu')
51
+ return text.replace(regex, (matched) => `【${matched}】`)
52
+ } catch {
53
+ return text
54
+ }
55
+ }
56
+
57
+ function renderedExcerptLine(line, match, options) {
58
+ if (line.role !== 'match' || !options.query) return line
59
+ const renderedText = match.match_kind === 'regex'
60
+ ? highlightRegex(line.text, options.query) : highlightLiteral(line.text, options.query)
61
+ return renderedText === line.text ? line : { ...line, rendered_text: renderedText }
62
+ }
63
+
64
+ function renderMatch(match, options) {
65
+ const range = match.line_start == null ? ''
66
+ : `命中:第 ${match.line_start === match.line_end ? match.line_start
67
+ : `${match.line_start}-${match.line_end}`} 行`
68
+ return [range, `证据:${EVIDENCE_LABELS[match.evidence_kind] || match.evidence_kind}`,
69
+ ...(match.excerpt || []).map((line) => renderLine(renderedExcerptLine(line, match, options))),
70
+ `引用:${match.citation}`].filter(Boolean).join('\n')
71
+ }
72
+
73
+ function renderSection(section) {
74
+ return [`字段:${section.section}(${section.completeness === 'complete' ? '完整' : '部分'})`,
75
+ ...(section.blocks || []).map((block) => block.label ? `${block.label}:${block.text}` : block.text),
76
+ `引用:${section.citation}`].join('\n')
77
+ }
78
+
79
+ function renderEntitySummary(summary) {
80
+ return [`实体:${summary.canonical_name}`,
81
+ summary.description ? `概述:${summary.description}` : '',
82
+ summary.history_summary ? `历史:${summary.history_summary}` : '',
83
+ summary.truncated ? '实体摘要已按模型上下文预算截断;需要更多内容时可按该自然标题继续读取。' : '',
84
+ `引用:${summary.citation}`].filter(Boolean).join('\n')
85
+ }
86
+
87
+ function renderDocument(document, options) {
88
+ const body = document.entity_summary ? renderEntitySummary(document.entity_summary)
89
+ : document.section_content ? renderSection(document.section_content)
90
+ : document.matches?.length ? document.matches.map((match) => renderMatch(match, options)).join('\n\n')
91
+ : document.available_sections?.length
92
+ ? `可用字段:${document.available_sections.join('、')}` : '资料入口'
93
+ const wikiNotice = ['character_wiki', 'story_wiki', 'character_activity_wiki']
94
+ .includes(document.resource_type)
95
+ ? '引文状态:Wiki 为整理性资料;其中引号内容未核验为当前资料包官方原文,逐字引用前请回查原文。'
96
+ : ''
97
+ const game = document.game === 'endfield' ? '终末地'
98
+ : document.game === 'arknights' ? '明日方舟' : ''
99
+ return [`## ${document.title}`, game ? `游戏:${game}` : '',
100
+ document.document_uid
101
+ ? `同名消歧定位:读取时仅提交 document_uid=${document.document_uid},它替代 title,不要同时提交二者。` : '',
102
+ `资料类型:${RESOURCE_LABELS[document.resource_type] || document.resource_type}`,
103
+ wikiNotice, body, document.matches_truncated ? '本篇仍有其他命中;请增加过滤条件或按已知行号读取。' : '']
104
+ .filter(Boolean).join('\n')
105
+ }
106
+
107
+ export function projectSearch(value, options = {}) {
108
+ const documents = value?.documents || []
109
+ const matches = documents.reduce((total, document) => total
110
+ + (document.entity_summary ? 1 : document.matches?.length || 0), 0)
111
+ const heading = value?.result_kind === 'documents'
112
+ ? `# 找到 ${documents.length} 篇资料入口`
113
+ : value?.result_kind === 'complete_sections'
114
+ ? `# 返回 ${documents.length} 篇资料的完整字段`
115
+ : `# 找到 ${documents.length} 篇资料,共展示 ${matches} 处命中`
116
+ const exhausted = value?.page?.exhausted === true
117
+ const next = value?.page?.next_after
118
+ ? `扫描尚未穷尽。继续时保留本次搜索词和过滤条件,并设置 after: ${JSON.stringify(value.page.next_after)}。`
119
+ : value?.page?.next_cursor
120
+ ? `旧版分页尚未结束。继续时仅提交 cursor: ${JSON.stringify(value.page.next_cursor)}。` : ''
121
+ const zero = documents.length ? '' : exhausted
122
+ ? '已检查完整检索范围,没有找到。请检查展示名、缩短连续字面串或移除冲突过滤条件。'
123
+ : value?.page?.next_after
124
+ ? '本页没有发现命中文档,但扫描位置已经推进;这不是全库零命中。'
125
+ : '该旧版分页链已经结束,但不能证明资料范围已经穷尽;需要完整性时请重新搜索。'
126
+ const complete = exhausted && documents.length
127
+ ? Number.isInteger(value.page.total_documents)
128
+ ? `已检查完整检索范围,共匹配 ${value.page.total_documents} 篇资料。`
129
+ : '已扫描至当前检索范围末尾。'
130
+ : ''
131
+ const warnings = (value?.warnings || []).length
132
+ ? `## 资料提示\n${value.warnings.map((item) => `- ${item.message || item}`).join('\n')}` : ''
133
+ const relations = (value?.retraveler_relations || []).length
134
+ ? `## 再旅者对应关系(人工审校附属字段)\n${value.retraveler_relations.map((item) =>
135
+ `- 终末地角色:${item.endfield_name};泰拉记忆原型:${item.terra_memory_prototype || '未登记'};` +
136
+ `状态:${item.relation_status}。这是跨游戏关系,不是人物别名。`).join('\n')}` : ''
137
+ return [heading, warnings, relations, ...documents.map((document) => renderDocument(document, options)), zero, complete, next]
138
+ .filter(Boolean).join('\n\n')
139
+ }