@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,11 +1,11 @@
1
1
  import { readdir } from "node:fs/promises";
2
- import { basename, isAbsolute, join, relative, sep } from "node:path";
2
+ import { isAbsolute, relative, join, sep } from "node:path";
3
3
  import ignore from "ignore";
4
- import { exists, readTextIfExists, resolveSecretsDir, resolveStateRoot } from "../paths.js";
4
+ import { AGENT_CONFIG_FILE, CONTENT_DIRNAME, LOCAL_CONTEXT_FILE, SECRETS_DIRNAME, exists, readTextIfExists, resolveSecretsDir, resolveStateRoot, } from "../paths.js";
5
5
  import { isGeneratedDockerignore } from "./container.js";
6
6
  /**
7
7
  * "Would docker's packer drop this path?" — built from a `.dockerignore`'s text via the `ignore` matcher (the same
8
- * library the workspace ignore files use), so `!` negation and last-match-wins are the library's problem, not ours.
8
+ * library the scaffolded ignore files use), so `!` negation and last-match-wins are the library's problem, not ours.
9
9
  */
10
10
  function dockerignoreMatcher(text) {
11
11
  const anchored = text
@@ -38,22 +38,26 @@ async function entriesIfExists(path) {
38
38
  throw new Error(`cannot read ${path} to check what the image would ship: ${error.message}`);
39
39
  }
40
40
  }
