talon-agent 1.12.0 → 1.34.0

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 (451) hide show
  1. package/README.md +111 -52
  2. package/package.json +39 -12
  3. package/prompts/README.md +112 -0
  4. package/prompts/base.md +12 -12
  5. package/prompts/discord.md +10 -47
  6. package/prompts/heartbeat.md +23 -8
  7. package/prompts/identity.md +12 -22
  8. package/prompts/native.md +23 -0
  9. package/prompts/system/contract-text-or-tools.md +8 -0
  10. package/prompts/system/contract-text-preferred.md +5 -0
  11. package/prompts/system/contract-tool-only.md +10 -0
  12. package/prompts/system/cron.md +3 -0
  13. package/prompts/system/daily-memory.md +3 -0
  14. package/prompts/system/goals.md +7 -0
  15. package/prompts/system/heartbeat-agent.md +44 -0
  16. package/prompts/system/persistent-memory.md +8 -0
  17. package/prompts/system/skills.md +9 -0
  18. package/prompts/system/triggers.md +5 -0
  19. package/prompts/system/workspace.md +9 -0
  20. package/prompts/teams.md +4 -14
  21. package/prompts/telegram.md +17 -89
  22. package/src/app.ts +278 -0
  23. package/src/backend/claude-sdk/constants.ts +22 -10
  24. package/src/backend/claude-sdk/factory.ts +79 -22
  25. package/src/backend/claude-sdk/handler.ts +431 -160
  26. package/src/backend/claude-sdk/index.ts +6 -2
  27. package/src/backend/claude-sdk/mcp-ready.ts +54 -0
  28. package/src/backend/claude-sdk/model-drift.ts +65 -0
  29. package/src/backend/claude-sdk/model-provider.ts +12 -6
  30. package/src/backend/claude-sdk/models/convert.ts +169 -0
  31. package/src/backend/claude-sdk/models/discovery.ts +203 -0
  32. package/src/backend/claude-sdk/models/index.ts +18 -0
  33. package/src/backend/claude-sdk/models/parsing.ts +264 -0
  34. package/src/backend/claude-sdk/models/static.ts +45 -0
  35. package/src/backend/claude-sdk/one-shot.ts +19 -13
  36. package/src/backend/claude-sdk/options.ts +228 -104
  37. package/src/backend/claude-sdk/state.ts +1 -1
  38. package/src/backend/claude-sdk/stream.ts +153 -45
  39. package/src/backend/claude-sdk/warm.ts +12 -5
  40. package/src/backend/codex/auth.ts +216 -40
  41. package/src/backend/codex/constants.ts +63 -22
  42. package/src/backend/codex/discovery.ts +427 -0
  43. package/src/backend/codex/factory.ts +63 -33
  44. package/src/backend/codex/handler/events.ts +239 -0
  45. package/src/backend/codex/handler/index.ts +15 -0
  46. package/src/backend/codex/handler/message.ts +669 -0
  47. package/src/backend/codex/handler/state.ts +14 -0
  48. package/src/backend/codex/handler/usage.ts +68 -0
  49. package/src/backend/codex/index.ts +2 -2
  50. package/src/backend/codex/init.ts +92 -11
  51. package/src/backend/codex/mcp-config.ts +89 -62
  52. package/src/backend/codex/models.ts +305 -54
  53. package/src/backend/codex/oauth-incompat.ts +302 -0
  54. package/src/backend/codex/one-shot.ts +91 -8
  55. package/src/backend/codex/state.ts +54 -3
  56. package/src/backend/codex/token-usage.ts +434 -0
  57. package/src/backend/kilo/factory.ts +60 -35
  58. package/src/backend/kilo/handler/index.ts +13 -0
  59. package/src/backend/kilo/handler/message.ts +317 -0
  60. package/src/backend/kilo/handler/state.ts +14 -0
  61. package/src/backend/kilo/handler/turn.ts +321 -0
  62. package/src/backend/kilo/index.ts +5 -5
  63. package/src/backend/kilo/model-provider.ts +26 -168
  64. package/src/backend/kilo/models/index.ts +52 -0
  65. package/src/backend/kilo/one-shot.ts +20 -142
  66. package/src/backend/kilo/server.ts +14 -21
  67. package/src/backend/openai-agents/builtins.ts +215 -114
  68. package/src/backend/openai-agents/constants.ts +41 -15
  69. package/src/backend/openai-agents/discovery.ts +332 -0
  70. package/src/backend/openai-agents/factory.ts +66 -28
  71. package/src/backend/openai-agents/handler/events.ts +170 -0
  72. package/src/backend/openai-agents/handler/index.ts +13 -0
  73. package/src/backend/openai-agents/handler/message.ts +527 -0
  74. package/src/backend/openai-agents/handler/state.ts +13 -0
  75. package/src/backend/openai-agents/index.ts +22 -4
  76. package/src/backend/openai-agents/init.ts +51 -88
  77. package/src/backend/openai-agents/mcp-pool.ts +252 -0
  78. package/src/backend/openai-agents/models.ts +118 -11
  79. package/src/backend/openai-agents/session.ts +277 -0
  80. package/src/backend/openai-agents/state.ts +82 -11
  81. package/src/backend/opencode/factory.ts +54 -25
  82. package/src/backend/opencode/handler/index.ts +13 -0
  83. package/src/backend/opencode/handler/message.ts +325 -0
  84. package/src/backend/opencode/handler/state.ts +14 -0
  85. package/src/backend/opencode/handler/turn.ts +304 -0
  86. package/src/backend/opencode/index.ts +2 -2
  87. package/src/backend/opencode/model-provider.ts +26 -168
  88. package/src/backend/opencode/models/index.ts +51 -0
  89. package/src/backend/opencode/one-shot.ts +20 -137
  90. package/src/backend/opencode/server.ts +12 -11
  91. package/src/backend/remote-server/client.ts +13 -6
  92. package/src/backend/remote-server/events.ts +59 -9
  93. package/src/backend/remote-server/lifecycle.ts +3 -1
  94. package/src/backend/remote-server/mcp.ts +52 -19
  95. package/src/backend/remote-server/model-catalog/catalog.ts +270 -0
  96. package/src/backend/remote-server/model-catalog/index.ts +100 -0
  97. package/src/backend/remote-server/model-catalog/presentation.ts +298 -0
  98. package/src/backend/remote-server/model-catalog/provider.ts +193 -0
  99. package/src/backend/remote-server/model-catalog/resolve.ts +225 -0
  100. package/src/backend/remote-server/model-catalog/types.ts +136 -0
  101. package/src/backend/remote-server/one-shot.ts +225 -0
  102. package/src/backend/remote-server/session-helpers.ts +3 -4
  103. package/src/backend/remote-server/state.ts +1 -1
  104. package/src/backend/shared/delivery-contract.ts +161 -0
  105. package/src/backend/shared/delivery.ts +49 -0
  106. package/src/backend/shared/flow-violation.ts +38 -7
  107. package/src/backend/shared/frontends.ts +66 -0
  108. package/src/backend/shared/handle-retry.ts +244 -0
  109. package/src/backend/shared/handler-to-events.ts +186 -0
  110. package/src/backend/shared/handler-types.ts +57 -0
  111. package/src/backend/shared/index.ts +51 -5
  112. package/src/backend/shared/metrics.ts +199 -0
  113. package/src/backend/shared/model-retry.ts +1 -1
  114. package/src/backend/shared/prompt-format.ts +69 -0
  115. package/src/backend/shared/session-name.ts +1 -1
  116. package/src/backend/shared/stream-state.ts +36 -2
  117. package/src/backend/shared/system-prompt.ts +200 -23
  118. package/src/bootstrap.ts +338 -38
  119. package/src/cli/chat.ts +49 -0
  120. package/src/cli/config-view.ts +100 -0
  121. package/src/cli/config.ts +105 -0
  122. package/src/cli/context.ts +23 -0
  123. package/src/cli/daemon.ts +95 -0
  124. package/src/cli/doctor.ts +53 -0
  125. package/src/cli/index.ts +139 -0
  126. package/src/cli/logs.ts +60 -0
  127. package/src/cli/menu.ts +104 -0
  128. package/src/cli/setup.ts +455 -0
  129. package/src/cli/status.ts +75 -0
  130. package/src/cli.ts +20 -1211
  131. package/src/core/agent-runtime/README.md +173 -0
  132. package/src/{backend/registry.ts → core/agent-runtime/backend-registry.ts} +15 -6
  133. package/src/core/agent-runtime/capabilities.ts +330 -0
  134. package/src/core/agent-runtime/contract-tests.ts +378 -0
  135. package/src/core/agent-runtime/events.ts +291 -0
  136. package/src/core/agent-runtime/index.ts +62 -0
  137. package/src/core/agent-runtime/model-ref.ts +130 -0
  138. package/src/core/background/cron.ts +469 -0
  139. package/src/core/{dream.ts → background/dream.ts} +118 -53
  140. package/src/core/background/heartbeat/agent.ts +333 -0
  141. package/src/core/background/heartbeat/index.ts +25 -0
  142. package/src/core/background/heartbeat/scheduler.ts +211 -0
  143. package/src/core/background/heartbeat/state.ts +153 -0
  144. package/src/core/background/index.ts +21 -0
  145. package/src/core/background/isolated-agent.ts +115 -0
  146. package/src/core/background/job-health.ts +140 -0
  147. package/src/core/background/job-oneshot.ts +165 -0
  148. package/src/core/background/job-prompt.ts +54 -0
  149. package/src/core/{pulse.ts → background/pulse.ts} +6 -5
  150. package/src/core/background/triggers/command.ts +60 -0
  151. package/src/core/background/triggers/exit.ts +202 -0
  152. package/src/core/background/triggers/index.ts +38 -0
  153. package/src/core/background/triggers/output.ts +142 -0
  154. package/src/core/background/triggers/resume.ts +127 -0
  155. package/src/core/background/triggers/spawn.ts +282 -0
  156. package/src/core/background/triggers/state.ts +52 -0
  157. package/src/core/constants.ts +57 -28
  158. package/src/core/daemon/control.ts +229 -0
  159. package/src/core/daemon/discovery.ts +169 -0
  160. package/src/core/daemon/pidfile.ts +98 -0
  161. package/src/core/doctor.ts +459 -0
  162. package/src/core/engine/backend-controller/holders.ts +17 -0
  163. package/src/core/engine/backend-controller/index.ts +71 -0
  164. package/src/core/engine/backend-controller/legacy.ts +111 -0
  165. package/src/core/engine/backend-controller/pool.ts +296 -0
  166. package/src/core/engine/backend-controller/rebind.ts +205 -0
  167. package/src/core/engine/backend-controller/state.ts +150 -0
  168. package/src/core/engine/backend-controller/types.ts +51 -0
  169. package/src/core/engine/dispatcher.ts +68 -0
  170. package/src/core/engine/gateway-actions/cron.ts +518 -0
  171. package/src/core/engine/gateway-actions/fetch-url.ts +120 -0
  172. package/src/core/engine/gateway-actions/goals.ts +178 -0
  173. package/src/core/engine/gateway-actions/history.ts +53 -0
  174. package/src/core/engine/gateway-actions/index.ts +60 -0
  175. package/src/core/engine/gateway-actions/models.ts +120 -0
  176. package/src/core/engine/gateway-actions/plugins.ts +83 -0
  177. package/src/core/engine/gateway-actions/scripts.ts +127 -0
  178. package/src/core/engine/gateway-actions/shared.ts +66 -0
  179. package/src/core/engine/gateway-actions/skills.ts +120 -0
  180. package/src/core/engine/gateway-actions/triggers.ts +237 -0
  181. package/src/core/engine/gateway-actions/types.ts +18 -0
  182. package/src/core/{gateway.ts → engine/gateway.ts} +223 -60
  183. package/src/core/engine/index.ts +20 -0
  184. package/src/core/engine/model-audit.ts +121 -0
  185. package/src/core/errors.ts +68 -6
  186. package/src/core/mcp-hub/children.ts +254 -0
  187. package/src/core/mcp-hub/index.ts +335 -0
  188. package/src/core/mcp-hub/proxy-server.ts +45 -0
  189. package/src/core/mcp-hub/talon-server.ts +71 -0
  190. package/src/core/memory/retrieval.ts +90 -0
  191. package/src/core/models/active-model.ts +441 -0
  192. package/src/core/{models.ts → models/catalog.ts} +6 -0
  193. package/src/core/models/index.ts +17 -0
  194. package/src/core/models/reasoning-levels.ts +57 -0
  195. package/src/core/plugin/actions.ts +32 -0
  196. package/src/core/plugin/builtins.ts +162 -0
  197. package/src/core/plugin/index.ts +37 -0
  198. package/src/core/plugin/loader.ts +289 -0
  199. package/src/core/plugin/mcp.ts +86 -0
  200. package/src/core/plugin/registry.ts +124 -0
  201. package/src/core/plugin/types.ts +126 -0
  202. package/src/core/prompt/assemble.ts +273 -0
  203. package/src/core/prompt/disk-prompts.ts +41 -0
  204. package/src/core/prompt/embed.ts +107 -0
  205. package/src/core/prompt/embedded-prompts.ts +85 -0
  206. package/src/core/prompt/index.ts +30 -0
  207. package/src/core/prompt/templates.ts +124 -0
  208. package/src/core/prompt/workspace-listing.ts +91 -0
  209. package/src/core/scripting/lua-runner.ts +210 -0
  210. package/src/core/scripts/runner.ts +125 -0
  211. package/src/core/soul/README.md +110 -0
  212. package/src/core/soul/RESEARCH.md +98 -0
  213. package/src/core/soul/associative.ts +98 -0
  214. package/src/core/soul/centrality.ts +98 -0
  215. package/src/core/soul/cluster.ts +83 -0
  216. package/src/core/soul/compiler.ts +207 -0
  217. package/src/core/soul/consolidate.ts +179 -0
  218. package/src/core/soul/critic.ts +159 -0
  219. package/src/core/soul/dag.ts +265 -0
  220. package/src/core/soul/delta.ts +123 -0
  221. package/src/core/soul/drift.ts +99 -0
  222. package/src/core/soul/embedder.ts +129 -0
  223. package/src/core/soul/emergent-critic.ts +96 -0
  224. package/src/core/soul/forgetting.ts +131 -0
  225. package/src/core/soul/governance.ts +93 -0
  226. package/src/core/soul/hash.ts +97 -0
  227. package/src/core/soul/hdc.ts +154 -0
  228. package/src/core/soul/index.ts +140 -0
  229. package/src/core/soul/kernel.ts +540 -0
  230. package/src/core/soul/lattice.ts +103 -0
  231. package/src/core/soul/lens.ts +110 -0
  232. package/src/core/soul/projector.ts +240 -0
  233. package/src/core/soul/reflect.ts +170 -0
  234. package/src/core/soul/reflex.ts +164 -0
  235. package/src/core/soul/retrieve.ts +146 -0
  236. package/src/core/soul/salience.ts +142 -0
  237. package/src/core/soul/service.ts +204 -0
  238. package/src/core/soul/settings.ts +47 -0
  239. package/src/core/soul/signals.ts +117 -0
  240. package/src/core/soul/talon-embedder.ts +80 -0
  241. package/src/core/soul/taps.ts +199 -0
  242. package/src/core/soul/types.ts +298 -0
  243. package/src/core/soul/valence.ts +83 -0
  244. package/src/core/tools/goals.ts +117 -0
  245. package/src/core/tools/index.ts +10 -0
  246. package/src/core/tools/mcp-env.ts +94 -0
  247. package/src/core/tools/mcp-server.ts +27 -4
  248. package/src/core/tools/messaging.ts +122 -29
  249. package/src/core/tools/models.ts +39 -0
  250. package/src/core/tools/scheduling.ts +133 -14
  251. package/src/core/tools/schemas.ts +16 -4
  252. package/src/core/tools/scripts.ts +78 -0
  253. package/src/core/tools/skills.ts +90 -0
  254. package/src/core/tools/stickers.ts +1 -1
  255. package/src/core/tools/triggers.ts +19 -3
  256. package/src/core/tools/types.ts +6 -6
  257. package/src/core/types.ts +62 -112
  258. package/src/core/update/self-update.ts +269 -0
  259. package/src/core/weaver/index.ts +10 -0
  260. package/src/core/weaver/loom.ts +125 -0
  261. package/src/core/weaver/thread-session.ts +51 -0
  262. package/src/core/weaver/thread.ts +196 -0
  263. package/src/core/weaver/weaver.ts +357 -0
  264. package/src/frontend/discord/actions/chat-info.ts +268 -0
  265. package/src/frontend/discord/actions/index.ts +77 -0
  266. package/src/frontend/discord/actions/media.ts +190 -0
  267. package/src/frontend/discord/actions/messaging.ts +277 -0
  268. package/src/frontend/discord/actions/shared.ts +100 -0
  269. package/src/frontend/discord/actions/types.ts +33 -0
  270. package/src/frontend/discord/admin.ts +13 -23
  271. package/src/frontend/discord/callbacks/autocomplete.ts +55 -0
  272. package/src/frontend/discord/{callbacks.ts → callbacks/components.ts} +150 -190
  273. package/src/frontend/discord/callbacks/index.ts +14 -0
  274. package/src/frontend/discord/callbacks/modals.ts +76 -0
  275. package/src/frontend/discord/callbacks/shared.ts +22 -0
  276. package/src/frontend/discord/commands/admin.ts +88 -0
  277. package/src/frontend/discord/commands/definitions.ts +200 -0
  278. package/src/frontend/discord/commands/index.ts +19 -0
  279. package/src/frontend/discord/commands/info.ts +106 -0
  280. package/src/frontend/discord/commands/router.ts +149 -0
  281. package/src/frontend/discord/commands/session.ts +89 -0
  282. package/src/frontend/discord/commands/settings.ts +405 -0
  283. package/src/frontend/discord/commands/shared.ts +50 -0
  284. package/src/frontend/discord/formatting.ts +8 -34
  285. package/src/frontend/discord/handlers/access.ts +248 -0
  286. package/src/frontend/discord/handlers/context.ts +161 -0
  287. package/src/frontend/discord/handlers/delivery.ts +94 -0
  288. package/src/frontend/discord/handlers/index.ts +34 -0
  289. package/src/frontend/discord/handlers/messages.ts +120 -0
  290. package/src/frontend/discord/handlers/queue.ts +135 -0
  291. package/src/frontend/discord/handlers/registry.ts +29 -0
  292. package/src/frontend/discord/handlers/state.ts +94 -0
  293. package/src/frontend/discord/helpers.ts +46 -57
  294. package/src/frontend/discord/index.ts +10 -7
  295. package/src/frontend/discord/middleware.ts +2 -2
  296. package/src/frontend/native/actions.ts +133 -0
  297. package/src/frontend/native/chats.ts +146 -0
  298. package/src/frontend/native/discovery.ts +50 -0
  299. package/src/frontend/native/index.ts +1227 -0
  300. package/src/frontend/native/logs.ts +95 -0
  301. package/src/frontend/native/protocol.ts +253 -0
  302. package/src/frontend/native/server.ts +612 -0
  303. package/src/frontend/native/settings.ts +205 -0
  304. package/src/frontend/native/turn-meta.ts +43 -0
  305. package/src/frontend/shared/format.ts +51 -0
  306. package/src/frontend/shared/reasoning-levels.ts +46 -0
  307. package/src/frontend/shared/session-status.ts +189 -0
  308. package/src/frontend/shared/status-context.ts +125 -0
  309. package/src/frontend/teams/actions.ts +7 -5
  310. package/src/frontend/teams/formatting.ts +7 -18
  311. package/src/frontend/teams/graph.ts +2 -1
  312. package/src/frontend/teams/index.ts +76 -54
  313. package/src/frontend/telegram/actions/chat-info.ts +323 -0
  314. package/src/frontend/telegram/actions/index.ts +68 -0
  315. package/src/frontend/telegram/actions/media.ts +224 -0
  316. package/src/frontend/telegram/actions/messaging.ts +295 -0
  317. package/src/frontend/telegram/actions/shared.ts +58 -0
  318. package/src/frontend/telegram/actions/types.ts +31 -0
  319. package/src/frontend/telegram/admin.ts +12 -22
  320. package/src/frontend/telegram/callbacks/effort.ts +68 -0
  321. package/src/frontend/telegram/callbacks/index.ts +68 -0
  322. package/src/frontend/telegram/callbacks/model.ts +311 -0
  323. package/src/frontend/telegram/callbacks/pulse.ts +50 -0
  324. package/src/frontend/telegram/callbacks/settings.ts +177 -0
  325. package/src/frontend/telegram/callbacks/shared.ts +71 -0
  326. package/src/frontend/telegram/commands/admin.ts +226 -0
  327. package/src/frontend/telegram/commands/definitions.ts +60 -0
  328. package/src/frontend/telegram/commands/index.ts +39 -0
  329. package/src/frontend/telegram/commands/info.ts +125 -0
  330. package/src/frontend/telegram/commands/session.ts +77 -0
  331. package/src/frontend/telegram/commands/settings.ts +345 -0
  332. package/src/frontend/telegram/commands/state.ts +34 -0
  333. package/src/frontend/telegram/formatting.ts +14 -25
  334. package/src/frontend/telegram/handlers/access.ts +287 -0
  335. package/src/frontend/telegram/handlers/context.ts +210 -0
  336. package/src/frontend/telegram/handlers/delivery.ts +236 -0
  337. package/src/frontend/telegram/handlers/index.ts +39 -0
  338. package/src/frontend/telegram/handlers/messages.ts +477 -0
  339. package/src/frontend/telegram/handlers/queue.ts +241 -0
  340. package/src/frontend/telegram/handlers/state.ts +75 -0
  341. package/src/frontend/telegram/helpers/diagnostics.ts +188 -0
  342. package/src/frontend/telegram/helpers/format.ts +41 -0
  343. package/src/frontend/telegram/helpers/index.ts +13 -0
  344. package/src/frontend/telegram/{helpers.ts → helpers/menu.ts} +209 -210
  345. package/src/frontend/telegram/index.ts +24 -27
  346. package/src/frontend/telegram/middleware.ts +16 -3
  347. package/src/frontend/telegram/model-callbacks.ts +14 -0
  348. package/src/frontend/telegram/model-menu.ts +317 -0
  349. package/src/frontend/telegram/sticker-library.ts +178 -0
  350. package/src/frontend/telegram/userbot.ts +2 -44
  351. package/src/frontend/terminal/commands.ts +47 -41
  352. package/src/frontend/terminal/index.ts +46 -31
  353. package/src/frontend/terminal/input.ts +5 -0
  354. package/src/frontend/terminal/renderer.ts +4 -2
  355. package/src/index.ts +13 -171
  356. package/src/login.ts +3 -2
  357. package/src/native/blake3-wasm-bytes.ts +7 -0
  358. package/src/native/blake3.ts +234 -0
  359. package/src/native/htmlents-wasm-bytes.ts +7 -0
  360. package/src/native/htmlents.ts +56 -0
  361. package/src/native/prelude.d.mts +168 -0
  362. package/src/native/prelude.mjs +1561 -0
  363. package/src/native/registry.ts +142 -0
  364. package/src/native/runtime.ts +164 -0
  365. package/src/native/scheduler-core/gleam.d.mts +2 -0
  366. package/src/native/scheduler-core/gleam.mjs +1 -0
  367. package/src/native/scheduler-core/scheduler_core.d.mts +76 -0
  368. package/src/native/scheduler-core/scheduler_core.mjs +252 -0
  369. package/src/native/scheduler-core.ts +124 -0
  370. package/src/native/sqlguard-wasm-bytes.ts +7 -0
  371. package/src/native/sqlguard.ts +107 -0
  372. package/src/native/strsim-wasm-bytes.ts +7 -0
  373. package/src/native/strsim.ts +98 -0
  374. package/src/native/textops-wasm-bytes.ts +7 -0
  375. package/src/native/textops.ts +83 -0
  376. package/src/native/warden.ts +287 -0
  377. package/src/plugins/github/index.ts +1 -1
  378. package/src/plugins/mempalace/index.ts +1 -1
  379. package/src/plugins/playwright/index.ts +1 -1
  380. package/src/storage/chat-settings.ts +335 -85
  381. package/src/storage/cron-store.ts +266 -109
  382. package/src/storage/daily-log.ts +15 -3
  383. package/src/storage/db.ts +206 -0
  384. package/src/storage/goal-store.ts +186 -0
  385. package/src/storage/history.ts +137 -188
  386. package/src/storage/kv.ts +52 -0
  387. package/src/storage/legacy-import.ts +47 -0
  388. package/src/storage/media-index.ts +118 -61
  389. package/src/storage/repositories/chat-settings-repo.ts +60 -0
  390. package/src/storage/repositories/cron-repo.ts +128 -0
  391. package/src/storage/repositories/goals-repo.ts +122 -0
  392. package/src/storage/repositories/history-repo.ts +207 -0
  393. package/src/storage/repositories/kv-repo.ts +25 -0
  394. package/src/storage/repositories/media-index-repo.ts +147 -0
  395. package/src/storage/repositories/scripts-repo.ts +81 -0
  396. package/src/storage/repositories/sessions-repo.ts +129 -0
  397. package/src/storage/repositories/triggers-repo.ts +158 -0
  398. package/src/storage/repositories/turn-meta-repo.ts +32 -0
  399. package/src/storage/scheduled-store.ts +84 -0
  400. package/src/storage/script-store.ts +198 -0
  401. package/src/storage/sessions.ts +227 -102
  402. package/src/storage/skill-store.ts +325 -0
  403. package/src/storage/sql/README.md +18 -0
  404. package/src/storage/sql/chat-settings.sql +11 -0
  405. package/src/storage/sql/cron.sql +40 -0
  406. package/src/storage/sql/db.sql +11 -0
  407. package/src/storage/sql/embed.ts +118 -0
  408. package/src/storage/sql/goals.sql +41 -0
  409. package/src/storage/sql/history.sql +83 -0
  410. package/src/storage/sql/kv.sql +11 -0
  411. package/src/storage/sql/media-index.sql +45 -0
  412. package/src/storage/sql/schema.sql +233 -0
  413. package/src/storage/sql/scripts.sql +28 -0
  414. package/src/storage/sql/sessions.sql +22 -0
  415. package/src/storage/sql/statements.generated.ts +500 -0
  416. package/src/storage/sql/triggers.sql +69 -0
  417. package/src/storage/sql/turn-meta.sql +24 -0
  418. package/src/storage/sticker-store.ts +141 -0
  419. package/src/storage/trigger-store.ts +104 -126
  420. package/src/storage/turn-meta.ts +118 -0
  421. package/src/util/chat-id.ts +30 -0
  422. package/src/util/config.ts +313 -195
  423. package/src/util/fs-path.ts +32 -0
  424. package/src/util/log.ts +53 -31
  425. package/src/util/mcp-launcher.ts +351 -33
  426. package/src/util/paths.ts +45 -17
  427. package/src/util/tail-file.ts +24 -0
  428. package/src/util/workspace.ts +161 -10
  429. package/tsconfig.json +1 -0
  430. package/src/backend/claude-sdk/models.ts +0 -501
  431. package/src/backend/codex/handler.ts +0 -595
  432. package/src/backend/kilo/handler.ts +0 -707
  433. package/src/backend/kilo/models.ts +0 -762
  434. package/src/backend/openai-agents/handler.ts +0 -539
  435. package/src/backend/openai-agents/mcp.ts +0 -139
  436. package/src/backend/opencode/handler.ts +0 -663
  437. package/src/backend/opencode/models.ts +0 -741
  438. package/src/core/cron.ts +0 -184
  439. package/src/core/dispatcher.ts +0 -144
  440. package/src/core/gateway-actions.ts +0 -603
  441. package/src/core/heartbeat.ts +0 -575
  442. package/src/core/plugin.ts +0 -776
  443. package/src/core/triggers.ts +0 -640
  444. package/src/frontend/discord/actions.ts +0 -729
  445. package/src/frontend/discord/commands.ts +0 -1036
  446. package/src/frontend/discord/handlers.ts +0 -798
  447. package/src/frontend/telegram/actions.ts +0 -731
  448. package/src/frontend/telegram/callbacks.ts +0 -419
  449. package/src/frontend/telegram/commands.ts +0 -642
  450. package/src/frontend/telegram/handlers.ts +0 -1352
  451. package/src/util/mcp-launcher.mjs +0 -140
