@tyvm/knowhow 0.0.33 → 0.0.35

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 (504) hide show
  1. package/autodoc/plugins/downloader/downloader.mdx +2 -2
  2. package/benchmarks/.dockerignore +7 -0
  3. package/benchmarks/README.md +166 -0
  4. package/benchmarks/docker/Dockerfile +68 -0
  5. package/benchmarks/example-config.yml +27 -0
  6. package/benchmarks/jest.config.js +13 -0
  7. package/benchmarks/package-lock.json +4297 -0
  8. package/benchmarks/package.json +39 -0
  9. package/benchmarks/results/4542435/2025-08-05/lms/lms-openai-gpt-oss-20b.json +2814 -0
  10. package/benchmarks/results/4542435/2025-08-05/lms/lms-qwen-qwen3-30b-a3b-2507.json +2014 -0
  11. package/benchmarks/results/4fb9125/2025-08-07/anthropic/anthropic-claude-sonnet-4-20250514.json +3121 -0
  12. package/benchmarks/results/5766aee/2025-08-02/lms-qwen/qwen3-coder-30b.json +98 -0
  13. package/benchmarks/results/6d73808/2025-08-07/openai/openai-gpt-5.json +3256 -0
  14. package/benchmarks/results/77bf0a6/2025-08-02/lms-qwen/qwen3-30b-a3b-2507.json +4298 -0
  15. package/benchmarks/results/8c0d445/2025-08-03/anthropic/anthropic-claude-sonnet-4-20250514.json +3031 -0
  16. package/benchmarks/results/8c0d445/2025-08-03/openai/openai-gpt-4.1-2025-04-14.json +2990 -0
  17. package/benchmarks/results/ac6b2ab/2025-08-03/anthropic/anthropic-claude-sonnet-4-20250514.json +3256 -0
  18. package/benchmarks/results/ac6b2ab/2025-08-03/lms/lms-qwen-qwen3-coder-30b.json +3007 -0
  19. package/benchmarks/results/ac6b2ab/2025-08-03/openai/openai-gpt-4.1-2025-04-14.json +3256 -0
  20. package/benchmarks/results/ac6b2ab/2025-08-03/openai/openai-gpt-4.1-mini-2025-04-14.json +3036 -0
  21. package/benchmarks/results/ac6b2ab/2025-08-03/openai/openai-gpt-4.1-nano-2025-04-14.json +3280 -0
  22. package/benchmarks/results/adff675/2025-08-04/lms/lms-qwen-qwen3-30b-a3b-2507.json +1920 -0
  23. package/benchmarks/results/adff675/2025-08-04/lms/lms-qwen-qwen3-coder-30b.json +3281 -0
  24. package/benchmarks/results/b502ed9/2025-08-03/lms-qwen/qwen3-coder-30b.json +2896 -0
  25. package/benchmarks/results/d1a8129/2025-08-03/lms/lms-qwen-qwen3-coder-30b.json +3011 -0
  26. package/benchmarks/results/e60471c/2025-08-03/lms/qwen3-30b-a3b-2507.json +3003 -0
  27. package/benchmarks/scripts/build-and-run.sh +47 -0
  28. package/benchmarks/scripts/clone-exercism.sh +92 -0
  29. package/benchmarks/scripts/validate.sh +48 -0
  30. package/benchmarks/src/__tests__/runner.test.ts +27 -0
  31. package/benchmarks/src/cli.ts +90 -0
  32. package/benchmarks/src/evaluators/EvaluatorRegistry.ts +64 -0
  33. package/benchmarks/src/evaluators/JavaScriptEvaluator.ts +183 -0
  34. package/benchmarks/src/evaluators/index.ts +3 -0
  35. package/benchmarks/src/evaluators/types.ts +22 -0
  36. package/benchmarks/src/index.ts +3 -0
  37. package/benchmarks/src/providers.ts +13 -0
  38. package/benchmarks/src/runner.ts +824 -0
  39. package/benchmarks/src/types.ts +63 -0
  40. package/benchmarks/tsconfig.json +19 -0
  41. package/jest.config.js +2 -1
  42. package/leaderboard/README.md +148 -0
  43. package/leaderboard/app/api/benchmark-data/route.ts +131 -0
  44. package/leaderboard/app/api/benchmark-detail/route.ts +172 -0
  45. package/leaderboard/app/details/[model]/[provider]/[language]/page.tsx +501 -0
  46. package/leaderboard/app/exercise/[model]/[provider]/[language]/[exercise]/page.tsx +375 -0
  47. package/leaderboard/app/globals.css +27 -0
  48. package/leaderboard/app/layout.tsx +21 -0
  49. package/leaderboard/app/page.tsx +170 -0
  50. package/leaderboard/components/LeaderboardTable.tsx +168 -0
  51. package/leaderboard/components/PerformanceChart.tsx +109 -0
  52. package/leaderboard/next-env.d.ts +5 -0
  53. package/leaderboard/next.config.js +4 -0
  54. package/leaderboard/package-lock.json +6363 -0
  55. package/leaderboard/package.json +28 -0
  56. package/leaderboard/postcss.config.js +6 -0
  57. package/leaderboard/tailwind.config.js +17 -0
  58. package/leaderboard/tsconfig.json +28 -0
  59. package/leaderboard/types/benchmark.ts +67 -0
  60. package/leaderboard/utils/dataProcessor.ts +33 -0
  61. package/package.json +2 -1
  62. package/src/agents/base/base.ts +182 -24
  63. package/src/agents/base/prompt.ts +28 -0
  64. package/src/agents/index.ts +3 -0
  65. package/src/agents/patcher/patcher.ts +6 -4
  66. package/src/agents/setup/setup.ts +56 -0
  67. package/src/agents/tools/agentCall.ts +6 -2
  68. package/src/agents/tools/aiClient.ts +74 -8
  69. package/src/agents/tools/execCommand.ts +13 -14
  70. package/src/agents/tools/executeScript/README.md +16 -0
  71. package/src/agents/tools/index.ts +2 -0
  72. package/src/agents/tools/list.ts +73 -16
  73. package/src/agents/tools/startAgentTask.ts +109 -0
  74. package/src/agents/tools/textSearch.ts +1 -1
  75. package/src/agents/tools/visionTool.ts +31 -2
  76. package/src/agents/tools/ycmd/client.ts +608 -0
  77. package/src/agents/tools/ycmd/definitions.ts +294 -0
  78. package/src/agents/tools/ycmd/detection.ts +211 -0
  79. package/src/agents/tools/ycmd/index.ts +11 -0
  80. package/src/agents/tools/ycmd/installer.ts +251 -0
  81. package/src/agents/tools/ycmd/server.ts +535 -0
  82. package/src/agents/tools/ycmd/serverManager.ts +316 -0
  83. package/src/agents/tools/ycmd/tools/completion.ts +113 -0
  84. package/src/agents/tools/ycmd/tools/diagnostics.ts +155 -0
  85. package/src/agents/tools/ycmd/tools/getLocations.ts +173 -0
  86. package/src/agents/tools/ycmd/tools/goto.ts +169 -0
  87. package/src/agents/tools/ycmd/tools/refactor.ts +204 -0
  88. package/src/agents/tools/ycmd/tools/signature.ts +174 -0
  89. package/src/agents/tools/ycmd/tools/start.ts +95 -0
  90. package/src/agents/tools/ycmd/utils/pathUtils.ts +59 -0
  91. package/src/ai.ts +15 -0
  92. package/src/chat/CliChatService.ts +277 -0
  93. package/src/chat/modules/AgentModule.ts +985 -0
  94. package/src/chat/modules/AskModule.ts +98 -0
  95. package/src/chat/modules/BaseChatModule.ts +66 -0
  96. package/src/chat/modules/InternalChatModule.ts +174 -0
  97. package/src/chat/modules/SearchModule.ts +166 -0
  98. package/src/chat/modules/SetupModule.ts +185 -0
  99. package/src/chat/modules/SystemModule.ts +120 -0
  100. package/src/chat/modules/VoiceModule.ts +70 -0
  101. package/src/chat/modules/index.js +5 -0
  102. package/src/chat/types.ts +97 -0
  103. package/src/chat.ts +9 -1
  104. package/src/chat2.ts +62 -0
  105. package/src/cli.ts +264 -35
  106. package/src/clients/anthropic.ts +14 -7
  107. package/src/clients/gemini.ts +15 -7
  108. package/src/clients/http.ts +17 -7
  109. package/src/clients/index.ts +117 -4
  110. package/src/clients/knowhow.ts +7 -2
  111. package/src/clients/knowhowMcp.ts +118 -0
  112. package/src/clients/openai.ts +32 -8
  113. package/src/clients/types.ts +1 -0
  114. package/src/clients/xai.ts +17 -5
  115. package/src/config.ts +30 -5
  116. package/src/conversion.ts +4 -1
  117. package/src/login.ts +26 -9
  118. package/src/microphone.ts +0 -1
  119. package/src/plugins/downloader/downloader.ts +191 -49
  120. package/src/plugins/downloader/plugin.ts +3 -1
  121. package/src/plugins/plugins.ts +3 -0
  122. package/src/processors/CustomVariables.ts +425 -0
  123. package/src/processors/HarmonyToolProcessor.ts +264 -0
  124. package/src/processors/XmlToolCallProcessor.ts +533 -0
  125. package/src/processors/index.ts +3 -0
  126. package/src/prompts/KnowhowConfigExamples.ts +376 -0
  127. package/src/services/KnowhowClient.ts +49 -3
  128. package/src/services/Mcp.ts +42 -3
  129. package/src/services/McpServer.ts +14 -4
  130. package/src/services/McpWebsocketTransport.ts +21 -7
  131. package/src/services/MessageProcessor.ts +10 -5
  132. package/src/services/index.ts +5 -0
  133. package/src/services/script-execution/ScriptExecutor.ts +34 -1
  134. package/src/services/types.ts +17 -14
  135. package/src/types.ts +17 -0
  136. package/src/utils/index.ts +138 -0
  137. package/tests/XmlToolCallProcessor.test.ts +468 -0
  138. package/tests/manual/ycmd/debug_diagnostics_test.ts +127 -0
  139. package/tests/manual/ycmd/fixtures/debug_diagnostics.ts +26 -0
  140. package/tests/manual/ycmd/fixtures/file_change_test.ts +17 -0
  141. package/tests/manual/ycmd/minimal_advanced_test.ts +108 -0
  142. package/tests/manual/ycmd/simple_diagnostics_test.ts +61 -0
  143. package/tests/manual/ycmd/simple_test.ts +74 -0
  144. package/tests/manual/ycmd/test-typescript-sample.ts +34 -0
  145. package/tests/manual/ycmd/test_advanced_features.ts +407 -0
  146. package/tests/manual/ycmd/test_advanced_with_tools.ts +320 -0
  147. package/tests/manual/ycmd/test_comprehensive_typescript.ts +179 -0
  148. package/tests/manual/ycmd/test_diagnostics_file_changes.ts +249 -0
  149. package/tests/manual/ycmd/test_diagnostics_fix.ts +99 -0
  150. package/tests/manual/ycmd/test_diagnostics_simple.ts +100 -0
  151. package/tests/manual/ycmd/test_diagnostics_timing.ts +120 -0
  152. package/tests/manual/ycmd/test_discover_commands.ts +310 -0
  153. package/tests/manual/ycmd/test_endpoints.ts +115 -0
  154. package/tests/manual/ycmd/test_final_comprehensive.ts +218 -0
  155. package/tests/manual/ycmd/test_final_validation.ts +150 -0
  156. package/tests/manual/ycmd/test_implementation.js +42 -0
  157. package/tests/manual/ycmd/test_individual_ycmd_tool.ts +39 -0
  158. package/tests/manual/ycmd/test_server_manager.ts +52 -0
  159. package/tests/manual/ycmd/test_simple_debug.ts +86 -0
  160. package/tests/manual/ycmd/test_tsserver_workflow.js +83 -0
  161. package/tests/manual/ycmd/test_tsserver_workflow.ts +122 -0
  162. package/tests/manual/ycmd/test_typescript_simple.ts +48 -0
  163. package/tests/manual/ycmd/test_typescript_ycmd.ts +105 -0
  164. package/tests/manual/ycmd/test_workspace_config.ts +90 -0
  165. package/tests/manual/ycmd/test_ycmd_auto_start.ts +137 -0
  166. package/tests/manual/ycmd/test_ycmd_comprehensive.ts +73 -0
  167. package/tests/manual/ycmd/test_ycmd_connection.py +10 -0
  168. package/tests/manual/ycmd/test_ycmd_direct.ts +142 -0
  169. package/tests/manual/ycmd/test_ycmd_experiment.ts +48 -0
  170. package/tests/manual/ycmd/test_ycmd_final.ts +200 -0
  171. package/tests/manual/ycmd/test_ycmd_fixed.py +18 -0
  172. package/tests/manual/ycmd/test_ycmd_integration.ts +112 -0
  173. package/tests/manual/ycmd/test_ycmd_simple.ts +45 -0
  174. package/tests/manual/ycmd/test_ycmd_usage.py +27 -0
  175. package/tests/manual/ycmd/working_simple_test.ts +134 -0
  176. package/ts_build/src/agents/base/base.d.ts +15 -1
  177. package/ts_build/src/agents/base/base.js +121 -20
  178. package/ts_build/src/agents/base/base.js.map +1 -1
  179. package/ts_build/src/agents/base/prompt.d.ts +1 -1
  180. package/ts_build/src/agents/base/prompt.js +28 -0
  181. package/ts_build/src/agents/base/prompt.js.map +1 -1
  182. package/ts_build/src/agents/index.d.ts +2 -0
  183. package/ts_build/src/agents/index.js +2 -0
  184. package/ts_build/src/agents/index.js.map +1 -1
  185. package/ts_build/src/agents/patcher/patcher.js +6 -3
  186. package/ts_build/src/agents/patcher/patcher.js.map +1 -1
  187. package/ts_build/src/agents/setup/setup.d.ts +8 -0
  188. package/ts_build/src/agents/setup/setup.js +59 -0
  189. package/ts_build/src/agents/setup/setup.js.map +1 -0
  190. package/ts_build/src/agents/tools/agentCall.js +5 -2
  191. package/ts_build/src/agents/tools/agentCall.js.map +1 -1
  192. package/ts_build/src/agents/tools/aiClient.d.ts +6 -5
  193. package/ts_build/src/agents/tools/aiClient.js +37 -6
  194. package/ts_build/src/agents/tools/aiClient.js.map +1 -1
  195. package/ts_build/src/agents/tools/execCommand.d.ts +2 -2
  196. package/ts_build/src/agents/tools/execCommand.js +5 -6
  197. package/ts_build/src/agents/tools/execCommand.js.map +1 -1
  198. package/ts_build/src/agents/tools/executeScript/index.d.ts +1 -1
  199. package/ts_build/src/agents/tools/index.d.ts +2 -0
  200. package/ts_build/src/agents/tools/index.js +2 -0
  201. package/ts_build/src/agents/tools/index.js.map +1 -1
  202. package/ts_build/src/agents/tools/list.js +66 -16
  203. package/ts_build/src/agents/tools/list.js.map +1 -1
  204. package/ts_build/src/agents/tools/startAgentTask.d.ts +13 -0
  205. package/ts_build/src/agents/tools/startAgentTask.js +74 -0
  206. package/ts_build/src/agents/tools/startAgentTask.js.map +1 -0
  207. package/ts_build/src/agents/tools/startChatTask.d.ts +13 -0
  208. package/ts_build/src/agents/tools/startChatTask.js +73 -0
  209. package/ts_build/src/agents/tools/startChatTask.js.map +1 -0
  210. package/ts_build/src/agents/tools/textSearch.js +1 -1
  211. package/ts_build/src/agents/tools/textSearch.js.map +1 -1
  212. package/ts_build/src/agents/tools/visionTool.d.ts +1 -1
  213. package/ts_build/src/agents/tools/visionTool.js +23 -3
  214. package/ts_build/src/agents/tools/visionTool.js.map +1 -1
  215. package/ts_build/src/agents/tools/ycmd/client.d.ts +93 -0
  216. package/ts_build/src/agents/tools/ycmd/client.js +355 -0
  217. package/ts_build/src/agents/tools/ycmd/client.js.map +1 -0
  218. package/ts_build/src/agents/tools/ycmd/definitions.d.ts +345 -0
  219. package/ts_build/src/agents/tools/ycmd/definitions.js +298 -0
  220. package/ts_build/src/agents/tools/ycmd/definitions.js.map +1 -0
  221. package/ts_build/src/agents/tools/ycmd/detection.d.ts +11 -0
  222. package/ts_build/src/agents/tools/ycmd/detection.js +175 -0
  223. package/ts_build/src/agents/tools/ycmd/detection.js.map +1 -0
  224. package/ts_build/src/agents/tools/ycmd/index.d.ts +8 -0
  225. package/ts_build/src/agents/tools/ycmd/index.js +20 -0
  226. package/ts_build/src/agents/tools/ycmd/index.js.map +1 -0
  227. package/ts_build/src/agents/tools/ycmd/installer.d.ts +19 -0
  228. package/ts_build/src/agents/tools/ycmd/installer.js +196 -0
  229. package/ts_build/src/agents/tools/ycmd/installer.js.map +1 -0
  230. package/ts_build/src/agents/tools/ycmd/server.d.ts +35 -0
  231. package/ts_build/src/agents/tools/ycmd/server.js +363 -0
  232. package/ts_build/src/agents/tools/ycmd/server.js.map +1 -0
  233. package/ts_build/src/agents/tools/ycmd/serverManager.d.ts +39 -0
  234. package/ts_build/src/agents/tools/ycmd/serverManager.js +210 -0
  235. package/ts_build/src/agents/tools/ycmd/serverManager.js.map +1 -0
  236. package/ts_build/src/agents/tools/ycmd/tools/completion.d.ts +22 -0
  237. package/ts_build/src/agents/tools/ycmd/tools/completion.js +72 -0
  238. package/ts_build/src/agents/tools/ycmd/tools/completion.js.map +1 -0
  239. package/ts_build/src/agents/tools/ycmd/tools/diagnostics.d.ts +42 -0
  240. package/ts_build/src/agents/tools/ycmd/tools/diagnostics.js +88 -0
  241. package/ts_build/src/agents/tools/ycmd/tools/diagnostics.js.map +1 -0
  242. package/ts_build/src/agents/tools/ycmd/tools/getLocations.d.ts +22 -0
  243. package/ts_build/src/agents/tools/ycmd/tools/getLocations.js +142 -0
  244. package/ts_build/src/agents/tools/ycmd/tools/getLocations.js.map +1 -0
  245. package/ts_build/src/agents/tools/ycmd/tools/goto.d.ts +20 -0
  246. package/ts_build/src/agents/tools/ycmd/tools/goto.js +101 -0
  247. package/ts_build/src/agents/tools/ycmd/tools/goto.js.map +1 -0
  248. package/ts_build/src/agents/tools/ycmd/tools/refactor.d.ts +32 -0
  249. package/ts_build/src/agents/tools/ycmd/tools/refactor.js +123 -0
  250. package/ts_build/src/agents/tools/ycmd/tools/refactor.js.map +1 -0
  251. package/ts_build/src/agents/tools/ycmd/tools/signature.d.ts +25 -0
  252. package/ts_build/src/agents/tools/ycmd/tools/signature.js +110 -0
  253. package/ts_build/src/agents/tools/ycmd/tools/signature.js.map +1 -0
  254. package/ts_build/src/agents/tools/ycmd/tools/start.d.ts +17 -0
  255. package/ts_build/src/agents/tools/ycmd/tools/start.js +65 -0
  256. package/ts_build/src/agents/tools/ycmd/tools/start.js.map +1 -0
  257. package/ts_build/src/agents/tools/ycmd/utils/pathUtils.d.ts +4 -0
  258. package/ts_build/src/agents/tools/ycmd/utils/pathUtils.js +67 -0
  259. package/ts_build/src/agents/tools/ycmd/utils/pathUtils.js.map +1 -0
  260. package/ts_build/src/ai.d.ts +1 -0
  261. package/ts_build/src/ai.js +40 -1
  262. package/ts_build/src/ai.js.map +1 -1
  263. package/ts_build/src/chat/ChatCommandHandler.d.ts +36 -0
  264. package/ts_build/src/chat/ChatCommandHandler.js +268 -0
  265. package/ts_build/src/chat/ChatCommandHandler.js.map +1 -0
  266. package/ts_build/src/chat/ChatInputManager.d.ts +22 -0
  267. package/ts_build/src/chat/ChatInputManager.js +85 -0
  268. package/ts_build/src/chat/ChatInputManager.js.map +1 -0
  269. package/ts_build/src/chat/ChatManager.d.ts +49 -0
  270. package/ts_build/src/chat/ChatManager.js +271 -0
  271. package/ts_build/src/chat/ChatManager.js.map +1 -0
  272. package/ts_build/src/chat/ChatSession.d.ts +32 -0
  273. package/ts_build/src/chat/ChatSession.js +3 -0
  274. package/ts_build/src/chat/ChatSession.js.map +1 -0
  275. package/ts_build/src/chat/ChatSessionManager.d.ts +19 -0
  276. package/ts_build/src/chat/ChatSessionManager.js +188 -0
  277. package/ts_build/src/chat/ChatSessionManager.js.map +1 -0
  278. package/ts_build/src/chat/ChatStateManager.d.ts +58 -0
  279. package/ts_build/src/chat/ChatStateManager.js +156 -0
  280. package/ts_build/src/chat/ChatStateManager.js.map +1 -0
  281. package/ts_build/src/chat/CliChatService.d.ts +35 -0
  282. package/ts_build/src/chat/CliChatService.js +201 -0
  283. package/ts_build/src/chat/CliChatService.js.map +1 -0
  284. package/ts_build/src/chat/InterruptibleInput.d.ts +20 -0
  285. package/ts_build/src/chat/InterruptibleInput.js +109 -0
  286. package/ts_build/src/chat/InterruptibleInput.js.map +1 -0
  287. package/ts_build/src/chat/interfaces/ChatModule.d.ts +6 -0
  288. package/ts_build/src/chat/interfaces/ChatModule.js +3 -0
  289. package/ts_build/src/chat/interfaces/ChatModule.js.map +1 -0
  290. package/ts_build/src/chat/modules/AgentModule.d.ts +57 -0
  291. package/ts_build/src/chat/modules/AgentModule.js +709 -0
  292. package/ts_build/src/chat/modules/AgentModule.js.map +1 -0
  293. package/ts_build/src/chat/modules/AskModule.d.ts +10 -0
  294. package/ts_build/src/chat/modules/AskModule.js +63 -0
  295. package/ts_build/src/chat/modules/AskModule.js.map +1 -0
  296. package/ts_build/src/chat/modules/BaseChatModule.d.ts +14 -0
  297. package/ts_build/src/chat/modules/BaseChatModule.js +32 -0
  298. package/ts_build/src/chat/modules/BaseChatModule.js.map +1 -0
  299. package/ts_build/src/chat/modules/InternalChatModule.d.ts +24 -0
  300. package/ts_build/src/chat/modules/InternalChatModule.js +127 -0
  301. package/ts_build/src/chat/modules/InternalChatModule.js.map +1 -0
  302. package/ts_build/src/chat/modules/SearchModule.d.ts +12 -0
  303. package/ts_build/src/chat/modules/SearchModule.js +119 -0
  304. package/ts_build/src/chat/modules/SearchModule.js.map +1 -0
  305. package/ts_build/src/chat/modules/SetupModule.d.ts +15 -0
  306. package/ts_build/src/chat/modules/SetupModule.js +147 -0
  307. package/ts_build/src/chat/modules/SetupModule.js.map +1 -0
  308. package/ts_build/src/chat/modules/SystemModule.d.ts +14 -0
  309. package/ts_build/src/chat/modules/SystemModule.js +90 -0
  310. package/ts_build/src/chat/modules/SystemModule.js.map +1 -0
  311. package/ts_build/src/chat/modules/VoiceModule.d.ts +11 -0
  312. package/ts_build/src/chat/modules/VoiceModule.js +57 -0
  313. package/ts_build/src/chat/modules/VoiceModule.js.map +1 -0
  314. package/ts_build/src/chat/types.d.ts +83 -0
  315. package/ts_build/src/chat/types.js +3 -0
  316. package/ts_build/src/chat/types.js.map +1 -0
  317. package/ts_build/src/chat.js +7 -1
  318. package/ts_build/src/chat.js.map +1 -1
  319. package/ts_build/src/chat2.d.ts +3 -0
  320. package/ts_build/src/chat2.js +47 -0
  321. package/ts_build/src/chat2.js.map +1 -0
  322. package/ts_build/src/cli.js +218 -37
  323. package/ts_build/src/cli.js.map +1 -1
  324. package/ts_build/src/clients/anthropic.d.ts +5 -2
  325. package/ts_build/src/clients/anthropic.js +12 -7
  326. package/ts_build/src/clients/anthropic.js.map +1 -1
  327. package/ts_build/src/clients/gemini.d.ts +6 -3
  328. package/ts_build/src/clients/gemini.js +13 -7
  329. package/ts_build/src/clients/gemini.js.map +1 -1
  330. package/ts_build/src/clients/http.d.ts +1 -0
  331. package/ts_build/src/clients/http.js +12 -5
  332. package/ts_build/src/clients/http.js.map +1 -1
  333. package/ts_build/src/clients/index.d.ts +10 -0
  334. package/ts_build/src/clients/index.js +74 -4
  335. package/ts_build/src/clients/index.js.map +1 -1
  336. package/ts_build/src/clients/knowhow.d.ts +3 -1
  337. package/ts_build/src/clients/knowhow.js +8 -2
  338. package/ts_build/src/clients/knowhow.js.map +1 -1
  339. package/ts_build/src/clients/knowhowMcp.d.ts +20 -0
  340. package/ts_build/src/clients/knowhowMcp.js +86 -0
  341. package/ts_build/src/clients/knowhowMcp.js.map +1 -0
  342. package/ts_build/src/clients/openai.d.ts +5 -2
  343. package/ts_build/src/clients/openai.js +29 -8
  344. package/ts_build/src/clients/openai.js.map +1 -1
  345. package/ts_build/src/clients/types.d.ts +1 -0
  346. package/ts_build/src/clients/xai.d.ts +5 -2
  347. package/ts_build/src/clients/xai.js +15 -5
  348. package/ts_build/src/clients/xai.js.map +1 -1
  349. package/ts_build/src/config.js +24 -3
  350. package/ts_build/src/config.js.map +1 -1
  351. package/ts_build/src/conversion.js +6 -4
  352. package/ts_build/src/conversion.js.map +1 -1
  353. package/ts_build/src/login.d.ts +1 -1
  354. package/ts_build/src/login.js +21 -7
  355. package/ts_build/src/login.js.map +1 -1
  356. package/ts_build/src/microphone.js.map +1 -1
  357. package/ts_build/src/plugins/downloader/downloader.d.ts +7 -5
  358. package/ts_build/src/plugins/downloader/downloader.js +147 -44
  359. package/ts_build/src/plugins/downloader/downloader.js.map +1 -1
  360. package/ts_build/src/plugins/downloader/plugin.js +5 -3
  361. package/ts_build/src/plugins/downloader/plugin.js.map +1 -1
  362. package/ts_build/src/plugins/plugins.js +3 -0
  363. package/ts_build/src/plugins/plugins.js.map +1 -1
  364. package/ts_build/src/processors/CustomVariables.d.ts +32 -0
  365. package/ts_build/src/processors/CustomVariables.js +297 -0
  366. package/ts_build/src/processors/CustomVariables.js.map +1 -0
  367. package/ts_build/src/processors/HarmonyToolProcessor.d.ts +15 -0
  368. package/ts_build/src/processors/HarmonyToolProcessor.js +154 -0
  369. package/ts_build/src/processors/HarmonyToolProcessor.js.map +1 -0
  370. package/ts_build/src/processors/XmlToolCallProcessor.d.ts +14 -0
  371. package/ts_build/src/processors/XmlToolCallProcessor.js +357 -0
  372. package/ts_build/src/processors/XmlToolCallProcessor.js.map +1 -0
  373. package/ts_build/src/processors/index.d.ts +3 -0
  374. package/ts_build/src/processors/index.js +7 -1
  375. package/ts_build/src/processors/index.js.map +1 -1
  376. package/ts_build/src/prompts/KnowhowConfigExamples.d.ts +2 -0
  377. package/ts_build/src/prompts/KnowhowConfigExamples.js +379 -0
  378. package/ts_build/src/prompts/KnowhowConfigExamples.js.map +1 -0
  379. package/ts_build/src/services/KnowhowClient.d.ts +22 -0
  380. package/ts_build/src/services/KnowhowClient.js +14 -2
  381. package/ts_build/src/services/KnowhowClient.js.map +1 -1
  382. package/ts_build/src/services/Mcp.d.ts +1 -0
  383. package/ts_build/src/services/Mcp.js +20 -3
  384. package/ts_build/src/services/Mcp.js.map +1 -1
  385. package/ts_build/src/services/McpServer.d.ts +1 -1
  386. package/ts_build/src/services/McpServer.js +8 -4
  387. package/ts_build/src/services/McpServer.js.map +1 -1
  388. package/ts_build/src/services/McpWebsocketTransport.js +17 -7
  389. package/ts_build/src/services/McpWebsocketTransport.js.map +1 -1
  390. package/ts_build/src/services/MessageProcessor.d.ts +1 -1
  391. package/ts_build/src/services/MessageProcessor.js +4 -4
  392. package/ts_build/src/services/MessageProcessor.js.map +1 -1
  393. package/ts_build/src/services/index.d.ts +2 -0
  394. package/ts_build/src/services/index.js +4 -0
  395. package/ts_build/src/services/index.js.map +1 -1
  396. package/ts_build/src/services/script-execution/ScriptExecutor.d.ts +1 -0
  397. package/ts_build/src/services/script-execution/ScriptExecutor.js +23 -0
  398. package/ts_build/src/services/script-execution/ScriptExecutor.js.map +1 -1
  399. package/ts_build/src/services/types.d.ts +2 -6
  400. package/ts_build/src/services/types.js +4 -4
  401. package/ts_build/src/services/types.js.map +1 -1
  402. package/ts_build/src/types.d.ts +11 -0
  403. package/ts_build/src/types.js +8 -0
  404. package/ts_build/src/types.js.map +1 -1
  405. package/ts_build/src/utils/index.d.ts +2 -0
  406. package/ts_build/src/utils/index.js +102 -1
  407. package/ts_build/src/utils/index.js.map +1 -1
  408. package/ts_build/tests/XmlToolCallProcessor.test.d.ts +1 -0
  409. package/ts_build/tests/XmlToolCallProcessor.test.js +376 -0
  410. package/ts_build/tests/XmlToolCallProcessor.test.js.map +1 -0
  411. package/ts_build/tests/manual/ycmd/debug_diagnostics_test.d.ts +1 -0
  412. package/ts_build/tests/manual/ycmd/debug_diagnostics_test.js +114 -0
  413. package/ts_build/tests/manual/ycmd/debug_diagnostics_test.js.map +1 -0
  414. package/ts_build/tests/manual/ycmd/minimal_advanced_test.d.ts +2 -0
  415. package/ts_build/tests/manual/ycmd/minimal_advanced_test.js +104 -0
  416. package/ts_build/tests/manual/ycmd/minimal_advanced_test.js.map +1 -0
  417. package/ts_build/tests/manual/ycmd/simple_diagnostics_test.d.ts +1 -0
  418. package/ts_build/tests/manual/ycmd/simple_diagnostics_test.js +74 -0
  419. package/ts_build/tests/manual/ycmd/simple_diagnostics_test.js.map +1 -0
  420. package/ts_build/tests/manual/ycmd/simple_test.d.ts +2 -0
  421. package/ts_build/tests/manual/ycmd/simple_test.js +82 -0
  422. package/ts_build/tests/manual/ycmd/simple_test.js.map +1 -0
  423. package/ts_build/tests/manual/ycmd/test-typescript-sample.d.ts +14 -0
  424. package/ts_build/tests/manual/ycmd/test-typescript-sample.js +20 -0
  425. package/ts_build/tests/manual/ycmd/test-typescript-sample.js.map +1 -0
  426. package/ts_build/tests/manual/ycmd/test_advanced_features.d.ts +2 -0
  427. package/ts_build/tests/manual/ycmd/test_advanced_features.js +297 -0
  428. package/ts_build/tests/manual/ycmd/test_advanced_features.js.map +1 -0
  429. package/ts_build/tests/manual/ycmd/test_advanced_with_tools.d.ts +3 -0
  430. package/ts_build/tests/manual/ycmd/test_advanced_with_tools.js +262 -0
  431. package/ts_build/tests/manual/ycmd/test_advanced_with_tools.js.map +1 -0
  432. package/ts_build/tests/manual/ycmd/test_comprehensive_typescript.d.ts +2 -0
  433. package/ts_build/tests/manual/ycmd/test_comprehensive_typescript.js +186 -0
  434. package/ts_build/tests/manual/ycmd/test_comprehensive_typescript.js.map +1 -0
  435. package/ts_build/tests/manual/ycmd/test_diagnostics_file_changes.d.ts +1 -0
  436. package/ts_build/tests/manual/ycmd/test_diagnostics_file_changes.js +174 -0
  437. package/ts_build/tests/manual/ycmd/test_diagnostics_file_changes.js.map +1 -0
  438. package/ts_build/tests/manual/ycmd/test_diagnostics_fix.d.ts +2 -0
  439. package/ts_build/tests/manual/ycmd/test_diagnostics_fix.js +106 -0
  440. package/ts_build/tests/manual/ycmd/test_diagnostics_fix.js.map +1 -0
  441. package/ts_build/tests/manual/ycmd/test_diagnostics_simple.d.ts +1 -0
  442. package/ts_build/tests/manual/ycmd/test_diagnostics_simple.js +104 -0
  443. package/ts_build/tests/manual/ycmd/test_diagnostics_simple.js.map +1 -0
  444. package/ts_build/tests/manual/ycmd/test_diagnostics_timing.d.ts +1 -0
  445. package/ts_build/tests/manual/ycmd/test_diagnostics_timing.js +119 -0
  446. package/ts_build/tests/manual/ycmd/test_diagnostics_timing.js.map +1 -0
  447. package/ts_build/tests/manual/ycmd/test_discover_commands.d.ts +2 -0
  448. package/ts_build/tests/manual/ycmd/test_discover_commands.js +243 -0
  449. package/ts_build/tests/manual/ycmd/test_discover_commands.js.map +1 -0
  450. package/ts_build/tests/manual/ycmd/test_endpoints.d.ts +2 -0
  451. package/ts_build/tests/manual/ycmd/test_endpoints.js +120 -0
  452. package/ts_build/tests/manual/ycmd/test_endpoints.js.map +1 -0
  453. package/ts_build/tests/manual/ycmd/test_final_comprehensive.d.ts +2 -0
  454. package/ts_build/tests/manual/ycmd/test_final_comprehensive.js +221 -0
  455. package/ts_build/tests/manual/ycmd/test_final_comprehensive.js.map +1 -0
  456. package/ts_build/tests/manual/ycmd/test_final_validation.d.ts +2 -0
  457. package/ts_build/tests/manual/ycmd/test_final_validation.js +160 -0
  458. package/ts_build/tests/manual/ycmd/test_final_validation.js.map +1 -0
  459. package/ts_build/tests/manual/ycmd/test_individual_ycmd_tool.d.ts +2 -0
  460. package/ts_build/tests/manual/ycmd/test_individual_ycmd_tool.js +37 -0
  461. package/ts_build/tests/manual/ycmd/test_individual_ycmd_tool.js.map +1 -0
  462. package/ts_build/tests/manual/ycmd/test_server_manager.d.ts +1 -0
  463. package/ts_build/tests/manual/ycmd/test_server_manager.js +38 -0
  464. package/ts_build/tests/manual/ycmd/test_server_manager.js.map +1 -0
  465. package/ts_build/tests/manual/ycmd/test_simple_debug.d.ts +2 -0
  466. package/ts_build/tests/manual/ycmd/test_simple_debug.js +99 -0
  467. package/ts_build/tests/manual/ycmd/test_simple_debug.js.map +1 -0
  468. package/ts_build/tests/manual/ycmd/test_tsserver_workflow.d.ts +1 -0
  469. package/ts_build/tests/manual/ycmd/test_tsserver_workflow.js +128 -0
  470. package/ts_build/tests/manual/ycmd/test_tsserver_workflow.js.map +1 -0
  471. package/ts_build/tests/manual/ycmd/test_typescript_simple.d.ts +1 -0
  472. package/ts_build/tests/manual/ycmd/test_typescript_simple.js +66 -0
  473. package/ts_build/tests/manual/ycmd/test_typescript_simple.js.map +1 -0
  474. package/ts_build/tests/manual/ycmd/test_typescript_ycmd.d.ts +1 -0
  475. package/ts_build/tests/manual/ycmd/test_typescript_ycmd.js +105 -0
  476. package/ts_build/tests/manual/ycmd/test_typescript_ycmd.js.map +1 -0
  477. package/ts_build/tests/manual/ycmd/test_workspace_config.d.ts +1 -0
  478. package/ts_build/tests/manual/ycmd/test_workspace_config.js +89 -0
  479. package/ts_build/tests/manual/ycmd/test_workspace_config.js.map +1 -0
  480. package/ts_build/tests/manual/ycmd/test_ycmd_auto_start.d.ts +2 -0
  481. package/ts_build/tests/manual/ycmd/test_ycmd_auto_start.js +130 -0
  482. package/ts_build/tests/manual/ycmd/test_ycmd_auto_start.js.map +1 -0
  483. package/ts_build/tests/manual/ycmd/test_ycmd_comprehensive.d.ts +1 -0
  484. package/ts_build/tests/manual/ycmd/test_ycmd_comprehensive.js +83 -0
  485. package/ts_build/tests/manual/ycmd/test_ycmd_comprehensive.js.map +1 -0
  486. package/ts_build/tests/manual/ycmd/test_ycmd_direct.d.ts +2 -0
  487. package/ts_build/tests/manual/ycmd/test_ycmd_direct.js +149 -0
  488. package/ts_build/tests/manual/ycmd/test_ycmd_direct.js.map +1 -0
  489. package/ts_build/tests/manual/ycmd/test_ycmd_experiment.d.ts +15 -0
  490. package/ts_build/tests/manual/ycmd/test_ycmd_experiment.js +58 -0
  491. package/ts_build/tests/manual/ycmd/test_ycmd_experiment.js.map +1 -0
  492. package/ts_build/tests/manual/ycmd/test_ycmd_final.d.ts +2 -0
  493. package/ts_build/tests/manual/ycmd/test_ycmd_final.js +195 -0
  494. package/ts_build/tests/manual/ycmd/test_ycmd_final.js.map +1 -0
  495. package/ts_build/tests/manual/ycmd/test_ycmd_integration.d.ts +3 -0
  496. package/ts_build/tests/manual/ycmd/test_ycmd_integration.js +110 -0
  497. package/ts_build/tests/manual/ycmd/test_ycmd_integration.js.map +1 -0
  498. package/ts_build/tests/manual/ycmd/test_ycmd_simple.d.ts +2 -0
  499. package/ts_build/tests/manual/ycmd/test_ycmd_simple.js +36 -0
  500. package/ts_build/tests/manual/ycmd/test_ycmd_simple.js.map +1 -0
  501. package/ts_build/tests/manual/ycmd/working_simple_test.d.ts +2 -0
  502. package/ts_build/tests/manual/ycmd/working_simple_test.js +134 -0
  503. package/ts_build/tests/manual/ycmd/working_simple_test.js.map +1 -0
  504. package/tsconfig.json +3 -1
