@fastagent-sh/fastagent 0.24.3 → 0.25.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 (480) hide show
  1. package/README.md +53 -82
  2. package/dist/agent-api.d.ts +452 -0
  3. package/dist/agent-api.js +201 -0
  4. package/dist/answer-text.d.ts +8 -0
  5. package/dist/answer-text.js +18 -0
  6. package/dist/atomic-write.d.ts +2 -2
  7. package/dist/atomic-write.js +2 -2
  8. package/dist/authoring.d.ts +77 -0
  9. package/dist/authoring.js +238 -0
  10. package/dist/channel.d.ts +29 -15
  11. package/dist/channel.js +4 -1
  12. package/dist/channels/agentcore-protocol.d.ts +36 -50
  13. package/dist/channels/agentcore-protocol.js +3 -3
  14. package/dist/channels/agentcore-service.d.ts +8 -18
  15. package/dist/channels/agentcore-service.js +108 -127
  16. package/dist/channels/agentcore.d.ts +8 -24
  17. package/dist/channels/agentcore.js +32 -65
  18. package/dist/channels/body.d.ts +0 -16
  19. package/dist/channels/body.js +0 -25
  20. package/dist/channels/busy.js +6 -1
  21. package/dist/channels/context.d.ts +4 -0
  22. package/dist/channels/context.js +35 -0
  23. package/dist/channels/discover.d.ts +18 -20
  24. package/dist/channels/discover.js +41 -99
  25. package/dist/channels/feishu/feishu-api.d.ts +54 -4
  26. package/dist/channels/feishu/feishu-api.js +192 -149
  27. package/dist/channels/feishu/feishu.d.ts +3 -0
  28. package/dist/channels/feishu/feishu.js +117 -106
  29. package/dist/channels/feishu/history.d.ts +55 -0
  30. package/dist/channels/feishu/history.js +199 -0
  31. package/dist/channels/feishu/invoke-turn.d.ts +13 -11
  32. package/dist/channels/feishu/invoke-turn.js +9 -10
  33. package/dist/channels/feishu/model.d.ts +2 -1
  34. package/dist/channels/feishu/normalize.js +100 -0
  35. package/dist/channels/feishu/preview.d.ts +2 -2
  36. package/dist/channels/feishu/register-webhook.d.ts +1 -0
  37. package/dist/channels/feishu/register-webhook.js +3 -2
  38. package/dist/channels/feishu/scaffold/channel.ts +65 -46
  39. package/dist/channels/feishu/scaffold/feishu-send.ts +38 -33
  40. package/dist/channels/feishu/scaffold/feishu-threads.ts +25 -0
  41. package/dist/channels/feishu/setup-mode.d.ts +45 -25
  42. package/dist/channels/feishu/setup-mode.js +74 -23
  43. package/dist/channels/feishu/shared-api.d.ts +24 -6
  44. package/dist/channels/feishu/shared-api.js +30 -24
  45. package/dist/channels/kit/context-buffer.d.ts +11 -2
  46. package/dist/channels/kit/context-buffer.js +7 -4
  47. package/dist/channels/kit/delivery.d.ts +19 -3
  48. package/dist/channels/kit/delivery.js +74 -15
  49. package/dist/channels/kit/event-stream.js +2 -1
  50. package/dist/channels/kit/invoke-turn-kit.d.ts +41 -41
  51. package/dist/channels/kit/invoke-turn-kit.js +62 -71
  52. package/dist/channels/kit/place-history.d.ts +107 -0
  53. package/dist/channels/kit/place-history.js +182 -0
  54. package/dist/channels/kit/preview-kit.d.ts +9 -5
  55. package/dist/channels/kit/preview-kit.js +36 -15
  56. package/dist/channels/kit/room-threads.d.ts +46 -0
  57. package/dist/channels/kit/room-threads.js +81 -0
  58. package/dist/channels/kit/seen.js +1 -1
  59. package/dist/channels/kit/stop-command.d.ts +6 -3
  60. package/dist/channels/kit/stop-command.js +20 -18
  61. package/dist/channels/kit/thread-fork.d.ts +17 -0
  62. package/dist/channels/kit/thread-fork.js +43 -0
  63. package/dist/channels/kit/thread-participants.js +1 -1
  64. package/dist/channels/kit/transport.d.ts +5 -0
  65. package/dist/channels/kit/transport.js +5 -0
  66. package/dist/channels/kit/turn-runner.d.ts +10 -9
  67. package/dist/channels/kit/turn-runner.js +17 -19
  68. package/dist/channels/kit/turn-store.d.ts +5 -4
  69. package/dist/channels/kit/turn-store.js +5 -5
  70. package/dist/channels/lark/lark.d.ts +3 -0
  71. package/dist/channels/lark/lark.js +5 -0
  72. package/dist/channels/lark/onboard.d.ts +5 -3
  73. package/dist/channels/lark/onboard.js +14 -14
  74. package/dist/channels/lark/scaffold/channel.ts +67 -44
  75. package/dist/channels/lark/scaffold/lark-send.ts +38 -33
  76. package/dist/channels/lark/scaffold/lark-threads.ts +25 -0
  77. package/dist/channels/respond.d.ts +0 -4
  78. package/dist/channels/respond.js +1 -1
  79. package/dist/channels/router.d.ts +18 -0
  80. package/dist/channels/router.js +68 -0
  81. package/dist/channels/serve.d.ts +5 -70
  82. package/dist/channels/serve.js +105 -287
  83. package/dist/channels/slack/history.d.ts +42 -0
  84. package/dist/channels/slack/history.js +282 -0
  85. package/dist/channels/slack/invoke-turn.d.ts +12 -5
  86. package/dist/channels/slack/invoke-turn.js +7 -5
  87. package/dist/channels/slack/manifest.d.ts +1 -4
  88. package/dist/channels/slack/manifest.js +22 -10
  89. package/dist/channels/slack/model.d.ts +2 -1
  90. package/dist/channels/slack/onboard.d.ts +0 -2
  91. package/dist/channels/slack/onboard.js +2 -4
  92. package/dist/channels/slack/onboarding-state.d.ts +0 -2
  93. package/dist/channels/slack/onboarding-state.js +0 -1
  94. package/dist/channels/slack/parse.d.ts +0 -5
  95. package/dist/channels/slack/parse.js +1 -16
  96. package/dist/channels/slack/preview.d.ts +2 -3
  97. package/dist/channels/slack/preview.js +78 -52
  98. package/dist/channels/slack/register-webhook.d.ts +1 -0
  99. package/dist/channels/slack/register-webhook.js +6 -5
  100. package/dist/channels/slack/scaffold/channel.ts +23 -24
  101. package/dist/channels/slack/scaffold/slack-send.ts +50 -43
  102. package/dist/channels/slack/scaffold/slack-threads.ts +29 -0
  103. package/dist/channels/slack/setup-server.d.ts +19 -0
  104. package/dist/channels/slack/setup-server.js +113 -11
  105. package/dist/channels/slack/shared-api.d.ts +15 -4
  106. package/dist/channels/slack/shared-api.js +19 -14
  107. package/dist/channels/slack/slack-api.d.ts +61 -2
  108. package/dist/channels/slack/slack-api.js +28 -5
  109. package/dist/channels/slack/slack.js +97 -52
  110. package/dist/channels/slack/welcomed.js +1 -1
  111. package/dist/channels/telegram/context-buffer.d.ts +6 -1
  112. package/dist/channels/telegram/context-buffer.js +19 -0
  113. package/dist/channels/telegram/invoke-turn.d.ts +8 -4
  114. package/dist/channels/telegram/invoke-turn.js +7 -7
  115. package/dist/channels/telegram/parse.d.ts +7 -2
  116. package/dist/channels/telegram/parse.js +7 -0
  117. package/dist/channels/telegram/preview.d.ts +2 -2
  118. package/dist/channels/telegram/register-webhook.d.ts +1 -0
  119. package/dist/channels/telegram/register-webhook.js +3 -2
  120. package/dist/channels/telegram/scaffold/channel.ts +27 -28
  121. package/dist/channels/telegram/scaffold/telegram-send.ts +61 -108
  122. package/dist/channels/telegram/shared-api.d.ts +34 -0
  123. package/dist/channels/telegram/shared-api.js +79 -0
  124. package/dist/channels/telegram/telegram-api.d.ts +15 -5
  125. package/dist/channels/telegram/telegram-api.js +10 -6
  126. package/dist/channels/telegram/telegram.js +27 -21
  127. package/dist/channels/telegram/turn-store.js +1 -1
  128. package/dist/channels/{kit/turn-queue.d.ts → turn-queue.d.ts} +2 -2
  129. package/dist/channels/{kit/turn-queue.js → turn-queue.js} +10 -10
  130. package/dist/cli/add-feishu.d.ts +42 -12
  131. package/dist/cli/add-feishu.js +177 -124
  132. package/dist/cli/add-slack.d.ts +8 -3
  133. package/dist/cli/add-slack.js +115 -63
  134. package/dist/cli/auth-view.d.ts +10 -3
  135. package/dist/cli/auth-view.js +8 -6
  136. package/dist/cli/box-login.d.ts +17 -7
  137. package/dist/cli/box-login.js +46 -12
  138. package/dist/cli/commands/add.d.ts +15 -4
  139. package/dist/cli/commands/add.js +252 -143
  140. package/dist/cli/commands/auth.d.ts +6 -0
  141. package/dist/cli/commands/auth.js +50 -0
  142. package/dist/cli/commands/content.d.ts +6 -0
  143. package/dist/cli/commands/content.js +45 -0
  144. package/dist/cli/commands/deploy/agentcore.js +50 -77
  145. package/dist/cli/commands/deploy/docker.js +38 -39
  146. package/dist/cli/commands/deploy/fly.js +21 -18
  147. package/dist/cli/commands/deploy/host-login.d.ts +26 -0
  148. package/dist/cli/commands/deploy/host-login.js +90 -0
  149. package/dist/cli/commands/deploy/railway.js +21 -26
  150. package/dist/cli/commands/deploy/shared.d.ts +45 -17
  151. package/dist/cli/commands/deploy/shared.js +34 -15
  152. package/dist/cli/commands/deploy.d.ts +0 -4
  153. package/dist/cli/commands/deploy.js +237 -50
  154. package/dist/cli/commands/destroy.js +8 -6
  155. package/dist/cli/commands/dev.d.ts +0 -2
  156. package/dist/cli/commands/dev.js +20 -19
  157. package/dist/cli/commands/env.d.ts +12 -0
  158. package/dist/cli/commands/env.js +190 -0
  159. package/dist/cli/commands/info.js +95 -156
  160. package/dist/cli/commands/init.d.ts +2 -2
  161. package/dist/cli/commands/init.js +35 -33
  162. package/dist/cli/commands/invoke.d.ts +6 -0
  163. package/dist/cli/commands/invoke.js +131 -16
  164. package/dist/cli/commands/login.d.ts +31 -2
  165. package/dist/cli/commands/login.js +413 -64
  166. package/dist/cli/commands/logout.d.ts +4 -0
  167. package/dist/cli/commands/logout.js +53 -0
  168. package/dist/cli/commands/logs.js +8 -6
  169. package/dist/cli/commands/models.d.ts +2 -1
  170. package/dist/cli/commands/models.js +39 -37
  171. package/dist/cli/commands/schedules.d.ts +21 -0
  172. package/dist/cli/commands/schedules.js +143 -0
  173. package/dist/cli/commands/start.d.ts +11 -10
  174. package/dist/cli/commands/start.js +35 -62
  175. package/dist/cli/content-view.d.ts +9 -0
  176. package/dist/cli/content-view.js +26 -0
  177. package/dist/cli/fail.d.ts +9 -12
  178. package/dist/cli/fail.js +17 -14
  179. package/dist/cli/invoke-stream.d.ts +12 -3
  180. package/dist/cli/invoke-stream.js +85 -23
  181. package/dist/cli/kernel.d.ts +9 -2
  182. package/dist/cli/kernel.js +15 -6
  183. package/dist/cli/login-relay.d.ts +3 -2
  184. package/dist/cli/login-relay.js +18 -6
  185. package/dist/cli/models-view.d.ts +5 -1
  186. package/dist/cli/models-view.js +1 -1
  187. package/dist/cli/person.d.ts +10 -0
  188. package/dist/cli/person.js +23 -0
  189. package/dist/cli/program.js +421 -203
  190. package/dist/cli/serve.d.ts +13 -63
  191. package/dist/cli/serve.js +31 -121
  192. package/dist/cli/shared.d.ts +21 -48
  193. package/dist/cli/shared.js +68 -89
  194. package/dist/cli/ticket.d.ts +136 -0
  195. package/dist/cli/ticket.js +476 -0
  196. package/dist/client.d.ts +7 -0
  197. package/dist/client.js +2 -0
  198. package/dist/content/declare.d.ts +70 -0
  199. package/dist/content/declare.js +163 -0
  200. package/dist/content/file.d.ts +32 -0
  201. package/dist/content/file.js +119 -0
  202. package/dist/content/git.d.ts +41 -0
  203. package/dist/content/git.js +217 -0
  204. package/dist/content/mount.d.ts +2 -0
  205. package/dist/content/mount.js +15 -0
  206. package/dist/content/resolve.d.ts +52 -0
  207. package/dist/content/resolve.js +151 -0
  208. package/dist/content/source.d.ts +27 -0
  209. package/dist/content/source.js +53 -0
  210. package/dist/conversation-sessions.d.ts +26 -0
  211. package/dist/conversation-sessions.js +99 -0
  212. package/dist/declared-secrets.d.ts +19 -37
  213. package/dist/declared-secrets.js +16 -58
  214. package/dist/deploy/agentcore/destroy.d.ts +3 -3
  215. package/dist/deploy/agentcore/destroy.js +46 -28
  216. package/dist/deploy/agentcore/forwarder.js +105 -22
  217. package/dist/deploy/agentcore/logs.js +1 -1
  218. package/dist/deploy/agentcore/plan.d.ts +10 -24
  219. package/dist/deploy/agentcore/plan.js +31 -135
  220. package/dist/deploy/agentcore/run.d.ts +1 -1
  221. package/dist/deploy/agentcore/run.js +8 -5
  222. package/dist/deploy/agentcore/shell.d.ts +1 -1
  223. package/dist/deploy/agentcore/shell.js +5 -5
  224. package/dist/deploy/api.d.ts +34 -0
  225. package/dist/deploy/api.js +50 -0
  226. package/dist/deploy/box-shell.d.ts +6 -0
  227. package/dist/deploy/box-shell.js +7 -0
  228. package/dist/deploy/build-context.d.ts +7 -5
  229. package/dist/deploy/build-context.js +41 -35
  230. package/dist/deploy/channel-ingress.d.ts +6 -1
  231. package/dist/deploy/channel-ingress.js +18 -5
  232. package/dist/deploy/container.d.ts +22 -9
  233. package/dist/deploy/container.js +96 -55
  234. package/dist/deploy/docker/plan.d.ts +3 -2
  235. package/dist/deploy/docker/plan.js +13 -14
  236. package/dist/deploy/docker/run.d.ts +2 -2
  237. package/dist/deploy/docker/run.js +8 -4
  238. package/dist/deploy/fly/plan.d.ts +1 -1
  239. package/dist/deploy/fly/plan.js +12 -21
  240. package/dist/deploy/fly/run.d.ts +10 -6
  241. package/dist/deploy/fly/run.js +11 -6
  242. package/dist/deploy/hosts.d.ts +2 -1
  243. package/dist/deploy/hosts.js +2 -1
  244. package/dist/deploy/preflight.d.ts +21 -23
  245. package/dist/deploy/preflight.js +222 -201
  246. package/dist/deploy/railway/plan.d.ts +8 -6
  247. package/dist/deploy/railway/plan.js +15 -58
  248. package/dist/deploy/railway/run.d.ts +8 -3
  249. package/dist/deploy/railway/run.js +12 -8
  250. package/dist/deploy/residency.d.ts +5 -11
  251. package/dist/deploy/residency.js +0 -6
  252. package/dist/deploy/runner.d.ts +1 -1
  253. package/dist/deploy/runner.js +1 -1
  254. package/dist/deploy/secrets.d.ts +16 -2
  255. package/dist/deploy/secrets.js +33 -6
  256. package/dist/deploy/workspace.d.ts +11 -6
  257. package/dist/deploy/workspace.js +55 -38
  258. package/dist/dev-supervisor.d.ts +11 -2
  259. package/dist/dev-supervisor.js +51 -26
  260. package/dist/effect-port.d.ts +4 -4
  261. package/dist/effect-port.js +4 -4
  262. package/dist/environment/apt.d.ts +4 -0
  263. package/dist/environment/apt.js +32 -0
  264. package/dist/environment/declare.d.ts +59 -0
  265. package/dist/environment/declare.js +210 -0
  266. package/dist/environment/mise.d.ts +50 -0
  267. package/dist/environment/mise.js +268 -0
  268. package/dist/feishu.d.ts +2 -2
  269. package/dist/feishu.js +2 -2
  270. package/dist/git.d.ts +13 -0
  271. package/dist/git.js +55 -0
  272. package/dist/harnesses/models/catalog.d.ts +20 -0
  273. package/dist/harnesses/models/catalog.js +254 -0
  274. package/dist/{engines/pi/auth.d.ts → harnesses/models/credentials.d.ts} +3 -3
  275. package/dist/{engines/pi/auth.js → harnesses/models/credentials.js} +3 -3
  276. package/dist/harnesses/models/environment.d.ts +43 -0
  277. package/dist/harnesses/models/environment.js +82 -0
  278. package/dist/{engines/pi → harnesses/models}/login.d.ts +57 -26
  279. package/dist/{engines/pi → harnesses/models}/login.js +187 -79
  280. package/dist/harnesses/models/models.d.ts +83 -0
  281. package/dist/harnesses/models/models.js +158 -0
  282. package/dist/harnesses/pi-durable/agent.d.ts +42 -0
  283. package/dist/harnesses/pi-durable/agent.js +579 -0
  284. package/dist/harnesses/pi-durable/defaults.d.ts +28 -0
  285. package/dist/harnesses/pi-durable/defaults.js +26 -0
  286. package/dist/harnesses/pi-durable/define.d.ts +77 -0
  287. package/dist/harnesses/pi-durable/define.js +28 -0
  288. package/dist/harnesses/pi-durable/entries.d.ts +32 -0
  289. package/dist/harnesses/pi-durable/entries.js +126 -0
  290. package/dist/harnesses/pi-durable/events.d.ts +25 -0
  291. package/dist/harnesses/pi-durable/events.js +238 -0
  292. package/dist/harnesses/pi-durable/ids.d.ts +16 -0
  293. package/dist/harnesses/pi-durable/ids.js +55 -0
  294. package/dist/harnesses/pi-durable/messages.d.ts +41 -0
  295. package/dist/harnesses/pi-durable/messages.js +116 -0
  296. package/dist/harnesses/pi-durable/open.d.ts +88 -0
  297. package/dist/harnesses/pi-durable/open.js +329 -0
  298. package/dist/harnesses/pi-durable/reads.d.ts +30 -0
  299. package/dist/harnesses/pi-durable/reads.js +94 -0
  300. package/dist/harnesses/pi-durable/registry.d.ts +18 -0
  301. package/dist/harnesses/pi-durable/registry.js +56 -0
  302. package/dist/harnesses/pi-durable/release.d.ts +13 -0
  303. package/dist/harnesses/pi-durable/release.js +40 -0
  304. package/dist/harnesses/pi-durable/serve.d.ts +80 -0
  305. package/dist/harnesses/pi-durable/serve.js +156 -0
  306. package/dist/harnesses/pi-durable/sessions.d.ts +27 -0
  307. package/dist/harnesses/pi-durable/sessions.js +47 -0
  308. package/dist/harnesses/pi-durable/storage.d.ts +4 -0
  309. package/dist/harnesses/pi-durable/storage.js +49 -0
  310. package/dist/harnesses/pi-durable/stream.d.ts +20 -0
  311. package/dist/harnesses/pi-durable/stream.js +221 -0
  312. package/dist/harnesses/pi-durable/text.d.ts +30 -0
  313. package/dist/harnesses/pi-durable/text.js +292 -0
  314. package/dist/harnesses/pi-durable/wake.d.ts +4 -0
  315. package/dist/harnesses/pi-durable/wake.js +81 -0
  316. package/dist/http/client.d.ts +6 -0
  317. package/dist/http/client.js +256 -0
  318. package/dist/http/contract.d.ts +541 -0
  319. package/dist/http/contract.js +179 -0
  320. package/dist/http/server.d.ts +34 -0
  321. package/dist/http/server.js +194 -0
  322. package/dist/index.d.ts +17 -4
  323. package/dist/index.js +10 -5
  324. package/dist/lark.d.ts +2 -2
  325. package/dist/lark.js +2 -2
  326. package/dist/locked-file.d.ts +17 -0
  327. package/dist/{engines/pi/locked-file.js → locked-file.js} +16 -10
  328. package/dist/once.d.ts +6 -0
  329. package/dist/once.js +23 -0
  330. package/dist/paths.d.ts +36 -52
  331. package/dist/paths.js +66 -182
  332. package/dist/runtime.d.ts +25 -2
  333. package/dist/runtime.js +27 -0
  334. package/dist/scaffold/add-channel.d.ts +14 -27
  335. package/dist/scaffold/add-channel.js +82 -180
  336. package/dist/scaffold/init.d.ts +17 -18
  337. package/dist/scaffold/init.js +87 -99
  338. package/dist/scaffold/templates/SYSTEM.md +12 -0
  339. package/dist/scaffold/templates/env.example +4 -10
  340. package/dist/scaffold/templates/fastagent.config.ts +21 -33
  341. package/dist/scaffold/templates/gitignore +8 -1
  342. package/dist/scaffold/templates/skills/writing-great-skills/SKILL.md +1 -2
  343. package/dist/scaffold/templates.d.ts +9 -4
  344. package/dist/scaffold/templates.js +7 -5
  345. package/dist/scaffold/vendor-skill.d.ts +1 -4
  346. package/dist/scaffold/vendor-skill.js +5 -6
  347. package/dist/schedule/cron.d.ts +13 -0
  348. package/dist/schedule/cron.js +52 -0
  349. package/dist/schedule/eventbridge-cron.d.ts +17 -0
  350. package/dist/schedule/eventbridge-cron.js +88 -0
  351. package/dist/schedule/schedule.d.ts +23 -0
  352. package/dist/schedule/schedule.js +34 -0
  353. package/dist/schedule/scheduler.d.ts +34 -33
  354. package/dist/schedule/scheduler.js +251 -137
  355. package/dist/schedule/state.d.ts +4 -14
  356. package/dist/schedule/state.js +7 -7
  357. package/dist/schedule/wake-alarm.d.ts +22 -2
  358. package/dist/schedule/wake-alarm.js +66 -20
  359. package/dist/schedule/wakeups.d.ts +16 -15
  360. package/dist/schedule/wakeups.js +47 -45
  361. package/dist/service.d.ts +56 -169
  362. package/dist/service.js +91 -187
  363. package/dist/serving-command.d.ts +10 -0
  364. package/dist/serving-command.js +16 -0
  365. package/dist/slack.d.ts +1 -1
  366. package/dist/slack.js +1 -1
  367. package/dist/{channels/kit/state.js → state-file.js} +6 -6
  368. package/dist/telegram.d.ts +1 -0
  369. package/dist/telegram.js +1 -0
  370. package/dist/tunnel.d.ts +3 -0
  371. package/dist/tunnel.js +12 -4
  372. package/dist/value-file.d.ts +21 -0
  373. package/dist/value-file.js +108 -0
  374. package/dist/version.d.ts +5 -0
  375. package/dist/version.js +14 -1
  376. package/package.json +18 -28
  377. package/dist/agent.d.ts +0 -106
  378. package/dist/agent.js +0 -21
  379. package/dist/channels/control.d.ts +0 -31
  380. package/dist/channels/control.js +0 -329
  381. package/dist/channels/define-channel.d.ts +0 -39
  382. package/dist/channels/define-channel.js +0 -9
  383. package/dist/channels/feishu/context-buffer.d.ts +0 -35
  384. package/dist/channels/feishu/context-buffer.js +0 -65
  385. package/dist/channels/feishu/scaffold/channel.websocket.ts +0 -31
  386. package/dist/channels/http.d.ts +0 -23
  387. package/dist/channels/http.js +0 -57
  388. package/dist/channels/lark/scaffold/channel.websocket.ts +0 -31
  389. package/dist/channels/slack/context-buffer.d.ts +0 -23
  390. package/dist/channels/slack/context-buffer.js +0 -37
  391. package/dist/channels/sse.d.ts +0 -4
  392. package/dist/channels/sse.js +0 -66
  393. package/dist/cli/commands/chat.d.ts +0 -3
  394. package/dist/cli/commands/chat.js +0 -14
  395. package/dist/cli/commands/routine-run.d.ts +0 -6
  396. package/dist/cli/commands/routine-run.js +0 -46
  397. package/dist/cli/commands/routine.d.ts +0 -25
  398. package/dist/cli/commands/routine.js +0 -122
  399. package/dist/cli/commands/tool.d.ts +0 -1
  400. package/dist/cli/commands/tool.js +0 -57
  401. package/dist/collect.d.ts +0 -63
  402. package/dist/collect.js +0 -90
  403. package/dist/core.d.ts +0 -13
  404. package/dist/core.js +0 -15
  405. package/dist/engines/pi/agent-models.d.ts +0 -83
  406. package/dist/engines/pi/agent-models.js +0 -120
  407. package/dist/engines/pi/agent-session-factory.d.ts +0 -121
  408. package/dist/engines/pi/agent-session-factory.js +0 -517
  409. package/dist/engines/pi/chat.d.ts +0 -3
  410. package/dist/engines/pi/chat.js +0 -8
  411. package/dist/engines/pi/config.d.ts +0 -71
  412. package/dist/engines/pi/config.js +0 -199
  413. package/dist/engines/pi/create.d.ts +0 -170
  414. package/dist/engines/pi/create.js +0 -343
  415. package/dist/engines/pi/definition.d.ts +0 -74
  416. package/dist/engines/pi/definition.js +0 -236
  417. package/dist/engines/pi/entry-images.d.ts +0 -14
  418. package/dist/engines/pi/entry-images.js +0 -23
  419. package/dist/engines/pi/invoke-session.d.ts +0 -18
  420. package/dist/engines/pi/invoke-session.js +0 -403
  421. package/dist/engines/pi/locked-file.d.ts +0 -9
  422. package/dist/engines/pi/machine.d.ts +0 -53
  423. package/dist/engines/pi/machine.js +0 -137
  424. package/dist/engines/pi/models.d.ts +0 -200
  425. package/dist/engines/pi/models.js +0 -533
  426. package/dist/engines/pi/open.d.ts +0 -180
  427. package/dist/engines/pi/open.js +0 -270
  428. package/dist/engines/pi/openai-account-models.d.ts +0 -35
  429. package/dist/engines/pi/openai-account-models.js +0 -116
  430. package/dist/engines/pi/report.d.ts +0 -18
  431. package/dist/engines/pi/report.js +0 -59
  432. package/dist/engines/pi/retry-event.d.ts +0 -6
  433. package/dist/engines/pi/retry-event.js +0 -15
  434. package/dist/engines/pi/service.d.ts +0 -9
  435. package/dist/engines/pi/service.js +0 -14
  436. package/dist/engines/pi/session-builder.d.ts +0 -13
  437. package/dist/engines/pi/session-builder.js +0 -117
  438. package/dist/engines/pi/session-control.d.ts +0 -77
  439. package/dist/engines/pi/session-control.js +0 -908
  440. package/dist/engines/pi/session-effects.d.ts +0 -14
  441. package/dist/engines/pi/session-effects.js +0 -30
  442. package/dist/engines/pi/session-inheritance.d.ts +0 -21
  443. package/dist/engines/pi/session-inheritance.js +0 -204
  444. package/dist/engines/pi/session-markers.d.ts +0 -49
  445. package/dist/engines/pi/session-markers.js +0 -60
  446. package/dist/engines/pi/session-settings.d.ts +0 -67
  447. package/dist/engines/pi/session-settings.js +0 -119
  448. package/dist/engines/pi/session-store.d.ts +0 -69
  449. package/dist/engines/pi/session-store.js +0 -430
  450. package/dist/engines/pi/tool-context.d.ts +0 -45
  451. package/dist/engines/pi/tool-context.js +0 -31
  452. package/dist/engines/pi/tool.d.ts +0 -99
  453. package/dist/engines/pi/tool.js +0 -118
  454. package/dist/engines/pi/turn-kit.d.ts +0 -83
  455. package/dist/engines/pi/turn-kit.js +0 -275
  456. package/dist/engines/pi/wake-tool.d.ts +0 -9
  457. package/dist/engines/pi/wake-tool.js +0 -92
  458. package/dist/loader.d.ts +0 -41
  459. package/dist/loader.js +0 -116
  460. package/dist/node.d.ts +0 -3
  461. package/dist/node.js +0 -4
  462. package/dist/observe.d.ts +0 -6
  463. package/dist/observe.js +0 -47
  464. package/dist/pi.d.ts +0 -25
  465. package/dist/pi.js +0 -15
  466. package/dist/scaffold/templates/APPEND_SYSTEM.md +0 -12
  467. package/dist/scaffold/templates/tools/fetch-url.ts +0 -25
  468. package/dist/schedule/discover.d.ts +0 -17
  469. package/dist/schedule/discover.js +0 -61
  470. package/dist/schedule/routine.d.ts +0 -43
  471. package/dist/schedule/routine.js +0 -32
  472. package/dist/schedule/run.d.ts +0 -55
  473. package/dist/schedule/run.js +0 -146
  474. package/dist/secrets-gate.d.ts +0 -32
  475. package/dist/secrets-gate.js +0 -33
  476. package/dist/session-remote.d.ts +0 -47
  477. package/dist/session-remote.js +0 -460
  478. package/dist/session.d.ts +0 -466
  479. package/dist/session.js +0 -57
  480. /package/dist/{channels/kit/state.d.ts → state-file.d.ts} +0 -0
