@fastagent-sh/fastagent 0.21.1 → 0.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (388) hide show
  1. package/README.md +9 -12
  2. package/dist/agent.d.ts +24 -37
  3. package/dist/agent.js +7 -15
  4. package/dist/atomic-write.d.ts +13 -17
  5. package/dist/atomic-write.js +18 -29
  6. package/dist/bind.d.ts +12 -22
  7. package/dist/bind.js +18 -27
  8. package/dist/channel.d.ts +11 -33
  9. package/dist/channels/agentcore-limits.d.ts +2 -13
  10. package/dist/channels/agentcore-limits.js +2 -13
  11. package/dist/channels/agentcore-protocol.d.ts +67 -58
  12. package/dist/channels/agentcore-protocol.js +23 -15
  13. package/dist/channels/agentcore-service.d.ts +19 -33
  14. package/dist/channels/agentcore-service.js +176 -59
  15. package/dist/channels/agentcore.d.ts +39 -33
  16. package/dist/channels/agentcore.js +90 -224
  17. package/dist/channels/body.d.ts +15 -2
  18. package/dist/channels/body.js +24 -2
  19. package/dist/channels/busy.d.ts +1 -21
  20. package/dist/channels/busy.js +2 -39
  21. package/dist/channels/control.d.ts +17 -62
  22. package/dist/channels/control.js +74 -182
  23. package/dist/channels/define-channel.d.ts +39 -0
  24. package/dist/channels/define-channel.js +9 -0
  25. package/dist/channels/discover.d.ts +10 -31
  26. package/dist/channels/discover.js +37 -31
  27. package/dist/channels/feishu/bootstrap-token.d.ts +1 -8
  28. package/dist/channels/feishu/bootstrap-token.js +7 -23
  29. package/dist/channels/feishu/card.d.ts +14 -28
  30. package/dist/channels/feishu/card.js +16 -30
  31. package/dist/channels/feishu/cloud.d.ts +1 -5
  32. package/dist/channels/feishu/context-buffer.d.ts +4 -23
  33. package/dist/channels/feishu/context-buffer.js +8 -31
  34. package/dist/channels/feishu/crypto.d.ts +10 -5
  35. package/dist/channels/feishu/crypto.js +12 -19
  36. package/dist/channels/feishu/feishu-api.d.ts +2 -1
  37. package/dist/channels/feishu/feishu-api.js +5 -4
  38. package/dist/channels/feishu/feishu.d.ts +4 -10
  39. package/dist/channels/feishu/feishu.js +113 -227
  40. package/dist/channels/feishu/invoke-turn.d.ts +5 -4
  41. package/dist/channels/feishu/invoke-turn.js +36 -54
  42. package/dist/channels/feishu/model.d.ts +4 -21
  43. package/dist/channels/feishu/model.js +1 -8
  44. package/dist/channels/feishu/normalize.d.ts +2 -10
  45. package/dist/channels/feishu/normalize.js +7 -42
  46. package/dist/channels/feishu/parse.d.ts +9 -29
  47. package/dist/channels/feishu/parse.js +8 -26
  48. package/dist/channels/feishu/preview.d.ts +12 -14
  49. package/dist/channels/feishu/preview.js +108 -207
  50. package/dist/channels/feishu/register-app.d.ts +8 -23
  51. package/dist/channels/feishu/register-app.js +7 -20
  52. package/dist/channels/feishu/register-webhook.d.ts +2 -9
  53. package/dist/channels/feishu/register-webhook.js +9 -33
  54. package/dist/channels/feishu/scaffold/channel.ts +27 -19
  55. package/dist/channels/feishu/scaffold/channel.websocket.ts +31 -0
  56. package/dist/channels/feishu/setup-mode.d.ts +11 -36
  57. package/dist/channels/feishu/setup-mode.js +7 -26
  58. package/dist/channels/feishu/ws-ingress.d.ts +1 -2
  59. package/dist/channels/feishu/ws-ingress.js +6 -8
  60. package/dist/channels/http.d.ts +15 -15
  61. package/dist/channels/http.js +19 -9
  62. package/dist/channels/kit/attachment-path.d.ts +4 -5
  63. package/dist/channels/kit/attachment-path.js +10 -34
  64. package/dist/channels/kit/context-buffer.d.ts +14 -21
  65. package/dist/channels/kit/context-buffer.js +25 -38
  66. package/dist/channels/kit/delivery.d.ts +35 -0
  67. package/dist/channels/kit/delivery.js +129 -0
  68. package/dist/channels/kit/event-stream.d.ts +5 -0
  69. package/dist/channels/kit/event-stream.js +29 -0
  70. package/dist/channels/kit/invoke-turn-kit.d.ts +53 -26
  71. package/dist/channels/kit/invoke-turn-kit.js +89 -32
  72. package/dist/channels/kit/preview-kit.d.ts +18 -72
  73. package/dist/channels/kit/preview-kit.js +22 -88
  74. package/dist/channels/kit/signature.d.ts +3 -9
  75. package/dist/channels/kit/signature.js +3 -9
  76. package/dist/channels/kit/state.d.ts +1 -2
  77. package/dist/channels/kit/state.js +5 -14
  78. package/dist/channels/kit/stop-command.d.ts +1 -2
  79. package/dist/channels/kit/stop-command.js +6 -9
  80. package/dist/channels/kit/tasks.d.ts +1 -1
  81. package/dist/channels/kit/tasks.js +8 -21
  82. package/dist/channels/kit/text.d.ts +2 -16
  83. package/dist/channels/kit/text.js +23 -31
  84. package/dist/channels/kit/thread-participants.d.ts +4 -17
  85. package/dist/channels/kit/thread-participants.js +8 -55
  86. package/dist/channels/kit/transport.d.ts +26 -0
  87. package/dist/channels/kit/transport.js +20 -0
  88. package/dist/channels/kit/turn-queue.d.ts +7 -11
  89. package/dist/channels/kit/turn-queue.js +21 -39
  90. package/dist/channels/kit/turn-runner.d.ts +32 -18
  91. package/dist/channels/kit/turn-runner.js +98 -53
  92. package/dist/channels/kit/turn-store.d.ts +32 -32
  93. package/dist/channels/kit/turn-store.js +45 -88
  94. package/dist/channels/lark/lark.d.ts +1 -5
  95. package/dist/channels/lark/onboard.d.ts +3 -12
  96. package/dist/channels/lark/onboard.js +3 -13
  97. package/dist/channels/lark/scaffold/channel.ts +27 -19
  98. package/dist/channels/lark/scaffold/channel.websocket.ts +31 -0
  99. package/dist/channels/registration.d.ts +9 -35
  100. package/dist/channels/registration.js +6 -37
  101. package/dist/channels/secret.js +2 -5
  102. package/dist/channels/serve.d.ts +47 -44
  103. package/dist/channels/serve.js +165 -101
  104. package/dist/channels/slack/config-api.d.ts +4 -27
  105. package/dist/channels/slack/config-api.js +5 -34
  106. package/dist/channels/slack/context-buffer.d.ts +2 -3
  107. package/dist/channels/slack/context-buffer.js +5 -5
  108. package/dist/channels/slack/invoke-turn.d.ts +3 -1
  109. package/dist/channels/slack/invoke-turn.js +25 -34
  110. package/dist/channels/slack/manifest.js +1 -3
  111. package/dist/channels/slack/model.d.ts +1 -2
  112. package/dist/channels/slack/model.js +1 -1
  113. package/dist/channels/slack/onboard.d.ts +4 -3
  114. package/dist/channels/slack/onboard.js +8 -11
  115. package/dist/channels/slack/onboarding-state.d.ts +3 -5
  116. package/dist/channels/slack/onboarding-state.js +9 -6
  117. package/dist/channels/slack/parse.d.ts +4 -13
  118. package/dist/channels/slack/parse.js +7 -28
  119. package/dist/channels/slack/preview.d.ts +12 -2
  120. package/dist/channels/slack/preview.js +292 -269
  121. package/dist/channels/slack/reaction.d.ts +11 -3
  122. package/dist/channels/slack/reaction.js +19 -8
  123. package/dist/channels/slack/register-webhook.js +4 -7
  124. package/dist/channels/slack/scaffold/channel.ts +20 -13
  125. package/dist/channels/slack/scaffold/slack-send.ts +2 -2
  126. package/dist/channels/slack/setup-server.d.ts +1 -5
  127. package/dist/channels/slack/setup-server.js +1 -5
  128. package/dist/channels/slack/shared-api.d.ts +1 -4
  129. package/dist/channels/slack/shared-api.js +2 -13
  130. package/dist/channels/slack/slack-api.d.ts +2 -1
  131. package/dist/channels/slack/slack-api.js +6 -4
  132. package/dist/channels/slack/slack.d.ts +11 -14
  133. package/dist/channels/slack/slack.js +121 -122
  134. package/dist/channels/sse.d.ts +1 -1
  135. package/dist/channels/sse.js +1 -1
  136. package/dist/channels/telegram/context-buffer.d.ts +7 -22
  137. package/dist/channels/telegram/context-buffer.js +6 -23
  138. package/dist/channels/telegram/invoke-turn.d.ts +7 -7
  139. package/dist/channels/telegram/invoke-turn.js +24 -43
  140. package/dist/channels/telegram/parse.d.ts +24 -51
  141. package/dist/channels/telegram/parse.js +32 -84
  142. package/dist/channels/telegram/preview.d.ts +10 -1
  143. package/dist/channels/telegram/preview.js +79 -100
  144. package/dist/channels/telegram/register-webhook.js +5 -23
  145. package/dist/channels/telegram/scaffold/channel.ts +25 -18
  146. package/dist/channels/telegram/scaffold/telegram-send.ts +6 -4
  147. package/dist/channels/telegram/telegram-api.d.ts +4 -3
  148. package/dist/channels/telegram/telegram-api.js +9 -7
  149. package/dist/channels/telegram/telegram.d.ts +4 -18
  150. package/dist/channels/telegram/telegram.js +38 -94
  151. package/dist/channels/telegram/turn-store.d.ts +11 -14
  152. package/dist/channels/telegram/turn-store.js +8 -6
  153. package/dist/channels/wait-health.d.ts +4 -6
  154. package/dist/channels/wait-health.js +10 -14
  155. package/dist/cli/add-feishu.d.ts +2 -12
  156. package/dist/cli/add-feishu.js +24 -71
  157. package/dist/cli/add-slack.d.ts +5 -3
  158. package/dist/cli/add-slack.js +53 -76
  159. package/dist/cli/auth-view.d.ts +2 -16
  160. package/dist/cli/auth-view.js +2 -16
  161. package/dist/cli/commands/add.js +25 -40
  162. package/dist/cli/commands/chat.d.ts +0 -1
  163. package/dist/cli/commands/chat.js +5 -6
  164. package/dist/cli/commands/deploy/agentcore.js +60 -65
  165. package/dist/cli/commands/deploy/docker.js +50 -23
  166. package/dist/cli/commands/deploy/fly.js +23 -61
  167. package/dist/cli/commands/deploy/railway.js +23 -18
  168. package/dist/cli/commands/deploy/shared.d.ts +38 -57
  169. package/dist/cli/commands/deploy/shared.js +40 -59
  170. package/dist/cli/commands/deploy.d.ts +10 -27
  171. package/dist/cli/commands/deploy.js +38 -60
  172. package/dist/cli/commands/destroy.d.ts +4 -0
  173. package/dist/cli/commands/destroy.js +56 -0
  174. package/dist/cli/commands/dev.d.ts +2 -1
  175. package/dist/cli/commands/dev.js +20 -23
  176. package/dist/cli/commands/info.d.ts +0 -2
  177. package/dist/cli/commands/info.js +83 -49
  178. package/dist/cli/commands/init.d.ts +1 -2
  179. package/dist/cli/commands/init.js +16 -55
  180. package/dist/cli/commands/invoke.d.ts +0 -1
  181. package/dist/cli/commands/invoke.js +5 -7
  182. package/dist/cli/commands/login.d.ts +2 -1
  183. package/dist/cli/commands/login.js +33 -38
  184. package/dist/cli/commands/logs.js +3 -4
  185. package/dist/cli/commands/models.js +1 -5
  186. package/dist/cli/commands/routine-run.d.ts +6 -0
  187. package/dist/cli/commands/routine-run.js +47 -0
  188. package/dist/cli/commands/routine.d.ts +25 -0
  189. package/dist/cli/commands/routine.js +122 -0
  190. package/dist/cli/commands/start.d.ts +31 -3
  191. package/dist/cli/commands/start.js +131 -81
  192. package/dist/cli/commands/tool.js +26 -12
  193. package/dist/cli/fail.d.ts +13 -23
  194. package/dist/cli/fail.js +20 -23
  195. package/dist/cli/invoke-stream.d.ts +1 -8
  196. package/dist/cli/kernel.d.ts +6 -38
  197. package/dist/cli/kernel.js +14 -77
  198. package/dist/cli/models-view.d.ts +1 -9
  199. package/dist/cli/models-view.js +11 -22
  200. package/dist/cli/program.d.ts +5 -6
  201. package/dist/cli/program.js +120 -157
  202. package/dist/cli/serve.d.ts +57 -41
  203. package/dist/cli/serve.js +94 -121
  204. package/dist/cli/shared.d.ts +15 -61
  205. package/dist/cli/shared.js +55 -181
  206. package/dist/cli.js +1 -8
  207. package/dist/collect.d.ts +6 -0
  208. package/dist/collect.js +6 -0
  209. package/dist/core.d.ts +4 -1
  210. package/dist/core.js +9 -7
  211. package/dist/declared-secrets.d.ts +55 -0
  212. package/dist/declared-secrets.js +88 -0
  213. package/dist/deploy/agentcore/aws-cli.d.ts +91 -0
  214. package/dist/deploy/agentcore/aws-cli.js +64 -0
  215. package/dist/deploy/agentcore/destroy.d.ts +51 -0
  216. package/dist/deploy/agentcore/destroy.js +273 -0
  217. package/dist/deploy/agentcore/forwarder.js +28 -79
  218. package/dist/deploy/agentcore/logs.d.ts +2 -18
  219. package/dist/deploy/agentcore/logs.js +27 -51
  220. package/dist/deploy/agentcore/plan.d.ts +85 -105
  221. package/dist/deploy/agentcore/plan.js +152 -314
  222. package/dist/deploy/agentcore/run.d.ts +28 -28
  223. package/dist/deploy/agentcore/run.js +227 -306
  224. package/dist/deploy/agentcore/zip.d.ts +2 -15
  225. package/dist/deploy/agentcore/zip.js +3 -17
  226. package/dist/deploy/build-context.d.ts +21 -0
  227. package/dist/deploy/build-context.js +137 -0
  228. package/dist/deploy/channel-ingress.d.ts +26 -39
  229. package/dist/deploy/channel-ingress.js +57 -28
  230. package/dist/deploy/container.d.ts +20 -34
  231. package/dist/deploy/container.js +49 -100
  232. package/dist/deploy/docker/plan.d.ts +12 -11
  233. package/dist/deploy/docker/plan.js +43 -24
  234. package/dist/deploy/docker/run.d.ts +22 -25
  235. package/dist/deploy/docker/run.js +39 -37
  236. package/dist/deploy/fly/plan.d.ts +15 -44
  237. package/dist/deploy/fly/plan.js +41 -73
  238. package/dist/deploy/fly/run.d.ts +16 -51
  239. package/dist/deploy/fly/run.js +42 -95
  240. package/dist/deploy/hosts.d.ts +24 -3
  241. package/dist/deploy/hosts.js +24 -3
  242. package/dist/deploy/preflight.d.ts +47 -41
  243. package/dist/deploy/preflight.js +282 -383
  244. package/dist/deploy/railway/plan.d.ts +16 -42
  245. package/dist/deploy/railway/plan.js +42 -60
  246. package/dist/deploy/railway/run.d.ts +30 -68
  247. package/dist/deploy/railway/run.js +86 -100
  248. package/dist/deploy/registration-gate.d.ts +6 -13
  249. package/dist/deploy/residency.d.ts +37 -0
  250. package/dist/deploy/residency.js +24 -0
  251. package/dist/deploy/runner.d.ts +10 -9
  252. package/dist/deploy/runner.js +7 -18
  253. package/dist/deploy/secrets.d.ts +40 -41
  254. package/dist/deploy/secrets.js +117 -103
  255. package/dist/deploy/workspace.d.ts +50 -0
  256. package/dist/deploy/workspace.js +197 -0
  257. package/dist/dev-supervisor.d.ts +1 -9
  258. package/dist/dev-supervisor.js +21 -64
  259. package/dist/effect-port.d.ts +50 -0
  260. package/dist/effect-port.js +77 -0
  261. package/dist/engines/pi/agent-session-factory.d.ts +50 -69
  262. package/dist/engines/pi/agent-session-factory.js +249 -146
  263. package/dist/engines/pi/auth.d.ts +15 -11
  264. package/dist/engines/pi/auth.js +96 -99
  265. package/dist/engines/pi/chat.d.ts +1 -5
  266. package/dist/engines/pi/chat.js +2 -14
  267. package/dist/engines/pi/config.d.ts +53 -51
  268. package/dist/engines/pi/config.js +83 -92
  269. package/dist/engines/pi/create.d.ts +60 -75
  270. package/dist/engines/pi/create.js +108 -141
  271. package/dist/engines/pi/definition.d.ts +14 -58
  272. package/dist/engines/pi/definition.js +21 -85
  273. package/dist/engines/pi/invoke-session.d.ts +5 -25
  274. package/dist/engines/pi/invoke-session.js +233 -244
  275. package/dist/engines/pi/login.d.ts +95 -35
  276. package/dist/engines/pi/login.js +259 -107
  277. package/dist/engines/pi/machine.d.ts +31 -0
  278. package/dist/engines/pi/machine.js +106 -0
  279. package/dist/engines/pi/models.d.ts +70 -89
  280. package/dist/engines/pi/models.js +188 -81
  281. package/dist/engines/pi/open.d.ts +65 -53
  282. package/dist/engines/pi/open.js +129 -69
  283. package/dist/engines/pi/report.d.ts +3 -12
  284. package/dist/engines/pi/report.js +2 -16
  285. package/dist/engines/pi/search-tools.d.ts +1 -9
  286. package/dist/engines/pi/search-tools.js +26 -57
  287. package/dist/engines/pi/service.d.ts +2 -16
  288. package/dist/engines/pi/service.js +2 -16
  289. package/dist/engines/pi/session-builder.d.ts +5 -9
  290. package/dist/engines/pi/session-builder.js +44 -82
  291. package/dist/engines/pi/session-control.js +286 -269
  292. package/dist/engines/pi/session-effects.d.ts +14 -0
  293. package/dist/engines/pi/session-effects.js +30 -0
  294. package/dist/engines/pi/session-inheritance.d.ts +9 -18
  295. package/dist/engines/pi/session-inheritance.js +103 -160
  296. package/dist/engines/pi/session-markers.d.ts +31 -30
  297. package/dist/engines/pi/session-markers.js +26 -25
  298. package/dist/engines/pi/session-settings.d.ts +6 -22
  299. package/dist/engines/pi/session-settings.js +10 -21
  300. package/dist/engines/pi/session-store.d.ts +26 -92
  301. package/dist/engines/pi/session-store.js +96 -310
  302. package/dist/engines/pi/tool-context.d.ts +17 -45
  303. package/dist/engines/pi/tool-context.js +7 -26
  304. package/dist/engines/pi/tool.d.ts +45 -36
  305. package/dist/engines/pi/tool.js +43 -57
  306. package/dist/engines/pi/turn-kit.d.ts +14 -52
  307. package/dist/engines/pi/turn-kit.js +18 -67
  308. package/dist/engines/pi/wake-tool.d.ts +2 -10
  309. package/dist/engines/pi/wake-tool.js +7 -27
  310. package/dist/env.d.ts +27 -28
  311. package/dist/env.js +45 -50
  312. package/dist/index.js +0 -2
  313. package/dist/lark.d.ts +1 -2
  314. package/dist/lark.js +1 -2
  315. package/dist/loader.d.ts +14 -55
  316. package/dist/loader.js +24 -43
  317. package/dist/log.d.ts +2 -12
  318. package/dist/log.js +3 -24
  319. package/dist/node.d.ts +2 -15
  320. package/dist/node.js +2 -18
  321. package/dist/observe.d.ts +2 -8
  322. package/dist/open-url.d.ts +1 -1
  323. package/dist/open-url.js +1 -1
  324. package/dist/paths.d.ts +70 -134
  325. package/dist/paths.js +165 -232
  326. package/dist/pi.d.ts +4 -6
  327. package/dist/pi.js +3 -3
  328. package/dist/proxy.d.ts +16 -6
  329. package/dist/proxy.js +52 -16
  330. package/dist/runtime.d.ts +18 -12
  331. package/dist/runtime.js +18 -11
  332. package/dist/scaffold/add-channel.d.ts +14 -31
  333. package/dist/scaffold/add-channel.js +48 -112
  334. package/dist/scaffold/init.d.ts +9 -31
  335. package/dist/scaffold/init.js +45 -138
  336. package/dist/scaffold/templates/env.example +6 -4
  337. package/dist/scaffold/templates/fastagent.config.ts +36 -0
  338. package/dist/scaffold/templates.d.ts +3 -3
  339. package/dist/scaffold/templates.js +5 -8
  340. package/dist/scaffold/vendor-skill.d.ts +2 -5
  341. package/dist/scaffold/vendor-skill.js +19 -29
  342. package/dist/schedule/cron.d.ts +9 -5
  343. package/dist/schedule/cron.js +9 -11
  344. package/dist/schedule/discover.d.ts +12 -12
  345. package/dist/schedule/discover.js +43 -34
  346. package/dist/schedule/routine.d.ts +43 -0
  347. package/dist/schedule/routine.js +32 -0
  348. package/dist/schedule/run.d.ts +55 -0
  349. package/dist/schedule/run.js +146 -0
  350. package/dist/schedule/scheduler.d.ts +44 -55
  351. package/dist/schedule/scheduler.js +291 -265
  352. package/dist/schedule/state.d.ts +105 -10
  353. package/dist/schedule/state.js +293 -19
  354. package/dist/schedule/wake-alarm.d.ts +10 -23
  355. package/dist/schedule/wake-alarm.js +91 -121
  356. package/dist/schedule/wakeups.d.ts +23 -39
  357. package/dist/schedule/wakeups.js +33 -75
  358. package/dist/secrets-gate.d.ts +32 -0
  359. package/dist/secrets-gate.js +33 -0
  360. package/dist/service.d.ts +137 -98
  361. package/dist/service.js +250 -252
  362. package/dist/session-remote.d.ts +33 -44
  363. package/dist/session-remote.js +203 -192
  364. package/dist/session.d.ts +166 -229
  365. package/dist/session.js +33 -55
  366. package/dist/tunnel.d.ts +8 -36
  367. package/dist/tunnel.js +24 -65
  368. package/dist/version.d.ts +2 -2
  369. package/dist/version.js +2 -2
  370. package/package.json +10 -16
  371. package/dist/channels/agentcore-state.d.ts +0 -77
  372. package/dist/channels/agentcore-state.js +0 -276
  373. package/dist/channels/github/github.d.ts +0 -31
  374. package/dist/channels/github/github.js +0 -89
  375. package/dist/channels/github/scaffold/channel.ts +0 -25
  376. package/dist/cli/commands/attach.d.ts +0 -108
  377. package/dist/cli/commands/attach.js +0 -637
  378. package/dist/cli/commands/fire.d.ts +0 -7
  379. package/dist/cli/commands/fire.js +0 -38
  380. package/dist/cli/commands/schedule.d.ts +0 -12
  381. package/dist/cli/commands/schedule.js +0 -87
  382. package/dist/github.d.ts +0 -3
  383. package/dist/github.js +0 -2
  384. package/dist/scaffold/templates/fastagent.config.mjs +0 -23
  385. package/dist/schedule/audit.d.ts +0 -18
  386. package/dist/schedule/audit.js +0 -57
  387. package/dist/schedule/schedule.d.ts +0 -35
  388. package/dist/schedule/schedule.js +0 -23
