charness 3.2.0 → 3.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (313) hide show
  1. package/.env.example +3 -6
  2. package/DEVELOPMENT.md +15 -0
  3. package/README.md +111 -38
  4. package/SETUP.md +121 -16
  5. package/dist/adapters/adapterEventRouting.d.ts +2 -1
  6. package/dist/adapters/adapterEventRouting.d.ts.map +1 -1
  7. package/dist/adapters/adapterEventRouting.js +3 -0
  8. package/dist/adapters/adapterEventRouting.js.map +1 -1
  9. package/dist/adapters/adapterNames.d.ts +13 -0
  10. package/dist/adapters/adapterNames.d.ts.map +1 -1
  11. package/dist/adapters/adapterNames.js +16 -0
  12. package/dist/adapters/adapterNames.js.map +1 -1
  13. package/dist/adapters/backendUnavailableError.d.ts +11 -0
  14. package/dist/adapters/backendUnavailableError.d.ts.map +1 -0
  15. package/dist/adapters/backendUnavailableError.js +19 -0
  16. package/dist/adapters/backendUnavailableError.js.map +1 -0
  17. package/dist/adapters/claudeCliAdapter.d.ts +29 -6
  18. package/dist/adapters/claudeCliAdapter.d.ts.map +1 -1
  19. package/dist/adapters/claudeCliAdapter.js +70 -16
  20. package/dist/adapters/claudeCliAdapter.js.map +1 -1
  21. package/dist/adapters/claudeJsonStreamAdapter.d.ts +36 -3
  22. package/dist/adapters/claudeJsonStreamAdapter.d.ts.map +1 -1
  23. package/dist/adapters/claudeJsonStreamAdapter.js +93 -30
  24. package/dist/adapters/claudeJsonStreamAdapter.js.map +1 -1
  25. package/dist/adapters/createAdapter.d.ts +3 -14
  26. package/dist/adapters/createAdapter.d.ts.map +1 -1
  27. package/dist/adapters/createAdapter.js +9 -19
  28. package/dist/adapters/createAdapter.js.map +1 -1
  29. package/dist/adapters/openCodeAdapter.d.ts +140 -12
  30. package/dist/adapters/openCodeAdapter.d.ts.map +1 -1
  31. package/dist/adapters/openCodeAdapter.js +385 -119
  32. package/dist/adapters/openCodeAdapter.js.map +1 -1
  33. package/dist/apiErrorRetry.d.ts +70 -6
  34. package/dist/apiErrorRetry.d.ts.map +1 -1
  35. package/dist/apiErrorRetry.js +312 -34
  36. package/dist/apiErrorRetry.js.map +1 -1
  37. package/dist/apiRetryKick.d.ts +26 -1
  38. package/dist/apiRetryKick.d.ts.map +1 -1
  39. package/dist/apiRetryKick.js +41 -2
  40. package/dist/apiRetryKick.js.map +1 -1
  41. package/dist/bot.d.ts +2 -1
  42. package/dist/bot.d.ts.map +1 -1
  43. package/dist/bot.js +736 -184
  44. package/dist/bot.js.map +1 -1
  45. package/dist/cli/claudeProfiles.d.ts +1 -1
  46. package/dist/cli/claudeProfiles.js +1 -1
  47. package/dist/cli/hot.d.ts +7 -1
  48. package/dist/cli/hot.d.ts.map +1 -1
  49. package/dist/cli/hot.js +29 -3
  50. package/dist/cli/hot.js.map +1 -1
  51. package/dist/configDirFile.d.ts +73 -0
  52. package/dist/configDirFile.d.ts.map +1 -0
  53. package/dist/configDirFile.js +216 -0
  54. package/dist/configDirFile.js.map +1 -0
  55. package/dist/connectors/telegram/commands/autoContinueLimits.d.ts +2 -2
  56. package/dist/connectors/telegram/commands/autoContinueLimits.d.ts.map +1 -1
  57. package/dist/connectors/telegram/commands/autoContinueLimits.js +4 -4
  58. package/dist/connectors/telegram/commands/autoContinueLimits.js.map +1 -1
  59. package/dist/connectors/telegram/commands/backendSwitch.d.ts +25 -0
  60. package/dist/connectors/telegram/commands/backendSwitch.d.ts.map +1 -0
  61. package/dist/connectors/telegram/commands/backendSwitch.js +104 -0
  62. package/dist/connectors/telegram/commands/backendSwitch.js.map +1 -0
  63. package/dist/connectors/telegram/commands/callbackMessage.d.ts +12 -0
  64. package/dist/connectors/telegram/commands/callbackMessage.d.ts.map +1 -1
  65. package/dist/connectors/telegram/commands/callbackMessage.js +24 -0
  66. package/dist/connectors/telegram/commands/callbackMessage.js.map +1 -1
  67. package/dist/connectors/telegram/commands/callbackToast.d.ts +36 -0
  68. package/dist/connectors/telegram/commands/callbackToast.d.ts.map +1 -0
  69. package/dist/connectors/telegram/commands/callbackToast.js +83 -0
  70. package/dist/connectors/telegram/commands/callbackToast.js.map +1 -0
  71. package/dist/connectors/telegram/commands/claudeAccounts.d.ts +18 -0
  72. package/dist/connectors/telegram/commands/claudeAccounts.d.ts.map +1 -1
  73. package/dist/connectors/telegram/commands/claudeAccounts.js +220 -66
  74. package/dist/connectors/telegram/commands/claudeAccounts.js.map +1 -1
  75. package/dist/connectors/telegram/commands/displayModes.d.ts.map +1 -1
  76. package/dist/connectors/telegram/commands/displayModes.js +4 -2
  77. package/dist/connectors/telegram/commands/displayModes.js.map +1 -1
  78. package/dist/connectors/telegram/commands/fallbackChain.d.ts +5 -8
  79. package/dist/connectors/telegram/commands/fallbackChain.d.ts.map +1 -1
  80. package/dist/connectors/telegram/commands/fallbackChain.js +183 -193
  81. package/dist/connectors/telegram/commands/fallbackChain.js.map +1 -1
  82. package/dist/connectors/telegram/commands/limitsBoard.d.ts +40 -0
  83. package/dist/connectors/telegram/commands/limitsBoard.d.ts.map +1 -0
  84. package/dist/connectors/telegram/commands/limitsBoard.js +281 -0
  85. package/dist/connectors/telegram/commands/limitsBoard.js.map +1 -0
  86. package/dist/connectors/telegram/commands/modelPage.d.ts +130 -0
  87. package/dist/connectors/telegram/commands/modelPage.d.ts.map +1 -0
  88. package/dist/connectors/telegram/commands/modelPage.js +120 -0
  89. package/dist/connectors/telegram/commands/modelPage.js.map +1 -0
  90. package/dist/connectors/telegram/commands/modelProviders.d.ts +9 -1
  91. package/dist/connectors/telegram/commands/modelProviders.d.ts.map +1 -1
  92. package/dist/connectors/telegram/commands/modelProviders.js +203 -111
  93. package/dist/connectors/telegram/commands/modelProviders.js.map +1 -1
  94. package/dist/connectors/telegram/commands/stt.d.ts +32 -0
  95. package/dist/connectors/telegram/commands/stt.d.ts.map +1 -0
  96. package/dist/connectors/telegram/commands/stt.js +460 -0
  97. package/dist/connectors/telegram/commands/stt.js.map +1 -0
  98. package/dist/effortLevels.d.ts +57 -7
  99. package/dist/effortLevels.d.ts.map +1 -1
  100. package/dist/effortLevels.js +65 -9
  101. package/dist/effortLevels.js.map +1 -1
  102. package/dist/i18n/de.d.ts.map +1 -1
  103. package/dist/i18n/de.js +160 -17
  104. package/dist/i18n/de.js.map +1 -1
  105. package/dist/i18n/en.d.ts.map +1 -1
  106. package/dist/i18n/en.js +160 -17
  107. package/dist/i18n/en.js.map +1 -1
  108. package/dist/i18n/es.d.ts.map +1 -1
  109. package/dist/i18n/es.js +160 -17
  110. package/dist/i18n/es.js.map +1 -1
  111. package/dist/i18n/fr.d.ts.map +1 -1
  112. package/dist/i18n/fr.js +160 -17
  113. package/dist/i18n/fr.js.map +1 -1
  114. package/dist/i18n/hi.d.ts.map +1 -1
  115. package/dist/i18n/hi.js +160 -17
  116. package/dist/i18n/hi.js.map +1 -1
  117. package/dist/i18n/ja.d.ts.map +1 -1
  118. package/dist/i18n/ja.js +160 -17
  119. package/dist/i18n/ja.js.map +1 -1
  120. package/dist/i18n/ka.d.ts.map +1 -1
  121. package/dist/i18n/ka.js +160 -17
  122. package/dist/i18n/ka.js.map +1 -1
  123. package/dist/i18n/pt.d.ts.map +1 -1
  124. package/dist/i18n/pt.js +160 -17
  125. package/dist/i18n/pt.js.map +1 -1
  126. package/dist/i18n/ru.d.ts.map +1 -1
  127. package/dist/i18n/ru.js +160 -17
  128. package/dist/i18n/ru.js.map +1 -1
  129. package/dist/i18n/uk.d.ts.map +1 -1
  130. package/dist/i18n/uk.js +160 -17
  131. package/dist/i18n/uk.js.map +1 -1
  132. package/dist/i18n/uz.d.ts.map +1 -1
  133. package/dist/i18n/uz.js +160 -17
  134. package/dist/i18n/uz.js.map +1 -1
  135. package/dist/i18n/zh.d.ts.map +1 -1
  136. package/dist/i18n/zh.js +160 -17
  137. package/dist/i18n/zh.js.map +1 -1
  138. package/dist/installManager.d.ts +20 -4
  139. package/dist/installManager.d.ts.map +1 -1
  140. package/dist/installManager.js +82 -14
  141. package/dist/installManager.js.map +1 -1
  142. package/dist/instanceSettings.d.ts +52 -0
  143. package/dist/instanceSettings.d.ts.map +1 -0
  144. package/dist/instanceSettings.js +136 -0
  145. package/dist/instanceSettings.js.map +1 -0
  146. package/dist/pinnedStatus.d.ts +7 -1
  147. package/dist/pinnedStatus.d.ts.map +1 -1
  148. package/dist/pinnedStatus.js +1 -1
  149. package/dist/pinnedStatus.js.map +1 -1
  150. package/dist/requests/requestLedger.d.ts +8 -0
  151. package/dist/requests/requestLedger.d.ts.map +1 -1
  152. package/dist/requests/requestLedger.js +19 -1
  153. package/dist/requests/requestLedger.js.map +1 -1
  154. package/dist/scheduler/mcpSurface.js +4 -4
  155. package/dist/scheduler/mcpSurface.js.map +1 -1
  156. package/dist/shutdown.d.ts +14 -0
  157. package/dist/shutdown.d.ts.map +1 -1
  158. package/dist/shutdown.js +16 -0
  159. package/dist/shutdown.js.map +1 -1
  160. package/dist/state.d.ts +54 -2
  161. package/dist/state.d.ts.map +1 -1
  162. package/dist/state.js +62 -1
  163. package/dist/state.js.map +1 -1
  164. package/dist/stt/sttAutoInstall.d.ts +39 -0
  165. package/dist/stt/sttAutoInstall.d.ts.map +1 -0
  166. package/dist/stt/sttAutoInstall.js +158 -0
  167. package/dist/stt/sttAutoInstall.js.map +1 -0
  168. package/dist/stt/sttChildEnv.d.ts +11 -0
  169. package/dist/stt/sttChildEnv.d.ts.map +1 -0
  170. package/dist/stt/sttChildEnv.js +30 -0
  171. package/dist/stt/sttChildEnv.js.map +1 -0
  172. package/dist/stt/sttConfigEdit.d.ts +71 -0
  173. package/dist/stt/sttConfigEdit.d.ts.map +1 -0
  174. package/dist/stt/sttConfigEdit.js +144 -0
  175. package/dist/stt/sttConfigEdit.js.map +1 -0
  176. package/dist/stt/sttInstall.d.ts +147 -0
  177. package/dist/stt/sttInstall.d.ts.map +1 -0
  178. package/dist/stt/sttInstall.js +491 -0
  179. package/dist/stt/sttInstall.js.map +1 -0
  180. package/dist/stt/sttInstallEntry.d.ts +2 -0
  181. package/dist/stt/sttInstallEntry.d.ts.map +1 -0
  182. package/dist/stt/sttInstallEntry.js +31 -0
  183. package/dist/stt/sttInstallEntry.js.map +1 -0
  184. package/dist/stt/sttInstallReporter.d.ts +45 -0
  185. package/dist/stt/sttInstallReporter.d.ts.map +1 -0
  186. package/dist/stt/sttInstallReporter.js +57 -0
  187. package/dist/stt/sttInstallReporter.js.map +1 -0
  188. package/dist/stt/sttRuntime.d.ts +35 -0
  189. package/dist/stt/sttRuntime.d.ts.map +1 -0
  190. package/dist/stt/sttRuntime.js +73 -0
  191. package/dist/stt/sttRuntime.js.map +1 -0
  192. package/dist/stt/sttScreenPlan.d.ts +193 -0
  193. package/dist/stt/sttScreenPlan.d.ts.map +1 -0
  194. package/dist/stt/sttScreenPlan.js +541 -0
  195. package/dist/stt/sttScreenPlan.js.map +1 -0
  196. package/dist/stt/sttSettings.d.ts +201 -0
  197. package/dist/stt/sttSettings.d.ts.map +1 -0
  198. package/dist/stt/sttSettings.js +387 -0
  199. package/dist/stt/sttSettings.js.map +1 -0
  200. package/dist/stt/sttSidecarOwner.d.ts +115 -0
  201. package/dist/stt/sttSidecarOwner.d.ts.map +1 -0
  202. package/dist/stt/sttSidecarOwner.js +475 -0
  203. package/dist/stt/sttSidecarOwner.js.map +1 -0
  204. package/dist/stt/transcribeChain.d.ts +36 -0
  205. package/dist/stt/transcribeChain.d.ts.map +1 -0
  206. package/dist/stt/transcribeChain.js +42 -0
  207. package/dist/stt/transcribeChain.js.map +1 -0
  208. package/dist/types.d.ts +77 -4
  209. package/dist/types.d.ts.map +1 -1
  210. package/dist/utils/adapterSwitchSessionIds.d.ts +32 -0
  211. package/dist/utils/adapterSwitchSessionIds.d.ts.map +1 -0
  212. package/dist/utils/adapterSwitchSessionIds.js +44 -0
  213. package/dist/utils/adapterSwitchSessionIds.js.map +1 -0
  214. package/dist/utils/backendSwitchPlan.d.ts +63 -0
  215. package/dist/utils/backendSwitchPlan.d.ts.map +1 -0
  216. package/dist/utils/backendSwitchPlan.js +73 -0
  217. package/dist/utils/backendSwitchPlan.js.map +1 -0
  218. package/dist/utils/claudeAccountPickerPlan.d.ts +12 -1
  219. package/dist/utils/claudeAccountPickerPlan.d.ts.map +1 -1
  220. package/dist/utils/claudeAccountPickerPlan.js +20 -1
  221. package/dist/utils/claudeAccountPickerPlan.js.map +1 -1
  222. package/dist/utils/claudeTranscriptContent.d.ts +24 -0
  223. package/dist/utils/claudeTranscriptContent.d.ts.map +1 -0
  224. package/dist/utils/claudeTranscriptContent.js +107 -0
  225. package/dist/utils/claudeTranscriptContent.js.map +1 -0
  226. package/dist/utils/claudeUsage.d.ts +47 -8
  227. package/dist/utils/claudeUsage.d.ts.map +1 -1
  228. package/dist/utils/claudeUsage.js +76 -14
  229. package/dist/utils/claudeUsage.js.map +1 -1
  230. package/dist/utils/claudeUsageRefresher.d.ts +8 -1
  231. package/dist/utils/claudeUsageRefresher.d.ts.map +1 -1
  232. package/dist/utils/claudeUsageRefresher.js +9 -4
  233. package/dist/utils/claudeUsageRefresher.js.map +1 -1
  234. package/dist/utils/effortPickerPlan.d.ts +54 -0
  235. package/dist/utils/effortPickerPlan.d.ts.map +1 -0
  236. package/dist/utils/effortPickerPlan.js +56 -0
  237. package/dist/utils/effortPickerPlan.js.map +1 -0
  238. package/dist/utils/ensureSessionPlan.d.ts +20 -4
  239. package/dist/utils/ensureSessionPlan.d.ts.map +1 -1
  240. package/dist/utils/ensureSessionPlan.js +17 -4
  241. package/dist/utils/ensureSessionPlan.js.map +1 -1
  242. package/dist/utils/fallbackBridge.d.ts +6 -2
  243. package/dist/utils/fallbackBridge.d.ts.map +1 -1
  244. package/dist/utils/fallbackBridge.js +10 -3
  245. package/dist/utils/fallbackBridge.js.map +1 -1
  246. package/dist/utils/fallbackChain.d.ts +36 -0
  247. package/dist/utils/fallbackChain.d.ts.map +1 -1
  248. package/dist/utils/fallbackChain.js +65 -1
  249. package/dist/utils/fallbackChain.js.map +1 -1
  250. package/dist/utils/fallbackSwitchNotice.d.ts +41 -0
  251. package/dist/utils/fallbackSwitchNotice.d.ts.map +1 -0
  252. package/dist/utils/fallbackSwitchNotice.js +75 -0
  253. package/dist/utils/fallbackSwitchNotice.js.map +1 -0
  254. package/dist/utils/fileSendService.d.ts +33 -10
  255. package/dist/utils/fileSendService.d.ts.map +1 -1
  256. package/dist/utils/fileSendService.js +78 -27
  257. package/dist/utils/fileSendService.js.map +1 -1
  258. package/dist/utils/jsonStreamHost.d.ts +39 -0
  259. package/dist/utils/jsonStreamHost.d.ts.map +1 -1
  260. package/dist/utils/jsonStreamHost.js +60 -1
  261. package/dist/utils/jsonStreamHost.js.map +1 -1
  262. package/dist/utils/limitEpisodeRecovery.d.ts +16 -2
  263. package/dist/utils/limitEpisodeRecovery.d.ts.map +1 -1
  264. package/dist/utils/limitEpisodeRecovery.js +44 -3
  265. package/dist/utils/limitEpisodeRecovery.js.map +1 -1
  266. package/dist/utils/limitSettings.d.ts +25 -0
  267. package/dist/utils/limitSettings.d.ts.map +1 -0
  268. package/dist/utils/limitSettings.js +31 -0
  269. package/dist/utils/limitSettings.js.map +1 -0
  270. package/dist/utils/limitsBoardPlan.d.ts +52 -0
  271. package/dist/utils/limitsBoardPlan.d.ts.map +1 -0
  272. package/dist/utils/limitsBoardPlan.js +93 -0
  273. package/dist/utils/limitsBoardPlan.js.map +1 -0
  274. package/dist/utils/openCodeUsage.d.ts +93 -0
  275. package/dist/utils/openCodeUsage.d.ts.map +1 -0
  276. package/dist/utils/openCodeUsage.js +248 -0
  277. package/dist/utils/openCodeUsage.js.map +1 -0
  278. package/dist/utils/operatorSwitchPlan.d.ts +61 -0
  279. package/dist/utils/operatorSwitchPlan.d.ts.map +1 -0
  280. package/dist/utils/operatorSwitchPlan.js +32 -0
  281. package/dist/utils/operatorSwitchPlan.js.map +1 -0
  282. package/dist/utils/promptDelivery.d.ts +40 -0
  283. package/dist/utils/promptDelivery.d.ts.map +1 -1
  284. package/dist/utils/promptDelivery.js +31 -0
  285. package/dist/utils/promptDelivery.js.map +1 -1
  286. package/dist/utils/recvPreviewRedaction.d.ts +14 -4
  287. package/dist/utils/recvPreviewRedaction.d.ts.map +1 -1
  288. package/dist/utils/recvPreviewRedaction.js +19 -7
  289. package/dist/utils/recvPreviewRedaction.js.map +1 -1
  290. package/dist/utils/startupReadiness.d.ts +3 -3
  291. package/dist/utils/startupReadiness.d.ts.map +1 -1
  292. package/dist/utils/startupReadiness.js +2 -2
  293. package/dist/utils/startupReadiness.js.map +1 -1
  294. package/dist/utils/threadStatusReport.d.ts +3 -1
  295. package/dist/utils/threadStatusReport.d.ts.map +1 -1
  296. package/dist/utils/threadStatusReport.js +4 -3
  297. package/dist/utils/threadStatusReport.js.map +1 -1
  298. package/dist/utils/timezone.d.ts +23 -0
  299. package/dist/utils/timezone.d.ts.map +1 -1
  300. package/dist/utils/timezone.js +38 -0
  301. package/dist/utils/timezone.js.map +1 -1
  302. package/dist/utils/transcribeAudio.d.ts +25 -12
  303. package/dist/utils/transcribeAudio.d.ts.map +1 -1
  304. package/dist/utils/transcribeAudio.js +39 -21
  305. package/dist/utils/transcribeAudio.js.map +1 -1
  306. package/dist/utils/usageRefreshBudget.d.ts +9 -0
  307. package/dist/utils/usageRefreshBudget.d.ts.map +1 -0
  308. package/dist/utils/usageRefreshBudget.js +27 -0
  309. package/dist/utils/usageRefreshBudget.js.map +1 -0
  310. package/examples/.env.example +7 -3
  311. package/examples/docker-compose.yml +9 -7
  312. package/package.json +5 -4
  313. package/stt/gigaam_sidecar.py +800 -0