@@ -5,137 +5,97 @@
5
5
  import { readFile } from "node:fs/promises";
6
6
  import { isCancel, log as clackLog, password, text as clackText } from "@clack/prompts";
7
7
  import { bootstrapFeishuVerificationToken } from "../channels/feishu/bootstrap-token.js";
8
- import { FEISHU_GROUP_CONTEXT_SCOPE, FEISHU_CONTEXT_ONBOARDING_SCOPES, FEISHU_MESSAGE_READ_SCOPE, feishuAppAddons, scopeSatisfied, } from "../channels/feishu/setup-mode.js";
8
+ import { FEISHU_APP_CONFIG_SCOPE, feishuAppAddons, feishuAppScopes, feishuScopeRequestUrl, scopeSatisfied, } from "../channels/feishu/setup-mode.js";
9
9
  import { cloudFor } from "../channels/feishu/cloud.js";
10
10
  import { createFeishuApi, isFeishuConfigApiMissing, isTransientFeishuRegistrationError, } from "../channels/feishu/feishu-api.js";
11
11
  import { registerFeishuApp } from "../channels/feishu/register-app.js";
12
- import { onboardLarkApp } from "../channels/lark/onboard.js";
13
- import { dotEnvPath, parseEnvContent } from "../env.js";
12
+ import { LARK_CONSOLE_URL, onboardLarkApp } from "../channels/lark/onboard.js";
13
+ import { dotEnvPath, loadEnvValues, parseEnvContent } from "../env.js";
14
14
  import { openExternalUrl } from "../open-url.js";
