@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
@@ -1,51 +1,124 @@
1
1
  /**
2
- * `fastagent add <channel>|skill` — scaffold channel glue (`channels/<kind>.ts`) or vendor an Agent Skills skill.
2
+ * `fastagent add <channel>|skill` — scaffold channel glue (`src/channels/<kind>.ts`) or vendor an Agent Skills skill.
3
3
  * slack/feishu/lark additionally CREATE OR RESUME the platform app.
4
4
  */
5
5
  import { randomBytes } from "node:crypto";
6
- import { readFile } from "node:fs/promises";
7
6
  import { join, relative, resolve } from "node:path";
8
- import { isCancel, select } from "@clack/prompts";
9
- import { onboardFeishuCloudApp } from "../add-feishu.js";
10
- import { dotEnvPath, enterAgentEnv } from "../../env.js";
11
- import { resolveStateRoot, SECRETS_DIRNAME, isUnderDir, displayPath } from "../../paths.js";
7
+ import { assertIndependentFeishuApps, larkCredentialsNeeded, onboardFeishuCloudApp } from "../add-feishu.js";
8
+ import { terminalPerson } from "../person.js";
9
+ import { isInteractive, shellArg } from "../shared.js";
10
+ import { checkTicket, printReport, refusedCheck, runTicket, startTicket, ticketExitCode, ticketReport, } from "../ticket.js";
11
+ import { cloudFor } from "../../channels/feishu/cloud.js";
12
+ import { feishuIngressFor } from "../../channels/feishu/setup-mode.js";
13
+ import { markDevServe, unmarkDevServe } from "../../serving-command.js";
14
+ import { channelIngress } from "../../channels/discover.js";
15
+ import { buildDefinitionShape, prepareDefinition } from "../../harnesses/pi-durable/open.js";
16
+ import { dotEnvPath, enterAgentEnv, loadEnvValues } from "../../env.js";
17
+ import { selectAgentEnvironment, resolveStateRoot, SECRETS_DIRNAME, isUnderDir, displayPath } from "../../paths.js";
12
18
  import { detectRuntime, readPackageJson } from "../../runtime.js";
13
19
  import { appendChannelDotEnv, appendChannelEnv, assertChannelReady, channelExists, channelSetup, scaffoldChannel, scaffoldCompanionTools, } from "../../scaffold/add-channel.js";
14
20
  import { vendorSkill } from "../../scaffold/vendor-skill.js";
