polen 0.9.1-next.2 → 0.10.0-next.10

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 (460) hide show
  1. package/README.md +49 -364
  2. package/build/api/api.d.ts +1 -0
  3. package/build/api/api.d.ts.map +1 -1
  4. package/build/api/api.js +1 -0
  5. package/build/api/api.js.map +1 -1
  6. package/build/api/config/configurator.d.ts +9 -1
  7. package/build/api/config/configurator.d.ts.map +1 -1
  8. package/build/api/config/configurator.js +18 -6
  9. package/build/api/config/configurator.js.map +1 -1
  10. package/build/api/config/load.js +5 -5
  11. package/build/api/config/load.js.map +1 -1
  12. package/build/api/config-resolver/resolve.js +2 -2
  13. package/build/api/config-resolver/resolve.js.map +1 -1
  14. package/build/api/content/$$.d.ts +7 -0
  15. package/build/api/content/$$.d.ts.map +1 -0
  16. package/build/api/content/$$.js +7 -0
  17. package/build/api/content/$$.js.map +1 -0
  18. package/build/api/content/$.d.ts +2 -0
  19. package/build/api/content/$.d.ts.map +1 -0
  20. package/build/api/content/$.js +2 -0
  21. package/build/api/content/$.js.map +1 -0
  22. package/build/api/content/metadata.d.ts +10 -0
  23. package/build/api/content/metadata.d.ts.map +1 -0
  24. package/build/api/content/metadata.js +9 -0
  25. package/build/api/content/metadata.js.map +1 -0
  26. package/build/api/content/navbar.d.ts +10 -0
  27. package/build/api/content/navbar.d.ts.map +1 -0
  28. package/build/api/content/navbar.js +45 -0
  29. package/build/api/content/navbar.js.map +1 -0
  30. package/build/api/content/page.d.ts +11 -0
  31. package/build/api/content/page.d.ts.map +1 -0
  32. package/build/api/content/page.js +2 -0
  33. package/build/api/content/page.js.map +1 -0
  34. package/build/api/content/scan.d.ts +19 -0
  35. package/build/api/content/scan.d.ts.map +1 -0
  36. package/build/api/content/scan.js +90 -0
  37. package/build/api/content/scan.js.map +1 -0
  38. package/build/api/content/sidebar.d.ts +104 -0
  39. package/build/api/content/sidebar.d.ts.map +1 -0
  40. package/build/api/content/sidebar.js +166 -0
  41. package/build/api/content/sidebar.js.map +1 -0
  42. package/build/api/content/utils.d.ts +5 -0
  43. package/build/api/content/utils.d.ts.map +1 -0
  44. package/build/api/content/utils.js +8 -0
  45. package/build/api/content/utils.js.map +1 -0
  46. package/build/api/schema/data-sources/schema-directory/schema-directory.js +1 -1
  47. package/build/api/schema/data-sources/schema-directory/schema-directory.js.map +1 -1
  48. package/build/api/static/index.d.ts +2 -0
  49. package/build/api/static/index.d.ts.map +1 -0
  50. package/build/api/static/index.js +2 -0
  51. package/build/api/static/index.js.map +1 -0
  52. package/build/api/static/manifest.d.ts +18 -0
  53. package/build/api/static/manifest.d.ts.map +1 -0
  54. package/build/api/static/manifest.js +13 -0
  55. package/build/api/static/manifest.js.map +1 -0
  56. package/build/api/static/rebase.d.ts +14 -0
  57. package/build/api/static/rebase.d.ts.map +1 -0
  58. package/build/api/static/rebase.js +110 -0
  59. package/build/api/static/rebase.js.map +1 -0
  60. package/build/api/static/static.d.ts +3 -0
  61. package/build/api/static/static.d.ts.map +1 -0
  62. package/build/api/static/static.js +3 -0
  63. package/build/api/static/static.js.map +1 -0
  64. package/build/api/vite/plugins/branding/index.d.ts +4 -0
  65. package/build/api/vite/plugins/branding/index.d.ts.map +1 -0
  66. package/build/api/vite/plugins/branding/index.js +80 -0
  67. package/build/api/vite/plugins/branding/index.js.map +1 -0
  68. package/build/api/vite/plugins/build.d.ts.map +1 -1
  69. package/build/api/vite/plugins/build.js +22 -1
  70. package/build/api/vite/plugins/build.js.map +1 -1
  71. package/build/api/vite/plugins/core.d.ts +2 -2
  72. package/build/api/vite/plugins/core.d.ts.map +1 -1
  73. package/build/api/vite/plugins/core.js +4 -5
  74. package/build/api/vite/plugins/core.js.map +1 -1
  75. package/build/api/vite/plugins/main.d.ts.map +1 -1
  76. package/build/api/vite/plugins/main.js +2 -1
  77. package/build/api/vite/plugins/main.js.map +1 -1
  78. package/build/api/vite/plugins/pages.d.ts +8 -14
  79. package/build/api/vite/plugins/pages.d.ts.map +1 -1
  80. package/build/api/vite/plugins/pages.js +110 -183
  81. package/build/api/vite/plugins/pages.js.map +1 -1
  82. package/build/api/vite/plugins/serve.js +5 -5
  83. package/build/api/vite/plugins/serve.js.map +1 -1
  84. package/build/cli/_/self-contained-mode.js +5 -5
  85. package/build/cli/_/self-contained-mode.js.map +1 -1
  86. package/build/cli/commands/static/$default.d.ts +3 -0
  87. package/build/cli/commands/static/$default.d.ts.map +1 -0
  88. package/build/cli/commands/static/$default.js +38 -0
  89. package/build/cli/commands/static/$default.js.map +1 -0
  90. package/build/cli/commands/static/rebase.d.ts +2 -0
  91. package/build/cli/commands/static/rebase.d.ts.map +1 -0
  92. package/build/cli/commands/static/rebase.js +26 -0
  93. package/build/cli/commands/static/rebase.js.map +1 -0
  94. package/build/cli/commands/static.d.ts +3 -0
  95. package/build/cli/commands/static.d.ts.map +1 -0
  96. package/build/cli/commands/static.js +5 -0
  97. package/build/cli/commands/static.js.map +1 -0
  98. package/build/exports/components.d.ts +2 -0
  99. package/build/exports/components.d.ts.map +1 -0
  100. package/build/exports/components.js +2 -0
  101. package/build/exports/components.js.map +1 -0
  102. package/build/lib/demos/builder.d.ts +83 -0
  103. package/build/lib/demos/builder.d.ts.map +1 -0
  104. package/build/lib/demos/builder.js +237 -0
  105. package/build/lib/demos/builder.js.map +1 -0
  106. package/build/lib/demos/config-schema.d.ts +243 -0
  107. package/build/lib/demos/config-schema.d.ts.map +1 -0
  108. package/build/lib/demos/config-schema.js +52 -0
  109. package/build/lib/demos/config-schema.js.map +1 -0
  110. package/build/lib/demos/config.d.ts +40 -0
  111. package/build/lib/demos/config.d.ts.map +1 -0
  112. package/build/lib/demos/config.js +180 -0
  113. package/build/lib/demos/config.js.map +1 -0
  114. package/build/lib/demos/index.d.ts +9 -0
  115. package/build/lib/demos/index.d.ts.map +1 -0
  116. package/build/lib/demos/index.js +8 -0
  117. package/build/lib/demos/index.js.map +1 -0
  118. package/build/lib/demos/ui/components.d.ts +33 -0
  119. package/build/lib/demos/ui/components.d.ts.map +1 -0
  120. package/build/lib/demos/ui/components.js +699 -0
  121. package/build/lib/demos/ui/components.js.map +1 -0
  122. package/build/lib/demos/ui/data-collector.d.ts +88 -0
  123. package/build/lib/demos/ui/data-collector.d.ts.map +1 -0
  124. package/build/lib/demos/ui/data-collector.js +174 -0
  125. package/build/lib/demos/ui/data-collector.js.map +1 -0
  126. package/build/lib/demos/ui/landing-page-cli.d.ts +3 -0
  127. package/build/lib/demos/ui/landing-page-cli.d.ts.map +1 -0
  128. package/build/lib/demos/ui/landing-page-cli.js +21 -0
  129. package/build/lib/demos/ui/landing-page-cli.js.map +1 -0
  130. package/build/lib/demos/ui/landing-page.d.ts +32 -0
  131. package/build/lib/demos/ui/landing-page.d.ts.map +1 -0
  132. package/build/lib/demos/ui/landing-page.js +83 -0
  133. package/build/lib/demos/ui/landing-page.js.map +1 -0
  134. package/build/lib/demos/ui/page-renderer.d.ts +26 -0
  135. package/build/lib/demos/ui/page-renderer.d.ts.map +1 -0
  136. package/build/lib/demos/ui/page-renderer.js +104 -0
  137. package/build/lib/demos/ui/page-renderer.js.map +1 -0
  138. package/build/lib/demos/utils.d.ts +14 -0
  139. package/build/lib/demos/utils.d.ts.map +1 -0
  140. package/build/lib/demos/utils.js +37 -0
  141. package/build/lib/demos/utils.js.map +1 -0
  142. package/build/lib/deployment/$$.d.ts +3 -0
  143. package/build/lib/deployment/$$.d.ts.map +1 -0
  144. package/build/lib/deployment/$$.js +3 -0
  145. package/build/lib/deployment/$$.js.map +1 -0
  146. package/build/lib/deployment/$.d.ts +2 -0
  147. package/build/lib/deployment/$.d.ts.map +1 -0
  148. package/build/lib/deployment/$.js +2 -0
  149. package/build/lib/deployment/$.js.map +1 -0
  150. package/build/lib/deployment/metadata.d.ts +32 -0
  151. package/build/lib/deployment/metadata.d.ts.map +1 -0
  152. package/build/lib/deployment/metadata.js +37 -0
  153. package/build/lib/deployment/metadata.js.map +1 -0
  154. package/build/lib/deployment/path-manager.d.ts +41 -0
  155. package/build/lib/deployment/path-manager.d.ts.map +1 -0
  156. package/build/lib/deployment/path-manager.js +157 -0
  157. package/build/lib/deployment/path-manager.js.map +1 -0
  158. package/build/lib/file-router/file-router.d.ts +0 -2
  159. package/build/lib/file-router/file-router.d.ts.map +1 -1
  160. package/build/lib/file-router/file-router.js +0 -2
  161. package/build/lib/file-router/file-router.js.map +1 -1
  162. package/build/lib/file-router/route.d.ts +2 -0
  163. package/build/lib/file-router/route.d.ts.map +1 -1
  164. package/build/lib/file-router/route.js.map +1 -1
  165. package/build/lib/file-router/scan.d.ts.map +1 -1
  166. package/build/lib/file-router/scan.js +22 -13
  167. package/build/lib/file-router/scan.js.map +1 -1
  168. package/build/lib/github-actions/git-controller.d.ts +50 -0
  169. package/build/lib/github-actions/git-controller.d.ts.map +1 -0
  170. package/build/lib/github-actions/git-controller.js +90 -0
  171. package/build/lib/github-actions/git-controller.js.map +1 -0
  172. package/build/lib/github-actions/github-actions.d.ts +7 -0
  173. package/build/lib/github-actions/github-actions.d.ts.map +1 -0
  174. package/build/lib/github-actions/github-actions.js +7 -0
  175. package/build/lib/github-actions/github-actions.js.map +1 -0
  176. package/build/lib/github-actions/index.d.ts +2 -0
  177. package/build/lib/github-actions/index.d.ts.map +1 -0
  178. package/build/lib/github-actions/index.js +2 -0
  179. package/build/lib/github-actions/index.js.map +1 -0
  180. package/build/lib/github-actions/lib/get-pr-deployments.d.ts +12 -0
  181. package/build/lib/github-actions/lib/get-pr-deployments.d.ts.map +1 -0
  182. package/build/lib/github-actions/lib/get-pr-deployments.js +51 -0
  183. package/build/lib/github-actions/lib/get-pr-deployments.js.map +1 -0
  184. package/build/lib/github-actions/pr-controller.d.ts +39 -0
  185. package/build/lib/github-actions/pr-controller.d.ts.map +1 -0
  186. package/build/lib/github-actions/pr-controller.js +122 -0
  187. package/build/lib/github-actions/pr-controller.js.map +1 -0
  188. package/build/lib/github-actions/run-step-cli.d.ts +9 -0
  189. package/build/lib/github-actions/run-step-cli.d.ts.map +1 -0
  190. package/build/lib/github-actions/run-step-cli.js +71 -0
  191. package/build/lib/github-actions/run-step-cli.js.map +1 -0
  192. package/build/lib/github-actions/runner.d.ts +17 -0
  193. package/build/lib/github-actions/runner.d.ts.map +1 -0
  194. package/build/lib/github-actions/runner.js +195 -0
  195. package/build/lib/github-actions/runner.js.map +1 -0
  196. package/build/lib/github-actions/schemas/context.d.ts +933 -0
  197. package/build/lib/github-actions/schemas/context.d.ts.map +1 -0
  198. package/build/lib/github-actions/schemas/context.js +407 -0
  199. package/build/lib/github-actions/schemas/context.js.map +1 -0
  200. package/build/lib/github-actions/schemas/index.d.ts +5 -0
  201. package/build/lib/github-actions/schemas/index.d.ts.map +1 -0
  202. package/build/lib/github-actions/schemas/index.js +5 -0
  203. package/build/lib/github-actions/schemas/index.js.map +1 -0
  204. package/build/lib/github-actions/search-module.d.ts +38 -0
  205. package/build/lib/github-actions/search-module.d.ts.map +1 -0
  206. package/build/lib/github-actions/search-module.js +40 -0
  207. package/build/lib/github-actions/search-module.js.map +1 -0
  208. package/build/lib/github-actions/step.d.ts +163 -0
  209. package/build/lib/github-actions/step.d.ts.map +1 -0
  210. package/build/lib/github-actions/step.js +121 -0
  211. package/build/lib/github-actions/step.js.map +1 -0
  212. package/build/lib/helpers.d.ts.map +1 -1
  213. package/build/lib/helpers.js +5 -3
  214. package/build/lib/helpers.js.map +1 -1
  215. package/build/lib/kit-temp.d.ts +54 -0
  216. package/build/lib/kit-temp.d.ts.map +1 -1
  217. package/build/lib/kit-temp.js +82 -14
  218. package/build/lib/kit-temp.js.map +1 -1
  219. package/build/lib/kit-temp.test-d.d.ts +2 -0
  220. package/build/lib/kit-temp.test-d.d.ts.map +1 -0
  221. package/build/lib/kit-temp.test-d.js +75 -0
  222. package/build/lib/kit-temp.test-d.js.map +1 -0
  223. package/build/lib/mask/$$.d.ts +3 -0
  224. package/build/lib/mask/$$.d.ts.map +1 -0
  225. package/build/lib/mask/$$.js +3 -0
  226. package/build/lib/mask/$$.js.map +1 -0
  227. package/build/lib/mask/$.d.ts +2 -0
  228. package/build/lib/mask/$.d.ts.map +1 -0
  229. package/build/lib/mask/$.js +2 -0
  230. package/build/lib/mask/$.js.map +1 -0
  231. package/build/lib/mask/apply.d.ts +86 -0
  232. package/build/lib/mask/apply.d.ts.map +1 -0
  233. package/build/lib/mask/apply.js +86 -0
  234. package/build/lib/mask/apply.js.map +1 -0
  235. package/build/lib/mask/mask.d.ts +124 -0
  236. package/build/lib/mask/mask.d.ts.map +1 -0
  237. package/build/lib/mask/mask.js +137 -0
  238. package/build/lib/mask/mask.js.map +1 -0
  239. package/build/lib/mask/mask.test-d.d.ts +2 -0
  240. package/build/lib/mask/mask.test-d.d.ts.map +1 -0
  241. package/build/lib/mask/mask.test-d.js +102 -0
  242. package/build/lib/mask/mask.test-d.js.map +1 -0
  243. package/build/lib/mutation-type.d.ts +18 -0
  244. package/build/lib/mutation-type.d.ts.map +1 -0
  245. package/build/lib/mutation-type.js +16 -0
  246. package/build/lib/mutation-type.js.map +1 -0
  247. package/build/lib/task/$$.d.ts +3 -0
  248. package/build/lib/task/$$.d.ts.map +1 -0
  249. package/build/lib/task/$$.js +3 -0
  250. package/build/lib/task/$$.js.map +1 -0
  251. package/build/lib/task/$.d.ts +2 -0
  252. package/build/lib/task/$.d.ts.map +1 -0
  253. package/build/lib/task/$.js +2 -0
  254. package/build/lib/task/$.js.map +1 -0
  255. package/build/lib/task/report.d.ts +28 -0
  256. package/build/lib/task/report.d.ts.map +1 -0
  257. package/build/lib/task/report.js +33 -0
  258. package/build/lib/task/report.js.map +1 -0
  259. package/build/lib/task/task.d.ts +44 -0
  260. package/build/lib/task/task.d.ts.map +1 -0
  261. package/build/lib/task/task.js +63 -0
  262. package/build/lib/task/task.js.map +1 -0
  263. package/build/lib/version-history/index.d.ts +3 -0
  264. package/build/lib/version-history/index.d.ts.map +1 -0
  265. package/build/lib/version-history/index.js +2 -0
  266. package/build/lib/version-history/index.js.map +1 -0
  267. package/build/lib/version-history/types.d.ts +64 -0
  268. package/build/lib/version-history/types.d.ts.map +1 -0
  269. package/build/lib/version-history/types.js +5 -0
  270. package/build/lib/version-history/types.js.map +1 -0
  271. package/build/lib/version-history/version-history.d.ts +85 -0
  272. package/build/lib/version-history/version-history.d.ts.map +1 -0
  273. package/build/lib/version-history/version-history.js +248 -0
  274. package/build/lib/version-history/version-history.js.map +1 -0
  275. package/build/project-data.d.ts +0 -1
  276. package/build/project-data.d.ts.map +1 -1
  277. package/build/sandbox.d.ts +2 -0
  278. package/build/sandbox.d.ts.map +1 -0
  279. package/build/sandbox.js +18 -0
  280. package/build/sandbox.js.map +1 -0
  281. package/build/singletons/debug.d.ts +1 -1
  282. package/build/singletons/debug.d.ts.map +1 -1
  283. package/build/singletons/debug.js +1 -1
  284. package/build/singletons/debug.js.map +1 -1
  285. package/build/template/components/HamburgerMenu.d.ts +9 -0
  286. package/build/template/components/HamburgerMenu.d.ts.map +1 -0
  287. package/build/template/components/HamburgerMenu.jsx +53 -0
  288. package/build/template/components/HamburgerMenu.jsx.map +1 -0
  289. package/build/template/components/Link.jsx +1 -1
  290. package/build/template/components/Logo.d.ts +9 -0
  291. package/build/template/components/Logo.d.ts.map +1 -0
  292. package/build/template/components/Logo.jsx +29 -0
  293. package/build/template/components/Logo.jsx.map +1 -0
  294. package/build/template/components/NotFound.d.ts +2 -0
  295. package/build/template/components/NotFound.d.ts.map +1 -0
  296. package/build/template/components/NotFound.jsx +26 -0
  297. package/build/template/components/NotFound.jsx.map +1 -0
  298. package/build/template/components/ThemeToggle.d.ts +3 -0
  299. package/build/template/components/ThemeToggle.d.ts.map +1 -0
  300. package/build/template/components/ThemeToggle.jsx +10 -0
  301. package/build/template/components/ThemeToggle.jsx.map +1 -0
  302. package/build/template/components/content/$$.d.ts +2 -0
  303. package/build/template/components/content/$$.d.ts.map +1 -0
  304. package/build/template/components/content/$$.js +2 -0
  305. package/build/template/components/content/$$.js.map +1 -0
  306. package/build/template/components/sidebar/Sidebar.d.ts +2 -2
  307. package/build/template/components/sidebar/Sidebar.d.ts.map +1 -1
  308. package/build/template/components/sidebar/SidebarItem.d.ts +3 -3
  309. package/build/template/components/sidebar/SidebarItem.d.ts.map +1 -1
  310. package/build/template/components/sidebar/SidebarItem.jsx +1 -1
  311. package/build/template/components/sidebar/SidebarItem.jsx.map +1 -1
  312. package/build/template/contexts/ThemeContext.d.ts +12 -0
  313. package/build/template/contexts/ThemeContext.d.ts.map +1 -0
  314. package/build/template/contexts/ThemeContext.jsx +41 -0
  315. package/build/template/contexts/ThemeContext.jsx.map +1 -0
  316. package/build/template/routes/root.d.ts.map +1 -1
  317. package/build/template/routes/root.jsx +66 -53
  318. package/build/template/routes/root.jsx.map +1 -1
  319. package/build/template/server/app.d.ts.map +1 -1
  320. package/build/template/server/app.js +2 -21
  321. package/build/template/server/app.js.map +1 -1
  322. package/package.json +27 -13
  323. package/src/api/api.ts +1 -0
  324. package/src/api/config/configurator.ts +28 -6
  325. package/src/api/config/load.ts +5 -5
  326. package/src/api/config-resolver/resolve.ts +2 -2
  327. package/src/api/content/$$.ts +6 -0
  328. package/src/api/content/$.test.ts +72 -0
  329. package/src/api/content/$.ts +1 -0
  330. package/src/api/content/metadata.ts +11 -0
  331. package/src/api/content/navbar.test.ts +55 -0
  332. package/src/api/content/navbar.ts +61 -0
  333. package/src/api/content/page.ts +12 -0
  334. package/src/api/content/scan.ts +117 -0
  335. package/src/api/content/sidebar.test.ts +297 -0
  336. package/src/api/content/sidebar.ts +283 -0
  337. package/src/api/content/utils.ts +7 -0
  338. package/src/api/schema/data-sources/schema-directory/schema-directory.ts +1 -1
  339. package/src/api/singletons/markdown/markdown.test.ts +1 -1
  340. package/src/api/static/index.ts +1 -0
  341. package/src/api/static/manifest.test.ts +106 -0
  342. package/src/api/static/manifest.ts +16 -0
  343. package/src/api/static/rebase.test.ts +229 -0
  344. package/src/api/static/rebase.ts +140 -0
  345. package/src/api/static/static.ts +2 -0
  346. package/src/api/utils/asset-url/asset-url.test.ts +4 -4
  347. package/src/api/vite/plugins/branding/index.ts +108 -0
  348. package/src/api/vite/plugins/build.ts +25 -1
  349. package/src/api/vite/plugins/core.ts +6 -7
  350. package/src/api/vite/plugins/main.ts +2 -0
  351. package/src/api/vite/plugins/pages.ts +131 -207
  352. package/src/api/vite/plugins/serve.ts +5 -5
  353. package/src/cli/_/self-contained-mode.ts +5 -5
  354. package/src/cli/commands/static/$default.ts +43 -0
  355. package/src/cli/commands/static/rebase.ts +37 -0
  356. package/src/cli/commands/static.ts +6 -0
  357. package/src/exports/components.ts +1 -0
  358. package/src/lib/demos/builder.ts +298 -0
  359. package/src/lib/demos/config-schema.ts +56 -0
  360. package/src/lib/demos/config.test.ts +193 -0
  361. package/src/lib/demos/config.ts +205 -0
  362. package/src/lib/demos/index.ts +9 -0
  363. package/src/lib/demos/ui/components.ts +739 -0
  364. package/src/lib/demos/ui/data-collector.ts +246 -0
  365. package/src/lib/demos/ui/landing-page-cli.ts +23 -0
  366. package/src/lib/demos/ui/landing-page.ts +126 -0
  367. package/src/lib/demos/ui/page-renderer.ts +124 -0
  368. package/src/lib/demos/utils.ts +43 -0
  369. package/src/lib/deployment/$$.ts +2 -0
  370. package/src/lib/deployment/$.test.ts +53 -0
  371. package/src/lib/deployment/$.ts +1 -0
  372. package/src/lib/deployment/metadata.ts +40 -0
  373. package/src/lib/deployment/path-manager.ts +186 -0
  374. package/src/lib/file-router/file-router.ts +0 -2
  375. package/src/lib/file-router/linter.test.ts +2 -0
  376. package/src/lib/file-router/route.ts +2 -0
  377. package/src/lib/file-router/scan.ts +26 -14
  378. package/src/lib/github-actions/git-controller.ts +151 -0
  379. package/src/lib/github-actions/github-actions.ts +6 -0
  380. package/src/lib/github-actions/index.ts +1 -0
  381. package/src/lib/github-actions/lib/get-pr-deployments.ts +76 -0
  382. package/src/lib/github-actions/pr-controller.test.ts +172 -0
  383. package/src/lib/github-actions/pr-controller.ts +183 -0
  384. package/src/lib/github-actions/run-step-cli.ts +84 -0
  385. package/src/lib/github-actions/runner.test.ts +192 -0
  386. package/src/lib/github-actions/runner.ts +226 -0
  387. package/src/lib/github-actions/schemas/context.ts +424 -0
  388. package/src/lib/github-actions/schemas/index.ts +5 -0
  389. package/src/lib/github-actions/search-module.test.ts +110 -0
  390. package/src/lib/github-actions/search-module.ts +76 -0
  391. package/src/lib/github-actions/step.test.ts +149 -0
  392. package/src/lib/github-actions/step.ts +232 -0
  393. package/src/lib/helpers.ts +4 -3
  394. package/src/lib/kit-temp.test-d.ts +115 -0
  395. package/src/lib/kit-temp.test.ts +127 -0
  396. package/src/lib/kit-temp.ts +128 -14
  397. package/src/lib/mask/$$.ts +2 -0
  398. package/src/lib/mask/$.test.ts +248 -0
  399. package/src/lib/mask/$.ts +1 -0
  400. package/src/lib/mask/apply.ts +134 -0
  401. package/src/lib/mask/mask.test-d.ts +144 -0
  402. package/src/lib/mask/mask.ts +244 -0
  403. package/src/lib/mutation-type.ts +20 -0
  404. package/src/lib/shiki/shiki.test.ts +1 -1
  405. package/src/lib/task/$$.ts +2 -0
  406. package/src/lib/task/$.test.ts +209 -0
  407. package/src/lib/task/$.ts +1 -0
  408. package/src/lib/task/report.ts +72 -0
  409. package/src/lib/task/task.ts +112 -0
  410. package/src/lib/version-history/index.test.ts +196 -0
  411. package/src/lib/version-history/index.ts +4 -0
  412. package/src/lib/version-history/types.ts +68 -0
  413. package/src/lib/version-history/version-history.ts +293 -0
  414. package/src/project-data.ts +0 -1
  415. package/src/sandbox.ts +20 -0
  416. package/src/singletons/debug.ts +1 -1
  417. package/src/template/components/HamburgerMenu.tsx +96 -0
  418. package/src/template/components/Link.tsx +1 -1
  419. package/src/template/components/Logo.tsx +46 -0
  420. package/src/template/components/NotFound.tsx +28 -0
  421. package/src/template/components/ThemeToggle.tsx +21 -0
  422. package/src/template/components/content/$$.ts +1 -0
  423. package/src/template/components/sidebar/Sidebar.tsx +2 -2
  424. package/src/template/components/sidebar/SidebarItem.tsx +8 -8
  425. package/src/template/contexts/ThemeContext.tsx +60 -0
  426. package/src/template/routes/root.tsx +85 -74
  427. package/src/template/server/app.ts +2 -27
  428. package/build/lib/file-router/scan-tree.d.ts +0 -20
  429. package/build/lib/file-router/scan-tree.d.ts.map +0 -1
  430. package/build/lib/file-router/scan-tree.js +0 -158
  431. package/build/lib/file-router/scan-tree.js.map +0 -1
  432. package/build/lib/file-router/sidebar/index.d.ts +0 -3
  433. package/build/lib/file-router/sidebar/index.d.ts.map +0 -1
  434. package/build/lib/file-router/sidebar/index.js +0 -4
  435. package/build/lib/file-router/sidebar/index.js.map +0 -1
  436. package/build/lib/file-router/sidebar/sidebar-tree.d.ts +0 -9
  437. package/build/lib/file-router/sidebar/sidebar-tree.d.ts.map +0 -1
  438. package/build/lib/file-router/sidebar/sidebar-tree.js +0 -85
  439. package/build/lib/file-router/sidebar/sidebar-tree.js.map +0 -1
  440. package/build/lib/file-router/sidebar/types.d.ts +0 -17
  441. package/build/lib/file-router/sidebar/types.d.ts.map +0 -1
  442. package/build/lib/file-router/sidebar/types.js +0 -2
  443. package/build/lib/file-router/sidebar/types.js.map +0 -1
  444. package/build/lib/tree/index.d.ts +0 -3
  445. package/build/lib/tree/index.d.ts.map +0 -1
  446. package/build/lib/tree/index.js +0 -2
  447. package/build/lib/tree/index.js.map +0 -1
  448. package/build/lib/tree/tree.d.ts +0 -62
  449. package/build/lib/tree/tree.d.ts.map +0 -1
  450. package/build/lib/tree/tree.js +0 -134
  451. package/build/lib/tree/tree.js.map +0 -1
  452. package/src/lib/file-router/scan-tree.test.ts +0 -189
  453. package/src/lib/file-router/scan-tree.ts +0 -205
  454. package/src/lib/file-router/sidebar/index.ts +0 -3
  455. package/src/lib/file-router/sidebar/sidebar-tree.test.ts +0 -123
  456. package/src/lib/file-router/sidebar/sidebar-tree.ts +0 -110
  457. package/src/lib/file-router/sidebar/types.ts +0 -19
  458. package/src/lib/tree/index.ts +0 -2
  459. package/src/lib/tree/tree.test.ts +0 -117
  460. package/src/lib/tree/tree.ts +0 -183
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Deployment path management for demos
3
+ */
4
+
5
+ import { promises as fs } from 'node:fs'
6
+ import { join } from 'node:path'
7
+
8
+ export interface RedirectConfig {
9
+ from: string
10
+ to: string
11
+ type?: 'html' | 'meta'
12
+ }
13
+
14
+ /**
15
+ * Manages deployment paths and base path updates for demo files
16
+ */
17
+ export class PathManager {
18
+ constructor() {}
19
+
20
+ /**
21
+ * Generate HTML redirect pages
22
+ */
23
+ async generateRedirects(redirects: RedirectConfig[], outputDir: string): Promise<void> {
24
+ try {
25
+ for (const redirect of redirects) {
26
+ const redirectPath = join(outputDir, redirect.from, 'index.html')
27
+ const redirectDir = join(outputDir, redirect.from)
28
+
29
+ await fs.mkdir(redirectDir, { recursive: true })
30
+
31
+ const html = this.createRedirectHtml(redirect.to)
32
+ await fs.writeFile(redirectPath, html)
33
+ }
34
+ } catch (error) {
35
+ throw new Error(`Failed to generate redirects: ${error instanceof Error ? error.message : String(error)}`)
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Create convenience redirects for demo examples
41
+ */
42
+ async createDemoRedirects(
43
+ examples: string[],
44
+ outputDir: string,
45
+ targetBasePath: string = '/latest/',
46
+ ): Promise<void> {
47
+ const redirects: RedirectConfig[] = examples.map(example => ({
48
+ from: example,
49
+ to: `${targetBasePath}${example}/`,
50
+ }))
51
+
52
+ await this.generateRedirects(redirects, outputDir)
53
+ }
54
+
55
+ /**
56
+ * Validate deployment structure
57
+ */
58
+ async validateDeploymentStructure(deploymentDir: string): Promise<{
59
+ valid: boolean
60
+ errors: string[]
61
+ warnings: string[]
62
+ }> {
63
+ const errors: string[] = []
64
+ const warnings: string[] = []
65
+
66
+ try {
67
+ // Check if deployment directory exists
68
+ await fs.access(deploymentDir)
69
+ } catch {
70
+ errors.push(`Deployment directory does not exist: ${deploymentDir}`)
71
+ return { valid: false, errors, warnings }
72
+ }
73
+
74
+ try {
75
+ // Check for index.html
76
+ const indexPath = join(deploymentDir, 'index.html')
77
+ await fs.access(indexPath)
78
+ } catch {
79
+ warnings.push('No index.html found in deployment root')
80
+ }
81
+
82
+ return {
83
+ valid: errors.length === 0,
84
+ errors,
85
+ warnings,
86
+ }
87
+ }
88
+
89
+ /**
90
+ * Clean up old deployment directories
91
+ */
92
+ async cleanupOldDeployments(
93
+ parentDir: string,
94
+ keepVersions: string[],
95
+ dryRun: boolean = false,
96
+ ): Promise<{ removed: string[]; kept: string[]; errors: string[] }> {
97
+ const removed: string[] = []
98
+ const kept: string[] = []
99
+ const errors: string[] = []
100
+
101
+ try {
102
+ const entries = await fs.readdir(parentDir, { withFileTypes: true })
103
+ const directories = entries
104
+ .filter(entry => entry.isDirectory())
105
+ .map(entry => entry.name)
106
+
107
+ for (const dir of directories) {
108
+ if (keepVersions.includes(dir)) {
109
+ kept.push(dir)
110
+ } else if (this.isSemverDirectory(dir)) {
111
+ if (!dryRun) {
112
+ try {
113
+ await fs.rm(join(parentDir, dir), { recursive: true, force: true })
114
+ removed.push(dir)
115
+ } catch (error) {
116
+ errors.push(`Failed to remove ${dir}: ${error}`)
117
+ }
118
+ } else {
119
+ removed.push(dir) // Dry run - just track what would be removed
120
+ }
121
+ } else {
122
+ kept.push(dir) // Keep non-semver directories
123
+ }
124
+ }
125
+ } catch (error) {
126
+ throw new Error(
127
+ `Failed to cleanup deployments in ${parentDir}: ${error instanceof Error ? error.message : String(error)}`,
128
+ )
129
+ }
130
+
131
+ return { removed, kept, errors }
132
+ }
133
+
134
+ // Private helper methods
135
+
136
+ private createRedirectHtml(targetUrl: string): string {
137
+ return `<!DOCTYPE html>
138
+ <html lang="en">
139
+ <head>
140
+ <meta charset="UTF-8">
141
+ <meta http-equiv="refresh" content="0; url=${targetUrl}">
142
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
143
+ <title>Redirecting...</title>
144
+ <style>
145
+ body {
146
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
147
+ display: flex;
148
+ align-items: center;
149
+ justify-content: center;
150
+ height: 100vh;
151
+ margin: 0;
152
+ background: #f5f5f5;
153
+ }
154
+ .redirect-message {
155
+ text-align: center;
156
+ padding: 2rem;
157
+ background: white;
158
+ border-radius: 8px;
159
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
160
+ }
161
+ .redirect-message a {
162
+ color: #0066cc;
163
+ text-decoration: none;
164
+ }
165
+ .redirect-message a:hover {
166
+ text-decoration: underline;
167
+ }
168
+ </style>
169
+ </head>
170
+ <body>
171
+ <div class="redirect-message">
172
+ <h1>Redirecting...</h1>
173
+ <p>If you are not redirected automatically, <a href="${targetUrl}">click here</a>.</p>
174
+ </div>
175
+ <script>
176
+ window.location.href = '${targetUrl}';
177
+ </script>
178
+ </body>
179
+ </html>`
180
+ }
181
+
182
+ private isSemverDirectory(name: string): boolean {
183
+ // Check if directory name looks like a semver version
184
+ return /^\d+\.\d+\.\d+/.test(name)
185
+ }
186
+ }
@@ -1,5 +1,3 @@
1
1
  export * from './linter.ts'
2
2
  export * from './route.ts'
3
- export * from './scan-tree.ts'
4
3
  export * from './scan.ts'
5
- export * from './sidebar/index.ts'
@@ -28,6 +28,8 @@ const createRoute = (path: string[], order?: number, isIndex = false): Route =>
28
28
  },
29
29
  },
