@fastagent-sh/fastagent 0.24.4 → 0.26.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.
- package/README.md +54 -82
- package/dist/agent-api.d.ts +460 -0
- package/dist/agent-api.js +209 -0
- package/dist/answer-text.d.ts +8 -0
- package/dist/answer-text.js +18 -0
- package/dist/atomic-write.d.ts +2 -2
- package/dist/atomic-write.js +2 -2
- package/dist/authoring.d.ts +81 -0
- package/dist/authoring.js +245 -0
- package/dist/channel.d.ts +29 -15
- package/dist/channel.js +4 -1
- package/dist/channels/agentcore-protocol.d.ts +36 -50
- package/dist/channels/agentcore-protocol.js +3 -3
- package/dist/channels/agentcore-service.d.ts +8 -18
- package/dist/channels/agentcore-service.js +108 -127
- package/dist/channels/agentcore.d.ts +8 -24
- package/dist/channels/agentcore.js +32 -65
- package/dist/channels/body.d.ts +0 -16
- package/dist/channels/body.js +0 -25
- package/dist/channels/busy.js +6 -1
- package/dist/channels/context.d.ts +4 -0
- package/dist/channels/context.js +35 -0
- package/dist/channels/discover.d.ts +18 -20
- package/dist/channels/discover.js +41 -99
- package/dist/channels/feishu/feishu-api.d.ts +54 -4
- package/dist/channels/feishu/feishu-api.js +192 -149
- package/dist/channels/feishu/feishu.d.ts +3 -0
- package/dist/channels/feishu/feishu.js +117 -106
- package/dist/channels/feishu/history.d.ts +55 -0
- package/dist/channels/feishu/history.js +199 -0
- package/dist/channels/feishu/invoke-turn.d.ts +13 -11
- package/dist/channels/feishu/invoke-turn.js +9 -10
- package/dist/channels/feishu/model.d.ts +2 -1
- package/dist/channels/feishu/normalize.js +100 -0
- package/dist/channels/feishu/preview.d.ts +2 -2
- package/dist/channels/feishu/register-webhook.d.ts +1 -0
- package/dist/channels/feishu/register-webhook.js +3 -2
- package/dist/channels/feishu/scaffold/channel.ts +65 -46
- package/dist/channels/feishu/scaffold/feishu-send.ts +38 -33
- package/dist/channels/feishu/scaffold/feishu-threads.ts +25 -0
- package/dist/channels/feishu/setup-mode.d.ts +45 -25
- package/dist/channels/feishu/setup-mode.js +74 -23
- package/dist/channels/feishu/shared-api.d.ts +24 -6
- package/dist/channels/feishu/shared-api.js +30 -24
- package/dist/channels/kit/context-buffer.d.ts +11 -2
- package/dist/channels/kit/context-buffer.js +7 -4
- package/dist/channels/kit/delivery.d.ts +19 -3
- package/dist/channels/kit/delivery.js +74 -15
- package/dist/channels/kit/event-stream.js +2 -1
- package/dist/channels/kit/invoke-turn-kit.d.ts +41 -41
- package/dist/channels/kit/invoke-turn-kit.js +62 -71
- package/dist/channels/kit/place-history.d.ts +107 -0
- package/dist/channels/kit/place-history.js +182 -0
- package/dist/channels/kit/preview-kit.d.ts +9 -5
- package/dist/channels/kit/preview-kit.js +36 -15
- package/dist/channels/kit/room-threads.d.ts +46 -0
- package/dist/channels/kit/room-threads.js +81 -0
- package/dist/channels/kit/seen.js +1 -1
- package/dist/channels/kit/stop-command.d.ts +6 -3
- package/dist/channels/kit/stop-command.js +20 -18
- package/dist/channels/kit/thread-fork.d.ts +17 -0
- package/dist/channels/kit/thread-fork.js +43 -0
- package/dist/channels/kit/thread-participants.js +1 -1
- package/dist/channels/kit/transport.d.ts +5 -0
- package/dist/channels/kit/transport.js +5 -0
- package/dist/channels/kit/turn-runner.d.ts +10 -9
- package/dist/channels/kit/turn-runner.js +17 -19
- package/dist/channels/kit/turn-store.d.ts +5 -4
- package/dist/channels/kit/turn-store.js +5 -5
- package/dist/channels/lark/lark.d.ts +3 -0
- package/dist/channels/lark/lark.js +5 -0
- package/dist/channels/lark/onboard.d.ts +5 -3
- package/dist/channels/lark/onboard.js +14 -14
- package/dist/channels/lark/scaffold/channel.ts +67 -44
- package/dist/channels/lark/scaffold/lark-send.ts +38 -33
- package/dist/channels/lark/scaffold/lark-threads.ts +25 -0
- package/dist/channels/respond.d.ts +0 -4
- package/dist/channels/respond.js +1 -1
- package/dist/channels/router.d.ts +18 -0
- package/dist/channels/router.js +68 -0
- package/dist/channels/serve.d.ts +5 -70
- package/dist/channels/serve.js +105 -287
- package/dist/channels/slack/history.d.ts +42 -0
- package/dist/channels/slack/history.js +282 -0
- package/dist/channels/slack/invoke-turn.d.ts +12 -5
- package/dist/channels/slack/invoke-turn.js +7 -5
- package/dist/channels/slack/manifest.d.ts +1 -4
- package/dist/channels/slack/manifest.js +22 -10
- package/dist/channels/slack/model.d.ts +2 -1
- package/dist/channels/slack/onboard.d.ts +0 -2
- package/dist/channels/slack/onboard.js +2 -4
- package/dist/channels/slack/onboarding-state.d.ts +0 -2
- package/dist/channels/slack/onboarding-state.js +0 -1
- package/dist/channels/slack/parse.d.ts +0 -5
- package/dist/channels/slack/parse.js +1 -16
- package/dist/channels/slack/preview.d.ts +2 -3
- package/dist/channels/slack/preview.js +78 -52
- package/dist/channels/slack/register-webhook.d.ts +1 -0
- package/dist/channels/slack/register-webhook.js +6 -5
- package/dist/channels/slack/scaffold/channel.ts +23 -24
- package/dist/channels/slack/scaffold/slack-send.ts +50 -43
- package/dist/channels/slack/scaffold/slack-threads.ts +29 -0
- package/dist/channels/slack/setup-server.d.ts +19 -0
- package/dist/channels/slack/setup-server.js +113 -11
- package/dist/channels/slack/shared-api.d.ts +15 -4
- package/dist/channels/slack/shared-api.js +19 -14
- package/dist/channels/slack/slack-api.d.ts +61 -2
- package/dist/channels/slack/slack-api.js +28 -5
- package/dist/channels/slack/slack.js +97 -52
- package/dist/channels/slack/welcomed.js +1 -1
- package/dist/channels/telegram/context-buffer.d.ts +6 -1
- package/dist/channels/telegram/context-buffer.js +19 -0
- package/dist/channels/telegram/invoke-turn.d.ts +8 -4
- package/dist/channels/telegram/invoke-turn.js +7 -7
- package/dist/channels/telegram/parse.d.ts +7 -2
- package/dist/channels/telegram/parse.js +7 -0
- package/dist/channels/telegram/preview.d.ts +2 -2
- package/dist/channels/telegram/register-webhook.d.ts +1 -0
- package/dist/channels/telegram/register-webhook.js +3 -2
- package/dist/channels/telegram/scaffold/channel.ts +27 -28
- package/dist/channels/telegram/scaffold/telegram-send.ts +61 -108
- package/dist/channels/telegram/shared-api.d.ts +34 -0
- package/dist/channels/telegram/shared-api.js +79 -0
- package/dist/channels/telegram/telegram-api.d.ts +15 -5
- package/dist/channels/telegram/telegram-api.js +10 -6
- package/dist/channels/telegram/telegram.js +27 -21
- package/dist/channels/telegram/turn-store.js +1 -1
- package/dist/channels/{kit/turn-queue.d.ts → turn-queue.d.ts} +2 -2
- package/dist/channels/{kit/turn-queue.js → turn-queue.js} +10 -10
- package/dist/cli/add-feishu.d.ts +42 -12
- package/dist/cli/add-feishu.js +177 -124
- package/dist/cli/add-slack.d.ts +8 -3
- package/dist/cli/add-slack.js +116 -64
- package/dist/cli/auth-view.d.ts +10 -3
- package/dist/cli/auth-view.js +8 -6
- package/dist/cli/box-login.d.ts +18 -7
- package/dist/cli/box-login.js +46 -12
- package/dist/cli/commands/add.d.ts +15 -4
- package/dist/cli/commands/add.js +253 -143
- package/dist/cli/commands/auth.d.ts +6 -0
- package/dist/cli/commands/auth.js +50 -0
- package/dist/cli/commands/content.d.ts +6 -0
- package/dist/cli/commands/content.js +45 -0
- package/dist/cli/commands/deploy/agentcore.js +50 -77
- package/dist/cli/commands/deploy/docker.js +38 -39
- package/dist/cli/commands/deploy/fly.js +21 -18
- package/dist/cli/commands/deploy/host-login.d.ts +26 -0
- package/dist/cli/commands/deploy/host-login.js +90 -0
- package/dist/cli/commands/deploy/railway.js +21 -26
- package/dist/cli/commands/deploy/shared.d.ts +45 -17
- package/dist/cli/commands/deploy/shared.js +34 -15
- package/dist/cli/commands/deploy.d.ts +0 -4
- package/dist/cli/commands/deploy.js +237 -50
- package/dist/cli/commands/destroy.js +8 -6
- package/dist/cli/commands/dev.d.ts +0 -2
- package/dist/cli/commands/dev.js +20 -19
- package/dist/cli/commands/env.d.ts +12 -0
- package/dist/cli/commands/env.js +191 -0
- package/dist/cli/commands/info.js +95 -156
- package/dist/cli/commands/init.d.ts +2 -2
- package/dist/cli/commands/init.js +35 -33
- package/dist/cli/commands/invoke.d.ts +6 -0
- package/dist/cli/commands/invoke.js +132 -16
- package/dist/cli/commands/login.d.ts +31 -2
- package/dist/cli/commands/login.js +416 -65
- package/dist/cli/commands/logout.d.ts +4 -0
- package/dist/cli/commands/logout.js +53 -0
- package/dist/cli/commands/logs.js +8 -6
- package/dist/cli/commands/models.d.ts +2 -1
- package/dist/cli/commands/models.js +39 -37
- package/dist/cli/commands/schedules.d.ts +21 -0
- package/dist/cli/commands/schedules.js +143 -0
- package/dist/cli/commands/start.d.ts +11 -10
- package/dist/cli/commands/start.js +35 -62
- package/dist/cli/content-view.d.ts +9 -0
- package/dist/cli/content-view.js +26 -0
- package/dist/cli/fail.d.ts +9 -12
- package/dist/cli/fail.js +17 -14
- package/dist/cli/invoke-stream.d.ts +12 -3
- package/dist/cli/invoke-stream.js +85 -23
- package/dist/cli/kernel.d.ts +9 -2
- package/dist/cli/kernel.js +15 -6
- package/dist/cli/login-relay.d.ts +6 -4
- package/dist/cli/login-relay.js +19 -7
- package/dist/cli/models-view.d.ts +5 -1
- package/dist/cli/models-view.js +1 -1
- package/dist/cli/person.d.ts +10 -0
- package/dist/cli/person.js +23 -0
- package/dist/cli/program.js +421 -203
- package/dist/cli/serve.d.ts +13 -63
- package/dist/cli/serve.js +31 -121
- package/dist/cli/shared.d.ts +21 -48
- package/dist/cli/shared.js +70 -89
- package/dist/cli/ticket.d.ts +136 -0
- package/dist/cli/ticket.js +476 -0
- package/dist/client.d.ts +7 -0
- package/dist/client.js +2 -0
- package/dist/content/declare.d.ts +70 -0
- package/dist/content/declare.js +163 -0
- package/dist/content/file.d.ts +32 -0
- package/dist/content/file.js +119 -0
- package/dist/content/git.d.ts +41 -0
- package/dist/content/git.js +220 -0
- package/dist/content/mount.d.ts +2 -0
- package/dist/content/mount.js +15 -0
- package/dist/content/resolve.d.ts +52 -0
- package/dist/content/resolve.js +151 -0
- package/dist/content/source.d.ts +27 -0
- package/dist/content/source.js +53 -0
- package/dist/conversation-sessions.d.ts +26 -0
- package/dist/conversation-sessions.js +99 -0
- package/dist/declared-secrets.d.ts +19 -37
- package/dist/declared-secrets.js +16 -58
- package/dist/deploy/agentcore/destroy.d.ts +3 -3
- package/dist/deploy/agentcore/destroy.js +46 -28
- package/dist/deploy/agentcore/forwarder.js +105 -22
- package/dist/deploy/agentcore/logs.js +1 -1
- package/dist/deploy/agentcore/plan.d.ts +10 -24
- package/dist/deploy/agentcore/plan.js +31 -135
- package/dist/deploy/agentcore/run.d.ts +1 -1
- package/dist/deploy/agentcore/run.js +8 -5
- package/dist/deploy/agentcore/shell.d.ts +1 -1
- package/dist/deploy/agentcore/shell.js +5 -5
- package/dist/deploy/api.d.ts +34 -0
- package/dist/deploy/api.js +50 -0
- package/dist/deploy/box-shell.d.ts +6 -0
- package/dist/deploy/box-shell.js +7 -0
- package/dist/deploy/build-context.d.ts +7 -5
- package/dist/deploy/build-context.js +41 -35
- package/dist/deploy/channel-ingress.d.ts +6 -1
- package/dist/deploy/channel-ingress.js +18 -5
- package/dist/deploy/container.d.ts +22 -9
- package/dist/deploy/container.js +96 -55
- package/dist/deploy/docker/plan.d.ts +3 -2
- package/dist/deploy/docker/plan.js +13 -14
- package/dist/deploy/docker/run.d.ts +2 -2
- package/dist/deploy/docker/run.js +8 -4
- package/dist/deploy/fly/plan.d.ts +1 -1
- package/dist/deploy/fly/plan.js +12 -21
- package/dist/deploy/fly/run.d.ts +10 -6
- package/dist/deploy/fly/run.js +11 -6
- package/dist/deploy/hosts.d.ts +2 -1
- package/dist/deploy/hosts.js +2 -1
- package/dist/deploy/preflight.d.ts +21 -23
- package/dist/deploy/preflight.js +223 -202
- package/dist/deploy/railway/plan.d.ts +8 -6
- package/dist/deploy/railway/plan.js +15 -58
- package/dist/deploy/railway/run.d.ts +8 -3
- package/dist/deploy/railway/run.js +12 -8
- package/dist/deploy/residency.d.ts +5 -11
- package/dist/deploy/residency.js +0 -6
- package/dist/deploy/runner.d.ts +1 -1
- package/dist/deploy/runner.js +1 -1
- package/dist/deploy/secrets.d.ts +16 -2
- package/dist/deploy/secrets.js +33 -6
- package/dist/deploy/workspace.d.ts +11 -6
- package/dist/deploy/workspace.js +55 -38
- package/dist/dev-supervisor.d.ts +11 -2
- package/dist/dev-supervisor.js +52 -27
- package/dist/effect-port.d.ts +4 -4
- package/dist/effect-port.js +4 -4
- package/dist/env.d.ts +0 -13
- package/dist/env.js +1 -44
- package/dist/environment/apt.d.ts +4 -0
- package/dist/environment/apt.js +32 -0
- package/dist/environment/declare.d.ts +59 -0
- package/dist/environment/declare.js +210 -0
- package/dist/environment/mise.d.ts +51 -0
- package/dist/environment/mise.js +272 -0
- package/dist/feishu.d.ts +2 -2
- package/dist/feishu.js +2 -2
- package/dist/git.d.ts +13 -0
- package/dist/git.js +55 -0
- package/dist/harnesses/models/catalog.d.ts +20 -0
- package/dist/harnesses/models/catalog.js +254 -0
- package/dist/{engines/pi/auth.d.ts → harnesses/models/credentials.d.ts} +3 -3
- package/dist/{engines/pi/auth.js → harnesses/models/credentials.js} +3 -3
- package/dist/harnesses/models/environment.d.ts +48 -0
- package/dist/harnesses/models/environment.js +88 -0
- package/dist/harnesses/models/host.d.ts +30 -0
- package/dist/harnesses/models/host.js +97 -0
- package/dist/{engines/pi → harnesses/models}/login.d.ts +66 -70
- package/dist/harnesses/models/login.js +439 -0
- package/dist/harnesses/models/models.d.ts +84 -0
- package/dist/harnesses/models/models.js +197 -0
- package/dist/harnesses/pi-durable/agent.d.ts +42 -0
- package/dist/harnesses/pi-durable/agent.js +581 -0
- package/dist/harnesses/pi-durable/defaults.d.ts +28 -0
- package/dist/harnesses/pi-durable/defaults.js +26 -0
- package/dist/harnesses/pi-durable/define.d.ts +77 -0
- package/dist/harnesses/pi-durable/define.js +28 -0
- package/dist/harnesses/pi-durable/entries.d.ts +32 -0
- package/dist/harnesses/pi-durable/entries.js +126 -0
- package/dist/harnesses/pi-durable/events.d.ts +25 -0
- package/dist/harnesses/pi-durable/events.js +238 -0
- package/dist/harnesses/pi-durable/ids.d.ts +16 -0
- package/dist/harnesses/pi-durable/ids.js +55 -0
- package/dist/harnesses/pi-durable/messages.d.ts +41 -0
- package/dist/harnesses/pi-durable/messages.js +116 -0
- package/dist/harnesses/pi-durable/open.d.ts +95 -0
- package/dist/harnesses/pi-durable/open.js +330 -0
- package/dist/harnesses/pi-durable/reads.d.ts +30 -0
- package/dist/harnesses/pi-durable/reads.js +94 -0
- package/dist/harnesses/pi-durable/registry.d.ts +18 -0
- package/dist/harnesses/pi-durable/registry.js +56 -0
- package/dist/harnesses/pi-durable/release.d.ts +13 -0
- package/dist/harnesses/pi-durable/release.js +40 -0
- package/dist/harnesses/pi-durable/serve.d.ts +90 -0
- package/dist/harnesses/pi-durable/serve.js +186 -0
- package/dist/harnesses/pi-durable/sessions.d.ts +27 -0
- package/dist/harnesses/pi-durable/sessions.js +47 -0
- package/dist/harnesses/pi-durable/storage.d.ts +4 -0
- package/dist/harnesses/pi-durable/storage.js +49 -0
- package/dist/harnesses/pi-durable/stream.d.ts +20 -0
- package/dist/harnesses/pi-durable/stream.js +221 -0
- package/dist/harnesses/pi-durable/text.d.ts +30 -0
- package/dist/harnesses/pi-durable/text.js +292 -0
- package/dist/harnesses/pi-durable/wake.d.ts +11 -0
- package/dist/harnesses/pi-durable/wake.js +90 -0
- package/dist/http/client.d.ts +6 -0
- package/dist/http/client.js +256 -0
- package/dist/http/contract.d.ts +541 -0
- package/dist/http/contract.js +179 -0
- package/dist/http/server.d.ts +34 -0
- package/dist/http/server.js +194 -0
- package/dist/index.d.ts +19 -4
- package/dist/index.js +13 -5
- package/dist/lark.d.ts +2 -2
- package/dist/lark.js +2 -2
- package/dist/locked-file.d.ts +17 -0
- package/dist/{engines/pi/locked-file.js → locked-file.js} +16 -10
- package/dist/once.d.ts +6 -0
- package/dist/once.js +23 -0
- package/dist/paths.d.ts +36 -52
- package/dist/paths.js +66 -182
- package/dist/runtime.d.ts +25 -2
- package/dist/runtime.js +27 -0
- package/dist/scaffold/add-channel.d.ts +14 -27
- package/dist/scaffold/add-channel.js +82 -180
- package/dist/scaffold/init.d.ts +17 -18
- package/dist/scaffold/init.js +87 -99
- package/dist/scaffold/templates/SYSTEM.md +12 -0
- package/dist/scaffold/templates/env.example +4 -10
- package/dist/scaffold/templates/fastagent.config.ts +21 -33
- package/dist/scaffold/templates/gitignore +8 -1
- package/dist/scaffold/templates/skills/writing-great-skills/SKILL.md +1 -2
- package/dist/scaffold/templates.d.ts +9 -4
- package/dist/scaffold/templates.js +7 -5
- package/dist/scaffold/vendor-skill.d.ts +1 -4
- package/dist/scaffold/vendor-skill.js +5 -6
- package/dist/schedule/cron.d.ts +13 -0
- package/dist/schedule/cron.js +52 -0
- package/dist/schedule/eventbridge-cron.d.ts +17 -0
- package/dist/schedule/eventbridge-cron.js +88 -0
- package/dist/schedule/schedule.d.ts +23 -0
- package/dist/schedule/schedule.js +34 -0
- package/dist/schedule/scheduler.d.ts +34 -33
- package/dist/schedule/scheduler.js +251 -137
- package/dist/schedule/state.d.ts +4 -14
- package/dist/schedule/state.js +7 -7
- package/dist/schedule/wake-alarm.d.ts +22 -2
- package/dist/schedule/wake-alarm.js +66 -20
- package/dist/schedule/wakeups.d.ts +16 -15
- package/dist/schedule/wakeups.js +47 -45
- package/dist/service.d.ts +56 -169
- package/dist/service.js +91 -187
- package/dist/serving-command.d.ts +10 -0
- package/dist/serving-command.js +16 -0
- package/dist/sign-in-api.d.ts +147 -0
- package/dist/sign-in-api.js +9 -0
- package/dist/slack.d.ts +1 -1
- package/dist/slack.js +1 -1
- package/dist/{channels/kit/state.js → state-file.js} +6 -6
- package/dist/telegram.d.ts +1 -0
- package/dist/telegram.js +1 -0
- package/dist/tunnel.d.ts +3 -0
- package/dist/tunnel.js +14 -5
- package/dist/value-file.d.ts +40 -0
- package/dist/value-file.js +164 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.js +14 -1
- package/package.json +18 -28
- package/dist/agent.d.ts +0 -106
- package/dist/agent.js +0 -21
- package/dist/channels/control.d.ts +0 -31
- package/dist/channels/control.js +0 -329
- package/dist/channels/define-channel.d.ts +0 -39
- package/dist/channels/define-channel.js +0 -9
- package/dist/channels/feishu/context-buffer.d.ts +0 -35
- package/dist/channels/feishu/context-buffer.js +0 -65
- package/dist/channels/feishu/scaffold/channel.websocket.ts +0 -31
- package/dist/channels/http.d.ts +0 -23
- package/dist/channels/http.js +0 -57
- package/dist/channels/lark/scaffold/channel.websocket.ts +0 -31
- package/dist/channels/slack/context-buffer.d.ts +0 -23
- package/dist/channels/slack/context-buffer.js +0 -37
- package/dist/channels/sse.d.ts +0 -4
- package/dist/channels/sse.js +0 -66
- package/dist/cli/commands/chat.d.ts +0 -3
- package/dist/cli/commands/chat.js +0 -14
- package/dist/cli/commands/routine-run.d.ts +0 -6
- package/dist/cli/commands/routine-run.js +0 -46
- package/dist/cli/commands/routine.d.ts +0 -25
- package/dist/cli/commands/routine.js +0 -122
- package/dist/cli/commands/tool.d.ts +0 -1
- package/dist/cli/commands/tool.js +0 -57
- package/dist/collect.d.ts +0 -63
- package/dist/collect.js +0 -90
- package/dist/core.d.ts +0 -13
- package/dist/core.js +0 -15
- package/dist/engines/pi/agent-models.d.ts +0 -83
- package/dist/engines/pi/agent-models.js +0 -120
- package/dist/engines/pi/agent-session-factory.d.ts +0 -121
- package/dist/engines/pi/agent-session-factory.js +0 -535
- package/dist/engines/pi/chat.d.ts +0 -3
- package/dist/engines/pi/chat.js +0 -8
- package/dist/engines/pi/config.d.ts +0 -71
- package/dist/engines/pi/config.js +0 -199
- package/dist/engines/pi/create.d.ts +0 -170
- package/dist/engines/pi/create.js +0 -343
- package/dist/engines/pi/definition.d.ts +0 -74
- package/dist/engines/pi/definition.js +0 -236
- package/dist/engines/pi/entry-images.d.ts +0 -14
- package/dist/engines/pi/entry-images.js +0 -23
- package/dist/engines/pi/invoke-session.d.ts +0 -18
- package/dist/engines/pi/invoke-session.js +0 -403
- package/dist/engines/pi/locked-file.d.ts +0 -9
- package/dist/engines/pi/login.js +0 -331
- package/dist/engines/pi/machine.d.ts +0 -53
- package/dist/engines/pi/machine.js +0 -137
- package/dist/engines/pi/models.d.ts +0 -200
- package/dist/engines/pi/models.js +0 -533
- package/dist/engines/pi/open.d.ts +0 -180
- package/dist/engines/pi/open.js +0 -270
- package/dist/engines/pi/openai-account-models.d.ts +0 -35
- package/dist/engines/pi/openai-account-models.js +0 -116
- package/dist/engines/pi/report.d.ts +0 -18
- package/dist/engines/pi/report.js +0 -59
- package/dist/engines/pi/retry-event.d.ts +0 -6
- package/dist/engines/pi/retry-event.js +0 -15
- package/dist/engines/pi/service.d.ts +0 -9
- package/dist/engines/pi/service.js +0 -14
- package/dist/engines/pi/session-builder.d.ts +0 -13
- package/dist/engines/pi/session-builder.js +0 -117
- package/dist/engines/pi/session-control.d.ts +0 -77
- package/dist/engines/pi/session-control.js +0 -908
- package/dist/engines/pi/session-effects.d.ts +0 -14
- package/dist/engines/pi/session-effects.js +0 -30
- package/dist/engines/pi/session-inheritance.d.ts +0 -21
- package/dist/engines/pi/session-inheritance.js +0 -204
- package/dist/engines/pi/session-markers.d.ts +0 -49
- package/dist/engines/pi/session-markers.js +0 -60
- package/dist/engines/pi/session-settings.d.ts +0 -67
- package/dist/engines/pi/session-settings.js +0 -119
- package/dist/engines/pi/session-store.d.ts +0 -69
- package/dist/engines/pi/session-store.js +0 -430
- package/dist/engines/pi/tool-context.d.ts +0 -45
- package/dist/engines/pi/tool-context.js +0 -31
- package/dist/engines/pi/tool.d.ts +0 -99
- package/dist/engines/pi/tool.js +0 -118
- package/dist/engines/pi/turn-kit.d.ts +0 -92
- package/dist/engines/pi/turn-kit.js +0 -288
- package/dist/engines/pi/wake-tool.d.ts +0 -9
- package/dist/engines/pi/wake-tool.js +0 -92
- package/dist/loader.d.ts +0 -41
- package/dist/loader.js +0 -116
- package/dist/node.d.ts +0 -3
- package/dist/node.js +0 -4
- package/dist/observe.d.ts +0 -6
- package/dist/observe.js +0 -47
- package/dist/pi.d.ts +0 -25
- package/dist/pi.js +0 -15
- package/dist/scaffold/templates/APPEND_SYSTEM.md +0 -12
- package/dist/scaffold/templates/tools/fetch-url.ts +0 -25
- package/dist/schedule/discover.d.ts +0 -17
- package/dist/schedule/discover.js +0 -61
- package/dist/schedule/routine.d.ts +0 -43
- package/dist/schedule/routine.js +0 -32
- package/dist/schedule/run.d.ts +0 -55
- package/dist/schedule/run.js +0 -146
- package/dist/secrets-gate.d.ts +0 -32
- package/dist/secrets-gate.js +0 -33
- package/dist/session-remote.d.ts +0 -47
- package/dist/session-remote.js +0 -460
- package/dist/session.d.ts +0 -466
- package/dist/session.js +0 -57
- /package/dist/{channels/kit/state.d.ts → state-file.d.ts} +0 -0
|
@@ -1,55 +1,26 @@
|
|
|
1
1
|
import { webhookRunbook } from "../channel-ingress.js";
|
|
2
|
-
import { containerArtifacts } from "../container.js";
|
|
2
|
+
import { containerArtifacts, imageHasGit } from "../container.js";
|
|
3
3
|
import { deploymentLoginCommand } from "../box-shell.js";
|
|
4
|
-
import {
|
|
4
|
+
import { WAKEUPS_WHEN_ASLEEP, residencyFor } from "../residency.js";
|
|
5
5
|
/** State root = the volume mount path, kept in lockstep. */
|
|
6
6
|
const MOUNT = "/data";
|
|
7
|
-
/** The
|
|
8
|
-
export const dockerfilePathVar = (prefix) => `/${prefix}Dockerfile`;
|
|
9
|
-
/** The name this tool gives BOTH the project and the service, derived from the workspace directory. */
|
|
7
|
+
/** The name this tool gives BOTH the project and the service, derived from the agent directory's name. */
|
|
10
8
|
export function toRailwayName(basename) {
|
|
11
9
|
return basename.replace(/[^a-zA-Z0-9-]+/g, "-").replace(/^-+|-+$/g, "") || "agent";
|
|
12
10
|
}
|
|
13
|
-
/** railway.json is JSON, so its ownership marker is a KEY rather than a comment line. */
|
|
14
|
-
const GENERATED_RAILWAY_KEY = "x-generated-by";
|
|
15
|
-
const GENERATED_RAILWAY_VALUE = "fastagent deploy railway";
|
|
16
|
-
export function isGeneratedRailwayJson(content) {
|
|
17
|
-
try {
|
|
18
|
-
return JSON.parse(content)[GENERATED_RAILWAY_KEY] === GENERATED_RAILWAY_VALUE;
|
|
19
|
-
}
|
|
20
|
-
catch {
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
/** railway.json — build/deploy only (Railway's config-as-code scope). */
|
|
25
|
-
function railwayJson(prefix) {
|
|
26
|
-
return `${JSON.stringify({
|
|
27
|
-
$schema: "https://railway.com/railway.schema.json",
|
|
28
|
-
[GENERATED_RAILWAY_KEY]: GENERATED_RAILWAY_VALUE,
|
|
29
|
-
// dockerfilePath is relative to the workspace root (`railway up`'s upload context).
|
|
30
|
-
build: { builder: "DOCKERFILE", dockerfilePath: `${prefix}Dockerfile` },
|
|
31
|
-
deploy: { healthcheckPath: "/health", restartPolicyType: "ON_FAILURE" },
|
|
32
|
-
}, null, 2)}\n`;
|
|
33
|
-
}
|
|
34
11
|
/** Compute the Railway deploy plan from the resolved definition. */
|
|
35
12
|
export function planRailwayDeploy(input) {
|
|
36
13
|
const { serviceName, channels } = input;
|
|
37
|
-
|
|
38
|
-
// product).
|
|
39
|
-
const configPath = `${input.agentPrefix}railway.json`;
|
|
40
|
-
const artifacts = [
|
|
41
|
-
{ path: configPath, content: railwayJson(input.agentPrefix) },
|
|
42
|
-
...containerArtifacts(input),
|
|
43
|
-
];
|
|
14
|
+
const artifacts = containerArtifacts(input);
|
|
44
15
|
const secrets = input.secrets ?? [];
|
|
45
16
|
// Order matters, not cosmetics: `railway init` creates a PROJECT with no service, but the volume and variables are
|
|
46
17
|
// service-scoped and `railway up` deploys THE service.
|
|
47
18
|
const runbook = [
|
|
48
|
-
`# Deploy to Railway.
|
|
19
|
+
`# Deploy to Railway. Dockerfile(.dockerignore) are generated above.`,
|
|
49
20
|
`# Prereqs: the Railway CLI (https://docs.railway.com/guides/cli) and \`railway login\`.`,
|
|
50
21
|
``,
|
|
51
22
|
`# One-time setup (init → service → volume → variables). Skip it on redeploy: repeating it creates`,
|
|
52
|
-
`# another project/service/volume, splitting the
|
|
23
|
+
`# another project/service/volume, splitting the agent's state.`,
|
|
53
24
|
``,
|
|
54
25
|
`# Create + link a project (writes .railway link state in this dir; the project — not a committed`,
|
|
55
26
|
`# file — is Railway's source of truth for identity, variables, and the volume).`,
|
|
@@ -64,22 +35,21 @@ export function planRailwayDeploy(input) {
|
|
|
64
35
|
`railway volume add --mount-path ${MOUNT}`,
|
|
65
36
|
``,
|
|
66
37
|
`# Variables — set BEFORE the first deploy so the box boots with them. Railway injects PORT itself.`,
|
|
67
|
-
|
|
68
|
-
`# Railway's documented route to a non-root Dockerfile (no dashboard step needed for the build).`,
|
|
69
|
-
`railway variables set FASTAGENT_STATE_DIR=${MOUNT}/.state FASTAGENT_SECRETS_DIR=${MOUNT}/.secrets RAILWAY_DOCKERFILE_PATH=${dockerfilePathVar(input.agentPrefix)}`,
|
|
38
|
+
`railway variables set FASTAGENT_STATE_DIR=${MOUNT}/.state FASTAGENT_SECRETS_DIR=${MOUNT}/.secrets`,
|
|
70
39
|
];
|
|
71
40
|
if (secrets.length > 0) {
|
|
72
41
|
runbook.push(`# Secrets:`, `# ${secrets.map((s) => `${s.name}: ${s.hint}`).join("\n# ")}`, `railway variables set ${secrets.map((s) => `${s.name}=<value>`).join(" ")}`);
|
|
73
42
|
}
|
|
74
|
-
runbook.push(``, `#
|
|
75
|
-
runbook.push(``, `# Before a new definition release, run \`fastagent deploy railway\` to refresh the release manifest.`, `# Upload this workspace and build on Railway (no local Docker needed):`, `railway up`);
|
|
43
|
+
runbook.push(``, `# Before a new definition release, run \`fastagent deploy railway\` to refresh the release manifest.`, `# Upload the agent directory and build on Railway (no local Docker needed): Railway builds the`, `# Dockerfile at its root. It marks the deploy live once the container starts, without waiting for`, `# /health: \`railway logs\` shows a box that crashes on boot.`, `railway up`);
|
|
76
44
|
// The credential is created on the box, never carried: the box is then the only holder of its grant.
|
|
77
45
|
if (input.boxLogin) {
|
|
78
|
-
runbook.push(``, `# Model auth: once it is up, the deployment logs in to ${input.boxLogin} itself (from
|
|
46
|
+
runbook.push(``, `# Model auth: once it is up, the deployment logs in to ${input.boxLogin} itself (from the agent directory):`, `${deploymentLoginCommand("railway", input.boxLogin)}`);
|
|
79
47
|
}
|
|
80
|
-
runbook.push(``, `# The volume keeps
|
|
81
|
-
? `# Railway uploads may strip .git
|
|
82
|
-
:
|
|
48
|
+
runbook.push(``, `# The volume keeps .state and .secrets across restarts and deploys; each release replaces /data/definition.`, input.shipsGit
|
|
49
|
+
? `# Railway uploads may strip .git, so the deployed definition may have no history.`
|
|
50
|
+
: imageHasGit(input)
|
|
51
|
+
? `# Git is installed (github content is cloned here, or context.json declares it in aptPackages).`
|
|
52
|
+
: `# To give the agent git, declare it: fastagent env add apt:git`);
|
|
83
53
|
// The public URL is minted, not deterministic (unlike Fly's <app>.fly.dev).
|
|
84
54
|
const steps = webhookRunbook(`https://<your-domain>`, channels);
|
|
85
55
|
if (steps.length > 0) {
|
|
@@ -90,19 +60,6 @@ export function planRailwayDeploy(input) {
|
|
|
90
60
|
const residency = residencyFor({ channels, hasCron: input.hasCron });
|
|
91
61
|
runbook.push(``, residency
|
|
92
62
|
? `# Scale-to-zero: do NOT enable App Sleeping — ${residency.why}.`
|
|
93
|
-
: `# Scale-to-zero (optional, dashboard-only — no CLI/API): Settings → Deploy → Serverless → App Sleeping —\n# ${WAKEUPS_WHEN_ASLEEP}.`,
|
|
94
|
-
? [
|
|
95
|
-
`# To sleep anyway: keep the time in a Railway CRON SERVICE (Settings -> Cron Schedule, >= 5 min) that`,
|
|
96
|
-
`# calls this service's \`POST /run\` over the private network — traffic from another service in the`,
|
|
97
|
-
`# project wakes a slept one. A cron service must EXIT, so it cannot be this service.`,
|
|
98
|
-
`# set a variable on the cron service and curl it (Railway resolves the reference at deploy):`,
|
|
99
|
-
`# AGENT_RUN=http://${serviceName}.railway.internal:\${{${serviceName}.PORT}}/run`,
|
|
100
|
-
`# curl --retry 3 -fsS -X POST "$AGENT_RUN" -H 'content-type: application/json' -d '{"name":"<routine>"}'`,
|
|
101
|
-
`# --retry because the FIRST request to a slept service may answer 502 (Railway documents it). The`,
|
|
102
|
-
`# route has no dedup, so decide for yourself whether a retry that may duplicate work is what you want.`,
|
|
103
|
-
`# \`POST /run\` is an API, not a clock: read its contract — docs/api-reference.md#post-run.`,
|
|
104
|
-
`# Asleep, ${WAKEUPS_WHEN_ASLEEP}.`,
|
|
105
|
-
]
|
|
106
|
-
: []), `# Keep this a SINGLE service: the ${MOUNT} volume is tied to one service; extra replicas split state.`);
|
|
63
|
+
: `# Scale-to-zero (optional, dashboard-only — no CLI/API): Settings → Deploy → Serverless → App Sleeping —\n# ${WAKEUPS_WHEN_ASLEEP}.`, `# Keep this a SINGLE service: the ${MOUNT} volume is tied to one service; extra replicas split state.`);
|
|
107
64
|
return { artifacts, runbook };
|
|
108
65
|
}
|
|
@@ -15,19 +15,24 @@ export interface RailwayRunPlan {
|
|
|
15
15
|
secrets: Record<string, string>;
|
|
16
16
|
/** Declared names the value file supplies no value for — the run gates on these before any side effect. */
|
|
17
17
|
missingSecrets: string[];
|
|
18
|
-
/** That value file,
|
|
18
|
+
/** That value file, agent-dir-relative, so the gate names the file this deploy actually read. */
|
|
19
19
|
valueFile: string;
|
|
20
20
|
/** Every declared channel and its ingress — the driver asks which of them have a webhook. */
|
|
21
21
|
channels: readonly DeclaredChannel[];
|
|
22
22
|
/** Opt-in (CLI `--into-linked`) to provision INTO the project this directory is already linked to. */
|
|
23
23
|
intoLinked: boolean;
|
|
24
|
-
/** `RAILWAY_DOCKERFILE_PATH` value (`/fastagent/Dockerfile`). */
|
|
25
|
-
dockerfilePath: string;
|
|
26
24
|
/**
|
|
27
25
|
* Log the box in (`fastagent login --deployment`) once it is up and before any webhook is pointed at it: a channel pointed at
|
|
28
26
|
* a box with no model credential answers every message with a failure. Resolves a gate line, or undefined.
|
|
29
27
|
*/
|
|
30
28
|
boxLogin?: BoxLoginStep;
|
|
29
|
+
/**
|
|
30
|
+
* Sign the host's CLI in when it is signed out, through whoever can (host-login.ts): resolves a gate line, or
|
|
31
|
+
* undefined once signed in. Absent: nobody can, and the run stops naming how.
|
|
32
|
+
*/
|
|
33
|
+
hostLogin?: () => Promise<string | undefined>;
|
|
34
|
+
/** The command a coding agent runs to deploy this, its person's steps handed to its user (`--run --json`). */
|
|
35
|
+
forAgent: string;
|
|
31
36
|
}
|
|
32
37
|
/**
|
|
33
38
|
* Done (with the live URL), or a gate the operator must clear before re-running (printed + non-zero exit by the CLI).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { loginGate, publicHealthGate, registerWebhooks, } from "../channel-ingress.js";
|
|
2
2
|
import { readOutput } from "../runner.js";
|
|
3
|
-
import { missingValuesGate } from "../secrets.js";
|
|
3
|
+
import { hostSignedOutGate, missingValuesGate } from "../secrets.js";
|
|
4
4
|
/** Whether `railway status --json` shows a linked project: non-empty stdout. */
|
|
5
5
|
export function isLinked(stdout) {
|
|
6
6
|
return stdout.trim() !== "";
|
|
@@ -77,14 +77,19 @@ export async function deployRailwayRun(plan, railway, log, registrars, healthPro
|
|
|
77
77
|
// Every --service below targets plan.name — the name this tool gives BOTH the project and the service (`init
|
|
78
78
|
// --name` + `add --service`).
|
|
79
79
|
const svc = ["--service", plan.name];
|
|
80
|
-
// 1.
|
|
81
|
-
|
|
82
|
-
return gate("not logged in to Railway — run `railway login`, or set RAILWAY_API_TOKEN (an account token), then re-run");
|
|
83
|
-
}
|
|
84
|
-
// 2. Gate missing required secret VALUES before any side effect (no half-created infra).
|
|
80
|
+
// 1. Gate missing required secret VALUES before any side effect (no half-created infra), and before asking a
|
|
81
|
+
// person to sign in for a deploy that would stop here anyway.
|
|
85
82
|
const missingValues = missingValuesGate(plan.missingSecrets, plan.valueFile);
|
|
86
83
|
if (missingValues)
|
|
87
84
|
return gate(missingValues);
|
|
85
|
+
// 2.
|
|
86
|
+
if ((await railway(["whoami"], { capture: true })).code !== 0) {
|
|
87
|
+
const failed = plan.hostLogin
|
|
88
|
+
? await plan.hostLogin()
|
|
89
|
+
: hostSignedOutGate("Railway", "railway login", "RAILWAY_API_TOKEN (an account token)", plan.forAgent);
|
|
90
|
+
if (failed)
|
|
91
|
+
return gate(failed);
|
|
92
|
+
}
|
|
88
93
|
// 3.
|
|
89
94
|
const status = await railway(["status", "--json"], { capture: true });
|
|
90
95
|
if (isLinked(status.stdout)) {
|
|
@@ -124,7 +129,6 @@ export async function deployRailwayRun(plan, railway, log, registrars, healthPro
|
|
|
124
129
|
const machineryVars = [
|
|
125
130
|
`FASTAGENT_STATE_DIR=${plan.mountPath}/.state`,
|
|
126
131
|
`FASTAGENT_SECRETS_DIR=${plan.mountPath}/.secrets`,
|
|
127
|
-
`RAILWAY_DOCKERFILE_PATH=${plan.dockerfilePath}`,
|
|
128
132
|
];
|
|
129
133
|
// The secret NAMES, not a count: `--run` uploads the whole value file, so the operator has to be able to see the
|
|
130
134
|
// list on every host.
|
|
@@ -153,7 +157,7 @@ export async function deployRailwayRun(plan, railway, log, registrars, healthPro
|
|
|
153
157
|
return gate("`railway volume add` failed — see the railway output above");
|
|
154
158
|
}
|
|
155
159
|
// Deploying before the volume is attached boots a container with no volume, which `start` refuses (it must
|
|
156
|
-
// never
|
|
160
|
+
// never publish a definition onto a disk that vanishes on restart).
|
|
157
161
|
let status;
|
|
158
162
|
for (let waited = 0;; waited += VOLUME_POLL_MS) {
|
|
159
163
|
const read = await volumeStatus();
|
|
@@ -4,9 +4,8 @@
|
|
|
4
4
|
* A host may only phrase its own REMEDY — the setting it owns (`min_machines_running`, App Sleeping) — never
|
|
5
5
|
* re-derive the reason.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* be ours — see {@link CRON_CAN_BE_EXTERNAL}; a long connection has none.
|
|
7
|
+
* A schedule is the agent's own clock: it keeps one machine up, and nothing here offers a way around that. Scaling to
|
|
8
|
+
* zero with timed work means not declaring the schedule and keeping the time elsewhere (docs/deploy.md), never both.
|
|
10
9
|
*
|
|
11
10
|
* A WAKE-UP IS NOT A REASON. Every serve mounts `wake`, so counting it would pin every deployment up. It does not
|
|
12
11
|
* need to: the wake-up store is on the volume and the poll drains what is due when the process starts, so a box that
|
|
@@ -15,23 +14,18 @@
|
|
|
15
14
|
*/
|
|
16
15
|
import type { DeclaredChannel } from "../channels/discover.ts";
|
|
17
16
|
/** Why one machine has to stay up. Also the order they are checked in. */
|
|
18
|
-
|
|
17
|
+
type ResidencyReason = "long-connection" | "cron";
|
|
19
18
|
export interface Residency {
|
|
20
19
|
reason: ResidencyReason;
|
|
21
20
|
/** The host-neutral cause, one clause, for a generated comment or a runbook line. */
|
|
22
21
|
why: string;
|
|
23
22
|
}
|
|
24
|
-
/**
|
|
25
|
-
* The ONE reason a caller may offer a way out of: a cron is a TIME, and a time can be kept elsewhere — a platform
|
|
26
|
-
* scheduler, a CI cron, a crontab — which then calls this agent. Nothing else here can be moved out: a long
|
|
27
|
-
* connection is one this process holds.
|
|
28
|
-
*/
|
|
29
|
-
export declare const CRON_CAN_BE_EXTERNAL: ResidencyReason;
|
|
30
23
|
/** What scaling to zero costs the agent's own wake-ups — said next to every setting that allows it. */
|
|
31
24
|
export declare const WAKEUPS_WHEN_ASLEEP = "the agent's own wake-ups then fire when a request next wakes the machine, not on time";
|
|
32
25
|
/** What forbids scale-to-zero for this deployment, or `undefined` when nothing does. */
|
|
33
26
|
export declare function residencyFor(facts: {
|
|
34
27
|
channels: readonly DeclaredChannel[];
|
|
35
|
-
/** `
|
|
28
|
+
/** `schedules/` declares at least one schedule. */
|
|
36
29
|
hasCron: boolean;
|
|
37
30
|
}): Residency | undefined;
|
|
31
|
+
export {};
|
package/dist/deploy/residency.js
CHANGED
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The ONE reason a caller may offer a way out of: a cron is a TIME, and a time can be kept elsewhere — a platform
|
|
3
|
-
* scheduler, a CI cron, a crontab — which then calls this agent. Nothing else here can be moved out: a long
|
|
4
|
-
* connection is one this process holds.
|
|
5
|
-
*/
|
|
6
|
-
export const CRON_CAN_BE_EXTERNAL = "cron";
|
|
7
1
|
/** What scaling to zero costs the agent's own wake-ups — said next to every setting that allows it. */
|
|
8
2
|
export const WAKEUPS_WHEN_ASLEEP = "the agent's own wake-ups then fire when a request next wakes the machine, not on time";
|
|
9
3
|
/** What forbids scale-to-zero for this deployment, or `undefined` when nothing does. */
|
package/dist/deploy/runner.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ export declare function readOutput<T>(run: CliRunner, bin: string, args: string[
|
|
|
29
29
|
gate: string;
|
|
30
30
|
}>;
|
|
31
31
|
/**
|
|
32
|
-
* Production {@link CliRunner}: spawn `bin` in `cwd` (the
|
|
32
|
+
* Production {@link CliRunner}: spawn `bin` in `cwd` (the agent directory, which is the build/upload context). stderr
|
|
33
33
|
* is always inherited to the terminal.
|
|
34
34
|
*/
|
|
35
35
|
export declare function spawnRunner(bin: string, cwd: string): CliRunner;
|
package/dist/deploy/runner.js
CHANGED
|
@@ -24,7 +24,7 @@ export async function readOutput(run, bin, args, read) {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
|
-
* Production {@link CliRunner}: spawn `bin` in `cwd` (the
|
|
27
|
+
* Production {@link CliRunner}: spawn `bin` in `cwd` (the agent directory, which is the build/upload context). stderr
|
|
28
28
|
* is always inherited to the terminal.
|
|
29
29
|
*/
|
|
30
30
|
export function spawnRunner(bin, cwd) {
|
package/dist/deploy/secrets.d.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The environment a deployed agent runs with — host-neutral.
|
|
3
3
|
*
|
|
4
|
-
* The value file (`.secrets/.env`) IS the deployed environment: every variable in it travels, on every host. What the
|
|
5
|
-
* definition declares (`defineTool`/`defineChannel
|
|
4
|
+
* The production value file (`.secrets/production/.env`) IS the deployed environment: every variable in it travels, on every host. What the
|
|
5
|
+
* definition declares (`defineTool`/`defineChannel`, the `variables` of `context.json`, plus the model's env key) only says
|
|
6
6
|
* which of those must have a value, so a missing one stops a deploy before its first side effect instead of a boot.
|
|
7
7
|
*/
|
|
8
8
|
import { type DeclaredSecret } from "../declared-secrets.ts";
|
|
9
9
|
/** Is this local auth source an env-var API key (→ becomes a deploy secret) vs OAuth / stored / none? */
|
|
10
10
|
export declare function isEnvKey(source: string | undefined): source is string;
|
|
11
|
+
/** Is `name` one the deployment sets itself (see {@link DEPLOY_OWNED}), including the chunked carriers? */
|
|
12
|
+
export declare function isDeployOwned(name: string): boolean;
|
|
11
13
|
/** One variable a runbook tells the operator to set, and where to look for its value. */
|
|
12
14
|
export interface DeploymentSecret {
|
|
13
15
|
name: string;
|
|
@@ -38,12 +40,24 @@ export declare function assembleSecrets(input: {
|
|
|
38
40
|
secrets: Record<string, string>;
|
|
39
41
|
missingSecrets: string[];
|
|
40
42
|
};
|
|
43
|
+
/**
|
|
44
|
+
* The stop for a host CLI signed out with nobody to sign it in. A token goes in the shell's (or CI's) environment,
|
|
45
|
+
* never in the production value file: everything there travels to the box, which runs an agent with a shell.
|
|
46
|
+
*/
|
|
47
|
+
export declare function hostSignedOutGate(host: string, login: string, token: string, forAgent: string): string;
|
|
41
48
|
/**
|
|
42
49
|
* The ONE refusal for declared names the deployed environment does not supply a value for — every host reaches it
|
|
43
50
|
* before its first side effect. Host-neutral because the reason is: the value file IS the deployed environment, so a
|
|
44
51
|
* name missing from it is missing from the deployment, whatever platform receives it.
|
|
45
52
|
*/
|
|
46
53
|
export declare function missingValuesGate(missing: readonly string[], valueFile: string): string | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* The refusal for a setting that shapes what `deploy` plans (a channel's ingress, read when `deploy` imports the
|
|
56
|
+
* channel here) and differs between this process and the value file. The box imports the channel with the file's
|
|
57
|
+
* value, so planning with this one would deploy a different channel than the one planned for: an export in this shell
|
|
58
|
+
* is the usual cause.
|
|
59
|
+
*/
|
|
60
|
+
export declare function divergentSettingsGate(names: readonly string[], env: NodeJS.ProcessEnv, values: ReadonlyMap<string, string>, valueFile: string): string | undefined;
|
|
47
61
|
/**
|
|
48
62
|
* Expand `FASTAGENT_ENV` into the process environment — what `start` does first on a host that carries the value file
|
|
49
63
|
* that way. The platform's own variables still win, as they do over a value file anywhere.
|
package/dist/deploy/secrets.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The environment a deployed agent runs with — host-neutral.
|
|
3
3
|
*
|
|
4
|
-
* The value file (`.secrets/.env`) IS the deployed environment: every variable in it travels, on every host. What the
|
|
5
|
-
* definition declares (`defineTool`/`defineChannel
|
|
4
|
+
* The production value file (`.secrets/production/.env`) IS the deployed environment: every variable in it travels, on every host. What the
|
|
5
|
+
* definition declares (`defineTool`/`defineChannel`, the `variables` of `context.json`, plus the model's env key) only says
|
|
6
6
|
* which of those must have a value, so a missing one stops a deploy before its first side effect instead of a boot.
|
|
7
7
|
*/
|
|
8
8
|
import { dedupeSecrets } from "../declared-secrets.js";
|
|
9
|
+
import { DEV_SERVE_ENV } from "../serving-command.js";
|
|
10
|
+
import { AGENT_ENVIRONMENT_ENV } from "../paths.js";
|
|
9
11
|
/** Is this local auth source an env-var API key (→ becomes a deploy secret) vs OAuth / stored / none? */
|
|
10
12
|
export function isEnvKey(source) {
|
|
11
13
|
return source !== undefined && /^[A-Z][A-Z0-9_]*$/.test(source);
|
|
@@ -16,7 +18,6 @@ export function isEnvKey(source) {
|
|
|
16
18
|
*/
|
|
17
19
|
const DEPLOY_OWNED = new Set([
|
|
18
20
|
"PORT",
|
|
19
|
-
"FASTAGENT_AGENT",
|
|
20
21
|
"FASTAGENT_MODEL",
|
|
21
22
|
"FASTAGENT_STATE_DIR",
|
|
22
23
|
"FASTAGENT_SECRETS_DIR",
|
|
@@ -27,9 +28,11 @@ const DEPLOY_OWNED = new Set([
|
|
|
27
28
|
"FASTAGENT_INGRESS_SECRET",
|
|
28
29
|
"FASTAGENT_WAKE_SECRET",
|
|
29
30
|
"FASTAGENT_DEV_WORKER",
|
|
31
|
+
DEV_SERVE_ENV,
|
|
32
|
+
AGENT_ENVIRONMENT_ENV,
|
|
30
33
|
]);
|
|
31
34
|
/** Is `name` one the deployment sets itself (see {@link DEPLOY_OWNED}), including the chunked carriers? */
|
|
32
|
-
function isDeployOwned(name) {
|
|
35
|
+
export function isDeployOwned(name) {
|
|
33
36
|
return DEPLOY_OWNED.has(name) || /^FASTAGENT_ENV(_\d+)?$/.test(name);
|
|
34
37
|
}
|
|
35
38
|
/** The value-file variables that travel: everything with a value that the deployment does not set itself. */
|
|
@@ -52,8 +55,9 @@ export function deploymentSecrets(modelAuth, declared, values, valueFile) {
|
|
|
52
55
|
};
|
|
53
56
|
if (isEnvKey(modelAuth))
|
|
54
57
|
add(modelAuth, "your model provider key");
|
|
55
|
-
for (const { name, source } of dedupeSecrets(declared))
|
|
56
|
-
add(name, `required by ${source}`);
|
|
58
|
+
for (const { name, source, description } of dedupeSecrets(declared)) {
|
|
59
|
+
add(name, `required by ${source}${description ? `: ${description}` : ""}`);
|
|
60
|
+
}
|
|
57
61
|
for (const name of Object.keys(carriedValues(values)))
|
|
58
62
|
add(name, `from ${valueFile}`);
|
|
59
63
|
return secrets;
|
|
@@ -79,6 +83,15 @@ export function assembleSecrets(input) {
|
|
|
79
83
|
}
|
|
80
84
|
return { secrets, missingSecrets };
|
|
81
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* The stop for a host CLI signed out with nobody to sign it in. A token goes in the shell's (or CI's) environment,
|
|
88
|
+
* never in the production value file: everything there travels to the box, which runs an agent with a shell.
|
|
89
|
+
*/
|
|
90
|
+
export function hostSignedOutGate(host, login, token, forAgent) {
|
|
91
|
+
return (`not logged in to ${host} — run \`${login}\` in a terminal (it opens a browser), or set ${token} in this ` +
|
|
92
|
+
`shell's environment, never in .secrets/production/.env (everything there travels to the box); then re-run. ` +
|
|
93
|
+
`From a coding agent, \`${forAgent}\` hands the sign-in to its user`);
|
|
94
|
+
}
|
|
82
95
|
/**
|
|
83
96
|
* The ONE refusal for declared names the deployed environment does not supply a value for — every host reaches it
|
|
84
97
|
* before its first side effect. Host-neutral because the reason is: the value file IS the deployed environment, so a
|
|
@@ -90,6 +103,20 @@ export function missingValuesGate(missing, valueFile) {
|
|
|
90
103
|
return (`no value for: ${missing.join(", ")} — the deployed environment is declared by ${valueFile}, and this deploy ` +
|
|
91
104
|
`reads only that file (exporting the variable here does not reach the deployment). Add them there and re-run`);
|
|
92
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* The refusal for a setting that shapes what `deploy` plans (a channel's ingress, read when `deploy` imports the
|
|
108
|
+
* channel here) and differs between this process and the value file. The box imports the channel with the file's
|
|
109
|
+
* value, so planning with this one would deploy a different channel than the one planned for: an export in this shell
|
|
110
|
+
* is the usual cause.
|
|
111
|
+
*/
|
|
112
|
+
export function divergentSettingsGate(names, env, values, valueFile) {
|
|
113
|
+
const differing = names.filter((name) => (env[name] ?? "") !== (values.get(name) ?? ""));
|
|
114
|
+
if (differing.length === 0)
|
|
115
|
+
return undefined;
|
|
116
|
+
const said = differing.map((name) => `${name} is "${env[name] ?? ""}" here and "${values.get(name) ?? ""}" in ${valueFile}`);
|
|
117
|
+
return (`${said.join("; ")} — the deployment receives only ${valueFile}, and this deploy would plan for a different ` +
|
|
118
|
+
`channel than the one it starts. Set it in ${valueFile} (or unset it here) and re-run`);
|
|
119
|
+
}
|
|
93
120
|
/**
|
|
94
121
|
* Collect a (possibly CHUNKED) carrier from the environment: `<name>` plus numbered continuations (`_2`, `_3`, …)
|
|
95
122
|
* concatenated in order. A host whose env values have a length cap splits a long value this way.
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export declare const RELEASE_FILE = "fastagent.release.json";
|
|
2
|
+
/** Where the storage holds the deployed definition, the agent's working directory on the host. */
|
|
3
|
+
export declare const DEPLOYED_DEFINITION_DIR = "definition";
|
|
2
4
|
export interface DeploymentRelease {
|
|
3
5
|
version: 1;
|
|
4
6
|
id: string;
|
|
@@ -11,14 +13,14 @@ export interface DeploymentRelease {
|
|
|
11
13
|
*/
|
|
12
14
|
model?: string;
|
|
13
15
|
}
|
|
14
|
-
/** The manifest names
|
|
15
|
-
*
|
|
16
|
-
*
|
|
16
|
+
/** The manifest names the agent the storage belongs to, and that name is also a content entry's name rule (one path
|
|
17
|
+
* segment). `deploy` asks BEFORE generating artifacts — a name `init` accepts but this rejects is the author's
|
|
18
|
+
* directory name, not a corrupt manifest. */
|
|
17
19
|
export declare function isReleaseAgentName(name: string): boolean;
|
|
18
20
|
export declare function parseDeploymentRelease(raw: string): DeploymentRelease;
|
|
19
21
|
/**
|
|
20
22
|
* Project a release's own declarations into the environment it was resolved FOR — the receiving half of the model
|
|
21
|
-
* chain, run by `prepareStartWorkspace` BEFORE the
|
|
23
|
+
* chain, run by `prepareStartWorkspace` BEFORE the agent's `.env` is read (so either source outranks a value
|
|
22
24
|
* edited on the box).
|
|
23
25
|
*
|
|
24
26
|
* `||=`: a variable the platform already holds still wins, because the deployment declares only the half of this
|
|
@@ -29,7 +31,10 @@ export declare function applyReleaseEnv(release: DeploymentRelease, env?: NodeJS
|
|
|
29
31
|
/** A `provider/modelId` spec. The id itself may carry `/` and `~` (`baseten/zai-org/GLM-5.3`, openrouter aliases);
|
|
30
32
|
* resolution only ever splits on the first slash. */
|
|
31
33
|
export declare function isModelSpec(value: string): boolean;
|
|
32
|
-
/**
|
|
34
|
+
/**
|
|
35
|
+
* Call while holding the deployment lease. Replaces the deployed definition with the release's (`source`, the image's
|
|
36
|
+
* copy) and returns where it now is; nothing else on the storage is touched.
|
|
37
|
+
*/
|
|
33
38
|
export declare function applyDeploymentRelease(source: string, root: string, release: DeploymentRelease): Promise<string>;
|
|
34
39
|
/** An unmounted directory must never look like a new disk. */
|
|
35
40
|
export declare function assertStorageMounted(root: string, paths?: string[]): Promise<void>;
|
|
@@ -37,7 +42,7 @@ export declare function assertStorageMounted(root: string, paths?: string[]): Pr
|
|
|
37
42
|
* passes a short one rather than waiting out the deployment default. */
|
|
38
43
|
export declare function leaseDeployment(metadata: string, waitSeconds?: number): Promise<() => Promise<void>>;
|
|
39
44
|
/**
|
|
40
|
-
* Prepare the deployed
|
|
45
|
+
* Prepare the deployed definition and return its path.
|
|
41
46
|
*
|
|
42
47
|
* The lease is NOT returned: it stays held for the process lifetime, because channel activation can
|
|
43
48
|
* start background writers that `close()` does not drain. The kernel drops it when the process exits.
|
package/dist/deploy/workspace.js
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Deployment-owned initialization of a host's storage: the lease, the release journal, and the definition each
|
|
3
|
+
* release replaces. The instance's state, credentials and content (`.state/`, `.secrets/`, `content/`) sit beside the
|
|
4
|
+
* definition and outlive every release; each release links its `content/` to the storage's.
|
|
5
|
+
*/
|
|
6
|
+
import { cp, lstat, mkdir, readFile, rename, rm, symlink } from "node:fs/promises";
|
|
3
7
|
import { join, resolve } from "node:path";
|
|
4
8
|
import { spawn } from "node:child_process";
|
|
5
9
|
import { closeSync, openSync } from "node:fs";
|
|
6
10
|
import { once } from "node:events";
|
|
7
11
|
import { writeFileAtomic } from "../atomic-write.js";
|
|
8
12
|
import { log } from "../log.js";
|
|
9
|
-
import { exists } from "../paths.js";
|
|
13
|
+
import { CONTENT_DIRNAME, exists } from "../paths.js";
|
|
10
14
|
import { detectRuntime, readPackageJson } from "../runtime.js";
|
|
11
15
|
export const RELEASE_FILE = "fastagent.release.json";
|
|
16
|
+
/** Where the storage holds the deployed definition, the agent's working directory on the host. */
|
|
17
|
+
export const DEPLOYED_DEFINITION_DIR = "definition";
|
|
12
18
|
/** The deployment's own bookkeeping on the storage: the lease, the release journal, the install marker. */
|
|
13
19
|
const deploymentMeta = (root) => join(root, ".deployment");
|
|
14
|
-
/** The manifest names
|
|
15
|
-
*
|
|
16
|
-
*
|
|
20
|
+
/** The manifest names the agent the storage belongs to, and that name is also a content entry's name rule (one path
|
|
21
|
+
* segment). `deploy` asks BEFORE generating artifacts — a name `init` accepts but this rejects is the author's
|
|
22
|
+
* directory name, not a corrupt manifest. */
|
|
17
23
|
export function isReleaseAgentName(name) {
|
|
18
24
|
return /^[a-zA-Z0-9_-]+$/.test(name);
|
|
19
25
|
}
|
|
@@ -31,7 +37,7 @@ export function parseDeploymentRelease(raw) {
|
|
|
31
37
|
}
|
|
32
38
|
/**
|
|
33
39
|
* Project a release's own declarations into the environment it was resolved FOR — the receiving half of the model
|
|
34
|
-
* chain, run by `prepareStartWorkspace` BEFORE the
|
|
40
|
+
* chain, run by `prepareStartWorkspace` BEFORE the agent's `.env` is read (so either source outranks a value
|
|
35
41
|
* edited on the box).
|
|
36
42
|
*
|
|
37
43
|
* `||=`: a variable the platform already holds still wins, because the deployment declares only the half of this
|
|
@@ -47,7 +53,7 @@ export function applyReleaseEnv(release, env = process.env) {
|
|
|
47
53
|
return;
|
|
48
54
|
log.info(`[fastagent] model ${effective} — from ${fromPlatform
|
|
49
55
|
? `a FASTAGENT_MODEL already set in this environment${release.model ? ", which outranks the release manifest" : ""}`
|
|
50
|
-
: "the release manifest (redeploy to change it)"}; editing FASTAGENT_MODEL in
|
|
56
|
+
: "the release manifest (redeploy to change it)"}; editing FASTAGENT_MODEL in the deployed agent's .env does not override it`);
|
|
51
57
|
}
|
|
52
58
|
/** A `provider/modelId` spec. The id itself may carry `/` and `~` (`baseten/zai-org/GLM-5.3`, openrouter aliases);
|
|
53
59
|
* resolution only ever splits on the first slash. */
|
|
@@ -55,12 +61,12 @@ export function isModelSpec(value) {
|
|
|
55
61
|
return /^\S+\/\S+$/.test(value);
|
|
56
62
|
}
|
|
57
63
|
/** A completed staging tree is published before its journal; readers start only after recovery. */
|
|
58
|
-
async function finishRelease(root,
|
|
64
|
+
async function finishRelease(root, release) {
|
|
59
65
|
const meta = deploymentMeta(root), staged = join(meta, "staged"), previous = join(meta, "previous");
|
|
60
|
-
const target =
|
|
66
|
+
const target = join(root, DEPLOYED_DEFINITION_DIR);
|
|
61
67
|
if (await exists(staged)) {
|
|
62
68
|
if (await exists(target)) {
|
|
63
|
-
if (
|
|
69
|
+
if (await exists(previous))
|
|
64
70
|
throw new Error(`deployment recovery conflict at ${target}`);
|
|
65
71
|
await rename(target, previous);
|
|
66
72
|
}
|
|
@@ -69,48 +75,59 @@ async function finishRelease(root, pending) {
|
|
|
69
75
|
else if (!(await exists(target))) {
|
|
70
76
|
throw new Error(`deployment recovery has neither staged nor active content: ${target}`);
|
|
71
77
|
}
|
|
72
|
-
writeFileAtomic(join(meta, "applied.json"), JSON.stringify(
|
|
78
|
+
writeFileAtomic(join(meta, "applied.json"), JSON.stringify(release));
|
|
73
79
|
await rm(previous, { recursive: true, force: true });
|
|
74
80
|
await rm(join(meta, "pending.json"));
|
|
75
81
|
}
|
|
76
|
-
/**
|
|
82
|
+
/**
|
|
83
|
+
* Call while holding the deployment lease. Replaces the deployed definition with the release's (`source`, the image's
|
|
84
|
+
* copy) and returns where it now is; nothing else on the storage is touched.
|
|
85
|
+
*/
|
|
77
86
|
export async function applyDeploymentRelease(source, root, release) {
|
|
78
87
|
const meta = deploymentMeta(root), staged = join(meta, "staged"), pendingPath = join(meta, "pending.json");
|
|
79
88
|
await mkdir(meta, { recursive: true });
|
|
89
|
+
await mkdir(join(root, CONTENT_DIRNAME), { recursive: true });
|
|
90
|
+
// A storage an earlier FastAgent laid out holds the agent's whole workspace there, which this one would leave
|
|
91
|
+
// behind unread: said, never silently abandoned.
|
|
92
|
+
const formerWorkspace = join(root, "base");
|
|
93
|
+
if (await exists(formerWorkspace)) {
|
|
94
|
+
throw new Error(`${formerWorkspace} holds a workspace from an earlier FastAgent, which no longer copies one to the host — ` +
|
|
95
|
+
`move out what you need and delete it, or deploy onto fresh storage`);
|
|
96
|
+
}
|
|
80
97
|
if (await exists(pendingPath)) {
|
|
81
|
-
const pending =
|
|
82
|
-
pending.release = parseDeploymentRelease(JSON.stringify(pending.release));
|
|
83
|
-
if (typeof pending.initial !== "boolean")
|
|
84
|
-
throw new Error("invalid pending deployment journal");
|
|
98
|
+
const pending = parseDeploymentRelease(await readFile(pendingPath, "utf8"));
|
|
85
99
|
await finishRelease(root, pending);
|
|
86
100
|
}
|
|
87
101
|
const appliedPath = join(meta, "applied.json");
|
|
88
102
|
const applied = (await exists(appliedPath)) ? parseDeploymentRelease(await readFile(appliedPath, "utf8")) : undefined;
|
|
89
|
-
const
|
|
103
|
+
const definition = join(root, DEPLOYED_DEFINITION_DIR);
|
|
90
104
|
if (applied?.agent !== undefined && applied.agent !== release.agent) {
|
|
91
|
-
throw new Error(`deployment selects ${release.agent}, but this
|
|
105
|
+
throw new Error(`deployment selects ${release.agent}, but this storage belongs to ${applied.agent}`);
|
|
92
106
|
}
|
|
93
107
|
// Logged on BOTH paths: rebuilding an image without regenerating the manifest keeps the id, and a
|
|
94
108
|
// deployment that silently kept the old definition looks identical to one that took the new one.
|
|
95
109
|
if (applied?.id === release.id) {
|
|
96
|
-
log.info(`[fastagent] release ${release.id} is already applied — keeping the
|
|
97
|
-
return
|
|
110
|
+
log.info(`[fastagent] release ${release.id} is already applied — keeping the deployed definition`);
|
|
111
|
+
return definition;
|
|
112
|
+
}
|
|
113
|
+
if (applied === undefined && (await exists(definition))) {
|
|
114
|
+
throw new Error(`refusing to initialize over an existing unowned definition: ${definition}`);
|
|
115
|
+
}
|
|
116
|
+
if (!(await exists(source)) || !(await lstat(source)).isDirectory()) {
|
|
117
|
+
throw new Error(`the release must contain its agent directory: ${source}`);
|
|
98
118
|
}
|
|
99
|
-
|
|
100
|
-
if (initial && (await exists(workspace)))
|
|
101
|
-
throw new Error(`refusing to initialize over an existing unowned workspace: ${workspace}`);
|
|
102
|
-
const definition = join(source, release.agent);
|
|
103
|
-
if (!(await exists(definition)) || !(await lstat(definition)).isDirectory())
|
|
104
|
-
throw new Error(`the release must contain its agent directory: ${definition}`);
|
|
105
|
-
log.info(initial
|
|
106
|
-
? `[fastagent] seeding the workspace from release ${release.id}`
|
|
107
|
-
: `[fastagent] publishing release ${release.id} over base/${release.agent}`);
|
|
119
|
+
log.info(`[fastagent] publishing release ${release.id} as ${DEPLOYED_DEFINITION_DIR}/`);
|
|
108
120
|
await rm(staged, { recursive: true, force: true });
|
|
109
|
-
await cp(
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
121
|
+
await cp(source, staged, { recursive: true, verbatimSymlinks: true });
|
|
122
|
+
// Where the agent reaches each content entry, on every instance: here, the storage's, which no release replaces.
|
|
123
|
+
await symlink(join("..", CONTENT_DIRNAME), join(staged, CONTENT_DIRNAME)).catch((error) => {
|
|
124
|
+
if (error.code !== "EEXIST")
|
|
125
|
+
throw error;
|
|
126
|
+
throw new Error(`the release holds ${CONTENT_DIRNAME}/, which a deploy keeps out of the image — rebuild it`);
|
|
127
|
+
});
|
|
128
|
+
writeFileAtomic(pendingPath, JSON.stringify(release));
|
|
129
|
+
await finishRelease(root, release);
|
|
130
|
+
return definition;
|
|
114
131
|
}
|
|
115
132
|
async function mountedPaths() {
|
|
116
133
|
const mounts = await readFile("/proc/self/mountinfo", "utf8");
|
|
@@ -142,7 +159,7 @@ export async function leaseDeployment(metadata, waitSeconds = 35) {
|
|
|
142
159
|
});
|
|
143
160
|
const [code, signal] = await once(child, "close");
|
|
144
161
|
if (code !== 0)
|
|
145
|
-
throw new Error(`could not acquire
|
|
162
|
+
throw new Error(`could not acquire deployment lease at ${metadata}: flock ${signal ?? code} ${stderr.trim()}`);
|
|
146
163
|
return async () => {
|
|
147
164
|
closeSync(fd);
|
|
148
165
|
};
|
|
@@ -152,12 +169,12 @@ export async function leaseDeployment(metadata, waitSeconds = 35) {
|
|
|
152
169
|
// A custom base image without util-linux fails every boot; the bare spawn error names neither
|
|
153
170
|
// the binary nor why a lease needs one.
|
|
154
171
|
if (error.code === "ENOENT")
|
|
155
|
-
throw new Error(`the
|
|
172
|
+
throw new Error(`the deployment lease needs the \`flock\` binary (util-linux): ${String(error)}`);
|
|
156
173
|
throw error;
|
|
157
174
|
}
|
|
158
175
|
}
|
|
159
176
|
/**
|
|
160
|
-
* Prepare the deployed
|
|
177
|
+
* Prepare the deployed definition and return its path.
|
|
161
178
|
*
|
|
162
179
|
* The lease is NOT returned: it stays held for the process lifetime, because channel activation can
|
|
163
180
|
* start background writers that `close()` does not drain. The kernel drops it when the process exits.
|