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