15
+ import { terminalPerson } from "./person.js";
16
+ import { AGENT_ENVIRONMENT_ENV } from "../paths.js";
15
17
  import { appendChannelDotEnv } from "../scaffold/add-channel.js";
16
18
  import { startCloudflareTunnel } from "../tunnel.js";
17
- export async function configureGroupBehavior(input) {
18
- const { kind, appId, apiBase, api, behavior, explicit } = input;
19
+ /**
20
+ * Check that the app holds what an app of this ingress needs ({@link feishuAppScopes}). A created app asks for them on
21
+ * its confirm page, and a tenant may still withhold some (its approval policy, or an app made by hand): those are
22
+ * NAMED, with what each one costs, and the console page that requests them is opened pre-filled. Nothing is requested
23
+ * through the config API — that needs a scope of its own, which a tenant can withhold just the same.
24
+ */
25
+ export async function checkAgentScopes(input) {
26
+ const { kind, appId, apiBase, api } = input;
19
27
  const note = input.note ?? ((message) => console.error(message));
20
- const openUrl = input.openUrl ?? openExternalUrl;
28
+ const person = input.person ?? terminalPerson;
29
+ const needed = feishuAppScopes(input.ingress);
30
+ const requested = needed.map((entry) => entry.request);
21
31
  let scopes;
22
- let inspected = true;
23
32
  try {
24
33
  scopes = await api.listAppScopes();
25
34
  }
26
35
  catch (error) {
27
- note(`[fastagent] warn: could not inspect ${kind} group-message permission: ${String(error)} — check Permissions & Scopes manually`);
28
- inspected = false;
29
- scopes = [];
30
- }
31
- const granted = (name) => scopes.some((scope) => scope.name === name && scope.grantStatus === 1 && (scope.type === undefined || scope.type === "tenant"));
32
- // Same type filter as `granted`: a user-type entry is not the tenant scope this path needs, so treating one as "on
33
- // the app" would report an approval that can never arrive and skip the PATCH that would actually add it.
34
- const onApp = (name) => scopes.some((scope) => scope.name === name && (scope.type === undefined || scope.type === "tenant"));
35
- // Both halves of the recommended path: delivery (the platform pushes un-mentioned group messages) and reading a
36
- // quoted message (so a thread's opening ask carries what it replies to).
37
- const missing = FEISHU_CONTEXT_ONBOARDING_SCOPES.filter((entry) => !scopeSatisfied(entry, granted));
38
- const missingNames = missing.map((entry) => entry.request);
39
- if (behavior === "mentions") {
40
- if (!inspected) {
41
- const permissionUrl = `${apiBase}/app/${encodeURIComponent(appId)}/permission`;
42
- note(`[fastagent] mention-only scope state could not be verified — check Permissions before publishing. Opening ${permissionUrl}`);
43
- openUrl(permissionUrl);
44
- return { publishReady: false };
45
- }
46
- if (granted(FEISHU_GROUP_CONTEXT_SCOPE)) {
47
- const permissionUrl = `${apiBase}/app/${encodeURIComponent(appId)}/permission`;
48
- note(`[fastagent] warn: mention-only was selected, but ${FEISHU_GROUP_CONTEXT_SCOPE} is already granted — remove it before publishing a new version to restore least-privilege platform delivery. Opening ${permissionUrl}`);
49
- openUrl(permissionUrl);
50
- return { publishReady: false };
51
- }
52
- note(`[fastagent] group behavior: mention-only — bare replies in the Agent's threads and group context buffering are disabled. ` +
53
- `Add ${FEISHU_MESSAGE_READ_SCOPE} by hand if you want an @mention to carry the message it quotes`);
54
- return { publishReady: true };
36
+ const url = feishuScopeRequestUrl(apiBase, appId, requested);
37
+ note(`[fastagent] warn: could not read the ${kind} app's permissions: ${String(error)}`);
38
+ person.afterwards(`make sure the ${kind} app holds ${requested.join(", ")} before publishing`, url);
39
+ return { publishReady: false, missing: [] };
55
40
  }
56
- note(`[fastagent] group behavior: context-aware (recommended) — ${kind} will deliver all group messages; ` +
57
- `FastAgent invokes @Agent, answers bare replies in threads it takes part in, and durably buffers ` +
58
- `other discussion. ${FEISHU_GROUP_CONTEXT_SCOPE} (delivery) is required; ${FEISHU_MESSAGE_READ_SCOPE} ` +
59
- `(reading a quoted message) is requested with it — without it a quoted message degrades to a marker`);
41
+ // A user-type entry is not the tenant scope the app acts with.
42
+ const tenant = scopes.filter((scope) => scope.type === undefined || scope.type === "tenant");
43
+ const granted = (name) => tenant.some((scope) => scope.name === name && scope.grantStatus === 1);
44
+ const missing = needed.filter((entry) => !scopeSatisfied(entry, granted));
60
45
  if (missing.length === 0) {
61
- note(`[fastagent] ${FEISHU_CONTEXT_ONBOARDING_SCOPES.map((entry) => entry.request).join(" + ")} are already granted`);
62
- return { publishReady: true };
63
- }
64
- const permissionUrl = `${apiBase}/app/${encodeURIComponent(appId)}/permission`;
65
- // A missing scope is in one of two states, and they need different actions.
66
- const awaitingApproval = missing.filter((entry) => scopeSatisfied(entry, onApp)).map((entry) => entry.request);
67
- const toRequest = missing.filter((entry) => !scopeSatisfied(entry, onApp)).map((entry) => entry.request);
68
- if (toRequest.length === 0) {
69
- note(`[fastagent] ${awaitingApproval.join(" + ")} awaiting approval — complete tenant-admin approval before publishing. Opening ${permissionUrl}`);
70
- openUrl(permissionUrl);
71
- return { publishReady: false };
72
- }
73
- if (!explicit) {
74
- // Defaulted, not chosen: report the gap and how to opt in, but leave the app's requested permission set untouched
75
- // (a scripted re-run must not silently escalate a mention-only app).
76
- note(`[fastagent] ${missingNames.join(" + ")} not granted (or could not be verified) — group behavior was ` +
77
- `defaulted, so nothing was requested. Re-run with --group-behavior context to add ${missing.length > 1 ? "them" : "it"} ` +
78
- `to the app draft, or --group-behavior mentions to stay least-privilege: ${permissionUrl}`);
79
- return { publishReady: false };
80
- }
81
- try {
82
- await api.addAppScopes(appId, toRequest);
83
- note(`[fastagent] added ${toRequest.join(" + ")} to the app draft — complete tenant-admin approval before publishing. Opening ${permissionUrl}`);
84
- }
85
- catch (error) {
86
- note(`[fastagent] warn: could not add ${toRequest.join(" + ")} automatically: ${String(error)} — add it manually before publishing. Opening ${permissionUrl}`);
46
+ note(`[fastagent] ${kind} app permissions: ${requested.join(", ")} granted`);
47
+ return { publishReady: true, missing: [] };
87
48
  }
88
- openUrl(permissionUrl);
89
- return { publishReady: false };
49
+ // "Not granted", not "not requested": the list omits a scope still under review (measured), so the two look alike.
50
+ const describe = (entry) => `\n ${entry.request}: without it ${entry.withoutIt}`;
51
+ const url = feishuScopeRequestUrl(apiBase, appId, missing.map((entry) => entry.request));
52
+ person.afterwards(`the ${kind} app is not granted:${missing.map(describe).join("")}\n` +
53
+ `Tick and enable them on that page (one may already be awaiting a tenant admin's approval), before publishing`, url);
54
+ return { publishReady: false, missing: missing.map((entry) => entry.request) };
90
55
  }
91
56
  /** Create or resume the platform app behind `add feishu` / `add lark`. */
92
- export async function onboardFeishuCloudApp(target, kind, ingress = "webhook", groupBehavior = { behavior: "context", explicit: false }) {
57
+ export async function onboardFeishuCloudApp(target, kind, ingress,
58
+ /** The command that continues an interrupted setup: the one that started it. */
59
+ rerun = `fastagent add ${kind}${ingress === "webhook" ? " --ingress webhook" : ""}`,
60
+ /** Who takes the steps only a person can: at this terminal, or a coding agent's person through a ticket. */
61
+ person = terminalPerson) {
93
62
  const env = dotEnvPath(target); // the file actually written — never the default spelling
94
63
  const { envPrefix, apiBase, capabilities } = cloudFor(kind);
95
- const requiredNames = [
96
- `${envPrefix}_APP_ID`,
97
- `${envPrefix}_APP_SECRET`,
98
- ...(ingress === "webhook" ? [`${envPrefix}_VERIFICATION_TOKEN`] : []),
99
- ];
64
+ const requiredNames = feishuAppSecretNames(kind, ingress);
100
65
  const existing = await activeDotEnvValues(target, requiredNames);
66
+ if (process.env[AGENT_ENVIRONMENT_ENV] === "production") {
67
+ assertIndependentFeishuApps(target, [kind], new Map(Object.entries(existing)));
68
+ }
101
69
  if (Object.keys(existing).length === requiredNames.length) {
102
70
  console.error(`[fastagent] ${requiredNames.join("/")} already set in ${env} — keeping them`);
103
71
  // WebSocket still needs its console mode/publish guidance.
104
72
  if (ingress === "webhook") {
105
73
  const appId = existing[`${envPrefix}_APP_ID`];
106
74
  const appSecret = existing[`${envPrefix}_APP_SECRET`];
107
- await configureGroupBehavior({
75
+ await checkAgentScopes({
108
76
  kind,
109
77
  appId,
110
78
  apiBase,
79
+ ingress,
111
80
  api: createFeishuApi({ kind, baseUrl: apiBase, appId, appSecret }),
112
- behavior: groupBehavior.behavior,
113
- explicit: groupBehavior.explicit,
81
+ person,
114
82
  });
115
83
  return undefined;
116
84
  }
117
85
  }
118
86
  if (capabilities.appCreation === "scan-to-create") {
119
- await createFeishuAppFlow(target, existing, ingress, groupBehavior);
87
+ await createFeishuAppFlow(target, existing, ingress, rerun, person);
120
88
  return undefined;
121
89
  }
122
90
  // guided-console (lark): the intl cloud cannot complete the bound device flow — collect + validate.
123
- if (!(process.stdin.isTTY && process.stdout.isTTY) &&
124
- !(existing[`${envPrefix}_APP_ID`] && existing[`${envPrefix}_APP_SECRET`])) {
125
- throw new Error("`add lark` needs an interactive terminal to onboard the Lark app credentials — re-run it in a terminal");
126
- }
127
- const credentials = await onboardLarkApp({
128
- openUrl: openExternalUrl,
129
- note: (message) => clackLog.info(message),
130
- async prompt(message, opts) {
131
- const result = opts?.hidden ? await password({ message }) : await clackText({ message });
132
- return isCancel(result) ? undefined : result;
133
- },
134
- }, {
91
+ const credentials = await onboardLarkApp(person === terminalPerson ? larkAtTerminal : larkThrough(person, env, rerun), {
135
92
  existing,
136
93
  ingress,
137
- groupBehavior: groupBehavior.behavior,
94
+ rerun,
138
95
  verifyCredentials: async (appId, appSecret) => {
96
+ if (process.env[AGENT_ENVIRONMENT_ENV] === "production") {
97
+ assertIndependentFeishuApps(target, ["lark"], new Map([["LARK_APP_ID", appId]]));
98
+ }
139
99
  await createFeishuApi({ kind: "lark", baseUrl: apiBase, appId, appSecret }).verifyCredentials();
140
100
  console.error(`[fastagent] Lark App ID / Secret verified`);
141
101
  },
@@ -165,23 +125,48 @@ export async function onboardFeishuCloudApp(target, kind, ingress = "webhook", g
165
125
  }
166
126
  },
167
127
  });
168
- await configureGroupBehavior({
128
+ await checkAgentScopes({
169
129
  kind: "lark",
170
130
  appId: credentials.LARK_APP_ID,
171
131
  apiBase,
132
+ ingress,
133
+ person,
172
134
  api: createFeishuApi({
173
135
  kind: "lark",
174
136
  baseUrl: apiBase,
175
137
  appId: credentials.LARK_APP_ID,
176
138
  appSecret: credentials.LARK_APP_SECRET,
177
139
  }),
178
- behavior: groupBehavior.behavior,
179
- explicit: groupBehavior.explicit,
180
140
  });
181
141
  return Object.fromEntries(Object.entries(credentials).filter((entry) => typeof entry[1] === "string"));
182
142
  }
143
+ /** Lark's guided console at a terminal: what to open, and the values asked for there. */
144
+ const larkAtTerminal = {
145
+ openUrl(url, action) {
146
+ clackLog.info(`${action}. Opening ${url}`);
147
+ openExternalUrl(url);
148
+ },
149
+ note: (message) => clackLog.info(message),
150
+ async prompt(message, opts) {
151
+ const result = opts?.hidden ? await password({ message }) : await clackText({ message });
152
+ return isCancel(result) ? undefined : result;
153
+ },
154
+ };
155
+ /**
156
+ * Lark's guided console through a coding agent's person: a page is a step left to them, with what they do there; a
157
+ * value it would ask for is theirs to set in the value file, and the setup continues when run again.
158
+ */
159
+ function larkThrough(person, env, rerun) {
160
+ return {
161
+ note: (message) => console.error(`[fastagent] ${message}`),
162
+ openUrl: (url, action) => person.afterwards(action, url),
163
+ async prompt(message) {
164
+ throw new Error(`${message} is needed: ask the user to set it in ${env}, then run \`${rerun}\` again`);
165
+ },
166
+ };
167
+ }
183
168
  /** The scan-to-create flow `add feishu` runs by default. */
184
- async function createFeishuAppFlow(target, existing, ingress, groupBehavior) {
169
+ async function createFeishuAppFlow(target, existing, ingress, rerun, person) {
185
170
  const env = dotEnvPath(target); // the file actually written — never the default spelling
186
171
  const { apiBase } = cloudFor("feishu");
187
172
  let appId = existing.FEISHU_APP_ID;
@@ -194,15 +179,13 @@ async function createFeishuAppFlow(target, existing, ingress, groupBehavior) {
194
179
  else {
195
180
  console.error(`[fastagent] creating the Feishu app (confirm in the app)…`);
196
181
  const app = await registerFeishuApp({
197
- name: "{user}'s agent", // the platform expands {user} to the confirming user's name; editable on the page
182
+ name: process.env[AGENT_ENVIRONMENT_ENV] === "production" ? "{user}'s production agent" : "{user}'s agent",
198
183
  desc: "Served by fastagent",
199
- // The agent template alone is not enough to SERVE (see feishuAppAddons).
200
- addons: feishuAppAddons(),
201
- onVerificationUrl: ({ url, expiresInS }) => {
202
- console.error(`\n Opening the confirmation link in your browser (or open it in Feishu / render it as a QR code) — valid for ${Math.round(expiresInS / 60)} minutes:\n\n ${url}\n\n waiting for confirmation… (keep this running — the credentials are delivered here)`);
203
- openExternalUrl(url); // best-effort, like `login` — the URL above is the fallback
204
- },
184
+ // The agent template alone is not enough to SERVE, nor to hear a group (see feishuAppAddons).
185
+ addons: feishuAppAddons(ingress),
186
+ onVerificationUrl: ({ url, expiresInS }) => person.waitsOn(url, "confirm the new Feishu app (in a browser, or in Feishu, or as a QR code)", Date.now() + expiresInS * 1000),
205
187
  });
188
+ person.carriesOn();
206
189
  console.error(`[fastagent] app created: ${app.appId}${app.tenantBrand ? ` (${app.tenantBrand} tenant)` : ""}`);
207
190
  // A cross-brand confirmation should be impossible (each confirm page refuses the other brand's code).
208
191
  if (app.tenantBrand && app.tenantBrand !== "feishu") {
@@ -221,25 +204,22 @@ async function createFeishuAppFlow(target, existing, ingress, groupBehavior) {
221
204
  ? `[fastagent] wrote FEISHU_APP_ID, FEISHU_APP_SECRET to ${env} before Token bootstrap`
222
205
  : `[fastagent] wrote FEISHU_APP_ID, FEISHU_APP_SECRET to ${env}`);
223
206
  }
224
- const groupSetup = await configureGroupBehavior({
207
+ const groupSetup = await checkAgentScopes({
225
208
  kind: "feishu",
226
209
  appId,
227
210
  apiBase,
211
+ ingress,
228
212
  api: createFeishuApi({ kind: "feishu", baseUrl: apiBase, appId, appSecret }),
229
- behavior: groupBehavior.behavior,
230
- explicit: groupBehavior.explicit,
213
+ person,
231
214
  });
232
215
  if (ingress === "websocket") {
233
216
  const versionUrl = `${apiBase}/app/${appId}/version`;
234
- if (groupSetup.publishReady) {
235
- console.error(`[fastagent] WebSocket ingress needs no Verification Token, Encrypt Key, Request URL, or tunnel. ` +
236
- `Choose long connection in Events & Callbacks, then CREATE + PUBLISH a version. Opening ${versionUrl}`);
237
- openExternalUrl(versionUrl);
238
- }
239
- else {
240
- console.error(`[fastagent] WebSocket ingress needs no Verification Token, Encrypt Key, Request URL, or tunnel. ` +
241
- `Choose long connection in Events & Callbacks, finish the permission work opened above, then CREATE + PUBLISH: ${versionUrl}`);
242
- }
217
+ const choose = "WebSocket ingress needs no Verification Token, Encrypt Key, Request URL, or tunnel: choose long connection in " +
218
+ "Events & Callbacks";
219
+ if (groupSetup.publishReady)
220
+ person.afterwards(`${choose}, then CREATE + PUBLISH a version`, versionUrl);
221
+ else
222
+ person.afterwards(`${choose}, finish the permission work above, then CREATE + PUBLISH a version: ${versionUrl}`);
243
223
  return;
244
224
  }
245
225
  // The webhook channel authenticates plaintext events by the platform-generated Verification Token.
@@ -256,20 +236,29 @@ async function createFeishuAppFlow(target, existing, ingress, groupBehavior) {
256
236
  // it was needed would otherwise be invisible.
257
237
  console.error(`[fastagent] could not read the app's Verification Token directly: ${error.message}`);
258
238
  }
259
- if (!token) {
239
+ // The bootstrap registers a Request URL through the config scope; without it every attempt is refused, so it is not
240
+ // tried, and the reason is the one the permission check above already named.
241
+ const configWithheld = groupSetup.missing.includes(FEISHU_APP_CONFIG_SCOPE);
242
+ if (!token && configWithheld) {
243
+ console.error(`[fastagent] not capturing the Verification Token: the app is not granted ${FEISHU_APP_CONFIG_SCOPE}. Choose webhook ` +
244
+ `in Events & Callbacks and set the Request URL there yourself (dev --tunnel and deploy --run cannot ` +
245
+ `either), or have the permission approved and re-run \`${rerun}\`.`);
246
+ }
247
+ else if (!token) {
260
248
  console.error(`[fastagent] capturing the Verification Token — a throwaway webhook registration delivers it (spinning up a temporary tunnel; can take a few minutes on a slow edge)…`);
261
249
  try {
262
250
  token = await bootstrapFeishuVerificationToken({
263
251
  api,
264
252
  appId,
265
253
  startTunnel: (port) => startCloudflareTunnel(port),
254
+ // Only edge weather is retried; a refusal (scope, auth, app under review) is reported as itself.
255
+ shouldRetryPatch: isTransientFeishuRegistrationError,
266
256
  });
267
257
  webhookModeChanged = true;
268
258
  console.error(`[fastagent] Verification Token captured`);
269
259
  }
270
260
  catch (e) {
271
- // Transient tunnel weather is the usual cause.
272
- console.error(`[fastagent] warn: could not capture the Verification Token: ${String(e)} — usually a transient tunnel issue; finish this app with the manual copy below`);
261
+ console.error(`[fastagent] warn: could not capture the Verification Token: ${String(e)} — finish this app with the manual copy below`);
273
262
  }
274
263
  }
275
264
  if (token) {
@@ -278,20 +267,47 @@ async function createFeishuAppFlow(target, existing, ingress, groupBehavior) {
278
267
  console.error(`[fastagent] wrote ${staged.written.join(", ")} to ${env}`);
279
268
  }
280
269
  else {
281
- console.error(`[fastagent] copy it manually: developer console → Events & Callbacks → Encryption Strategy → Verification Token → ${tokenVar} in ${env}`);
270
+ person.afterwards(`copy the Verification Token: developer console → Events & Callbacks → Encryption Strategy → Verification ` +
271
+ `Token → ${tokenVar} in ${env}`);
282
272
  }
283
273
  if (webhookModeChanged) {
284
274
  // The bootstrap's PATCH flipped event mode in the DRAFT.
285
275
  const versionUrl = `${apiBase}/app/${appId}/version`;
286
- if (groupSetup.publishReady) {
287
- console.error(`[fastagent] one console click remains: CREATE + PUBLISH a version (self-approved) — the switch to webhook mode takes effect on publish. Opening ${versionUrl}`);
288
- openExternalUrl(versionUrl);
289
- }
290
- else {
291
- console.error(`[fastagent] after the permission work opened above, CREATE + PUBLISH a version — the switch to webhook mode takes effect on publish: ${versionUrl}`);
292
- }
276
+ const publish = "CREATE + PUBLISH a version (self-approved): the switch to webhook mode takes effect on publish";
277
+ if (groupSetup.publishReady)
278
+ person.afterwards(publish, versionUrl);
279
+ else
280
+ person.afterwards(`after the permission work above, ${publish}: ${versionUrl}`);
293
281
  }
294
282
  }
283
+ /**
284
+ * Lark's app credentials, which only the person can get, from the app they create in Lark's console: with no one at a
285
+ * terminal to type them, the report naming where they set them (the selected environment's file), when either is
286
+ * absent. `again` is the command that continues once they have.
287
+ */
288
+ export async function larkCredentialsNeeded(agentDir, again) {
289
+ const held = await activeDotEnvValues(agentDir, ["LARK_APP_ID", "LARK_APP_SECRET"]);
290
+ if (held.LARK_APP_ID && held.LARK_APP_SECRET)
291
+ return undefined;
292
+ const valueFile = dotEnvPath(agentDir);
293
+ return {
294
+ json: {
295
+ status: "need_user_action",
296
+ url: LARK_CONSOLE_URL,
297
+ variables: ["LARK_APP_ID", "LARK_APP_SECRET"],
298
+ value_file: valueFile,
299
+ check_command: `${again} --json`,
300
+ agent_next_steps: "Give the URL to the user so they can create the Lark app there, and ask them to set LARK_APP_ID and " +
301
+ `LARK_APP_SECRET (from its Credentials & Basic Info) in ${valueFile} themselves, not in this ` +
302
+ "conversation. Once they say they have, run check_command.",
303
+ },
304
+ text: [
305
+ `need_user_action: create the Lark app at ${LARK_CONSOLE_URL}`,
306
+ ` and set LARK_APP_ID and LARK_APP_SECRET in ${valueFile}`,
307
+ `then run: ${again}`,
308
+ ],
309
+ };
310
+ }
295
311
  /**
296
312
  * Active agent `.env` (`.secrets/.env`) values for the requested names — decided by THE .env parser, so this check can
297
313
  * never disagree with what `loadDotEnv` reads.
@@ -312,3 +328,40 @@ async function activeDotEnvValues(dir, names) {
312
328
  return value ? [[name, value]] : [];
313
329
  }));
314
330
  }
331
+ export function feishuAppSecretNames(kind, ingress) {
332
+ const prefix = cloudFor(kind).envPrefix;
333
+ return [
334
+ `${prefix}_APP_ID`,
335
+ `${prefix}_APP_SECRET`,
336
+ ...(ingress === "webhook" ? [`${prefix}_VERIFICATION_TOKEN`] : []),
337
+ ];
338
+ }
339
+ export function unpreparedFeishuApps(channels, values) {
340
+ return ["feishu", "lark"].flatMap((kind) => {
341
+ const channel = channels.find((entry) => entry.name === kind);
342
+ if (!channel)
343
+ return [];
344
+ const ingress = channel.ingress === "webhook" ? "webhook" : "websocket";
345
+ return feishuAppSecretNames(kind, ingress).some((name) => !values.get(name)?.trim()) ? [{ kind, ingress }] : [];
346
+ });
347
+ }
348
+ export function assertIndependentFeishuApps(agentDir, kinds, values) {
349
+ const devFile = dotEnvPath(agentDir, {});
350
+ const devValues = loadEnvValues(devFile);
351
+ for (const kind of kinds) {
352
+ const name = `${cloudFor(kind).envPrefix}_APP_ID`;
353
+ const appId = values.get(name)?.trim();
354
+ if (appId && appId === devValues.get(name)?.trim()) {
355
+ throw new Error(`${kind}: dev and production use the same app (${name}) — create a separate production app in ` +
356
+ `${dotEnvPath(agentDir)}; copying dev credentials would take its messages away`);
357
+ }
358
+ }
359
+ }
360
+ export async function prepareFeishuApps(agentDir, apps, rerun, person, onboard = onboardFeishuCloudApp) {
361
+ for (const { kind, ingress } of apps) {
362
+ console.error(`[fastagent] ${kind}: preparing the production app for ${ingress} in ${dotEnvPath(agentDir)}`);
363
+ const created = await onboard(agentDir, kind, ingress, rerun, person);
364
+ if (created)
365
+ await appendChannelDotEnv(agentDir, kind, created, Object.keys(created), ingress);
366
+ }
367
+ }
@@ -1,5 +1,5 @@
1
- import { type GroupBehaviorChoice } from "../scaffold/add-channel.ts";
2
- /** Interactive single-workspace internal-app creation + installation. */
1
+ import type { Person } from "./person.ts";
2
+ /** Single-workspace internal-app creation + installation. */
3
3
  export declare function onboardSlackInternalApp(input: {
4
4
  /**
5
5
  * The AGENT DIR — credentials land in its `.env` ({@link dotEnvPath}: `FASTAGENT_SECRETS_DIR` moves it, so messages
@@ -7,7 +7,12 @@ export declare function onboardSlackInternalApp(input: {
7
7
  */
8
8
  target: string;
9
9
  stateRoot: string;
10
- groupBehavior: GroupBehaviorChoice;
11
10
  /** `--replace-config`: go straight to replacing the local App Configuration token pair. */
12
11
  replaceConfig?: boolean;
12
+ /**
13
+ * A coding agent's person, through a ticket: nothing is asked at a terminal. The token pair is pasted on a page the
14
+ * setup server shows, which then takes the browser on to Slack's install page; the app takes its default name, and
15
+ * a saved pair is kept. Absent: the terminal asks.
16
+ */
17
+ person?: Person;
13
18
  }): Promise<void>;