@fastagent-sh/fastagent 0.29.0 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. package/README.md +9 -4
  2. package/dist/atomic-write.d.ts +4 -5
  3. package/dist/atomic-write.js +4 -5
  4. package/dist/authoring.d.ts +32 -15
  5. package/dist/authoring.js +147 -127
  6. package/dist/channels/agentcore-protocol.d.ts +8 -3
  7. package/dist/channels/agentcore-protocol.js +3 -1
  8. package/dist/channels/agentcore-service.d.ts +1 -0
  9. package/dist/channels/agentcore-service.js +14 -4
  10. package/dist/channels/agentcore.d.ts +9 -0
  11. package/dist/channels/agentcore.js +29 -4
  12. package/dist/channels/context.d.ts +2 -0
  13. package/dist/channels/context.js +5 -1
  14. package/dist/channels/feishu/feishu-api.d.ts +2 -1
  15. package/dist/channels/feishu/feishu.d.ts +0 -3
  16. package/dist/channels/feishu/feishu.js +10 -10
  17. package/dist/channels/feishu/register-app.js +3 -5
  18. package/dist/channels/feishu/scaffold/channel.ts +32 -34
  19. package/dist/channels/feishu/scaffold/feishu-send.ts +5 -5
  20. package/dist/channels/feishu/scaffold/feishu-threads.ts +3 -3
  21. package/dist/channels/feishu/setup-mode.d.ts +2 -12
  22. package/dist/channels/feishu/setup-mode.js +2 -22
  23. package/dist/channels/feishu/setup.d.ts +12 -0
  24. package/dist/channels/feishu/setup.js +197 -0
  25. package/dist/channels/kit/abortable.d.ts +8 -0
  26. package/dist/channels/kit/abortable.js +22 -0
  27. package/dist/channels/lark/lark.d.ts +0 -3
  28. package/dist/channels/lark/lark.js +0 -5
  29. package/dist/channels/lark/scaffold/channel.ts +33 -35
  30. package/dist/channels/lark/scaffold/lark-send.ts +5 -5
  31. package/dist/channels/lark/scaffold/lark-threads.ts +3 -3
  32. package/dist/channels/lark/setup.d.ts +9 -0
  33. package/dist/channels/lark/setup.js +57 -0
  34. package/dist/channels/setup.d.ts +112 -0
  35. package/dist/channels/setup.js +31 -0
  36. package/dist/channels/slack/history.js +1 -1
  37. package/dist/channels/slack/manifest.d.ts +17 -7
  38. package/dist/channels/slack/manifest.js +12 -16
  39. package/dist/channels/slack/scaffold/channel.ts +44 -30
  40. package/dist/channels/slack/scaffold/slack-send.ts +8 -8
  41. package/dist/channels/slack/scaffold/slack-threads.ts +4 -4
  42. package/dist/channels/slack/setup.d.ts +7 -0
  43. package/dist/channels/slack/setup.js +119 -0
  44. package/dist/channels/slack/slack-api.d.ts +2 -0
  45. package/dist/channels/slack/slack-api.js +4 -0
  46. package/dist/channels/slack/slack.d.ts +21 -2
  47. package/dist/channels/slack/slack.js +398 -338
  48. package/dist/channels/slack/socket.d.ts +57 -0
  49. package/dist/channels/slack/socket.js +305 -0
  50. package/dist/channels/telegram/polling.d.ts +27 -0
  51. package/dist/channels/telegram/polling.js +105 -0
  52. package/dist/channels/telegram/scaffold/channel.ts +52 -32
  53. package/dist/channels/telegram/scaffold/telegram-send.ts +9 -9
  54. package/dist/channels/telegram/setup.d.ts +2 -0
  55. package/dist/channels/telegram/setup.js +42 -0
  56. package/dist/channels/telegram/telegram-api.d.ts +27 -1
  57. package/dist/channels/telegram/telegram-api.js +7 -6
  58. package/dist/channels/telegram/telegram.d.ts +11 -3
  59. package/dist/channels/telegram/telegram.js +184 -157
  60. package/dist/channels/webhook-evidence.d.ts +11 -0
  61. package/dist/channels/webhook-evidence.js +71 -0
  62. package/dist/channels/webhooks.d.ts +37 -0
  63. package/dist/channels/webhooks.js +70 -0
  64. package/dist/child-env.d.ts +16 -0
  65. package/dist/child-env.js +30 -0
  66. package/dist/cli/box-login.js +4 -1
  67. package/dist/cli/channel-app.d.ts +3 -0
  68. package/dist/cli/channel-app.js +35 -0
  69. package/dist/cli/channel-setup.d.ts +38 -0
  70. package/dist/cli/channel-setup.js +195 -0
  71. package/dist/cli/commands/add.d.ts +6 -14
  72. package/dist/cli/commands/add.js +45 -303
  73. package/dist/cli/commands/auth.js +8 -2
  74. package/dist/cli/commands/build.d.ts +5 -0
  75. package/dist/cli/commands/build.js +16 -0
  76. package/dist/cli/commands/channels.d.ts +19 -0
  77. package/dist/cli/commands/channels.js +230 -0
  78. package/dist/cli/commands/content.d.ts +7 -3
  79. package/dist/cli/commands/content.js +16 -10
  80. package/dist/cli/commands/deploy/agentcore.js +55 -23
  81. package/dist/cli/commands/deploy/channel-apps.d.ts +17 -0
  82. package/dist/cli/commands/deploy/channel-apps.js +30 -0
  83. package/dist/cli/commands/deploy/docker.js +32 -65
  84. package/dist/cli/commands/deploy/fly.js +28 -12
  85. package/dist/cli/commands/deploy/railway.js +38 -13
  86. package/dist/cli/commands/deploy/secrets-step.d.ts +19 -0
  87. package/dist/cli/commands/deploy/secrets-step.js +66 -0
  88. package/dist/cli/commands/deploy/shared.d.ts +16 -5
  89. package/dist/cli/commands/deploy/shared.js +25 -8
  90. package/dist/cli/commands/deploy.js +53 -60
  91. package/dist/cli/commands/dev.d.ts +2 -0
  92. package/dist/cli/commands/dev.js +15 -3
  93. package/dist/cli/commands/env.js +1 -1
  94. package/dist/cli/commands/info.d.ts +2 -0
  95. package/dist/cli/commands/info.js +60 -25
  96. package/dist/cli/commands/init.js +3 -1
  97. package/dist/cli/commands/invoke.d.ts +2 -0
  98. package/dist/cli/commands/invoke.js +20 -7
  99. package/dist/cli/commands/login.d.ts +0 -7
  100. package/dist/cli/commands/login.js +22 -10
  101. package/dist/cli/commands/logout.js +1 -1
  102. package/dist/cli/commands/mcp.js +14 -6
  103. package/dist/cli/commands/models.js +3 -2
  104. package/dist/cli/commands/schedules.d.ts +4 -2
  105. package/dist/cli/commands/schedules.js +14 -10
  106. package/dist/cli/commands/secrets.d.ts +14 -0
  107. package/dist/cli/commands/secrets.js +213 -0
  108. package/dist/cli/commands/start.d.ts +14 -14
  109. package/dist/cli/commands/start.js +46 -60
  110. package/dist/cli/content-view.d.ts +4 -6
  111. package/dist/cli/content-view.js +5 -11
  112. package/dist/cli/first-run-channels.d.ts +3 -0
  113. package/dist/cli/first-run-channels.js +63 -0
  114. package/dist/cli/instance.d.ts +41 -0
  115. package/dist/cli/instance.js +155 -0
  116. package/dist/cli/invoke-stream.d.ts +5 -2
  117. package/dist/cli/invoke-stream.js +7 -2
  118. package/dist/cli/program.js +282 -110
  119. package/dist/cli/serve.d.ts +4 -5
  120. package/dist/cli/serve.js +4 -7
  121. package/dist/cli/shared.d.ts +11 -2
  122. package/dist/cli/shared.js +32 -19
  123. package/dist/cli/ticket.js +50 -6
  124. package/dist/content/declare.d.ts +31 -37
  125. package/dist/content/declare.js +59 -60
  126. package/dist/content/file.d.ts +23 -12
  127. package/dist/content/file.js +48 -35
  128. package/dist/content/git.d.ts +0 -10
  129. package/dist/content/git.js +5 -39
  130. package/dist/content/resolve.d.ts +18 -22
  131. package/dist/content/resolve.js +32 -66
  132. package/dist/content/source.d.ts +7 -8
  133. package/dist/content/source.js +10 -28
  134. package/dist/credentials-page.d.ts +26 -0
  135. package/dist/credentials-page.js +185 -0
  136. package/dist/declared-secrets.d.ts +10 -3
  137. package/dist/declared-secrets.js +8 -4
  138. package/dist/deploy/agentcore/destroy.d.ts +4 -1
  139. package/dist/deploy/agentcore/destroy.js +25 -1
  140. package/dist/deploy/agentcore/forwarder.js +1 -1
  141. package/dist/deploy/agentcore/plan.d.ts +7 -21
  142. package/dist/deploy/agentcore/plan.js +47 -49
  143. package/dist/deploy/agentcore/run.d.ts +18 -10
  144. package/dist/deploy/agentcore/run.js +93 -70
  145. package/dist/deploy/agentcore/runtime-secrets.d.ts +7 -0
  146. package/dist/deploy/agentcore/runtime-secrets.js +108 -0
  147. package/dist/deploy/agentcore/shell.js +12 -19
  148. package/dist/deploy/agentcore/sigv4.d.ts +7 -0
  149. package/dist/deploy/agentcore/sigv4.js +15 -0
  150. package/dist/deploy/agentcore/slr.d.ts +18 -0
  151. package/dist/deploy/agentcore/slr.js +27 -0
  152. package/dist/deploy/agentcore/store.d.ts +7 -0
  153. package/dist/deploy/agentcore/store.js +115 -0
  154. package/dist/deploy/api.d.ts +14 -14
  155. package/dist/deploy/api.js +26 -24
  156. package/dist/deploy/box-shell.d.ts +3 -1
  157. package/dist/deploy/build-context.d.ts +4 -4
  158. package/dist/deploy/build-context.js +11 -15
  159. package/dist/deploy/channel-ingress.d.ts +35 -9
  160. package/dist/deploy/channel-ingress.js +119 -22
  161. package/dist/deploy/container.d.ts +35 -10
  162. package/dist/deploy/container.js +79 -37
  163. package/dist/deploy/delivered-text.d.ts +13 -0
  164. package/dist/deploy/delivered-text.js +86 -0
  165. package/dist/deploy/docker/plan.d.ts +7 -8
  166. package/dist/deploy/docker/plan.js +31 -52
  167. package/dist/deploy/docker/run.d.ts +5 -43
  168. package/dist/deploy/docker/run.js +9 -84
  169. package/dist/deploy/file-store.d.ts +2 -0
  170. package/dist/deploy/file-store.js +17 -0
  171. package/dist/deploy/fly/plan.d.ts +3 -2
  172. package/dist/deploy/fly/plan.js +20 -9
  173. package/dist/deploy/fly/run.d.ts +18 -8
  174. package/dist/deploy/fly/run.js +24 -42
  175. package/dist/deploy/fly/store.d.ts +12 -0
  176. package/dist/deploy/fly/store.js +83 -0
  177. package/dist/deploy/hosts.d.ts +1 -2
  178. package/dist/deploy/hosts.js +1 -2
  179. package/dist/deploy/preflight.d.ts +18 -5
  180. package/dist/deploy/preflight.js +135 -63
  181. package/dist/deploy/railway/ignore.d.ts +8 -0
  182. package/dist/deploy/railway/ignore.js +57 -0
  183. package/dist/deploy/railway/plan.d.ts +1 -2
  184. package/dist/deploy/railway/plan.js +8 -6
  185. package/dist/deploy/railway/run.d.ts +21 -15
  186. package/dist/deploy/railway/run.js +32 -78
  187. package/dist/deploy/railway/store.d.ts +29 -0
  188. package/dist/deploy/railway/store.js +143 -0
  189. package/dist/deploy/runner.d.ts +5 -2
  190. package/dist/deploy/runner.js +4 -3
  191. package/dist/deploy/secret-store.d.ts +63 -0
  192. package/dist/deploy/secret-store.js +98 -0
  193. package/dist/deploy/secrets.d.ts +29 -46
  194. package/dist/deploy/secrets.js +49 -122
  195. package/dist/deploy/workspace.d.ts +6 -12
  196. package/dist/deploy/workspace.js +18 -94
  197. package/dist/dev-supervisor.js +6 -8
  198. package/dist/environment/declare.js +3 -2
  199. package/dist/environment/mise.d.ts +3 -1
  200. package/dist/environment/mise.js +4 -2
  201. package/dist/feishu.d.ts +1 -1
  202. package/dist/feishu.js +1 -1
  203. package/dist/harnesses/models/catalog.d.ts +1 -0
  204. package/dist/harnesses/models/catalog.js +1 -2
  205. package/dist/harnesses/models/environment.d.ts +7 -2
  206. package/dist/harnesses/models/environment.js +9 -5
  207. package/dist/harnesses/models/host.d.ts +0 -7
  208. package/dist/harnesses/models/host.js +10 -1
  209. package/dist/harnesses/models/login.d.ts +0 -8
  210. package/dist/harnesses/models/login.js +5 -4
  211. package/dist/harnesses/models/models.d.ts +7 -2
  212. package/dist/harnesses/models/models.js +28 -4
  213. package/dist/harnesses/pi-durable/agent.js +59 -38
  214. package/dist/harnesses/pi-durable/build.d.ts +12 -0
  215. package/dist/harnesses/pi-durable/build.js +270 -0
  216. package/dist/harnesses/pi-durable/built.d.ts +24 -0
  217. package/dist/harnesses/pi-durable/built.js +136 -0
  218. package/dist/harnesses/pi-durable/config.d.ts +81 -0
  219. package/dist/harnesses/pi-durable/config.js +266 -0
  220. package/dist/harnesses/pi-durable/define.d.ts +63 -13
  221. package/dist/harnesses/pi-durable/define.js +23 -2
  222. package/dist/harnesses/pi-durable/definition.d.ts +72 -0
  223. package/dist/harnesses/pi-durable/definition.js +143 -0
  224. package/dist/harnesses/pi-durable/events.d.ts +4 -3
  225. package/dist/harnesses/pi-durable/events.js +179 -136
  226. package/dist/harnesses/pi-durable/execution-env.d.ts +17 -0
  227. package/dist/harnesses/pi-durable/execution-env.js +11 -0
  228. package/dist/harnesses/pi-durable/mcp.js +1 -3
  229. package/dist/harnesses/pi-durable/open.d.ts +35 -37
  230. package/dist/harnesses/pi-durable/open.js +91 -153
  231. package/dist/harnesses/pi-durable/reads.d.ts +0 -1
  232. package/dist/harnesses/pi-durable/reads.js +1 -3
  233. package/dist/harnesses/pi-durable/registry.d.ts +4 -6
  234. package/dist/harnesses/pi-durable/registry.js +29 -26
  235. package/dist/harnesses/pi-durable/release.d.ts +2 -2
  236. package/dist/harnesses/pi-durable/release.js +10 -7
  237. package/dist/harnesses/pi-durable/serve.d.ts +91 -15
  238. package/dist/harnesses/pi-durable/serve.js +109 -47
  239. package/dist/harnesses/pi-durable/sessions.js +15 -12
  240. package/dist/harnesses/pi-durable/text-sources.d.ts +30 -0
  241. package/dist/harnesses/pi-durable/text-sources.js +55 -0
  242. package/dist/harnesses/pi-durable/text.d.ts +16 -4
  243. package/dist/harnesses/pi-durable/text.js +115 -59
  244. package/dist/harnesses/pi-durable/wake.js +8 -8
  245. package/dist/http/client.js +9 -3
  246. package/dist/http/contract.d.ts +3 -3
  247. package/dist/http/server.d.ts +1 -1
  248. package/dist/http/server.js +1 -1
  249. package/dist/index.d.ts +8 -5
  250. package/dist/index.js +4 -1
  251. package/dist/instance-name.d.ts +7 -0
  252. package/dist/instance-name.js +26 -0
  253. package/dist/lark.d.ts +1 -1
  254. package/dist/lark.js +1 -1
  255. package/dist/mcp/client.js +11 -2
  256. package/dist/mcp/config.d.ts +70 -18
  257. package/dist/mcp/config.js +136 -53
  258. package/dist/mcp/host.d.ts +5 -2
  259. package/dist/mcp/host.js +14 -6
  260. package/dist/mcp/sign-in.js +2 -2
  261. package/dist/mcp-api.d.ts +14 -0
  262. package/dist/paths.d.ts +22 -8
  263. package/dist/paths.js +44 -11
  264. package/dist/runtime-websocket.d.ts +14 -0
  265. package/dist/runtime-websocket.js +39 -0
  266. package/dist/scaffold/add-channel.d.ts +9 -16
  267. package/dist/scaffold/add-channel.js +13 -83
  268. package/dist/scaffold/templates/env.example +4 -5
  269. package/dist/scaffold/templates/fastagent.config.ts +20 -14
  270. package/dist/scaffold/templates/gitignore +9 -6
  271. package/dist/scaffold/templates.d.ts +6 -2
  272. package/dist/scaffold/templates.js +7 -2
  273. package/dist/scaffold/vendor-skill.js +4 -2
  274. package/dist/service.d.ts +44 -6
  275. package/dist/service.js +110 -10
  276. package/dist/serving-command.d.ts +10 -0
  277. package/dist/serving-command.js +1 -0
  278. package/dist/slack.d.ts +1 -1
  279. package/dist/slack.js +1 -1
  280. package/dist/strip-edges.d.ts +10 -0
  281. package/dist/strip-edges.js +22 -0
  282. package/dist/telegram.d.ts +1 -1
  283. package/dist/telegram.js +1 -1
  284. package/dist/tunnel.d.ts +0 -1
  285. package/dist/tunnel.js +2 -8
  286. package/dist/value-file.d.ts +11 -6
  287. package/dist/value-file.js +21 -9
  288. package/dist/version.d.ts +7 -1
  289. package/dist/version.js +9 -3
  290. package/package.json +6 -5
  291. package/dist/channels/lark/credentials-page.d.ts +0 -25
  292. package/dist/channels/lark/credentials-page.js +0 -206
  293. package/dist/channels/lark/onboard.d.ts +0 -52
  294. package/dist/channels/lark/onboard.js +0 -86
  295. package/dist/channels/slack/config-api.d.ts +0 -69
  296. package/dist/channels/slack/config-api.js +0 -162
  297. package/dist/channels/slack/onboard.d.ts +0 -40
  298. package/dist/channels/slack/onboard.js +0 -136
  299. package/dist/channels/slack/onboarding-state.d.ts +0 -31
  300. package/dist/channels/slack/onboarding-state.js +0 -64
  301. package/dist/channels/slack/register-webhook.d.ts +0 -12
  302. package/dist/channels/slack/register-webhook.js +0 -67
  303. package/dist/channels/slack/setup-server.d.ts +0 -32
  304. package/dist/channels/slack/setup-server.js +0 -246
  305. package/dist/cli/add-feishu.d.ts +0 -41
  306. package/dist/cli/add-feishu.js +0 -391
  307. package/dist/cli/add-slack.d.ts +0 -18
  308. package/dist/cli/add-slack.js +0 -216
  309. package/dist/harnesses/pi-durable/parked.d.ts +0 -18
  310. package/dist/harnesses/pi-durable/parked.js +0 -27
