plum-e2e 2.10.0 → 2.12.1

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 (661) hide show
  1. package/.env +1 -1
  2. package/CLAUDE.md +1 -1
  3. package/README.md +28 -27
  4. package/backend/app.js +1 -1
  5. package/backend/lib/csv.js +21 -0
  6. package/backend/lib/exportResponse.js +37 -0
  7. package/backend/lib/serverBootstrap.js +2 -2
  8. package/backend/lib/serverConfig.js +5 -3
  9. package/backend/mcp/server.js +44 -0
  10. package/backend/middleware/runnerOrAdmin.js +1 -1
  11. package/backend/package.json +1 -1
  12. package/backend/routes/reports.routes.js +19 -0
  13. package/backend/routes/runners.routes.js +1 -1
  14. package/backend/routes/test-cases.routes.js +12 -0
  15. package/backend/routes/test-runs.routes.js +17 -0
  16. package/backend/routes/test-suites.routes.js +34 -0
  17. package/backend/scripts/{manage-runners.mjs → manage-nodes.mjs} +67 -52
  18. package/backend/services/exportService.js +339 -0
  19. package/backend/services/testImportService.js +87 -0
  20. package/bin/plum.js +201 -75
  21. package/docker-compose.yml +1 -1
  22. package/frontend/.svelte-kit/adapter-node/.vite/manifest.json +49 -41
  23. package/frontend/.svelte-kit/{output/server/_app/immutable/assets/Toast.DENwYn3g.css → adapter-node/_app/immutable/assets/Button.C1zsJAUG.css} +1 -1
  24. package/frontend/.svelte-kit/adapter-node/_app/immutable/assets/ExportMenu.DsJQ1Qua.css +6 -0
  25. package/frontend/.svelte-kit/{output/client/_app/immutable/assets/_layout.HkPnpRl9.css → adapter-node/_app/immutable/assets/_layout.DWCC-fI9.css} +1 -1
  26. package/frontend/.svelte-kit/adapter-node/_app/immutable/assets/_page.B3djLY18.css +6 -0
  27. package/frontend/.svelte-kit/adapter-node/_app/immutable/assets/_page.BNh9zY8Y.css +6 -0
  28. package/frontend/.svelte-kit/adapter-node/_app/immutable/assets/_page.D1jbMcpb.css +6 -0
  29. package/frontend/.svelte-kit/adapter-node/_app/immutable/assets/_page.DOC8fPSI.css +6 -0
  30. package/frontend/.svelte-kit/adapter-node/_app/immutable/assets/_page.Dm1nSEgE.css +6 -0
  31. package/frontend/.svelte-kit/adapter-node/chunks/{Toast.js → Button.js} +2 -17
  32. package/frontend/.svelte-kit/adapter-node/chunks/ConfirmModal.js +1 -1
  33. package/frontend/.svelte-kit/adapter-node/chunks/EmptyState.js +1 -1
  34. package/frontend/.svelte-kit/adapter-node/chunks/common.js +11 -4
  35. package/frontend/.svelte-kit/adapter-node/chunks/constants.js +1 -1
  36. package/frontend/.svelte-kit/adapter-node/chunks/internal.js +1 -1
  37. package/frontend/.svelte-kit/adapter-node/chunks/repository.js +21 -17
  38. package/frontend/.svelte-kit/adapter-node/entries/pages/live/_id_/_page.svelte.js +1 -1
  39. package/frontend/.svelte-kit/adapter-node/entries/pages/reports/_id_/_page.svelte.js +9 -2
  40. package/frontend/.svelte-kit/adapter-node/entries/pages/scheduled-tests/_page.svelte.js +2 -5
  41. package/frontend/.svelte-kit/adapter-node/entries/pages/settings/_page.svelte.js +300 -253
  42. package/frontend/.svelte-kit/adapter-node/entries/pages/test-repository/_page.svelte.js +63 -36
  43. package/frontend/.svelte-kit/adapter-node/entries/pages/test-repository/runs/_id_/_page.svelte.js +3 -6
  44. package/frontend/.svelte-kit/adapter-node/entries/pages/test-repository/suites/_id_/_page.svelte.js +15 -17
  45. package/frontend/.svelte-kit/adapter-node/manifest-full.js +1 -1
  46. package/frontend/.svelte-kit/adapter-node/manifest.js +1 -1
  47. package/frontend/.svelte-kit/adapter-node/nodes/0.js +2 -2
  48. package/frontend/.svelte-kit/adapter-node/nodes/1.js +1 -1
  49. package/frontend/.svelte-kit/adapter-node/nodes/10.js +2 -2
  50. package/frontend/.svelte-kit/adapter-node/nodes/11.js +2 -2
  51. package/frontend/.svelte-kit/adapter-node/nodes/12.js +2 -2
  52. package/frontend/.svelte-kit/adapter-node/nodes/2.js +1 -1
  53. package/frontend/.svelte-kit/adapter-node/nodes/3.js +2 -2
  54. package/frontend/.svelte-kit/adapter-node/nodes/4.js +1 -1
  55. package/frontend/.svelte-kit/adapter-node/nodes/5.js +1 -1
  56. package/frontend/.svelte-kit/adapter-node/nodes/6.js +2 -2
  57. package/frontend/.svelte-kit/adapter-node/nodes/7.js +2 -2
  58. package/frontend/.svelte-kit/adapter-node/nodes/8.js +2 -2
  59. package/frontend/.svelte-kit/adapter-node/nodes/9.js +1 -1
  60. package/frontend/.svelte-kit/generated/server/internal.js +1 -1
  61. package/frontend/.svelte-kit/output/client/.vite/manifest.json +451 -414
  62. package/frontend/.svelte-kit/output/client/_app/immutable/assets/{0.CmJTG5mP.css → 0.DbhNvxzA.css} +1 -1
  63. package/frontend/.svelte-kit/output/client/_app/immutable/assets/10.D2ehp3UL.css +6 -0
  64. package/frontend/.svelte-kit/output/client/_app/immutable/assets/12.Dm1nSEgE.css +6 -0
  65. package/frontend/.svelte-kit/output/client/_app/immutable/assets/3.B3djLY18.css +6 -0
  66. package/frontend/.svelte-kit/output/client/_app/immutable/assets/6.BofiCOMr.css +6 -0
  67. package/frontend/.svelte-kit/output/client/_app/immutable/assets/8.DOC8fPSI.css +6 -0
  68. package/frontend/.svelte-kit/{adapter-node/_app/immutable/assets/Toast.DENwYn3g.css → output/client/_app/immutable/assets/Button.C1zsJAUG.css} +1 -1
  69. package/frontend/.svelte-kit/output/client/_app/immutable/assets/ExportMenu.DsJQ1Qua.css +6 -0
  70. package/frontend/{build/client/_app/immutable/assets/_layout.HkPnpRl9.css → .svelte-kit/output/client/_app/immutable/assets/_layout.DWCC-fI9.css} +1 -1
  71. package/frontend/.svelte-kit/output/client/_app/immutable/assets/_page.B3djLY18.css +6 -0
  72. package/frontend/.svelte-kit/output/client/_app/immutable/assets/_page.BNh9zY8Y.css +6 -0
  73. package/frontend/.svelte-kit/output/client/_app/immutable/assets/_page.D1jbMcpb.css +6 -0
  74. package/frontend/.svelte-kit/output/client/_app/immutable/assets/_page.DOC8fPSI.css +6 -0
  75. package/frontend/.svelte-kit/output/client/_app/immutable/assets/_page.Dm1nSEgE.css +6 -0
  76. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/{C2_rQ4aY.js → 3MBVX4Yb.js} +1 -1
  77. package/frontend/{build/client/_app/immutable/chunks/CfkUW1vA.js → .svelte-kit/output/client/_app/immutable/chunks/6VDMVB5U.js} +1 -1
  78. package/frontend/{build/client/_app/immutable/chunks/B0_HKFXV.js → .svelte-kit/output/client/_app/immutable/chunks/B2lVGNml.js} +1 -1
  79. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/B74j8LrV.js +6 -0
  80. package/frontend/{build/client/_app/immutable/chunks/CboYYxrf.js → .svelte-kit/output/client/_app/immutable/chunks/BCh31ecr.js} +1 -1
  81. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/BDb8hZHu.js +6 -0
  82. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/BIDsfWFz.js +6 -0
  83. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/{CeH-RgMb.js → BIf7lHIm.js} +1 -1
  84. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/BTV7EXZb.js +11 -0
  85. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/{DAmOMhaf.js → BWGoOYU0.js} +1 -1
  86. package/frontend/{build/client/_app/immutable/chunks/DiVmSEJa.js → .svelte-kit/output/client/_app/immutable/chunks/BX-5iVGy.js} +2 -2
  87. package/frontend/{build/client/_app/immutable/chunks/BAvTKHxT.js → .svelte-kit/output/client/_app/immutable/chunks/BnXsGCy3.js} +1 -1
  88. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/C4Z3p6jE.js +6 -0
  89. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/CNpD-yNH.js +6 -0
  90. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/CUPWZLIN.js +6 -0
  91. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/{Ck6C3Fl0.js → CXQhSK1T.js} +1 -1
  92. package/frontend/{build/client/_app/immutable/chunks/C00jnSU2.js → .svelte-kit/output/client/_app/immutable/chunks/CtgCYzu5.js} +1 -1
  93. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/D72giPTu.js +6 -0
  94. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/{GDjpV3r7.js → DDx3no2z.js} +1 -1
  95. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/DFZtPGTY.js +6 -0
  96. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/D_thT6pZ.js +6 -0
  97. package/frontend/{build/client/_app/immutable/chunks/C8S7qQjQ.js → .svelte-kit/output/client/_app/immutable/chunks/DeiVAbyn.js} +1 -1
  98. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/Dn1b1Jgc.js +6 -0
  99. package/frontend/{build/client/_app/immutable/chunks/d2K3c8Kx.js → .svelte-kit/output/client/_app/immutable/chunks/QwDXcLXz.js} +1 -1
  100. package/frontend/{build/client/_app/immutable/chunks/Cgw8TOOy.js → .svelte-kit/output/client/_app/immutable/chunks/gCgJ3Cwu.js} +1 -1
  101. package/frontend/{build/client/_app/immutable/chunks/BJ_ypKl3.js → .svelte-kit/output/client/_app/immutable/chunks/htkwR9b-.js} +1 -1
  102. package/frontend/{build/client/_app/immutable/chunks/C7uEQ-LH.js → .svelte-kit/output/client/_app/immutable/chunks/iL4SCrvY.js} +1 -1
  103. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/{CoTEzvLa.js → kFFd6Oo5.js} +1 -1
  104. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/{DWzEJYIF.js → prk8PJfA.js} +1 -1
  105. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/qvxlSGpD.js +6 -0
  106. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/{B00vxw57.js → tsOANt55.js} +1 -1
  107. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/zXSLr47H.js +6 -0
  108. package/frontend/.svelte-kit/output/client/_app/immutable/entry/app.oEEXlUWx.js +7 -0
  109. package/frontend/{build/client/_app/immutable/entry/start.BXOLyf9R.js → .svelte-kit/output/client/_app/immutable/entry/start.BtJ124rC.js} +1 -1
  110. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/0.coxCxRRE.js +6 -0
  111. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/{1.BI97il3r.js → 1.C-Zryp-y.js} +1 -1
  112. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/10.CXqf0Rbs.js +6 -0
  113. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/11.PLIMGzrY.js +6 -0
  114. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/12.BGCTaTPG.js +6 -0
  115. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/{2.Dr6yugXz.js → 2.Bno00fr8.js} +1 -1
  116. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/3.HmZmGlze.js +6 -0
  117. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/{4.DDADylfF.js → 4.ahxFrDUH.js} +1 -1
  118. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/5.BXasF8ka.js +6 -0
  119. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/6.DYiAtU_m.js +10 -0
  120. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/7.B_XntBZ1.js +6 -0
  121. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/8.iy5VcxjU.js +9 -0
  122. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/{9.BOK0GNF_.js → 9.Bcqk4p04.js} +1 -1
  123. package/frontend/.svelte-kit/output/client/_app/version.json +1 -1
  124. package/frontend/.svelte-kit/output/server/.vite/manifest.json +49 -41
  125. package/frontend/{build/client/_app/immutable/assets/Toast.DENwYn3g.css → .svelte-kit/output/server/_app/immutable/assets/Button.C1zsJAUG.css} +1 -1
  126. package/frontend/.svelte-kit/output/server/_app/immutable/assets/ExportMenu.DsJQ1Qua.css +6 -0
  127. package/frontend/.svelte-kit/{adapter-node/_app/immutable/assets/_layout.HkPnpRl9.css → output/server/_app/immutable/assets/_layout.DWCC-fI9.css} +1 -1
  128. package/frontend/.svelte-kit/output/server/_app/immutable/assets/_page.B3djLY18.css +6 -0
  129. package/frontend/.svelte-kit/output/server/_app/immutable/assets/_page.BNh9zY8Y.css +6 -0
  130. package/frontend/.svelte-kit/output/server/_app/immutable/assets/_page.D1jbMcpb.css +6 -0
  131. package/frontend/.svelte-kit/output/server/_app/immutable/assets/_page.DOC8fPSI.css +6 -0
  132. package/frontend/.svelte-kit/output/server/_app/immutable/assets/_page.Dm1nSEgE.css +6 -0
  133. package/frontend/.svelte-kit/output/server/chunks/{Toast.js → Button.js} +2 -17
  134. package/frontend/.svelte-kit/output/server/chunks/ConfirmModal.js +1 -1
  135. package/frontend/.svelte-kit/output/server/chunks/EmptyState.js +1 -1
  136. package/frontend/.svelte-kit/output/server/chunks/common.js +11 -4
  137. package/frontend/.svelte-kit/output/server/chunks/constants.js +1 -1
  138. package/frontend/.svelte-kit/output/server/chunks/internal.js +1 -1
  139. package/frontend/.svelte-kit/output/server/chunks/repository.js +21 -17
  140. package/frontend/.svelte-kit/output/server/entries/pages/live/_id_/_page.svelte.js +1 -1
  141. package/frontend/.svelte-kit/output/server/entries/pages/reports/_id_/_page.svelte.js +9 -2
  142. package/frontend/.svelte-kit/output/server/entries/pages/scheduled-tests/_page.svelte.js +2 -5
  143. package/frontend/.svelte-kit/output/server/entries/pages/settings/_page.svelte.js +300 -253
  144. package/frontend/.svelte-kit/output/server/entries/pages/test-repository/_page.svelte.js +63 -36
  145. package/frontend/.svelte-kit/output/server/entries/pages/test-repository/runs/_id_/_page.svelte.js +3 -6
  146. package/frontend/.svelte-kit/output/server/entries/pages/test-repository/suites/_id_/_page.svelte.js +15 -17
  147. package/frontend/.svelte-kit/output/server/manifest-full.js +1 -1
  148. package/frontend/.svelte-kit/output/server/manifest.js +1 -1
  149. package/frontend/.svelte-kit/output/server/nodes/0.js +2 -2
  150. package/frontend/.svelte-kit/output/server/nodes/1.js +1 -1
  151. package/frontend/.svelte-kit/output/server/nodes/10.js +2 -2
  152. package/frontend/.svelte-kit/output/server/nodes/11.js +2 -2
  153. package/frontend/.svelte-kit/output/server/nodes/12.js +2 -2
  154. package/frontend/.svelte-kit/output/server/nodes/2.js +1 -1
  155. package/frontend/.svelte-kit/output/server/nodes/3.js +2 -2
  156. package/frontend/.svelte-kit/output/server/nodes/4.js +1 -1
  157. package/frontend/.svelte-kit/output/server/nodes/5.js +1 -1
  158. package/frontend/.svelte-kit/output/server/nodes/6.js +2 -2
  159. package/frontend/.svelte-kit/output/server/nodes/7.js +2 -2
  160. package/frontend/.svelte-kit/output/server/nodes/8.js +2 -2
  161. package/frontend/.svelte-kit/output/server/nodes/9.js +1 -1
  162. package/frontend/build/client/_app/immutable/assets/{0.CmJTG5mP.css → 0.DbhNvxzA.css} +1 -1
  163. package/frontend/build/client/_app/immutable/assets/0.DbhNvxzA.css.br +0 -0
  164. package/frontend/build/client/_app/immutable/assets/0.DbhNvxzA.css.gz +0 -0
  165. package/frontend/build/client/_app/immutable/assets/10.D2ehp3UL.css +6 -0
  166. package/frontend/build/client/_app/immutable/assets/10.D2ehp3UL.css.br +0 -0
  167. package/frontend/build/client/_app/immutable/assets/10.D2ehp3UL.css.gz +0 -0
  168. package/frontend/build/client/_app/immutable/assets/12.Dm1nSEgE.css +6 -0
  169. package/frontend/build/client/_app/immutable/assets/12.Dm1nSEgE.css.br +0 -0
  170. package/frontend/build/client/_app/immutable/assets/12.Dm1nSEgE.css.gz +0 -0
  171. package/frontend/build/client/_app/immutable/assets/3.B3djLY18.css +6 -0
  172. package/frontend/build/client/_app/immutable/assets/3.B3djLY18.css.br +0 -0
  173. package/frontend/build/client/_app/immutable/assets/3.B3djLY18.css.gz +0 -0
  174. package/frontend/build/client/_app/immutable/assets/6.BofiCOMr.css +6 -0
  175. package/frontend/build/client/_app/immutable/assets/6.BofiCOMr.css.br +0 -0
  176. package/frontend/build/client/_app/immutable/assets/6.BofiCOMr.css.gz +0 -0
  177. package/frontend/build/client/_app/immutable/assets/8.DOC8fPSI.css +6 -0
  178. package/frontend/build/client/_app/immutable/assets/8.DOC8fPSI.css.br +0 -0
  179. package/frontend/build/client/_app/immutable/assets/8.DOC8fPSI.css.gz +0 -0
  180. package/frontend/{.svelte-kit/output/client/_app/immutable/assets/Toast.DENwYn3g.css → build/client/_app/immutable/assets/Button.C1zsJAUG.css} +1 -1
  181. package/frontend/build/client/_app/immutable/assets/Button.C1zsJAUG.css.br +0 -0
  182. package/frontend/build/client/_app/immutable/assets/Button.C1zsJAUG.css.gz +0 -0
  183. package/frontend/build/client/_app/immutable/assets/ExportMenu.DsJQ1Qua.css +6 -0
  184. package/frontend/build/client/_app/immutable/assets/ExportMenu.DsJQ1Qua.css.br +0 -0
  185. package/frontend/build/client/_app/immutable/assets/ExportMenu.DsJQ1Qua.css.gz +0 -0
  186. package/frontend/{.svelte-kit/output/server/_app/immutable/assets/_layout.HkPnpRl9.css → build/client/_app/immutable/assets/_layout.DWCC-fI9.css} +1 -1
  187. package/frontend/build/client/_app/immutable/assets/_layout.DWCC-fI9.css.br +0 -0
  188. package/frontend/build/client/_app/immutable/assets/_layout.DWCC-fI9.css.gz +0 -0
  189. package/frontend/build/client/_app/immutable/assets/_page.B3djLY18.css +6 -0
  190. package/frontend/build/client/_app/immutable/assets/_page.B3djLY18.css.br +0 -0
  191. package/frontend/build/client/_app/immutable/assets/_page.B3djLY18.css.gz +0 -0
  192. package/frontend/build/client/_app/immutable/assets/_page.BNh9zY8Y.css +6 -0
  193. package/frontend/build/client/_app/immutable/assets/_page.BNh9zY8Y.css.br +0 -0
  194. package/frontend/build/client/_app/immutable/assets/_page.BNh9zY8Y.css.gz +0 -0
  195. package/frontend/build/client/_app/immutable/assets/_page.D1jbMcpb.css +6 -0
  196. package/frontend/build/client/_app/immutable/assets/_page.D1jbMcpb.css.br +0 -0
  197. package/frontend/build/client/_app/immutable/assets/_page.D1jbMcpb.css.gz +0 -0
  198. package/frontend/build/client/_app/immutable/assets/_page.DOC8fPSI.css +6 -0
  199. package/frontend/build/client/_app/immutable/assets/_page.DOC8fPSI.css.br +0 -0
  200. package/frontend/build/client/_app/immutable/assets/_page.DOC8fPSI.css.gz +0 -0
  201. package/frontend/build/client/_app/immutable/assets/_page.Dm1nSEgE.css +6 -0
  202. package/frontend/build/client/_app/immutable/assets/_page.Dm1nSEgE.css.br +0 -0
  203. package/frontend/build/client/_app/immutable/assets/_page.Dm1nSEgE.css.gz +0 -0
  204. package/frontend/build/client/_app/immutable/chunks/{C2_rQ4aY.js → 3MBVX4Yb.js} +1 -1
  205. package/frontend/build/client/_app/immutable/chunks/3MBVX4Yb.js.br +0 -0
  206. package/frontend/build/client/_app/immutable/chunks/3MBVX4Yb.js.gz +0 -0
  207. package/frontend/{.svelte-kit/output/client/_app/immutable/chunks/CfkUW1vA.js → build/client/_app/immutable/chunks/6VDMVB5U.js} +1 -1
  208. package/frontend/build/client/_app/immutable/chunks/6VDMVB5U.js.br +0 -0
  209. package/frontend/build/client/_app/immutable/chunks/6VDMVB5U.js.gz +0 -0
  210. package/frontend/{.svelte-kit/output/client/_app/immutable/chunks/B0_HKFXV.js → build/client/_app/immutable/chunks/B2lVGNml.js} +1 -1
  211. package/frontend/build/client/_app/immutable/chunks/B2lVGNml.js.br +0 -0
  212. package/frontend/build/client/_app/immutable/chunks/B2lVGNml.js.gz +0 -0
  213. package/frontend/build/client/_app/immutable/chunks/B74j8LrV.js +6 -0
  214. package/frontend/build/client/_app/immutable/chunks/B74j8LrV.js.br +0 -0
  215. package/frontend/build/client/_app/immutable/chunks/B74j8LrV.js.gz +0 -0
  216. package/frontend/{.svelte-kit/output/client/_app/immutable/chunks/CboYYxrf.js → build/client/_app/immutable/chunks/BCh31ecr.js} +1 -1
  217. package/frontend/build/client/_app/immutable/chunks/BCh31ecr.js.br +6 -0
  218. package/frontend/build/client/_app/immutable/chunks/BCh31ecr.js.gz +0 -0
  219. package/frontend/build/client/_app/immutable/chunks/BDb8hZHu.js +6 -0
  220. package/frontend/build/client/_app/immutable/chunks/BDb8hZHu.js.br +0 -0
  221. package/frontend/build/client/_app/immutable/chunks/BDb8hZHu.js.gz +0 -0
  222. package/frontend/build/client/_app/immutable/chunks/BIDsfWFz.js +6 -0
  223. package/frontend/build/client/_app/immutable/chunks/BIDsfWFz.js.br +0 -0
  224. package/frontend/build/client/_app/immutable/chunks/BIDsfWFz.js.gz +0 -0
  225. package/frontend/build/client/_app/immutable/chunks/{CeH-RgMb.js → BIf7lHIm.js} +1 -1
  226. package/frontend/build/client/_app/immutable/chunks/BIf7lHIm.js.br +0 -0
  227. package/frontend/build/client/_app/immutable/chunks/{CeH-RgMb.js.gz → BIf7lHIm.js.gz} +0 -0
  228. package/frontend/build/client/_app/immutable/chunks/BTV7EXZb.js +11 -0
  229. package/frontend/build/client/_app/immutable/chunks/BTV7EXZb.js.br +0 -0
  230. package/frontend/build/client/_app/immutable/chunks/BTV7EXZb.js.gz +0 -0
  231. package/frontend/build/client/_app/immutable/chunks/{DAmOMhaf.js → BWGoOYU0.js} +1 -1
  232. package/frontend/build/client/_app/immutable/chunks/BWGoOYU0.js.br +0 -0
  233. package/frontend/build/client/_app/immutable/chunks/BWGoOYU0.js.gz +0 -0
  234. package/frontend/{.svelte-kit/output/client/_app/immutable/chunks/DiVmSEJa.js → build/client/_app/immutable/chunks/BX-5iVGy.js} +2 -2
  235. package/frontend/build/client/_app/immutable/chunks/BX-5iVGy.js.br +0 -0
  236. package/frontend/build/client/_app/immutable/chunks/BX-5iVGy.js.gz +0 -0
  237. package/frontend/{.svelte-kit/output/client/_app/immutable/chunks/BAvTKHxT.js → build/client/_app/immutable/chunks/BnXsGCy3.js} +1 -1
  238. package/frontend/build/client/_app/immutable/chunks/BnXsGCy3.js.br +0 -0
  239. package/frontend/build/client/_app/immutable/chunks/BnXsGCy3.js.gz +0 -0
  240. package/frontend/build/client/_app/immutable/chunks/C4Z3p6jE.js +6 -0
  241. package/frontend/build/client/_app/immutable/chunks/C4Z3p6jE.js.br +0 -0
  242. package/frontend/build/client/_app/immutable/chunks/C4Z3p6jE.js.gz +0 -0
  243. package/frontend/build/client/_app/immutable/chunks/CNpD-yNH.js +6 -0
  244. package/frontend/build/client/_app/immutable/chunks/CNpD-yNH.js.br +0 -0
  245. package/frontend/build/client/_app/immutable/chunks/CNpD-yNH.js.gz +0 -0
  246. package/frontend/build/client/_app/immutable/chunks/CUPWZLIN.js +6 -0
  247. package/frontend/build/client/_app/immutable/chunks/CUPWZLIN.js.br +0 -0
  248. package/frontend/build/client/_app/immutable/chunks/CUPWZLIN.js.gz +0 -0
  249. package/frontend/build/client/_app/immutable/chunks/{Ck6C3Fl0.js → CXQhSK1T.js} +1 -1
  250. package/frontend/build/client/_app/immutable/chunks/CXQhSK1T.js.br +0 -0
  251. package/frontend/build/client/_app/immutable/chunks/CXQhSK1T.js.gz +0 -0
  252. package/frontend/{.svelte-kit/output/client/_app/immutable/chunks/C00jnSU2.js → build/client/_app/immutable/chunks/CtgCYzu5.js} +1 -1
  253. package/frontend/build/client/_app/immutable/chunks/CtgCYzu5.js.br +0 -0
  254. package/frontend/build/client/_app/immutable/chunks/CtgCYzu5.js.gz +0 -0
  255. package/frontend/build/client/_app/immutable/chunks/D72giPTu.js +6 -0
  256. package/frontend/build/client/_app/immutable/chunks/D72giPTu.js.br +0 -0
  257. package/frontend/build/client/_app/immutable/chunks/D72giPTu.js.gz +0 -0
  258. package/frontend/build/client/_app/immutable/chunks/{GDjpV3r7.js → DDx3no2z.js} +1 -1
  259. package/frontend/build/client/_app/immutable/chunks/DDx3no2z.js.br +0 -0
  260. package/frontend/build/client/_app/immutable/chunks/DDx3no2z.js.gz +0 -0
  261. package/frontend/build/client/_app/immutable/chunks/DFZtPGTY.js +6 -0
  262. package/frontend/build/client/_app/immutable/chunks/DFZtPGTY.js.br +0 -0
  263. package/frontend/build/client/_app/immutable/chunks/DFZtPGTY.js.gz +0 -0
  264. package/frontend/build/client/_app/immutable/chunks/D_thT6pZ.js +6 -0
  265. package/frontend/build/client/_app/immutable/chunks/D_thT6pZ.js.br +0 -0
  266. package/frontend/build/client/_app/immutable/chunks/D_thT6pZ.js.gz +0 -0
  267. package/frontend/{.svelte-kit/output/client/_app/immutable/chunks/C8S7qQjQ.js → build/client/_app/immutable/chunks/DeiVAbyn.js} +1 -1
  268. package/frontend/build/client/_app/immutable/chunks/DeiVAbyn.js.br +6 -0
  269. package/frontend/build/client/_app/immutable/chunks/DeiVAbyn.js.gz +0 -0
  270. package/frontend/build/client/_app/immutable/chunks/Dn1b1Jgc.js +6 -0
  271. package/frontend/build/client/_app/immutable/chunks/Dn1b1Jgc.js.br +0 -0
  272. package/frontend/build/client/_app/immutable/chunks/Dn1b1Jgc.js.gz +0 -0
  273. package/frontend/{.svelte-kit/output/client/_app/immutable/chunks/d2K3c8Kx.js → build/client/_app/immutable/chunks/QwDXcLXz.js} +1 -1
  274. package/frontend/build/client/_app/immutable/chunks/QwDXcLXz.js.br +0 -0
  275. package/frontend/build/client/_app/immutable/chunks/QwDXcLXz.js.gz +0 -0
  276. package/frontend/{.svelte-kit/output/client/_app/immutable/chunks/Cgw8TOOy.js → build/client/_app/immutable/chunks/gCgJ3Cwu.js} +1 -1
  277. package/frontend/build/client/_app/immutable/chunks/gCgJ3Cwu.js.br +0 -0
  278. package/frontend/build/client/_app/immutable/chunks/gCgJ3Cwu.js.gz +0 -0
  279. package/frontend/{.svelte-kit/output/client/_app/immutable/chunks/BJ_ypKl3.js → build/client/_app/immutable/chunks/htkwR9b-.js} +1 -1
  280. package/frontend/build/client/_app/immutable/chunks/htkwR9b-.js.br +0 -0
  281. package/frontend/build/client/_app/immutable/chunks/htkwR9b-.js.gz +0 -0
  282. package/frontend/{.svelte-kit/output/client/_app/immutable/chunks/C7uEQ-LH.js → build/client/_app/immutable/chunks/iL4SCrvY.js} +1 -1
  283. package/frontend/build/client/_app/immutable/chunks/iL4SCrvY.js.br +0 -0
  284. package/frontend/build/client/_app/immutable/chunks/iL4SCrvY.js.gz +0 -0
  285. package/frontend/build/client/_app/immutable/chunks/{CoTEzvLa.js → kFFd6Oo5.js} +1 -1
  286. package/frontend/build/client/_app/immutable/chunks/kFFd6Oo5.js.br +0 -0
  287. package/frontend/build/client/_app/immutable/chunks/kFFd6Oo5.js.gz +0 -0
  288. package/frontend/build/client/_app/immutable/chunks/{DWzEJYIF.js → prk8PJfA.js} +1 -1
  289. package/frontend/build/client/_app/immutable/chunks/prk8PJfA.js.br +0 -0
  290. package/frontend/build/client/_app/immutable/chunks/prk8PJfA.js.gz +0 -0
  291. package/frontend/build/client/_app/immutable/chunks/qvxlSGpD.js +6 -0
  292. package/frontend/build/client/_app/immutable/chunks/qvxlSGpD.js.br +0 -0
  293. package/frontend/build/client/_app/immutable/chunks/qvxlSGpD.js.gz +0 -0
  294. package/frontend/build/client/_app/immutable/chunks/{B00vxw57.js → tsOANt55.js} +1 -1
  295. package/frontend/build/client/_app/immutable/chunks/tsOANt55.js.br +0 -0
  296. package/frontend/build/client/_app/immutable/chunks/tsOANt55.js.gz +0 -0
  297. package/frontend/build/client/_app/immutable/chunks/zXSLr47H.js +6 -0
  298. package/frontend/build/client/_app/immutable/chunks/zXSLr47H.js.br +0 -0
  299. package/frontend/build/client/_app/immutable/chunks/zXSLr47H.js.gz +0 -0
  300. package/frontend/build/client/_app/immutable/entry/app.oEEXlUWx.js +7 -0
  301. package/frontend/build/client/_app/immutable/entry/app.oEEXlUWx.js.br +0 -0
  302. package/frontend/build/client/_app/immutable/entry/app.oEEXlUWx.js.gz +0 -0
  303. package/frontend/{.svelte-kit/output/client/_app/immutable/entry/start.BXOLyf9R.js → build/client/_app/immutable/entry/start.BtJ124rC.js} +1 -1
  304. package/frontend/build/client/_app/immutable/entry/{start.BXOLyf9R.js.br → start.BtJ124rC.js.br} +1 -1
  305. package/frontend/build/client/_app/immutable/entry/{start.BXOLyf9R.js.gz → start.BtJ124rC.js.gz} +0 -0
  306. package/frontend/build/client/_app/immutable/nodes/0.coxCxRRE.js +6 -0
  307. package/frontend/build/client/_app/immutable/nodes/0.coxCxRRE.js.br +0 -0
  308. package/frontend/build/client/_app/immutable/nodes/0.coxCxRRE.js.gz +0 -0
  309. package/frontend/build/client/_app/immutable/nodes/{1.BI97il3r.js → 1.C-Zryp-y.js} +1 -1
  310. package/frontend/build/client/_app/immutable/nodes/1.C-Zryp-y.js.br +0 -0
  311. package/frontend/build/client/_app/immutable/nodes/1.C-Zryp-y.js.gz +0 -0
  312. package/frontend/build/client/_app/immutable/nodes/10.CXqf0Rbs.js +6 -0
  313. package/frontend/build/client/_app/immutable/nodes/10.CXqf0Rbs.js.br +0 -0
  314. package/frontend/build/client/_app/immutable/nodes/10.CXqf0Rbs.js.gz +0 -0
  315. package/frontend/build/client/_app/immutable/nodes/11.PLIMGzrY.js +6 -0
  316. package/frontend/build/client/_app/immutable/nodes/11.PLIMGzrY.js.br +0 -0
  317. package/frontend/build/client/_app/immutable/nodes/11.PLIMGzrY.js.gz +0 -0
  318. package/frontend/build/client/_app/immutable/nodes/12.BGCTaTPG.js +6 -0
  319. package/frontend/build/client/_app/immutable/nodes/12.BGCTaTPG.js.br +0 -0
  320. package/frontend/build/client/_app/immutable/nodes/12.BGCTaTPG.js.gz +0 -0
  321. package/frontend/build/client/_app/immutable/nodes/{2.Dr6yugXz.js → 2.Bno00fr8.js} +1 -1
  322. package/frontend/build/client/_app/immutable/nodes/2.Bno00fr8.js.br +0 -0
  323. package/frontend/build/client/_app/immutable/nodes/2.Bno00fr8.js.gz +0 -0
  324. package/frontend/build/client/_app/immutable/nodes/3.HmZmGlze.js +6 -0
  325. package/frontend/build/client/_app/immutable/nodes/3.HmZmGlze.js.br +0 -0
  326. package/frontend/build/client/_app/immutable/nodes/3.HmZmGlze.js.gz +0 -0
  327. package/frontend/build/client/_app/immutable/nodes/{4.DDADylfF.js → 4.ahxFrDUH.js} +1 -1
  328. package/frontend/build/client/_app/immutable/nodes/4.ahxFrDUH.js.br +0 -0
  329. package/frontend/build/client/_app/immutable/nodes/4.ahxFrDUH.js.gz +0 -0
  330. package/frontend/build/client/_app/immutable/nodes/5.BXasF8ka.js +6 -0
  331. package/frontend/build/client/_app/immutable/nodes/5.BXasF8ka.js.br +0 -0
  332. package/frontend/build/client/_app/immutable/nodes/5.BXasF8ka.js.gz +0 -0
  333. package/frontend/build/client/_app/immutable/nodes/6.DYiAtU_m.js +10 -0
  334. package/frontend/build/client/_app/immutable/nodes/6.DYiAtU_m.js.br +0 -0
  335. package/frontend/build/client/_app/immutable/nodes/6.DYiAtU_m.js.gz +0 -0
  336. package/frontend/build/client/_app/immutable/nodes/7.B_XntBZ1.js +6 -0
  337. package/frontend/build/client/_app/immutable/nodes/7.B_XntBZ1.js.br +0 -0
  338. package/frontend/build/client/_app/immutable/nodes/7.B_XntBZ1.js.gz +0 -0
  339. package/frontend/build/client/_app/immutable/nodes/8.iy5VcxjU.js +9 -0
  340. package/frontend/build/client/_app/immutable/nodes/8.iy5VcxjU.js.br +0 -0
  341. package/frontend/build/client/_app/immutable/nodes/8.iy5VcxjU.js.gz +0 -0
  342. package/frontend/build/client/_app/immutable/nodes/{9.BOK0GNF_.js → 9.Bcqk4p04.js} +1 -1
  343. package/frontend/build/client/_app/immutable/nodes/9.Bcqk4p04.js.br +0 -0
  344. package/frontend/build/client/_app/immutable/nodes/9.Bcqk4p04.js.gz +0 -0
  345. package/frontend/build/client/_app/version.json +1 -1
  346. package/frontend/build/client/_app/version.json.br +0 -0
  347. package/frontend/build/client/_app/version.json.gz +0 -0
  348. package/frontend/build/server/chunks/0-C9vi7MPa.js +22 -0
  349. package/frontend/build/server/chunks/0-C9vi7MPa.js.map +5 -0
  350. package/frontend/build/server/chunks/{1-B3HpigzL.js → 1-DzLSP_fj.js} +2 -2
  351. package/frontend/build/server/chunks/{1-B3HpigzL.js.map → 1-DzLSP_fj.js.map} +1 -1
  352. package/frontend/build/server/chunks/10-C2C3V4ib.js +14 -0
  353. package/frontend/build/server/chunks/10-C2C3V4ib.js.map +5 -0
  354. package/frontend/build/server/chunks/11-TJq4Q43D.js +14 -0
  355. package/frontend/build/server/chunks/11-TJq4Q43D.js.map +5 -0
  356. package/frontend/build/server/chunks/12-B1JDiNwh.js +14 -0
  357. package/frontend/build/server/chunks/12-B1JDiNwh.js.map +5 -0
  358. package/frontend/build/server/chunks/2-Dalgd2D4.js +14 -0
  359. package/frontend/build/server/chunks/{2-DioMbKbC.js.map → 2-Dalgd2D4.js.map} +1 -1
  360. package/frontend/build/server/chunks/3-DZ2GSPqb.js +14 -0
  361. package/frontend/build/server/chunks/3-DZ2GSPqb.js.map +5 -0
  362. package/frontend/build/server/chunks/4-C-1FSKpN.js +14 -0
  363. package/frontend/build/server/chunks/{4-BM-49dbE.js.map → 4-C-1FSKpN.js.map} +1 -1
  364. package/frontend/build/server/chunks/5-ZN8cEN5r.js +14 -0
  365. package/frontend/build/server/chunks/{5-Brx_KOzy.js.map → 5-ZN8cEN5r.js.map} +1 -1
  366. package/frontend/build/server/chunks/6-CInDe8Ui.js +14 -0
  367. package/frontend/build/server/chunks/6-CInDe8Ui.js.map +5 -0
  368. package/frontend/build/server/chunks/7-DTNbErSe.js +14 -0
  369. package/frontend/build/server/chunks/7-DTNbErSe.js.map +5 -0
  370. package/frontend/build/server/chunks/8-DTzm-G0z.js +14 -0
  371. package/frontend/build/server/chunks/8-DTzm-G0z.js.map +5 -0
  372. package/frontend/build/server/chunks/9-CjMorbDi.js +14 -0
  373. package/frontend/build/server/chunks/{9-BMAKiAem.js.map → 9-CjMorbDi.js.map} +1 -1
  374. package/frontend/build/server/chunks/{Toast-CHB87F8k.js → Button-B9h9viZX.js} +3 -17
  375. package/frontend/build/server/chunks/Button-B9h9viZX.js.map +5 -0
  376. package/frontend/build/server/chunks/{ConfirmModal-CtGWHl0v.js → ConfirmModal-C6Cz898n.js} +2 -2
  377. package/frontend/build/server/chunks/{ConfirmModal-CtGWHl0v.js.map → ConfirmModal-C6Cz898n.js.map} +1 -1
  378. package/frontend/build/server/chunks/{EmptyState-Zpm9tJe1.js → EmptyState-CRtsJIv6.js} +2 -2
  379. package/frontend/build/server/chunks/{EmptyState-Zpm9tJe1.js.map → EmptyState-CRtsJIv6.js.map} +1 -1
  380. package/frontend/build/server/chunks/{_layout.svelte-C_6nsIpT.js → _layout.svelte-CiX-oQp_.js} +4 -4
  381. package/frontend/build/server/chunks/{_layout.svelte-C_6nsIpT.js.map → _layout.svelte-CiX-oQp_.js.map} +1 -1
  382. package/frontend/build/server/chunks/{_page.svelte-CTebwzwy.js → _page.svelte-BYYUOBOB.js} +12 -7
  383. package/frontend/build/server/chunks/_page.svelte-BYYUOBOB.js.map +5 -0
  384. package/frontend/build/server/chunks/{_page.svelte-DHZhNTPg.js → _page.svelte-BaxqeEYc.js} +68 -42
  385. package/frontend/build/server/chunks/_page.svelte-BaxqeEYc.js.map +5 -0
  386. package/frontend/build/server/chunks/_page.svelte-C2WqvInJ.js +898 -0
  387. package/frontend/build/server/chunks/_page.svelte-C2WqvInJ.js.map +5 -0
  388. package/frontend/build/server/chunks/{_page.svelte-Bamoq11m.js → _page.svelte-CP6jA1ex.js} +6 -6
  389. package/frontend/build/server/chunks/{_page.svelte-Bamoq11m.js.map → _page.svelte-CP6jA1ex.js.map} +1 -1
  390. package/frontend/build/server/chunks/{_page.svelte-CbTrCeeX.js → _page.svelte-D6b-klLK.js} +9 -9
  391. package/frontend/build/server/chunks/{_page.svelte-CbTrCeeX.js.map → _page.svelte-D6b-klLK.js.map} +1 -1
  392. package/frontend/build/server/chunks/{_page.svelte-DObTHQe2.js → _page.svelte-DAIQT067.js} +8 -8
  393. package/frontend/build/server/chunks/_page.svelte-DAIQT067.js.map +5 -0
  394. package/frontend/build/server/chunks/{_page.svelte-CmJKt3-H.js → _page.svelte-DBjTpquQ.js} +18 -21
  395. package/frontend/build/server/chunks/_page.svelte-DBjTpquQ.js.map +5 -0
  396. package/frontend/build/server/chunks/{_page.svelte-CAlhaCzS.js → _page.svelte-mZF4NrfU.js} +9 -12
  397. package/frontend/build/server/chunks/_page.svelte-mZF4NrfU.js.map +5 -0
  398. package/frontend/build/server/chunks/{_page.svelte-BNwU9zza.js → _page.svelte-nrlgIFaU.js} +8 -11
  399. package/frontend/build/server/chunks/_page.svelte-nrlgIFaU.js.map +5 -0
  400. package/frontend/build/server/chunks/{common-DYYTVHPw.js → common-DS-Z0UFe.js} +7 -2
  401. package/frontend/build/server/chunks/common-DS-Z0UFe.js.map +5 -0
  402. package/frontend/build/server/chunks/{constants-BYVkTZ-O.js → constants-OmHysD51.js} +2 -2
  403. package/frontend/build/server/chunks/{constants-BYVkTZ-O.js.map → constants-OmHysD51.js.map} +1 -1
  404. package/frontend/build/server/chunks/{format-2pqy61MU.js → format-Bqb0as15.js} +2 -2
  405. package/frontend/build/server/chunks/{format-2pqy61MU.js.map → format-Bqb0as15.js.map} +1 -1
  406. package/frontend/build/server/chunks/{reports-WuXG6tj3.js → reports-chCHCDzB.js} +2 -2
  407. package/frontend/build/server/chunks/{reports-WuXG6tj3.js.map → reports-chCHCDzB.js.map} +1 -1
  408. package/frontend/build/server/chunks/{reports2-CCpI0xkQ.js → reports2-Dr3zu9CD.js} +2 -2
  409. package/frontend/build/server/chunks/{reports2-CCpI0xkQ.js.map → reports2-Dr3zu9CD.js.map} +1 -1
  410. package/frontend/build/server/chunks/{repository-TYWcFuWP.js → repository-DSsWVKEb.js} +5 -3
  411. package/frontend/build/server/chunks/repository-DSsWVKEb.js.map +5 -0
  412. package/frontend/build/server/chunks/{runner-D5yCWOsy.js → runner-aaUtOqck.js} +3 -3
  413. package/frontend/build/server/chunks/{runner-D5yCWOsy.js.map → runner-aaUtOqck.js.map} +1 -1
  414. package/frontend/build/server/index.js +1 -1
  415. package/frontend/build/server/index.js.map +1 -1
  416. package/frontend/build/server/manifest.js +14 -14
  417. package/frontend/build/server/manifest.js.map +1 -1
  418. package/frontend/src/lib/api/reports.js +7 -0
  419. package/frontend/src/lib/api/repository.js +28 -0
  420. package/frontend/src/lib/components/layout/RunnerPanel.svelte +2 -1
  421. package/frontend/src/lib/components/reports/LiveReplayer.svelte +0 -6
  422. package/frontend/src/lib/components/reports/RecordingPlayer.svelte +29 -6
  423. package/frontend/src/lib/components/ui/ExportMenu.svelte +154 -0
  424. package/frontend/src/lib/components/ui/NotificationStack.svelte +99 -0
  425. package/frontend/src/lib/constants.js +1 -1
  426. package/frontend/src/lib/copy/common.js +9 -0
  427. package/frontend/src/lib/copy/reports.js +7 -0
  428. package/frontend/src/lib/copy/repository.js +4 -0
  429. package/frontend/src/lib/copy/settings.js +15 -0
  430. package/frontend/src/lib/stores/notifications.js +23 -0
  431. package/frontend/src/lib/utils/download.js +28 -0
  432. package/frontend/src/routes/+layout.svelte +2 -0
  433. package/frontend/src/routes/reports/[id]/+page.svelte +37 -3
  434. package/frontend/src/routes/scheduled-tests/+page.svelte +9 -17
  435. package/frontend/src/routes/settings/+page.svelte +140 -56
  436. package/frontend/src/routes/test-repository/+page.svelte +47 -16
  437. package/frontend/src/routes/test-repository/runs/[id]/+page.svelte +14 -23
  438. package/frontend/src/routes/test-repository/suites/[id]/+page.svelte +38 -22
  439. package/package.json +1 -1
  440. package/frontend/.svelte-kit/adapter-node/_app/immutable/assets/_page.5IJAEAjc.css +0 -6
  441. package/frontend/.svelte-kit/adapter-node/_app/immutable/assets/_page.B9H_IpSU.css +0 -6
  442. package/frontend/.svelte-kit/adapter-node/_app/immutable/assets/_page.Be5c3USL.css +0 -6
  443. package/frontend/.svelte-kit/adapter-node/_app/immutable/assets/_page.COwSGmmy.css +0 -6
  444. package/frontend/.svelte-kit/adapter-node/_app/immutable/assets/_page.Dp6vaGRc.css +0 -6
  445. package/frontend/.svelte-kit/generated/client/nodes/13.js +0 -6
  446. package/frontend/.svelte-kit/output/client/_app/immutable/assets/10.CdaQUS6U.css +0 -6
  447. package/frontend/.svelte-kit/output/client/_app/immutable/assets/12.B9H_IpSU.css +0 -6
  448. package/frontend/.svelte-kit/output/client/_app/immutable/assets/3.Be5c3USL.css +0 -6
  449. package/frontend/.svelte-kit/output/client/_app/immutable/assets/6.BN5XbLUX.css +0 -6
  450. package/frontend/.svelte-kit/output/client/_app/immutable/assets/8.COwSGmmy.css +0 -6
  451. package/frontend/.svelte-kit/output/client/_app/immutable/assets/Button.FOWXxvc7.css +0 -6
  452. package/frontend/.svelte-kit/output/client/_app/immutable/assets/_page.5IJAEAjc.css +0 -6
  453. package/frontend/.svelte-kit/output/client/_app/immutable/assets/_page.B9H_IpSU.css +0 -6
  454. package/frontend/.svelte-kit/output/client/_app/immutable/assets/_page.Be5c3USL.css +0 -6
  455. package/frontend/.svelte-kit/output/client/_app/immutable/assets/_page.COwSGmmy.css +0 -6
  456. package/frontend/.svelte-kit/output/client/_app/immutable/assets/_page.Dp6vaGRc.css +0 -6
  457. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/2-KCkWZO.js +0 -6
  458. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/BbYY_TzB.js +0 -6
  459. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/Beula-TH.js +0 -11
  460. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/CZWchtW8.js +0 -6
  461. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/CegSvdD-.js +0 -6
  462. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/Cfmt4_tJ.js +0 -6
  463. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/DB3YXVFP.js +0 -6
  464. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/DgQy0SB2.js +0 -6
  465. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/Dl-F6VCo.js +0 -6
  466. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/DuAVKaL3.js +0 -6
  467. package/frontend/.svelte-kit/output/client/_app/immutable/chunks/K1h4wprj.js +0 -6
  468. package/frontend/.svelte-kit/output/client/_app/immutable/entry/app.DRjRA71t.js +0 -7
  469. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/0.CRb8Nyce.js +0 -6
  470. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/10.kyazROhw.js +0 -6
  471. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/11.B3vMgT2v.js +0 -6
  472. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/12.DkPcIrgW.js +0 -6
  473. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/3.DUiL7fb5.js +0 -6
  474. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/5.N4CeDeoD.js +0 -6
  475. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/6.DWd93Bv5.js +0 -10
  476. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/7.c8d1cQQM.js +0 -6
  477. package/frontend/.svelte-kit/output/client/_app/immutable/nodes/8.Cvd3MauU.js +0 -9
  478. package/frontend/.svelte-kit/output/server/_app/immutable/assets/_page.5IJAEAjc.css +0 -6
  479. package/frontend/.svelte-kit/output/server/_app/immutable/assets/_page.B9H_IpSU.css +0 -6
  480. package/frontend/.svelte-kit/output/server/_app/immutable/assets/_page.Be5c3USL.css +0 -6
  481. package/frontend/.svelte-kit/output/server/_app/immutable/assets/_page.COwSGmmy.css +0 -6
  482. package/frontend/.svelte-kit/output/server/_app/immutable/assets/_page.Dp6vaGRc.css +0 -6
  483. package/frontend/build/client/_app/immutable/assets/0.CmJTG5mP.css.br +0 -0
  484. package/frontend/build/client/_app/immutable/assets/0.CmJTG5mP.css.gz +0 -0
  485. package/frontend/build/client/_app/immutable/assets/10.CdaQUS6U.css +0 -6
  486. package/frontend/build/client/_app/immutable/assets/10.CdaQUS6U.css.br +0 -0
  487. package/frontend/build/client/_app/immutable/assets/10.CdaQUS6U.css.gz +0 -0
  488. package/frontend/build/client/_app/immutable/assets/12.B9H_IpSU.css +0 -6
  489. package/frontend/build/client/_app/immutable/assets/12.B9H_IpSU.css.br +0 -0
  490. package/frontend/build/client/_app/immutable/assets/12.B9H_IpSU.css.gz +0 -0
  491. package/frontend/build/client/_app/immutable/assets/3.Be5c3USL.css +0 -6
  492. package/frontend/build/client/_app/immutable/assets/3.Be5c3USL.css.br +0 -0
  493. package/frontend/build/client/_app/immutable/assets/3.Be5c3USL.css.gz +0 -0
  494. package/frontend/build/client/_app/immutable/assets/6.BN5XbLUX.css +0 -6
  495. package/frontend/build/client/_app/immutable/assets/6.BN5XbLUX.css.br +0 -0
  496. package/frontend/build/client/_app/immutable/assets/6.BN5XbLUX.css.gz +0 -0
  497. package/frontend/build/client/_app/immutable/assets/8.COwSGmmy.css +0 -6
  498. package/frontend/build/client/_app/immutable/assets/8.COwSGmmy.css.br +0 -0
  499. package/frontend/build/client/_app/immutable/assets/8.COwSGmmy.css.gz +0 -0
  500. package/frontend/build/client/_app/immutable/assets/Button.FOWXxvc7.css +0 -6
  501. package/frontend/build/client/_app/immutable/assets/Button.FOWXxvc7.css.br +0 -0
  502. package/frontend/build/client/_app/immutable/assets/Button.FOWXxvc7.css.gz +0 -0
  503. package/frontend/build/client/_app/immutable/assets/Toast.DENwYn3g.css.br +0 -0
  504. package/frontend/build/client/_app/immutable/assets/Toast.DENwYn3g.css.gz +0 -0
  505. package/frontend/build/client/_app/immutable/assets/_layout.HkPnpRl9.css.br +0 -0
  506. package/frontend/build/client/_app/immutable/assets/_layout.HkPnpRl9.css.gz +0 -0
  507. package/frontend/build/client/_app/immutable/assets/_page.5IJAEAjc.css +0 -6
  508. package/frontend/build/client/_app/immutable/assets/_page.5IJAEAjc.css.br +0 -0
  509. package/frontend/build/client/_app/immutable/assets/_page.5IJAEAjc.css.gz +0 -0
  510. package/frontend/build/client/_app/immutable/assets/_page.B9H_IpSU.css +0 -6
  511. package/frontend/build/client/_app/immutable/assets/_page.B9H_IpSU.css.br +0 -0
  512. package/frontend/build/client/_app/immutable/assets/_page.B9H_IpSU.css.gz +0 -0
  513. package/frontend/build/client/_app/immutable/assets/_page.Be5c3USL.css +0 -6
  514. package/frontend/build/client/_app/immutable/assets/_page.Be5c3USL.css.br +0 -0
  515. package/frontend/build/client/_app/immutable/assets/_page.Be5c3USL.css.gz +0 -0
  516. package/frontend/build/client/_app/immutable/assets/_page.COwSGmmy.css +0 -6
  517. package/frontend/build/client/_app/immutable/assets/_page.COwSGmmy.css.br +0 -0
  518. package/frontend/build/client/_app/immutable/assets/_page.COwSGmmy.css.gz +0 -0
  519. package/frontend/build/client/_app/immutable/assets/_page.Dp6vaGRc.css +0 -6
  520. package/frontend/build/client/_app/immutable/assets/_page.Dp6vaGRc.css.br +0 -0
  521. package/frontend/build/client/_app/immutable/assets/_page.Dp6vaGRc.css.gz +0 -0
  522. package/frontend/build/client/_app/immutable/chunks/2-KCkWZO.js +0 -6
  523. package/frontend/build/client/_app/immutable/chunks/2-KCkWZO.js.br +0 -0
  524. package/frontend/build/client/_app/immutable/chunks/2-KCkWZO.js.gz +0 -0
  525. package/frontend/build/client/_app/immutable/chunks/B00vxw57.js.br +0 -0
  526. package/frontend/build/client/_app/immutable/chunks/B00vxw57.js.gz +0 -0
  527. package/frontend/build/client/_app/immutable/chunks/B0_HKFXV.js.br +0 -0
  528. package/frontend/build/client/_app/immutable/chunks/B0_HKFXV.js.gz +0 -0
  529. package/frontend/build/client/_app/immutable/chunks/BAvTKHxT.js.br +0 -0
  530. package/frontend/build/client/_app/immutable/chunks/BAvTKHxT.js.gz +0 -0
  531. package/frontend/build/client/_app/immutable/chunks/BJ_ypKl3.js.br +0 -0
  532. package/frontend/build/client/_app/immutable/chunks/BJ_ypKl3.js.gz +0 -0
  533. package/frontend/build/client/_app/immutable/chunks/BbYY_TzB.js +0 -6
  534. package/frontend/build/client/_app/immutable/chunks/BbYY_TzB.js.br +0 -0
  535. package/frontend/build/client/_app/immutable/chunks/BbYY_TzB.js.gz +0 -0
  536. package/frontend/build/client/_app/immutable/chunks/Beula-TH.js +0 -11
  537. package/frontend/build/client/_app/immutable/chunks/Beula-TH.js.br +0 -0
  538. package/frontend/build/client/_app/immutable/chunks/Beula-TH.js.gz +0 -0
  539. package/frontend/build/client/_app/immutable/chunks/C00jnSU2.js.br +0 -0
  540. package/frontend/build/client/_app/immutable/chunks/C00jnSU2.js.gz +0 -0
  541. package/frontend/build/client/_app/immutable/chunks/C2_rQ4aY.js.br +0 -0
  542. package/frontend/build/client/_app/immutable/chunks/C2_rQ4aY.js.gz +0 -0
  543. package/frontend/build/client/_app/immutable/chunks/C7uEQ-LH.js.br +0 -0
  544. package/frontend/build/client/_app/immutable/chunks/C7uEQ-LH.js.gz +0 -0
  545. package/frontend/build/client/_app/immutable/chunks/C8S7qQjQ.js.br +0 -0
  546. package/frontend/build/client/_app/immutable/chunks/C8S7qQjQ.js.gz +0 -0
  547. package/frontend/build/client/_app/immutable/chunks/CZWchtW8.js +0 -6
  548. package/frontend/build/client/_app/immutable/chunks/CZWchtW8.js.br +0 -0
  549. package/frontend/build/client/_app/immutable/chunks/CZWchtW8.js.gz +0 -0
  550. package/frontend/build/client/_app/immutable/chunks/CboYYxrf.js.br +0 -6
  551. package/frontend/build/client/_app/immutable/chunks/CboYYxrf.js.gz +0 -0
  552. package/frontend/build/client/_app/immutable/chunks/CeH-RgMb.js.br +0 -0
  553. package/frontend/build/client/_app/immutable/chunks/CegSvdD-.js +0 -6
  554. package/frontend/build/client/_app/immutable/chunks/CegSvdD-.js.br +0 -0
  555. package/frontend/build/client/_app/immutable/chunks/CegSvdD-.js.gz +0 -0
  556. package/frontend/build/client/_app/immutable/chunks/CfkUW1vA.js.br +0 -0
  557. package/frontend/build/client/_app/immutable/chunks/CfkUW1vA.js.gz +0 -0
  558. package/frontend/build/client/_app/immutable/chunks/Cfmt4_tJ.js +0 -6
  559. package/frontend/build/client/_app/immutable/chunks/Cfmt4_tJ.js.br +0 -0
  560. package/frontend/build/client/_app/immutable/chunks/Cfmt4_tJ.js.gz +0 -0
  561. package/frontend/build/client/_app/immutable/chunks/Cgw8TOOy.js.br +0 -0
  562. package/frontend/build/client/_app/immutable/chunks/Cgw8TOOy.js.gz +0 -0
  563. package/frontend/build/client/_app/immutable/chunks/Ck6C3Fl0.js.br +0 -0
  564. package/frontend/build/client/_app/immutable/chunks/Ck6C3Fl0.js.gz +0 -0
  565. package/frontend/build/client/_app/immutable/chunks/CoTEzvLa.js.br +0 -0
  566. package/frontend/build/client/_app/immutable/chunks/CoTEzvLa.js.gz +0 -0
  567. package/frontend/build/client/_app/immutable/chunks/DAmOMhaf.js.br +0 -0
  568. package/frontend/build/client/_app/immutable/chunks/DAmOMhaf.js.gz +0 -0
  569. package/frontend/build/client/_app/immutable/chunks/DB3YXVFP.js +0 -6
  570. package/frontend/build/client/_app/immutable/chunks/DB3YXVFP.js.br +0 -0
  571. package/frontend/build/client/_app/immutable/chunks/DB3YXVFP.js.gz +0 -0
  572. package/frontend/build/client/_app/immutable/chunks/DWzEJYIF.js.br +0 -7
  573. package/frontend/build/client/_app/immutable/chunks/DWzEJYIF.js.gz +0 -0
  574. package/frontend/build/client/_app/immutable/chunks/DgQy0SB2.js +0 -6
  575. package/frontend/build/client/_app/immutable/chunks/DgQy0SB2.js.br +0 -0
  576. package/frontend/build/client/_app/immutable/chunks/DgQy0SB2.js.gz +0 -0
  577. package/frontend/build/client/_app/immutable/chunks/DiVmSEJa.js.br +0 -0
  578. package/frontend/build/client/_app/immutable/chunks/DiVmSEJa.js.gz +0 -0
  579. package/frontend/build/client/_app/immutable/chunks/Dl-F6VCo.js +0 -6
  580. package/frontend/build/client/_app/immutable/chunks/Dl-F6VCo.js.br +0 -0
  581. package/frontend/build/client/_app/immutable/chunks/Dl-F6VCo.js.gz +0 -0
  582. package/frontend/build/client/_app/immutable/chunks/DuAVKaL3.js +0 -6
  583. package/frontend/build/client/_app/immutable/chunks/DuAVKaL3.js.br +0 -0
  584. package/frontend/build/client/_app/immutable/chunks/DuAVKaL3.js.gz +0 -0
  585. package/frontend/build/client/_app/immutable/chunks/GDjpV3r7.js.br +0 -0
  586. package/frontend/build/client/_app/immutable/chunks/GDjpV3r7.js.gz +0 -0
  587. package/frontend/build/client/_app/immutable/chunks/K1h4wprj.js +0 -6
  588. package/frontend/build/client/_app/immutable/chunks/K1h4wprj.js.br +0 -0
  589. package/frontend/build/client/_app/immutable/chunks/K1h4wprj.js.gz +0 -0
  590. package/frontend/build/client/_app/immutable/chunks/d2K3c8Kx.js.br +0 -0
  591. package/frontend/build/client/_app/immutable/chunks/d2K3c8Kx.js.gz +0 -0
  592. package/frontend/build/client/_app/immutable/entry/app.DRjRA71t.js +0 -7
  593. package/frontend/build/client/_app/immutable/entry/app.DRjRA71t.js.br +0 -0
  594. package/frontend/build/client/_app/immutable/entry/app.DRjRA71t.js.gz +0 -0
  595. package/frontend/build/client/_app/immutable/nodes/0.CRb8Nyce.js +0 -6
  596. package/frontend/build/client/_app/immutable/nodes/0.CRb8Nyce.js.br +0 -0
  597. package/frontend/build/client/_app/immutable/nodes/0.CRb8Nyce.js.gz +0 -0
  598. package/frontend/build/client/_app/immutable/nodes/1.BI97il3r.js.br +0 -0
  599. package/frontend/build/client/_app/immutable/nodes/1.BI97il3r.js.gz +0 -0
  600. package/frontend/build/client/_app/immutable/nodes/10.kyazROhw.js +0 -6
  601. package/frontend/build/client/_app/immutable/nodes/10.kyazROhw.js.br +0 -0
  602. package/frontend/build/client/_app/immutable/nodes/10.kyazROhw.js.gz +0 -0
  603. package/frontend/build/client/_app/immutable/nodes/11.B3vMgT2v.js +0 -6
  604. package/frontend/build/client/_app/immutable/nodes/11.B3vMgT2v.js.br +0 -0
  605. package/frontend/build/client/_app/immutable/nodes/11.B3vMgT2v.js.gz +0 -0
  606. package/frontend/build/client/_app/immutable/nodes/12.DkPcIrgW.js +0 -6
  607. package/frontend/build/client/_app/immutable/nodes/12.DkPcIrgW.js.br +0 -0
  608. package/frontend/build/client/_app/immutable/nodes/12.DkPcIrgW.js.gz +0 -0
  609. package/frontend/build/client/_app/immutable/nodes/2.Dr6yugXz.js.br +0 -0
  610. package/frontend/build/client/_app/immutable/nodes/2.Dr6yugXz.js.gz +0 -0
  611. package/frontend/build/client/_app/immutable/nodes/3.DUiL7fb5.js +0 -6
  612. package/frontend/build/client/_app/immutable/nodes/3.DUiL7fb5.js.br +0 -0
  613. package/frontend/build/client/_app/immutable/nodes/3.DUiL7fb5.js.gz +0 -0
  614. package/frontend/build/client/_app/immutable/nodes/4.DDADylfF.js.br +0 -0
  615. package/frontend/build/client/_app/immutable/nodes/4.DDADylfF.js.gz +0 -0
  616. package/frontend/build/client/_app/immutable/nodes/5.N4CeDeoD.js +0 -6
  617. package/frontend/build/client/_app/immutable/nodes/5.N4CeDeoD.js.br +0 -0
  618. package/frontend/build/client/_app/immutable/nodes/5.N4CeDeoD.js.gz +0 -0
  619. package/frontend/build/client/_app/immutable/nodes/6.DWd93Bv5.js +0 -10
  620. package/frontend/build/client/_app/immutable/nodes/6.DWd93Bv5.js.br +0 -0
  621. package/frontend/build/client/_app/immutable/nodes/6.DWd93Bv5.js.gz +0 -0
  622. package/frontend/build/client/_app/immutable/nodes/7.c8d1cQQM.js +0 -6
  623. package/frontend/build/client/_app/immutable/nodes/7.c8d1cQQM.js.br +0 -0
  624. package/frontend/build/client/_app/immutable/nodes/7.c8d1cQQM.js.gz +0 -0
  625. package/frontend/build/client/_app/immutable/nodes/8.Cvd3MauU.js +0 -9
  626. package/frontend/build/client/_app/immutable/nodes/8.Cvd3MauU.js.br +0 -0
  627. package/frontend/build/client/_app/immutable/nodes/8.Cvd3MauU.js.gz +0 -0
  628. package/frontend/build/client/_app/immutable/nodes/9.BOK0GNF_.js.br +0 -0
  629. package/frontend/build/client/_app/immutable/nodes/9.BOK0GNF_.js.gz +0 -0
  630. package/frontend/build/server/chunks/0-_rljpEay.js +0 -22
  631. package/frontend/build/server/chunks/0-_rljpEay.js.map +0 -5
  632. package/frontend/build/server/chunks/10-BQBBYpxV.js +0 -14
  633. package/frontend/build/server/chunks/10-BQBBYpxV.js.map +0 -5
  634. package/frontend/build/server/chunks/11-10xw0TIP.js +0 -14
  635. package/frontend/build/server/chunks/11-10xw0TIP.js.map +0 -5
  636. package/frontend/build/server/chunks/12-CZ3_Uw3c.js +0 -14
  637. package/frontend/build/server/chunks/12-CZ3_Uw3c.js.map +0 -5
  638. package/frontend/build/server/chunks/2-DioMbKbC.js +0 -14
  639. package/frontend/build/server/chunks/3-CgiZg_9v.js +0 -14
  640. package/frontend/build/server/chunks/3-CgiZg_9v.js.map +0 -5
  641. package/frontend/build/server/chunks/4-BM-49dbE.js +0 -14
  642. package/frontend/build/server/chunks/5-Brx_KOzy.js +0 -14
  643. package/frontend/build/server/chunks/6-C5swINND.js +0 -14
  644. package/frontend/build/server/chunks/6-C5swINND.js.map +0 -5
  645. package/frontend/build/server/chunks/7-B8e4y3CB.js +0 -14
  646. package/frontend/build/server/chunks/7-B8e4y3CB.js.map +0 -5
  647. package/frontend/build/server/chunks/8-BZtkZMIZ.js +0 -14
  648. package/frontend/build/server/chunks/8-BZtkZMIZ.js.map +0 -5
  649. package/frontend/build/server/chunks/9-BMAKiAem.js +0 -14
  650. package/frontend/build/server/chunks/Toast-CHB87F8k.js.map +0 -5
  651. package/frontend/build/server/chunks/_page.svelte-BNwU9zza.js.map +0 -5
  652. package/frontend/build/server/chunks/_page.svelte-CAlhaCzS.js.map +0 -5
  653. package/frontend/build/server/chunks/_page.svelte-CTebwzwy.js.map +0 -5
  654. package/frontend/build/server/chunks/_page.svelte-CmJKt3-H.js.map +0 -5
  655. package/frontend/build/server/chunks/_page.svelte-DHZhNTPg.js.map +0 -5
  656. package/frontend/build/server/chunks/_page.svelte-DObTHQe2.js.map +0 -5
  657. package/frontend/build/server/chunks/_page.svelte-ywHy9KCh.js +0 -852
  658. package/frontend/build/server/chunks/_page.svelte-ywHy9KCh.js.map +0 -5
  659. package/frontend/build/server/chunks/common-DYYTVHPw.js.map +0 -5
  660. package/frontend/build/server/chunks/repository-TYWcFuWP.js.map +0 -5
  661. package/frontend/src/lib/components/ui/Toast.svelte +0 -24