@@ -1,125 +1,175 @@
1
- /**
2
- * `fastagent start [dir]`: run the agent in production posture — the SAME assembly as dev (your
3
- * directory is the agent), just no file-watching. No build step: start reads the definition directly.
4
- */
5
- import { dirname } from "node:path";
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ /** Production serving. */
10
+ import { join, resolve } from "node:path";
11
+ import { pathToFileURL } from "node:url";
12
+ import { createRequire } from "node:module";
13
+ import { readFile } from "node:fs/promises";
14
+ import * as Effect from "effect/Effect";
6
15
  import { writeFileAtomic } from "../../atomic-write.js";
7
- import { authSeedBytes, collectAuthSeed } from "../../deploy/secrets.js";
8
- import { resolveAuthPath, resolveSessionsDirOverride } from "../../engines/pi/config.js";
9
- import { SECRET_FILE_MODE, ensureSecretsDir, resolveSecretsDir, isUnderDir, exists } from "../../paths.js";
16
+ import { applyCarriedEnv, authSeedBytes, collectAuthSeed } from "../../deploy/secrets.js";
17
+ import { applyReleaseEnv, installAgentDependencies, parseDeploymentRelease, prepareDeployment, } from "../../deploy/workspace.js";
18
+ import { resolveAuthPath } from "../../engines/pi/config.js";
19
+ import { SECRET_FILE_MODE, resolveSecretsDir, isAgentcoreRuntime, isUnderDir, exists } from "../../paths.js";
10
20
  import { log, setLogLevel } from "../../log.js";