41
- export async function buildContextPaths(workspace, agentDir, agentPrefix, authPath) {
41
+ export async function buildContextPaths(agentDir, authPath) {
42
42
  const inContext = (p) => {
43
- const rel = relative(workspace, p);
43
+ const rel = relative(agentDir, p);
44
44
  return rel === "" || rel.startsWith("..") || isAbsolute(rel) ? undefined : rel.split(sep).join("/");
45
45
  };
46
46
  // The secrets DIR is the unit of RESPONSIBILITY, but never the unit of the leak QUESTION below.
47
47
  const secretsRel = inContext(resolveSecretsDir(agentDir));
48
48
  const authRel = inContext(authPath);
49
49
  const authElsewhere = authRel !== undefined && (secretsRel === undefined || !authRel.startsWith(`${secretsRel}/`));
50
- const secretPaths = [...(secretsRel ? [secretsRel] : []), ...(authElsewhere ? [authRel] : [])];
50
+ const secretsDirs = [SECRETS_DIRNAME];
51
+ if (secretsRel && secretsRel !== SECRETS_DIRNAME && !secretsRel.startsWith(`${SECRETS_DIRNAME}/`)) {
52
+ secretsDirs.push(secretsRel);
53
+ }
54
+ const secretPaths = [...secretsDirs, ...(authElsewhere ? [authRel] : [])];
51
55
  // ONE rule for every checked path: a file that is not there cannot be baked, so gating on it would be a refusal
52
56
  // about a spelling rather than about what would ship (an agent that has never run `login` has no auth.json).
53
57
  const present = async (rels) => {
54
58
  const found = [];
55
59
  for (const rel of rels)
56
- if (await exists(join(workspace, rel)))
60
+ if (await exists(join(agentDir, rel)))
57
61
  found.push(rel);
58
62
  return found;
59
63
  };
@@ -61,20 +65,17 @@ export async function buildContextPaths(workspace, agentDir, agentPrefix, authPa
61
65
  // at warn level.
62
66
  const stateRel = inContext(resolveStateRoot(agentDir));
63
67
  // Existence gates the WARNING, never the generated exclude (same split as secretPaths vs leakCandidates).
64
- const stateShips = stateRel !== undefined && (await exists(join(workspace, stateRel))) ? stateRel : undefined;
65
- // The `.env` family at the two levels fastagent is RESPONSIBLE for: the agent dir and the workspace root.
66
- const dotEnvFiles = async (relDir) => {
67
- const names = (await entriesIfExists(join(workspace, relDir || "."))).map((entry) => entry.name);
68
- // POSIX separators, like every other context-relative path here (`inContext`).
69
- return names
70
- .filter((n) => (n === ".env" || n.startsWith(".env.")) && n !== ".env.example")
71
- .map((n) => join(relDir, n).split(sep).join("/"));
72
- };
73
- const envFiles = (await Promise.all([...new Set(["", agentPrefix])].map(dotEnvFiles))).flat();
68
+ const stateShips = stateRel !== undefined && (await exists(join(agentDir, stateRel))) ? stateRel : undefined;
69
+ const contentShips = (await exists(join(agentDir, CONTENT_DIRNAME))) ? CONTENT_DIRNAME : undefined;
70
+ const bindingsShip = (await exists(join(agentDir, LOCAL_CONTEXT_FILE))) ? LOCAL_CONTEXT_FILE : undefined;
71
+ // The `.env` family at the level fastagent is RESPONSIBLE for: the agent dir's root.
72
+ const envFiles = (await entriesIfExists(agentDir))
73
+ .map((entry) => entry.name)
74
+ .filter((n) => (n === ".env" || n.startsWith(".env.")) && n !== ".env.example");
74
75
  // Everything ACTUALLY inside the secrets dir, minus the two tracked scaffolds the image ships on purpose (they
75
76
  // carry no values; the generated ignore re-includes them by name).
76
77
  const secretDirFiles = async (dirRel) => {
77
- const entries = await entriesIfExists(join(workspace, dirRel));
78
+ const entries = await entriesIfExists(join(agentDir, dirRel));
78
79
  const files = [];
79
80
  for (const entry of entries) {
80
81
  if (entry.name === ".gitignore" || entry.name === ".env.example")
@@ -87,21 +88,21 @@ export async function buildContextPaths(workspace, agentDir, agentPrefix, authPa
87
88
  return files;
88
89
  };
89
90
  const leakCandidates = [
90
- ...(secretsRel ? await secretDirFiles(secretsRel) : []),
91
+ ...(await Promise.all(secretsDirs.map(secretDirFiles))).flat(),
91
92
  ...(await present(authElsewhere && authRel !== undefined ? [authRel] : [])),
92
93
  ...envFiles,
93
94
  ];
94
95
  // Same existence rule: a node_modules that is not there cannot be uploaded.
95
- const depDirs = await present([...new Set([`${agentPrefix}node_modules`, "node_modules"])]);
96
+ const depDirs = await present(["node_modules"]);
96
97
  const machineryPaths = [...secretPaths, ...(stateRel ? [stateRel] : [])];
97
- return { machineryPaths, leakCandidates, stateShips, depDirs };
98
+ return { machineryPaths, leakCandidates, stateShips, contentShips, bindingsShip, depDirs };
98
99
  }
99
100
  /** Interrogate BOTH ignore files deploy emits, when the author kept them. */
100
101
  export async function checkKeptIgnoreFiles(ctx, report) {
101
- const { workspace, agentDir, agentPrefix, force } = ctx;
102
- const { leakCandidates, stateShips, depDirs } = ctx.paths;
103
- for (const rel of [".dockerignore", `${agentPrefix}Dockerfile.dockerignore`]) {
104
- const kept = await readTextIfExists(join(workspace, rel));
102
+ const { agentDir, force } = ctx;
103
+ const { leakCandidates, stateShips, contentShips, bindingsShip, depDirs } = ctx.paths;
104
+ for (const rel of [".dockerignore", "Dockerfile.dockerignore"]) {
105
+ const kept = await readTextIfExists(join(agentDir, rel));
105
106
  if (kept === undefined)
106
107
  continue;
107
108
  // One WE generated is regenerated by this very run under --force, so checking the stale content on disk would
@@ -113,15 +114,13 @@ export async function checkKeptIgnoreFiles(ctx, report) {
113
114
  ? `Re-run with --force to regenerate it.`
114
115
  : `Add ${lines.map((p) => `\`${p}\``).join(" and ")} before deploying (the same lines the generated ${rel} writes).`;
115
116
  const excluded = dockerignoreMatcher(kept);
116
- // Asked as a DIRECTORY (trailing slash), which is what it is.
117
- if (excluded(`${basename(agentDir)}/`)) {
118
- const text = `your ${rel} (kept) excludes \`${basename(agentDir)}\` — the build context would ship WITHOUT the ` +
119
- `agent entirely (the deployed box has no prompt/config and crash-loops). Remove that rule ` +
120
- `before deploying.`;
117
+ // The marker of an agent: without it the deployed box has no agent to open.
118
+ if (excluded(AGENT_CONFIG_FILE)) {
119
+ const text = `your ${rel} (kept) excludes \`${AGENT_CONFIG_FILE}\` — the image would ship WITHOUT the agent's ` +
120
+ `config (the deployed box has no agent to open and crash-loops). Remove that rule before deploying.`;
121
121
  report.issue(text);
122
122
  }
123
- // Resolved paths, not spellings: dockerignore patterns are root-anchored (unlike .gitignore), so a bare
124
- // `.secrets` line does not cover `fastagent/.secrets`.
123
+ // Resolved paths, not spellings: dockerignore patterns are root-anchored (unlike .gitignore).
125
124
  const leaks = leakCandidates.filter((p) => !excluded(p));
126
125
  if (leaks.length > 0) {
127
126
  const text = `your ${rel} (kept) does not exclude ${leaks.map((p) => `\`${p}\``).join(", ")} — the build ` +
@@ -131,7 +130,14 @@ export async function checkKeptIgnoreFiles(ctx, report) {
131
130
  if (stateShips && !excluded(`${stateShips}/sessions`)) {
132
131
  report.warn(`your ${rel} (kept) does not exclude \`${stateShips}\` — the build machine's sessions/channel state would ship in the image. ${remedy([`/${stateShips}`])}`);
133
132
  }
134
- // Both the agent's own node_modules and the workspace's.
133
+ // An issue, not a warning: a release holding content/ is refused on the host, which links its own there.
134
+ if (contentShips && !excluded(`${contentShips}/x`)) {
135
+ report.issue(`your ${rel} (kept) does not exclude \`${contentShips}\` — this machine's clones of the agent's content would ship in the image. ${remedy([`/${contentShips}`])}`);
136
+ }
137
+ // A warning: the host reads it, and the paths it names (this machine's, the user's name in them) are not there.
138
+ if (bindingsShip && !excluded(bindingsShip)) {
139
+ report.warn(`your ${rel} (kept) does not exclude \`${bindingsShip}\` — the directories of this machine the agent is bound to would ship in the image, and the host would look for them at every start. ${remedy([`/${bindingsShip}`])}`);
140
+ }
135
141
  const unexcludedDeps = depDirs.filter((p) => !excluded(`${p}/.package-lock.json`));
136
142
  if (unexcludedDeps.length > 0) {
137
143
  report.warn(`your ${rel} does not exclude ${unexcludedDeps.map((p) => `\`${p}\``).join(" or ")} — the ` +
@@ -139,8 +145,8 @@ export async function checkKeptIgnoreFiles(ctx, report) {
139
145
  `freshly-installed ones. ${remedy(unexcludedDeps.map((p) => `/${p}`))}`);
140
146
  }
141
147
  if (excluded(".git/HEAD")) {
142
- report.note(`your ${rel} excludes .git — the baked copy ships WITHOUT history/remote, so the agent ` +
143
- `cannot pull/commit/push it; it must \`git clone\` its repo in the workspace instead (or remove the .git line).`);
148
+ report.note(`your ${rel} excludes .git — the baked definition ships WITHOUT its history (remove the .git line ` +
149
+ `to ship it).`);
144
150
  }
145
151
  }