package/bin/plum.js CHANGED
@@ -146,6 +146,47 @@ function cancelAndExit() {
146
146
 
147
147
  const VALID_BROWSERS = ['chromium', 'firefox'];
148
148
 
149
+ // A bare host:port silently breaks link generation and CORS, so require a scheme.
150
+ async function promptPublicUrl(message, initial) {
151
+ for (;;) {
152
+ const v = await clack.text({
153
+ message: `${message} — include the http:// or https:// prefix`,
154
+ placeholder: initial,
155
+ defaultValue: initial
156
+ });
157
+ if (clack.isCancel(v)) cancelAndExit();
158
+ const val = (v || initial).trim();
159
+ if (/^https?:\/\//i.test(val)) return val.replace(/\/+$/, '');
160
+ clack.log.warn('That needs a full URL starting with http:// or https://');
161
+ }
162
+ }
163
+
164
+ // onFree() fires when the user agrees to free an in-use port — lets the caller flag it for clearing.
165
+ async function promptPort(message, initial, onFree) {
166
+ const { findPidOnPort } = runnerProcessLib();
167
+ for (;;) {
168
+ const v = await clack.text({
169
+ message,
170
+ placeholder: String(initial),
171
+ defaultValue: String(initial)
172
+ });
173
+ if (clack.isCancel(v)) cancelAndExit();
174
+ const port = (v || String(initial)).trim();
175
+ const pid = findPidOnPort(Number(port));
176
+ if (!pid) return port;
177
+ const free = await clack.confirm({
178
+ message: `Port ${port} is in use (pid ${pid}) — free it when Plum starts?`,
179
+ initialValue: true
180
+ });
181
+ if (clack.isCancel(free)) cancelAndExit();
182
+ if (free) {
183
+ onFree();
184
+ return port;
185
+ }
186
+ clack.log.warn('Pick a different port, or stop that process yourself.');
187
+ }
188
+ }
189
+
149
190
  /* -----------------------------------------------------
150
191
  * Server flow
151
192
  * ------------------------------------------------------ */
@@ -176,12 +217,14 @@ async function configureServer({ force }) {
176
217
 
177
218
  const overrides = {
178
219
  headless: getFlag(args, '--headless'),
220
+ mode: getFlag(args, '--mode'),
179
221
  backendPort: getFlag(args, '--backend-port'),
180
222
  frontendPort: getFlag(args, '--frontend-port'),
181
223
  apiUrl: getFlag(args, '--api-url'),
182
224
  uiUrl: getFlag(args, '--ui-url')
183
225
  };
184
226
  if (overrides.headless !== undefined) cfg.headless = overrides.headless === 'true';
227
+ if (overrides.mode !== undefined) cfg.mode = overrides.mode;
185
228
  if (overrides.backendPort !== undefined) cfg.backendPort = overrides.backendPort;
186
229
  if (overrides.frontendPort !== undefined) cfg.frontendPort = overrides.frontendPort;
187
230
  if (overrides.apiUrl !== undefined) cfg.apiUrl = overrides.apiUrl;
@@ -189,6 +232,7 @@ async function configureServer({ force }) {
189
232
 
190
233
  const hasFlags = anyFlags(args, [
191
234
  '--headless',
235
+ '--mode',
192
236
  '--backend-port',
193
237
  '--frontend-port',
194
238
  '--api-url',
@@ -197,47 +241,63 @@ async function configureServer({ force }) {
197
241
  const interactive = force || (interactiveAllowed() && !hasFlags);
198
242
 
199
243
  if (interactive) {
244
+ const mode = await clack.select({
245
+ message: 'Where are you setting up Plum?',
246
+ options: [
247
+ { value: 'production', label: 'Production / Network server' },
248
+ { value: 'local', label: 'Local machine' }
249
+ ],
250
+ initialValue: cfg.mode === 'production' ? 'production' : 'local'
251
+ });
252
+ if (clack.isCancel(mode)) cancelAndExit();
253
+ cfg.mode = mode;
254
+
255
+ const useDefaults = await clack.confirm({
256
+ message:
257
+ 'Use the default ports (backend 3001, frontend 3002)? ' +
258
+ 'Any process already using those ports will be stopped.'
259
+ });
260
+ if (clack.isCancel(useDefaults)) cancelAndExit();
261
+
262
+ if (useDefaults) {
263
+ cfg.backendPort = '3001';
264
+ cfg.frontendPort = '3002';
265
+ cfg.clearPorts = true;
266
+ clack.log.warn(
267
+ 'Ports 3001 and 3002 will be freed before Plum starts. ' +
268
+ 'The database runs inside Docker and is not affected.'
269
+ );
270
+ } else {
271
+ cfg.backendPort = await promptPort('Backend port', cfg.backendPort, () => {
272
+ cfg.clearPorts = true;
273
+ });
274
+ cfg.frontendPort = await promptPort('Frontend (UI) port', cfg.frontendPort, () => {
275
+ cfg.clearPorts = true;
276
+ });
277
+ }
278
+
279
+ if (mode === 'production') {
280
+ cfg.apiUrl = await promptPublicUrl(
281
+ 'Public URL of the Plum backend / API',
282
+ cfg.apiUrl || `http://localhost:${cfg.backendPort}`
283
+ );
284
+ cfg.uiUrl = await promptPublicUrl(
285
+ 'Public URL of the Plum UI (frontend)',
286
+ cfg.uiUrl || `http://localhost:${cfg.frontendPort}`
287
+ );
288
+ } else {
289
+ cfg.apiUrl = `http://localhost:${cfg.backendPort}`;
290
+ cfg.uiUrl = `http://localhost:${cfg.frontendPort}`;
291
+ }
292
+
200
293
  const headless = await clack.confirm({
201
294
  message: 'Run browsers headless?',
202
295
  initialValue: cfg.headless
203
296
  });
204
297
  if (clack.isCancel(headless)) cancelAndExit();
205
298
  cfg.headless = headless;
206
-
207
- const backendPort = await clack.text({
208
- message: 'Backend port',
209
- placeholder: String(cfg.backendPort),
210
- defaultValue: String(cfg.backendPort)
211
- });
212
- if (clack.isCancel(backendPort)) cancelAndExit();
213
- cfg.backendPort = backendPort || cfg.backendPort;
214
-
215
- const frontendPort = await clack.text({
216
- message: 'Frontend (UI) port',
217
- placeholder: String(cfg.frontendPort),
218
- defaultValue: String(cfg.frontendPort)
219
- });
220
- if (clack.isCancel(frontendPort)) cancelAndExit();
221
- cfg.frontendPort = frontendPort || cfg.frontendPort;
222
-
223
- const defaultApiUrl = `http://localhost:${cfg.backendPort}`;
224
- const apiUrl = await clack.text({
225
- message: 'Public URL for the API (only if reverse-proxying behind a domain)',
226
- placeholder: cfg.apiUrl || defaultApiUrl,
227
- defaultValue: cfg.apiUrl || defaultApiUrl
228
- });
229
- if (clack.isCancel(apiUrl)) cancelAndExit();
230
- cfg.apiUrl = apiUrl || defaultApiUrl;
231
-
232
- const defaultUiUrl = `http://localhost:${cfg.frontendPort}`;
233
- const uiUrl = await clack.text({
234
- message: 'Public URL for the UI (only if reverse-proxying behind a domain)',
235
- placeholder: cfg.uiUrl || defaultUiUrl,
236
- defaultValue: cfg.uiUrl || defaultUiUrl
237
- });
238
- if (clack.isCancel(uiUrl)) cancelAndExit();
239
- cfg.uiUrl = uiUrl || defaultUiUrl;
240
299
  } else {
300
+ if (!cfg.mode) cfg.mode = 'local';
241
301
  if (!cfg.apiUrl) cfg.apiUrl = `http://localhost:${cfg.backendPort}`;
242
302
  if (!cfg.uiUrl) cfg.uiUrl = `http://localhost:${cfg.frontendPort}`;
243
303
  }
@@ -371,6 +431,19 @@ async function runFirstUserSetup(apiBase, uiUrl) {
371
431
  }
372
432
  }
373
433
 
434
+ // A stale process on the backend/frontend port fails the whole stack with a
435
+ // bind error — clear it before `docker compose up`.
436
+ async function clearServerPorts(cfg) {
437
+ const { findPidOnPort, killPort } = runnerProcessLib();
438
+ for (const port of [cfg.backendPort, cfg.frontendPort]) {
439
+ const p = Number(port);
440
+ if (findPidOnPort(p)) {
441
+ clack.log.step(`Freeing port ${port}…`);
442
+ await killPort(p);
443
+ }
444
+ }
445
+ }
446
+
374
447
  // docker compose failures (port conflicts, daemon not running, etc.) must not
375
448
  // crash the process with a raw stack trace — that would abort serverStart()
376
449
  // before it ever reaches the first-user prompt, with no indication why.
@@ -402,6 +475,8 @@ async function serverStart() {
402
475
  applyServerConfig(cfg);
403
476
  clack.log.info(`UI: ${pc.cyan(cfg.uiUrl)}`);
404
477
 
478
+ if (cfg.clearPorts) await clearServerPorts(cfg);
479
+
405
480
  if (!runDockerComposeUp(cfg)) {
406
481
  clack.outro(pc.red('Plum did not start.'));
407
482
  process.exitCode = 1;
@@ -457,7 +532,7 @@ async function serverRestart() {
457
532
  const NPM_INSTALL_RETRIES = 3;
458
533
  const NPM_INSTALL_RETRY_DELAY_MS = 5000;
459
534
 
460
- function npmInstallLatestWithRetry() {
535
+ async function npmInstallLatestWithRetry() {
461
536
  for (let attempt = 1; attempt <= NPM_INSTALL_RETRIES; attempt++) {
462
537
  try {
463
538
  execSync('npm install -g plum-e2e@latest', { stdio: 'inherit' });
@@ -467,7 +542,7 @@ function npmInstallLatestWithRetry() {
467
542
  clack.log.warn(
468
543
  `npm install failed (attempt ${attempt}/${NPM_INSTALL_RETRIES}) — this is often a transient registry propagation delay right after a new release. Retrying in ${NPM_INSTALL_RETRY_DELAY_MS / 1000}s…`
469
544
  );
470
- execSync(`sleep ${NPM_INSTALL_RETRY_DELAY_MS / 1000}`);
545
+ await new Promise((r) => setTimeout(r, NPM_INSTALL_RETRY_DELAY_MS));
471
546
  }
472
547
  }
473
548
  }
@@ -478,12 +553,31 @@ function readPlumVersion() {
478
553
  return JSON.parse(fs.readFileSync(path.join(plumRoot, 'package.json'), 'utf8')).version;
479
554
  }
480
555
 
556
+ /** Latest version published to npm, or null when the registry can't be reached. */
557
+ function fetchLatestPublishedVersion() {
558
+ try {
559
+ return execSync('npm view plum-e2e version', {
560
+ encoding: 'utf8',
561
+ stdio: ['ignore', 'pipe', 'ignore']
562
+ }).trim();
563
+ } catch {
564
+ return null;
565
+ }
566
+ }
567
+
481
568
  async function serverUpdate() {
482
569
  clack.intro(pc.bgMagenta(pc.white(' 🟣 Plum — Update ')));
483
570
 
484
571
  const fromVersion = readPlumVersion();
485
- clack.log.step(`Fetching latest Plum version… (currently ${fromVersion})`);
486
- if (!npmInstallLatestWithRetry()) {
572
+ clack.log.step(`Checking for a newer Plum release… (you have ${fromVersion})`);
573
+
574
+ const latest = fetchLatestPublishedVersion();
575
+ if (latest && latest === fromVersion) {
576
+ clack.outro(pc.green(`Already on the latest version (${fromVersion}). Nothing to do.`));
577
+ return;
578
+ }
579
+
580
+ if (!(await npmInstallLatestWithRetry())) {
487
581
  clack.log.error(
488
582
  `Failed to install the latest version after ${NPM_INSTALL_RETRIES} attempts. Try again shortly, or run "npm install -g plum-e2e@latest" manually to see the full error.`
489
583
  );
@@ -623,9 +717,10 @@ async function configureNode({ force, name: nameArg }) {
623
717
  !name &&
624
718
  !anyFlags(args, ['--primary', '--url', '--port', '--token', '--browser']));
625
719
 
720
+ // Name first — the saved config for that name seeds the other defaults.
626
721
  if (!name && interactive) {
627
722
  const v = await clack.text({
628
- message: 'Runner name',
723
+ message: 'Node name or alias — call it whatever you like',
629
724
  placeholder: 'node-1',
630
725
  defaultValue: 'node-1'
631
726
  });
@@ -636,40 +731,67 @@ async function configureNode({ force, name: nameArg }) {
636
731
 
637
732
  const saved = loadNodeByName(name);
638
733
 
734
+ let mode = getFlag(args, '--mode') ?? saved.mode ?? 'local';
639
735
  let primary = getFlag(args, '--primary') ?? process.env.PRIMARY_URL ?? saved.primary ?? '';
640
- // Not 3001 that's the primary's default; a co-located node must not collide.
641
- let port = getFlag(args, '--port') ?? saved.port ?? '3002';
736
+ // Away from 3001 (primary) and 3002 (frontend) so a co-located node doesn't collide.
737
+ let port = getFlag(args, '--port') ?? saved.port ?? '9001';
642
738
  let browser = getFlag(args, '--browser') ?? saved.browser ?? 'chromium';
643
739
  let token = getFlag(args, '--token') ?? process.env.NODE_TOKEN ?? saved.token ?? generateToken();
644
740
  let url = getFlag(args, '--url') ?? saved.url ?? '';
645
741
 
646
742
  if (interactive) {
647
- const primaryVal = await clack.text({
648
- message: 'Your Plum server backend URL',
649
- placeholder: primary || 'http://localhost:3001',
650
- defaultValue: primary
743
+ const modeVal = await clack.select({
744
+ message: 'Is this node for a production / network setup, or this local machine?',
745
+ options: [
746
+ { value: 'production', label: 'Production / Network' },
747
+ { value: 'local', label: 'Local machine' }
748
+ ],
749
+ initialValue: mode === 'production' ? 'production' : 'local'
651
750
  });
652
- if (clack.isCancel(primaryVal)) cancelAndExit();
653
- primary = primaryVal || primary;
751
+ if (clack.isCancel(modeVal)) cancelAndExit();
752
+ mode = modeVal;
753
+
754
+ if (mode === 'production') {
755
+ primary = await promptPublicUrl(
756
+ 'Plum server backend URL or IP address (include the port)',
757
+ primary || 'https://plum.example.com'
758
+ );
759
+ } else {
760
+ const bp = await clack.text({
761
+ message:
762
+ 'Port your Plum backend runs on (default 3001 — if you changed it or are unsure, ' +
763
+ 'run `docker compose ps` or check Docker Desktop on the server machine)',
764
+ placeholder: '3001',
765
+ defaultValue: '3001'
766
+ });
767
+ if (clack.isCancel(bp)) cancelAndExit();
768
+ primary = `http://localhost:${(bp || '3001').trim()}`;
769
+ }
654
770
 
655
771
  const portVal = await clack.text({
656
- message: 'Local port this Plum node listens on',
772
+ message:
773
+ 'Port this node will listen on — it runs there, and any process already using ' +
774
+ 'that port is stopped when the node starts',
657
775
  placeholder: port,
658
776
  defaultValue: port
659
777
  });
660
778
  if (clack.isCancel(portVal)) cancelAndExit();
661
- port = portVal || port;
779
+ port = (portVal || port).trim();
662
780
 
663
- const defaultUrl = url || `http://${detectLanIp()}:${port}`;
664
- const urlVal = await clack.text({
665
- message: 'The URL your Plum server calls to reach this node',
666
- placeholder: defaultUrl,
667
- defaultValue: defaultUrl
668
- });
669
- if (clack.isCancel(urlVal)) cancelAndExit();
670
- url = urlVal || defaultUrl;
781
+ if (mode === 'production') {
782
+ url = await promptPublicUrl(
783
+ 'URL your Plum server uses to reach this node (e.g. https://node-1.example.com)',
784
+ url && !url.includes('host.docker.internal') ? url : 'https://node-1.example.com'
785
+ );
786
+ } else {
787
+ // Local primary runs in Docker — it reaches a host node via
788
+ // host.docker.internal, not localhost.
789
+ url = `http://host.docker.internal:${port}`;
790
+ clack.log.info(`This node will register with the server as ${pc.cyan(url)}`);
791
+ }
671
792
  }
672
793
 
794
+ // Flag path with no --url: fall back to the LAN-IP guess (interactive already set it).
673
795
  if (!url) url = `http://${detectLanIp()}:${port}`;
674
796
 
675
797
  if (!VALID_BROWSERS.includes(browser)) {
@@ -680,6 +802,7 @@ async function configureNode({ force, name: nameArg }) {
680
802
  saveNodeByName(name, {
681
803
  id: saved.id ?? null,
682
804
  name,
805
+ mode,
683
806
  url,
684
807
  token,
685
808
  primary,
@@ -688,7 +811,7 @@ async function configureNode({ force, name: nameArg }) {
688
811
  pid: saved.pid ?? null
689
812
  });
690
813
  globalRegistryLib().registerInstall('node', nodeHome(name));
691
- return { primary, port, browser, token, name, url };
814
+ return { primary, port, browser, token, name, url, mode };
692
815
  }
693
816
 
694
817
  async function registerNode({ primary, name, url, token, browser, port }) {
@@ -725,7 +848,7 @@ async function registerNode({ primary, name, url, token, browser, port }) {
725
848
  }
726
849
 
727
850
  // Register a node with the primary and start its process here — this is the one
728
- // path both `plum node start` and manage-runners' "Add new runner" run.
851
+ // path both `plum node start` and manage-nodes' "Add new node" run.
729
852
  async function bringNodeUp(cfg) {
730
853
  const { prepareEnv, startNode, findPidOnPort, killPort, nodeReachable } = runnerProcessLib();
731
854
 
@@ -773,7 +896,7 @@ async function bringNodeUp(cfg) {
773
896
  }
774
897
 
775
898
  async function nodeStart({ reconfig, name }) {
776
- clack.intro(pc.bgMagenta(pc.white(' 🟣 Plum — Node Runner ')));
899
+ clack.intro(pc.bgMagenta(pc.white(' 🟣 Plum — Node ')));
777
900
  migrateLegacyNodes();
778
901
  const cfg = await configureNode({ force: reconfig, name });
779
902
  await bringNodeUp(cfg);
@@ -917,8 +1040,8 @@ function readRunnerTokenFromPrimary() {
917
1040
  return null;
918
1041
  }
919
1042
 
920
- async function openManageRunnersMenu(primaryUrl) {
921
- const manageScript = path.join(plumRoot, 'backend', 'scripts', 'manage-runners.mjs');
1043
+ async function openManageNodesMenu(primaryUrl) {
1044
+ const manageScript = path.join(plumRoot, 'backend', 'scripts', 'manage-nodes.mjs');
922
1045
  const apiUrl = primaryUrl || 'http://localhost:3001';
923
1046
  const env = { ...process.env, PLUM_API_URL: apiUrl };
924
1047
  if (!env.PLUM_RUNNER_TOKEN) {
@@ -1059,7 +1182,7 @@ switch (command) {
1059
1182
  ' ```bash',
1060
1183
  ' plum start',
1061
1184
  ' ```',
1062
- ' On first run, Plum asks you to create an admin account. Then open **http://localhost:5173** and sign in.',
1185
+ ' On first run, Plum asks you to create an admin account. Then open **http://localhost:3002** and sign in.',
1063
1186
  '',
1064
1187
  '---',
1065
1188
  '',
@@ -1075,7 +1198,7 @@ switch (command) {
1075
1198
  '| `plum server reconfig` | Change server URL/ports without starting |',
1076
1199
  '| `plum stop` | Stop the server |',
1077
1200
  '| `plum create-step` | Interactively generate a new step definition |',
1078
- '| `plum node start <name>` | Register a runner node and start it here |',
1201
+ '| `plum node start <name>` | Register a node and start it here |',
1079
1202
  '| `plum node list` | List this machine’s nodes |',
1080
1203
  '',
1081
1204
  '---',
@@ -1127,6 +1250,7 @@ switch (command) {
1127
1250
  '- **Test Cases** — Document steps (Action / Test Data / Expected Output), set priority, and assign a Cucumber `@tag` to link automation.',
1128
1251
  '- **Test Runs** — Build a run from any combination of cases, execute them one by one (pass/fail/blocked/skip), and track history.',
1129
1252
  '- **Auto-linking** — When a build completes, Plum matches Cucumber scenario tags against `automatedTag` values on your test cases and marks them as automated.',
1253
+ '- **Export / import** — Export test cases (whole repository or one suite) as CSV or JSON from the Suites tab. The JSON re-imports from **Settings → Test Cases** — a case whose ID already exists is skipped; anything else is imported with a fresh ID.',
1130
1254
  '',
1131
1255
  'To link a test case to automation, set its **Automated tag** (e.g. `test-login-1`) to match the `@tag` on the Cucumber scenario.',
1132
1256
  '',
@@ -1201,14 +1325,14 @@ switch (command) {
1201
1325
 
1202
1326
  case 'start':
1203
1327
  console.log(
1204
- `\nSpecify what to start:\n ${pc.cyan('plum server start')} — start the web UI stack (Docker)\n ${pc.cyan('plum node start')} — start a runner node\n`
1328
+ `\nSpecify what to start:\n ${pc.cyan('plum server start')} — start the web UI stack (Docker)\n ${pc.cyan('plum node start')} — start a node\n`
1205
1329
  );
1206
1330
  process.exit(1);
1207
1331
  break;
1208
1332
 
1209
1333
  case 'restart':
1210
1334
  console.log(
1211
- `\nSpecify what to restart:\n ${pc.cyan('plum server restart')} — rebuild and restart the server\n ${pc.cyan('plum node restart')} — restart the runner node\n`
1335
+ `\nSpecify what to restart:\n ${pc.cyan('plum server restart')} — rebuild and restart the server\n ${pc.cyan('plum node restart')} — restart the node\n`
1212
1336
  );
1213
1337
  process.exit(1);
1214
1338
  break;
@@ -1309,7 +1433,7 @@ switch (command) {
1309
1433
 
1310
1434
  case 'stop':
1311
1435
  console.log(
1312
- `\nSpecify what to stop:\n ${pc.cyan('plum server stop')} — stop the web UI stack\n ${pc.cyan('plum node stop')} — stop the runner node\n`
1436
+ `\nSpecify what to stop:\n ${pc.cyan('plum server stop')} — stop the web UI stack\n ${pc.cyan('plum node stop')} — stop the node\n`
1313
1437
  );
1314
1438
  process.exit(1);
1315
1439
  break;
@@ -1329,7 +1453,7 @@ switch (command) {
1329
1453
  ' delete <name> stop it, delete its config, unregister it from the primary',
1330
1454
  ' reconfig [name] re-enter settings and re-register, without starting',
1331
1455
  '',
1332
- ' Options for start: --primary <url> --url <url> --port <n> --token <s> --browser <chromium|firefox>',
1456
+ ' Options for start: --mode <local|production> --primary <url> --url <url> --port <n> --token <s> --browser <chromium|firefox>',
1333
1457
  ''
1334
1458
  ].join('\n')
1335
1459
  );
@@ -1368,7 +1492,7 @@ switch (command) {
1368
1492
  break;
1369
1493
  }
1370
1494
 
1371
- case 'manage-runners': {
1495
+ case 'manage-nodes': {
1372
1496
  const { listNodeNames, loadNodeByName } = nodeRegisterLib();
1373
1497
  const firstNode = listNodeNames()
1374
1498
  .map(loadNodeByName)
@@ -1378,7 +1502,7 @@ switch (command) {
1378
1502
  process.env.PLUM_API_URL ??
1379
1503
  firstNode?.primary ??
1380
1504
  'http://localhost:3001';
1381
- await openManageRunnersMenu(primaryUrl);
1505
+ await openManageNodesMenu(primaryUrl);
1382
1506
  break;
1383
1507
  }
1384
1508
 
@@ -1415,8 +1539,9 @@ switch (command) {
1415
1539
  console.log(' init Set up a new Plum project');
1416
1540
  console.log(' server start Start the full UI stack (interactive)');
1417
1541
  console.log(' --headless <bool> Run browsers headless (true/false)');
1542
+ console.log(' --mode <m> local | production (default: local)');
1418
1543
  console.log(' --backend-port <n> Host port for the backend/API (default: 3001)');
1419
- console.log(' --frontend-port <n> Host port for the UI (default: 5173)');
1544
+ console.log(' --frontend-port <n> Host port for the UI (default: 3002)');
1420
1545
  console.log(
1421
1546
  ' --api-url <url> Public URL for the API (only if reverse-proxying; default: http://localhost:<backend-port>)'
1422
1547
  );
@@ -1430,12 +1555,13 @@ switch (command) {
1430
1555
  ' update Update Plum and restart whichever is running (server/node)'
1431
1556
  );
1432
1557
  console.log(' node start [name] Register a node with the primary and start it here');
1558
+ console.log(' --mode <m> local | production (default: local)');
1433
1559
  console.log(' --primary <url> Primary Plum server to register with');
1434
- console.log(' --url <url> Address the primary calls back (default: <lan-ip>:<port>;');
1560
+ console.log(' --url <url> Address the primary calls back (default, local mode:');
1435
1561
  console.log(
1436
- ' pass a domain like https://node1.example behind a TLS proxy)'
1562
+ ' http://host.docker.internal:<port>; production: pass a domain)'
1437
1563
  );
1438
- console.log(' --port <n> Local HTTP port the node listens on (default: 3002)');
1564
+ console.log(' --port <n> Local HTTP port the node listens on (default: 9001)');
1439
1565
  console.log(' --token <secret> Auth token (auto-generated + saved if omitted)');
1440
1566
  console.log(' --browser <name> chromium | firefox (default: chromium)');
1441
1567
  console.log(' node list List this machine’s nodes and their status');
@@ -1447,7 +1573,7 @@ switch (command) {
1447
1573
  console.log(
1448
1574
  ' node reconfig [name] Re-enter a node’s settings and re-register, without starting'
1449
1575
  );
1450
- console.log(' manage-runners Open the runner management menu');
1576
+ console.log(' manage-nodes Open the node management menu');
1451
1577
  console.log(
1452
1578
  ' --primary <url> Primary server URL (default: saved config or localhost:3001)'
1453
1579
  );
@@ -40,7 +40,7 @@ services:
40
40
  frontend:
41
41
  build: ./frontend
42
42
  ports:
43
- - '${FRONTEND_PORT:-5173}:5173'
43
+ - '${FRONTEND_PORT:-3002}:5173'
44
44
  depends_on:
45
45
  - backend
46
46
  networks: