@rubytech/create-realagent-code 0.1.601 → 0.1.603

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 (245) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/neo4j/schema.cypher +7 -0
  3. package/payload/platform/plugins/admin/hooks/video-frames-inject.sh +141 -0
  4. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +19 -1
  5. package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +12 -0
  6. package/payload/platform/plugins/docs/references/admin-ui.md +2 -0
  7. package/payload/platform/plugins/docs/references/telegram-guide.md +16 -0
  8. package/payload/platform/plugins/scheduling/PLUGIN.md +2 -0
  9. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate-audits.test.js +67 -1
  10. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate-audits.test.js.map +1 -1
  11. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate.test.js +89 -1
  12. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/gate.test.js.map +1 -1
  13. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/outage-marker.test.d.ts +2 -0
  14. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/outage-marker.test.d.ts.map +1 -0
  15. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/outage-marker.test.js +160 -0
  16. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/outage-marker.test.js.map +1 -0
  17. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/routine-run.test.js +16 -0
  18. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/routine-run.test.js.map +1 -1
  19. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.d.ts +31 -1
  20. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.d.ts.map +1 -1
  21. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.js +42 -4
  22. package/payload/platform/plugins/scheduling/mcp/dist/lib/gate.js.map +1 -1
  23. package/payload/platform/plugins/scheduling/mcp/dist/lib/outage-marker.d.ts +101 -0
  24. package/payload/platform/plugins/scheduling/mcp/dist/lib/outage-marker.d.ts.map +1 -0
  25. package/payload/platform/plugins/scheduling/mcp/dist/lib/outage-marker.js +130 -0
  26. package/payload/platform/plugins/scheduling/mcp/dist/lib/outage-marker.js.map +1 -0
  27. package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-run.d.ts +10 -1
  28. package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-run.d.ts.map +1 -1
  29. package/payload/platform/plugins/scheduling/mcp/dist/lib/routine-run.js.map +1 -1
  30. package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.d.ts +24 -0
  31. package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.d.ts.map +1 -1
  32. package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.js +89 -0
  33. package/payload/platform/plugins/scheduling/mcp/dist/lib/schedule-audit.js.map +1 -1
  34. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js +67 -1
  35. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/agent-turn-dispatch.test.js.map +1 -1
  36. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/gate-dispatch-wiring.test.js +31 -0
  37. package/payload/platform/plugins/scheduling/mcp/dist/scripts/__tests__/gate-dispatch-wiring.test.js.map +1 -1
  38. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts +10 -1
  39. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.d.ts.map +1 -1
  40. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js +46 -1
  41. package/payload/platform/plugins/scheduling/mcp/dist/scripts/agent-turn-dispatch.js.map +1 -1
  42. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js +72 -4
  43. package/payload/platform/plugins/scheduling/mcp/dist/scripts/check-due-events.js.map +1 -1
  44. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/scheduling-gate.test.js +81 -4
  45. package/payload/platform/plugins/scheduling/mcp/dist/tools/__tests__/scheduling-gate.test.js.map +1 -1
  46. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.d.ts +50 -0
  47. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.d.ts.map +1 -1
  48. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.js +48 -7
  49. package/payload/platform/plugins/scheduling/mcp/dist/tools/scheduling-gate.js.map +1 -1
  50. package/payload/platform/services/telegram-channel/dist/notification.d.ts +6 -0
  51. package/payload/platform/services/telegram-channel/dist/notification.d.ts.map +1 -1
  52. package/payload/platform/services/telegram-channel/dist/notification.js +12 -5
  53. package/payload/platform/services/telegram-channel/dist/notification.js.map +1 -1
  54. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts +5 -0
  55. package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
  56. package/payload/platform/services/whatsapp-channel/dist/notification.js +9 -3
  57. package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
  58. package/payload/platform/templates/account-settings.json +6 -0
  59. package/payload/server/chunk-CYU75QAV.js +377 -0
  60. package/payload/server/{chunk-34FPJYHN.js → chunk-GI5AVCRG.js} +87 -146
  61. package/payload/server/chunk-KUVNCAE4.js +77 -0
  62. package/payload/server/{manager-7BXVB76I.js → manager-VDHT3YYI.js} +2 -1
  63. package/payload/server/maxy-edge.js +33 -1
  64. package/payload/server/public/activity.html +6 -6
  65. package/payload/server/public/agents.html +5 -5
  66. package/payload/server/public/assets/{AdminLoginScreens-B3W6J6Bl.js → AdminLoginScreens-DI5bNlX8.js} +1 -1
  67. package/payload/server/public/assets/AdminLoginScreens-DI5bNlX8.js.br +0 -0
  68. package/payload/server/public/assets/AdminLoginScreens-DI5bNlX8.js.gz +0 -0
  69. package/payload/server/public/assets/{AdminShell-C3R-vMZ5.js → AdminShell-B-iX9ahJ.js} +1 -1
  70. package/payload/server/public/assets/AdminShell-B-iX9ahJ.js.br +0 -0
  71. package/payload/server/public/assets/AdminShell-B-iX9ahJ.js.gz +0 -0
  72. package/payload/server/public/assets/{activity-tzv68iBs.js → activity-CqgFwANo.js} +1 -1
  73. package/payload/server/public/assets/activity-CqgFwANo.js.br +0 -0
  74. package/payload/server/public/assets/activity-CqgFwANo.js.gz +0 -0
  75. package/payload/server/public/assets/admin-K63n6ybW.js +1 -0
  76. package/payload/server/public/assets/admin-K63n6ybW.js.br +0 -0
  77. package/payload/server/public/assets/admin-K63n6ybW.js.gz +0 -0
  78. package/payload/server/public/assets/{agents-DUZfeY3X.js → agents-cue5Zf8X.js} +1 -1
  79. package/payload/server/public/assets/agents-cue5Zf8X.js.br +0 -0
  80. package/payload/server/public/assets/agents-cue5Zf8X.js.gz +0 -0
  81. package/payload/server/public/assets/{browser-DwLaXqjO.js → browser-CqDBcKwU.js} +1 -1
  82. package/payload/server/public/assets/browser-CqDBcKwU.js.br +0 -0
  83. package/payload/server/public/assets/browser-CqDBcKwU.js.gz +0 -0
  84. package/payload/server/public/assets/{calendar-Cli8Qjl9.js → calendar-BgzuW5Rt.js} +1 -1
  85. package/payload/server/public/assets/calendar-BgzuW5Rt.js.br +0 -0
  86. package/payload/server/public/assets/calendar-BgzuW5Rt.js.gz +0 -0
  87. package/payload/server/public/assets/chat-HYZViu2u.js +1 -0
  88. package/payload/server/public/assets/chat-HYZViu2u.js.br +3 -0
  89. package/payload/server/public/assets/chat-HYZViu2u.js.gz +0 -0
  90. package/payload/server/public/assets/chevron-left-C5FXH9r_.js +1 -0
  91. package/payload/server/public/assets/chevron-left-C5FXH9r_.js.br +0 -0
  92. package/payload/server/public/assets/clock-DxPtyejC.js +1 -0
  93. package/payload/server/public/assets/clock-DxPtyejC.js.br +0 -0
  94. package/payload/server/public/assets/clock-DxPtyejC.js.gz +0 -0
  95. package/payload/server/public/assets/{copy-yhhwfEbQ.js → copy-BNhZ0flH.js} +1 -1
  96. package/payload/server/public/assets/copy-BNhZ0flH.js.br +0 -0
  97. package/payload/server/public/assets/copy-BNhZ0flH.js.gz +0 -0
  98. package/payload/server/public/assets/data-kCBB8Z4Z.js +1 -0
  99. package/payload/server/public/assets/data-kCBB8Z4Z.js.br +0 -0
  100. package/payload/server/public/assets/data-kCBB8Z4Z.js.gz +0 -0
  101. package/payload/server/public/assets/{field-jg0YQNDy.js → field-X4OVA3vx.js} +1 -1
  102. package/payload/server/public/assets/field-X4OVA3vx.js.br +0 -0
  103. package/payload/server/public/assets/field-X4OVA3vx.js.gz +0 -0
  104. package/payload/server/public/assets/{file-text-D0EdW7h4.js → file-text-BddO_2EI.js} +1 -1
  105. package/payload/server/public/assets/file-text-BddO_2EI.js.br +0 -0
  106. package/payload/server/public/assets/file-text-BddO_2EI.js.gz +0 -0
  107. package/payload/server/public/assets/{graph--AUr4uBc.js → graph-l7tzHqvm.js} +1 -1
  108. package/payload/server/public/assets/graph-l7tzHqvm.js.br +0 -0
  109. package/payload/server/public/assets/graph-l7tzHqvm.js.gz +0 -0
  110. package/payload/server/public/assets/{graph-labels-DM0CiAX1.js → graph-labels-CtFFq5W2.js} +1 -1
  111. package/payload/server/public/assets/graph-labels-CtFFq5W2.js.br +0 -0
  112. package/payload/server/public/assets/graph-labels-CtFFq5W2.js.gz +0 -0
  113. package/payload/server/public/assets/jsx-runtime-bq0g4NlA.css +1 -0
  114. package/payload/server/public/assets/jsx-runtime-bq0g4NlA.css.br +0 -0
  115. package/payload/server/public/assets/jsx-runtime-bq0g4NlA.css.gz +0 -0
  116. package/payload/server/public/assets/{operator-CNYKStFX.js → operator-Dg-dwf7a.js} +1 -1
  117. package/payload/server/public/assets/operator-Dg-dwf7a.js.br +7 -0
  118. package/payload/server/public/assets/operator-Dg-dwf7a.js.gz +0 -0
  119. package/payload/server/public/assets/page-Ci1bfIbs.js +1 -0
  120. package/payload/server/public/assets/page-Ci1bfIbs.js.br +0 -0
  121. package/payload/server/public/assets/page-Ci1bfIbs.js.gz +0 -0
  122. package/payload/server/public/assets/page-Y9JmFq0Q.js +32 -0
  123. package/payload/server/public/assets/page-Y9JmFq0Q.js.br +0 -0
  124. package/payload/server/public/assets/page-Y9JmFq0Q.js.gz +0 -0
  125. package/payload/server/public/assets/play-BSZVGpQT.js +1 -0
  126. package/payload/server/public/assets/play-BSZVGpQT.js.br +0 -0
  127. package/payload/server/public/assets/play-BSZVGpQT.js.gz +0 -0
  128. package/payload/server/public/assets/{public-7gXDqCog.js → public-m66FAza_.js} +1 -1
  129. package/payload/server/public/assets/public-m66FAza_.js.br +0 -0
  130. package/payload/server/public/assets/public-m66FAza_.js.gz +0 -0
  131. package/payload/server/public/assets/{rotate-ccw-DhqNTPpo.js → rotate-ccw-DTOJmOxB.js} +1 -1
  132. package/payload/server/public/assets/rotate-ccw-DTOJmOxB.js.br +0 -0
  133. package/payload/server/public/assets/rotate-ccw-DTOJmOxB.js.gz +0 -0
  134. package/payload/server/public/assets/{routines-DN_yDtEj.js → routines-6fxZNacQ.js} +1 -1
  135. package/payload/server/public/assets/routines-6fxZNacQ.js.br +0 -0
  136. package/payload/server/public/assets/routines-6fxZNacQ.js.gz +0 -0
  137. package/payload/server/public/assets/{skills-pb_3BdOl.js → skills-51mqx-s5.js} +1 -1
  138. package/payload/server/public/assets/skills-51mqx-s5.js.br +0 -0
  139. package/payload/server/public/assets/skills-51mqx-s5.js.gz +0 -0
  140. package/payload/server/public/assets/{tasks-BQm4boat.js → tasks-D4y-Cwa3.js} +1 -1
  141. package/payload/server/public/assets/tasks-D4y-Cwa3.js.br +0 -0
  142. package/payload/server/public/assets/tasks-D4y-Cwa3.js.gz +0 -0
  143. package/payload/server/public/assets/{triangle-alert-d7yjaIqv.js → triangle-alert-BzCjDFts.js} +1 -1
  144. package/payload/server/public/assets/triangle-alert-BzCjDFts.js.br +0 -0
  145. package/payload/server/public/assets/triangle-alert-BzCjDFts.js.gz +0 -0
  146. package/payload/server/public/assets/{useCopyFeedback-CZ6Qhfkj.js → useCopyFeedback-BG7h37Rx.js} +1 -1
  147. package/payload/server/public/assets/useCopyFeedback-BG7h37Rx.js.br +2 -0
  148. package/payload/server/public/assets/useCopyFeedback-BG7h37Rx.js.gz +0 -0
  149. package/payload/server/public/assets/{useMediaQuery-R1smYLx4.js → useMediaQuery-CqwktQr_.js} +1 -1
  150. package/payload/server/public/assets/useMediaQuery-CqwktQr_.js.br +0 -0
  151. package/payload/server/public/assets/useMediaQuery-CqwktQr_.js.gz +0 -0
  152. package/payload/server/public/assets/useVoiceRecorder-CAZcUc1s.js +2 -0
  153. package/payload/server/public/assets/useVoiceRecorder-CAZcUc1s.js.br +0 -0
  154. package/payload/server/public/assets/useVoiceRecorder-CAZcUc1s.js.gz +0 -0
  155. package/payload/server/public/assets/{wrench-DL1pbaCs.js → wrench-B2WKLLQG.js} +1 -1
  156. package/payload/server/public/assets/wrench-B2WKLLQG.js.br +0 -0
  157. package/payload/server/public/assets/wrench-B2WKLLQG.js.gz +0 -0
  158. package/payload/server/public/browser.html +5 -5
  159. package/payload/server/public/calendar.html +8 -8
  160. package/payload/server/public/chat.html +14 -14
  161. package/payload/server/public/data.html +12 -12
  162. package/payload/server/public/field.html +3 -3
  163. package/payload/server/public/graph.html +10 -10
  164. package/payload/server/public/index.html +14 -14
  165. package/payload/server/public/operator.html +16 -16
  166. package/payload/server/public/public.html +14 -14
  167. package/payload/server/public/routines.html +8 -8
  168. package/payload/server/public/skills.html +6 -6
  169. package/payload/server/public/tasks.html +7 -7
  170. package/payload/server/server.js +1067 -783
  171. package/payload/server/video-extract.js +36 -0
  172. package/payload/server/public/assets/AdminLoginScreens-B3W6J6Bl.js.br +0 -0
  173. package/payload/server/public/assets/AdminLoginScreens-B3W6J6Bl.js.gz +0 -0
  174. package/payload/server/public/assets/AdminShell-C3R-vMZ5.js.br +0 -0
  175. package/payload/server/public/assets/AdminShell-C3R-vMZ5.js.gz +0 -0
  176. package/payload/server/public/assets/activity-tzv68iBs.js.br +0 -0
  177. package/payload/server/public/assets/activity-tzv68iBs.js.gz +0 -0
  178. package/payload/server/public/assets/admin-CzW_9jm3.js +0 -1
  179. package/payload/server/public/assets/admin-CzW_9jm3.js.br +0 -0
  180. package/payload/server/public/assets/admin-CzW_9jm3.js.gz +0 -0
  181. package/payload/server/public/assets/agents-DUZfeY3X.js.br +0 -0
  182. package/payload/server/public/assets/agents-DUZfeY3X.js.gz +0 -0
  183. package/payload/server/public/assets/browser-DwLaXqjO.js.br +0 -0
  184. package/payload/server/public/assets/browser-DwLaXqjO.js.gz +0 -0
  185. package/payload/server/public/assets/calendar-Cli8Qjl9.js.br +0 -0
  186. package/payload/server/public/assets/calendar-Cli8Qjl9.js.gz +0 -0
  187. package/payload/server/public/assets/chat-ByAgBgm1.js +0 -1
  188. package/payload/server/public/assets/chat-ByAgBgm1.js.br +0 -1
  189. package/payload/server/public/assets/chat-ByAgBgm1.js.gz +0 -0
  190. package/payload/server/public/assets/chevron-left-BIYVnwvk.js +0 -1
  191. package/payload/server/public/assets/chevron-left-BIYVnwvk.js.br +0 -0
  192. package/payload/server/public/assets/clock-Dzy79hq3.js +0 -1
  193. package/payload/server/public/assets/clock-Dzy79hq3.js.br +0 -0
  194. package/payload/server/public/assets/clock-Dzy79hq3.js.gz +0 -0
  195. package/payload/server/public/assets/copy-yhhwfEbQ.js.br +0 -0
  196. package/payload/server/public/assets/copy-yhhwfEbQ.js.gz +0 -0
  197. package/payload/server/public/assets/data-CsMMki2A.js +0 -1
  198. package/payload/server/public/assets/data-CsMMki2A.js.br +0 -0
  199. package/payload/server/public/assets/data-CsMMki2A.js.gz +0 -0
  200. package/payload/server/public/assets/field-jg0YQNDy.js.br +0 -0
  201. package/payload/server/public/assets/field-jg0YQNDy.js.gz +0 -0
  202. package/payload/server/public/assets/file-text-D0EdW7h4.js.br +0 -0
  203. package/payload/server/public/assets/file-text-D0EdW7h4.js.gz +0 -0
  204. package/payload/server/public/assets/graph--AUr4uBc.js.br +0 -0
  205. package/payload/server/public/assets/graph--AUr4uBc.js.gz +0 -0
  206. package/payload/server/public/assets/graph-labels-DM0CiAX1.js.br +0 -0
  207. package/payload/server/public/assets/graph-labels-DM0CiAX1.js.gz +0 -0
  208. package/payload/server/public/assets/jsx-runtime-lfcjzaWi.css +0 -1
  209. package/payload/server/public/assets/jsx-runtime-lfcjzaWi.css.br +0 -0
  210. package/payload/server/public/assets/jsx-runtime-lfcjzaWi.css.gz +0 -0
  211. package/payload/server/public/assets/operator-CNYKStFX.js.br +0 -0
  212. package/payload/server/public/assets/operator-CNYKStFX.js.gz +0 -0
  213. package/payload/server/public/assets/page-DSsEpl8J.js +0 -32
  214. package/payload/server/public/assets/page-DSsEpl8J.js.br +0 -0
  215. package/payload/server/public/assets/page-DSsEpl8J.js.gz +0 -0
  216. package/payload/server/public/assets/page-DjhmwxnY.js +0 -1
  217. package/payload/server/public/assets/page-DjhmwxnY.js.br +0 -0
  218. package/payload/server/public/assets/page-DjhmwxnY.js.gz +0 -0
  219. package/payload/server/public/assets/play-DhZlml5b.js +0 -1
  220. package/payload/server/public/assets/play-DhZlml5b.js.br +0 -0
  221. package/payload/server/public/assets/play-DhZlml5b.js.gz +0 -0
  222. package/payload/server/public/assets/public-7gXDqCog.js.br +0 -0
  223. package/payload/server/public/assets/public-7gXDqCog.js.gz +0 -0
  224. package/payload/server/public/assets/rotate-ccw-DhqNTPpo.js.br +0 -0
  225. package/payload/server/public/assets/rotate-ccw-DhqNTPpo.js.gz +0 -0
  226. package/payload/server/public/assets/routines-DN_yDtEj.js.br +0 -0
  227. package/payload/server/public/assets/routines-DN_yDtEj.js.gz +0 -0
  228. package/payload/server/public/assets/skills-pb_3BdOl.js.br +0 -0
  229. package/payload/server/public/assets/skills-pb_3BdOl.js.gz +0 -0
  230. package/payload/server/public/assets/tasks-BQm4boat.js.br +0 -0
  231. package/payload/server/public/assets/tasks-BQm4boat.js.gz +0 -0
  232. package/payload/server/public/assets/triangle-alert-d7yjaIqv.js.br +0 -0
  233. package/payload/server/public/assets/triangle-alert-d7yjaIqv.js.gz +0 -0
  234. package/payload/server/public/assets/useCopyFeedback-CZ6Qhfkj.js.br +0 -0
  235. package/payload/server/public/assets/useCopyFeedback-CZ6Qhfkj.js.gz +0 -0
  236. package/payload/server/public/assets/useMediaQuery-R1smYLx4.js.br +0 -0
  237. package/payload/server/public/assets/useMediaQuery-R1smYLx4.js.gz +0 -0
  238. package/payload/server/public/assets/useVoiceRecorder-DM1v6sRa.js +0 -2
  239. package/payload/server/public/assets/useVoiceRecorder-DM1v6sRa.js.br +0 -0
  240. package/payload/server/public/assets/useVoiceRecorder-DM1v6sRa.js.gz +0 -0
  241. package/payload/server/public/assets/wrench-DL1pbaCs.js.br +0 -0
  242. package/payload/server/public/assets/wrench-DL1pbaCs.js.gz +0 -0
  243. /package/payload/server/public/assets/{jsx-runtime-BtDK2X5t.js → jsx-runtime-UK6hgBWO.js} +0 -0
  244. /package/payload/server/public/assets/{jsx-runtime-BtDK2X5t.js.br → jsx-runtime-UK6hgBWO.js.br} +0 -0
  245. /package/payload/server/public/assets/{jsx-runtime-BtDK2X5t.js.gz → jsx-runtime-UK6hgBWO.js.gz} +0 -0
