@overcrow/mcp 0.0.0-stage → 0.1.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 (461) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +90 -2
  3. package/dist/audit/index.js +103 -0
  4. package/dist/audit/lexer.js +417 -0
  5. package/dist/audit/project.js +200 -0
  6. package/dist/audit/rules.js +661 -0
  7. package/dist/bootstrap/download.js +229 -0
  8. package/dist/bootstrap/install.js +280 -0
  9. package/dist/bootstrap/pin.js +85 -0
  10. package/dist/bootstrap/pin.json +119 -0
  11. package/dist/bootstrap/zip.js +258 -0
  12. package/dist/cli.js +200 -0
  13. package/dist/confine.js +244 -0
  14. package/dist/content/docs/en/cli.md +353 -0
  15. package/dist/content/docs/en/dev-channel.md +130 -0
  16. package/dist/content/docs/en/elements.md +469 -0
  17. package/dist/content/docs/en/forms.md +328 -0
  18. package/dist/content/docs/en/guide.md +253 -0
  19. package/dist/content/docs/en/index.md +85 -0
  20. package/dist/content/docs/en/limits.md +241 -0
  21. package/dist/content/docs/en/logic.md +446 -0
  22. package/dist/content/docs/en/manifest.md +381 -0
  23. package/dist/content/docs/en/mcp.md +165 -0
  24. package/dist/content/docs/en/package.md +131 -0
  25. package/dist/content/docs/en/publishing.md +162 -0
  26. package/dist/content/docs/en/reference.md +55 -0
  27. package/dist/content/docs/en/result-shapes.md +332 -0
  28. package/dist/content/docs/en/sdk.md +295 -0
  29. package/dist/content/docs/en/security.md +115 -0
  30. package/dist/content/docs/en/service-reference.md +344 -0
  31. package/dist/content/docs/en/services.md +517 -0
  32. package/dist/content/docs/en/style-properties.md +270 -0
  33. package/dist/content/docs/en/style.md +266 -0
  34. package/dist/content/docs/en/testing.md +400 -0
  35. package/dist/content/docs/en/view.md +338 -0
  36. package/dist/content/docs/en/widgets.md +76 -0
  37. package/dist/content/docs/fr/cli.md +367 -0
  38. package/dist/content/docs/fr/dev-channel.md +140 -0
  39. package/dist/content/docs/fr/elements.md +475 -0
  40. package/dist/content/docs/fr/forms.md +341 -0
  41. package/dist/content/docs/fr/guide.md +264 -0
  42. package/dist/content/docs/fr/index.md +90 -0
  43. package/dist/content/docs/fr/limits.md +244 -0
  44. package/dist/content/docs/fr/logic.md +461 -0
  45. package/dist/content/docs/fr/manifest.md +392 -0
  46. package/dist/content/docs/fr/mcp.md +173 -0
  47. package/dist/content/docs/fr/package.md +139 -0
  48. package/dist/content/docs/fr/publishing.md +172 -0
  49. package/dist/content/docs/fr/reference.md +59 -0
  50. package/dist/content/docs/fr/result-shapes.md +333 -0
  51. package/dist/content/docs/fr/sdk.md +301 -0
  52. package/dist/content/docs/fr/security.md +129 -0
  53. package/dist/content/docs/fr/service-reference.md +346 -0
  54. package/dist/content/docs/fr/services.md +540 -0
  55. package/dist/content/docs/fr/style-properties.md +272 -0
  56. package/dist/content/docs/fr/style.md +281 -0
  57. package/dist/content/docs/fr/testing.md +417 -0
  58. package/dist/content/docs/fr/view.md +352 -0
  59. package/dist/content/docs/fr/widgets.md +81 -0
  60. package/dist/content/examples/clock/LICENSE +21 -0
  61. package/dist/content/examples/clock/README.md +75 -0
  62. package/dist/content/examples/clock/listing.json +19 -0
  63. package/dist/content/examples/clock/locales/en.json +4 -0
  64. package/dist/content/examples/clock/locales/fr.json +4 -0
  65. package/dist/content/examples/clock/logic.ts +85 -0
  66. package/dist/content/examples/clock/manifest.json +44 -0
  67. package/dist/content/examples/clock/package.json +16 -0
  68. package/dist/content/examples/clock/style.ocss +26 -0
  69. package/dist/content/examples/clock/tests/hidden.scenario.json +68 -0
  70. package/dist/content/examples/clock/tests/load-logic.mjs +22 -0
  71. package/dist/content/examples/clock/tests/logic.test.mjs +89 -0
  72. package/dist/content/examples/clock/tests/options.scenario.json +108 -0
  73. package/dist/content/examples/clock/tests/preview.scenario.json +25 -0
  74. package/dist/content/examples/clock/tests/render.scenario.json +94 -0
  75. package/dist/content/examples/clock/tests/summer-time.scenario.json +74 -0
  76. package/dist/content/examples/clock/tests/ticks.scenario.json +120 -0
  77. package/dist/content/examples/clock/tsconfig.json +16 -0
  78. package/dist/content/examples/clock/view.ocml +8 -0
  79. package/dist/content/examples/countdown/LICENSE +20 -0
  80. package/dist/content/examples/countdown/listing.json +10 -0
  81. package/dist/content/examples/countdown/locales/en.json +15 -0
  82. package/dist/content/examples/countdown/locales/fr.json +15 -0
  83. package/dist/content/examples/countdown/logic.ts +179 -0
  84. package/dist/content/examples/countdown/manifest.json +34 -0
  85. package/dist/content/examples/countdown/package.json +15 -0
  86. package/dist/content/examples/countdown/style.ocss +94 -0
  87. package/dist/content/examples/countdown/tsconfig.json +16 -0
  88. package/dist/content/examples/countdown/view.ocml +42 -0
  89. package/dist/content/examples/fps/LICENSE +21 -0
  90. package/dist/content/examples/fps/README.md +64 -0
  91. package/dist/content/examples/fps/listing.json +19 -0
  92. package/dist/content/examples/fps/locales/en.json +11 -0
  93. package/dist/content/examples/fps/locales/fr.json +11 -0
  94. package/dist/content/examples/fps/logic.ts +64 -0
  95. package/dist/content/examples/fps/manifest.json +30 -0
  96. package/dist/content/examples/fps/package.json +16 -0
  97. package/dist/content/examples/fps/style.ocss +31 -0
  98. package/dist/content/examples/fps/tests/label.scenario.json +63 -0
  99. package/dist/content/examples/fps/tests/load-logic.mjs +22 -0
  100. package/dist/content/examples/fps/tests/logic.test.mjs +60 -0
  101. package/dist/content/examples/fps/tests/preview.scenario.json +29 -0
  102. package/dist/content/examples/fps/tests/refused.scenario.json +20 -0
  103. package/dist/content/examples/fps/tests/render.scenario.json +96 -0
  104. package/dist/content/examples/fps/tests/stale.scenario.json +91 -0
  105. package/dist/content/examples/fps/tests/unavailable.scenario.json +111 -0
  106. package/dist/content/examples/fps/tsconfig.json +16 -0
  107. package/dist/content/examples/fps/view.ocml +11 -0
  108. package/dist/content/examples/media/LICENSE +21 -0
  109. package/dist/content/examples/media/README.md +147 -0
  110. package/dist/content/examples/media/listing.json +19 -0
  111. package/dist/content/examples/media/locales/en.json +11 -0
  112. package/dist/content/examples/media/locales/fr.json +11 -0
  113. package/dist/content/examples/media/logic.ts +191 -0
  114. package/dist/content/examples/media/manifest.json +35 -0
  115. package/dist/content/examples/media/package.json +16 -0
  116. package/dist/content/examples/media/style.ocss +148 -0
  117. package/dist/content/examples/media/tests/covers.scenario.json +144 -0
  118. package/dist/content/examples/media/tests/gesture.scenario.json +173 -0
  119. package/dist/content/examples/media/tests/load-logic.mjs +22 -0
  120. package/dist/content/examples/media/tests/logic.test.mjs +176 -0
  121. package/dist/content/examples/media/tests/marquee.scenario.json +127 -0
  122. package/dist/content/examples/media/tests/preview.scenario.json +52 -0
  123. package/dist/content/examples/media/tests/read-only.scenario.json +53 -0
  124. package/dist/content/examples/media/tests/refused.scenario.json +22 -0
  125. package/dist/content/examples/media/tests/refused.test.mjs +31 -0
  126. package/dist/content/examples/media/tests/render.scenario.json +136 -0
  127. package/dist/content/examples/media/tests/states.scenario.json +257 -0
  128. package/dist/content/examples/media/tests/unavailable.scenario.json +120 -0
  129. package/dist/content/examples/media/tsconfig.json +16 -0
  130. package/dist/content/examples/media/view.ocml +41 -0
  131. package/dist/content/examples/notes/LICENSE +21 -0
  132. package/dist/content/examples/notes/README.md +219 -0
  133. package/dist/content/examples/notes/listing.json +19 -0
  134. package/dist/content/examples/notes/locales/en.json +25 -0
  135. package/dist/content/examples/notes/locales/fr.json +25 -0
  136. package/dist/content/examples/notes/logic.ts +799 -0
  137. package/dist/content/examples/notes/manifest.json +40 -0
  138. package/dist/content/examples/notes/package.json +16 -0
  139. package/dist/content/examples/notes/style.ocss +469 -0
  140. package/dist/content/examples/notes/tests/checks.scenario.json +237 -0
  141. package/dist/content/examples/notes/tests/create.scenario.json +260 -0
  142. package/dist/content/examples/notes/tests/delete.scenario.json +342 -0
  143. package/dist/content/examples/notes/tests/drafts.scenario.json +714 -0
  144. package/dist/content/examples/notes/tests/editor.scenario.json +232 -0
  145. package/dist/content/examples/notes/tests/frame.scenario.json +93 -0
  146. package/dist/content/examples/notes/tests/interactive.scenario.json +344 -0
  147. package/dist/content/examples/notes/tests/limits.scenario.json +1351 -0
  148. package/dist/content/examples/notes/tests/load-logic.mjs +22 -0
  149. package/dist/content/examples/notes/tests/logic.test.mjs +514 -0
  150. package/dist/content/examples/notes/tests/preview.scenario.json +99 -0
  151. package/dist/content/examples/notes/tests/read-only.scenario.json +105 -0
  152. package/dist/content/examples/notes/tests/refused.scenario.json +33 -0
  153. package/dist/content/examples/notes/tests/save.scenario.json +378 -0
  154. package/dist/content/examples/notes/tests/states.scenario.json +640 -0
  155. package/dist/content/examples/notes/tests/typing.scenario.json +562 -0
  156. package/dist/content/examples/notes/tests/unavailable.scenario.json +246 -0
  157. package/dist/content/examples/notes/tsconfig.json +16 -0
  158. package/dist/content/examples/notes/view.ocml +154 -0
  159. package/dist/content/examples/performance/LICENSE +21 -0
  160. package/dist/content/examples/performance/README.md +134 -0
  161. package/dist/content/examples/performance/listing.json +19 -0
  162. package/dist/content/examples/performance/locales/en.json +20 -0
  163. package/dist/content/examples/performance/locales/fr.json +20 -0
  164. package/dist/content/examples/performance/logic.ts +210 -0
  165. package/dist/content/examples/performance/manifest.json +83 -0
  166. package/dist/content/examples/performance/package.json +16 -0
  167. package/dist/content/examples/performance/style.ocss +75 -0
  168. package/dist/content/examples/performance/tests/fahrenheit.scenario.json +110 -0
  169. package/dist/content/examples/performance/tests/horizontal.scenario.json +96 -0
  170. package/dist/content/examples/performance/tests/load-logic.mjs +22 -0
  171. package/dist/content/examples/performance/tests/logic.test.mjs +226 -0
  172. package/dist/content/examples/performance/tests/menu.scenario.json +170 -0
  173. package/dist/content/examples/performance/tests/no-fps-source.scenario.json +47 -0
  174. package/dist/content/examples/performance/tests/preview.scenario.json +45 -0
  175. package/dist/content/examples/performance/tests/refused.scenario.json +20 -0
  176. package/dist/content/examples/performance/tests/refused.test.mjs +19 -0
  177. package/dist/content/examples/performance/tests/region.scenario.json +89 -0
  178. package/dist/content/examples/performance/tests/render.scenario.json +112 -0
  179. package/dist/content/examples/performance/tests/sources.scenario.json +151 -0
  180. package/dist/content/examples/performance/tests/stale.scenario.json +111 -0
  181. package/dist/content/examples/performance/tests/telemetry-only.scenario.json +44 -0
  182. package/dist/content/examples/performance/tests/thresholds.scenario.json +147 -0
  183. package/dist/content/examples/performance/tests/waiting.scenario.json +105 -0
  184. package/dist/content/examples/performance/tsconfig.json +16 -0
  185. package/dist/content/examples/performance/view.ocml +18 -0
  186. package/dist/content/examples/playervox-journal/LICENSE +21 -0
  187. package/dist/content/examples/playervox-journal/README.md +150 -0
  188. package/dist/content/examples/playervox-journal/listing.json +19 -0
  189. package/dist/content/examples/playervox-journal/locales/en.json +25 -0
  190. package/dist/content/examples/playervox-journal/locales/fr.json +25 -0
  191. package/dist/content/examples/playervox-journal/logic.ts +556 -0
  192. package/dist/content/examples/playervox-journal/manifest.json +19 -0
  193. package/dist/content/examples/playervox-journal/package.json +16 -0
  194. package/dist/content/examples/playervox-journal/style.ocss +142 -0
  195. package/dist/content/examples/playervox-journal/tests/changes.scenario.json +482 -0
  196. package/dist/content/examples/playervox-journal/tests/delete.scenario.json +432 -0
  197. package/dist/content/examples/playervox-journal/tests/frame.scenario.json +169 -0
  198. package/dist/content/examples/playervox-journal/tests/load-logic.mjs +22 -0
  199. package/dist/content/examples/playervox-journal/tests/logic.test.mjs +349 -0
  200. package/dist/content/examples/playervox-journal/tests/paging.scenario.json +428 -0
  201. package/dist/content/examples/playervox-journal/tests/preview.scenario.json +184 -0
  202. package/dist/content/examples/playervox-journal/tests/read-only.scenario.json +157 -0
  203. package/dist/content/examples/playervox-journal/tests/refused.scenario.json +39 -0
  204. package/dist/content/examples/playervox-journal/tests/scale.scenario.json +286 -0
  205. package/dist/content/examples/playervox-journal/tests/signed-out.scenario.json +134 -0
  206. package/dist/content/examples/playervox-journal/tests/states.scenario.json +741 -0
  207. package/dist/content/examples/playervox-journal/tests/unavailable.scenario.json +183 -0
  208. package/dist/content/examples/playervox-journal/tsconfig.json +16 -0
  209. package/dist/content/examples/playervox-journal/view.ocml +52 -0
  210. package/dist/content/examples/playervox-rating/LICENSE +21 -0
  211. package/dist/content/examples/playervox-rating/README.md +166 -0
  212. package/dist/content/examples/playervox-rating/listing.json +19 -0
  213. package/dist/content/examples/playervox-rating/locales/en.json +35 -0
  214. package/dist/content/examples/playervox-rating/locales/fr.json +35 -0
  215. package/dist/content/examples/playervox-rating/logic.ts +581 -0
  216. package/dist/content/examples/playervox-rating/manifest.json +19 -0
  217. package/dist/content/examples/playervox-rating/package.json +16 -0
  218. package/dist/content/examples/playervox-rating/style.ocss +333 -0
  219. package/dist/content/examples/playervox-rating/tests/account.scenario.json +125 -0
  220. package/dist/content/examples/playervox-rating/tests/bounds.scenario.json +73 -0
  221. package/dist/content/examples/playervox-rating/tests/draft.scenario.json +199 -0
  222. package/dist/content/examples/playervox-rating/tests/form.scenario.json +142 -0
  223. package/dist/content/examples/playervox-rating/tests/load-logic.mjs +22 -0
  224. package/dist/content/examples/playervox-rating/tests/logic.test.mjs +346 -0
  225. package/dist/content/examples/playervox-rating/tests/offline.scenario.json +142 -0
  226. package/dist/content/examples/playervox-rating/tests/preview.scenario.json +44 -0
  227. package/dist/content/examples/playervox-rating/tests/publish-keyboard.scenario.json +221 -0
  228. package/dist/content/examples/playervox-rating/tests/publish-pointer.scenario.json +314 -0
  229. package/dist/content/examples/playervox-rating/tests/read-only.scenario.json +70 -0
  230. package/dist/content/examples/playervox-rating/tests/refused.scenario.json +45 -0
  231. package/dist/content/examples/playervox-rating/tests/states.scenario.json +362 -0
  232. package/dist/content/examples/playervox-rating/tsconfig.json +16 -0
  233. package/dist/content/examples/playervox-rating/view.ocml +62 -0
  234. package/dist/content/examples/playervox-reviews/LICENSE +21 -0
  235. package/dist/content/examples/playervox-reviews/README.md +194 -0
  236. package/dist/content/examples/playervox-reviews/listing.json +19 -0
  237. package/dist/content/examples/playervox-reviews/locales/en.json +32 -0
  238. package/dist/content/examples/playervox-reviews/locales/fr.json +32 -0
  239. package/dist/content/examples/playervox-reviews/logic.ts +822 -0
  240. package/dist/content/examples/playervox-reviews/manifest.json +30 -0
  241. package/dist/content/examples/playervox-reviews/package.json +16 -0
  242. package/dist/content/examples/playervox-reviews/style.ocss +260 -0
  243. package/dist/content/examples/playervox-reviews/tests/account.scenario.json +249 -0
  244. package/dist/content/examples/playervox-reviews/tests/bounds.scenario.json +336 -0
  245. package/dist/content/examples/playervox-reviews/tests/changes.scenario.json +515 -0
  246. package/dist/content/examples/playervox-reviews/tests/filter.scenario.json +400 -0
  247. package/dist/content/examples/playervox-reviews/tests/frame.scenario.json +185 -0
  248. package/dist/content/examples/playervox-reviews/tests/keyboard.scenario.json +188 -0
  249. package/dist/content/examples/playervox-reviews/tests/load-logic.mjs +22 -0
  250. package/dist/content/examples/playervox-reviews/tests/logic.test.mjs +559 -0
  251. package/dist/content/examples/playervox-reviews/tests/offline-start.scenario.json +152 -0
  252. package/dist/content/examples/playervox-reviews/tests/offline.scenario.json +311 -0
  253. package/dist/content/examples/playervox-reviews/tests/paging.scenario.json +497 -0
  254. package/dist/content/examples/playervox-reviews/tests/preview.scenario.json +286 -0
  255. package/dist/content/examples/playervox-reviews/tests/reading.scenario.json +591 -0
  256. package/dist/content/examples/playervox-reviews/tests/refused.scenario.json +54 -0
  257. package/dist/content/examples/playervox-reviews/tests/scale.scenario.json +303 -0
  258. package/dist/content/examples/playervox-reviews/tests/states.scenario.json +700 -0
  259. package/dist/content/examples/playervox-reviews/tests/unavailable.scenario.json +192 -0
  260. package/dist/content/examples/playervox-reviews/tsconfig.json +16 -0
  261. package/dist/content/examples/playervox-reviews/view.ocml +110 -0
  262. package/dist/content/examples/playervox-score/LICENSE +21 -0
  263. package/dist/content/examples/playervox-score/README.md +131 -0
  264. package/dist/content/examples/playervox-score/listing.json +19 -0
  265. package/dist/content/examples/playervox-score/locales/en.json +23 -0
  266. package/dist/content/examples/playervox-score/locales/fr.json +23 -0
  267. package/dist/content/examples/playervox-score/logic.ts +430 -0
  268. package/dist/content/examples/playervox-score/manifest.json +47 -0
  269. package/dist/content/examples/playervox-score/package.json +16 -0
  270. package/dist/content/examples/playervox-score/style.ocss +247 -0
  271. package/dist/content/examples/playervox-score/tests/grades.scenario.json +279 -0
  272. package/dist/content/examples/playervox-score/tests/load-logic.mjs +22 -0
  273. package/dist/content/examples/playervox-score/tests/logic.test.mjs +229 -0
  274. package/dist/content/examples/playervox-score/tests/options.scenario.json +302 -0
  275. package/dist/content/examples/playervox-score/tests/preview.scenario.json +68 -0
  276. package/dist/content/examples/playervox-score/tests/pulse.scenario.json +157 -0
  277. package/dist/content/examples/playervox-score/tests/refused.scenario.json +21 -0
  278. package/dist/content/examples/playervox-score/tests/signed-out.scenario.json +46 -0
  279. package/dist/content/examples/playervox-score/tests/states.scenario.json +450 -0
  280. package/dist/content/examples/playervox-score/tests/unavailable.scenario.json +84 -0
  281. package/dist/content/examples/playervox-score/tsconfig.json +16 -0
  282. package/dist/content/examples/playervox-score/view.ocml +51 -0
  283. package/dist/content/examples/session/LICENSE +21 -0
  284. package/dist/content/examples/session/README.md +57 -0
  285. package/dist/content/examples/session/listing.json +19 -0
  286. package/dist/content/examples/session/locales/en.json +3 -0
  287. package/dist/content/examples/session/locales/fr.json +3 -0
  288. package/dist/content/examples/session/logic.ts +26 -0
  289. package/dist/content/examples/session/manifest.json +19 -0
  290. package/dist/content/examples/session/package.json +16 -0
  291. package/dist/content/examples/session/style.ocss +16 -0
  292. package/dist/content/examples/session/tests/hidden.scenario.json +45 -0
  293. package/dist/content/examples/session/tests/load-logic.mjs +22 -0
  294. package/dist/content/examples/session/tests/logic.test.mjs +37 -0
  295. package/dist/content/examples/session/tests/preview.scenario.json +28 -0
  296. package/dist/content/examples/session/tests/refused.scenario.json +20 -0
  297. package/dist/content/examples/session/tests/refused.test.mjs +16 -0
  298. package/dist/content/examples/session/tests/render.scenario.json +95 -0
  299. package/dist/content/examples/session/tests/ticks.scenario.json +139 -0
  300. package/dist/content/examples/session/tests/unknown.scenario.json +37 -0
  301. package/dist/content/examples/session/tsconfig.json +16 -0
  302. package/dist/content/examples/session/view.ocml +11 -0
  303. package/dist/content/examples/stopwatch/LICENSE +21 -0
  304. package/dist/content/examples/stopwatch/README.md +99 -0
  305. package/dist/content/examples/stopwatch/listing.json +19 -0
  306. package/dist/content/examples/stopwatch/locales/en.json +8 -0
  307. package/dist/content/examples/stopwatch/locales/fr.json +8 -0
  308. package/dist/content/examples/stopwatch/logic.ts +93 -0
  309. package/dist/content/examples/stopwatch/manifest.json +19 -0
  310. package/dist/content/examples/stopwatch/package.json +16 -0
  311. package/dist/content/examples/stopwatch/style.ocss +54 -0
  312. package/dist/content/examples/stopwatch/tests/errors.scenario.json +121 -0
  313. package/dist/content/examples/stopwatch/tests/gesture.scenario.json +154 -0
  314. package/dist/content/examples/stopwatch/tests/hidden.scenario.json +57 -0
  315. package/dist/content/examples/stopwatch/tests/hundredths.scenario.json +173 -0
  316. package/dist/content/examples/stopwatch/tests/load-logic.mjs +22 -0
  317. package/dist/content/examples/stopwatch/tests/logic.test.mjs +99 -0
  318. package/dist/content/examples/stopwatch/tests/preview.scenario.json +36 -0
  319. package/dist/content/examples/stopwatch/tests/read-only.scenario.json +42 -0
  320. package/dist/content/examples/stopwatch/tests/read-only.test.mjs +18 -0
  321. package/dist/content/examples/stopwatch/tests/refused.scenario.json +22 -0
  322. package/dist/content/examples/stopwatch/tests/refused.test.mjs +18 -0
  323. package/dist/content/examples/stopwatch/tests/render.scenario.json +105 -0
  324. package/dist/content/examples/stopwatch/tests/states.scenario.json +246 -0
  325. package/dist/content/examples/stopwatch/tests/unknown.scenario.json +40 -0
  326. package/dist/content/examples/stopwatch/tsconfig.json +16 -0
  327. package/dist/content/examples/stopwatch/view.ocml +29 -0
  328. package/dist/content/examples/twitch-chat/LICENSE +21 -0
  329. package/dist/content/examples/twitch-chat/README.md +283 -0
  330. package/dist/content/examples/twitch-chat/listing.json +19 -0
  331. package/dist/content/examples/twitch-chat/locales/en.json +52 -0
  332. package/dist/content/examples/twitch-chat/locales/fr.json +52 -0
  333. package/dist/content/examples/twitch-chat/logic.ts +887 -0
  334. package/dist/content/examples/twitch-chat/manifest.json +33 -0
  335. package/dist/content/examples/twitch-chat/package.json +16 -0
  336. package/dist/content/examples/twitch-chat/style.ocss +544 -0
  337. package/dist/content/examples/twitch-chat/tests/account.scenario.json +325 -0
  338. package/dist/content/examples/twitch-chat/tests/burst.scenario.json +1866 -0
  339. package/dist/content/examples/twitch-chat/tests/channel-refused.scenario.json +372 -0
  340. package/dist/content/examples/twitch-chat/tests/channel.scenario.json +480 -0
  341. package/dist/content/examples/twitch-chat/tests/draft.scenario.json +279 -0
  342. package/dist/content/examples/twitch-chat/tests/fade.scenario.json +269 -0
  343. package/dist/content/examples/twitch-chat/tests/failures.scenario.json +420 -0
  344. package/dist/content/examples/twitch-chat/tests/favorites.scenario.json +376 -0
  345. package/dist/content/examples/twitch-chat/tests/frame.scenario.json +152 -0
  346. package/dist/content/examples/twitch-chat/tests/lifetime.scenario.json +186 -0
  347. package/dist/content/examples/twitch-chat/tests/load-logic.mjs +22 -0
  348. package/dist/content/examples/twitch-chat/tests/logic.test.mjs +1053 -0
  349. package/dist/content/examples/twitch-chat/tests/passive.scenario.json +536 -0
  350. package/dist/content/examples/twitch-chat/tests/preview.scenario.json +147 -0
  351. package/dist/content/examples/twitch-chat/tests/read-only.scenario.json +202 -0
  352. package/dist/content/examples/twitch-chat/tests/read-only.test.mjs +63 -0
  353. package/dist/content/examples/twitch-chat/tests/refused.scenario.json +65 -0
  354. package/dist/content/examples/twitch-chat/tests/refused.test.mjs +43 -0
  355. package/dist/content/examples/twitch-chat/tests/render.scenario.json +347 -0
  356. package/dist/content/examples/twitch-chat/tests/reply.scenario.json +384 -0
  357. package/dist/content/examples/twitch-chat/tests/send-refused.scenario.json +383 -0
  358. package/dist/content/examples/twitch-chat/tests/send.scenario.json +300 -0
  359. package/dist/content/examples/twitch-chat/tests/states.scenario.json +455 -0
  360. package/dist/content/examples/twitch-chat/tests/unavailable.scenario.json +256 -0
  361. package/dist/content/examples/twitch-chat/tests/unread.scenario.json +997 -0
  362. package/dist/content/examples/twitch-chat/tsconfig.json +16 -0
  363. package/dist/content/examples/twitch-chat/view.ocml +141 -0
  364. package/dist/content/examples/warframe-market/LICENSE +21 -0
  365. package/dist/content/examples/warframe-market/README.md +176 -0
  366. package/dist/content/examples/warframe-market/listing.json +19 -0
  367. package/dist/content/examples/warframe-market/locales/en.json +44 -0
  368. package/dist/content/examples/warframe-market/locales/fr.json +44 -0
  369. package/dist/content/examples/warframe-market/logic.ts +1265 -0
  370. package/dist/content/examples/warframe-market/manifest.json +92 -0
  371. package/dist/content/examples/warframe-market/package.json +16 -0
  372. package/dist/content/examples/warframe-market/style.ocss +422 -0
  373. package/dist/content/examples/warframe-market/tests/bounds.scenario.json +60 -0
  374. package/dist/content/examples/warframe-market/tests/cached.scenario.json +70 -0
  375. package/dist/content/examples/warframe-market/tests/detail.scenario.json +251 -0
  376. package/dist/content/examples/warframe-market/tests/errors.scenario.json +105 -0
  377. package/dist/content/examples/warframe-market/tests/fixtures.json +295 -0
  378. package/dist/content/examples/warframe-market/tests/load-logic.mjs +22 -0
  379. package/dist/content/examples/warframe-market/tests/logic.test.mjs +505 -0
  380. package/dist/content/examples/warframe-market/tests/no-clipboard.scenario.json +104 -0
  381. package/dist/content/examples/warframe-market/tests/passive.scenario.json +87 -0
  382. package/dist/content/examples/warframe-market/tests/preview.scenario.json +146 -0
  383. package/dist/content/examples/warframe-market/tests/refresh.scenario.json +56 -0
  384. package/dist/content/examples/warframe-market/tests/refused.scenario.json +74 -0
  385. package/dist/content/examples/warframe-market/tests/render.scenario.json +210 -0
  386. package/dist/content/examples/warframe-market/tests/search.scenario.json +189 -0
  387. package/dist/content/examples/warframe-market/tests/unavailable.scenario.json +54 -0
  388. package/dist/content/examples/warframe-market/tsconfig.json +16 -0
  389. package/dist/content/examples/warframe-market/view.ocml +116 -0
  390. package/dist/content/examples/weather/LICENSE +20 -0
  391. package/dist/content/examples/weather/listing.json +10 -0
  392. package/dist/content/examples/weather/locales/en.json +9 -0
  393. package/dist/content/examples/weather/locales/fr.json +9 -0
  394. package/dist/content/examples/weather/logic.ts +62 -0
  395. package/dist/content/examples/weather/manifest.json +51 -0
  396. package/dist/content/examples/weather/package.json +15 -0
  397. package/dist/content/examples/weather/style.ocss +29 -0
  398. package/dist/content/examples/weather/tsconfig.json +16 -0
  399. package/dist/content/examples/weather/view.ocml +12 -0
  400. package/dist/content/index.json +3601 -0
  401. package/dist/content/reference/errors.json +1712 -0
  402. package/dist/content/reference/limits.json +1154 -0
  403. package/dist/content/reference/manifest.md +223 -0
  404. package/dist/content/reference/permissions.json +413 -0
  405. package/dist/content/templates/blank/locales/en.json +3 -0
  406. package/dist/content/templates/blank/locales/fr.json +3 -0
  407. package/dist/content/templates/blank/logic.ts +7 -0
  408. package/dist/content/templates/blank/manifest.json +16 -0
  409. package/dist/content/templates/blank/style.ocss +10 -0
  410. package/dist/content/templates/blank/tests/example.scenario.json +10 -0
  411. package/dist/content/templates/blank/view.ocml +6 -0
  412. package/dist/content/templates/chart/locales/en.json +3 -0
  413. package/dist/content/templates/chart/locales/fr.json +3 -0
  414. package/dist/content/templates/chart/logic.ts +27 -0
  415. package/dist/content/templates/chart/manifest.json +16 -0
  416. package/dist/content/templates/chart/style.ocss +27 -0
  417. package/dist/content/templates/chart/tests/example.scenario.json +10 -0
  418. package/dist/content/templates/chart/view.ocml +10 -0
  419. package/dist/content/templates/counter/locales/en.json +4 -0
  420. package/dist/content/templates/counter/locales/fr.json +4 -0
  421. package/dist/content/templates/counter/logic.ts +20 -0
  422. package/dist/content/templates/counter/manifest.json +16 -0
  423. package/dist/content/templates/counter/style.ocss +26 -0
  424. package/dist/content/templates/counter/tests/example.scenario.json +11 -0
  425. package/dist/content/templates/counter/view.ocml +13 -0
  426. package/dist/content/templates/list/locales/en.json +8 -0
  427. package/dist/content/templates/list/locales/fr.json +8 -0
  428. package/dist/content/templates/list/logic.ts +35 -0
  429. package/dist/content/templates/list/manifest.json +16 -0
  430. package/dist/content/templates/list/style.ocss +42 -0
  431. package/dist/content/templates/list/tests/example.scenario.json +10 -0
  432. package/dist/content/templates/list/view.ocml +17 -0
  433. package/dist/content/templates/shared/LICENSE +20 -0
  434. package/dist/content/templates/shared/package.json +14 -0
  435. package/dist/content/templates/shared/tsconfig.json +16 -0
  436. package/dist/content.js +68 -0
  437. package/dist/env.js +156 -0
  438. package/dist/fingerprint.js +32 -0
  439. package/dist/ids.js +27 -0
  440. package/dist/index.js +82 -0
  441. package/dist/knowledge.js +222 -0
  442. package/dist/npm.js +149 -0
  443. package/dist/prompts.js +47 -0
  444. package/dist/resources.js +82 -0
  445. package/dist/run.js +120 -0
  446. package/dist/server.js +43 -0
  447. package/dist/session.js +205 -0
  448. package/dist/sources.js +218 -0
  449. package/dist/text.js +80 -0
  450. package/dist/texts.js +44 -0
  451. package/dist/tools/audit.js +105 -0
  452. package/dist/tools/build.js +453 -0
  453. package/dist/tools/common.js +122 -0
  454. package/dist/tools/docs.js +196 -0
  455. package/dist/tools/preview.js +87 -0
  456. package/dist/tools/project.js +178 -0
  457. package/dist/tools/setup.js +146 -0
  458. package/dist/tools/submission.js +369 -0
  459. package/dist/version.js +3 -0
  460. package/npm-shrinkwrap.json +402 -0
  461. package/package.json +52 -4