11
21
  import { createPiAgentFromDir } from "../../engines/pi/open.js";
12
- import { mountAgentService } from "../../service.js";
22
+ import { DEFAULT_HTTP_PORT, mountAgentService } from "../../service.js";
13
23
  import { logAgentLoop } from "../../observe.js";
14
- import { isAgentcoreRuntime, mountAgentcoreService } from "../../channels/agentcore-service.js";
24
+ import { mountAgentcoreService, deferAgentcoreService } from "../../channels/agentcore-service.js";
15
25
  import { createWakeAlarmSink } from "../../schedule/wake-alarm.js";
16
26
  import { setWakeupsSink } from "../../schedule/wakeups.js";
17
27
  import { failStartup } from "../fail.js";
18
- import { cliMountOptions, resolveBindHost, serveService } from "../serve.js";
28
+ import { announceControl, assertTunnelBindable, bindLine, cliMountOptions, serveService, serve, withRunOverrides, } from "../serve.js";
19
29
  import { enterAgentCommand, parseBind, parsePort, reportAssembly } from "../shared.js";
20
30
  export async function runStart(dirArg, opts) {
21
- // Flag validation first: a bad --port is a USAGE error (exit 2), and reporting it must not depend on
22
- // the directory being an agent (which is a runtime/environment failure, exit 1).
23
31
  const portFlag = parsePort(opts.port, "--port", "flag");
24
32
  const bindFlag = parseBind(opts.bind);
33
+ // A host that carries the value file as ONE encoded variable (AgentCore): expanded before anything reads the env.
34
+ try {
35
+ applyCarriedEnv();
36
+ }
37
+ catch (error) {
38
+ failStartup(error);
39
+ }
40
+ setLogLevel("info");
41
+ if (isAgentcoreRuntime()) {
42
+ // The generated Runtime resource sets PORT; 8080 is the platform's contract when nothing does.
43
+ const port = portFlag ?? parsePort(process.env.PORT, "PORT env", "env") ?? 8080;
44
+ const deferred = deferAgentcoreService({
45
+ prepare: () => prepareStartWorkspace(dirArg),
46
+ assemble: async (prepared) => {
47
+ const service = await openPreparedWorkspace(prepared, opts);
48
+ await service.ready;
49
+ announceControl(service, { host: bindFlag, tunnel: false });
50
+ return service;
51
+ },
52
+ });
53
+ serve(deferred.handler, { port, host: bindFlag }, {
54
+ // The assembly report waits for the first envelope, so this line is the only sign of life a booted container
55
+ // gives.
56
+ onListening: (port) => {
57
+ // NOT `readyAddressLines`: this posture serves the Runtime's `/invocations` contract, not our `/invoke`.
58
+ log.info(bindLine(bindFlag, port));
59
+ log.info("[fastagent] agentcore: the definition opens on the first invocation");
60
+ },
61
+ onShutdown: () => deferred.close(),
62
+ });
63
+ return;
64
+ }
65
+ // Deployed storage refusals (no mount, a held lease, a missing `flock`, a failed install) are the operator's only
66
+ // clue in a crash-looping container.
67
+ const service = await openStartService(dirArg, opts).catch(failStartup);
25
68
  const tunnel = opts.tunnel ?? false;
26
- setLogLevel("info"); // production posture: info+, the debug turn trace (and its end-user content) gated out
69
+ // An unset bind stays the wildcard: this is the container posture, and a published port needs it.
70
+ assertTunnelBindable(bindFlag, tunnel);
71
+ serveService(service, { port: portFlag ?? parsePort(process.env.PORT, "PORT env", "env") ?? service.port, host: bindFlag }, { tunnel, agentDir: service.agentDir, stateRoot: service.stateRoot });
72
+ }
73
+ /**
74
+ * Stage one — TAKE the workspace: verify the storage is mounted, apply the release, and point the machinery at the
75
+ * volume.
76
+ */
77
+ export async function prepareStartWorkspace(dirArg) {
78
+ const manifestPath = process.env.FASTAGENT_RELEASE_FILE;
79
+ if (!manifestPath)
80
+ return { dir: dirArg };
81
+ const storage = process.env.FASTAGENT_STORAGE_DIR;
82
+ if (!storage)
83
+ throw new Error("FASTAGENT_STORAGE_DIR is required for a deployed workspace");
84
+ const root = resolve(storage);
85
+ const manifest = parseDeploymentRelease(await readFile(manifestPath, "utf8"));
86
+ const dir = await prepareDeployment(resolve(dirArg), root, manifest);
87
+ // Defaults, not overrides: an operator who pointed either dir somewhere else meant it, and silently relocating
88
+ // their state is the one failure they could not diagnose from the logs.
89
+ process.env.FASTAGENT_STATE_DIR ||= join(root, ".state");
90
+ process.env.FASTAGENT_SECRETS_DIR ||= join(root, ".secrets");
91
+ process.env.FASTAGENT_AGENT = manifest.agent;
92
+ // The release's own declarations, projected into the environment it was resolved FOR. This must stay BEFORE
93
+ // `enterAgentEnv` reads the workspace's `.env`, which is what makes either source outrank a value edited on the
94
+ // box (applyReleaseEnv's own tests pin the precedence).
95
+ applyReleaseEnv(manifest);
96
+ process.chdir(dir);
97
+ return { dir, deployed: { root, agent: manifest.agent } };
98
+ }
99
+ /**
100
+ * Stage two — RUN in the prepared workspace: install the agent's dependencies, then open through the workspace's own
101
+ * FastAgent install.
102
+ */
103
+ export async function openPreparedWorkspace(prepared, opts) {
104
+ let open = openPreparedStartService;
105
+ if (prepared.deployed) {
106
+ const { root, agent } = prepared.deployed;
107
+ const agentDir = join(prepared.dir, agent);
108
+ if (await exists(join(agentDir, "package.json"))) {
109
+ await installAgentDependencies(root, agentDir);
110
+ // Tools and their session context must share the workspace's runtime module instance.
111
+ const entry = createRequire(join(agentDir, "package.json")).resolve("@fastagent-sh/fastagent");
112
+ const local = (await import(__rewriteRelativeImportExtension(new URL("./cli/commands/start.js", pathToFileURL(entry)).href)));
113
+ // A version-skewed dependency resolves and imports fine, then fails as "open is not a function" with nothing
114
+ // naming the two versions.
115
+ if (typeof local.openPreparedStartService !== "function") {
116
+ throw new Error(`${entry} does not export openPreparedStartService — align the agent's @fastagent-sh/fastagent version with the deploy CLI`);
117
+ }
118
+ open = local.openPreparedStartService;
119
+ }
120
+ }
121
+ return open(prepared.dir, opts);
122
+ }
123
+ export async function openStartService(dirArg, opts) {
124
+ return openPreparedWorkspace(await prepareStartWorkspace(dirArg), opts);
125
+ }
126
+ /** Internal entry loaded from the active workspace's installed package after storage initialization. */
127
+ export async function openPreparedStartService(dirArg, opts) {
27
128
  const placement = await enterAgentCommand(dirArg, opts);
28
- // A `deploy --run` may carry the operator's local credential as FASTAGENT_AUTH_SEED —
29
- // materialize it into the writable secrets dir BEFORE the opener resolves auth (once, absent-only).
30
- // Same resolveAuthPath the opener uses — ONE owner of the flag > env > default chain.
31
- await maybeSeedAuth(resolveAuthPath(placement.agentDir, opts.authPath));
32
- // The same opener dev uses (single assembly source), just no watch.
33
- const opened = await createPiAgentFromDir(placement.workspace, {
129
+ await maybeSeedAuth(resolveAuthPath(placement.agentDir));
130
+ const opened = await createPiAgentFromDir(placement.agentDir, {
34
131
  model: opts.model,
35
- sessionsDir: resolveSessionsDirOverride(opts.sessionsDir),
36
- authPath: opts.authPath,
37
- serving: true, // long-running serve: the scheduler poller runs (wake mounts iff config.selfSchedule)
38
- }).catch(failStartup);
132
+ serving: true,
133
+ });
39
134
  const { agent, agentDir, config, stateRoot, sessionsDir } = opened;
40
- // The same report `dev` prints; `state:`/`sessions:` are start's own extras, and the persistence
41
- // notes below are why (see reportAssembly on the asymmetry).
42
135
  await reportAssembly(opened, {
43
136
  afterTools: [
44
137
  ["state", stateRoot],
45
138
  ["sessions", sessionsDir],
46
139
  ],
47
140
  });
48
- // State defaults under the agent dir, which a redeploy may replace wholesale. Gate on where the
49
- // state root ACTUALLY resolved (inside the agent dir?), not on the raw env var: an empty
50
- // `FASTAGENT_STATE_DIR=""` reads as unset (resolveStateRoot) and still lands in-agent, so a raw
51
- // `=== undefined` check would wrongly silence the warning. A sessions override to a volume does not
52
- // help — channel state (the telegram turn/context files replay depends on) is still in-agent.
53
- // (auth.json is NOT under the state root — it lives in the secrets dir, resolveSecretsDir.)
54
141
  if (isUnderDir(stateRoot, agentDir)) {
55
- log.info(`[fastagent] note: state (sessions, channel state) lives under the definition dir; point ` +
56
- `FASTAGENT_STATE_DIR at a persistent volume so a redeploy that replaces the dir does not wipe it.`);
142
+ log.info("[fastagent] note: state lives under the definition; use FASTAGENT_STATE_DIR on persistent storage for deployment.");
57
143
  }
58
- // The secrets dir is the SAME trap on a different lifecycle: auth.json is MACHINE-WRITTEN (OAuth
59
- // rotation), so the copy under the definition dir is the only valid one — a redeploy that replaces
60
- // the dir loses a credential no re-seed can restore. An independent check on purpose: moving ONE
61
- // of the two to a volume must not silence the note about the other.
62
144
  if (isUnderDir(resolveSecretsDir(agentDir), agentDir)) {
63
- log.info(`[fastagent] note: secrets (.env, rotated auth.json) live under the definition dir; point ` +
64
- `FASTAGENT_SECRETS_DIR at a persistent volume so a redeploy that replaces the dir does not wipe them.`);
145
+ log.info("[fastagent] note: credentials live under the definition; use FASTAGENT_SECRETS_DIR on persistent storage for deployment.");
65
146
  }
66
- // Same debug turn trace as dev; gated out here by the info level.
67
147
  const traced = logAgentLoop(agent);
68
- const host = resolveBindHost(bindFlag, config.http?.host, tunnel);
69
- // ONE branch for the whole posture. AgentCore assembles differently — lazy channels over a
70
- // pre-restore state mount, an external clock, no resident connections — but it yields the same
71
- // AgentService, so everything below this point is common.
72
- // The wake-alarm sink is a PROCESS-global (schedule/wakeups.ts) — this process IS the AgentCore
73
- // deployment, so the process entry installs it. A service can be closed; a global cannot be
74
- // handed to something that can, without inventing an ownership the singleton does not have.
75
- const onStateReady = isAgentcoreRuntime() && config.selfSchedule ? armWakeAlarms(stateRoot) : undefined;
148
+ const onStateReady = isAgentcoreRuntime() ? armWakeAlarms(stateRoot) : undefined;
149
+ const mountable = withRunOverrides(opened, opts);
76
150
  const service = await (isAgentcoreRuntime()
77
- ? mountAgentcoreService(opened, { wrapAgent: () => traced, onStateReady })
78
- : mountAgentService(opened, cliMountOptions(() => traced))).catch(failStartup);
79
- serveService(service, { port: portFlag ?? parsePort(process.env.PORT, "PORT env", "env") ?? config.http?.port ?? 8787, host }, { tunnel, agentDir, stateRoot });
80
- // No graceful drain: webhook turns run fire-and-forget; SIGTERM just exits mid-turn. Whether an
81
- // in-flight turn is LOST depends on the channel: the Telegram channel persists turn intent pre-ACK
82
- // and replays it next start (turn-store.ts, L1 durable execution, at-least-once); HTTP and other
83
- // channels have no such layer, so their in-flight turns are still lost (the asker re-invokes).
151
+ ? mountAgentcoreService(mountable, { wrapAgent: () => traced, onStateReady })
152
+ : mountAgentService(mountable, cliMountOptions(() => traced)));
153
+ return { ...service, stateRoot, port: config.http?.port ?? DEFAULT_HTTP_PORT };
84
154
  }
