@fastagent-sh/fastagent 0.28.0 → 0.30.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 (325) hide show
  1. package/README.md +10 -4
  2. package/dist/atomic-write.d.ts +4 -5
  3. package/dist/atomic-write.js +4 -5
  4. package/dist/authoring.d.ts +32 -15
  5. package/dist/authoring.js +147 -127
  6. package/dist/channels/agentcore-protocol.d.ts +8 -3
  7. package/dist/channels/agentcore-protocol.js +3 -1
  8. package/dist/channels/agentcore-service.d.ts +1 -0
  9. package/dist/channels/agentcore-service.js +14 -4
  10. package/dist/channels/agentcore.d.ts +9 -0
  11. package/dist/channels/agentcore.js +29 -4
  12. package/dist/channels/context.d.ts +2 -0
  13. package/dist/channels/context.js +5 -1
  14. package/dist/channels/feishu/feishu-api.d.ts +3 -1
  15. package/dist/channels/feishu/feishu-api.js +4 -0
  16. package/dist/channels/feishu/feishu.d.ts +0 -3
  17. package/dist/channels/feishu/feishu.js +10 -10
  18. package/dist/channels/feishu/register-app.d.ts +2 -0
  19. package/dist/channels/feishu/register-app.js +4 -6
  20. package/dist/channels/feishu/scaffold/channel.ts +32 -34
  21. package/dist/channels/feishu/scaffold/feishu-send.ts +5 -5
  22. package/dist/channels/feishu/scaffold/feishu-threads.ts +3 -3
  23. package/dist/channels/feishu/setup-mode.d.ts +2 -12
  24. package/dist/channels/feishu/setup-mode.js +2 -22
  25. package/dist/channels/feishu/setup.d.ts +12 -0
  26. package/dist/channels/feishu/setup.js +197 -0
  27. package/dist/channels/kit/abortable.d.ts +8 -0
  28. package/dist/channels/kit/abortable.js +22 -0
  29. package/dist/channels/lark/lark.d.ts +0 -3
  30. package/dist/channels/lark/lark.js +0 -5
  31. package/dist/channels/lark/scaffold/channel.ts +33 -35
  32. package/dist/channels/lark/scaffold/lark-send.ts +5 -5
  33. package/dist/channels/lark/scaffold/lark-threads.ts +3 -3
  34. package/dist/channels/lark/setup.d.ts +9 -0
  35. package/dist/channels/lark/setup.js +57 -0
  36. package/dist/channels/setup.d.ts +112 -0
  37. package/dist/channels/setup.js +31 -0
  38. package/dist/channels/slack/history.js +1 -1
  39. package/dist/channels/slack/manifest.d.ts +17 -7
  40. package/dist/channels/slack/manifest.js +12 -16
  41. package/dist/channels/slack/scaffold/channel.ts +44 -30
  42. package/dist/channels/slack/scaffold/slack-send.ts +8 -8
  43. package/dist/channels/slack/scaffold/slack-threads.ts +4 -4
  44. package/dist/channels/slack/setup.d.ts +7 -0
  45. package/dist/channels/slack/setup.js +119 -0
  46. package/dist/channels/slack/slack-api.d.ts +2 -0
  47. package/dist/channels/slack/slack-api.js +4 -0
  48. package/dist/channels/slack/slack.d.ts +21 -2
  49. package/dist/channels/slack/slack.js +398 -338
  50. package/dist/channels/slack/socket.d.ts +57 -0
  51. package/dist/channels/slack/socket.js +305 -0
  52. package/dist/channels/telegram/polling.d.ts +27 -0
  53. package/dist/channels/telegram/polling.js +105 -0
  54. package/dist/channels/telegram/scaffold/channel.ts +52 -32
  55. package/dist/channels/telegram/scaffold/telegram-send.ts +9 -9
  56. package/dist/channels/telegram/setup.d.ts +2 -0
  57. package/dist/channels/telegram/setup.js +42 -0
  58. package/dist/channels/telegram/telegram-api.d.ts +27 -1
  59. package/dist/channels/telegram/telegram-api.js +7 -6
  60. package/dist/channels/telegram/telegram.d.ts +11 -3
  61. package/dist/channels/telegram/telegram.js +184 -157
  62. package/dist/channels/wait-health.js +1 -1
  63. package/dist/channels/webhook-evidence.d.ts +11 -0
  64. package/dist/channels/webhook-evidence.js +71 -0
  65. package/dist/channels/webhooks.d.ts +37 -0
  66. package/dist/channels/webhooks.js +70 -0
  67. package/dist/child-env.d.ts +16 -0
  68. package/dist/child-env.js +30 -0
  69. package/dist/cli/box-login.js +4 -1
  70. package/dist/cli/channel-app.d.ts +3 -0
  71. package/dist/cli/channel-app.js +35 -0
  72. package/dist/cli/channel-setup.d.ts +38 -0
  73. package/dist/cli/channel-setup.js +195 -0
  74. package/dist/cli/commands/add.d.ts +6 -14
  75. package/dist/cli/commands/add.js +45 -310
  76. package/dist/cli/commands/auth.js +8 -2
  77. package/dist/cli/commands/build.d.ts +5 -0
  78. package/dist/cli/commands/build.js +16 -0
  79. package/dist/cli/commands/channels.d.ts +19 -0
  80. package/dist/cli/commands/channels.js +230 -0
  81. package/dist/cli/commands/content.d.ts +7 -3
  82. package/dist/cli/commands/content.js +16 -10
  83. package/dist/cli/commands/deploy/agentcore.js +55 -23
  84. package/dist/cli/commands/deploy/channel-apps.d.ts +17 -0
  85. package/dist/cli/commands/deploy/channel-apps.js +30 -0
  86. package/dist/cli/commands/deploy/docker.js +32 -65
  87. package/dist/cli/commands/deploy/fly.js +28 -12
  88. package/dist/cli/commands/deploy/railway.js +38 -13
  89. package/dist/cli/commands/deploy/secrets-step.d.ts +19 -0
  90. package/dist/cli/commands/deploy/secrets-step.js +66 -0
  91. package/dist/cli/commands/deploy/shared.d.ts +16 -5
  92. package/dist/cli/commands/deploy/shared.js +25 -8
  93. package/dist/cli/commands/deploy.js +53 -67
  94. package/dist/cli/commands/dev.d.ts +2 -0
  95. package/dist/cli/commands/dev.js +15 -3
  96. package/dist/cli/commands/env.js +1 -1
  97. package/dist/cli/commands/info.d.ts +2 -0
  98. package/dist/cli/commands/info.js +63 -24
  99. package/dist/cli/commands/init.js +3 -1
  100. package/dist/cli/commands/invoke.d.ts +2 -0
  101. package/dist/cli/commands/invoke.js +20 -7
  102. package/dist/cli/commands/login.d.ts +0 -7
  103. package/dist/cli/commands/login.js +22 -10
  104. package/dist/cli/commands/logout.js +1 -1
  105. package/dist/cli/commands/mcp.d.ts +12 -0
  106. package/dist/cli/commands/mcp.js +164 -0
  107. package/dist/cli/commands/models.js +3 -2
  108. package/dist/cli/commands/schedules.d.ts +4 -2
  109. package/dist/cli/commands/schedules.js +14 -10
  110. package/dist/cli/commands/secrets.d.ts +14 -0
  111. package/dist/cli/commands/secrets.js +213 -0
  112. package/dist/cli/commands/start.d.ts +14 -14
  113. package/dist/cli/commands/start.js +46 -60
  114. package/dist/cli/content-view.d.ts +4 -6
  115. package/dist/cli/content-view.js +5 -11
  116. package/dist/cli/first-run-channels.d.ts +3 -0
  117. package/dist/cli/first-run-channels.js +63 -0
  118. package/dist/cli/instance.d.ts +41 -0
  119. package/dist/cli/instance.js +155 -0
  120. package/dist/cli/invoke-stream.d.ts +5 -2
  121. package/dist/cli/invoke-stream.js +7 -2
  122. package/dist/cli/program.js +339 -108
  123. package/dist/cli/serve.d.ts +4 -5
  124. package/dist/cli/serve.js +4 -7
  125. package/dist/cli/shared.d.ts +11 -2
  126. package/dist/cli/shared.js +32 -19
  127. package/dist/cli/ticket.js +50 -6
  128. package/dist/content/declare.d.ts +31 -37
  129. package/dist/content/declare.js +59 -60
  130. package/dist/content/file.d.ts +23 -12
  131. package/dist/content/file.js +48 -35
  132. package/dist/content/git.d.ts +0 -10
  133. package/dist/content/git.js +5 -39
  134. package/dist/content/resolve.d.ts +18 -22
  135. package/dist/content/resolve.js +32 -66
  136. package/dist/content/source.d.ts +7 -8
  137. package/dist/content/source.js +10 -28
  138. package/dist/credentials-page.d.ts +26 -0
  139. package/dist/credentials-page.js +185 -0
  140. package/dist/declared-secrets.d.ts +10 -3
  141. package/dist/declared-secrets.js +8 -4
  142. package/dist/deploy/agentcore/destroy.d.ts +4 -1
  143. package/dist/deploy/agentcore/destroy.js +26 -2
  144. package/dist/deploy/agentcore/forwarder.js +1 -1
  145. package/dist/deploy/agentcore/plan.d.ts +7 -21
  146. package/dist/deploy/agentcore/plan.js +47 -49
  147. package/dist/deploy/agentcore/run.d.ts +18 -10
  148. package/dist/deploy/agentcore/run.js +93 -70
  149. package/dist/deploy/agentcore/runtime-secrets.d.ts +7 -0
  150. package/dist/deploy/agentcore/runtime-secrets.js +108 -0
  151. package/dist/deploy/agentcore/shell.js +12 -19
  152. package/dist/deploy/agentcore/sigv4.d.ts +7 -0
  153. package/dist/deploy/agentcore/sigv4.js +15 -0
  154. package/dist/deploy/agentcore/slr.d.ts +18 -0
  155. package/dist/deploy/agentcore/slr.js +27 -0
  156. package/dist/deploy/agentcore/store.d.ts +7 -0
  157. package/dist/deploy/agentcore/store.js +115 -0
  158. package/dist/deploy/api.d.ts +14 -14
  159. package/dist/deploy/api.js +26 -24
  160. package/dist/deploy/box-shell.d.ts +3 -1
  161. package/dist/deploy/build-context.d.ts +4 -4
  162. package/dist/deploy/build-context.js +11 -11
  163. package/dist/deploy/channel-ingress.d.ts +35 -9
  164. package/dist/deploy/channel-ingress.js +119 -22
  165. package/dist/deploy/container.d.ts +35 -10
  166. package/dist/deploy/container.js +80 -39
  167. package/dist/deploy/delivered-text.d.ts +13 -0
  168. package/dist/deploy/delivered-text.js +86 -0
  169. package/dist/deploy/docker/plan.d.ts +7 -8
  170. package/dist/deploy/docker/plan.js +31 -52
  171. package/dist/deploy/docker/run.d.ts +18 -43
  172. package/dist/deploy/docker/run.js +57 -79
  173. package/dist/deploy/file-store.d.ts +2 -0
  174. package/dist/deploy/file-store.js +17 -0
  175. package/dist/deploy/fly/plan.d.ts +3 -2
  176. package/dist/deploy/fly/plan.js +20 -9
  177. package/dist/deploy/fly/run.d.ts +18 -22
  178. package/dist/deploy/fly/run.js +25 -44
  179. package/dist/deploy/fly/store.d.ts +12 -0
  180. package/dist/deploy/fly/store.js +83 -0
  181. package/dist/deploy/hosts.d.ts +1 -2
  182. package/dist/deploy/hosts.js +1 -2
  183. package/dist/deploy/preflight.d.ts +18 -5
  184. package/dist/deploy/preflight.js +135 -63
  185. package/dist/deploy/railway/ignore.d.ts +8 -0
  186. package/dist/deploy/railway/ignore.js +57 -0
  187. package/dist/deploy/railway/plan.d.ts +1 -2
  188. package/dist/deploy/railway/plan.js +8 -6
  189. package/dist/deploy/railway/run.d.ts +21 -15
  190. package/dist/deploy/railway/run.js +32 -78
  191. package/dist/deploy/railway/store.d.ts +29 -0
  192. package/dist/deploy/railway/store.js +143 -0
  193. package/dist/deploy/runner.d.ts +5 -2
  194. package/dist/deploy/runner.js +4 -3
  195. package/dist/deploy/secret-store.d.ts +63 -0
  196. package/dist/deploy/secret-store.js +98 -0
  197. package/dist/deploy/secrets.d.ts +29 -46
  198. package/dist/deploy/secrets.js +49 -122
  199. package/dist/deploy/workspace.d.ts +6 -12
  200. package/dist/deploy/workspace.js +18 -94
  201. package/dist/dev-supervisor.js +6 -7
  202. package/dist/environment/declare.js +3 -2
  203. package/dist/environment/mise.d.ts +3 -1
  204. package/dist/environment/mise.js +4 -2
  205. package/dist/feishu.d.ts +1 -1
  206. package/dist/feishu.js +1 -1
  207. package/dist/harnesses/models/catalog.d.ts +1 -0
  208. package/dist/harnesses/models/catalog.js +1 -2
  209. package/dist/harnesses/models/environment.d.ts +7 -2
  210. package/dist/harnesses/models/environment.js +9 -5
  211. package/dist/harnesses/models/host.d.ts +0 -7
  212. package/dist/harnesses/models/host.js +10 -1
  213. package/dist/harnesses/models/login.d.ts +0 -8
  214. package/dist/harnesses/models/login.js +5 -4
  215. package/dist/harnesses/models/models.d.ts +7 -2
  216. package/dist/harnesses/models/models.js +28 -4
  217. package/dist/harnesses/pi-durable/agent.js +59 -38
  218. package/dist/harnesses/pi-durable/build.d.ts +12 -0
  219. package/dist/harnesses/pi-durable/build.js +270 -0
  220. package/dist/harnesses/pi-durable/built.d.ts +24 -0
  221. package/dist/harnesses/pi-durable/built.js +136 -0
  222. package/dist/harnesses/pi-durable/config.d.ts +81 -0
  223. package/dist/harnesses/pi-durable/config.js +266 -0
  224. package/dist/harnesses/pi-durable/define.d.ts +63 -13
  225. package/dist/harnesses/pi-durable/define.js +23 -2
  226. package/dist/harnesses/pi-durable/definition.d.ts +72 -0
  227. package/dist/harnesses/pi-durable/definition.js +143 -0
  228. package/dist/harnesses/pi-durable/events.d.ts +4 -3
  229. package/dist/harnesses/pi-durable/events.js +179 -136
  230. package/dist/harnesses/pi-durable/execution-env.d.ts +17 -0
  231. package/dist/harnesses/pi-durable/execution-env.js +11 -0
  232. package/dist/harnesses/pi-durable/mcp.d.ts +3 -0
  233. package/dist/harnesses/pi-durable/mcp.js +32 -0
  234. package/dist/harnesses/pi-durable/open.d.ts +36 -38
  235. package/dist/harnesses/pi-durable/open.js +97 -150
  236. package/dist/harnesses/pi-durable/reads.d.ts +0 -1
  237. package/dist/harnesses/pi-durable/reads.js +1 -3
  238. package/dist/harnesses/pi-durable/registry.d.ts +4 -6
  239. package/dist/harnesses/pi-durable/registry.js +29 -26
  240. package/dist/harnesses/pi-durable/release.d.ts +2 -2
  241. package/dist/harnesses/pi-durable/release.js +10 -7
  242. package/dist/harnesses/pi-durable/serve.d.ts +95 -15
  243. package/dist/harnesses/pi-durable/serve.js +151 -59
  244. package/dist/harnesses/pi-durable/sessions.js +15 -12
  245. package/dist/harnesses/pi-durable/text-sources.d.ts +30 -0
  246. package/dist/harnesses/pi-durable/text-sources.js +55 -0
  247. package/dist/harnesses/pi-durable/text.d.ts +16 -4
  248. package/dist/harnesses/pi-durable/text.js +115 -59
  249. package/dist/harnesses/pi-durable/wake.js +8 -8
  250. package/dist/http/client.js +9 -3
  251. package/dist/http/server.d.ts +1 -1
  252. package/dist/http/server.js +1 -1
  253. package/dist/index.d.ts +11 -4
  254. package/dist/index.js +8 -1
  255. package/dist/instance-name.d.ts +7 -0
  256. package/dist/instance-name.js +26 -0
  257. package/dist/lark.d.ts +1 -1
  258. package/dist/lark.js +1 -1
  259. package/dist/locked-file.d.ts +2 -2
  260. package/dist/locked-file.js +8 -3
  261. package/dist/mcp/auth.d.ts +22 -0
  262. package/dist/mcp/auth.js +180 -0
  263. package/dist/mcp/client.d.ts +15 -0
  264. package/dist/mcp/client.js +179 -0
  265. package/dist/mcp/config.d.ts +86 -0
  266. package/dist/mcp/config.js +225 -0
  267. package/dist/mcp/grants.d.ts +4 -0
  268. package/dist/mcp/grants.js +132 -0
  269. package/dist/mcp/host.d.ts +19 -0
  270. package/dist/mcp/host.js +128 -0
  271. package/dist/mcp/network.d.ts +12 -0
  272. package/dist/mcp/network.js +150 -0
  273. package/dist/mcp/sign-in.d.ts +2 -0
  274. package/dist/mcp/sign-in.js +204 -0
  275. package/dist/mcp-api.d.ts +107 -0
  276. package/dist/mcp-api.js +10 -0
  277. package/dist/paths.d.ts +22 -8
  278. package/dist/paths.js +44 -11
  279. package/dist/runtime-websocket.d.ts +14 -0
  280. package/dist/runtime-websocket.js +39 -0
  281. package/dist/scaffold/add-channel.d.ts +9 -16
  282. package/dist/scaffold/add-channel.js +13 -83
  283. package/dist/scaffold/templates/env.example +4 -5
  284. package/dist/scaffold/templates/fastagent.config.ts +20 -14
  285. package/dist/scaffold/templates/gitignore +9 -6
  286. package/dist/scaffold/templates.d.ts +6 -2
  287. package/dist/scaffold/templates.js +7 -2
  288. package/dist/scaffold/vendor-skill.js +4 -2
  289. package/dist/service.d.ts +44 -6
  290. package/dist/service.js +110 -10
  291. package/dist/serving-command.d.ts +10 -0
  292. package/dist/serving-command.js +1 -0
  293. package/dist/setup-page.d.ts +51 -0
  294. package/dist/setup-page.js +149 -0
  295. package/dist/slack.d.ts +1 -1
  296. package/dist/slack.js +1 -1
  297. package/dist/strip-edges.d.ts +10 -0
  298. package/dist/strip-edges.js +22 -0
  299. package/dist/telegram.d.ts +1 -1
  300. package/dist/telegram.js +1 -1
  301. package/dist/tunnel.d.ts +0 -1
  302. package/dist/tunnel.js +2 -8
  303. package/dist/value-file.d.ts +12 -6
  304. package/dist/value-file.js +36 -25
  305. package/dist/version.d.ts +7 -1
  306. package/dist/version.js +9 -3
  307. package/package.json +8 -6
  308. package/dist/channels/lark/onboard.d.ts +0 -36
  309. package/dist/channels/lark/onboard.js +0 -56
  310. package/dist/channels/slack/config-api.d.ts +0 -69
  311. package/dist/channels/slack/config-api.js +0 -162
  312. package/dist/channels/slack/onboard.d.ts +0 -40
  313. package/dist/channels/slack/onboard.js +0 -136
  314. package/dist/channels/slack/onboarding-state.d.ts +0 -31
  315. package/dist/channels/slack/onboarding-state.js +0 -64
  316. package/dist/channels/slack/register-webhook.d.ts +0 -12
  317. package/dist/channels/slack/register-webhook.js +0 -67
  318. package/dist/channels/slack/setup-server.d.ts +0 -32
  319. package/dist/channels/slack/setup-server.js +0 -201
  320. package/dist/cli/add-feishu.d.ts +0 -50
  321. package/dist/cli/add-feishu.js +0 -367
  322. package/dist/cli/add-slack.d.ts +0 -18
  323. package/dist/cli/add-slack.js +0 -216
  324. package/dist/harnesses/pi-durable/parked.d.ts +0 -18
  325. package/dist/harnesses/pi-durable/parked.js +0 -27
