@fastagent-sh/fastagent 0.21.1 → 0.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (388) hide show
  1. package/README.md +9 -12
  2. package/dist/agent.d.ts +24 -37
  3. package/dist/agent.js +7 -15
  4. package/dist/atomic-write.d.ts +13 -17
  5. package/dist/atomic-write.js +18 -29
  6. package/dist/bind.d.ts +12 -22
  7. package/dist/bind.js +18 -27
  8. package/dist/channel.d.ts +11 -33
  9. package/dist/channels/agentcore-limits.d.ts +2 -13
  10. package/dist/channels/agentcore-limits.js +2 -13
  11. package/dist/channels/agentcore-protocol.d.ts +67 -58
  12. package/dist/channels/agentcore-protocol.js +23 -15
  13. package/dist/channels/agentcore-service.d.ts +19 -33
  14. package/dist/channels/agentcore-service.js +176 -59
  15. package/dist/channels/agentcore.d.ts +39 -33
  16. package/dist/channels/agentcore.js +90 -224
  17. package/dist/channels/body.d.ts +15 -2
  18. package/dist/channels/body.js +24 -2
  19. package/dist/channels/busy.d.ts +1 -21
  20. package/dist/channels/busy.js +2 -39
  21. package/dist/channels/control.d.ts +17 -62
  22. package/dist/channels/control.js +74 -182
  23. package/dist/channels/define-channel.d.ts +39 -0
  24. package/dist/channels/define-channel.js +9 -0
  25. package/dist/channels/discover.d.ts +10 -31
  26. package/dist/channels/discover.js +37 -31
  27. package/dist/channels/feishu/bootstrap-token.d.ts +1 -8
  28. package/dist/channels/feishu/bootstrap-token.js +7 -23
  29. package/dist/channels/feishu/card.d.ts +14 -28
  30. package/dist/channels/feishu/card.js +16 -30
  31. package/dist/channels/feishu/cloud.d.ts +1 -5
  32. package/dist/channels/feishu/context-buffer.d.ts +4 -23
  33. package/dist/channels/feishu/context-buffer.js +8 -31
  34. package/dist/channels/feishu/crypto.d.ts +10 -5
  35. package/dist/channels/feishu/crypto.js +12 -19
  36. package/dist/channels/feishu/feishu-api.d.ts +2 -1
  37. package/dist/channels/feishu/feishu-api.js +5 -4
  38. package/dist/channels/feishu/feishu.d.ts +4 -10
  39. package/dist/channels/feishu/feishu.js +113 -227
  40. package/dist/channels/feishu/invoke-turn.d.ts +5 -4
  41. package/dist/channels/feishu/invoke-turn.js +36 -54
  42. package/dist/channels/feishu/model.d.ts +4 -21
  43. package/dist/channels/feishu/model.js +1 -8
  44. package/dist/channels/feishu/normalize.d.ts +2 -10
  45. package/dist/channels/feishu/normalize.js +7 -42
  46. package/dist/channels/feishu/parse.d.ts +9 -29
  47. package/dist/channels/feishu/parse.js +8 -26
  48. package/dist/channels/feishu/preview.d.ts +12 -14
  49. package/dist/channels/feishu/preview.js +108 -207
  50. package/dist/channels/feishu/register-app.d.ts +8 -23
  51. package/dist/channels/feishu/register-app.js +7 -20
  52. package/dist/channels/feishu/register-webhook.d.ts +2 -9
  53. package/dist/channels/feishu/register-webhook.js +9 -33
  54. package/dist/channels/feishu/scaffold/channel.ts +27 -19
  55. package/dist/channels/feishu/scaffold/channel.websocket.ts +31 -0
  56. package/dist/channels/feishu/setup-mode.d.ts +11 -36
  57. package/dist/channels/feishu/setup-mode.js +7 -26
  58. package/dist/channels/feishu/ws-ingress.d.ts +1 -2
  59. package/dist/channels/feishu/ws-ingress.js +6 -8
  60. package/dist/channels/http.d.ts +15 -15
  61. package/dist/channels/http.js +19 -9
  62. package/dist/channels/kit/attachment-path.d.ts +4 -5
  63. package/dist/channels/kit/attachment-path.js +10 -34
  64. package/dist/channels/kit/context-buffer.d.ts +14 -21
  65. package/dist/channels/kit/context-buffer.js +25 -38
  66. package/dist/channels/kit/delivery.d.ts +35 -0
  67. package/dist/channels/kit/delivery.js +129 -0
  68. package/dist/channels/kit/event-stream.d.ts +5 -0
  69. package/dist/channels/kit/event-stream.js +29 -0
  70. package/dist/channels/kit/invoke-turn-kit.d.ts +53 -26
  71. package/dist/channels/kit/invoke-turn-kit.js +89 -32
  72. package/dist/channels/kit/preview-kit.d.ts +18 -72
  73. package/dist/channels/kit/preview-kit.js +22 -88
  74. package/dist/channels/kit/signature.d.ts +3 -9
  75. package/dist/channels/kit/signature.js +3 -9
  76. package/dist/channels/kit/state.d.ts +1 -2
  77. package/dist/channels/kit/state.js +5 -14
  78. package/dist/channels/kit/stop-command.d.ts +1 -2
  79. package/dist/channels/kit/stop-command.js +6 -9
  80. package/dist/channels/kit/tasks.d.ts +1 -1
  81. package/dist/channels/kit/tasks.js +8 -21
  82. package/dist/channels/kit/text.d.ts +2 -16
  83. package/dist/channels/kit/text.js +23 -31
  84. package/dist/channels/kit/thread-participants.d.ts +4 -17
  85. package/dist/channels/kit/thread-participants.js +8 -55
  86. package/dist/channels/kit/transport.d.ts +26 -0
  87. package/dist/channels/kit/transport.js +20 -0
  88. package/dist/channels/kit/turn-queue.d.ts +7 -11
  89. package/dist/channels/kit/turn-queue.js +21 -39
  90. package/dist/channels/kit/turn-runner.d.ts +32 -18
  91. package/dist/channels/kit/turn-runner.js +98 -53
  92. package/dist/channels/kit/turn-store.d.ts +32 -32
  93. package/dist/channels/kit/turn-store.js +45 -88
  94. package/dist/channels/lark/lark.d.ts +1 -5
  95. package/dist/channels/lark/onboard.d.ts +3 -12
  96. package/dist/channels/lark/onboard.js +3 -13
  97. package/dist/channels/lark/scaffold/channel.ts +27 -19
  98. package/dist/channels/lark/scaffold/channel.websocket.ts +31 -0
  99. package/dist/channels/registration.d.ts +9 -35
  100. package/dist/channels/registration.js +6 -37
  101. package/dist/channels/secret.js +2 -5
  102. package/dist/channels/serve.d.ts +47 -44
  103. package/dist/channels/serve.js +165 -101
  104. package/dist/channels/slack/config-api.d.ts +4 -27
  105. package/dist/channels/slack/config-api.js +5 -34
  106. package/dist/channels/slack/context-buffer.d.ts +2 -3
  107. package/dist/channels/slack/context-buffer.js +5 -5
  108. package/dist/channels/slack/invoke-turn.d.ts +3 -1
  109. package/dist/channels/slack/invoke-turn.js +25 -34
  110. package/dist/channels/slack/manifest.js +1 -3
  111. package/dist/channels/slack/model.d.ts +1 -2
  112. package/dist/channels/slack/model.js +1 -1
  113. package/dist/channels/slack/onboard.d.ts +4 -3
  114. package/dist/channels/slack/onboard.js +8 -11
  115. package/dist/channels/slack/onboarding-state.d.ts +3 -5
  116. package/dist/channels/slack/onboarding-state.js +9 -6
  117. package/dist/channels/slack/parse.d.ts +4 -13
  118. package/dist/channels/slack/parse.js +7 -28
  119. package/dist/channels/slack/preview.d.ts +12 -2
  120. package/dist/channels/slack/preview.js +292 -269
  121. package/dist/channels/slack/reaction.d.ts +11 -3
  122. package/dist/channels/slack/reaction.js +19 -8
  123. package/dist/channels/slack/register-webhook.js +4 -7
  124. package/dist/channels/slack/scaffold/channel.ts +20 -13
  125. package/dist/channels/slack/scaffold/slack-send.ts +2 -2
  126. package/dist/channels/slack/setup-server.d.ts +1 -5
  127. package/dist/channels/slack/setup-server.js +1 -5
  128. package/dist/channels/slack/shared-api.d.ts +1 -4
  129. package/dist/channels/slack/shared-api.js +2 -13
  130. package/dist/channels/slack/slack-api.d.ts +2 -1
  131. package/dist/channels/slack/slack-api.js +6 -4
  132. package/dist/channels/slack/slack.d.ts +11 -14
  133. package/dist/channels/slack/slack.js +121 -122
  134. package/dist/channels/sse.d.ts +1 -1
  135. package/dist/channels/sse.js +1 -1
  136. package/dist/channels/telegram/context-buffer.d.ts +7 -22
  137. package/dist/channels/telegram/context-buffer.js +6 -23
  138. package/dist/channels/telegram/invoke-turn.d.ts +7 -7
  139. package/dist/channels/telegram/invoke-turn.js +24 -43
  140. package/dist/channels/telegram/parse.d.ts +24 -51
  141. package/dist/channels/telegram/parse.js +32 -84
  142. package/dist/channels/telegram/preview.d.ts +10 -1
  143. package/dist/channels/telegram/preview.js +79 -100
  144. package/dist/channels/telegram/register-webhook.js +5 -23
  145. package/dist/channels/telegram/scaffold/channel.ts +25 -18
  146. package/dist/channels/telegram/scaffold/telegram-send.ts +6 -4
  147. package/dist/channels/telegram/telegram-api.d.ts +4 -3
  148. package/dist/channels/telegram/telegram-api.js +9 -7
  149. package/dist/channels/telegram/telegram.d.ts +4 -18
  150. package/dist/channels/telegram/telegram.js +38 -94
  151. package/dist/channels/telegram/turn-store.d.ts +11 -14
  152. package/dist/channels/telegram/turn-store.js +8 -6
  153. package/dist/channels/wait-health.d.ts +4 -6
  154. package/dist/channels/wait-health.js +10 -14
  155. package/dist/cli/add-feishu.d.ts +2 -12
  156. package/dist/cli/add-feishu.js +24 -71
  157. package/dist/cli/add-slack.d.ts +5 -3
  158. package/dist/cli/add-slack.js +53 -76
  159. package/dist/cli/auth-view.d.ts +2 -16
  160. package/dist/cli/auth-view.js +2 -16
  161. package/dist/cli/commands/add.js +25 -40
  162. package/dist/cli/commands/chat.d.ts +0 -1
  163. package/dist/cli/commands/chat.js +5 -6
  164. package/dist/cli/commands/deploy/agentcore.js +60 -65
  165. package/dist/cli/commands/deploy/docker.js +50 -23
  166. package/dist/cli/commands/deploy/fly.js +23 -61
  167. package/dist/cli/commands/deploy/railway.js +23 -18
  168. package/dist/cli/commands/deploy/shared.d.ts +38 -57
  169. package/dist/cli/commands/deploy/shared.js +40 -59
  170. package/dist/cli/commands/deploy.d.ts +10 -27
  171. package/dist/cli/commands/deploy.js +38 -60
  172. package/dist/cli/commands/destroy.d.ts +4 -0
  173. package/dist/cli/commands/destroy.js +56 -0
  174. package/dist/cli/commands/dev.d.ts +2 -1
  175. package/dist/cli/commands/dev.js +20 -23
  176. package/dist/cli/commands/info.d.ts +0 -2
  177. package/dist/cli/commands/info.js +83 -49
  178. package/dist/cli/commands/init.d.ts +1 -2
  179. package/dist/cli/commands/init.js +16 -55
  180. package/dist/cli/commands/invoke.d.ts +0 -1
  181. package/dist/cli/commands/invoke.js +5 -7
  182. package/dist/cli/commands/login.d.ts +2 -1
  183. package/dist/cli/commands/login.js +33 -38
  184. package/dist/cli/commands/logs.js +3 -4
  185. package/dist/cli/commands/models.js +1 -5
  186. package/dist/cli/commands/routine-run.d.ts +6 -0
  187. package/dist/cli/commands/routine-run.js +47 -0
  188. package/dist/cli/commands/routine.d.ts +25 -0
  189. package/dist/cli/commands/routine.js +122 -0
  190. package/dist/cli/commands/start.d.ts +31 -3
  191. package/dist/cli/commands/start.js +131 -81
  192. package/dist/cli/commands/tool.js +26 -12
  193. package/dist/cli/fail.d.ts +13 -23
  194. package/dist/cli/fail.js +20 -23
  195. package/dist/cli/invoke-stream.d.ts +1 -8
  196. package/dist/cli/kernel.d.ts +6 -38
  197. package/dist/cli/kernel.js +14 -77
  198. package/dist/cli/models-view.d.ts +1 -9
  199. package/dist/cli/models-view.js +11 -22
  200. package/dist/cli/program.d.ts +5 -6
  201. package/dist/cli/program.js +120 -157
  202. package/dist/cli/serve.d.ts +57 -41
  203. package/dist/cli/serve.js +94 -121
  204. package/dist/cli/shared.d.ts +15 -61
  205. package/dist/cli/shared.js +55 -181
  206. package/dist/cli.js +1 -8
  207. package/dist/collect.d.ts +6 -0
  208. package/dist/collect.js +6 -0
  209. package/dist/core.d.ts +4 -1
  210. package/dist/core.js +9 -7
  211. package/dist/declared-secrets.d.ts +55 -0
  212. package/dist/declared-secrets.js +88 -0
  213. package/dist/deploy/agentcore/aws-cli.d.ts +91 -0
  214. package/dist/deploy/agentcore/aws-cli.js +64 -0
  215. package/dist/deploy/agentcore/destroy.d.ts +51 -0
  216. package/dist/deploy/agentcore/destroy.js +273 -0
  217. package/dist/deploy/agentcore/forwarder.js +28 -79
  218. package/dist/deploy/agentcore/logs.d.ts +2 -18
  219. package/dist/deploy/agentcore/logs.js +27 -51
  220. package/dist/deploy/agentcore/plan.d.ts +85 -105
  221. package/dist/deploy/agentcore/plan.js +152 -314
  222. package/dist/deploy/agentcore/run.d.ts +28 -28
  223. package/dist/deploy/agentcore/run.js +227 -306
  224. package/dist/deploy/agentcore/zip.d.ts +2 -15
  225. package/dist/deploy/agentcore/zip.js +3 -17
  226. package/dist/deploy/build-context.d.ts +21 -0
  227. package/dist/deploy/build-context.js +137 -0
  228. package/dist/deploy/channel-ingress.d.ts +26 -39
  229. package/dist/deploy/channel-ingress.js +57 -28
  230. package/dist/deploy/container.d.ts +20 -34
  231. package/dist/deploy/container.js +49 -100
  232. package/dist/deploy/docker/plan.d.ts +12 -11
  233. package/dist/deploy/docker/plan.js +43 -24
  234. package/dist/deploy/docker/run.d.ts +22 -25
  235. package/dist/deploy/docker/run.js +39 -37
  236. package/dist/deploy/fly/plan.d.ts +15 -44
  237. package/dist/deploy/fly/plan.js +41 -73
  238. package/dist/deploy/fly/run.d.ts +16 -51
  239. package/dist/deploy/fly/run.js +42 -95
  240. package/dist/deploy/hosts.d.ts +24 -3
  241. package/dist/deploy/hosts.js +24 -3
  242. package/dist/deploy/preflight.d.ts +47 -41
  243. package/dist/deploy/preflight.js +282 -383
  244. package/dist/deploy/railway/plan.d.ts +16 -42
  245. package/dist/deploy/railway/plan.js +42 -60
  246. package/dist/deploy/railway/run.d.ts +30 -68
  247. package/dist/deploy/railway/run.js +86 -100
  248. package/dist/deploy/registration-gate.d.ts +6 -13
  249. package/dist/deploy/residency.d.ts +37 -0
  250. package/dist/deploy/residency.js +24 -0
  251. package/dist/deploy/runner.d.ts +10 -9
  252. package/dist/deploy/runner.js +7 -18
  253. package/dist/deploy/secrets.d.ts +40 -41
  254. package/dist/deploy/secrets.js +117 -103
  255. package/dist/deploy/workspace.d.ts +50 -0
  256. package/dist/deploy/workspace.js +197 -0
  257. package/dist/dev-supervisor.d.ts +1 -9
  258. package/dist/dev-supervisor.js +21 -64
  259. package/dist/effect-port.d.ts +50 -0
  260. package/dist/effect-port.js +77 -0
  261. package/dist/engines/pi/agent-session-factory.d.ts +50 -69
  262. package/dist/engines/pi/agent-session-factory.js +249 -146
  263. package/dist/engines/pi/auth.d.ts +15 -11
  264. package/dist/engines/pi/auth.js +96 -99
  265. package/dist/engines/pi/chat.d.ts +1 -5
  266. package/dist/engines/pi/chat.js +2 -14
  267. package/dist/engines/pi/config.d.ts +53 -51
  268. package/dist/engines/pi/config.js +83 -92
  269. package/dist/engines/pi/create.d.ts +60 -75
  270. package/dist/engines/pi/create.js +108 -141
  271. package/dist/engines/pi/definition.d.ts +14 -58
  272. package/dist/engines/pi/definition.js +21 -85
  273. package/dist/engines/pi/invoke-session.d.ts +5 -25
  274. package/dist/engines/pi/invoke-session.js +233 -244
  275. package/dist/engines/pi/login.d.ts +95 -35
  276. package/dist/engines/pi/login.js +259 -107
  277. package/dist/engines/pi/machine.d.ts +31 -0
  278. package/dist/engines/pi/machine.js +106 -0
  279. package/dist/engines/pi/models.d.ts +70 -89
  280. package/dist/engines/pi/models.js +188 -81
  281. package/dist/engines/pi/open.d.ts +65 -53
  282. package/dist/engines/pi/open.js +129 -69
  283. package/dist/engines/pi/report.d.ts +3 -12
  284. package/dist/engines/pi/report.js +2 -16
  285. package/dist/engines/pi/search-tools.d.ts +1 -9
  286. package/dist/engines/pi/search-tools.js +26 -57
  287. package/dist/engines/pi/service.d.ts +2 -16
  288. package/dist/engines/pi/service.js +2 -16
  289. package/dist/engines/pi/session-builder.d.ts +5 -9
  290. package/dist/engines/pi/session-builder.js +44 -82
  291. package/dist/engines/pi/session-control.js +286 -269
  292. package/dist/engines/pi/session-effects.d.ts +14 -0
  293. package/dist/engines/pi/session-effects.js +30 -0
  294. package/dist/engines/pi/session-inheritance.d.ts +9 -18
  295. package/dist/engines/pi/session-inheritance.js +103 -160
  296. package/dist/engines/pi/session-markers.d.ts +31 -30
  297. package/dist/engines/pi/session-markers.js +26 -25
  298. package/dist/engines/pi/session-settings.d.ts +6 -22
  299. package/dist/engines/pi/session-settings.js +10 -21
  300. package/dist/engines/pi/session-store.d.ts +26 -92
  301. package/dist/engines/pi/session-store.js +96 -310
  302. package/dist/engines/pi/tool-context.d.ts +17 -45
  303. package/dist/engines/pi/tool-context.js +7 -26
  304. package/dist/engines/pi/tool.d.ts +45 -36
  305. package/dist/engines/pi/tool.js +43 -57
  306. package/dist/engines/pi/turn-kit.d.ts +14 -52
  307. package/dist/engines/pi/turn-kit.js +18 -67
  308. package/dist/engines/pi/wake-tool.d.ts +2 -10
  309. package/dist/engines/pi/wake-tool.js +7 -27
  310. package/dist/env.d.ts +27 -28
  311. package/dist/env.js +45 -50
  312. package/dist/index.js +0 -2
  313. package/dist/lark.d.ts +1 -2
  314. package/dist/lark.js +1 -2
  315. package/dist/loader.d.ts +14 -55
  316. package/dist/loader.js +24 -43
  317. package/dist/log.d.ts +2 -12
  318. package/dist/log.js +3 -24
  319. package/dist/node.d.ts +2 -15
  320. package/dist/node.js +2 -18
  321. package/dist/observe.d.ts +2 -8
  322. package/dist/open-url.d.ts +1 -1
  323. package/dist/open-url.js +1 -1
  324. package/dist/paths.d.ts +70 -134
  325. package/dist/paths.js +165 -232
  326. package/dist/pi.d.ts +4 -6
  327. package/dist/pi.js +3 -3
  328. package/dist/proxy.d.ts +16 -6
  329. package/dist/proxy.js +52 -16
  330. package/dist/runtime.d.ts +18 -12
  331. package/dist/runtime.js +18 -11
  332. package/dist/scaffold/add-channel.d.ts +14 -31
  333. package/dist/scaffold/add-channel.js +48 -112
  334. package/dist/scaffold/init.d.ts +9 -31
  335. package/dist/scaffold/init.js +45 -138
  336. package/dist/scaffold/templates/env.example +6 -4
  337. package/dist/scaffold/templates/fastagent.config.ts +36 -0
  338. package/dist/scaffold/templates.d.ts +3 -3
  339. package/dist/scaffold/templates.js +5 -8
  340. package/dist/scaffold/vendor-skill.d.ts +2 -5
  341. package/dist/scaffold/vendor-skill.js +19 -29
  342. package/dist/schedule/cron.d.ts +9 -5
  343. package/dist/schedule/cron.js +9 -11
  344. package/dist/schedule/discover.d.ts +12 -12
  345. package/dist/schedule/discover.js +43 -34
  346. package/dist/schedule/routine.d.ts +43 -0
  347. package/dist/schedule/routine.js +32 -0
  348. package/dist/schedule/run.d.ts +55 -0
  349. package/dist/schedule/run.js +146 -0
  350. package/dist/schedule/scheduler.d.ts +44 -55
  351. package/dist/schedule/scheduler.js +291 -265
  352. package/dist/schedule/state.d.ts +105 -10
  353. package/dist/schedule/state.js +293 -19
  354. package/dist/schedule/wake-alarm.d.ts +10 -23
  355. package/dist/schedule/wake-alarm.js +91 -121
  356. package/dist/schedule/wakeups.d.ts +23 -39
  357. package/dist/schedule/wakeups.js +33 -75
  358. package/dist/secrets-gate.d.ts +32 -0
  359. package/dist/secrets-gate.js +33 -0
  360. package/dist/service.d.ts +137 -98
  361. package/dist/service.js +250 -252
  362. package/dist/session-remote.d.ts +33 -44
  363. package/dist/session-remote.js +203 -192
  364. package/dist/session.d.ts +166 -229
  365. package/dist/session.js +33 -55
  366. package/dist/tunnel.d.ts +8 -36
  367. package/dist/tunnel.js +24 -65
  368. package/dist/version.d.ts +2 -2
  369. package/dist/version.js +2 -2
  370. package/package.json +10 -16
  371. package/dist/channels/agentcore-state.d.ts +0 -77
  372. package/dist/channels/agentcore-state.js +0 -276
  373. package/dist/channels/github/github.d.ts +0 -31
  374. package/dist/channels/github/github.js +0 -89
  375. package/dist/channels/github/scaffold/channel.ts +0 -25
  376. package/dist/cli/commands/attach.d.ts +0 -108
  377. package/dist/cli/commands/attach.js +0 -637
  378. package/dist/cli/commands/fire.d.ts +0 -7
  379. package/dist/cli/commands/fire.js +0 -38
  380. package/dist/cli/commands/schedule.d.ts +0 -12
  381. package/dist/cli/commands/schedule.js +0 -87
  382. package/dist/github.d.ts +0 -3
  383. package/dist/github.js +0 -2
  384. package/dist/scaffold/templates/fastagent.config.mjs +0 -23
  385. package/dist/schedule/audit.d.ts +0 -18
  386. package/dist/schedule/audit.js +0 -57
  387. package/dist/schedule/schedule.d.ts +0 -35
  388. package/dist/schedule/schedule.js +0 -23