@@ -0,0 +1,115 @@
1
+ import { type ExternalProcessIdentity } from '../installManager';
2
+ import { type SttPaths } from './sttInstall';
3
+ import { type SttConfigFile, type SttGigaamSettings } from './sttSettings';
4
+ import type { TranscriptionEndpoint } from '../utils/transcribeAudio';
5
+ /**
6
+ * @description The lifecycle of the local engine's process (`stt/gigaam_sidecar.py`), owned by the bot and
7
+ * started ON DEMAND: a voice whose chain reaches the local engine calls {@link SttSidecarOwner.ensure}, which
8
+ * adopts the recorded live process or spawns a new one and waits until it is ready. Nothing starts at boot.
9
+ *
10
+ * - **Hosted outside the bot's process tree** (`startExternallyParentedProcess`, the OpenCode generations'
11
+ * host), so a hot reload never kills it and the next worker adopts it from the record.
12
+ * - **Dies with its owner**: the sidecar polls its owner (`--owner-pid` + start token), so even a SIGKILLed bot
13
+ * or supervisor leaves none behind within ~2 s. The owner is the `charness hot` supervisor in hot mode (it
14
+ * exports {@link sttOwnerPidEnvName} + {@link sttOwnerStartTokenEnvName} before it starts nodemon) or the bot
15
+ * process itself in plain mode. Without a context the engine is unavailable.
16
+ * - **No watchdog, no restart backoff.** A crash, a refusal or a timeout makes the CURRENT voice fall back to
17
+ * the next engine; the NEXT voice's ensure finds the dead process and spawns a new one. Only a spawn-storm
18
+ * guard exists: three spawn failures within ten minutes mark the engine unhealthy for five.
19
+ * - Every signal is guarded by the recorded process start token.
20
+ */
21
+ /** Exported by the hot supervisor to its worker: the supervisor's pid and `/proc` start token. */
22
+ export declare const sttOwnerPidEnvName = "CHARNESS_STT_OWNER_PID";
23
+ export declare const sttOwnerStartTokenEnvName = "CHARNESS_STT_OWNER_START_TOKEN";
24
+ /** The env variable the sidecar reads its bearer token from (never an argument: `ps` shows arguments). */
25
+ export declare const sttSidecarTokenEnvName = "CHARNESS_STT_SIDECAR_TOKEN";
26
+ /** @name SttOwnerContext @description The long-lived process the sidecar dies with. */
27
+ export interface SttOwnerContext {
28
+ pid: number;
29
+ startToken: string;
30
+ }
31
+ /**
32
+ * @description The owner context of THIS bot process. A hot worker takes its supervisor's from the env the
33
+ * supervisor exported (none, or malformed → `null`: an older supervisor that cannot own a sidecar); a plain bot
34
+ * is its own owner.
35
+ */
36
+ export declare function resolveSttOwnerContext(env?: NodeJS.ProcessEnv, ownPid?: number, readStartToken?: (pid: number) => string | null): SttOwnerContext | null;
37
+ /** @name SttSidecarEndpoint @description Where a running sidecar listens and the token it wants. */
38
+ export interface SttSidecarEndpoint {
39
+ port: number;
40
+ token: string;
41
+ }
42
+ /** What `GET /health` of the sidecar answers (the fields the bot reads). */
43
+ export interface SttSidecarHealth {
44
+ status: string;
45
+ busyRequests: number;
46
+ }
47
+ /** @name SttSidecarStatus @description What `/stt` shows about the local engine's process. */
48
+ export type SttSidecarStatus = {
49
+ state: 'notRunning';
50
+ }
51
+ /** `busyRequests` absent: the process lives but did not answer /health in time — it is busy with a long voice. */
52
+ | {
53
+ state: 'running';
54
+ busyRequests?: number;
55
+ } | {
56
+ state: 'unhealthy';
57
+ unhealthyUntil: number;
58
+ };
59
+ export interface SttSidecarOwnerDeps {
60
+ getDataDir: () => string;
61
+ getOwnerContext: () => SttOwnerContext | null;
62
+ /** What to run: the venv interpreter with the script, or (tests) any program that follows the same contract. */
63
+ getLaunch: (paths: SttPaths) => {
64
+ command: string;
65
+ args: string[];
66
+ };
67
+ getBaseEnv: () => NodeJS.ProcessEnv;
68
+ startProcess: (command: string, args: string[], env: NodeJS.ProcessEnv) => Promise<ExternalProcessIdentity>;
69
+ checkIsIdentityCurrent: (identity: ExternalProcessIdentity) => boolean;
70
+ signalProcess: (identity: ExternalProcessIdentity, signal: NodeJS.Signals) => boolean;
71
+ fetchHealth: (port: number, token: string, timeoutMs: number) => Promise<SttSidecarHealth | null>;
72
+ nowMs: () => number;
73
+ sleep: (ms: number) => Promise<void>;
74
+ /** How long a spawn may take to become ready; tests shorten it. */
75
+ readyTimeoutMs: number;
76
+ /** The two /health waits when adopting a live process (first, then the patient retry); tests shorten them. */
77
+ adoptHealthTimeoutsMs: readonly [number, number];
78
+ log: (line: string) => void;
79
+ }
80
+ /** @description The production dependencies over the real process host. */
81
+ export declare function createDefaultSttSidecarOwnerDeps(getDataDir: () => string): SttSidecarOwnerDeps;
82
+ /** @description `GET /health` with the token; `null` for anything but a clean 200 `ok` within the timeout. */
83
+ export declare function fetchSttSidecarHealth(port: number, token: string, timeoutMs: number): Promise<SttSidecarHealth | null>;
84
+ /** @description The sidecar's endpoint as the chain's HTTP client wants it. */
85
+ export declare function getSttSidecarTranscriptionEndpoint(endpoint: SttSidecarEndpoint): TranscriptionEndpoint;
86
+ /** @description The identity of a process plus the config it was started with — what adoption compares. */
87
+ export declare function getSttSidecarConfigHash(settings: SttGigaamSettings): string;
88
+ /**
89
+ * @description Does moving from `previous` to `next` invalidate a running sidecar? The local engine was
90
+ * disabled or removed, or a knob the process was started with changed (the config hash would catch these at
91
+ * the next ensure; stopping now returns the memory at once).
92
+ */
93
+ export declare function checkIsSidecarRestartNeeded(previous: SttConfigFile, next: SttConfigFile): boolean;
94
+ export interface SttSidecarOwner {
95
+ /** Adopt the recorded live process or start one; resolves when it is ready. Concurrent calls share ONE attempt. */
96
+ ensure: (settings: SttGigaamSettings) => Promise<SttSidecarEndpoint>;
97
+ /** Stop the recorded process (guarded, bounded at ~3 s) and drop the record. Idempotent. */
98
+ stop: () => Promise<void>;
99
+ getStatus: () => Promise<SttSidecarStatus>;
100
+ /** The spawn-storm guard has marked the engine unhealthy (sync: it feeds the per-voice chain resolve). */
101
+ checkIsUnhealthy: () => boolean;
102
+ resetSpawnGuard: () => void;
103
+ /** After a settings save: stop a running process the change invalidates. Never spawns. */
104
+ applySettingsChange: (previous: SttConfigFile, next: SttConfigFile) => Promise<void>;
105
+ /** At boot: drop a dead process's record, stop one whose owner is not the current one, leave a matching live one. */
106
+ cleanupAtBoot: () => Promise<void>;
107
+ }
108
+ /** @description The local engine's lifecycle over its injected dependencies. */
109
+ export declare function createSttSidecarOwner(deps: SttSidecarOwnerDeps): SttSidecarOwner;
110
+ /**
111
+ * @description Stop whatever sidecar the record names — for the hot supervisor's own shutdown, which holds no
112
+ * owner object. Guarded and bounded at ~3 s like {@link SttSidecarOwner.stop}.
113
+ */
114
+ export declare function stopRecordedSttSidecar(deps: SttSidecarOwnerDeps): Promise<void>;
115
+ //# sourceMappingURL=sttSidecarOwner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sttSidecarOwner.d.ts","sourceRoot":"","sources":["../../src/stt/sttSidecarOwner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,475 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.sttSidecarTokenEnvName = exports.sttOwnerStartTokenEnvName = exports.sttOwnerPidEnvName = void 0;
37
+ exports.resolveSttOwnerContext = resolveSttOwnerContext;
38
+ exports.createDefaultSttSidecarOwnerDeps = createDefaultSttSidecarOwnerDeps;
39
+ exports.fetchSttSidecarHealth = fetchSttSidecarHealth;
40
+ exports.getSttSidecarTranscriptionEndpoint = getSttSidecarTranscriptionEndpoint;
41
+ exports.getSttSidecarConfigHash = getSttSidecarConfigHash;
42
+ exports.checkIsSidecarRestartNeeded = checkIsSidecarRestartNeeded;
43
+ exports.createSttSidecarOwner = createSttSidecarOwner;
44
+ exports.stopRecordedSttSidecar = stopRecordedSttSidecar;
45
+ const crypto = __importStar(require("crypto"));
46
+ const fs = __importStar(require("fs"));
47
+ const http = __importStar(require("http"));
48
+ const path = __importStar(require("path"));
49
+ const installManager_1 = require("../installManager");
50
+ const localClock_1 = require("../utils/localClock");
51
+ const sttInstall_1 = require("./sttInstall");
52
+ const sttChildEnv_1 = require("./sttChildEnv");
53
+ const sttSettings_1 = require("./sttSettings");
54
+ /**
55
+ * @description The lifecycle of the local engine's process (`stt/gigaam_sidecar.py`), owned by the bot and
56
+ * started ON DEMAND: a voice whose chain reaches the local engine calls {@link SttSidecarOwner.ensure}, which
57
+ * adopts the recorded live process or spawns a new one and waits until it is ready. Nothing starts at boot.
58
+ *
59
+ * - **Hosted outside the bot's process tree** (`startExternallyParentedProcess`, the OpenCode generations'
60
+ * host), so a hot reload never kills it and the next worker adopts it from the record.
61
+ * - **Dies with its owner**: the sidecar polls its owner (`--owner-pid` + start token), so even a SIGKILLed bot
62
+ * or supervisor leaves none behind within ~2 s. The owner is the `charness hot` supervisor in hot mode (it
63
+ * exports {@link sttOwnerPidEnvName} + {@link sttOwnerStartTokenEnvName} before it starts nodemon) or the bot
64
+ * process itself in plain mode. Without a context the engine is unavailable.
65
+ * - **No watchdog, no restart backoff.** A crash, a refusal or a timeout makes the CURRENT voice fall back to
66
+ * the next engine; the NEXT voice's ensure finds the dead process and spawns a new one. Only a spawn-storm
67
+ * guard exists: three spawn failures within ten minutes mark the engine unhealthy for five.
68
+ * - Every signal is guarded by the recorded process start token.
69
+ */
70
+ /** Exported by the hot supervisor to its worker: the supervisor's pid and `/proc` start token. */
71
+ exports.sttOwnerPidEnvName = 'CHARNESS_STT_OWNER_PID';
72
+ exports.sttOwnerStartTokenEnvName = 'CHARNESS_STT_OWNER_START_TOKEN';
73
+ /** The env variable the sidecar reads its bearer token from (never an argument: `ps` shows arguments). */
74
+ exports.sttSidecarTokenEnvName = 'CHARNESS_STT_SIDECAR_TOKEN';
75
+ const recordFileName = 'sidecar.json';
76
+ const logFileName = 'sidecar.log';
77
+ const readyFilePrefix = 'ready-';
78
+ const readyFileSuffix = '.json';
79
+ const readyTimeoutMs = 15_000;
80
+ const readyPollMs = 100;
81
+ /** The record's port while the sidecar still loads its model: the process is there, nothing listens yet. */
82
+ const startingRecordPort = 0;
83
+ const adoptHealthTimeoutMs = 1_000;
84
+ /** A sidecar recognising a long voice with every core busy answers /health late: ask once more, patiently. */
85
+ const adoptHealthRetryTimeoutMs = 5_000;
86
+ /** A live, matching sidecar that answered no /health this many ensures in a row is wedged and replaced. */
87
+ const unansweredAdoptionLimit = 3;
88
+ const statusHealthTimeoutMs = 1_000;
89
+ const stopBudgetMs = 3_000;
90
+ const killGraceMs = 500;
91
+ const exitPollMs = 50;
92
+ const spawnFailureLimit = 3;
93
+ const spawnFailureWindowMs = 10 * 60 * 1000;
94
+ const unhealthyDurationMs = 5 * 60 * 1000;
95
+ const tokenBytes = 32;
96
+ const readyFileRandomBytes = 6;
97
+ const gigaamModelName = 'gigaam';
98
+ const transcriptionsPath = '/v1/audio/transcriptions';
99
+ const loopbackHost = '127.0.0.1';
100
+ const configHashLength = 16;
101
+ /**
102
+ * @description The owner context of THIS bot process. A hot worker takes its supervisor's from the env the
103
+ * supervisor exported (none, or malformed → `null`: an older supervisor that cannot own a sidecar); a plain bot
104
+ * is its own owner.
105
+ */
106
+ function resolveSttOwnerContext(env = process.env, ownPid = process.pid, readStartToken = (pid) => (0, installManager_1.getProcessIdentity)(pid)?.startToken ?? null) {
107
+ if ((0, installManager_1.checkIsOpenCodeExternalHost)(env)) {
108
+ const pid = Number(env[exports.sttOwnerPidEnvName]);
109
+ const startToken = env[exports.sttOwnerStartTokenEnvName];
110
+ return Number.isInteger(pid) && pid > 0 && startToken ? { pid, startToken } : null;
111
+ }
112
+ const startToken = readStartToken(ownPid);
113
+ return startToken ? { pid: ownPid, startToken } : null;
114
+ }
115
+ /** @description The production dependencies over the real process host. */
116
+ function createDefaultSttSidecarOwnerDeps(getDataDir) {
117
+ return {
118
+ getDataDir,
119
+ getOwnerContext: () => resolveSttOwnerContext(),
120
+ getLaunch: (paths) => ({ command: paths.venvPython, args: ['-I', (0, sttInstall_1.getSidecarScriptPath)()] }),
121
+ getBaseEnv: () => (0, sttChildEnv_1.getSttChildEnv)(),
122
+ startProcess: (command, args, env) => (0, installManager_1.startExternallyParentedProcess)(command, args, env),
123
+ checkIsIdentityCurrent: installManager_1.checkIsProcessIdentityCurrent,
124
+ signalProcess: installManager_1.signalExternallyHostedProcess,
125
+ fetchHealth: fetchSttSidecarHealth,
126
+ nowMs: Date.now,
127
+ sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
128
+ readyTimeoutMs,
129
+ adoptHealthTimeoutsMs: [adoptHealthTimeoutMs, adoptHealthRetryTimeoutMs],
130
+ log: (line) => console.log(line),
131
+ };
132
+ }
133
+ /** @description `GET /health` with the token; `null` for anything but a clean 200 `ok` within the timeout. */
134
+ function fetchSttSidecarHealth(port, token, timeoutMs) {
135
+ return new Promise((resolve) => {
136
+ const request = http.get({ host: loopbackHost, port, path: '/health', headers: { Authorization: `Bearer ${token}` }, timeout: timeoutMs }, (response) => {
137
+ let body = '';
138
+ response.setEncoding('utf8');
139
+ response.on('data', (chunk) => { body += chunk; });
140
+ response.on('error', () => resolve(null));
141
+ response.on('end', () => {
142
+ if (response.statusCode !== 200)
143
+ return resolve(null);
144
+ try {
145
+ const health = JSON.parse(body);
146
+ resolve(health.status === 'ok' ? { status: health.status, busyRequests: health.busyRequests ?? 0 } : null);
147
+ }
148
+ catch {
149
+ resolve(null);
150
+ }
151
+ });
152
+ });
153
+ request.on('timeout', () => request.destroy());
154
+ request.on('error', () => resolve(null));
155
+ });
156
+ }
157
+ /** @description The sidecar's endpoint as the chain's HTTP client wants it. */
158
+ function getSttSidecarTranscriptionEndpoint(endpoint) {
159
+ return {
160
+ url: `http://${loopbackHost}:${endpoint.port}${transcriptionsPath}`,
161
+ apiKey: endpoint.token,
162
+ model: gigaamModelName,
163
+ };
164
+ }
165
+ /** @description The identity of a process plus the config it was started with — what adoption compares. */
166
+ function getSttSidecarConfigHash(settings) {
167
+ const canonical = JSON.stringify({
168
+ idleMinutes: settings.idleMinutes,
169
+ workers: settings.workers,
170
+ threads: settings.threads ?? sttSettings_1.defaultGigaamThreads,
171
+ scriptVersion: sttInstall_1.gigaamScriptVersion,
172
+ });
173
+ return crypto.createHash('sha256').update(canonical).digest('hex').slice(0, configHashLength);
174
+ }
175
+ function hasEnabledLocalEngine(config) {
176
+ return config.engines.some((engine) => engine.kind === 'gigaam' && !engine.isDisabled);
177
+ }
178
+ /**
179
+ * @description Does moving from `previous` to `next` invalidate a running sidecar? The local engine was
180
+ * disabled or removed, or a knob the process was started with changed (the config hash would catch these at
181
+ * the next ensure; stopping now returns the memory at once).
182
+ */
183
+ function checkIsSidecarRestartNeeded(previous, next) {
184
+ if (hasEnabledLocalEngine(previous) && !hasEnabledLocalEngine(next))
185
+ return true;
186
+ return getSttSidecarConfigHash(previous.gigaam) !== getSttSidecarConfigHash(next.gigaam);
187
+ }
188
+ function isSttSidecarRecord(value) {
189
+ return (Number.isInteger(value.pid) &&
190
+ typeof value.startToken === 'string' &&
191
+ Number.isInteger(value.port) &&
192
+ typeof value.token === 'string' &&
193
+ typeof value.configHash === 'string' &&
194
+ Number.isInteger(value.ownerPid) &&
195
+ typeof value.ownerStartToken === 'string' &&
196
+ typeof value.startedAt === 'string');
197
+ }
198
+ /** @description The local engine's lifecycle over its injected dependencies. */
199
+ function createSttSidecarOwner(deps) {
200
+ let inFlightEnsure = null;
201
+ let spawnFailureTimes = [];
202
+ let unhealthyUntilMs = 0;
203
+ let unansweredAdoptions = 0;
204
+ const getPaths = () => (0, sttInstall_1.getSttPaths)(deps.getDataDir());
205
+ const getRecordPath = () => path.join(getPaths().root, recordFileName);
206
+ function readRecord() {
207
+ try {
208
+ const parsed = JSON.parse(fs.readFileSync(getRecordPath(), 'utf8'));
209
+ return isSttSidecarRecord(parsed) ? parsed : null;
210
+ }
211
+ catch {
212
+ return null;
213
+ }
214
+ }
215
+ function removeRecord() {
216
+ fs.rmSync(getRecordPath(), { force: true });
217
+ }
218
+ async function waitUntilGone(identity, budgetMs) {
219
+ const deadlineMs = deps.nowMs() + budgetMs;
220
+ while (deps.checkIsIdentityCurrent(identity)) {
221
+ if (deps.nowMs() >= deadlineMs)
222
+ return false;
223
+ await deps.sleep(exitPollMs);
224
+ }
225
+ return true;
226
+ }
227
+ /** SIGTERM, wait up to `graceMs`, then SIGKILL — both guarded by the start token. */
228
+ async function terminate(identity, graceMs) {
229
+ if (!deps.checkIsIdentityCurrent(identity))
230
+ return;
231
+ deps.signalProcess(identity, 'SIGTERM');
232
+ if (await waitUntilGone(identity, graceMs))
233
+ return;
234
+ deps.signalProcess(identity, 'SIGKILL');
235
+ await waitUntilGone(identity, killGraceMs);
236
+ }
237
+ function noteSpawnFailure() {
238
+ const nowMs = deps.nowMs();
239
+ spawnFailureTimes = [...spawnFailureTimes.filter((failedAt) => nowMs - failedAt < spawnFailureWindowMs), nowMs];
240
+ if (spawnFailureTimes.length < spawnFailureLimit)
241
+ return;
242
+ unhealthyUntilMs = nowMs + unhealthyDurationMs;
243
+ spawnFailureTimes = [];
244
+ deps.log(`[STT] gigaam marked unhealthy until ${(0, localClock_1.formatLocalClock)(unhealthyUntilMs)} after ${spawnFailureLimit} failed starts`);
245
+ }
246
+ function readReadyFile(readyFile) {
247
+ try {
248
+ const { pid, port } = JSON.parse(fs.readFileSync(readyFile, 'utf8'));
249
+ return typeof pid === 'number' && Number.isInteger(pid) && typeof port === 'number' && Number.isInteger(port) ? { pid, port } : null;
250
+ }
251
+ catch {
252
+ return null;
253
+ }
254
+ }
255
+ /**
256
+ * Wait for a sidecar that is still loading its model (its record has no port yet) to publish the port. `gone`: the
257
+ * process ended or the record now belongs to another start; `timeout`: alive but not listening in time (wedged).
258
+ */
259
+ async function waitForRecordedPort(starting) {
260
+ const deadlineMs = deps.nowMs() + deps.readyTimeoutMs;
261
+ for (;;) {
262
+ const current = readRecord();
263
+ if (!current || current.pid !== starting.pid || !deps.checkIsIdentityCurrent(current))
264
+ return { kind: 'gone' };
265
+ if (current.port !== startingRecordPort)
266
+ return { kind: 'listening', record: current };
267
+ if (deps.nowMs() >= deadlineMs)
268
+ return { kind: 'timeout' };
269
+ await deps.sleep(readyPollMs);
270
+ }
271
+ }
272
+ async function adoptRecorded(settings, owner) {
273
+ let record = readRecord();
274
+ if (!record) {
275
+ removeRecord();
276
+ return null;
277
+ }
278
+ const isAlive = deps.checkIsIdentityCurrent(record);
279
+ const isSameOwner = record.ownerPid === owner.pid && record.ownerStartToken === owner.startToken;
280
+ if (isAlive && isSameOwner && record.configHash === getSttSidecarConfigHash(settings)) {
281
+ if (record.port === startingRecordPort) {
282
+ // A start nobody finished waiting for (a reloaded worker's) or another voice's: wait for it, never start a second one.
283
+ deps.log(`[STT] sidecar pid ${record.pid} is still loading the model; waiting for it`);
284
+ const waited = await waitForRecordedPort(record);
285
+ if (waited.kind === 'gone') {
286
+ if (readRecord()?.pid === record.pid)
287
+ removeRecord();
288
+ return null;
289
+ }
290
+ if (waited.kind === 'listening')
291
+ record = waited.record;
292
+ }
293
+ if (record.port !== startingRecordPort) {
294
+ const endpoint = { port: record.port, token: record.token };
295
+ const [firstTimeoutMs, retryTimeoutMs] = deps.adoptHealthTimeoutsMs;
296
+ if ((await deps.fetchHealth(record.port, record.token, firstTimeoutMs)) ?? (await deps.fetchHealth(record.port, record.token, retryTimeoutMs))) {
297
+ unansweredAdoptions = 0;
298
+ return endpoint;
299
+ }
300
+ // Alive, ours, the right config, but silent: a sidecar busy with a long voice answers /health late and
301
+ // killing it would drop another topic's recognition. Use it; replace it only when it stays silent.
302
+ unansweredAdoptions++;
303
+ if (unansweredAdoptions < unansweredAdoptionLimit) {
304
+ deps.log(`[STT] sidecar pid ${record.pid} did not answer /health (${unansweredAdoptions}/${unansweredAdoptionLimit}); using it anyway`);
305
+ return endpoint;
306
+ }
307
+ deps.log(`[STT] sidecar pid ${record.pid} stayed silent ${unansweredAdoptionLimit} times in a row; replacing it`);
308
+ unansweredAdoptions = 0;
309
+ }
310
+ else {
311
+ deps.log(`[STT] sidecar pid ${record.pid} did not start listening in ${Math.round(deps.readyTimeoutMs / 1000)} s; replacing it`);
312
+ }
313
+ }
314
+ // Dead, another owner's or another config's — or wedged: it must go before a new one starts.
315
+ if (isAlive)
316
+ await terminate(record, stopBudgetMs);
317
+ removeRecord();
318
+ return null;
319
+ }
320
+ async function spawnSidecar(settings, owner) {
321
+ if (deps.nowMs() < unhealthyUntilMs) {
322
+ throw new Error(`gigaam is unhealthy until ${(0, localClock_1.formatLocalClock)(unhealthyUntilMs)}`);
323
+ }
324
+ const paths = getPaths();
325
+ fs.mkdirSync(paths.root, { recursive: true });
326
+ const token = crypto.randomBytes(tokenBytes).toString('hex');
327
+ const readyFile = path.join(paths.root, `${readyFilePrefix}${crypto.randomBytes(readyFileRandomBytes).toString('hex')}${readyFileSuffix}`);
328
+ const launch = deps.getLaunch(paths);
329
+ const args = [
330
+ ...launch.args,
331
+ '--ready-file', readyFile,
332
+ '--record-file', getRecordPath(),
333
+ '--log-file', path.join(paths.root, logFileName),
334
+ '--idle-minutes', settings.idleMinutes.toString(),
335
+ '--workers', settings.workers.toString(),
336
+ '--threads', (settings.threads ?? sttSettings_1.defaultGigaamThreads).toString(),
337
+ '--owner-pid', owner.pid.toString(),
338
+ '--owner-start-token', owner.startToken,
339
+ '--config-hash', getSttSidecarConfigHash(settings),
340
+ ];
341
+ // The token and the offline cache reach the process through its env, never its arguments.
342
+ const env = {
343
+ ...deps.getBaseEnv(),
344
+ [exports.sttSidecarTokenEnvName]: token,
345
+ HF_HOME: paths.hfHome,
346
+ HF_HUB_OFFLINE: '1',
347
+ };
348
+ const startedAtMs = deps.nowMs();
349
+ let identity;
350
+ try {
351
+ identity = await deps.startProcess(launch.command, args, env);
352
+ }
353
+ catch (error) {
354
+ noteSpawnFailure();
355
+ throw new Error(`the local engine could not be started: ${error instanceof Error ? error.message : 'unknown error'}`);
356
+ }
357
+ const fail = async (reason) => {
358
+ await terminate(identity, 0);
359
+ fs.rmSync(readyFile, { force: true });
360
+ // The sidecar claimed the record before it loaded the model: a start that failed must not leave it behind.
361
+ if (readRecord()?.pid === identity.pid)
362
+ removeRecord();
363
+ noteSpawnFailure();
364
+ throw new Error(reason);
365
+ };
366
+ for (;;) {
367
+ const ready = readReadyFile(readyFile);
368
+ if (ready && ready.pid === identity.pid) {
369
+ // The sidecar recorded itself before it wrote the ready file; the token in that record is the one it was given.
370
+ const record = readRecord();
371
+ if (!record || record.pid !== identity.pid || record.token !== token) {
372
+ return fail('the local engine did not record itself (see sidecar.log)');
373
+ }
374
+ fs.rmSync(readyFile, { force: true });
375
+ deps.log(`[STT] sidecar started pid ${identity.pid} port ${ready.port} in ${deps.nowMs() - startedAtMs}ms (workers ${settings.workers})`);
376
+ spawnFailureTimes = [];
377
+ return { port: ready.port, token };
378
+ }
379
+ if (!deps.checkIsIdentityCurrent(identity)) {
380
+ // Two starts at once (a reloaded worker asked while the first was still loading): ours found the record
381
+ // claimed and left. That is no failure — use the sidecar that holds the record.
382
+ const earlierStart = await adoptRecorded(settings, owner);
383
+ if (earlierStart) {
384
+ fs.rmSync(readyFile, { force: true });
385
+ deps.log(`[STT] sidecar pid ${identity.pid} found another start already running and left; using that one`);
386
+ return earlierStart;
387
+ }
388
+ return fail('the local engine exited before it was ready (see sidecar.log)');
389
+ }
390
+ if (deps.nowMs() - startedAtMs >= deps.readyTimeoutMs) {
391
+ return fail(`the local engine was not ready in ${Math.round(deps.readyTimeoutMs / 1000)} s`);
392
+ }
393
+ await deps.sleep(readyPollMs);
394
+ }
395
+ }
396
+ async function ensureOnce(settings) {
397
+ const owner = deps.getOwnerContext();
398
+ if (!owner)
399
+ throw new Error('the local engine has no owner process to start it with (restart the bot supervisor)');
400
+ return (await adoptRecorded(settings, owner)) ?? (await spawnSidecar(settings, owner));
401
+ }
402
+ async function stop() {
403
+ const record = readRecord();
404
+ if (record)
405
+ await terminate(record, stopBudgetMs - killGraceMs);
406
+ removeRecord();
407
+ }
408
+ return {
409
+ ensure: (settings) => {
410
+ if (!inFlightEnsure) {
411
+ inFlightEnsure = ensureOnce(settings).finally(() => { inFlightEnsure = null; });
412
+ }
413
+ return inFlightEnsure;
414
+ },
415
+ stop,
416
+ async getStatus() {
417
+ if (deps.nowMs() < unhealthyUntilMs)
418
+ return { state: 'unhealthy', unhealthyUntil: unhealthyUntilMs };
419
+ const record = readRecord();
420
+ // A record without a port is a start still loading the model: nothing to ask yet.
421
+ if (!record || record.port === startingRecordPort || !deps.checkIsIdentityCurrent(record))
422
+ return { state: 'notRunning' };
423
+ const health = await deps.fetchHealth(record.port, record.token, statusHealthTimeoutMs);
424
+ // Alive but silent is busy, not gone: it is recognising something long.
425
+ return health ? { state: 'running', busyRequests: health.busyRequests } : { state: 'running' };
426
+ },
427
+ checkIsUnhealthy: () => deps.nowMs() < unhealthyUntilMs,
428
+ resetSpawnGuard: () => {
429
+ spawnFailureTimes = [];
430
+ unhealthyUntilMs = 0;
431
+ },
432
+ async applySettingsChange(previous, next) {
433
+ if (checkIsSidecarRestartNeeded(previous, next))
434
+ await stop();
435
+ },
436
+ async cleanupAtBoot() {
437
+ const paths = getPaths();
438
+ try {
439
+ for (const name of fs.readdirSync(paths.root)) {
440
+ if (name.startsWith(readyFilePrefix) && name.endsWith(readyFileSuffix))
441
+ fs.rmSync(path.join(paths.root, name), { force: true });
442
+ }
443
+ }
444
+ catch {
445
+ return; // no stt dir: nothing was ever started
446
+ }
447
+ const record = readRecord();
448
+ if (!record) {
449
+ removeRecord(); // an unreadable record is as good as none
450
+ return;
451
+ }
452
+ if (!deps.checkIsIdentityCurrent(record)) {
453
+ removeRecord();
454
+ deps.log(`[STT] removed the record of a sidecar that is gone (pid ${record.pid})`);
455
+ return;
456
+ }
457
+ const owner = deps.getOwnerContext();
458
+ if (owner && record.ownerPid === owner.pid && record.ownerStartToken === owner.startToken) {
459
+ deps.log(`[STT] sidecar pid ${record.pid} is still running; it will be adopted by the next voice`);
460
+ return;
461
+ }
462
+ await terminate(record, stopBudgetMs - killGraceMs);
463
+ removeRecord();
464
+ deps.log(`[STT] stopped sidecar pid ${record.pid}: it belonged to another owner`);
465
+ },
466
+ };
467
+ }
468
+ /**
469
+ * @description Stop whatever sidecar the record names — for the hot supervisor's own shutdown, which holds no
470
+ * owner object. Guarded and bounded at ~3 s like {@link SttSidecarOwner.stop}.
471
+ */
472
+ function stopRecordedSttSidecar(deps) {
473
+ return createSttSidecarOwner(deps).stop();
474
+ }
475
+ //# sourceMappingURL=sttSidecarOwner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sttSidecarOwner.js","sourceRoot":"","sources":["../../src/stt/sttSidecarOwner.ts"],"names":[],"mappings":"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"}