@fastagent-sh/fastagent 0.24.4 → 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 -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/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
package/dist/cli/commands/add.js
CHANGED
|
@@ -1,51 +1,124 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `fastagent add <channel>|skill` — scaffold channel glue (`channels/<kind>.ts`) or vendor an Agent Skills skill.
|
|
2
|
+
* `fastagent add <channel>|skill` — scaffold channel glue (`src/channels/<kind>.ts`) or vendor an Agent Skills skill.
|
|
3
3
|
* slack/feishu/lark additionally CREATE OR RESUME the platform app.
|
|
4
4
|
*/
|
|
5
5
|
import { randomBytes } from "node:crypto";
|
|
6
|
-
import { readFile } from "node:fs/promises";
|
|
7
6
|
import { join, relative, resolve } from "node:path";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
7
|
+
import { assertIndependentFeishuApps, larkCredentialsNeeded, onboardFeishuCloudApp } from "../add-feishu.js";
|
|
8
|
+
import { terminalPerson } from "../person.js";
|
|
9
|
+
import { isInteractive, shellArg } from "../shared.js";
|
|
10
|
+
import { checkTicket, printReport, refusedCheck, runTicket, startTicket, ticketExitCode, ticketReport, } from "../ticket.js";
|
|
11
|
+
import { cloudFor } from "../../channels/feishu/cloud.js";
|
|
12
|
+
import { feishuIngressFor } from "../../channels/feishu/setup-mode.js";
|
|
13
|
+
import { markDevServe, unmarkDevServe } from "../../serving-command.js";
|
|
14
|
+
import { channelIngress } from "../../channels/discover.js";
|
|
15
|
+
import { buildDefinitionShape, prepareDefinition } from "../../harnesses/pi-durable/open.js";
|
|
16
|
+
import { dotEnvPath, enterAgentEnv, loadEnvValues } from "../../env.js";
|
|
17
|
+
import { selectAgentEnvironment, resolveStateRoot, SECRETS_DIRNAME, isUnderDir, displayPath } from "../../paths.js";
|
|
12
18
|
import { detectRuntime, readPackageJson } from "../../runtime.js";
|
|
13
19
|
import { appendChannelDotEnv, appendChannelEnv, assertChannelReady, channelExists, channelSetup, scaffoldChannel, scaffoldCompanionTools, } from "../../scaffold/add-channel.js";
|
|
14
20
|
import { vendorSkill } from "../../scaffold/vendor-skill.js";
|
|
15
|
-
import { failStartup, failUsage,
|
|
16
|
-
|
|
21
|
+
import { failStartup, failUsage, agentDirOrExit } from "../fail.js";
|
|
22
|
+
import { unprotectedSecretsNote } from "../../value-file.js";
|
|
23
|
+
/** Without a terminal, how long an app's setup stays open for the person to finish their part. */
|
|
24
|
+
const UNATTENDED_TIMEOUT_SECONDS = 900;
|
|
25
|
+
/** `fastagent add <kind> [dir]`: scaffold `src/channels/<kind>.ts`, the adapter configured with a starter policy. */
|
|
17
26
|
export async function runAddChannel(channelKind, dirArg, opts) {
|
|
18
|
-
|
|
19
|
-
|
|
27
|
+
if (opts.check !== undefined)
|
|
28
|
+
return checkSetup(channelKind, opts.check, opts);
|
|
29
|
+
if (opts.ticket !== undefined) {
|
|
30
|
+
// The process `startTicket` started: it takes the ticket before anything slow (the definition is built to plan),
|
|
31
|
+
// then does the whole `add`, its person the ticket's.
|
|
32
|
+
await runTicket(opts.ticket, async (step) => ({
|
|
33
|
+
...(await addChannel(channelKind, await planAdd(channelKind, dirArg, opts), opts, step.person)),
|
|
34
|
+
}));
|
|
35
|
+
process.exit(0);
|
|
36
|
+
}
|
|
37
|
+
const plan = await planAdd(channelKind, dirArg, opts);
|
|
38
|
+
const unattended = opts.input === false || opts.json === true || !isInteractive();
|
|
39
|
+
if (unattended && opts.onboard !== false && channelKind !== "telegram") {
|
|
40
|
+
return setUpUnattended(channelKind, opts, plan);
|
|
41
|
+
}
|
|
42
|
+
const added = await addChannel(channelKind, plan, opts, terminalPerson).catch(failStartup);
|
|
43
|
+
if (opts.json)
|
|
44
|
+
console.log(JSON.stringify({ status: "done", ...added }, null, 2));
|
|
45
|
+
// App-creation flows leave platform/tunnel sockets behind that would otherwise hold the one-shot scaffold command
|
|
46
|
+
// open after all durable boundaries have completed.
|
|
47
|
+
process.exit(0);
|
|
48
|
+
}
|
|
49
|
+
/** What `add` settles before it changes anything, refusing what it can while nothing has changed. */
|
|
50
|
+
async function planAdd(channelKind, dirArg, opts) {
|
|
51
|
+
// The channel (glue + companion tools + secrets) is agent surface: everything lands in the AGENT DIR.
|
|
20
52
|
if (opts.replaceConfig && opts.onboard === false) {
|
|
21
53
|
failUsage("--replace-config replaces onboarding credentials; it cannot be combined with --no-onboard");
|
|
22
54
|
}
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
55
|
+
const target = agentDirOrExit(resolve(dirArg));
|
|
56
|
+
const environment = opts.environment ?? "dev";
|
|
57
|
+
if (environment !== "dev" && environment !== "production") {
|
|
58
|
+
failUsage(`--env must be "dev" or "production", got "${environment}"`);
|
|
59
|
+
}
|
|
60
|
+
selectAgentEnvironment(environment);
|
|
61
|
+
if (environment === "production")
|
|
62
|
+
unmarkDevServe();
|
|
63
|
+
else
|
|
64
|
+
markDevServe();
|
|
65
|
+
enterAgentEnv(target);
|
|
66
|
+
if (environment === "production" && (channelKind === "feishu" || channelKind === "lark")) {
|
|
67
|
+
try {
|
|
68
|
+
assertIndependentFeishuApps(target, [channelKind], loadEnvValues(dotEnvPath(target)));
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
failStartup(error);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Paths are printed to someone standing in their CWD, which may be elsewhere, while every file belongs to the AGENT
|
|
26
75
|
// dir — prefix them, or they point at nothing.
|
|
27
76
|
const agentFromCwd = displayPath(process.cwd(), target);
|
|
28
77
|
const inAgent = (p) => (agentFromCwd === undefined ? p : join(agentFromCwd, p));
|
|
29
|
-
const envPath = dotEnvPath(target);
|
|
30
|
-
const envLabel = isUnderDir(envPath, target) ? inAgent(relative(target, envPath)) : envPath;
|
|
31
78
|
// An existing channel file is authored glue: kept, never rewritten.
|
|
32
|
-
const file = join(target, "channels", `${channelKind}.ts`);
|
|
79
|
+
const file = join(target, "src", "channels", `${channelKind}.ts`);
|
|
33
80
|
const existsAlready = await channelExists(target, channelKind).catch(failStartup);
|
|
34
|
-
const ingress =
|
|
35
|
-
|
|
81
|
+
const ingress = resolveIngress(channelKind, opts.ingress);
|
|
82
|
+
if (existsAlready &&
|
|
83
|
+
(ingress.setting || (environment === "production" && opts.onboard !== false)) &&
|
|
84
|
+
(channelKind === "feishu" || channelKind === "lark")) {
|
|
85
|
+
await assertChannelReadsSetting(target, channelKind, ingress.setting ?? { [`${cloudFor(channelKind).envPrefix}_INGRESS`]: ingress.ingress }, inAgent(relative(target, file)));
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
target,
|
|
89
|
+
environment,
|
|
90
|
+
inAgent,
|
|
91
|
+
agentFromCwd,
|
|
92
|
+
file,
|
|
93
|
+
existsAlready,
|
|
94
|
+
...ingress,
|
|
95
|
+
rerun: `fastagent add ${channelKind}${agentFromCwd === undefined ? "" : ` ${shellArg(agentFromCwd)}`}` +
|
|
96
|
+
`${environment === "production" ? " --env production" : ""}${opts.ingress ? ` --ingress ${opts.ingress}` : ""}` +
|
|
97
|
+
`${opts.replaceConfig ? " --replace-config" : ""}`,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Everything `add <kind>` does once the person's part can be done: the channel, its tools and variables, the app's
|
|
102
|
+
* onboarding through `person`, and the next steps, printed and returned with the variables it wrote.
|
|
103
|
+
*/
|
|
104
|
+
async function addChannel(channelKind, plan, opts, person) {
|
|
105
|
+
const { target, environment, inAgent, agentFromCwd, file, existsAlready, ingress, pinned, setting, rerun } = plan;
|
|
106
|
+
const envPath = dotEnvPath(target);
|
|
107
|
+
const envLabel = isUnderDir(envPath, target) ? inAgent(relative(target, envPath)) : envPath;
|
|
108
|
+
const before = loadEnvValues(envPath);
|
|
36
109
|
if (existsAlready) {
|
|
37
|
-
console.error(`[fastagent] ${relative(target, file)} already exists — keeping it`);
|
|
110
|
+
console.error(`[fastagent] ${inAgent(relative(target, file))} already exists — keeping it`);
|
|
38
111
|
}
|
|
39
112
|
else {
|
|
40
|
-
await assertChannelReady(target)
|
|
41
|
-
await scaffoldChannel(target, channelKind
|
|
42
|
-
console.error(`[fastagent] created ${relative(target, file)}`);
|
|
113
|
+
await assertChannelReady(target);
|
|
114
|
+
await scaffoldChannel(target, channelKind);
|
|
115
|
+
console.error(`[fastagent] created ${inAgent(relative(target, file))}`);
|
|
43
116
|
}
|
|
44
117
|
// Companion tools are the package's, not authored glue.
|
|
45
|
-
for (const tool of await scaffoldCompanionTools(target, channelKind)
|
|
46
|
-
console.error(`[fastagent] wrote ${relative(target, tool)}`);
|
|
118
|
+
for (const tool of await scaffoldCompanionTools(target, channelKind)) {
|
|
119
|
+
console.error(`[fastagent] wrote ${inAgent(relative(target, tool))}`);
|
|
47
120
|
}
|
|
48
|
-
if (await appendChannelEnv(target, channelKind
|
|
121
|
+
if (await appendChannelEnv(target, channelKind)) {
|
|
49
122
|
console.error(`[fastagent] added ${channelKind} env vars to ${inAgent(join(SECRETS_DIRNAME, ".env.example"))}`);
|
|
50
123
|
}
|
|
51
124
|
// Stateful app onboarding is re-runnable after the scaffold boundary.
|
|
@@ -55,163 +128,201 @@ export async function runAddChannel(channelKind, dirArg, opts) {
|
|
|
55
128
|
created = await onboardSlackInternalApp({
|
|
56
129
|
target,
|
|
57
130
|
stateRoot: resolveStateRoot(target),
|
|
58
|
-
groupBehavior,
|
|
59
131
|
replaceConfig: opts.replaceConfig,
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
.catch(failStartup);
|
|
132
|
+
...(person === terminalPerson ? {} : { person }),
|
|
133
|
+
}).then(() => undefined);
|
|
63
134
|
}
|
|
64
|
-
else if (channelKind === "feishu" || channelKind === "lark") {
|
|
65
|
-
created = await onboardFeishuCloudApp(target, channelKind, ingress,
|
|
135
|
+
else if ((channelKind === "feishu" || channelKind === "lark") && opts.onboard !== false) {
|
|
136
|
+
created = await onboardFeishuCloudApp(target, channelKind, ingress, rerun, person);
|
|
66
137
|
}
|
|
67
|
-
const setup = channelSetup(channelKind, ingress,
|
|
138
|
+
const setup = channelSetup(channelKind, ingress, pinned);
|
|
68
139
|
const env = setup.env;
|
|
69
140
|
const steps = channelKind === "slack" && opts.onboard !== false
|
|
70
141
|
? [
|
|
71
142
|
// No line about the Request URL: the `dev --tunnel` line below is the whole instruction, and FastAgent sets
|
|
72
143
|
// that URL itself when the agent first runs.
|
|
73
144
|
"invite the app to each channel it should read",
|
|
74
|
-
|
|
145
|
+
// The tool lines are the scaffold's (one list), whichever path set the app up.
|
|
146
|
+
...setup.steps.filter((step) => step.includes("{tools}/")),
|
|
75
147
|
]
|
|
76
148
|
: setup.steps;
|
|
77
149
|
const generated = Object.fromEntries(env.filter((e) => e.generate).map((e) => [e.name, randomBytes(24).toString("hex")]));
|
|
78
150
|
// Kind-neutral: every channel's generated secrets get the same treatment.
|
|
79
|
-
const dotEnv = await appendChannelDotEnv(target, channelKind, { ...generated, ...created }, Object.keys(created ?? {}),
|
|
151
|
+
const dotEnv = await appendChannelDotEnv(target, channelKind, { ...generated, ...created, ...setting }, [...Object.keys(created ?? {}), ...Object.keys(setting ?? {})], ingress);
|
|
80
152
|
if (dotEnv.unprotectedSecretsDir) {
|
|
81
|
-
console.error(`[fastagent] note: ${dotEnv.unprotectedSecretsDir}
|
|
82
|
-
`no .gitignore — that directory is yours, so fastagent will not write one into it. Make sure git ` +
|
|
83
|
-
`does not track what is in there.`);
|
|
153
|
+
console.error(`[fastagent] note: ${unprotectedSecretsNote(dotEnv.unprotectedSecretsDir)}`);
|
|
84
154
|
}
|
|
85
155
|
if (dotEnv.written.length > 0) {
|
|
86
156
|
console.error(`[fastagent] wrote ${dotEnv.written.join(", ")} to ${envLabel}`);
|
|
87
157
|
}
|
|
88
|
-
const install = detectRuntime(target, await readPackageJson(target)
|
|
89
|
-
|
|
90
|
-
|
|
158
|
+
const install = detectRuntime(target, await readPackageJson(target)).runtime === "bun" ? "bun install" : "npm install";
|
|
159
|
+
const next = [];
|
|
160
|
+
/** One next step: printed, and returned for a caller that reads them as data. */
|
|
161
|
+
const step = (line) => {
|
|
162
|
+
next.push(line.trim());
|
|
163
|
+
console.error(` ${line}`);
|
|
164
|
+
};
|
|
91
165
|
console.error(` next steps:`);
|
|
92
|
-
|
|
166
|
+
step(`${agentFromCwd === undefined ? install : `(cd ${agentFromCwd} && ${install})`} # if @fastagent-sh/fastagent is not installed yet`);
|
|
167
|
+
// Onboarding writes some itself (an app's ID and secret, a bot token) before the write above: what this `add` wrote is
|
|
168
|
+
// what the file holds now and did not before.
|
|
169
|
+
const now = loadEnvValues(envPath);
|
|
170
|
+
const written = [...now.keys()].filter((name) => now.get(name) && now.get(name) !== before.get(name));
|
|
93
171
|
for (const e of env) {
|
|
94
|
-
if (dotEnv.alreadySet.includes(e.name))
|
|
95
|
-
continue; // the user already
|
|
96
|
-
if (
|
|
172
|
+
if (!written.includes(e.name) && dotEnv.alreadySet.includes(e.name))
|
|
173
|
+
continue; // the user's already: nothing to do
|
|
174
|
+
if (written.includes(e.name)) {
|
|
97
175
|
// Written, but its hint may still carry an action — keep the variable visible instead of silently absorbing it.
|
|
98
|
-
|
|
176
|
+
step(`${e.name} — ${e.generate ? "generated and " : ""}written to ${envLabel} # ${e.hint}`);
|
|
99
177
|
continue;
|
|
100
178
|
}
|
|
101
179
|
const value = e.generate ? `=${generated[e.name]}` : "";
|
|
102
180
|
const action = e.required ? "set" : "optionally set";
|
|
103
|
-
|
|
181
|
+
step(`${action} ${e.name}${value} in ${envLabel} # ${e.hint}`);
|
|
104
182
|
}
|
|
105
|
-
|
|
106
|
-
// resolve them to the real agent-dir-relative locations here.
|
|
183
|
+
const serveCommand = environment === "production" ? "fastagent start" : "fastagent dev";
|
|
107
184
|
for (const s of steps) {
|
|
108
|
-
|
|
185
|
+
step(s
|
|
186
|
+
.replace("{channel}", inAgent(relative(target, file)))
|
|
187
|
+
.replace("{tools}", inAgent(join("src", "tools")))
|
|
188
|
+
.replaceAll("{serve}", serveCommand));
|
|
109
189
|
}
|
|
110
|
-
if (
|
|
111
|
-
|
|
190
|
+
if (environment === "production") {
|
|
191
|
+
step(`fastagent deploy <host> --run # deploy with the production app and credentials`);
|
|
192
|
+
}
|
|
193
|
+
else if (ingress === "websocket") {
|
|
194
|
+
step(`fastagent dev # no public URL or tunnel required`);
|
|
112
195
|
}
|
|
113
196
|
else if (channelKind === "slack") {
|
|
114
|
-
|
|
197
|
+
step(`fastagent dev --tunnel # ${opts.onboard === false ? "serve locally + print the URL to paste into the Slack app's Event Subscriptions" : "start the agent — then message it in Slack"}`);
|
|
115
198
|
}
|
|
116
199
|
else if (channelKind !== "lark") {
|
|
117
|
-
|
|
200
|
+
step(`fastagent dev --tunnel # serve locally + a public URL, auto-registering the webhook`);
|
|
118
201
|
}
|
|
119
|
-
|
|
120
|
-
// open after all durable boundaries have completed.
|
|
121
|
-
process.exit(0);
|
|
202
|
+
return { written, next_steps: next };
|
|
122
203
|
}
|
|
123
|
-
|
|
204
|
+
/** The command that reads an app's setup ticket, as every such ticket records it. */
|
|
205
|
+
const setupCheck = (kind) => `fastagent add ${kind} --check`;
|
|
206
|
+
/** What the person does for each kind's app, to follow "so they can". */
|
|
207
|
+
const SETUP_ACTIONS = {
|
|
208
|
+
slack: "set up the Slack app: paste a configuration token on the page, then click Allow in Slack",
|
|
209
|
+
feishu: "confirm the new Feishu app",
|
|
210
|
+
lark: "finish setting up the Lark app",
|
|
211
|
+
};
|
|
212
|
+
/**
|
|
213
|
+
* `add slack|feishu|lark` with no one at a terminal to ask, for a coding agent: what the person must provide first is
|
|
214
|
+
* named (Lark's app credentials, in the file the agent reads), never asked for in the agent's conversation; then the
|
|
215
|
+
* app's setup runs in a process of its own (ticket.ts), and the command returns once the person has a step to take, it
|
|
216
|
+
* is done, or it is still working at it.
|
|
217
|
+
*/
|
|
218
|
+
async function setUpUnattended(kind, opts, at) {
|
|
219
|
+
const { target } = at;
|
|
220
|
+
if (kind === "lark") {
|
|
221
|
+
const needed = await larkCredentialsNeeded(target, at.rerun).catch(failStartup);
|
|
222
|
+
if (needed !== undefined) {
|
|
223
|
+
printReport(opts.json, needed.json, needed.text);
|
|
224
|
+
process.exit(0);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
const timeout = opts.timeout === undefined ? UNATTENDED_TIMEOUT_SECONDS : Number(opts.timeout);
|
|
228
|
+
if (!Number.isInteger(timeout) || timeout <= 0)
|
|
229
|
+
failUsage(`--timeout must be a whole number of seconds`);
|
|
230
|
+
const ticket = await startTicket({
|
|
231
|
+
// One setup per agent, channel and environment: another agent's is its own business.
|
|
232
|
+
subject: `add:${kind}:${at.environment}:${target}`,
|
|
233
|
+
action: SETUP_ACTIONS[kind],
|
|
234
|
+
check: setupCheck(kind),
|
|
235
|
+
restart: at.rerun,
|
|
236
|
+
timeoutSeconds: timeout,
|
|
237
|
+
waitsFirst: false,
|
|
238
|
+
whenRunning: "replace",
|
|
239
|
+
command: {
|
|
240
|
+
file: process.execPath,
|
|
241
|
+
args: [
|
|
242
|
+
...process.execArgv,
|
|
243
|
+
process.argv[1],
|
|
244
|
+
"add",
|
|
245
|
+
kind,
|
|
246
|
+
target,
|
|
247
|
+
...(at.environment === "production" ? ["--env", "production"] : []),
|
|
248
|
+
...(opts.ingress === undefined ? [] : ["--ingress", opts.ingress]),
|
|
249
|
+
...(opts.replaceConfig ? ["--replace-config"] : []),
|
|
250
|
+
],
|
|
251
|
+
cwd: process.cwd(),
|
|
252
|
+
},
|
|
253
|
+
});
|
|
254
|
+
reportSetup(ticket, opts, "started");
|
|
255
|
+
process.exit(ticketExitCode(ticket));
|
|
256
|
+
}
|
|
257
|
+
/** `add <kind> --check <ticket>`. */
|
|
258
|
+
async function checkSetup(kind, id, opts) {
|
|
259
|
+
const refused = refusedCheck(id, setupCheck(kind));
|
|
260
|
+
if (refused !== undefined)
|
|
261
|
+
failUsage(refused);
|
|
262
|
+
// There: refusedCheck read it, and a ticket is pruned only a day after it ends.
|
|
263
|
+
const ticket = (await checkTicket(id));
|
|
264
|
+
reportSetup(ticket, opts, "checked");
|
|
265
|
+
process.exit(ticketExitCode(ticket));
|
|
266
|
+
}
|
|
267
|
+
/** An app's setup ticket for whoever started or checked it: the shared report, and what a finished setup adds. */
|
|
268
|
+
function reportSetup(ticket, opts, when) {
|
|
269
|
+
const { json, text } = ticketReport(ticket, when, (result) => {
|
|
270
|
+
const written = result.written ?? [];
|
|
271
|
+
const next = result.next_steps ?? [];
|
|
272
|
+
return {
|
|
273
|
+
fields: { written, next_steps: next },
|
|
274
|
+
text: [...(written.length > 0 ? [`wrote ${written.join(", ")}`] : []), ...next.map((line) => `next: ${line}`)],
|
|
275
|
+
next: `The app is set up. Its next steps are in next_steps.`,
|
|
276
|
+
};
|
|
277
|
+
});
|
|
278
|
+
printReport(opts.json, json, text);
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* What `add` sets the app up for, and whether it writes the choice down. `--ingress` is the `<PREFIX>_INGRESS`
|
|
282
|
+
* setting in the selected environment. The channel rule supplies its default: WebSocket in dev, webhook in production.
|
|
283
|
+
*/
|
|
284
|
+
function resolveIngress(kind, raw) {
|
|
124
285
|
if (raw !== undefined && raw !== "webhook" && raw !== "websocket") {
|
|
125
286
|
failUsage(`--ingress must be "webhook" or "websocket", got "${raw}"`);
|
|
126
287
|
}
|
|
127
|
-
const requested = raw;
|
|
128
288
|
if (kind !== "feishu" && kind !== "lark")
|
|
129
|
-
return "webhook";
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
144
|
-
if (requested && requested !== existing) {
|
|
145
|
-
failStartup(new Error(`${file} already selects ${existing} delivery — changing mode is a migration; edit the factory and platform subscription together`));
|
|
146
|
-
}
|
|
147
|
-
return existing;
|
|
148
|
-
}
|
|
149
|
-
if (requested)
|
|
150
|
-
return requested;
|
|
151
|
-
if (!(process.stdin.isTTY && process.stdout.isTTY)) {
|
|
152
|
-
console.error(`[fastagent] no interactive terminal — defaulting ${kind} ingress to webhook (use --ingress websocket)`);
|
|
153
|
-
return "webhook";
|
|
154
|
-
}
|
|
155
|
-
const answer = await select({
|
|
156
|
-
message: `How should ${kind === "feishu" ? "Feishu" : "Lark"} deliver events?`,
|
|
157
|
-
// The default must match the non-interactive branch above.
|
|
158
|
-
initialValue: "webhook",
|
|
159
|
-
options: [
|
|
160
|
-
{
|
|
161
|
-
value: "webhook",
|
|
162
|
-
label: "Webhook endpoint",
|
|
163
|
-
hint: "works on every deploy target; supports scale-to-zero; requires a public HTTPS URL",
|
|
164
|
-
},
|
|
165
|
-
{
|
|
166
|
-
value: "websocket",
|
|
167
|
-
label: "WebSocket long connection",
|
|
168
|
-
hint: "no public URL; needs an always-on process (not on AgentCore)",
|
|
169
|
-
},
|
|
170
|
-
],
|
|
171
|
-
});
|
|
172
|
-
if (isCancel(answer))
|
|
173
|
-
failStartup(new Error(`${kind} onboarding cancelled`));
|
|
174
|
-
return answer;
|
|
289
|
+
return { ingress: "webhook", pinned: false };
|
|
290
|
+
const name = `${cloudFor(kind).envPrefix}_INGRESS`;
|
|
291
|
+
if (raw !== undefined)
|
|
292
|
+
return { ingress: raw, pinned: true, setting: { [name]: raw } };
|
|
293
|
+
try {
|
|
294
|
+
return {
|
|
295
|
+
ingress: feishuIngressFor(kind, process.env),
|
|
296
|
+
pinned: Boolean(process.env[name]?.trim()),
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
catch (error) {
|
|
300
|
+
// A malformed value in the environment: the author's to fix, said as the rule says it.
|
|
301
|
+
return failUsage(error.message);
|
|
302
|
+
}
|
|
175
303
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
304
|
+
/**
|
|
305
|
+
* A setting only takes effect in a channel file that reads it: one that names its factory receives the same way
|
|
306
|
+
* whatever the setting says, so writing the setting (and configuring the app for it) would change nothing but the app.
|
|
307
|
+
* Asked of the channel as the agent builds it, under the value this command is about to write.
|
|
308
|
+
*/
|
|
309
|
+
async function assertChannelReadsSetting(target, kind, setting, shown) {
|
|
310
|
+
Object.assign(process.env, setting); // the value this command writes anyway
|
|
311
|
+
const channel = await prepareDefinition(target)
|
|
312
|
+
.then((definition) => buildDefinitionShape(definition, process.env).channels.get(kind))
|
|
313
|
+
.catch((error) => failStartup(new Error(`the agent does not build (${error.message}) — fix it and re-run`)));
|
|
314
|
+
const [[name, value]] = Object.entries(setting);
|
|
315
|
+
const wanted = value === "webhook" ? "webhook" : "long-connection";
|
|
316
|
+
const shape = channel === undefined ? undefined : channelIngress(channel);
|
|
317
|
+
if (shape !== wanted) {
|
|
318
|
+
failStartup(new Error(`${shown} receives by ${shape === "webhook" ? "webhook" : "WebSocket"} whatever ${name} says — it names ` +
|
|
319
|
+
`its factory instead of reading the setting, so ${name}=${value} would change nothing but the app. Move ` +
|
|
320
|
+
`the file aside and re-run to scaffold one that reads it, or edit its factory yourself`));
|
|
179
321
|
}
|
|
180
|
-
if (kind !== "feishu" && kind !== "lark" && kind !== "slack")
|
|
181
|
-
return { behavior: "context", explicit: false };
|
|
182
|
-
if (raw !== undefined)
|
|
183
|
-
return { behavior: raw, explicit: true };
|
|
184
|
-
const defaultBehavior = "context";
|
|
185
|
-
if (!(process.stdin.isTTY && process.stdout.isTTY)) {
|
|
186
|
-
console.error(`[fastagent] no interactive terminal — assuming ${kind} group behavior ${defaultBehavior}; pass --group-behavior explicitly to override`);
|
|
187
|
-
return { behavior: defaultBehavior, explicit: false };
|
|
188
|
-
}
|
|
189
|
-
const choices = [
|
|
190
|
-
{
|
|
191
|
-
value: "context",
|
|
192
|
-
label: "Context-aware groups (recommended)",
|
|
193
|
-
hint: kind === "slack"
|
|
194
|
-
? "bare replies in the Agent's threads + buffer; requires channel/group/mpim history scopes"
|
|
195
|
-
: "bare replies in the Agent's threads + buffer; im:message.group_msg delivers all group messages",
|
|
196
|
-
},
|
|
197
|
-
{
|
|
198
|
-
value: "mentions",
|
|
199
|
-
label: "Mention-only (least privilege)",
|
|
200
|
-
hint: "only explicit @Agent messages; no group-wide message permission",
|
|
201
|
-
},
|
|
202
|
-
];
|
|
203
|
-
const answer = await select({
|
|
204
|
-
message: "Choose group-chat behavior",
|
|
205
|
-
initialValue: defaultBehavior,
|
|
206
|
-
options: choices,
|
|
207
|
-
});
|
|
208
|
-
if (isCancel(answer))
|
|
209
|
-
failStartup(new Error(`${kind} onboarding cancelled`));
|
|
210
|
-
return { behavior: answer, explicit: true };
|
|
211
322
|
}
|
|
212
323
|
/** `fastagent add skill <source> [dir]`: vendor an Agent Skills skill into <dir>/skills/<name>/. */
|
|
213
324
|
export async function runAddSkill(source, dirArg, opts) {
|
|
214
|
-
const
|
|
325
|
+
const target = agentDirOrExit(resolve(dirArg));
|
|
215
326
|
if (!source) {
|
|
216
327
|
// A missing source is a usage error (exit 2), but the guide is worth more than a bare missing-argument line.
|
|
217
328
|
failUsage(`add a skill — two ways:\n` +
|
|
@@ -225,7 +336,7 @@ export async function runAddSkill(source, dirArg, opts) {
|
|
|
225
336
|
}
|
|
226
337
|
// Skills are agent surface — vendored into the agent dir's `skills/`.
|
|
227
338
|
enterAgentEnv(target); // a git-ref source is a network fetch (giget uses global fetch)
|
|
228
|
-
const { name, description, dest, hasScripts,
|
|
339
|
+
const { name, description, dest, hasScripts, overwritten } = await vendorSkill(target, source, {
|
|
229
340
|
update: opts.update ?? false,
|
|
230
341
|
}).catch(failStartup);
|
|
231
342
|
console.error(`[fastagent] ${overwritten ? "updated" : "vendored"} skill "${name}" → ${dest}/`);
|
|
@@ -233,10 +344,8 @@ export async function runAddSkill(source, dirArg, opts) {
|
|
|
233
344
|
console.error(` overwrote it — \`git diff ${dest}\` to review, \`git checkout ${dest}\` to revert`);
|
|
234
345
|
if (description)
|
|
235
346
|
console.error(` ${description.length > 100 ? `${description.slice(0, 100)}…` : description}`);
|
|
236
|
-
for (const d of diagnostics)
|
|
237
|
-
console.error(` warn: ${d.message}`);
|
|
238
347
|
if (hasScripts) {
|
|
239
348
|
console.error(` warn: this skill ships scripts/ (executable code that runs in your agent) — review it before deploying`);
|
|
240
349
|
}
|
|
241
|
-
console.error(` next: mention "${name}" in
|
|
350
|
+
console.error(` next: mention "${name}" in SYSTEM.md so the model knows when to use it; then \`fastagent dev\``);
|
|
242
351
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { enterAgentEnv } from "../../env.js";
|
|
2
|
+
import { modelEnvironment } from "../../harnesses/models/environment.js";
|
|
3
|
+
import { providerOf } from "../../harnesses/models/models.js";
|
|
4
|
+
import { definitionProviders } from "../../harnesses/pi-durable/open.js";
|
|
5
|
+
import { installProxyFetch } from "../../proxy.js";
|
|
6
|
+
import { failStartup, failUsage, optionalAgentDirOrExit } from "../fail.js";
|
|
7
|
+
const EXIT_CODES = { ready: 0, not_ready: 1, invalid: 2 };
|
|
8
|
+
export async function runAuthCheck(opts) {
|
|
9
|
+
if (opts.provider === undefined && opts.model === undefined) {
|
|
10
|
+
failUsage("auth check needs --provider <id> or --model <provider/modelId>");
|
|
11
|
+
}
|
|
12
|
+
const agentDir = opts.global ? undefined : optionalAgentDirOrExit(process.cwd());
|
|
13
|
+
let providers = [];
|
|
14
|
+
if (agentDir) {
|
|
15
|
+
enterAgentEnv(agentDir);
|
|
16
|
+
providers = await definitionProviders(agentDir).catch(failStartup);
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
installProxyFetch();
|
|
20
|
+
}
|
|
21
|
+
const environment = await modelEnvironment(agentDir, {}, providers);
|
|
22
|
+
let provider = opts.provider;
|
|
23
|
+
let modelId;
|
|
24
|
+
if (opts.model !== undefined) {
|
|
25
|
+
const ofModel = providerOf(opts.model);
|
|
26
|
+
modelId = opts.model.slice(ofModel.length + 1);
|
|
27
|
+
if (modelId === "" || environment.models.getModel(ofModel, modelId) === undefined) {
|
|
28
|
+
failUsage(`unknown model "${opts.model}": \`fastagent models\` lists the ones there are`);
|
|
29
|
+
}
|
|
30
|
+
if (provider !== undefined && provider !== ofModel)
|
|
31
|
+
failUsage(`${opts.model} is not a model of ${provider}`);
|
|
32
|
+
provider = ofModel;
|
|
33
|
+
}
|
|
34
|
+
const result = await check(environment, provider, modelId);
|
|
35
|
+
console.log(opts.json ? JSON.stringify(result) : result.status);
|
|
36
|
+
process.exitCode = EXIT_CODES[result.status];
|
|
37
|
+
}
|
|
38
|
+
async function check(environment, provider, modelId) {
|
|
39
|
+
if (environment.models.getProvider(provider) === undefined) {
|
|
40
|
+
return { status: "not_ready", provider, reason: "provider_not_found" };
|
|
41
|
+
}
|
|
42
|
+
const held = await environment.authStatus(provider, modelId);
|
|
43
|
+
const path = held.path === undefined ? {} : { path: held.path };
|
|
44
|
+
if (held.error !== undefined)
|
|
45
|
+
return { status: "invalid", provider, reason: "invalid_state", error: held.error, ...path };
|
|
46
|
+
if (held.source === undefined)
|
|
47
|
+
return { status: "not_ready", provider, reason: "credentials_not_configured", ...path };
|
|
48
|
+
const authType = held.source === "OAuth" ? "oauth" : "api_key";
|
|
49
|
+
return { status: "ready", provider, authType, source: held.source, ...path };
|
|
50
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type SourceOptions } from "../../content/source.ts";
|
|
2
|
+
/** A name refusal is the caller's to fix by naming another (exit 2); anything else is a startup failure (exit 1). */
|
|
3
|
+
export declare function failEdit(hint: string): (error: unknown) => never;
|
|
4
|
+
export declare function runContentList(dirArg: string, json: boolean): Promise<void>;
|
|
5
|
+
export declare function runContentAdd(source: string, dirArg: string, opts: SourceOptions): Promise<void>;
|
|
6
|
+
export declare function runContentRemove(name: string, dirArg: string): Promise<void>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `fastagent content list|add|remove`: what the agent works on and knows, as `context.json` declares it and
|
|
3
|
+
* `context.local.json` binds it on this machine.
|
|
4
|
+
*/
|
|
5
|
+
import { resolve } from "node:path";
|
|
6
|
+
import { ContentNameError, addContent, listContent, removeContent } from "../../authoring.js";
|
|
7
|
+
import { readContentSource } from "../../content/source.js";
|
|
8
|
+
import { contentLines } from "../content-view.js";
|
|
9
|
+
import { failStartup, failUsage } from "../fail.js";
|
|
10
|
+
/** A name refusal is the caller's to fix by naming another (exit 2); anything else is a startup failure (exit 1). */
|
|
11
|
+
export function failEdit(hint) {
|
|
12
|
+
return (error) => {
|
|
13
|
+
if (error instanceof ContentNameError)
|
|
14
|
+
failUsage(`${error.message}${hint}`);
|
|
15
|
+
failStartup(error);
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export async function runContentList(dirArg, json) {
|
|
19
|
+
const { content, absent } = await listContent(resolve(dirArg)).catch(failStartup);
|
|
20
|
+
if (json) {
|
|
21
|
+
console.log(JSON.stringify({ content, absent }, null, 2));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
for (const [label, value] of contentLines(content, absent))
|
|
25
|
+
console.log(`${`${label}:`.padEnd(10)} ${value}`);
|
|
26
|
+
}
|
|
27
|
+
export async function runContentAdd(source, dirArg, opts) {
|
|
28
|
+
const { addition, notes } = await Promise.resolve()
|
|
29
|
+
.then(() => readContentSource(source, process.cwd(), opts))
|
|
30
|
+
.catch(failStartup);
|
|
31
|
+
for (const note of notes)
|
|
32
|
+
console.error(`[fastagent] ${note}`);
|
|
33
|
+
const { name, content, notes: left } = await addContent(resolve(dirArg), addition).catch(failEdit(" — pass --name"));
|
|
34
|
+
const added = content.filter((entry) => entry.name === name);
|
|
35
|
+
for (const [label, value] of contentLines(added))
|
|
36
|
+
console.error(`[fastagent] ${label} ${value}`);
|
|
37
|
+
for (const note of left)
|
|
38
|
+
console.error(`[fastagent] ${note}`);
|
|
39
|
+
}
|
|
40
|
+
export async function runContentRemove(name, dirArg) {
|
|
41
|
+
const removed = await removeContent(resolve(dirArg), name).catch(failEdit(""));
|
|
42
|
+
console.error(`[fastagent] removed content ${removed.name}`);
|
|
43
|
+
for (const note of removed.notes)
|
|
44
|
+
console.error(`[fastagent] ${note}`);
|
|
45
|
+
}
|