@@ -1,325 +1,60 @@
1
1
  /**
2
2
  * `fastagent add <channel>|skill` — scaffold channel glue (`src/channels/<kind>.ts`) or vendor an Agent Skills skill.
3
- * slack/feishu/lark additionally CREATE OR RESUME the platform app.
3
+ * A channel changes the program only (channel-setup.md §2): its platform app, and the values of the instance that runs
4
+ * it, are `channels setup`'s.
4
5
  */
5
- import { randomBytes } from "node:crypto";
6
6
  import { join, relative, resolve } from "node:path";
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";
7
+ import { shellArg } from "../shared.js";
16
8
  import { enterAgentEnv } from "../../env.js";
17
- import { dotEnvPath, loadEnvValues } from "../../value-file.js";
18
- import { selectAgentEnvironment, resolveStateRoot, SECRETS_DIRNAME, isUnderDir, displayPath } from "../../paths.js";
9
+ import { SECRETS_DIRNAME, displayPath } from "../../paths.js";
19
10
  import { detectRuntime, readPackageJson } from "../../runtime.js";
20
- import { appendChannelDotEnv, appendChannelEnv, assertChannelReady, channelExists, channelSetup, scaffoldChannel, scaffoldCompanionTools, } from "../../scaffold/add-channel.js";
11
+ import { appendChannelEnv, assertChannelReady, channelExists, channelSetup, scaffoldChannel, scaffoldCompanionTools, } from "../../scaffold/add-channel.js";
21
12
  import { vendorSkill } from "../../scaffold/vendor-skill.js";