@@ -7,11 +7,28 @@
7
7
 
8
8
  import pc from "picocolors";
9
9
  import type { TalonConfig } from "../../util/config.js";
10
- import type { QueryBackend } from "../../core/types.js";
10
+ import type { Backend } from "../../core/agent-runtime/capabilities.js";
11
11
  import type { Renderer } from "./renderer.js";
12
12
  import { formatTimeAgo } from "./renderer.js";
13
13
  import { isTerminalChatId } from "../../util/chat-id.js";
14
- import { resolveModel as coreResolveModel } from "../../core/models.js";
14
+ import {
15
+ resolveModel as coreResolveModel,
16
+ getModels,
17
+ } from "../../core/models/catalog.js";
18
+ import { buildCacheDisplay } from "../shared/status-context.js";
19
+ import {
20
+ getChatSettings,
21
+ setChatModel,
22
+ setChatEffort,
23
+ resolveModelName,
24
+ } from "../../storage/chat-settings.js";
25
+ import {
26
+ getAllSessions,
27
+ getSession,
28
+ getSessionInfo,
29
+ setSessionName,
30
+ } from "../../storage/sessions.js";
31
+ import { getLoadedPlugins } from "../../core/plugin/index.js";
15
32
 
16
33
  // ── Types ────────────────────────────────────────────────────────────────────