@@ -0,0 +1,377 @@
1
+ import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
2
+
3
+ // app/lib/stt/index.ts
4
+ import { execFile } from "child_process";
5
+ import { unlink, stat } from "fs/promises";
6
+ import { promisify } from "util";
7
+ var execFileAsync = promisify(execFile);
8
+ var TAG = "[stt]";
9
+ var WHISPER_BINARY = process.env.WHISPER_BINARY ?? "/opt/whisper.cpp/build/bin/whisper-cli";
10
+ var WHISPER_MODEL = process.env.WHISPER_MODEL ?? "/opt/whisper.cpp/models/ggml-base.bin";
11
+ var WHISPER_TIMEOUT_MS = 20 * 60 * 1e3;
12
+ var SPECIAL_TOKEN_RE = /\[_[A-Z]+(?:_\d+)?_?\]/g;
13
+ function stripSpecialTokens(input) {
14
+ const matches = input.match(SPECIAL_TOKEN_RE);
15
+ const count = matches ? matches.length : 0;
16
+ if (!count) return { text: input, count: 0 };
17
+ const text = input.replace(SPECIAL_TOKEN_RE, "").replace(/[ \t]{2,}/g, " ").trim();
18
+ return { text, count };
19
+ }
20
+ var SEGMENT_RE = /^\[(\d{2}):(\d{2}):(\d{2})\.(\d{3})\s*-->\s*(\d{2}):(\d{2}):(\d{2})\.(\d{3})\]\s*(.*)$/;
21
+ function toMs(h, m, s, ms) {
22
+ return ((Number(h) * 60 + Number(m)) * 60 + Number(s)) * 1e3 + Number(ms);
23
+ }
24
+ function parseWhisperSegments(stdout) {
25
+ const segments = [];
26
+ for (const line of stdout.split("\n")) {
27
+ const m = SEGMENT_RE.exec(line.trim());
28
+ if (!m) continue;
29
+ const { text } = stripSpecialTokens(m[9].trim());
30
+ if (!text) continue;
31
+ segments.push({
32
+ startMs: toMs(m[1], m[2], m[3], m[4]),
33
+ endMs: toMs(m[5], m[6], m[7], m[8]),
34
+ text
35
+ });
36
+ }
37
+ return segments;
38
+ }
39
+ async function transcribeWithTimestamps(audioPath, mimetype) {
40
+ const startMs = Date.now();
41
+ const wavPath = audioPath.replace(/\.[^.]+$/, "") + ".video.wav";
42
+ try {
43
+ await execFileAsync("ffmpeg", [
44
+ "-i",
45
+ audioPath,
46
+ "-ar",
47
+ "16000",
48
+ "-ac",
49
+ "1",
50
+ "-c:a",
51
+ "pcm_s16le",
52
+ "-y",
53
+ wavPath
54
+ ], { timeout: 6e4 });
55
+ } catch (err) {
56
+ const reason = err instanceof Error ? err.message : String(err);
57
+ console.error(`${TAG} timestamps failed: ffmpeg conversion error=${reason}`);
58
+ return void 0;
59
+ }
60
+ try {
61
+ const { stdout } = await execFileAsync(WHISPER_BINARY, [
62
+ "-m",
63
+ WHISPER_MODEL,
64
+ "-f",
65
+ wavPath,
66
+ "-l",
67
+ "auto"
68
+ ], { timeout: WHISPER_TIMEOUT_MS, maxBuffer: 10 * 1024 * 1024 });
69
+ const segments = parseWhisperSegments(stdout);
70
+ const durationMs = Date.now() - startMs;
71
+ if (segments.length === 0) {
72
+ console.error(
73
+ `${TAG} timestamps: no segments parsed duration_ms=${durationMs} mimetype=${mimetype}`
74
+ );
75
+ return void 0;
76
+ }
77
+ console.error(
78
+ `${TAG} timestamps done segments=${segments.length} duration_ms=${durationMs}`
79
+ );
80
+ return segments;
81
+ } catch (err) {
82
+ const durationMs = Date.now() - startMs;
83
+ const reason = err instanceof Error ? err.message : String(err);
84
+ console.error(`${TAG} timestamps failed duration_ms=${durationMs} error=${reason}`);
85
+ return void 0;
86
+ } finally {
87
+ unlink(wavPath).catch(() => {
88
+ });
89
+ }
90
+ }
91
+ async function transcribe(audioPath, mimetype) {
92
+ const startMs = Date.now();
93
+ let audioBytes = 0;
94
+ try {
95
+ const s = await stat(audioPath);
96
+ audioBytes = s.size;
97
+ } catch {
98
+ console.error(`${TAG} failed: file not readable path=${audioPath}`);
99
+ return void 0;
100
+ }
101
+ console.error(
102
+ `${TAG} start provider=whisper-local audio_bytes=${audioBytes} mimetype=${mimetype} path=${audioPath}`
103
+ );
104
+ const wavPath = audioPath.replace(/\.[^.]+$/, "") + ".wav";
105
+ try {
106
+ await execFileAsync("ffmpeg", [
107
+ "-i",
108
+ audioPath,
109
+ "-ar",
110
+ "16000",
111
+ "-ac",
112
+ "1",
113
+ "-c:a",
114
+ "pcm_s16le",
115
+ "-y",
116
+ // overwrite without prompting
117
+ wavPath
118
+ ], { timeout: 3e4 });
119
+ } catch (err) {
120
+ const reason = err instanceof Error ? err.message : String(err);
121
+ console.error(`${TAG} failed: ffmpeg conversion error=${reason}`);
122
+ return void 0;
123
+ }
124
+ try {
125
+ const { stdout, stderr } = await execFileAsync(WHISPER_BINARY, [
126
+ "-m",
127
+ WHISPER_MODEL,
128
+ "-f",
129
+ wavPath,
130
+ "--no-timestamps",
131
+ "-l",
132
+ "auto"
133
+ ], { timeout: WHISPER_TIMEOUT_MS, maxBuffer: 10 * 1024 * 1024 });
134
+ const durationMs = Date.now() - startMs;
135
+ const { text, count: stripped } = stripSpecialTokens(stdout.trim());
136
+ if (!text) {
137
+ console.error(`${TAG} failed: whisper returned empty output duration_ms=${durationMs}`);
138
+ return void 0;
139
+ }
140
+ const langMatch = stderr.match(/auto-detected language:\s*(\w+)/);
141
+ const language = langMatch?.[1] ?? "unknown";
142
+ const words = text.split(/\s+/).filter(Boolean).length;
143
+ console.error(
144
+ `${TAG} done provider=whisper-local duration_ms=${durationMs} words=${words} stripped=${stripped} lang=${language}`
145
+ );
146
+ return { text, language, durationMs };
147
+ } catch (err) {
148
+ const durationMs = Date.now() - startMs;
149
+ const reason = err instanceof Error ? err.message : String(err);
150
+ console.error(`${TAG} failed provider=whisper-local duration_ms=${durationMs} error=${reason}`);
151
+ return void 0;
152
+ } finally {
153
+ unlink(wavPath).catch(() => {
154
+ });
155
+ }
156
+ }
157
+
158
+ // app/lib/video/frames.ts
159
+ import { execFile as execFile2 } from "child_process";
160
+ import { join } from "path";
161
+ import { promisify as promisify2 } from "util";
162
+ var execFileAsync2 = promisify2(execFile2);
163
+ var TAG2 = "[video]";
164
+ var SCENE_THRESHOLD = 0.3;
165
+ var DENSITY_INTERVAL_S = 4;
166
+ var MIN_FRAMES = 3;
167
+ var MAX_FRAMES = 24;
168
+ var DEDUPE_TOLERANCE_S = 0.5;
169
+ function round3(n) {
170
+ return Math.round(n * 1e3) / 1e3;
171
+ }
172
+ function selectFrameTimestamps(durationSec, sceneTimes) {
173
+ if (!Number.isFinite(durationSec) || durationSec <= 0) return [];
174
+ const floorTimes = [];
175
+ for (let t = 0; t < durationSec; t += DENSITY_INTERVAL_S) floorTimes.push(round3(t));
176
+ const inRange = sceneTimes.filter((t) => Number.isFinite(t) && t >= 0 && t < durationSec);
177
+ const sorted = [...floorTimes, ...inRange].sort((a, b) => a - b);
178
+ const merged = [];
179
+ for (const t of sorted) {
180
+ if (merged.length === 0 || t - merged[merged.length - 1] >= DEDUPE_TOLERANCE_S) {
181
+ merged.push(round3(t));
182
+ }
183
+ }
184
+ if (merged.length < MIN_FRAMES) {
185
+ const step = durationSec / MIN_FRAMES;
186
+ return Array.from({ length: MIN_FRAMES }, (_, i) => round3(i * step));
187
+ }
188
+ if (merged.length > MAX_FRAMES) {
189
+ const last = merged.length - 1;
190
+ const picked = [];
191
+ for (let i = 0; i < MAX_FRAMES; i++) {
192
+ picked.push(merged[Math.round(i * last / (MAX_FRAMES - 1))]);
193
+ }
194
+ return picked;
195
+ }
196
+ return merged;
197
+ }
198
+ var defaultExec = async (file, args) => {
199
+ const { stdout, stderr } = await execFileAsync2(file, args, {
200
+ timeout: 12e4,
201
+ maxBuffer: 10 * 1024 * 1024
202
+ });
203
+ return { stdout, stderr };
204
+ };
205
+ var PTS_TIME_RE = /pts_time:([0-9]+(?:\.[0-9]+)?)/g;
206
+ async function detectSceneTimes(path, execImpl = defaultExec) {
207
+ try {
208
+ const { stdout, stderr } = await execImpl("ffmpeg", [
209
+ "-v",
210
+ "error",
211
+ "-i",
212
+ path,
213
+ "-vf",
214
+ `select='gt(scene,${SCENE_THRESHOLD})',metadata=print:file=-`,
215
+ "-an",
216
+ "-f",
217
+ "null",
218
+ "-"
219
+ ]);
220
+ const times = [];
221
+ for (const m of `${stdout}
222
+ ${stderr}`.matchAll(PTS_TIME_RE)) {
223
+ const t = Number(m[1]);
224
+ if (Number.isFinite(t)) times.push(t);
225
+ }
226
+ return times.sort((a, b) => a - b);
227
+ } catch (err) {
228
+ const reason = err instanceof Error ? err.message : String(err);
229
+ console.error(`${TAG2} scene detect failed error=${reason} path=${path}`);
230
+ return [];
231
+ }
232
+ }
233
+ async function extractFrames(path, timestamps, outDir, execImpl = defaultExec) {
234
+ const stem = `video-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
235
+ const refs = [];
236
+ for (const tSec of timestamps) {
237
+ const out = join(outDir, `${stem}-${tSec.toFixed(3).replace(".", "_")}.jpg`);
238
+ try {
239
+ await execImpl("ffmpeg", [
240
+ "-v",
241
+ "error",
242
+ "-ss",
243
+ String(tSec),
244
+ "-i",
245
+ path,
246
+ "-frames:v",
247
+ "1",
248
+ "-q:v",
249
+ "4",
250
+ "-y",
251
+ out
252
+ ]);
253
+ refs.push({ tSec, path: out });
254
+ } catch (err) {
255
+ const reason = err instanceof Error ? err.message : String(err);
256
+ console.error(`${TAG2} frame extract failed t=${tSec} error=${reason}`);
257
+ }
258
+ }
259
+ return refs;
260
+ }
261
+
262
+ // app/lib/video/probe.ts
263
+ import { execFile as execFile3 } from "child_process";
264
+ import { promisify as promisify3 } from "util";
265
+ var execFileAsync3 = promisify3(execFile3);
266
+ var TAG3 = "[video]";
267
+ var defaultExec2 = async (file, args) => {
268
+ const { stdout } = await execFileAsync3(file, args, { timeout: 3e4 });
269
+ return { stdout };
270
+ };
271
+ async function probeVideo(path, execImpl = defaultExec2) {
272
+ try {
273
+ const { stdout } = await execImpl("ffprobe", [
274
+ "-v",
275
+ "error",
276
+ "-show_entries",
277
+ "format=duration",
278
+ "-show_entries",
279
+ "stream=codec_type",
280
+ "-of",
281
+ "json",
282
+ path
283
+ ]);
284
+ const parsed = JSON.parse(stdout);
285
+ const durationSec = Number(parsed.format?.duration);
286
+ if (!Number.isFinite(durationSec) || durationSec <= 0) {
287
+ console.error(`${TAG3} probe failed: unparseable duration path=${path}`);
288
+ return void 0;
289
+ }
290
+ const kinds = (parsed.streams ?? []).map((s) => s.codec_type);
291
+ return {
292
+ durationSec,
293
+ hasAudio: kinds.includes("audio"),
294
+ hasVideo: kinds.includes("video")
295
+ };
296
+ } catch (err) {
297
+ const reason = err instanceof Error ? err.message : String(err);
298
+ console.error(`${TAG3} probe failed: ffprobe error=${reason} path=${path}`);
299
+ return void 0;
300
+ }
301
+ }
302
+
303
+ // app/lib/video/timeline.ts
304
+ function stamp(totalSec) {
305
+ const s = Math.floor(totalSec % 60);
306
+ const m = Math.floor(totalSec / 60 % 60);
307
+ const h = Math.floor(totalSec / 3600);
308
+ const mm = String(m).padStart(2, "0");
309
+ const ss = String(s).padStart(2, "0");
310
+ return h > 0 ? `${h}:${mm}:${ss}` : `${mm}:${ss}`;
311
+ }
312
+ function renderTimeline(frames, segments) {
313
+ const events = [];
314
+ for (const s of segments) {
315
+ const tSec = s.startMs / 1e3;
316
+ events.push({ tSec, rank: 0, line: `[${stamp(tSec)}] ${s.text}` });
317
+ }
318
+ for (const f of frames) {
319
+ events.push({ tSec: f.tSec, rank: 1, line: `[${stamp(f.tSec)}] frame \u2192 ${f.path}` });
320
+ }
321
+ events.sort((a, b) => a.tSec - b.tSec || a.rank - b.rank);
322
+ const header = segments.length > 0 ? `Video timeline \u2014 ${frames.length} frame(s) and the spoken transcript, on the video's own clock.` : `Video timeline \u2014 ${frames.length} frame(s); no speech was transcribed from this video.`;
323
+ return [
324
+ header,
325
+ "Read each frame path below to see that moment.",
326
+ "",
327
+ ...events.map((e) => e.line)
328
+ ].join("\n");
329
+ }
330
+
331
+ // app/lib/video/index.ts
332
+ var TAG4 = "[video]";
333
+ var MAX_DURATION_S = 300;
334
+ var MEDIA_DIR = "/tmp/maxy-media";
335
+ var defaults = {
336
+ probe: probeVideo,
337
+ detectScenes: detectSceneTimes,
338
+ extract: extractFrames,
339
+ transcribe: transcribeWithTimestamps,
340
+ outDir: MEDIA_DIR
341
+ };
342
+ async function extractVideo(path, mimetype, deps = {}) {
343
+ const d = { ...defaults, ...deps };
344
+ const startedMs = Date.now();
345
+ const probe = await d.probe(path);
346
+ if (!probe) {
347
+ console.error(`${TAG4} skipped=probe-failed path=${path}`);
348
+ return void 0;
349
+ }
350
+ if (!probe.hasVideo) {
351
+ console.error(`${TAG4} skipped=no-video-stream path=${path}`);
352
+ return void 0;
353
+ }
354
+ if (probe.durationSec > MAX_DURATION_S) {
355
+ console.error(
356
+ `${TAG4} skipped=duration duration_s=${probe.durationSec.toFixed(1)} max_s=${MAX_DURATION_S} path=${path}`
357
+ );
358
+ return void 0;
359
+ }
360
+ const sceneTimes = await d.detectScenes(path);
361
+ const timestamps = selectFrameTimestamps(probe.durationSec, sceneTimes);
362
+ const frames = await d.extract(path, timestamps, d.outDir);
363
+ if (frames.length === 0) {
364
+ console.error(`${TAG4} skipped=no-frames path=${path}`);
365
+ return void 0;
366
+ }
367
+ const segments = probe.hasAudio ? await d.transcribe(path, mimetype) : void 0;
368
+ console.error(
369
+ `${TAG4} done frames=${frames.length} segments=${segments?.length ?? 0} duration_ms=${Date.now() - startedMs} video_s=${probe.durationSec.toFixed(1)}`
370
+ );
371
+ return renderTimeline(frames, segments ?? []);
372
+ }
373
+
374
+ export {
375
+ transcribe,
376
+ extractVideo
377
+ };