85
- /**
86
- * Materialize `FASTAGENT_AUTH_SEED` (base64 of an auth.json, set by `deploy --run`) into the
87
- * writable secrets dir ONCE — only when the seed is set AND the auth file is absent, so a refreshed
88
- * volume copy is never clobbered by the stale seed. Lets a deploy carry the operator's local
89
- * OAuth/API credential so the box runs on the SAME subscription. No-op locally (the seed is unset).
90
- */
91
155
  async function maybeSeedAuth(authPath) {
92
- // collectAuthSeed: the seed may arrive CHUNKED (FASTAGENT_AUTH_SEED + _2…) on hosts with a small
93
- // env-value max length (AgentCore); single-var hosts are unchanged.
94
156
  const bytes = authSeedBytes(collectAuthSeed(process.env), await exists(authPath));
95
157
  if (!bytes)
96
158
  return;
97
- await ensureSecretsDir(dirname(authPath));
98
- // Same spelling as the credential store: the mode is applied before the content is reachable, so
99
- // the seed can never be published at some other file's looser permissions. It does NOT close the
100
- // gap between the `exists` check and the write — the rename would overwrite a file created in
101
- // between, against this function's absent-only promise. That window needs two `start` processes on
102
- // one secrets dir, which no supported deployment runs (one container, one volume).
103
- writeFileAtomic(authPath, bytes, SECRET_FILE_MODE);
159
+ writeFileAtomic(authPath, bytes, SECRET_FILE_MODE); // creates the directory it needs
104
160
  log.info(`[fastagent] seeded ${authPath} from FASTAGENT_AUTH_SEED (first boot)`);
105
161
  }
