@hasna/microservices 0.0.16 → 0.0.18

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 (293) hide show
  1. package/README.md +143 -23
  2. package/bin/index.js +784 -13987
  3. package/bin/mcp.js +298 -10973
  4. package/dist/index.js +251 -10056
  5. package/package.json +36 -26
  6. package/microservices/microservice-ads/package.json +0 -28
  7. package/microservices/microservice-ads/src/cli/index.ts +0 -605
  8. package/microservices/microservice-ads/src/db/campaigns.ts +0 -797
  9. package/microservices/microservice-ads/src/db/database.ts +0 -91
  10. package/microservices/microservice-ads/src/db/migrations.ts +0 -60
  11. package/microservices/microservice-ads/src/index.ts +0 -39
  12. package/microservices/microservice-ads/src/mcp/index.ts +0 -480
  13. package/microservices/microservice-analytics/package.json +0 -28
  14. package/microservices/microservice-analytics/src/cli/index.ts +0 -373
  15. package/microservices/microservice-analytics/src/db/analytics.ts +0 -564
  16. package/microservices/microservice-analytics/src/db/database.ts +0 -91
  17. package/microservices/microservice-analytics/src/db/migrations.ts +0 -50
  18. package/microservices/microservice-analytics/src/index.ts +0 -37
  19. package/microservices/microservice-analytics/src/mcp/index.ts +0 -334
  20. package/microservices/microservice-assets/package.json +0 -28
  21. package/microservices/microservice-assets/src/cli/index.ts +0 -375
  22. package/microservices/microservice-assets/src/db/assets.ts +0 -370
  23. package/microservices/microservice-assets/src/db/database.ts +0 -91
  24. package/microservices/microservice-assets/src/db/migrations.ts +0 -51
  25. package/microservices/microservice-assets/src/index.ts +0 -32
  26. package/microservices/microservice-assets/src/mcp/index.ts +0 -346
  27. package/microservices/microservice-bookkeeping/package.json +0 -28
  28. package/microservices/microservice-bookkeeping/src/cli/index.ts +0 -386
  29. package/microservices/microservice-bookkeeping/src/db/bookkeeping.ts +0 -591
  30. package/microservices/microservice-bookkeeping/src/db/database.ts +0 -91
  31. package/microservices/microservice-bookkeeping/src/db/migrations.ts +0 -52
  32. package/microservices/microservice-bookkeeping/src/index.ts +0 -32
  33. package/microservices/microservice-bookkeeping/src/mcp/index.ts +0 -284
  34. package/microservices/microservice-calendar/package.json +0 -28
  35. package/microservices/microservice-calendar/src/cli/index.ts +0 -287
  36. package/microservices/microservice-calendar/src/db/calendar.ts +0 -328
  37. package/microservices/microservice-calendar/src/db/database.ts +0 -91
  38. package/microservices/microservice-calendar/src/db/migrations.ts +0 -47
  39. package/microservices/microservice-calendar/src/index.ts +0 -24
  40. package/microservices/microservice-calendar/src/mcp/index.ts +0 -226
  41. package/microservices/microservice-company/package.json +0 -28
  42. package/microservices/microservice-company/src/cli/index.ts +0 -1126
  43. package/microservices/microservice-company/src/db/company.ts +0 -854
  44. package/microservices/microservice-company/src/db/database.ts +0 -91
  45. package/microservices/microservice-company/src/db/migrations.ts +0 -214
  46. package/microservices/microservice-company/src/db/workflow-migrations.ts +0 -44
  47. package/microservices/microservice-company/src/index.ts +0 -60
  48. package/microservices/microservice-company/src/lib/audit.ts +0 -168
  49. package/microservices/microservice-company/src/lib/finance.ts +0 -299
  50. package/microservices/microservice-company/src/lib/settings.ts +0 -85
  51. package/microservices/microservice-company/src/lib/workflows.ts +0 -698
  52. package/microservices/microservice-company/src/mcp/index.ts +0 -991
  53. package/microservices/microservice-compliance/package.json +0 -28
  54. package/microservices/microservice-compliance/src/cli/index.ts +0 -467
  55. package/microservices/microservice-compliance/src/db/compliance.ts +0 -633
  56. package/microservices/microservice-compliance/src/db/database.ts +0 -91
  57. package/microservices/microservice-compliance/src/db/migrations.ts +0 -63
  58. package/microservices/microservice-compliance/src/index.ts +0 -46
  59. package/microservices/microservice-compliance/src/mcp/index.ts +0 -438
  60. package/microservices/microservice-contacts/package.json +0 -28
  61. package/microservices/microservice-contacts/src/cli/index.ts +0 -393
  62. package/microservices/microservice-contacts/src/db/companies.ts +0 -167
  63. package/microservices/microservice-contacts/src/db/contacts.ts +0 -249
  64. package/microservices/microservice-contacts/src/db/database.ts +0 -91
  65. package/microservices/microservice-contacts/src/db/migrations.ts +0 -71
  66. package/microservices/microservice-contacts/src/db/relationships.ts +0 -53
  67. package/microservices/microservice-contacts/src/index.ts +0 -42
  68. package/microservices/microservice-contacts/src/mcp/index.ts +0 -303
  69. package/microservices/microservice-contracts/package.json +0 -28
  70. package/microservices/microservice-contracts/src/cli/index.ts +0 -770
  71. package/microservices/microservice-contracts/src/db/contracts.ts +0 -925
  72. package/microservices/microservice-contracts/src/db/database.ts +0 -91
  73. package/microservices/microservice-contracts/src/db/migrations.ts +0 -141
  74. package/microservices/microservice-contracts/src/index.ts +0 -43
  75. package/microservices/microservice-contracts/src/mcp/index.ts +0 -617
  76. package/microservices/microservice-crm/package.json +0 -28
  77. package/microservices/microservice-crm/src/cli/index.ts +0 -396
  78. package/microservices/microservice-crm/src/db/database.ts +0 -91
  79. package/microservices/microservice-crm/src/db/migrations.ts +0 -66
  80. package/microservices/microservice-crm/src/db/pipeline.ts +0 -397
  81. package/microservices/microservice-crm/src/index.ts +0 -34
  82. package/microservices/microservice-crm/src/mcp/index.ts +0 -294
  83. package/microservices/microservice-documents/package.json +0 -28
  84. package/microservices/microservice-documents/src/cli/index.ts +0 -246
  85. package/microservices/microservice-documents/src/db/database.ts +0 -91
  86. package/microservices/microservice-documents/src/db/documents.ts +0 -316
  87. package/microservices/microservice-documents/src/db/migrations.ts +0 -49
  88. package/microservices/microservice-documents/src/index.ts +0 -24
  89. package/microservices/microservice-documents/src/mcp/index.ts +0 -202
  90. package/microservices/microservice-domains/package.json +0 -28
  91. package/microservices/microservice-domains/src/cli/index.ts +0 -1111
  92. package/microservices/microservice-domains/src/db/database.ts +0 -91
  93. package/microservices/microservice-domains/src/db/domains.ts +0 -1164
  94. package/microservices/microservice-domains/src/db/migrations.ts +0 -60
  95. package/microservices/microservice-domains/src/index.ts +0 -65
  96. package/microservices/microservice-domains/src/lib/brandsight.ts +0 -350
  97. package/microservices/microservice-domains/src/lib/godaddy.ts +0 -338
  98. package/microservices/microservice-domains/src/lib/namecheap.ts +0 -262
  99. package/microservices/microservice-domains/src/lib/registrar.ts +0 -355
  100. package/microservices/microservice-domains/src/mcp/index.ts +0 -781
  101. package/microservices/microservice-expenses/package.json +0 -28
  102. package/microservices/microservice-expenses/src/cli/index.ts +0 -267
  103. package/microservices/microservice-expenses/src/db/database.ts +0 -91
  104. package/microservices/microservice-expenses/src/db/expenses.ts +0 -345
  105. package/microservices/microservice-expenses/src/db/migrations.ts +0 -45
  106. package/microservices/microservice-expenses/src/index.ts +0 -25
  107. package/microservices/microservice-expenses/src/mcp/index.ts +0 -196
  108. package/microservices/microservice-habits/package.json +0 -28
  109. package/microservices/microservice-habits/src/cli/index.ts +0 -315
  110. package/microservices/microservice-habits/src/db/database.ts +0 -91
  111. package/microservices/microservice-habits/src/db/habits.ts +0 -451
  112. package/microservices/microservice-habits/src/db/migrations.ts +0 -46
  113. package/microservices/microservice-habits/src/index.ts +0 -31
  114. package/microservices/microservice-habits/src/mcp/index.ts +0 -313
  115. package/microservices/microservice-health/package.json +0 -28
  116. package/microservices/microservice-health/src/cli/index.ts +0 -484
  117. package/microservices/microservice-health/src/db/database.ts +0 -91
  118. package/microservices/microservice-health/src/db/health.ts +0 -708
  119. package/microservices/microservice-health/src/db/migrations.ts +0 -70
  120. package/microservices/microservice-health/src/index.ts +0 -63
  121. package/microservices/microservice-health/src/mcp/index.ts +0 -437
  122. package/microservices/microservice-hiring/package.json +0 -28
  123. package/microservices/microservice-hiring/src/cli/index.ts +0 -741
  124. package/microservices/microservice-hiring/src/db/database.ts +0 -91
  125. package/microservices/microservice-hiring/src/db/hiring.ts +0 -1085
  126. package/microservices/microservice-hiring/src/db/migrations.ts +0 -89
  127. package/microservices/microservice-hiring/src/index.ts +0 -80
  128. package/microservices/microservice-hiring/src/lib/scoring.ts +0 -206
  129. package/microservices/microservice-hiring/src/mcp/index.ts +0 -709
  130. package/microservices/microservice-inventory/package.json +0 -28
  131. package/microservices/microservice-inventory/src/cli/index.ts +0 -365
  132. package/microservices/microservice-inventory/src/db/database.ts +0 -91
  133. package/microservices/microservice-inventory/src/db/inventory.ts +0 -393
  134. package/microservices/microservice-inventory/src/db/migrations.ts +0 -54
  135. package/microservices/microservice-inventory/src/index.ts +0 -28
  136. package/microservices/microservice-inventory/src/mcp/index.ts +0 -250
  137. package/microservices/microservice-invoices/dashboard/index.html +0 -12
  138. package/microservices/microservice-invoices/dashboard/package.json +0 -29
  139. package/microservices/microservice-invoices/dashboard/tsconfig.json +0 -14
  140. package/microservices/microservice-invoices/dashboard/vite.config.ts +0 -15
  141. package/microservices/microservice-invoices/package.json +0 -31
  142. package/microservices/microservice-invoices/src/cli/index.ts +0 -308
  143. package/microservices/microservice-invoices/src/db/business.ts +0 -241
  144. package/microservices/microservice-invoices/src/db/clients.ts +0 -127
  145. package/microservices/microservice-invoices/src/db/database.ts +0 -91
  146. package/microservices/microservice-invoices/src/db/invoices.ts +0 -345
  147. package/microservices/microservice-invoices/src/db/migrations.ts +0 -184
  148. package/microservices/microservice-invoices/src/index.ts +0 -56
  149. package/microservices/microservice-invoices/src/mcp/index.ts +0 -242
  150. package/microservices/microservice-invoices/src/server/index.ts +0 -162
  151. package/microservices/microservice-leads/package.json +0 -28
  152. package/microservices/microservice-leads/src/cli/index.ts +0 -596
  153. package/microservices/microservice-leads/src/db/database.ts +0 -91
  154. package/microservices/microservice-leads/src/db/leads.ts +0 -520
  155. package/microservices/microservice-leads/src/db/lists.ts +0 -151
  156. package/microservices/microservice-leads/src/db/migrations.ts +0 -93
  157. package/microservices/microservice-leads/src/index.ts +0 -65
  158. package/microservices/microservice-leads/src/lib/enrichment.ts +0 -202
  159. package/microservices/microservice-leads/src/lib/scoring.ts +0 -134
  160. package/microservices/microservice-leads/src/mcp/index.ts +0 -533
  161. package/microservices/microservice-notes/package.json +0 -28
  162. package/microservices/microservice-notes/src/cli/index.ts +0 -63
  163. package/microservices/microservice-notes/src/db/database.ts +0 -91
  164. package/microservices/microservice-notes/src/db/migrations.ts +0 -40
  165. package/microservices/microservice-notes/src/db/notes.ts +0 -114
  166. package/microservices/microservice-notes/src/index.ts +0 -2
  167. package/microservices/microservice-notes/src/mcp/index.ts +0 -37
  168. package/microservices/microservice-notifications/package.json +0 -28
  169. package/microservices/microservice-notifications/src/cli/index.ts +0 -349
  170. package/microservices/microservice-notifications/src/db/database.ts +0 -91
  171. package/microservices/microservice-notifications/src/db/migrations.ts +0 -62
  172. package/microservices/microservice-notifications/src/db/notifications.ts +0 -509
  173. package/microservices/microservice-notifications/src/index.ts +0 -41
  174. package/microservices/microservice-notifications/src/mcp/index.ts +0 -422
  175. package/microservices/microservice-payments/package.json +0 -28
  176. package/microservices/microservice-payments/src/cli/index.ts +0 -609
  177. package/microservices/microservice-payments/src/db/database.ts +0 -91
  178. package/microservices/microservice-payments/src/db/migrations.ts +0 -81
  179. package/microservices/microservice-payments/src/db/payments.ts +0 -1204
  180. package/microservices/microservice-payments/src/index.ts +0 -51
  181. package/microservices/microservice-payments/src/mcp/index.ts +0 -683
  182. package/microservices/microservice-payroll/package.json +0 -28
  183. package/microservices/microservice-payroll/src/cli/index.ts +0 -643
  184. package/microservices/microservice-payroll/src/db/database.ts +0 -91
  185. package/microservices/microservice-payroll/src/db/migrations.ts +0 -95
  186. package/microservices/microservice-payroll/src/db/payroll.ts +0 -1377
  187. package/microservices/microservice-payroll/src/index.ts +0 -48
  188. package/microservices/microservice-payroll/src/mcp/index.ts +0 -666
  189. package/microservices/microservice-products/package.json +0 -28
  190. package/microservices/microservice-products/src/cli/index.ts +0 -416
  191. package/microservices/microservice-products/src/db/categories.ts +0 -154
  192. package/microservices/microservice-products/src/db/database.ts +0 -91
  193. package/microservices/microservice-products/src/db/migrations.ts +0 -58
  194. package/microservices/microservice-products/src/db/pricing-tiers.ts +0 -66
  195. package/microservices/microservice-products/src/db/products.ts +0 -452
  196. package/microservices/microservice-products/src/index.ts +0 -53
  197. package/microservices/microservice-products/src/mcp/index.ts +0 -453
  198. package/microservices/microservice-projects/package.json +0 -28
  199. package/microservices/microservice-projects/src/cli/index.ts +0 -480
  200. package/microservices/microservice-projects/src/db/database.ts +0 -91
  201. package/microservices/microservice-projects/src/db/migrations.ts +0 -65
  202. package/microservices/microservice-projects/src/db/projects.ts +0 -715
  203. package/microservices/microservice-projects/src/index.ts +0 -57
  204. package/microservices/microservice-projects/src/mcp/index.ts +0 -501
  205. package/microservices/microservice-proposals/package.json +0 -28
  206. package/microservices/microservice-proposals/src/cli/index.ts +0 -400
  207. package/microservices/microservice-proposals/src/db/database.ts +0 -91
  208. package/microservices/microservice-proposals/src/db/migrations.ts +0 -52
  209. package/microservices/microservice-proposals/src/db/proposals.ts +0 -532
  210. package/microservices/microservice-proposals/src/index.ts +0 -37
  211. package/microservices/microservice-proposals/src/mcp/index.ts +0 -375
  212. package/microservices/microservice-reading/package.json +0 -28
  213. package/microservices/microservice-reading/src/cli/index.ts +0 -464
  214. package/microservices/microservice-reading/src/db/database.ts +0 -91
  215. package/microservices/microservice-reading/src/db/migrations.ts +0 -59
  216. package/microservices/microservice-reading/src/db/reading.ts +0 -524
  217. package/microservices/microservice-reading/src/index.ts +0 -51
  218. package/microservices/microservice-reading/src/mcp/index.ts +0 -368
  219. package/microservices/microservice-shipping/package.json +0 -28
  220. package/microservices/microservice-shipping/src/cli/index.ts +0 -606
  221. package/microservices/microservice-shipping/src/db/database.ts +0 -91
  222. package/microservices/microservice-shipping/src/db/migrations.ts +0 -69
  223. package/microservices/microservice-shipping/src/db/shipping.ts +0 -1093
  224. package/microservices/microservice-shipping/src/index.ts +0 -53
  225. package/microservices/microservice-shipping/src/mcp/index.ts +0 -533
  226. package/microservices/microservice-social/package.json +0 -29
  227. package/microservices/microservice-social/src/cli/index.ts +0 -1583
  228. package/microservices/microservice-social/src/db/database.ts +0 -91
  229. package/microservices/microservice-social/src/db/migrations.ts +0 -160
  230. package/microservices/microservice-social/src/db/social.ts +0 -1076
  231. package/microservices/microservice-social/src/index.ts +0 -46
  232. package/microservices/microservice-social/src/lib/audience.ts +0 -353
  233. package/microservices/microservice-social/src/lib/content-ai.ts +0 -278
  234. package/microservices/microservice-social/src/lib/media.ts +0 -311
  235. package/microservices/microservice-social/src/lib/mentions.ts +0 -434
  236. package/microservices/microservice-social/src/lib/metrics-sync.ts +0 -264
  237. package/microservices/microservice-social/src/lib/publisher.ts +0 -377
  238. package/microservices/microservice-social/src/lib/scheduler.ts +0 -229
  239. package/microservices/microservice-social/src/lib/sentiment.ts +0 -256
  240. package/microservices/microservice-social/src/lib/threads.ts +0 -291
  241. package/microservices/microservice-social/src/mcp/index.ts +0 -1425
  242. package/microservices/microservice-social/src/server/index.ts +0 -441
  243. package/microservices/microservice-subscriptions/package.json +0 -28
  244. package/microservices/microservice-subscriptions/src/cli/index.ts +0 -715
  245. package/microservices/microservice-subscriptions/src/db/database.ts +0 -91
  246. package/microservices/microservice-subscriptions/src/db/migrations.ts +0 -125
  247. package/microservices/microservice-subscriptions/src/db/subscriptions.ts +0 -1256
  248. package/microservices/microservice-subscriptions/src/index.ts +0 -41
  249. package/microservices/microservice-subscriptions/src/mcp/index.ts +0 -631
  250. package/microservices/microservice-timesheets/package.json +0 -28
  251. package/microservices/microservice-timesheets/src/cli/index.ts +0 -373
  252. package/microservices/microservice-timesheets/src/db/database.ts +0 -91
  253. package/microservices/microservice-timesheets/src/db/locale.ts +0 -217
  254. package/microservices/microservice-timesheets/src/db/migrations.ts +0 -74
  255. package/microservices/microservice-timesheets/src/db/timesheets.ts +0 -447
  256. package/microservices/microservice-timesheets/src/index.ts +0 -44
  257. package/microservices/microservice-timesheets/src/mcp/index.ts +0 -269
  258. package/microservices/microservice-transcriber/package.json +0 -29
  259. package/microservices/microservice-transcriber/src/cli/index.ts +0 -1593
  260. package/microservices/microservice-transcriber/src/db/annotations.ts +0 -37
  261. package/microservices/microservice-transcriber/src/db/comments.ts +0 -166
  262. package/microservices/microservice-transcriber/src/db/database.ts +0 -91
  263. package/microservices/microservice-transcriber/src/db/migrations.ts +0 -118
  264. package/microservices/microservice-transcriber/src/db/proofread.ts +0 -119
  265. package/microservices/microservice-transcriber/src/db/transcripts.ts +0 -395
  266. package/microservices/microservice-transcriber/src/index.ts +0 -43
  267. package/microservices/microservice-transcriber/src/lib/config.ts +0 -77
  268. package/microservices/microservice-transcriber/src/lib/diff.ts +0 -91
  269. package/microservices/microservice-transcriber/src/lib/downloader.ts +0 -638
  270. package/microservices/microservice-transcriber/src/lib/feeds.ts +0 -62
  271. package/microservices/microservice-transcriber/src/lib/live.ts +0 -94
  272. package/microservices/microservice-transcriber/src/lib/notion.ts +0 -129
  273. package/microservices/microservice-transcriber/src/lib/proofread.ts +0 -296
  274. package/microservices/microservice-transcriber/src/lib/providers.ts +0 -713
  275. package/microservices/microservice-transcriber/src/lib/summarizer.ts +0 -147
  276. package/microservices/microservice-transcriber/src/lib/translator.ts +0 -75
  277. package/microservices/microservice-transcriber/src/lib/webhook.ts +0 -37
  278. package/microservices/microservice-transcriber/src/mcp/index.ts +0 -1330
  279. package/microservices/microservice-transcriber/src/server/index.ts +0 -199
  280. package/microservices/microservice-travel/package.json +0 -28
  281. package/microservices/microservice-travel/src/cli/index.ts +0 -505
  282. package/microservices/microservice-travel/src/db/database.ts +0 -91
  283. package/microservices/microservice-travel/src/db/migrations.ts +0 -77
  284. package/microservices/microservice-travel/src/db/travel.ts +0 -802
  285. package/microservices/microservice-travel/src/index.ts +0 -60
  286. package/microservices/microservice-travel/src/mcp/index.ts +0 -495
  287. package/microservices/microservice-wiki/package.json +0 -28
  288. package/microservices/microservice-wiki/src/cli/index.ts +0 -345
  289. package/microservices/microservice-wiki/src/db/database.ts +0 -91
  290. package/microservices/microservice-wiki/src/db/migrations.ts +0 -55
  291. package/microservices/microservice-wiki/src/db/wiki.ts +0 -395
  292. package/microservices/microservice-wiki/src/index.ts +0 -32
  293. package/microservices/microservice-wiki/src/mcp/index.ts +0 -344