146
152
  }
@@ -6,6 +6,11 @@ export interface Registrars {
6
6
  telegram: (baseUrl: string) => Promise<RegistrationOutcome>;
7
7
  slack?: (baseUrl: string) => Promise<RegistrationOutcome>;
8
8
  feishu?: (baseUrl: string, kind: "feishu" | "lark") => Promise<RegistrationOutcome>;
9
+ /**
10
+ * Where a channel's manual step goes beside the log, for a person who reads no log: a coding agent's user, through
11
+ * the deploy's ticket (its `afterwards`).
12
+ */
13
+ leave?: (step: string) => void;
9
14
  }
10
15
  /**
11
16
  * The first-party channels this deployment must point at a URL: webhook ingress, and a kind this tool knows how to
@@ -38,7 +43,7 @@ export type PublicHealthProbe = (healthUrl: string) => Promise<boolean>;
38
43
  * failed" — a diagnosis that hides the actual cause.
39
44
  *
40
45
  * Asked ONLY when this deployment actually has a webhook to point, or a login on the box follows (the box must
41
- * have prepared its workspace and installed the CLI the login runs). A definition with neither (schedules only, the
46
+ * have prepared its storage and installed the CLI the login runs). A definition with neither (schedules only, the
42
47
  * built-in `POST /invoke`, or long-connection channels) needs no inbound reachability at all, and demanding it would
43
48
  * invent a failure for a deploy run from a network that cannot reach the platform's edge.
44
49
  */
@@ -2,6 +2,9 @@ import { registrationGate } from "./registration-gate.js";
2
2
  import { waitForHealth } from "../channels/wait-health.js";