106
162
  /**
107
- * Install the wake-ALARM sink before the scheduler starts — the boot wake pump may advance a
108
- * recurring entry, and that save must already re-arm its alarm. Returns the post-restore reconcile:
109
- * running it at boot would read the pre-restore state mount, see no pending wake-ups, and conclude
110
- * there is nothing to re-arm.
163
+ * Install the wake-ALARM sink before the scheduler starts: the first wake poll may advance a recurring entry, and that
164
+ * save must already re-arm its alarm.
111
165
  */
112
166
  function armWakeAlarms(stateRoot) {
113
167
  const secret = process.env.FASTAGENT_WAKE_SECRET;
114
168
  if (!secret) {
115
- log.warn(`[fastagent] FASTAGENT_WAKE_SECRET is not set — wake-ups fire only while a session is awake ` +
116
- `(redeploy with the current template to fix)`);
169
+ log.warn("[fastagent] FASTAGENT_WAKE_SECRET is missing; external wake alarms cannot be registered");
117
170
  return undefined;
118
171
  }
119
- const sink = createWakeAlarmSink({ secret });
172
+ const sink = Effect.runSync(createWakeAlarmSink({ secret }));
120
173
  setWakeupsSink(sink);
121
- log.info(`[fastagent] wake alarms: EventBridge-backed via the forwarder`);
122
- // Boot reconcile: pending wake-ups may exist while their alarms were lost (a deploy replaced the
123
- // forwarder, a sink call failed). The sink re-reads the store, so a bare notification is enough.
124
174
  return () => sink(stateRoot);
125
175
  }
