@fastagent-sh/fastagent 0.14.0 → 0.16.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 +16 -6
- package/dist/agent.d.ts +20 -0
- package/dist/agent.js +9 -0
- package/dist/channels/agentcore-limits.d.ts +7 -0
- package/dist/channels/agentcore-limits.js +9 -0
- package/dist/channels/agentcore-state.d.ts +83 -0
- package/dist/channels/agentcore-state.js +258 -0
- package/dist/channels/agentcore.d.ts +98 -0
- package/dist/channels/agentcore.js +260 -0
- package/dist/channels/busy.d.ts +23 -0
- package/dist/channels/busy.js +53 -0
- package/dist/channels/context-buffer.d.ts +35 -0
- package/dist/channels/context-buffer.js +103 -0
- package/dist/channels/control.d.ts +28 -0
- package/dist/channels/control.js +214 -0
- package/dist/channels/feishu/card.js +1 -1
- package/dist/channels/feishu/context-buffer.d.ts +15 -13
- package/dist/channels/feishu/context-buffer.js +62 -69
- package/dist/channels/feishu/feishu-api.d.ts +11 -3
- package/dist/channels/feishu/feishu-api.js +24 -3
- package/dist/channels/feishu/feishu.d.ts +27 -27
- package/dist/channels/feishu/feishu.js +318 -207
- package/dist/channels/feishu/invoke-turn.d.ts +7 -20
- package/dist/channels/feishu/invoke-turn.js +44 -79
- package/dist/channels/feishu/model.d.ts +2 -2
- package/dist/channels/feishu/normalize.d.ts +2 -1
- package/dist/channels/feishu/normalize.js +0 -1
- package/dist/channels/feishu/parse.d.ts +22 -8
- package/dist/channels/feishu/parse.js +24 -7
- package/dist/channels/feishu/preview.d.ts +4 -7
- package/dist/channels/feishu/preview.js +27 -142
- package/dist/channels/feishu/register-app.d.ts +2 -1
- package/dist/channels/feishu/register-webhook.d.ts +2 -1
- package/dist/channels/feishu/scaffold/channel.ts +9 -8
- package/dist/channels/feishu/scaffold/feishu-send.ts +6 -4
- package/dist/channels/feishu/setup-mode.d.ts +37 -0
- package/dist/channels/feishu/setup-mode.js +28 -0
- package/dist/channels/feishu/ws-ingress.d.ts +28 -0
- package/dist/channels/feishu/ws-ingress.js +136 -0
- package/dist/channels/github/github.js +16 -7
- package/dist/channels/http.d.ts +14 -0
- package/dist/channels/http.js +36 -3
- package/dist/channels/invoke-turn-kit.d.ts +65 -0
- package/dist/channels/invoke-turn-kit.js +87 -0
- package/dist/channels/lark/lark.d.ts +4 -2
- package/dist/channels/lark/lark.js +4 -1
- package/dist/channels/lark/onboard.d.ts +8 -4
- package/dist/channels/lark/onboard.js +8 -0
- package/dist/channels/lark/scaffold/channel.ts +9 -8
- package/dist/channels/lark/scaffold/lark-send.ts +6 -4
- package/dist/channels/preview-kit.d.ts +115 -0
- package/dist/channels/preview-kit.js +184 -0
- package/dist/channels/seen.d.ts +5 -0
- package/dist/channels/seen.js +35 -0
- package/dist/channels/slack/bot-auth.d.ts +15 -0
- package/dist/channels/slack/bot-auth.js +146 -0
- package/dist/channels/slack/config-api.d.ts +60 -0
- package/dist/channels/slack/config-api.js +149 -0
- package/dist/channels/slack/context-buffer.d.ts +24 -0
- package/dist/channels/slack/context-buffer.js +37 -0
- package/dist/channels/slack/invoke-turn.d.ts +19 -0
- package/dist/channels/slack/invoke-turn.js +63 -0
- package/dist/channels/slack/manifest.d.ts +49 -0
- package/dist/channels/slack/manifest.js +69 -0
- package/dist/channels/slack/model.d.ts +67 -0
- package/dist/channels/slack/model.js +2 -0
- package/dist/channels/slack/onboard.d.ts +41 -0
- package/dist/channels/slack/onboard.js +120 -0
- package/dist/channels/slack/onboarding-state.d.ts +31 -0
- package/dist/channels/slack/onboarding-state.js +69 -0
- package/dist/channels/slack/parse.d.ts +38 -0
- package/dist/channels/slack/parse.js +124 -0
- package/dist/channels/slack/preview.d.ts +23 -0
- package/dist/channels/slack/preview.js +403 -0
- package/dist/channels/slack/reaction.d.ts +24 -0
- package/dist/channels/slack/reaction.js +62 -0
- package/dist/channels/slack/register-webhook.d.ts +10 -0
- package/dist/channels/slack/register-webhook.js +49 -0
- package/dist/channels/slack/scaffold/channel.ts +33 -0
- package/dist/channels/slack/scaffold/slack-send.ts +171 -0
- package/dist/channels/slack/setup-server.d.ts +17 -0
- package/dist/channels/slack/setup-server.js +103 -0
- package/dist/channels/slack/slack-api.d.ts +57 -0
- package/dist/channels/slack/slack-api.js +399 -0
- package/dist/channels/slack/slack.d.ts +51 -0
- package/dist/channels/slack/slack.js +496 -0
- package/dist/channels/slack/welcomed.d.ts +5 -0
- package/dist/channels/slack/welcomed.js +32 -0
- package/dist/channels/state.d.ts +11 -4
- package/dist/channels/state.js +22 -15
- package/dist/channels/stop-command.d.ts +6 -0
- package/dist/channels/stop-command.js +36 -0
- package/dist/channels/tasks.d.ts +7 -0
- package/dist/channels/tasks.js +25 -0
- package/dist/channels/telegram/context-buffer.d.ts +8 -17
- package/dist/channels/telegram/context-buffer.js +6 -85
- package/dist/channels/telegram/invoke-turn.d.ts +5 -22
- package/dist/channels/telegram/invoke-turn.js +11 -58
- package/dist/channels/telegram/parse.d.ts +0 -7
- package/dist/channels/telegram/parse.js +4 -2
- package/dist/channels/telegram/preview.d.ts +4 -7
- package/dist/channels/telegram/preview.js +24 -142
- package/dist/channels/telegram/scaffold/telegram-send.ts +6 -3
- package/dist/channels/telegram/telegram.js +24 -10
- package/dist/channels/{feishu/text.d.ts → text.d.ts} +15 -1
- package/dist/channels/{feishu/text.js → text.js} +15 -1
- package/dist/channels/thread-participants.d.ts +21 -0
- package/dist/channels/thread-participants.js +132 -0
- package/dist/channels/turn-queue.js +8 -1
- package/dist/channels/turn-store.d.ts +1 -1
- package/dist/channels/turn-store.js +2 -3
- package/dist/cli/add-feishu.d.ts +30 -0
- package/dist/cli/add-feishu.js +366 -0
- package/dist/cli/add-slack.d.ts +11 -0
- package/dist/cli/add-slack.js +199 -0
- package/dist/{cli-auth.d.ts → cli/auth-view.d.ts} +1 -1
- package/dist/{cli-auth.js → cli/auth-view.js} +1 -1
- package/dist/cli/commands/add.d.ts +4 -0
- package/dist/cli/commands/add.js +191 -60
- package/dist/cli/commands/attach.d.ts +82 -0
- package/dist/cli/commands/attach.js +563 -0
- package/dist/cli/commands/chat.d.ts +1 -0
- package/dist/cli/commands/chat.js +12 -7
- package/dist/cli/commands/deploy.d.ts +3 -1
- package/dist/cli/commands/deploy.js +384 -82
- package/dist/cli/commands/dev.js +34 -26
- package/dist/cli/commands/fire.js +17 -18
- package/dist/cli/commands/info.js +36 -29
- package/dist/cli/commands/init.d.ts +1 -1
- package/dist/cli/commands/init.js +65 -53
- package/dist/cli/commands/invoke.js +11 -9
- package/dist/cli/commands/login.js +48 -45
- package/dist/cli/commands/models.js +1 -1
- package/dist/cli/commands/schedule.js +6 -8
- package/dist/cli/commands/start.js +102 -39
- package/dist/cli/commands/tool.js +23 -18
- package/dist/cli/fail.d.ts +17 -2
- package/dist/cli/fail.js +25 -1
- package/dist/{invoke-stream.d.ts → cli/invoke-stream.d.ts} +1 -1
- package/dist/{invoke-stream.js → cli/invoke-stream.js} +4 -0
- package/dist/cli/kernel.d.ts +3 -2
- package/dist/cli/models-view.d.ts +21 -0
- package/dist/cli/models-view.js +66 -0
- package/dist/cli/program.js +135 -56
- package/dist/cli/serve.d.ts +60 -20
- package/dist/cli/serve.js +252 -47
- package/dist/cli/shared.d.ts +40 -7
- package/dist/cli/shared.js +180 -38
- package/dist/collect.d.ts +14 -3
- package/dist/collect.js +24 -0
- package/dist/core.d.ts +3 -1
- package/dist/core.js +2 -0
- package/dist/deploy/agentcore/plan.d.ts +117 -0
- package/dist/deploy/agentcore/plan.js +721 -0
- package/dist/deploy/agentcore/run.d.ts +73 -0
- package/dist/deploy/agentcore/run.js +412 -0
- package/dist/deploy/agentcore/zip.d.ts +17 -0
- package/dist/deploy/agentcore/zip.js +68 -0
- package/dist/deploy/container.d.ts +26 -25
- package/dist/deploy/container.js +93 -89
- package/dist/deploy/docker/plan.d.ts +3 -3
- package/dist/deploy/docker/plan.js +20 -23
- package/dist/deploy/fly/plan.d.ts +5 -1
- package/dist/deploy/fly/plan.js +39 -26
- package/dist/deploy/fly/run.d.ts +17 -5
- package/dist/deploy/fly/run.js +52 -7
- package/dist/deploy/preflight.d.ts +20 -8
- package/dist/deploy/preflight.js +267 -71
- package/dist/deploy/railway/plan.d.ts +10 -1
- package/dist/deploy/railway/plan.js +53 -20
- package/dist/deploy/railway/run.d.ts +13 -5
- package/dist/deploy/railway/run.js +22 -7
- package/dist/deploy/runner.d.ts +7 -3
- package/dist/deploy/runner.js +9 -3
- package/dist/deploy/secrets.d.ts +2 -1
- package/dist/deploy/secrets.js +23 -3
- package/dist/dev-supervisor.d.ts +11 -10
- package/dist/dev-supervisor.js +56 -50
- package/dist/engines/pi/auth.d.ts +8 -7
- package/dist/engines/pi/auth.js +12 -10
- package/dist/engines/pi/channel.d.ts +22 -16
- package/dist/engines/pi/channel.js +92 -62
- package/dist/engines/pi/chat.d.ts +4 -16
- package/dist/engines/pi/chat.js +8 -261
- package/dist/engines/pi/config.d.ts +20 -55
- package/dist/engines/pi/config.js +49 -121
- package/dist/engines/pi/create.d.ts +30 -10
- package/dist/engines/pi/create.js +33 -26
- package/dist/engines/pi/definition.d.ts +7 -26
- package/dist/engines/pi/definition.js +8 -54
- package/dist/engines/pi/harness.d.ts +49 -0
- package/dist/engines/pi/harness.js +90 -2
- package/dist/engines/pi/invoke.d.ts +55 -2
- package/dist/engines/pi/invoke.js +304 -19
- package/dist/engines/pi/login.d.ts +12 -1
- package/dist/engines/pi/login.js +16 -4
- package/dist/engines/pi/models.d.ts +59 -13
- package/dist/engines/pi/models.js +62 -24
- package/dist/engines/pi/open.d.ts +114 -0
- package/dist/engines/pi/open.js +127 -0
- package/dist/engines/pi/session-builder.d.ts +16 -0
- package/dist/engines/pi/session-builder.js +308 -0
- package/dist/engines/pi/session-control.d.ts +50 -0
- package/dist/engines/pi/session-control.js +604 -0
- package/dist/engines/pi/sessions.d.ts +17 -2
- package/dist/engines/pi/sessions.js +9 -0
- package/dist/engines/pi/tool-context.d.ts +18 -11
- package/dist/engines/pi/tool-context.js +3 -9
- package/dist/engines/pi/tool.d.ts +6 -8
- package/dist/engines/pi/tool.js +10 -1
- package/dist/engines/pi/wake-tool.d.ts +0 -3
- package/dist/engines/pi/wake-tool.js +9 -7
- package/dist/env.d.ts +16 -4
- package/dist/env.js +43 -5
- package/dist/feishu.d.ts +1 -1
- package/dist/feishu.js +1 -1
- package/dist/host/node.d.ts +25 -8
- package/dist/host/node.js +5 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/lark.d.ts +1 -1
- package/dist/lark.js +1 -1
- package/dist/loader.d.ts +2 -2
- package/dist/loader.js +3 -3
- package/dist/log.d.ts +1 -1
- package/dist/log.js +1 -1
- package/dist/observe.js +3 -0
- package/dist/paths.d.ts +138 -0
- package/dist/paths.js +326 -0
- package/dist/pi.d.ts +6 -5
- package/dist/pi.js +4 -3
- package/dist/runtime.d.ts +7 -5
- package/dist/runtime.js +2 -2
- package/dist/scaffold/add-channel.d.ts +26 -9
- package/dist/scaffold/add-channel.js +175 -40
- package/dist/scaffold/init.d.ts +32 -41
- package/dist/scaffold/init.js +161 -185
- package/dist/scaffold/templates/env.example +15 -6
- package/dist/scaffold/templates/fastagent.config.mjs +5 -4
- package/dist/scaffold/templates/gitignore +14 -6
- package/dist/scaffold/templates/persona.md +4 -2
- package/dist/scaffold/templates/secrets.gitignore +5 -0
- package/dist/scaffold/templates.d.ts +1 -7
- package/dist/scaffold/templates.js +3 -25
- package/dist/scaffold/vendor-skill.d.ts +2 -2
- package/dist/scaffold/vendor-skill.js +13 -13
- package/dist/schedule/discover.js +4 -4
- package/dist/schedule/scheduler.d.ts +40 -1
- package/dist/schedule/scheduler.js +89 -56
- package/dist/schedule/state.js +1 -1
- package/dist/schedule/wake-alarm.d.ts +47 -0
- package/dist/schedule/wake-alarm.js +136 -0
- package/dist/schedule/wakeups.d.ts +1 -3
- package/dist/schedule/wakeups.js +19 -1
- package/dist/session-remote.d.ts +53 -0
- package/dist/session-remote.js +336 -0
- package/dist/session.d.ts +265 -0
- package/dist/session.js +37 -0
- package/dist/slack.d.ts +2 -0
- package/dist/slack.js +2 -0
- package/dist/tunnel.d.ts +7 -4
- package/dist/tunnel.js +23 -12
- package/package.json +22 -7
- package/dist/channels/feishu/owned-threads.d.ts +0 -11
- package/dist/channels/feishu/owned-threads.js +0 -47
- package/dist/channels/feishu/seen.d.ts +0 -5
- package/dist/channels/feishu/seen.js +0 -47
- package/dist/cli-add-feishu.d.ts +0 -8
- package/dist/cli-add-feishu.js +0 -223
- package/dist/cli-models.d.ts +0 -11
- package/dist/cli-models.js +0 -20
- package/dist/engines/pi/workspace.d.ts +0 -56
- package/dist/engines/pi/workspace.js +0 -72
- package/dist/scaffold/templates/gitignore.agentdir-root +0 -5
- package/dist/scaffold/templates/gitignore.kit +0 -2
- package/dist/workspace.d.ts +0 -9
- package/dist/workspace.js +0 -45
package/dist/tunnel.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `--tunnel`: expose the local dev server on a public HTTPS URL via a Cloudflare quick tunnel, then
|
|
3
|
-
* auto-register the first-party webhook channels against it (Telegram setWebhook;
|
|
4
|
-
* application-config PATCH; GitHub
|
|
3
|
+
* auto-register the first-party webhook channels against it (Telegram setWebhook; onboarded Slack
|
|
4
|
+
* App Manifest update; Feishu/Lark application-config PATCH; GitHub/manual Slack print URLs). This closes the
|
|
5
5
|
* "local dev → public URL" gap webhooks need.
|
|
6
6
|
*
|
|
7
7
|
* Process orchestration, not assembly — lives outside the engine, beside dev-supervisor.ts.
|
|
@@ -25,10 +25,13 @@ type SpawnCloudflared = (port: number) => ChildProcess;
|
|
|
25
25
|
*/
|
|
26
26
|
export declare function startCloudflareTunnel(port: number, spawnFn?: SpawnCloudflared, attemptTimeoutMs?: number): Promise<Tunnel | undefined>;
|
|
27
27
|
/**
|
|
28
|
-
* Print the public URL and wire up
|
|
29
|
-
* Feishu/Lark
|
|
28
|
+
* Print the public URL and wire up first-party webhook channels found under `dir` (the agent
|
|
29
|
+
* ROOT): Telegram and Feishu/Lark use runtime credentials; onboarded Slack uses its owner-local config
|
|
30
|
+
* token; GitHub and a manually scaffolded Slack app receive explicit console URLs.
|
|
30
31
|
*/
|
|
31
32
|
export declare function announceWebhooks(dir: string, baseUrl: string, opts?: {
|
|
32
33
|
openUrl?: (url: string) => void;
|
|
34
|
+
routeChannels?: string[];
|
|
35
|
+
stateRoot?: string;
|
|
33
36
|
}): Promise<void>;
|
|
34
37
|
export {};
|
package/dist/tunnel.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `--tunnel`: expose the local dev server on a public HTTPS URL via a Cloudflare quick tunnel, then
|
|
3
|
-
* auto-register the first-party webhook channels against it (Telegram setWebhook;
|
|
4
|
-
* application-config PATCH; GitHub
|
|
3
|
+
* auto-register the first-party webhook channels against it (Telegram setWebhook; onboarded Slack
|
|
4
|
+
* App Manifest update; Feishu/Lark application-config PATCH; GitHub/manual Slack print URLs). This closes the
|
|
5
5
|
* "local dev → public URL" gap webhooks need.
|
|
6
6
|
*
|
|
7
7
|
* Process orchestration, not assembly — lives outside the engine, beside dev-supervisor.ts.
|
|
@@ -10,8 +10,10 @@ import { spawn } from "node:child_process";
|
|
|
10
10
|
import { readdirSync } from "node:fs";
|
|
11
11
|
import { join } from "node:path";
|
|
12
12
|
import { registerFeishuWebhook } from "./channels/feishu/register-webhook.js";
|
|
13
|
+
import { registerSlackWebhook } from "./channels/slack/register-webhook.js";
|
|
13
14
|
import { registerTelegramWebhook } from "./channels/telegram/register-webhook.js";
|
|
14
|
-
import { loadDotEnv } from "./env.js";
|
|
15
|
+
import { dotEnvPath, loadDotEnv } from "./env.js";
|
|
16
|
+
import { resolveStateRoot } from "./paths.js";
|
|
15
17
|
import { log } from "./log.js";
|
|
16
18
|
// `(?!api\.)`: cloudflared's ERROR lines mention its request endpoint (`https://api.trycloudflare.com/tunnel`,
|
|
17
19
|
// e.g. "failed to request quick Tunnel: Post ... timeout" under a flaky proxy) — without the exclusion a
|
|
@@ -116,8 +118,9 @@ function channelBasenames(dir) {
|
|
|
116
118
|
}
|
|
117
119
|
}
|
|
118
120
|
/**
|
|
119
|
-
* Print the public URL and wire up
|
|
120
|
-
* Feishu/Lark
|
|
121
|
+
* Print the public URL and wire up first-party webhook channels found under `dir` (the agent
|
|
122
|
+
* ROOT): Telegram and Feishu/Lark use runtime credentials; onboarded Slack uses its owner-local config
|
|
123
|
+
* token; GitHub and a manually scaffolded Slack app receive explicit console URLs.
|
|
121
124
|
*/
|
|
122
125
|
export async function announceWebhooks(dir, baseUrl, opts = {}) {
|
|
123
126
|
log.info(`[fastagent] public URL: ${baseUrl}`);
|
|
@@ -130,27 +133,35 @@ export async function announceWebhooks(dir, baseUrl, opts = {}) {
|
|
|
130
133
|
// void-called with no unhandledRejection handler, so a throw here would terminate the process. Warn
|
|
131
134
|
// (surface it, rule 8) and continue best-effort; each registrar then surfaces its own
|
|
132
135
|
// missing-credential guidance. loadDotEnv keeps throwing for the synchronous command callers.
|
|
133
|
-
log.warn(`[fastagent] could not read ${
|
|
136
|
+
log.warn(`[fastagent] could not read ${dotEnvPath(dir)}: ${error.message} — continuing without it`);
|
|
134
137
|
}
|
|
135
|
-
|
|
136
|
-
|
|
138
|
+
// Serving passes the validated route-channel subset. The basename fallback preserves the public
|
|
139
|
+
// helper's behavior for callers that did not assemble channels first.
|
|
140
|
+
const routeChannels = opts.routeChannels ?? channelBasenames(dir);
|
|
141
|
+
if (routeChannels.length === 0)
|
|
137
142
|
return;
|
|
138
143
|
// Readiness is the registrar's job now: a fresh quick tunnel returns Cloudflare 530 for ~20-30s before
|
|
139
144
|
// its origin connects, and the automatic registrars poll /health before configuring the platform (the
|
|
140
145
|
// same wait the deploy runners rely on). GitHub needs no wait — the operator adds that webhook by hand.
|
|
141
|
-
if (
|
|
146
|
+
if (routeChannels.includes("telegram"))
|
|
142
147
|
await registerTelegramWebhook(baseUrl);
|
|
143
|
-
if (
|
|
148
|
+
if (routeChannels.includes("github")) {
|
|
144
149
|
log.info(`[fastagent] github: add a webhook in your repo (Settings → Webhooks): Payload URL = ${baseUrl}/webhook, content type application/json, secret = GITHUB_WEBHOOK_SECRET`);
|
|
145
150
|
}
|
|
151
|
+
if (routeChannels.includes("slack")) {
|
|
152
|
+
await registerSlackWebhook(baseUrl, {
|
|
153
|
+
stateRoot: opts.stateRoot ?? resolveStateRoot(dir),
|
|
154
|
+
log: (message) => log.info(message),
|
|
155
|
+
});
|
|
156
|
+
}
|
|
146
157
|
// feishu/lark register programmatically too (application-v7 config PATCH — telegram-setWebhook
|
|
147
158
|
// parity), once per mounted kind (each kind is its own app with its own credentials); the registrar
|
|
148
159
|
// owns its own health wait and degrades to the manual console instruction.
|
|
149
160
|
const feishuOptions = {
|
|
150
161
|
onManualRegistration: ({ consoleUrl }) => opts.openUrl?.(consoleUrl),
|
|
151
162
|
};
|
|
152
|
-
if (
|
|
163
|
+
if (routeChannels.includes("feishu"))
|
|
153
164
|
await registerFeishuWebhook(baseUrl, "feishu", feishuOptions);
|
|
154
|
-
if (
|
|
165
|
+
if (routeChannels.includes("lark"))
|
|
155
166
|
await registerFeishuWebhook(baseUrl, "lark", feishuOptions);
|
|
156
167
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fastagent-sh/fastagent",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Vibe first. Then FastAgent: turn a local agent directory into a live service in your app, on GitHub,
|
|
3
|
+
"version": "0.16.0",
|
|
4
|
+
"description": "Vibe first. Then FastAgent: turn a local agent directory into a live service in your app, on GitHub, Telegram, Slack, or behind any channel.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
7
7
|
"ai-agent",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"agent-skills",
|
|
11
11
|
"agent-serving",
|
|
12
12
|
"telegram",
|
|
13
|
+
"slack",
|
|
13
14
|
"github",
|
|
14
15
|
"webhook",
|
|
15
16
|
"sse",
|
|
@@ -42,6 +43,10 @@
|
|
|
42
43
|
"types": "./dist/core.d.ts",
|
|
43
44
|
"default": "./dist/core.js"
|
|
44
45
|
},
|
|
46
|
+
"./session": {
|
|
47
|
+
"types": "./dist/session.d.ts",
|
|
48
|
+
"default": "./dist/session.js"
|
|
49
|
+
},
|
|
45
50
|
"./pi": {
|
|
46
51
|
"types": "./dist/pi.d.ts",
|
|
47
52
|
"default": "./dist/pi.js"
|
|
@@ -54,6 +59,10 @@
|
|
|
54
59
|
"types": "./dist/telegram.d.ts",
|
|
55
60
|
"default": "./dist/telegram.js"
|
|
56
61
|
},
|
|
62
|
+
"./slack": {
|
|
63
|
+
"types": "./dist/slack.d.ts",
|
|
64
|
+
"default": "./dist/slack.js"
|
|
65
|
+
},
|
|
57
66
|
"./feishu": {
|
|
58
67
|
"types": "./dist/feishu.d.ts",
|
|
59
68
|
"default": "./dist/feishu.js"
|
|
@@ -82,15 +91,20 @@
|
|
|
82
91
|
"prepack": "npm run build",
|
|
83
92
|
"test": "vitest --run",
|
|
84
93
|
"typecheck": "tsc --noEmit",
|
|
85
|
-
"lint": "biome check src test && node scripts/check-doc-links.mjs",
|
|
94
|
+
"lint": "biome check src test && node scripts/check-doc-links.mjs && knip",
|
|
86
95
|
"format": "biome check --write src test",
|
|
87
|
-
"postbuild": "node scripts/copy-scaffold-assets.mjs"
|
|
96
|
+
"postbuild": "node scripts/copy-scaffold-assets.mjs",
|
|
97
|
+
"release:patch": "node scripts/release.mjs patch",
|
|
98
|
+
"release:minor": "node scripts/release.mjs minor",
|
|
99
|
+
"release:major": "node scripts/release.mjs major",
|
|
100
|
+
"knip": "knip"
|
|
88
101
|
},
|
|
89
102
|
"dependencies": {
|
|
90
103
|
"@clack/prompts": "^1.6.0",
|
|
91
|
-
"@earendil-works/pi-agent-core": "^0.
|
|
92
|
-
"@earendil-works/pi-ai": "^0.
|
|
93
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
104
|
+
"@earendil-works/pi-agent-core": "^0.81.1",
|
|
105
|
+
"@earendil-works/pi-ai": "^0.81.1",
|
|
106
|
+
"@earendil-works/pi-coding-agent": "^0.81.1",
|
|
107
|
+
"@larksuiteoapi/node-sdk": "^1.71.1",
|
|
94
108
|
"@octokit/webhooks-methods": "^6.0.0",
|
|
95
109
|
"@octokit/webhooks-types": "^7.6.1",
|
|
96
110
|
"chokidar": "^5.0.0",
|
|
@@ -105,6 +119,7 @@
|
|
|
105
119
|
"devDependencies": {
|
|
106
120
|
"@biomejs/biome": "^2.5.2",
|
|
107
121
|
"@types/proper-lockfile": "^4.1.4",
|
|
122
|
+
"knip": "^6.29.0",
|
|
108
123
|
"typescript": "^7.0.2",
|
|
109
124
|
"vitest": "^4.1.9"
|
|
110
125
|
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export interface OwnedFeishuThread {
|
|
2
|
-
rootId: string;
|
|
3
|
-
chatId: string;
|
|
4
|
-
createdAt: number;
|
|
5
|
-
}
|
|
6
|
-
export interface OwnedFeishuThreads {
|
|
7
|
-
has(chatId: string, rootId: string): boolean;
|
|
8
|
-
/** Idempotent, synchronous, pre-ACK persistence. A failed write throws so the platform redelivers. */
|
|
9
|
-
add(chatId: string, rootId: string): void;
|
|
10
|
-
}
|
|
11
|
-
export declare function createOwnedFeishuThreads(path: string, label: string, now?: () => number): OwnedFeishuThreads;
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Durable ownership index for group threads the channel created from a top-level summon. Feishu/Lark
|
|
3
|
-
* deliver an ordinary thread continuation as `thread_id + root_id`; the root is the original user
|
|
4
|
-
* message the channel reply-threaded under. Keeping that root across restarts lets the default route
|
|
5
|
-
* admit unmentioned continuations only inside Agent-managed threads, never across the whole group.
|
|
6
|
-
*/
|
|
7
|
-
import { log } from "../../log.js";
|
|
8
|
-
import { loadStateFile, saveStateFile } from "../state.js";
|
|
9
|
-
function isRecord(value) {
|
|
10
|
-
const record = value;
|
|
11
|
-
return (typeof record?.rootId === "string" &&
|
|
12
|
-
typeof record.chatId === "string" &&
|
|
13
|
-
typeof record.createdAt === "number" &&
|
|
14
|
-
Number.isFinite(record.createdAt));
|
|
15
|
-
}
|
|
16
|
-
export function createOwnedFeishuThreads(path, label, now = Date.now) {
|
|
17
|
-
const raw = loadStateFile(path);
|
|
18
|
-
let records = new Map();
|
|
19
|
-
if (raw !== undefined) {
|
|
20
|
-
if (typeof raw === "object" &&
|
|
21
|
-
raw !== null &&
|
|
22
|
-
!Array.isArray(raw) &&
|
|
23
|
-
Object.entries(raw).every(([rootId, record]) => isRecord(record) && record.rootId === rootId)) {
|
|
24
|
-
records = new Map(Object.entries(raw));
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
log.warn(`${label} unexpected shape in ${path} — starting with no managed group threads`);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
return {
|
|
31
|
-
has(chatId, rootId) {
|
|
32
|
-
const record = records.get(rootId);
|
|
33
|
-
return record?.chatId === chatId;
|
|
34
|
-
},
|
|
35
|
-
add(chatId, rootId) {
|
|
36
|
-
const existing = records.get(rootId);
|
|
37
|
-
if (existing?.chatId === chatId)
|
|
38
|
-
return;
|
|
39
|
-
const next = new Map(records);
|
|
40
|
-
next.set(rootId, { rootId, chatId, createdAt: now() });
|
|
41
|
-
// Persist the staged copy first: an IO failure must not leave memory claiming durability the file
|
|
42
|
-
// does not have. The webhook remains un-ACKed and the platform can redeliver after recovery.
|
|
43
|
-
saveStateFile(path, Object.fromEntries(next));
|
|
44
|
-
records = next;
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bounded delivery dedup for message_ids whose webhook handling produced a durable side effect: either
|
|
3
|
-
* an accepted turn intent or a buffered group-context entry. Feishu/Lark document duplicate pushes even
|
|
4
|
-
* after a successful 200 and recommend idempotency on message_id (not event_id). The unfinished-turn
|
|
5
|
-
* store cannot cover a duplicate after completion, and a duplicated background event would otherwise be
|
|
6
|
-
* folded twice.
|
|
7
|
-
*
|
|
8
|
-
* Record only AFTER the pre-ACK side effect is durable: recording first could turn a later state-write
|
|
9
|
-
* failure into silent loss when the platform redelivers. The ring write is best-effort post-persist
|
|
10
|
-
* insurance. A crash between the two writes, a ring-write failure, or an id older than the bounded cap
|
|
11
|
-
* retains L1's at-least-once tail; this is dedup, not exactly-once execution.
|
|
12
|
-
*/
|
|
13
|
-
import { log } from "../../log.js";
|
|
14
|
-
import { loadStateFile, saveStateFile } from "../state.js";
|
|
15
|
-
export function createSeenRing(path, label = "[feishu]", cap = 2000) {
|
|
16
|
-
const load = () => {
|
|
17
|
-
const raw = loadStateFile(path);
|
|
18
|
-
if (raw === undefined)
|
|
19
|
-
return [];
|
|
20
|
-
if (Array.isArray(raw) && raw.every((id) => typeof id === "string"))
|
|
21
|
-
return raw.slice(-cap);
|
|
22
|
-
log.warn(`${label} unexpected shape in ${path} — starting with no seen ids`);
|
|
23
|
-
return [];
|
|
24
|
-
};
|
|
25
|
-
const order = load();
|
|
26
|
-
const ids = new Set(order);
|
|
27
|
-
return {
|
|
28
|
-
has: (id) => ids.has(id),
|
|
29
|
-
add(id) {
|
|
30
|
-
if (ids.has(id))
|
|
31
|
-
return;
|
|
32
|
-
ids.add(id);
|
|
33
|
-
order.push(id);
|
|
34
|
-
while (order.length > cap) {
|
|
35
|
-
const evicted = order.shift();
|
|
36
|
-
if (evicted !== undefined)
|
|
37
|
-
ids.delete(evicted);
|
|
38
|
-
}
|
|
39
|
-
try {
|
|
40
|
-
saveStateFile(path, order);
|
|
41
|
-
}
|
|
42
|
-
catch (error) {
|
|
43
|
-
log.warn(`${label} seen-ring write failed (delivery dedup is in-memory until restart): ${String(error)}`);
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
};
|
|
47
|
-
}
|
package/dist/cli-add-feishu.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Create or resume the platform app behind `add feishu` / `add lark`. Returns credentials for the
|
|
3
|
-
* caller's generic .env write (the guided Lark path), or undefined when nothing remains to write —
|
|
4
|
-
* the feishu path persists its own two credential stages internally (the App ID/Secret boundary is
|
|
5
|
-
* irreversible and must not wait for the caller). Throws on refusal (a committable .env, a
|
|
6
|
-
* non-interactive lark run); the caller surfaces that as a startup failure.
|
|
7
|
-
*/
|
|
8
|
-
export declare function onboardFeishuCloudApp(target: string, kind: "feishu" | "lark", envIgnored: boolean): Promise<Record<string, string> | undefined>;
|
package/dist/cli-add-feishu.js
DELETED
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `fastagent add feishu|lark` app onboarding — the cloud-facing half of runAdd, kept out of cli.ts
|
|
3
|
-
* (which self-executes on import), mirroring cli-models.ts/cli-auth.ts. The POLICY already lives in
|
|
4
|
-
* testable modules (register-app.ts, bootstrap-token.ts, lark/onboard.ts); this layer is the terminal
|
|
5
|
-
* wiring: clack prompts, .env staging, browser opens, progress lines.
|
|
6
|
-
*
|
|
7
|
-
* Feishu (scan-to-create): the device flow creates the app; App ID/Secret are persisted at the
|
|
8
|
-
* irreversible creation boundary, then the Verification Token is captured over a throwaway tunnel and
|
|
9
|
-
* persisted as a second stage — a re-run RESUMES the app instead of minting another. Lark
|
|
10
|
-
* (guided-console): open the unbound launcher, validate entered credentials, probe the same
|
|
11
|
-
* webhook/token bootstrap, and fall back to a manual token prompt on the definitive config-route 404.
|
|
12
|
-
*/
|
|
13
|
-
import { readFile } from "node:fs/promises";
|
|
14
|
-
import { join } from "node:path";
|
|
15
|
-
import { isCancel, log as clackLog, password, text as clackText } from "@clack/prompts";
|
|
16
|
-
import { bootstrapFeishuVerificationToken } from "./channels/feishu/bootstrap-token.js";
|
|
17
|
-
import { cloudFor } from "./channels/feishu/cloud.js";
|
|
18
|
-
import { createFeishuApi, isFeishuConfigApiMissing, isTransientFeishuRegistrationError, } from "./channels/feishu/feishu-api.js";
|
|
19
|
-
import { registerFeishuApp } from "./channels/feishu/register-app.js";
|
|
20
|
-
import { onboardLarkApp } from "./channels/lark/onboard.js";
|
|
21
|
-
import { parseEnvContent } from "./env.js";
|
|
22
|
-
import { openExternalUrl } from "./open-url.js";
|
|
23
|
-
import { appendChannelDotEnv } from "./scaffold/add-channel.js";
|
|
24
|
-
import { startCloudflareTunnel } from "./tunnel.js";
|
|
25
|
-
/**
|
|
26
|
-
* Create or resume the platform app behind `add feishu` / `add lark`. Returns credentials for the
|
|
27
|
-
* caller's generic .env write (the guided Lark path), or undefined when nothing remains to write —
|
|
28
|
-
* the feishu path persists its own two credential stages internally (the App ID/Secret boundary is
|
|
29
|
-
* irreversible and must not wait for the caller). Throws on refusal (a committable .env, a
|
|
30
|
-
* non-interactive lark run); the caller surfaces that as a startup failure.
|
|
31
|
-
*/
|
|
32
|
-
export async function onboardFeishuCloudApp(target, kind, envIgnored) {
|
|
33
|
-
const { envPrefix, apiBase, capabilities } = cloudFor(kind);
|
|
34
|
-
// The CLI must never materialize a real credential into a committable file — refuse, don't warn.
|
|
35
|
-
if (!envIgnored) {
|
|
36
|
-
throw new Error(kind === "feishu"
|
|
37
|
-
? "`add feishu` creates an app and writes real credentials to .env — add .env to .gitignore/.fastagentignore first, then re-run"
|
|
38
|
-
: "`add lark` writes real app credentials to .env — add .env to .gitignore/.fastagentignore first, then re-run");
|
|
39
|
-
}
|
|
40
|
-
const existing = await activeDotEnvValues(target, [
|
|
41
|
-
`${envPrefix}_APP_ID`,
|
|
42
|
-
`${envPrefix}_APP_SECRET`,
|
|
43
|
-
`${envPrefix}_VERIFICATION_TOKEN`,
|
|
44
|
-
]);
|
|
45
|
-
if (Object.keys(existing).length === 3) {
|
|
46
|
-
console.error(`[fastagent] ${envPrefix}_APP_ID/SECRET/VERIFICATION_TOKEN already set in .env — keeping them`);
|
|
47
|
-
return undefined;
|
|
48
|
-
}
|
|
49
|
-
if (capabilities.appCreation === "scan-to-create") {
|
|
50
|
-
await createFeishuAppFlow(target, existing);
|
|
51
|
-
return undefined;
|
|
52
|
-
}
|
|
53
|
-
// guided-console (lark): the intl cloud cannot complete the bound device flow — collect + validate.
|
|
54
|
-
if (!(process.stdin.isTTY && process.stdout.isTTY)) {
|
|
55
|
-
throw new Error("`add lark` needs an interactive terminal to onboard the Lark app credentials — re-run it in a terminal");
|
|
56
|
-
}
|
|
57
|
-
return onboardLarkApp({
|
|
58
|
-
openUrl: openExternalUrl,
|
|
59
|
-
note: (message) => clackLog.info(message),
|
|
60
|
-
async prompt(message, opts) {
|
|
61
|
-
const result = opts?.hidden ? await password({ message }) : await clackText({ message });
|
|
62
|
-
return isCancel(result) ? undefined : result;
|
|
63
|
-
},
|
|
64
|
-
}, {
|
|
65
|
-
existing,
|
|
66
|
-
verifyCredentials: async (appId, appSecret) => {
|
|
67
|
-
await createFeishuApi({ kind: "lark", baseUrl: apiBase, appId, appSecret }).verifyCredentials();
|
|
68
|
-
console.error(`[fastagent] Lark App ID / Secret verified`);
|
|
69
|
-
},
|
|
70
|
-
bootstrapWebhook: async (appId, appSecret) => {
|
|
71
|
-
const api = createFeishuApi({ kind: "lark", baseUrl: apiBase, appId, appSecret });
|
|
72
|
-
console.error(`[fastagent] trying Lark's webhook-mode + Verification-Token bootstrap (temporary tunnel)…`);
|
|
73
|
-
try {
|
|
74
|
-
const token = await bootstrapFeishuVerificationToken({
|
|
75
|
-
api,
|
|
76
|
-
appId,
|
|
77
|
-
kind: "lark",
|
|
78
|
-
startTunnel: (port) => startCloudflareTunnel(port),
|
|
79
|
-
onTunnelReady: (url) => console.error(`[fastagent] temporary tunnel ready → ${url}; registering webhook mode now…`),
|
|
80
|
-
onPatchRetry: ({ error, attempt, attempts, retryMs }) => console.error(`[fastagent] Lark could not validate the fresh tunnel yet (${String(error)}); retrying PATCH ${attempt + 1}/${attempts} in ${Math.round(retryMs / 1000)}s…`),
|
|
81
|
-
// A route-level 404 is definitive, not edge weather: fall back immediately. Retry only
|
|
82
|
-
// actual edge/network weather; scope/auth/config failures remain immediate.
|
|
83
|
-
shouldRetryPatch: (error) => !isFeishuConfigApiMissing(error) && isTransientFeishuRegistrationError(error),
|
|
84
|
-
});
|
|
85
|
-
console.error(`[fastagent] Lark Verification Token captured; Subscription mode changed to webhook in the app draft`);
|
|
86
|
-
return { token };
|
|
87
|
-
}
|
|
88
|
-
catch (error) {
|
|
89
|
-
if (!isFeishuConfigApiMissing(error))
|
|
90
|
-
throw error;
|
|
91
|
-
const manualReason = "This Lark app returned HTTP 404 for the application-config API, so automatic mode/token bootstrap is unavailable.";
|
|
92
|
-
console.error(`[fastagent] ${manualReason}`);
|
|
93
|
-
return { manualReason };
|
|
94
|
-
}
|
|
95
|
-
},
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* The scan-to-create flow `add feishu` runs by default. The device-authorization grant
|
|
100
|
-
* creates a pre-configured agent app (bot capability, messaging scopes, event subscriptions) when the
|
|
101
|
-
* user confirms a link in the app, and hands back the credentials; App ID/Secret are persisted at that
|
|
102
|
-
* irreversible boundary before the platform-generated Verification Token is captured from the
|
|
103
|
-
* registration challenge (bootstrap-token.ts). The Token is persisted as a second stage, so .env is
|
|
104
|
-
* complete before the one remaining version-publish action. The event Request URL is NOT left pointing at the throwaway
|
|
105
|
-
* tunnel for long: `dev --tunnel` / `deploy --run` re-register it against the live URL.
|
|
106
|
-
*
|
|
107
|
-
* Feishu is the reference cloud and the only kind that runs this BOUND device flow. Lark is an explicit
|
|
108
|
-
* compatibility profile: its lagging control plane uses the unbound launcher + guided credentials,
|
|
109
|
-
* then probes the canonical token/mode bootstrap with a manual fallback.
|
|
110
|
-
*/
|
|
111
|
-
async function createFeishuAppFlow(target, existing) {
|
|
112
|
-
const { apiBase } = cloudFor("feishu");
|
|
113
|
-
let appId = existing.FEISHU_APP_ID;
|
|
114
|
-
let appSecret = existing.FEISHU_APP_SECRET;
|
|
115
|
-
if (appId && appSecret) {
|
|
116
|
-
console.error(`[fastagent] resuming Feishu app ${appId} from .env to capture its missing Verification Token`);
|
|
117
|
-
}
|
|
118
|
-
else {
|
|
119
|
-
console.error(`[fastagent] creating the Feishu app (confirm in the app)…`);
|
|
120
|
-
const app = await registerFeishuApp({
|
|
121
|
-
name: "{user}'s agent", // the platform expands {user} to the confirming user's name; editable on the page
|
|
122
|
-
desc: "Served by fastagent",
|
|
123
|
-
// The agent template alone is not enough to SERVE: the v7 config PATCH (webhook auto-registration
|
|
124
|
-
// in `dev --tunnel` / `deploy --run`) demands application:application:patch, and the app must
|
|
125
|
-
// subscribe the receive event. Addons merge both onto the confirm page — no manual app setup.
|
|
126
|
-
addons: {
|
|
127
|
-
scopes: { tenant: ["application:application:patch"] },
|
|
128
|
-
events: { items: { tenant: ["im.message.receive_v1"] } },
|
|
129
|
-
},
|
|
130
|
-
onVerificationUrl: ({ url, expiresInS }) => {
|
|
131
|
-
console.error(`\n Opening the confirmation link in your browser (or open it in Feishu / render it as a QR code) — valid for ${Math.round(expiresInS / 60)} minutes:\n\n ${url}\n\n waiting for confirmation… (keep this running — the credentials are delivered here)`);
|
|
132
|
-
openExternalUrl(url); // best-effort, like `login` — the URL above is the fallback
|
|
133
|
-
},
|
|
134
|
-
});
|
|
135
|
-
console.error(`[fastagent] app created: ${app.appId}${app.tenantBrand ? ` (${app.tenantBrand} tenant)` : ""}`);
|
|
136
|
-
// A cross-brand confirmation should be impossible (each confirm page refuses the other brand's
|
|
137
|
-
// code) — but if the platform ever reports one, the credentials would land in the WRONG kind's env
|
|
138
|
-
// namespace and serve the wrong cloud. Fail visibly instead of writing them.
|
|
139
|
-
if (app.tenantBrand && app.tenantBrand !== "feishu") {
|
|
140
|
-
throw new Error(`the confirming account is a ${app.tenantBrand} tenant, but this is \`add feishu\` — run \`fastagent add ${app.tenantBrand}\` instead`);
|
|
141
|
-
}
|
|
142
|
-
appId = app.appId;
|
|
143
|
-
appSecret = app.appSecret;
|
|
144
|
-
// IRREVERSIBLE BOUNDARY: the remote app now exists and its one-time Secret is in memory. Persist
|
|
145
|
-
// both before any config read, temporary tunnel, or Token bootstrap can be interrupted. Partial old
|
|
146
|
-
// lines are overwritten because these newly-minted credentials are authoritative as one pair.
|
|
147
|
-
await appendChannelDotEnv(target, "feishu", {
|
|
148
|
-
FEISHU_APP_ID: appId,
|
|
149
|
-
FEISHU_APP_SECRET: appSecret,
|
|
150
|
-
// A Token from a partial OLD credential set belongs to another App. Clear it at the same
|
|
151
|
-
// boundary; successful bootstrap below replaces the empty line with this App's Token.
|
|
152
|
-
FEISHU_VERIFICATION_TOKEN: "",
|
|
153
|
-
}, ["FEISHU_APP_ID", "FEISHU_APP_SECRET", "FEISHU_VERIFICATION_TOKEN"]);
|
|
154
|
-
console.error(`[fastagent] wrote FEISHU_APP_ID, FEISHU_APP_SECRET to .env before Token bootstrap`);
|
|
155
|
-
}
|
|
156
|
-
// The webhook channel authenticates plaintext events by the platform-generated Verification Token.
|
|
157
|
-
// Try the cheap read first (the v6 detail MAY someday return `encryption`), then the real path: the
|
|
158
|
-
// token's only programmatic delivery is the url_verification challenge during registration — capture
|
|
159
|
-
// it over a throwaway tunnel (bootstrap-token.ts). Failing both is a one-line manual copy; the staged
|
|
160
|
-
// ID/Secret pair makes a re-run resume this App rather than mint another one.
|
|
161
|
-
const tokenVar = "FEISHU_VERIFICATION_TOKEN";
|
|
162
|
-
const api = createFeishuApi({ baseUrl: apiBase, appId, appSecret });
|
|
163
|
-
let token;
|
|
164
|
-
let webhookModeChanged = false;
|
|
165
|
-
try {
|
|
166
|
-
const cfg = await api.getAppConfig(appId);
|
|
167
|
-
token = cfg.verificationToken;
|
|
168
|
-
}
|
|
169
|
-
catch {
|
|
170
|
-
/* the read surface is best-effort — the bootstrap below is the real path */
|
|
171
|
-
}
|
|
172
|
-
if (!token) {
|
|
173
|
-
console.error(`[fastagent] capturing the Verification Token — a throwaway webhook registration delivers it (spinning up a temporary tunnel; can take a few minutes on a slow edge)…`);
|
|
174
|
-
try {
|
|
175
|
-
token = await bootstrapFeishuVerificationToken({
|
|
176
|
-
api,
|
|
177
|
-
appId,
|
|
178
|
-
startTunnel: (port) => startCloudflareTunnel(port),
|
|
179
|
-
});
|
|
180
|
-
webhookModeChanged = true;
|
|
181
|
-
console.error(`[fastagent] Verification Token captured`);
|
|
182
|
-
}
|
|
183
|
-
catch (e) {
|
|
184
|
-
// Transient tunnel weather is the usual cause. Do NOT suggest re-running `add feishu` as a new
|
|
185
|
-
// scan: the staged pair makes the re-run resume THIS app; manual copy completes it too.
|
|
186
|
-
console.error(`[fastagent] warn: could not capture the Verification Token: ${String(e)} — usually a transient tunnel issue; finish this app with the manual copy below`);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
if (token) {
|
|
190
|
-
// Persist the second credential stage immediately too — opening the publish page and generic
|
|
191
|
-
// scaffold finalization happen only after the complete runtime credential set is durable.
|
|
192
|
-
const staged = await appendChannelDotEnv(target, "feishu", { [tokenVar]: token }, [tokenVar]);
|
|
193
|
-
console.error(`[fastagent] wrote ${staged.written.join(", ")} to .env`);
|
|
194
|
-
}
|
|
195
|
-
else {
|
|
196
|
-
console.error(`[fastagent] copy it manually: developer console → Events & Callbacks → Encryption Strategy → Verification Token → ${tokenVar} in .env`);
|
|
197
|
-
}
|
|
198
|
-
if (webhookModeChanged) {
|
|
199
|
-
// The bootstrap's PATCH flipped event mode in the DRAFT. It takes effect only after a version
|
|
200
|
-
// publish, which has no API; later dev/deploy runs change only the Request URL immediately.
|
|
201
|
-
const versionUrl = `${apiBase}/app/${appId}/version`;
|
|
202
|
-
console.error(`[fastagent] one console click remains: CREATE + PUBLISH a version (self-approved) — the switch to webhook mode takes effect on publish. Opening ${versionUrl}`);
|
|
203
|
-
openExternalUrl(versionUrl);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
/** Active run-root `.env` values for the requested names — decided by THE .env parser, so this
|
|
207
|
-
* check can never disagree with what `loadEnvFile` reads. Empty/commented values are absent. */
|
|
208
|
-
async function activeDotEnvValues(dir, names) {
|
|
209
|
-
let content;
|
|
210
|
-
try {
|
|
211
|
-
content = await readFile(join(dir, ".env"), "utf8");
|
|
212
|
-
}
|
|
213
|
-
catch (e) {
|
|
214
|
-
if (e.code === "ENOENT")
|
|
215
|
-
return {};
|
|
216
|
-
throw e;
|
|
217
|
-
}
|
|
218
|
-
const parsed = parseEnvContent(content);
|
|
219
|
-
return Object.fromEntries(names.flatMap((name) => {
|
|
220
|
-
const value = parsed.get(name)?.trim();
|
|
221
|
-
return value ? [[name, value]] : [];
|
|
222
|
-
}));
|
|
223
|
-
}
|
package/dist/cli-models.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CLI presenter for `fastagent models [search]`: the stdout/stderr output DECISION, kept out of the
|
|
3
|
-
* engine config layer (config.ts owns model resolution / listModels) so this process-boundary behavior
|
|
4
|
-
* is unit-testable without spawning the CLI.
|
|
5
|
-
*/
|
|
6
|
-
/** The output of `fastagent models [search]`: the spec `lines` to print to stdout (a case-insensitive
|
|
7
|
-
* substring filter; no search → all), and an stderr `error` diagnostic when a search matches nothing. */
|
|
8
|
-
export declare function formatModelsCommand(specs: string[], search?: string): {
|
|
9
|
-
lines: string[];
|
|
10
|
-
error?: string;
|
|
11
|
-
};
|
package/dist/cli-models.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CLI presenter for `fastagent models [search]`: the stdout/stderr output DECISION, kept out of the
|
|
3
|
-
* engine config layer (config.ts owns model resolution / listModels) so this process-boundary behavior
|
|
4
|
-
* is unit-testable without spawning the CLI.
|
|
5
|
-
*/
|
|
6
|
-
/** The output of `fastagent models [search]`: the spec `lines` to print to stdout (a case-insensitive
|
|
7
|
-
* substring filter; no search → all), and an stderr `error` diagnostic when a search matches nothing. */
|
|
8
|
-
export function formatModelsCommand(specs, search) {
|
|
9
|
-
if (!search)
|
|
10
|
-
return { lines: specs };
|
|
11
|
-
const q = search.toLowerCase();
|
|
12
|
-
const matches = specs.filter((spec) => spec.toLowerCase().includes(q));
|
|
13
|
-
if (matches.length === 0)
|
|
14
|
-
return { lines: matches, error: `no model matches "${search}"` };
|
|
15
|
-
// Rank a PROVIDER-name match (query in the part before "/") above an incidental model-id match, so
|
|
16
|
-
// `models anthropic` leads with anthropic/* rather than burying it under amazon-bedrock/anthropic.*
|
|
17
|
-
// and google-vertex/…-anthropic-… (which only match in the model id). Order within each group is kept.
|
|
18
|
-
const providerMatch = (spec) => spec.slice(0, spec.indexOf("/")).toLowerCase().includes(q);
|
|
19
|
-
return { lines: [...matches.filter(providerMatch), ...matches.filter((s) => !providerMatch(s))] };
|
|
20
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import type { Agent } from "../../agent.ts";
|
|
2
|
-
import { type FastagentConfig } from "./config.ts";
|
|
3
|
-
import type { ModuleLoadFailure } from "../../loader.ts";
|
|
4
|
-
import { type LoadedDefinition } from "./definition.ts";
|
|
5
|
-
import type { ToolCollision } from "./tool.ts";
|
|
6
|
-
export interface CreatePiAgentFromWorkspaceOptions {
|
|
7
|
-
/** Model spec override (e.g. the CLI --model flag). Precedence: this > FASTAGENT_MODEL > config.model. */
|
|
8
|
-
model?: string;
|
|
9
|
-
/**
|
|
10
|
-
* Session store directory. Default `<dir>/.fastagent/sessions` (gitignored machine state). `start`
|
|
11
|
-
* overrides it (--sessions-dir / FASTAGENT_SESSIONS_DIR / a mounted volume) so production continuity
|
|
12
|
-
* survives redeploys.
|
|
13
|
-
*/
|
|
14
|
-
sessionsDir?: string;
|
|
15
|
-
/**
|
|
16
|
-
* Credentials file override. Default `<dir>/.fastagent/auth.json` (project-level, gitignored under
|
|
17
|
-
* the same `*`-ignored `.fastagent`). Override via --auth-path / FASTAGENT_AUTH_PATH; point it at
|
|
18
|
-
* `~/.fastagent/auth.json` to share one credential across projects.
|
|
19
|
-
*/
|
|
20
|
-
authPath?: string;
|
|
21
|
-
/**
|
|
22
|
-
* This is a long-running SERVE (`dev`/`start`), where the scheduler poller runs — so a self-scheduled
|
|
23
|
-
* wake-up is actually honored. One-shot entries (`invoke`/`fire`) leave it off (they exit after the turn
|
|
24
|
-
* and never poll). The built-in `wake` tool mounts only when this is set AND `config.selfSchedule` is on.
|
|
25
|
-
*/
|
|
26
|
-
serving?: boolean;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* "Point at a workspace → agent": load the config, resolve model and tools, then L2. Throws a clear
|
|
30
|
-
* error when no model source is set (fail visibly at startup). Returns everything an entry point needs
|
|
31
|
-
* to report what it assembled.
|
|
32
|
-
*/
|
|
33
|
-
export declare function createPiAgentFromWorkspace(dir: string, options?: CreatePiAgentFromWorkspaceOptions): Promise<{
|
|
34
|
-
agent: Agent;
|
|
35
|
-
definition: LoadedDefinition;
|
|
36
|
-
config: FastagentConfig;
|
|
37
|
-
configPath?: string;
|
|
38
|
-
/** The resolved "provider/modelId" spec actually in use. */
|
|
39
|
-
modelSpec: string;
|
|
40
|
-
/** Absolute agent-definition dir in use (config.agentDir resolved against dir; = dir when unset). Channels/tools/persona come from here. */
|
|
41
|
-
agentDir: string;
|
|
42
|
-
/** Absolute state root in use (FASTAGENT_STATE_DIR > <dir>/.fastagent) — the ChannelContext's stateRoot. */
|
|
43
|
-
stateRoot: string;
|
|
44
|
-
/** Absolute session store directory in use (for the startup report). */
|
|
45
|
-
sessionsDir: string;
|
|
46
|
-
/** Absolute credentials file in use (for the startup report). */
|
|
47
|
-
authPath: string;
|
|
48
|
-
/** Non-default, active-by-default tool names in effect: config.tools + discovered tools/. Each name
|
|
49
|
-
* lives in exactly one report slot — deferred names are in {@link deferredToolNames} instead. */
|
|
50
|
-
toolNames: string[];
|
|
51
|
-
/** Tools registered but not initially active (deferred) — activated via search_tools. */
|
|
52
|
-
deferredToolNames: string[];
|
|
53
|
-
toolCollisions: ToolCollision[];
|
|
54
|
-
/** `tools/` files that failed to import — skipped, reported by the caller, never fatal. */
|
|
55
|
-
toolFailures: ModuleLoadFailure[];
|
|
56
|
-
}>;
|