@fastagent-sh/fastagent 0.24.4 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -82
- package/dist/agent-api.d.ts +460 -0
- package/dist/agent-api.js +209 -0
- package/dist/answer-text.d.ts +8 -0
- package/dist/answer-text.js +18 -0
- package/dist/atomic-write.d.ts +2 -2
- package/dist/atomic-write.js +2 -2
- package/dist/authoring.d.ts +81 -0
- package/dist/authoring.js +245 -0
- package/dist/channel.d.ts +29 -15
- package/dist/channel.js +4 -1
- package/dist/channels/agentcore-protocol.d.ts +36 -50
- package/dist/channels/agentcore-protocol.js +3 -3
- package/dist/channels/agentcore-service.d.ts +8 -18
- package/dist/channels/agentcore-service.js +108 -127
- package/dist/channels/agentcore.d.ts +8 -24
- package/dist/channels/agentcore.js +32 -65
- package/dist/channels/body.d.ts +0 -16
- package/dist/channels/body.js +0 -25
- package/dist/channels/busy.js +6 -1
- package/dist/channels/context.d.ts +4 -0
- package/dist/channels/context.js +35 -0
- package/dist/channels/discover.d.ts +18 -20
- package/dist/channels/discover.js +41 -99
- package/dist/channels/feishu/feishu-api.d.ts +54 -4
- package/dist/channels/feishu/feishu-api.js +192 -149
- package/dist/channels/feishu/feishu.d.ts +3 -0
- package/dist/channels/feishu/feishu.js +117 -106
- package/dist/channels/feishu/history.d.ts +55 -0
- package/dist/channels/feishu/history.js +199 -0
- package/dist/channels/feishu/invoke-turn.d.ts +13 -11
- package/dist/channels/feishu/invoke-turn.js +9 -10
- package/dist/channels/feishu/model.d.ts +2 -1
- package/dist/channels/feishu/normalize.js +100 -0
- package/dist/channels/feishu/preview.d.ts +2 -2
- package/dist/channels/feishu/register-webhook.d.ts +1 -0
- package/dist/channels/feishu/register-webhook.js +3 -2
- package/dist/channels/feishu/scaffold/channel.ts +65 -46
- package/dist/channels/feishu/scaffold/feishu-send.ts +38 -33
- package/dist/channels/feishu/scaffold/feishu-threads.ts +25 -0
- package/dist/channels/feishu/setup-mode.d.ts +45 -25
- package/dist/channels/feishu/setup-mode.js +74 -23
- package/dist/channels/feishu/shared-api.d.ts +24 -6
- package/dist/channels/feishu/shared-api.js +30 -24
- package/dist/channels/kit/context-buffer.d.ts +11 -2
- package/dist/channels/kit/context-buffer.js +7 -4
- package/dist/channels/kit/delivery.d.ts +19 -3
- package/dist/channels/kit/delivery.js +74 -15
- package/dist/channels/kit/event-stream.js +2 -1
- package/dist/channels/kit/invoke-turn-kit.d.ts +41 -41
- package/dist/channels/kit/invoke-turn-kit.js +62 -71
- package/dist/channels/kit/place-history.d.ts +107 -0
- package/dist/channels/kit/place-history.js +182 -0
- package/dist/channels/kit/preview-kit.d.ts +9 -5
- package/dist/channels/kit/preview-kit.js +36 -15
- package/dist/channels/kit/room-threads.d.ts +46 -0
- package/dist/channels/kit/room-threads.js +81 -0
- package/dist/channels/kit/seen.js +1 -1
- package/dist/channels/kit/stop-command.d.ts +6 -3
- package/dist/channels/kit/stop-command.js +20 -18
- package/dist/channels/kit/thread-fork.d.ts +17 -0
- package/dist/channels/kit/thread-fork.js +43 -0
- package/dist/channels/kit/thread-participants.js +1 -1
- package/dist/channels/kit/transport.d.ts +5 -0
- package/dist/channels/kit/transport.js +5 -0
- package/dist/channels/kit/turn-runner.d.ts +10 -9
- package/dist/channels/kit/turn-runner.js +17 -19
- package/dist/channels/kit/turn-store.d.ts +5 -4
- package/dist/channels/kit/turn-store.js +5 -5
- package/dist/channels/lark/lark.d.ts +3 -0
- package/dist/channels/lark/lark.js +5 -0
- package/dist/channels/lark/onboard.d.ts +5 -3
- package/dist/channels/lark/onboard.js +14 -14
- package/dist/channels/lark/scaffold/channel.ts +67 -44
- package/dist/channels/lark/scaffold/lark-send.ts +38 -33
- package/dist/channels/lark/scaffold/lark-threads.ts +25 -0
- package/dist/channels/respond.d.ts +0 -4
- package/dist/channels/respond.js +1 -1
- package/dist/channels/router.d.ts +18 -0
- package/dist/channels/router.js +68 -0
- package/dist/channels/serve.d.ts +5 -70
- package/dist/channels/serve.js +105 -287
- package/dist/channels/slack/history.d.ts +42 -0
- package/dist/channels/slack/history.js +282 -0
- package/dist/channels/slack/invoke-turn.d.ts +12 -5
- package/dist/channels/slack/invoke-turn.js +7 -5
- package/dist/channels/slack/manifest.d.ts +1 -4
- package/dist/channels/slack/manifest.js +22 -10
- package/dist/channels/slack/model.d.ts +2 -1
- package/dist/channels/slack/onboard.d.ts +0 -2
- package/dist/channels/slack/onboard.js +2 -4
- package/dist/channels/slack/onboarding-state.d.ts +0 -2
- package/dist/channels/slack/onboarding-state.js +0 -1
- package/dist/channels/slack/parse.d.ts +0 -5
- package/dist/channels/slack/parse.js +1 -16
- package/dist/channels/slack/preview.d.ts +2 -3
- package/dist/channels/slack/preview.js +78 -52
- package/dist/channels/slack/register-webhook.d.ts +1 -0
- package/dist/channels/slack/register-webhook.js +6 -5
- package/dist/channels/slack/scaffold/channel.ts +23 -24
- package/dist/channels/slack/scaffold/slack-send.ts +50 -43
- package/dist/channels/slack/scaffold/slack-threads.ts +29 -0
- package/dist/channels/slack/setup-server.d.ts +19 -0
- package/dist/channels/slack/setup-server.js +113 -11
- package/dist/channels/slack/shared-api.d.ts +15 -4
- package/dist/channels/slack/shared-api.js +19 -14
- package/dist/channels/slack/slack-api.d.ts +61 -2
- package/dist/channels/slack/slack-api.js +28 -5
- package/dist/channels/slack/slack.js +97 -52
- package/dist/channels/slack/welcomed.js +1 -1
- package/dist/channels/telegram/context-buffer.d.ts +6 -1
- package/dist/channels/telegram/context-buffer.js +19 -0
- package/dist/channels/telegram/invoke-turn.d.ts +8 -4
- package/dist/channels/telegram/invoke-turn.js +7 -7
- package/dist/channels/telegram/parse.d.ts +7 -2
- package/dist/channels/telegram/parse.js +7 -0
- package/dist/channels/telegram/preview.d.ts +2 -2
- package/dist/channels/telegram/register-webhook.d.ts +1 -0
- package/dist/channels/telegram/register-webhook.js +3 -2
- package/dist/channels/telegram/scaffold/channel.ts +27 -28
- package/dist/channels/telegram/scaffold/telegram-send.ts +61 -108
- package/dist/channels/telegram/shared-api.d.ts +34 -0
- package/dist/channels/telegram/shared-api.js +79 -0
- package/dist/channels/telegram/telegram-api.d.ts +15 -5
- package/dist/channels/telegram/telegram-api.js +10 -6
- package/dist/channels/telegram/telegram.js +27 -21
- package/dist/channels/telegram/turn-store.js +1 -1
- package/dist/channels/{kit/turn-queue.d.ts → turn-queue.d.ts} +2 -2
- package/dist/channels/{kit/turn-queue.js → turn-queue.js} +10 -10
- package/dist/cli/add-feishu.d.ts +42 -12
- package/dist/cli/add-feishu.js +177 -124
- package/dist/cli/add-slack.d.ts +8 -3
- package/dist/cli/add-slack.js +116 -64
- package/dist/cli/auth-view.d.ts +10 -3
- package/dist/cli/auth-view.js +8 -6
- package/dist/cli/box-login.d.ts +18 -7
- package/dist/cli/box-login.js +46 -12
- package/dist/cli/commands/add.d.ts +15 -4
- package/dist/cli/commands/add.js +253 -143
- package/dist/cli/commands/auth.d.ts +6 -0
- package/dist/cli/commands/auth.js +50 -0
- package/dist/cli/commands/content.d.ts +6 -0
- package/dist/cli/commands/content.js +45 -0
- package/dist/cli/commands/deploy/agentcore.js +50 -77
- package/dist/cli/commands/deploy/docker.js +38 -39
- package/dist/cli/commands/deploy/fly.js +21 -18
- package/dist/cli/commands/deploy/host-login.d.ts +26 -0
- package/dist/cli/commands/deploy/host-login.js +90 -0
- package/dist/cli/commands/deploy/railway.js +21 -26
- package/dist/cli/commands/deploy/shared.d.ts +45 -17
- package/dist/cli/commands/deploy/shared.js +34 -15
- package/dist/cli/commands/deploy.d.ts +0 -4
- package/dist/cli/commands/deploy.js +237 -50
- package/dist/cli/commands/destroy.js +8 -6
- package/dist/cli/commands/dev.d.ts +0 -2
- package/dist/cli/commands/dev.js +20 -19
- package/dist/cli/commands/env.d.ts +12 -0
- package/dist/cli/commands/env.js +191 -0
- package/dist/cli/commands/info.js +95 -156
- package/dist/cli/commands/init.d.ts +2 -2
- package/dist/cli/commands/init.js +35 -33
- package/dist/cli/commands/invoke.d.ts +6 -0
- package/dist/cli/commands/invoke.js +132 -16
- package/dist/cli/commands/login.d.ts +31 -2
- package/dist/cli/commands/login.js +416 -65
- package/dist/cli/commands/logout.d.ts +4 -0
- package/dist/cli/commands/logout.js +53 -0
- package/dist/cli/commands/logs.js +8 -6
- package/dist/cli/commands/models.d.ts +2 -1
- package/dist/cli/commands/models.js +39 -37
- package/dist/cli/commands/schedules.d.ts +21 -0
- package/dist/cli/commands/schedules.js +143 -0
- package/dist/cli/commands/start.d.ts +11 -10
- package/dist/cli/commands/start.js +35 -62
- package/dist/cli/content-view.d.ts +9 -0
- package/dist/cli/content-view.js +26 -0
- package/dist/cli/fail.d.ts +9 -12
- package/dist/cli/fail.js +17 -14
- package/dist/cli/invoke-stream.d.ts +12 -3
- package/dist/cli/invoke-stream.js +85 -23
- package/dist/cli/kernel.d.ts +9 -2
- package/dist/cli/kernel.js +15 -6
- package/dist/cli/login-relay.d.ts +6 -4
- package/dist/cli/login-relay.js +19 -7
- package/dist/cli/models-view.d.ts +5 -1
- package/dist/cli/models-view.js +1 -1
- package/dist/cli/person.d.ts +10 -0
- package/dist/cli/person.js +23 -0
- package/dist/cli/program.js +421 -203
- package/dist/cli/serve.d.ts +13 -63
- package/dist/cli/serve.js +31 -121
- package/dist/cli/shared.d.ts +21 -48
- package/dist/cli/shared.js +70 -89
- package/dist/cli/ticket.d.ts +136 -0
- package/dist/cli/ticket.js +476 -0
- package/dist/client.d.ts +7 -0
- package/dist/client.js +2 -0
- package/dist/content/declare.d.ts +70 -0
- package/dist/content/declare.js +163 -0
- package/dist/content/file.d.ts +32 -0
- package/dist/content/file.js +119 -0
- package/dist/content/git.d.ts +41 -0
- package/dist/content/git.js +220 -0
- package/dist/content/mount.d.ts +2 -0
- package/dist/content/mount.js +15 -0
- package/dist/content/resolve.d.ts +52 -0
- package/dist/content/resolve.js +151 -0
- package/dist/content/source.d.ts +27 -0
- package/dist/content/source.js +53 -0
- package/dist/conversation-sessions.d.ts +26 -0
- package/dist/conversation-sessions.js +99 -0
- package/dist/declared-secrets.d.ts +19 -37
- package/dist/declared-secrets.js +16 -58
- package/dist/deploy/agentcore/destroy.d.ts +3 -3
- package/dist/deploy/agentcore/destroy.js +46 -28
- package/dist/deploy/agentcore/forwarder.js +105 -22
- package/dist/deploy/agentcore/logs.js +1 -1
- package/dist/deploy/agentcore/plan.d.ts +10 -24
- package/dist/deploy/agentcore/plan.js +31 -135
- package/dist/deploy/agentcore/run.d.ts +1 -1
- package/dist/deploy/agentcore/run.js +8 -5
- package/dist/deploy/agentcore/shell.d.ts +1 -1
- package/dist/deploy/agentcore/shell.js +5 -5
- package/dist/deploy/api.d.ts +34 -0
- package/dist/deploy/api.js +50 -0
- package/dist/deploy/box-shell.d.ts +6 -0
- package/dist/deploy/box-shell.js +7 -0
- package/dist/deploy/build-context.d.ts +7 -5
- package/dist/deploy/build-context.js +41 -35
- package/dist/deploy/channel-ingress.d.ts +6 -1
- package/dist/deploy/channel-ingress.js +18 -5
- package/dist/deploy/container.d.ts +22 -9
- package/dist/deploy/container.js +96 -55
- package/dist/deploy/docker/plan.d.ts +3 -2
- package/dist/deploy/docker/plan.js +13 -14
- package/dist/deploy/docker/run.d.ts +2 -2
- package/dist/deploy/docker/run.js +8 -4
- package/dist/deploy/fly/plan.d.ts +1 -1
- package/dist/deploy/fly/plan.js +12 -21
- package/dist/deploy/fly/run.d.ts +10 -6
- package/dist/deploy/fly/run.js +11 -6
- package/dist/deploy/hosts.d.ts +2 -1
- package/dist/deploy/hosts.js +2 -1
- package/dist/deploy/preflight.d.ts +21 -23
- package/dist/deploy/preflight.js +223 -202
- package/dist/deploy/railway/plan.d.ts +8 -6
- package/dist/deploy/railway/plan.js +15 -58
- package/dist/deploy/railway/run.d.ts +8 -3
- package/dist/deploy/railway/run.js +12 -8
- package/dist/deploy/residency.d.ts +5 -11
- package/dist/deploy/residency.js +0 -6
- package/dist/deploy/runner.d.ts +1 -1
- package/dist/deploy/runner.js +1 -1
- package/dist/deploy/secrets.d.ts +16 -2
- package/dist/deploy/secrets.js +33 -6
- package/dist/deploy/workspace.d.ts +11 -6
- package/dist/deploy/workspace.js +55 -38
- package/dist/dev-supervisor.d.ts +11 -2
- package/dist/dev-supervisor.js +52 -27
- package/dist/effect-port.d.ts +4 -4
- package/dist/effect-port.js +4 -4
- package/dist/env.d.ts +0 -13
- package/dist/env.js +1 -44
- package/dist/environment/apt.d.ts +4 -0
- package/dist/environment/apt.js +32 -0
- package/dist/environment/declare.d.ts +59 -0
- package/dist/environment/declare.js +210 -0
- package/dist/environment/mise.d.ts +51 -0
- package/dist/environment/mise.js +272 -0
- package/dist/feishu.d.ts +2 -2
- package/dist/feishu.js +2 -2
- package/dist/git.d.ts +13 -0
- package/dist/git.js +55 -0
- package/dist/harnesses/models/catalog.d.ts +20 -0
- package/dist/harnesses/models/catalog.js +254 -0
- package/dist/{engines/pi/auth.d.ts → harnesses/models/credentials.d.ts} +3 -3
- package/dist/{engines/pi/auth.js → harnesses/models/credentials.js} +3 -3
- package/dist/harnesses/models/environment.d.ts +48 -0
- package/dist/harnesses/models/environment.js +88 -0
- package/dist/harnesses/models/host.d.ts +30 -0
- package/dist/harnesses/models/host.js +97 -0
- package/dist/{engines/pi → harnesses/models}/login.d.ts +66 -70
- package/dist/harnesses/models/login.js +439 -0
- package/dist/harnesses/models/models.d.ts +84 -0
- package/dist/harnesses/models/models.js +197 -0
- package/dist/harnesses/pi-durable/agent.d.ts +42 -0
- package/dist/harnesses/pi-durable/agent.js +581 -0
- package/dist/harnesses/pi-durable/defaults.d.ts +28 -0
- package/dist/harnesses/pi-durable/defaults.js +26 -0
- package/dist/harnesses/pi-durable/define.d.ts +77 -0
- package/dist/harnesses/pi-durable/define.js +28 -0
- package/dist/harnesses/pi-durable/entries.d.ts +32 -0
- package/dist/harnesses/pi-durable/entries.js +126 -0
- package/dist/harnesses/pi-durable/events.d.ts +25 -0
- package/dist/harnesses/pi-durable/events.js +238 -0
- package/dist/harnesses/pi-durable/ids.d.ts +16 -0
- package/dist/harnesses/pi-durable/ids.js +55 -0
- package/dist/harnesses/pi-durable/messages.d.ts +41 -0
- package/dist/harnesses/pi-durable/messages.js +116 -0
- package/dist/harnesses/pi-durable/open.d.ts +95 -0
- package/dist/harnesses/pi-durable/open.js +330 -0
- package/dist/harnesses/pi-durable/reads.d.ts +30 -0
- package/dist/harnesses/pi-durable/reads.js +94 -0
- package/dist/harnesses/pi-durable/registry.d.ts +18 -0
- package/dist/harnesses/pi-durable/registry.js +56 -0
- package/dist/harnesses/pi-durable/release.d.ts +13 -0
- package/dist/harnesses/pi-durable/release.js +40 -0
- package/dist/harnesses/pi-durable/serve.d.ts +90 -0
- package/dist/harnesses/pi-durable/serve.js +186 -0
- package/dist/harnesses/pi-durable/sessions.d.ts +27 -0
- package/dist/harnesses/pi-durable/sessions.js +47 -0
- package/dist/harnesses/pi-durable/storage.d.ts +4 -0
- package/dist/harnesses/pi-durable/storage.js +49 -0
- package/dist/harnesses/pi-durable/stream.d.ts +20 -0
- package/dist/harnesses/pi-durable/stream.js +221 -0
- package/dist/harnesses/pi-durable/text.d.ts +30 -0
- package/dist/harnesses/pi-durable/text.js +292 -0
- package/dist/harnesses/pi-durable/wake.d.ts +11 -0
- package/dist/harnesses/pi-durable/wake.js +90 -0
- package/dist/http/client.d.ts +6 -0
- package/dist/http/client.js +256 -0
- package/dist/http/contract.d.ts +541 -0
- package/dist/http/contract.js +179 -0
- package/dist/http/server.d.ts +34 -0
- package/dist/http/server.js +194 -0
- package/dist/index.d.ts +19 -4
- package/dist/index.js +13 -5
- package/dist/lark.d.ts +2 -2
- package/dist/lark.js +2 -2
- package/dist/locked-file.d.ts +17 -0
- package/dist/{engines/pi/locked-file.js → locked-file.js} +16 -10
- package/dist/once.d.ts +6 -0
- package/dist/once.js +23 -0
- package/dist/paths.d.ts +36 -52
- package/dist/paths.js +66 -182
- package/dist/runtime.d.ts +25 -2
- package/dist/runtime.js +27 -0
- package/dist/scaffold/add-channel.d.ts +14 -27
- package/dist/scaffold/add-channel.js +82 -180
- package/dist/scaffold/init.d.ts +17 -18
- package/dist/scaffold/init.js +87 -99
- package/dist/scaffold/templates/SYSTEM.md +12 -0
- package/dist/scaffold/templates/env.example +4 -10
- package/dist/scaffold/templates/fastagent.config.ts +21 -33
- package/dist/scaffold/templates/gitignore +8 -1
- package/dist/scaffold/templates/skills/writing-great-skills/SKILL.md +1 -2
- package/dist/scaffold/templates.d.ts +9 -4
- package/dist/scaffold/templates.js +7 -5
- package/dist/scaffold/vendor-skill.d.ts +1 -4
- package/dist/scaffold/vendor-skill.js +5 -6
- package/dist/schedule/cron.d.ts +13 -0
- package/dist/schedule/cron.js +52 -0
- package/dist/schedule/eventbridge-cron.d.ts +17 -0
- package/dist/schedule/eventbridge-cron.js +88 -0
- package/dist/schedule/schedule.d.ts +23 -0
- package/dist/schedule/schedule.js +34 -0
- package/dist/schedule/scheduler.d.ts +34 -33
- package/dist/schedule/scheduler.js +251 -137
- package/dist/schedule/state.d.ts +4 -14
- package/dist/schedule/state.js +7 -7
- package/dist/schedule/wake-alarm.d.ts +22 -2
- package/dist/schedule/wake-alarm.js +66 -20
- package/dist/schedule/wakeups.d.ts +16 -15
- package/dist/schedule/wakeups.js +47 -45
- package/dist/service.d.ts +56 -169
- package/dist/service.js +91 -187
- package/dist/serving-command.d.ts +10 -0
- package/dist/serving-command.js +16 -0
- package/dist/sign-in-api.d.ts +147 -0
- package/dist/sign-in-api.js +9 -0
- package/dist/slack.d.ts +1 -1
- package/dist/slack.js +1 -1
- package/dist/{channels/kit/state.js → state-file.js} +6 -6
- package/dist/telegram.d.ts +1 -0
- package/dist/telegram.js +1 -0
- package/dist/tunnel.d.ts +3 -0
- package/dist/tunnel.js +14 -5
- package/dist/value-file.d.ts +40 -0
- package/dist/value-file.js +164 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.js +14 -1
- package/package.json +18 -28
- package/dist/agent.d.ts +0 -106
- package/dist/agent.js +0 -21
- package/dist/channels/control.d.ts +0 -31
- package/dist/channels/control.js +0 -329
- package/dist/channels/define-channel.d.ts +0 -39
- package/dist/channels/define-channel.js +0 -9
- package/dist/channels/feishu/context-buffer.d.ts +0 -35
- package/dist/channels/feishu/context-buffer.js +0 -65
- package/dist/channels/feishu/scaffold/channel.websocket.ts +0 -31
- package/dist/channels/http.d.ts +0 -23
- package/dist/channels/http.js +0 -57
- package/dist/channels/lark/scaffold/channel.websocket.ts +0 -31
- package/dist/channels/slack/context-buffer.d.ts +0 -23
- package/dist/channels/slack/context-buffer.js +0 -37
- package/dist/channels/sse.d.ts +0 -4
- package/dist/channels/sse.js +0 -66
- package/dist/cli/commands/chat.d.ts +0 -3
- package/dist/cli/commands/chat.js +0 -14
- package/dist/cli/commands/routine-run.d.ts +0 -6
- package/dist/cli/commands/routine-run.js +0 -46
- package/dist/cli/commands/routine.d.ts +0 -25
- package/dist/cli/commands/routine.js +0 -122
- package/dist/cli/commands/tool.d.ts +0 -1
- package/dist/cli/commands/tool.js +0 -57
- package/dist/collect.d.ts +0 -63
- package/dist/collect.js +0 -90
- package/dist/core.d.ts +0 -13
- package/dist/core.js +0 -15
- package/dist/engines/pi/agent-models.d.ts +0 -83
- package/dist/engines/pi/agent-models.js +0 -120
- package/dist/engines/pi/agent-session-factory.d.ts +0 -121
- package/dist/engines/pi/agent-session-factory.js +0 -535
- package/dist/engines/pi/chat.d.ts +0 -3
- package/dist/engines/pi/chat.js +0 -8
- package/dist/engines/pi/config.d.ts +0 -71
- package/dist/engines/pi/config.js +0 -199
- package/dist/engines/pi/create.d.ts +0 -170
- package/dist/engines/pi/create.js +0 -343
- package/dist/engines/pi/definition.d.ts +0 -74
- package/dist/engines/pi/definition.js +0 -236
- package/dist/engines/pi/entry-images.d.ts +0 -14
- package/dist/engines/pi/entry-images.js +0 -23
- package/dist/engines/pi/invoke-session.d.ts +0 -18
- package/dist/engines/pi/invoke-session.js +0 -403
- package/dist/engines/pi/locked-file.d.ts +0 -9
- package/dist/engines/pi/login.js +0 -331
- package/dist/engines/pi/machine.d.ts +0 -53
- package/dist/engines/pi/machine.js +0 -137
- package/dist/engines/pi/models.d.ts +0 -200
- package/dist/engines/pi/models.js +0 -533
- package/dist/engines/pi/open.d.ts +0 -180
- package/dist/engines/pi/open.js +0 -270
- package/dist/engines/pi/openai-account-models.d.ts +0 -35
- package/dist/engines/pi/openai-account-models.js +0 -116
- package/dist/engines/pi/report.d.ts +0 -18
- package/dist/engines/pi/report.js +0 -59
- package/dist/engines/pi/retry-event.d.ts +0 -6
- package/dist/engines/pi/retry-event.js +0 -15
- package/dist/engines/pi/service.d.ts +0 -9
- package/dist/engines/pi/service.js +0 -14
- package/dist/engines/pi/session-builder.d.ts +0 -13
- package/dist/engines/pi/session-builder.js +0 -117
- package/dist/engines/pi/session-control.d.ts +0 -77
- package/dist/engines/pi/session-control.js +0 -908
- package/dist/engines/pi/session-effects.d.ts +0 -14
- package/dist/engines/pi/session-effects.js +0 -30
- package/dist/engines/pi/session-inheritance.d.ts +0 -21
- package/dist/engines/pi/session-inheritance.js +0 -204
- package/dist/engines/pi/session-markers.d.ts +0 -49
- package/dist/engines/pi/session-markers.js +0 -60
- package/dist/engines/pi/session-settings.d.ts +0 -67
- package/dist/engines/pi/session-settings.js +0 -119
- package/dist/engines/pi/session-store.d.ts +0 -69
- package/dist/engines/pi/session-store.js +0 -430
- package/dist/engines/pi/tool-context.d.ts +0 -45
- package/dist/engines/pi/tool-context.js +0 -31
- package/dist/engines/pi/tool.d.ts +0 -99
- package/dist/engines/pi/tool.js +0 -118
- package/dist/engines/pi/turn-kit.d.ts +0 -92
- package/dist/engines/pi/turn-kit.js +0 -288
- package/dist/engines/pi/wake-tool.d.ts +0 -9
- package/dist/engines/pi/wake-tool.js +0 -92
- package/dist/loader.d.ts +0 -41
- package/dist/loader.js +0 -116
- package/dist/node.d.ts +0 -3
- package/dist/node.js +0 -4
- package/dist/observe.d.ts +0 -6
- package/dist/observe.js +0 -47
- package/dist/pi.d.ts +0 -25
- package/dist/pi.js +0 -15
- package/dist/scaffold/templates/APPEND_SYSTEM.md +0 -12
- package/dist/scaffold/templates/tools/fetch-url.ts +0 -25
- package/dist/schedule/discover.d.ts +0 -17
- package/dist/schedule/discover.js +0 -61
- package/dist/schedule/routine.d.ts +0 -43
- package/dist/schedule/routine.js +0 -32
- package/dist/schedule/run.d.ts +0 -55
- package/dist/schedule/run.js +0 -146
- package/dist/secrets-gate.d.ts +0 -32
- package/dist/secrets-gate.js +0 -33
- package/dist/session-remote.d.ts +0 -47
- package/dist/session-remote.js +0 -460
- package/dist/session.d.ts +0 -466
- package/dist/session.js +0 -57
- /package/dist/{channels/kit/state.d.ts → state-file.d.ts} +0 -0
package/dist/cli/commands/add.js
CHANGED
|
@@ -1,51 +1,125 @@
|
|
|
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 { enterAgentEnv } from "../../env.js";
|
|
17
|
+
import { dotEnvPath, loadEnvValues } from "../../value-file.js";
|
|
18
|
+
import { selectAgentEnvironment, resolveStateRoot, SECRETS_DIRNAME, isUnderDir, displayPath } from "../../paths.js";
|
|
12
19
|
import { detectRuntime, readPackageJson } from "../../runtime.js";
|
|
13
20
|
import { appendChannelDotEnv, appendChannelEnv, assertChannelReady, channelExists, channelSetup, scaffoldChannel, scaffoldCompanionTools, } from "../../scaffold/add-channel.js";
|
|
14
21
|
import { vendorSkill } from "../../scaffold/vendor-skill.js";
|
|
15
|
-
import { failStartup, failUsage,
|
|
16
|
-
|
|
22
|
+
import { failStartup, failUsage, agentDirOrExit } from "../fail.js";
|
|
23
|
+
import { unprotectedSecretsNote } from "../../value-file.js";
|
|
24
|
+
/** Without a terminal, how long an app's setup stays open for the person to finish their part. */
|
|
25
|
+
const UNATTENDED_TIMEOUT_SECONDS = 900;
|
|
26
|
+
/** `fastagent add <kind> [dir]`: scaffold `src/channels/<kind>.ts`, the adapter configured with a starter policy. */
|
|
17
27
|
export async function runAddChannel(channelKind, dirArg, opts) {
|
|
18
|
-
|
|
19
|
-
|
|
28
|
+
if (opts.check !== undefined)
|
|
29
|
+
return checkSetup(channelKind, opts.check, opts);
|
|
30
|
+
if (opts.ticket !== undefined) {
|
|
31
|
+
// The process `startTicket` started: it takes the ticket before anything slow (the definition is built to plan),
|
|
32
|
+
// then does the whole `add`, its person the ticket's.
|
|
33
|
+
await runTicket(opts.ticket, async (step) => ({
|
|
34
|
+
...(await addChannel(channelKind, await planAdd(channelKind, dirArg, opts), opts, step.person)),
|
|
35
|
+
}));
|
|
36
|
+
process.exit(0);
|
|
37
|
+
}
|
|
38
|
+
const plan = await planAdd(channelKind, dirArg, opts);
|
|
39
|
+
const unattended = opts.input === false || opts.json === true || !isInteractive();
|
|
40
|
+
if (unattended && opts.onboard !== false && channelKind !== "telegram") {
|
|
41
|
+
return setUpUnattended(channelKind, opts, plan);
|
|
42
|
+
}
|
|
43
|
+
const added = await addChannel(channelKind, plan, opts, terminalPerson).catch(failStartup);
|
|
44
|
+
if (opts.json)
|
|
45
|
+
console.log(JSON.stringify({ status: "done", ...added }, null, 2));
|
|
46
|
+
// App-creation flows leave platform/tunnel sockets behind that would otherwise hold the one-shot scaffold command
|
|
47
|
+
// open after all durable boundaries have completed.
|
|
48
|
+
process.exit(0);
|
|
49
|
+
}
|
|
50
|
+
/** What `add` settles before it changes anything, refusing what it can while nothing has changed. */
|
|
51
|
+
async function planAdd(channelKind, dirArg, opts) {
|
|
52
|
+
// The channel (glue + companion tools + secrets) is agent surface: everything lands in the AGENT DIR.
|
|
20
53
|
if (opts.replaceConfig && opts.onboard === false) {
|
|
21
54
|
failUsage("--replace-config replaces onboarding credentials; it cannot be combined with --no-onboard");
|
|
22
55
|
}
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
56
|
+
const target = agentDirOrExit(resolve(dirArg));
|
|
57
|
+
const environment = opts.environment ?? "dev";
|
|
58
|
+
if (environment !== "dev" && environment !== "production") {
|
|
59
|
+
failUsage(`--env must be "dev" or "production", got "${environment}"`);
|
|
60
|
+
}
|
|
61
|
+
selectAgentEnvironment(environment);
|
|
62
|
+
if (environment === "production")
|
|
63
|
+
unmarkDevServe();
|
|
64
|
+
else
|
|
65
|
+
markDevServe();
|
|
66
|
+
enterAgentEnv(target);
|
|
67
|
+
if (environment === "production" && (channelKind === "feishu" || channelKind === "lark")) {
|
|
68
|
+
try {
|
|
69
|
+
assertIndependentFeishuApps(target, [channelKind], loadEnvValues(dotEnvPath(target)));
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
failStartup(error);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Paths are printed to someone standing in their CWD, which may be elsewhere, while every file belongs to the AGENT
|
|
26
76
|
// dir — prefix them, or they point at nothing.
|
|
27
77
|
const agentFromCwd = displayPath(process.cwd(), target);
|
|
28
78
|
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
79
|
// An existing channel file is authored glue: kept, never rewritten.
|
|
32
|
-
const file = join(target, "channels", `${channelKind}.ts`);
|
|
80
|
+
const file = join(target, "src", "channels", `${channelKind}.ts`);
|
|
33
81
|
const existsAlready = await channelExists(target, channelKind).catch(failStartup);
|
|
34
|
-
const ingress =
|
|
35
|
-
|
|
82
|
+
const ingress = resolveIngress(channelKind, opts.ingress);
|
|
83
|
+
if (existsAlready &&
|
|
84
|
+
(ingress.setting || (environment === "production" && opts.onboard !== false)) &&
|
|
85
|
+
(channelKind === "feishu" || channelKind === "lark")) {
|
|
86
|
+
await assertChannelReadsSetting(target, channelKind, ingress.setting ?? { [`${cloudFor(channelKind).envPrefix}_INGRESS`]: ingress.ingress }, inAgent(relative(target, file)));
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
target,
|
|
90
|
+
environment,
|
|
91
|
+
inAgent,
|
|
92
|
+
agentFromCwd,
|
|
93
|
+
file,
|
|
94
|
+
existsAlready,
|
|
95
|
+
...ingress,
|
|
96
|
+
rerun: `fastagent add ${channelKind}${agentFromCwd === undefined ? "" : ` ${shellArg(agentFromCwd)}`}` +
|
|
97
|
+
`${environment === "production" ? " --env production" : ""}${opts.ingress ? ` --ingress ${opts.ingress}` : ""}` +
|
|
98
|
+
`${opts.replaceConfig ? " --replace-config" : ""}`,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Everything `add <kind>` does once the person's part can be done: the channel, its tools and variables, the app's
|
|
103
|
+
* onboarding through `person`, and the next steps, printed and returned with the variables it wrote.
|
|
104
|
+
*/
|
|
105
|
+
async function addChannel(channelKind, plan, opts, person) {
|
|
106
|
+
const { target, environment, inAgent, agentFromCwd, file, existsAlready, ingress, pinned, setting, rerun } = plan;
|
|
107
|
+
const envPath = dotEnvPath(target);
|
|
108
|
+
const envLabel = isUnderDir(envPath, target) ? inAgent(relative(target, envPath)) : envPath;
|
|
109
|
+
const before = loadEnvValues(envPath);
|
|
36
110
|
if (existsAlready) {
|
|
37
|
-
console.error(`[fastagent] ${relative(target, file)} already exists — keeping it`);
|
|
111
|
+
console.error(`[fastagent] ${inAgent(relative(target, file))} already exists — keeping it`);
|
|
38
112
|
}
|
|
39
113
|
else {
|
|
40
|
-
await assertChannelReady(target)
|
|
41
|
-
await scaffoldChannel(target, channelKind
|
|
42
|
-
console.error(`[fastagent] created ${relative(target, file)}`);
|
|
114
|
+
await assertChannelReady(target);
|
|
115
|
+
await scaffoldChannel(target, channelKind);
|
|
116
|
+
console.error(`[fastagent] created ${inAgent(relative(target, file))}`);
|
|
43
117
|
}
|
|
44
118
|
// 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)}`);
|
|
119
|
+
for (const tool of await scaffoldCompanionTools(target, channelKind)) {
|
|
120
|
+
console.error(`[fastagent] wrote ${inAgent(relative(target, tool))}`);
|
|
47
121
|
}
|
|
48
|
-
if (await appendChannelEnv(target, channelKind
|
|
122
|
+
if (await appendChannelEnv(target, channelKind)) {
|
|
49
123
|
console.error(`[fastagent] added ${channelKind} env vars to ${inAgent(join(SECRETS_DIRNAME, ".env.example"))}`);
|
|
50
124
|
}
|
|
51
125
|
// Stateful app onboarding is re-runnable after the scaffold boundary.
|
|
@@ -55,163 +129,201 @@ export async function runAddChannel(channelKind, dirArg, opts) {
|
|
|
55
129
|
created = await onboardSlackInternalApp({
|
|
56
130
|
target,
|
|
57
131
|
stateRoot: resolveStateRoot(target),
|
|
58
|
-
groupBehavior,
|
|
59
132
|
replaceConfig: opts.replaceConfig,
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
.catch(failStartup);
|
|
133
|
+
...(person === terminalPerson ? {} : { person }),
|
|
134
|
+
}).then(() => undefined);
|
|
63
135
|
}
|
|
64
|
-
else if (channelKind === "feishu" || channelKind === "lark") {
|
|
65
|
-
created = await onboardFeishuCloudApp(target, channelKind, ingress,
|
|
136
|
+
else if ((channelKind === "feishu" || channelKind === "lark") && opts.onboard !== false) {
|
|
137
|
+
created = await onboardFeishuCloudApp(target, channelKind, ingress, rerun, person);
|
|
66
138
|
}
|
|
67
|
-
const setup = channelSetup(channelKind, ingress,
|
|
139
|
+
const setup = channelSetup(channelKind, ingress, pinned);
|
|
68
140
|
const env = setup.env;
|
|
69
141
|
const steps = channelKind === "slack" && opts.onboard !== false
|
|
70
142
|
? [
|
|
71
143
|
// No line about the Request URL: the `dev --tunnel` line below is the whole instruction, and FastAgent sets
|
|
72
144
|
// that URL itself when the agent first runs.
|
|
73
145
|
"invite the app to each channel it should read",
|
|
74
|
-
|
|
146
|
+
// The tool lines are the scaffold's (one list), whichever path set the app up.
|
|
147
|
+
...setup.steps.filter((step) => step.includes("{tools}/")),
|
|
75
148
|
]
|
|
76
149
|
: setup.steps;
|
|
77
150
|
const generated = Object.fromEntries(env.filter((e) => e.generate).map((e) => [e.name, randomBytes(24).toString("hex")]));
|
|
78
151
|
// Kind-neutral: every channel's generated secrets get the same treatment.
|
|
79
|
-
const dotEnv = await appendChannelDotEnv(target, channelKind, { ...generated, ...created }, Object.keys(created ?? {}),
|
|
152
|
+
const dotEnv = await appendChannelDotEnv(target, channelKind, { ...generated, ...created, ...setting }, [...Object.keys(created ?? {}), ...Object.keys(setting ?? {})], ingress);
|
|
80
153
|
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.`);
|
|
154
|
+
console.error(`[fastagent] note: ${unprotectedSecretsNote(dotEnv.unprotectedSecretsDir)}`);
|
|
84
155
|
}
|
|
85
156
|
if (dotEnv.written.length > 0) {
|
|
86
157
|
console.error(`[fastagent] wrote ${dotEnv.written.join(", ")} to ${envLabel}`);
|
|
87
158
|
}
|
|
88
|
-
const install = detectRuntime(target, await readPackageJson(target)
|
|
89
|
-
|
|
90
|
-
|
|
159
|
+
const install = detectRuntime(target, await readPackageJson(target)).runtime === "bun" ? "bun install" : "npm install";
|
|
160
|
+
const next = [];
|
|
161
|
+
/** One next step: printed, and returned for a caller that reads them as data. */
|
|
162
|
+
const step = (line) => {
|
|
163
|
+
next.push(line.trim());
|
|
164
|
+
console.error(` ${line}`);
|
|
165
|
+
};
|
|
91
166
|
console.error(` next steps:`);
|
|
92
|
-
|
|
167
|
+
step(`${agentFromCwd === undefined ? install : `(cd ${agentFromCwd} && ${install})`} # if @fastagent-sh/fastagent is not installed yet`);
|
|
168
|
+
// Onboarding writes some itself (an app's ID and secret, a bot token) before the write above: what this `add` wrote is
|
|
169
|
+
// what the file holds now and did not before.
|
|
170
|
+
const now = loadEnvValues(envPath);
|
|
171
|
+
const written = [...now.keys()].filter((name) => now.get(name) && now.get(name) !== before.get(name));
|
|
93
172
|
for (const e of env) {
|
|
94
|
-
if (dotEnv.alreadySet.includes(e.name))
|
|
95
|
-
continue; // the user already
|
|
96
|
-
if (
|
|
173
|
+
if (!written.includes(e.name) && dotEnv.alreadySet.includes(e.name))
|
|
174
|
+
continue; // the user's already: nothing to do
|
|
175
|
+
if (written.includes(e.name)) {
|
|
97
176
|
// Written, but its hint may still carry an action — keep the variable visible instead of silently absorbing it.
|
|
98
|
-
|
|
177
|
+
step(`${e.name} — ${e.generate ? "generated and " : ""}written to ${envLabel} # ${e.hint}`);
|
|
99
178
|
continue;
|
|
100
179
|
}
|
|
101
180
|
const value = e.generate ? `=${generated[e.name]}` : "";
|
|
102
181
|
const action = e.required ? "set" : "optionally set";
|
|
103
|
-
|
|
182
|
+
step(`${action} ${e.name}${value} in ${envLabel} # ${e.hint}`);
|
|
104
183
|
}
|
|
105
|
-
|
|
106
|
-
// resolve them to the real agent-dir-relative locations here.
|
|
184
|
+
const serveCommand = environment === "production" ? "fastagent start" : "fastagent dev";
|
|
107
185
|
for (const s of steps) {
|
|
108
|
-
|
|
186
|
+
step(s
|
|
187
|
+
.replace("{channel}", inAgent(relative(target, file)))
|
|
188
|
+
.replace("{tools}", inAgent(join("src", "tools")))
|
|
189
|
+
.replaceAll("{serve}", serveCommand));
|
|
109
190
|
}
|
|
110
|
-
if (
|
|
111
|
-
|
|
191
|
+
if (environment === "production") {
|
|
192
|
+
step(`fastagent deploy <host> --run # deploy with the production app and credentials`);
|
|
193
|
+
}
|
|
194
|
+
else if (ingress === "websocket") {
|
|
195
|
+
step(`fastagent dev # no public URL or tunnel required`);
|
|
112
196
|
}
|
|
113
197
|
else if (channelKind === "slack") {
|
|
114
|
-
|
|
198
|
+
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
199
|
}
|
|
116
200
|
else if (channelKind !== "lark") {
|
|
117
|
-
|
|
201
|
+
step(`fastagent dev --tunnel # serve locally + a public URL, auto-registering the webhook`);
|
|
118
202
|
}
|
|
119
|
-
|
|
120
|
-
// open after all durable boundaries have completed.
|
|
121
|
-
process.exit(0);
|
|
203
|
+
return { written, next_steps: next };
|
|
122
204
|
}
|
|
123
|
-
|
|
205
|
+
/** The command that reads an app's setup ticket, as every such ticket records it. */
|
|
206
|
+
const setupCheck = (kind) => `fastagent add ${kind} --check`;
|
|
207
|
+
/** What the person does for each kind's app, to follow "so they can". */
|
|
208
|
+
const SETUP_ACTIONS = {
|
|
209
|
+
slack: "set up the Slack app: paste a configuration token on the page, then click Allow in Slack",
|
|
210
|
+
feishu: "confirm the new Feishu app",
|
|
211
|
+
lark: "finish setting up the Lark app",
|
|
212
|
+
};
|
|
213
|
+
/**
|
|
214
|
+
* `add slack|feishu|lark` with no one at a terminal to ask, for a coding agent: what the person must provide first is
|
|
215
|
+
* named (Lark's app credentials, in the file the agent reads), never asked for in the agent's conversation; then the
|
|
216
|
+
* 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
|
|
217
|
+
* is done, or it is still working at it.
|
|
218
|
+
*/
|
|
219
|
+
async function setUpUnattended(kind, opts, at) {
|
|
220
|
+
const { target } = at;
|
|
221
|
+
if (kind === "lark") {
|
|
222
|
+
const needed = await larkCredentialsNeeded(target, at.rerun).catch(failStartup);
|
|
223
|
+
if (needed !== undefined) {
|
|
224
|
+
printReport(opts.json, needed.json, needed.text);
|
|
225
|
+
process.exit(0);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
const timeout = opts.timeout === undefined ? UNATTENDED_TIMEOUT_SECONDS : Number(opts.timeout);
|
|
229
|
+
if (!Number.isInteger(timeout) || timeout <= 0)
|
|
230
|
+
failUsage(`--timeout must be a whole number of seconds`);
|
|
231
|
+
const ticket = await startTicket({
|
|
232
|
+
// One setup per agent, channel and environment: another agent's is its own business.
|
|
233
|
+
subject: `add:${kind}:${at.environment}:${target}`,
|
|
234
|
+
action: SETUP_ACTIONS[kind],
|
|
235
|
+
check: setupCheck(kind),
|
|
236
|
+
restart: at.rerun,
|
|
237
|
+
timeoutSeconds: timeout,
|
|
238
|
+
waitsFirst: false,
|
|
239
|
+
whenRunning: "replace",
|
|
240
|
+
command: {
|
|
241
|
+
file: process.execPath,
|
|
242
|
+
args: [
|
|
243
|
+
...process.execArgv,
|
|
244
|
+
process.argv[1],
|
|
245
|
+
"add",
|
|
246
|
+
kind,
|
|
247
|
+
target,
|
|
248
|
+
...(at.environment === "production" ? ["--env", "production"] : []),
|
|
249
|
+
...(opts.ingress === undefined ? [] : ["--ingress", opts.ingress]),
|
|
250
|
+
...(opts.replaceConfig ? ["--replace-config"] : []),
|
|
251
|
+
],
|
|
252
|
+
cwd: process.cwd(),
|
|
253
|
+
},
|
|
254
|
+
});
|
|
255
|
+
reportSetup(ticket, opts, "started");
|
|
256
|
+
process.exit(ticketExitCode(ticket));
|
|
257
|
+
}
|
|
258
|
+
/** `add <kind> --check <ticket>`. */
|
|
259
|
+
async function checkSetup(kind, id, opts) {
|
|
260
|
+
const refused = refusedCheck(id, setupCheck(kind));
|
|
261
|
+
if (refused !== undefined)
|
|
262
|
+
failUsage(refused);
|
|
263
|
+
// There: refusedCheck read it, and a ticket is pruned only a day after it ends.
|
|
264
|
+
const ticket = (await checkTicket(id));
|
|
265
|
+
reportSetup(ticket, opts, "checked");
|
|
266
|
+
process.exit(ticketExitCode(ticket));
|
|
267
|
+
}
|
|
268
|
+
/** An app's setup ticket for whoever started or checked it: the shared report, and what a finished setup adds. */
|
|
269
|
+
function reportSetup(ticket, opts, when) {
|
|
270
|
+
const { json, text } = ticketReport(ticket, when, (result) => {
|
|
271
|
+
const written = result.written ?? [];
|
|
272
|
+
const next = result.next_steps ?? [];
|
|
273
|
+
return {
|
|
274
|
+
fields: { written, next_steps: next },
|
|
275
|
+
text: [...(written.length > 0 ? [`wrote ${written.join(", ")}`] : []), ...next.map((line) => `next: ${line}`)],
|
|
276
|
+
next: `The app is set up. Its next steps are in next_steps.`,
|
|
277
|
+
};
|
|
278
|
+
});
|
|
279
|
+
printReport(opts.json, json, text);
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* What `add` sets the app up for, and whether it writes the choice down. `--ingress` is the `<PREFIX>_INGRESS`
|
|
283
|
+
* setting in the selected environment. The channel rule supplies its default: WebSocket in dev, webhook in production.
|
|
284
|
+
*/
|
|
285
|
+
function resolveIngress(kind, raw) {
|
|
124
286
|
if (raw !== undefined && raw !== "webhook" && raw !== "websocket") {
|
|
125
287
|
failUsage(`--ingress must be "webhook" or "websocket", got "${raw}"`);
|
|
126
288
|
}
|
|
127
|
-
const requested = raw;
|
|
128
289
|
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;
|
|
290
|
+
return { ingress: "webhook", pinned: false };
|
|
291
|
+
const name = `${cloudFor(kind).envPrefix}_INGRESS`;
|
|
292
|
+
if (raw !== undefined)
|
|
293
|
+
return { ingress: raw, pinned: true, setting: { [name]: raw } };
|
|
294
|
+
try {
|
|
295
|
+
return {
|
|
296
|
+
ingress: feishuIngressFor(kind, process.env),
|
|
297
|
+
pinned: Boolean(process.env[name]?.trim()),
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
catch (error) {
|
|
301
|
+
// A malformed value in the environment: the author's to fix, said as the rule says it.
|
|
302
|
+
return failUsage(error.message);
|
|
303
|
+
}
|
|
175
304
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
305
|
+
/**
|
|
306
|
+
* A setting only takes effect in a channel file that reads it: one that names its factory receives the same way
|
|
307
|
+
* whatever the setting says, so writing the setting (and configuring the app for it) would change nothing but the app.
|
|
308
|
+
* Asked of the channel as the agent builds it, under the value this command is about to write.
|
|
309
|
+
*/
|
|
310
|
+
async function assertChannelReadsSetting(target, kind, setting, shown) {
|
|
311
|
+
Object.assign(process.env, setting); // the value this command writes anyway
|
|
312
|
+
const channel = await prepareDefinition(target)
|
|
313
|
+
.then((definition) => buildDefinitionShape(definition, process.env).channels.get(kind))
|
|
314
|
+
.catch((error) => failStartup(new Error(`the agent does not build (${error.message}) — fix it and re-run`)));
|
|
315
|
+
const [[name, value]] = Object.entries(setting);
|
|
316
|
+
const wanted = value === "webhook" ? "webhook" : "long-connection";
|
|
317
|
+
const shape = channel === undefined ? undefined : channelIngress(channel);
|
|
318
|
+
if (shape !== wanted) {
|
|
319
|
+
failStartup(new Error(`${shown} receives by ${shape === "webhook" ? "webhook" : "WebSocket"} whatever ${name} says — it names ` +
|
|
320
|
+
`its factory instead of reading the setting, so ${name}=${value} would change nothing but the app. Move ` +
|
|
321
|
+
`the file aside and re-run to scaffold one that reads it, or edit its factory yourself`));
|
|
179
322
|
}
|
|
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
323
|
}
|
|
212
324
|
/** `fastagent add skill <source> [dir]`: vendor an Agent Skills skill into <dir>/skills/<name>/. */
|
|
213
325
|
export async function runAddSkill(source, dirArg, opts) {
|
|
214
|
-
const
|
|
326
|
+
const target = agentDirOrExit(resolve(dirArg));
|
|
215
327
|
if (!source) {
|
|
216
328
|
// A missing source is a usage error (exit 2), but the guide is worth more than a bare missing-argument line.
|
|
217
329
|
failUsage(`add a skill — two ways:\n` +
|
|
@@ -225,7 +337,7 @@ export async function runAddSkill(source, dirArg, opts) {
|
|
|
225
337
|
}
|
|
226
338
|
// Skills are agent surface — vendored into the agent dir's `skills/`.
|
|
227
339
|
enterAgentEnv(target); // a git-ref source is a network fetch (giget uses global fetch)
|
|
228
|
-
const { name, description, dest, hasScripts,
|
|
340
|
+
const { name, description, dest, hasScripts, overwritten } = await vendorSkill(target, source, {
|
|
229
341
|
update: opts.update ?? false,
|
|
230
342
|
}).catch(failStartup);
|
|
231
343
|
console.error(`[fastagent] ${overwritten ? "updated" : "vendored"} skill "${name}" → ${dest}/`);
|
|
@@ -233,10 +345,8 @@ export async function runAddSkill(source, dirArg, opts) {
|
|
|
233
345
|
console.error(` overwrote it — \`git diff ${dest}\` to review, \`git checkout ${dest}\` to revert`);
|
|
234
346
|
if (description)
|
|
235
347
|
console.error(` ${description.length > 100 ? `${description.slice(0, 100)}…` : description}`);
|
|
236
|
-
for (const d of diagnostics)
|
|
237
|
-
console.error(` warn: ${d.message}`);
|
|
238
348
|
if (hasScripts) {
|
|
239
349
|
console.error(` warn: this skill ships scripts/ (executable code that runs in your agent) — review it before deploying`);
|
|
240
350
|
}
|
|
241
|
-
console.error(` next: mention "${name}" in
|
|
351
|
+
console.error(` next: mention "${name}" in SYSTEM.md so the model knows when to use it; then \`fastagent dev\``);
|
|
242
352
|
}
|
|
@@ -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
|
+
}
|