@@ -1,36 +1,50 @@
1
1
  /** `fastagent tool <name> '<json>' [dir]`: run one tool's body directly with JSON args — no model. */
2
2
  import { resolve } from "node:path";
3
- import { loadDotEnv } from "../../env.js";
3
+ import { enterAgentEnv } from "../../env.js";
4
4
  import { loadConfig } from "../../engines/pi/config.js";
5
5
  import { resolveAgentTools } from "../../engines/pi/create.js";
6
6
  import { reportModuleLoadFailures } from "../../loader.js";
7
7
  import { turnContext } from "../../engines/pi/tool-context.js";
8
- import { failStartup, failUsage, placementOrExit } from "../fail.js";
8
+ import { failStartup, failUsage, gateSecretsOrExit, placementOrExit } from "../fail.js";
9
9
  export async function runTool(name, argsJson, dirArg) {
10
- // Argument shape first: malformed JSON is a USAGE error (exit 2), independent of whether the
11
- // directory is an agent (a runtime failure, exit 1).
10
+ // Argument shape first: malformed JSON is a USAGE error (exit 2), independent of whether the directory is an agent
11
+ // (a runtime failure, exit 1).
12
12
  const args = parseToolArgs(argsJson);
13
13
  const { agentDir, workspace } = placementOrExit(resolve(dirArg));
14
- loadDotEnv(agentDir); // a tool may read a key from .env
14
+ enterAgentEnv(agentDir); // a tool may read a key from .env — and fetch through the proxy it declares
15
15
  const { config } = await loadConfig(agentDir).catch(failStartup);
16
16
  // The same tool set dev/start mount (all coding tools + config.tools + discovered, deduped), so the runner
17
- // exercises exactly what gets served — a shadowed tool is surfaced, not silently run. Resolve the
18
- // placement like the openers, so `fastagent tool` finds the SAME tools/ as dev/start.
19
- const { tools, toolCollisions, toolFailures } = await resolveAgentTools(config, agentDir, workspace).catch(failStartup);
17
+ // exercises exactly what gets served.
18
+ const { tools, toolCollisions, toolFailures, toolSecrets } = await resolveAgentTools(config, agentDir, workspace).catch(failStartup);
20
19
  for (const c of toolCollisions) {
21
20
  console.error(`[fastagent] warn: tool "${c.name}" (${c.source}) is shadowed by a default/config tool — not mounted`);
22
21
  }
22
+ // Reported BEFORE the name is looked up: a file that failed to import is missing from `tools`, so
23
+ // "unknown tool" is exactly the case where the author most needs to hear that something blew up
24
+ // rather than that they mistyped it.
23
25
  reportModuleLoadFailures(toolFailures);
24
26
  const tool = tools.find((t) => t.name === name);
25
27
  if (!tool) {
26
28
  failStartup(new Error(`unknown tool "${name}". available: ${tools.map((t) => t.name).join(", ") || "(none)"}`));
27
29
  }
30
+ // This command RUNS one tool body, so it takes the same guarantee dev/start take — for THAT tool
31
+ // only (`owner`): running one tool by hand must not require the credentials of the tools it is not
32
+ // running, and `routine run` scopes the same way for one routine.
33
+ // The failures go to the gate as well, even though they were just printed: the gate's guarantee is
34
+ // that a refusal never hides them, and it cannot know a caller already reported. A repeated line on
35
+ // the refusal path is the cheaper failure than one that depends on this call site remembering.
36
+ gateSecretsOrExit({ declared: toolSecrets, failures: toolFailures, owner: name });
28
37
  // Authored tools read cwd from turnContext; coding tools are already rooted at the workspace.
29
38
  const result = await turnContext.run({ cwd: workspace }, () => tool.execute(`cli-${name}`, args)).catch(failStartup);
30
- const out = result?.details !== undefined
31
- ? result.details
32
- : (result?.content ?? []).map((c) => ("text" in c ? c.text : "")).join("");
33
- console.log(typeof out === "string" ? out : JSON.stringify(out, null, 2));
39
+ // What the MODEL receives, which is not what is printed below: the printed form is `details` (readable, indented),
40
+ // the model's is the content text (compact JSON). Piping stdout through `wc -c` therefore answers the wrong
41
+ // question, and there is nowhere else to ask this one — so the run that a tool author already does reports it.
42
+ const modelText = (result?.content ?? []).map((c) => ("text" in c ? c.text : "")).join("");
43
+ const out = result?.details !== undefined ? result.details : modelText;
44
+ console.log(typeof out === "string" ? out : JSON.stringify(out, null, 2)); // stdout stays DATA
45
+ // No threshold warning: context windows run from 128k to 1M, so any fixed ceiling here would be invented. The
46
+ // number is the signal; docs/api-reference.md carries the judgement. ~4 chars/token is the usual rough figure.
47
+ console.error(`[fastagent] result: ${modelText.length} chars ≈ ${Math.ceil(modelText.length / 4)} tokens to the model`);
34
48
  }
