summer-engine 3.1.0 → 3.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 (366) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +27 -5
  3. package/.codex-plugin/plugin.json +28 -6
  4. package/.cursor-plugin/plugin.json +27 -5
  5. package/.factory-plugin/plugin.json +27 -5
  6. package/.opencode/plugins/summer.js +1 -1
  7. package/CHANGELOG.md +102 -0
  8. package/README.md +18 -3
  9. package/assets/audit/scene_audit.gd +4136 -0
  10. package/assets/seeing/seeing_probe.gd +1873 -0
  11. package/dist/cli/commands/skills.js +20 -2
  12. package/dist/core/api-client.d.ts +9 -1
  13. package/dist/core/api-client.js +21 -4
  14. package/dist/core/capabilities/agent-playbook.js +46 -0
  15. package/dist/core/capabilities/audit/accept.d.ts +55 -0
  16. package/dist/core/capabilities/audit/accept.js +147 -0
  17. package/dist/core/capabilities/audit/args.d.ts +95 -0
  18. package/dist/core/capabilities/audit/args.js +89 -0
  19. package/dist/core/capabilities/audit/audit.d.ts +56 -0
  20. package/dist/core/capabilities/audit/audit.js +287 -0
  21. package/dist/core/capabilities/audit/frame.d.ts +14 -0
  22. package/dist/core/capabilities/audit/frame.js +35 -0
  23. package/dist/core/capabilities/audit/gaps.d.ts +96 -0
  24. package/dist/core/capabilities/audit/gaps.js +257 -0
  25. package/dist/core/capabilities/audit/judge.d.ts +162 -0
  26. package/dist/core/capabilities/audit/judge.js +1134 -0
  27. package/dist/core/capabilities/audit/math.d.ts +110 -0
  28. package/dist/core/capabilities/audit/math.js +263 -0
  29. package/dist/core/capabilities/audit/summary.d.ts +74 -0
  30. package/dist/core/capabilities/audit/summary.js +212 -0
  31. package/dist/core/capabilities/board.d.ts +31 -0
  32. package/dist/core/capabilities/board.js +43 -0
  33. package/dist/core/capabilities/camera-view.d.ts +4 -2
  34. package/dist/core/capabilities/camera-view.js +6 -3
  35. package/dist/core/capabilities/connect-signal.d.ts +85 -0
  36. package/dist/core/capabilities/connect-signal.js +285 -0
  37. package/dist/core/capabilities/engine-fallbacks.d.ts +5 -0
  38. package/dist/core/capabilities/engine-fallbacks.js +5 -0
  39. package/dist/core/capabilities/engine-ops.d.ts +5 -1
  40. package/dist/core/capabilities/engine-ops.js +0 -3
  41. package/dist/core/capabilities/engine-receipt.d.ts +12 -0
  42. package/dist/core/capabilities/engine-receipt.js +26 -0
  43. package/dist/core/capabilities/file-read.d.ts +64 -0
  44. package/dist/core/capabilities/file-read.js +325 -0
  45. package/dist/core/capabilities/game-task-plan.js +4 -2
  46. package/dist/core/capabilities/grep.d.ts +60 -0
  47. package/dist/core/capabilities/grep.js +190 -0
  48. package/dist/core/capabilities/inspect-node.d.ts +56 -0
  49. package/dist/core/capabilities/inspect-node.js +225 -0
  50. package/dist/core/capabilities/inspect-resource.d.ts +61 -0
  51. package/dist/core/capabilities/inspect-resource.js +376 -0
  52. package/dist/core/capabilities/math3d.d.ts +28 -0
  53. package/dist/core/capabilities/math3d.js +88 -0
  54. package/dist/core/capabilities/motion-generation.d.ts +62 -0
  55. package/dist/core/capabilities/motion-generation.js +138 -0
  56. package/dist/core/capabilities/placement-batch.d.ts +102 -0
  57. package/dist/core/capabilities/placement-batch.js +483 -0
  58. package/dist/core/capabilities/placement-math.d.ts +70 -0
  59. package/dist/core/capabilities/placement-math.js +209 -0
  60. package/dist/core/capabilities/placement-script.d.ts +42 -0
  61. package/dist/core/capabilities/placement-script.js +1096 -0
  62. package/dist/core/capabilities/placement.d.ts +485 -0
  63. package/dist/core/capabilities/placement.js +1731 -0
  64. package/dist/core/capabilities/project-context.d.ts +33 -2
  65. package/dist/core/capabilities/project-context.js +87 -4
  66. package/dist/core/capabilities/replace-node.d.ts +91 -0
  67. package/dist/core/capabilities/replace-node.js +423 -0
  68. package/dist/core/capabilities/runtime-control.d.ts +18 -2
  69. package/dist/core/capabilities/runtime-control.js +67 -2
  70. package/dist/core/capabilities/scene-batch.d.ts +63 -0
  71. package/dist/core/capabilities/scene-batch.js +394 -0
  72. package/dist/core/capabilities/scene-readback.d.ts +36 -0
  73. package/dist/core/capabilities/scene-readback.js +54 -0
  74. package/dist/core/capabilities/seeing/args.d.ts +348 -0
  75. package/dist/core/capabilities/seeing/args.js +178 -0
  76. package/dist/core/capabilities/seeing/candidates.d.ts +127 -0
  77. package/dist/core/capabilities/seeing/candidates.js +282 -0
  78. package/dist/core/capabilities/seeing/math.d.ts +134 -0
  79. package/dist/core/capabilities/seeing/math.js +269 -0
  80. package/dist/core/capabilities/seeing/probe.d.ts +62 -0
  81. package/dist/core/capabilities/seeing/probe.js +188 -0
  82. package/dist/core/capabilities/seeing/scoring.d.ts +235 -0
  83. package/dist/core/capabilities/seeing/scoring.js +639 -0
  84. package/dist/core/capabilities/seeing/seeing.d.ts +233 -0
  85. package/dist/core/capabilities/seeing/seeing.js +1341 -0
  86. package/dist/core/capabilities/seeing/shot-store.d.ts +52 -0
  87. package/dist/core/capabilities/seeing/shot-store.js +204 -0
  88. package/dist/core/capabilities/surface-snap-mesh.d.ts +88 -0
  89. package/dist/core/capabilities/surface-snap-mesh.js +425 -0
  90. package/dist/core/capabilities/surface-snap.d.ts +77 -0
  91. package/dist/core/capabilities/surface-snap.js +461 -0
  92. package/dist/core/capabilities/tool-dispatch.js +231 -72
  93. package/dist/core/capabilities/tscn.d.ts +85 -0
  94. package/dist/core/capabilities/tscn.js +391 -0
  95. package/dist/core/capabilities/world-snapshot.d.ts +58 -0
  96. package/dist/core/capabilities/world-snapshot.js +150 -0
  97. package/dist/core/capability-skew.d.ts +5 -5
  98. package/dist/core/capability-skew.js +14 -6
  99. package/dist/core/headless/worker-engine-client.d.ts +1 -1
  100. package/dist/core/headless/worker-engine-client.js +2 -2
  101. package/dist/core/library-read.d.ts +37 -5
  102. package/dist/core/library-read.js +264 -33
  103. package/dist/core/library-search.d.ts +2 -2
  104. package/dist/installer/agent-config.js +5 -3
  105. package/dist/installer/agent-table.d.ts +16 -0
  106. package/dist/installer/agent-table.js +52 -17
  107. package/dist/mcp/server.js +9 -3
  108. package/dist/mcp/tools/asset-tools.js +21 -3
  109. package/dist/mcp/tools/audit-tools.d.ts +23 -0
  110. package/dist/mcp/tools/audit-tools.js +60 -0
  111. package/dist/mcp/tools/debug-tools.js +3 -1
  112. package/dist/mcp/tools/file-tools.js +17 -4
  113. package/dist/mcp/tools/generate-tools.js +74 -66
  114. package/dist/mcp/tools/library-tools.js +2 -0
  115. package/dist/mcp/tools/perception-tools.js +6 -19
  116. package/dist/mcp/tools/placement-tools.d.ts +24 -0
  117. package/dist/mcp/tools/placement-tools.js +91 -0
  118. package/dist/mcp/tools/project-tools.js +18 -15
  119. package/dist/mcp/tools/scene-tools.js +71 -83
  120. package/dist/mcp/tools/seeing-tools.d.ts +24 -0
  121. package/dist/mcp/tools/seeing-tools.js +64 -0
  122. package/dist/mcp/tools/spatial-tools.js +17 -9
  123. package/dist/mcp/tools/visual-tools.js +59 -7
  124. package/gemini-extension.json +26 -4
  125. package/integrations/amp/README.md +1 -1
  126. package/integrations/crush/README.md +1 -1
  127. package/integrations/grok-build/README.md +1 -1
  128. package/integrations/hermes/README.md +1 -1
  129. package/integrations/kimi-code/README.md +1 -1
  130. package/integrations/mistral-vibe/README.md +1 -1
  131. package/integrations/opencode/README.md +1 -1
  132. package/integrations/rovo-dev/README.md +1 -1
  133. package/integrations/vscode-copilot/README.md +1 -1
  134. package/integrations/warp/README.md +1 -1
  135. package/integrations/windsurf/README.md +1 -1
  136. package/library/references/mcp-tools-reference/mcp-tools-reference.md +59 -15
  137. package/library/references/mcp-tools-reference/resource.yaml +1 -1
  138. package/library/references/summer-folder/resource.yaml +1 -1
  139. package/library/references/summer-folder/summer-folder.md +1 -1
  140. package/library/skills/3d-lighting/SKILL.md +1 -1
  141. package/library/skills/README.md +36 -14
  142. package/library/skills/adaptive-music/SKILL.md +1 -1
  143. package/library/skills/agent-playtesting/SKILL.md +1 -1
  144. package/library/skills/ai-characters-in-games/SKILL.md +220 -0
  145. package/library/skills/ai-characters-in-games/resource.yaml +30 -0
  146. package/library/skills/ambient-bed/SKILL.md +1 -1
  147. package/library/skills/animated-loop/SKILL.md +1 -1
  148. package/library/skills/animation-tree/SKILL.md +1 -1
  149. package/library/skills/art-direction/SKILL.md +1 -1
  150. package/library/skills/asset-strategy/SKILL.md +2 -1
  151. package/library/skills/asset-strategy/resource.yaml +2 -1
  152. package/library/skills/audio-direction/SKILL.md +1 -1
  153. package/library/skills/auto-fire-targeting/SKILL.md +1 -1
  154. package/library/skills/brainstorm-game/SKILL.md +1 -1
  155. package/library/skills/brainstorming/SKILL.md +1 -1
  156. package/library/skills/browse-templates/SKILL.md +3 -3
  157. package/library/skills/browse-templates/resource.yaml +1 -1
  158. package/library/skills/camera-rigs/SKILL.md +128 -0
  159. package/library/skills/camera-rigs/resource.yaml +29 -0
  160. package/library/skills/celeste-momentum-platforming/SKILL.md +1 -1
  161. package/library/skills/character-animation-wiring/SKILL.md +1 -1
  162. package/library/skills/character-model/SKILL.md +1 -1
  163. package/library/skills/character-movement/SKILL.md +326 -0
  164. package/library/skills/character-movement/references/default-third-person-controller.gd +201 -0
  165. package/library/skills/character-movement/references/default-third-person-verification-probe.gd +154 -0
  166. package/library/skills/character-movement/references/movement-3d.md +136 -0
  167. package/library/skills/character-movement/references/platformer-feel.md +83 -0
  168. package/library/skills/character-movement/resource.yaml +40 -0
  169. package/library/skills/character-portrait/SKILL.md +1 -1
  170. package/library/skills/cinematic-cutscene/SKILL.md +1 -1
  171. package/library/skills/combat-basics/SKILL.md +159 -0
  172. package/library/skills/combat-basics/references/projectiles-and-aoe.md +100 -0
  173. package/library/skills/combat-basics/resource.yaml +34 -0
  174. package/library/skills/concept-art/SKILL.md +1 -1
  175. package/library/skills/create-asset-sheet/SKILL.md +1 -1
  176. package/library/skills/debug/SKILL.md +1 -1
  177. package/library/skills/debugging-game-feel/SKILL.md +1 -1
  178. package/library/skills/design-level/SKILL.md +1 -1
  179. package/library/skills/design-mechanic/SKILL.md +1 -1
  180. package/library/skills/design-npc/SKILL.md +1 -1
  181. package/library/skills/diagnosing-perf-regressions/SKILL.md +1 -1
  182. package/library/skills/dispatching-parallel-agents/SKILL.md +1 -1
  183. package/library/skills/driving-the-editor-ui/SKILL.md +1 -1
  184. package/library/skills/environment-kit/SKILL.md +1 -1
  185. package/library/skills/export-and-ship/SKILL.md +1 -1
  186. package/library/skills/fabricating-assets/SKILL.md +1 -1
  187. package/library/skills/facial-and-lipsync/SKILL.md +1 -1
  188. package/library/skills/fps-controller/SKILL.md +9 -7
  189. package/library/skills/fps-controller/resource.yaml +4 -1
  190. package/library/skills/game-feel/SKILL.md +1 -1
  191. package/library/skills/gameskill/SKILL.md +1 -1
  192. package/library/skills/gdscript-patterns/SKILL.md +1 -1
  193. package/library/skills/generate-motion/SKILL.md +9 -9
  194. package/library/skills/generate-motion/resource.yaml +2 -1
  195. package/library/skills/godogen-visual-proof-game-generation/SKILL.md +1 -1
  196. package/library/skills/headless-scripting/SKILL.md +1 -1
  197. package/library/skills/in-game-purchases/SKILL.md +254 -0
  198. package/library/skills/in-game-purchases/resource.yaml +29 -0
  199. package/library/skills/instantiate-asset-pack/SKILL.md +1 -1
  200. package/library/skills/investigating-bugs/SKILL.md +1 -1
  201. package/library/skills/lumera-single-image-scene-reconstruction/SKILL.md +1 -1
  202. package/library/skills/make-game/SKILL.md +25 -3
  203. package/library/skills/make-game/references/2d-platformer-polish.md +93 -0
  204. package/library/skills/make-game/references/2d-platformer.md +117 -0
  205. package/library/skills/make-game/references/2d-rpg-content.md +234 -0
  206. package/library/skills/make-game/references/2d-rpg.md +241 -0
  207. package/library/skills/make-game/references/2d-survivors-progression.md +201 -0
  208. package/library/skills/make-game/references/2d-survivors.md +237 -0
  209. package/library/skills/make-game/references/3d-fps-systems.md +216 -0
  210. package/library/skills/make-game/references/3d-fps.md +177 -0
  211. package/library/skills/make-game/references/3d-horror-systems.md +186 -0
  212. package/library/skills/make-game/references/3d-horror.md +201 -0
  213. package/library/skills/make-game/references/3d-third-person-systems.md +220 -0
  214. package/library/skills/make-game/references/3d-third-person.md +215 -0
  215. package/library/skills/make-game/resource.yaml +6 -1
  216. package/library/skills/multiplayer/SKILL.md +150 -0
  217. package/library/skills/multiplayer/resource.yaml +33 -0
  218. package/library/skills/multiplayer-movement/SKILL.md +510 -0
  219. package/library/skills/multiplayer-movement/files.md +501 -0
  220. package/library/skills/multiplayer-movement/resource.yaml +30 -0
  221. package/library/skills/multiplayer-project/SKILL.md +521 -0
  222. package/library/skills/multiplayer-project/files.md +448 -0
  223. package/library/skills/multiplayer-project/resource.yaml +36 -0
  224. package/library/skills/multiplayer-publish/SKILL.md +229 -0
  225. package/library/skills/multiplayer-publish/export-errors.md +89 -0
  226. package/library/skills/multiplayer-publish/resource.yaml +28 -0
  227. package/library/skills/multiplayer-state/SKILL.md +438 -0
  228. package/library/skills/multiplayer-state/files.md +592 -0
  229. package/library/skills/multiplayer-state/resource.yaml +35 -0
  230. package/library/skills/multiplayer-testing/SKILL.md +236 -0
  231. package/library/skills/multiplayer-testing/resource.yaml +39 -0
  232. package/library/skills/music-track/SKILL.md +1 -1
  233. package/library/skills/navigate-summer/SKILL.md +1 -1
  234. package/library/skills/new-project/SKILL.md +1 -1
  235. package/library/skills/organic-model/SKILL.md +1 -1
  236. package/library/skills/pixel-art/SKILL.md +1 -1
  237. package/library/skills/play/SKILL.md +1 -1
  238. package/library/skills/playtesting-a-feature/SKILL.md +1 -1
  239. package/library/skills/procedural-animation/SKILL.md +2 -2
  240. package/library/skills/procedural-animation/resource.yaml +1 -1
  241. package/library/skills/prop-model/SKILL.md +1 -1
  242. package/library/skills/psx-retro-rendering/SKILL.md +1 -1
  243. package/library/skills/realtime-wet-surfaces/SKILL.md +2 -2
  244. package/library/skills/remote-deploy/SKILL.md +1 -1
  245. package/library/skills/retarget/SKILL.md +1 -1
  246. package/library/skills/running-in-the-cloud/SKILL.md +1 -1
  247. package/library/skills/save-load/SKILL.md +156 -0
  248. package/library/skills/save-load/resource.yaml +27 -0
  249. package/library/skills/scene-composition/SKILL.md +1 -1
  250. package/library/skills/scene-hierarchy-design/SKILL.md +1 -1
  251. package/library/skills/scene-scripting/SKILL.md +1 -1
  252. package/library/skills/scene-to-level/SKILL.md +1 -1
  253. package/library/skills/skill-create/SKILL.md +1 -1
  254. package/library/skills/skill-improve/SKILL.md +1 -1
  255. package/library/skills/skill-test/SKILL.md +1 -1
  256. package/library/skills/skintokens-auto-rigging/SKILL.md +1 -1
  257. package/library/skills/skybox-panorama/SKILL.md +1 -1
  258. package/library/skills/sound-effect/SKILL.md +1 -1
  259. package/library/skills/spatial-placement/SKILL.md +134 -3
  260. package/library/skills/spatial-placement/references/kit-placement-tools.md +364 -0
  261. package/library/skills/spatial-placement/resource.yaml +16 -2
  262. package/library/skills/sprite-sheet/SKILL.md +1 -1
  263. package/library/skills/summer-analytics/SKILL.md +147 -0
  264. package/library/skills/summer-analytics/resource.yaml +28 -0
  265. package/library/skills/summer-friends/SKILL.md +226 -0
  266. package/library/skills/summer-friends/resource.yaml +28 -0
  267. package/library/skills/summer-leaderboards/SKILL.md +231 -0
  268. package/library/skills/summer-leaderboards/resource.yaml +30 -0
  269. package/library/skills/summer-match-results/SKILL.md +286 -0
  270. package/library/skills/summer-match-results/resource.yaml +32 -0
  271. package/library/skills/summer-matchmaking/SKILL.md +301 -0
  272. package/library/skills/summer-matchmaking/resource.yaml +32 -0
  273. package/library/skills/summer-parties/SKILL.md +253 -0
  274. package/library/skills/summer-parties/resource.yaml +30 -0
  275. package/library/skills/summer-player-data/SKILL.md +322 -0
  276. package/library/skills/summer-player-data/resource.yaml +30 -0
  277. package/library/skills/summer-store/SKILL.md +271 -0
  278. package/library/skills/summer-store/resource.yaml +29 -0
  279. package/library/skills/summer-world-chat/SKILL.md +195 -0
  280. package/library/skills/summer-world-chat/resource.yaml +30 -0
  281. package/library/skills/summer-world-saves/SKILL.md +284 -0
  282. package/library/skills/summer-world-saves/resource.yaml +29 -0
  283. package/library/skills/text-to-motion/SKILL.md +99 -0
  284. package/library/skills/text-to-motion/prompts-and-controls.md +34 -0
  285. package/library/skills/text-to-motion/resource.yaml +41 -0
  286. package/library/skills/text-to-motion/rigging-for-text-motion.md +54 -0
  287. package/library/skills/tileable-texture/SKILL.md +1 -1
  288. package/library/skills/trailer-shot/SKILL.md +1 -1
  289. package/library/skills/tune-performance/SKILL.md +1 -1
  290. package/library/skills/ui-basics/SKILL.md +10 -1
  291. package/library/skills/ui-graphics/SKILL.md +1 -1
  292. package/library/skills/use-widget-asset/SKILL.md +1 -1
  293. package/library/skills/using-summer/SKILL.md +2 -2
  294. package/library/skills/using-summer/resource.yaml +2 -2
  295. package/library/skills/vehicle-model/SKILL.md +1 -1
  296. package/library/skills/verification-before-completion/SKILL.md +1 -1
  297. package/library/skills/verifying-scenes/SKILL.md +76 -2
  298. package/library/skills/verifying-scenes/resource.yaml +13 -2
  299. package/library/skills/vfx-dissolve/SKILL.md +1 -1
  300. package/library/skills/vfx-fire/SKILL.md +1 -1
  301. package/library/skills/vfx-hit-spark/SKILL.md +1 -1
  302. package/library/skills/vfx-lightning/SKILL.md +1 -1
  303. package/library/skills/vfx-magic-glow/SKILL.md +1 -1
  304. package/library/skills/vfx-muzzle-flash/SKILL.md +1 -1
  305. package/library/skills/vfx-smoke/SKILL.md +1 -1
  306. package/library/skills/vfx-water-ripple/SKILL.md +1 -1
  307. package/library/skills/voice-line/SKILL.md +1 -1
  308. package/library/skills/web-and-touch-input/SKILL.md +38 -0
  309. package/library/skills/web-and-touch-input/resource.yaml +28 -0
  310. package/library/skills/web-compatibility-look/SKILL.md +62 -0
  311. package/library/skills/web-compatibility-look/resource.yaml +30 -0
  312. package/library/skills/world-building-3d/SKILL.md +8 -1
  313. package/library/skills/world-building-3d/references/spatial-tools.md +1 -1
  314. package/library/skills/world-building-3d/resource.yaml +2 -1
  315. package/library/skills/writing-plans/SKILL.md +1 -1
  316. package/library/skills/writing-skills/SKILL.md +1 -1
  317. package/library/templates/3d-lan-multiplayer-starter/resource.yaml +2 -2
  318. package/library/tools/attach-to-surface/resource.yaml +142 -0
  319. package/library/tools/batch/resource.yaml +9 -3
  320. package/library/tools/connect-ports/resource.yaml +120 -0
  321. package/library/tools/connect-signal/resource.yaml +3 -2
  322. package/library/tools/debug-views/resource.yaml +94 -0
  323. package/library/tools/frame-nodes/resource.yaml +104 -0
  324. package/library/tools/frame-shot/resource.yaml +134 -0
  325. package/library/tools/generate-motion/resource.yaml +44 -9
  326. package/library/tools/get-board/resource.yaml +50 -0
  327. package/library/tools/get-project-context/resource.yaml +13 -2
  328. package/library/tools/grep/resource.yaml +77 -0
  329. package/library/tools/inspect-asset/resource.yaml +71 -0
  330. package/library/tools/inspect-node/resource.yaml +9 -2
  331. package/library/tools/inspect-resource/resource.yaml +16 -5
  332. package/library/tools/instantiate-scene/resource.yaml +27 -2
  333. package/library/tools/measure/resource.yaml +96 -0
  334. package/library/tools/place-adjacent/resource.yaml +113 -0
  335. package/library/tools/play/resource.yaml +15 -2
  336. package/library/tools/raycast/resource.yaml +101 -0
  337. package/library/tools/read-file/resource.yaml +36 -2
  338. package/library/tools/read-library/resource.yaml +2 -2
  339. package/library/tools/repeat-along/resource.yaml +129 -0
  340. package/library/tools/replace-node/resource.yaml +11 -5
  341. package/library/tools/scene-audit/resource.yaml +144 -0
  342. package/library/tools/screenshot/resource.yaml +13 -2
  343. package/library/tools/search-assets/resource.yaml +18 -0
  344. package/library/tools/shot-sheet/resource.yaml +110 -0
  345. package/library/tools/snap-to-surface/resource.yaml +4 -1
  346. package/library/tools/world-snapshot/resource.yaml +24 -3
  347. package/library/tools/zoom/resource.yaml +105 -0
  348. package/package.json +1 -1
  349. package/registry/generated/aliases.json +17 -3
  350. package/registry/generated/counts.json +3 -3
  351. package/registry/generated/gemini-extension.json +26 -4
  352. package/registry/generated/index.json +2154 -469
  353. package/registry/generated/marketplace.claude.json +2 -2
  354. package/registry/generated/plugin.claude.json +27 -5
  355. package/registry/generated/plugin.codex.json +28 -6
  356. package/registry/generated/plugin.cursor.json +27 -5
  357. package/registry/generated/plugin.factory.json +27 -5
  358. package/registry/generated/skills-index.md +36 -14
  359. package/registry/generated/skills-registry.json +421 -124
  360. package/registry/generated/templates-registry.json +2 -2
  361. package/library/skills/host-authoritative-state/SKILL.md +0 -332
  362. package/library/skills/host-authoritative-state/resource.yaml +0 -28
  363. package/library/skills/peer-to-peer-multiplayer/SKILL.md +0 -373
  364. package/library/skills/peer-to-peer-multiplayer/resource.yaml +0 -28
  365. package/library/skills/setup-multiplayer/SKILL.md +0 -336
  366. package/library/skills/setup-multiplayer/resource.yaml +0 -28
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Pure math behind summer_scene_audit: everything the judgment side needs
3
+ * that is worth testing without an engine. The in-engine kernel
4
+ * (assets/audit/scene_audit.gd) only measures; these functions decide.
5
+ *
6
+ * Conventions match the engine: +Y up, a basis is three COLUMN vectors
7
+ * (x, y, z), a transform maps local to world as origin + basis * v.
8
+ */
9
+ import { type Vec3 } from "../seeing/math.js";
10
+ export type { Vec3 };
11
+ /** Basis as the kernel writes it: [x.x, x.y, x.z, y.x, y.y, y.z, z.x, z.y, z.z]. */
12
+ export type Basis9 = readonly number[];
13
+ export declare function basisColumns(b: Basis9): [Vec3, Vec3, Vec3];
14
+ /** Rotation angle (degrees) between two bases, scale removed. */
15
+ export declare function basisAngleDegrees(a: Basis9, b: Basis9): number;
16
+ /** Horizontal direction along a wall whose (horizontal) normal is n. */
17
+ export declare function wallDirection(normal: Vec3): Vec3;
18
+ /** Angle in [0, 90] degrees between an axis and a line (sign-free). */
19
+ export declare function lineAngleDegrees(axis: Vec3, line: Vec3): number;
20
+ /** Camera defaults when the scene has no perspective camera (Godot's Camera3D). */
21
+ export declare const DEFAULT_NEAR = 0.05;
22
+ export declare const DEFAULT_FAR = 4000;
23
+ /** Compatibility / WebGL2 depth buffer. */
24
+ export declare const DEPTH_BITS = 24;
25
+ /** The distance a surface is judged at when no viewpoint is known. */
26
+ export declare const TYPICAL_VIEW_M = 30;
27
+ /** Float noise in world transforms: never call a smaller gap resolvable. */
28
+ export declare const MIN_ZFIGHT_TOLERANCE = 0.0001;
29
+ /**
30
+ * World distance one depth-buffer step spans at `distance` from a perspective
31
+ * camera: z^2 (f - n) / (f n 2^bits). It grows with the square of the
32
+ * distance and shrinks with a larger near plane.
33
+ */
34
+ export declare function depthResolution(distance: number, near?: number, far?: number, bits?: number): number;
35
+ /** Two faces closer than this flicker: twice the depth step at `distance`. */
36
+ export declare function zFightTolerance(distance: number, near?: number, far?: number, factor?: number, bits?: number): number;
37
+ export type Vec2 = readonly [number, number];
38
+ /**
39
+ * Ratio of the two singular values of the 3x2 Jacobian d(world)/d(uv): how
40
+ * much more world distance one UV direction covers than the other. 1 = square
41
+ * texels, 8 = a texel stretched 8:1. Collapsed UVs (zero UV area) are
42
+ * Infinity: the texture is smeared into a strip.
43
+ */
44
+ export declare function uvStretchRatio(p0: Vec3, p1: Vec3, p2: Vec3, t0: Vec2, t1: Vec2, t2: Vec2): number;
45
+ export declare function triangleArea(p0: Vec3, p1: Vec3, p2: Vec3): number;
46
+ export interface Sample2 {
47
+ u: number;
48
+ v: number;
49
+ }
50
+ /**
51
+ * Connected groups of samples: two samples are neighbours when both
52
+ * coordinates differ by at most `reach` (1.5 x the grid spacing joins the
53
+ * 8-neighbourhood and off-grid seam samples). Returns groups of indices,
54
+ * largest first. Uses a bucket grid, so it is linear in practice.
55
+ */
56
+ export declare function clusterSamples(samples: readonly Sample2[], reach: number): number[][];
57
+ /** One down-ray sample and the ground it stands for: a grid cell, 10 cm of a
58
+ * seam across its width, or one step of a strip along a wall base. */
59
+ export interface Footprint {
60
+ x: number;
61
+ z: number;
62
+ sx: number;
63
+ sz: number;
64
+ area: number;
65
+ }
66
+ export interface FootprintExtent {
67
+ x0: number;
68
+ x1: number;
69
+ z0: number;
70
+ z1: number;
71
+ w: number;
72
+ d: number;
73
+ /** The longer and the shorter side (a seam is 8.4 x 0.04 m). */
74
+ long: number;
75
+ short: number;
76
+ area: number;
77
+ }
78
+ /**
79
+ * Bounds and area of a cluster of missed rays. The area is the sum of the
80
+ * samples' own footprints, never more than their bounding box: a 4 cm seam
81
+ * walked by 84 rays is 0.34 m2, not 84 grid cells.
82
+ */
83
+ export declare function footprintExtent(cells: readonly Footprint[]): FootprintExtent;
84
+ /** The most frequent value (ties: the first seen); `fallback` when empty. */
85
+ export declare function mostCommon(values: readonly number[], fallback?: number): number;
86
+ export declare function median(values: readonly number[]): number;
87
+ export declare function percentile(values: readonly number[], p: number): number;
88
+ /** Median centre and the distance beyond which a piece is "far out". */
89
+ export declare function robustBounds(points: readonly Vec3[]): {
90
+ center: Vec3;
91
+ radius: number;
92
+ limit: number;
93
+ };
94
+ /** Distance along `dir` (unit) from `p` to the point where it would be seen. */
95
+ export declare function fitCameraDistance(size: number, fovDegrees: number, fill?: number): number;
96
+ /** World axis label of a vector's dominant component ("+X", "-Y", ...). */
97
+ export declare function axisName(v: Vec3): string;
98
+ /** The local axis of a piece (basis columns) that a world direction runs along. */
99
+ export declare function localAxisName(b: readonly number[], v: Vec3): string;
100
+ export interface Box {
101
+ lo: Vec3;
102
+ hi: Vec3;
103
+ }
104
+ export declare function makeBox(a: Vec3, b: Vec3): Box;
105
+ export declare function growBox(b: Box, g: number): Box;
106
+ export declare function boxCenter(b: Box): Vec3;
107
+ /** Overlap of two boxes, or null when they do not overlap (touching counts). */
108
+ export declare function boxIntersection(a: Box, b: Box): Box | null;
109
+ /** Shortest distance between two boxes (0 when they touch or overlap). */
110
+ export declare function boxDistance(a: Box, b: Box): number;
@@ -0,0 +1,263 @@
1
+ /**
2
+ * Pure math behind summer_scene_audit: everything the judgment side needs
3
+ * that is worth testing without an engine. The in-engine kernel
4
+ * (assets/audit/scene_audit.gd) only measures; these functions decide.
5
+ *
6
+ * Conventions match the engine: +Y up, a basis is three COLUMN vectors
7
+ * (x, y, z), a transform maps local to world as origin + basis * v.
8
+ */
9
+ import { dot, length, normalize, scale, sub } from "../seeing/math.js";
10
+ export function basisColumns(b) {
11
+ return [
12
+ [b[0], b[1], b[2]],
13
+ [b[3], b[4], b[5]],
14
+ [b[6], b[7], b[8]],
15
+ ];
16
+ }
17
+ /** Rotation angle (degrees) between two bases, scale removed. */
18
+ export function basisAngleDegrees(a, b) {
19
+ const ca = basisColumns(a).map((c) => normalize(c));
20
+ const cb = basisColumns(b).map((c) => normalize(c));
21
+ // trace(A^T B) = sum of column dot products for orthonormal bases.
22
+ const trace = dot(ca[0], cb[0]) + dot(ca[1], cb[1]) + dot(ca[2], cb[2]);
23
+ const c = Math.min(1, Math.max(-1, (trace - 1) / 2));
24
+ return (Math.acos(c) * 180) / Math.PI;
25
+ }
26
+ // ---------------------------------------------------------------------------
27
+ // orientation: parallelism of a long axis to a wall
28
+ // ---------------------------------------------------------------------------
29
+ /** Horizontal direction along a wall whose (horizontal) normal is n. */
30
+ export function wallDirection(normal) {
31
+ return normalize([-normal[2], 0, normal[0]]);
32
+ }
33
+ /** Angle in [0, 90] degrees between an axis and a line (sign-free). */
34
+ export function lineAngleDegrees(axis, line) {
35
+ const a = normalize([axis[0], 0, axis[2]]);
36
+ const l = normalize([line[0], 0, line[2]]);
37
+ const c = Math.min(1, Math.abs(dot(a, l)));
38
+ return (Math.acos(c) * 180) / Math.PI;
39
+ }
40
+ // ---------------------------------------------------------------------------
41
+ // z_fight: depth precision decides how close is "coplanar"
42
+ // ---------------------------------------------------------------------------
43
+ /** Camera defaults when the scene has no perspective camera (Godot's Camera3D). */
44
+ export const DEFAULT_NEAR = 0.05;
45
+ export const DEFAULT_FAR = 4000;
46
+ /** Compatibility / WebGL2 depth buffer. */
47
+ export const DEPTH_BITS = 24;
48
+ /** The distance a surface is judged at when no viewpoint is known. */
49
+ export const TYPICAL_VIEW_M = 30;
50
+ /** Float noise in world transforms: never call a smaller gap resolvable. */
51
+ export const MIN_ZFIGHT_TOLERANCE = 0.0001;
52
+ /**
53
+ * World distance one depth-buffer step spans at `distance` from a perspective
54
+ * camera: z^2 (f - n) / (f n 2^bits). It grows with the square of the
55
+ * distance and shrinks with a larger near plane.
56
+ */
57
+ export function depthResolution(distance, near = DEFAULT_NEAR, far = DEFAULT_FAR, bits = DEPTH_BITS) {
58
+ const n = Math.max(1e-4, near);
59
+ const f = Math.max(n * 1.0001, far);
60
+ return (distance * distance * (f - n)) / (f * n * 2 ** bits);
61
+ }
62
+ /** Two faces closer than this flicker: twice the depth step at `distance`. */
63
+ export function zFightTolerance(distance, near = DEFAULT_NEAR, far = DEFAULT_FAR, factor = 2, bits = DEPTH_BITS) {
64
+ return Math.max(MIN_ZFIGHT_TOLERANCE, factor * depthResolution(distance, near, far, bits));
65
+ }
66
+ /**
67
+ * Ratio of the two singular values of the 3x2 Jacobian d(world)/d(uv): how
68
+ * much more world distance one UV direction covers than the other. 1 = square
69
+ * texels, 8 = a texel stretched 8:1. Collapsed UVs (zero UV area) are
70
+ * Infinity: the texture is smeared into a strip.
71
+ */
72
+ export function uvStretchRatio(p0, p1, p2, t0, t1, t2) {
73
+ const e1 = sub(p1, p0);
74
+ const e2 = sub(p2, p0);
75
+ const u1 = [t1[0] - t0[0], t1[1] - t0[1]];
76
+ const u2 = [t2[0] - t0[0], t2[1] - t0[1]];
77
+ const det = u1[0] * u2[1] - u2[0] * u1[1];
78
+ if (Math.abs(det) < 1e-12)
79
+ return Number.POSITIVE_INFINITY;
80
+ const inv = 1 / det;
81
+ const du = scale(sub(scale(e1, u2[1]), scale(e2, u1[1])), inv);
82
+ const dv = scale(sub(scale(e2, u1[0]), scale(e1, u2[0])), inv);
83
+ const aa = dot(du, du);
84
+ const bb = dot(dv, dv);
85
+ const ab = dot(du, dv);
86
+ const disc = Math.sqrt(Math.max(0, (aa - bb) * (aa - bb) + 4 * ab * ab));
87
+ const s1 = (aa + bb + disc) / 2;
88
+ const s2 = (aa + bb - disc) / 2;
89
+ if (s2 <= 1e-14)
90
+ return Number.POSITIVE_INFINITY;
91
+ return Math.sqrt(s1 / s2);
92
+ }
93
+ export function triangleArea(p0, p1, p2) {
94
+ const e1 = sub(p1, p0);
95
+ const e2 = sub(p2, p0);
96
+ const c = [e1[1] * e2[2] - e1[2] * e2[1], e1[2] * e2[0] - e1[0] * e2[2], e1[0] * e2[1] - e1[1] * e2[0]];
97
+ return length(c) / 2;
98
+ }
99
+ /**
100
+ * Connected groups of samples: two samples are neighbours when both
101
+ * coordinates differ by at most `reach` (1.5 x the grid spacing joins the
102
+ * 8-neighbourhood and off-grid seam samples). Returns groups of indices,
103
+ * largest first. Uses a bucket grid, so it is linear in practice.
104
+ */
105
+ export function clusterSamples(samples, reach) {
106
+ const parent = samples.map((_, i) => i);
107
+ const find = (i) => {
108
+ while (parent[i] !== i) {
109
+ parent[i] = parent[parent[i]];
110
+ i = parent[i];
111
+ }
112
+ return i;
113
+ };
114
+ const union = (a, b) => {
115
+ const ra = find(a);
116
+ const rb = find(b);
117
+ if (ra !== rb)
118
+ parent[ra] = rb;
119
+ };
120
+ const cell = Math.max(reach, 1e-6);
121
+ const buckets = new Map();
122
+ const key = (i, j) => `${i},${j}`;
123
+ samples.forEach((s, idx) => {
124
+ const i = Math.floor(s.u / cell);
125
+ const j = Math.floor(s.v / cell);
126
+ for (let di = -1; di <= 1; di++) {
127
+ for (let dj = -1; dj <= 1; dj++) {
128
+ for (const other of buckets.get(key(i + di, j + dj)) ?? []) {
129
+ const o = samples[other];
130
+ if (Math.abs(o.u - s.u) <= reach + 1e-9 && Math.abs(o.v - s.v) <= reach + 1e-9)
131
+ union(idx, other);
132
+ }
133
+ }
134
+ }
135
+ const k = key(i, j);
136
+ const list = buckets.get(k);
137
+ if (list)
138
+ list.push(idx);
139
+ else
140
+ buckets.set(k, [idx]);
141
+ });
142
+ const groups = new Map();
143
+ samples.forEach((_, i) => {
144
+ const r = find(i);
145
+ const g = groups.get(r);
146
+ if (g)
147
+ g.push(i);
148
+ else
149
+ groups.set(r, [i]);
150
+ });
151
+ return [...groups.values()].sort((a, b) => b.length - a.length || a[0] - b[0]);
152
+ }
153
+ /**
154
+ * Bounds and area of a cluster of missed rays. The area is the sum of the
155
+ * samples' own footprints, never more than their bounding box: a 4 cm seam
156
+ * walked by 84 rays is 0.34 m2, not 84 grid cells.
157
+ */
158
+ export function footprintExtent(cells) {
159
+ if (!cells.length)
160
+ return { x0: 0, x1: 0, z0: 0, z1: 0, w: 0, d: 0, long: 0, short: 0, area: 0 };
161
+ let x0 = Infinity;
162
+ let x1 = -Infinity;
163
+ let z0 = Infinity;
164
+ let z1 = -Infinity;
165
+ let sum = 0;
166
+ for (const c of cells) {
167
+ x0 = Math.min(x0, c.x - c.sx / 2);
168
+ x1 = Math.max(x1, c.x + c.sx / 2);
169
+ z0 = Math.min(z0, c.z - c.sz / 2);
170
+ z1 = Math.max(z1, c.z + c.sz / 2);
171
+ sum += Math.max(0, c.area);
172
+ }
173
+ const w = x1 - x0;
174
+ const d = z1 - z0;
175
+ return { x0, x1, z0, z1, w, d, long: Math.max(w, d), short: Math.min(w, d), area: Math.min(sum, w * d) };
176
+ }
177
+ /** The most frequent value (ties: the first seen); `fallback` when empty. */
178
+ export function mostCommon(values, fallback = -1) {
179
+ const counts = new Map();
180
+ for (const v of values)
181
+ counts.set(v, (counts.get(v) ?? 0) + 1);
182
+ let best = fallback;
183
+ let n = 0;
184
+ for (const [v, c] of counts) {
185
+ if (c > n) {
186
+ best = v;
187
+ n = c;
188
+ }
189
+ }
190
+ return best;
191
+ }
192
+ // ---------------------------------------------------------------------------
193
+ // Robust bounds for "far out of bounds"
194
+ // ---------------------------------------------------------------------------
195
+ export function median(values) {
196
+ if (!values.length)
197
+ return 0;
198
+ const s = [...values].sort((a, b) => a - b);
199
+ const m = Math.floor(s.length / 2);
200
+ return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;
201
+ }
202
+ export function percentile(values, p) {
203
+ if (!values.length)
204
+ return 0;
205
+ const s = [...values].sort((a, b) => a - b);
206
+ const idx = Math.min(s.length - 1, Math.max(0, Math.ceil((p / 100) * s.length) - 1));
207
+ return s[idx];
208
+ }
209
+ /** Median centre and the distance beyond which a piece is "far out". */
210
+ export function robustBounds(points) {
211
+ const center = [median(points.map((p) => p[0])), median(points.map((p) => p[1])), median(points.map((p) => p[2]))];
212
+ const radius = percentile(points.map((p) => length(sub(p, center))), 95);
213
+ return { center, radius, limit: Math.max(3 * radius, radius + 50) };
214
+ }
215
+ /** Distance along `dir` (unit) from `p` to the point where it would be seen. */
216
+ export function fitCameraDistance(size, fovDegrees, fill = 0.55) {
217
+ const half = Math.tan((fovDegrees * Math.PI) / 360);
218
+ return size / (2 * half * fill);
219
+ }
220
+ // ---------------------------------------------------------------------------
221
+ // Axis labels (z_fight: which way to nudge)
222
+ // ---------------------------------------------------------------------------
223
+ /** World axis label of a vector's dominant component ("+X", "-Y", ...). */
224
+ export function axisName(v) {
225
+ const k = Math.abs(v[0]) >= Math.abs(v[1]) && Math.abs(v[0]) >= Math.abs(v[2]) ? 0 : Math.abs(v[1]) >= Math.abs(v[2]) ? 1 : 2;
226
+ return `${v[k] >= 0 ? "+" : "-"}${"XYZ"[k]}`;
227
+ }
228
+ /** The local axis of a piece (basis columns) that a world direction runs along. */
229
+ export function localAxisName(b, v) {
230
+ const cols = basisColumns(b);
231
+ const local = [0, 1, 2].map((k) => {
232
+ const c = cols[k];
233
+ const L = length(c) || 1;
234
+ return (c[0] * v[0] + c[1] * v[1] + c[2] * v[2]) / L;
235
+ });
236
+ return axisName(local);
237
+ }
238
+ export function makeBox(a, b) {
239
+ return { lo: [Math.min(a[0], b[0]), Math.min(a[1], b[1]), Math.min(a[2], b[2])], hi: [Math.max(a[0], b[0]), Math.max(a[1], b[1]), Math.max(a[2], b[2])] };
240
+ }
241
+ export function growBox(b, g) {
242
+ return { lo: [b.lo[0] - g, b.lo[1] - g, b.lo[2] - g], hi: [b.hi[0] + g, b.hi[1] + g, b.hi[2] + g] };
243
+ }
244
+ export function boxCenter(b) {
245
+ return [(b.lo[0] + b.hi[0]) / 2, (b.lo[1] + b.hi[1]) / 2, (b.lo[2] + b.hi[2]) / 2];
246
+ }
247
+ /** Overlap of two boxes, or null when they do not overlap (touching counts). */
248
+ export function boxIntersection(a, b) {
249
+ const lo = [Math.max(a.lo[0], b.lo[0]), Math.max(a.lo[1], b.lo[1]), Math.max(a.lo[2], b.lo[2])];
250
+ const hi = [Math.min(a.hi[0], b.hi[0]), Math.min(a.hi[1], b.hi[1]), Math.min(a.hi[2], b.hi[2])];
251
+ if (lo[0] > hi[0] || lo[1] > hi[1] || lo[2] > hi[2])
252
+ return null;
253
+ return { lo, hi };
254
+ }
255
+ /** Shortest distance between two boxes (0 when they touch or overlap). */
256
+ export function boxDistance(a, b) {
257
+ let s = 0;
258
+ for (let k = 0; k < 3; k++) {
259
+ const d = a.hi[k] < b.lo[k] ? b.lo[k] - a.hi[k] : b.hi[k] < a.lo[k] ? a.lo[k] - b.hi[k] : 0;
260
+ s += d * d;
261
+ }
262
+ return Math.sqrt(s);
263
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * The compact audit result: counts per check, time per check, and ONE page of
3
+ * issues sorted by severity, never more than SUMMARY_CAP_BYTES of JSON. Agents
4
+ * cannot read results of tens of kilobytes, so the cap is enforced here by
5
+ * construction: issues are added while they fit, and the result names the
6
+ * offset of the next page.
7
+ */
8
+ import { type AuditCheck, type Severity } from "./args.js";
9
+ import type { AuditIssue } from "./judge.js";
10
+ export declare const SUMMARY_CAP_BYTES = 5000;
11
+ export declare function bytes(value: unknown): number;
12
+ /** Severity first, then the check's place in the list, then magnitude. */
13
+ export declare function sortIssues(issues: readonly AuditIssue[]): AuditIssue[];
14
+ export declare function filterIssues(issues: readonly AuditIssue[], minSeverity?: Severity): AuditIssue[];
15
+ export type CheckCounts = Partial<Record<Severity, number>> & {
16
+ partial?: number;
17
+ accepted?: number;
18
+ };
19
+ /** Per check: { error: n, warn: n, look: n } without zeros, plus `partial`
20
+ * (the share of the check's samples it covered) when the editor-time budget
21
+ * stopped it early. Checks that ran in full and found nothing are listed
22
+ * in `clean`; a partial check never is. */
23
+ export declare function countIssues(issues: readonly AuditIssue[], ran: readonly AuditCheck[], partial?: Partial<Record<AuditCheck, number>>, accepted?: readonly AuditIssue[]): {
24
+ counts: Record<string, CheckCounts>;
25
+ clean: AuditCheck[];
26
+ };
27
+ /** Kernel stages and the checks each one measures for. */
28
+ export declare const STAGE_CHECKS: Readonly<Record<string, readonly AuditCheck[]>>;
29
+ /**
30
+ * The kernel's partial stages ({stage: [done, planned]}) -> the share each
31
+ * requested check covered (the lowest of its stages, 2 decimals, never
32
+ * rounded up to 1), and the stages that are not checks (framing).
33
+ */
34
+ export declare function partialChecks(raw: unknown, ran: readonly AuditCheck[]): {
35
+ checks: Partial<Record<AuditCheck, number>>;
36
+ other: Record<string, number>;
37
+ };
38
+ export interface CompactIssue {
39
+ n: number;
40
+ check: AuditCheck;
41
+ sev: Severity;
42
+ path: string;
43
+ pos: readonly number[];
44
+ why: string;
45
+ ev: Record<string, unknown>;
46
+ next: string;
47
+ /** Pass it in accept:[{key, reason}] to hide this item on later audits. */
48
+ key: string;
49
+ /** An accepted item (show_accepted) and the reason given. */
50
+ accepted?: string;
51
+ /** It was accepted, but its evidence changed. */
52
+ accept_stale?: string;
53
+ }
54
+ export declare function compactIssue(issue: AuditIssue, n: number): CompactIssue;
55
+ export interface PageInput {
56
+ base: Record<string, unknown>;
57
+ issues: readonly AuditIssue[];
58
+ offset: number;
59
+ limit: number;
60
+ cap?: number;
61
+ }
62
+ export interface Page {
63
+ body: Record<string, unknown>;
64
+ shown: CompactIssue[];
65
+ }
66
+ /**
67
+ * One page: `base` (counts, timings, notes) plus issues[offset..] added one
68
+ * at a time while the JSON stays within `cap`. `next_offset` names where the
69
+ * next page starts; `trimmed_to_fit` says the byte cap (not `limit`) ended
70
+ * the page.
71
+ */
72
+ export declare function buildPage({ base, issues, offset, limit, cap }: PageInput): Page;
73
+ /** Kernel stage timings -> time per check (ms), plus setup and totals. */
74
+ export declare function timingPerCheck(ms: Record<string, unknown> | undefined, extra: Record<string, number>): Record<string, number | string>;
@@ -0,0 +1,212 @@
1
+ /**
2
+ * The compact audit result: counts per check, time per check, and ONE page of
3
+ * issues sorted by severity, never more than SUMMARY_CAP_BYTES of JSON. Agents
4
+ * cannot read results of tens of kilobytes, so the cap is enforced here by
5
+ * construction: issues are added while they fit, and the result names the
6
+ * offset of the next page.
7
+ */
8
+ import { AUDIT_CHECKS, SEVERITIES } from "./args.js";
9
+ import { issueKey } from "./accept.js";
10
+ export const SUMMARY_CAP_BYTES = 5000;
11
+ const SEVERITY_RANK = { error: 0, warn: 1, look: 2 };
12
+ const CHECK_RANK = new Map(AUDIT_CHECKS.map((c, i) => [c, i]));
13
+ export function bytes(value) {
14
+ return Buffer.byteLength(JSON.stringify(value), "utf8");
15
+ }
16
+ /** Severity first, then the check's place in the list, then magnitude. */
17
+ export function sortIssues(issues) {
18
+ return [...issues].sort((a, b) => SEVERITY_RANK[a.severity] - SEVERITY_RANK[b.severity] ||
19
+ (CHECK_RANK.get(a.check) ?? 99) - (CHECK_RANK.get(b.check) ?? 99) ||
20
+ b.score - a.score ||
21
+ a.path.localeCompare(b.path));
22
+ }
23
+ export function filterIssues(issues, minSeverity = "look") {
24
+ const limit = SEVERITY_RANK[minSeverity];
25
+ return issues.filter((i) => SEVERITY_RANK[i.severity] <= limit);
26
+ }
27
+ /** Per check: { error: n, warn: n, look: n } without zeros, plus `partial`
28
+ * (the share of the check's samples it covered) when the editor-time budget
29
+ * stopped it early. Checks that ran in full and found nothing are listed
30
+ * in `clean`; a partial check never is. */
31
+ export function countIssues(issues, ran, partial = {}, accepted = []) {
32
+ const counts = {};
33
+ for (const i of issues) {
34
+ const c = (counts[i.check] ??= {});
35
+ c[i.severity] = (c[i.severity] ?? 0) + 1;
36
+ }
37
+ for (const i of accepted) {
38
+ const c = (counts[i.check] ??= {});
39
+ c.accepted = (c.accepted ?? 0) + 1;
40
+ }
41
+ const ordered = {};
42
+ for (const check of AUDIT_CHECKS) {
43
+ const share = ran.includes(check) ? partial[check] : undefined;
44
+ if (!counts[check] && share === undefined)
45
+ continue;
46
+ const c = {};
47
+ for (const s of SEVERITIES)
48
+ if (counts[check]?.[s])
49
+ c[s] = counts[check][s];
50
+ if (counts[check]?.accepted)
51
+ c.accepted = counts[check].accepted;
52
+ if (share !== undefined)
53
+ c.partial = share;
54
+ ordered[check] = c;
55
+ }
56
+ return { counts: ordered, clean: ran.filter((c) => !counts[c] && partial[c] === undefined) };
57
+ }
58
+ /** Kernel stages and the checks each one measures for. */
59
+ export const STAGE_CHECKS = {
60
+ through_hole: ["through_hole", "z_fight"],
61
+ floor_gap: ["floor_gap", "z_fight"],
62
+ floating_sunken: ["floating", "sunken"],
63
+ interpenetration: ["interpenetration"],
64
+ orientation: ["orientation"],
65
+ uv_stretch: ["uv_stretch"],
66
+ z_fight_geometry: ["z_fight"],
67
+ gap_setup: ["exposed_edge", "open_fixture_end", "depth_step"],
68
+ exposed_edge: ["exposed_edge"],
69
+ open_fixture_end: ["open_fixture_end"],
70
+ depth_step: ["depth_step"],
71
+ lights: ["lights"],
72
+ resource: ["resource"],
73
+ };
74
+ /**
75
+ * The kernel's partial stages ({stage: [done, planned]}) -> the share each
76
+ * requested check covered (the lowest of its stages, 2 decimals, never
77
+ * rounded up to 1), and the stages that are not checks (framing).
78
+ */
79
+ export function partialChecks(raw, ran) {
80
+ const checks = {};
81
+ const other = {};
82
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
83
+ return { checks, other };
84
+ for (const [stage, value] of Object.entries(raw)) {
85
+ if (!Array.isArray(value))
86
+ continue;
87
+ const done = Number(value[0]);
88
+ const total = Number(value[1]);
89
+ if (!Number.isFinite(done) || !Number.isFinite(total) || total <= 0 || done >= total)
90
+ continue;
91
+ const share = Math.min(0.99, Math.floor((Math.max(0, done) / total) * 100) / 100);
92
+ const mapped = STAGE_CHECKS[stage];
93
+ if (!mapped) {
94
+ other[stage] = share;
95
+ continue;
96
+ }
97
+ for (const check of mapped) {
98
+ if (!ran.includes(check))
99
+ continue;
100
+ checks[check] = Math.min(checks[check] ?? 1, share);
101
+ }
102
+ }
103
+ return { checks, other };
104
+ }
105
+ export function compactIssue(issue, n) {
106
+ return {
107
+ n,
108
+ check: issue.check,
109
+ sev: issue.severity,
110
+ path: issue.path,
111
+ pos: issue.pos,
112
+ why: issue.why,
113
+ ev: issue.ev,
114
+ next: issue.next,
115
+ key: issueKey(issue),
116
+ ...(issue.accepted ? { accepted: issue.accepted } : {}),
117
+ ...(issue.acceptStale ? { accept_stale: issue.acceptStale } : {}),
118
+ };
119
+ }
120
+ /** A single issue that alone is too big for the page: cut its prose. */
121
+ function shrink(issue, budget) {
122
+ let out = { ...issue, why: issue.why.slice(0, 200), next: issue.next.slice(0, 160) };
123
+ if (bytes(out) <= budget)
124
+ return out;
125
+ const ev = {};
126
+ for (const [k, v] of Object.entries(issue.ev).slice(0, 4))
127
+ ev[k] = typeof v === "string" ? v.slice(0, 80) : v;
128
+ out = { ...out, ev };
129
+ if (bytes(out) <= budget)
130
+ return out;
131
+ return { ...out, why: out.why.slice(0, 100), ev: {}, next: out.next.slice(0, 80) };
132
+ }
133
+ /**
134
+ * One page: `base` (counts, timings, notes) plus issues[offset..] added one
135
+ * at a time while the JSON stays within `cap`. `next_offset` names where the
136
+ * next page starts; `trimmed_to_fit` says the byte cap (not `limit`) ended
137
+ * the page.
138
+ */
139
+ export function buildPage({ base, issues, offset, limit, cap = SUMMARY_CAP_BYTES }) {
140
+ const start = Math.min(Math.max(0, offset), issues.length);
141
+ const shown = [];
142
+ const frame = (list, extra = {}) => ({
143
+ ...base,
144
+ matching: issues.length,
145
+ offset: start,
146
+ shown: list.length,
147
+ ...extra,
148
+ issues: list,
149
+ });
150
+ let trimmed = false;
151
+ for (let i = start; i < issues.length && shown.length < limit; i++) {
152
+ const candidate = compactIssue(issues[i], i + 1);
153
+ // Fit against the largest tail the page can end with (a next offset AND
154
+ // the trimmed flag), so adding the flag afterwards never breaks the cap.
155
+ const tail = { next_offset: issues.length, trimmed_to_fit: true };
156
+ if (bytes(frame([...shown, candidate], tail)) <= cap) {
157
+ shown.push(candidate);
158
+ continue;
159
+ }
160
+ if (shown.length === 0) {
161
+ const room = cap - bytes(frame([], tail)) - 8;
162
+ const small = shrink(candidate, room);
163
+ if (bytes(frame([small], tail)) <= cap) {
164
+ shown.push(small);
165
+ trimmed = true;
166
+ continue;
167
+ }
168
+ }
169
+ trimmed = true;
170
+ break;
171
+ }
172
+ const end = start + shown.length;
173
+ const body = frame(shown, {
174
+ next_offset: end < issues.length ? end : null,
175
+ ...(trimmed ? { trimmed_to_fit: true } : {}),
176
+ });
177
+ // A base so large that nothing fits (should not happen): drop the notes.
178
+ if (bytes(body) > cap && Array.isArray(body.notes)) {
179
+ const lean = { ...body, notes: body.notes.slice(0, 1) };
180
+ return { body: lean, shown };
181
+ }
182
+ return { body, shown };
183
+ }
184
+ /** Kernel stage timings -> time per check (ms), plus setup and totals. */
185
+ export function timingPerCheck(ms, extra) {
186
+ const m = (k) => (typeof ms?.[k] === "number" ? ms[k] : 0);
187
+ const out = {
188
+ setup: Math.round((m("collect") + m("roles") + m("mesh_pass") + m("physics_build")) * 10) / 10,
189
+ setup_parts: `walk ${Math.round(m("collect"))} + roles ${Math.round(m("roles"))} + meshes ${Math.round(m("mesh_pass"))} + physics ${Math.round(m("physics_build"))}`,
190
+ };
191
+ const map = [
192
+ ["through_hole", "through_hole"],
193
+ ["floor_gap", "floor_gap"],
194
+ ["floating_sunken", "floating+sunken"],
195
+ ["interpenetration", "interpenetration"],
196
+ ["orientation", "orientation"],
197
+ ["uv_stretch", "uv_stretch"],
198
+ ["z_fight_geometry", "z_fight_geometry"],
199
+ ["gap_setup", "gap_setup"],
200
+ ["exposed_edge", "exposed_edge"],
201
+ ["open_fixture_end", "open_fixture_end"],
202
+ ["depth_step", "depth_step"],
203
+ ["lights", "lights"],
204
+ ["resource", "resource"],
205
+ ["poses", "framing"],
206
+ ];
207
+ for (const [stage, name] of map)
208
+ if (typeof ms?.[stage] === "number")
209
+ out[name] = ms[stage];
210
+ out.editor_total = m("total");
211
+ return { ...out, ...extra };
212
+ }