17
34
 
@@ -26,7 +43,7 @@ export type CommandContext = {
26
43
  /** Close the terminal (for /quit). */
27
44
  close: () => void;
28
45
  /** AI backend (available after bootstrap). */
29
- backend?: QueryBackend | null;
46
+ backend?: Backend | null;
30
47
  };
31
48
 
32
49
  export type CommandHandler = (
@@ -96,8 +113,6 @@ export function registerBuiltinCommands(): void {
96
113
  argHint: "[name]",
97
114
  description: "Switch model",
98
115
  async handler(args, ctx) {
99
- const { getChatSettings, setChatModel, resolveModelName } =
100
- await import("../../storage/chat-settings.js");
101
116
  const currentModel =
102
117
  getChatSettings(ctx.chatId()).model ?? ctx.config.model;
103
118
  const be = ctx.backend;
@@ -106,7 +121,7 @@ export function registerBuiltinCommands(): void {
106
121
  const lowerArgs = trimmedArgs.toLowerCase();
107
122
 
108
123
  if (!trimmedArgs) {
109
- const modelInfo = await be?.getModelInfo?.(currentModel);
124
+ const modelInfo = await be?.models?.getRawModelInfo?.(currentModel);
110
125
  const displayName = modelInfo?.displayName ?? currentModel;
111
126
  const details = modelInfo
112
127
  ? [
@@ -125,8 +140,8 @@ export function registerBuiltinCommands(): void {
125
140
  ` Context window: ${modelInfo.contextWindow.toLocaleString()}`,
126
141
  );
127
142
  }
128
- if (be?.getProviders) {
129
- const providers = await be.getProviders();
143
+ if (be?.models?.getProviders) {
144
+ const providers = await be.models?.getProviders();
130
145
  const connected = providers.filter((p) => p.connected);
131
146
  if (connected.length > 0) {
132
147
  ctx.renderer.writeln(
@@ -149,9 +164,9 @@ export function registerBuiltinCommands(): void {
149
164
  }
150
165
 
151
166
  if (lowerArgs === "free" || lowerArgs === "list" || lowerArgs === "all") {
152
- if (be?.listModels) {
167
+ if (be?.models?.listModels) {
153
168
  const filter = lowerArgs === "free" ? "free" : "all";
154
- const { models, total } = await be.listModels(filter);
169
+ const { models, total } = await be.models.listModels(filter);
155
170
  const list = models.slice(0, 20);
156
171
  ctx.renderer.writeSystem(
157
172
  `${filter === "free" ? "Free" : "Available"} models (${total})`,
@@ -165,7 +180,6 @@ export function registerBuiltinCommands(): void {
165
180
  ctx.renderer.writeln(` …and ${total - list.length} more`);
166
181
  }
167
182
  } else {
168
- const { getModels } = await import("../../core/models.js");
169
183
  const names = getModels()
170
184
  .map((m) => m.aliases[0] ?? m.id)
171
185
  .join(", ");
@@ -176,8 +190,8 @@ export function registerBuiltinCommands(): void {
176
190
  }
177
191
 
178
192
  if (lowerArgs === "providers") {
179
- if (be?.getProviders) {
180
- const providers = await be.getProviders();
193
+ if (be?.models?.getProviders) {
194
+ const providers = await be.models?.getProviders();
181
195
  ctx.renderer.writeSystem(`Providers (${providers.length})`);
182
196
  for (const p of providers.slice(0, 20)) {
183
197
  ctx.renderer.writeln(
@@ -192,11 +206,11 @@ export function registerBuiltinCommands(): void {
192
206
  }
193
207
 
194
208
  // Resolve model query via backend
195
- if (be?.resolveModel) {
196
- const resolution = await be.resolveModel(trimmedArgs);
209
+ if (be?.models?.resolveModelInfo) {
210
+ const resolution = await be.models?.resolveModelInfo(trimmedArgs);
197
211
  if (resolution.kind === "missing") {
198
212
  const msg =
199
- be.formatModelError?.(trimmedArgs, resolution) ??
213
+ be.models?.formatModelError?.(trimmedArgs, resolution) ??
200
214
  `No model matched "${trimmedArgs}".`;
201
215
  ctx.renderer.writeError(msg);
202
216
  ctx.reprompt();
@@ -237,8 +251,6 @@ export function registerBuiltinCommands(): void {
237
251
  argHint: "[lvl]",
238
252
  description: "Thinking effort (off/low/medium/high/max)",
239
253
  async handler(args, ctx) {
240
- const { getChatSettings, setChatEffort } =
241
- await import("../../storage/chat-settings.js");
242
254
  if (!args) {
243
255
  ctx.renderer.writeSystem(
244
256
  `Effort: ${getChatSettings(ctx.chatId()).effort ?? "adaptive"}`,
@@ -260,10 +272,6 @@ export function registerBuiltinCommands(): void {
260
272
  name: "status",
261
273
  description: "Session stats",
262
274
  async handler(_args, ctx) {
263
- const { getSessionInfo } = await import("../../storage/sessions.js");
264
- const { getChatSettings } =
265
- await import("../../storage/chat-settings.js");
266
- const { getLoadedPlugins } = await import("../../core/plugin.js");
267
275
  const info = getSessionInfo(ctx.chatId());
268
276
  const u = info.usage;
269
277
  const be = ctx.backend;
@@ -279,9 +287,9 @@ export function registerBuiltinCommands(): void {
279
287
  const nameStr = info.sessionName ? `"${info.sessionName}" · ` : "";
280
288
 
281
289
  // Enrich from backend when available
282
- if (be?.getSessionSnapshot && info.sessionId) {
283
- const snap = await be
284
- .getSessionSnapshot(info.sessionId)
290
+ if (be?.usage?.getSessionSnapshot && info.sessionId) {
291
+ const snap = await be.usage
292
+ ?.getSessionSnapshot(info.sessionId)
285
293
  .catch(() => undefined);
286
294
  if (snap) {
287
295
  displayInputTokens = snap.inputTokens ?? displayInputTokens;
@@ -291,28 +299,29 @@ export function registerBuiltinCommands(): void {
291
299
  }
292
300
  }
293
301
 
294
- if (be?.getModelInfo) {
295
- const modelInfo = await be
296
- .getModelInfo(activeModel)
302
+ const cache = buildCacheDisplay({
303
+ cacheMetrics: be?.cacheMetrics,
304
+ inputTokens: displayInputTokens,
305
+ cacheRead: displayCacheRead,
306
+ cacheWrite: displayCacheWrite,
307
+ });
308
+ if (be?.models?.getRawModelInfo) {
309
+ const modelInfo = await be.models
310
+ ?.getRawModelInfo(activeModel)
297
311
  .catch(() => undefined);
298
- const label = be.backendLabel ?? "Backend";
312
+ const label = be.label ?? "Backend";
299
313
  if (modelInfo) {
300
314
  backendModelLine = ` ${pc.bold(label)} ${modelInfo.displayName} · ${modelInfo.providerName}${modelInfo.free ? " · free" : ""}`;
301
315
  if (modelInfo.contextWindow) {
302
- backendContextLine = ` ${pc.dim(`context window ${modelInfo.contextWindow.toLocaleString()} · cache ${displayCacheRead.toLocaleString()} / ${displayCacheWrite.toLocaleString()}`)}`;
316
+ backendContextLine = cache
317
+ ? ` ${pc.dim(`context window ${modelInfo.contextWindow.toLocaleString()} · cache ${cache.read.toLocaleString()} / ${cache.write.toLocaleString()}`)}`
318
+ : ` ${pc.dim(`context window ${modelInfo.contextWindow.toLocaleString()}`)}`;
303
319
  }
304
320
  }
305
321
  }
306
322
 
307
- const cacheHit =
308
- displayInputTokens + displayCacheRead > 0
309
- ? Math.round(
310
- (displayCacheRead / (displayInputTokens + displayCacheRead)) *
311
- 100,
312
- )
313
- : 0;
314
323
  ctx.renderer.writeln(
315
- ` ${pc.bold("Session")} ${nameStr}turns ${info.turns} · ${cacheHit}% cache`,
324
+ ` ${pc.bold("Session")} ${nameStr}turns ${info.turns}${cache ? ` · ${cache.hitPct}% cache` : ""}`,
316
325
  );
317
326
  ctx.renderer.writeln(
318
327
  ` ${pc.dim(`in ${displayInputTokens.toLocaleString()} · out ${displayOutputTokens.toLocaleString()} tokens`)}`,
@@ -360,7 +369,6 @@ export function registerBuiltinCommands(): void {
360
369
  name: "resume",
361
370
  description: "List & resume a past session",
362
371
  async handler(_args, ctx) {
363
- const { getAllSessions } = await import("../../storage/sessions.js");
364
372
  const sessions = getAllSessions()
365
373
  .filter(
366
374
  (s) =>
@@ -420,8 +428,6 @@ export function registerBuiltinCommands(): void {
420
428
  argHint: "[name]",
421
429
  description: "Name the current session",
422
430
  async handler(args, ctx) {
423
- const { getSession, setSessionName } =
424
- await import("../../storage/sessions.js");
425
431
  // Ensure session exists in store (auto-creates if needed)
426
432
  getSession(ctx.chatId());
427
433
  if (!args) {
@@ -11,13 +11,14 @@
11
11
  import pc from "picocolors";
12
12
  import type { TalonConfig } from "../../util/config.js";
13
13
  import type { ContextManager, ActionResult } from "../../core/types.js";
14
- import type { Gateway } from "../../core/gateway.js";
14
+ import type { Gateway } from "../../core/engine/gateway.js";
15
15
  import { log } from "../../util/log.js";
16
16
  import {
17
17
  deriveNumericChatId,
18
18
  generateTerminalChatId,
19
19
  } from "../../util/chat-id.js";
20
- import { resolveModel } from "../../core/models.js";
20
+ import { resolveModel } from "../../core/models/catalog.js";
21
+ import { toolInputToRecord } from "../../core/agent-runtime/events.js";
21
22
  import { createRenderer } from "./renderer.js";
22
23
  import { createInput } from "./input.js";
23
24
  import {
@@ -26,6 +27,7 @@ import {
26
27
  clearCommands,
27
28
  type CommandContext,
28
29
  } from "./commands.js";
30
+ import { buildCacheDisplay } from "../shared/status-context.js";
29
31
 
30
32
  // ── State ────────────────────────────────────────────────────────────────────
31
33
 
@@ -118,7 +120,8 @@ export function createTerminalFrontend(
118
120
  let toolCallCount = 0;
119
121
 
120
122
  const context: ContextManager = {
121
- acquire: () => gateway.setContext(terminalNumericId, terminalChatId),
123
+ acquire: () =>
124
+ gateway.setContext(terminalNumericId, terminalChatId, "terminal"),
122
125
  release: () => gateway.clearContext(terminalNumericId),
123
126
  getMessageCount: (chatId: number) => gateway.getMessageCount(chatId),
124
127
  };
@@ -138,7 +141,10 @@ export function createTerminalFrontend(
138
141
  getBridgePort: () => gateway.getPort(),
139
142
 
140
143
  async init() {
141
- gateway.setFrontendHandler(createActionHandler(gateway, renderer));
144
+ gateway.registerFrontendHandler(
145
+ "terminal",
146
+ createActionHandler(gateway, renderer),
147
+ );
142
148
  const port = await gateway.start(19877);
143
149
  log("bot", `Terminal gateway on port ${port}`);
144
150
  },
@@ -155,7 +161,7 @@ export function createTerminalFrontend(
155
161
  );
156
162
  renderer.writeln(` ${pc.dim("─".repeat(renderer.cols - 2))}`);
157
163
 
158
- const { execute } = await import("../../core/dispatcher.js");
164
+ const { execute } = await import("../../core/engine/dispatcher.js");
159
165
  const { getSessionInfo } = await import("../../storage/sessions.js");
160
166
  const input = createInput(` ${pc.green("❯")} `);
161
167
 
@@ -216,26 +222,36 @@ export function createTerminalFrontend(
216
222
  senderName: "User",
217
223
  isGroup: false,
218
224
  source: "message",
219
- onStreamDelta: (_accumulated, phase) => {
220
- if (phase === "thinking" && currentPhase !== "thinking") {
221
- currentPhase = "thinking";
222
- renderer.updateSpinnerLabel("thinking");
223
- } else if (phase === "text" && currentPhase !== "text") {
224
- currentPhase = "text";
225
- renderer.updateSpinnerLabel("responding");
225
+ onEvent: async (event) => {
226
+ switch (event.type) {
227
+ case "text_delta":
228
+ if (currentPhase !== "text") {
229
+ currentPhase = "text";
230
+ renderer.updateSpinnerLabel("responding");
231
+ }
232
+ break;
233
+ case "reasoning":
234
+ if (currentPhase !== "thinking") {
235
+ currentPhase = "thinking";
236
+ renderer.updateSpinnerLabel("thinking");
237
+ }
238
+ break;
239
+ case "tool_call":
240
+ renderer.stopSpinner();
241
+ currentPhase = "tool";
242
+ toolCallCount++;
243
+ renderer.renderToolCall(
244
+ event.name,
245
+ toolInputToRecord(event.name, event.input),
246
+ );
247
+ renderer.startSpinner("running tools");
248
+ break;
249
+ case "assistant_message":
250
+ renderer.stopSpinner();
251
+ renderer.renderAssistantMessage(event.text);
252
+ break;
226
253
  }
227
254
  },
228
- onToolUse: (toolName, toolInput) => {
229
- renderer.stopSpinner();
230
- currentPhase = "tool";
231
- toolCallCount++;
232
- renderer.renderToolCall(toolName, toolInput);
233
- renderer.startSpinner("running tools");
234
- },
235
- onTextBlock: async (blockText) => {
236
- renderer.stopSpinner();
237
- renderer.renderAssistantMessage(blockText);
238
- },
239
255
  });
240
256
 
241
257
  renderer.stopSpinner();
@@ -247,20 +263,19 @@ export function createTerminalFrontend(
247
263
 
248
264
  const info = getSessionInfo(terminalChatId);
249
265
  const u = info.usage;
250
- const cacheHit =
251
- u.totalInputTokens + u.totalCacheRead > 0
252
- ? Math.round(
253
- (u.totalCacheRead / (u.totalInputTokens + u.totalCacheRead)) *
254
- 100,
255
- )
256
- : 0;
266
+ const cache = buildCacheDisplay({
267
+ cacheMetrics: gateway.backend?.cacheMetrics,
268
+ inputTokens: u.totalInputTokens,
269
+ cacheRead: u.totalCacheRead,
270
+ cacheWrite: u.totalCacheWrite,
271
+ });
257
272
  renderer.renderStatusLine(result.durationMs, toolCallCount, {
258
273
  model: modelDisplay,
259
274
  sessionName: info.sessionName,
260
275
  turns: info.turns,
261
276
  inputTokens: u.totalInputTokens,
262
277
  outputTokens: u.totalOutputTokens,
263
- cacheHitPct: cacheHit,
278
+ cacheHitPct: cache?.hitPct,
264
279
  costUsd: u.estimatedCostUsd,
265
280
  });
266
281
  reprompt(); // readline back on, show prompt
@@ -289,6 +289,11 @@ export function createInput(promptStr: string): InputHandler {
289
289
  paused = false;
290
290
  },
291
291
  close() {
292
+ if (pendingResolve) {
293
+ const resolve = pendingResolve;
294
+ pendingResolve = null;
295
+ resolve("");
296
+ }
292
297
  process.stdout.write("\x1b[?2004l");
293
298
  if (process.stdin.isTTY) process.stdin.setRawMode(false);
294
299
  process.stdin.pause();
@@ -16,7 +16,7 @@ export type StatusBarInfo = {
16
16
  turns: number;
17
17
  inputTokens: number;
18
18
  outputTokens: number;
19
- cacheHitPct: number;
19
+ cacheHitPct?: number;
20
20
  costUsd: number;
21
21
  };
22
22
 
@@ -189,8 +189,10 @@ export function createRenderer(cols?: number, displayName = "Talon"): Renderer {
189
189
  p.push(
190
190
  `${info.turns} turn${info.turns !== 1 ? "s" : ""}`,
191
191
  `${fmtTok(info.inputTokens + info.outputTokens)} tok`,
192
- `${info.cacheHitPct}% cache`,
193
192
  );
193
+ if (typeof info.cacheHitPct === "number") {
194
+ p.push(`${info.cacheHitPct}% cache`);
195
+ }
194
196
  if (tools > 0) p.push(`${tools} tool${tools > 1 ? "s" : ""}`);
195
197
  writeln();
196
198
  writeln(` ${pc.dim(p.join(" · "))}`);
package/src/index.ts CHANGED
@@ -1,178 +1,20 @@
1
1
  /**
2
- * Talon agentic AI harness.
3
- * Composition root: loads config, creates frontend + backend, wires dispatcher.
2
+ * Talon entry shim.
4
3
  *
5
- * Frontends (Telegram, Terminal) and backends (Claude, OpenCode)
6
- * are loaded dynamically only the selected platform's dependencies are required.
4
+ * Dispatches the hidden `_mcp-launch` (MCP supervisor) and `_lua-run`
5
+ * (WASM Lua trigger runner) subcommands BEFORE the app graph loads
6
+ * both are Talon re-invoking itself (see util/mcp-launcher.ts). The
7
+ * dynamic import keeps these helper processes light: they evaluate this
8
+ * shim and their own module, never the backends/frontends/plugins.
7
9
  */
8
10
 
9
- import { getFrontends } from "./util/config.js";
10
- import { startUploadCleanup, stopUploadCleanup } from "./util/workspace.js";
11
- import { flushSessions } from "./storage/sessions.js";
12
- import { flushChatSettings } from "./storage/chat-settings.js";
13
- import { flushCronJobs } from "./storage/cron-store.js";
14
- import { flushTriggers } from "./storage/trigger-store.js";
15
- import { flushHistory } from "./storage/history.js";
16
- import { flushMediaIndex } from "./storage/media-index.js";
17
- import { getActiveCount } from "./core/dispatcher.js";
18
- import { startPulseTimer, stopPulseTimer } from "./core/pulse.js";
19
- import {
20
- startHeartbeatTimer,
21
- stopHeartbeatTimer,
22
- awaitCurrentRun as awaitHeartbeat,
23
- } from "./core/heartbeat.js";
24
- import { startCronTimer, stopCronTimer } from "./core/cron.js";
25
- import { shutdownTriggers } from "./core/triggers.js";
26
- import { startWatchdog, stopWatchdog } from "./util/watchdog.js";
27
- import { log, logError, logWarn } from "./util/log.js";
28
- import { bootstrap, initBackendAndDispatcher } from "./bootstrap.js";
29
- import { Gateway } from "./core/gateway.js";
30
- import type { Frontend } from "./bootstrap.js";
11
+ import { MCP_LAUNCH_SUBCOMMAND, runSupervisor } from "./util/mcp-launcher.js";
12
+ import { LUA_RUN_SUBCOMMAND, runLuaMain } from "./core/scripting/lua-runner.js";
31
13
 
32
- // ── Bootstrap ────────────────────────────────────────────────────────────────
33
-
34
- import { writeFileSync, unlinkSync } from "node:fs";
35
- import { files as pathFiles } from "./util/paths.js";
36
-
37
- const { config } = await bootstrap();
38
-
39
- // Write PID file for daemon management
40
- try {
41
- writeFileSync(pathFiles.pid, String(process.pid));
42
- } catch {
43
- /* ok */
44
- }
45
-
46
- // ── Create gateway + frontend ─────────────────────────────────────────────────
47
-
48
- const gateway = new Gateway();
49
-
50
- const selectedFrontend = getFrontends(config)[0]; // use first configured frontend
51
- let frontend: Frontend;
52
-
53
- if (selectedFrontend === "terminal") {
54
- const { createTerminalFrontend } =
55
- await import("./frontend/terminal/index.js");
56
- frontend = createTerminalFrontend(config, gateway);
57
- log("bot", "Frontend: Terminal");
58
- } else if (selectedFrontend === "teams") {
59
- const { createTeamsFrontend } = await import("./frontend/teams/index.js");
60
- frontend = createTeamsFrontend(config, gateway);
61
- log("bot", "Frontend: Teams");
62
- } else if (selectedFrontend === "discord") {
63
- const { createDiscordFrontend } = await import("./frontend/discord/index.js");
64
- frontend = createDiscordFrontend(config, gateway);
65
- log("bot", "Frontend: Discord");
14
+ if (process.argv[2] === MCP_LAUNCH_SUBCOMMAND) {
15
+ await runSupervisor(process.argv.slice(3));
16
+ } else if (process.argv[2] === LUA_RUN_SUBCOMMAND) {
17
+ await runLuaMain(process.argv.slice(3));
66
18
  } else {
67
- const { createTelegramFrontend } =
68
- await import("./frontend/telegram/index.js");
69
- frontend = createTelegramFrontend(config, gateway);
70
- log("bot", "Frontend: Telegram");
19
+ await import("./app.js");
71
20
  }
72
-
73
- // ── Create backend + wire dispatcher ─────────────────────────────────────────
74
-
75
- const { backend } = await initBackendAndDispatcher(config, frontend);
76
- gateway.backend = backend;
77
-
78
- // ── Graceful shutdown ────────────────────────────────────────────────────────
79
-
80
- let shuttingDown = false;
81
-
82
- const SHUTDOWN_TIMEOUT_MS = 15_000;
83
-
84
- async function gracefulShutdown(signal: string): Promise<void> {
85
- if (shuttingDown) return;
86
- shuttingDown = true;
87
- log("shutdown", `${signal} received, shutting down gracefully...`);
88
-
89
- const forceTimer = setTimeout(() => {
90
- logError("shutdown", "Timeout exceeded, forcing exit");
91
- process.exit(1);
92
- }, SHUTDOWN_TIMEOUT_MS);
93
- forceTimer.unref();
94
-
95
- const pending = getActiveCount();
96
- if (pending > 0) {
97
- log("shutdown", `Waiting for ${pending} in-flight queries to drain...`);
98
- await new Promise((r) => setTimeout(r, 5000));
99
- }
100
-
101
- await frontend.stop();
102
- if (config.backend === "opencode") {
103
- const { stopOpenCodeServer } = await import("./backend/opencode/index.js");
104
- stopOpenCodeServer();
105
- }
106
- // Destroy plugins (cleanup resources)
107
- if (config.plugins.length > 0) {
108
- const { destroyPlugins } = await import("./core/plugin.js");
109
- await destroyPlugins();
110
- }
111
- stopPulseTimer();
112
- stopHeartbeatTimer();
113
- await awaitHeartbeat();
114
- stopCronTimer();
115
- await shutdownTriggers();
116
- stopWatchdog();
117
- stopUploadCleanup();
118
- flushSessions();
119
- flushChatSettings();
120
- flushCronJobs();
121
- flushTriggers();
122
- flushHistory();
123
- flushMediaIndex();
124
- try {
125
- unlinkSync(pathFiles.pid);
126
- } catch {
127
- /* ok */
128
- }
129
- log("shutdown", "State saved");
130
- process.exit(0);
131
- }
132
-
133
- process.on("SIGTERM", () => gracefulShutdown("SIGTERM"));
134
- process.on("SIGINT", () => gracefulShutdown("SIGINT"));
135
-
136
- process.on("uncaughtException", (err) => {
137
- // EPIPE errors from network sockets (e.g. Telegram MTProto) are transient —
138
- // gramjs will reconnect; crashing the process here is wrong.
139
- if ((err as NodeJS.ErrnoException).code === "EPIPE") {
140
- logWarn("bot", `Suppressed transient EPIPE error: ${err.message}`);
141
- return;
142
- }
143
- logError("bot", "Uncaught exception", err);
144
- flushSessions();
145
- flushChatSettings();
146
- flushCronJobs();
147
- flushTriggers();
148
- flushHistory();
149
- flushMediaIndex();
150
- process.exit(1);
151
- });
152
-
153
- process.on("unhandledRejection", (reason) => {
154
- logWarn(
155
- "bot",
156
- `Unhandled rejection: ${reason instanceof Error ? reason.message : reason}`,
157
- );
158
- });
159
-
160
- // ── Start ────────────────────────────────────────────────────────────────────
161
-
162
- async function main(): Promise<void> {
163
- await frontend.init();
164
- log("bot", "Starting Talon...");
165
-
166
- if (config.pulse) startPulseTimer(config.pulseIntervalMs);
167
- if (config.heartbeat) startHeartbeatTimer(config.heartbeatIntervalMinutes);
168
- startCronTimer();
169
- startWatchdog(config.workspace);
170
- startUploadCleanup(config.workspace);
171
-
172
- await frontend.start();
173
- }
174
-
175
- main().catch((err) => {
176
- logError("bot", "Fatal startup error", err);
177
- process.exit(1);
178
- });
package/src/login.ts CHANGED
@@ -10,9 +10,10 @@
10
10
 
11
11
  import { TelegramClient } from "telegram";
12
12
  import { StringSession } from "telegram/sessions/index.js";
13
- import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
13
+ import { existsSync, readFileSync, mkdirSync } from "node:fs";
14
14
  import { resolve, dirname } from "node:path";
15
15
  import { createInterface } from "node:readline";
16
+ import writeFileAtomic from "write-file-atomic";
16
17
  import { files } from "./util/paths.js";
17
18
 
18
19
  // Load .env
@@ -76,7 +77,7 @@ async function main() {
76
77
  const newSession = client.session.save() as unknown as string;
77
78
  const dir = dirname(SESSION_FILE);
78
79
  if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
79
- writeFileSync(SESSION_FILE, newSession);
80
+ writeFileAtomic.sync(SESSION_FILE, newSession);
80
81
  console.log(`Session saved to ${SESSION_FILE}`);
81
82
 
82
83
  await client.disconnect();