@@ -1,3 +1,11 @@
1
+ /**
2
+ * `fastagent login [provider]`: sign in to a model provider, into the project-level auth file
3
+ * (`<agentDir>/.secrets/auth.json`) by default, or `FASTAGENT_AUTH_PATH`. In a terminal it asks, as pi's `/login`
4
+ * does; otherwise (a script, a coding agent: no terminal, `--no-input` or `--json`) nothing is asked and nothing
5
+ * waits: what it needs is named, and a person's step is handed back with a ticket to check (ticket.ts).
6
+ * `--deployment` runs the same login on this agent's deployed box instead (box-login.ts); `--stdio` is the box's half.
7
+ */
8
+ import { definedValues } from "../../declared-secrets.js";
1
9
  import { enterAgentEnv } from "../../env.js";
2
10
  import { dotEnvPath } from "../../value-file.js";
3
11
  import { GLOBAL_AUTH_PATH, resolveAuthPath, } from "../../harnesses/models/credentials.js";
@@ -7,7 +15,8 @@ import { findAgentDir, globalHome, selectAgentEnvironment } from "../../paths.js
7
15
  import { SignInCancelled } from "../../sign-in-api.js";
8
16
  import { LoginRefused, PI_DEFAULT_MODELS, chooseLogin, loginFlow, loginOptionsOver, loginOver, loginStatusText, } from "../../harnesses/models/login.js";
