unity-open-mcp 0.1.0 → 0.3.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 (447) hide show
  1. package/dist/agent-identity.d.ts +52 -0
  2. package/dist/agent-identity.js +115 -0
  3. package/dist/agent-identity.js.map +1 -0
  4. package/dist/batch-spawn.d.ts +7 -0
  5. package/dist/batch-spawn.js +155 -29
  6. package/dist/batch-spawn.js.map +1 -1
  7. package/dist/capabilities/build-capabilities.d.ts +45 -0
  8. package/dist/capabilities/build-capabilities.js +262 -27
  9. package/dist/capabilities/build-capabilities.js.map +1 -1
  10. package/dist/capabilities/cost-hints.d.ts +82 -0
  11. package/dist/capabilities/cost-hints.js +185 -0
  12. package/dist/capabilities/cost-hints.js.map +1 -0
  13. package/dist/capabilities/lifecycle.d.ts +40 -0
  14. package/dist/capabilities/lifecycle.js +353 -0
  15. package/dist/capabilities/lifecycle.js.map +1 -0
  16. package/dist/capabilities/rule-catalog.d.ts +13 -1
  17. package/dist/capabilities/rule-catalog.js +620 -75
  18. package/dist/capabilities/rule-catalog.js.map +1 -1
  19. package/dist/capabilities/tool-groups.d.ts +21 -0
  20. package/dist/capabilities/tool-groups.js +411 -14
  21. package/dist/capabilities/tool-groups.js.map +1 -1
  22. package/dist/cli/args.d.ts +32 -1
  23. package/dist/cli/args.js +201 -4
  24. package/dist/cli/args.js.map +1 -1
  25. package/dist/cli/cli.d.ts +21 -0
  26. package/dist/cli/cli.js +68 -5
  27. package/dist/cli/cli.js.map +1 -1
  28. package/dist/cli/commands.d.ts +33 -0
  29. package/dist/cli/commands.js +400 -0
  30. package/dist/cli/commands.js.map +1 -1
  31. package/dist/cli/exit-codes.d.ts +43 -0
  32. package/dist/cli/exit-codes.js +78 -0
  33. package/dist/cli/exit-codes.js.map +1 -0
  34. package/dist/compile-verify.d.ts +65 -0
  35. package/dist/compile-verify.js +94 -0
  36. package/dist/compile-verify.js.map +1 -0
  37. package/dist/compressible-router.js +64 -11
  38. package/dist/compressible-router.js.map +1 -1
  39. package/dist/compression/asset-model.d.ts +15 -0
  40. package/dist/compression/compact.d.ts +5 -4
  41. package/dist/compression/compact.js +13 -10
  42. package/dist/compression/compact.js.map +1 -1
  43. package/dist/dialog-dismiss.d.ts +127 -74
  44. package/dist/dialog-dismiss.js +427 -170
  45. package/dist/dialog-dismiss.js.map +1 -1
  46. package/dist/dialog-policy.d.ts +141 -0
  47. package/dist/dialog-policy.js +345 -0
  48. package/dist/dialog-policy.js.map +1 -0
  49. package/dist/gate-error.d.ts +6 -0
  50. package/dist/gate-error.js +13 -2
  51. package/dist/gate-error.js.map +1 -1
  52. package/dist/hub-control.d.ts +247 -0
  53. package/dist/hub-control.js +703 -0
  54. package/dist/hub-control.js.map +1 -0
  55. package/dist/index.d.ts +1 -1
  56. package/dist/index.js +46 -12
  57. package/dist/index.js.map +1 -1
  58. package/dist/live-client.d.ts +123 -3
  59. package/dist/live-client.js +526 -69
  60. package/dist/live-client.js.map +1 -1
  61. package/dist/offline.d.ts +105 -0
  62. package/dist/offline.js +816 -23
  63. package/dist/offline.js.map +1 -1
  64. package/dist/output-profile.d.ts +110 -0
  65. package/dist/output-profile.js +255 -0
  66. package/dist/output-profile.js.map +1 -0
  67. package/dist/retry-policy.d.ts +72 -0
  68. package/dist/retry-policy.js +146 -0
  69. package/dist/retry-policy.js.map +1 -0
  70. package/dist/routers.d.ts +4 -0
  71. package/dist/routers.js +2 -2
  72. package/dist/routers.js.map +1 -1
  73. package/dist/server-instructions.d.ts +18 -0
  74. package/dist/server-instructions.js +145 -0
  75. package/dist/server-instructions.js.map +1 -0
  76. package/dist/tool-router.d.ts +38 -1
  77. package/dist/tool-router.js +690 -37
  78. package/dist/tool-router.js.map +1 -1
  79. package/dist/tool-session-state.d.ts +37 -0
  80. package/dist/tool-session-state.js +78 -1
  81. package/dist/tool-session-state.js.map +1 -1
  82. package/dist/tools/apply-fix.js +16 -2
  83. package/dist/tools/apply-fix.js.map +1 -1
  84. package/dist/tools/asmdef-create.d.ts +2 -0
  85. package/dist/tools/asmdef-create.js +114 -0
  86. package/dist/tools/asmdef-create.js.map +1 -0
  87. package/dist/tools/asmdef-get.d.ts +2 -0
  88. package/dist/tools/asmdef-get.js +31 -0
  89. package/dist/tools/asmdef-get.js.map +1 -0
  90. package/dist/tools/asmdef-list.d.ts +2 -0
  91. package/dist/tools/asmdef-list.js +41 -0
  92. package/dist/tools/asmdef-list.js.map +1 -0
  93. package/dist/tools/asmdef-modify.d.ts +2 -0
  94. package/dist/tools/asmdef-modify.js +108 -0
  95. package/dist/tools/asmdef-modify.js.map +1 -0
  96. package/dist/tools/audio-listener-get.d.ts +2 -0
  97. package/dist/tools/audio-listener-get.js +16 -0
  98. package/dist/tools/audio-listener-get.js.map +1 -0
  99. package/dist/tools/audio-mixer-get-parameter.d.ts +2 -0
  100. package/dist/tools/audio-mixer-get-parameter.js +25 -0
  101. package/dist/tools/audio-mixer-get-parameter.js.map +1 -0
  102. package/dist/tools/audio-mixer-set-parameter.d.ts +2 -0
  103. package/dist/tools/audio-mixer-set-parameter.js +44 -0
  104. package/dist/tools/audio-mixer-set-parameter.js.map +1 -0
  105. package/dist/tools/audio-source-add.d.ts +2 -0
  106. package/dist/tools/audio-source-add.js +94 -0
  107. package/dist/tools/audio-source-add.js.map +1 -0
  108. package/dist/tools/audio-source-modify.d.ts +2 -0
  109. package/dist/tools/audio-source-modify.js +52 -0
  110. package/dist/tools/audio-source-modify.js.map +1 -0
  111. package/dist/tools/bridge-status.js +16 -6
  112. package/dist/tools/bridge-status.js.map +1 -1
  113. package/dist/tools/build-get-active-target.js +1 -2
  114. package/dist/tools/build-get-active-target.js.map +1 -1
  115. package/dist/tools/build-get-defines.js +1 -1
  116. package/dist/tools/build-get-defines.js.map +1 -1
  117. package/dist/tools/build-get-scenes.js +1 -2
  118. package/dist/tools/build-get-scenes.js.map +1 -1
  119. package/dist/tools/build-get-targets.js +1 -1
  120. package/dist/tools/build-get-targets.js.map +1 -1
  121. package/dist/tools/build-set-defines.js +1 -2
  122. package/dist/tools/build-set-defines.js.map +1 -1
  123. package/dist/tools/build-set-scenes.js +1 -1
  124. package/dist/tools/build-set-scenes.js.map +1 -1
  125. package/dist/tools/build-set-target.js +1 -1
  126. package/dist/tools/build-set-target.js.map +1 -1
  127. package/dist/tools/build-start.js +0 -1
  128. package/dist/tools/build-start.js.map +1 -1
  129. package/dist/tools/cinemachine-brain-ensure.d.ts +2 -0
  130. package/dist/tools/cinemachine-brain-ensure.js +27 -0
  131. package/dist/tools/cinemachine-brain-ensure.js.map +1 -0
  132. package/dist/tools/cinemachine-camera-list.d.ts +2 -0
  133. package/dist/tools/cinemachine-camera-list.js +15 -0
  134. package/dist/tools/cinemachine-camera-list.js.map +1 -0
  135. package/dist/tools/cinemachine-create-camera.d.ts +2 -0
  136. package/dist/tools/cinemachine-create-camera.js +55 -0
  137. package/dist/tools/cinemachine-create-camera.js.map +1 -0
  138. package/dist/tools/cinemachine-set-body.d.ts +2 -0
  139. package/dist/tools/cinemachine-set-body.js +33 -0
  140. package/dist/tools/cinemachine-set-body.js.map +1 -0
  141. package/dist/tools/cinemachine-set-lens.d.ts +2 -0
  142. package/dist/tools/cinemachine-set-lens.js +41 -0
  143. package/dist/tools/cinemachine-set-lens.js.map +1 -0
  144. package/dist/tools/cinemachine-set-noise.d.ts +2 -0
  145. package/dist/tools/cinemachine-set-noise.js +31 -0
  146. package/dist/tools/cinemachine-set-noise.js.map +1 -0
  147. package/dist/tools/cinemachine-set-targets.d.ts +2 -0
  148. package/dist/tools/cinemachine-set-targets.js +30 -0
  149. package/dist/tools/cinemachine-set-targets.js.map +1 -0
  150. package/dist/tools/console-log.js +2 -2
  151. package/dist/tools/console-log.js.map +1 -1
  152. package/dist/tools/constraint-add.d.ts +2 -0
  153. package/dist/tools/constraint-add.js +85 -0
  154. package/dist/tools/constraint-add.js.map +1 -0
  155. package/dist/tools/dependencies.d.ts +2 -0
  156. package/dist/tools/dependencies.js +76 -0
  157. package/dist/tools/dependencies.js.map +1 -0
  158. package/dist/tools/editor-add-tag.js +2 -3
  159. package/dist/tools/editor-add-tag.js.map +1 -1
  160. package/dist/tools/editor-clear-history.d.ts +2 -0
  161. package/dist/tools/editor-clear-history.js +25 -0
  162. package/dist/tools/editor-clear-history.js.map +1 -0
  163. package/dist/tools/editor-get-layers.js +3 -3
  164. package/dist/tools/editor-get-layers.js.map +1 -1
  165. package/dist/tools/editor-get-tags.js +2 -2
  166. package/dist/tools/editor-get-tags.js.map +1 -1
  167. package/dist/tools/editor-redo.js +2 -3
  168. package/dist/tools/editor-redo.js.map +1 -1
  169. package/dist/tools/editor-undo-history.d.ts +2 -0
  170. package/dist/tools/editor-undo-history.js +21 -0
  171. package/dist/tools/editor-undo-history.js.map +1 -0
  172. package/dist/tools/editor-undo.js +3 -3
  173. package/dist/tools/editor-undo.js.map +1 -1
  174. package/dist/tools/editorprefs-delete.d.ts +2 -0
  175. package/dist/tools/editorprefs-delete.js +23 -0
  176. package/dist/tools/editorprefs-delete.js.map +1 -0
  177. package/dist/tools/editorprefs-get.d.ts +2 -0
  178. package/dist/tools/editorprefs-get.js +28 -0
  179. package/dist/tools/editorprefs-get.js.map +1 -0
  180. package/dist/tools/editorprefs-set.d.ts +2 -0
  181. package/dist/tools/editorprefs-set.js +33 -0
  182. package/dist/tools/editorprefs-set.js.map +1 -0
  183. package/dist/tools/find-references.js +24 -4
  184. package/dist/tools/find-references.js.map +1 -1
  185. package/dist/tools/frame-debugger.d.ts +2 -0
  186. package/dist/tools/frame-debugger.js +48 -0
  187. package/dist/tools/frame-debugger.js.map +1 -0
  188. package/dist/tools/gameobject-modify.js +69 -2
  189. package/dist/tools/gameobject-modify.js.map +1 -1
  190. package/dist/tools/gate-budget-estimate.js +2 -1
  191. package/dist/tools/gate-budget-estimate.js.map +1 -1
  192. package/dist/tools/hub-available-releases.d.ts +2 -0
  193. package/dist/tools/hub-available-releases.js +23 -0
  194. package/dist/tools/hub-available-releases.js.map +1 -0
  195. package/dist/tools/hub-get-install-path.d.ts +2 -0
  196. package/dist/tools/hub-get-install-path.js +20 -0
  197. package/dist/tools/hub-get-install-path.js.map +1 -0
  198. package/dist/tools/hub-install-editor.d.ts +2 -0
  199. package/dist/tools/hub-install-editor.js +47 -0
  200. package/dist/tools/hub-install-editor.js.map +1 -0
  201. package/dist/tools/hub-install-modules.d.ts +2 -0
  202. package/dist/tools/hub-install-modules.js +44 -0
  203. package/dist/tools/hub-install-modules.js.map +1 -0
  204. package/dist/tools/hub-list-editors.d.ts +2 -0
  205. package/dist/tools/hub-list-editors.js +25 -0
  206. package/dist/tools/hub-list-editors.js.map +1 -0
  207. package/dist/tools/hub-set-install-path.d.ts +2 -0
  208. package/dist/tools/hub-set-install-path.js +30 -0
  209. package/dist/tools/hub-set-install-path.js.map +1 -0
  210. package/dist/tools/impact-preview.js +2 -2
  211. package/dist/tools/impact-preview.js.map +1 -1
  212. package/dist/tools/index.d.ts +14 -0
  213. package/dist/tools/index.js +534 -24
  214. package/dist/tools/index.js.map +1 -1
  215. package/dist/tools/light-add.d.ts +2 -0
  216. package/dist/tools/light-add.js +73 -0
  217. package/dist/tools/light-add.js.map +1 -0
  218. package/dist/tools/light-modify.d.ts +2 -0
  219. package/dist/tools/light-modify.js +36 -0
  220. package/dist/tools/light-modify.js.map +1 -0
  221. package/dist/tools/light-set.d.ts +2 -0
  222. package/dist/tools/light-set.js +54 -0
  223. package/dist/tools/light-set.js.map +1 -0
  224. package/dist/tools/list-assets-of-type.d.ts +2 -0
  225. package/dist/tools/list-assets-of-type.js +54 -0
  226. package/dist/tools/list-assets-of-type.js.map +1 -0
  227. package/dist/tools/lod-add-level.d.ts +2 -0
  228. package/dist/tools/lod-add-level.js +66 -0
  229. package/dist/tools/lod-add-level.js.map +1 -0
  230. package/dist/tools/lod-group-configure.d.ts +2 -0
  231. package/dist/tools/lod-group-configure.js +64 -0
  232. package/dist/tools/lod-group-configure.js.map +1 -0
  233. package/dist/tools/manage-tools.js +7 -5
  234. package/dist/tools/manage-tools.js.map +1 -1
  235. package/dist/tools/memory-snapshot-capture.d.ts +2 -0
  236. package/dist/tools/memory-snapshot-capture.js +61 -0
  237. package/dist/tools/memory-snapshot-capture.js.map +1 -0
  238. package/dist/tools/mutation-explain.js +2 -2
  239. package/dist/tools/mutation-explain.js.map +1 -1
  240. package/dist/tools/playerprefs-delete.d.ts +2 -0
  241. package/dist/tools/playerprefs-delete.js +24 -0
  242. package/dist/tools/playerprefs-delete.js.map +1 -0
  243. package/dist/tools/playerprefs-get.d.ts +2 -0
  244. package/dist/tools/playerprefs-get.js +28 -0
  245. package/dist/tools/playerprefs-get.js.map +1 -0
  246. package/dist/tools/playerprefs-set.d.ts +2 -0
  247. package/dist/tools/playerprefs-set.js +37 -0
  248. package/dist/tools/playerprefs-set.js.map +1 -0
  249. package/dist/tools/profiler-capture-frame.d.ts +2 -0
  250. package/dist/tools/profiler-capture-frame.js +75 -0
  251. package/dist/tools/profiler-capture-frame.js.map +1 -0
  252. package/dist/tools/profiler-clear-data.js +1 -2
  253. package/dist/tools/profiler-clear-data.js.map +1 -1
  254. package/dist/tools/profiler-enable-module.js +4 -5
  255. package/dist/tools/profiler-enable-module.js.map +1 -1
  256. package/dist/tools/profiler-get-status.js +5 -6
  257. package/dist/tools/profiler-get-status.js.map +1 -1
  258. package/dist/tools/profiler-load-data.js +4 -5
  259. package/dist/tools/profiler-load-data.js.map +1 -1
  260. package/dist/tools/profiler-save-data.js +3 -3
  261. package/dist/tools/profiler-save-data.js.map +1 -1
  262. package/dist/tools/profiler-set-config.js +5 -5
  263. package/dist/tools/profiler-set-config.js.map +1 -1
  264. package/dist/tools/profiler-start.js +4 -4
  265. package/dist/tools/profiler-start.js.map +1 -1
  266. package/dist/tools/profiler-stop.js +2 -3
  267. package/dist/tools/profiler-stop.js.map +1 -1
  268. package/dist/tools/read-asset.js +21 -3
  269. package/dist/tools/read-asset.js.map +1 -1
  270. package/dist/tools/reflection-probe-bake.d.ts +2 -0
  271. package/dist/tools/reflection-probe-bake.js +47 -0
  272. package/dist/tools/reflection-probe-bake.js.map +1 -0
  273. package/dist/tools/reflection-probe-get.d.ts +2 -0
  274. package/dist/tools/reflection-probe-get.js +19 -0
  275. package/dist/tools/reflection-probe-get.js.map +1 -0
  276. package/dist/tools/reimport-package.d.ts +2 -0
  277. package/dist/tools/reimport-package.js +53 -0
  278. package/dist/tools/reimport-package.js.map +1 -0
  279. package/dist/tools/scan-paths.js +19 -0
  280. package/dist/tools/scan-paths.js.map +1 -1
  281. package/dist/tools/scene-focus.js +1 -1
  282. package/dist/tools/scene-focus.js.map +1 -1
  283. package/dist/tools/scene-get-data.js +31 -13
  284. package/dist/tools/scene-get-data.js.map +1 -1
  285. package/dist/tools/scene-get-dirty-summary.js +1 -1
  286. package/dist/tools/scene-get-dirty-summary.js.map +1 -1
  287. package/dist/tools/sceneview-get-camera.d.ts +2 -0
  288. package/dist/tools/sceneview-get-camera.js +16 -0
  289. package/dist/tools/sceneview-get-camera.js.map +1 -0
  290. package/dist/tools/sceneview-set-camera.d.ts +2 -0
  291. package/dist/tools/sceneview-set-camera.js +58 -0
  292. package/dist/tools/sceneview-set-camera.js.map +1 -0
  293. package/dist/tools/script-write.js +2 -2
  294. package/dist/tools/script-write.js.map +1 -1
  295. package/dist/tools/scriptableobject-create.d.ts +2 -0
  296. package/dist/tools/scriptableobject-create.js +86 -0
  297. package/dist/tools/scriptableobject-create.js.map +1 -0
  298. package/dist/tools/search-assets.js +20 -3
  299. package/dist/tools/search-assets.js.map +1 -1
  300. package/dist/tools/settings-get-lighting.js +3 -4
  301. package/dist/tools/settings-get-lighting.js.map +1 -1
  302. package/dist/tools/settings-get-player.js +2 -2
  303. package/dist/tools/settings-get-player.js.map +1 -1
  304. package/dist/tools/settings-get-quality.js +1 -2
  305. package/dist/tools/settings-get-quality.js.map +1 -1
  306. package/dist/tools/settings-get-render-pipeline.d.ts +2 -0
  307. package/dist/tools/settings-get-render-pipeline.js +19 -0
  308. package/dist/tools/settings-get-render-pipeline.js.map +1 -0
  309. package/dist/tools/settings-get-time.d.ts +2 -0
  310. package/dist/tools/settings-get-time.js +18 -0
  311. package/dist/tools/settings-get-time.js.map +1 -0
  312. package/dist/tools/settings-set-lighting.js +5 -5
  313. package/dist/tools/settings-set-lighting.js.map +1 -1
  314. package/dist/tools/settings-set-physics.js +2 -2
  315. package/dist/tools/settings-set-physics.js.map +1 -1
  316. package/dist/tools/settings-set-player.js +2 -2
  317. package/dist/tools/settings-set-player.js.map +1 -1
  318. package/dist/tools/settings-set-quality-level.d.ts +2 -0
  319. package/dist/tools/settings-set-quality-level.js +44 -0
  320. package/dist/tools/settings-set-quality-level.js.map +1 -0
  321. package/dist/tools/settings-set-quality.js +2 -2
  322. package/dist/tools/settings-set-quality.js.map +1 -1
  323. package/dist/tools/settings-set-time.d.ts +2 -0
  324. package/dist/tools/settings-set-time.js +53 -0
  325. package/dist/tools/settings-set-time.js.map +1 -0
  326. package/dist/tools/shader-get-data.js +3 -3
  327. package/dist/tools/shader-get-data.js.map +1 -1
  328. package/dist/tools/shader-graph-create.d.ts +2 -0
  329. package/dist/tools/shader-graph-create.js +40 -0
  330. package/dist/tools/shader-graph-create.js.map +1 -0
  331. package/dist/tools/shader-graph-node-add.d.ts +2 -0
  332. package/dist/tools/shader-graph-node-add.js +50 -0
  333. package/dist/tools/shader-graph-node-add.js.map +1 -0
  334. package/dist/tools/shader-graph-node-connect.d.ts +2 -0
  335. package/dist/tools/shader-graph-node-connect.js +60 -0
  336. package/dist/tools/shader-graph-node-connect.js.map +1 -0
  337. package/dist/tools/shader-graph-open.d.ts +2 -0
  338. package/dist/tools/shader-graph-open.js +29 -0
  339. package/dist/tools/shader-graph-open.js.map +1 -0
  340. package/dist/tools/skybox-get.d.ts +2 -0
  341. package/dist/tools/skybox-get.js +13 -0
  342. package/dist/tools/skybox-get.js.map +1 -0
  343. package/dist/tools/skybox-set.d.ts +2 -0
  344. package/dist/tools/skybox-set.js +34 -0
  345. package/dist/tools/skybox-set.js.map +1 -0
  346. package/dist/tools/spriteatlas-add-packable.d.ts +2 -0
  347. package/dist/tools/spriteatlas-add-packable.js +40 -0
  348. package/dist/tools/spriteatlas-add-packable.js.map +1 -0
  349. package/dist/tools/spriteatlas-create.d.ts +2 -0
  350. package/dist/tools/spriteatlas-create.js +41 -0
  351. package/dist/tools/spriteatlas-create.js.map +1 -0
  352. package/dist/tools/spriteatlas-delete.d.ts +2 -0
  353. package/dist/tools/spriteatlas-delete.js +32 -0
  354. package/dist/tools/spriteatlas-delete.js.map +1 -0
  355. package/dist/tools/spriteatlas-get.d.ts +2 -0
  356. package/dist/tools/spriteatlas-get.js +23 -0
  357. package/dist/tools/spriteatlas-get.js.map +1 -0
  358. package/dist/tools/spriteatlas-list.d.ts +2 -0
  359. package/dist/tools/spriteatlas-list.js +21 -0
  360. package/dist/tools/spriteatlas-list.js.map +1 -0
  361. package/dist/tools/spriteatlas-modify.d.ts +2 -0
  362. package/dist/tools/spriteatlas-modify.js +55 -0
  363. package/dist/tools/spriteatlas-modify.js.map +1 -0
  364. package/dist/tools/spriteatlas-remove-packable.d.ts +2 -0
  365. package/dist/tools/spriteatlas-remove-packable.js +39 -0
  366. package/dist/tools/spriteatlas-remove-packable.js.map +1 -0
  367. package/dist/tools/terrain-create.d.ts +2 -0
  368. package/dist/tools/terrain-create.js +73 -0
  369. package/dist/tools/terrain-create.js.map +1 -0
  370. package/dist/tools/terrain-paint-layer.d.ts +2 -0
  371. package/dist/tools/terrain-paint-layer.js +85 -0
  372. package/dist/tools/terrain-paint-layer.js.map +1 -0
  373. package/dist/tools/terrain-place-trees.d.ts +2 -0
  374. package/dist/tools/terrain-place-trees.js +92 -0
  375. package/dist/tools/terrain-place-trees.js.map +1 -0
  376. package/dist/tools/terrain-set-heights.d.ts +2 -0
  377. package/dist/tools/terrain-set-heights.js +68 -0
  378. package/dist/tools/terrain-set-heights.js.map +1 -0
  379. package/dist/tools/terrain-set-neighbors.d.ts +2 -0
  380. package/dist/tools/terrain-set-neighbors.js +65 -0
  381. package/dist/tools/terrain-set-neighbors.js.map +1 -0
  382. package/dist/tools/texture-get-importer.d.ts +2 -0
  383. package/dist/tools/texture-get-importer.js +25 -0
  384. package/dist/tools/texture-get-importer.js.map +1 -0
  385. package/dist/tools/texture-get.d.ts +2 -0
  386. package/dist/tools/texture-get.js +23 -0
  387. package/dist/tools/texture-get.js.map +1 -0
  388. package/dist/tools/texture-reimport.d.ts +2 -0
  389. package/dist/tools/texture-reimport.js +33 -0
  390. package/dist/tools/texture-reimport.js.map +1 -0
  391. package/dist/tools/texture-set-import.d.ts +2 -0
  392. package/dist/tools/texture-set-import.js +52 -0
  393. package/dist/tools/texture-set-import.js.map +1 -0
  394. package/dist/tools/tilemap-box-fill.d.ts +2 -0
  395. package/dist/tools/tilemap-box-fill.js +32 -0
  396. package/dist/tools/tilemap-box-fill.js.map +1 -0
  397. package/dist/tools/tilemap-create-rule-tile.d.ts +2 -0
  398. package/dist/tools/tilemap-create-rule-tile.js +39 -0
  399. package/dist/tools/tilemap-create-rule-tile.js.map +1 -0
  400. package/dist/tools/tilemap-create-tile-asset.d.ts +2 -0
  401. package/dist/tools/tilemap-create-tile-asset.js +35 -0
  402. package/dist/tools/tilemap-create-tile-asset.js.map +1 -0
  403. package/dist/tools/tilemap-create.d.ts +2 -0
  404. package/dist/tools/tilemap-create.js +32 -0
  405. package/dist/tools/tilemap-create.js.map +1 -0
  406. package/dist/tools/tilemap-set-tile.d.ts +2 -0
  407. package/dist/tools/tilemap-set-tile.js +33 -0
  408. package/dist/tools/tilemap-set-tile.js.map +1 -0
  409. package/dist/tools/timeline-clip-add.d.ts +2 -0
  410. package/dist/tools/timeline-clip-add.js +43 -0
  411. package/dist/tools/timeline-clip-add.js.map +1 -0
  412. package/dist/tools/timeline-create.d.ts +2 -0
  413. package/dist/tools/timeline-create.js +32 -0
  414. package/dist/tools/timeline-create.js.map +1 -0
  415. package/dist/tools/timeline-director-bind.d.ts +2 -0
  416. package/dist/tools/timeline-director-bind.js +34 -0
  417. package/dist/tools/timeline-director-bind.js.map +1 -0
  418. package/dist/tools/timeline-modify.d.ts +2 -0
  419. package/dist/tools/timeline-modify.js +44 -0
  420. package/dist/tools/timeline-modify.js.map +1 -0
  421. package/dist/tools/timeline-track-add.d.ts +2 -0
  422. package/dist/tools/timeline-track-add.js +37 -0
  423. package/dist/tools/timeline-track-add.js.map +1 -0
  424. package/dist/tools/ui-canvas-add.d.ts +2 -0
  425. package/dist/tools/ui-canvas-add.js +66 -0
  426. package/dist/tools/ui-canvas-add.js.map +1 -0
  427. package/dist/tools/ui-element-add.d.ts +2 -0
  428. package/dist/tools/ui-element-add.js +65 -0
  429. package/dist/tools/ui-element-add.js.map +1 -0
  430. package/dist/tools/ui-element-modify.d.ts +2 -0
  431. package/dist/tools/ui-element-modify.js +59 -0
  432. package/dist/tools/ui-element-modify.js.map +1 -0
  433. package/dist/tools/ui-layout-group-add.d.ts +2 -0
  434. package/dist/tools/ui-layout-group-add.js +80 -0
  435. package/dist/tools/ui-layout-group-add.js.map +1 -0
  436. package/dist/tools/validate-edit.js +22 -1
  437. package/dist/tools/validate-edit.js.map +1 -1
  438. package/dist/tools/vfx-block-edit.d.ts +2 -0
  439. package/dist/tools/vfx-block-edit.js +51 -0
  440. package/dist/tools/vfx-block-edit.js.map +1 -0
  441. package/dist/tools/vfx-list.d.ts +2 -0
  442. package/dist/tools/vfx-list.js +31 -0
  443. package/dist/tools/vfx-list.js.map +1 -0
  444. package/dist/tools/vfx-open.d.ts +2 -0
  445. package/dist/tools/vfx-open.js +29 -0
  446. package/dist/tools/vfx-open.js.map +1 -0
  447. package/package.json +1 -1