22
- import { failStartup, failUsage, agentDirOrExit } from "../fail.js";
23
- import { unprotectedSecretsNote } from "../../value-file.js";
24
- /** Without a terminal, how long an app's setup stays open for the person to finish their part. */
25
- const UNATTENDED_TIMEOUT_SECONDS = 900;
26
- /** `fastagent add <kind> [dir]`: scaffold `src/channels/<kind>.ts`, the adapter configured with a starter policy. */
27
- export async function runAddChannel(channelKind, dirArg, opts) {
28
- if (opts.check !== undefined)
29
- return checkSetup(channelKind, opts.check, opts);
30
- if (opts.ticket !== undefined) {
31
- // The process `startTicket` started: it takes the ticket before anything slow (the definition is built to plan),
32
- // then does the whole `add`, its person the ticket's.
33
- await runTicket(opts.ticket, async (step) => ({
34
- ...(await addChannel(channelKind, await planAdd(channelKind, dirArg, opts), opts, step.person)),
35
- }));
36
- process.exit(0);
37
- }
38
- const plan = await planAdd(channelKind, dirArg, opts);
39
- const unattended = opts.input === false || opts.json === true || !isInteractive();
40
- if (unattended && opts.onboard !== false && channelKind !== "telegram") {
41
- return setUpUnattended(channelKind, opts, plan);
42
- }
43
- const added = await addChannel(channelKind, plan, opts, terminalPerson).catch(failStartup);
44
- if (opts.json)
45
- console.log(JSON.stringify({ status: "done", ...added }, null, 2));
46
- // App-creation flows leave platform/tunnel sockets behind that would otherwise hold the one-shot scaffold command
47
- // open after all durable boundaries have completed.
48
- process.exit(0);
49
- }
50
- /** What `add` settles before it changes anything, refusing what it can while nothing has changed. */
51
- async function planAdd(channelKind, dirArg, opts) {
52
- // The channel (glue + companion tools + secrets) is agent surface: everything lands in the AGENT DIR.
53
- if (opts.replaceConfig && opts.onboard === false) {
54
- failUsage("--replace-config replaces onboarding credentials; it cannot be combined with --no-onboard");
55
- }
13
+ import { agentDirOrExit, failStartup, failUsage } from "../fail.js";
14
+ /**
15
+ * `add <channel>`: the program only (channel-setup.md §2). It writes the channel file and its tools and names the
16
+ * values they read in `.secrets/.env.example`; it asks nothing and creates no app. The app, and the values of the
17
+ * instance that runs it, are `channels setup`'s.
18
+ */
19
+ export async function runAddChannel(kind, dirArg, opts) {
56
20
  const target = agentDirOrExit(resolve(dirArg));
57
- const environment = opts.environment ?? "dev";
58
- if (environment !== "dev" && environment !== "production") {
59
- failUsage(`--env must be "dev" or "production", got "${environment}"`);
60
- }
61
- selectAgentEnvironment(environment);
62
- if (environment === "production")
63
- unmarkDevServe();
64
- else
65
- markDevServe();
66
- enterAgentEnv(target);
67
- if (environment === "production" && (channelKind === "feishu" || channelKind === "lark")) {
68
- try {
69
- assertIndependentFeishuApps(target, [channelKind], loadEnvValues(dotEnvPath(target)));
70
- }
71
- catch (error) {
72
- failStartup(error);
73
- }
74
- }
75
- // Paths are printed to someone standing in their CWD, which may be elsewhere, while every file belongs to the AGENT
76
- // dir — prefix them, or they point at nothing.
77
21
  const agentFromCwd = displayPath(process.cwd(), target);
78
22
  const inAgent = (p) => (agentFromCwd === undefined ? p : join(agentFromCwd, p));
79
- // An existing channel file is authored glue: kept, never rewritten.
80
- const file = join(target, "src", "channels", `${channelKind}.ts`);
81
- const existsAlready = await channelExists(target, channelKind).catch(failStartup);
82
- const ingress = resolveIngress(channelKind, opts.ingress);
83
- if (existsAlready &&
84
- (ingress.setting || (environment === "production" && opts.onboard !== false)) &&
85
- (channelKind === "feishu" || channelKind === "lark")) {
86
- await assertChannelReadsSetting(target, channelKind, ingress.setting ?? { [`${cloudFor(channelKind).envPrefix}_INGRESS`]: ingress.ingress }, inAgent(relative(target, file)));
87
- }
88
- return {
89
- target,
90
- environment,
91
- inAgent,
92
- agentFromCwd,
93
- file,
94
- existsAlready,
95
- ...ingress,
96
- rerun: `fastagent add ${channelKind}${agentFromCwd === undefined ? "" : ` ${shellArg(agentFromCwd)}`}` +
97
- `${environment === "production" ? " --env production" : ""}${opts.ingress ? ` --ingress ${opts.ingress}` : ""}` +
98
- `${opts.replaceConfig ? " --replace-config" : ""}`,
99
- };
100
- }
101
- /**
102
- * Everything `add <kind>` does once the person's part can be done: the channel, its tools and variables, the app's
103
- * onboarding through `person`, and the next steps, printed and returned with the variables it wrote.
104
- */
105
- async function addChannel(channelKind, plan, opts, person) {
106
- const { target, environment, inAgent, agentFromCwd, file, existsAlready, ingress, pinned, setting, rerun } = plan;
107
- const envPath = dotEnvPath(target);
108
- const envLabel = isUnderDir(envPath, target) ? inAgent(relative(target, envPath)) : envPath;
109
- const before = loadEnvValues(envPath);
110
- if (existsAlready) {
111
- console.error(`[fastagent] ${inAgent(relative(target, file))} already exists — keeping it`);
112
- }
113
- else {
114
- await assertChannelReady(target);
115
- await scaffoldChannel(target, channelKind);
116
- console.error(`[fastagent] created ${inAgent(relative(target, file))}`);
117
- }
118
- // Companion tools are the package's, not authored glue.
119
- for (const tool of await scaffoldCompanionTools(target, channelKind)) {
120
- console.error(`[fastagent] wrote ${inAgent(relative(target, tool))}`);
121
- }
122
- if (await appendChannelEnv(target, channelKind)) {
123
- console.error(`[fastagent] added ${channelKind} env vars to ${inAgent(join(SECRETS_DIRNAME, ".env.example"))}`);
124
- }
125
- // Stateful app onboarding is re-runnable after the scaffold boundary.
126
- let created;
127
- if (channelKind === "slack" && opts.onboard !== false) {
128
- const { onboardSlackInternalApp } = await import("../add-slack.js");
129
- created = await onboardSlackInternalApp({
130
- target,
131
- stateRoot: resolveStateRoot(target),
132
- replaceConfig: opts.replaceConfig,
133
- ...(person === terminalPerson ? {} : { person }),
134
- }).then(() => undefined);
135
- }
136
- else if ((channelKind === "feishu" || channelKind === "lark") && opts.onboard !== false) {
137
- created = await onboardFeishuCloudApp(target, channelKind, ingress, rerun, person);
138
- }
139
- const setup = channelSetup(channelKind, ingress, pinned);
140
- const env = setup.env;
141
- const steps = channelKind === "slack" && opts.onboard !== false
142
- ? [
143
- // No line about the Request URL: the `dev --tunnel` line below is the whole instruction, and FastAgent sets
144
- // that URL itself when the agent first runs.
145
- "invite the app to each channel it should read",
146
- // The tool lines are the scaffold's (one list), whichever path set the app up.
147
- ...setup.steps.filter((step) => step.includes("{tools}/")),
148
- ]
149
- : setup.steps;
150
- const generated = Object.fromEntries(env.filter((e) => e.generate).map((e) => [e.name, randomBytes(24).toString("hex")]));
151
- // Kind-neutral: every channel's generated secrets get the same treatment.
152
- const dotEnv = await appendChannelDotEnv(target, channelKind, { ...generated, ...created, ...setting }, [...Object.keys(created ?? {}), ...Object.keys(setting ?? {})], ingress);
153
- if (dotEnv.unprotectedSecretsDir) {
154
- console.error(`[fastagent] note: ${unprotectedSecretsNote(dotEnv.unprotectedSecretsDir)}`);
155
- }
156
- if (dotEnv.written.length > 0) {
157
- console.error(`[fastagent] wrote ${dotEnv.written.join(", ")} to ${envLabel}`);
158
- }
159
- const install = detectRuntime(target, await readPackageJson(target)).runtime === "bun" ? "bun install" : "npm install";
160
- const next = [];
161
- /** One next step: printed, and returned for a caller that reads them as data. */
162
- const step = (line) => {
163
- next.push(line.trim());
164
- console.error(` ${line}`);
165
- };
166
- console.error(` next steps:`);
167
- step(`${agentFromCwd === undefined ? install : `(cd ${agentFromCwd} && ${install})`} # if @fastagent-sh/fastagent is not installed yet`);
168
- // Onboarding writes some itself (an app's ID and secret, a bot token) before the write above: what this `add` wrote is
169
- // what the file holds now and did not before.
170
- const now = loadEnvValues(envPath);
171
- const written = [...now.keys()].filter((name) => now.get(name) && now.get(name) !== before.get(name));
172
- for (const e of env) {
173
- if (!written.includes(e.name) && dotEnv.alreadySet.includes(e.name))
174
- continue; // the user's already: nothing to do
175
- if (written.includes(e.name)) {
176
- // Written, but its hint may still carry an action — keep the variable visible instead of silently absorbing it.
177
- step(`${e.name} — ${e.generate ? "generated and " : ""}written to ${envLabel} # ${e.hint}`);
178
- continue;
23
+ const file = join(target, "src", "channels", `${kind}.ts`);
24
+ const created = [];
25
+ await (async () => {
26
+ if (await channelExists(target, kind)) {
27
+ console.error(`[fastagent] ${inAgent(relative(target, file))} already exists — keeping it`);
179
28
  }
180
- const value = e.generate ? `=${generated[e.name]}` : "";
181
- const action = e.required ? "set" : "optionally set";
182
- step(`${action} ${e.name}${value} in ${envLabel} # ${e.hint}`);
183
- }
184
- const serveCommand = environment === "production" ? "fastagent start" : "fastagent dev";
185
- for (const s of steps) {
186
- step(s
187
- .replace("{channel}", inAgent(relative(target, file)))
188
- .replace("{tools}", inAgent(join("src", "tools")))
189
- .replaceAll("{serve}", serveCommand));
190
- }
191
- if (environment === "production") {
192
- step(`fastagent deploy <host> --run # deploy with the production app and credentials`);
193
- }
194
- else if (ingress === "websocket") {
195
- step(`fastagent dev # no public URL or tunnel required`);
196
- }
197
- else if (channelKind === "slack") {
198
- 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"}`);
199
- }
200
- else if (channelKind !== "lark") {
201
- step(`fastagent dev --tunnel # serve locally + a public URL, auto-registering the webhook`);
202
- }
203
- return { written, next_steps: next };
204
- }
205
- /** The command that reads an app's setup ticket, as every such ticket records it. */
206
- const setupCheck = (kind) => `fastagent add ${kind} --check`;
207
- /** What the person does for each kind's app, to follow "so they can". */
208
- const SETUP_ACTIONS = {
209
- slack: "set up the Slack app: paste a configuration token on the page, then click Allow in Slack",
210
- feishu: "confirm the new Feishu app",
211
- lark: "finish setting up the Lark app",
212
- };
213
- /**
214
- * `add slack|feishu|lark` with no one at a terminal to ask, for a coding agent: what the person must provide first is
215
- * named (Lark's app credentials, in the file the agent reads), never asked for in the agent's conversation; then the
216
- * 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
217
- * is done, or it is still working at it.
218
- */
219
- async function setUpUnattended(kind, opts, at) {
220
- const { target } = at;
221
- if (kind === "lark") {
222
- const needed = await larkCredentialsNeeded(target, at.rerun).catch(failStartup);
223
- if (needed !== undefined) {
224
- printReport(opts.json, needed.json, needed.text);
225
- process.exit(0);
29
+ else {
30
+ await assertChannelReady(target);
31
+ await scaffoldChannel(target, kind);
32
+ created.push(inAgent(relative(target, file)));
33
+ console.error(`[fastagent] created ${inAgent(relative(target, file))}`);
226
34
  }
227
- }
228
- const timeout = opts.timeout === undefined ? UNATTENDED_TIMEOUT_SECONDS : Number(opts.timeout);
229
- if (!Number.isInteger(timeout) || timeout <= 0)
230
- failUsage(`--timeout must be a whole number of seconds`);
231
- const ticket = await startTicket({
232
- // One setup per agent, channel and environment: another agent's is its own business.
233
- subject: `add:${kind}:${at.environment}:${target}`,
234
- action: SETUP_ACTIONS[kind],
235
- check: setupCheck(kind),
236
- restart: at.rerun,
237
- timeoutSeconds: timeout,
238
- waitsFirst: false,
239
- whenRunning: "replace",
240
- command: {
241
- file: process.execPath,
242
- args: [
243
- ...process.execArgv,
244
- process.argv[1],
245
- "add",
246
- kind,
247
- target,
248
- ...(at.environment === "production" ? ["--env", "production"] : []),
249
- ...(opts.ingress === undefined ? [] : ["--ingress", opts.ingress]),
250
- ...(opts.replaceConfig ? ["--replace-config"] : []),
251
- ],
252
- cwd: process.cwd(),
253
- },
254
- });
255
- reportSetup(ticket, opts, "started");
256
- process.exit(ticketExitCode(ticket));
257
- }
258
- /** `add <kind> --check <ticket>`. */
259
- async function checkSetup(kind, id, opts) {
260
- const refused = refusedCheck(id, setupCheck(kind));
261
- if (refused !== undefined)
262
- failUsage(refused);
263
- // There: refusedCheck read it, and a ticket is pruned only a day after it ends.
264
- const ticket = (await checkTicket(id));
265
- reportSetup(ticket, opts, "checked");
266
- process.exit(ticketExitCode(ticket));
267
- }
268
- /** An app's setup ticket for whoever started or checked it: the shared report, and what a finished setup adds. */
269
- function reportSetup(ticket, opts, when) {
270
- const { json, text } = ticketReport(ticket, when, (result) => {
271
- const written = result.written ?? [];
272
- const next = result.next_steps ?? [];
273
- return {
274
- fields: { written, next_steps: next },
275
- text: [...(written.length > 0 ? [`wrote ${written.join(", ")}`] : []), ...next.map((line) => `next: ${line}`)],
276
- next: `The app is set up. Its next steps are in next_steps.`,
277
- };
278
- });
279
- printReport(opts.json, json, text);
280
- }
281
- /**
282
- * What `add` sets the app up for, and whether it writes the choice down. `--ingress` is the `<PREFIX>_INGRESS`
283
- * setting in the selected environment. The channel rule supplies its default: WebSocket in dev, webhook in production.
284
- */
285
- function resolveIngress(kind, raw) {
286
- if (raw !== undefined && raw !== "webhook" && raw !== "websocket") {
287
- failUsage(`--ingress must be "webhook" or "websocket", got "${raw}"`);
288
- }
289
- if (kind !== "feishu" && kind !== "lark")
290
- return { ingress: "webhook", pinned: false };
291
- const name = `${cloudFor(kind).envPrefix}_INGRESS`;
292
- if (raw !== undefined)
293
- return { ingress: raw, pinned: true, setting: { [name]: raw } };
294
- try {
295
- return {
296
- ingress: feishuIngressFor(kind, process.env),
297
- pinned: Boolean(process.env[name]?.trim()),
298
- };
299
- }
300
- catch (error) {
301
- // A malformed value in the environment: the author's to fix, said as the rule says it.
302
- return failUsage(error.message);
303
- }
304
- }
305
- /**
306
- * A setting only takes effect in a channel file that reads it: one that names its factory receives the same way
307
- * whatever the setting says, so writing the setting (and configuring the app for it) would change nothing but the app.
308
- * Asked of the channel as the agent builds it, under the value this command is about to write.
309
- */
310
- async function assertChannelReadsSetting(target, kind, setting, shown) {
311
- Object.assign(process.env, setting); // the value this command writes anyway
312
- const channel = await prepareDefinition(target)
313
- .then((definition) => buildDefinitionShape(definition, process.env).channels.get(kind))
314
- .catch((error) => failStartup(new Error(`the agent does not build (${error.message}) — fix it and re-run`)));
315
- const [[name, value]] = Object.entries(setting);
316
- const wanted = value === "webhook" ? "webhook" : "long-connection";
317
- const shape = channel === undefined ? undefined : channelIngress(channel);
318
- if (shape !== wanted) {
319
- failStartup(new Error(`${shown} receives by ${shape === "webhook" ? "webhook" : "WebSocket"} whatever ${name} says — it names ` +
320
- `its factory instead of reading the setting, so ${name}=${value} would change nothing but the app. Move ` +
321
- `the file aside and re-run to scaffold one that reads it, or edit its factory yourself`));
322
- }
35
+ // Companion tools are the package's, not authored glue.
36
+ for (const tool of await scaffoldCompanionTools(target, kind)) {
37
+ created.push(inAgent(relative(target, tool)));
38
+ console.error(`[fastagent] wrote ${inAgent(relative(target, tool))}`);
39
+ }
40
+ if (await appendChannelEnv(target, kind)) {
41
+ console.error(`[fastagent] added ${kind} env vars to ${inAgent(join(SECRETS_DIRNAME, ".env.example"))}`);
42
+ }
43
+ })().catch(failStartup);
44
+ const install = detectRuntime(target, await readPackageJson(target)).runtime === "bun" ? "bun install" : "npm install";
45
+ const next = [
46
+ `${agentFromCwd === undefined ? install : `(cd ${agentFromCwd} && ${install})`} # if @fastagent-sh/fastagent is not installed yet`,
47
+ `fastagent channels setup ${kind}${agentFromCwd === undefined ? "" : ` ${shellArg(agentFromCwd)}`} # creates the app and asks for its credentials`,
48
+ `edit ${inAgent(relative(target, file))} — customise routing with route() (optional; the defaults already work)`,
49
+ ...channelSetup(kind).steps.map((line) => line.replace("{tools}", inAgent(join("src", "tools")))),
50
+ "fastagent dev",
51
+ ];
52
+ console.error(" next steps:");
53
+ for (const line of next)
54
+ console.error(` ${line}`);
55
+ if (opts.json)
56
+ console.log(JSON.stringify({ status: "done", created, next_steps: next }, null, 2));
57
+ process.exit(0);
323
58
  }
324
59
  /** `fastagent add skill <source> [dir]`: vendor an Agent Skills skill into <dir>/skills/<name>/. */
325
60
  export async function runAddSkill(source, dirArg, opts) {
@@ -1,3 +1,9 @@
1
+ /**
2
+ * `fastagent auth check`: whether a provider is ready for the agent here, as pi's `auth check` answers it, for a script
3
+ * or a coding agent: `ready`, `not_ready` or `invalid` on stdout, exit 0, 1 or 2. The answer is the one the agent's
4
+ * messages would get (`ModelEnvironment.authStatus`, a due refresh included).
5
+ */
6
+ import { definedValues } from "../../declared-secrets.js";
1
7
  import { enterAgentEnv } from "../../env.js";
2
8
  import { modelEnvironment } from "../../harnesses/models/environment.js";
3
9
  import { providerOf } from "../../harnesses/models/models.js";
@@ -13,12 +19,12 @@ export async function runAuthCheck(opts) {
13
19
  let providers = [];
14
20
  if (agentDir) {
15
21
  enterAgentEnv(agentDir);
16
- providers = await definitionProviders(agentDir).catch(failStartup);
22
+ providers = await definitionProviders(agentDir, process.env).catch(failStartup);
17
23
  }
18
24
  else {
19
25
  installProxyFetch();
20
26
  }
21
- const environment = await modelEnvironment(agentDir, {}, providers);
27
+ const environment = await modelEnvironment(agentDir, {}, providers, { environment: definedValues(process.env) });
22
28
  let provider = opts.provider;
23
29
  let modelId;
24
30
  if (opts.model !== undefined) {
@@ -0,0 +1,5 @@
1
+ export interface BuildCommandOptions {
2
+ check: boolean;
3
+ json: boolean;
4
+ }
5
+ export declare function runBuild(dirArg: string, opts: BuildCommandOptions): Promise<void>;
@@ -0,0 +1,16 @@
1
+ /** `fastagent build [agent] [--no-check] [--json]`: the agent compiled into `dist/`. */
2
+ import { relative, resolve } from "node:path";
3
+ import { buildProject } from "../../harnesses/pi-durable/build.js";
4
+ import { log } from "../../log.js";
5
+ import { agentDirOrExit, failStartup } from "../fail.js";
6
+ export async function runBuild(dirArg, opts) {
7
+ const dir = agentDirOrExit(resolve(dirArg));
8
+ const { dist, definition, warnings } = await buildProject(dir, { check: opts.check }).catch(failStartup);
9
+ for (const warning of warnings)
10
+ log.warn(`[fastagent] ${warning}`);
11
+ if (opts.json) {
12
+ console.log(JSON.stringify({ dist, name: definition.name, version: definition.version, warnings }));
13
+ return;
14
+ }
15
+ console.log(relative(process.cwd(), dist) || dist);
16
+ }
@@ -0,0 +1,19 @@
1
+ export interface ChannelsSetupOptions {
2
+ recordUrl: boolean;
3
+ /** The instance configuration: what names how the channel receives, and where `--ingress` is written. */
4
+ config?: string;
5
+ /** The value file the credentials are kept in (created when missing). */
6
+ envFile?: string;
7
+ ingress?: string;
8
+ url?: string;
9
+ json: boolean;
10
+ /** false ⇔ `--no-input`. */
11
+ input?: boolean;
12
+ /** `--check <ticket>`: where a setup started without a terminal stands. */
13
+ check?: string;
14
+ /** `--timeout <seconds>`: how long a setup started without a terminal stays open. */
15
+ timeout?: string;
16
+ /** `--ticket <id>`: the process that runs a ticket's setup. */
17
+ ticket?: string;
18
+ }
19
+ export declare function runChannelsSetup(name: string, dirArg: string, opts: ChannelsSetupOptions): Promise<void>;