hoi4-agent-tools 0.0.0-bootstrap.1 → 0.1.3

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 (416) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/LICENSE +201 -0
  3. package/README.md +140 -2
  4. package/SECURITY.md +17 -0
  5. package/dist/bin/http.d.ts +3 -0
  6. package/dist/bin/http.d.ts.map +1 -0
  7. package/dist/bin/http.js +27 -0
  8. package/dist/bin/http.js.map +1 -0
  9. package/dist/bin/setup.d.ts +3 -0
  10. package/dist/bin/setup.d.ts.map +1 -0
  11. package/dist/bin/setup.js +188 -0
  12. package/dist/bin/setup.js.map +1 -0
  13. package/dist/bin/stdio.d.ts +3 -0
  14. package/dist/bin/stdio.d.ts.map +1 -0
  15. package/dist/bin/stdio.js +36 -0
  16. package/dist/bin/stdio.js.map +1 -0
  17. package/dist/hoi4_agent_tools/core/artifacts.d.ts +117 -0
  18. package/dist/hoi4_agent_tools/core/artifacts.d.ts.map +1 -0
  19. package/dist/hoi4_agent_tools/core/artifacts.js +1047 -0
  20. package/dist/hoi4_agent_tools/core/artifacts.js.map +1 -0
  21. package/dist/hoi4_agent_tools/core/canonical.d.ts +13 -0
  22. package/dist/hoi4_agent_tools/core/canonical.d.ts.map +1 -0
  23. package/dist/hoi4_agent_tools/core/canonical.js +41 -0
  24. package/dist/hoi4_agent_tools/core/canonical.js.map +1 -0
  25. package/dist/hoi4_agent_tools/core/configuration.d.ts +137 -0
  26. package/dist/hoi4_agent_tools/core/configuration.d.ts.map +1 -0
  27. package/dist/hoi4_agent_tools/core/configuration.js +383 -0
  28. package/dist/hoi4_agent_tools/core/configuration.js.map +1 -0
  29. package/dist/hoi4_agent_tools/core/diagnostic-collector.d.ts +18 -0
  30. package/dist/hoi4_agent_tools/core/diagnostic-collector.d.ts.map +1 -0
  31. package/dist/hoi4_agent_tools/core/diagnostic-collector.js +45 -0
  32. package/dist/hoi4_agent_tools/core/diagnostic-collector.js.map +1 -0
  33. package/dist/hoi4_agent_tools/core/diagnostics.d.ts +26 -0
  34. package/dist/hoi4_agent_tools/core/diagnostics.d.ts.map +1 -0
  35. package/dist/hoi4_agent_tools/core/diagnostics.js +25 -0
  36. package/dist/hoi4_agent_tools/core/diagnostics.js.map +1 -0
  37. package/dist/hoi4_agent_tools/core/diff.d.ts +22 -0
  38. package/dist/hoi4_agent_tools/core/diff.d.ts.map +1 -0
  39. package/dist/hoi4_agent_tools/core/diff.js +93 -0
  40. package/dist/hoi4_agent_tools/core/diff.js.map +1 -0
  41. package/dist/hoi4_agent_tools/core/engine.d.ts +56 -0
  42. package/dist/hoi4_agent_tools/core/engine.d.ts.map +1 -0
  43. package/dist/hoi4_agent_tools/core/engine.js +319 -0
  44. package/dist/hoi4_agent_tools/core/engine.js.map +1 -0
  45. package/dist/hoi4_agent_tools/core/image-diff.d.ts +14 -0
  46. package/dist/hoi4_agent_tools/core/image-diff.d.ts.map +1 -0
  47. package/dist/hoi4_agent_tools/core/image-diff.js +121 -0
  48. package/dist/hoi4_agent_tools/core/image-diff.js.map +1 -0
  49. package/dist/hoi4_agent_tools/core/index.d.ts +64 -0
  50. package/dist/hoi4_agent_tools/core/index.d.ts.map +1 -0
  51. package/dist/hoi4_agent_tools/core/index.js +963 -0
  52. package/dist/hoi4_agent_tools/core/index.js.map +1 -0
  53. package/dist/hoi4_agent_tools/core/index.public.d.ts +16 -0
  54. package/dist/hoi4_agent_tools/core/index.public.d.ts.map +1 -0
  55. package/dist/hoi4_agent_tools/core/index.public.js +16 -0
  56. package/dist/hoi4_agent_tools/core/index.public.js.map +1 -0
  57. package/dist/hoi4_agent_tools/core/render-budget.d.ts +51 -0
  58. package/dist/hoi4_agent_tools/core/render-budget.d.ts.map +1 -0
  59. package/dist/hoi4_agent_tools/core/render-budget.js +109 -0
  60. package/dist/hoi4_agent_tools/core/render-budget.js.map +1 -0
  61. package/dist/hoi4_agent_tools/core/result.d.ts +45 -0
  62. package/dist/hoi4_agent_tools/core/result.d.ts.map +1 -0
  63. package/dist/hoi4_agent_tools/core/result.js +26 -0
  64. package/dist/hoi4_agent_tools/core/result.js.map +1 -0
  65. package/dist/hoi4_agent_tools/core/scanner.d.ts +28 -0
  66. package/dist/hoi4_agent_tools/core/scanner.d.ts.map +1 -0
  67. package/dist/hoi4_agent_tools/core/scanner.js +136 -0
  68. package/dist/hoi4_agent_tools/core/scanner.js.map +1 -0
  69. package/dist/hoi4_agent_tools/core/server-state.d.ts +31 -0
  70. package/dist/hoi4_agent_tools/core/server-state.d.ts.map +1 -0
  71. package/dist/hoi4_agent_tools/core/server-state.js +413 -0
  72. package/dist/hoi4_agent_tools/core/server-state.js.map +1 -0
  73. package/dist/hoi4_agent_tools/core/source/encoding.d.ts +10 -0
  74. package/dist/hoi4_agent_tools/core/source/encoding.d.ts.map +1 -0
  75. package/dist/hoi4_agent_tools/core/source/encoding.js +54 -0
  76. package/dist/hoi4_agent_tools/core/source/encoding.js.map +1 -0
  77. package/dist/hoi4_agent_tools/core/source/index.d.ts +7 -0
  78. package/dist/hoi4_agent_tools/core/source/index.d.ts.map +1 -0
  79. package/dist/hoi4_agent_tools/core/source/index.js +7 -0
  80. package/dist/hoi4_agent_tools/core/source/index.js.map +1 -0
  81. package/dist/hoi4_agent_tools/core/source/lexer.d.ts +30 -0
  82. package/dist/hoi4_agent_tools/core/source/lexer.d.ts.map +1 -0
  83. package/dist/hoi4_agent_tools/core/source/lexer.js +266 -0
  84. package/dist/hoi4_agent_tools/core/source/lexer.js.map +1 -0
  85. package/dist/hoi4_agent_tools/core/source/limits.d.ts +21 -0
  86. package/dist/hoi4_agent_tools/core/source/limits.d.ts.map +1 -0
  87. package/dist/hoi4_agent_tools/core/source/limits.js +49 -0
  88. package/dist/hoi4_agent_tools/core/source/limits.js.map +1 -0
  89. package/dist/hoi4_agent_tools/core/source/localisation.d.ts +20 -0
  90. package/dist/hoi4_agent_tools/core/source/localisation.d.ts.map +1 -0
  91. package/dist/hoi4_agent_tools/core/source/localisation.js +163 -0
  92. package/dist/hoi4_agent_tools/core/source/localisation.js.map +1 -0
  93. package/dist/hoi4_agent_tools/core/source/parser.d.ts +44 -0
  94. package/dist/hoi4_agent_tools/core/source/parser.d.ts.map +1 -0
  95. package/dist/hoi4_agent_tools/core/source/parser.js +334 -0
  96. package/dist/hoi4_agent_tools/core/source/parser.js.map +1 -0
  97. package/dist/hoi4_agent_tools/core/source/rewrite.d.ts +10 -0
  98. package/dist/hoi4_agent_tools/core/source/rewrite.d.ts.map +1 -0
  99. package/dist/hoi4_agent_tools/core/source/rewrite.js +28 -0
  100. package/dist/hoi4_agent_tools/core/source/rewrite.js.map +1 -0
  101. package/dist/hoi4_agent_tools/core/svg-text.d.ts +34 -0
  102. package/dist/hoi4_agent_tools/core/svg-text.d.ts.map +1 -0
  103. package/dist/hoi4_agent_tools/core/svg-text.js +127 -0
  104. package/dist/hoi4_agent_tools/core/svg-text.js.map +1 -0
  105. package/dist/hoi4_agent_tools/core/transaction-limits.d.ts +9 -0
  106. package/dist/hoi4_agent_tools/core/transaction-limits.d.ts.map +1 -0
  107. package/dist/hoi4_agent_tools/core/transaction-limits.js +9 -0
  108. package/dist/hoi4_agent_tools/core/transaction-limits.js.map +1 -0
  109. package/dist/hoi4_agent_tools/core/transactions.d.ts +162 -0
  110. package/dist/hoi4_agent_tools/core/transactions.d.ts.map +1 -0
  111. package/dist/hoi4_agent_tools/core/transactions.js +1181 -0
  112. package/dist/hoi4_agent_tools/core/transactions.js.map +1 -0
  113. package/dist/hoi4_agent_tools/core/workspace.d.ts +68 -0
  114. package/dist/hoi4_agent_tools/core/workspace.d.ts.map +1 -0
  115. package/dist/hoi4_agent_tools/core/workspace.js +794 -0
  116. package/dist/hoi4_agent_tools/core/workspace.js.map +1 -0
  117. package/dist/hoi4_agent_tools/focus/compiler.d.ts +9 -0
  118. package/dist/hoi4_agent_tools/focus/compiler.d.ts.map +1 -0
  119. package/dist/hoi4_agent_tools/focus/compiler.js +273 -0
  120. package/dist/hoi4_agent_tools/focus/compiler.js.map +1 -0
  121. package/dist/hoi4_agent_tools/focus/continuous-render.d.ts +32 -0
  122. package/dist/hoi4_agent_tools/focus/continuous-render.d.ts.map +1 -0
  123. package/dist/hoi4_agent_tools/focus/continuous-render.js +179 -0
  124. package/dist/hoi4_agent_tools/focus/continuous-render.js.map +1 -0
  125. package/dist/hoi4_agent_tools/focus/drift.d.ts +22 -0
  126. package/dist/hoi4_agent_tools/focus/drift.d.ts.map +1 -0
  127. package/dist/hoi4_agent_tools/focus/drift.js +124 -0
  128. package/dist/hoi4_agent_tools/focus/drift.js.map +1 -0
  129. package/dist/hoi4_agent_tools/focus/geometry.d.ts +17 -0
  130. package/dist/hoi4_agent_tools/focus/geometry.d.ts.map +1 -0
  131. package/dist/hoi4_agent_tools/focus/geometry.js +35 -0
  132. package/dist/hoi4_agent_tools/focus/geometry.js.map +1 -0
  133. package/dist/hoi4_agent_tools/focus/importer.d.ts +9 -0
  134. package/dist/hoi4_agent_tools/focus/importer.d.ts.map +1 -0
  135. package/dist/hoi4_agent_tools/focus/importer.js +732 -0
  136. package/dist/hoi4_agent_tools/focus/importer.js.map +1 -0
  137. package/dist/hoi4_agent_tools/focus/index.d.ts +14 -0
  138. package/dist/hoi4_agent_tools/focus/index.d.ts.map +1 -0
  139. package/dist/hoi4_agent_tools/focus/index.js +14 -0
  140. package/dist/hoi4_agent_tools/focus/index.js.map +1 -0
  141. package/dist/hoi4_agent_tools/focus/layout.d.ts +5 -0
  142. package/dist/hoi4_agent_tools/focus/layout.d.ts.map +1 -0
  143. package/dist/hoi4_agent_tools/focus/layout.js +653 -0
  144. package/dist/hoi4_agent_tools/focus/layout.js.map +1 -0
  145. package/dist/hoi4_agent_tools/focus/limits.d.ts +9 -0
  146. package/dist/hoi4_agent_tools/focus/limits.d.ts.map +1 -0
  147. package/dist/hoi4_agent_tools/focus/limits.js +9 -0
  148. package/dist/hoi4_agent_tools/focus/limits.js.map +1 -0
  149. package/dist/hoi4_agent_tools/focus/lint.d.ts +14 -0
  150. package/dist/hoi4_agent_tools/focus/lint.d.ts.map +1 -0
  151. package/dist/hoi4_agent_tools/focus/lint.js +839 -0
  152. package/dist/hoi4_agent_tools/focus/lint.js.map +1 -0
  153. package/dist/hoi4_agent_tools/focus/model.d.ts +303 -0
  154. package/dist/hoi4_agent_tools/focus/model.d.ts.map +1 -0
  155. package/dist/hoi4_agent_tools/focus/model.js +20 -0
  156. package/dist/hoi4_agent_tools/focus/model.js.map +1 -0
  157. package/dist/hoi4_agent_tools/focus/native-effects.d.ts +9 -0
  158. package/dist/hoi4_agent_tools/focus/native-effects.d.ts.map +1 -0
  159. package/dist/hoi4_agent_tools/focus/native-effects.js +563 -0
  160. package/dist/hoi4_agent_tools/focus/native-effects.js.map +1 -0
  161. package/dist/hoi4_agent_tools/focus/planning.d.ts +15 -0
  162. package/dist/hoi4_agent_tools/focus/planning.d.ts.map +1 -0
  163. package/dist/hoi4_agent_tools/focus/planning.js +241 -0
  164. package/dist/hoi4_agent_tools/focus/planning.js.map +1 -0
  165. package/dist/hoi4_agent_tools/focus/presentation.d.ts +24 -0
  166. package/dist/hoi4_agent_tools/focus/presentation.d.ts.map +1 -0
  167. package/dist/hoi4_agent_tools/focus/presentation.js +204 -0
  168. package/dist/hoi4_agent_tools/focus/presentation.js.map +1 -0
  169. package/dist/hoi4_agent_tools/focus/render.d.ts +35 -0
  170. package/dist/hoi4_agent_tools/focus/render.d.ts.map +1 -0
  171. package/dist/hoi4_agent_tools/focus/render.js +491 -0
  172. package/dist/hoi4_agent_tools/focus/render.js.map +1 -0
  173. package/dist/hoi4_agent_tools/focus/service.d.ts +82 -0
  174. package/dist/hoi4_agent_tools/focus/service.d.ts.map +1 -0
  175. package/dist/hoi4_agent_tools/focus/service.js +492 -0
  176. package/dist/hoi4_agent_tools/focus/service.js.map +1 -0
  177. package/dist/hoi4_agent_tools/focus/source-update.d.ts +6 -0
  178. package/dist/hoi4_agent_tools/focus/source-update.d.ts.map +1 -0
  179. package/dist/hoi4_agent_tools/focus/source-update.js +328 -0
  180. package/dist/hoi4_agent_tools/focus/source-update.js.map +1 -0
  181. package/dist/hoi4_agent_tools/gui/animation-manifest.d.ts +37 -0
  182. package/dist/hoi4_agent_tools/gui/animation-manifest.d.ts.map +1 -0
  183. package/dist/hoi4_agent_tools/gui/animation-manifest.js +66 -0
  184. package/dist/hoi4_agent_tools/gui/animation-manifest.js.map +1 -0
  185. package/dist/hoi4_agent_tools/gui/assets.d.ts +71 -0
  186. package/dist/hoi4_agent_tools/gui/assets.d.ts.map +1 -0
  187. package/dist/hoi4_agent_tools/gui/assets.js +629 -0
  188. package/dist/hoi4_agent_tools/gui/assets.js.map +1 -0
  189. package/dist/hoi4_agent_tools/gui/dds.d.ts +17 -0
  190. package/dist/hoi4_agent_tools/gui/dds.d.ts.map +1 -0
  191. package/dist/hoi4_agent_tools/gui/dds.js +245 -0
  192. package/dist/hoi4_agent_tools/gui/dds.js.map +1 -0
  193. package/dist/hoi4_agent_tools/gui/helpers.d.ts +101 -0
  194. package/dist/hoi4_agent_tools/gui/helpers.d.ts.map +1 -0
  195. package/dist/hoi4_agent_tools/gui/helpers.js +1072 -0
  196. package/dist/hoi4_agent_tools/gui/helpers.js.map +1 -0
  197. package/dist/hoi4_agent_tools/gui/index.d.ts +15 -0
  198. package/dist/hoi4_agent_tools/gui/index.d.ts.map +1 -0
  199. package/dist/hoi4_agent_tools/gui/index.js +15 -0
  200. package/dist/hoi4_agent_tools/gui/index.js.map +1 -0
  201. package/dist/hoi4_agent_tools/gui/layout.d.ts +6 -0
  202. package/dist/hoi4_agent_tools/gui/layout.d.ts.map +1 -0
  203. package/dist/hoi4_agent_tools/gui/layout.js +753 -0
  204. package/dist/hoi4_agent_tools/gui/layout.js.map +1 -0
  205. package/dist/hoi4_agent_tools/gui/limits.d.ts +25 -0
  206. package/dist/hoi4_agent_tools/gui/limits.d.ts.map +1 -0
  207. package/dist/hoi4_agent_tools/gui/limits.js +27 -0
  208. package/dist/hoi4_agent_tools/gui/limits.js.map +1 -0
  209. package/dist/hoi4_agent_tools/gui/renderer.d.ts +18 -0
  210. package/dist/hoi4_agent_tools/gui/renderer.d.ts.map +1 -0
  211. package/dist/hoi4_agent_tools/gui/renderer.js +388 -0
  212. package/dist/hoi4_agent_tools/gui/renderer.js.map +1 -0
  213. package/dist/hoi4_agent_tools/gui/scenario.d.ts +66 -0
  214. package/dist/hoi4_agent_tools/gui/scenario.d.ts.map +1 -0
  215. package/dist/hoi4_agent_tools/gui/scenario.js +191 -0
  216. package/dist/hoi4_agent_tools/gui/scenario.js.map +1 -0
  217. package/dist/hoi4_agent_tools/gui/source-graph.d.ts +7 -0
  218. package/dist/hoi4_agent_tools/gui/source-graph.d.ts.map +1 -0
  219. package/dist/hoi4_agent_tools/gui/source-graph.js +1074 -0
  220. package/dist/hoi4_agent_tools/gui/source-graph.js.map +1 -0
  221. package/dist/hoi4_agent_tools/gui/source-patch.d.ts +13 -0
  222. package/dist/hoi4_agent_tools/gui/source-patch.d.ts.map +1 -0
  223. package/dist/hoi4_agent_tools/gui/source-patch.js +90 -0
  224. package/dist/hoi4_agent_tools/gui/source-patch.js.map +1 -0
  225. package/dist/hoi4_agent_tools/gui/studio.d.ts +86 -0
  226. package/dist/hoi4_agent_tools/gui/studio.d.ts.map +1 -0
  227. package/dist/hoi4_agent_tools/gui/studio.js +830 -0
  228. package/dist/hoi4_agent_tools/gui/studio.js.map +1 -0
  229. package/dist/hoi4_agent_tools/gui/tga.d.ts +16 -0
  230. package/dist/hoi4_agent_tools/gui/tga.d.ts.map +1 -0
  231. package/dist/hoi4_agent_tools/gui/tga.js +157 -0
  232. package/dist/hoi4_agent_tools/gui/tga.js.map +1 -0
  233. package/dist/hoi4_agent_tools/gui/types.d.ts +322 -0
  234. package/dist/hoi4_agent_tools/gui/types.d.ts.map +1 -0
  235. package/dist/hoi4_agent_tools/gui/types.js +19 -0
  236. package/dist/hoi4_agent_tools/gui/types.js.map +1 -0
  237. package/dist/hoi4_agent_tools/gui/validators.d.ts +8 -0
  238. package/dist/hoi4_agent_tools/gui/validators.d.ts.map +1 -0
  239. package/dist/hoi4_agent_tools/gui/validators.js +951 -0
  240. package/dist/hoi4_agent_tools/gui/validators.js.map +1 -0
  241. package/dist/hoi4_agent_tools/map/bmp.d.ts +62 -0
  242. package/dist/hoi4_agent_tools/map/bmp.d.ts.map +1 -0
  243. package/dist/hoi4_agent_tools/map/bmp.js +363 -0
  244. package/dist/hoi4_agent_tools/map/bmp.js.map +1 -0
  245. package/dist/hoi4_agent_tools/map/diagnostic-limit.d.ts +5 -0
  246. package/dist/hoi4_agent_tools/map/diagnostic-limit.d.ts.map +1 -0
  247. package/dist/hoi4_agent_tools/map/diagnostic-limit.js +21 -0
  248. package/dist/hoi4_agent_tools/map/diagnostic-limit.js.map +1 -0
  249. package/dist/hoi4_agent_tools/map/index.d.ts +8 -0
  250. package/dist/hoi4_agent_tools/map/index.d.ts.map +1 -0
  251. package/dist/hoi4_agent_tools/map/index.js +8 -0
  252. package/dist/hoi4_agent_tools/map/index.js.map +1 -0
  253. package/dist/hoi4_agent_tools/map/limits.d.ts +13 -0
  254. package/dist/hoi4_agent_tools/map/limits.d.ts.map +1 -0
  255. package/dist/hoi4_agent_tools/map/limits.js +13 -0
  256. package/dist/hoi4_agent_tools/map/limits.js.map +1 -0
  257. package/dist/hoi4_agent_tools/map/model.d.ts +269 -0
  258. package/dist/hoi4_agent_tools/map/model.d.ts.map +1 -0
  259. package/dist/hoi4_agent_tools/map/model.js +1114 -0
  260. package/dist/hoi4_agent_tools/map/model.js.map +1 -0
  261. package/dist/hoi4_agent_tools/map/operations.d.ts +401 -0
  262. package/dist/hoi4_agent_tools/map/operations.d.ts.map +1 -0
  263. package/dist/hoi4_agent_tools/map/operations.js +2717 -0
  264. package/dist/hoi4_agent_tools/map/operations.js.map +1 -0
  265. package/dist/hoi4_agent_tools/map/render.d.ts +90 -0
  266. package/dist/hoi4_agent_tools/map/render.d.ts.map +1 -0
  267. package/dist/hoi4_agent_tools/map/render.js +759 -0
  268. package/dist/hoi4_agent_tools/map/render.js.map +1 -0
  269. package/dist/hoi4_agent_tools/map/service.d.ts +81 -0
  270. package/dist/hoi4_agent_tools/map/service.d.ts.map +1 -0
  271. package/dist/hoi4_agent_tools/map/service.js +695 -0
  272. package/dist/hoi4_agent_tools/map/service.js.map +1 -0
  273. package/dist/hoi4_agent_tools/map/validation.d.ts +23 -0
  274. package/dist/hoi4_agent_tools/map/validation.d.ts.map +1 -0
  275. package/dist/hoi4_agent_tools/map/validation.js +1177 -0
  276. package/dist/hoi4_agent_tools/map/validation.js.map +1 -0
  277. package/dist/hoi4_agent_tools/mcp/prompts/register.d.ts +3 -0
  278. package/dist/hoi4_agent_tools/mcp/prompts/register.d.ts.map +1 -0
  279. package/dist/hoi4_agent_tools/mcp/prompts/register.js +50 -0
  280. package/dist/hoi4_agent_tools/mcp/prompts/register.js.map +1 -0
  281. package/dist/hoi4_agent_tools/mcp/registry/metadata.d.ts +9 -0
  282. package/dist/hoi4_agent_tools/mcp/registry/metadata.d.ts.map +1 -0
  283. package/dist/hoi4_agent_tools/mcp/registry/metadata.js +10 -0
  284. package/dist/hoi4_agent_tools/mcp/registry/metadata.js.map +1 -0
  285. package/dist/hoi4_agent_tools/mcp/resources/register.d.ts +5 -0
  286. package/dist/hoi4_agent_tools/mcp/resources/register.d.ts.map +1 -0
  287. package/dist/hoi4_agent_tools/mcp/resources/register.js +278 -0
  288. package/dist/hoi4_agent_tools/mcp/resources/register.js.map +1 -0
  289. package/dist/hoi4_agent_tools/mcp/security/auth.d.ts +24 -0
  290. package/dist/hoi4_agent_tools/mcp/security/auth.d.ts.map +1 -0
  291. package/dist/hoi4_agent_tools/mcp/security/auth.js +234 -0
  292. package/dist/hoi4_agent_tools/mcp/security/auth.js.map +1 -0
  293. package/dist/hoi4_agent_tools/mcp/server/base-tools.d.ts +35 -0
  294. package/dist/hoi4_agent_tools/mcp/server/base-tools.d.ts.map +1 -0
  295. package/dist/hoi4_agent_tools/mcp/server/base-tools.js +835 -0
  296. package/dist/hoi4_agent_tools/mcp/server/base-tools.js.map +1 -0
  297. package/dist/hoi4_agent_tools/mcp/server/create.d.ts +5 -0
  298. package/dist/hoi4_agent_tools/mcp/server/create.d.ts.map +1 -0
  299. package/dist/hoi4_agent_tools/mcp/server/create.js +26 -0
  300. package/dist/hoi4_agent_tools/mcp/server/create.js.map +1 -0
  301. package/dist/hoi4_agent_tools/mcp/server/output-schemas.d.ts +133 -0
  302. package/dist/hoi4_agent_tools/mcp/server/output-schemas.d.ts.map +1 -0
  303. package/dist/hoi4_agent_tools/mcp/server/output-schemas.js +127 -0
  304. package/dist/hoi4_agent_tools/mcp/server/output-schemas.js.map +1 -0
  305. package/dist/hoi4_agent_tools/mcp/server/progress.d.ts +8 -0
  306. package/dist/hoi4_agent_tools/mcp/server/progress.d.ts.map +1 -0
  307. package/dist/hoi4_agent_tools/mcp/server/progress.js +21 -0
  308. package/dist/hoi4_agent_tools/mcp/server/progress.js.map +1 -0
  309. package/dist/hoi4_agent_tools/mcp/server/result.d.ts +232 -0
  310. package/dist/hoi4_agent_tools/mcp/server/result.d.ts.map +1 -0
  311. package/dist/hoi4_agent_tools/mcp/server/result.js +353 -0
  312. package/dist/hoi4_agent_tools/mcp/server/result.js.map +1 -0
  313. package/dist/hoi4_agent_tools/mcp/tools/focus.d.ts +5 -0
  314. package/dist/hoi4_agent_tools/mcp/tools/focus.d.ts.map +1 -0
  315. package/dist/hoi4_agent_tools/mcp/tools/focus.js +1059 -0
  316. package/dist/hoi4_agent_tools/mcp/tools/focus.js.map +1 -0
  317. package/dist/hoi4_agent_tools/mcp/tools/gui.d.ts +111 -0
  318. package/dist/hoi4_agent_tools/mcp/tools/gui.d.ts.map +1 -0
  319. package/dist/hoi4_agent_tools/mcp/tools/gui.js +598 -0
  320. package/dist/hoi4_agent_tools/mcp/tools/gui.js.map +1 -0
  321. package/dist/hoi4_agent_tools/mcp/tools/map.d.ts +5 -0
  322. package/dist/hoi4_agent_tools/mcp/tools/map.d.ts.map +1 -0
  323. package/dist/hoi4_agent_tools/mcp/tools/map.js +685 -0
  324. package/dist/hoi4_agent_tools/mcp/tools/map.js.map +1 -0
  325. package/dist/hoi4_agent_tools/mcp/transports/bounded-stdio.d.ts +58 -0
  326. package/dist/hoi4_agent_tools/mcp/transports/bounded-stdio.d.ts.map +1 -0
  327. package/dist/hoi4_agent_tools/mcp/transports/bounded-stdio.js +181 -0
  328. package/dist/hoi4_agent_tools/mcp/transports/bounded-stdio.js.map +1 -0
  329. package/dist/hoi4_agent_tools/mcp/transports/event-store.d.ts +26 -0
  330. package/dist/hoi4_agent_tools/mcp/transports/event-store.d.ts.map +1 -0
  331. package/dist/hoi4_agent_tools/mcp/transports/event-store.js +86 -0
  332. package/dist/hoi4_agent_tools/mcp/transports/event-store.js.map +1 -0
  333. package/dist/hoi4_agent_tools/mcp/transports/http.d.ts +28 -0
  334. package/dist/hoi4_agent_tools/mcp/transports/http.d.ts.map +1 -0
  335. package/dist/hoi4_agent_tools/mcp/transports/http.js +744 -0
  336. package/dist/hoi4_agent_tools/mcp/transports/http.js.map +1 -0
  337. package/dist/hoi4_agent_tools/mcp/transports/protocol-gate.d.ts +15 -0
  338. package/dist/hoi4_agent_tools/mcp/transports/protocol-gate.d.ts.map +1 -0
  339. package/dist/hoi4_agent_tools/mcp/transports/protocol-gate.js +51 -0
  340. package/dist/hoi4_agent_tools/mcp/transports/protocol-gate.js.map +1 -0
  341. package/dist/hoi4_agent_tools/runtime.d.ts +4 -0
  342. package/dist/hoi4_agent_tools/runtime.d.ts.map +1 -0
  343. package/dist/hoi4_agent_tools/runtime.js +27 -0
  344. package/dist/hoi4_agent_tools/runtime.js.map +1 -0
  345. package/dist/hoi4_agent_tools/schemas/common.d.ts +74 -0
  346. package/dist/hoi4_agent_tools/schemas/common.d.ts.map +1 -0
  347. package/dist/hoi4_agent_tools/schemas/common.js +51 -0
  348. package/dist/hoi4_agent_tools/schemas/common.js.map +1 -0
  349. package/dist/hoi4_agent_tools/schemas/focus.d.ts +784 -0
  350. package/dist/hoi4_agent_tools/schemas/focus.d.ts.map +1 -0
  351. package/dist/hoi4_agent_tools/schemas/focus.js +330 -0
  352. package/dist/hoi4_agent_tools/schemas/focus.js.map +1 -0
  353. package/dist/hoi4_agent_tools/schemas/index.d.ts +5 -0
  354. package/dist/hoi4_agent_tools/schemas/index.d.ts.map +1 -0
  355. package/dist/hoi4_agent_tools/schemas/index.js +5 -0
  356. package/dist/hoi4_agent_tools/schemas/index.js.map +1 -0
  357. package/dist/hoi4_agent_tools/schemas/map.d.ts +654 -0
  358. package/dist/hoi4_agent_tools/schemas/map.d.ts.map +1 -0
  359. package/dist/hoi4_agent_tools/schemas/map.js +570 -0
  360. package/dist/hoi4_agent_tools/schemas/map.js.map +1 -0
  361. package/dist/hoi4_agent_tools/schemas/transaction.d.ts +259 -0
  362. package/dist/hoi4_agent_tools/schemas/transaction.d.ts.map +1 -0
  363. package/dist/hoi4_agent_tools/schemas/transaction.js +104 -0
  364. package/dist/hoi4_agent_tools/schemas/transaction.js.map +1 -0
  365. package/dist/hoi4_agent_tools/version.d.ts +6 -0
  366. package/dist/hoi4_agent_tools/version.d.ts.map +1 -0
  367. package/dist/hoi4_agent_tools/version.js +7 -0
  368. package/dist/hoi4_agent_tools/version.js.map +1 -0
  369. package/dist/index.d.ts +3 -0
  370. package/dist/index.d.ts.map +1 -0
  371. package/dist/index.js +3 -0
  372. package/dist/index.js.map +1 -0
  373. package/docs/README.md +22 -0
  374. package/docs/adr/0001-runtime-and-language.md +16 -0
  375. package/docs/adr/0002-lossless-source-model.md +18 -0
  376. package/docs/adr/0003-image-and-font-codecs.md +18 -0
  377. package/docs/adr/0004-focus-layout.md +16 -0
  378. package/docs/adr/0005-offline-rendering.md +18 -0
  379. package/docs/adr/0006-mcp-sdk-and-protocol.md +16 -0
  380. package/docs/adr/0007-storage-and-transactions.md +24 -0
  381. package/docs/adr/0008-test-strategy.md +18 -0
  382. package/docs/adr/0009-packaging-and-registry.md +16 -0
  383. package/docs/adr/0010-unsupported-and-refusal-policy.md +18 -0
  384. package/docs/adr/0011-http-security.md +16 -0
  385. package/docs/adr/README.md +13 -0
  386. package/docs/architecture.md +60 -0
  387. package/docs/artifacts.md +133 -0
  388. package/docs/compatibility.md +33 -0
  389. package/docs/completion-report.md +69 -0
  390. package/docs/configuration.md +285 -0
  391. package/docs/focus-workflow.md +68 -0
  392. package/docs/gui-workflow.md +121 -0
  393. package/docs/limitations.md +30 -0
  394. package/docs/map-workflow.md +89 -0
  395. package/docs/performance.md +117 -0
  396. package/docs/release.md +200 -0
  397. package/docs/research/mcp-2026-07-10.md +46 -0
  398. package/docs/research/source-ledger.md +68 -0
  399. package/docs/security.md +139 -0
  400. package/docs/self-hosting.md +168 -0
  401. package/docs/testing.md +43 -0
  402. package/docs/third-party-notices.md +11 -0
  403. package/docs/transactions.md +162 -0
  404. package/docs/troubleshooting.md +46 -0
  405. package/package.json +98 -5
  406. package/schemas/configuration.schema.json +794 -0
  407. package/schemas/continuous-focus-palette.schema.json +325 -0
  408. package/schemas/focus-plan.schema.json +902 -0
  409. package/schemas/focus-planning-sidecar.schema.json +364 -0
  410. package/schemas/gui-animation-source.schema.json +176 -0
  411. package/schemas/gui-helper.schema.json +301 -0
  412. package/schemas/gui-scenario.schema.json +298 -0
  413. package/schemas/map-operation.schema.json +2284 -0
  414. package/schemas/operation-result.schema.json +344 -0
  415. package/schemas/transaction-manifest.schema.json +685 -0
  416. package/server.json +32 -0
