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
@@ -0,0 +1,455 @@
1
+ /**
2
+ * Guided setup wizard — collects frontend/backend config interactively and
3
+ * writes talon.json.
4
+ */
5
+
6
+ import * as p from "@clack/prompts";
7
+ import pc from "picocolors";
8
+ import { printBanner, loadConfig, saveConfig, type Config } from "./config.js";
9
+
10
+ export async function runSetup(): Promise<void> {
11
+ printBanner();
12
+ p.intro(pc.inverse(" Setup Wizard "));
13
+
14
+ const config = loadConfig();
15
+ const existingFrontends = Array.isArray(config.frontend)
16
+ ? config.frontend
17
+ : [config.frontend || "telegram"];
18
+
19
+ const frontendSelection = await p.multiselect({
20
+ message: "Frontend platforms (space to toggle, enter to confirm)",
21
+ initialValues: existingFrontends,
22
+ options: [
23
+ {
24
+ value: "telegram",
25
+ label: `Telegram ${pc.dim("— bot via @BotFather")}`,
26
+ },
27
+ {
28
+ value: "discord",
29
+ label: `Discord ${pc.dim("— bot via Developer Portal (discord.js v14)")}`,
30
+ },
31
+ {
32
+ value: "teams",
33
+ label: `Teams ${pc.dim("— Microsoft Teams via Power Automate")}`,
34
+ },
35
+ {
36
+ value: "terminal",
37
+ label: `Terminal ${pc.dim("— local CLI chat")}`,
38
+ },
39
+ ],
40
+ required: true,
41
+ });
42
+ if (p.isCancel(frontendSelection)) {
43
+ p.cancel("Cancelled.");
44
+ process.exit(0);
45
+ }
46
+ const selectedFrontends = frontendSelection as string[];
47
+
48
+ let botToken: string | undefined;
49
+ let adminId: string | undefined;
50
+ let apiId: number | undefined;
51
+ let apiHash: string | undefined;
52
+
53
+ if (selectedFrontends.includes("telegram")) {
54
+ const token = await p.text({
55
+ message: "Bot token",
56
+ placeholder: "Paste your token from @BotFather",
57
+ initialValue: config.botToken || undefined,
58
+ validate: (v) => {
59
+ if (!v) return "Token is required";
60
+ if (!v.includes(":")) return "Invalid format";
61
+ },
62
+ });
63
+ if (p.isCancel(token)) {
64
+ p.cancel("Cancelled.");
65
+ process.exit(0);
66
+ }
67
+ botToken = token;
68
+
69
+ adminId = (await p.text({
70
+ message: "Your Telegram user ID",
71
+ placeholder: "optional — message @userinfobot to find yours",
72
+ initialValue: config.adminUserId ? String(config.adminUserId) : "",
73
+ })) as string;
74
+ if (p.isCancel(adminId)) {
75
+ p.cancel("Cancelled.");
76
+ process.exit(0);
77
+ }
78
+
79
+ const wantUserbot = await p.confirm({
80
+ message: "Set up userbot for full history access?",
81
+ initialValue: !!(config.apiId && config.apiHash),
82
+ });
83
+ if (p.isCancel(wantUserbot)) {
84
+ p.cancel("Cancelled.");
85
+ process.exit(0);
86
+ }
87
+
88
+ if (wantUserbot) {
89
+ p.note(
90
+ "Get these from https://my.telegram.org → API development tools",
91
+ "Telegram API credentials",
92
+ );
93
+ const id = await p.text({
94
+ message: "API ID",
95
+ placeholder: "12345678",
96
+ initialValue: config.apiId ? String(config.apiId) : "",
97
+ validate: (v) => {
98
+ if (v && isNaN(parseInt(v, 10))) return "Must be a number";
99
+ },
100
+ });
101
+ if (p.isCancel(id)) {
102
+ p.cancel("Cancelled.");
103
+ process.exit(0);
104
+ }
105
+ const hash = await p.text({
106
+ message: "API Hash",
107
+ initialValue: config.apiHash || "",
108
+ });
109
+ if (p.isCancel(hash)) {
110
+ p.cancel("Cancelled.");
111
+ process.exit(0);
112
+ }
113
+ if (id) apiId = parseInt(id, 10);
114
+ if (hash) apiHash = hash as string;
115
+ }
116
+ }
117
+
118
+ let teamsWebhookUrl: string | undefined;
119
+ let teamsWebhookSecret: string | undefined;
120
+ let teamsWebhookPort: number | undefined;
121
+ let teamsBotDisplayName: string | undefined;
122
+
123
+ if (selectedFrontends.includes("teams")) {
124
+ p.note(
125
+ "Set up two Power Automate workflows in Teams:\n" +
126
+ "1. Send: 'Post to a channel when a webhook request is received' — copy the URL below\n" +
127
+ "2. Receive: 'When a new channel message is added' → HTTP POST to your Talon endpoint",
128
+ "Teams Setup",
129
+ );
130
+
131
+ const url = await p.text({
132
+ message: "Power Automate webhook URL (for sending to Teams)",
133
+ placeholder: "https://prod-XX.westus.logic.azure.com/workflows/...",
134
+ initialValue: config.teamsWebhookUrl || undefined,
135
+ validate: (v) => {
136
+ if (!v) return "Webhook URL is required";
137
+ try {
138
+ new URL(v);
139
+ } catch {
140
+ return "Must be a valid URL";
141
+ }
142
+ },
143
+ });
144
+ if (p.isCancel(url)) {
145
+ p.cancel("Cancelled.");
146
+ process.exit(0);
147
+ }
148
+ teamsWebhookUrl = url;
149
+
150
+ const secret = (await p.text({
151
+ message: "Webhook secret for inbound verification",
152
+ placeholder: "optional — shared secret to verify incoming webhooks",
153
+ initialValue: config.teamsWebhookSecret || "",
154
+ })) as string;
155
+ if (p.isCancel(secret)) {
156
+ p.cancel("Cancelled.");
157
+ process.exit(0);
158
+ }
159
+ if (secret) teamsWebhookSecret = secret;
160
+
161
+ const port = await p.text({
162
+ message: "Webhook receiver port",
163
+ placeholder: "19878",
164
+ initialValue: config.teamsWebhookPort
165
+ ? String(config.teamsWebhookPort)
166
+ : "19878",
167
+ validate: (v) => {
168
+ if (!v) return "Port is required";
169
+ const n = parseInt(v, 10);
170
+ if (isNaN(n) || n < 1024 || n > 65535) return "Port must be 1024-65535";
171
+ },
172
+ });
173
+ if (p.isCancel(port)) {
174
+ p.cancel("Cancelled.");
175
+ process.exit(0);
176
+ }
177
+ teamsWebhookPort = parseInt(port as string, 10);
178
+
179
+ const botName = (await p.text({
180
+ message: "Bot display name in Teams (for echo loop prevention)",
181
+ placeholder: "optional — e.g. 'Talon Bot'",
182
+ initialValue: config.teamsBotDisplayName || "",
183
+ })) as string;
184
+ if (p.isCancel(botName)) {
185
+ p.cancel("Cancelled.");
186
+ process.exit(0);
187
+ }
188
+ if (botName) teamsBotDisplayName = botName;
189
+ }
190
+
191
+ let discordBotToken: string | undefined;
192
+ let discordApplicationId: string | undefined;
193
+
194
+ if (selectedFrontends.includes("discord")) {
195
+ p.note(
196
+ "Get bot token + application ID from\n" +
197
+ "https://discord.com/developers/applications → your app → Bot",
198
+ "Discord Setup",
199
+ );
200
+
201
+ const token = await p.text({
202
+ message: "Discord bot token",
203
+ placeholder: "MTxxxxxxxxxxxxxxxxxxxxxxxxxxx",
204
+ initialValue: config.discord?.botToken || undefined,
205
+ validate: (v) => {
206
+ if (!v) return "Bot token is required";
207
+ },
208
+ });
209
+ if (p.isCancel(token)) {
210
+ p.cancel("Cancelled.");
211
+ process.exit(0);
212
+ }
213
+ discordBotToken = token as string;
214
+
215
+ const appId = await p.text({
216
+ message: "Discord application ID",
217
+ placeholder: "1234567890123456789",
218
+ initialValue: config.discord?.applicationId || undefined,
219
+ validate: (v) => {
220
+ if (!v) return "Application ID is required";
221
+ },
222
+ });
223
+ if (p.isCancel(appId)) {
224
+ p.cancel("Cancelled.");
225
+ process.exit(0);
226
+ }
227
+ discordApplicationId = appId as string;
228
+ }
229
+
230
+ // Discover models from SDK; fall back to static list if SDK isn't available
231
+ const {
232
+ registerClaudeModels,
233
+ registerClaudeModelsStatic,
234
+ CLAUDE_MODELS_STATIC,
235
+ } = await import("../backend/claude-sdk/models/index.js");
236
+ try {
237
+ const { dirs } = await import("../util/paths.js");
238
+ await registerClaudeModels({
239
+ model: config.model,
240
+ cwd: dirs.workspace,
241
+ permissionMode: "bypassPermissions",
242
+ allowDangerouslySkipPermissions: true,
243
+ ...(config.claudeBinary
244
+ ? { pathToClaudeCodeExecutable: config.claudeBinary }
245
+ : {}),
246
+ });
247
+ } catch {
248
+ // Setup wizard may run before Claude Code is installed — use static list
249
+ registerClaudeModelsStatic(CLAUDE_MODELS_STATIC);
250
+ }
251
+ const { getModels } = await import("../core/models/catalog.js");
252
+ const registeredModels = getModels();
253
+
254
+ const model = await p.select({
255
+ message: "Default model",
256
+ initialValue: config.model,
257
+ options: registeredModels.map((m) => ({
258
+ value: m.id,
259
+ label: `${m.displayName.padEnd(12)}${m.description ? pc.dim(`— ${m.description}`) : ""}`,
260
+ })),
261
+ });
262
+ if (p.isCancel(model)) {
263
+ p.cancel("Cancelled.");
264
+ process.exit(0);
265
+ }
266
+
267
+ const pulse = !selectedFrontends.every((f) => f === "terminal")
268
+ ? await p.confirm({
269
+ message: "Enable pulse? (periodic group engagement)",
270
+ initialValue: config.pulse,
271
+ })
272
+ : false;
273
+ if (p.isCancel(pulse)) {
274
+ p.cancel("Cancelled.");
275
+ process.exit(0);
276
+ }
277
+
278
+ // ── Backend selection ──
279
+ const backendSelection = await p.select({
280
+ message: "AI backend",
281
+ initialValue: config.backend ?? "claude",
282
+ options: [
283
+ {
284
+ value: "claude",
285
+ label: `Claude ${pc.dim("— Anthropic Claude Agent SDK")}`,
286
+ },
287
+ {
288
+ value: "kilo",
289
+ label: `Kilo ${pc.dim("— @kilocode/sdk (multi-provider routing)")}`,
290
+ },
291
+ {
292
+ value: "opencode",
293
+ label: `OpenCode ${pc.dim("— @opencode-ai/sdk")}`,
294
+ },
295
+ {
296
+ value: "codex",
297
+ label: `Codex ${pc.dim("— OpenAI Codex CLI (@openai/codex)")}`,
298
+ },
299
+ {
300
+ value: "openai-agents",
301
+ label: `OpenAI Agents ${pc.dim("— @openai/agents (OpenAI or any OpenAI-compatible endpoint)")}`,
302
+ },
303
+ ],
304
+ });
305
+ if (p.isCancel(backendSelection)) {
306
+ p.cancel("Cancelled.");
307
+ process.exit(0);
308
+ }
309
+ const backend = backendSelection as Config["backend"];
310
+
311
+ // ── Backend-specific config ──
312
+ let claudeBinary: string | undefined;
313
+ let codexApiKey: string | undefined;
314
+ let openaiApiKey: string | undefined;
315
+ let openaiBaseUrl: string | undefined;
316
+ let openaiApiMode: "responses" | "chat_completions" | undefined;
317
+
318
+ if (backend === "claude") {
319
+ const claudeBinaryInput = await p.text({
320
+ message: "Claude Code binary path",
321
+ placeholder: "leave empty for default (claude)",
322
+ initialValue: config.claudeBinary || "",
323
+ });
324
+ if (p.isCancel(claudeBinaryInput)) {
325
+ p.cancel("Cancelled.");
326
+ process.exit(0);
327
+ }
328
+ claudeBinary = (claudeBinaryInput as string).trim() || undefined;
329
+ } else if (backend === "codex") {
330
+ const keyInput = await p.text({
331
+ message: "Codex OpenAI API key",
332
+ placeholder:
333
+ "leave empty to use CODEX_API_KEY / TALON_CODEX_KEY env or `codex login` auth",
334
+ initialValue: config.codexApiKey || "",
335
+ });
336
+ if (p.isCancel(keyInput)) {
337
+ p.cancel("Cancelled.");
338
+ process.exit(0);
339
+ }
340
+ codexApiKey = (keyInput as string).trim() || undefined;
341
+ } else if (backend === "openai-agents") {
342
+ const keyInput = await p.text({
343
+ message:
344
+ "API key (OpenAI, OpenRouter, Azure, or whatever your endpoint requires)",
345
+ placeholder: "leave empty to use OPENAI_API_KEY env",
346
+ initialValue: config.openaiApiKey || "",
347
+ });
348
+ if (p.isCancel(keyInput)) {
349
+ p.cancel("Cancelled.");
350
+ process.exit(0);
351
+ }
352
+ openaiApiKey = (keyInput as string).trim() || undefined;
353
+
354
+ const baseUrlInput = await p.text({
355
+ message:
356
+ "Base URL " +
357
+ pc.dim(
358
+ "(leave empty for OpenAI direct; e.g. https://openrouter.ai/api/v1)",
359
+ ),
360
+ placeholder: "https://openrouter.ai/api/v1",
361
+ initialValue: config.openaiBaseUrl || "",
362
+ });
363
+ if (p.isCancel(baseUrlInput)) {
364
+ p.cancel("Cancelled.");
365
+ process.exit(0);
366
+ }
367
+ openaiBaseUrl = (baseUrlInput as string).trim() || undefined;
368
+
369
+ if (openaiBaseUrl) {
370
+ const modeSelection = await p.select({
371
+ message: "OpenAI API surface",
372
+ options: [
373
+ {
374
+ value: "chat_completions",
375
+ label: `Chat Completions ${pc.dim("— most third parties (OpenRouter, Ollama, LiteLLM, most Azure)")}`,
376
+ },
377
+ {
378
+ value: "responses",
379
+ label: `Responses ${pc.dim("— OpenAI native, requires proxy support")}`,
380
+ },
381
+ ],
382
+ initialValue: config.openaiApiMode ?? "chat_completions",
383
+ });
384
+ if (p.isCancel(modeSelection)) {
385
+ p.cancel("Cancelled.");
386
+ process.exit(0);
387
+ }
388
+ openaiApiMode = modeSelection as "responses" | "chat_completions";
389
+ }
390
+ }
391
+
392
+ // kilo / opencode need no extra prompts — bundled SDK + per-provider
393
+ // creds configured separately (kilo via `kilo login`, opencode via
394
+ // its own auth flow).
395
+
396
+ const newConfig: Config = {
397
+ frontend:
398
+ selectedFrontends.length === 1 ? selectedFrontends[0] : selectedFrontends,
399
+ backend,
400
+ botToken: selectedFrontends.includes("telegram") ? botToken : undefined,
401
+ claudeBinary,
402
+ codexApiKey,
403
+ openaiApiKey,
404
+ openaiBaseUrl,
405
+ openaiApiMode,
406
+ model: model as string,
407
+ concurrency: config.concurrency,
408
+ pulse: pulse as boolean,
409
+ pulseIntervalMs: config.pulseIntervalMs,
410
+ adminUserId: adminId ? parseInt(adminId, 10) || undefined : undefined,
411
+ apiId,
412
+ apiHash,
413
+ maxMessageLength: config.maxMessageLength,
414
+ plugins: config.plugins,
415
+ // Teams
416
+ teamsWebhookUrl: selectedFrontends.includes("teams")
417
+ ? teamsWebhookUrl
418
+ : undefined,
419
+ teamsWebhookSecret: selectedFrontends.includes("teams")
420
+ ? teamsWebhookSecret
421
+ : undefined,
422
+ teamsWebhookPort: selectedFrontends.includes("teams")
423
+ ? teamsWebhookPort
424
+ : undefined,
425
+ teamsBotDisplayName: selectedFrontends.includes("teams")
426
+ ? teamsBotDisplayName
427
+ : undefined,
428
+ // Discord — bot token + applicationId. Allowlists / admin IDs /
429
+ // mention vs channel-wide reply behaviour are left as defaults in
430
+ // the wizard; advanced users hand-edit talon.json.
431
+ discord:
432
+ selectedFrontends.includes("discord") &&
433
+ discordBotToken &&
434
+ discordApplicationId
435
+ ? {
436
+ ...config.discord,
437
+ botToken: discordBotToken,
438
+ applicationId: discordApplicationId,
439
+ }
440
+ : config.discord,
441
+ };
442
+
443
+ const s = p.spinner();
444
+ s.start("Saving configuration");
445
+ saveConfig(newConfig);
446
+ s.stop("Configuration saved");
447
+
448
+ p.outro(`Run ${pc.cyan(pc.bold("talon start"))} to launch Talon`);
449
+
450
+ if (selectedFrontends.includes("telegram") && apiId && apiHash) {
451
+ console.log(
452
+ ` ${pc.yellow("!")} Run ${pc.cyan("npx tsx src/login.ts")} to authenticate the userbot first.\n`,
453
+ );
454
+ }
455
+ }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * `talon status` — render the running instance's health, or a stopped summary
3
+ * pulled from the config file.
4
+ */
5
+
6
+ import pc from "picocolors";
7
+ import { existsSync } from "node:fs";
8
+ import { findRunningInstance } from "../core/daemon/discovery.js";
9
+ import { printBanner, loadConfig } from "./config.js";
10
+ import { CONFIG_FILE } from "./context.js";
11
+
12
+ export function formatUptime(seconds: number): string {
13
+ if (seconds < 60) return `${seconds}s`;
14
+ if (seconds < 3600) return `${Math.floor(seconds / 60)}m ${seconds % 60}s`;
15
+ return `${Math.floor(seconds / 3600)}h ${Math.floor((seconds % 3600) / 60)}m`;
16
+ }
17
+
18
+ export async function showStatus(): Promise<void> {
19
+ printBanner();
20
+ const instance = await findRunningInstance();
21
+
22
+ if (instance?.health) {
23
+ const h = instance.health;
24
+ const ok = h.ok as boolean;
25
+ console.log(
26
+ ` ${ok ? pc.green("●") : pc.yellow("●")} ${pc.bold("Running")} ${ok ? pc.green("healthy") : pc.yellow("degraded")}`,
27
+ );
28
+ console.log();
29
+ console.log(` ${pc.dim("PID")} ${instance.pid}`);
30
+ if (instance.port)
31
+ console.log(` ${pc.dim("Gateway")} 127.0.0.1:${instance.port}`);
32
+ console.log(
33
+ ` ${pc.dim("Uptime")} ${formatUptime(h.uptime as number)}`,
34
+ );
35
+ console.log(` ${pc.dim("Memory")} ${h.memory} MB`);
36
+ console.log(` ${pc.dim("Sessions")} ${h.sessions}`);
37
+ console.log(` ${pc.dim("Messages")} ${h.messages}`);
38
+ console.log(` ${pc.dim("Queue")} ${h.queue} pending`);
39
+ console.log(` ${pc.dim("Errors")} ${h.errors}`);
40
+ console.log(` ${pc.dim("Last active")} ${h.lastActivity}\n`);
41
+ return;
42
+ }
43
+
44
+ if (instance) {
45
+ console.log(
46
+ ` ${pc.yellow("●")} ${pc.bold("Running")} (PID ${instance.pid}) ${pc.dim("— health endpoint not reachable, possibly still starting")}`,
47
+ );
48
+ console.log(` Check ${pc.cyan("talon logs")} for details.\n`);
49
+ return;
50
+ }
51
+
52
+ console.log(` ${pc.red("●")} ${pc.bold("Stopped")}\n`);
53
+ if (existsSync(CONFIG_FILE)) {
54
+ const config = loadConfig();
55
+ const fes = Array.isArray(config.frontend)
56
+ ? config.frontend
57
+ : [config.frontend];
58
+ console.log(` ${pc.dim("Frontend")} ${fes.join(", ")}`);
59
+ if (fes.includes("telegram"))
60
+ console.log(
61
+ ` ${pc.dim("Token")} ${config.botToken ? pc.green("configured") : pc.red("not set")}`,
62
+ );
63
+ if (fes.includes("teams"))
64
+ console.log(
65
+ ` ${pc.dim("Teams")} ${config.teamsWebhookUrl ? pc.green("configured") : pc.red("not set")}`,
66
+ );
67
+ console.log(` ${pc.dim("Model")} ${config.model}`);
68
+ console.log(` ${pc.dim("Config")} ${pc.dim(CONFIG_FILE)}\n`);
69
+ console.log(
70
+ ` Start with ${pc.cyan("talon start")} or ${pc.cyan("talon chat")}\n`,
71
+ );
72
+ } else {
73
+ console.log(` Run ${pc.cyan("talon setup")} to get started.\n`);
74
+ }
75
+ }