35
49
  /** Parse the CLI's JSON args blob; malformed input syntax is a usage error (exit 2). */
36
50
  function parseToolArgs(argsJson) {
@@ -1,34 +1,24 @@
1
1
  import { type ResolvedPlacement } from "../paths.ts";
2
- /**
3
- * The ONE error prefix every error message carries — bold red when stderr renders color, plain
4
- * otherwise. Errors are the only place the CLI uses color at all.
5
- */
2
+ import { gateSecrets } from "../secrets-gate.ts";
3
+ /** The ONE error prefix every error message carries — bold red when stderr renders color, plain otherwise. */
6
4
  export declare function errorPrefix(colors?: boolean): string;
7
5
  /**
8
- * User-fixable startup problems (missing model / bad config / broken definition) are thrown as plain
9
- * `Error` — print just the message. Anything else (TypeError, non-Error) is a bug: keep the stack.
10
- * Shared by the kernel and the command modules; exit 1 (runtime failure).
6
+ * User-fixable startup problems (missing model / bad config / broken definition) are thrown as plain `Error` — print
7
+ * just the message. Anything else (a TypeError, a non-Error throw) is a bug: keep the stack.
11
8
  */
12
9
  export declare function failStartup(error: unknown): never;
13
10
  /**
14
- * THE placement entry point for commands: resolve `dir`, or exit 1 with the one-line refusal. Every
15
- * command that needs an agent goes through this — the try/catch was hand-repeated at sixteen call
16
- * sites, which is sixteen chances to forget it (`dev`'s supervisor did, and surfaced a raw stack).
17
- *
18
- * The catch is what makes it a function at all: placement resolves SYNCHRONOUSLY, before any promise
19
- * exists, so it cannot ride the `.catch(failStartup)` every async startup chain carries — and its
20
- * refusals ("not a fastagent agent", plus the two dead ends with their own exits) are user-fixable,
21
- * which means a one-line `Error:` and exit 1, never a stack.
22
- *
23
- * Not every command calls it — and the exceptions are the useful part of this note. `init` CREATES the
24
- * agent (it must run where there is none). `models` is directory-independent. `login` needs one only for
25
- * the project-level credential and falls back to the global one, and `attach --url/--token` reads
26
- * nothing local. Everything else needs an agent, so it comes through here.
11
+ * {@link gateSecrets} at the process boundary, for a command that runs ONE owner's code (`fastagent
12
+ * tool`, `fastagent routine run`). The gate throws SYNCHRONOUSLY, so there is no promise to hang the usual
13
+ * `.catch(failStartup)` on, and a raw throw reaches `cli.ts`'s top-level await as a Node stack that
14
+ * buries the one line naming the file. The catch translates that expected failure into the CLI's
15
+ * single-line refusal and exits 1; nothing is recovered.
27
16
  */
17
+ export declare function gateSecretsOrExit(input: Parameters<typeof gateSecrets>[0]): void;
18
+ /** THE placement entry point for commands: resolve `dir`, or exit 1 with the one-line refusal. */
28
19
  export declare function placementOrExit(dir: string): ResolvedPlacement;
29
20
  /**
30
- * A usage error the parser could not catch (a bad value shape, an invalid flag/argument combination
31
- * discovered in a command body): print the message and exit 2 — the same class as a parse error.
32
- * Exit codes follow responsibility, not the layer that happens to discover the problem.
21
+ * A usage error the parser could not catch (a bad value shape, an invalid flag/argument combination discovered in a
22
+ * command body): print the message and exit 2.
33
23
  */
34
24
  export declare function failUsage(message: string): never;
package/dist/cli/fail.js CHANGED
@@ -1,19 +1,16 @@
1
1
  import { resolvePlacement } from "../paths.js";
2
+ import { gateSecrets } from "../secrets-gate.js";
2
3
  /** stderr renders color: a color TTY, with Node's `hasColors()` carrying the NO_COLOR/TERM=dumb veto. */
3
4
  function stderrHasColors() {
4
5
  return process.stderr.isTTY === true && (process.stderr.hasColors?.() ?? false);
5
6
  }
6
- /**
7
- * The ONE error prefix every error message carries — bold red when stderr renders color, plain
8
- * otherwise. Errors are the only place the CLI uses color at all.
9
- */
7
+ /** The ONE error prefix every error message carries — bold red when stderr renders color, plain otherwise. */
10
8
  export function errorPrefix(colors = stderrHasColors()) {
11
9
  return colors ? "\x1b[1;31mError:\x1b[0m" : "Error:";
12
10
  }
13
11
  /**
14
- * User-fixable startup problems (missing model / bad config / broken definition) are thrown as plain
15
- * `Error` — print just the message. Anything else (TypeError, non-Error) is a bug: keep the stack.
16
- * Shared by the kernel and the command modules; exit 1 (runtime failure).
12
+ * User-fixable startup problems (missing model / bad config / broken definition) are thrown as plain `Error` — print
13
+ * just the message. Anything else (a TypeError, a non-Error throw) is a bug: keep the stack.
17
14
  */
18
15
  export function failStartup(error) {
19
16
  if (error instanceof Error && error.constructor === Error)
@@ -23,20 +20,21 @@ export function failStartup(error) {
23
20
  process.exit(1);
24
21
  }
25
22
  /**
26
- * THE placement entry point for commands: resolve `dir`, or exit 1 with the one-line refusal. Every
27
- * command that needs an agent goes through this — the try/catch was hand-repeated at sixteen call
28
- * sites, which is sixteen chances to forget it (`dev`'s supervisor did, and surfaced a raw stack).
29
- *
30
- * The catch is what makes it a function at all: placement resolves SYNCHRONOUSLY, before any promise
31
- * exists, so it cannot ride the `.catch(failStartup)` every async startup chain carries — and its
32
- * refusals ("not a fastagent agent", plus the two dead ends with their own exits) are user-fixable,
33
- * which means a one-line `Error:` and exit 1, never a stack.
34
- *
35
- * Not every command calls it — and the exceptions are the useful part of this note. `init` CREATES the
36
- * agent (it must run where there is none). `models` is directory-independent. `login` needs one only for
37
- * the project-level credential and falls back to the global one, and `attach --url/--token` reads
38
- * nothing local. Everything else needs an agent, so it comes through here.
23
+ * {@link gateSecrets} at the process boundary, for a command that runs ONE owner's code (`fastagent
24
+ * tool`, `fastagent routine run`). The gate throws SYNCHRONOUSLY, so there is no promise to hang the usual
25
+ * `.catch(failStartup)` on, and a raw throw reaches `cli.ts`'s top-level await as a Node stack that
26
+ * buries the one line naming the file. The catch translates that expected failure into the CLI's
27
+ * single-line refusal and exits 1; nothing is recovered.
39
28
  */
29
+ export function gateSecretsOrExit(input) {
30
+ try {
31
+ gateSecrets(input);
32
+ }
33
+ catch (error) {
34
+ failStartup(error);
35
+ }
36
+ }
37
+ /** THE placement entry point for commands: resolve `dir`, or exit 1 with the one-line refusal. */
40
38
  export function placementOrExit(dir) {
41
39
  try {
42
40
  return resolvePlacement(dir);
@@ -46,9 +44,8 @@ export function placementOrExit(dir) {
46
44
  }
47
45
  }
48
46
  /**
49
- * A usage error the parser could not catch (a bad value shape, an invalid flag/argument combination
50
- * discovered in a command body): print the message and exit 2 — the same class as a parse error.
51
- * Exit codes follow responsibility, not the layer that happens to discover the problem.
47
+ * A usage error the parser could not catch (a bad value shape, an invalid flag/argument combination discovered in a
48
+ * command body): print the message and exit 2.
52
49
  */
53
50
  export function failUsage(message) {
54
51
  console.error(`${errorPrefix()} ${message}`);
@@ -1,10 +1,3 @@
1
- /**
2
- * Render an Agent event stream to two sinks plus an exit code — the `fastagent invoke` contract, a
3
- * PURE function (IO injected) so it is unit-testable: text deltas → `out`; tool start + an ERRORED
4
- * tool_ended → `err`; `failed` → `err` + a non-zero exit code (the CI-gating guarantee).
5
- *
6
- * An errored tool inside an otherwise-completed turn still surfaces (the diagnostic the operator
7
- * needs); tool_ended carries no name, so it is remembered from the matching tool_started.
8
- */
1
+ /** Render an Agent event stream to two sinks plus an exit code. */
9
2
  import type { AgentEvent } from "../agent.ts";
10
3
  export declare function runInvokeStream(events: AsyncIterable<AgentEvent>, out: (text: string) => void, err: (line: string) => void): Promise<number>;
@@ -1,16 +1,4 @@
1
- /**
2
- * CLI kernel — commands as data. A {@link CommandSpec} carries everything the CLI surface needs
3
- * (summary, args/flags, examples, narrative notes, a lazy `run`), and {@link buildProgram} renders
4
- * the set through commander. Commander is called ONLY from this module; the notation specs are
5
- * written in — docopt-style argument brackets (`<required>`/`[optional]`), the flag DSL
6
- * (`--auth-path <file>`, `--no-x` negation), and the derived option keys ({@link optionKey}) — is a
7
- * contract this module owns and validates at build time. Replacing the parser means re-implementing
8
- * that notation here (one module), not editing the specs.
9
- *
10
- * Follows clig.dev: per-command help in four spellings (`-h`/`--help`/`help <cmd>`/bare-with-missing-args),
11
- * examples in help, "did you mean" suggestions (never auto-run), and one exit-code policy — 0 success,
12
- * 1 runtime failure (owned by the command bodies), 2 usage error (anything the parser itself rejects).
13
- */
1
+ /** CLI kernel — commands as data. */
14
2
  import { Command } from "commander";
15
3
  /** One positional argument, in commander syntax: `<name>` required, `[dir]` optional. */
16
4
  interface ArgSpec {
@@ -20,12 +8,10 @@ interface ArgSpec {
20
8
  /** Closed value set — the parser rejects anything else as a usage error (exit 2). */
21
9
  choices?: string[];
22
10
  }
23
- /** One flag, in the flag DSL: `--json`, or `--auth-path <file>` for a value-taking flag. */
11
+ /** One flag, in the flag DSL: `--json`, or `--bind <addr>` for a value-taking flag. */
24
12
  export interface FlagSpec {
25
13
  flags: string;
26
14
  description: string;
27
- /** Mutually exclusive with these {@link optionKey} values — validated at build time. */
28
- conflicts?: string[];
29
15
  }
30
16
  interface ExampleSpec {
31
17
  cmd: string;
@@ -46,13 +32,11 @@ export interface CommandSpec {
46
32
  /** A group command (e.g. `schedule`) declares subcommands instead of `run`. */
47
33
  subcommands?: CommandSpec[];
48
34
  /**
49
- * The implementation: positional args in declaration order (an optional arg without a default is
50
- * `undefined`), then the parsed flags. Lazy-import the actual work so `fastagent <cmd>` pays only
51
- * for the modules that command uses. Runtime failures exit 1 from inside (fail visibly).
35
+ * The implementation: positional args in declaration order (an optional arg without a default is `undefined`), then
36
+ * the parsed flags.
52
37
  */
53
38
  run?: (args: (string | undefined)[], flags: Record<string, unknown>) => Promise<void> | void;
54
39
  }
55
- /** Program-level configuration. Output/exit/width seams let tests drive the program in-process. */
56
40
  export interface ProgramOptions {
57
41
  /** Printed by `-v`/`--version`. */
58
42
  version?: string;
@@ -60,29 +44,13 @@ export interface ProgramOptions {
60
44
  examples?: ExampleSpec[];
61
45
  /** Top-level closing prose (the docs link) — reflowed like any notes. */
62
46
  notes?: string;
63
- /**
64
- * Fixed help width — a TEST seam. Production omits it: commander then adapts to the terminal
65
- * (and falls back to 80 when piped), the modern behavior. Our verbatim Examples/notes text is
66
- * hand-wrapped at ≤78 columns so it reads well at any width ≥ 80 (prose caps, like man pages).
67
- */
47
+ /** Fixed help width — a TEST seam. */
68
48
  helpWidth?: number;
69
- /**
70
- * Force help colors on/off — a TEST seam. Production omits it: commander detects per stream
71
- * (color TTY → on; pipe, NO_COLOR, TERM=dumb → off) and strips every SGR code when off.
72
- */
49
+ /** Force help colors on/off — a TEST seam. */
73
50
  colors?: boolean;
74
51
  out?: (chunk: string) => void;
75
52
  err?: (chunk: string) => void;
76
53
  exit?: (code: number) => never;
77
54
  }
78
- /**
79
- * The option key a flag string yields on the parsed-flags record — THE naming rule specs rely on:
80
- * camelCase of the long name (`--auth-path` → `authPath`); a `--no-x` flag negates and stores under
81
- * `x` (absent ⇒ `x !== false`). Owned and enforced here so `conflicts` references and run-body reads
82
- * answer to one authority, not to an implicit parser behavior. Throws on a flag without a long form
83
- * (clig: every flag has a full-length spelling).
84
- */
85
- export declare function optionKey(flags: string): string;
86
- /** Build the commander program for `specs`. The CLI entry parses with it; tests inject the IO seams. */
87
55
  export declare function buildProgram(specs: readonly CommandSpec[], options?: ProgramOptions): Command;
88
56
  export {};