3
3
  const feishuCloud = (kind, label) => ({
4
4
  path: `/${kind}`,
5
+ // The subscription mode is the published version's: a switch from long connection waits for the publish.
6
+ delivers: "delivers to this deployment once its published version is in webhook mode (after a first deploy, publish the " +
7
+ "version it opened)",
5
8
  register: (r, baseUrl) => r.feishu?.(baseUrl, kind),
6
9
  manual: (baseUrl) => `${kind}: set the event Request URL in the developer console (Events & Callbacks) → ${baseUrl}/${kind} (the app must be running when you save)`,
7
10
  runbook: (baseUrl) => [
@@ -14,6 +17,7 @@ const feishuCloud = (kind, label) => ({
14
17
  const INGRESS = {
15
18
  telegram: {
16
19
  path: "/telegram",
20
+ delivers: "now delivers to this deployment",
17
21
  register: (r, baseUrl) => r.telegram(baseUrl),
18
22
  manual: (baseUrl) => `telegram: set the webhook → ${baseUrl}/telegram (secret_token = TELEGRAM_SECRET_TOKEN)`,
19
23
  runbook: (baseUrl) => [
@@ -25,11 +29,12 @@ const INGRESS = {
25
29
  },
26
30
  slack: {
27
31
  path: "/slack",
32
+ delivers: "now delivers to this deployment",
28
33
  register: (r, baseUrl) => r.slack?.(baseUrl),
29
34
  manual: (baseUrl) => `slack: set Event Subscriptions → Request URL → ${baseUrl}/slack`,
30
35
  runbook: (baseUrl) => [
31
36
  `# Set Slack Event Subscriptions → Request URL (default route POST /slack; the running service`,
32
- `# answers Slack's challenge), and match scopes/subscriptions to the app \`add slack --group-behavior\` created:`,
37
+ `# answers Slack's challenge), and match scopes/subscriptions to the app \`add slack\` created:`,
33
38
  `# Request URL = ${baseUrl}/slack`,
34
39
  ],
35
40
  },
@@ -70,11 +75,15 @@ export async function pointChannelsAt(input) {
70
75
  input.log(`registering ${kind} webhook…`);
71
76
  outcomes.push({ kind, outcome: await running });
72
77
  }
78
+ // What the registrar said is in the log; the person who reads none gets the one route to set.
79
+ for (const { kind } of outcomes.filter(({ outcome }) => outcome === "manual")) {
80
+ input.registrars.leave?.(INGRESS[kind].manual(input.baseUrl));
81
+ }
73
82
  return outcomes;
74
83
  }
75
84
  /**
76
- * How long a just-deployed public URL gets to answer `/health`: the FIRST boot seeds the whole workspace onto the
77
- * volume before it binds a port, so this budget covers a copy on slow host storage, not a listen.
85
+ * How long a just-deployed public URL gets to answer `/health`: the boot publishes the definition onto the volume
86
+ * before it binds a port, so this budget covers a copy on slow host storage, not a listen.
78
87
  */
79
88
  const PUBLIC_HEALTH_TIMEOUT_MS = 180_000;
80
89
  /** How often the wait announces itself, so a crash-looping app is not three silent minutes. */
@@ -86,7 +95,7 @@ const WAIT_NOTICE_MS = 15_000;
86
95
  * failed" — a diagnosis that hides the actual cause.
87
96
  *
88
97
  * Asked ONLY when this deployment actually has a webhook to point, or a login on the box follows (the box must
89
- * have prepared its workspace and installed the CLI the login runs). A definition with neither (schedules only, the
98
+ * have prepared its storage and installed the CLI the login runs). A definition with neither (schedules only, the
90
99
  * built-in `POST /invoke`, or long-connection channels) needs no inbound reachability at all, and demanding it would
91
100
  * invent a failure for a deploy run from a network that cannot reach the platform's edge.
92
101
  */
@@ -151,7 +160,11 @@ function announce(log) {
151
160
  /** {@link pointChannelsAt} plus the shared gate policy, for a command that EXITS. */
152
161
  export async function registerWebhooks(input) {
153
162
  const reg = registrationGate(input.log, input.retryHint);
154
- for (const { kind, outcome } of await pointChannelsAt(input))
163
+ const outcomes = await pointChannelsAt(input);
164
+ for (const { kind, outcome } of outcomes)
155
165
  reg.track(kind, outcome);
166
+ for (const { kind } of outcomes.filter(({ outcome }) => outcome === "registered")) {
167
+ input.log(`the selected production ${kind} app ${INGRESS[kind].delivers}`);
168
+ }
156
169
  return reg.gate();
157
170
  }
@@ -1,7 +1,11 @@
1
+ /** What every deploy writes whoever wrote it before: build output, by its file name, never kept or reported stale. */
2
+ export declare const BUILD_OUTPUTS: readonly string[];
1
3
  export interface Artifact {
2
4
  path: string;
3
5
  content: string;
4
6
  }
7
+ /** Where a generated image holds the definition: the build context, which is the agent directory. */
8
+ export declare const IMAGE_DEFINITION_DIR = "/app/definition";
5
9
  /**
6
10
  * The shell command that runs `fastagent login --stdio <args>` inside a running generated image, as the server there
7
11
  * would see it: in the deployed agent directory, with the storage and credential paths resolved by the same defaults
@@ -15,7 +19,7 @@ export interface Artifact {
15
19
  * result line), so the command answers for it: one result line naming the mismatch, instead of a shell that ended
16
20
  * with nothing to say. No quote or backtick in it: hosts wrap this whole line in `sh -c '…'`.
17
21
  */
18
- export declare function boxLoginCommand(agent: string, args: readonly string[], storage?: string): string;
22
+ export declare function boxLoginCommand(args: readonly string[], storage?: string): string;
19
23
  /** Fixed first-line prefix of a fastagent-generated Dockerfile. */
20
24
  export declare const GENERATED_DOCKERFILE_MARKER = "# Generated by `fastagent deploy`";
21
25
  /** The ONE predicate for "did fastagent generate this Dockerfile?". */
@@ -34,8 +38,13 @@ export interface ContainerInput {
34
38
  bunVersion?: string;
35
39
  /** This fastagent version, to PIN the global install on the markdown path (reproducible redeploys). */
36
40
  version: string;
37
- /** Extra apt packages (fastagent.config deploy.apt) baked in for the agent's tools — git, ripgrep, …. */
41
+ /**
42
+ * The Debian packages the image installs: what FastAgent needs (git for content and a shipped `.git`, CA certificates
43
+ * and curl for mise), then the agent's `aptPackages`.
44
+ */
38
45
  apt?: string[];
46
+ /** The packages the agent declares, as mise is given them (`gh@2`): the image installs them with the agent's own mise. */
47
+ packages?: string[];
39
48
  /**
40
49
  * The model this deployment resolved, recorded in the release manifest — set only when the deployed environment's
41
50
  * VALUE FILE named it (a `config.model` needs nothing: the config ships too). The manifest is the carrier because
@@ -43,15 +52,19 @@ export interface ContainerInput {
43
52
  * interpolate the operator's shell.
44
53
  */
45
54
  modelSpec?: string;
46
- /**
47
- * Where deploy's artifacts and the agent's own files sit, relative to the BUILD CONTEXT (which is always the
48
- * workspace).
49
- */
50
- agentPrefix: string;
51
- /** Workspace-relative machinery paths the NAME-based excludes below would miss. */
55
+ /** The agent's name, recorded in the release manifest: the agent directory's own name. */
56
+ agent: string;
57
+ /** Agent-dir-relative machinery paths the NAME-based excludes below would miss. */
52
58
  machineryPaths?: string[];
53
- /** Whether the baked workspace ships a `.git` (preflight fact). */
59
+ /** Whether the agent directory ships a `.git` (preflight fact). */
54
60
  shipsGit?: boolean;
55
61
  }
62
+ /** Whether the image has git: FastAgent installs it for its own needs, or the agent declares it in `aptPackages`. */
63
+ export declare function imageHasGit(input: Pick<ContainerInput, "apt">): boolean;
64
+ /**
65
+ * The Node image an npm-based agent runs on: the newest of the floor's line. A floating tag, so every build pulls it
66
+ * (docker/run.ts, agentcore/run.ts): a copy cached before the floor's release would start a Node the CLI refuses.
67
+ */
68
+ export declare const NODE_IMAGE: string;
56
69
  /** The Dockerfile + ignore artifacts — spread into any host's artifact list. */
57
70
  export declare function containerArtifacts(input: ContainerInput): Artifact[];
@@ -1,16 +1,30 @@
1
1
  /** The portable container — Dockerfile + .dockerignore, host-neutral. */
2
- import { SECRETS_DIRNAME, STATE_DIRNAME } from "../paths.js";
3
- import { RELEASE_FILE, parseDeploymentRelease } from "./workspace.js";
4
- /** The result line for a box CLI that refused `login --stdio` as an unknown option (see {@link boxLoginCommand}). */
2
+ import { CONTENT_DIRNAME, LOCAL_CONTEXT_FILE, SECRETS_DIRNAME, STATE_DIRNAME } from "../paths.js";
3
+ import { RUNTIME_FLOOR } from "../runtime.js";
4
+ import { DEPLOYED_DEFINITION_DIR, RELEASE_FILE, parseDeploymentRelease } from "./workspace.js";
5
+ import { MISE_ENVIRONMENT } from "../environment/mise.js";
6
+ import { BOX_CLI_PREDATES } from "./box-shell.js";
7
+ /**
8
+ * The packages the image installs, one per line as mise is given them: build output every deploy writes beside the
9
+ * release manifest, so the layer that installs them is built again when they change and not when anything else does.
10
+ */
11
+ const PACKAGES_FILE = "fastagent.packages";
12
+ /** What every deploy writes whoever wrote it before: build output, by its file name, never kept or reported stale. */
13
+ export const BUILD_OUTPUTS = [RELEASE_FILE, PACKAGES_FILE];
14
+ /**
15
+ * The result line for a box CLI that refused this CLI's `login --stdio` as a usage error: an option it does not know
16
+ * (`--stdio` itself, or one added since, such as `--method`). See {@link boxLoginCommand}.
17
+ */
5
18
  const STDIO_PREDATED = JSON.stringify({
6
19
  type: "result",
7
20
  ok: false,
8
21
  reason: "failed",
9
- message: "the fastagent installed in the agent on the box predates login --stdio: align the @fastagent-sh/fastagent " +
10
- "version in the agent package.json with the CLI that deploys it, then redeploy",
22
+ message: BOX_CLI_PREDATES,
11
23
  }).replaceAll('"', '\\"');
12
24
  /** Where a generated image keeps its storage (`FASTAGENT_STORAGE_DIR`); every host mounts its volume here. */
13
25
  const STORAGE_DIR = "/data";
26
+ /** Where a generated image holds the definition: the build context, which is the agent directory. */
27
+ export const IMAGE_DEFINITION_DIR = "/app/definition";
14
28
  /**
15
29
  * The shell command that runs `fastagent login --stdio <args>` inside a running generated image, as the server there
16
30
  * would see it: in the deployed agent directory, with the storage and credential paths resolved by the same defaults
@@ -24,8 +38,8 @@ const STORAGE_DIR = "/data";
24
38
  * result line), so the command answers for it: one result line naming the mismatch, instead of a shell that ended
25
39
  * with nothing to say. No quote or backtick in it: hosts wrap this whole line in `sh -c '…'`.
26
40
  */
27
- export function boxLoginCommand(agent, args, storage) {
28
- for (const value of [agent, ...args, ...(storage ? [storage] : [])]) {
41
+ export function boxLoginCommand(args, storage) {
42
+ for (const value of [...args, ...(storage ? [storage] : [])]) {
29
43
  if (!/^[\w.@/-]+$/.test(value))
30
44
  throw new Error(`cannot pass ${JSON.stringify(value)} to a shell on the box`);
31
45
  }
@@ -36,7 +50,7 @@ export function boxLoginCommand(agent, args, storage) {
36
50
  `root="\${FASTAGENT_STORAGE_DIR:-${STORAGE_DIR}}"`,
37
51
  `export FASTAGENT_SECRETS_DIR="\${FASTAGENT_SECRETS_DIR:-$root/.secrets}"`,
38
52
  ]),
39
- `cd "$root/base/${agent}" || exit 1`,
53
+ `cd "$root/${DEPLOYED_DEFINITION_DIR}" || exit 1`,
40
54
  `f=fastagent`,
41
55
  `if [ -x node_modules/.bin/fastagent ]; then f=node_modules/.bin/fastagent; if command -v bun >/dev/null; then f="bun run fastagent"; fi; fi`,
42
56
  `$f login --stdio ${args.join(" ")}`,
@@ -51,14 +65,15 @@ export const GENERATED_DOCKERFILE_MARKER = "# Generated by `fastagent deploy`";
51
65
  export function isGeneratedDockerfile(content) {
52
66
  return content.startsWith(GENERATED_DOCKERFILE_MARKER);
53
67
  }
54
- /**
55
- * First line of a generated `.dockerignore` — and, for the workspace-root one, the single artifact deploy writes
56
- * outside the agent dir.
57
- */
68
+ /** First line of a generated `.dockerignore`. */
58
69
  const GENERATED_DOCKERIGNORE_MARKER = "# Generated by `fastagent deploy`";
59
70
  export function isGeneratedDockerignore(content) {
60
71
  return content.startsWith(GENERATED_DOCKERIGNORE_MARKER);
61
72
  }
73
+ /** Whether the image has git: FastAgent installs it for its own needs, or the agent declares it in `aptPackages`. */
74
+ export function imageHasGit(input) {
75
+ return input.apt?.includes("git") === true;
76
+ }
62
77
  /** The apt layer (cached right after FROM). */
63
78
  function aptLayer(packages) {
64
79
  return packages && packages.length > 0
@@ -68,47 +83,69 @@ function aptLayer(packages) {
68
83
  `
69
84
  : "";
70
85
  }
86
+ /** mise's own directories for the build, thrown away with the layer: nothing of them is read at run time. */
87
+ const BUILD_MISE_DIR = "/tmp/mise";
88
+ /**
89
+ * The layer that installs the agent's packages, after its dependencies (the agent's own mise among them) and before the
90
+ * definition, so it stays cached while the definition changes. It reads them from {@link PACKAGES_FILE}, which deploy
91
+ * writes, rather than listing them: the Dockerfile is kept once written, and a list here would make every package
92
+ * change one that `--run` stops on. The packages go to mise's system directory (`--system`,
93
+ * /usr/local/share/mise/installs), which every mise reads beside its own data directory, so a start installs nothing.
94
+ */
95
+ function environmentLayer(dir) {
96
+ const isolation = Object.entries(MISE_ENVIRONMENT)
97
+ .map(([key, value]) => `${key}=${value}`)
98
+ .join(" ");
99
+ // The agent's own mise, by its package: the bin link is not reliable (mise.ts `miseBinary`).
100
+ const mise = `${dir}/node_modules/@jdxcode/mise-linux-$(case "$(uname -m)" in aarch64|arm64) echo arm64;; *) echo x64;; esac)/bin/mise`;
101
+ const steps = [
102
+ `export ${isolation} MISE_DATA_DIR=${BUILD_MISE_DIR} MISE_CACHE_DIR=${BUILD_MISE_DIR}/cache MISE_STATE_DIR=${BUILD_MISE_DIR}/state MISE="${mise}"`,
103
+ // One argument per line, read as it is: no quote or backslash in a package means anything to xargs.
104
+ `xargs -d '\\n' -a ${PACKAGES_FILE} "$MISE" install --system`,
105
+ `rm -rf ${BUILD_MISE_DIR}`,
106
+ ];
107
+ return `COPY ${PACKAGES_FILE} ./
108
+ RUN ${steps.join(" \\\n && ")}
109
+ `;
110
+ }
111
+ /**
112
+ * The Node image an npm-based agent runs on: the newest of the floor's line. A floating tag, so every build pulls it
113
+ * (docker/run.ts, agentcore/run.ts): a copy cached before the floor's release would start a Node the CLI refuses.
114
+ */
115
+ export const NODE_IMAGE = `node:${RUNTIME_FLOOR.node.split(".")[0]}-slim`;
71
116
  function dockerfile(input) {
72
- // The whole workspace is baked at /app; deps install (and the local bin lives) under the agent, which is always a
73
- // SUBDIRECTORY of it (the workspace is the agent dir's parent), so the prefix is never empty.
74
- const prefix = input.agentPrefix;
75
- const dir = prefix.replace(/\/$/, "");
76
- const into = (p) => `${prefix}${p}`;
77
- // A build step that must run IN the agent dir (`RUN` already gets a shell from docker).
78
- const at = (cmd) => `cd ${dir} && ${cmd}`;
79
- // The entrypoint.
80
- const bunCmd = `["sh", "-c", "cd ${dir} && exec bun run fastagent start /app"]`;
81
- const layoutNote = `The whole directory is the agent's workspace; the agent itself lives in ${prefix}`;
82
- // apt layer right after FROM (cached across code changes): the agent's tools may shell out to git etc., which
83
- // node:22-slim lacks.
117
+ // The build context is the agent directory, baked at IMAGE_DEFINITION_DIR; deps install (and the local bin lives)
118
+ // there.
119
+ const dir = IMAGE_DEFINITION_DIR;
120
+ const layoutNote = `The agent directory is baked at ${dir}`;
121
+ // apt layer right after FROM (cached across code changes): the agent's tools may shell out to git etc., which the
122
+ // slim image lacks.
84
123
  const apt = aptLayer(input.apt);
85
- // PIN the agent into the image.
86
- const pin = `ENV FASTAGENT_AGENT=${dir}\n`;
87
124
  // The caches stay off the volume: they are rebuildable, and a host mount is the slow disk.
88
- const deployment = `ENV FASTAGENT_RELEASE_FILE=/app/${into(RELEASE_FILE)}\nENV FASTAGENT_STORAGE_DIR=${STORAGE_DIR}\nENV npm_config_cache=/tmp/fastagent/npm\nENV BUN_INSTALL_CACHE_DIR=/tmp/fastagent/bun\n`;
125
+ const deployment = `ENV FASTAGENT_RELEASE_FILE=${dir}/${RELEASE_FILE}\nENV FASTAGENT_STORAGE_DIR=${STORAGE_DIR}\nENV npm_config_cache=/tmp/fastagent/npm\nENV BUN_INSTALL_CACHE_DIR=/tmp/fastagent/bun\n`;
89
126
  // No package.json → pure markdown/skills agent: install the pinned CLI GLOBALLY and run `fastagent` from PATH.
90
127
  if (!input.hasPackageJson) {
91
128
  return `${GENERATED_DOCKERFILE_MARKER}. ${layoutNote}
92
- # npm-based (a markdown/skills agent installs the pinned CLI globally; node:22-slim has npm).
93
- FROM node:22-slim
94
- ${apt}WORKDIR /app
95
- ${deployment}${pin}RUN npm i -g @fastagent-sh/fastagent@${input.version}
129
+ # npm-based (a markdown/skills agent installs the pinned CLI globally; ${NODE_IMAGE} has npm).
130
+ FROM ${NODE_IMAGE}
131
+ ${apt}WORKDIR ${dir}
132
+ ${deployment}RUN npm i -g @fastagent-sh/fastagent@${input.version}
96
133
  COPY . .
97
- CMD ["fastagent", "start", "/app"]
134
+ CMD ["fastagent", "start", "${dir}"]
98
135
  `;
99
136
  }
137
+ const environment = input.packages && input.packages.length > 0 ? environmentLayer(dir) : "";
100
138
  const isBun = input.runtime === "bun";
101
- const base = isBun ? `oven/bun:${input.bunVersion ?? "1"}` : "node:22-slim";
139
+ const base = isBun ? `oven/bun:${input.bunVersion ?? "1"}` : NODE_IMAGE;
102
140
  const note = isBun
103
141
  ? "# Bun-based (packageManager: bun / a bun lockfile detected). fastagent runs under Bun (bun run)."
104
142
  : "# npm-based — for pnpm/yarn, adapt the install line + the lockfile COPY (corepack enable, etc.).";
105
143
  const head = `${GENERATED_DOCKERFILE_MARKER}. ${layoutNote}
106
144
  ${note}
107
145
  FROM ${base}
108
- ${apt}WORKDIR /app
109
- ${deployment}${pin}`;
110
- // Install ALL deps (no --omit=dev / --production): a repo-as-agent (e.g. an Astro site it operates on) needs its
111
- // full toolchain.
146
+ ${apt}WORKDIR ${dir}
147
+ ${deployment}`;
148
+ // Install ALL deps (no --omit=dev / --production): an agent's tools may need its full toolchain.
112
149
  //
113
150
  // `*.tgz` RIDES ALONG with the manifest, because the install layer runs BEFORE `COPY . .` and a
114
151
  // `"dep": "file:./something.tgz"` resolves against the directory it is installing in. Without this the file is
@@ -117,42 +154,43 @@ ${deployment}${pin}`;
117
154
  if (isBun) {
118
155
  // `--frozen-lockfile` needs bun.lock and hard-fails without it.
119
156
  const install = input.hasLockfile ? "bun install --frozen-lockfile" : "bun install";
120
- return `${head}COPY ${into("package.json")} ${into("bun.lock*")} ${into("*.tgz")} ./${prefix}
121
- RUN ${at(install)}
122
- COPY . .
123
- CMD ${bunCmd}
157
+ return `${head}COPY package.json bun.lock* *.tgz ./
158
+ RUN ${install}
159
+ ${environment}COPY . .
160
+ CMD ["bun", "run", "fastagent", "start", "${dir}"]
124
161
  `;
125
162
  }
126
163
  // `npm ci` requires a lockfile and hard-fails without one (a common `init --no-install` agent); fall back to `npm
127
164
  // install` when there is none so the build never breaks.
128
165
  const install = input.hasLockfile ? "npm ci" : "npm install";
129
- return `${head}COPY ${into("package.json")} ${into("package-lock.json*")} ${into("*.tgz")} ./${prefix}
130
- RUN ${at(install)}
131
- COPY . .
132
- CMD ["./${into("node_modules/.bin/fastagent")}", "start", "/app"]
166
+ return `${head}COPY package.json package-lock.json* *.tgz ./
167
+ RUN ${install}
168
+ ${environment}COPY . .
169
+ CMD ["./node_modules/.bin/fastagent", "start", "${dir}"]
133
170
  `;
134
171
  }
135
172
  /** Patterns are RECURSIVE (`**​/`) on purpose. */
136
173
  const dockerignore = (input) => DOCKERIGNORE_BASE +
137
174
  (input.machineryPaths ?? [])
138
- // Skip what the name-based rules above already cover: the default `<agent>/.secrets` / `<agent>/.state` and
139
- // anything inside them.
140
- .filter((p) => [`${input.agentPrefix}${SECRETS_DIRNAME}`, `${input.agentPrefix}${STATE_DIRNAME}`].every((covered) => p !== covered && !p.startsWith(`${covered}/`)))
175
+ // Skip what the name-based rules above already cover: the default `.secrets` / `.state` and anything inside them.
176
+ .filter((p) => [SECRETS_DIRNAME, STATE_DIRNAME].every((covered) => p !== covered && !p.startsWith(`${covered}/`)))
141
177
  .map((p) => `# resolved machinery path (FASTAGENT_SECRETS_DIR / FASTAGENT_AUTH_PATH / FASTAGENT_STATE_DIR)\n/${p}\n`)
142
178
  .join("");
143
179
  const DOCKERIGNORE_BASE = `${GENERATED_DOCKERIGNORE_MARKER}. Delete this line to take ownership (deploy then keeps your file).
144
180
  **/node_modules
145
181
  **/${SECRETS_DIRNAME}/**
146
182
  **/${STATE_DIRNAME}
183
+ /${CONTENT_DIRNAME}
184
+ /${LOCAL_CONTEXT_FILE}
147
185
  **/.cache
148
186
  **/.env
149
187
  **/.env.*
150
188
  !**/.env.example
151
189
  !**/${SECRETS_DIRNAME}/.gitignore
152
190
  **/*.log
153
- # .git is deliberately shipped: the agent can pull to freshen content and push its work back
154
- # (the generated image installs the git binary when this directory ships a .git; otherwise
155
- # add deploy.apt ["git"]). For a smaller image with no git needs, add a ".git" line here.
191
+ # .git is deliberately shipped with the definition (the generated image installs the git binary
192
+ # when this directory ships a .git; otherwise run "fastagent env add apt:git"). For a smaller image with no
193
+ # git needs, add a ".git" line here.
156
194
  `;
157
195
  /** The Dockerfile + ignore artifacts — spread into any host's artifact list. */
158
196
  export function containerArtifacts(input) {
@@ -160,14 +198,17 @@ export function containerArtifacts(input) {
160
198
  const release = {
161
199
  version: 1,
162
200
  id: input.releaseId,
163
- agent: input.agentPrefix.replace(/\/$/, ""),
201
+ agent: input.agent,
164
202
  ...(input.modelSpec !== undefined ? { model: input.modelSpec } : {}),
165
203
  };
166
204
  parseDeploymentRelease(JSON.stringify(release));
167
205
  return [
168
- { path: `${input.agentPrefix}${RELEASE_FILE}`, content: `${JSON.stringify(release, null, 2)}\n` },
169
- { path: `${input.agentPrefix}Dockerfile`, content: dockerfile(input) },
206
+ { path: RELEASE_FILE, content: `${JSON.stringify(release, null, 2)}\n` },
207
+ // Written without packages too, empty: a list an earlier deploy left would otherwise outlive the last package.
208
+ { path: PACKAGES_FILE, content: (input.packages ?? []).map((spec) => `${spec}\n`).join("") },
209
+ { path: "Dockerfile", content: dockerfile(input) },
210
+ // Both names: BuildKit prefers the one beside the Dockerfile, the classic builder reads the context root's.
170
211
  { path: ".dockerignore", content: ignore },
171
- { path: `${input.agentPrefix}Dockerfile.dockerignore`, content: ignore },
212
+ { path: "Dockerfile.dockerignore", content: ignore },
172
213
  ];
173
214
  }
@@ -21,18 +21,19 @@ export interface DockerPlanInput extends ContainerInput {
21
21
  * carries.
22
22
  */
23
23
  secrets?: readonly DeploymentSecret[];
24
- /** The value file as the pre-flight resolved it (it follows `FASTAGENT_SECRETS_DIR`), workspace-relative. */
24
+ /** The value file as the pre-flight resolved it (it follows `FASTAGENT_SECRETS_DIR`), agent-dir-relative. */
25
25
  valueFile: string;
26
26
  }
27
27
  export interface DockerPlan {
28
28
  /** fastagent.compose.yml + the shared Dockerfile/ignore artifacts. */
29
29
  artifacts: Artifact[];
30
- /** Compose file path relative to the workspace root (under the agent prefix). */
30
+ /** Compose file path relative to the agent directory. */
31
31
  composePath: string;
32
32
  /** Ordered local build/run/operate instructions. */
33
33
  runbook: string[];
34
34
  }
35
35
  export declare const DOCKER_COMPOSE_FILE = "fastagent.compose.yml";
36
+ export declare const DOCKER_VALUE_FILE = ".secrets/production/.env";
36
37
  export declare const MIN_DOCKER_COMPOSE_VERSION = "2.3.3";
37
38
  /** Pinned: generated deployment artifacts must not silently move when Cloudflare publishes `latest`. */
38
39
  export declare const CLOUDFLARED_IMAGE = "cloudflare/cloudflared:2026.7.1";