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,105 @@
1
+ /**
2
+ * CLI config model + load/save/format helpers, plus the banner.
3
+ *
4
+ * This is the on-disk `talon.json` shape as the CLI sees it; the runtime has
5
+ * its own richer config type in util/config.ts.
6
+ */
7
+
8
+ import pc from "picocolors";
9
+ import { existsSync, readFileSync, mkdirSync } from "node:fs";
10
+ import writeFileAtomic from "write-file-atomic";
11
+ import { dirs } from "../util/paths.js";
12
+ import { CONFIG_FILE } from "./context.js";
13
+
14
+ export function printBanner(): void {
15
+ console.log();
16
+ console.log(` ${pc.bold(pc.cyan("🦅 Talon"))}`);
17
+ console.log(` ${pc.dim("Agentic AI harness")}`);
18
+ console.log();
19
+ }
20
+
21
+ export type Config = {
22
+ frontend: string | string[];
23
+ /** Active backend (`claude` / `kilo` / `opencode` / `codex` / `openai-agents`). */
24
+ backend?: "claude" | "kilo" | "opencode" | "codex" | "openai-agents";
25
+ botToken?: string;
26
+ claudeBinary?: string;
27
+ /** Codex-specific OpenAI API key. */
28
+ codexApiKey?: string;
29
+ /** OpenAI API key — used by OpenAI Agents and legacy Codex config. */
30
+ openaiApiKey?: string;
31
+ /** OpenAI-compatible base URL — OpenRouter, Azure, Ollama, LiteLLM, etc. */
32
+ openaiBaseUrl?: string;
33
+ /** OpenAI API surface — "responses" (default) or "chat_completions" (most third parties). */
34
+ openaiApiMode?: "responses" | "chat_completions";
35
+ model: string;
36
+ concurrency: number;
37
+ pulse: boolean;
38
+ pulseIntervalMs: number;
39
+ adminUserId?: number;
40
+ apiId?: number;
41
+ apiHash?: string;
42
+ maxMessageLength: number;
43
+ plugins?: unknown[];
44
+ // Teams
45
+ teamsWebhookUrl?: string;
46
+ teamsWebhookSecret?: string;
47
+ teamsWebhookPort?: number;
48
+ teamsBotDisplayName?: string;
49
+ // Discord
50
+ discord?: {
51
+ botToken: string;
52
+ applicationId: string;
53
+ allowedUsers?: string[];
54
+ allowedGuilds?: string[];
55
+ allowedChannels?: string[];
56
+ adminUserIds?: string[];
57
+ [key: string]: unknown;
58
+ };
59
+ };
60
+
61
+ export const DEFAULTS: Config = {
62
+ frontend: "telegram",
63
+ model: "default",
64
+ concurrency: 1,
65
+ pulse: true,
66
+ pulseIntervalMs: 300000,
67
+ maxMessageLength: 4000,
68
+ };
69
+
70
+ export function loadConfig(): Config {
71
+ try {
72
+ if (existsSync(CONFIG_FILE)) {
73
+ return { ...DEFAULTS, ...JSON.parse(readFileSync(CONFIG_FILE, "utf-8")) };
74
+ }
75
+ } catch {
76
+ /* corrupt */
77
+ }
78
+ return { ...DEFAULTS };
79
+ }
80
+
81
+ export function saveConfig(config: Config): void {
82
+ if (!existsSync(dirs.root)) mkdirSync(dirs.root, { recursive: true });
83
+ const clean = Object.fromEntries(
84
+ Object.entries(config).filter(([, v]) => v !== undefined),
85
+ );
86
+ writeFileAtomic.sync(CONFIG_FILE, JSON.stringify(clean, null, 2) + "\n");
87
+ }
88
+
89
+ export function maskToken(token: string | undefined): string {
90
+ if (!token || token.length < 10) return pc.red("not set");
91
+ return pc.green(token.slice(0, 8) + "..." + token.slice(-4));
92
+ }
93
+
94
+ export function isConfigured(config: Config): boolean {
95
+ const fes = Array.isArray(config.frontend)
96
+ ? config.frontend
97
+ : [config.frontend];
98
+ return fes.every((fe) => {
99
+ if (fe === "telegram") return !!config.botToken;
100
+ if (fe === "terminal") return true;
101
+ if (fe === "teams") return !!config.teamsWebhookUrl;
102
+ if (fe === "discord") return !!config.discord?.botToken;
103
+ return false;
104
+ });
105
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Shared CLI context — package root and well-known file paths.
3
+ *
4
+ * PKG_ROOT is resolved from this file's own location (src/cli/) two levels up
5
+ * to the package root, so it's independent of the process cwd — matching the
6
+ * original `src/cli.ts` derivation (which sat one level up, in src/).
7
+ */
8
+
9
+ import { dirname, resolve } from "node:path";
10
+ import { files as pathFiles } from "../util/paths.js";
11
+
12
+ // Bun-compiled binaries embed the source tree — import.meta.dirname points
13
+ // into the virtual FS (prefix ~BUN / $bunfs) which has no real disk path.
14
+ // Fall back to the directory containing the executable instead.
15
+ const isBunEmbedded =
16
+ (import.meta.dirname ?? "").includes("~BUN") ||
17
+ (import.meta.dirname ?? "").includes("$bunfs");
18
+
19
+ export const PKG_ROOT = isBunEmbedded
20
+ ? dirname(process.execPath)
21
+ : resolve(import.meta.dirname ?? process.cwd(), "..", "..");
22
+ export const CONFIG_FILE = pathFiles.config;
23
+ export const LOG_FILE = pathFiles.log;
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Daemon management — renders the outcomes of start/stop/restart.
3
+ *
4
+ * Lifecycle logic lives in core/daemon/ (pidfile, discovery, control);
5
+ * this module only renders the outcomes.
6
+ */
7
+
8
+ import pc from "picocolors";
9
+ import {
10
+ startDaemon,
11
+ stopDaemon,
12
+ restartDaemon,
13
+ type StartOutcome,
14
+ type StopOutcome,
15
+ } from "../core/daemon/control.js";
16
+ import { PKG_ROOT } from "./context.js";
17
+
18
+ function renderStartOutcome(result: StartOutcome): void {
19
+ if (result.ok) {
20
+ const port = result.port ? `, gateway :${result.port}` : "";
21
+ console.log(` ${pc.green("●")} Talon started (PID ${result.pid}${port})`);
22
+ console.log(` ${pc.dim("Logs:")} talon logs`);
23
+ console.log(` ${pc.dim("Stop:")} talon stop\n`);
24
+ return;
25
+ }
26
+ switch (result.reason) {
27
+ case "already-running": {
28
+ const inst = result.instance;
29
+ const port = inst.port ? `, gateway :${inst.port}` : "";
30
+ console.log(
31
+ ` ${pc.yellow("!")} Talon is already running (PID ${inst.pid}${port})`,
32
+ );
33
+ if (inst.pidfileStale) {
34
+ console.log(
35
+ ` ${pc.dim("The PID file was stale — repaired from the live instance.")}`,
36
+ );
37
+ }
38
+ console.log(
39
+ ` Use ${pc.cyan("talon restart")} to restart, or ${pc.cyan("talon stop")} to stop.\n`,
40
+ );
41
+ return;
42
+ }
43
+ case "spawn-failed":
44
+ console.log(
45
+ ` ${pc.red("✖")} Failed to start Talon${result.detail ? pc.dim(` — ${result.detail}`) : ""}\n`,
46
+ );
47
+ return;
48
+ case "exited-early":
49
+ console.log(` ${pc.red("✖")} Talon ${result.detail} during startup`);
50
+ console.log(` Check ${pc.cyan("talon logs")} for details.\n`);
51
+ return;
52
+ case "boot-timeout":
53
+ console.log(
54
+ ` ${pc.yellow("!")} Talon was spawned but has not reported healthy yet.`,
55
+ );
56
+ console.log(
57
+ ` It may still be starting — check ${pc.cyan("talon status")} and ${pc.cyan("talon logs")}.\n`,
58
+ );
59
+ return;
60
+ }
61
+ }
62
+
63
+ function renderStopOutcome(result: StopOutcome): void {
64
+ if (result.stopped) {
65
+ const how =
66
+ result.method === "http"
67
+ ? "graceful"
68
+ : result.method === "sigterm"
69
+ ? "SIGTERM"
70
+ : "SIGKILL";
71
+ console.log(` ${pc.red("●")} Talon stopped (PID ${result.pid}, ${how})\n`);
72
+ return;
73
+ }
74
+ if (result.reason === "not-running") {
75
+ console.log(` ${pc.dim("●")} Talon is not running\n`);
76
+ return;
77
+ }
78
+ console.log(
79
+ ` ${pc.red("✖")} Could not stop Talon (PID ${result.pid}) — the process did not exit\n`,
80
+ );
81
+ }
82
+
83
+ export async function daemonStart(): Promise<void> {
84
+ renderStartOutcome(await startDaemon({ pkgRoot: PKG_ROOT }));
85
+ }
86
+
87
+ export async function daemonStop(): Promise<void> {
88
+ renderStopOutcome(await stopDaemon());
89
+ }
90
+
91
+ export async function daemonRestart(): Promise<void> {
92
+ const { stop, start } = await restartDaemon({ pkgRoot: PKG_ROOT });
93
+ renderStopOutcome(stop);
94
+ renderStartOutcome(start);
95
+ }
@@ -0,0 +1,53 @@
1
+ /**
2
+ * `talon doctor` — environment + native-module checks, plus whether the bot
3
+ * is currently running.
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
+ const DOCTOR_ICONS: Record<string, string> = {
13
+ ok: pc.green("✓"),
14
+ warn: pc.yellow("!"),
15
+ fail: pc.red("✗"),
16
+ info: pc.dim("-"),
17
+ };
18
+
19
+ export async function runDoctor(): Promise<void> {
20
+ printBanner();
21
+ console.log(` ${pc.bold("Environment check")}\n`);
22
+ const { collectDoctorReport } = await import("../core/doctor.js");
23
+ const hasConfigFile = existsSync(CONFIG_FILE);
24
+ const report = await collectDoctorReport({
25
+ config: hasConfigFile ? loadConfig() : undefined,
26
+ hasConfigFile,
27
+ });
28
+ for (const check of report.checks) {
29
+ const detail = check.detail ? ` ${pc.dim(`(${check.detail})`)}` : "";
30
+ console.log(` ${DOCTOR_ICONS[check.status]} ${check.label}${detail}`);
31
+ }
32
+ // Native plane, one line per embedded module with provenance.
33
+ for (const mod of report.native) {
34
+ const size = mod.sizeBytes
35
+ ? ` · ${(mod.sizeBytes / 1024).toFixed(1)} KB`
36
+ : "";
37
+ const note = mod.note ? ` ${pc.dim(`(${mod.note})`)}` : "";
38
+ console.log(
39
+ ` ${mod.ok ? pc.green("✓") : pc.red("✗")} Native: ${mod.name} ${pc.dim(`${mod.language} → ${mod.target}${size}`)}${note}`,
40
+ );
41
+ }
42
+ const instance = await findRunningInstance();
43
+ if (instance) {
44
+ console.log(` ${pc.green("✓")} Bot is running (PID ${instance.pid})`);
45
+ } else {
46
+ console.log(` ${pc.dim("-")} Bot is not running`);
47
+ }
48
+ console.log(
49
+ report.issues === 0
50
+ ? `\n ${pc.green("All checks passed.")}\n`
51
+ : `\n ${pc.yellow(`${report.issues} issue(s) found.`)}\n`,
52
+ );
53
+ }
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Talon CLI — interactive setup, management, and monitoring.
3
+ *
4
+ * The entry point (`src/cli.ts`) handles the must-run-first hidden subcommand
5
+ * dispatch, then delegates to `runCli()` here. Each user-facing command lives
6
+ * in its own module:
7
+ *
8
+ * - `config` — config model + load/save/format + banner
9
+ * - `setup` — guided setup wizard
10
+ * - `status` — health / stats summary
11
+ * - `config-view` — print + edit configuration
12
+ * - `logs` — tail the log file
13
+ * - `doctor` — environment + native-module checks
14
+ * - `chat` — terminal chat mode
15
+ * - `daemon` — start/stop/restart outcome rendering
16
+ * - `menu` — interactive main menu (no-subcommand default)
17
+ */
18
+
19
+ import pc from "picocolors";
20
+ // Imported (not read from disk) so `--version` works in a standalone
21
+ // `bun build --compile` binary, which has no package.json on disk — bun
22
+ // inlines the JSON at compile time; tsx/node resolve it from the package.
23
+ import pkg from "../../package.json" with { type: "json" };
24
+ import { PKG_ROOT } from "./context.js";
25
+ import { printBanner } from "./config.js";
26
+ import { runSetup } from "./setup.js";
27
+ import { showStatus } from "./status.js";
28
+ import { viewConfig } from "./config-view.js";
29
+ import { tailLogs } from "./logs.js";
30
+ import { runDoctor } from "./doctor.js";
31
+ import { startChat } from "./chat.js";
32
+ import { daemonStart, daemonStop, daemonRestart } from "./daemon.js";
33
+ import { mainMenu } from "./menu.js";
34
+
35
+ export * from "./context.js";
36
+ export * from "./config.js";
37
+ export { runSetup } from "./setup.js";
38
+ export { showStatus, formatUptime } from "./status.js";
39
+ export { viewConfig } from "./config-view.js";
40
+ export { tailLogs, formatLogLine } from "./logs.js";
41
+ export { runDoctor } from "./doctor.js";
42
+ export { startChat } from "./chat.js";
43
+ export { daemonStart, daemonStop, daemonRestart } from "./daemon.js";
44
+ export { mainMenu } from "./menu.js";
45
+
46
+ /** Every dispatchable subcommand — the unknown-command suggester's vocabulary. */
47
+ const CLI_COMMANDS = [
48
+ "setup",
49
+ "status",
50
+ "config",
51
+ "logs",
52
+ "start",
53
+ "stop",
54
+ "restart",
55
+ "run",
56
+ "chat",
57
+ "doctor",
58
+ ];
59
+
60
+ /** Route a `talon <command>` invocation. Called by the entry point. */
61
+ export async function runCli(): Promise<void> {
62
+ const command = process.argv[2];
63
+ switch (command) {
64
+ case "setup":
65
+ runSetup();
66
+ break;
67
+ case "status":
68
+ showStatus();
69
+ break;
70
+ case "config":
71
+ viewConfig();
72
+ break;
73
+ case "logs":
74
+ tailLogs();
75
+ break;
76
+ case "start":
77
+ printBanner();
78
+ await daemonStart();
79
+ break;
80
+ case "stop":
81
+ printBanner();
82
+ await daemonStop();
83
+ break;
84
+ case "restart":
85
+ printBanner();
86
+ await daemonRestart();
87
+ break;
88
+ case "run":
89
+ process.chdir(PKG_ROOT);
90
+ import("../index.js");
91
+ break;
92
+ case "chat":
93
+ process.chdir(PKG_ROOT);
94
+ startChat();
95
+ break;
96
+ case "doctor":
97
+ runDoctor();
98
+ break;
99
+ case "--version":
100
+ case "-v": {
101
+ console.log(pkg.version);
102
+ break;
103
+ }
104
+ case "--help":
105
+ case "-h":
106
+ printBanner();
107
+ console.log(" Usage: talon [command]\n");
108
+ console.log(" Commands:");
109
+ console.log(` ${pc.cyan("setup")} Guided setup wizard`);
110
+ console.log(` ${pc.cyan("start")} Start as background daemon`);
111
+ console.log(` ${pc.cyan("stop")} Stop the daemon`);
112
+ console.log(` ${pc.cyan("restart")} Restart the daemon`);
113
+ console.log(` ${pc.cyan("run")} Run in foreground (attached)`);
114
+ console.log(` ${pc.cyan("chat")} Terminal chat mode`);
115
+ console.log(` ${pc.cyan("status")} Show bot health`);
116
+ console.log(` ${pc.cyan("config")} View/edit configuration`);
117
+ console.log(` ${pc.cyan("logs")} Tail log file`);
118
+ console.log(` ${pc.cyan("doctor")} Validate environment`);
119
+ console.log(` ${pc.cyan("--version")} Print the package version`);
120
+ console.log();
121
+ console.log(
122
+ ` Run ${pc.cyan("talon")} with no args for interactive menu.\n`,
123
+ );
124
+ break;
125
+ case undefined:
126
+ mainMenu();
127
+ break;
128
+ default: {
129
+ // "did you mean ...?" via the C similarity core (native/strsim-c).
130
+ const { closestMatch } = await import("../native/strsim.js");
131
+ const suggestion = closestMatch(command, CLI_COMMANDS);
132
+ const hint = suggestion
133
+ ? `Did you mean ${pc.cyan(`talon ${suggestion.value}`)}?`
134
+ : `Run ${pc.cyan("talon --help")} for usage.`;
135
+ console.error(` Unknown command: ${command}\n ${hint}\n`);
136
+ process.exit(1);
137
+ }
138
+ }
139
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * `talon logs` — pretty-print the last lines of the JSON log file and then
3
+ * tail it live.
4
+ */
5
+
6
+ import pc from "picocolors";
7
+ import { existsSync, readFileSync, watchFile } from "node:fs";
8
+ import { printBanner } from "./config.js";
9
+ import { LOG_FILE } from "./context.js";
10
+
11
+ const LEVEL_LABELS: Record<number, string> = {
12
+ 10: pc.dim("TRC"),
13
+ 20: pc.dim("DBG"),
14
+ 30: pc.blue("INF"),
15
+ 40: pc.yellow("WRN"),
16
+ 50: pc.red("ERR"),
17
+ 60: pc.bgRed(pc.white("FTL")),
18
+ };
19
+
20
+ export function formatLogLine(line: string): string {
21
+ try {
22
+ const obj = JSON.parse(line);
23
+ const level = LEVEL_LABELS[obj.level as number] ?? pc.dim("???");
24
+ const time = pc.dim(
25
+ new Date(obj.time as number).toTimeString().slice(0, 8),
26
+ );
27
+ const comp = pc.cyan(((obj.component as string) ?? "?").padEnd(10));
28
+ return ` ${time} ${level} ${comp} ${obj.msg}${obj.err ? pc.red(` (${obj.err})`) : ""}`;
29
+ } catch {
30
+ return ` ${line}`;
31
+ }
32
+ }
33
+
34
+ export async function tailLogs(): Promise<void> {
35
+ printBanner();
36
+ if (!existsSync(LOG_FILE)) {
37
+ console.log(
38
+ ` No log file. Start the bot first: ${pc.cyan("talon start")}\n`,
39
+ );
40
+ return;
41
+ }
42
+ console.log(
43
+ ` ${pc.dim("Tailing")} ${pc.dim(LOG_FILE)}\n ${pc.dim("Press Ctrl+C to stop")}\n`,
44
+ );
45
+ const content = readFileSync(LOG_FILE, "utf-8");
46
+ const lines = content.trim().split("\n");
47
+ for (const line of lines.slice(-30)) console.log(formatLogLine(line));
48
+ let lastSize = lines.length;
49
+ watchFile(LOG_FILE, { interval: 500 }, () => {
50
+ try {
51
+ const nl = readFileSync(LOG_FILE, "utf-8").trim().split("\n");
52
+ for (let i = lastSize; i < nl.length; i++)
53
+ console.log(formatLogLine(nl[i]));
54
+ lastSize = nl.length;
55
+ } catch {
56
+ /* ignore */
57
+ }
58
+ });
59
+ await new Promise(() => {});
60
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Interactive main menu — shown when `talon` runs with no subcommand. Runs
3
+ * setup on first launch, otherwise offers start/stop/chat/status/config/etc.
4
+ */
5
+
6
+ import * as p from "@clack/prompts";
7
+ import pc from "picocolors";
8
+ import { existsSync } from "node:fs";
9
+ import { findRunningInstance } from "../core/daemon/discovery.js";
10
+ import { printBanner, loadConfig, isConfigured } from "./config.js";
11
+ import { CONFIG_FILE, PKG_ROOT } from "./context.js";
12
+ import { runSetup } from "./setup.js";
13
+ import { showStatus } from "./status.js";
14
+ import { viewConfig } from "./config-view.js";
15
+ import { tailLogs } from "./logs.js";
16
+ import { startChat } from "./chat.js";
17
+ import { daemonStart, daemonStop, daemonRestart } from "./daemon.js";
18
+
19
+ export async function mainMenu(): Promise<void> {
20
+ printBanner();
21
+ if (!existsSync(CONFIG_FILE) || !isConfigured(loadConfig())) {
22
+ p.intro(pc.inverse(" Welcome to Talon "));
23
+ p.note(
24
+ "Talon is an agentic AI harness.\nSupports Telegram and Terminal.\nLet's get you set up.",
25
+ "First time?",
26
+ );
27
+ await runSetup();
28
+ return;
29
+ }
30
+
31
+ const running = (await findRunningInstance()) !== null;
32
+ const config = loadConfig();
33
+ const statusDot = running
34
+ ? `${pc.green("●")} running`
35
+ : `${pc.red("●")} stopped`;
36
+ const fes = Array.isArray(config.frontend)
37
+ ? config.frontend
38
+ : [config.frontend];
39
+ const frontendLabel = fes
40
+ .map((f) =>
41
+ f === "telegram"
42
+ ? "Telegram"
43
+ : f === "teams"
44
+ ? "Teams"
45
+ : f === "discord"
46
+ ? "Discord"
47
+ : "Terminal",
48
+ )
49
+ .join(" + ");
50
+
51
+ const action = await p.select({
52
+ message: `Talon ${statusDot} ${pc.dim(`(${frontendLabel})`)}`,
53
+ options: [
54
+ ...(!running
55
+ ? [
56
+ {
57
+ value: "start" as const,
58
+ label: `Start ${frontendLabel}`,
59
+ hint: "background daemon",
60
+ },
61
+ ]
62
+ : []),
63
+ ...(running
64
+ ? [
65
+ { value: "restart" as const, label: "Restart" },
66
+ { value: "stop" as const, label: "Stop" },
67
+ ]
68
+ : []),
69
+ { value: "chat", label: "Chat in terminal", hint: "talk to Talon here" },
70
+ { value: "status", label: "Status", hint: "health and stats" },
71
+ { value: "config", label: "Config", hint: "view or edit" },
72
+ { value: "logs", label: "Logs", hint: "tail live" },
73
+ { value: "setup", label: "Setup", hint: "re-run wizard" },
74
+ ],
75
+ });
76
+ if (p.isCancel(action)) process.exit(0);
77
+ switch (action) {
78
+ case "start":
79
+ await daemonStart();
80
+ break;
81
+ case "stop":
82
+ daemonStop();
83
+ break;
84
+ case "restart":
85
+ await daemonRestart();
86
+ break;
87
+ case "chat":
88
+ process.chdir(PKG_ROOT);
89
+ await startChat();
90
+ break;
91
+ case "status":
92
+ await showStatus();
93
+ break;
94
+ case "config":
95
+ await viewConfig();
96
+ break;
97
+ case "logs":
98
+ await tailLogs();
99
+ break;
100
+ case "setup":
101
+ await runSetup();
102
+ break;
103
+ }
104
+ }