@@ -0,0 +1,146 @@
1
+ // status and setup: what is ready, and the one tool that downloads.
2
+ import { z } from "zod";
3
+ import { findNpmCli } from "../npm.js";
4
+ import { DESCRIPTIONS } from "../texts.js";
5
+ import { VERSION } from "../version.js";
6
+ import { fail, failure, ok, progress, READ_ONLY, withRoots } from "./common.js";
7
+ const NODE_MINIMUM = [22, 18];
8
+ function nodeOk(version = process.versions.node) {
9
+ const [major = 0, minor = 0] = version.split(".").map(Number);
10
+ return (major > NODE_MINIMUM[0] ||
11
+ (major === NODE_MINIMUM[0] && minor >= NODE_MINIMUM[1]));
12
+ }
13
+ export function registerSetupTools(env) {
14
+ const { server, session } = env;
15
+ server.registerTool("status", {
16
+ title: "Status",
17
+ description: DESCRIPTIONS.status,
18
+ inputSchema: z.strictObject({}),
19
+ outputSchema: z.object({
20
+ server: z.string(),
21
+ node: z.object({ version: z.string(), ok: z.boolean() }),
22
+ npm: z.boolean(),
23
+ platform: z.object({
24
+ supported: z.boolean(),
25
+ name: z.string().nullable(),
26
+ message: z.string().nullable(),
27
+ }),
28
+ release: z.string().nullable(),
29
+ sdk: z.string(),
30
+ typescript: z.string(),
31
+ tools: z.object({
32
+ installed: z.boolean(),
33
+ cli: z.string().nullable(),
34
+ folder: z.string().nullable(),
35
+ }),
36
+ projectFolders: z.array(z.string()),
37
+ projectProblem: z.string().nullable(),
38
+ next: z.string(),
39
+ }),
40
+ annotations: { title: "Status", ...READ_ONLY },
41
+ }, async (_args, ctx) => {
42
+ const platform = session.platform;
43
+ const tools = await session.installedTools().catch(() => undefined);
44
+ const answer = await session.roots(ctx, server);
45
+ if ("input" in answer)
46
+ return answer.input;
47
+ const confinement = "confinement" in answer ? answer.confinement : undefined;
48
+ const redactor = session.redactor(confinement);
49
+ const release = session.options.pin.release;
50
+ let next;
51
+ if (!("platform" in platform))
52
+ next = platform.unsupported;
53
+ else if (!nodeOk())
54
+ next = `Node.js ${process.versions.node} is too old: install Node.js 22.18 or later.`;
55
+ else if (!release)
56
+ next =
57
+ "This version of @overcrow/mcp is not tied to a published OverCrow release yet: update it.";
58
+ else if (!tools)
59
+ next = "Run setup to install the creator tools.";
60
+ else if ("error" in answer)
61
+ next = answer.error;
62
+ else
63
+ next = "Ready. Create a widget with create_widget, or check an existing one with check.";
64
+ return ok({
65
+ server: `@overcrow/mcp ${VERSION}`,
66
+ node: { version: process.versions.node, ok: nodeOk() },
67
+ npm: findNpmCli() !== undefined,
68
+ platform: {
69
+ supported: "platform" in platform,
70
+ name: "platform" in platform ? platform.platform : null,
71
+ message: "unsupported" in platform ? platform.unsupported : null,
72
+ },
73
+ release,
74
+ sdk: session.options.pin.npm.sdk.version,
75
+ typescript: session.options.pin.npm.typescript.version,
76
+ tools: {
77
+ installed: tools !== undefined,
78
+ cli: tools ? tools.cliVersion : null,
79
+ folder: tools ? tools.directory : null,
80
+ },
81
+ projectFolders: confinement ? confinement.roots.map((root) => root.path) : [],
82
+ projectProblem: "error" in answer ? answer.error : null,
83
+ next,
84
+ }, next, { redactor });
85
+ });
86
+ server.registerTool("setup", {
87
+ title: "Install the creator tools",
88
+ description: DESCRIPTIONS.setup,
89
+ inputSchema: z.strictObject({
90
+ zipPath: z
91
+ .string()
92
+ .min(1)
93
+ .max(1024)
94
+ .optional()
95
+ .describe("A local copy of the creator tools ZIP, inside the project, for offline use. It must be the exact pinned file."),
96
+ }),
97
+ outputSchema: z.object({
98
+ release: z.string(),
99
+ platform: z.string(),
100
+ cli: z.string(),
101
+ folder: z.string(),
102
+ source: z.enum(["cache", "local", "download"]),
103
+ seconds: z.number(),
104
+ }),
105
+ annotations: {
106
+ title: "Install the creator tools",
107
+ readOnlyHint: false,
108
+ destructiveHint: false,
109
+ idempotentHint: true,
110
+ openWorldHint: true,
111
+ },
112
+ }, async ({ zipPath }, ctx) => {
113
+ const started = Date.now();
114
+ const report = progress(ctx);
115
+ const run = async (localZip, redactor = session.redactor()) => {
116
+ try {
117
+ const { tools, source } = await session.setup(localZip, report
118
+ ? (done, total) => report(done, total, "Downloading the creator tools")
119
+ : undefined, ctx.mcpReq.signal);
120
+ const summary = source === "cache"
121
+ ? `The creator tools of OverCrow ${tools.release} are already installed and intact.`
122
+ : `Installed the creator tools of OverCrow ${tools.release} (CLI ${tools.cliVersion}) after checking every file.`;
123
+ return ok({
124
+ release: tools.release,
125
+ platform: tools.platform,
126
+ cli: tools.cliVersion,
127
+ folder: tools.directory,
128
+ source,
129
+ seconds: Math.round((Date.now() - started) / 100) / 10,
130
+ }, summary, { redactor });
131
+ }
132
+ catch (error) {
133
+ return failure(error, redactor);
134
+ }
135
+ };
136
+ if (zipPath === undefined)
137
+ return run(undefined);
138
+ // A local ZIP is read only inside the project folders.
139
+ return withRoots(env, ctx, async (confinement, redactor) => {
140
+ if (!zipPath.toLowerCase().endsWith(".zip"))
141
+ return fail("zipPath must name a .zip file.");
142
+ const file = await confinement.resolve(zipPath, "file");
143
+ return run(file, redactor);
144
+ });
145
+ });
146
+ }
@@ -0,0 +1,369 @@
1
+ // prepare_submission: everything the OverCrow creator space asks for, checked
2
+ // on the project; the ZIP of the sources written to dist/ once nothing
3
+ // fails; and the texts the creator space asks for, listed for the assistant
4
+ // to draft with the user. Nothing is sent: the user sends the ZIP and the
5
+ // texts in the creator space.
6
+ import { join } from "node:path";
7
+ import { z } from "zod";
8
+ import { auditWidget } from "../audit/index.js";
9
+ import { readWidget } from "../audit/project.js";
10
+ import { Cli } from "../cli.js";
11
+ import { limit } from "../content.js";
12
+ import { sourcesFingerprint } from "../fingerprint.js";
13
+ import { ID_FORMS, idProblem, isPlaceholderId, WIDGET_ID } from "../ids.js";
14
+ import { selectSources, writeSourcesZip } from "../sources.js";
15
+ import { cleanLine } from "../text.js";
16
+ import { DESCRIPTIONS } from "../texts.js";
17
+ import { ok, widgetDirectory, withRoots } from "./common.js";
18
+ const DIRECTORY = z
19
+ .string()
20
+ .min(1)
21
+ .max(1024)
22
+ .describe("The widget folder (it holds manifest.json), relative to the project folder.");
23
+ const VERSION = /^\d+\.\d+\.\d+$/;
24
+ const MAX_LISTED_INCLUDED = 200;
25
+ const MAX_LISTED_EXCLUDED = 100;
26
+ export const SEND = "The user sends the ZIP and these texts in the OverCrow creator space on overcrow.playervox.com.";
27
+ const KIB = 1024;
28
+ const kib = (bytes) => `${Math.max(1, Math.round(bytes / KIB))} KiB`;
29
+ const size = (bytes) => bytes >= KIB * KIB && bytes % (KIB * KIB) === 0
30
+ ? `${bytes / (KIB * KIB)} MiB`
31
+ : bytes >= KIB
32
+ ? `${Math.ceil(bytes / KIB)} KiB`
33
+ : `${bytes} bytes`;
34
+ export function registerSubmissionTool(env) {
35
+ const { server, session } = env;
36
+ server.registerTool("prepare_submission", {
37
+ title: "Prepare the submission",
38
+ description: DESCRIPTIONS.prepare_submission,
39
+ inputSchema: z.strictObject({ directory: DIRECTORY }),
40
+ outputSchema: z.object({
41
+ directory: z.string(),
42
+ id: z.string().nullable(),
43
+ version: z.string().nullable(),
44
+ ready: z.boolean(),
45
+ checklist: z.array(z.object({
46
+ item: z.string(),
47
+ status: z.enum(["pass", "fail", "todo"]),
48
+ detail: z.string(),
49
+ })),
50
+ sources: z.object({
51
+ zip: z.string().nullable(),
52
+ bytes: z.number().nullable(),
53
+ sha256: z.string().nullable(),
54
+ files: z.number(),
55
+ included: z.array(z.object({ path: z.string(), bytes: z.number() })),
56
+ excluded: z.array(z.object({ path: z.string(), reason: z.string() })),
57
+ omitted: z.number(),
58
+ }),
59
+ texts: z.array(z.object({
60
+ kind: z.enum(["permission", "privacy-policy", "release-notes", "description"]),
61
+ subject: z.string(),
62
+ current: z.string().nullable(),
63
+ ask: z.string(),
64
+ })),
65
+ next: z.string(),
66
+ notes: z.array(z.string()),
67
+ }),
68
+ annotations: {
69
+ title: "Prepare the submission",
70
+ readOnlyHint: false,
71
+ destructiveHint: false,
72
+ idempotentHint: true,
73
+ openWorldHint: false,
74
+ },
75
+ }, async ({ directory }, ctx) => withRoots(env, ctx, async (confinement, redactor) => {
76
+ const target = await widgetDirectory(confinement, directory);
77
+ const tools = await session.installedTools();
78
+ const project = await readWidget(target);
79
+ const audit = await auditWidget(target);
80
+ const manifest = project.manifest ?? {};
81
+ const listing = project.listing;
82
+ const files = new Map(project.files.map((file) => [file.path, file]));
83
+ const checklist = [];
84
+ // 1. The ID.
85
+ const id = audit.id ?? "";
86
+ const idIssue = idProblem(id) ??
87
+ (isPlaceholderId(id) ? `The ID ${id} is a placeholder: use ${ID_FORMS}.` : undefined);
88
+ checklist.push({
89
+ item: "Widget ID",
90
+ status: idIssue ? "fail" : "pass",
91
+ detail: idIssue ?? `${id}: final. Keep it for every version; it can never be reused.`,
92
+ });
93
+ // 2. check and the static admission, with the creator tools.
94
+ let review = [];
95
+ if (tools) {
96
+ const cli = new Cli(tools);
97
+ const check = await cli.check(target, ctx.mcpReq.signal);
98
+ const errors = check.diagnostics.filter((d) => d.severity === "error").length;
99
+ const warnings = check.diagnostics.length - errors;
100
+ checklist.push({
101
+ item: "check: no error, no warning",
102
+ status: errors + warnings === 0 ? "pass" : "fail",
103
+ detail: errors + warnings === 0
104
+ ? "Clean."
105
+ : `${errors} error(s), ${warnings} warning(s): the creator space refuses warnings too.`,
106
+ });
107
+ const report = await cli.admit(target, ctx.mcpReq.signal);
108
+ const diagnostics = Array.isArray(report.diagnostics)
109
+ ? report.diagnostics
110
+ : [];
111
+ // The listing is filled in the creator space: listing.json is optional.
112
+ const noListing = diagnostics.some((d) => d.code === "admission.listing_missing");
113
+ const others = diagnostics.filter((d) => d.code !== "admission.listing_missing");
114
+ const admitted = (report.admitted === true || noListing) && others.length === 0;
115
+ review = Array.isArray(report.review) ? report.review : [];
116
+ checklist.push({
117
+ item: "Static admission (overcrow-widget admit)",
118
+ status: admitted ? "pass" : "fail",
119
+ detail: admitted
120
+ ? noListing
121
+ ? "Admitted. There is no listing.json: the listing is filled in the creator space, which can also import a listing.json placed next to manifest.json."
122
+ : "Admitted, with its listing.json."
123
+ : others
124
+ .slice(0, 8)
125
+ .map((d) => `${cleanLine(String(d.code ?? ""), 48)}: ${cleanLine(String(d.message ?? ""), 200)}`)
126
+ .join("; ") || "Refused.",
127
+ });
128
+ }
129
+ else {
130
+ checklist.push({
131
+ item: "check and static admission",
132
+ status: "fail",
133
+ detail: "Run setup first: they need the creator tools.",
134
+ });
135
+ }
136
+ // 3. The tests, the audit, the preview, the texts and the licence.
137
+ const lastTest = session.lastTests.get(target);
138
+ const unchanged = lastTest !== undefined && lastTest.fingerprint === (await sourcesFingerprint(target));
139
+ const passedRun = unchanged && lastTest.complete && lastTest.failed === 0 && lastTest.passed > 0
140
+ ? lastTest
141
+ : undefined;
142
+ checklist.push({
143
+ item: "Tests pass",
144
+ status: passedRun ? "pass" : "fail",
145
+ detail: passedRun
146
+ ? `All ${passedRun.passed} scenarios passed at ${passedRun.at.toISOString().slice(11, 16)} UTC, and no source changed since.`
147
+ : lastTest && !unchanged
148
+ ? "The sources changed since the last test run: run test again."
149
+ : "Run test (every scenario, not one): each must pass with its reference images.",
150
+ });
151
+ const high = audit.findings.filter((finding) => finding.severity === "high" && finding.rule !== "reserved-id");
152
+ checklist.push({
153
+ item: "Audit: no high finding",
154
+ status: high.length === 0 ? "pass" : "fail",
155
+ detail: high.length === 0
156
+ ? `Security ${audit.scores.security}/100, lightness ${audit.scores.lightness}/100.`
157
+ : high
158
+ .map((f) => f.message)
159
+ .slice(0, 5)
160
+ .join(" "),
161
+ });
162
+ checklist.push(previewItem(listing, files));
163
+ checklist.push(languagesItem(manifest, files));
164
+ checklist.push({
165
+ item: "LICENSE",
166
+ status: files.has("LICENSE") ? "pass" : "fail",
167
+ detail: files.has("LICENSE")
168
+ ? "Any licence is accepted, including all rights reserved: choose the same one in the creator space."
169
+ : "There is no LICENSE file: add the text of your licence (any licence is accepted, including all rights reserved).",
170
+ });
171
+ // 4. What the creator space asks when sending: the texts to draft.
172
+ const permissions = review.length > 0
173
+ ? review.map(describeReview)
174
+ : audit.authority.filter((line) => !line.startsWith("Nothing:"));
175
+ const origins = networkOrigins(manifest);
176
+ checklist.push({
177
+ item: "Each permission justified",
178
+ status: permissions.length === 0 ? "pass" : "todo",
179
+ detail: permissions.length === 0
180
+ ? "The widget asks for no permission: nothing to justify."
181
+ : `${permissions.length} permission(s): the creator space asks why the widget needs each one. Draft one or two sentences for each (texts).`,
182
+ });
183
+ checklist.push({
184
+ item: "Privacy policy",
185
+ status: origins.length === 0 ? "pass" : "todo",
186
+ detail: origins.length === 0
187
+ ? "Not needed: the widget uses no network."
188
+ : `The widget contacts ${origins.join(", ")}: the creator space asks for the address of a privacy policy.`,
189
+ });
190
+ checklist.push({
191
+ item: "Release notes in English and French",
192
+ status: "todo",
193
+ detail: "Shown to players with the update: draft them (texts).",
194
+ });
195
+ const texts = textsToWrite(permissions, origins, listing);
196
+ // 5. The ZIP of the sources, once nothing above fails.
197
+ const selection = await selectSources(target);
198
+ const blocked = checklist.some((entry) => entry.status === "fail");
199
+ let written;
200
+ let zipProblem = selection.problem;
201
+ const version = VERSION.test(audit.version ?? "") ? audit.version : "";
202
+ if (!blocked && !zipProblem && WIDGET_ID.test(id) && version) {
203
+ const dist = await confinement.resolve(join(target, "dist"), "new-directory");
204
+ const result = await writeSourcesZip(target, selection.included, dist, `${id}-${version}-sources.zip`).catch((error) => ({
205
+ problem: `The ZIP could not be written to dist/ (${cleanLine(String(error.code ?? error.message), 80)}).`,
206
+ }));
207
+ if ("problem" in result)
208
+ zipProblem = result.problem;
209
+ else
210
+ written = result;
211
+ }
212
+ checklist.push({
213
+ item: "Sources ZIP",
214
+ status: written ? "pass" : "fail",
215
+ detail: written
216
+ ? `${confinement.display(written.path)}: ${selection.included.length} files, ${kib(written.bytes)}. The sources stay private: only PlayerVox reviewers read them, and players get the package built from them.`
217
+ : (zipProblem ?? "Not written yet: fix the failed items above first."),
218
+ });
219
+ const ready = checklist.every((entry) => entry.status !== "fail");
220
+ const included = selection.included.slice(0, MAX_LISTED_INCLUDED);
221
+ const excluded = selection.excluded.slice(0, MAX_LISTED_EXCLUDED);
222
+ const failed = checklist.filter((entry) => entry.status === "fail").length;
223
+ return ok({
224
+ directory: confinement.display(target),
225
+ id: audit.id,
226
+ version: audit.version,
227
+ ready,
228
+ checklist,
229
+ sources: {
230
+ zip: written ? confinement.display(written.path) : null,
231
+ bytes: written?.bytes ?? null,
232
+ sha256: written?.sha256 ?? null,
233
+ files: selection.included.length,
234
+ included,
235
+ excluded,
236
+ omitted: selection.included.length -
237
+ included.length +
238
+ (selection.excluded.length - excluded.length),
239
+ },
240
+ texts,
241
+ next: ready
242
+ ? `Draft each text of texts with the user, then show them the checklist, the ZIP and the drafts. ${SEND}`
243
+ : "Fix the failed items with the user, then run prepare_submission again.",
244
+ notes: [
245
+ `This tool sends, signs and publishes nothing. ${SEND}`,
246
+ "For an update, the creator space asks only about the permissions this version adds.",
247
+ ],
248
+ }, ready
249
+ ? `Ready: ${confinement.display(written?.path ?? target)} (${selection.included.length} files). ${texts.length} text(s) to draft with the user.`
250
+ : `Not ready: ${failed} item(s) to fix.`, { data: true, redactor });
251
+ }));
252
+ }
253
+ function previewItem(listing, files) {
254
+ const path = typeof listing?.preview === "string" ? cleanLine(listing.preview, 256) : "assets/preview.png";
255
+ const file = files.get(path);
256
+ if (!file) {
257
+ return {
258
+ item: "Preview",
259
+ status: "fail",
260
+ detail: `There is no ${path}: use_preview copies a reference image of a test scenario there (a 4:3 PNG rendered at 150 %, 256 KiB at most).`,
261
+ };
262
+ }
263
+ if (!file.image)
264
+ return { item: "Preview", status: "fail", detail: `${path} is not a PNG.` };
265
+ if (file.bytes > limit("MAX_PREVIEW_BYTES")) {
266
+ return {
267
+ item: "Preview",
268
+ status: "fail",
269
+ detail: `${path} weighs ${kib(file.bytes)}: a preview may weigh 256 KiB at most.`,
270
+ };
271
+ }
272
+ const { width, height } = file.image;
273
+ const fourByThree = Math.abs(width * 3 - height * 4) <= Math.max(width, height) * 0.01;
274
+ return {
275
+ item: "Preview",
276
+ status: "pass",
277
+ detail: `${path}, ${width}×${height}, ${kib(file.bytes)}${fourByThree ? "" : ": not 4:3, so it is shown in a 4:3 box"}. It is also the listing's preview in the creator space.`,
278
+ };
279
+ }
280
+ function languagesItem(manifest, files) {
281
+ const name = (manifest.name ?? {});
282
+ const en = typeof name.en === "string" ? name.en.trim() : "";
283
+ const fr = typeof name.fr === "string" ? name.fr.trim() : "";
284
+ const locales = ["en", "fr"].filter((locale) => files.has(`locales/${locale}.json`));
285
+ const problems = [
286
+ en && fr ? null : "manifest.json needs a name in English (en) and in French (fr)",
287
+ locales.length === 1
288
+ ? `locales/${locales[0] === "en" ? "fr" : "en"}.json is missing: give the interface texts in both languages`
289
+ : null,
290
+ ].filter((problem) => problem !== null);
291
+ return {
292
+ item: "Texts in English and French",
293
+ status: problems.length === 0 ? "pass" : "fail",
294
+ detail: problems.length > 0
295
+ ? `${problems.join("; ")}.`
296
+ : `Name "${cleanLine(en, 64)}" / "${cleanLine(fr, 64)}"; ${locales.length === 2 ? "interface texts in locales/en.json and locales/fr.json" : "no locales (the view uses no t())"}. Check that the French is a real translation.`,
297
+ };
298
+ }
299
+ function networkOrigins(manifest) {
300
+ const permissions = (manifest.permissions ?? {});
301
+ const rules = Array.isArray(permissions.network)
302
+ ? permissions.network
303
+ : [];
304
+ const origins = rules
305
+ .map((rule) => (typeof rule.origin === "string" ? cleanLine(rule.origin, 200) : ""))
306
+ .filter((origin) => origin !== "");
307
+ return [...new Set(origins)].slice(0, 16);
308
+ }
309
+ function textsToWrite(permissions, origins, listing) {
310
+ const texts = permissions.map((permission) => ({
311
+ kind: "permission",
312
+ subject: permission,
313
+ current: null,
314
+ ask: "Why the widget needs this permission, in one or two plain sentences, for the reviewer.",
315
+ }));
316
+ if (origins.length > 0) {
317
+ texts.push({
318
+ kind: "privacy-policy",
319
+ subject: origins.join(", "),
320
+ current: null,
321
+ ask: "The address of a privacy policy that says what the widget sends to these servers and why. Ask the user for it, never invent one; if they have none, offer to draft its text for them to publish.",
322
+ });
323
+ }
324
+ for (const [locale, language] of [
325
+ ["en", "English"],
326
+ ["fr", "French"],
327
+ ]) {
328
+ texts.push({
329
+ kind: "release-notes",
330
+ subject: locale,
331
+ current: null,
332
+ ask: `What changes for players in this version, in ${language}: short and plain, no marketing.`,
333
+ });
334
+ }
335
+ const localizations = Array.isArray(listing?.localizations)
336
+ ? listing.localizations
337
+ : [];
338
+ for (const [locale, language] of [
339
+ ["en", "English"],
340
+ ["fr", "French"],
341
+ ]) {
342
+ const found = localizations.find((entry) => entry.locale === locale);
343
+ texts.push({
344
+ kind: "description",
345
+ subject: locale,
346
+ current: typeof found?.description === "string" ? cleanLine(found.description, 600) : null,
347
+ ask: `What the widget shows or does, in ${language}, 500 characters at most: the first two lines appear on the catalog card. Say what it contacts if it uses the network.`,
348
+ });
349
+ }
350
+ return texts;
351
+ }
352
+ function describeReview(item) {
353
+ switch (item.kind) {
354
+ case "capability":
355
+ return `Capability ${cleanLine(String(item.name), 64)}${item.sensitive ? " (sensitive)" : ""}${item.account ? `, needs a ${cleanLine(String(item.account), 32)} account` : ""}.`;
356
+ case "network":
357
+ return `Network: ${cleanLine(String(item.method), 8)} ${cleanLine(String(item.origin), 200)}${cleanLine(String(item.path), 300)}, responses up to ${size(Number(item.maxResponseBytes))}.`;
358
+ case "clipboardWrite":
359
+ return "Clipboard: writes text when the user acts.";
360
+ case "storage":
361
+ return item.processLifetime
362
+ ? "Storage, kept only while OverCrow runs."
363
+ : "Storage on this computer.";
364
+ case "gameEvent":
365
+ return `Game event ${cleanLine(String(item.name), 64)}.`;
366
+ default:
367
+ return cleanLine(JSON.stringify(item), 200);
368
+ }
369
+ }
@@ -0,0 +1,3 @@
1
+ // The package version; scripts/build.mjs refuses a build where it differs
2
+ // from package.json.
3
+ export const VERSION = "0.1.0";