@@ -5,14 +5,14 @@ import Logger from "progress-estimator";
5
5
  import { DownloadInfo, KeyframeInfo, TranscriptChunk } from "./types";
6
6
  import { visionTool } from "../../agents/tools/visionTool";
7
7
  import { execAsync, fileExists, readFile, mkdir } from "../../utils";
8
- import { openai } from "../../ai";
8
+ import OpenAI from "openai";
9
9
  import { Clients } from "../../clients";
10
10
  import { Models } from "../../types";
11
11
 
12
12
  const logger = Logger();
13
13
 
14
14
  export class DownloaderService {
15
- constructor(private openAi: typeof openai, private clients: typeof Clients) {}
15
+ constructor(private openAi: OpenAI, private clients: typeof Clients) {}
16
16
 
17
17
  async askGptVision(
18
18
  imageUrl: string,
@@ -65,6 +65,36 @@ export class DownloaderService {
65
65
  return info;
66
66
  }
67
67
 
68
+ private async acquireLock(
69
+ lockPath: string,
70
+ timeoutMs = 30000
71
+ ): Promise<() => void> {
72
+ const startTime = Date.now();
73
+
74
+ while (Date.now() - startTime < timeoutMs) {
75
+ try {
76
+ await fs.promises.writeFile(lockPath, process.pid.toString(), {
77
+ flag: "wx",
78
+ });
79
+ console.log(`Lock acquired: ${lockPath}`);
80
+ return async () => {
81
+ try {
82
+ await fs.promises.unlink(lockPath);
83
+ console.log(`Lock released: ${lockPath}`);
84
+ } catch (error) {
85
+ console.warn(`Failed to release lock ${lockPath}:`, error);
86
+ }
87
+ };
88
+ } catch (error) {
89
+ if (error.code !== "EEXIST") {
90
+ throw error;
91
+ }
92
+ await new Promise((resolve) => setTimeout(resolve, 100));
93
+ }
94
+ }
95
+ throw new Error(`Failed to acquire lock ${lockPath} within ${timeoutMs}ms`);
96
+ }
97
+
68
98
  public async chunk(
69
99
  filePath: string,
70
100
  outputDir: string,
@@ -77,44 +107,120 @@ export class DownloaderService {
77
107
  console.log({ fileName, fileExt });
78
108
  console.log("Chunking file", filePath);
79
109
 
80
- // create a temp directory
81
- const outputDirPath = path.join(outputDir, `${fileName}/chunks`);
82
- await fs.promises.mkdir(outputDirPath, { recursive: true });
83
- const existingFolderFiles = await fs.promises.readdir(outputDirPath);
84
- const existingChunkNames = existingFolderFiles.filter(
85
- (f) => f.includes("chunk") && f.endsWith(".mp3")
86
- );
110
+ // Create lock to prevent concurrent chunking of the same file
111
+ const lockPath = path.join(outputDir, `${fileName}.chunking.lock`);
112
+ const releaseLock = await this.acquireLock(lockPath);
113
+
114
+ try {
115
+ // create a temp directory
116
+ const outputDirPath = path.join(outputDir, `${fileName}/chunks`);
117
+ await fs.promises.mkdir(outputDirPath, { recursive: true });
118
+ const existingFolderFiles = await fs.promises.readdir(outputDirPath);
119
+ const existingChunkNames = existingFolderFiles.filter(
120
+ (f) => f.includes("chunk") && f.endsWith(".mp3")
121
+ );
87
122
 
88
- if (existingChunkNames.length > 0) {
89
- if (reuseExistingChunks) {
90
- console.log("Chunks already exist, skipping");
91
- const names = existingChunkNames.map((chunkName) =>
92
- path.join(outputDirPath, chunkName)
93
- );
94
- return names;
95
- } else {
96
- for (const file of existingFolderFiles) {
97
- fs.rmSync(path.join(outputDirPath, file), { recursive: true });
123
+ if (existingChunkNames.length > 0) {
124
+ if (reuseExistingChunks) {
125
+ console.log("Chunks already exist, skipping");
126
+ await releaseLock();
127
+ const names = existingChunkNames.map((chunkName) =>
128
+ path.join(outputDirPath, chunkName)
129
+ );
130
+ return names;
131
+ } else {
132
+ for (const file of existingFolderFiles) {
133
+ fs.rmSync(path.join(outputDirPath, file), { recursive: true });
134
+ }
98
135
  }
99
136
  }
100
- }
101
137
 
102
- const command = `ffmpeg -i "${filePath}" -f segment -segment_time ${CHUNK_LENGTH_SECONDS} -map 0:a:0 -acodec mp3 -vn "${outputDirPath}/chunk%03d.mp3"`;
103
- await execAsync(command);
138
+ const command = `ffmpeg -i "${filePath}" -f segment -segment_time ${CHUNK_LENGTH_SECONDS} -map 0:a:0 -acodec mp3 -vn "${outputDirPath}/chunk%04d.mp3"`;
139
+ await execAsync(command);
104
140
 
105
- const folderFiles = await fs.promises.readdir(outputDirPath);
106
- const chunkNames = folderFiles.filter(
107
- (f) => f.includes("chunk") && f.endsWith(".mp3")
108
- );
109
- console.log("Chunked into", chunkNames.length, "chunks");
110
- return chunkNames.map((chunkName) => path.join(outputDirPath, chunkName));
141
+ const folderFiles = await fs.promises.readdir(outputDirPath);
142
+ const chunkNames = folderFiles.filter(
143
+ (f) => f.includes("chunk") && f.endsWith(".mp3")
144
+ );
145
+ console.log("Chunked into", chunkNames.length, "chunks");
146
+ return chunkNames.map((chunkName) => path.join(outputDirPath, chunkName));
147
+ } catch (error) {
148
+ console.error("Error during chunking:", error);
149
+ throw error;
150
+ } finally {
151
+ await releaseLock();
152
+ }
111
153
  }
112
154
 
155
+ // Add transcription locking to prevent race conditions
156
+ private transcriptionLocks = new Map<string, Promise<TranscriptChunk[]>>();
157
+
113
158
  public async *streamTranscription(
114
159
  files: string[],
115
160
  outputPath: string,
116
161
  reusePreviousTranscript = true
117
162
  ): AsyncGenerator<TranscriptChunk> {
163
+ const exists = await fileExists(outputPath);
164
+ if (exists && reusePreviousTranscript) {
165
+ console.log("Transcription already exists, using cached data");
166
+ const contents = await readFile(outputPath);
167
+ const data = JSON.parse(contents.toString()) as TranscriptChunk[];
168
+ for (const item of data) {
169
+ yield item;
170
+ }
171
+ return;
172
+ }
173
+
174
+ // Prevent concurrent transcription of the same output file
175
+ const lockKey = outputPath;
176
+ if (this.transcriptionLocks.has(lockKey)) {
177
+ console.log("Waiting for concurrent transcription to complete...");
178
+ await this.transcriptionLocks.get(lockKey);
179
+ // After waiting, check again if file exists
180
+ const existsNow = await fileExists(outputPath);
181
+ if (existsNow && reusePreviousTranscript) {
182
+ console.log(
183
+ "Transcription completed by concurrent process, using cached data"
184
+ );
185
+ const contents = await readFile(outputPath);
186
+ const data = JSON.parse(contents.toString()) as TranscriptChunk[];
187
+ for (const item of data) {
188
+ yield item;
189
+ }
190
+ return;
191
+ }
192
+ }
193
+
194
+ // Create a promise for this transcription operation
195
+ const transcriptionPromise = (async () => {
196
+ const results: TranscriptChunk[] = [];
197
+ for await (const chunk of this.performTranscription(
198
+ files,
199
+ outputPath,
200
+ reusePreviousTranscript
201
+ )) {
202
+ results.push(chunk);
203
+ }
204
+ return results;
205
+ })();
206
+ this.transcriptionLocks.set(lockKey, transcriptionPromise);
207
+
208
+ try {
209
+ const results = await transcriptionPromise;
210
+ for (const chunk of results) {
211
+ yield chunk;
212
+ }
213
+ } finally {
214
+ this.transcriptionLocks.delete(lockKey);
215
+ }
216
+ }
217
+
218
+ private async *performTranscription(
219
+ files: string[],
220
+ outputPath: string,
221
+ reusePreviousTranscript: boolean
222
+ ): AsyncGenerator<TranscriptChunk> {
223
+ const allTranscripts = [];
118
224
  for (const file of files) {
119
225
  const chunkName = path.parse(file).name;
120
226
  const chunkTranscriptPath = path.join(
@@ -124,13 +230,19 @@ export class DownloaderService {
124
230
  const chunkExists = await fileExists(chunkTranscriptPath);
125
231
 
126
232
  if (chunkExists && reusePreviousTranscript) {
127
- console.log(chunkTranscriptPath, " transcription already exists, skipping");
233
+ console.log(
234
+ chunkTranscriptPath,
235
+ " transcription already exists, using cached data"
236
+ );
128
237
  const contents = await readFile(chunkTranscriptPath);
129
- yield {
238
+ const cached = {
130
239
  chunkPath: chunkTranscriptPath,
131
240
  text: contents.toString(),
132
241
  usd_cost: 0,
133
242
  };
243
+
244
+ yield cached;
245
+ allTranscripts.push(cached);
134
246
  continue;
135
247
  }
136
248
 
@@ -149,12 +261,16 @@ export class DownloaderService {
149
261
  await fs.promises.writeFile(chunkTranscriptPath, transcript.text);
150
262
 
151
263
  // save chunk transcript to file
152
- yield {
264
+ const data = {
153
265
  chunkPath: chunkTranscriptPath,
154
266
  text: transcript.text,
155
267
  usd_cost: 30 * 0.0001, // assume 30 seconds,
156
268
  };
269
+ yield data;
270
+ allTranscripts.push(data);
157
271
  }
272
+
273
+ fs.writeFileSync(outputPath, JSON.stringify(allTranscripts, null, 2));
158
274
  }
159
275
 
160
276
  public async transcribeChunks(
@@ -164,7 +280,7 @@ export class DownloaderService {
164
280
  ): Promise<string[]> {
165
281
  const exists = await fileExists(outputPath);
166
282
  if (exists && reusePreviousTranscript) {
167
- console.log("Transcription already exists, skipping");
283
+ console.log("Transcription already exists, using cached data");
168
284
  const contents = await readFile(outputPath);
169
285
  return JSON.parse(contents.toString()) as string[];
170
286
  }
@@ -185,12 +301,13 @@ export class DownloaderService {
185
301
 
186
302
  public async *streamKeyFrameExtraction(
187
303
  filePath: string,
188
- outputPath: string,
304
+ videoJsonPath: string,
305
+ reusePreviousKeyframes: boolean = true,
189
306
  interval: number = 10
190
307
  ): AsyncGenerator<KeyframeInfo> {
191
- if (fs.existsSync(outputPath)) {
192
- console.log("Keyframes already exist, skipping");
193
- const contents = await readFile(outputPath);
308
+ if (reusePreviousKeyframes && fs.existsSync(videoJsonPath)) {
309
+ console.log("Keyframes already exist, using cached data");
310
+ const contents = await readFile(videoJsonPath);
194
311
  const data = JSON.parse(contents.toString()) as KeyframeInfo[];
195
312
  for (const keyframe of data) {
196
313
  yield { ...keyframe, usd_cost: 0 };
@@ -199,16 +316,18 @@ export class DownloaderService {
199
316
  }
200
317
 
201
318
  const parsed = path.parse(filePath);
202
- const outputDir = path.dirname(outputPath);
319
+ const outputDir = path.dirname(videoJsonPath);
203
320
  const fileName = parsed.name;
204
321
  const keyframesDir = path.join(outputDir, `/keyframes`);
205
322
  await fs.promises.mkdir(keyframesDir, { recursive: true });
206
323
 
207
324
  const command = `ffmpeg -i "${filePath}" -vf "fps=1/${interval},scale=640:-1" "${keyframesDir}/frame%04d.jpg"`;
208
325
  await execAsync(command);
326
+ console.log("Extracting keyframe:", command);
209
327
 
210
328
  const keyframes = await fs.promises.readdir(keyframesDir);
211
329
 
330
+ const allKeyframes = [];
212
331
  for (const keyframe of keyframes) {
213
332
  const keyframePath = path.join(keyframesDir, keyframe);
214
333
  const keyframeName = path.parse(keyframe).name;
@@ -218,10 +337,11 @@ export class DownloaderService {
218
337
  );
219
338
  const descriptionExists = await fileExists(keyframeDescriptionPath);
220
339
 
221
- if (descriptionExists) {
340
+ if (descriptionExists && reusePreviousKeyframes) {
222
341
  const cached = await readFile(keyframeDescriptionPath);
223
342
  const cachedJson = JSON.parse(cached.toString()) as KeyframeInfo;
224
343
  yield { ...cachedJson, usd_cost: 0 };
344
+ allKeyframes.push(cachedJson);
225
345
  continue;
226
346
  }
227
347
 
@@ -237,18 +357,26 @@ export class DownloaderService {
237
357
  JSON.stringify(keyframeJson, null, 2)
238
358
  );
239
359
  yield keyframeJson;
360
+ allKeyframes.push(keyframeJson);
240
361
  }
362
+
363
+ await fs.promises.writeFile(
364
+ videoJsonPath,
365
+ JSON.stringify(allKeyframes, null, 2)
366
+ );
241
367
  }
242
368
 
243
369
  public async extractKeyframes(
244
370
  filePath: string,
245
371
  outputPath: string,
372
+ reusePreviousKeyframes: boolean = true,
246
373
  interval: number = 10
247
374
  ): Promise<KeyframeInfo[]> {
248
375
  const keyframes: KeyframeInfo[] = [];
249
376
  for await (const keyframe of this.streamKeyFrameExtraction(
250
377
  filePath,
251
378
  outputPath,
379
+ reusePreviousKeyframes,
252
380
  interval
253
381
  )) {
254
382
  keyframes.push(keyframe);
@@ -265,6 +393,7 @@ export class DownloaderService {
265
393
  encoding: "base64",
266
394
  });
267
395
  const image = `data:image/jpeg;base64,${base64}`;
396
+ console.log("Describing keyframe:", keyframePath);
268
397
  const response = await this.askGptVision(image, question);
269
398
  return response;
270
399
  }
@@ -285,7 +414,9 @@ export class DownloaderService {
285
414
  // Skip chunking if the full output exists
286
415
  const exists = await fileExists(outputPath);
287
416
  if (exists && reusePreviousTranscript) {
288
- console.log(`Transcription ${outputPath} already exists, skipping`);
417
+ console.log(
418
+ `Transcription ${outputPath} already exists, using cached data`
419
+ );
289
420
  const fileContent = await readFile(outputPath, "utf8");
290
421
  return outputPath.endsWith("txt")
291
422
  ? fileContent.split("\n")
@@ -318,14 +449,21 @@ export class DownloaderService {
318
449
  // Skip chunking if the full output exists
319
450
  const exists = await fileExists(outputPath);
320
451
  if (exists && reusePreviousTranscript) {
321
- console.log(`Transcription ${outputPath} already exists, skipping`);
452
+ console.log(
453
+ `Transcription ${outputPath} already exists, using cached data`
454
+ );
322
455
  const fileContent = await readFile(outputPath, "utf8");
323
456
  const lines = outputPath.endsWith("txt")
324
457
  ? fileContent.split("\n")
325
458
  : JSON.parse(fileContent);
326
459
 
327
- for (const line of lines)
328
- yield { chunkPath: "", text: line, usd_cost: 0 };
460
+ for (const line of lines) {
461
+ if (typeof line === "string") {
462
+ yield { chunkPath: "", text: line, usd_cost: 0 };
463
+ } else {
464
+ yield line as TranscriptChunk;
465
+ }
466
+ }
329
467
  return;
330
468
  }
331
469
 
@@ -364,6 +502,7 @@ export class DownloaderService {
364
502
  const videoAnalysis = await this.extractKeyframes(
365
503
  filePath,
366
504
  outputPath,
505
+ reusePreviousTranscript,
367
506
  chunkTime
368
507
  );
369
508
 
@@ -381,19 +520,20 @@ export class DownloaderService {
381
520
  chunkTime = 30
382
521
  ) {
383
522
  const parsed = path.parse(filePath);
384
- const outputPath = `${parsed.dir}/${parsed.name}/video.json`;
523
+ const videoJson = `${parsed.dir}/${parsed.name}/video.json`;
385
524
 
386
525
  console.log("Processing audio...");
387
- const transcriptions = await this.streamProcessAudio(
526
+ const transcriptions = this.streamProcessAudio(
388
527
  filePath,
389
528
  reusePreviousTranscript,
390
529
  chunkTime
391
530
  );
392
531
 
393
532
  console.log("Extracting keyframes...");
394
- const videoAnalysis = await this.streamKeyFrameExtraction(
533
+ const videoAnalysis = this.streamKeyFrameExtraction(
395
534
  filePath,
396
- outputPath,
535
+ videoJson,
536
+ reusePreviousTranscript,
397
537
  chunkTime
398
538
  );
399
539
 
@@ -402,10 +542,12 @@ export class DownloaderService {
402
542
  ?.value as TranscriptChunk;
403
543
  yield {
404
544
  frame,
405
- transcription,
545
+ transcription: transcription || {
546
+ chunkPath: "",
547
+ text: "[missing transcript]",
548
+ usd_cost: 0,
549
+ },
406
550
  };
407
551
  }
408
552
  }
409
553
  }
410
-
411
- export const Downloader = new DownloaderService(openai, Clients);
@@ -2,7 +2,7 @@ import fs from "fs";
2
2
  import { PluginBase, PluginMeta } from "../PluginBase";
3
3
  import { MinimalEmbedding } from "../../types";
4
4
  import { convertToText, processVideo } from "../../conversion";
5
- import { Downloader } from "./downloader";
5
+ import { services } from "../../services";
6
6
 
7
7
  export class DownloaderPlugin extends PluginBase {
8
8
  static readonly meta: PluginMeta = {
@@ -40,6 +40,7 @@ export class DownloaderPlugin extends PluginBase {
40
40
  try {
41
41
  console.log("DOWNLOADER PLUGIN: attempting", url);
42
42
  const downloadDir = ".knowhow/downloads/";
43
+ const { Downloader } = services();
43
44
  const fileInfo = await Downloader.download(url, downloadDir);
44
45
  const filePath = `${downloadDir}${fileInfo.id}.${fileInfo.ext}`;
45
46
  transcript += await convertToText(filePath);
@@ -59,6 +60,7 @@ export class DownloaderPlugin extends PluginBase {
59
60
  const embeddings: MinimalEmbedding[] = [];
60
61
  for (const url of urls) {
61
62
  const downloadDir = ".knowhow/downloads/";
63
+ const { Downloader } = services();
62
64
  const fileInfo = await Downloader.download(url, downloadDir);
63
65
  const filePath = `${downloadDir}${fileInfo.id}.${fileInfo.ext}`;
64
66
  const processed = await processVideo(filePath);
@@ -79,6 +79,9 @@ export class PluginService {
79
79
  }
80
80
 
81
81
  async callMany(plugins: string[], userInput?: string) {
82
+ if (!plugins || plugins.length === 0) {
83
+ return "";
84
+ }
82
85
  const calls = plugins.map(async (p) => {
83
86
  return this.call(p, userInput);
84
87
  });