package/dist/offline.js CHANGED
@@ -1,6 +1,5 @@
1
1
  // Offline asset reader — parses text-serialized Unity assets (.prefab/.unity/
2
- // .asset) from disk without a running Editor. Ported from unity-scanner
3
- // internal/unityasset (yaml.go, scan.go, kind.go, project.go).
2
+ // .asset) from disk without a running Editor.
4
3
  //
5
4
  // Single runtime module (so it loads cleanly under node --experimental-strip-
6
5
  // types in tests: no cross-file runtime imports). Type-only contract lives in
@@ -13,7 +12,7 @@
13
12
  import { readFile, readdir, stat } from "node:fs/promises";
14
13
  import { join, basename, extname, relative, sep } from "node:path";
15
14
  // ===========================================================================
16
- // Native Unity class IDs → names (from unity-scanner yaml.go).
15
+ // Native Unity class IDs → names.
17
16
  // ===========================================================================
18
17
  const nativeClassNames = {
19
18
  1: "GameObject",
@@ -45,10 +44,11 @@ function nativeClassName(classID) {
45
44
  return nativeClassNames[classID] ?? "";
46
45
  }
47
46
  // ===========================================================================
48
- // Kind / extension utilities (from unity-scanner kind.go).
47
+ // Kind / extension utilities.
49
48
  // ===========================================================================
50
49
  const extToKind = {
51
50
  ".anim": "anim",
51
+ ".asmdef": "asmdef",
52
52
  ".asset": "asset",
53
53
  ".controller": "controller",
54
54
  ".cs": "cs",
@@ -58,13 +58,47 @@ const extToKind = {
58
58
  ".physicMaterial": "physics",
59
59
  ".playable": "playable",
60
60
  ".prefab": "prefab",
61
+ ".preset": "preset",
61
62
  ".shader": "shader",
63
+ ".shadergraph": "shadergraph",
64
+ ".shadersubgraph": "shadergraph",
62
65
  ".spriteatlas": "atlas",
66
+ ".terrainlayer": "terrainlayer",
63
67
  ".unity": "scene",
64
68
  ".uss": "uss",
65
69
  ".uxml": "uxml",
70
+ ".vfx": "vfx",
66
71
  ".meta": "meta",
67
72
  };
73
+ // ===========================================================================
74
+ // M24 — offline-parseable extension sets.
75
+ // YAML_PARSEABLE covers text-serialized Unity YAML; JSON_PARSEABLE covers the
76
+ // JSON asset kinds unity-scanner does not handle (our differentiator). Both are
77
+ // merged into OFFLINE_PARSEABLE for the read_asset / search / find_references
78
+ // gates. LISTABLE stays broader (it never parses, only enumerates files).
79
+ // ===========================================================================
80
+ const YAML_PARSEABLE_EXTENSIONS = new Set([
81
+ ".prefab", ".unity", ".asset", ".mat", ".controller", ".anim", ".playable",
82
+ ".preset", ".spriteatlas", ".terrainlayer", ".vfx",
83
+ ]);
84
+ const JSON_PARSEABLE_EXTENSIONS = new Set([
85
+ ".asmdef", ".shadergraph", ".shadersubgraph",
86
+ ]);
87
+ const OFFLINE_PARSEABLE_EXTENSIONS = new Set([
88
+ ...YAML_PARSEABLE_EXTENSIONS,
89
+ ...JSON_PARSEABLE_EXTENSIONS,
90
+ ]);
91
+ function offlineParseKind(assetPath) {
92
+ const dot = assetPath.lastIndexOf(".");
93
+ if (dot < 0)
94
+ return null;
95
+ const ext = assetPath.slice(dot).toLowerCase();
96
+ if (YAML_PARSEABLE_EXTENSIONS.has(ext))
97
+ return "yaml";
98
+ if (JSON_PARSEABLE_EXTENSIONS.has(ext))
99
+ return "json";
100
+ return null;
101
+ }
68
102
  const kindAliases = {
69
103
  prefabs: "prefab",
70
104
  scenes: "scene",
@@ -106,7 +140,6 @@ function shouldSkipDir(name) {
106
140
  }
107
141
  // ===========================================================================
108
142
  // YAML parser — split YAML into documents, extract key fields per object.
109
- // (Ported from unity-scanner yaml.go ParseAssetWithOptions.)
110
143
  // ===========================================================================
111
144
  function parseAsset(data) {
112
145
  const objects = [];
@@ -848,7 +881,7 @@ function shortGUID(guid) {
848
881
  return guid.slice(0, 8);
849
882
  }
850
883
  // ===========================================================================
851
- // GUID index builder — reads .meta files (from unity-scanner yaml.go).
884
+ // GUID index builder — reads .meta files.
852
885
  // ===========================================================================
853
886
  function readMetaGUID(data) {
854
887
  let start;
@@ -953,29 +986,65 @@ async function walkMeta(dir, fn) {
953
986
  // ===========================================================================
954
987
  // readAssetOffline — parse a text-serialized asset → AssetModel.
955
988
  // ===========================================================================
956
- const OFFLINE_EXTENSIONS = new Set([
957
- ".prefab", ".unity", ".asset", ".mat", ".controller", ".anim", ".playable",
958
- ]);
959
989
  export function isOfflineAsset(assetPath) {
960
- const dot = assetPath.lastIndexOf(".");
961
- if (dot < 0)
962
- return false;
963
- return OFFLINE_EXTENSIONS.has(assetPath.slice(dot).toLowerCase());
990
+ return offlineParseKind(assetPath) !== null;
991
+ }
992
+ /**
993
+ * M24 — full-hierarchy parity helper. The offline `objectCount` counts every
994
+ * YAML object in the file; the live `read_asset` bridge counts only GameObjects
995
+ * + the components attached to them (it walks the loaded Transform tree, not
996
+ * the raw YAML). This helper returns the live-comparable counts so an
997
+ * acceptance test can verify the offline-reconstructed tree matches a live read
998
+ * node-for-node and component-for-component, without depending on the bridge.
999
+ *
1000
+ * Returns `{ nodes, components }` where `nodes` is the GameObject count and
1001
+ * `components` is the sum of components across the tree — the two numbers the
1002
+ * live `ReadAssetTool` emits as `objectCount` (nodes+components) and
1003
+ * `componentCount`.
1004
+ */
1005
+ export function countHierarchy(model) {
1006
+ let nodes = 0;
1007
+ let components = 0;
1008
+ const walk = (list) => {
1009
+ for (const node of list) {
1010
+ nodes++;
1011
+ components += node.components.length;
1012
+ walk(node.children);
1013
+ }
1014
+ };
1015
+ walk(model.roots);
1016
+ return { nodes, components };
964
1017
  }
965
1018
  export async function readAssetOffline(assetPath, opts) {
966
1019
  const absPath = join(opts.projectRoot, assetPath);
967
1020
  const data = await readFile(absPath, "utf-8");
1021
+ const kind = kindForPath(assetPath);
1022
+ const guid = await safeReadMetaGUID(absPath + ".meta");
1023
+ const parseKind = offlineParseKind(assetPath);
1024
+ // M24 — JSON asset kinds (.asmdef/.shadergraph/.shadersubgraph/.vfx) parse
1025
+ // through a separate path; unity-scanner handles YAML only, so this is the
1026
+ // coverage differentiator. vfx is YAML+binary, but its object headers + GUID
1027
+ // refs still parse via the YAML path (binary blobs are skipped).
1028
+ if (parseKind === "json") {
1029
+ const guidIndex = await buildGUIDIndex(opts.projectRoot, new Set(findGUIDs(data)));
1030
+ const model = buildJsonAssetModel(data, assetPath, kind, guid, guidIndex, opts.fieldLimit);
1031
+ return { model, source: "offline" };
1032
+ }
968
1033
  const parsed = parseAsset(data);
969
1034
  parsed.path = assetPath;
970
- parsed.kind = kindForPath(assetPath);
971
- parsed.guid = await safeReadMetaGUID(absPath + ".meta");
1035
+ parsed.kind = kind;
1036
+ parsed.guid = guid;
972
1037
  const wantedScripts = scriptGUIDs(parsed);
973
1038
  const scriptIndex = await buildScriptIndex(opts.projectRoot, wantedScripts);
974
1039
  const wantedGUIDs = collectFieldGUIDs(parsed);
975
1040
  const guidIndex = await buildGUIDIndex(opts.projectRoot, wantedGUIDs);
976
1041
  for (const [g, p] of scriptIndex)
977
1042
  guidIndex.set(g, p);
978
- return { model: buildAssetModel(parsed, scriptIndex, guidIndex, opts.fieldLimit), source: "offline" };
1043
+ const integrity = runYamlIntegrityChecks(parsed, guidIndex);
1044
+ return {
1045
+ model: { ...buildAssetModel(parsed, scriptIndex, guidIndex, opts.fieldLimit), ...(integrity ? { integrity } : {}) },
1046
+ source: "offline",
1047
+ };
979
1048
  }
980
1049
  async function safeReadMetaGUID(metaPath) {
981
1050
  try {
@@ -1041,6 +1110,261 @@ function buildAssetModel(parsed, scriptIndex, guidIndex, fieldLimit) {
1041
1110
  ...(overrides.length > 0 ? { overrides } : {}),
1042
1111
  };
1043
1112
  }
1113
+ // ===========================================================================
1114
+ // M24 — JSON asset parser (.asmdef / .shadergraph / .shadersubgraph).
1115
+ //
1116
+ // unity-scanner handles YAML only; this path is the coverage differentiator.
1117
+ // Each kind has a distinct on-disk shape:
1118
+ // - .asmdef → a single JSON object (assembly-definition manifest).
1119
+ // - .shadergraph / .shadersubgraph → a JSON-document stream: multiple pretty-
1120
+ // printed JSON objects concatenated on blank-line boundaries, each carrying
1121
+ // an "m_Type" discriminator. The first is always the graph root.
1122
+ // GUID references inside the JSON are resolved against the meta index the same
1123
+ // way YAML field refs are.
1124
+ // ===========================================================================
1125
+ function buildJsonAssetModel(data, assetPath, kind, guid, guidIndex, fieldLimit) {
1126
+ const issues = [];
1127
+ const objects = parseJsonAsset(data, issues);
1128
+ const flatObjects = [];
1129
+ for (const obj of objects) {
1130
+ const fields = jsonFields(obj.value, fieldLimit, guidIndex);
1131
+ flatObjects.push({
1132
+ name: obj.name,
1133
+ type: obj.type,
1134
+ fields: fields.length > 0 ? fields : undefined,
1135
+ });
1136
+ }
1137
+ const integrity = runJsonIntegrityChecks(kind, objects, issues, assetPath);
1138
+ return {
1139
+ kind,
1140
+ path: assetPath,
1141
+ guid: guid || undefined,
1142
+ objectCount: objects.length,
1143
+ componentCount: 0,
1144
+ roots: [],
1145
+ flatObjects,
1146
+ ...(integrity.length > 0 ? { integrity } : {}),
1147
+ };
1148
+ }
1149
+ /**
1150
+ * Parse a JSON asset into one or more JsonParsedObjects. `.asmdef` is a single
1151
+ * object; `.shadergraph` is a stream of objects. Malformed JSON records an
1152
+ * integrity issue instead of throwing — a partial read is more useful to an
1153
+ * agent than a hard failure when the bridge is down.
1154
+ */
1155
+ function parseJsonAsset(data, issues) {
1156
+ const ext = "json";
1157
+ const chunks = splitJsonStream(data);
1158
+ if (chunks.length === 0) {
1159
+ issues.push({ code: "malformed_json", detail: "no JSON objects found", severity: "error" });
1160
+ return [];
1161
+ }
1162
+ const out = [];
1163
+ for (let i = 0; i < chunks.length; i++) {
1164
+ let value;
1165
+ try {
1166
+ value = JSON.parse(chunks[i]);
1167
+ }
1168
+ catch (e) {
1169
+ issues.push({
1170
+ code: "malformed_json",
1171
+ detail: `object ${i + 1}: ${e.message}`,
1172
+ severity: "error",
1173
+ });
1174
+ continue;
1175
+ }
1176
+ out.push(jsonParsedObject(value, i));
1177
+ }
1178
+ return out;
1179
+ function jsonParsedObject(value, index) {
1180
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
1181
+ const obj = value;
1182
+ const type = typeof obj.m_Type === "string" && obj.m_Type !== ""
1183
+ ? jsonShortType(obj.m_Type)
1184
+ : "json";
1185
+ const name = pickString(obj.m_Name) ??
1186
+ pickString(obj.m_ObjectId) ??
1187
+ pickString(obj.name) ??
1188
+ (type !== "json" ? `${type}#${index}` : `object#${index}`);
1189
+ return { name, type, value };
1190
+ }
1191
+ return { name: `value#${index}`, type: ext, value };
1192
+ }
1193
+ }
1194
+ function pickString(v) {
1195
+ return typeof v === "string" && v !== "" ? v : undefined;
1196
+ }
1197
+ /** Shorten a ShaderGraph m_Type like "UnityEditor.ShaderGraph.MultiplyNode" → "MultiplyNode". */
1198
+ function jsonShortType(full) {
1199
+ const dot = full.lastIndexOf(".");
1200
+ return dot >= 0 ? full.slice(dot + 1) : full;
1201
+ }
1202
+ /**
1203
+ * A `.shadergraph` is a stream of pretty-printed JSON objects. They are
1204
+ * separated by blank lines, but a single object's pretty-printed body also
1205
+ * contains newlines — so the split must track brace depth, not line gaps.
1206
+ * `.asmdef` is a single object; this still returns a one-element array.
1207
+ */
1208
+ function splitJsonStream(data) {
1209
+ const trimmed = data.trim();
1210
+ if (trimmed === "")
1211
+ return [];
1212
+ const chunks = [];
1213
+ let depth = 0;
1214
+ let inString = false;
1215
+ let escape = false;
1216
+ let start = -1;
1217
+ for (let i = 0; i < trimmed.length; i++) {
1218
+ const ch = trimmed[i];
1219
+ if (inString) {
1220
+ if (escape)
1221
+ escape = false;
1222
+ else if (ch === "\\")
1223
+ escape = true;
1224
+ else if (ch === '"')
1225
+ inString = false;
1226
+ continue;
1227
+ }
1228
+ if (ch === '"') {
1229
+ inString = true;
1230
+ continue;
1231
+ }
1232
+ if (ch === "{") {
1233
+ if (depth === 0)
1234
+ start = i;
1235
+ depth++;
1236
+ }
1237
+ else if (ch === "}") {
1238
+ depth--;
1239
+ if (depth === 0 && start >= 0) {
1240
+ chunks.push(trimmed.slice(start, i + 1));
1241
+ start = -1;
1242
+ }
1243
+ }
1244
+ }
1245
+ // Fallback: if brace tracking found nothing (e.g. a top-level array or a
1246
+ // malformed file), try a single JSON.parse on the whole content so the
1247
+ // malformed_json issue path can report it.
1248
+ if (chunks.length === 0)
1249
+ chunks.push(trimmed);
1250
+ return chunks;
1251
+ }
1252
+ /**
1253
+ * Flatten a parsed JSON value into display fields. Scalars, arrays, and nested
1254
+ * objects are summarized into short `name: value` rows, mirroring the YAML
1255
+ * field renderer. GUID refs are resolved against the meta index.
1256
+ */
1257
+ function jsonFields(value, limit, guidIndex) {
1258
+ if (value === null || typeof value !== "object" || Array.isArray(value))
1259
+ return [];
1260
+ const obj = value;
1261
+ const out = [];
1262
+ for (const [key, raw] of Object.entries(obj)) {
1263
+ if (out.length >= limit && limit > 0)
1264
+ break;
1265
+ out.push({ name: key, value: jsonScalar(raw, guidIndex) });
1266
+ }
1267
+ return out;
1268
+ }
1269
+ function jsonScalar(value, guidIndex) {
1270
+ if (value === null)
1271
+ return "null";
1272
+ switch (typeof value) {
1273
+ case "string":
1274
+ return resolveReferences(value, guidIndex, EMPTY_PARSED);
1275
+ case "number":
1276
+ case "boolean":
1277
+ return String(value);
1278
+ default: {
1279
+ if (Array.isArray(value))
1280
+ return `[${value.length}]`;
1281
+ const obj = value;
1282
+ // Inline {fileID, guid, type} PPtr → resolve to asset name.
1283
+ if (typeof obj.guid === "string" && obj.guid.length === 32) {
1284
+ return resolveReferences(`{fileID: ${obj.fileID ?? 0}, guid: ${obj.guid}, type: ${obj.type ?? 0}}`, guidIndex, EMPTY_PARSED);
1285
+ }
1286
+ const keys = Object.keys(obj);
1287
+ if (keys.length === 0)
1288
+ return "{}";
1289
+ return `{${keys.slice(0, 4).join(", ")}${keys.length > 4 ? ", …" : ""}}`;
1290
+ }
1291
+ }
1292
+ }
1293
+ // A ParsedAsset stand-in used only by resolveReferences' local-reference path.
1294
+ // JSON assets have no in-file fileIDs, so local ref resolution is a no-op.
1295
+ const EMPTY_PARSED = { path: "", kind: "", guid: "", objects: [], byID: new Map() };
1296
+ // ===========================================================================
1297
+ // M24 — offline integrity checks. The verify rule suite (M25) consumes these
1298
+ // signals; here we only emit asset-local findings derivable from raw bytes.
1299
+ // ===========================================================================
1300
+ function runYamlIntegrityChecks(parsed, guidIndex) {
1301
+ const issues = [];
1302
+ // Orphaned PrefabInstance: a PrefabInstance whose m_SourcePrefab GUID is
1303
+ // missing from the project (the base prefab was deleted or never imported).
1304
+ for (const obj of parsed.objects) {
1305
+ if (obj.type !== "PrefabInstance")
1306
+ continue;
1307
+ const sourceGuid = readGUIDField(obj.lines, "m_SourcePrefab");
1308
+ if (sourceGuid !== "" && !guidIndex.has(sourceGuid)) {
1309
+ issues.push({
1310
+ code: "orphaned_prefab_instance",
1311
+ detail: `m_SourcePrefab guid ${sourceGuid} not found in project`,
1312
+ severity: "warning",
1313
+ });
1314
+ }
1315
+ }
1316
+ // Unresolved field GUIDs (missing references) — every guid: in a field that
1317
+ // the meta index cannot resolve. Component m_Script guids get their own code
1318
+ // so a missing-script is distinguishable from a missing asset ref.
1319
+ const missingScripts = new Set();
1320
+ const missingRefs = new Set();
1321
+ for (const obj of parsed.objects) {
1322
+ for (const line of obj.lines) {
1323
+ if (!line.includes("guid:"))
1324
+ continue;
1325
+ const isScript = line.includes("m_Script");
1326
+ for (const g of findGUIDs(line)) {
1327
+ if (guidIndex.has(g))
1328
+ continue;
1329
+ if (isScript)
1330
+ missingScripts.add(g);
1331
+ else
1332
+ missingRefs.add(g);
1333
+ }
1334
+ }
1335
+ }
1336
+ for (const g of missingScripts) {
1337
+ issues.push({ code: "missing_script_reference", detail: `script guid ${g} unresolved`, severity: "error" });
1338
+ }
1339
+ for (const g of missingRefs) {
1340
+ issues.push({ code: "missing_reference", detail: `asset guid ${g} unresolved`, severity: "warning" });
1341
+ }
1342
+ return issues;
1343
+ }
1344
+ function runJsonIntegrityChecks(kind, objects, parseIssues, _assetPath) {
1345
+ const issues = [...parseIssues];
1346
+ if (kind === "asmdef") {
1347
+ const first = objects[0]?.value;
1348
+ if (first && typeof first === "object" && !Array.isArray(first)) {
1349
+ const obj = first;
1350
+ if (pickString(obj.name) === undefined) {
1351
+ issues.push({ code: "asmdef_missing_name", detail: "asmdef has no 'name' field", severity: "error" });
1352
+ }
1353
+ }
1354
+ }
1355
+ if (kind === "shadergraph") {
1356
+ // A valid graph stream must start with the GraphData root.
1357
+ const rootType = objects[0]?.type;
1358
+ if (rootType !== undefined && !rootType.includes("GraphData")) {
1359
+ issues.push({
1360
+ code: "shadergraph_root_missing",
1361
+ detail: `first object is ${rootType}, expected a GraphData root`,
1362
+ severity: "warning",
1363
+ });
1364
+ }
1365
+ }
1366
+ return issues;
1367
+ }
1044
1368
  function convertNode(node, parsed, scriptIndex, guidIndex, fieldLimit) {
1045
1369
  const comps = componentsFor(parsed, node.gameObject.id, scriptIndex);
1046
1370
  const components = comps.map((c) => {
@@ -1069,9 +1393,7 @@ function toComponentField(f) {
1069
1393
  // ===========================================================================
1070
1394
  // searchAssetsOffline — scan Assets/ → SearchModel.
1071
1395
  // ===========================================================================
1072
- const SEARCHABLE_EXTENSIONS = new Set([
1073
- ".prefab", ".unity", ".asset", ".mat", ".controller", ".anim", ".playable",
1074
- ]);
1396
+ const SEARCHABLE_EXTENSIONS = OFFLINE_PARSEABLE_EXTENSIONS;
1075
1397
  export async function searchAssetsOffline(opts) {
1076
1398
  const nameQuery = (opts.name ?? "").trim().toLowerCase();
1077
1399
  const componentQuery = (opts.component ?? "").trim().toLowerCase();
@@ -1098,6 +1420,24 @@ export async function searchAssetsOffline(opts) {
1098
1420
  const kind = kindForPath(filePath);
1099
1421
  if (typeFilter && typeFilter.size > 0 && !typeFilter.has(kind))
1100
1422
  continue;
1423
+ const guid = await safeReadMetaGUID(filePath + ".meta");
1424
+ // M24 — JSON asset kinds route through a content-based match path (they
1425
+ // have no GameObject/component tree for the YAML matcher to walk).
1426
+ if (offlineParseKind(filePath) === "json") {
1427
+ let content;
1428
+ try {
1429
+ content = await readFile(filePath, "utf-8");
1430
+ }
1431
+ catch {
1432
+ continue;
1433
+ }
1434
+ const match = checkJsonMatch(content, guidIndex, assetPath, kind, guid, {
1435
+ nameQuery, componentQuery, guidQuery,
1436
+ });
1437
+ if (match)
1438
+ matches.push(match);
1439
+ continue;
1440
+ }
1101
1441
  let parsed;
1102
1442
  try {
1103
1443
  parsed = parseAsset(await readFile(filePath, "utf-8"));
@@ -1107,7 +1447,6 @@ export async function searchAssetsOffline(opts) {
1107
1447
  }
1108
1448
  parsed.path = assetPath;
1109
1449
  parsed.kind = kind;
1110
- const guid = await safeReadMetaGUID(filePath + ".meta");
1111
1450
  const match = checkMatch(parsed, scriptIndex, guidIndex, assetPath, kind, guid, { nameQuery, componentQuery, guidQuery });
1112
1451
  if (match)
1113
1452
  matches.push(match);
@@ -1172,6 +1511,39 @@ function checkMatch(parsed, scriptIndex, guidIndex, assetPath, kind, guid, crite
1172
1511
  return null;
1173
1512
  return { path: assetPath, guid: guid || undefined, kind, reasons, objects: objects.length > 0 ? objects : undefined };
1174
1513
  }
1514
+ /**
1515
+ * M24 — content-based matcher for JSON asset kinds (.asmdef/.shadergraph).
1516
+ * They have no GameObject tree, so matching is by file name, raw-text GUID
1517
+ * presence, and content substring (name/component queries search the raw text
1518
+ * since JSON is human-readable). This keeps `search_assets` offline-capable for
1519
+ * the expanded type set.
1520
+ */
1521
+ function checkJsonMatch(content, guidIndex, assetPath, kind, guid, criteria) {
1522
+ const reasons = [];
1523
+ const { nameQuery, componentQuery, guidQuery } = criteria;
1524
+ const fileName = basename(assetPath);
1525
+ const lower = content.toLowerCase();
1526
+ if (nameQuery && fileName.toLowerCase().includes(nameQuery))
1527
+ reasons.push("file-name");
1528
+ if (guidQuery) {
1529
+ if (guid.toLowerCase() === guidQuery)
1530
+ reasons.push("guid");
1531
+ else if (lower.includes(guidQuery))
1532
+ reasons.push("guid");
1533
+ }
1534
+ if (nameQuery && !reasons.includes("file-name") && lower.includes(nameQuery)) {
1535
+ reasons.push("gameobject");
1536
+ }
1537
+ if (componentQuery && lower.includes(componentQuery)) {
1538
+ reasons.push("component");
1539
+ }
1540
+ if (!componentQuery && !nameQuery && !guidQuery)
1541
+ reasons.push("file-name");
1542
+ if (reasons.length === 0)
1543
+ return null;
1544
+ void guidIndex;
1545
+ return { path: assetPath, guid: guid || undefined, kind, reasons };
1546
+ }
1175
1547
  function flattenHierarchy(nodes) {
1176
1548
  const out = [];
1177
1549
  const walk = (ns) => {
@@ -1245,6 +1617,9 @@ const LISTABLE_EXTENSIONS = new Set([
1245
1617
  ".prefab", ".unity", ".asset", ".mat", ".controller", ".anim", ".playable",
1246
1618
  ".cs", ".shader", ".spriteatlas", ".physicMaterial", ".physicsMaterial2D",
1247
1619
  ".overrideController", ".uxml", ".uss",
1620
+ // M24 — expanded offline-parseable kinds (also listable so they show up in
1621
+ // directory listings; listing never parses, so they cost nothing to include).
1622
+ ".asmdef", ".shadergraph", ".shadersubgraph", ".vfx", ".preset", ".terrainlayer",
1248
1623
  ]);
1249
1624
  export async function listAssetsOffline(opts) {
1250
1625
  const folder = opts.folder ?? "Assets";
@@ -1336,9 +1711,7 @@ async function walkFiles(dir, projectRoot, fn) {
1336
1711
  // fast-filter (content.includes(guid)) → optional YAML parse for verbose
1337
1712
  // locations → group + cap + collapse.
1338
1713
  // ===========================================================================
1339
- const REFERENCEABLE_EXTENSIONS = new Set([
1340
- ".prefab", ".unity", ".asset", ".mat", ".controller", ".anim", ".playable",
1341
- ]);
1714
+ const REFERENCEABLE_EXTENSIONS = OFFLINE_PARSEABLE_EXTENSIONS;
1342
1715
  export async function findReferencesOffline(opts) {
1343
1716
  const detail = (opts.detail ?? "normal");
1344
1717
  const maxResults = opts.maxResults ?? 100;
@@ -1492,4 +1865,424 @@ function extractReferenceLocations(content, targetGuid, maxPerFile) {
1492
1865
  }
1493
1866
  return locations;
1494
1867
  }
1868
+ /** Collect the forward edges declared by a single asset: every external GUID
1869
+ * reference (field PPtrs + m_Script + PrefabInstance m_SourcePrefab). This is
1870
+ * the offline forward-edge primitive — unity-scanner has no full forward-edge
1871
+ * builder, so this is authored net-new on the existing GUID-extraction
1872
+ * primitives (findGUIDs / readGUIDField / parseAsset). */
1873
+ function collectForwardEdges(parsed) {
1874
+ const edges = [];
1875
+ const seen = new Set();
1876
+ // 1. PrefabInstance.m_SourcePrefab — the base-prefab edge of a variant.
1877
+ for (const obj of parsed.objects) {
1878
+ if (obj.type !== "PrefabInstance")
1879
+ continue;
1880
+ const sourceGuid = readGUIDField(obj.lines, "m_SourcePrefab");
1881
+ if (sourceGuid !== "" && seen.add(`prefab:${sourceGuid}`)) {
1882
+ edges.push({ guid: sourceGuid, assetPath: "", kind: "prefab_source", resolved: false });
1883
+ }
1884
+ }
1885
+ // 2. m_Script GUIDs on MonoBehaviours — the script-class edge.
1886
+ for (const obj of parsed.objects) {
1887
+ if (obj.type !== "MonoBehaviour")
1888
+ continue;
1889
+ if (obj.scriptGUID !== "" && seen.add(`script:${obj.scriptGUID}`)) {
1890
+ edges.push({ guid: obj.scriptGUID, assetPath: "", kind: "script", resolved: false });
1891
+ }
1892
+ }
1893
+ // 3. Every other guid: field — material refs, asset refs, animation clips,
1894
+ // etc. m_Script is handled above; m_SourcePrefab target: GUIDs inside
1895
+ // PrefabInstance.m_Modifications are included here so variant overrides
1896
+ // count as forward edges too.
1897
+ for (const obj of parsed.objects) {
1898
+ for (const line of obj.lines) {
1899
+ if (!line.includes("guid:"))
1900
+ continue;
1901
+ if (line.includes("m_Script:"))
1902
+ continue; // handled as a script edge above
1903
+ for (const g of findGUIDs(line)) {
1904
+ if (!seen.add(`pptr:${g}`))
1905
+ continue;
1906
+ edges.push({ guid: g, assetPath: "", kind: "pptr", resolved: false });
1907
+ }
1908
+ }
1909
+ }
1910
+ return edges;
1911
+ }
1912
+ /** Resolve forward edges against the GUID→path index. Mutates each edge in
1913
+ * place: sets assetPath + resolved. Returns the broken (unresolved) GUIDs. */
1914
+ function resolveForwardEdges(edges, guidIndex) {
1915
+ const broken = [];
1916
+ const brokenSeen = new Set();
1917
+ for (const edge of edges) {
1918
+ const path = guidIndex.get(edge.guid);
1919
+ if (path !== undefined) {
1920
+ edge.assetPath = path;
1921
+ edge.resolved = true;
1922
+ }
1923
+ else if (brokenSeen.add(edge.guid)) {
1924
+ broken.push(edge.guid);
1925
+ }
1926
+ }
1927
+ return broken;
1928
+ }
1929
+ export async function dependenciesOffline(opts) {
1930
+ const detail = (opts.detail ?? "normal");
1931
+ const maxResults = opts.maxResults ?? 100;
1932
+ const includeImpact = opts.includeImpact ?? false;
1933
+ const maxImpactDepth = opts.maxImpactDepth ?? 5;
1934
+ const maxCycleDepth = opts.maxCycleDepth ?? 8;
1935
+ // Resolve target GUID + path (mirrors findReferencesOffline's resolution).
1936
+ let targetGuid = "";
1937
+ let targetPath = "";
1938
+ if (opts.guid) {
1939
+ targetGuid = opts.guid.toLowerCase();
1940
+ }
1941
+ else if (opts.assetPath) {
1942
+ targetPath = opts.assetPath;
1943
+ targetGuid = (await safeReadMetaGUID(join(opts.projectRoot, opts.assetPath + ".meta"))).toLowerCase();
1944
+ }
1945
+ if (targetGuid === "") {
1946
+ return emptyDependencies(targetPath, "", detail);
1947
+ }
1948
+ if (targetPath === "") {
1949
+ const idx = await buildGUIDIndex(opts.projectRoot, new Set([targetGuid]));
1950
+ targetPath = idx.get(targetGuid) ?? "";
1951
+ }
1952
+ // ---- Forward edges ----
1953
+ // Parse the queried asset + collect its declared edges, then resolve each
1954
+ // against a GUID→path index scoped to exactly the GUIDs this asset names.
1955
+ let forwardEdges = [];
1956
+ let brokenGuids = [];
1957
+ let cycles = [];
1958
+ let forwardSkipped;
1959
+ const absPath = join(opts.projectRoot, targetPath);
1960
+ let data;
1961
+ try {
1962
+ data = await readFile(absPath, "utf-8");
1963
+ }
1964
+ catch {
1965
+ // The queried asset isn't on disk (GUID resolve but path is stale). No
1966
+ // forward edges can be extracted; reverse edges still computed below.
1967
+ forwardSkipped = "queried asset not readable on disk";
1968
+ }
1969
+ if (data !== undefined) {
1970
+ try {
1971
+ const parsed = parseAsset(data);
1972
+ parsed.path = targetPath;
1973
+ forwardEdges = collectForwardEdges(parsed);
1974
+ const wanted = new Set(forwardEdges.map((e) => e.guid));
1975
+ const guidIndex = await buildGUIDIndex(opts.projectRoot, wanted);
1976
+ brokenGuids = resolveForwardEdges(forwardEdges, guidIndex);
1977
+ if (forwardEdges.length > 0) {
1978
+ cycles = await detectCyclesOffline(targetPath, forwardEdges, opts.projectRoot, maxCycleDepth);
1979
+ }
1980
+ }
1981
+ catch (err) {
1982
+ // Not parseable as Unity YAML (JSON-only kind, binary, malformed). The
1983
+ // forward arrays stay empty; reverse edges are unaffected. This is the
1984
+ // honest signal — the offline forward parser covers text-serialized YAML
1985
+ // only, matching the documented offline coverage.
1986
+ forwardSkipped = err instanceof Error ? err.message : String(err);
1987
+ }
1988
+ }
1989
+ // ---- Reverse edges ---- (reuse the findReferencesOffline machinery).
1990
+ const refResult = await findReferencesOffline({
1991
+ assetPath: targetPath || undefined,
1992
+ guid: targetGuid,
1993
+ detail: "normal",
1994
+ projectRoot: opts.projectRoot,
1995
+ });
1996
+ const reverseEdges = refResult.referencedBy.map((e) => ({
1997
+ assetPath: e.assetPath,
1998
+ guid: e.guid ?? "",
1999
+ kind: e.kind,
2000
+ }));
2001
+ // ---- Transitive impact (optional) ----
2002
+ let impact;
2003
+ if (includeImpact) {
2004
+ impact = await computeTransitiveImpact(targetGuid, targetPath, opts.projectRoot, maxImpactDepth);
2005
+ }
2006
+ // ---- Apply detail + caps ----
2007
+ const displayForward = detail === "summary" ? [] : forwardEdges;
2008
+ const totalCount = reverseEdges.length;
2009
+ let displayReverse;
2010
+ let truncated = 0;
2011
+ if (detail === "summary") {
2012
+ displayReverse = [];
2013
+ }
2014
+ else if (maxResults > 0 && totalCount > maxResults) {
2015
+ displayReverse = reverseEdges.slice(0, maxResults);
2016
+ truncated = totalCount - maxResults;
2017
+ }
2018
+ else {
2019
+ displayReverse = reverseEdges;
2020
+ }
2021
+ return {
2022
+ queriedAssetPath: targetPath,
2023
+ queriedAssetGuid: targetGuid,
2024
+ forwardDependencies: displayForward,
2025
+ forwardCount: forwardEdges.length,
2026
+ brokenForwardGuids: brokenGuids,
2027
+ cycles,
2028
+ reverseDependencies: displayReverse,
2029
+ reverseCount: totalCount,
2030
+ impact,
2031
+ detail,
2032
+ truncated,
2033
+ ...(forwardSkipped ? { forwardSkipped } : {}),
2034
+ _source: "offline",
2035
+ };
2036
+ }
2037
+ function emptyDependencies(path, guid, detail) {
2038
+ return {
2039
+ queriedAssetPath: path,
2040
+ queriedAssetGuid: guid,
2041
+ forwardDependencies: [],
2042
+ forwardCount: 0,
2043
+ brokenForwardGuids: [],
2044
+ cycles: [],
2045
+ reverseDependencies: [],
2046
+ reverseCount: 0,
2047
+ detail,
2048
+ truncated: 0,
2049
+ _source: "offline",
2050
+ };
2051
+ }
2052
+ /** Forward-cycle detection via DFS over the transitive forward closure of the
2053
+ * queried asset. Bounded by maxDepth to stay cheap on large graphs; a cycle
2054
+ * is reported when the DFS revisits the queried asset's path. This mirrors
2055
+ * the C# Dependencies.Scanner.DetectCycles shape (each cycle is a path list).
2056
+ *
2057
+ * unity-scanner has no cycle detector — this is authored net-new. */
2058
+ async function detectCyclesOffline(startPath, startEdges, projectRoot, maxDepth) {
2059
+ const cycles = [];
2060
+ // Build a small forward-edge cache so repeated visits of the same asset
2061
+ // parse once. Keyed by asset path.
2062
+ const edgeCache = new Map();
2063
+ edgeCache.set(startPath, startEdges);
2064
+ async function edgesOf(path) {
2065
+ const cached = edgeCache.get(path);
2066
+ if (cached)
2067
+ return cached;
2068
+ try {
2069
+ const data = await readFile(join(projectRoot, path), "utf-8");
2070
+ const parsed = parseAsset(data);
2071
+ const edges = collectForwardEdges(parsed);
2072
+ // Best-effort resolve so the DFS walks resolved paths only.
2073
+ const idx = await buildGUIDIndex(projectRoot, new Set(edges.map((e) => e.guid)));
2074
+ resolveForwardEdges(edges, idx);
2075
+ edgeCache.set(path, edges);
2076
+ return edges;
2077
+ }
2078
+ catch {
2079
+ edgeCache.set(path, []);
2080
+ return [];
2081
+ }
2082
+ }
2083
+ // DFS from each resolved forward neighbor of the start asset, looking for a
2084
+ // path back to startPath. visited guards against re-descending the same node
2085
+ // within one root-neighbor walk (the cycle itself is the back-edge to start).
2086
+ const visiting = new Set();
2087
+ async function dfs(current, trail) {
2088
+ if (trail.length > maxDepth)
2089
+ return;
2090
+ const edges = await edgesOf(current);
2091
+ for (const edge of edges) {
2092
+ if (!edge.resolved || edge.assetPath === "")
2093
+ continue;
2094
+ if (edge.assetPath === startPath) {
2095
+ cycles.push([...trail, startPath]);
2096
+ continue;
2097
+ }
2098
+ if (visiting.has(edge.assetPath))
2099
+ continue;
2100
+ visiting.add(edge.assetPath);
2101
+ await dfs(edge.assetPath, [...trail, edge.assetPath]);
2102
+ visiting.delete(edge.assetPath);
2103
+ }
2104
+ }
2105
+ for (const edge of startEdges) {
2106
+ if (!edge.resolved || edge.assetPath === "" || edge.assetPath === startPath)
2107
+ continue;
2108
+ visiting.clear();
2109
+ visiting.add(edge.assetPath);
2110
+ await dfs(edge.assetPath, [startPath, edge.assetPath]);
2111
+ }
2112
+ return cycles;
2113
+ }
2114
+ /** Transitive impact closure via BFS over reverse edges. Starting from the
2115
+ * queried asset's direct referencers, walk one hop out at a time, accumulating
2116
+ * every asset that (transitively) depends on the queried asset. Bounded by
2117
+ * maxDepth. This is the "what breaks if I delete/move this?" answer — neither
2118
+ * the offline nor the live path did multi-hop reverse before T24.2. */
2119
+ async function computeTransitiveImpact(startGuid, startPath, projectRoot, maxDepth) {
2120
+ const affected = [];
2121
+ const seen = new Set([startPath]);
2122
+ let frontier = [];
2123
+ let truncated = false;
2124
+ // Seed: direct reverse edges of the queried asset.
2125
+ const seed = await findReferencesOffline({
2126
+ assetPath: startPath || undefined,
2127
+ guid: startGuid,
2128
+ detail: "normal",
2129
+ projectRoot,
2130
+ });
2131
+ for (const e of seed.referencedBy) {
2132
+ if (seen.has(e.assetPath))
2133
+ continue;
2134
+ seen.add(e.assetPath);
2135
+ frontier.push(e.assetPath);
2136
+ affected.push({ assetPath: e.assetPath, depth: 1 });
2137
+ }
2138
+ // BFS: for each level, resolve the reverse edges of every frontier asset.
2139
+ for (let depth = 2; depth <= maxDepth; depth++) {
2140
+ if (frontier.length === 0)
2141
+ break;
2142
+ const next = [];
2143
+ for (const nodePath of frontier) {
2144
+ const nodeGuid = await safeReadMetaGUID(join(projectRoot, nodePath + ".meta"));
2145
+ if (nodeGuid === "")
2146
+ continue;
2147
+ const res = await findReferencesOffline({
2148
+ guid: nodeGuid,
2149
+ detail: "normal",
2150
+ projectRoot,
2151
+ });
2152
+ for (const e of res.referencedBy) {
2153
+ if (seen.has(e.assetPath))
2154
+ continue;
2155
+ seen.add(e.assetPath);
2156
+ next.push(e.assetPath);
2157
+ affected.push({ assetPath: e.assetPath, depth });
2158
+ }
2159
+ }
2160
+ frontier = next;
2161
+ if (depth === maxDepth && frontier.length > 0) {
2162
+ // The next level exists but we stop here — the closure is a prefix.
2163
+ truncated = true;
2164
+ }
2165
+ }
2166
+ return {
2167
+ affected,
2168
+ affectedCount: affected.length,
2169
+ maxDepth,
2170
+ truncated,
2171
+ };
2172
+ }
2173
+ /** Scan the whole Assets/ tree for project-wide integrity issues that the
2174
+ * per-read checks cannot surface (orphaned .meta, duplicate GUIDs) plus the
2175
+ * aggregated missing-reference set. Offline counterpart of a full verify
2176
+ * scan_paths run for these three rule families. */
2177
+ export async function scanIntegrityOffline(opts) {
2178
+ const issues = [];
2179
+ const assetsDir = join(opts.projectRoot, "Assets");
2180
+ // ---- Walk every .meta + every asset file in one pass ----
2181
+ // We collect: guidByPath (path -> guid), pathByGuid (guid -> paths[]), and
2182
+ // the set of asset files (companions for the orphan-meta check). Skipping a
2183
+ // dir uses the same skipDirs policy as every other offline walk.
2184
+ const guidByPath = new Map();
2185
+ const allAssetPaths = new Set();
2186
+ const assetFiles = await collectFiles(assetsDir);
2187
+ for (const absPath of assetFiles) {
2188
+ const assetPath = toAssetPath(opts.projectRoot, absPath);
2189
+ allAssetPaths.add(assetPath);
2190
+ const metaGuid = await safeReadMetaGUID(absPath + ".meta");
2191
+ if (metaGuid !== "") {
2192
+ guidByPath.set(assetPath, metaGuid);
2193
+ }
2194
+ }
2195
+ // Also index .meta-only paths (files whose companion was deleted show up
2196
+ // here but not in allAssetPaths — those are the orphans). walkMeta gives us
2197
+ // every .meta under Assets/.
2198
+ const metaOnlyPaths = new Set();
2199
+ await walkMeta(assetsDir, async (metaPath) => {
2200
+ const assetPath = toAssetPath(opts.projectRoot, metaPath.slice(0, -5));
2201
+ if (!allAssetPaths.has(assetPath)) {
2202
+ metaOnlyPaths.add(assetPath);
2203
+ }
2204
+ });
2205
+ // ---- orphan_meta: .meta whose companion asset is gone ----
2206
+ for (const path of metaOnlyPaths) {
2207
+ issues.push({
2208
+ path: path + ".meta",
2209
+ code: "orphan_meta",
2210
+ severity: "warning",
2211
+ detail: `meta file has no companion asset at ${path}`,
2212
+ });
2213
+ }
2214
+ // ---- duplicate_guid: GUID shared by 2+ assets ----
2215
+ const pathsByGuid = new Map();
2216
+ for (const [assetPath, guid] of guidByPath) {
2217
+ const list = pathsByGuid.get(guid);
2218
+ if (list)
2219
+ list.push(assetPath);
2220
+ else
2221
+ pathsByGuid.set(guid, [assetPath]);
2222
+ }
2223
+ for (const [guid, paths] of pathsByGuid) {
2224
+ if (paths.length < 2)
2225
+ continue;
2226
+ for (const p of paths) {
2227
+ issues.push({
2228
+ path: p,
2229
+ code: "duplicate_guid",
2230
+ severity: "error",
2231
+ detail: `guid ${guid} shared by ${paths.length} assets`,
2232
+ relatedPaths: paths.filter((other) => other !== p),
2233
+ });
2234
+ }
2235
+ }
2236
+ // ---- aggregated missing references (the per-read check, project-wide) ----
2237
+ // Re-uses the full GUID index so unresolved field GUIDs are detected once
2238
+ // per asset across the whole tree. This is the offline seed for the
2239
+ // missing_references verify rule (M25 consumes these primitives).
2240
+ const fullGuidIndex = await buildGUIDIndex(opts.projectRoot);
2241
+ for (const absPath of assetFiles) {
2242
+ const ext = extname(absPath).toLowerCase();
2243
+ if (!OFFLINE_PARSEABLE_EXTENSIONS.has(ext))
2244
+ continue;
2245
+ const assetPath = toAssetPath(opts.projectRoot, absPath);
2246
+ let data;
2247
+ try {
2248
+ data = await readFile(absPath, "utf-8");
2249
+ }
2250
+ catch {
2251
+ continue;
2252
+ }
2253
+ if (!data.includes("guid:"))
2254
+ continue; // fast filter: no refs at all
2255
+ try {
2256
+ const parsed = parseAsset(data);
2257
+ parsed.path = assetPath;
2258
+ // Run the per-asset YAML integrity check against the FULL index (not a
2259
+ // scoped one) so a ref resolves even if its target lives far away.
2260
+ const perAsset = runYamlIntegrityChecks(parsed, fullGuidIndex);
2261
+ for (const issue of perAsset) {
2262
+ issues.push({
2263
+ path: assetPath,
2264
+ code: issue.code,
2265
+ severity: issue.severity,
2266
+ detail: issue.detail,
2267
+ });
2268
+ }
2269
+ }
2270
+ catch {
2271
+ // Not parseable as YAML — skip. JSON integrity is per-read only; a
2272
+ // project-wide JSON scan is out of scope for the verify-engine seed.
2273
+ }
2274
+ }
2275
+ // ---- group by code ----
2276
+ const byCode = {};
2277
+ for (const issue of issues) {
2278
+ byCode[issue.code] = (byCode[issue.code] ?? 0) + 1;
2279
+ }
2280
+ return {
2281
+ issues,
2282
+ byCode,
2283
+ totalIssues: issues.length,
2284
+ assetsScanned: allAssetPaths.size,
2285
+ _source: "offline",
2286
+ };
2287
+ }
1495
2288
  //# sourceMappingURL=offline.js.map