@fastagent-sh/fastagent 0.21.1 → 0.22.1
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 +9 -12
- package/dist/agent.d.ts +24 -37
- package/dist/agent.js +7 -15
- package/dist/atomic-write.d.ts +13 -17
- package/dist/atomic-write.js +18 -29
- package/dist/bind.d.ts +12 -22
- package/dist/bind.js +18 -27
- package/dist/channel.d.ts +11 -33
- package/dist/channels/agentcore-limits.d.ts +2 -13
- package/dist/channels/agentcore-limits.js +2 -13
- package/dist/channels/agentcore-protocol.d.ts +67 -58
- package/dist/channels/agentcore-protocol.js +23 -15
- package/dist/channels/agentcore-service.d.ts +19 -33
- package/dist/channels/agentcore-service.js +176 -59
- package/dist/channels/agentcore.d.ts +39 -33
- package/dist/channels/agentcore.js +90 -224
- package/dist/channels/body.d.ts +15 -2
- package/dist/channels/body.js +24 -2
- package/dist/channels/busy.d.ts +1 -21
- package/dist/channels/busy.js +2 -39
- package/dist/channels/control.d.ts +17 -62
- package/dist/channels/control.js +74 -182
- package/dist/channels/define-channel.d.ts +39 -0
- package/dist/channels/define-channel.js +9 -0
- package/dist/channels/discover.d.ts +10 -31
- package/dist/channels/discover.js +37 -31
- package/dist/channels/feishu/bootstrap-token.d.ts +1 -8
- package/dist/channels/feishu/bootstrap-token.js +7 -23
- package/dist/channels/feishu/card.d.ts +14 -28
- package/dist/channels/feishu/card.js +16 -30
- package/dist/channels/feishu/cloud.d.ts +1 -5
- package/dist/channels/feishu/context-buffer.d.ts +4 -23
- package/dist/channels/feishu/context-buffer.js +8 -31
- package/dist/channels/feishu/crypto.d.ts +10 -5
- package/dist/channels/feishu/crypto.js +12 -19
- package/dist/channels/feishu/feishu-api.d.ts +2 -1
- package/dist/channels/feishu/feishu-api.js +5 -4
- package/dist/channels/feishu/feishu.d.ts +4 -10
- package/dist/channels/feishu/feishu.js +113 -227
- package/dist/channels/feishu/invoke-turn.d.ts +5 -4
- package/dist/channels/feishu/invoke-turn.js +36 -54
- package/dist/channels/feishu/model.d.ts +4 -21
- package/dist/channels/feishu/model.js +1 -8
- package/dist/channels/feishu/normalize.d.ts +2 -10
- package/dist/channels/feishu/normalize.js +7 -42
- package/dist/channels/feishu/parse.d.ts +9 -29
- package/dist/channels/feishu/parse.js +8 -26
- package/dist/channels/feishu/preview.d.ts +12 -14
- package/dist/channels/feishu/preview.js +108 -207
- package/dist/channels/feishu/register-app.d.ts +8 -23
- package/dist/channels/feishu/register-app.js +7 -20
- package/dist/channels/feishu/register-webhook.d.ts +2 -9
- package/dist/channels/feishu/register-webhook.js +9 -33
- package/dist/channels/feishu/scaffold/channel.ts +27 -19
- package/dist/channels/feishu/scaffold/channel.websocket.ts +31 -0
- package/dist/channels/feishu/setup-mode.d.ts +11 -36
- package/dist/channels/feishu/setup-mode.js +7 -26
- package/dist/channels/feishu/ws-ingress.d.ts +1 -2
- package/dist/channels/feishu/ws-ingress.js +6 -8
- package/dist/channels/http.d.ts +15 -15
- package/dist/channels/http.js +19 -9
- package/dist/channels/kit/attachment-path.d.ts +4 -5
- package/dist/channels/kit/attachment-path.js +10 -34
- package/dist/channels/kit/context-buffer.d.ts +14 -21
- package/dist/channels/kit/context-buffer.js +25 -38
- package/dist/channels/kit/delivery.d.ts +35 -0
- package/dist/channels/kit/delivery.js +129 -0
- package/dist/channels/kit/event-stream.d.ts +5 -0
- package/dist/channels/kit/event-stream.js +29 -0
- package/dist/channels/kit/invoke-turn-kit.d.ts +53 -26
- package/dist/channels/kit/invoke-turn-kit.js +89 -32
- package/dist/channels/kit/preview-kit.d.ts +18 -72
- package/dist/channels/kit/preview-kit.js +22 -88
- package/dist/channels/kit/signature.d.ts +3 -9
- package/dist/channels/kit/signature.js +3 -9
- package/dist/channels/kit/state.d.ts +1 -2
- package/dist/channels/kit/state.js +5 -14
- package/dist/channels/kit/stop-command.d.ts +1 -2
- package/dist/channels/kit/stop-command.js +6 -9
- package/dist/channels/kit/tasks.d.ts +1 -1
- package/dist/channels/kit/tasks.js +8 -21
- package/dist/channels/kit/text.d.ts +2 -16
- package/dist/channels/kit/text.js +23 -31
- package/dist/channels/kit/thread-participants.d.ts +4 -17
- package/dist/channels/kit/thread-participants.js +8 -55
- package/dist/channels/kit/transport.d.ts +26 -0
- package/dist/channels/kit/transport.js +20 -0
- package/dist/channels/kit/turn-queue.d.ts +7 -11
- package/dist/channels/kit/turn-queue.js +21 -39
- package/dist/channels/kit/turn-runner.d.ts +32 -18
- package/dist/channels/kit/turn-runner.js +98 -53
- package/dist/channels/kit/turn-store.d.ts +32 -32
- package/dist/channels/kit/turn-store.js +45 -88
- package/dist/channels/lark/lark.d.ts +1 -5
- package/dist/channels/lark/onboard.d.ts +3 -12
- package/dist/channels/lark/onboard.js +3 -13
- package/dist/channels/lark/scaffold/channel.ts +27 -19
- package/dist/channels/lark/scaffold/channel.websocket.ts +31 -0
- package/dist/channels/registration.d.ts +9 -35
- package/dist/channels/registration.js +6 -37
- package/dist/channels/secret.js +2 -5
- package/dist/channels/serve.d.ts +47 -44
- package/dist/channels/serve.js +165 -101
- package/dist/channels/slack/config-api.d.ts +4 -27
- package/dist/channels/slack/config-api.js +5 -34
- package/dist/channels/slack/context-buffer.d.ts +2 -3
- package/dist/channels/slack/context-buffer.js +5 -5
- package/dist/channels/slack/invoke-turn.d.ts +3 -1
- package/dist/channels/slack/invoke-turn.js +25 -34
- package/dist/channels/slack/manifest.js +1 -3
- package/dist/channels/slack/model.d.ts +1 -2
- package/dist/channels/slack/model.js +1 -1
- package/dist/channels/slack/onboard.d.ts +4 -3
- package/dist/channels/slack/onboard.js +8 -11
- package/dist/channels/slack/onboarding-state.d.ts +3 -5
- package/dist/channels/slack/onboarding-state.js +9 -6
- package/dist/channels/slack/parse.d.ts +4 -13
- package/dist/channels/slack/parse.js +7 -28
- package/dist/channels/slack/preview.d.ts +12 -2
- package/dist/channels/slack/preview.js +292 -269
- package/dist/channels/slack/reaction.d.ts +11 -3
- package/dist/channels/slack/reaction.js +19 -8
- package/dist/channels/slack/register-webhook.js +4 -7
- package/dist/channels/slack/scaffold/channel.ts +20 -13
- package/dist/channels/slack/scaffold/slack-send.ts +2 -2
- package/dist/channels/slack/setup-server.d.ts +1 -5
- package/dist/channels/slack/setup-server.js +1 -5
- package/dist/channels/slack/shared-api.d.ts +1 -4
- package/dist/channels/slack/shared-api.js +2 -13
- package/dist/channels/slack/slack-api.d.ts +2 -1
- package/dist/channels/slack/slack-api.js +6 -4
- package/dist/channels/slack/slack.d.ts +11 -14
- package/dist/channels/slack/slack.js +121 -122
- package/dist/channels/sse.d.ts +1 -1
- package/dist/channels/sse.js +1 -1
- package/dist/channels/telegram/context-buffer.d.ts +7 -22
- package/dist/channels/telegram/context-buffer.js +6 -23
- package/dist/channels/telegram/invoke-turn.d.ts +7 -7
- package/dist/channels/telegram/invoke-turn.js +24 -43
- package/dist/channels/telegram/parse.d.ts +24 -51
- package/dist/channels/telegram/parse.js +32 -84
- package/dist/channels/telegram/preview.d.ts +10 -1
- package/dist/channels/telegram/preview.js +79 -100
- package/dist/channels/telegram/register-webhook.js +5 -23
- package/dist/channels/telegram/scaffold/channel.ts +25 -18
- package/dist/channels/telegram/scaffold/telegram-send.ts +6 -4
- package/dist/channels/telegram/telegram-api.d.ts +4 -3
- package/dist/channels/telegram/telegram-api.js +9 -7
- package/dist/channels/telegram/telegram.d.ts +4 -18
- package/dist/channels/telegram/telegram.js +38 -94
- package/dist/channels/telegram/turn-store.d.ts +11 -14
- package/dist/channels/telegram/turn-store.js +8 -6
- package/dist/channels/wait-health.d.ts +4 -6
- package/dist/channels/wait-health.js +10 -14
- package/dist/cli/add-feishu.d.ts +2 -12
- package/dist/cli/add-feishu.js +24 -71
- package/dist/cli/add-slack.d.ts +5 -3
- package/dist/cli/add-slack.js +53 -76
- package/dist/cli/auth-view.d.ts +2 -16
- package/dist/cli/auth-view.js +2 -16
- package/dist/cli/commands/add.js +25 -40
- package/dist/cli/commands/chat.d.ts +0 -1
- package/dist/cli/commands/chat.js +5 -6
- package/dist/cli/commands/deploy/agentcore.js +60 -65
- package/dist/cli/commands/deploy/docker.js +50 -23
- package/dist/cli/commands/deploy/fly.js +23 -61
- package/dist/cli/commands/deploy/railway.js +23 -18
- package/dist/cli/commands/deploy/shared.d.ts +38 -57
- package/dist/cli/commands/deploy/shared.js +40 -59
- package/dist/cli/commands/deploy.d.ts +10 -27
- package/dist/cli/commands/deploy.js +38 -60
- package/dist/cli/commands/destroy.d.ts +4 -0
- package/dist/cli/commands/destroy.js +56 -0
- package/dist/cli/commands/dev.d.ts +2 -1
- package/dist/cli/commands/dev.js +20 -23
- package/dist/cli/commands/info.d.ts +0 -2
- package/dist/cli/commands/info.js +83 -49
- package/dist/cli/commands/init.d.ts +1 -2
- package/dist/cli/commands/init.js +16 -55
- package/dist/cli/commands/invoke.d.ts +0 -1
- package/dist/cli/commands/invoke.js +5 -7
- package/dist/cli/commands/login.d.ts +2 -1
- package/dist/cli/commands/login.js +33 -38
- package/dist/cli/commands/logs.js +3 -4
- package/dist/cli/commands/models.js +1 -5
- package/dist/cli/commands/routine-run.d.ts +6 -0
- package/dist/cli/commands/routine-run.js +47 -0
- package/dist/cli/commands/routine.d.ts +25 -0
- package/dist/cli/commands/routine.js +122 -0
- package/dist/cli/commands/start.d.ts +31 -3
- package/dist/cli/commands/start.js +131 -81
- package/dist/cli/commands/tool.js +26 -12
- package/dist/cli/fail.d.ts +13 -23
- package/dist/cli/fail.js +20 -23
- package/dist/cli/invoke-stream.d.ts +1 -8
- package/dist/cli/kernel.d.ts +6 -38
- package/dist/cli/kernel.js +14 -77
- package/dist/cli/models-view.d.ts +1 -9
- package/dist/cli/models-view.js +11 -22
- package/dist/cli/program.d.ts +5 -6
- package/dist/cli/program.js +120 -157
- package/dist/cli/serve.d.ts +57 -41
- package/dist/cli/serve.js +94 -121
- package/dist/cli/shared.d.ts +15 -61
- package/dist/cli/shared.js +55 -181
- package/dist/cli.js +1 -8
- package/dist/collect.d.ts +6 -0
- package/dist/collect.js +6 -0
- package/dist/core.d.ts +4 -1
- package/dist/core.js +9 -7
- package/dist/declared-secrets.d.ts +55 -0
- package/dist/declared-secrets.js +88 -0
- package/dist/deploy/agentcore/aws-cli.d.ts +91 -0
- package/dist/deploy/agentcore/aws-cli.js +64 -0
- package/dist/deploy/agentcore/destroy.d.ts +51 -0
- package/dist/deploy/agentcore/destroy.js +273 -0
- package/dist/deploy/agentcore/forwarder.js +28 -79
- package/dist/deploy/agentcore/logs.d.ts +2 -18
- package/dist/deploy/agentcore/logs.js +27 -51
- package/dist/deploy/agentcore/plan.d.ts +85 -105
- package/dist/deploy/agentcore/plan.js +152 -314
- package/dist/deploy/agentcore/run.d.ts +28 -28
- package/dist/deploy/agentcore/run.js +227 -306
- package/dist/deploy/agentcore/zip.d.ts +2 -15
- package/dist/deploy/agentcore/zip.js +3 -17
- package/dist/deploy/build-context.d.ts +21 -0
- package/dist/deploy/build-context.js +137 -0
- package/dist/deploy/channel-ingress.d.ts +26 -39
- package/dist/deploy/channel-ingress.js +57 -28
- package/dist/deploy/container.d.ts +20 -34
- package/dist/deploy/container.js +49 -100
- package/dist/deploy/docker/plan.d.ts +12 -11
- package/dist/deploy/docker/plan.js +43 -24
- package/dist/deploy/docker/run.d.ts +22 -25
- package/dist/deploy/docker/run.js +39 -37
- package/dist/deploy/fly/plan.d.ts +15 -44
- package/dist/deploy/fly/plan.js +41 -73
- package/dist/deploy/fly/run.d.ts +16 -51
- package/dist/deploy/fly/run.js +42 -95
- package/dist/deploy/hosts.d.ts +24 -3
- package/dist/deploy/hosts.js +24 -3
- package/dist/deploy/preflight.d.ts +47 -41
- package/dist/deploy/preflight.js +282 -383
- package/dist/deploy/railway/plan.d.ts +16 -42
- package/dist/deploy/railway/plan.js +42 -60
- package/dist/deploy/railway/run.d.ts +30 -68
- package/dist/deploy/railway/run.js +86 -100
- package/dist/deploy/registration-gate.d.ts +6 -13
- package/dist/deploy/residency.d.ts +37 -0
- package/dist/deploy/residency.js +24 -0
- package/dist/deploy/runner.d.ts +10 -9
- package/dist/deploy/runner.js +7 -18
- package/dist/deploy/secrets.d.ts +40 -41
- package/dist/deploy/secrets.js +117 -103
- package/dist/deploy/workspace.d.ts +50 -0
- package/dist/deploy/workspace.js +197 -0
- package/dist/dev-supervisor.d.ts +1 -9
- package/dist/dev-supervisor.js +21 -64
- package/dist/effect-port.d.ts +50 -0
- package/dist/effect-port.js +77 -0
- package/dist/engines/pi/agent-session-factory.d.ts +50 -69
- package/dist/engines/pi/agent-session-factory.js +249 -146
- package/dist/engines/pi/auth.d.ts +15 -11
- package/dist/engines/pi/auth.js +96 -99
- package/dist/engines/pi/chat.d.ts +1 -5
- package/dist/engines/pi/chat.js +2 -14
- package/dist/engines/pi/config.d.ts +53 -51
- package/dist/engines/pi/config.js +83 -92
- package/dist/engines/pi/create.d.ts +60 -75
- package/dist/engines/pi/create.js +108 -141
- package/dist/engines/pi/definition.d.ts +14 -58
- package/dist/engines/pi/definition.js +21 -85
- package/dist/engines/pi/invoke-session.d.ts +5 -25
- package/dist/engines/pi/invoke-session.js +233 -244
- package/dist/engines/pi/login.d.ts +95 -35
- package/dist/engines/pi/login.js +259 -107
- package/dist/engines/pi/machine.d.ts +31 -0
- package/dist/engines/pi/machine.js +106 -0
- package/dist/engines/pi/models.d.ts +70 -89
- package/dist/engines/pi/models.js +188 -81
- package/dist/engines/pi/open.d.ts +65 -53
- package/dist/engines/pi/open.js +129 -69
- package/dist/engines/pi/report.d.ts +3 -12
- package/dist/engines/pi/report.js +2 -16
- package/dist/engines/pi/search-tools.d.ts +1 -9
- package/dist/engines/pi/search-tools.js +26 -57
- package/dist/engines/pi/service.d.ts +2 -16
- package/dist/engines/pi/service.js +2 -16
- package/dist/engines/pi/session-builder.d.ts +5 -9
- package/dist/engines/pi/session-builder.js +44 -82
- package/dist/engines/pi/session-control.js +286 -269
- package/dist/engines/pi/session-effects.d.ts +14 -0
- package/dist/engines/pi/session-effects.js +30 -0
- package/dist/engines/pi/session-inheritance.d.ts +9 -18
- package/dist/engines/pi/session-inheritance.js +103 -160
- package/dist/engines/pi/session-markers.d.ts +31 -30
- package/dist/engines/pi/session-markers.js +26 -25
- package/dist/engines/pi/session-settings.d.ts +6 -22
- package/dist/engines/pi/session-settings.js +10 -21
- package/dist/engines/pi/session-store.d.ts +26 -92
- package/dist/engines/pi/session-store.js +96 -310
- package/dist/engines/pi/tool-context.d.ts +17 -45
- package/dist/engines/pi/tool-context.js +7 -26
- package/dist/engines/pi/tool.d.ts +45 -36
- package/dist/engines/pi/tool.js +43 -57
- package/dist/engines/pi/turn-kit.d.ts +14 -52
- package/dist/engines/pi/turn-kit.js +18 -67
- package/dist/engines/pi/wake-tool.d.ts +2 -10
- package/dist/engines/pi/wake-tool.js +7 -27
- package/dist/env.d.ts +27 -28
- package/dist/env.js +45 -50
- package/dist/index.js +0 -2
- package/dist/lark.d.ts +1 -2
- package/dist/lark.js +1 -2
- package/dist/loader.d.ts +14 -55
- package/dist/loader.js +24 -43
- package/dist/log.d.ts +2 -12
- package/dist/log.js +3 -24
- package/dist/node.d.ts +2 -15
- package/dist/node.js +2 -18
- package/dist/observe.d.ts +2 -8
- package/dist/open-url.d.ts +1 -1
- package/dist/open-url.js +1 -1
- package/dist/paths.d.ts +70 -134
- package/dist/paths.js +165 -232
- package/dist/pi.d.ts +4 -6
- package/dist/pi.js +3 -3
- package/dist/proxy.d.ts +16 -6
- package/dist/proxy.js +52 -16
- package/dist/runtime.d.ts +18 -12
- package/dist/runtime.js +18 -11
- package/dist/scaffold/add-channel.d.ts +14 -31
- package/dist/scaffold/add-channel.js +48 -112
- package/dist/scaffold/init.d.ts +9 -31
- package/dist/scaffold/init.js +45 -138
- package/dist/scaffold/templates/env.example +6 -4
- package/dist/scaffold/templates/fastagent.config.ts +36 -0
- package/dist/scaffold/templates.d.ts +3 -3
- package/dist/scaffold/templates.js +5 -8
- package/dist/scaffold/vendor-skill.d.ts +2 -5
- package/dist/scaffold/vendor-skill.js +19 -29
- package/dist/schedule/cron.d.ts +9 -5
- package/dist/schedule/cron.js +9 -11
- package/dist/schedule/discover.d.ts +12 -12
- package/dist/schedule/discover.js +43 -34
- package/dist/schedule/routine.d.ts +43 -0
- package/dist/schedule/routine.js +32 -0
- package/dist/schedule/run.d.ts +55 -0
- package/dist/schedule/run.js +146 -0
- package/dist/schedule/scheduler.d.ts +44 -55
- package/dist/schedule/scheduler.js +291 -265
- package/dist/schedule/state.d.ts +105 -10
- package/dist/schedule/state.js +293 -19
- package/dist/schedule/wake-alarm.d.ts +10 -23
- package/dist/schedule/wake-alarm.js +91 -121
- package/dist/schedule/wakeups.d.ts +23 -39
- package/dist/schedule/wakeups.js +33 -75
- package/dist/secrets-gate.d.ts +32 -0
- package/dist/secrets-gate.js +33 -0
- package/dist/service.d.ts +137 -98
- package/dist/service.js +250 -252
- package/dist/session-remote.d.ts +33 -44
- package/dist/session-remote.js +203 -192
- package/dist/session.d.ts +166 -229
- package/dist/session.js +33 -55
- package/dist/tunnel.d.ts +8 -36
- package/dist/tunnel.js +24 -65
- package/dist/version.d.ts +2 -2
- package/dist/version.js +2 -2
- package/package.json +10 -16
- package/dist/channels/agentcore-state.d.ts +0 -77
- package/dist/channels/agentcore-state.js +0 -276
- package/dist/channels/github/github.d.ts +0 -31
- package/dist/channels/github/github.js +0 -89
- package/dist/channels/github/scaffold/channel.ts +0 -25
- package/dist/cli/commands/attach.d.ts +0 -108
- package/dist/cli/commands/attach.js +0 -637
- package/dist/cli/commands/fire.d.ts +0 -7
- package/dist/cli/commands/fire.js +0 -38
- package/dist/cli/commands/schedule.d.ts +0 -12
- package/dist/cli/commands/schedule.js +0 -87
- package/dist/github.d.ts +0 -3
- package/dist/github.js +0 -2
- package/dist/scaffold/templates/fastagent.config.mjs +0 -23
- package/dist/schedule/audit.d.ts +0 -18
- package/dist/schedule/audit.js +0 -57
- package/dist/schedule/schedule.d.ts +0 -35
- package/dist/schedule/schedule.js +0 -23
|
@@ -1,38 +1,25 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `fastagent init [dir]`: scaffold a runnable agent and install its dependencies. Where the files land is
|
|
3
|
-
* a default plus one knob, never a detection and never a prompt — non-interactive executors (coding
|
|
4
|
-
* agents) get deterministic behavior they can read. By default the agent goes into `./fastagent/` and the
|
|
5
|
-
* directory around it is untouched; `--agent-dir <name>` names that directory anything, and `--agent-dir .`
|
|
6
|
-
* (spelled `--flat`) makes the directory itself the agent (a standalone agent repo, a monorepo package).
|
|
7
|
-
*/
|
|
1
|
+
/** `fastagent init [dir]`: scaffold a runnable agent and install its dependencies. */
|
|
8
2
|
import { spawn } from "node:child_process";
|
|
9
|
-
import { basename,
|
|
10
|
-
import { DEFAULT_AGENT_DIRNAME,
|
|
11
|
-
import { detectRuntime, readPackageJson } from "../../runtime.js";
|
|
3
|
+
import { basename, resolve } from "node:path";
|
|
4
|
+
import { DEFAULT_AGENT_DIRNAME, agentsAt, displayPath } from "../../paths.js";
|
|
12
5
|
import { agentDirName, agentDirNameError, scaffoldAgent } from "../../scaffold/init.js";
|
|
13
6
|
import { failStartup, failUsage } from "../fail.js";
|
|
14
7
|
export async function runInit(dirArg, opts) {
|
|
15
8
|
const dir = resolve(dirArg);
|
|
16
|
-
// A rejected flag VALUE is the usage class, same as one the parser rejects
|
|
17
|
-
// where exit 2 lives, not inside the scaffolder (whose throws are runtime failures, exit 1).
|
|
9
|
+
// A rejected flag VALUE is the usage class, same as one the parser rejects.
|
|
18
10
|
const requested = agentDirName(opts.agentDir);
|
|
19
11
|
const invalid = agentDirNameError(requested);
|
|
20
12
|
if (invalid)
|
|
21
13
|
failUsage(`--agent-dir "${requested}" ${invalid}`);
|
|
22
|
-
const {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}).catch(failStartup);
|
|
26
|
-
const flat = rel === ".";
|
|
27
|
-
// The agent dir is where the manifest lives, so any install runs there — never against a surrounding
|
|
28
|
-
// workspace's package.json (its deps are its own concern). With `.` they are the same directory.
|
|
14
|
+
const { agentDir: rel, created } = await scaffoldAgent(dir, { agentDir: requested }).catch(failStartup);
|
|
15
|
+
// The agent dir is where the manifest lives, so the install runs there — never against a surrounding workspace's
|
|
16
|
+
// package.json (its deps are its own concern).
|
|
29
17
|
const agentDir = resolve(dir, rel);
|
|
30
|
-
console.error(`[fastagent] initialized ${dir}
|
|
18
|
+
console.error(`[fastagent] initialized ${dir} — agent in ./${rel}/`);
|
|
31
19
|
console.error(` created: ${created.join(", ")}`);
|
|
32
|
-
// A second agent beside an existing one is a supported shape, not an accident (an engineer's, a PM's
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
// refusal. The default name is the tie-break, so a workspace keeping `fastagent/` needs nothing.
|
|
20
|
+
// A second agent beside an existing one is a supported shape, not an accident (an engineer's, a PM's and a content
|
|
21
|
+
// owner's agent can drive one repository), but it changes how this workspace resolves from now on — so say it HERE,
|
|
22
|
+
// at the moment it becomes true, instead of at the next command's refusal.
|
|
36
23
|
const siblings = agentsAt(dir).map((a) => basename(a));
|
|
37
24
|
if (siblings.length > 1) {
|
|
38
25
|
const pick = siblings.includes(DEFAULT_AGENT_DIRNAME)
|
|
@@ -40,34 +27,9 @@ export async function runInit(dirArg, opts) {
|
|
|
40
27
|
: `set FASTAGENT_AGENT=<name> (in your shell or .envrc) to pick one`;
|
|
41
28
|
console.error(`[fastagent] note: ${dir} now holds ${siblings.length} agents (${siblings.join(", ")}) — ${pick}`);
|
|
42
29
|
}
|
|
43
|
-
if (kept.length > 0) {
|
|
44
|
-
// Adopting a directory: its own files win, always. Say which ones — and for the two that carry a
|
|
45
|
-
// consequence, say what that consequence is, because keeping them silently leaves the agent broken
|
|
46
|
-
// (package.json) or its machinery committable (.gitignore).
|
|
47
|
-
console.error(` kept your existing: ${kept.join(", ")}`);
|
|
48
|
-
if (kept.includes(join(rel, "package.json")) && complete) {
|
|
49
|
-
const add = detectRuntime(agentDir, await readPackageJson(agentDir)).runtime === "bun" ? "bun add" : "npm install";
|
|
50
|
-
console.error(`[fastagent] note: your package.json is untouched, so it does not list @fastagent-sh/fastagent — ` +
|
|
51
|
-
`run \`${add} @fastagent-sh/fastagent\` there or the scaffolded tools/ cannot resolve`);
|
|
52
|
-
}
|
|
53
|
-
const keptSecretsIgnore = kept.includes(join(rel, SECRETS_DIRNAME, ".gitignore"));
|
|
54
|
-
if (kept.includes(join(rel, ".gitignore"))) {
|
|
55
|
-
// The "credentials are covered either way" reassurance holds only when `.secrets/.gitignore` is
|
|
56
|
-
// OURS. On an adopted directory it may be the author's too, and then we know nothing about it —
|
|
57
|
-
// `add <channel>` defends that file with a write; `init` must not claim more than it did.
|
|
58
|
-
console.error(`[fastagent] note: your .gitignore is untouched — make sure it ignores node_modules, .state ` +
|
|
59
|
-
`and .cache` +
|
|
60
|
-
(keptSecretsIgnore ? `` : ` (.secrets/ carries its own .gitignore, so credentials are covered either way)`));
|
|
61
|
-
}
|
|
62
|
-
if (keptSecretsIgnore) {
|
|
63
|
-
console.error(`[fastagent] note: your ${join(rel, SECRETS_DIRNAME, ".gitignore")} is untouched — verify it ignores ` +
|
|
64
|
-
`everything but .env.example, because credentials land in that directory`);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
const willInstall = complete && opts.install && !kept.includes(join(rel, "package.json"));
|
|
68
30
|
let installFailed = false;
|
|
69
|
-
if (
|
|
70
|
-
console.error(`[fastagent] installing dependencies (npm install
|
|
31
|
+
if (opts.install) {
|
|
32
|
+
console.error(`[fastagent] installing dependencies (npm install in ${rel})…`);
|
|
71
33
|
installFailed = (await npmInstall(agentDir)) !== 0;
|
|
72
34
|
if (installFailed)
|
|
73
35
|
console.error(`[fastagent] warn: npm install failed — run it manually in ${agentDir} before \`fastagent dev\``);
|
|
@@ -76,13 +38,12 @@ export async function runInit(dirArg, opts) {
|
|
|
76
38
|
const cdTarget = displayPath(process.cwd(), dir);
|
|
77
39
|
if (cdTarget)
|
|
78
40
|
console.error(` cd ${cdTarget}`);
|
|
79
|
-
if (
|
|
80
|
-
console.error(`
|
|
81
|
-
}
|
|
41
|
+
if (!opts.install || installFailed)
|
|
42
|
+
console.error(` (cd ${rel} && npm install)`);
|
|
82
43
|
console.error(` fastagent dev # serve locally and iterate`);
|
|
83
44
|
console.error(` fastagent add skill <owner/repo/path> # vendor more skills from GitHub`);
|
|
84
45
|
}
|
|
85
|
-
/** Run `npm install` in `cwd` (inherit stdio).
|
|
46
|
+
/** Run `npm install` in `cwd` (inherit stdio). */
|
|
86
47
|
function npmInstall(cwd) {
|
|
87
48
|
return new Promise((resolveCode) => {
|
|
88
49
|
const child = spawn("npm", ["install"], { cwd, stdio: "inherit" });
|
|
@@ -6,19 +6,17 @@ import { failStartup } from "../fail.js";
|
|
|
6
6
|
import { enterAgentCommand, reportAuth } from "../shared.js";
|
|
7
7
|
export async function runInvoke(message, dirArg, opts) {
|
|
8
8
|
const placement = await enterAgentCommand(dirArg, opts);
|
|
9
|
-
const { agent, modelSpec,
|
|
9
|
+
const { agent, modelSpec, auth } = await createPiAgentFromDir(placement.agentDir, {
|
|
10
10
|
model: opts.model,
|
|
11
|
-
authPath: opts.authPath, // flag > FASTAGENT_AUTH_PATH > default — resolved by the opener (one owner)
|
|
12
11
|
}).catch(failStartup);
|
|
13
|
-
// BOTH directories, like dev/start:
|
|
14
|
-
// typed, so it cannot tell you which agent actually ran.
|
|
12
|
+
// BOTH directories, like dev/start: which agent ran, and what it worked on.
|
|
15
13
|
console.error(`[fastagent] invoke: ${placement.agentDir} (workspace ${placement.workspace}, ${modelSpec})`);
|
|
16
|
-
await reportAuth(placement.agentDir, modelSpec,
|
|
14
|
+
await reportAuth(placement.agentDir, modelSpec, auth);
|
|
17
15
|
// Fresh session per invoke (one-shot, no resume). runInvokeStream maps events→IO: reply→stdout,
|
|
18
16
|
// tool/failure→stderr, exit 1 iff the turn failed (so CI can gate on it).
|
|
19
17
|
const exitCode = await runInvokeStream(agent.invoke({ session: randomUUID() }, { text: message }), (text) => process.stdout.write(text), (line) => console.error(line));
|
|
20
18
|
process.stdout.write("\n");
|
|
21
|
-
// Always exit explicitly: the undici proxy agent's keep-alive sockets would otherwise hold the
|
|
22
|
-
//
|
|
19
|
+
// Always exit explicitly: the undici proxy agent's keep-alive sockets would otherwise hold the event loop open
|
|
20
|
+
// after a successful one-shot turn.
|
|
23
21
|
process.exit(exitCode);
|
|
24
22
|
}
|
|
@@ -1,59 +1,54 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `fastagent login [provider]`: authenticate a model provider into the project-level auth file
|
|
3
|
-
* (`<agentDir>/.secrets/auth.json`) by default, or
|
|
4
|
-
* positional is the PROVIDER (not a dir), so the agent resolves from cwd — `cd` into your agent
|
|
5
|
-
* before logging in. OUTSIDE an agent there is no project credential to write, so the target is the
|
|
6
|
-
* user-global `~/.fastagent/.secrets/auth.json` (which is what running it from $HOME has always
|
|
7
|
-
* meant) — announced on stderr BEFORE the flow, because that is a different credential than the one
|
|
8
|
-
* `dev`/`start` in a real agent would read, and a silent scope switch is exactly the surprise this
|
|
9
|
-
* command must not ship.
|
|
10
|
-
*
|
|
11
|
-
* fastagent writes no `.gitignore` here or anywhere else at runtime: `init` scaffolds the agent's one
|
|
12
|
-
* ignore file (covering `.secrets/`) and the author owns it from then on. The credential store creates
|
|
13
|
-
* its own directory, mode 0700.
|
|
3
|
+
* (`<agentDir>/.secrets/auth.json`) by default, or `FASTAGENT_AUTH_PATH`.
|
|
14
4
|
*/
|
|
15
5
|
import { homedir } from "node:os";
|
|
16
6
|
import { join } from "node:path";
|
|
17
|
-
import {
|
|
7
|
+
import { enterAgentEnv } from "../../env.js";
|
|
18
8
|
import { resolveAuthPath } from "../../engines/pi/config.js";
|
|
9
|
+
import { GLOBAL_AUTH_PATH } from "../../engines/pi/auth.js";
|
|
19
10
|
import { GLOBAL_HOME_DIR, findAgentDir, placementDeadEnd } from "../../paths.js";
|
|
20
|
-
import { LoginCancelled } from "../../engines/pi/login.js";
|
|
21
|
-
import { installProxyFetch } from "../../proxy.js";
|
|
11
|
+
import { LoginCancelled, loginFlow } from "../../engines/pi/login.js";
|
|
22
12
|
import { failStartup, placementOrExit } from "../fail.js";
|
|
23
|
-
import { isInteractive,
|
|
13
|
+
import { isInteractive, terminalLoginIO } from "../shared.js";
|
|
24
14
|
export async function runLogin(provider, opts) {
|
|
25
15
|
const cwd = process.cwd();
|
|
26
16
|
const agentDir = findAgentDir(cwd);
|
|
27
|
-
// "Outside an agent" must mean exactly that
|
|
28
|
-
// directory holding several) is a dead end every other command refuses, and taking the global fallback
|
|
29
|
-
// there would write a credential to a different scope under a message saying there is no agent here.
|
|
17
|
+
// "Outside an agent" must mean exactly that.
|
|
30
18
|
if (!agentDir && placementDeadEnd(cwd))
|
|
31
19
|
placementOrExit(cwd);
|
|
32
|
-
// Outside any agent the target is the user-global machinery home — handed over explicitly, so the
|
|
33
|
-
//
|
|
20
|
+
// Outside any agent the target is the user-global machinery home — handed over explicitly, so the path resolvers
|
|
21
|
+
// need no "is this $HOME?" special case to infer it.
|
|
34
22
|
const loginDir = agentDir ?? join(homedir(), GLOBAL_HOME_DIR);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
23
|
+
// FASTAGENT_AUTH_PATH and a proxy may both be configured in the project .env, and the OAuth token exchange must go
|
|
24
|
+
// through that proxy (region-locked providers).
|
|
25
|
+
enterAgentEnv(loginDir);
|
|
26
|
+
// `-g` names the global file outright. Otherwise: FASTAGENT_AUTH_PATH > default — the one owner. The
|
|
27
|
+
// store built here is deliberately UNLAYERED: reading falls back to the global file, but writing must land
|
|
28
|
+
// exactly where the operator said, or a second `login` for a provider they already have globally would silently
|
|
29
|
+
// rewrite the global credential instead of creating the project-level override they asked for.
|
|
30
|
+
const authPath = opts.global ? GLOBAL_AUTH_PATH : resolveAuthPath(loginDir);
|
|
31
|
+
// Announce when the FALLBACK is what decided the target: outside an agent with no explicit path, the credential
|
|
32
|
+
// lands somewhere no agent will read.
|
|
33
|
+
if (!agentDir && !opts.global && !process.env.FASTAGENT_AUTH_PATH) {
|
|
34
|
+
console.error(`[fastagent] no agent here (no fastagent.config.ts, here or one level inside) — ` +
|
|
35
|
+
`logging in GLOBALLY (${authPath}). Every agent on this machine reads this file for providers its own ` +
|
|
36
|
+
`.secrets/auth.json does not have, so this is usually what you want; \`cd\` into an agent to give that ` +
|
|
37
|
+
`one its own account instead.`);
|
|
46
38
|
}
|
|
47
|
-
// login is inherently interactive — loginFlow renders provider/method menus and opens a browser (or
|
|
48
|
-
//
|
|
49
|
-
// and would hang; --no-input asks for the same posture explicitly. Fail fast with the reason instead
|
|
50
|
-
// of stalling on an unanswerable prompt.
|
|
39
|
+
// login is inherently interactive — loginFlow renders provider/method menus and opens a browser (or prompts for a
|
|
40
|
+
// key).
|
|
51
41
|
if (opts.input === false || !isInteractive()) {
|
|
52
42
|
failStartup(new Error(`login is interactive (it shows a menu and opens a browser) — run it in a terminal, not a pipe/CI`));
|
|
53
43
|
}
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
|
|
44
|
+
// An entered API key is verified with one minimal request (login.ts); a rejected one is asked for again.
|
|
45
|
+
// Inside an agent, the key is checked on that agent's registry: its models.json may point a provider at a gateway.
|
|
46
|
+
// Not with `-g`: the global file serves every agent on the machine, so no one agent's routing may judge its key.
|
|
47
|
+
const result = await loginFlow(terminalLoginIO(), {
|
|
48
|
+
authPath,
|
|
49
|
+
...(provider ? { provider } : {}),
|
|
50
|
+
...(agentDir && !opts.global ? { agentDir } : {}),
|
|
51
|
+
}).catch((error) => {
|
|
57
52
|
if (error instanceof LoginCancelled) {
|
|
58
53
|
// A decision, not a failure — neutral wording; non-zero exit because no credential was stored.
|
|
59
54
|
console.error(`[fastagent] login cancelled`);
|
|
@@ -3,15 +3,14 @@ import { basename, resolve } from "node:path";
|
|
|
3
3
|
import { agentcoreName } from "../../deploy/agentcore/plan.js";
|
|
4
4
|
import { tailAgentcoreLogs } from "../../deploy/agentcore/logs.js";
|
|
5
5
|
import { spawnRunner } from "../../deploy/runner.js";
|
|
6
|
-
import {
|
|
6
|
+
import { enterAgentEnv } from "../../env.js";
|
|
7
7
|
import { failStartup, failUsage, placementOrExit } from "../fail.js";
|
|
8
8
|
export async function runLogs(host, dirArg, opts) {
|
|
9
|
-
// The host argument is DISPATCHED here, as in runDeploy
|
|
10
|
-
// single member today, and a future second host must land on its own reader, not silently on this one.
|
|
9
|
+
// The host argument is DISPATCHED here, as in runDeploy.
|
|
11
10
|
if (host !== "agentcore")
|
|
12
11
|
failUsage(`logs: unsupported host "${host}" — only agentcore has remote logs`);
|
|
13
12
|
const placement = placementOrExit(resolve(dirArg));
|
|
14
|
-
|
|
13
|
+
enterAgentEnv(placement.agentDir); // AWS_PROFILE/region/proxy may be definition-local, as on deploy
|
|
15
14
|
const source = opts.source ?? "runtime";
|
|
16
15
|
if (source !== "runtime" && source !== "forwarder") {
|
|
17
16
|
failUsage(`logs: --source must be "runtime" or "forwarder"`);
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `fastagent models [search]`: print every registered "provider/modelId"; `[search]` filters by
|
|
3
|
-
* substring. This module pulls the pi model catalog (heavy) — it is lazy-imported by the spec, so
|
|
4
|
-
* only an actual `models` invocation pays for it.
|
|
5
|
-
*/
|
|
1
|
+
/** `fastagent models [search]`: print every registered "provider/modelId"; `[search]` filters by substring. */
|
|
6
2
|
import { formatModelsCommand } from "../models-view.js";
|
|
7
3
|
import { listModels } from "../../engines/pi/config.js";
|
|
8
4
|
import { createPiModels } from "../../engines/pi/models.js";
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `fastagent routine run <name> [dir]`: run ONE routine's turn immediately — the authoring loop for routines (like
|
|
3
|
+
* `invoke` is for a prompt). Cron or not: a routine that declares none has no other local entry.
|
|
4
|
+
*/
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { displayPath } from "../../paths.js";
|
|
7
|
+
import { reportModuleLoadFailures } from "../../loader.js";
|
|
8
|
+
import { createPiAgentFromDir } from "../../engines/pi/open.js";
|
|
9
|
+
import { runInvokeStream } from "../invoke-stream.js";
|
|
10
|
+
import { loadRoutines } from "../../schedule/discover.js";
|
|
11
|
+
import { routineSession } from "../../schedule/routine.js";
|
|
12
|
+
import { failStartup, gateSecretsOrExit } from "../fail.js";
|
|
13
|
+
import { enterAgentCommand, reportAuth } from "../shared.js";
|
|
14
|
+
export async function runRoutine(name, dirArg, opts) {
|
|
15
|
+
const placement = await enterAgentCommand(dirArg, opts);
|
|
16
|
+
// Routines are agent surface — discovered where dev/start/`routine list` do (the agent dir), so this command
|
|
17
|
+
// sees the same set the clock serves.
|
|
18
|
+
const { routines, secrets, failures } = await loadRoutines(placement.agentDir).catch(failStartup);
|
|
19
|
+
// Reported BEFORE the name is looked up: a routine file that failed to import is missing from
|
|
20
|
+
// `routines`, so "unknown routine" is the case where the author most needs to hear about it.
|
|
21
|
+
reportModuleLoadFailures(failures);
|
|
22
|
+
const routine = routines.find((r) => r.name === name);
|
|
23
|
+
if (!routine) {
|
|
24
|
+
// Name the discovery path: a schedule misplaced in the workspace (outside the agent dir) should read as "wrong
|
|
25
|
+
// place", not "broken file".
|
|
26
|
+
failStartup(new Error(`unknown routine "${name}" (looked in ${displayPath(process.cwd(), join(placement.agentDir, "routines")) ?? "routines"}). ` +
|
|
27
|
+
`available: ${routines.map((r) => r.name).join(", ") || "(none)"}`));
|
|
28
|
+
}
|
|
29
|
+
// This RUNS the routine, so it takes the serving path's guarantee: a prompt built from an
|
|
30
|
+
// unset declared value is the degraded turn this feature exists to prevent (`Post the digest to `
|
|
31
|
+
// — sent and executed), and the loader resolved it into a string before anything could notice.
|
|
32
|
+
// THIS schedule only (`owner`): running one routine must not fail because a SIBLING ROUTINE needs a
|
|
33
|
+
// credential this machine has no reason to hold. The agent assembled below is a different question
|
|
34
|
+
// and gates every mounted tool — a run's turn can call any of them — so this command is not free of a
|
|
35
|
+
// tool's declaration, only of another routine's. The failures go to the gate too, even though they
|
|
36
|
+
// were printed above: its guarantee must not depend on this call site remembering (a repeated line
|
|
37
|
+
// on the refusal path is the cheaper failure).
|
|
38
|
+
gateSecretsOrExit({ declared: secrets, failures, owner: name });
|
|
39
|
+
const { agent, modelSpec, auth } = await createPiAgentFromDir(placement.agentDir, {
|
|
40
|
+
model: opts.model,
|
|
41
|
+
}).catch(failStartup);
|
|
42
|
+
console.error(`[fastagent] routine run: ${name} (${modelSpec})`);
|
|
43
|
+
await reportAuth(placement.agentDir, modelSpec, auth);
|
|
44
|
+
const exitCode = await runInvokeStream(agent.invoke({ session: routineSession(name) }, { text: routine.prompt }), (text) => process.stdout.write(text), (line) => console.error(line));
|
|
45
|
+
process.stdout.write("\n");
|
|
46
|
+
process.exit(exitCode);
|
|
47
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `fastagent routine history <name> [dir]`: print this routine's fired slots — when each fired, how it ended, how
|
|
3
|
+
* long it took.
|
|
4
|
+
*
|
|
5
|
+
* The history IS the claims (`schedule/claims/<name>/`), so it is bounded by construction and carries no turn text:
|
|
6
|
+
* what the run SAID is in its session (`routine:<name>`), stored once, like any other turn's, under the state
|
|
7
|
+
* root's `sessions/` — which is where this command points rather than copying any of it here.
|
|
8
|
+
*
|
|
9
|
+
* This command does NOT try to say which turn belongs to which fire. Nothing links them: a routine's fires share
|
|
10
|
+
* ONE continuing conversation, so the session id is the same for all of them, and the turn-level identifier would
|
|
11
|
+
* have to cross the engine-neutral contract (no `AgentEvent` carries an entry id) or cost the shared conversation.
|
|
12
|
+
* A claim's timestamp against a time-ordered journal is what an operator reads anyway — matching them HERE only
|
|
13
|
+
* moves a human's judgement into a heuristic that cannot be right about a session other writers also append to.
|
|
14
|
+
*/
|
|
15
|
+
export declare function runRoutineHistory(name: string, dirArg: string, json: boolean): void;
|
|
16
|
+
/**
|
|
17
|
+
* `fastagent routine list [dir]`: every declared routine, and when (or whether) a clock fires it.
|
|
18
|
+
*
|
|
19
|
+
* IT ALSO READS the agent's pending wake-ups. They are a different owner (the state, not the definition) but the
|
|
20
|
+
* same question when an operator is asking it: "what is going to wake this agent up?". Deleting the command that
|
|
21
|
+
* CANCELLED one was right — `unwake({ id })` covers it, and a serve that can receive the alarm can also be spoken
|
|
22
|
+
* to — but that argument is about WRITING. Without a read, the only way to learn why an agent wakes at 3am is to
|
|
23
|
+
* open `<stateRoot>/schedule/wakeups.json` by hand.
|
|
24
|
+
*/
|
|
25
|
+
export declare function runRoutineList(dirArg: string, json: boolean): Promise<void>;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `fastagent routine history|list` — the routines this DEFINITION declares.
|
|
3
|
+
*
|
|
4
|
+
* The agent's own pending wake-ups are not here and have no command: they live in the state, not the definition,
|
|
5
|
+
* and `unwake({ id })` is what cancels one (schedule/wakeups.ts says why).
|
|
6
|
+
*/
|
|
7
|
+
import { resolve } from "node:path";
|
|
8
|
+
import { enterAgentEnv } from "../../env.js";
|
|
9
|
+
import { resolveSessionsDir, resolveStateRoot } from "../../paths.js";
|
|
10
|
+
import { reportModuleLoadFailures } from "../../loader.js";
|
|
11
|
+
import { nextRun } from "../../schedule/cron.js";
|
|
12
|
+
import { loadRoutines } from "../../schedule/discover.js";
|
|
13
|
+
import { routineSession } from "../../schedule/routine.js";
|
|
14
|
+
import { isSafeScheduleName, readFires } from "../../schedule/state.js";
|
|
15
|
+
import { listWakeups } from "../../schedule/wakeups.js";
|
|
16
|
+
import { failStartup, placementOrExit } from "../fail.js";
|
|
17
|
+
/**
|
|
18
|
+
* `fastagent routine history <name> [dir]`: print this routine's fired slots — when each fired, how it ended, how
|
|
19
|
+
* long it took.
|
|
20
|
+
*
|
|
21
|
+
* The history IS the claims (`schedule/claims/<name>/`), so it is bounded by construction and carries no turn text:
|
|
22
|
+
* what the run SAID is in its session (`routine:<name>`), stored once, like any other turn's, under the state
|
|
23
|
+
* root's `sessions/` — which is where this command points rather than copying any of it here.
|
|
24
|
+
*
|
|
25
|
+
* This command does NOT try to say which turn belongs to which fire. Nothing links them: a routine's fires share
|
|
26
|
+
* ONE continuing conversation, so the session id is the same for all of them, and the turn-level identifier would
|
|
27
|
+
* have to cross the engine-neutral contract (no `AgentEvent` carries an entry id) or cost the shared conversation.
|
|
28
|
+
* A claim's timestamp against a time-ordered journal is what an operator reads anyway — matching them HERE only
|
|
29
|
+
* moves a human's judgement into a heuristic that cannot be right about a session other writers also append to.
|
|
30
|
+
*/
|
|
31
|
+
export function runRoutineHistory(name, dirArg, json) {
|
|
32
|
+
const { agentDir: target } = placementOrExit(resolve(dirArg));
|
|
33
|
+
enterAgentEnv(target); // FASTAGENT_STATE_DIR may live in .env — read the SAME state root the scheduler wrote
|
|
34
|
+
const stateRoot = resolveStateRoot(target);
|
|
35
|
+
// A name that cannot be a routine is a MISTYPED ARGUMENT, and it must not look like an empty history: exit 1 the
|
|
36
|
+
// way every other user-input refusal does, so `--json` printing nothing is never read as "the command succeeded".
|
|
37
|
+
if (!isSafeScheduleName(name)) {
|
|
38
|
+
failStartup(new Error(`"${name}" cannot be a routine name (no path separators, "." or "..")`));
|
|
39
|
+
}
|
|
40
|
+
// `readFires` throws a raw fs error on unreadable state, because its other caller is the serving boot, which must
|
|
41
|
+
// fail rather than arm a schedule it cannot read. This caller is a read-only CLI command: the same fact is an
|
|
42
|
+
// operator's to fix, so it exits the way every other refusal in this file does instead of printing a Node stack.
|
|
43
|
+
let fires;
|
|
44
|
+
try {
|
|
45
|
+
fires = readFires(stateRoot, name);
|
|
46
|
+
}
|
|
47
|
+
catch (e) {
|
|
48
|
+
failStartup(new Error(`the fired-slot claims for "${name}" are unreadable (state: ${stateRoot}): ${String(e)}`));
|
|
49
|
+
}
|
|
50
|
+
if (json) {
|
|
51
|
+
console.log(JSON.stringify(fires, null, 2));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (fires.length === 0) {
|
|
55
|
+
// No special case for "wake": it is an ordinary schedule name now (`discover.ts` stopped reserving it).
|
|
56
|
+
console.error(`no recorded fires for "${name}" (state: ${stateRoot})`);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
// The question is "did LAST NIGHT's run fail?", so text mode tails the most recent fires; --json above is the
|
|
60
|
+
// whole retained window.
|
|
61
|
+
const TAIL = 20;
|
|
62
|
+
const shown = fires.slice(-TAIL);
|
|
63
|
+
for (const f of shown) {
|
|
64
|
+
// An unreported fire has no duration to print, and `0ms` would be a value a fast turn really produces — the
|
|
65
|
+
// column stays empty rather than claiming the turn took no time.
|
|
66
|
+
const took = f.ms === undefined ? "" : `${f.ms}ms`;
|
|
67
|
+
console.log(`${f.firedAt} ${(f.outcome ?? "unreported").padEnd(11)} ${took.padStart(8)}`);
|
|
68
|
+
}
|
|
69
|
+
if (fires.length > shown.length) {
|
|
70
|
+
console.error(`(the last ${shown.length} of ${fires.length} fires — --json for all)`);
|
|
71
|
+
}
|
|
72
|
+
// The other half of the answer, and where it lives: these rows say a fire happened, not what it produced. The
|
|
73
|
+
// session id comes from the ONE place that spells it and the directory from the ONE place that resolves it. The
|
|
74
|
+
// record is one level further down and under a name pi accepts (`piSessionId` escapes the `:`), so the pointer
|
|
75
|
+
// says how to recognise the file rather than claiming a path the reader can paste.
|
|
76
|
+
console.error(`(what these runs said: session ${routineSession(name)} — a JSON-lines journal under ${resolveSessionsDir(target)}, ` +
|
|
77
|
+
`in the file whose name carries "${name}")`);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* `fastagent routine list [dir]`: every declared routine, and when (or whether) a clock fires it.
|
|
81
|
+
*
|
|
82
|
+
* IT ALSO READS the agent's pending wake-ups. They are a different owner (the state, not the definition) but the
|
|
83
|
+
* same question when an operator is asking it: "what is going to wake this agent up?". Deleting the command that
|
|
84
|
+
* CANCELLED one was right — `unwake({ id })` covers it, and a serve that can receive the alarm can also be spoken
|
|
85
|
+
* to — but that argument is about WRITING. Without a read, the only way to learn why an agent wakes at 3am is to
|
|
86
|
+
* open `<stateRoot>/schedule/wakeups.json` by hand.
|
|
87
|
+
*/
|
|
88
|
+
export async function runRoutineList(dirArg, json) {
|
|
89
|
+
const { agentDir: target } = placementOrExit(resolve(dirArg));
|
|
90
|
+
enterAgentEnv(target);
|
|
91
|
+
const { routines, failures } = await loadRoutines(target).catch(failStartup);
|
|
92
|
+
reportModuleLoadFailures(failures);
|
|
93
|
+
const wakeups = listWakeups(resolveStateRoot(target));
|
|
94
|
+
if (json) {
|
|
95
|
+
console.log(JSON.stringify({
|
|
96
|
+
routines: routines.map((r) => ({
|
|
97
|
+
...r,
|
|
98
|
+
next: r.cron === undefined ? null : (nextRun(r.cron, r.tz, new Date())?.toISOString() ?? null),
|
|
99
|
+
})),
|
|
100
|
+
wakeups,
|
|
101
|
+
}, null, 2));
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (routines.length === 0 && wakeups.length === 0) {
|
|
105
|
+
console.error(`nothing declared or pending — no routines/ files, no wake-ups (agent: ${target})`);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
for (const r of routines) {
|
|
109
|
+
// A routine with no cron is not broken and not idle: it is reached by NAME (`routine run`, `POST /run`), and
|
|
110
|
+
// saying "on demand" is the difference between that and a cron that will never fire again.
|
|
111
|
+
const when = r.cron === undefined
|
|
112
|
+
? "on demand".padEnd(26)
|
|
113
|
+
: `${(nextRun(r.cron, r.tz, new Date())?.toISOString() ?? "(never)").padEnd(26)}cron ${r.cron}${r.tz ? ` ${r.tz}` : ""}`;
|
|
114
|
+
console.log(`${r.name.padEnd(20)} ${when}`);
|
|
115
|
+
}
|
|
116
|
+
// Labelled, because these two are NOT the same kind of thing: a routine is the author's, a wake-up is the
|
|
117
|
+
// agent's own and is cancelled with `unwake` rather than a command here.
|
|
118
|
+
for (const w of wakeups) {
|
|
119
|
+
const kind = w.cron ? `cron ${w.cron}${w.tz ? ` ${w.tz}` : ""}` : "one-shot";
|
|
120
|
+
console.log(`wake ${w.id} ${w.fireAt} ${kind} session=${w.session} ${w.prompt.slice(0, 60)}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -1,11 +1,39 @@
|
|
|
1
|
+
import { type AgentService } from "../../service.ts";
|
|
1
2
|
export interface StartOptions {
|
|
2
3
|
port?: string;
|
|
3
4
|
bind?: string;
|
|
4
5
|
model?: string;
|
|
5
|
-
sessionsDir?: string;
|
|
6
|
-
authPath?: string;
|
|
7
6
|
tunnel?: boolean;
|
|
8
|
-
/** false ⇔ `--no-
|
|
7
|
+
/** false ⇔ `--no-invoke`: withhold `POST /invoke` for THIS run (`http.invoke` is the persistent form). */
|
|
8
|
+
invoke?: boolean;
|
|
9
9
|
input?: boolean;
|
|
10
10
|
}
|
|
11
|
+
type StartedService = AgentService & {
|
|
12
|
+
stateRoot: string;
|
|
13
|
+
port: number;
|
|
14
|
+
};
|
|
11
15
|
export declare function runStart(dirArg: string, opts: StartOptions): Promise<void>;
|
|
16
|
+
/** What the storage stage hands the opening stage. */
|
|
17
|
+
export interface PreparedWorkspace {
|
|
18
|
+
/** The workspace to open — the volume's `base/` when a release manifest selected one. */
|
|
19
|
+
dir: string;
|
|
20
|
+
/** Set when this process took a deployed workspace. */
|
|
21
|
+
deployed?: {
|
|
22
|
+
root: string;
|
|
23
|
+
agent: string;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Stage one — TAKE the workspace: verify the storage is mounted, apply the release, and point the machinery at the
|
|
28
|
+
* volume.
|
|
29
|
+
*/
|
|
30
|
+
export declare function prepareStartWorkspace(dirArg: string): Promise<PreparedWorkspace>;
|
|
31
|
+
/**
|
|
32
|
+
* Stage two — RUN in the prepared workspace: install the agent's dependencies, then open through the workspace's own
|
|
33
|
+
* FastAgent install.
|
|
34
|
+
*/
|
|
35
|
+
export declare function openPreparedWorkspace(prepared: PreparedWorkspace, opts: StartOptions): Promise<StartedService>;
|
|
36
|
+
export declare function openStartService(dirArg: string, opts: StartOptions): Promise<StartedService>;
|
|
37
|
+
/** Internal entry loaded from the active workspace's installed package after storage initialization. */
|
|
38
|
+
export declare function openPreparedStartService(dirArg: string, opts: StartOptions): Promise<StartedService>;
|
|
39
|
+
export {};
|