30
30
  },
31
+ id: `/project/pages/${path.join('/')}/${name}.md`,
32
+ parentId: path.length > 1 ? `/project/pages/${path.slice(0, -1).join('/')}` : null,
31
33
  }
32
34
  }
33
35
 
@@ -36,6 +36,8 @@ export const pathToExpression = (path: Path) => {
36
36
  export interface Route {
37
37
  logical: RouteLogical
38
38
  file: RouteFile
39
+ id: string // Absolute file path for unique identification
40
+ parentId: string | null // Parent directory path, null for root-level files
39
41
  }
40
42
 
41
43
  export interface RouteLogical {
@@ -1,9 +1,7 @@
1
1
  import { TinyGlobby } from '#dep/tiny-globby/index'
2
- import { Tree } from '#lib/tree/index'
3
2
  import { Path, Str } from '@wollybeard/kit'
4
3
  import { type Diagnostic, lint } from './linter.ts'
5
- import { type Route, type RouteFile, type RouteLogical, routeToPathExpression } from './route.ts'
6
- import { scanTree } from './scan-tree.ts'
4
+ import { type Route, type RouteFile, type RouteLogical } from './route.ts'
7
5
 
8
6
  //
9
7
  //
@@ -47,21 +45,21 @@ export const scan = async (parameters: {
47
45
  dir: string
48
46
  glob?: string
49
47
  }): Promise<ScanResult> => {
50
- // Use tree-based scanner
51
- const treeResult = await scanTree(parameters)
52
-
53
- // Flatten tree to get routes
54
- const routes: Route[] = []
55
- Tree.visit(treeResult.routeTree, (node) => {
56
- if (node.value.type === 'file' && node.value.route) {
57
- routes.push(node.value.route)
58
- }
48
+ const { dir, glob = `**/*.{md,mdx}` } = parameters
49
+
50
+ // Get all files directly
51
+ const filePaths = await TinyGlobby.glob(glob, {
52
+ absolute: true,
53
+ cwd: dir,
54
+ onlyFiles: true,
59
55
  })
60
56
 
57
+ // Convert to routes
58
+ const routes = filePaths.map(filePath => filePathToRoute(filePath, dir))
59
+
61
60
  // Apply linting
62
61
  const lintResult = lint(routes)
63
62
 
64
- // Routes are already sorted by the tree structure
65
63
  return lintResult
66
64
  }
67
65
 
@@ -74,14 +72,28 @@ export const filePathToRoute = (filePathExpression: string, rootDir: string): Ro
74
72
  }
75
73
  const logical = filePathToRouteLogical(file.path.relative)
76
74
 
75
+ // Generate id and parentId for tree building
76
+ const id = filePathExpression // Use absolute path as unique ID
77
+ const relativePath = Path.relative(rootDir, filePathExpression)
78
+ const parentDir = Path.dirname(relativePath)
79
+ const parentId = parentDir === '.' ? null : Path.join(rootDir, parentDir)
80
+
77
81
  return {
78
82
  logical,
79
83
  file,
84
+ id,
85
+ parentId,
80
86
  }
81
87
  }
82
88
 
83
89
  export const filePathToRouteLogical = (filePath: Path.Parsed): RouteLogical => {
84
- const dirPath = Str.split(Str.removeSurrounding(filePath.dir, Path.sep), Path.sep)
90
+ const dirSegments = Str.split(Str.removeSurrounding(filePath.dir, Path.sep), Path.sep)
91
+
92
+ // Parse numbered prefixes from directory segments
93
+ const dirPath = dirSegments.map(segment => {
94
+ const prefixMatch = Str.match(segment, conventions.numberedPrefix.pattern)
95
+ return prefixMatch?.groups.name ?? segment
96
+ })
85
97
 
86
98
  // Parse numbered prefix from filename
87
99
  const prefixMatch = Str.match(filePath.name, conventions.numberedPrefix.pattern)
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Git controller for GitHub Actions
3
+ * Provides simple git operations without exposing subprocess details
4
+ */
5
+
6
+ import type { $ as ZxDollar } from 'zx'
7
+
8
+ export interface GitCommitOptions {
9
+ /**
10
+ * Commit message
11
+ */
12
+ message: string
13
+ /**
14
+ * Optional commit body for additional details
15
+ */
16
+ body?: string
17
+ /**
18
+ * Files or patterns to stage (defaults to '.')
19
+ */
20
+ add?: string | string[]
21
+ /**
22
+ * Working directory (defaults to current directory)
23
+ */
24
+ cwd?: string
25
+ /**
26
+ * Whether to push after committing (defaults to true)
27
+ */
28
+ push?: boolean
29
+ /**
30
+ * Whether to automatically configure the user to be GitHub (defaults to true)
31
+ */
32
+ autoConfigureUser?: boolean
33
+ }
34
+
35
+ export interface GitController {
36
+ /**
37
+ * Create a commit with the staged changes
38
+ */
39
+ commit(options: GitCommitOptions): Promise<boolean>
40
+
41
+ /**
42
+ * Check if there are any changes (staged or unstaged)
43
+ */
44
+ hasChanges(cwd?: string): Promise<boolean>
45
+
46
+ /**
47
+ * Configure git user for commits
48
+ */
49
+ configureUser(name?: string, email?: string): Promise<void>
50
+ }
51
+
52
+ /**
53
+ * Create a git controller instance
54
+ */
55
+ export function createGitController($: typeof ZxDollar): GitController {
56
+ const api: GitController = {
57
+ async commit(options) {
58
+ const {
59
+ message,
60
+ body,
61
+ add = '.',
62
+ cwd,
63
+ push = true,
64
+ autoConfigureUser = true,
65
+ } = options
66
+
67
+ const hasChanges = await api.hasChanges('gh-pages')
68
+ if (!hasChanges) {
69
+ console.log('No changes to commit')
70
+ return false
71
+ }
72
+
73
+ if (autoConfigureUser) {
74
+ await api.configureUser()
75
+ }
76
+
77
+ try {
78
+ // Stage files
79
+ const filesToAdd = Array.isArray(add) ? add : [add]
80
+ for (const pattern of filesToAdd) {
81
+ if (cwd) {
82
+ await $`cd ${cwd} && git add ${pattern}`
83
+ } else {
84
+ await $`git add ${pattern}`
85
+ }
86
+ }
87
+
88
+ // Check if there are changes to commit
89
+ const statusCmd = cwd ? $`cd ${cwd} && git status --porcelain` : $`git status --porcelain`
90
+ const status = await statusCmd
91
+
92
+ if (!status.stdout.trim()) {
93
+ return false // No changes to commit
94
+ }
95
+
96
+ // Build commit message
97
+ let fullMessage = message
98
+ if (body) {
99
+ fullMessage = `${message}\n\n${body}`
100
+ }
101
+
102
+ // Commit
103
+ if (cwd) {
104
+ await $`cd ${cwd} && git commit -m ${fullMessage}`
105
+ } else {
106
+ await $`git commit -m ${fullMessage}`
107
+ }
108
+
109
+ // Push if requested
110
+ if (push) {
111
+ if (cwd) {
112
+ await $`cd ${cwd} && git push`
113
+ } else {
114
+ await $`git push`
115
+ }
116
+ }
117
+
118
+ return true
119
+ } catch (error) {
120
+ throw new Error(`Git commit failed: ${error}`)
121
+ }
122
+ },
123
+
124
+ async hasChanges(cwd) {
125
+ try {
126
+ const cmd = cwd
127
+ ? $`cd ${cwd} && git status --porcelain`
128
+ : $`git status --porcelain`
129
+
130
+ const result = await cmd
131
+ return result.stdout.trim().length > 0
132
+ } catch (error) {
133
+ throw new Error(`Failed to check git status: ${error}`)
134
+ }
135
+ },
136
+
137
+ async configureUser(name, email) {
138
+ try {
139
+ const userName = name || 'github-actions[bot]'
140
+ const userEmail = email || 'github-actions[bot]@users.noreply.github.com'
141
+
142
+ await $`git config user.name ${userName}`
143
+ await $`git config user.email ${userEmail}`
144
+ } catch (error) {
145
+ throw new Error(`Failed to configure git user: ${error}`)
146
+ }
147
+ },
148
+ }
149
+
150
+ return api
151
+ }
@@ -0,0 +1,6 @@
1
+ export * from './git-controller.ts'
2
+ export * from './pr-controller.ts'
3
+ export * from './runner.ts'
4
+ export * from './schemas/index.ts'
5
+ export * from './search-module.ts'
6
+ export * from './step.ts'
@@ -0,0 +1 @@
1
+ export * as GitHubActions from './github-actions.ts'
@@ -0,0 +1,76 @@
1
+ import type { GitHub } from '@actions/github/lib/utils.ts'
2
+
3
+ export interface Deployment {
4
+ sha: string
5
+ shortSha: string
6
+ createdAt: string
7
+ status?: string
8
+ }
9
+
10
+ /**
11
+ * Fetch deployments for a specific PR using GitHub API
12
+ */
13
+ export async function fetchPullRequestDeployments(
14
+ github: InstanceType<typeof GitHub>,
15
+ owner: string,
16
+ repo: string,
17
+ prNumber: string | number,
18
+ ): Promise<Deployment[]> {
19
+ const deployments: Deployment[] = []
20
+
21
+ try {
22
+ // Get all deployments for this PR's environment
23
+ const { data: ghDeployments } = await github.rest.repos.listDeployments({
24
+ owner,
25
+ repo,
26
+ environment: `pr-${prNumber}`,
27
+ per_page: 100,
28
+ })
29
+
30
+ // Debug logging
31
+ console.log(`Found ${ghDeployments.length} deployments for PR #${prNumber}`)
32
+
33
+ // Process each deployment
34
+ for (const deployment of ghDeployments) {
35
+ console.log(
36
+ `Processing deployment: ${deployment.id}, SHA: ${deployment.sha.substring(0, 7)}, Ref: ${deployment.ref}`,
37
+ )
38
+
39
+ // Get the latest status for this deployment
40
+ const { data: statuses } = await github.rest.repos.listDeploymentStatuses({
41
+ owner,
42
+ repo,
43
+ deployment_id: deployment.id,
44
+ per_page: 1,
45
+ })
46
+
47
+ const latestStatus = statuses[0]
48
+ const state = latestStatus?.state
49
+
50
+ console.log(` Status: ${state || 'no status'}`)
51
+
52
+ // Include successful and inactive deployments
53
+ if (state === 'success' || state === 'inactive') {
54
+ const shortSha = deployment.sha.substring(0, 7)
55
+
56
+ deployments.push({
57
+ sha: deployment.sha,
58
+ shortSha,
59
+ createdAt: deployment.created_at,
60
+ status: state,
61
+ })
62
+ console.log(` Added to deployments list`)
63
+ }
64
+ }
65
+
66
+ // Sort by creation date (newest first)
67
+ deployments.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())
68
+
69
+ console.log(`Returning ${deployments.length} successful deployments for PR #${prNumber}`)
70
+ } catch (error) {
71
+ console.error(`Error fetching deployments for PR #${prNumber}:`, error)
72
+ throw error
73
+ }
74
+
75
+ return deployments
76
+ }
@@ -0,0 +1,172 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
2
+ import { createPullRequestController } from './pr-controller.ts'
3
+
4
+ describe('createPRController', () => {
5
+ const mockGitHub = {
6
+ rest: {
7
+ issues: {
8
+ listComments: vi.fn(),
9
+ createComment: vi.fn(),
10
+ updateComment: vi.fn(),
11
+ deleteComment: vi.fn(),
12
+ },
13
+ },
14
+ } as any
15
+
16
+ const mockContext = {
17
+ eventName: 'pull_request',
18
+ repo: {
19
+ owner: 'test-owner',
20
+ repo: 'test-repo',
21
+ },
22
+ payload: {
23
+ pull_request: {
24
+ number: 123,
25
+ },
26
+ },
27
+ } as any
28
+
29
+ beforeEach(() => {
30
+ vi.clearAllMocks()
31
+ })
32
+
33
+ it('returns no-op controller for non-PR events', () => {
34
+ const nonPRContext = {
35
+ ...mockContext,
36
+ eventName: 'push',
37
+ payload: {},
38
+ }
39
+
40
+ const controller = createPullRequestController(mockGitHub, nonPRContext)
41
+ expect(controller).toBeDefined()
42
+ expect(controller.isActive).toBe(false)
43
+ expect(controller.number).toBe(0)
44
+ })
45
+
46
+ it('returns active PR controller for PR events', () => {
47
+ const controller = createPullRequestController(mockGitHub, mockContext)
48
+ expect(controller).toBeDefined()
49
+ expect(controller.isActive).toBe(true)
50
+ expect(controller.number).toBe(123)
51
+ })
52
+
53
+ describe('PR controller methods', () => {
54
+ it('creates new comment when none exists', async () => {
55
+ mockGitHub.rest.issues.listComments.mockResolvedValue({ data: [] })
56
+
57
+ const controller = createPullRequestController(mockGitHub, mockContext)!
58
+ await controller.comment({ id: 'test', content: 'Hello world' })
59
+
60
+ expect(mockGitHub.rest.issues.createComment).toHaveBeenCalledWith({
61
+ owner: 'test-owner',
62
+ repo: 'test-repo',
63
+ issue_number: 123,
64
+ body: 'Hello world\n\n<!-- comment-id: test -->',
65
+ })
66
+ })
67
+
68
+ it('uses default comment ID when not provided', async () => {
69
+ mockGitHub.rest.issues.listComments.mockResolvedValue({ data: [] })
70
+
71
+ const controller = createPullRequestController(mockGitHub, mockContext, 'pr-comment')!
72
+ await controller.comment({ content: 'Hello world' })
73
+
74
+ expect(mockGitHub.rest.issues.createComment).toHaveBeenCalledWith({
75
+ owner: 'test-owner',
76
+ repo: 'test-repo',
77
+ issue_number: 123,
78
+ body: 'Hello world\n\n<!-- comment-id: pr-comment -->',
79
+ })
80
+ })
81
+
82
+ it('updates existing comment', async () => {
83
+ mockGitHub.rest.issues.listComments.mockResolvedValue({
84
+ data: [
85
+ {
86
+ id: 456,
87
+ body: 'Old content\n\n<!-- comment-id: test -->',
88
+ },
89
+ ],
90
+ })
91
+
92
+ const controller = createPullRequestController(mockGitHub, mockContext)!
93
+ await controller.comment({ id: 'test', content: 'New content' })
94
+
95
+ expect(mockGitHub.rest.issues.updateComment).toHaveBeenCalledWith({
96
+ owner: 'test-owner',
97
+ repo: 'test-repo',
98
+ comment_id: 456,
99
+ body: 'New content\n\n<!-- comment-id: test -->',
100
+ })
101
+ })
102
+
103
+ it('deletes comment by ID', async () => {
104
+ mockGitHub.rest.issues.listComments.mockResolvedValue({
105
+ data: [
106
+ {
107
+ id: 456,
108
+ body: 'Content\n\n<!-- comment-id: test -->',
109
+ },
110
+ ],
111
+ })
112
+
113
+ const controller = createPullRequestController(mockGitHub, mockContext)!
114
+ await controller.deleteComment('test')
115
+
116
+ expect(mockGitHub.rest.issues.deleteComment).toHaveBeenCalledWith({
117
+ owner: 'test-owner',
118
+ repo: 'test-repo',
119
+ comment_id: 456,
120
+ })
121
+ })
122
+
123
+ it('handles issue_comment events on PRs', () => {
124
+ const issueCommentContext = {
125
+ ...mockContext,
126
+ eventName: 'issue_comment',
127
+ payload: {
128
+ issue: {
129
+ number: 789,
130
+ pull_request: {}, // Presence indicates it's a PR
131
+ },
132
+ },
133
+ }
134
+
135
+ const controller = createPullRequestController(mockGitHub, issueCommentContext)
136
+ expect(controller).toBeDefined()
137
+ expect(controller.number).toBe(789)
138
+ })
139
+ })
140
+
141
+ describe('No-op PR controller', () => {
142
+ it('throws error for non-optional comments', async () => {
143
+ const nonPRContext = {
144
+ ...mockContext,
145
+ eventName: 'push',
146
+ payload: {},
147
+ }
148
+
149
+ const controller = createPullRequestController(mockGitHub, nonPRContext)
150
+
151
+ await expect(controller.comment({ content: 'Test' })).rejects.toThrow(
152
+ 'Not in a PR context, cannot create comment',
153
+ )
154
+ })
155
+
156
+ it('logs and continues for optional comments', async () => {
157
+ const consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
158
+ const nonPRContext = {
159
+ ...mockContext,
160
+ eventName: 'push',
161
+ payload: {},
162
+ }
163
+
164
+ const controller = createPullRequestController(mockGitHub, nonPRContext)
165
+
166
+ await expect(controller.comment({ content: 'Test', optional: true })).resolves.not.toThrow()
167
+ expect(consoleLogSpy).toHaveBeenCalledWith('[skip] Not in a PR context, cannot create comment')
168
+
169
+ consoleLogSpy.mockRestore()
170
+ })
171
+ })
172
+ })