@fastagent-sh/fastagent 0.20.0 → 0.21.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 +5 -1
- package/dist/channels/agentcore-protocol.d.ts +112 -0
- package/dist/channels/agentcore-protocol.js +22 -0
- package/dist/channels/agentcore-service.d.ts +0 -4
- package/dist/channels/agentcore-service.js +1 -6
- package/dist/channels/agentcore-state.d.ts +5 -11
- package/dist/channels/agentcore-state.js +4 -1
- package/dist/channels/agentcore.d.ts +1 -67
- package/dist/channels/agentcore.js +90 -89
- package/dist/channels/control.d.ts +1 -1
- package/dist/channels/control.js +13 -62
- package/dist/channels/discover.d.ts +0 -1
- package/dist/channels/discover.js +1 -3
- package/dist/channels/feishu/context-buffer.d.ts +6 -0
- package/dist/channels/feishu/context-buffer.js +0 -38
- package/dist/channels/feishu/crypto.d.ts +0 -2
- package/dist/channels/feishu/crypto.js +3 -8
- package/dist/channels/feishu/feishu-api.js +2 -4
- package/dist/channels/feishu/feishu.js +56 -115
- package/dist/channels/feishu/parse.d.ts +4 -3
- package/dist/channels/feishu/parse.js +5 -4
- package/dist/channels/feishu/register-webhook.d.ts +5 -5
- package/dist/channels/feishu/register-webhook.js +43 -57
- package/dist/channels/feishu/scaffold/feishu-send.ts +12 -67
- package/dist/channels/feishu/setup-mode.d.ts +30 -0
- package/dist/channels/feishu/setup-mode.js +26 -0
- package/dist/channels/feishu/shared-api.d.ts +10 -0
- package/dist/channels/feishu/shared-api.js +38 -0
- package/dist/channels/http.d.ts +0 -8
- package/dist/channels/http.js +4 -56
- package/dist/channels/kit/turn-runner.d.ts +59 -0
- package/dist/channels/kit/turn-runner.js +84 -0
- package/dist/channels/lark/scaffold/lark-send.ts +12 -67
- package/dist/channels/registration.d.ts +36 -1
- package/dist/channels/registration.js +57 -1
- package/dist/channels/secret.d.ts +1 -0
- package/dist/channels/secret.js +16 -0
- package/dist/channels/slack/config-api.d.ts +35 -3
- package/dist/channels/slack/config-api.js +51 -9
- package/dist/channels/slack/manifest.js +5 -1
- package/dist/channels/slack/onboard.d.ts +5 -5
- package/dist/channels/slack/onboard.js +41 -20
- package/dist/channels/slack/register-webhook.d.ts +3 -2
- package/dist/channels/slack/register-webhook.js +34 -14
- package/dist/channels/slack/scaffold/channel.ts +3 -10
- package/dist/channels/slack/scaffold/slack-send.ts +18 -126
- package/dist/channels/slack/shared-api.d.ts +10 -0
- package/dist/channels/slack/shared-api.js +34 -0
- package/dist/channels/slack/slack-api.d.ts +20 -2
- package/dist/channels/slack/slack-api.js +81 -22
- package/dist/channels/slack/slack.d.ts +0 -10
- package/dist/channels/slack/slack.js +60 -99
- package/dist/channels/sse.d.ts +4 -0
- package/dist/channels/sse.js +66 -0
- package/dist/channels/telegram/register-webhook.d.ts +6 -9
- package/dist/channels/telegram/register-webhook.js +44 -42
- package/dist/channels/telegram/telegram.js +47 -142
- package/dist/channels/wait-health.js +7 -4
- package/dist/cli/add-feishu.js +3 -10
- package/dist/cli/add-slack.js +7 -20
- package/dist/cli/commands/add.d.ts +0 -1
- package/dist/cli/commands/add.js +22 -31
- package/dist/cli/commands/chat.js +6 -12
- package/dist/cli/commands/deploy/agentcore.d.ts +2 -0
- package/dist/cli/commands/deploy/agentcore.js +178 -0
- package/dist/cli/commands/deploy/docker.d.ts +2 -0
- package/dist/cli/commands/deploy/docker.js +119 -0
- package/dist/cli/commands/deploy/fly.d.ts +2 -0
- package/dist/cli/commands/deploy/fly.js +131 -0
- package/dist/cli/commands/deploy/railway.d.ts +2 -0
- package/dist/cli/commands/deploy/railway.js +71 -0
- package/dist/cli/commands/deploy/shared.d.ts +114 -0
- package/dist/cli/commands/deploy/shared.js +124 -0
- package/dist/cli/commands/deploy.d.ts +17 -49
- package/dist/cli/commands/deploy.js +39 -618
- package/dist/cli/commands/dev.js +17 -46
- package/dist/cli/commands/fire.js +6 -12
- package/dist/cli/commands/info.js +2 -1
- package/dist/cli/commands/invoke.js +4 -11
- package/dist/cli/commands/schedule.js +1 -1
- package/dist/cli/commands/start.js +17 -46
- package/dist/cli/commands/tool.js +3 -8
- package/dist/cli/kernel.d.ts +0 -2
- package/dist/cli/kernel.js +0 -2
- package/dist/cli/program.js +7 -12
- package/dist/cli/serve.d.ts +36 -19
- package/dist/cli/serve.js +91 -7
- package/dist/cli/shared.d.ts +13 -18
- package/dist/cli/shared.js +20 -4
- package/dist/deploy/agentcore/forwarder.js +250 -0
- package/dist/deploy/agentcore/plan.d.ts +23 -2
- package/dist/deploy/agentcore/plan.js +29 -244
- package/dist/deploy/agentcore/run.d.ts +4 -20
- package/dist/deploy/agentcore/run.js +22 -7
- package/dist/deploy/channel-ingress.js +1 -1
- package/dist/deploy/docker/run.d.ts +17 -3
- package/dist/deploy/docker/run.js +30 -8
- package/dist/deploy/fly/plan.js +7 -0
- package/dist/deploy/fly/run.d.ts +27 -0
- package/dist/deploy/fly/run.js +102 -20
- package/dist/deploy/hosts.d.ts +5 -0
- package/dist/deploy/hosts.js +4 -0
- package/dist/deploy/preflight.js +3 -3
- package/dist/deploy/railway/plan.d.ts +5 -0
- package/dist/deploy/railway/plan.js +7 -0
- package/dist/deploy/railway/run.d.ts +2 -1
- package/dist/deploy/railway/run.js +5 -4
- package/dist/deploy/secrets.js +0 -17
- package/dist/engines/pi/agent-session-factory.d.ts +37 -17
- package/dist/engines/pi/agent-session-factory.js +109 -85
- package/dist/engines/pi/config.d.ts +1 -1
- package/dist/engines/pi/create.d.ts +22 -39
- package/dist/engines/pi/create.js +58 -73
- package/dist/engines/pi/definition.js +8 -8
- package/dist/engines/pi/invoke-session.js +13 -30
- package/dist/engines/pi/open.d.ts +2 -2
- package/dist/engines/pi/open.js +31 -41
- package/dist/engines/pi/retry-event.d.ts +6 -0
- package/dist/engines/pi/retry-event.js +15 -0
- package/dist/engines/pi/session-builder.js +26 -113
- package/dist/engines/pi/session-control.d.ts +10 -18
- package/dist/engines/pi/session-control.js +47 -81
- package/dist/engines/pi/session-settings.d.ts +1 -1
- package/dist/engines/pi/session-settings.js +1 -1
- package/dist/engines/pi/session-store.d.ts +12 -17
- package/dist/engines/pi/session-store.js +18 -40
- package/dist/engines/pi/tool-context.d.ts +3 -3
- package/dist/engines/pi/tool.d.ts +6 -9
- package/dist/engines/pi/tool.js +1 -0
- package/dist/feishu.d.ts +1 -0
- package/dist/feishu.js +1 -0
- package/dist/lark.d.ts +1 -0
- package/dist/lark.js +1 -0
- package/dist/loader.d.ts +2 -0
- package/dist/loader.js +5 -0
- package/dist/log.d.ts +9 -17
- package/dist/log.js +25 -30
- package/dist/paths.d.ts +7 -3
- package/dist/paths.js +17 -4
- package/dist/scaffold/add-channel.d.ts +6 -1
- package/dist/scaffold/add-channel.js +48 -65
- package/dist/schedule/wake-alarm.d.ts +1 -12
- package/dist/schedule/wake-alarm.js +2 -3
- package/dist/service.d.ts +23 -22
- package/dist/service.js +7 -73
- package/dist/session-remote.d.ts +5 -5
- package/dist/session-remote.js +25 -28
- package/dist/session.d.ts +1 -1
- package/dist/slack.d.ts +2 -0
- package/dist/slack.js +1 -0
- package/dist/tunnel.d.ts +16 -6
- package/dist/tunnel.js +53 -12
- package/package.json +5 -4
- package/dist/channels/slack/bot-auth.d.ts +0 -15
- package/dist/channels/slack/bot-auth.js +0 -135
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What every host's deploy command shares: the context the dispatcher hands a host, the artifact
|
|
3
|
+
* writer with its ownership rule, and the `--run` credential carry. Host facts live in
|
|
4
|
+
* `cli/commands/deploy/<host>.ts`; this file holds nothing that names one.
|
|
5
|
+
*/
|
|
6
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
7
|
+
import { dirname, join } from "node:path";
|
|
8
|
+
import { registerFeishuWebhook } from "../../../channels/feishu/register-webhook.js";
|
|
9
|
+
import { DEPLOY_REGISTRATION_ATTEMPTS } from "../../../channels/registration.js";
|
|
10
|
+
import { registerSlackWebhook } from "../../../channels/slack/register-webhook.js";
|
|
11
|
+
import { registerTelegramWebhook } from "../../../channels/telegram/register-webhook.js";
|
|
12
|
+
import { isGeneratedDockerfile, isGeneratedDockerignore } from "../../../deploy/container.js";
|
|
13
|
+
import { assembleSecrets } from "../../../deploy/secrets.js";
|
|
14
|
+
import { exists, resolveStateRoot } from "../../../paths.js";
|
|
15
|
+
import { failStartup } from "../../fail.js";
|
|
16
|
+
/** The registrars every host driver gets. One wiring: a channel's credentials are the channel's, not
|
|
17
|
+
* the host's, so which of them can run end-to-end never varies by deployment target.
|
|
18
|
+
*
|
|
19
|
+
* All three get {@link DEPLOY_REGISTRATION_ATTEMPTS} rather than the default: a host CLI returns
|
|
20
|
+
* before the deployment answers, and a registration that gives up first GATES the deploy — reporting
|
|
21
|
+
* a working deployment as one to re-run. `dev --tunnel` keeps the shorter default; it is a resident
|
|
22
|
+
* process whose URL is live when it is printed, as does `deploy docker --run` — it reuses that same
|
|
23
|
+
* announcer, having already health-probed the container and waited for the Quick Tunnel URL.
|
|
24
|
+
*
|
|
25
|
+
* Accepted cost: pointChannelsAt registers serially, so a deployment whose channels are ALL
|
|
26
|
+
* unreachable spends the budget once per channel (3 x 180s) before it gates. Registering in parallel
|
|
27
|
+
* would not shorten a single failing channel, and the failing case is the one nobody is waiting on. */
|
|
28
|
+
export function registrarsFor(agentDir) {
|
|
29
|
+
const attempts = DEPLOY_REGISTRATION_ATTEMPTS;
|
|
30
|
+
return {
|
|
31
|
+
telegram: (baseUrl) => registerTelegramWebhook(baseUrl, { attempts }),
|
|
32
|
+
slack: (baseUrl) => registerSlackWebhook(baseUrl, { stateRoot: resolveStateRoot(agentDir), attempts }),
|
|
33
|
+
feishu: (baseUrl, kind) => registerFeishuWebhook(baseUrl, kind, { attempts }),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The `--run` credential carry, for every host: the local model credential (an env key, or the whole
|
|
38
|
+
* auth.json as a `FASTAGENT_AUTH_SEED`) plus channel secrets. Four drivers assembled this identically.
|
|
39
|
+
*/
|
|
40
|
+
export async function carryCredentials(params) {
|
|
41
|
+
const { modelAuth, modelKeyInDefinition, authPath, channels, extraSecrets } = params;
|
|
42
|
+
return assembleSecrets({
|
|
43
|
+
modelAuth,
|
|
44
|
+
modelKeyInDefinition,
|
|
45
|
+
authFile: (await exists(authPath)) ? await readFile(authPath) : undefined,
|
|
46
|
+
channels,
|
|
47
|
+
extraSecrets,
|
|
48
|
+
env: process.env,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
/** Gate a `--run` that has no model credential to carry. Its remediation is `fastagent login`, which
|
|
52
|
+
* is why it is separate from `missingSecrets` (a `.env` fix) rather than folded into it. Docker states
|
|
53
|
+
* the same gate inside its driver, where it belongs after the daemon check. */
|
|
54
|
+
export function gateOnModelCredential(needsModelCredential) {
|
|
55
|
+
if (!needsModelCredential)
|
|
56
|
+
return;
|
|
57
|
+
failStartup(new Error(`deploy stopped: no model credential — run \`fastagent login\`, or set a provider API key in .env, then re-run`));
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Write each generated artifact under `target`, under ONE ownership rule: **deploy only ever overwrites
|
|
61
|
+
* its own output.** Each generated file opens with a marker, so a file on disk is either OURS (a previous
|
|
62
|
+
* `deploy` wrote it) or the author's — and `--force` means "my generated artifact is authoritative",
|
|
63
|
+
* which never licenses clobbering a file we did not write. To hand a path back to fastagent, delete it.
|
|
64
|
+
*
|
|
65
|
+
* That single rule replaced a second mechanism (a per-host list of paths exempt from `--force`), which
|
|
66
|
+
* only described one shape: with the agent inside the workspace, the root `.dockerignore` is the
|
|
67
|
+
* WORKSPACE's file and was listed; with the agent flat, the list was empty — so `--force` would have
|
|
68
|
+
* overwritten a hand-written root `Dockerfile` in a repository `init --flat` had explicitly adopted.
|
|
69
|
+
* Ownership is a property of the file, not of where the agent sits.
|
|
70
|
+
*
|
|
71
|
+
* A KEPT file of OURS that no longer matches what deploy would generate now (config/channel/lockfile/
|
|
72
|
+
* version drift — or the author's edits, which we cannot tell apart) is flagged stale; `--force`
|
|
73
|
+
* regenerates that one.
|
|
74
|
+
*
|
|
75
|
+
* Exported for its own test — this is a four-branch state machine over (exists, ours, force) that used
|
|
76
|
+
* to be proven by spawning the CLI eight times, which is command LOGIC re-run through a subprocess
|
|
77
|
+
* (see vitest.config.ts) and the suite's slowest test.
|
|
78
|
+
*/
|
|
79
|
+
export async function writeArtifacts(target, artifacts, options) {
|
|
80
|
+
for (const a of artifacts) {
|
|
81
|
+
const abs = join(target, a.path);
|
|
82
|
+
// Pure build output, not operator-owned configuration. It must track the generated template/runbook.
|
|
83
|
+
if (options.alwaysWrite?.includes(a.path)) {
|
|
84
|
+
await mkdir(dirname(abs), { recursive: true });
|
|
85
|
+
await writeFile(abs, a.content);
|
|
86
|
+
console.error(`[fastagent] wrote ${a.path}`);
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
const existing = (await exists(abs)) ? await readFile(abs, "utf8") : undefined;
|
|
90
|
+
const ours = existing !== undefined && isOurArtifact(a.path, existing, options.isOurs);
|
|
91
|
+
if (existing !== undefined && !ours) {
|
|
92
|
+
// Only the `.dockerignore` has content checks in preflight — pointing at "the preflight warnings"
|
|
93
|
+
// for the other kinds would send the reader looking for output that is never printed.
|
|
94
|
+
console.error(`[fastagent] kept ${a.path} — not generated by fastagent, so --force does not touch it ` +
|
|
95
|
+
`(delete it to let deploy own the path)` +
|
|
96
|
+
(a.path.endsWith(".dockerignore")
|
|
97
|
+
? `; see the preflight warnings for what it must exclude`
|
|
98
|
+
: a.path.endsWith("Dockerfile")
|
|
99
|
+
? `; deploy still assumes it listens on $PORT and runs \`fastagent start /app\``
|
|
100
|
+
: ``));
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (existing !== undefined && !options.force) {
|
|
104
|
+
console.error(existing !== a.content
|
|
105
|
+
? `[fastagent] kept ${a.path} — it no longer matches what deploy would generate (config changed, or ` +
|
|
106
|
+
`you edited it); pass --force to regenerate.`
|
|
107
|
+
: `[fastagent] kept ${a.path} (unchanged)`);
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
await mkdir(dirname(abs), { recursive: true }); // artifacts live under fastagent/
|
|
111
|
+
await writeFile(abs, a.content);
|
|
112
|
+
console.error(`[fastagent] wrote ${a.path}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/** Did fastagent generate the file at `path`? The container's two artifacts are every host's; the
|
|
116
|
+
* rest is the host's own answer. A kind neither names is permanently classified as the author's,
|
|
117
|
+
* which silently turns `--force` into a no-op for that file. */
|
|
118
|
+
function isOurArtifact(path, content, host) {
|
|
119
|
+
if (path.endsWith("Dockerfile"))
|
|
120
|
+
return isGeneratedDockerfile(content);
|
|
121
|
+
if (path.endsWith(".dockerignore"))
|
|
122
|
+
return isGeneratedDockerignore(content);
|
|
123
|
+
return host(path, content);
|
|
124
|
+
}
|
|
@@ -1,25 +1,21 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
authPath?: string;
|
|
18
|
-
/** false ⇔ `--no-input`. */
|
|
19
|
-
input?: boolean;
|
|
20
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* `fastagent deploy <host> [dir]`: generate host artifacts from the resolved definition and print an
|
|
3
|
+
* ordered deploy runbook. Host-scoped (`docker` | `fly` | `railway` — the extension seam). It does NOT
|
|
4
|
+
* run the host CLI by default: fastagent owns the definition-aware artifacts and precise runbook;
|
|
5
|
+
* Docker may opt into a generated ephemeral tunnel, while durable ingress stays operator-owned. The pre-flight
|
|
6
|
+
* (config/model/channels/container facts) is host-neutral; each host's module (`./deploy/<host>.ts`)
|
|
7
|
+
* adds its artifacts, its kept-file semantics, its gates and its `--run` drive over the neutral
|
|
8
|
+
* `deploy/<host>/` plan + driver. Read-only on the definition; the only writes are generated
|
|
9
|
+
* artifacts (never clobbered without --force). `--run` drives the target CLI instead of printing.
|
|
10
|
+
*/
|
|
11
|
+
import type { DeployHost } from "../../deploy/hosts.ts";
|
|
12
|
+
import { type DeployOptions, type HostDeploy, writeArtifacts } from "./deploy/shared.ts";
|
|
13
|
+
export { writeArtifacts };
|
|
14
|
+
/** Every host, by the name the CLI takes. Typed over {@link DeployHost} so a host added to the list
|
|
15
|
+
* without a module here fails to compile. */
|
|
16
|
+
export declare const HOSTS: Record<DeployHost, HostDeploy>;
|
|
21
17
|
/** A flag exactly one host honours, and what the OTHERS do instead. `instead` is exhaustive over the
|
|
22
|
-
* non-owners, so a host added to
|
|
18
|
+
* non-owners, so a host added to `DEPLOY_HOSTS` cannot silently lose its line. */
|
|
23
19
|
interface HostOnlyFlag<Owner extends DeployHost> {
|
|
24
20
|
flag: string;
|
|
25
21
|
owner: Owner;
|
|
@@ -43,31 +39,3 @@ export declare const HOST_ONLY_FLAGS: (HostOnlyFlag<"fly"> | HostOnlyFlag<"railw
|
|
|
43
39
|
* disagree about the spelling of a host name. */
|
|
44
40
|
export declare function warnHostOnlyFlags(host: DeployHost, opts: DeployOptions): void;
|
|
45
41
|
export declare function runDeploy(host: DeployHost, dirArg: string, opts: DeployOptions): Promise<void>;
|
|
46
|
-
/**
|
|
47
|
-
* Write each generated artifact under `target`, under ONE ownership rule: **deploy only ever overwrites
|
|
48
|
-
* its own output.** Each generated file opens with a marker, so a file on disk is either OURS (a previous
|
|
49
|
-
* `deploy` wrote it) or the author's — and `--force` means "my generated artifact is authoritative",
|
|
50
|
-
* which never licenses clobbering a file we did not write. To hand a path back to fastagent, delete it.
|
|
51
|
-
*
|
|
52
|
-
* That single rule replaced a second mechanism (a per-host list of paths exempt from `--force`), which
|
|
53
|
-
* only described one shape: with the agent inside the workspace, the root `.dockerignore` is the
|
|
54
|
-
* WORKSPACE's file and was listed; with the agent flat, the list was empty — so `--force` would have
|
|
55
|
-
* overwritten a hand-written root `Dockerfile` in a repository `init --flat` had explicitly adopted.
|
|
56
|
-
* Ownership is a property of the file, not of where the agent sits.
|
|
57
|
-
*
|
|
58
|
-
* A KEPT file of OURS that no longer matches what deploy would generate now (config/channel/lockfile/
|
|
59
|
-
* version drift — or the author's edits, which we cannot tell apart) is flagged stale; `--force`
|
|
60
|
-
* regenerates that one.
|
|
61
|
-
*
|
|
62
|
-
* Exported for its own test — this is a four-branch state machine over (exists, ours, force) that used
|
|
63
|
-
* to be proven by spawning the CLI eight times, which is command LOGIC re-run through a subprocess
|
|
64
|
-
* (see vitest.config.ts) and the suite's slowest test.
|
|
65
|
-
*/
|
|
66
|
-
export declare function writeArtifacts(target: string, artifacts: {
|
|
67
|
-
path: string;
|
|
68
|
-
content: string;
|
|
69
|
-
}[], options: {
|
|
70
|
-
force: boolean;
|
|
71
|
-
alwaysWrite?: string[];
|
|
72
|
-
}): Promise<void>;
|
|
73
|
-
export {};
|