@@ -1,5 +1,4 @@
1
- /** Lightweight Slack emoji ack on the user's triggering message: 👀 while working, ✅ when done.
2
- * Every failure is non-fatal — the turn's threaded reply is the real deliverable. */
1
+ /** Lightweight Slack emoji ack on the user's triggering message: 👀 while working, ✅ when done. */
3
2
  import { log } from "../../log.js";
4
3
  const EMOJI_RE = /^(?:[a-z0-9_+-]+)(?:::skin-tone-[2-6])?$/;
5
4
  /** Normalize a Slack emoji name (strip surrounding colons, lowercase); return null if invalid. */
@@ -27,6 +26,22 @@ export function resolveReactionEmojis(reactionAck) {
27
26
  completed: pick(reactionAck.completed, "white_check_mark", "completed"),
28
27
  };
29
28
  }
29
+ // Every step is best effort: an ack is decoration, and must never fail the turn carrying it.
30
+ const dropProcessing = ({ api, channelId, ts, emojis, label }) => api
31
+ .removeReaction(channelId, ts, emojis.processing)
32
+ .catch((error) => log.warn(`${label} could not remove the processing reaction: ${String(error)}`));
33
+ const addCompleted = ({ api, channelId, ts, emojis, label }) => api
34
+ .addReaction(channelId, ts, emojis.completed)
35
+ .catch((error) => log.warn(`${label} could not add the completed reaction: ${String(error)}`));
36
+ /**
37
+ * Finish an ack this process did not start: 👀 on the asker's message was added by the run that produced the answer,
38
+ * and a re-delivery is the only thing left that can turn it into ✅. Without it the ack says "still working" under a
39
+ * delivered answer, forever.
40
+ */
41
+ export async function completeSlackReaction(target) {
42
+ await dropProcessing(target);
43
+ await addCompleted(target);
44
+ }
30
45
  const NO_REACTION = {
31
46
  complete: async () => undefined,
32
47
  remove: async () => undefined,
@@ -46,16 +61,12 @@ export async function startSlackReaction(args) {
46
61
  if (!active)
47
62
  return;
48
63
  active = false;
49
- await api
50
- .removeReaction(channelId, ts, emojis.processing)
51
- .catch((error) => log.warn(`${label} could not remove the processing reaction: ${String(error)}`));
64
+ await dropProcessing(args);
52
65
  };
53
66
  return {
54
67
  complete: async () => {
55
68
  await removeProcessing();
56
- await api
57
- .addReaction(channelId, ts, emojis.completed)
58
- .catch((error) => log.warn(`${label} could not add the completed reaction: ${String(error)}`));
69
+ await addCompleted(args);
59
70
  },
60
71
  remove: removeProcessing,
61
72
  };
@@ -23,8 +23,7 @@ export async function registerSlackWebhook(baseUrl, options) {
23
23
  const consoleFallback = `set ${publicBaseUrl}/slack as the Event Subscriptions Request URL in the Slack console`;
24
24
  let current;
25
25
  try {
26
- // Rotation is not retried with the manifest below: each rotate invalidates the previous pair, so a
27
- // repeat would spend tokens on a failure that is about the URL, not about the credential.
26
+ // Rotation is not retried with the manifest below.
28
27
  current = await currentSlackConfigToken(options.stateRoot, state, {
29
28
  apiBaseUrl: options.apiBaseUrl,
30
29
  fetch: options.fetch,
@@ -35,16 +34,14 @@ export async function registerSlackWebhook(baseUrl, options) {
35
34
  `re-run \`fastagent add slack --replace-config\` to repair it, or ${consoleFallback}`);
36
35
  return "failed";
37
36
  }
38
- // Slack verifies the new request_url with a challenge DURING apps.manifest.update, from Slack's own
39
- // network — that verdict IS the readiness signal, so it is retried while a fresh tunnel/container
40
- // warms up. No local `/health` poll precedes it: this machine's reach is the wrong question (#421).
37
+ // Slack verifies the new request_url with a challenge DURING apps.manifest.update, from Slack's own network.
41
38
  try {
42
39
  await retryWhile(() => updateSlackAppManifest(current.token, current.state.appId, buildSlackManifest({
43
40
  name: current.state.appName,
44
41
  groupBehavior: current.state.groupBehavior,
45
42
  requestUrl: `${publicBaseUrl}/slack`,
46
- // A manifest update replaces the whole manifest and redirect_urls may not be empty, so a
47
- // placeholder is declared; a reinstall replaces it with its one-shot local setup callback.
43
+ // A manifest update replaces the whole manifest and redirect_urls may not be empty, so a placeholder is
44
+ // declared.
48
45
  redirectUrl: `${publicBaseUrl}/slack/oauth/callback`,
49
46
  }), { apiBaseUrl: options.apiBaseUrl, fetch: options.fetch }), isSlackRequestUrlUnverified, {
50
47
  attempts: options.attempts,
@@ -1,4 +1,5 @@
1
1
  import { slackChannel } from "@fastagent-sh/fastagent/slack";
2
+ import { defineChannel } from "@fastagent-sh/fastagent";
2
3
 
3
4
  // Slack HTTP Events API channel. Setup:
4
5
  // 1. Create a Slack app at https://api.slack.com/apps and add a bot user.
@@ -10,17 +11,23 @@ import { slackChannel } from "@fastagent-sh/fastagent/slack";
10
11
  // Set Request URL to https://<host>/slack.
11
12
  // 4. Install the app (reinstall after changing scopes) and leave token rotation OFF: it cannot be
12
13
  // turned off again, and this channel takes one long-lived Bot User OAuth Token.
13
- export default slackChannel({
14
- botToken: process.env.SLACK_BOT_TOKEN ?? "", // OAuth & Permissions → Bot User OAuth Token (xoxb-…)
15
- signingSecret: process.env.SLACK_SIGNING_SECRET ?? "", // Basic Information → App Credentials
16
- // Slack Agent stream; its inline tool traces show each call's first argument and stay in the
17
- // delivered message. "classic" settles into the answer alone (and gives up native streaming).
18
- rendering: "native",
19
- // Optional per-reply footer, if your policy requires one: aiDisclaimer: "AI-generated; verify important information.",
20
- // welcome: "Custom first-run DM greeting", // sent once on first DM open; false disables (default: a generic greeting)
21
- // reactionAck: false, // disable the 👀→✅ ack on the user's message (default on; needs reactions:write)
22
- // No session modes: an answer attaches to its question with a thread (Slack has no quote primitive),
23
- // and that thread is the session — see docs/design/participant-model.md.
24
- // Dev/personal bot: surface raw errors. Remove this for a customer-facing bot; details remain in logs.
25
- onError: (failed) => `⚠️ ${failed.details}`,
14
+ export default defineChannel({
15
+ // The env vars this channel needs. fastagent carries them to a deployed box and refuses to serve
16
+ // while one is unset — a bare process.env read gets neither guarantee.
17
+ secrets: ["SLACK_BOT_TOKEN", "SLACK_SIGNING_SECRET"],
18
+ channel: (secrets) =>
19
+ slackChannel({
20
+ botToken: secrets.SLACK_BOT_TOKEN, // OAuth & Permissions → Bot User OAuth Token (xoxb-…)
21
+ signingSecret: secrets.SLACK_SIGNING_SECRET, // Basic Information → App Credentials
22
+ // Slack Agent stream; its inline tool traces show each call's first argument and stay in the
23
+ // delivered message. "classic" settles into the answer alone (and gives up native streaming).
24
+ rendering: "native",
25
+ // Optional per-reply footer, if your policy requires one: aiDisclaimer: "AI-generated; verify important information.",
26
+ // welcome: "Custom first-run DM greeting", // sent once on first DM open; false disables (default: a generic greeting)
27
+ // reactionAck: false, // disable the 👀→✅ ack on the user's message (default on; needs reactions:write)
28
+ // No session modes: an answer attaches to its question with a thread (Slack has no quote primitive),
29
+ // and that thread is the session — see docs/design/participant-model.md.
30
+ // Dev/personal bot: surface raw errors. Remove this for a customer-facing bot; details remain in logs.
31
+ onError: (failed) => `⚠️ ${failed.details}`,
32
+ }),
26
33
  });
@@ -3,13 +3,13 @@ import { slackTransport } from "@fastagent-sh/fastagent/slack";
3
3
 
4
4
  // Send a message or upload a local file to Slack. In a CHAT turn the channel delivers the reply
5
5
  // itself — do NOT call this to answer a normal chat turn (that posts the message twice). This tool is
6
- // for file uploads, and for turns NO channel is carrying: a scheduled turn (schedules/<name>.ts) or a
6
+ // for file uploads, and for turns NO channel is carrying: a scheduled turn (routines/<name>.ts) or a
7
7
  // self-scheduled wake-up, whose plain reply is not delivered anywhere. The channelId/threadTs come
8
8
  // from the [slack: …] context line in a chat turn; a scheduled/woken turn has no such line, so its
9
9
  // prompt must name the target channel id. tools/ is auto-discovered.
10
10
  //
11
11
  // Delivery rides the channel's own transport (slackTransport): its token, API base, Markdown splitting
12
- // and rate-limit handling. With no channel mounted (`fastagent fire` / `invoke`) it is built from
12
+ // and rate-limit handling. With no channel mounted (`fastagent routine run` / `invoke`) it is built from
13
13
  // SLACK_BOT_TOKEN in .env.
14
14
 
15
15
  export default defineTool({
@@ -9,9 +9,5 @@ export interface SlackSetupServer {
9
9
  }>;
10
10
  close(): Promise<void>;
11
11
  }
12
- /**
13
- * Temporary onboarding-only responder. Its unguessable paths live for one command: one path echoes only
14
- * Slack's URL-verification challenge, while the other captures one OAuth redirect. It never accepts
15
- * event callbacks or runs Agent work.
16
- */
12
+ /** Temporary onboarding-only responder. */
17
13
  export declare function startSlackSetupServer(): Promise<SlackSetupServer>;
@@ -1,10 +1,6 @@
1
1
  import { randomBytes } from "node:crypto";
2
2
  import { createServer } from "node:http";
3
- /**
4
- * Temporary onboarding-only responder. Its unguessable paths live for one command: one path echoes only
5
- * Slack's URL-verification challenge, while the other captures one OAuth redirect. It never accepts
6
- * event callbacks or runs Agent work.
7
- */
3
+ /** Temporary onboarding-only responder. */
8
4
  export async function startSlackSetupServer() {
9
5
  const nonce = randomBytes(24).toString("hex");
10
6
  const requestPath = `/slack/setup/${nonce}`;
@@ -3,8 +3,5 @@ import { type SlackApi } from "./slack-api.ts";
3
3
  export type SlackTransport = Pick<SlackApi, "sendMarkdown" | "uploadFile">;
4
4
  /** A re-mount replaces the entry: the channel's transport is the authoritative one for its root. */
5
5
  export declare function registerSlackApi(stateRoot: string, api: SlackApi): void;
6
- /**
7
- * The transport of the agent whose workspace is `cwd` (a tool's `ctx.cwd`). The state root is derived
8
- * exactly as the opener derives it for the channel, so both name the same mount.
9
- */
6
+ /** The transport of the agent whose workspace is `cwd` (a tool's `ctx.cwd`). */
10
7
  export declare function slackTransport(cwd: string): SlackTransport;
@@ -1,13 +1,5 @@
1
1
  /**
2
- * The ONE Slack transport per state root a process holds: the mounted channel's, shared with the
3
- * scaffolded send tool.
4
- *
5
- * The tool used to carry a transport of its own over `SLACK_BOT_TOKEN` (#458). Sharing the channel's
6
- * gives it the channel's `apiBaseUrl`, Markdown splitting and rate-limit handling, and one place to
7
- * read the credential. The channel registers at mount; the tool resolves at EXECUTE, never at load,
8
- * and builds a transport from the env only where no channel is mounted (`fastagent fire` / `invoke`)
9
- * — that fallback knows no `apiBaseUrl`, since the option lives in the channel's glue, which is not
10
- * loaded on those paths.
2
+ * The ONE Slack transport per state root a process holds: the mounted channel's, shared with the scaffolded send tool.
11
3
  */
12
4
  import { resolvePlacement, resolveStateRoot } from "../../paths.js";
13
5
  import { createSlackApi } from "./slack-api.js";
@@ -16,10 +8,7 @@ const byStateRoot = new Map();
16
8
  export function registerSlackApi(stateRoot, api) {
17
9
  byStateRoot.set(stateRoot, api);
18
10
  }
19
- /**
20
- * The transport of the agent whose workspace is `cwd` (a tool's `ctx.cwd`). The state root is derived
21
- * exactly as the opener derives it for the channel, so both name the same mount.
22
- */
11
+ /** The transport of the agent whose workspace is `cwd` (a tool's `ctx.cwd`). */
23
12
  export function slackTransport(cwd) {
24
13
  const stateRoot = resolveStateRoot(resolvePlacement(cwd).agentDir);
25
14
  let api = byStateRoot.get(stateRoot);
@@ -1,4 +1,5 @@
1
1
  import type { ImageRef } from "../../agent.ts";
2
+ import type { CallOptions } from "../kit/transport.ts";
2
3
  import type { SlackFile } from "./model.ts";
3
4
  export interface SlackTarget {
4
5
  channelId: string;
@@ -46,7 +47,7 @@ export interface SlackApi {
46
47
  postMessage(target: SlackTarget, text: string): Promise<string>;
47
48
  postMarkdown(target: SlackTarget, markdown: string): Promise<string>;
48
49
  updateMessage(channelId: string, ts: string, text: string): Promise<void>;
49
- updateMarkdown(channelId: string, ts: string, markdown: string): Promise<void>;
50
+ updateMarkdown(channelId: string, ts: string, markdown: string, opts?: CallOptions): Promise<void>;
50
51
  deleteMessage(channelId: string, ts: string): Promise<void>;
51
52
  /** Post standard Markdown, split under Slack's limit. `target.channelId` may be a user id: Slack
52
53
  * then opens (or reuses) the app's DM with that user, and the result names it. */
@@ -37,6 +37,7 @@ const NATIVE_UNAVAILABLE_ERRORS = new Set([
37
37
  export function isSlackNativeUnavailable(error) {
38
38
  return error instanceof SlackApiError && !!error.slackError && NATIVE_UNAVAILABLE_ERRORS.has(error.slackError);
39
39
  }
40
+ /** Sleep on the GLOBAL timer (not `node:timers/promises`) so tests can drive it with fake timers. */
40
41
  const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
41
42
  /** Split a Slack text/Markdown field at a code-point-safe boundary, preferring a newline. */
42
43
  export function chunkSlackText(text, maxPoints = SLACK_MAX_MARKDOWN) {
@@ -145,7 +146,8 @@ function assertLongLivedBotToken(botToken) {
145
146
  export function createSlackApi({ botToken, baseUrl = "https://slack.com/api" }) {
146
147
  assertLongLivedBotToken(botToken);
147
148
  const apiBase = baseUrl.replace(/\/$/, "");
148
- const call = async (method, body, httpMethod = "POST") => {
149
+ const call = async (method, body, httpMethod = "POST", opts = {}) => {
150
+ const retries = opts.retries ?? RETRIES;
149
151
  const url = new URL(`${apiBase}/${method}`);
150
152
  if (httpMethod === "GET") {
151
153
  for (const [name, value] of Object.entries(body)) {
@@ -181,7 +183,7 @@ export function createSlackApi({ botToken, baseUrl = "https://slack.com/api" })
181
183
  if (response.ok && data.ok === true)
182
184
  return data;
183
185
  const rateLimited = response.status === 429 || data.error === "ratelimited";
184
- if (rateLimited && attempt < RETRIES) {
186
+ if (rateLimited && attempt < retries) {
185
187
  const retryAfter = Number(response.headers.get("retry-after") ?? attempt + 1);
186
188
  if (Number.isFinite(retryAfter) && retryAfter <= MAX_RETRY_AFTER_S) {
187
189
  await wait(Math.max(1, retryAfter) * 1000);
@@ -261,9 +263,9 @@ export function createSlackApi({ botToken, baseUrl = "https://slack.com/api" })
261
263
  throw error;
262
264
  }
263
265
  },
264
- async updateMarkdown(channelId, ts, markdown) {
266
+ async updateMarkdown(channelId, ts, markdown, opts) {
265
267
  try {
266
- await call("chat.update", { channel: channelId, ts, markdown_text: markdown });
268
+ await call("chat.update", { channel: channelId, ts, markdown_text: markdown }, "POST", opts);
267
269
  }
268
270
  catch (error) {
269
271
  if (error instanceof SlackApiError && error.slackError === "message_not_modified")
@@ -8,23 +8,20 @@ export interface SlackChannelOptions {
8
8
  botToken: string;
9
9
  /** App signing secret used to verify the raw Events API request body. */
10
10
  signingSecret: string;
11
- /** `native` (default) uses Slack Agent streams for threaded replies. Its inline tool traces carry a
12
- * bounded summary of each call's first argument and cannot be retracted, so they stay in the
13
- * delivered message beside the answer. `classic` retains the compatibility renderer based on one
14
- * rate-limited edited message, which settles into the answer alone. A top-level target necessarily
15
- * uses the classic renderer, because Slack streams require a parent user message; a custom route
16
- * reaches one either by returning `threadTs: null` or by redirecting to another channel without
17
- * naming a thread. */
11
+ /**
12
+ * `native` (default) uses Slack Agent streams for threaded replies; `classic` retains the compatibility renderer
13
+ * based on one rate-limited edited message. A top-level target necessarily uses `classic`, because Slack streams
14
+ * require a parent user message — a custom route reaches one either by returning `threadTs: null` or by redirecting
15
+ * to another channel without naming a thread.
16
+ */
18
17
  rendering?: SlackRendering;
19
- /** Optional footer for successful Agent replies. Omitted or `false` sends no repetitive disclaimer. */
18
+ /** Optional footer for successful Agent replies. */
20
19
  aiDisclaimer?: string | false;
21
- /** First-run direct-message welcome, sent once when a user first opens the DM (`app_home_opened`,
22
- * `tab: "messages"`). A string customizes it; `false` disables it. Plain Markdown only — no interactive
23
- * buttons until an interactivity endpoint exists. Defaults to a generic greeting. */
20
+ /**
21
+ * First-run direct-message welcome, sent once when a user first opens the DM (`app_home_opened`, `tab: "messages"`).
22
+ */
24
23
  welcome?: string | false;
25
- /** Lightweight emoji ack on the user's triggering message: 👀 while working, ✅ when done. `false`
26
- * disables it; an object overrides either emoji name. Requires the `reactions:write` scope; a missing
27
- * scope degrades to no ack. */
24
+ /** Lightweight emoji ack on the user's triggering message: 👀 while working, ✅ when done. */
28
25
  reactionAck?: false | {
29
26
  processing?: string;
30
27
  completed?: string;