15
- import { failStartup, failUsage, placementOrExit } from "../fail.js";
16
- /** `fastagent add <kind> [dir]`: scaffold `channels/<kind>.ts` — the adapter import plus a starter `on()`. */
21
+ import { failStartup, failUsage, agentDirOrExit } from "../fail.js";
22
+ import { unprotectedSecretsNote } from "../../value-file.js";
23
+ /** Without a terminal, how long an app's setup stays open for the person to finish their part. */
24
+ const UNATTENDED_TIMEOUT_SECONDS = 900;
25
+ /** `fastagent add <kind> [dir]`: scaffold `src/channels/<kind>.ts`, the adapter configured with a starter policy. */
17
26
  export async function runAddChannel(channelKind, dirArg, opts) {
18
- // The channel (glue + companion tool + secrets) is agent surface — everything lands in the AGENT DIR
19
- // (`fastagent/`), the same place dev/start discover channels/.
27
+ if (opts.check !== undefined)
28
+ return checkSetup(channelKind, opts.check, opts);
29
+ if (opts.ticket !== undefined) {
30
+ // The process `startTicket` started: it takes the ticket before anything slow (the definition is built to plan),
31
+ // then does the whole `add`, its person the ticket's.
32
+ await runTicket(opts.ticket, async (step) => ({
33
+ ...(await addChannel(channelKind, await planAdd(channelKind, dirArg, opts), opts, step.person)),
34
+ }));
35
+ process.exit(0);
36
+ }
37
+ const plan = await planAdd(channelKind, dirArg, opts);
38
+ const unattended = opts.input === false || opts.json === true || !isInteractive();
39
+ if (unattended && opts.onboard !== false && channelKind !== "telegram") {
40
+ return setUpUnattended(channelKind, opts, plan);
41
+ }
42
+ const added = await addChannel(channelKind, plan, opts, terminalPerson).catch(failStartup);
43
+ if (opts.json)
44
+ console.log(JSON.stringify({ status: "done", ...added }, null, 2));
45
+ // App-creation flows leave platform/tunnel sockets behind that would otherwise hold the one-shot scaffold command
46
+ // open after all durable boundaries have completed.
47
+ process.exit(0);
48
+ }
49
+ /** What `add` settles before it changes anything, refusing what it can while nothing has changed. */
50
+ async function planAdd(channelKind, dirArg, opts) {
51
+ // The channel (glue + companion tools + secrets) is agent surface: everything lands in the AGENT DIR.
20
52
  if (opts.replaceConfig && opts.onboard === false) {
21
53
  failUsage("--replace-config replaces onboarding credentials; it cannot be combined with --no-onboard");
22
54
  }
23
- const { agentDir: target } = placementOrExit(resolve(dirArg));
24
- enterAgentEnv(target); // onboarding state follows the same FASTAGENT_STATE_DIR as serving/deploy
25
- // Paths are printed to someone standing in their CWD, usually the workspace, while every file belongs to the AGENT
55
+ const target = agentDirOrExit(resolve(dirArg));
56
+ const environment = opts.environment ?? "dev";
57
+ if (environment !== "dev" && environment !== "production") {
58
+ failUsage(`--env must be "dev" or "production", got "${environment}"`);
59
+ }
60
+ selectAgentEnvironment(environment);
61
+ if (environment === "production")
62
+ unmarkDevServe();
63
+ else
64
+ markDevServe();
65
+ enterAgentEnv(target);
66
+ if (environment === "production" && (channelKind === "feishu" || channelKind === "lark")) {
67
+ try {
68
+ assertIndependentFeishuApps(target, [channelKind], loadEnvValues(dotEnvPath(target)));
69
+ }
70
+ catch (error) {
71
+ failStartup(error);
72
+ }
73
+ }
74
+ // Paths are printed to someone standing in their CWD, which may be elsewhere, while every file belongs to the AGENT
26
75
  // dir — prefix them, or they point at nothing.
27
76
  const agentFromCwd = displayPath(process.cwd(), target);
28
77
  const inAgent = (p) => (agentFromCwd === undefined ? p : join(agentFromCwd, p));
29
- const envPath = dotEnvPath(target);
30
- const envLabel = isUnderDir(envPath, target) ? inAgent(relative(target, envPath)) : envPath;
31
78
  // An existing channel file is authored glue: kept, never rewritten.
32
- const file = join(target, "channels", `${channelKind}.ts`);
79
+ const file = join(target, "src", "channels", `${channelKind}.ts`);
33
80
  const existsAlready = await channelExists(target, channelKind).catch(failStartup);
34
- const ingress = await resolveIngress(channelKind, file, existsAlready, opts.ingress);
35
- const groupBehavior = await resolveGroupBehavior(channelKind, opts.groupBehavior);
81
+ const ingress = resolveIngress(channelKind, opts.ingress);
82
+ if (existsAlready &&
83
+ (ingress.setting || (environment === "production" && opts.onboard !== false)) &&
84
+ (channelKind === "feishu" || channelKind === "lark")) {
85
+ await assertChannelReadsSetting(target, channelKind, ingress.setting ?? { [`${cloudFor(channelKind).envPrefix}_INGRESS`]: ingress.ingress }, inAgent(relative(target, file)));
86
+ }
87
+ return {
88
+ target,
89
+ environment,
90
+ inAgent,
91
+ agentFromCwd,
92
+ file,
93
+ existsAlready,
94
+ ...ingress,
95
+ rerun: `fastagent add ${channelKind}${agentFromCwd === undefined ? "" : ` ${shellArg(agentFromCwd)}`}` +
96
+ `${environment === "production" ? " --env production" : ""}${opts.ingress ? ` --ingress ${opts.ingress}` : ""}` +
97
+ `${opts.replaceConfig ? " --replace-config" : ""}`,
98
+ };
99
+ }
100
+ /**
101
+ * Everything `add <kind>` does once the person's part can be done: the channel, its tools and variables, the app's
102
+ * onboarding through `person`, and the next steps, printed and returned with the variables it wrote.
103
+ */
104
+ async function addChannel(channelKind, plan, opts, person) {
105
+ const { target, environment, inAgent, agentFromCwd, file, existsAlready, ingress, pinned, setting, rerun } = plan;
106
+ const envPath = dotEnvPath(target);
107
+ const envLabel = isUnderDir(envPath, target) ? inAgent(relative(target, envPath)) : envPath;
108
+ const before = loadEnvValues(envPath);
36
109
  if (existsAlready) {
37
- console.error(`[fastagent] ${relative(target, file)} already exists — keeping it`);
110
+ console.error(`[fastagent] ${inAgent(relative(target, file))} already exists — keeping it`);
38
111
  }
39
112
  else {
40
- await assertChannelReady(target).catch(failStartup);
41
- await scaffoldChannel(target, channelKind, { ingress }).catch(failStartup);
42
- console.error(`[fastagent] created ${relative(target, file)}`);
113
+ await assertChannelReady(target);
114
+ await scaffoldChannel(target, channelKind);
115
+ console.error(`[fastagent] created ${inAgent(relative(target, file))}`);
43
116
  }
44
117
  // Companion tools are the package's, not authored glue.
45
- for (const tool of await scaffoldCompanionTools(target, channelKind).catch(failStartup)) {
46
- console.error(`[fastagent] wrote ${relative(target, tool)}`);
118
+ for (const tool of await scaffoldCompanionTools(target, channelKind)) {
119
+ console.error(`[fastagent] wrote ${inAgent(relative(target, tool))}`);
47
120
  }
48
- if (await appendChannelEnv(target, channelKind, ingress).catch(failStartup)) {
121
+ if (await appendChannelEnv(target, channelKind)) {
49
122
  console.error(`[fastagent] added ${channelKind} env vars to ${inAgent(join(SECRETS_DIRNAME, ".env.example"))}`);
50
123
  }
51
124
  // Stateful app onboarding is re-runnable after the scaffold boundary.
@@ -55,163 +128,201 @@ export async function runAddChannel(channelKind, dirArg, opts) {
55
128
  created = await onboardSlackInternalApp({
56
129
  target,
57
130
  stateRoot: resolveStateRoot(target),
58
- groupBehavior,
59
131
  replaceConfig: opts.replaceConfig,
60
- })
61
- .then(() => undefined)
62
- .catch(failStartup);
132
+ ...(person === terminalPerson ? {} : { person }),
133
+ }).then(() => undefined);
63
134
  }
64
- else if (channelKind === "feishu" || channelKind === "lark") {
65
- created = await onboardFeishuCloudApp(target, channelKind, ingress, groupBehavior).catch(failStartup);
135
+ else if ((channelKind === "feishu" || channelKind === "lark") && opts.onboard !== false) {
136
+ created = await onboardFeishuCloudApp(target, channelKind, ingress, rerun, person);
66
137
  }
67
- const setup = channelSetup(channelKind, ingress, groupBehavior.behavior);
138
+ const setup = channelSetup(channelKind, ingress, pinned);
68
139
  const env = setup.env;
69
140
  const steps = channelKind === "slack" && opts.onboard !== false
70
141
  ? [
71
142
  // No line about the Request URL: the `dev --tunnel` line below is the whole instruction, and FastAgent sets
72
143
  // that URL itself when the agent first runs.
73
144
  "invite the app to each channel it should read",
74
- "the agent can send messages or files by calling the scaffolded {tools}/slack-send.ts tool",
145
+ // The tool lines are the scaffold's (one list), whichever path set the app up.
146
+ ...setup.steps.filter((step) => step.includes("{tools}/")),
75
147
  ]
76
148
  : setup.steps;
77
149
  const generated = Object.fromEntries(env.filter((e) => e.generate).map((e) => [e.name, randomBytes(24).toString("hex")]));
78
150
  // Kind-neutral: every channel's generated secrets get the same treatment.
79
- const dotEnv = await appendChannelDotEnv(target, channelKind, { ...generated, ...created }, Object.keys(created ?? {}), ingress).catch(failStartup);
151
+ const dotEnv = await appendChannelDotEnv(target, channelKind, { ...generated, ...created, ...setting }, [...Object.keys(created ?? {}), ...Object.keys(setting ?? {})], ingress);
80
152
  if (dotEnv.unprotectedSecretsDir) {
81
- console.error(`[fastagent] note: ${dotEnv.unprotectedSecretsDir} (FASTAGENT_SECRETS_DIR) now holds a secret and has ` +
82
- `no .gitignore — that directory is yours, so fastagent will not write one into it. Make sure git ` +
83
- `does not track what is in there.`);
153
+ console.error(`[fastagent] note: ${unprotectedSecretsNote(dotEnv.unprotectedSecretsDir)}`);
84
154
  }
85
155
  if (dotEnv.written.length > 0) {
86
156
  console.error(`[fastagent] wrote ${dotEnv.written.join(", ")} to ${envLabel}`);
87
157
  }
88
- const install = detectRuntime(target, await readPackageJson(target).catch(failStartup)).runtime === "bun"
89
- ? "bun install"
90
- : "npm install";
158
+ const install = detectRuntime(target, await readPackageJson(target)).runtime === "bun" ? "bun install" : "npm install";
159
+ const next = [];
160
+ /** One next step: printed, and returned for a caller that reads them as data. */
161
+ const step = (line) => {
162
+ next.push(line.trim());
163
+ console.error(` ${line}`);
164
+ };
91
165
  console.error(` next steps:`);
92
- console.error(` ${agentFromCwd === undefined ? install : `(cd ${agentFromCwd} && ${install})`} # if @fastagent-sh/fastagent is not installed yet`);
166
+ step(`${agentFromCwd === undefined ? install : `(cd ${agentFromCwd} && ${install})`} # if @fastagent-sh/fastagent is not installed yet`);
167
+ // Onboarding writes some itself (an app's ID and secret, a bot token) before the write above: what this `add` wrote is
168
+ // what the file holds now and did not before.
169
+ const now = loadEnvValues(envPath);
170
+ const written = [...now.keys()].filter((name) => now.get(name) && now.get(name) !== before.get(name));
93
171
  for (const e of env) {
94
- if (dotEnv.alreadySet.includes(e.name))
95
- continue; // the user already has it — nothing to do
96
- if (dotEnv.written.includes(e.name)) {
172
+ if (!written.includes(e.name) && dotEnv.alreadySet.includes(e.name))
173
+ continue; // the user's already: nothing to do
174
+ if (written.includes(e.name)) {
97
175
  // Written, but its hint may still carry an action — keep the variable visible instead of silently absorbing it.
98
- console.error(` ${e.name} — ${e.generate ? "generated and " : ""}written to ${envLabel} # ${e.hint}`);
176
+ step(`${e.name} — ${e.generate ? "generated and " : ""}written to ${envLabel} # ${e.hint}`);
99
177
  continue;
100
178
  }
101
179
  const value = e.generate ? `=${generated[e.name]}` : "";
102
180
  const action = e.required ? "set" : "optionally set";
103
- console.error(` ${action} ${e.name}${value} in ${envLabel} # ${e.hint}`);
181
+ step(`${action} ${e.name}${value} in ${envLabel} # ${e.hint}`);
104
182
  }
105
- // Steps carry `{channel}`/`{tools}` path placeholders (their filenames are the scaffold's private knowledge) —
106
- // resolve them to the real agent-dir-relative locations here.
183
+ const serveCommand = environment === "production" ? "fastagent start" : "fastagent dev";
107
184
  for (const s of steps) {
108
- console.error(` ${s.replace("{channel}", inAgent(relative(target, file))).replace("{tools}", inAgent("tools"))}`);
185
+ step(s
186
+ .replace("{channel}", inAgent(relative(target, file)))
187
+ .replace("{tools}", inAgent(join("src", "tools")))
188
+ .replaceAll("{serve}", serveCommand));
109
189
  }
110
- if (ingress === "websocket") {
111
- console.error(` fastagent dev # no public URL or tunnel required`);
190
+ if (environment === "production") {
191
+ step(`fastagent deploy <host> --run # deploy with the production app and credentials`);
192
+ }
193
+ else if (ingress === "websocket") {
194
+ step(`fastagent dev # no public URL or tunnel required`);
112
195
  }
113
196
  else if (channelKind === "slack") {
114
- console.error(` fastagent dev --tunnel # ${opts.onboard === false ? "serve locally + print the URL to paste into the Slack app's Event Subscriptions" : "start the agent — then message it in Slack"}`);
197
+ step(`fastagent dev --tunnel # ${opts.onboard === false ? "serve locally + print the URL to paste into the Slack app's Event Subscriptions" : "start the agent — then message it in Slack"}`);
115
198
  }
116
199
  else if (channelKind !== "lark") {
117
- console.error(` fastagent dev --tunnel # serve locally + a public URL, auto-registering the webhook`);
200
+ step(`fastagent dev --tunnel # serve locally + a public URL, auto-registering the webhook`);
118
201
  }
119
- // App-creation flows leave platform/tunnel sockets behind that would otherwise hold the one-shot scaffold command
120
- // open after all durable boundaries have completed.
121
- process.exit(0);
202
+ return { written, next_steps: next };
122
203
  }
123
- async function resolveIngress(kind, file, existsAlready, raw) {
204
+ /** The command that reads an app's setup ticket, as every such ticket records it. */
205
+ const setupCheck = (kind) => `fastagent add ${kind} --check`;
206
+ /** What the person does for each kind's app, to follow "so they can". */
207
+ const SETUP_ACTIONS = {
208
+ slack: "set up the Slack app: paste a configuration token on the page, then click Allow in Slack",
209
+ feishu: "confirm the new Feishu app",
210
+ lark: "finish setting up the Lark app",
211
+ };
212
+ /**
213
+ * `add slack|feishu|lark` with no one at a terminal to ask, for a coding agent: what the person must provide first is
214
+ * named (Lark's app credentials, in the file the agent reads), never asked for in the agent's conversation; then the
215
+ * app's setup runs in a process of its own (ticket.ts), and the command returns once the person has a step to take, it
216
+ * is done, or it is still working at it.
217
+ */
218
+ async function setUpUnattended(kind, opts, at) {
219
+ const { target } = at;
220
+ if (kind === "lark") {
221
+ const needed = await larkCredentialsNeeded(target, at.rerun).catch(failStartup);
222
+ if (needed !== undefined) {
223
+ printReport(opts.json, needed.json, needed.text);
224
+ process.exit(0);
225
+ }
226
+ }
227
+ const timeout = opts.timeout === undefined ? UNATTENDED_TIMEOUT_SECONDS : Number(opts.timeout);
228
+ if (!Number.isInteger(timeout) || timeout <= 0)
229
+ failUsage(`--timeout must be a whole number of seconds`);
230
+ const ticket = await startTicket({
231
+ // One setup per agent, channel and environment: another agent's is its own business.
232
+ subject: `add:${kind}:${at.environment}:${target}`,
233
+ action: SETUP_ACTIONS[kind],
234
+ check: setupCheck(kind),
235
+ restart: at.rerun,
236
+ timeoutSeconds: timeout,
237
+ waitsFirst: false,
238
+ whenRunning: "replace",
239
+ command: {
240
+ file: process.execPath,
241
+ args: [
242
+ ...process.execArgv,
243
+ process.argv[1],
244
+ "add",
245
+ kind,
246
+ target,
247
+ ...(at.environment === "production" ? ["--env", "production"] : []),
248
+ ...(opts.ingress === undefined ? [] : ["--ingress", opts.ingress]),
249
+ ...(opts.replaceConfig ? ["--replace-config"] : []),
250
+ ],
251
+ cwd: process.cwd(),
252
+ },
253
+ });
254
+ reportSetup(ticket, opts, "started");
255
+ process.exit(ticketExitCode(ticket));
256
+ }
257
+ /** `add <kind> --check <ticket>`. */
258
+ async function checkSetup(kind, id, opts) {
259
+ const refused = refusedCheck(id, setupCheck(kind));
260
+ if (refused !== undefined)
261
+ failUsage(refused);
262
+ // There: refusedCheck read it, and a ticket is pruned only a day after it ends.
263
+ const ticket = (await checkTicket(id));
264
+ reportSetup(ticket, opts, "checked");
265
+ process.exit(ticketExitCode(ticket));
266
+ }
267
+ /** An app's setup ticket for whoever started or checked it: the shared report, and what a finished setup adds. */
268
+ function reportSetup(ticket, opts, when) {
269
+ const { json, text } = ticketReport(ticket, when, (result) => {
270
+ const written = result.written ?? [];
271
+ const next = result.next_steps ?? [];
272
+ return {
273
+ fields: { written, next_steps: next },
274
+ text: [...(written.length > 0 ? [`wrote ${written.join(", ")}`] : []), ...next.map((line) => `next: ${line}`)],
275
+ next: `The app is set up. Its next steps are in next_steps.`,
276
+ };
277
+ });
278
+ printReport(opts.json, json, text);
279
+ }
280
+ /**
281
+ * What `add` sets the app up for, and whether it writes the choice down. `--ingress` is the `<PREFIX>_INGRESS`
282
+ * setting in the selected environment. The channel rule supplies its default: WebSocket in dev, webhook in production.
283
+ */
284
+ function resolveIngress(kind, raw) {
124
285
  if (raw !== undefined && raw !== "webhook" && raw !== "websocket") {
125
286
  failUsage(`--ingress must be "webhook" or "websocket", got "${raw}"`);
126
287
  }
127
- const requested = raw;
128
288
  if (kind !== "feishu" && kind !== "lark")
129
- return "webhook";
130
- if (existsAlready) {
131
- const source = await readFile(file, "utf8").catch(failStartup);
132
- const factory = source.match(/\b(?:feishu|lark)(WebSocket)?Channel\s*\(/);
133
- const existing = factory
134
- ? factory[1] === "WebSocket"
135
- ? "websocket"
136
- : "webhook"
137
- : undefined;
138
- if (!existing) {
139
- if (!requested) {
140
- failUsage(`${file} uses an unrecognized channel factory — re-run with --ingress webhook|websocket to confirm its mode`);
141
- }
142
- return requested;
143
- }
144
- if (requested && requested !== existing) {
145
- failStartup(new Error(`${file} already selects ${existing} delivery — changing mode is a migration; edit the factory and platform subscription together`));
146
- }
147
- return existing;
148
- }
149
- if (requested)
150
- return requested;
151
- if (!(process.stdin.isTTY && process.stdout.isTTY)) {
152
- console.error(`[fastagent] no interactive terminal — defaulting ${kind} ingress to webhook (use --ingress websocket)`);
153
- return "webhook";
154
- }
155
- const answer = await select({
156
- message: `How should ${kind === "feishu" ? "Feishu" : "Lark"} deliver events?`,
157
- // The default must match the non-interactive branch above.
158
- initialValue: "webhook",
159
- options: [
160
- {
161
- value: "webhook",
162
- label: "Webhook endpoint",
163
- hint: "works on every deploy target; supports scale-to-zero; requires a public HTTPS URL",
164
- },
165
- {
166
- value: "websocket",
167
- label: "WebSocket long connection",
168
- hint: "no public URL; needs an always-on process (not on AgentCore)",
169
- },
170
- ],
171
- });
172
- if (isCancel(answer))
173
- failStartup(new Error(`${kind} onboarding cancelled`));
174
- return answer;
289
+ return { ingress: "webhook", pinned: false };
290
+ const name = `${cloudFor(kind).envPrefix}_INGRESS`;
291
+ if (raw !== undefined)
292
+ return { ingress: raw, pinned: true, setting: { [name]: raw } };
293
+ try {
294
+ return {
295
+ ingress: feishuIngressFor(kind, process.env),
296
+ pinned: Boolean(process.env[name]?.trim()),
297
+ };
298
+ }
299
+ catch (error) {
300
+ // A malformed value in the environment: the author's to fix, said as the rule says it.
301
+ return failUsage(error.message);
302
+ }
175
303
  }
176
- async function resolveGroupBehavior(kind, raw) {
177
- if (raw !== undefined && raw !== "context" && raw !== "mentions") {
178
- failUsage(`--group-behavior must be "context" or "mentions", got "${raw}"`);
304
+ /**
305
+ * A setting only takes effect in a channel file that reads it: one that names its factory receives the same way
306
+ * whatever the setting says, so writing the setting (and configuring the app for it) would change nothing but the app.
307
+ * Asked of the channel as the agent builds it, under the value this command is about to write.
308
+ */
309
+ async function assertChannelReadsSetting(target, kind, setting, shown) {
310
+ Object.assign(process.env, setting); // the value this command writes anyway
311
+ const channel = await prepareDefinition(target)
312
+ .then((definition) => buildDefinitionShape(definition, process.env).channels.get(kind))
313
+ .catch((error) => failStartup(new Error(`the agent does not build (${error.message}) — fix it and re-run`)));
314
+ const [[name, value]] = Object.entries(setting);
315
+ const wanted = value === "webhook" ? "webhook" : "long-connection";
316
+ const shape = channel === undefined ? undefined : channelIngress(channel);
317
+ if (shape !== wanted) {
318
+ failStartup(new Error(`${shown} receives by ${shape === "webhook" ? "webhook" : "WebSocket"} whatever ${name} says — it names ` +
319
+ `its factory instead of reading the setting, so ${name}=${value} would change nothing but the app. Move ` +
320
+ `the file aside and re-run to scaffold one that reads it, or edit its factory yourself`));
179
321
  }
180
- if (kind !== "feishu" && kind !== "lark" && kind !== "slack")
181
- return { behavior: "context", explicit: false };
182
- if (raw !== undefined)
183
- return { behavior: raw, explicit: true };
184
- const defaultBehavior = "context";
185
- if (!(process.stdin.isTTY && process.stdout.isTTY)) {
186
- console.error(`[fastagent] no interactive terminal — assuming ${kind} group behavior ${defaultBehavior}; pass --group-behavior explicitly to override`);
187
- return { behavior: defaultBehavior, explicit: false };
188
- }
189
- const choices = [
190
- {
191
- value: "context",
192
- label: "Context-aware groups (recommended)",
193
- hint: kind === "slack"
194
- ? "bare replies in the Agent's threads + buffer; requires channel/group/mpim history scopes"
195
- : "bare replies in the Agent's threads + buffer; im:message.group_msg delivers all group messages",
196
- },
197
- {
198
- value: "mentions",
199
- label: "Mention-only (least privilege)",
200
- hint: "only explicit @Agent messages; no group-wide message permission",
201
- },
202
- ];
203
- const answer = await select({
204
- message: "Choose group-chat behavior",
205
- initialValue: defaultBehavior,
206
- options: choices,
207
- });
208
- if (isCancel(answer))
209
- failStartup(new Error(`${kind} onboarding cancelled`));
210
- return { behavior: answer, explicit: true };
211
322
  }
212
323
  /** `fastagent add skill <source> [dir]`: vendor an Agent Skills skill into <dir>/skills/<name>/. */
213
324
  export async function runAddSkill(source, dirArg, opts) {
214
- const { agentDir: target } = placementOrExit(resolve(dirArg));
325
+ const target = agentDirOrExit(resolve(dirArg));
215
326
  if (!source) {
216
327
  // A missing source is a usage error (exit 2), but the guide is worth more than a bare missing-argument line.
217
328
  failUsage(`add a skill — two ways:\n` +
@@ -225,7 +336,7 @@ export async function runAddSkill(source, dirArg, opts) {
225
336
  }
226
337
  // Skills are agent surface — vendored into the agent dir's `skills/`.
227
338
  enterAgentEnv(target); // a git-ref source is a network fetch (giget uses global fetch)
228
- const { name, description, dest, hasScripts, diagnostics, overwritten } = await vendorSkill(target, source, {
339
+ const { name, description, dest, hasScripts, overwritten } = await vendorSkill(target, source, {
229
340
  update: opts.update ?? false,
230
341
  }).catch(failStartup);
231
342
  console.error(`[fastagent] ${overwritten ? "updated" : "vendored"} skill "${name}" → ${dest}/`);
@@ -233,10 +344,8 @@ export async function runAddSkill(source, dirArg, opts) {
233
344
  console.error(` overwrote it — \`git diff ${dest}\` to review, \`git checkout ${dest}\` to revert`);
234
345
  if (description)
235
346
  console.error(` ${description.length > 100 ? `${description.slice(0, 100)}…` : description}`);
236
- for (const d of diagnostics)
237
- console.error(` warn: ${d.message}`);
238
347
  if (hasScripts) {
239
348
  console.error(` warn: this skill ships scripts/ (executable code that runs in your agent) — review it before deploying`);
240
349
  }
241
- console.error(` next: mention "${name}" in APPEND_SYSTEM.md so the model knows when to use it; then \`fastagent dev\``);
350
+ console.error(` next: mention "${name}" in SYSTEM.md so the model knows when to use it; then \`fastagent dev\``);
242
351
  }
@@ -0,0 +1,6 @@
1
+ export declare function runAuthCheck(opts: {
2
+ provider?: string;
3
+ model?: string;
4
+ global?: boolean;
5
+ json?: boolean;
6
+ }): Promise<void>;
@@ -0,0 +1,50 @@
1
+ import { enterAgentEnv } from "../../env.js";
2
+ import { modelEnvironment } from "../../harnesses/models/environment.js";
3
+ import { providerOf } from "../../harnesses/models/models.js";
4
+ import { definitionProviders } from "../../harnesses/pi-durable/open.js";
5
+ import { installProxyFetch } from "../../proxy.js";
6
+ import { failStartup, failUsage, optionalAgentDirOrExit } from "../fail.js";
7
+ const EXIT_CODES = { ready: 0, not_ready: 1, invalid: 2 };
8
+ export async function runAuthCheck(opts) {
9
+ if (opts.provider === undefined && opts.model === undefined) {
10
+ failUsage("auth check needs --provider <id> or --model <provider/modelId>");
11
+ }
12
+ const agentDir = opts.global ? undefined : optionalAgentDirOrExit(process.cwd());
13
+ let providers = [];
14
+ if (agentDir) {
15
+ enterAgentEnv(agentDir);
16
+ providers = await definitionProviders(agentDir).catch(failStartup);
17
+ }
18
+ else {
19
+ installProxyFetch();
20
+ }
21
+ const environment = await modelEnvironment(agentDir, {}, providers);
22
+ let provider = opts.provider;
23
+ let modelId;
24
+ if (opts.model !== undefined) {
25
+ const ofModel = providerOf(opts.model);
26
+ modelId = opts.model.slice(ofModel.length + 1);
27
+ if (modelId === "" || environment.models.getModel(ofModel, modelId) === undefined) {
28
+ failUsage(`unknown model "${opts.model}": \`fastagent models\` lists the ones there are`);
29
+ }
30
+ if (provider !== undefined && provider !== ofModel)
31
+ failUsage(`${opts.model} is not a model of ${provider}`);
32
+ provider = ofModel;
33
+ }
34
+ const result = await check(environment, provider, modelId);
35
+ console.log(opts.json ? JSON.stringify(result) : result.status);
36
+ process.exitCode = EXIT_CODES[result.status];
37
+ }
38
+ async function check(environment, provider, modelId) {
39
+ if (environment.models.getProvider(provider) === undefined) {
40
+ return { status: "not_ready", provider, reason: "provider_not_found" };
41
+ }
42
+ const held = await environment.authStatus(provider, modelId);
43
+ const path = held.path === undefined ? {} : { path: held.path };
44
+ if (held.error !== undefined)
45
+ return { status: "invalid", provider, reason: "invalid_state", error: held.error, ...path };
46
+ if (held.source === undefined)
47
+ return { status: "not_ready", provider, reason: "credentials_not_configured", ...path };
48
+ const authType = held.source === "OAuth" ? "oauth" : "api_key";
49
+ return { status: "ready", provider, authType, source: held.source, ...path };
50
+ }
@@ -0,0 +1,6 @@
1
+ import { type SourceOptions } from "../../content/source.ts";
2
+ /** A name refusal is the caller's to fix by naming another (exit 2); anything else is a startup failure (exit 1). */
3
+ export declare function failEdit(hint: string): (error: unknown) => never;
4
+ export declare function runContentList(dirArg: string, json: boolean): Promise<void>;
5
+ export declare function runContentAdd(source: string, dirArg: string, opts: SourceOptions): Promise<void>;
6
+ export declare function runContentRemove(name: string, dirArg: string): Promise<void>;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * `fastagent content list|add|remove`: what the agent works on and knows, as `context.json` declares it and
3
+ * `context.local.json` binds it on this machine.
4
+ */
5
+ import { resolve } from "node:path";
6
+ import { ContentNameError, addContent, listContent, removeContent } from "../../authoring.js";
7
+ import { readContentSource } from "../../content/source.js";
8
+ import { contentLines } from "../content-view.js";
9
+ import { failStartup, failUsage } from "../fail.js";
10
+ /** A name refusal is the caller's to fix by naming another (exit 2); anything else is a startup failure (exit 1). */
11
+ export function failEdit(hint) {
12
+ return (error) => {
13
+ if (error instanceof ContentNameError)
14
+ failUsage(`${error.message}${hint}`);
15
+ failStartup(error);
16
+ };
17
+ }
18
+ export async function runContentList(dirArg, json) {
19
+ const { content, absent } = await listContent(resolve(dirArg)).catch(failStartup);
20
+ if (json) {
21
+ console.log(JSON.stringify({ content, absent }, null, 2));
22
+ return;
23
+ }
24
+ for (const [label, value] of contentLines(content, absent))
25
+ console.log(`${`${label}:`.padEnd(10)} ${value}`);
26
+ }
27
+ export async function runContentAdd(source, dirArg, opts) {
28
+ const { addition, notes } = await Promise.resolve()
29
+ .then(() => readContentSource(source, process.cwd(), opts))
30
+ .catch(failStartup);
31
+ for (const note of notes)
32
+ console.error(`[fastagent] ${note}`);
33
+ const { name, content, notes: left } = await addContent(resolve(dirArg), addition).catch(failEdit(" — pass --name"));
34
+ const added = content.filter((entry) => entry.name === name);
35
+ for (const [label, value] of contentLines(added))
36
+ console.error(`[fastagent] ${label} ${value}`);
37
+ for (const note of left)
38
+ console.error(`[fastagent] ${note}`);
39
+ }
40
+ export async function runContentRemove(name, dirArg) {
41
+ const removed = await removeContent(resolve(dirArg), name).catch(failEdit(""));
42
+ console.error(`[fastagent] removed content ${removed.name}`);
43
+ for (const note of removed.notes)
44
+ console.error(`[fastagent] ${note}`);
45
+ }