@@ -1,94 +0,0 @@
1
- /**
2
- * Live/streaming transcription — record from microphone via ffmpeg,
3
- * chunk into segments, transcribe each as they complete.
4
- */
5
-
6
- import { existsSync, unlinkSync } from "node:fs";
7
- import { join } from "node:path";
8
- import { tmpdir } from "node:os";
9
- import type { TranscribeOptions } from "./providers.js";
10
- import { transcribeFile } from "./providers.js";
11
-
12
- export interface LiveTranscribeOptions extends TranscribeOptions {
13
- chunkDurationSec?: number; // seconds per chunk (default: 30)
14
- onChunk?: (text: string, chunkIndex: number) => void;
15
- onError?: (error: Error, chunkIndex: number) => void;
16
- }
17
-
18
- /**
19
- * Record from default audio input and transcribe in real-time.
20
- * Returns a controller to stop recording.
21
- *
22
- * Uses ffmpeg with avfoundation (macOS) or alsa/pulse (Linux).
23
- * Each chunk is saved, transcribed, then deleted.
24
- */
25
- export function startLiveTranscription(options: LiveTranscribeOptions = {}): {
26
- stop: () => Promise<{ fullText: string; chunks: string[] }>;
27
- } {
28
- const chunkDuration = options.chunkDurationSec ?? 30;
29
- const sessionId = crypto.randomUUID().slice(0, 8);
30
- const chunks: string[] = [];
31
- let chunkIndex = 0;
32
- let stopped = false;
33
- let currentProc: ReturnType<typeof Bun.spawn> | null = null;
34
- let resolveStop: ((value: { fullText: string; chunks: string[] }) => void) | null = null;
35
-
36
- const processChunk = async (chunkPath: string, idx: number) => {
37
- if (!existsSync(chunkPath)) return;
38
- try {
39
- const result = await transcribeFile(chunkPath, {
40
- provider: options.provider,
41
- language: options.language,
42
- diarize: options.diarize,
43
- });
44
- chunks.push(result.text);
45
- options.onChunk?.(result.text, idx);
46
- } catch (err) {
47
- options.onError?.(err instanceof Error ? err : new Error(String(err)), idx);
48
- } finally {
49
- try { unlinkSync(chunkPath); } catch {}
50
- }
51
- };
52
-
53
- const recordLoop = async () => {
54
- while (!stopped) {
55
- const chunkPath = join(tmpdir(), `live-${sessionId}-${chunkIndex}.wav`);
56
- const idx = chunkIndex++;
57
-
58
- // Detect platform for audio input
59
- const isLinux = process.platform === "linux";
60
- const inputArgs = isLinux
61
- ? ["-f", "pulse", "-i", "default"]
62
- : ["-f", "avfoundation", "-i", ":0"]; // macOS default mic
63
-
64
- currentProc = Bun.spawn(
65
- ["ffmpeg", "-y", ...inputArgs, "-t", String(chunkDuration), "-ac", "1", "-ar", "16000", chunkPath],
66
- { stdout: "pipe", stderr: "pipe" }
67
- );
68
-
69
- await currentProc.exited;
70
- currentProc = null;
71
-
72
- if (stopped && !existsSync(chunkPath)) break;
73
-
74
- // Transcribe the chunk (don't await — let it process while next chunk records)
75
- processChunk(chunkPath, idx);
76
- }
77
-
78
- // Wait for any pending transcriptions to settle
79
- await new Promise((r) => setTimeout(r, 500));
80
- resolveStop?.({ fullText: chunks.join(" "), chunks });
81
- };
82
-
83
- // Start recording in background
84
- recordLoop();
85
-
86
- return {
87
- stop: () => {
88
- stopped = true;
89
- // Kill current ffmpeg recording
90
- try { currentProc?.kill(); } catch {}
91
- return new Promise((resolve) => { resolveStop = resolve; });
92
- },
93
- };
94
- }
@@ -1,129 +0,0 @@
1
- /**
2
- * Notion export — pushes a transcript to a Notion page as blocks.
3
- * Uses the Notion API directly (no SDK dependency needed).
4
- * Requires NOTION_API_KEY and a target page/database ID.
5
- */
6
-
7
- import type { Transcript } from "../db/transcripts.js";
8
-
9
- const NOTION_API = "https://api.notion.com/v1";
10
- const NOTION_VERSION = "2022-06-28";
11
-
12
- function getNotionHeaders(): Record<string, string> {
13
- const key = process.env["NOTION_API_KEY"];
14
- if (!key) throw new Error("NOTION_API_KEY is not set. Create an integration at https://www.notion.so/my-integrations");
15
- return {
16
- Authorization: `Bearer ${key}`,
17
- "Notion-Version": NOTION_VERSION,
18
- "Content-Type": "application/json",
19
- };
20
- }
21
-
22
- /**
23
- * Create a new Notion page under a parent page with the transcript content.
24
- */
25
- export async function pushToNotion(
26
- transcript: Transcript,
27
- parentPageId: string
28
- ): Promise<{ pageId: string; url: string }> {
29
- const blocks = buildNotionBlocks(transcript);
30
-
31
- const res = await fetch(`${NOTION_API}/pages`, {
32
- method: "POST",
33
- headers: getNotionHeaders(),
34
- body: JSON.stringify({
35
- parent: { page_id: parentPageId },
36
- properties: {
37
- title: {
38
- title: [{ text: { content: transcript.title ?? "Transcript" } }],
39
- },
40
- },
41
- children: blocks.slice(0, 100), // Notion limit: 100 blocks per request
42
- }),
43
- });
44
-
45
- if (!res.ok) {
46
- const body = await res.text();
47
- throw new Error(`Notion API error ${res.status}: ${body}`);
48
- }
49
-
50
- const data = (await res.json()) as { id: string; url: string };
51
-
52
- // Append remaining blocks if >100
53
- if (blocks.length > 100) {
54
- for (let i = 100; i < blocks.length; i += 100) {
55
- await fetch(`${NOTION_API}/blocks/${data.id}/children`, {
56
- method: "PATCH",
57
- headers: getNotionHeaders(),
58
- body: JSON.stringify({ children: blocks.slice(i, i + 100) }),
59
- });
60
- }
61
- }
62
-
63
- return { pageId: data.id, url: data.url };
64
- }
65
-
66
- function buildNotionBlocks(t: Transcript): Array<Record<string, unknown>> {
67
- const blocks: Array<Record<string, unknown>> = [];
68
-
69
- // Metadata callout
70
- const meta = [
71
- t.provider && `Provider: ${t.provider}`,
72
- t.duration_seconds && `Duration: ${Math.floor(t.duration_seconds / 60)}m ${Math.floor(t.duration_seconds % 60)}s`,
73
- t.word_count && `Words: ${t.word_count}`,
74
- t.source_url && `Source: ${t.source_url}`,
75
- ].filter(Boolean).join(" | ");
76
-
77
- if (meta) {
78
- blocks.push({
79
- object: "block",
80
- type: "callout",
81
- callout: {
82
- icon: { emoji: "🎙️" },
83
- rich_text: [{ type: "text", text: { content: meta } }],
84
- },
85
- });
86
- }
87
-
88
- // Summary
89
- if (t.metadata?.summary) {
90
- blocks.push(heading("Summary", 2));
91
- blocks.push(paragraph(t.metadata.summary));
92
- }
93
-
94
- // Chapters or plain text
95
- if (t.metadata?.chapters && t.metadata.chapters.length > 0) {
96
- for (const ch of t.metadata.chapters) {
97
- blocks.push(heading(ch.title, 2));
98
- // Split long text into 2000-char chunks (Notion block text limit)
99
- for (const chunk of splitText(ch.text, 2000)) {
100
- blocks.push(paragraph(chunk));
101
- }
102
- }
103
- } else if (t.transcript_text) {
104
- blocks.push(heading("Transcript", 2));
105
- for (const chunk of splitText(t.transcript_text, 2000)) {
106
- blocks.push(paragraph(chunk));
107
- }
108
- }
109
-
110
- return blocks;
111
- }
112
-
113
- function heading(text: string, level: 2 | 3): Record<string, unknown> {
114
- const key = `heading_${level}`;
115
- return { object: "block", type: key, [key]: { rich_text: [{ type: "text", text: { content: text } }] } };
116
- }
117
-
118
- function paragraph(text: string): Record<string, unknown> {
119
- return { object: "block", type: "paragraph", paragraph: { rich_text: [{ type: "text", text: { content: text } }] } };
120
- }
121
-
122
- function splitText(text: string, maxLen: number): string[] {
123
- if (text.length <= maxLen) return [text];
124
- const chunks: string[] = [];
125
- for (let i = 0; i < text.length; i += maxLen) {
126
- chunks.push(text.slice(i, i + maxLen));
127
- }
128
- return chunks;
129
- }
@@ -1,296 +0,0 @@
1
- /**
2
- * AI-powered non-destructive spellcheck/proofread for transcripts.
3
- * Uses OpenAI or Anthropic to find spelling, grammar, punctuation, and clarity issues.
4
- * NEVER modifies transcript_text directly — issues are stored in proofread_issues table
5
- * and must be explicitly applied one by one.
6
- */
7
-
8
- import { getTranscript, updateTranscript } from "../db/transcripts.js";
9
- import {
10
- createProofreadIssue,
11
- listProofreadIssues,
12
- getProofreadIssue,
13
- updateIssueStatus,
14
- getProofreadStats as getDbProofreadStats,
15
- type ProofreadIssue,
16
- type IssueType,
17
- type IssueStatus,
18
- type ListProofreadIssuesOptions,
19
- type ProofreadStats,
20
- } from "../db/proofread.js";
21
- import { getDefaultSummaryProvider, type SummaryProvider } from "./summarizer.js";
22
-
23
- export type { ProofreadIssue, ProofreadStats, IssueType, IssueStatus };
24
-
25
- export interface ProofreadOptions {
26
- types?: IssueType[];
27
- confidence_threshold?: number;
28
- provider?: SummaryProvider;
29
- }
30
-
31
- interface RawProofreadIssue {
32
- issue_type: string;
33
- position_start: number;
34
- position_end: number;
35
- original_text: string;
36
- suggestion: string;
37
- confidence: number;
38
- explanation: string;
39
- }
40
-
41
- const PROOFREAD_PROMPT = (text: string, types?: IssueType[]) => {
42
- const typeFilter = types && types.length > 0
43
- ? `Only check for these issue types: ${types.join(", ")}.`
44
- : "Check for all issue types: spelling, grammar, punctuation, clarity.";
45
-
46
- return `You are a professional proofreader. Analyze the following transcript text and find all issues.
47
-
48
- ${typeFilter}
49
-
50
- For each issue found, return a JSON object with:
51
- - "issue_type": one of "spelling", "grammar", "punctuation", "clarity"
52
- - "position_start": character index where the issue starts in the original text
53
- - "position_end": character index where the issue ends in the original text
54
- - "original_text": the exact text that has the issue
55
- - "suggestion": the corrected text
56
- - "confidence": a number 0-1 indicating how confident you are this is an issue
57
- - "explanation": brief explanation of the issue
58
-
59
- Return ONLY a valid JSON array of issue objects. If no issues found, return [].
60
- Do not wrap in markdown code fences.
61
-
62
- Transcript text:
63
- ${text.slice(0, 15000)}`;
64
- };
65
-
66
- async function callOpenAI(prompt: string, maxTokens: number): Promise<string> {
67
- const apiKey = process.env["OPENAI_API_KEY"];
68
- if (!apiKey) throw new Error("OPENAI_API_KEY is not set");
69
-
70
- const res = await fetch("https://api.openai.com/v1/chat/completions", {
71
- method: "POST",
72
- headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
73
- body: JSON.stringify({
74
- model: "gpt-4o-mini",
75
- messages: [{ role: "user", content: prompt }],
76
- max_tokens: maxTokens,
77
- temperature: 0.2,
78
- }),
79
- });
80
-
81
- if (!res.ok) { const body = await res.text(); throw new Error(`OpenAI API error ${res.status}: ${body}`); }
82
- const data = (await res.json()) as { choices: Array<{ message: { content: string } }> };
83
- return data.choices[0]?.message?.content?.trim() ?? "";
84
- }
85
-
86
- async function callAnthropic(prompt: string, maxTokens: number): Promise<string> {
87
- const apiKey = process.env["ANTHROPIC_API_KEY"];
88
- if (!apiKey) throw new Error("ANTHROPIC_API_KEY is not set");
89
-
90
- const res = await fetch("https://api.anthropic.com/v1/messages", {
91
- method: "POST",
92
- headers: { "x-api-key": apiKey, "anthropic-version": "2023-06-01", "Content-Type": "application/json" },
93
- body: JSON.stringify({
94
- model: "claude-haiku-4-5-20251001",
95
- max_tokens: maxTokens,
96
- messages: [{ role: "user", content: prompt }],
97
- }),
98
- });
99
-
100
- if (!res.ok) { const body = await res.text(); throw new Error(`Anthropic API error ${res.status}: ${body}`); }
101
- const data = (await res.json()) as { content: Array<{ type: string; text: string }> };
102
- return data.content.find((b) => b.type === "text")?.text?.trim() ?? "";
103
- }
104
-
105
- function parseAIResponse(raw: string): RawProofreadIssue[] {
106
- const cleaned = raw.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
107
- try {
108
- const parsed = JSON.parse(cleaned);
109
- if (!Array.isArray(parsed)) return [];
110
- return parsed.filter(
111
- (item: unknown) =>
112
- typeof item === "object" &&
113
- item !== null &&
114
- "issue_type" in item &&
115
- "original_text" in item
116
- );
117
- } catch {
118
- return [];
119
- }
120
- }
121
-
122
- const VALID_ISSUE_TYPES: Set<string> = new Set(["spelling", "grammar", "punctuation", "clarity"]);
123
-
124
- /**
125
- * Run AI proofreading on a transcript. Stores issues in DB. Never changes transcript_text.
126
- */
127
- export async function proofreadTranscript(
128
- transcriptId: string,
129
- options: ProofreadOptions = {}
130
- ): Promise<ProofreadIssue[]> {
131
- const transcript = getTranscript(transcriptId);
132
- if (!transcript) throw new Error(`Transcript '${transcriptId}' not found.`);
133
- if (!transcript.transcript_text) throw new Error(`Transcript '${transcriptId}' has no text.`);
134
-
135
- const provider = options.provider ?? getDefaultSummaryProvider();
136
- if (!provider) throw new Error("No AI provider configured. Set OPENAI_API_KEY or ANTHROPIC_API_KEY.");
137
-
138
- const prompt = PROOFREAD_PROMPT(transcript.transcript_text, options.types);
139
- const confidenceThreshold = options.confidence_threshold ?? 0.7;
140
-
141
- let raw: string;
142
- if (provider === "openai") {
143
- raw = await callOpenAI(prompt, 3000);
144
- } else {
145
- raw = await callAnthropic(prompt, 3000);
146
- }
147
-
148
- const rawIssues = parseAIResponse(raw);
149
- const created: ProofreadIssue[] = [];
150
-
151
- for (const issue of rawIssues) {
152
- // Validate issue_type
153
- if (!VALID_ISSUE_TYPES.has(issue.issue_type)) continue;
154
-
155
- // Filter by confidence threshold
156
- const confidence = typeof issue.confidence === "number" ? issue.confidence : 0.8;
157
- if (confidence < confidenceThreshold) continue;
158
-
159
- // Filter by types if specified
160
- if (options.types && options.types.length > 0 && !options.types.includes(issue.issue_type as IssueType)) continue;
161
-
162
- const created_issue = createProofreadIssue({
163
- transcript_id: transcriptId,
164
- issue_type: issue.issue_type as IssueType,
165
- position_start: typeof issue.position_start === "number" ? issue.position_start : undefined,
166
- position_end: typeof issue.position_end === "number" ? issue.position_end : undefined,
167
- original_text: String(issue.original_text),
168
- suggestion: issue.suggestion ? String(issue.suggestion) : undefined,
169
- confidence,
170
- explanation: issue.explanation ? String(issue.explanation) : undefined,
171
- });
172
-
173
- created.push(created_issue);
174
- }
175
-
176
- return created;
177
- }
178
-
179
- /**
180
- * List proofread issues for a transcript with optional filters.
181
- */
182
- export function listIssues(
183
- transcriptId: string,
184
- filters?: ListProofreadIssuesOptions
185
- ): ProofreadIssue[] {
186
- return listProofreadIssues(transcriptId, filters);
187
- }
188
-
189
- /**
190
- * Apply a suggestion: replaces the original_text in transcript_text at the
191
- * specified position with the suggestion, and marks the issue as 'applied'.
192
- */
193
- export function applySuggestion(issueId: string): ProofreadIssue | null {
194
- const issue = getProofreadIssue(issueId);
195
- if (!issue) return null;
196
- if (issue.status !== "pending") return issue; // already handled
197
-
198
- if (!issue.suggestion) {
199
- // No suggestion to apply, just dismiss
200
- return updateIssueStatus(issueId, "dismissed");
201
- }
202
-
203
- const transcript = getTranscript(issue.transcript_id);
204
- if (!transcript || !transcript.transcript_text) return null;
205
-
206
- let newText: string;
207
-
208
- if (issue.position_start !== null && issue.position_end !== null) {
209
- // Apply at exact position if the text at that position matches
210
- const textAtPosition = transcript.transcript_text.slice(issue.position_start, issue.position_end);
211
- if (textAtPosition === issue.original_text) {
212
- newText =
213
- transcript.transcript_text.slice(0, issue.position_start) +
214
- issue.suggestion +
215
- transcript.transcript_text.slice(issue.position_end);
216
- } else {
217
- // Position mismatch (text may have shifted from prior edits), fall back to first occurrence
218
- newText = transcript.transcript_text.replace(issue.original_text, issue.suggestion);
219
- }
220
- } else {
221
- // No position info, replace first occurrence
222
- newText = transcript.transcript_text.replace(issue.original_text, issue.suggestion);
223
- }
224
-
225
- // Only update if text actually changed
226
- if (newText !== transcript.transcript_text) {
227
- updateTranscript(issue.transcript_id, { transcript_text: newText });
228
- }
229
-
230
- return updateIssueStatus(issueId, "applied");
231
- }
232
-
233
- /**
234
- * Dismiss an issue without changing the transcript text.
235
- */
236
- export function dismissIssue(issueId: string): ProofreadIssue | null {
237
- const issue = getProofreadIssue(issueId);
238
- if (!issue) return null;
239
- return updateIssueStatus(issueId, "dismissed");
240
- }
241
-
242
- /**
243
- * Get proofread statistics for a transcript.
244
- */
245
- export { getDbProofreadStats as getProofreadStats };
246
-
247
- /**
248
- * Export annotated transcript text with inline markers showing issues.
249
- * Format: [TYPE: "original" -> "suggestion"]
250
- */
251
- export function exportAnnotated(transcriptId: string): string {
252
- const transcript = getTranscript(transcriptId);
253
- if (!transcript || !transcript.transcript_text) {
254
- throw new Error(`Transcript '${transcriptId}' not found or has no text.`);
255
- }
256
-
257
- const issues = listProofreadIssues(transcriptId, { status: "pending" });
258
- if (issues.length === 0) return transcript.transcript_text;
259
-
260
- // Sort issues by position_start descending so we can safely replace from end to start
261
- // without shifting positions. Issues without positions are handled via string replacement.
262
- const positionalIssues = issues
263
- .filter((i) => i.position_start !== null && i.position_end !== null)
264
- .sort((a, b) => (b.position_start ?? 0) - (a.position_start ?? 0));
265
-
266
- const nonPositionalIssues = issues.filter((i) => i.position_start === null || i.position_end === null);
267
-
268
- let text = transcript.transcript_text;
269
-
270
- // Apply positional annotations from end to start
271
- for (const issue of positionalIssues) {
272
- const start = issue.position_start!;
273
- const end = issue.position_end!;
274
- const marker = formatMarker(issue);
275
- text = text.slice(0, start) + marker + text.slice(end);
276
- }
277
-
278
- // Apply non-positional annotations via first occurrence replacement
279
- for (const issue of nonPositionalIssues) {
280
- const marker = formatMarker(issue);
281
- const idx = text.indexOf(issue.original_text);
282
- if (idx !== -1) {
283
- text = text.slice(0, idx) + marker + text.slice(idx + issue.original_text.length);
284
- }
285
- }
286
-
287
- return text;
288
- }
289
-
290
- function formatMarker(issue: ProofreadIssue): string {
291
- const type = issue.issue_type.toUpperCase();
292
- if (issue.suggestion) {
293
- return `[${type}: "${issue.original_text}" -> "${issue.suggestion}"]`;
294
- }
295
- return `[${type}: "${issue.original_text}"]`;
296
- }