9
17
  import { environmentAuth, keyVariables, loginProviders } from "../../harnesses/models/models.js";
10
- import { definitionProviders, loadConfig, modelSpecFor } from "../../harnesses/pi-durable/open.js";
18
+ import { resolveConfig } from "../../harnesses/pi-durable/config.js";
19
+ import { definitionProviders, loadDevProject, modelSpecFor } from "../../harnesses/pi-durable/open.js";
11
20
  import { loginOnBox, ticketLoginIO } from "../box-login.js";
12
21
  import { deploymentLoginCommand } from "../../deploy/box-shell.js";
13
22
  import { agentDirOrExit, failStartup, failUsage, optionalAgentDirOrExit } from "../fail.js";
@@ -49,7 +58,7 @@ export async function runLogin(provider, opts) {
49
58
  const ownAgent = opts.global ? undefined : agentDir;
50
59
  // The definition's providers too: a gateway's key is verified against the gateway, not a built-in's endpoint. Not for
51
60
  // `-g`: the global file serves every agent on this machine, so no one agent's providers decide what it holds.
52
- const providersOf = () => (ownAgent ? definitionProviders(ownAgent) : Promise.resolve([]));
61
+ const providersOf = () => (ownAgent ? definitionProviders(ownAgent, process.env) : Promise.resolve([]));
53
62
  if (opts.ticket !== undefined) {
54
63
  // The process `startTicket` started: it takes the ticket before loading the definition, then signs in.
55
64
  await runTicket(opts.ticket, async (step) => {
@@ -73,7 +82,8 @@ export async function runLogin(provider, opts) {
73
82
  }
74
83
  // What the agent reads, its file over the global one, is what authenticates each provider for it now.
75
84
  const statusFrom = ownAgent
76
- ? (await modelEnvironment(ownAgent, {}, providers)).credentials
85
+ ? (await modelEnvironment(ownAgent, {}, providers, { environment: definedValues(process.env) }))
86
+ .credentials
77
87
  : authPath;
78
88
  if (opts.input === false || opts.json === true || !isInteractive()) {
79
89
  const offered = await loginOptionsOver(statusFrom, providers);
@@ -122,7 +132,7 @@ export async function runLogin(provider, opts) {
122
132
  }
123
133
  process.exit(0); // the undici proxy agent's keep-alive sockets would otherwise hold the event loop open
124
134
  }
125
- const modelHint = (model, name) => `this agent has no model: \`model: "${model}"\` in fastagent.config.ts uses ${name}'s default`;
135
+ const modelHint = (model, name) => `this agent has no model: \`defaults: { model: "${model}" }\` in fastagent.config.ts uses ${name}'s default`;
126
136
  /** `--method`'s words, pi's: an account (OAuth) or an API key. */
127
137
  function methodOf(value) {
128
138
  if (value === "account")
@@ -143,7 +153,9 @@ function secondsOf(value) {
143
153
  * sign-in. Printed, never written: the model belongs in the author's own config.
144
154
  */
145
155
  async function defaultModelHint(agentDir, provider) {
146
- const config = await loadConfig(agentDir).catch(failStartup);
156
+ const config = await loadDevProject(agentDir)
157
+ .then(({ definition, instance }) => resolveConfig(definition, instance))
158
+ .catch(failStartup);
147
159
  if (modelSpecFor(config, undefined) !== undefined)
148
160
  return undefined;
149
161
  const modelId = PI_DEFAULT_MODELS[provider];
@@ -406,7 +418,7 @@ async function runDeploymentLogin(provider, opts) {
406
418
  * as a variable its deploy carries, so the person sets it in the production value file and the agent deploys again.
407
419
  */
408
420
  async function requestDeploymentLogin(agentDir, host, given, opts, timeoutSeconds) {
409
- const providers = await definitionProviders(agentDir).catch(failStartup);
421
+ const providers = await definitionProviders(agentDir, process.env).catch(failStartup);
410
422
  const offered = await loginOptionsOver(resolveAuthPath(agentDir), providers);
411
423
  let choice;
412
424
  try {
@@ -487,13 +499,13 @@ async function stdioLogin(io, provider, opts) {
487
499
  throw new Error(`login --stdio: ${process.cwd()} is not an agent directory`);
488
500
  // A deployed box has no value file to read: its variables reach this process only as the host's shell hands them
489
501
  // down (the container's for `docker compose exec`, the platform's over fly/railway ssh), and this installs the egress
490
- // proxy they name. AgentCore's command shell hands down none of the runtime's, so a proxy carried there in
491
- // FASTAGENT_ENV does not reach the login (docs/deploy.md).
502
+ // proxy they name. AgentCore's command shell hands down none of the runtime's, so a proxy the runtime has
503
+ // in its values does not reach the login (docs/deploy.md).
492
504
  enterAgentEnv(agentDir);
493
505
  // The model environment the serving Agent reads (openServing), its definition's providers included, so "logged in"
494
506
  // means what the server will use, and a provider only the definition declares can be signed in to.
495
- const providers = await definitionProviders(agentDir);
496
- const models = await modelEnvironment(agentDir, {}, providers);
507
+ const providers = await definitionProviders(agentDir, process.env);
508
+ const models = await modelEnvironment(agentDir, {}, providers, { environment: definedValues(process.env) });
497
509
  const auth = models.auth;
498
510
  if (opts.ifMissing && provider) {
499
511
  // The server's own answer (`authStatus`), the one its startup report prints. Known ceiling: nothing is asked of
@@ -15,7 +15,7 @@ export async function runLogout(provider, opts) {
15
15
  enterAgentEnv(agentDir ?? globalHome());
16
16
  const authPath = opts.global ? GLOBAL_AUTH_PATH : resolveAuthPath(agentDir ?? globalHome());
17
17
  const store = fastagentCredentialStore(authPath);
18
- const known = loginProviders(agentDir ? await definitionProviders(agentDir).catch(failStartup) : []);
18
+ const known = loginProviders(agentDir ? await definitionProviders(agentDir, process.env).catch(failStartup) : []);
19
19
  const stored = (await store.list())
20
20
  .map(({ providerId, type }) => ({
21
21
  id: providerId,
@@ -3,7 +3,8 @@ import { confirm, isCancel } from "@clack/prompts";
3
3
  import { inspectMcp, mcpContext, writeMcpBinding, httpServer } from "../../mcp/host.js";
4
4
  import { signInMcp } from "../../mcp/sign-in.js";
5
5
  import { holdingInstance } from "../../harnesses/pi-durable/serve.js";
6
- import { resolveMcpServers } from "../../mcp/config.js";
6
+ import { declareMcp, mcpInstance, resolveMcpServers } from "../../mcp/config.js";
7
+ import { devInstanceConfig, namedInstanceConfig } from "../../harnesses/pi-durable/config.js";
7
8
  import { McpError } from "../../mcp-api.js";
8
9
  import { selectAgentEnvironment } from "../../paths.js";
9
10
  import { enterAgentEnv } from "../../env.js";
@@ -37,8 +38,12 @@ export async function runMcp(action, server, dir, options) {
37
38
  return failUsage("--env must be dev or production");
38
39
  selectAgentEnvironment(environment);
39
40
  enterAgentEnv(target);
41
+ // The servers the instance of this environment opens: the program's, and what its configuration adds. `dev` reads the
42
+ // one `--config` names or else the project's; `start` never reads the project's.
43
+ const instance = await (environment === "production" ? namedInstanceConfig() : devInstanceConfig(target)).catch(failStartup);
44
+ const config = instance?.label;
40
45
  if (action === "list") {
41
- const servers = await inspectMcp(target).catch(failStartup);
46
+ const servers = await inspectMcp(target, config === undefined ? {} : { config }).catch(failStartup);
42
47
  if (options.json)
43
48
  console.log(JSON.stringify(servers));
44
49
  else
@@ -47,7 +52,7 @@ export async function runMcp(action, server, dir, options) {
47
52
  return;
48
53
  }
49
54
  if (!server)
50
- return failUsage(`mcp ${action} needs a server name from .mcp.json`);
55
+ return failUsage(`mcp ${action} needs a server name from the program's context.json or the instance's fastagent.json`);
51
56
  const context = mcpContext(target);
52
57
  if (action === "disconnect") {
53
58
  await holdingInstance(context.stateRoot, () => writeMcpBinding(context.stateRoot, server, undefined)).catch(failStartup);
@@ -55,11 +60,13 @@ export async function runMcp(action, server, dir, options) {
55
60
  status: "done",
56
61
  server,
57
62
  grant_revoked: false,
58
- agent_next_steps: "The instance binding was removed. The stored grant was not revoked; reauthorize or update .mcp.json before reopening.",
59
- }, ["Binding removed; the stored grant was not revoked. Reauthorize or update .mcp.json before reopening."]);
63
+ agent_next_steps: "The instance binding was removed. The stored grant was not revoked; reauthorize or update the server's declaration before reopening.",
64
+ }, [
65
+ "Binding removed; the stored grant was not revoked. Reauthorize or update the server's declaration before reopening.",
66
+ ]);
60
67
  return;
61
68
  }
62
- httpServer(resolveMcpServers(target, context.environment, server), server);
69
+ httpServer(resolveMcpServers(declareMcp(target, mcpInstance(config)), context.environment, server, target, {}), server);
63
70
  const seconds = options.timeout === undefined ? 900 : Number(options.timeout);
64
71
  if (!Number.isInteger(seconds) || seconds <= 0)
65
72
  return failUsage("--timeout must be a positive whole number of seconds");
@@ -73,6 +80,7 @@ export async function runMcp(action, server, dir, options) {
73
80
  const run = async (step) => {
74
81
  const grant = await signInMcp({
75
82
  agentDir: target,
83
+ ...(config === undefined ? {} : { config }),
76
84
  server,
77
85
  store: context.auth.store,
78
86
  scopes,
@@ -3,6 +3,7 @@
3
3
  * published catalogs, and the providers its definition declares), or, outside an agent, the built-ins; `[search]`
4
4
  * filters by substring. `--refresh` asks the network for the lists even when the kept ones are fresh.
5
5
  */
6
+ import { definedValues } from "../../declared-secrets.js";
6
7
  import { InMemoryCredentialStore } from "@earendil-works/pi-ai";
7
8
  import { modelEnvironment } from "../../harnesses/models/environment.js";
8
9
  import { listModels, providerOf } from "../../harnesses/models/models.js";
@@ -18,13 +19,13 @@ export async function runModels(search, opts = {}) {
18
19
  let providers = [];
19
20
  if (agentDir) {
20
21
  enterAgentEnv(agentDir); // a provider in code may read its secrets when it is built
21
- providers = await definitionProviders(agentDir).catch(failStartup);
22
+ providers = await definitionProviders(agentDir, process.env).catch(failStartup);
22
23
  }
23
24
  else {
24
25
  installProxyFetch();
25
26
  }
26
27
  // Outside an agent, no credentials file is read: the built-ins' lists need none.
27
- const environment = await modelEnvironment(agentDir, agentDir ? {} : { credentialStore: new InMemoryCredentialStore() }, providers, { force: opts.refresh === true });
28
+ const environment = await modelEnvironment(agentDir, agentDir ? {} : { credentialStore: new InMemoryCredentialStore() }, providers, { force: opts.refresh === true, environment: definedValues(process.env) });
28
29
  const { lines, error } = formatModelsCommand(listModels(environment.models), search);
29
30
  if (opts.json) {
30
31
  const models = lines.map((spec) => {
@@ -1,9 +1,10 @@
1
+ import { type InstanceFlags } from "../instance.ts";
1
2
  /**
2
3
  * Text mode answers "when does each run next, and did the last run work?" from the newest claim alone, so an old file
3
4
  * in the retained window cannot fail it; `--json` adds each schedule's whole retained fire history (the claims under
4
5
  * `schedule/claims/<name>/`). What a run SAID is in its session, once it has fired.
5
6
  */
6
- export declare function runSchedulesList(dirArg: string, json: boolean): Promise<void>;
7
+ export declare function runSchedulesList(dirArg: string, json: boolean, instance?: InstanceFlags): Promise<void>;
7
8
  /**
8
9
  * Fire the schedule `name` now, as its clock would: in its session, with its claim and its outcome recorded. It opens
9
10
  * the instance's storage, so a serve of it refuses this, and the other way round. The answer goes to stdout; exit 0
@@ -12,10 +13,11 @@ export declare function runSchedulesList(dirArg: string, json: boolean): Promise
12
13
  export declare function runScheduleNow(name: string, dirArg: string, opts: {
13
14
  model?: string;
14
15
  input?: boolean;
16
+ instance?: InstanceFlags;
15
17
  }): Promise<void>;
16
18
  /**
17
19
  * Cancel the pending wake-up `id`, whatever session set it: the one way out of a wake-up set where nobody can message
18
20
  * the agent (a schedule's own session). It holds the instance's storage while it writes, so it is refused while a serve
19
21
  * of the instance runs, whose poll writes the same store.
20
22
  */
21
- export declare function runUnwake(id: string, dirArg: string): Promise<void>;
23
+ export declare function runUnwake(id: string, dirArg: string, instance?: InstanceFlags): Promise<void>;
@@ -8,8 +8,7 @@
8
8
  import { resolve } from "node:path";
9
9
  import * as Effect from "effect/Effect";
10
10
  import { AgentError, hasEnded } from "../../agent-api.js";
11
- import { enterAgentEnv } from "../../env.js";
12
- import { buildDefinitionShape, prepareDefinition } from "../../harnesses/pi-durable/open.js";
11
+ import { buildDefinitionShape, loadDevProject, loadSourceDefinition } from "../../harnesses/pi-durable/open.js";
13
12
  import { holdingInstance, openServing } from "../../harnesses/pi-durable/serve.js";
14
13
  import { resolveStateRoot } from "../../paths.js";
15
14
  import { nextRun } from "../../schedule/cron.js";
@@ -18,18 +17,19 @@ import { latestFire, readFires } from "../../schedule/state.js";
18
17
  import { listWakeups, removeAnyWakeup } from "../../schedule/wakeups.js";
19
18
  import { agentDirOrExit, failStartup, failUsage } from "../fail.js";
20
19
  import { exitCodeOf } from "../invoke-stream.js";
20
+ import { enterInstance, instanceInputs } from "../instance.js";
21
21
  import { enterAgentCommand, reportAuth } from "../shared.js";
22
22
  /**
23
23
  * Text mode answers "when does each run next, and did the last run work?" from the newest claim alone, so an old file
24
24
  * in the retained window cannot fail it; `--json` adds each schedule's whole retained fire history (the claims under
25
25
  * `schedule/claims/<name>/`). What a run SAID is in its session, once it has fired.
26
26
  */
27
- export async function runSchedulesList(dirArg, json) {
27
+ export async function runSchedulesList(dirArg, json, instance) {
28
28
  const target = agentDirOrExit(resolve(dirArg));
29
- enterAgentEnv(target); // FASTAGENT_STATE_DIR may live in .env — read the SAME state root the scheduler wrote
29
+ enterInstance(target, instance); // FASTAGENT_STATE_DIR may live in .env — read the SAME state root the scheduler wrote
30
30
  const stateRoot = resolveStateRoot(target);
31
31
  // Its shape only: listing what will fire needs none of the values the code reads.
32
- const { schedules } = await prepareDefinition(target)
32
+ const { schedules } = await loadSourceDefinition(target)
33
33
  .then((definition) => buildDefinitionShape(definition, process.env))
34
34
  .catch(failStartup);
35
35
  const sessions = scheduleSessions(stateRoot);
@@ -83,7 +83,7 @@ export async function runScheduleNow(name, dirArg, opts) {
83
83
  // The name before the model, from the definition's shape: a script told its schedule does not exist need not set up
84
84
  // a model first.
85
85
  const { agentDir, modelSpec } = await enterAgentCommand(dirArg, opts, async (target) => {
86
- const declared = await prepareDefinition(target)
86
+ const declared = await loadSourceDefinition(target)
87
87
  .then((definition) => buildDefinitionShape(definition, process.env).schedules.map((s) => s.name))
88
88
  .catch(failStartup);
89
89
  if (!declared.includes(name)) {
@@ -91,10 +91,14 @@ export async function runScheduleNow(name, dirArg, opts) {
91
91
  }
92
92
  });
93
93
  // Refused while the instance holds work a stopped serve left: this process would run it, and cut it off at its exit.
94
- const { agent, models, schedules, stateRoot } = await openServing(agentDir, {
94
+ const { agent, models, schedules, stateRoot } = await loadDevProject(agentDir)
95
+ .then(({ definition, instance }) => openServing(definition, {
95
96
  model: modelSpec,
97
+ ...instanceInputs(agentDir),
96
98
  unfinished: "refuse",
97
- }).catch(failStartup);
99
+ ...(instance === undefined ? {} : { config: instance }),
100
+ }))
101
+ .catch(failStartup);
98
102
  const schedule = schedules.find((s) => s.name === name);
99
103
  if (schedule === undefined) {
100
104
  // Checked above: only an edit of src/schedules/ while this ran gets here.
@@ -131,9 +135,9 @@ export async function runScheduleNow(name, dirArg, opts) {
131
135
  * the agent (a schedule's own session). It holds the instance's storage while it writes, so it is refused while a serve
132
136
  * of the instance runs, whose poll writes the same store.
133
137
  */
134
- export async function runUnwake(id, dirArg) {
138
+ export async function runUnwake(id, dirArg, instance) {
135
139
  const target = agentDirOrExit(resolve(dirArg));
136
- enterAgentEnv(target);
140
+ enterInstance(target, instance);
137
141
  const stateRoot = resolveStateRoot(target);
138
142
  const removed = await holdingInstance(stateRoot, () => removeAnyWakeup(stateRoot, id)).catch(failStartup);
139
143
  if (removed === undefined) {
@@ -0,0 +1,14 @@
1
+ /** The targets that keep a deployment's values in a store of their own. */
2
+ export type SecretsHost = "docker" | "fly" | "railway" | "agentcore";
3
+ export interface SecretsOptions {
4
+ /** `--config <file>`: the instance configuration the deployment delivers; its channels decide which names it reads. */
5
+ config?: string;
6
+ /** `--env-file <file>` (push): where the values come from. */
7
+ envFile?: string;
8
+ /** `--from-env` (push): the environment this command runs in. */
9
+ fromEnv?: boolean;
10
+ /** `--generate` (set): a random value, printed once. */
11
+ generate?: boolean;
12
+ json?: boolean;
13
+ }
14
+ export declare function runSecrets(action: "list" | "set" | "push", host: SecretsHost, name: string | undefined, dirArg: string, opts: SecretsOptions): Promise<void>;
@@ -0,0 +1,213 @@
1
+ /**
2
+ * `fastagent secrets list|set|push <host>`: a deployment's values on the target that keeps them (agent-artifact.md
3
+ * §6.2). `deploy` checks names and never carries a file; these are how the values get there. A value is never an
4
+ * argument: it is typed without echo, read from standard input, taken from a value file, or from the environment of a
5
+ * command that injected it (`op run -- fastagent secrets push fly --from-env`).
6
+ */
7
+ import { randomBytes } from "node:crypto";
8
+ import { basename, resolve } from "node:path";
9
+ import { isCancel, password } from "@clack/prompts";
10
+ import { isEnvName } from "../../declared-secrets.js";
11
+ import { agentcoreName, agentcoreSecretName } from "../../deploy/agentcore/plan.js";
12
+ import { agentcoreSecretStore } from "../../deploy/agentcore/store.js";
13
+ import { deploymentApi } from "../../deploy/api.js";
14
+ import { fileStore } from "../../deploy/file-store.js";
15
+ import { toFlyAppName, parseFlyAppName } from "../../deploy/fly/plan.js";
16
+ import { flyStore } from "../../deploy/fly/store.js";
17
+ import { toRailwayName } from "../../deploy/railway/plan.js";
18
+ import { railwayStore } from "../../deploy/railway/store.js";
19
+ import { preflightDeploy } from "../../deploy/preflight.js";
20
+ import { awsRunner, spawnRunner } from "../../deploy/runner.js";
21
+ import { declaredNames, hostSignedOutGate, secretNeeds } from "../../deploy/secrets.js";
22
+ import { readInstanceConfigFile, resolveConfig } from "../../harnesses/pi-durable/config.js";
23
+ import { loadSourceDefinition } from "../../harnesses/pi-durable/open.js";
24
+ import { API_KEY_VARIABLE } from "../../http/server.js";
25
+ import { readTextIfExists, selectAgentEnvironment } from "../../paths.js";
26
+ import { unmarkDevServe } from "../../serving-command.js";
27
+ import { dotEnvPath, loadEnvValues } from "../../value-file.js";
28
+ import { agentDirOrExit, failStartup, failUsage } from "../fail.js";
29
+ import { printReport } from "../ticket.js";
30
+ import { join } from "node:path";
31
+ const LABELS = {
32
+ docker: "Docker",
33
+ fly: "Fly",
34
+ railway: "Railway",
35
+ agentcore: "AWS Secrets Manager",
36
+ };
37
+ /** The store of `host` for the agent in `agentDir`, its CLI signed in. */
38
+ async function openStore(host, agentDir) {
39
+ const log = (message) => console.error(`[fastagent] ${message}`);
40
+ if (host === "docker")
41
+ return fileStore(agentDir, dotEnvPath(agentDir));
42
+ if (host === "agentcore")
43
+ return agentcoreSecretStore(awsRunner(agentDir), agentcoreSecretName(agentcoreName(basename(agentDir))), log);
44
+ if (host === "fly") {
45
+ const fly = spawnRunner("fly", agentDir, { stdoutToStderr: true });
46
+ if ((await fly(["version"], { capture: true })).code === 127) {
47
+ failStartup(new Error("flyctl not found — install it: https://fly.io/docs/flyctl/install, then re-run"));
48
+ }
49
+ if ((await fly(["auth", "whoami"], { capture: true })).code !== 0) {
50
+ failStartup(new Error(hostSignedOutGate("Fly", "fly auth login", "FLY_API_TOKEN", "fly auth login")));
51
+ }
52
+ const toml = await readTextIfExists(join(agentDir, "fly.toml"));
53
+ const app = (toml && parseFlyAppName(toml)) ?? toFlyAppName(basename(agentDir));
54
+ return flyStore(fly, app, log, { stage: false });
55
+ }
56
+ const railway = spawnRunner("railway", agentDir, { stdoutToStderr: true });
57
+ if ((await railway(["--version"], { capture: true })).code === 127) {
58
+ failStartup(new Error("railway CLI not found — install it: https://docs.railway.com/guides/cli, then re-run"));
59
+ }
60
+ if ((await railway(["whoami"], { capture: true })).code !== 0) {
61
+ failStartup(new Error(hostSignedOutGate("Railway", "railway login", "RAILWAY_API_TOKEN (an account token)", "railway login")));
62
+ }
63
+ return railwayStore(railway, toRailwayName(basename(agentDir)), log, { redeploy: true });
64
+ }
65
+ /** What the definition declares for the deployment, and the production value file it reads. */
66
+ async function declared(agentDir, configFile, host) {
67
+ const instance = configFile === undefined ? undefined : await readInstanceConfigFile(resolve(configFile));
68
+ const definition = await loadSourceDefinition(agentDir);
69
+ const config = resolveConfig(definition, instance);
70
+ const api = deploymentApi({ config, hostServes: host !== "agentcore" });
71
+ const facts = await preflightDeploy({
72
+ agentDir,
73
+ config,
74
+ ...(instance === undefined
75
+ ? {}
76
+ : { delivered: { source: instance, text: `${JSON.stringify(instance.values, null, 2)}\n` } }),
77
+ run: false,
78
+ force: false,
79
+ noResidentProcess: false,
80
+ storageResets: false,
81
+ servesApi: api.served,
82
+ });
83
+ if (!facts.ok)
84
+ throw new Error(facts.gate);
85
+ return {
86
+ needs: secretNeeds(facts.modelAuth, facts.declaredSecrets, facts.modelKey),
87
+ names: declaredNames(facts.modelAuth, facts.declaredSecrets, facts.modelKey),
88
+ modelKeys: facts.modelKey.variables,
89
+ // The key of the Agent API: on the hosts that serve it.
90
+ apiNames: api.served ? [API_KEY_VARIABLE] : [],
91
+ };
92
+ }
93
+ async function readStdin() {
94
+ const chunks = [];
95
+ for await (const chunk of process.stdin)
96
+ chunks.push(Buffer.from(chunk));
97
+ return Buffer.concat(chunks).toString("utf8");
98
+ }
99
+ /** The value for `name`: random with `--generate`, else typed without echo at a terminal, else the whole standard input. */
100
+ async function valueFor(name, generate) {
101
+ if (generate)
102
+ return { value: randomBytes(32).toString("base64url"), minted: true };
103
+ if (process.stdin.isTTY) {
104
+ const typed = await password({ message: name });
105
+ if (isCancel(typed))
106
+ throw new Error("cancelled");
107
+ return { value: String(typed), minted: false };
108
+ }
109
+ return { value: (await readStdin()).replace(/\r?\n$/, ""), minted: false };
110
+ }
111
+ export async function runSecrets(action, host, name, dirArg, opts) {
112
+ if (action === "set" && !isEnvName(name))
113
+ failUsage(`${name} is not an environment variable name`);
114
+ if (action === "push" && opts.fromEnv && opts.envFile !== undefined) {
115
+ failUsage("--env-file and --from-env are two sources: pass one");
116
+ }
117
+ const agentDir = agentDirOrExit(resolve(dirArg));
118
+ // The deployment's own, never the development instance's: its channels receive the way the box will choose.
119
+ selectAgentEnvironment("production");
120
+ unmarkDevServe();
121
+ try {
122
+ const store = await openStore(host, agentDir);
123
+ if (action === "list")
124
+ return await list(store, host, agentDir, opts);
125
+ if (action === "set")
126
+ return await set(store, host, name, opts, agentDir);
127
+ return await push(store, host, agentDir, opts);
128
+ }
129
+ catch (error) {
130
+ failStartup(error);
131
+ }
132
+ }
133
+ /** When a written value reaches what is running: a Docker container reads its file at start, an AgentCore session its secret. */
134
+ function noteWhenItTakesEffect(host) {
135
+ if (host === "docker") {
136
+ console.error("[fastagent] note: a running container reads it after `docker compose up -d`, or the next `deploy docker --run`");
137
+ }
138
+ if (host === "agentcore") {
139
+ console.error("[fastagent] note: the runtime reads the secret when a session starts: a session already running keeps its values " +
140
+ "until it ends (its idle timeout) or the next deploy");
141
+ }
142
+ }
143
+ async function list(store, host, agentDir, opts) {
144
+ const label = LABELS[host];
145
+ const { needs, names, modelKeys } = await declared(agentDir, opts.config, host);
146
+ // A target with no app yet holds nothing: every name is missing, which is an answer and not a failure.
147
+ const present = await store.exists();
148
+ if (!present)
149
+ console.error(`[fastagent] ${label} has no app for this agent yet: the first set, push or \`deploy --run\` makes it`);
150
+ const have = present ? await store.names() : new Set();
151
+ const required = new Set(needs.map((need) => need.name));
152
+ const rows = names.map((name) => ({
153
+ name,
154
+ set: have.has(name),
155
+ required: required.has(name),
156
+ hint: needs.find((need) => need.name === name)?.hint ??
157
+ (modelKeys.includes(name) ? "your model provider key, or a login on the box" : undefined),
158
+ }));
159
+ printReport(opts.json, { host: label, exists: present, secrets: rows }, rows.map(({ name, set, required: must, hint }) => `${set ? "set " : "missing"} ${name} (${must ? (hint ?? "required") : `optional${hint === undefined ? "" : `: ${hint}`}`})`));
160
+ }
161
+ async function set(store, host, name, opts, agentDir) {
162
+ const label = LABELS[host];
163
+ const { names, apiNames } = await declared(agentDir, opts.config, host);
164
+ if (!names.includes(name) && !apiNames.includes(name)) {
165
+ console.error(`[fastagent] warn: ${name} is not declared by the definition, so nothing reads it on ${label}`);
166
+ }
167
+ const { value, minted } = await valueFor(name, opts.generate);
168
+ if (value.trim() === "")
169
+ throw new Error(`${name} would be empty`);
170
+ await store.ensure();
171
+ await store.write({ [name]: value });
172
+ console.error(`[fastagent] set ${name} on ${label}`);
173
+ noteWhenItTakesEffect(host);
174
+ // The one time a value is shown: it was made here and nobody holds it yet.
175
+ if (minted)
176
+ console.log(value);
177
+ }
178
+ async function push(store, host, agentDir, opts) {
179
+ const label = LABELS[host];
180
+ const { names, apiNames } = await declared(agentDir, opts.config, host);
181
+ const known = new Set([...names, ...apiNames]);
182
+ let source;
183
+ let where;
184
+ if (opts.fromEnv) {
185
+ source = new Map(Object.entries(process.env).flatMap(([n, v]) => (v === undefined ? [] : [[n, v]])));
186
+ where = "the environment";
187
+ }
188
+ else {
189
+ if (host === "docker" && opts.envFile === undefined) {
190
+ throw new Error(`${dotEnvPath(agentDir)} is Docker's own store, so there is nothing to push from it: pass --env-file <file> or --from-env`);
191
+ }
192
+ const file = opts.envFile === undefined ? dotEnvPath(agentDir) : resolve(opts.envFile);
193
+ source = loadEnvValues(file);
194
+ where = file;
195
+ if (source.size === 0 && opts.envFile === undefined) {
196
+ throw new Error(`${file} holds no values: pass --env-file <file>, or --from-env for the environment`);
197
+ }
198
+ }
199
+ const toWrite = {};
200
+ for (const [n, v] of source)
201
+ if (known.has(n) && v.trim() !== "")
202
+ toWrite[n] = v;
203
+ const skipped = opts.fromEnv ? [] : [...source.keys()].filter((n) => !known.has(n));
204
+ if (skipped.length > 0) {
205
+ console.error(`[fastagent] not pushed, since the definition does not declare them: ${skipped.join(", ")}`);
206
+ }
207
+ if (Object.keys(toWrite).length === 0)
208
+ throw new Error(`${where} holds a value for none of the names the definition declares`);
209
+ await store.ensure();
210
+ await store.write(toWrite);
211
+ console.error(`[fastagent] pushed ${Object.keys(toWrite).length} value(s) from ${where} to ${label}: ${Object.keys(toWrite).join(", ")}`);
212
+ noteWhenItTakesEffect(host);
213
+ }
@@ -1,5 +1,6 @@
1
1
  import type { Agent } from "../../agent-api.ts";
2
- import type { AgentConfig } from "../../harnesses/pi-durable/define.ts";
2
+ import type { EffectiveConfig } from "../../harnesses/pi-durable/config.ts";
3
+ import { type InstanceFlags } from "../instance.ts";
3
4
  import { type ServedAgent } from "../../service.ts";
4
5
  export interface StartOptions {
5
6
  port?: string;
@@ -7,29 +8,28 @@ export interface StartOptions {
7
8
  model?: string;
8
9
  tunnel?: boolean;
9
10
  input?: boolean;
11
+ instance?: InstanceFlags;
10
12
  }
11
13
  /** What `start` opened and serves: the agent too, for a deployment's own check of what it runs. */
12
14
  type StartedService = ServedAgent & {
13
15
  agent: Agent;
14
16
  stateRoot: string;
15
17
  port: number;
16
- config: AgentConfig;
18
+ config: EffectiveConfig;
17
19
  };
18
20
  export declare function runStart(dirArg: string, opts: StartOptions): Promise<void>;
19
- /** What the storage stage hands the opening stage. */
20
- export interface PreparedWorkspace {
21
- /** The agent directory to open — the storage's deployed definition when a release manifest selected one. */
22
- dir: string;
23
- /** The storage root, set when this process took a deployment's storage. */
24
- deployed?: {
25
- root: string;
26
- };
27
- }
28
21
  /**
29
- * Stage one — TAKE the storage: verify it is mounted, apply the release, and point the machinery at the volume.
22
+ * Stage one — TAKE the storage, on a deployed box (a release manifest names it): it is mounted, held by this process,
23
+ * and this agent's; it becomes the instance's root, and the machinery points at it. The program stays where the image
24
+ * built it, `dirArg`. Returns that directory. Elsewhere, nothing is taken.
25
+ */
26
+ export declare function prepareStartWorkspace(dirArg: string): Promise<string>;
27
+ /**
28
+ * AgentCore's stage one: the deployment's values first, on the first invocation, so a failed read is that invocation's
29
+ * failure and the next asks again; then the storage.
30
30
  */
31
- export declare function prepareStartWorkspace(dirArg: string): Promise<PreparedWorkspace>;
31
+ export declare function prepareAgentcoreWorkspace(dirArg: string): Promise<string>;
32
32
  export declare function openStartService(dirArg: string, opts: StartOptions): Promise<StartedService>;
33
- /** Internal entry loaded from the agent's installed package after storage initialization. */
33
+ /** Stage two: open the built definition in `dirArg` and serve it. */
34
34
  export declare function openPreparedStartService(dirArg: string, opts: StartOptions): Promise<StartedService>;
35
35
  export {};