@fastagent-sh/fastagent 0.21.0 → 0.22.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 (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 -43
  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 +209 -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 +153 -228
  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,48 +1,18 @@
1
1
  /**
2
- * Auth for the pi engine: a read-WRITE {@link CredentialStore} over a fastagent credentials file,
3
- * consumed by the `Models` collection (models.ts). The path is project-level by default
4
- * (`<agentDir>/.secrets/auth.json`, resolved by the opener); {@link GLOBAL_AUTH_PATH} is the
5
- * global location used as the override target / login default, not an implicit per-provider fallback.
6
- *
7
- * Project-level default + NO implicit project↔global fallback, for two reasons: (1) isolation — each
8
- * agent can use a different account/subscription; (2) fail-visibly — a missing credential surfaces at
9
- * startup instead of being masked by a machine-global one that won't exist on a fresh deploy box. A
10
- * *fallback* specifically is refused because the only safe shape (read global, write the rotated token
11
- * back to the project file) would diverge: OAuth refresh tokens are single-use, so consuming global's
12
- * token and persisting the new one elsewhere leaves global stale for every other consumer.
13
- *
14
- * Sharing is still SAFE the right way: point everything at ONE file (`FASTAGENT_AUTH_PATH` → the
15
- * global path). One file means one refresh lifecycle under the store's cross-process write lock
16
- * (refresh re-reads the latest token under the lock), the documented same-machine pattern.
17
- * fastagent's store stays SEPARATE from the pi CLI's `~/.pi/agent/auth.json` for the same single-
18
- * lifecycle reason: two uncoordinated files over one grant would each rotate and break the other.
19
- *
20
- * Locking is vendored here on `proper-lockfile`, with the same parameters pi's file backend used
21
- * before pi 0.80.8 stopped exporting it (upstream's stated migration path for SDK consumers is a
22
- * custom pi-ai `CredentialStore`, which this file is). The lock guards the WRITE path only. `read`
23
- * is pi-ai's per-request hot path, so it stays UNLOCKED — safe because every write that carries a
24
- * CREDENTIAL publishes by rename ({@link writeFileAtomic}): a reader sees one whole version of the
25
- * file or another, never a partial one, so a rotation has no torn-read window for an unlocked read
26
- * to absorb. The one in-place write left is the `{}` bootstrap below, whose window an unlocked read
27
- * observes as an empty file — reported as corrupt, which for a zero-byte auth.json is the right
28
- * answer either way. The write path refuses to overwrite a corrupt file (never clobbering other
29
- * providers' credentials).
2
+ * Auth for the pi engine: a read-WRITE {@link CredentialStore} over a fastagent credentials file, consumed by the
3
+ * `Models` collection (models.ts). The write path refuses to overwrite a corrupt file, so a torn read never clobbers
4
+ * the other providers' credentials.
30
5
  */
31
- import { chmodSync, existsSync, readFileSync, writeFileSync } from "node:fs";
6
+ import { existsSync, lstatSync, mkdirSync, readFileSync, readlinkSync, realpathSync, writeFileSync } from "node:fs";
32
7
  import { homedir } from "node:os";
33
- import { dirname, join } from "node:path";
34
- import { GLOBAL_HOME_DIR, SECRETS_DIRNAME, SECRET_FILE_MODE, ensureSecretsDir } from "../../paths.js";
8
+ import { dirname, join, resolve } from "node:path";
9
+ import { GLOBAL_HOME_DIR, SECRETS_DIRNAME, SECRET_FILE_MODE } from "../../paths.js";
35
10
  import { writeFileAtomic } from "../../atomic-write.js";
36
11
  import { log } from "../../log.js";
37
12
  import lockfile from "proper-lockfile";
38
13
  /**
39
- * The GLOBAL fastagent credentials file (distinct from pi's `~/.pi`), under the user-global machinery
40
- * home `~/.fastagent/` — which carries the same unified shape as a workspace (`.secrets/auth.json`).
41
- * The project-level default is `<agentDir>/.secrets/auth.json` (computed by the opener and by
42
- * `fastagent login`); this is only the `loginFlow()` PROGRAMMATIC fallback (when a caller omits
43
- * `authPath`) and the path to point `--auth-path`/`FASTAGENT_AUTH_PATH` at to deliberately share ONE
44
- * credential file across projects (safe — one file, one lock-serialized refresh lifecycle). The
45
- * `fastagent login` CLI is project-level by default, never this.
14
+ * The GLOBAL fastagent credentials file (distinct from pi's `~/.pi`), under the user-global machinery home
15
+ * `~/.fastagent/`.
46
16
  */
47
17
  export const GLOBAL_AUTH_PATH = join(homedir(), GLOBAL_HOME_DIR, SECRETS_DIRNAME, "auth.json");
48
18
  /** A valid stored credential, or undefined — a foreign/old entry reads as not-configured, not a crash. */
@@ -52,27 +22,33 @@ function pick(creds, providerId) {
52
22
  }
53
23
  const AUTH_FILE_WRITE_OPTIONS = { encoding: "utf8", mode: SECRET_FILE_MODE };
54
24
  /**
55
- * Serialized cross-process read-modify-write of the credentials file: exponential-backoff retries,
56
- * 30s staleness, and compromise detection (the parameters pi's `FileAuthStorageBackend` used).
57
- * Ensures the file exists first (0700 dir, 0600 file, EXCLUSIVE create: a concurrent first write
58
- * must never be clobbered by the init) because `proper-lockfile` locks an existing path. A
59
- * compromised lock aborts before the write rather than clobbering a concurrent writer, and a
60
- * failed unlock after a successful operation rejects instead of leaving a stale lock silently.
25
+ * The file a write must land IN, which is not always the path it is addressed BY. pi writes the auth file in place,
26
+ * so it follows a symlink to the target; an atomic rename would replace the link with a regular file instead, and
27
+ * from then on the two tools would be editing different files — the same split the shared lock exists to prevent,
28
+ * arriving one write later. A dangling link (a dotfile manager that has not checked the target out yet) still names
29
+ * where the credentials belong, so it is followed too rather than overwritten.
61
30
  */
31
+ function writeTarget(authPath) {
32
+ if (existsSync(authPath))
33
+ return realpathSync(authPath);
34
+ const link = lstatSync(authPath, { throwIfNoEntry: false });
35
+ // ponytail: one hop. A chain of dangling links would have its second link replaced; resolve iteratively if that
36
+ // ever shows up in a real layout.
37
+ return link?.isSymbolicLink() ? resolve(dirname(authPath), readlinkSync(authPath)) : authPath;
38
+ }
39
+ /** Serialized cross-process read-modify-write of the credentials file. */
62
40
  async function withLockedAuthFile(authPath, fn) {
63
- // 0700 unconditionally, including on a directory an operator named with `--auth-path`: pointing a
64
- // credential file somewhere is asking for that somewhere to hold a credential. Where the process
65
- // cannot chmod (a mount it does not own), this raises — the write fails visibly instead of
66
- // quietly leaving the directory readable, which is the trade this repo takes everywhere else.
67
- await ensureSecretsDir(dirname(authPath));
41
+ mkdirSync(dirname(authPath), { recursive: true });
68
42
  if (!existsSync(authPath)) {
69
43
  try {
44
+ // `wx` makes this an exclusive CREATE, which is the one case `writeFileSync` honours `mode` in — so no chmod
45
+ // after it (unlike writeFileAtomic, whose temp may already exist from a crashed writer).
70
46
  writeFileSync(authPath, "{}", { ...AUTH_FILE_WRITE_OPTIONS, flag: "wx" });
71
- chmodSync(authPath, SECRET_FILE_MODE);
72
47
  }
73
48
  catch (error) {
74
- // EEXIST: another process created the file between the existence check and this exclusive
75
- // create; its content (possibly already-written credentials) must not be clobbered.
49
+ // EEXIST: the path IS taken, by something `existsSync` does not see through — either another process created
50
+ // the file just now (its credentials must not be clobbered) or the path is a dangling symlink. Both are left
51
+ // alone: the write below resolves where they belong.
76
52
  if (error.code !== "EEXIST")
77
53
  throw error;
78
54
  }
@@ -83,6 +59,12 @@ async function withLockedAuthFile(authPath, fn) {
83
59
  throw compromised;
84
60
  };
85
61
  const release = await lockfile.lock(authPath, {
62
+ // MUST match pi-coding-agent's `core/auth-storage.js`, which locks with `realpath: false`. When the auth file
63
+ // itself is a symlink (dotfile managers do this), the two settings name DIFFERENT lock files and both locks can
64
+ // be held at once — so `pi` and `fastagent` would refresh the same provider concurrently, and a rotated refresh
65
+ // token logs one of them out. Resolving the link would be the stronger rule, but only if BOTH sides did it, and
66
+ // we do not own the other side.
67
+ realpath: false,
86
68
  retries: { retries: 10, factor: 2, minTimeout: 100, maxTimeout: 10_000, randomize: true },
87
69
  stale: 30_000,
88
70
  onCompromised: (error) => {
@@ -95,12 +77,11 @@ async function withLockedAuthFile(authPath, fn) {
95
77
  const current = existsSync(authPath) ? readFileSync(authPath, "utf8") : undefined;
96
78
  const out = await fn(current);
97
79
  throwIfCompromised();
98
- // Rename, not an in-place rewrite: it is what lets `read` stay unlocked, and it is the only
99
- // spelling that applies the mode before the content is reachable — `writeFileSync`'s `mode` is
100
- // a no-op on an existing file, so a chmod after it leaves the new credential briefly readable
101
- // at whatever mode the old file carried.
102
- if (out.next !== undefined)
103
- writeFileAtomic(authPath, out.next, SECRET_FILE_MODE);
80
+ // Rename, not an in-place rewrite: it is what lets `read` stay unlocked, and it is the only spelling that applies
81
+ // the mode before the content is reachable.
82
+ if (out.next !== undefined) {
83
+ writeFileAtomic(writeTarget(authPath), out.next, SECRET_FILE_MODE);
84
+ }
104
85
  throwIfCompromised();
105
86
  result = out.result;
106
87
  }
@@ -114,10 +95,8 @@ async function withLockedAuthFile(authPath, fn) {
114
95
  }
115
96
  throw error;
116
97
  }
117
- // Success path: a failed release is a real cleanup failure (the leftover auth.json.lock stalls
118
- // the next writer for the staleness window with zero diagnostics), so it surfaces instead of
119
- // resolving a silently degraded operation. A compromise detected after the last in-band check
120
- // surfaces here too.
98
+ // Success path: a failed release is a real cleanup failure (the leftover auth.json.lock stalls the next writer for
99
+ // the staleness window with zero diagnostics), so it surfaces instead of resolving a silently degraded operation.
121
100
  try {
122
101
  await release();
123
102
  }
@@ -128,12 +107,7 @@ async function withLockedAuthFile(authPath, fn) {
128
107
  throwIfCompromised();
129
108
  return result;
130
109
  }
131
- /**
132
- * Decode the credentials JSON, shared by the read and write paths. The root must be a plain
133
- * non-null, non-array object: `[]`, `null`, and scalar roots pass JSON.parse but break the record
134
- * semantics (an array root even swallows writes, since JSON.stringify drops string keys on arrays).
135
- * Structurally invalid = corrupt, exactly like unparsable text.
136
- */
110
+ /** Decode the credentials JSON, shared by the read and write paths. */
137
111
  function decodeCreds(raw) {
138
112
  let parsed;
139
113
  try {
@@ -146,13 +120,7 @@ function decodeCreds(raw) {
146
120
  return undefined;
147
121
  return parsed;
148
122
  }
149
- /**
150
- * UNLOCKED read of the whole credentials file, shared by `read` and `list`. ONE read: the write
151
- * publishes by rename, so this observes one whole version or another and has nothing to absorb by
152
- * re-reading. A missing file reads as undefined silently (normal not-configured); anything that
153
- * does not decode is a real corruption — a hand-edit — and says so immediately, rather than after
154
- * retrying a race that cannot happen.
155
- */
123
+ /** UNLOCKED read of the whole credentials file, shared by `read` and `list`. */
156
124
  function readCreds(authPath, warn) {
157
125
  let raw;
158
126
  try {
@@ -171,9 +139,8 @@ function readCreds(authPath, warn) {
171
139
  return undefined;
172
140
  }
173
141
  /**
174
- * Parse the credentials JSON for a WRITE: a corrupt file must THROW, because serializing `{}` over
175
- * it would wipe every other provider's credentials. The throw aborts the locked write, leaving the
176
- * file intact.
142
+ * Parse the credentials JSON for a WRITE: a corrupt file must THROW, because serializing `{}` over it would wipe every
143
+ * other provider's credentials.
177
144
  */
178
145
  function parseForWrite(raw, where) {
179
146
  if (!raw)
@@ -184,32 +151,61 @@ function parseForWrite(raw, where) {
184
151
  }
185
152
  return creds;
186
153
  }
187
- /** A read-write `CredentialStore` backed by the given credentials file (default {@link GLOBAL_AUTH_PATH};
188
- * the directory opener passes the project-level `<root>/.secrets/auth.json`). */
154
+ /**
155
+ * A read-write `CredentialStore` over the given credentials file (default {@link GLOBAL_AUTH_PATH}; the directory
156
+ * opener passes the project-level `<root>/.secrets/auth.json`), optionally falling back to a second file.
157
+ *
158
+ * The fallback is PER PROVIDER, not per file: logging one provider into a project must not hide the others a person
159
+ * already has globally. And the layer a credential was READ from is the layer its refresh is written back to —
160
+ * anything else would conjure a second holder of the same OAuth grant, which is the failure this whole area exists
161
+ * to avoid. A provider present in neither layer is new, and new credentials belong to the primary.
162
+ */
189
163
  export function fastagentCredentialStore(authPath = GLOBAL_AUTH_PATH, options = {}) {
190
164
  const warn = options.warn ?? ((message) => log.warn(message));
165
+ const fallback = options.fallbackPath !== undefined && options.fallbackPath !== authPath ? options.fallbackPath : undefined;
166
+ /**
167
+ * The file that owns this provider: where it already is, else the primary.
168
+ *
169
+ * Known ceiling: this read is UNLOCKED, so a concurrent `fastagent login` writing the same provider into the
170
+ * primary between here and the lock below sends this refresh to the fallback instead — the one window in which the
171
+ * "one grant, one copy" rule can be lost. Re-checking under the lock means locking both files in a fixed order;
172
+ * worth it only if concurrent logins stop being a rounding error.
173
+ */
174
+ const owner = (providerId) => {
175
+ if (fallback === undefined)
176
+ return authPath;
177
+ const primary = readCreds(authPath, warn);
178
+ if (primary && pick(primary, providerId))
179
+ return authPath;
180
+ const secondary = readCreds(fallback, warn);
181
+ return secondary && pick(secondary, providerId) ? fallback : authPath;
182
+ };
191
183
  return {
192
184
  async read(providerId) {
193
- const creds = readCreds(authPath, warn);
194
- return creds ? pick(creds, providerId) : undefined;
185
+ for (const path of fallback === undefined ? [authPath] : [authPath, fallback]) {
186
+ const creds = readCreds(path, warn);
187
+ const found = creds && pick(creds, providerId);
188
+ if (found)
189
+ return found;
190
+ }
191
+ return undefined;
195
192
  },
196
193
  async list() {
197
- // Metadata only, never secrets (the pi-ai `list` contract). Foreign/old entries are filtered
198
- // with the same validation as `read`, so both surfaces agree on what "configured" means.
199
- const creds = readCreds(authPath, warn);
200
- if (!creds)
201
- return [];
202
- const infos = [];
203
- for (const [providerId, cred] of Object.entries(creds)) {
204
- if (cred && (cred.type === "oauth" || cred.type === "api_key")) {
205
- infos.push({ providerId, type: cred.type });
194
+ // Metadata only, never secrets (the pi-ai `list` contract). Reverse order, so the primary's entry for a
195
+ // provider present in both overwrites the fallback's — the same precedence `read` applies.
196
+ const infos = new Map();
197
+ for (const path of fallback === undefined ? [authPath] : [fallback, authPath]) {
198
+ for (const [providerId, cred] of Object.entries(readCreds(path, warn) ?? {})) {
199
+ if (cred && (cred.type === "oauth" || cred.type === "api_key"))
200
+ infos.set(providerId, { providerId, type: cred.type });
206
201
  }
207
202
  }
208
- return infos;
203
+ return [...infos.values()];
209
204
  },
210
205
  modify(providerId, fn) {
211
- return withLockedAuthFile(authPath, async (current) => {
212
- const creds = parseForWrite(current, authPath); // corrupt → throw → no clobber
206
+ const path = owner(providerId);
207
+ return withLockedAuthFile(path, async (current) => {
208
+ const creds = parseForWrite(current, path); // corrupt → throw → no clobber
213
209
  const next = await fn(pick(creds, providerId));
214
210
  if (next === undefined)
215
211
  return { result: pick(creds, providerId) }; // unchanged: no write
@@ -218,12 +214,13 @@ export function fastagentCredentialStore(authPath = GLOBAL_AUTH_PATH, options =
218
214
  });
219
215
  },
220
216
  async delete(providerId) {
221
- // No-op when nothing is stored: do NOT take the lock (which would create the file) on a
222
- // machine that never stored this provider.
223
- if (!existsSync(authPath))
217
+ const path = owner(providerId);
218
+ // No-op when nothing is stored: do NOT take the lock (which would create the file) on a machine that never
219
+ // stored this provider.
220
+ if (!existsSync(path))
224
221
  return;
225
- await withLockedAuthFile(authPath, async (current) => {
226
- const creds = parseForWrite(current, authPath);
222
+ await withLockedAuthFile(path, async (current) => {
223
+ const creds = parseForWrite(current, path);
227
224
  if (!(providerId in creds))
228
225
  return { result: undefined }; // absent: no write
229
226
  delete creds[providerId];
@@ -1,7 +1,3 @@
1
1
  import { type BuildSessionRuntimeOptions } from "./session-builder.ts";
2
- /**
3
- * Open the workspace's agent in pi's interactive TUI and run until the user exits. The agent is
4
- * fastagent's assembled agent (same model/tools/skills/prompt/auth as dev/start serve); pi's TUI
5
- * handles login, rendering, and same-workspace sessions natively.
6
- */
2
+ /** Open the workspace's agent in pi's interactive TUI and run until the user exits. */
7
3
  export declare function runPiChat(dir: string, options?: BuildSessionRuntimeOptions): Promise<void>;
@@ -1,19 +1,7 @@
1
- /**
2
- * Chat: open a workspace into pi's interactive TUI (`fastagent chat`). A pi-specific COMMAND, not an
3
- * engine-neutral channel: it drives pi's full session API (InteractiveMode) for fidelity, so it lives
4
- * under engines/pi/ and is not re-exported.
5
- *
6
- * The TUI is ONE consumer of the shared definition-aware builder (session-builder.ts) — the same
7
- * assembly, model surface, and fastagent auth that serving uses. Log in with `fastagent login` (or
8
- * pi's TUI `/login`, which writes through the same credential store into the workspace auth file).
9
- */
1
+ /** Chat: open a workspace into pi's interactive TUI (`fastagent chat`). */
10
2
  import { InteractiveMode } from "@earendil-works/pi-coding-agent";
11
3
  import { buildAgentSessionRuntime } from "./session-builder.js";
12
- /**
13
- * Open the workspace's agent in pi's interactive TUI and run until the user exits. The agent is
14
- * fastagent's assembled agent (same model/tools/skills/prompt/auth as dev/start serve); pi's TUI
15
- * handles login, rendering, and same-workspace sessions natively.
16
- */
4
+ /** Open the workspace's agent in pi's interactive TUI and run until the user exits. */
17
5
  export async function runPiChat(dir, options = {}) {
18
6
  const runtime = await buildAgentSessionRuntime(dir, options);
19
7
  await new InteractiveMode(runtime, {}).run();
@@ -2,47 +2,40 @@ import type { ThinkingLevel } from "@earendil-works/pi-agent-core";
2
2
  import type { FastagentTool } from "./tool.ts";
3
3
  import type { Models } from "@earendil-works/pi-ai";
4
4
  import type { AnyModel } from "./models.ts";
5
+ import type { HttpSurface } from "../../service.ts";
5
6
  export interface FastagentConfig {
6
- /** "provider/modelId". Precedence: CLI --model > FASTAGENT_MODEL > config. */
7
+ /** "provider/modelId". */
7
8
  model?: string;
8
- /** Reasoning effort for the model, pi's scale ("off" | "minimal" | "low" | "medium" | "high" |
9
- * "xhigh" | "max"). Unset = pi's default. Authors tune thinking in the pi TUI while vibing — this
10
- * is the serving-side counterpart (fidelity). Levels a model doesn't support are clamped by pi. */
9
+ /** Reasoning effort for the model, pi's scale ("off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max"). */
11
10
  thinkingLevel?: ThinkingLevel;
12
- /** Extra custom tools, appended after the pi coding tools — never replaces them. `FastagentTool`
13
- * = AgentTool plus the optional `deferred` marker (see defineTool). */
11
+ /** Extra custom tools, appended after the pi coding tools — never replaces them. */
14
12
  tools?: FastagentTool[];
15
- /** `host` is the bind address: unset (or `0.0.0.0`) binds all interfaces — what containers need;
16
- * `127.0.0.1` keeps the serve (including `/control/*`) off the LAN. Precedence: `--bind` > this. */
17
- http?: {
13
+ /** What the serve publishes on its port, and to which browsers (each key is documented on {@link HttpSurface}). */
14
+ http?: HttpSurface & {
15
+ /** Default port for `dev` / `start` (`DEFAULT_HTTP_PORT` when unset). */
18
16
  port?: number;
19
- host?: string;
20
17
  };
21
- /** Mount the built-in `wake` tool so the agent can schedule its OWN follow-up turns (self-scheduling).
22
- * Off by default — self-scheduling is an autonomy capability, opt in when you want it. Only takes
23
- * effect on the serving path (`dev`/`start`, where the scheduler poller honors a wake-up). */
24
- selfSchedule?: boolean;
25
18
  /**
26
- * Serve the session control plane over HTTP (`/control/*`: state/entries/events + dispatch —
27
- * steer/abort/compact + session properties and lifecycle) for remote consumers: a Web panel, a desktop app, `fastagent
28
- * attach`. Default off (it is a remote-control surface). When on, `dev`/`start` generate a
29
- * per-boot bearer token and write `<stateRoot>/control.json` for local discovery. The serve
30
- * binds all interfaces by default, so the routes are LAN-reachable with the token as the only
31
- * protection — bind loopback (`--bind 127.0.0.1`; not `http.host`, which travels into a deployed
32
- * image), firewall the port, or wrap it for real exposure (docs/design/session-control.md §14).
19
+ * Serve the session control plane over HTTP (`/control/*`: state/entries/events + dispatch — steer/abort/compact +
20
+ * session properties and lifecycle) for remote consumers.
33
21
  */
34
22
  sessionControl?: boolean;
35
- /** Deploy-time declarations for what the agent needs on the box, so real agents don't hand-write a
36
- * Dockerfile / hand-set variables. */
23
+ /**
24
+ * Deploy-time declarations for what the agent needs on the box, so real agents don't hand-write a Dockerfile /
25
+ * hand-set variables.
26
+ */
37
27
  deploy?: {
38
- /** Extra secret env-var NAMES the deployed agent needs beyond the model key + channel secrets — e.g.
39
- * a `GH_TOKEN` its tools use. `deploy` carries each from the LOCAL env to the host secret store and
40
- * lists them in the runbook; a missing value gates `--run` (like a channel secret). */
41
- secrets?: string[];
42
- /** Extra apt packages baked into the generated image (Debian default repos: git, ripgrep, jq…). For a
43
- * package needing a custom apt repo (e.g. gh) or a different base image, provide your own Dockerfile
44
- * — `deploy` keeps an existing one. */
28
+ /** Extra apt packages baked into the generated image (Debian default repos: git, ripgrep, jq…). */
45
29
  apt?: string[];
30
+ /** `deploy agentcore` only. */
31
+ agentcore?: {
32
+ /**
33
+ * How long an idle AgentCore session keeps its microVM, 60–1209600 seconds (default 180). Memory bills for the
34
+ * whole idle tail, and a session past it cold-starts — the workload picks the trade: a chat agent talked to in
35
+ * bursts wants a longer tail, a schedule-only agent a shorter one.
36
+ */
37
+ idleTimeoutSeconds?: number;
38
+ };
46
39
  };
47
40
  }
48
41
  /** Identity function for typing and IDE completion (vite/next-style). */
@@ -52,37 +45,46 @@ export interface LoadedConfig {
52
45
  /** Config file path; undefined when the loader was pointed at a directory holding none. */
53
46
  path?: string;
54
47
  }
55
- /** A valid bindable port. */
56
48
  export declare function isValidPort(n: number): boolean;
57
- /** Load `<dir>/fastagent.config.ts|.js|.mjs`. No file = defaults; a wrong-shape file throws. */
49
+ /** Load `<dir>/fastagent.config.ts`. */
58
50
  export declare function loadConfig(dir: string): Promise<LoadedConfig>;
59
- /** The provider prefix of a "provider/modelId" spec. A spec without "/" returns whole — downstream
60
- * lookups then miss visibly (an unknown-provider error / a login-required hint), never a mangled id
61
- * (`slice(0, indexOf("/"))` silently drops the last char when "/" is absent). */
51
+ /** The provider prefix of a "provider/modelId" spec. */
62
52
  export declare function providerOf(spec: string): string;
63
53
  /** Resolve "provider/modelId" → a pi Model from `models`, so auth resolves from the same collection. */
64
54
  export declare function resolveModel(models: Models, spec: string): AnyModel;
65
55
  /** All registered "provider/modelId" specs in `models`, sorted — the list behind `fastagent models`. */
66
56
  export declare function listModels(models: Models): string[];
67
- /**
68
- * Rewrite the `model` in a config file's SOURCE TEXT to `spec`, for the first-run picker's write-back.
69
- * Handles the scaffold's commented placeholder (`// model: "…"`) and an existing `model:` line; returns
70
- * null when neither is present (no config file, or a hand-shaped one) so the caller falls back to a
71
- * printed hint instead of guessing where to insert. Text-level (not AST) on purpose — it only ever
72
- * touches a line it recognizes, never reformats the author's file.
73
- */
57
+ /** Rewrite the `model` in a config file's SOURCE TEXT to `spec`, for the first-run picker's write-back. */
74
58
  export declare function rewriteConfigModel(src: string, spec: string): string | null;
75
- /** Model selection precedence: CLI flag > FASTAGENT_MODEL env > config default. */
76
- export declare function resolveModelSpec(flag: string | undefined, config: FastagentConfig, env?: NodeJS.ProcessEnv): string | undefined;
77
59
  /**
78
- * `start`'s sessions-dir override: `--sessions-dir` flag > `FASTAGENT_SESSIONS_DIR` env > undefined
79
- * (the opener then falls back to {@link defaultSessionsDir} under the {@link resolveStateRoot} root).
80
- * Resolved to absolute so the store and the startup report agree regardless of cwd.
60
+ * Model selection precedence: CLI flag > FASTAGENT_MODEL env > config default. An EMPTY `FASTAGENT_MODEL` is
61
+ * "unset", not "no model": `export FASTAGENT_MODEL=` in a shell or CI job, and an `environment:`/`env` entry that
62
+ * interpolates a missing variable, both arrive as `""` — and a set-but-empty value that shadowed `config.model`
63
+ * would refuse to start an agent whose config names a model.
81
64
  */
82
- export declare function resolveSessionsDirOverride(flag: string | undefined, env?: NodeJS.ProcessEnv): string | undefined;
65
+ export declare function resolveModelSpec(flag: string | undefined, config: FastagentConfig, env?: NodeJS.ProcessEnv): string | undefined;
83
66
  /** The default credentials file under a resolved secrets dir ({@link resolveSecretsDir}). */
84
67
  export declare function defaultAuthPath(secretsDir: string): string;
85
68
  /** The effective auth file for an agent: override if present, else `<secrets dir>/auth.json`. */
86
- export declare function resolveAuthPath(dir: string, flag: string | undefined, env?: NodeJS.ProcessEnv): string;
87
- /** The default sessions dir under a resolved state root ({@link resolveStateRoot}). */
88
- export declare function defaultSessionsDir(stateRoot: string): string;
69
+ export declare function resolveAuthPath(dir: string, flag?: string, env?: NodeJS.ProcessEnv): string;
70
+ /**
71
+ * Which credentials files an agent reads: `path` first, then, per provider, `fallback` — present only when nothing
72
+ * named the path ({@link resolveAuthFallback}). One value because it is one decision: the opener, the model list, the
73
+ * startup report and the first-run picker all read through it.
74
+ */
75
+ export interface AuthLayers {
76
+ path: string;
77
+ fallback?: string;
78
+ }
79
+ /** The {@link AuthLayers} an agent directory reads: `authPath` option > `FASTAGENT_AUTH_PATH` > its own file. */
80
+ export declare function resolveAuthLayers(agentDir: string, authPath?: string, env?: NodeJS.ProcessEnv): AuthLayers;
81
+ /**
82
+ * Where a credential the project does not have is read from instead: the user-global store, because a login is a
83
+ * PERSON on a machine and not a project — one `login -g` then serves every agent here. Undefined when an explicit
84
+ * path was named: "use this file" is an instruction, not a preference, so it gets no second layer.
85
+ *
86
+ * BOTH knobs {@link resolveAuthPath} reads count as that instruction, `FASTAGENT_SECRETS_DIR` included — it is what
87
+ * the Fly/Railway/AgentCore artifacts set, and a deployed container must read its mounted credentials and nothing
88
+ * else (the artifact is the truth).
89
+ */
90
+ export declare function resolveAuthFallback(flag?: string, env?: NodeJS.ProcessEnv): string | undefined;