@@ -0,0 +1,1059 @@
1
+ import { z } from 'zod/v4';
2
+ import { boundedSourceHashEvidence, publicArtifactLink } from '../../core/artifacts.js';
3
+ import { compareCodeUnits, canonicalJson, sha256Bytes } from '../../core/canonical.js';
4
+ import { comparePngImages, createTransparentPng } from '../../core/image-diff.js';
5
+ import { RenderBudget } from '../../core/render-budget.js';
6
+ import { emptyServiceResult, ServiceError } from '../../core/result.js';
7
+ import { parseClausewitz } from '../../core/source/index.js';
8
+ import { readDependenciesFromScannedFiles } from '../../core/transactions.js';
9
+ import { FocusWorkbench, assertFocusPlanAuthority, detectContinuousFocusDrift, detectFocusDrift, focusPlanHash, focusPresentationEvidence, focusPlanningSidecarPath, importContinuousFocusPalettes, importFocusTrees, linkContinuousFocusPalettes, parseFocusPlanningSidecar, renderContinuousFocusPalette, renderFocusTree, resolveFocusPresentation, enrichFocusPlanFromSidecar, } from '../../focus/index.js';
10
+ import { continuousFocusPaletteSchema, focusLayoutDecisionSchema, focusLayoutSchema, focusTreePlanSchema, } from '../../schemas/focus.js';
11
+ import { workspaceIdSchema, workspaceRelativePathSchema } from '../../schemas/common.js';
12
+ import { PACKAGE_VERSION } from '../../version.js';
13
+ import { nonNegativeIntegerSchema, renderHashesSchema, sha256Schema, } from '../server/output-schemas.js';
14
+ import { progressReporter } from '../server/progress.js';
15
+ import { errorResult, setInlineFilesScanned, strictOperationResultSchema, toolResult, } from '../server/result.js';
16
+ import { requireServerScope, transactionResourceLink, } from '../server/base-tools.js';
17
+ const focusScanOutputSchema = strictOperationResultSchema(z
18
+ .object({
19
+ revision: sha256Schema,
20
+ treeCount: nonNegativeIntegerSchema,
21
+ trees: z
22
+ .array(z
23
+ .object({
24
+ id: z.string().max(256),
25
+ sourcePath: z.string().max(4096),
26
+ focusCount: nonNegativeIntegerSchema,
27
+ branchCount: nonNegativeIntegerSchema,
28
+ continuousPaletteCount: nonNegativeIntegerSchema,
29
+ continuousFocusCount: nonNegativeIntegerSchema,
30
+ resolvedTitleCount: nonNegativeIntegerSchema,
31
+ })
32
+ .strict())
33
+ .max(100),
34
+ })
35
+ .strict());
36
+ const focusLintOutputSchema = strictOperationResultSchema(z.discriminatedUnion('mode', [
37
+ z
38
+ .object({
39
+ mode: z.literal('national'),
40
+ treeId: z.string().max(256),
41
+ focusCount: nonNegativeIntegerSchema,
42
+ layoutHash: sha256Schema,
43
+ diagnosticCount: nonNegativeIntegerSchema,
44
+ })
45
+ .strict(),
46
+ z
47
+ .object({
48
+ mode: z.literal('continuous'),
49
+ paletteId: z.string().max(256),
50
+ focusCount: nonNegativeIntegerSchema,
51
+ diagnosticCount: nonNegativeIntegerSchema,
52
+ })
53
+ .strict(),
54
+ ]));
55
+ const focusLayoutOutputSchema = strictOperationResultSchema(z
56
+ .object({
57
+ treeId: z.string().max(256),
58
+ layoutHash: sha256Schema,
59
+ nodeCount: nonNegativeIntegerSchema,
60
+ decisions: z.array(focusLayoutDecisionSchema).max(100),
61
+ })
62
+ .strict());
63
+ const focusRenderOutputSchema = strictOperationResultSchema(z.discriminatedUnion('mode', [
64
+ z
65
+ .object({
66
+ mode: z.literal('national'),
67
+ treeId: z.string().max(256),
68
+ layoutHash: sha256Schema,
69
+ hashes: renderHashesSchema,
70
+ width: nonNegativeIntegerSchema,
71
+ height: nonNegativeIntegerSchema,
72
+ })
73
+ .strict(),
74
+ z
75
+ .object({
76
+ mode: z.literal('continuous'),
77
+ paletteId: z.string().max(256),
78
+ focusCount: nonNegativeIntegerSchema,
79
+ hashes: renderHashesSchema,
80
+ width: nonNegativeIntegerSchema,
81
+ height: nonNegativeIntegerSchema,
82
+ })
83
+ .strict(),
84
+ ]));
85
+ const focusDriftBaseOutputSchema = z
86
+ .object({
87
+ status: z.enum([
88
+ 'clean',
89
+ 'plan_changed',
90
+ 'source_changed_formatting',
91
+ 'source_changed_semantically',
92
+ 'converged',
93
+ 'conflict',
94
+ 'target_missing',
95
+ 'tree_removed',
96
+ ]),
97
+ sourceChanged: z.boolean(),
98
+ planChanged: z.boolean(),
99
+ requiresAuthority: z.boolean(),
100
+ savedPlanHash: sha256Schema,
101
+ currentPlanHash: z.string().max(256),
102
+ importedPlanHash: sha256Schema,
103
+ savedSourceHash: sha256Schema,
104
+ currentSourceHash: sha256Schema,
105
+ })
106
+ .strict();
107
+ const focusDriftOutputSchema = focusDriftBaseOutputSchema;
108
+ const continuousFocusDriftOutputSchema = focusDriftBaseOutputSchema;
109
+ const focusPlanOutputSchema = strictOperationResultSchema(z.discriminatedUnion('mode', [
110
+ z
111
+ .object({
112
+ mode: z.literal('national'),
113
+ treeId: z.string().max(256),
114
+ drift: focusDriftOutputSchema,
115
+ created: z.boolean(),
116
+ layoutHash: sha256Schema,
117
+ expiresAt: z.iso.datetime(),
118
+ transactionFileCount: nonNegativeIntegerSchema,
119
+ transactionArtifactCount: nonNegativeIntegerSchema,
120
+ })
121
+ .strict(),
122
+ z
123
+ .object({
124
+ mode: z.literal('continuous'),
125
+ paletteId: z.string().max(256),
126
+ drift: continuousFocusDriftOutputSchema,
127
+ created: z.boolean(),
128
+ expiresAt: z.iso.datetime(),
129
+ transactionFileCount: nonNegativeIntegerSchema,
130
+ transactionArtifactCount: nonNegativeIntegerSchema,
131
+ })
132
+ .strict(),
133
+ ]));
134
+ const focusPathInput = z
135
+ .object({
136
+ workspaceId: workspaceIdSchema,
137
+ relativePath: workspaceRelativePathSchema,
138
+ treeId: z.string().min(1).max(256).optional(),
139
+ })
140
+ .strict();
141
+ const focusLintInput = z
142
+ .object({
143
+ mode: z.enum(['national', 'continuous']).optional(),
144
+ workspaceId: workspaceIdSchema,
145
+ relativePath: workspaceRelativePathSchema,
146
+ treeId: z.string().min(1).max(256).optional(),
147
+ paletteId: z.string().min(1).max(256).optional(),
148
+ })
149
+ .strict()
150
+ .superRefine((value, context) => {
151
+ const mode = value.mode ?? 'national';
152
+ if (mode === 'national' && value.paletteId !== undefined)
153
+ context.addIssue({
154
+ code: 'custom',
155
+ path: ['paletteId'],
156
+ message: 'paletteId is only valid in continuous mode',
157
+ });
158
+ if (mode === 'continuous' && value.treeId !== undefined)
159
+ context.addIssue({
160
+ code: 'custom',
161
+ path: ['treeId'],
162
+ message: 'treeId is only valid in national mode',
163
+ });
164
+ });
165
+ const focusRenderInput = z
166
+ .object({
167
+ mode: z.enum(['national', 'continuous']).optional(),
168
+ workspaceId: workspaceIdSchema,
169
+ relativePath: workspaceRelativePathSchema,
170
+ treeId: z.string().min(1).max(256).optional(),
171
+ paletteId: z.string().min(1).max(256).optional(),
172
+ horizontalSpacing: z.number().int().min(80).max(1000).optional(),
173
+ verticalSpacing: z.number().int().min(60).max(1000).optional(),
174
+ columns: z.number().int().min(1).max(12).optional(),
175
+ padding: z.number().int().min(0).max(1000).optional(),
176
+ })
177
+ .strict()
178
+ .superRefine((value, context) => {
179
+ const mode = value.mode ?? 'national';
180
+ const invalid = mode === 'national'
181
+ ? [
182
+ ['paletteId', value.paletteId],
183
+ ['columns', value.columns],
184
+ ]
185
+ : [
186
+ ['treeId', value.treeId],
187
+ ['horizontalSpacing', value.horizontalSpacing],
188
+ ['verticalSpacing', value.verticalSpacing],
189
+ ];
190
+ for (const [field, fieldValue] of invalid) {
191
+ if (fieldValue !== undefined)
192
+ context.addIssue({
193
+ code: 'custom',
194
+ path: [field],
195
+ message: `${field} is not valid in ${mode} mode`,
196
+ });
197
+ }
198
+ if (mode === 'continuous' && value.padding !== undefined && value.padding < 24)
199
+ context.addIssue({
200
+ code: 'custom',
201
+ path: ['padding'],
202
+ message: 'continuous focus padding must be at least 24 pixels',
203
+ });
204
+ });
205
+ const focusPlanInput = z
206
+ .object({
207
+ mode: z.enum(['national', 'continuous']).optional(),
208
+ workspaceId: workspaceIdSchema,
209
+ relativePath: workspaceRelativePathSchema,
210
+ plan: z.union([focusTreePlanSchema, continuousFocusPaletteSchema]),
211
+ authority: z.enum(['plan', 'source']).optional(),
212
+ createIfMissing: z.boolean().default(false),
213
+ })
214
+ .strict()
215
+ .superRefine((value, context) => {
216
+ const mode = value.mode ?? 'national';
217
+ const schema = mode === 'continuous' ? continuousFocusPaletteSchema : focusTreePlanSchema;
218
+ if (!schema.safeParse(value.plan).success)
219
+ context.addIssue({
220
+ code: 'custom',
221
+ path: ['plan'],
222
+ message: `plan must be a ${mode} focus plan`,
223
+ });
224
+ });
225
+ const artifactProducing = {
226
+ readOnlyHint: false,
227
+ destructiveHint: false,
228
+ idempotentHint: true,
229
+ openWorldHint: false,
230
+ };
231
+ function compactDrift(drift) {
232
+ const { currentSourcePlan: _currentSourcePlan, ...summary } = drift;
233
+ return summary;
234
+ }
235
+ function normalizedRoot(value) {
236
+ return value.replaceAll('\\', '/').replace(/^\.\//u, '').replace(/\/+$/u, '').toLowerCase();
237
+ }
238
+ function underConfiguredRoot(relativePath, roots) {
239
+ const candidate = relativePath.replaceAll('\\', '/').toLowerCase();
240
+ return roots.some((root) => {
241
+ const normalized = normalizedRoot(root);
242
+ return candidate === normalized || candidate.startsWith(`${normalized}/`);
243
+ });
244
+ }
245
+ function activeFocusFiles(snapshot, focusRoots) {
246
+ return snapshot.files.filter(({ relativePath, shadowedBy }) => shadowedBy === undefined &&
247
+ underConfiguredRoot(relativePath, focusRoots) &&
248
+ relativePath.toLowerCase().endsWith('.txt'));
249
+ }
250
+ function activeContinuousFocusFiles(snapshot) {
251
+ return snapshot.files.filter(({ relativePath, shadowedBy }) => shadowedBy === undefined &&
252
+ relativePath.replaceAll('\\', '/').toLowerCase().startsWith('common/continuous_focus/') &&
253
+ relativePath.toLowerCase().endsWith('.txt'));
254
+ }
255
+ function continuousPalettes(snapshot) {
256
+ const palettes = [];
257
+ const diagnostics = [];
258
+ for (const file of activeContinuousFocusFiles(snapshot)) {
259
+ const document = parseClausewitz(file.bytes, file.displayPath);
260
+ const imported = importContinuousFocusPalettes(document);
261
+ palettes.push(...imported.continuousFocusPalettes);
262
+ diagnostics.push(...imported.diagnostics);
263
+ }
264
+ return { palettes, diagnostics };
265
+ }
266
+ function activeSidecar(snapshot, focusFile) {
267
+ const relativePath = focusPlanningSidecarPath(focusFile.relativePath).toLowerCase();
268
+ const file = snapshot.files.find((candidate) => candidate.shadowedBy === undefined && candidate.relativePath.toLowerCase() === relativePath);
269
+ return file === undefined ? undefined : { file, sidecar: parseFocusPlanningSidecar(file.bytes) };
270
+ }
271
+ function importFocusFile(snapshot, file, palettes) {
272
+ const document = parseClausewitz(file.bytes, file.displayPath);
273
+ const imported = importFocusTrees(document, { references: referenceCatalog(snapshot) });
274
+ const sidecar = activeSidecar(snapshot, file);
275
+ imported.plans = imported.plans.map((plan) => {
276
+ const enriched = sidecar === undefined
277
+ ? { plan, diagnostics: [] }
278
+ : enrichFocusPlanFromSidecar(plan, sidecar.sidecar);
279
+ imported.diagnostics.push(...enriched.diagnostics);
280
+ return linkContinuousFocusPalettes(enriched.plan, palettes);
281
+ });
282
+ return imported;
283
+ }
284
+ function selectedFocusFile(snapshot, focusRoots, relativePath) {
285
+ const file = activeFocusFiles(snapshot, focusRoots).find((candidate) => candidate.relativePath === relativePath);
286
+ if (file === undefined) {
287
+ throw new ServiceError('FOCUS_SOURCE_NOT_FOUND', `Focus source was not found: ${relativePath}`);
288
+ }
289
+ return file;
290
+ }
291
+ function selectedContinuousFocusFile(snapshot, relativePath) {
292
+ const file = activeContinuousFocusFiles(snapshot).find((candidate) => candidate.relativePath === relativePath);
293
+ if (file === undefined) {
294
+ throw new ServiceError('CONTINUOUS_FOCUS_SOURCE_NOT_FOUND', `Continuous focus source was not found: ${relativePath}`);
295
+ }
296
+ return file;
297
+ }
298
+ function selectPlan(result, treeId) {
299
+ if (result.plans.length === 0) {
300
+ throw new ServiceError('FOCUS_TREE_NOT_FOUND', 'The source file contains no focus tree');
301
+ }
302
+ if (treeId === undefined) {
303
+ if (result.plans.length !== 1) {
304
+ throw new ServiceError('FOCUS_TREE_ID_REQUIRED', 'The source file contains multiple focus trees; provide treeId', { treeIds: result.plans.map(({ id }) => id) });
305
+ }
306
+ return result.plans[0];
307
+ }
308
+ const plan = result.plans.find(({ id }) => id === treeId);
309
+ if (plan === undefined) {
310
+ throw new ServiceError('FOCUS_TREE_NOT_FOUND', `Focus tree was not found: ${treeId}`);
311
+ }
312
+ return plan;
313
+ }
314
+ function selectContinuousPlan(result, paletteId) {
315
+ if (result.continuousFocusPalettes.length === 0) {
316
+ throw new ServiceError('CONTINUOUS_FOCUS_PALETTE_NOT_FOUND', 'The source file contains no continuous focus palette');
317
+ }
318
+ if (paletteId === undefined) {
319
+ if (result.continuousFocusPalettes.length !== 1) {
320
+ throw new ServiceError('CONTINUOUS_FOCUS_PALETTE_ID_REQUIRED', 'The source file contains multiple continuous focus palettes; provide paletteId', { paletteIds: result.continuousFocusPalettes.map(({ id }) => id) });
321
+ }
322
+ return result.continuousFocusPalettes[0];
323
+ }
324
+ const plan = result.continuousFocusPalettes.find(({ id }) => id === paletteId);
325
+ if (plan === undefined) {
326
+ throw new ServiceError('CONTINUOUS_FOCUS_PALETTE_NOT_FOUND', `Continuous focus palette was not found: ${paletteId}`);
327
+ }
328
+ return plan;
329
+ }
330
+ function referenceCatalog(snapshot) {
331
+ const identifiers = (kind) => [
332
+ ...new Set(snapshot.index
333
+ .findAll(kind)
334
+ .filter(({ overridden }) => !overridden)
335
+ .map(({ id }) => id)),
336
+ ].sort((left, right) => compareCodeUnits(left, right));
337
+ return {
338
+ decision: identifiers('decision'),
339
+ decision_category: identifiers('decision_category'),
340
+ event: identifiers('event'),
341
+ idea: identifiers('idea'),
342
+ leader: identifiers('leader'),
343
+ formable: identifiers('formable'),
344
+ helper: identifiers('scripted_effect'),
345
+ };
346
+ }
347
+ function validationFromDiagnostics(diagnostics) {
348
+ const blocking = diagnostics.filter(({ severity }) => severity === 'error' || severity === 'blocker');
349
+ return {
350
+ passed: blocking.length === 0,
351
+ checks: [
352
+ {
353
+ id: 'focus-diagnostics',
354
+ passed: blocking.length === 0,
355
+ message: blocking.length === 0
356
+ ? 'Focus source, references, and layout have no blocking diagnostics'
357
+ : `${blocking.length} blocking focus diagnostics`,
358
+ },
359
+ ],
360
+ };
361
+ }
362
+ export function registerFocusTools(server, engine, context) {
363
+ const workbench = new FocusWorkbench(engine.resolver, engine.transactions, engine.artifacts);
364
+ server.registerTool('hoi4.focus_scan', {
365
+ title: 'Scan focus trees',
366
+ description: 'Import active focus-tree source through the shared lossless parser and return compact summaries plus a full resource artifact.',
367
+ inputSchema: z
368
+ .object({
369
+ workspaceId: workspaceIdSchema,
370
+ relativePath: workspaceRelativePathSchema.optional(),
371
+ })
372
+ .strict(),
373
+ outputSchema: focusScanOutputSchema,
374
+ annotations: artifactProducing,
375
+ }, async ({ workspaceId, relativePath }, extra) => {
376
+ try {
377
+ const progress = progressReporter(extra);
378
+ await progress.report(0, 3, 'Building shared workspace index');
379
+ const snapshot = await engine.scan(workspaceId, {}, context.principal, progress.signal);
380
+ const workspace = engine.resolver.get(workspaceId, context.principal);
381
+ const selectedFiles = activeFocusFiles(snapshot, workspace.registration.roots.focus).filter((file) => relativePath === undefined || file.relativePath === relativePath);
382
+ if (selectedFiles.length === 0) {
383
+ throw new ServiceError('FOCUS_SOURCE_NOT_FOUND', 'No active focus source matched the request');
384
+ }
385
+ const selectedSidecarFiles = selectedFiles.flatMap((file) => {
386
+ const resolved = activeSidecar(snapshot, file);
387
+ return resolved === undefined ? [] : [resolved.file];
388
+ });
389
+ const plans = [];
390
+ const diagnostics = [];
391
+ const paletteImport = continuousPalettes(snapshot);
392
+ diagnostics.push(...paletteImport.diagnostics);
393
+ for (const file of selectedFiles) {
394
+ progress.signal.throwIfAborted();
395
+ const imported = importFocusFile(snapshot, file, paletteImport.palettes);
396
+ plans.push(...imported.plans);
397
+ diagnostics.push(...imported.diagnostics);
398
+ }
399
+ const presentation = await resolveFocusPresentation({
400
+ plans,
401
+ palettes: paletteImport.palettes,
402
+ files: snapshot.files,
403
+ index: snapshot.index,
404
+ scanner: engine.scanner,
405
+ workspace,
406
+ signal: progress.signal,
407
+ });
408
+ diagnostics.push(...presentation.diagnostics);
409
+ await progress.report(2, 3, 'Writing imported planning models');
410
+ const completeSourceHashes = Object.fromEntries(Object.entries({
411
+ ...Object.fromEntries([
412
+ ...selectedFiles,
413
+ ...selectedSidecarFiles,
414
+ ...activeContinuousFocusFiles(snapshot),
415
+ ].map(({ displayPath, sha256 }) => [displayPath, sha256])),
416
+ ...presentation.sourceHashes,
417
+ }).sort(([left], [right]) => compareCodeUnits(left, right)));
418
+ const sourceEvidence = boundedSourceHashEvidence(completeSourceHashes);
419
+ const artifact = await engine.artifacts.putChunked(workspace, `focus-scan.${snapshot.revision.slice(0, 16)}.json`, 'application/json', `${canonicalJson({
420
+ schemaVersion: 1,
421
+ revision: snapshot.revision,
422
+ plans,
423
+ continuousFocusPalettes: paletteImport.palettes,
424
+ presentation: focusPresentationEvidence(presentation),
425
+ sourceHashes: completeSourceHashes,
426
+ diagnostics,
427
+ })}\n`, {
428
+ kind: 'focus-scan',
429
+ toolVersion: PACKAGE_VERSION,
430
+ schemaVersion: 'focus-scan.v1',
431
+ sourceHashes: sourceEvidence.sourceHashes,
432
+ metadata: { sourceHashInventory: sourceEvidence.inventory },
433
+ }, 'Imported focus planning models and source-linked diagnostics', progress.signal);
434
+ const result = emptyServiceResult(workspaceId, {
435
+ revision: snapshot.revision,
436
+ treeCount: plans.length,
437
+ trees: plans.slice(0, 100).map((plan) => ({
438
+ id: plan.id,
439
+ sourcePath: plan.provenance.sourcePath,
440
+ focusCount: plan.focuses.length,
441
+ branchCount: plan.branchGroups.length,
442
+ continuousPaletteCount: plan.continuousFocusPaletteIds.length,
443
+ continuousFocusCount: plan.continuousFocusIds.length,
444
+ resolvedTitleCount: plan.focuses.filter(({ id }) => presentation.entries[id]?.titleSourceLocation !== undefined).length,
445
+ })),
446
+ });
447
+ result.code = 'FOCUS_SCANNED';
448
+ setInlineFilesScanned(result, [
449
+ ...new Set([
450
+ ...selectedFiles.map(({ displayPath }) => displayPath),
451
+ ...selectedSidecarFiles.map(({ displayPath }) => displayPath),
452
+ ...activeContinuousFocusFiles(snapshot).map(({ displayPath }) => displayPath),
453
+ ...presentation.filesScanned,
454
+ ]),
455
+ ].sort((left, right) => compareCodeUnits(left, right)));
456
+ result.diagnostics = diagnostics.slice(0, 100);
457
+ result.artifacts = [publicArtifactLink(artifact)];
458
+ result.validation = validationFromDiagnostics(diagnostics);
459
+ await progress.report(3, 3, 'Focus scan complete');
460
+ return toolResult(result);
461
+ }
462
+ catch (error) {
463
+ return errorResult(error, workspaceId);
464
+ }
465
+ });
466
+ server.registerTool('hoi4.focus_lint', {
467
+ title: 'Lint focus source',
468
+ description: 'Lint one national focus tree or continuous focus palette. Omit mode for backward-compatible national behavior.',
469
+ inputSchema: focusLintInput,
470
+ outputSchema: focusLintOutputSchema,
471
+ annotations: artifactProducing,
472
+ }, async (input, extra) => {
473
+ const { workspaceId, relativePath } = input;
474
+ try {
475
+ const progress = progressReporter(extra);
476
+ await progress.report(0, 3, 'Importing and indexing focus source');
477
+ const snapshot = await engine.scan(workspaceId, {}, context.principal, progress.signal);
478
+ const workspace = engine.resolver.get(workspaceId, context.principal);
479
+ if (input.mode === 'continuous') {
480
+ selectedContinuousFocusFile(snapshot, relativePath);
481
+ const imported = await workbench.importContinuousPath(workspaceId, relativePath, context.principal);
482
+ const plan = selectContinuousPlan(imported.result, input.paletteId);
483
+ const diagnostics = [...imported.result.diagnostics, ...workbench.lintContinuous(plan)];
484
+ await progress.report(2, 3, 'Writing continuous focus lint evidence');
485
+ const artifact = await engine.artifacts.put(workspace, `${plan.id.replace(/[^A-Za-z0-9._-]/gu, '_')}.continuous-focus-lint.json`, 'application/json', `${canonicalJson({ schemaVersion: 1, mode: 'continuous', paletteId: plan.id, diagnostics })}\n`, {
486
+ kind: 'continuous-focus-lint',
487
+ toolVersion: PACKAGE_VERSION,
488
+ schemaVersion: 'continuous-focus-lint.v1',
489
+ sourceHashes: { [plan.provenance.sourcePath]: plan.provenance.sourceHash },
490
+ }, 'Complete continuous focus lint report', progress.signal);
491
+ const result = emptyServiceResult(workspaceId, {
492
+ mode: 'continuous',
493
+ paletteId: plan.id,
494
+ focusCount: plan.focuses.length,
495
+ diagnosticCount: diagnostics.length,
496
+ });
497
+ result.code = 'CONTINUOUS_FOCUS_LINTED';
498
+ setInlineFilesScanned(result, [plan.provenance.sourcePath]);
499
+ result.diagnostics = diagnostics.slice(0, 100);
500
+ result.artifacts = [publicArtifactLink(artifact)];
501
+ result.validation = validationFromDiagnostics(diagnostics);
502
+ await progress.report(3, 3, 'Continuous focus lint complete');
503
+ return toolResult(result);
504
+ }
505
+ const paletteImport = continuousPalettes(snapshot);
506
+ const imported = importFocusFile(snapshot, selectedFocusFile(snapshot, workspace.registration.roots.focus, relativePath), paletteImport.palettes);
507
+ const plan = selectPlan(imported, input.treeId);
508
+ const layout = await workbench.layoutAsync(plan, { signal: progress.signal });
509
+ const diagnostics = [
510
+ ...paletteImport.diagnostics,
511
+ ...imported.diagnostics,
512
+ ...workbench.lint(plan, {
513
+ index: snapshot.index,
514
+ references: referenceCatalog(snapshot),
515
+ layout,
516
+ }),
517
+ ];
518
+ await progress.report(2, 3, 'Writing focus lint evidence');
519
+ const artifact = await engine.artifacts.put(workspace, `${plan.id.replace(/[^A-Za-z0-9._-]/gu, '_')}.focus-lint.json`, 'application/json', `${canonicalJson({ schemaVersion: 1, treeId: plan.id, layoutHash: layout.layoutHash, diagnostics })}\n`, {
520
+ kind: 'focus-lint',
521
+ toolVersion: PACKAGE_VERSION,
522
+ schemaVersion: 'focus-lint.v1',
523
+ sourceHashes: { [plan.provenance.sourcePath]: plan.provenance.sourceHash },
524
+ }, 'Complete focus lint report', progress.signal);
525
+ const result = emptyServiceResult(workspaceId, {
526
+ mode: 'national',
527
+ treeId: plan.id,
528
+ focusCount: plan.focuses.length,
529
+ layoutHash: layout.layoutHash,
530
+ diagnosticCount: diagnostics.length,
531
+ });
532
+ result.code = 'FOCUS_LINTED';
533
+ setInlineFilesScanned(result, [plan.provenance.sourcePath]);
534
+ result.diagnostics = diagnostics.slice(0, 100);
535
+ result.artifacts = [publicArtifactLink(artifact)];
536
+ result.validation = validationFromDiagnostics(diagnostics);
537
+ await progress.report(3, 3, 'Focus lint complete');
538
+ return toolResult(result);
539
+ }
540
+ catch (error) {
541
+ return errorResult(error, workspaceId);
542
+ }
543
+ });
544
+ server.registerTool('hoi4.focus_layout', {
545
+ title: 'Plan stable focus layout',
546
+ description: 'Create a deterministic constraint layout while preserving pinned, relative, and previous automatic positions.',
547
+ inputSchema: focusPathInput
548
+ .extend({
549
+ previous: focusLayoutSchema.optional(),
550
+ laneSpacing: z.number().int().min(1).max(100).optional(),
551
+ nodeSpacing: z.number().int().min(1).max(100).optional(),
552
+ })
553
+ .strict(),
554
+ outputSchema: focusLayoutOutputSchema,
555
+ annotations: artifactProducing,
556
+ }, async ({ workspaceId, relativePath, treeId, previous, laneSpacing, nodeSpacing }, extra) => {
557
+ try {
558
+ const progress = progressReporter(extra);
559
+ await progress.report(0, 3, 'Importing and indexing focus source');
560
+ const snapshot = await engine.scan(workspaceId, {}, context.principal, progress.signal);
561
+ const workspace = engine.resolver.get(workspaceId, context.principal);
562
+ const paletteImport = continuousPalettes(snapshot);
563
+ const imported = importFocusFile(snapshot, selectedFocusFile(snapshot, workspace.registration.roots.focus, relativePath), paletteImport.palettes);
564
+ const plan = selectPlan(imported, treeId);
565
+ const layout = await workbench.layoutAsync(plan, {
566
+ ...(previous === undefined ? {} : { previous: previous }),
567
+ ...(laneSpacing === undefined ? {} : { laneSpacing }),
568
+ ...(nodeSpacing === undefined ? {} : { nodeSpacing }),
569
+ signal: progress.signal,
570
+ });
571
+ progress.signal.throwIfAborted();
572
+ await progress.report(2, 3, 'Writing stable focus layout evidence');
573
+ const artifact = await engine.artifacts.put(workspace, `${plan.id.replace(/[^A-Za-z0-9._-]/gu, '_')}.focus-layout.json`, 'application/json', `${canonicalJson(layout)}\n`, {
574
+ kind: 'focus-layout',
575
+ toolVersion: PACKAGE_VERSION,
576
+ schemaVersion: 'focus-layout.v1',
577
+ sourceHashes: { [plan.provenance.sourcePath]: plan.provenance.sourceHash },
578
+ }, 'Stable focus layout decisions and diagnostics', progress.signal);
579
+ const diagnostics = [
580
+ ...paletteImport.diagnostics,
581
+ ...imported.diagnostics,
582
+ ...layout.diagnostics,
583
+ ];
584
+ const result = emptyServiceResult(workspaceId, {
585
+ treeId: plan.id,
586
+ layoutHash: layout.layoutHash,
587
+ nodeCount: layout.nodes.length,
588
+ decisions: layout.decisions.slice(0, 100),
589
+ });
590
+ result.code = 'FOCUS_LAYOUT_PLANNED';
591
+ setInlineFilesScanned(result, [plan.provenance.sourcePath]);
592
+ result.diagnostics = diagnostics.slice(0, 100);
593
+ result.artifacts = [publicArtifactLink(artifact)];
594
+ result.validation = validationFromDiagnostics(diagnostics);
595
+ await progress.report(3, 3, 'Focus layout complete');
596
+ return toolResult(result);
597
+ }
598
+ catch (error) {
599
+ return errorResult(error, workspaceId);
600
+ }
601
+ });
602
+ server.registerTool('hoi4.focus_render', {
603
+ title: 'Render focus review artifacts',
604
+ description: 'Generate deterministic HTML, SVG, genuine PNG, JSON, and source-map artifacts for a national tree or continuous palette. Omit mode for national behavior.',
605
+ inputSchema: focusRenderInput,
606
+ outputSchema: focusRenderOutputSchema,
607
+ annotations: artifactProducing,
608
+ }, async (input, extra) => {
609
+ const { workspaceId, relativePath } = input;
610
+ try {
611
+ const progress = progressReporter(extra);
612
+ await progress.report(0, 3, 'Importing and indexing focus source');
613
+ const snapshot = await engine.scan(workspaceId, {}, context.principal, progress.signal);
614
+ const workspace = engine.resolver.get(workspaceId, context.principal);
615
+ const renderBudget = new RenderBudget();
616
+ if (input.mode === 'continuous') {
617
+ selectedContinuousFocusFile(snapshot, relativePath);
618
+ const imported = await workbench.importContinuousPath(workspaceId, relativePath, context.principal);
619
+ const plan = selectContinuousPlan(imported.result, input.paletteId);
620
+ const presentation = await resolveFocusPresentation({
621
+ plans: [],
622
+ palettes: [plan],
623
+ files: snapshot.files,
624
+ index: snapshot.index,
625
+ scanner: engine.scanner,
626
+ workspace,
627
+ budget: renderBudget,
628
+ signal: progress.signal,
629
+ });
630
+ await progress.report(1, 3, 'Rendering continuous focus artifacts');
631
+ const rendered = await workbench.renderContinuousAndStore(workspaceId, plan, {
632
+ ...(context.principal === undefined ? {} : { principal: context.principal }),
633
+ presentation,
634
+ sourceHashes: presentation.sourceHashes,
635
+ ...(input.columns === undefined ? {} : { columns: input.columns }),
636
+ ...(input.padding === undefined ? {} : { padding: input.padding }),
637
+ renderProfile: { sourceRevision: snapshot.revision },
638
+ budget: renderBudget,
639
+ signal: progress.signal,
640
+ });
641
+ const diagnostics = [...imported.result.diagnostics, ...rendered.diagnostics];
642
+ const result = emptyServiceResult(workspaceId, {
643
+ mode: 'continuous',
644
+ paletteId: plan.id,
645
+ focusCount: plan.focuses.length,
646
+ hashes: rendered.bundle.hashes,
647
+ width: rendered.bundle.width,
648
+ height: rendered.bundle.height,
649
+ });
650
+ result.code = 'CONTINUOUS_FOCUS_RENDERED';
651
+ setInlineFilesScanned(result, [...new Set([plan.provenance.sourcePath, ...presentation.filesScanned])].sort((left, right) => compareCodeUnits(left, right)));
652
+ result.diagnostics = diagnostics.slice(0, 100);
653
+ result.artifacts = rendered.artifacts.map(publicArtifactLink);
654
+ result.validation = validationFromDiagnostics(diagnostics);
655
+ await progress.report(3, 3, 'Continuous focus render complete');
656
+ return toolResult(result);
657
+ }
658
+ const paletteImport = continuousPalettes(snapshot);
659
+ const imported = importFocusFile(snapshot, selectedFocusFile(snapshot, workspace.registration.roots.focus, relativePath), paletteImport.palettes);
660
+ const plan = selectPlan(imported, input.treeId);
661
+ const linkedPalettes = paletteImport.palettes.filter(({ id }) => plan.continuousFocusPaletteIds.includes(id));
662
+ const presentation = await resolveFocusPresentation({
663
+ plans: [plan],
664
+ palettes: linkedPalettes,
665
+ files: snapshot.files,
666
+ index: snapshot.index,
667
+ scanner: engine.scanner,
668
+ workspace,
669
+ budget: renderBudget,
670
+ signal: progress.signal,
671
+ });
672
+ await progress.report(1, 3, 'Rendering focus artifacts');
673
+ const rendered = await workbench.renderAndStore(workspaceId, plan, {
674
+ ...(context.principal === undefined ? {} : { principal: context.principal }),
675
+ index: snapshot.index,
676
+ references: referenceCatalog(snapshot),
677
+ presentation,
678
+ sourceHashes: presentation.sourceHashes,
679
+ ...(input.horizontalSpacing === undefined
680
+ ? {}
681
+ : { horizontalSpacing: input.horizontalSpacing }),
682
+ ...(input.verticalSpacing === undefined
683
+ ? {}
684
+ : { verticalSpacing: input.verticalSpacing }),
685
+ ...(input.padding === undefined ? {} : { padding: input.padding }),
686
+ renderProfile: { sourceRevision: snapshot.revision },
687
+ budget: renderBudget,
688
+ signal: progress.signal,
689
+ });
690
+ const diagnostics = [
691
+ ...paletteImport.diagnostics,
692
+ ...imported.diagnostics,
693
+ ...rendered.diagnostics,
694
+ ];
695
+ const result = emptyServiceResult(workspaceId, {
696
+ mode: 'national',
697
+ treeId: plan.id,
698
+ layoutHash: rendered.layout.layoutHash,
699
+ hashes: rendered.bundle.hashes,
700
+ width: rendered.bundle.width,
701
+ height: rendered.bundle.height,
702
+ });
703
+ result.code = 'FOCUS_RENDERED';
704
+ setInlineFilesScanned(result, [...new Set([plan.provenance.sourcePath, ...presentation.filesScanned])].sort((left, right) => compareCodeUnits(left, right)));
705
+ result.diagnostics = diagnostics.slice(0, 100);
706
+ result.artifacts = rendered.artifacts.map(publicArtifactLink);
707
+ result.validation = validationFromDiagnostics(diagnostics);
708
+ await progress.report(3, 3, 'Focus render complete');
709
+ return toolResult(result);
710
+ }
711
+ catch (error) {
712
+ return errorResult(error, workspaceId);
713
+ }
714
+ });
715
+ server.registerTool('hoi4.focus_plan_changes', {
716
+ title: 'Dry-run focus source changes',
717
+ description: 'Compile a validated national tree or continuous palette plan into source and create a hash-bound dry-run transaction; never applies it. Omit mode for national behavior.',
718
+ inputSchema: focusPlanInput,
719
+ outputSchema: focusPlanOutputSchema,
720
+ annotations: {
721
+ readOnlyHint: false,
722
+ destructiveHint: false,
723
+ idempotentHint: false,
724
+ openWorldHint: false,
725
+ },
726
+ }, async (input, extra) => {
727
+ const { workspaceId, relativePath, authority, createIfMissing } = input;
728
+ try {
729
+ requireServerScope(context, 'hoi4:write');
730
+ const progress = progressReporter(extra);
731
+ await progress.report(0, 5, 'Validating shared index and source authority');
732
+ const snapshot = await engine.scan(workspaceId, {}, context.principal, progress.signal);
733
+ const workspace = engine.resolver.get(workspaceId, context.principal);
734
+ if (input.mode === 'continuous') {
735
+ const plan = input.plan;
736
+ if (createIfMissing &&
737
+ (!relativePath.toLowerCase().endsWith('.txt') ||
738
+ !underConfiguredRoot(relativePath, ['common/continuous_focus'])))
739
+ throw new ServiceError('CONTINUOUS_FOCUS_SOURCE_PATH_INVALID', 'New continuous focus sources must be .txt files beneath common/continuous_focus', { relativePath });
740
+ const sourceFile = activeContinuousFocusFiles(snapshot).find((candidate) => candidate.relativePath === relativePath);
741
+ if (sourceFile === undefined && !createIfMissing)
742
+ selectedContinuousFocusFile(snapshot, relativePath);
743
+ if (sourceFile !== undefined && sourceFile.rootKind !== 'mod')
744
+ throw new ServiceError('CONTINUOUS_FOCUS_SOURCE_READ_ONLY', 'Continuous focus changes require a mod-owned source; create a new mod source path instead of shadowing a read-only file', { relativePath, rootKind: sourceFile.rootKind });
745
+ const imported = sourceFile === undefined
746
+ ? undefined
747
+ : await workbench.importContinuousPath(workspaceId, relativePath, context.principal);
748
+ const currentPlan = imported?.result.continuousFocusPalettes.find(({ id }) => id === plan.id);
749
+ if (currentPlan === undefined && !createIfMissing) {
750
+ if (imported === undefined)
751
+ selectedContinuousFocusFile(snapshot, relativePath);
752
+ else
753
+ selectContinuousPlan(imported.result, plan.id);
754
+ }
755
+ if (currentPlan === undefined && createIfMissing && sourceFile !== undefined)
756
+ throw new ServiceError('CONTINUOUS_FOCUS_CREATE_REQUIRES_NEW_SOURCE', 'Creating a continuous-focus palette requires a new mod source file so unrelated existing source is never repurposed', { relativePath, paletteId: plan.id });
757
+ if (currentPlan !== undefined && imported !== undefined)
758
+ assertFocusPlanAuthority(detectContinuousFocusDrift(plan, imported.document), authority);
759
+ const renderBudget = new RenderBudget();
760
+ const presentation = await resolveFocusPresentation({
761
+ plans: [],
762
+ palettes: [...(currentPlan === undefined ? [] : [currentPlan]), plan],
763
+ files: snapshot.files,
764
+ index: snapshot.index,
765
+ scanner: engine.scanner,
766
+ workspace,
767
+ budget: renderBudget,
768
+ signal: progress.signal,
769
+ });
770
+ const currentDiagnostics = currentPlan === undefined
771
+ ? []
772
+ : [...(imported?.result.diagnostics ?? []), ...workbench.lintContinuous(currentPlan)];
773
+ await progress.report(1, 5, 'Rendering before and proposed continuous focus plans');
774
+ const currentRender = currentPlan === undefined
775
+ ? undefined
776
+ : await renderContinuousFocusPalette(currentPlan, currentDiagnostics, {
777
+ presentation,
778
+ signal: progress.signal,
779
+ budget: renderBudget,
780
+ });
781
+ const proposedPlanHash = focusPlanHash(plan);
782
+ const reviewPlan = {
783
+ ...plan,
784
+ provenance: {
785
+ sourcePath: `plan:${plan.id}`,
786
+ sourceHash: proposedPlanHash,
787
+ importedPlanHash: proposedPlanHash,
788
+ },
789
+ };
790
+ const proposed = await workbench.renderContinuousAndStore(workspaceId, reviewPlan, {
791
+ ...(context.principal === undefined ? {} : { principal: context.principal }),
792
+ presentation,
793
+ sourceHashes: presentation.sourceHashes,
794
+ renderProfile: { sourceRevision: snapshot.revision, proposedPlanHash },
795
+ budget: renderBudget,
796
+ signal: progress.signal,
797
+ });
798
+ const beforePng = currentRender?.png ??
799
+ (await createTransparentPng(proposed.bundle.width, proposed.bundle.height, 'new continuous focus baseline', renderBudget));
800
+ const comparison = await comparePngImages(beforePng, proposed.bundle.png, 8, progress.signal, renderBudget);
801
+ const stem = plan.id.replace(/[^A-Za-z0-9._-]/gu, '_').slice(0, 80) || 'continuous';
802
+ const provenance = {
803
+ toolVersion: PACKAGE_VERSION,
804
+ schemaVersion: 'continuous-focus-visual-diff.v1',
805
+ sourceHashes: {
806
+ before: sourceFile?.sha256 ?? sha256Bytes(Buffer.alloc(0)),
807
+ proposedPlan: proposedPlanHash,
808
+ },
809
+ renderProfile: { offline: true, kind: 'continuous-focus-palette' },
810
+ };
811
+ const comparisonArtifacts = await engine.artifacts.withAtomicWrites(workspace, [
812
+ {
813
+ name: `${stem}.continuous-focus-before.png`,
814
+ mimeType: 'image/png',
815
+ content: beforePng,
816
+ provenance: { ...provenance, kind: 'continuous-focus-before-render' },
817
+ },
818
+ {
819
+ name: `${stem}.continuous-focus-visual-diff.png`,
820
+ mimeType: 'image/png',
821
+ content: comparison.png,
822
+ provenance: { ...provenance, kind: 'continuous-focus-visual-diff' },
823
+ },
824
+ {
825
+ name: `${stem}.continuous-focus-visual-diff.json`,
826
+ mimeType: 'application/json',
827
+ content: comparison.json,
828
+ provenance: { ...provenance, kind: 'continuous-focus-visual-diff-json' },
829
+ },
830
+ ], (stored) => Promise.resolve([...stored]), progress.signal);
831
+ const reviewArtifacts = [
832
+ ...proposed.artifacts.map(publicArtifactLink),
833
+ ...comparisonArtifacts.map(publicArtifactLink),
834
+ ];
835
+ await progress.report(3, 5, 'Creating hash-bound continuous focus transaction');
836
+ const planned = await workbench.planContinuousChanges({
837
+ workspaceId,
838
+ relativePath,
839
+ plan,
840
+ createIfMissing,
841
+ ...(authority === undefined ? {} : { authority }),
842
+ ...(context.principal === undefined ? {} : { principal: context.principal }),
843
+ artifacts: reviewArtifacts,
844
+ readDependencies: readDependenciesFromScannedFiles(snapshot.files),
845
+ signal: progress.signal,
846
+ });
847
+ const transaction = planned.transaction;
848
+ const result = emptyServiceResult(workspaceId, {
849
+ mode: 'continuous',
850
+ paletteId: plan.id,
851
+ drift: compactDrift(planned.drift),
852
+ created: planned.drift.status === 'target_missing',
853
+ expiresAt: transaction.expiresAt,
854
+ transactionFileCount: transaction.files.length,
855
+ transactionArtifactCount: transaction.artifacts.length,
856
+ });
857
+ result.status = transaction.validation.passed ? 'ok' : 'blocked';
858
+ result.code = transaction.validation.passed
859
+ ? 'CONTINUOUS_FOCUS_CHANGES_PLANNED'
860
+ : 'CONTINUOUS_FOCUS_CHANGES_BLOCKED';
861
+ setInlineFilesScanned(result, [
862
+ ...new Set([
863
+ ...(sourceFile === undefined ? [] : [sourceFile.displayPath]),
864
+ ...presentation.filesScanned,
865
+ ]),
866
+ ].sort((left, right) => compareCodeUnits(left, right)));
867
+ result.proposedFiles = transaction.files
868
+ .slice(0, 100)
869
+ .map(({ relativePath: file }) => file);
870
+ result.diagnostics = transaction.diagnostics.slice(0, 100);
871
+ result.transactionId = transaction.transactionId;
872
+ result.planHash = transaction.planHash;
873
+ result.artifacts = [transactionResourceLink(transaction)];
874
+ result.validation = transaction.validation;
875
+ result.rollbackStatus = transaction.rollbackStatus;
876
+ result.blockers = transaction.diagnostics
877
+ .filter(({ severity }) => severity === 'error' || severity === 'blocker')
878
+ .map(({ code, message, details }) => ({
879
+ code,
880
+ message,
881
+ ...(details === undefined ? {} : { details }),
882
+ }));
883
+ await progress.report(5, 5, 'Continuous focus dry run complete');
884
+ return toolResult(result);
885
+ }
886
+ const plan = input.plan;
887
+ if (createIfMissing &&
888
+ (!relativePath.toLowerCase().endsWith('.txt') ||
889
+ !underConfiguredRoot(relativePath, workspace.registration.roots.focus)))
890
+ throw new ServiceError('FOCUS_SOURCE_PATH_INVALID', 'New national focus sources must be .txt files beneath a configured focus root', { relativePath });
891
+ const focusFile = activeFocusFiles(snapshot, workspace.registration.roots.focus).find((candidate) => candidate.relativePath === relativePath);
892
+ if (focusFile === undefined && !createIfMissing)
893
+ selectedFocusFile(snapshot, workspace.registration.roots.focus, relativePath);
894
+ if (focusFile !== undefined && focusFile.rootKind !== 'mod')
895
+ throw new ServiceError('FOCUS_SOURCE_READ_ONLY', 'National focus changes require a mod-owned source; create a new mod source path instead of shadowing a read-only file', { relativePath, rootKind: focusFile.rootKind });
896
+ const sidecar = focusFile === undefined ? undefined : activeSidecar(snapshot, focusFile);
897
+ const catalog = referenceCatalog(snapshot);
898
+ const imported = focusFile === undefined
899
+ ? undefined
900
+ : await workbench.importPath(workspaceId, relativePath, context.principal, sidecar?.sidecar, catalog);
901
+ const paletteImport = continuousPalettes(snapshot);
902
+ if (imported !== undefined)
903
+ imported.result.plans = imported.result.plans.map((current) => linkContinuousFocusPalettes(current, paletteImport.palettes));
904
+ const currentPlan = imported?.result.plans.find(({ id }) => id === plan.id);
905
+ if (currentPlan === undefined && !createIfMissing) {
906
+ if (imported === undefined)
907
+ selectedFocusFile(snapshot, workspace.registration.roots.focus, relativePath);
908
+ else
909
+ selectPlan(imported.result, plan.id);
910
+ }
911
+ if (currentPlan === undefined && createIfMissing && focusFile !== undefined)
912
+ throw new ServiceError('FOCUS_CREATE_REQUIRES_NEW_SOURCE', 'Creating a national focus tree requires a new mod source file so an existing source and its planning sidecar cannot be repurposed', { relativePath, treeId: plan.id });
913
+ if (currentPlan !== undefined && imported !== undefined)
914
+ assertFocusPlanAuthority(detectFocusDrift(plan, imported.document, catalog), authority);
915
+ const renderBudget = new RenderBudget();
916
+ const presentation = await resolveFocusPresentation({
917
+ plans: [...(currentPlan === undefined ? [] : [currentPlan]), plan],
918
+ palettes: paletteImport.palettes.filter(({ id }) => plan.continuousFocusPaletteIds.includes(id)),
919
+ files: snapshot.files,
920
+ index: snapshot.index,
921
+ scanner: engine.scanner,
922
+ workspace,
923
+ budget: renderBudget,
924
+ signal: progress.signal,
925
+ });
926
+ const currentLayout = currentPlan === undefined
927
+ ? undefined
928
+ : await workbench.layoutAsync(currentPlan, { signal: progress.signal });
929
+ const currentDiagnostics = currentPlan === undefined || currentLayout === undefined
930
+ ? []
931
+ : workbench.lint(currentPlan, {
932
+ index: snapshot.index,
933
+ references: catalog,
934
+ layout: currentLayout,
935
+ });
936
+ await progress.report(1, 5, 'Rendering before and proposed focus plans');
937
+ const currentRender = currentPlan === undefined || currentLayout === undefined
938
+ ? undefined
939
+ : await renderFocusTree(currentPlan, currentLayout, currentDiagnostics, {
940
+ presentation,
941
+ signal: progress.signal,
942
+ budget: renderBudget,
943
+ });
944
+ const proposedPlanHash = focusPlanHash(plan);
945
+ const reviewPlan = {
946
+ ...plan,
947
+ provenance: {
948
+ sourcePath: `plan:${plan.id}`,
949
+ sourceHash: proposedPlanHash,
950
+ importedPlanHash: proposedPlanHash,
951
+ },
952
+ };
953
+ const proposed = await workbench.renderAndStore(workspaceId, reviewPlan, {
954
+ ...(context.principal === undefined ? {} : { principal: context.principal }),
955
+ index: snapshot.index,
956
+ references: catalog,
957
+ presentation,
958
+ sourceHashes: presentation.sourceHashes,
959
+ renderProfile: { sourceRevision: snapshot.revision, proposedPlanHash },
960
+ budget: renderBudget,
961
+ signal: progress.signal,
962
+ });
963
+ const beforePng = currentRender?.png ??
964
+ (await createTransparentPng(proposed.bundle.width, proposed.bundle.height, 'new national focus baseline', renderBudget));
965
+ const comparison = await comparePngImages(beforePng, proposed.bundle.png, 8, progress.signal, renderBudget);
966
+ const stem = plan.id.replace(/[^A-Za-z0-9._-]/gu, '_').slice(0, 80) || 'focus-tree';
967
+ const provenance = {
968
+ toolVersion: PACKAGE_VERSION,
969
+ schemaVersion: 'focus-visual-diff.v1',
970
+ sourceHashes: {
971
+ before: focusFile?.sha256 ?? sha256Bytes(Buffer.alloc(0)),
972
+ proposedPlan: proposedPlanHash,
973
+ },
974
+ renderProfile: { offline: true, layoutHash: proposed.layout.layoutHash },
975
+ };
976
+ const comparisonArtifacts = await engine.artifacts.withAtomicWrites(workspace, [
977
+ {
978
+ name: `${stem}.focus-before.png`,
979
+ mimeType: 'image/png',
980
+ content: beforePng,
981
+ provenance: { ...provenance, kind: 'focus-before-render' },
982
+ },
983
+ {
984
+ name: `${stem}.focus-visual-diff.png`,
985
+ mimeType: 'image/png',
986
+ content: comparison.png,
987
+ provenance: { ...provenance, kind: 'focus-visual-diff' },
988
+ },
989
+ {
990
+ name: `${stem}.focus-visual-diff.json`,
991
+ mimeType: 'application/json',
992
+ content: comparison.json,
993
+ provenance: { ...provenance, kind: 'focus-visual-diff-json' },
994
+ },
995
+ ], (stored) => Promise.resolve([...stored]), progress.signal);
996
+ const reviewArtifacts = [
997
+ ...proposed.artifacts.map(publicArtifactLink),
998
+ ...comparisonArtifacts.map(publicArtifactLink),
999
+ ];
1000
+ await progress.report(3, 5, 'Creating hash-bound focus transaction');
1001
+ const planned = await workbench.planChanges({
1002
+ workspaceId,
1003
+ relativePath,
1004
+ plan,
1005
+ createIfMissing,
1006
+ ...(authority === undefined ? {} : { authority }),
1007
+ ...(context.principal === undefined ? {} : { principal: context.principal }),
1008
+ index: snapshot.index,
1009
+ references: catalog,
1010
+ artifacts: reviewArtifacts,
1011
+ readDependencies: readDependenciesFromScannedFiles(snapshot.files),
1012
+ signal: progress.signal,
1013
+ });
1014
+ const transaction = planned.transaction;
1015
+ const result = emptyServiceResult(workspaceId, {
1016
+ mode: 'national',
1017
+ treeId: plan.id,
1018
+ drift: compactDrift(planned.drift),
1019
+ created: planned.drift.status === 'target_missing',
1020
+ layoutHash: planned.layout.layoutHash,
1021
+ expiresAt: transaction.expiresAt,
1022
+ transactionFileCount: transaction.files.length,
1023
+ transactionArtifactCount: transaction.artifacts.length,
1024
+ });
1025
+ result.status = transaction.validation.passed ? 'ok' : 'blocked';
1026
+ result.code = transaction.validation.passed
1027
+ ? 'FOCUS_CHANGES_PLANNED'
1028
+ : 'FOCUS_CHANGES_BLOCKED';
1029
+ setInlineFilesScanned(result, [
1030
+ ...new Set([
1031
+ ...(focusFile === undefined ? [] : [focusFile.displayPath]),
1032
+ ...presentation.filesScanned,
1033
+ ]),
1034
+ ].sort((left, right) => compareCodeUnits(left, right)));
1035
+ result.proposedFiles = transaction.files
1036
+ .slice(0, 100)
1037
+ .map(({ relativePath: file }) => file);
1038
+ result.diagnostics = transaction.diagnostics.slice(0, 100);
1039
+ result.transactionId = transaction.transactionId;
1040
+ result.planHash = transaction.planHash;
1041
+ result.artifacts = [transactionResourceLink(transaction)];
1042
+ result.validation = transaction.validation;
1043
+ result.rollbackStatus = transaction.rollbackStatus;
1044
+ result.blockers = transaction.diagnostics
1045
+ .filter(({ severity }) => severity === 'error' || severity === 'blocker')
1046
+ .map(({ code, message, details }) => ({
1047
+ code,
1048
+ message,
1049
+ ...(details === undefined ? {} : { details }),
1050
+ }));
1051
+ await progress.report(5, 5, 'Focus dry run complete');
1052
+ return toolResult(result);
1053
+ }
1054
+ catch (error) {
1055
+ return errorResult(error, workspaceId);
1056
+ }
1057
+ });
1058
+ }
1059
+ //# sourceMappingURL=focus.js.map