@overcrow/mcp 0.0.0 → 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 +91 -1
  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 +50 -4
@@ -0,0 +1,139 @@
1
+ {
2
+ "scenarioVersion": 1,
3
+ "name": "ticks",
4
+ "description": "The host advances the value each whole second, without VM timers; hours never wrap; a new anchor re-anchors the display at once.",
5
+ "fixtures": {
6
+ "subscriptions": {
7
+ "session.subscribe": {
8
+ "elapsedMs": 1999,
9
+ "at": 0
10
+ }
11
+ }
12
+ },
13
+ "steps": [
14
+ {
15
+ "expect": {
16
+ "text": [
17
+ "00:00:01"
18
+ ],
19
+ "calls": [
20
+ {
21
+ "service": "session.subscribe",
22
+ "outcome": "ok"
23
+ }
24
+ ]
25
+ }
26
+ },
27
+ {
28
+ "advance": {
29
+ "ms": 1
30
+ }
31
+ },
32
+ {
33
+ "expect": {
34
+ "text": [
35
+ "00:00:02"
36
+ ]
37
+ }
38
+ },
39
+ {
40
+ "advance": {
41
+ "ms": 998
42
+ }
43
+ },
44
+ {
45
+ "expect": {
46
+ "text": [
47
+ "00:00:02"
48
+ ],
49
+ "noText": [
50
+ "00:00:03"
51
+ ]
52
+ }
53
+ },
54
+ {
55
+ "advance": {
56
+ "ms": 2
57
+ }
58
+ },
59
+ {
60
+ "expect": {
61
+ "text": [
62
+ "00:00:03"
63
+ ],
64
+ "calls": []
65
+ }
66
+ },
67
+ {
68
+ "publish": {
69
+ "service": "session.subscribe",
70
+ "value": {
71
+ "elapsedMs": 90061000,
72
+ "at": 1001
73
+ }
74
+ }
75
+ },
76
+ {
77
+ "expect": {
78
+ "text": [
79
+ "25:01:01"
80
+ ]
81
+ }
82
+ },
83
+ {
84
+ "publish": {
85
+ "service": "session.subscribe",
86
+ "value": {
87
+ "elapsedMs": 359999000,
88
+ "at": 1001
89
+ }
90
+ }
91
+ },
92
+ {
93
+ "advance": {
94
+ "ms": 1000
95
+ }
96
+ },
97
+ {
98
+ "expect": {
99
+ "text": [
100
+ "100:00:00"
101
+ ],
102
+ "image": "hundred-hours"
103
+ }
104
+ },
105
+ {
106
+ "publish": {
107
+ "service": "session.subscribe",
108
+ "value": {
109
+ "elapsedMs": 0,
110
+ "at": 2001
111
+ }
112
+ }
113
+ },
114
+ {
115
+ "expect": {
116
+ "text": [
117
+ "00:00:00"
118
+ ],
119
+ "noText": [
120
+ "100:00:00"
121
+ ]
122
+ }
123
+ },
124
+ {
125
+ "publish": {
126
+ "service": "session.subscribe",
127
+ "value": null
128
+ }
129
+ },
130
+ {
131
+ "expect": {
132
+ "text": [
133
+ "--:--:--"
134
+ ],
135
+ "fault": "none"
136
+ }
137
+ }
138
+ ]
139
+ }
@@ -0,0 +1,37 @@
1
+ {
2
+ "scenarioVersion": 1,
3
+ "name": "unknown",
4
+ "description": "The game is present but its duration is unknown (null): --:--:--.",
5
+ "fixtures": {
6
+ "subscriptions": {
7
+ "session.subscribe": null
8
+ }
9
+ },
10
+ "steps": [
11
+ {
12
+ "expect": {
13
+ "state": "running",
14
+ "text": [
15
+ "--:--:--"
16
+ ],
17
+ "image": "unknown-dark"
18
+ }
19
+ },
20
+ {
21
+ "host": {
22
+ "theme": "light",
23
+ "locale": "fr",
24
+ "scale": 1500
25
+ }
26
+ },
27
+ {
28
+ "expect": {
29
+ "text": [
30
+ "--:--:--"
31
+ ],
32
+ "image": "unknown-light-fr-150",
33
+ "fault": "none"
34
+ }
35
+ }
36
+ ]
37
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2023",
4
+ "lib": ["ES2023"],
5
+ "types": [],
6
+ "module": "ES2022",
7
+ "moduleResolution": "bundler",
8
+ "strict": true,
9
+ "noEmit": true,
10
+ "isolatedModules": true,
11
+ "verbatimModuleSyntax": true,
12
+ "noUncheckedIndexedAccess": true,
13
+ "exactOptionalPropertyTypes": true
14
+ },
15
+ "include": ["logic.ts"]
16
+ }
@@ -0,0 +1,11 @@
1
+ <!-- Session: the time since the game process started, advanced by the host
2
+ from the service's anchor (parity sheet: playervox-overcrow
3
+ docs/builtin-parity/session.md). -->
4
+ <box class="session" label={t("label")}>
5
+ <if test={state.session}>
6
+ <elapsed class="value" base={state.session.elapsedMs} at={state.session.at} running={true} format="hh:mm:ss"/>
7
+ </if>
8
+ <else>
9
+ <text class="value">--:--:--</text>
10
+ </else>
11
+ </box>
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Valhallab SASU
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,99 @@
1
+ # Manual stopwatch
2
+
3
+ `com.playervox.overcrow.stopwatch` — a stopwatch to the hundredth of a
4
+ second, `HH:MM:SS.cc`, started, paused and reset with its buttons or with
5
+ OverCrow's global shortcuts. A built-in of OverCrow, written against the
6
+ public `@overcrow/sdk` and packaged with `overcrow-widget` like any
7
+ creator's widget. MIT.
8
+
9
+ ## What it shows
10
+
11
+ | State | Shows |
12
+ | --- | --- |
13
+ | Zero | `00:00:00.00`, the play button |
14
+ | Running | the time advancing to the hundredth, truncated; the pause button |
15
+ | Paused | the frozen time, the play button |
16
+ | Past 99 hours | hours never wrap: `100:00:00.00` |
17
+ | State unknown, no grant, or the service failed | `--:--:--.--`, no buttons, no reminder |
18
+
19
+ Below the time, a reminder of the host's two shortcuts, in the host's
20
+ own words for its platform: `Super+Alt+T Start / pause · Super+Alt+Z
21
+ Reset` on Linux, `Ctrl+Shift+P` and `Ctrl+Shift+R` on Windows. In French:
22
+ `Démarrer / pause`, `Réinitialiser`. The time uses the interface font with
23
+ tabular figures and `.` before the hundredths in both languages.
24
+
25
+ ## Controls
26
+
27
+ | Mode | Control | Does |
28
+ | --- | --- | --- |
29
+ | Interactive | Play or pause button ("Start" / "Pause", FR "Démarrer" / "Pause") | `stopwatch.toggle` |
30
+ | Interactive | Reset button ("Reset", FR "Réinitialiser") | `stopwatch.reset`: zero, paused |
31
+ | Interactive | Enter or Space on a focused button | the same |
32
+ | Interactive | Hover or focus a button | tooltip `{label} ({chord})`, e.g. "Start (Super+Alt+T)" |
33
+ | Passive | — | no buttons: the time and the reminder only |
34
+ | Any | OverCrow's global shortcuts | the host acts on its stopwatch directly; the widget shows the result |
35
+
36
+ Each button makes one call on its own gesture; the host refuses a call
37
+ made outside a gesture (`gesture_required`). The state a command returns
38
+ shows at once. A command the host cannot apply (`unavailable`, or
39
+ `stale_context` after a game change) changes nothing on screen.
40
+
41
+ ## Menu
42
+
43
+ No widget row: only the host's rows.
44
+
45
+ ## Permissions
46
+
47
+ - `stopwatch.read`: the state of the host's single stopwatch and the
48
+ labels of its shortcuts. Not sensitive.
49
+ - `stopwatch.control`: start, pause and reset it. Not sensitive. Without
50
+ it the widget shows no buttons.
51
+
52
+ The widget stores nothing: the host keeps one stopwatch for as long as it
53
+ runs, resets it when the game changes, and forgets it when it stops. While
54
+ a widget holding `stopwatch.control` is enabled, the host binds the
55
+ shortcuts whenever the game has focus, even when the widget is hidden in
56
+ Passive mode.
57
+
58
+ ## How it works
59
+
60
+ `stopwatch.subscribe` gives the state as an anchor, `{ running,
61
+ elapsedMs, at, shortcuts }` on the host's monotonic clock, or `null`
62
+ without a game. The view's `elapsed` element (`format="hh:mm:ss.cc"`)
63
+ shows it and the host advances it, at most at 60 Hz while it is running
64
+ and visible: the widget runs no timer and sends nothing while the
65
+ stopwatch runs. `shortcuts.bound` is `false` when another application took
66
+ a chord; the reminder stays, as before, and OverCrow's Control Center
67
+ reports the conflict.
68
+
69
+ ## Tests
70
+
71
+ - `tests/logic.test.mjs`, `tests/read-only.test.mjs`,
72
+ `tests/refused.test.mjs`: the logic on `@overcrow/sdk/testing`.
73
+ - Scenarios with their reference images:
74
+ - `render`: running, with its buttons, in both themes and languages at
75
+ 100 and 150 %;
76
+ - `states`: zero, running, paused and reset through the buttons, Passive
77
+ mode, shortcuts seen as updates, Windows chords;
78
+ - `hundredths`: the host's hundredths, truncated, without calls; hours
79
+ past 99; a new anchor; no game;
80
+ - `hidden`, `gesture` (Passive clicks call nothing; a click, Enter and
81
+ Space each make one call), `errors`, `unknown`, `refused`,
82
+ `read-only`.
83
+
84
+ ## Cost
85
+
86
+ Measured on 2026-09-30 with OverCrow's release build, on an AMD Ryzen 7
87
+ 5800X3D Linux workstation and in a Windows 11 virtual machine (2 vCPU):
88
+
89
+ | | Linux | Windows (VM) |
90
+ | --- | --- | --- |
91
+ | Widget start, warm, into the overlay's runtime | 6.9 ms (p50), 7.0 ms at most | VM ready in 14 ms (p50) |
92
+ | VM memory | 0.57–0.58 MiB anonymous | 0.85 MiB private working set |
93
+ | Private memory in all (VM, sandbox helpers, overlay share) | about 5 MB | — |
94
+ | CPU, paused or hidden | 0.03 % of one core, no frame | — |
95
+ | CPU, running and shown | 0.7 % of one core: 59 frames a second of 0.06–0.10 ms | — |
96
+ | VM CPU while running | none: the host advances the value | — |
97
+
98
+ The egui stopwatch it replaces also drew one frame per display refresh
99
+ while running (0.04 ms each, painting only) and nothing when paused.
@@ -0,0 +1,19 @@
1
+ {
2
+ "author": "PlayerVox",
3
+ "spdxLicense": "MIT",
4
+ "sourceUrl": "https://github.com/Valhallab/playervox-overcrow-releases/tree/main/widgets/stopwatch",
5
+ "preview": "assets/preview.png",
6
+ "defaultLocale": "en",
7
+ "localizations": [
8
+ {
9
+ "locale": "en",
10
+ "name": "Manual stopwatch",
11
+ "description": "A stopwatch to the hundredth of a second, started, paused and reset with its buttons or the host’s shortcuts."
12
+ },
13
+ {
14
+ "locale": "fr",
15
+ "name": "Chronomètre",
16
+ "description": "Un chronomètre au centième de seconde, démarré, mis en pause et réinitialisé par ses boutons ou les raccourcis de l’hôte."
17
+ }
18
+ ]
19
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "label": "Stopwatch",
3
+ "start": "Start",
4
+ "pause": "Pause",
5
+ "reset": "Reset",
6
+ "with-chord": "{label} ({chord})",
7
+ "reminder": "{toggle}  Start / pause  ·  {reset}  Reset"
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "label": "Chronomètre",
3
+ "start": "Démarrer",
4
+ "pause": "Pause",
5
+ "reset": "Réinitialiser",
6
+ "with-chord": "{label} ({chord})",
7
+ "reminder": "{toggle}  Démarrer / pause  ·  {reset}  Réinitialiser"
8
+ }
@@ -0,0 +1,93 @@
1
+ // Manual stopwatch: the host keeps one stopwatch, which its global shortcuts
2
+ // also drive. The widget shows it and commands it on a gesture. The host
3
+ // sends an anchor (`elapsedMs` at its monotonic `at`) and advances the
4
+ // `elapsed` element itself, hundredths included: the widget has no timer.
5
+ import {
6
+ hasGrant,
7
+ host,
8
+ initState,
9
+ onHost,
10
+ stopwatch,
11
+ t,
12
+ type Stopwatch,
13
+ } from "@overcrow/sdk";
14
+
15
+ declare module "@overcrow/sdk" {
16
+ interface WidgetState {
17
+ /** The latest state, or `null` while it is unknown. */
18
+ stopwatch: Stopwatch | null;
19
+ /** The buttons take input only in Interactive mode. */
20
+ interactive: boolean;
21
+ }
22
+ }
23
+
24
+ const canRead = hasGrant("stopwatch.read");
25
+ const canControl = hasGrant("stopwatch.control");
26
+
27
+ const state = initState({
28
+ stopwatch: null as Stopwatch | null,
29
+ interactive: host.mode === "interactive",
30
+ });
31
+
32
+ /** The state a subscription update leaves: none after a failure. */
33
+ export function current(update: { ok: boolean; value?: Stopwatch | null }): Stopwatch | null {
34
+ return update.ok ? (update.value ?? null) : null;
35
+ }
36
+
37
+ /** The buttons: Interactive mode, the control grant and a known state. */
38
+ export function showControls(interactive: boolean, known: Stopwatch | null): boolean {
39
+ return interactive && canControl && known !== null;
40
+ }
41
+
42
+ /** The label of the start/pause button. */
43
+ export function toggleLabel(running: boolean): string {
44
+ return t(running ? "pause" : "start");
45
+ }
46
+
47
+ /** A button's tooltip: its label and the host's chord. */
48
+ export function withChord(label: string, chord: string): string {
49
+ return t("with-chord", { label, chord });
50
+ }
51
+
52
+ /** The reminder of the host's two shortcuts. */
53
+ export function reminder(shortcuts: Stopwatch["shortcuts"]): string {
54
+ return t("reminder", { toggle: shortcuts.toggle, reset: shortcuts.reset });
55
+ }
56
+
57
+ /**
58
+ * Applies the state a command returned, at once: the next subscription
59
+ * update carries the same state. A failure (`unavailable` when the host
60
+ * cannot act) changes nothing, as the host did not act.
61
+ */
62
+ function command(call: () => Promise<Stopwatch | null>): void {
63
+ call().then(
64
+ (next) => {
65
+ if (canRead) {
66
+ state.stopwatch = next;
67
+ }
68
+ },
69
+ () => {},
70
+ );
71
+ }
72
+
73
+ export function toggle(): void {
74
+ command(() => stopwatch.toggle());
75
+ }
76
+
77
+ export function reset(): void {
78
+ command(() => stopwatch.reset());
79
+ }
80
+
81
+ onHost((changed) => {
82
+ if (changed.includes("mode")) {
83
+ state.interactive = host.mode === "interactive";
84
+ }
85
+ });
86
+
87
+ // Without the grant the host would refuse the subscription: show the
88
+ // unknown time instead of asking.
89
+ if (canRead) {
90
+ stopwatch.subscribe((update) => {
91
+ state.stopwatch = current(update);
92
+ });
93
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "apiVersion": 1,
4
+ "id": "com.playervox.overcrow.stopwatch",
5
+ "version": "1.0.3",
6
+ "name": {
7
+ "en": "Manual stopwatch",
8
+ "fr": "Chronomètre"
9
+ },
10
+ "sizing": {
11
+ "fit": "both",
12
+ "preferred": { "width": 330, "height": 72 },
13
+ "min": { "width": 60, "height": 24 },
14
+ "max": { "width": 640, "height": 240 }
15
+ },
16
+ "permissions": {
17
+ "capabilities": ["stopwatch.read", "stopwatch.control"]
18
+ }
19
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "overcrow-widget-stopwatch",
3
+ "version": "1.0.3",
4
+ "private": true,
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "scripts": {
8
+ "check": "overcrow-widget check",
9
+ "package": "overcrow-widget package",
10
+ "test": "node --test tests/*.test.mjs"
11
+ },
12
+ "devDependencies": {
13
+ "@overcrow/sdk": "1.0.0",
14
+ "typescript": "6.0.3"
15
+ }
16
+ }
@@ -0,0 +1,54 @@
1
+ /* The time, the buttons beside it in Interactive mode, the shortcut
2
+ reminder below; the wrapper draws the panel and its 8 px margin, the
3
+ content adds 2 px on the sides (the built-in's 10 × 8 px margin) and
4
+ 3 px between the lines. */
5
+ .stopwatch {
6
+ flex-direction: column;
7
+ align-items: start;
8
+ gap: 3px;
9
+ padding: 0 2px;
10
+ }
11
+
12
+ .row {
13
+ flex-direction: row;
14
+ align-items: center;
15
+ gap: 6px;
16
+ }
17
+
18
+ /* The UI font with tabular figures: the hundredths never shift. */
19
+ .value {
20
+ font-family: var(--font-ui);
21
+ font-size: var(--font-size-value);
22
+ font-variant-numeric: tabular-nums;
23
+ color: var(--color-text);
24
+ white-space: nowrap;
25
+ margin-right: 2px;
26
+ }
27
+
28
+ /* The built-in's compact icon buttons: a raised surface, lighter under
29
+ the pointer or with the keyboard focus. */
30
+ .control {
31
+ width: var(--icon-button-size);
32
+ height: var(--icon-button-size);
33
+ padding: 5px;
34
+ /* The icon (sized by `font-size`) fills the 12 px content box exactly
35
+ and is centred in it. */
36
+ font-size: 12px;
37
+ justify-content: center;
38
+ align-items: center;
39
+ border-radius: var(--radius-sm);
40
+ background: var(--color-surface-raised);
41
+ color: var(--color-text);
42
+ }
43
+
44
+ .control:hover,
45
+ .control:focus {
46
+ background: var(--color-surface-hover);
47
+ }
48
+
49
+ .reminder {
50
+ font-family: var(--font-ui);
51
+ font-size: var(--font-size-small);
52
+ color: var(--color-text-muted);
53
+ white-space: nowrap;
54
+ }
@@ -0,0 +1,121 @@
1
+ {
2
+ "scenarioVersion": 1,
3
+ "name": "errors",
4
+ "description": "A command the host cannot apply (unavailable, or stale_context after a game change) changes nothing on screen; the next one succeeds.",
5
+ "host": {
6
+ "mode": "interactive"
7
+ },
8
+ "fixtures": {
9
+ "calls": {
10
+ "stopwatch.toggle": [
11
+ {
12
+ "error": "unavailable"
13
+ },
14
+ {
15
+ "value": {
16
+ "running": true,
17
+ "elapsedMs": 5000,
18
+ "at": 0,
19
+ "shortcuts": {
20
+ "toggle": "Super+Alt+T",
21
+ "reset": "Super+Alt+Z",
22
+ "bound": true
23
+ }
24
+ }
25
+ }
26
+ ],
27
+ "stopwatch.reset": [
28
+ {
29
+ "error": "stale_context"
30
+ }
31
+ ]
32
+ },
33
+ "subscriptions": {
34
+ "stopwatch.subscribe": {
35
+ "running": false,
36
+ "elapsedMs": 5000,
37
+ "at": 0,
38
+ "shortcuts": {
39
+ "toggle": "Super+Alt+T",
40
+ "reset": "Super+Alt+Z",
41
+ "bound": true
42
+ }
43
+ }
44
+ }
45
+ },
46
+ "steps": [
47
+ {
48
+ "pointer": {
49
+ "click": {
50
+ "label": "Start"
51
+ }
52
+ }
53
+ },
54
+ {
55
+ "expect": {
56
+ "text": [
57
+ "00:00:05.00"
58
+ ],
59
+ "calls": [
60
+ {
61
+ "service": "stopwatch.subscribe",
62
+ "outcome": "ok"
63
+ },
64
+ {
65
+ "service": "stopwatch.toggle",
66
+ "outcome": "unavailable"
67
+ }
68
+ ],
69
+ "fault": "none"
70
+ }
71
+ },
72
+ {
73
+ "pointer": {
74
+ "click": {
75
+ "label": "Reset"
76
+ }
77
+ }
78
+ },
79
+ {
80
+ "expect": {
81
+ "text": [
82
+ "00:00:05.00"
83
+ ],
84
+ "calls": [
85
+ {
86
+ "service": "stopwatch.reset",
87
+ "outcome": "stale_context"
88
+ }
89
+ ],
90
+ "fault": "none"
91
+ }
92
+ },
93
+ {
94
+ "pointer": {
95
+ "click": {
96
+ "label": "Start"
97
+ }
98
+ }
99
+ },
100
+ {
101
+ "advance": {
102
+ "ms": 250
103
+ }
104
+ },
105
+ {
106
+ "expect": {
107
+ "text": [
108
+ "00:00:05.25"
109
+ ],
110
+ "calls": [
111
+ {
112
+ "service": "stopwatch.toggle",
113
+ "outcome": "ok"
114
+ }
115
+ ],
116
+ "image": "after-errors",
117
+ "fault": "none"
118
+ }
119
+ }
120
+ ]
121
+ }