@fastagent-sh/fastagent 0.12.0 → 0.13.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 +42 -36
- package/dist/channels/feishu/bootstrap-token.d.ts +42 -0
- package/dist/channels/feishu/bootstrap-token.js +94 -0
- package/dist/channels/feishu/card.d.ts +32 -0
- package/dist/channels/feishu/card.js +66 -0
- package/dist/channels/feishu/cloud.d.ts +17 -0
- package/dist/channels/feishu/cloud.js +19 -0
- package/dist/channels/feishu/crypto.d.ts +13 -0
- package/dist/channels/feishu/crypto.js +41 -0
- package/dist/channels/feishu/feishu-api.d.ts +108 -0
- package/dist/channels/feishu/feishu-api.js +325 -0
- package/dist/channels/feishu/feishu.d.ts +36 -0
- package/dist/channels/feishu/feishu.js +359 -0
- package/dist/channels/feishu/invoke-turn.d.ts +59 -0
- package/dist/channels/feishu/invoke-turn.js +106 -0
- package/dist/channels/feishu/parse.d.ts +125 -0
- package/dist/channels/feishu/parse.js +175 -0
- package/dist/channels/feishu/preview.d.ts +36 -0
- package/dist/channels/feishu/preview.js +387 -0
- package/dist/channels/feishu/register-app.d.ts +70 -0
- package/dist/channels/feishu/register-app.js +141 -0
- package/dist/channels/feishu/register-webhook.d.ts +22 -0
- package/dist/channels/feishu/register-webhook.js +106 -0
- package/dist/channels/feishu/scaffold/channel.ts +34 -0
- package/dist/channels/feishu/scaffold/feishu-send.ts +87 -0
- package/dist/channels/feishu/seen.d.ts +5 -0
- package/dist/channels/feishu/seen.js +47 -0
- package/dist/channels/feishu/text.d.ts +13 -0
- package/dist/channels/feishu/text.js +63 -0
- package/dist/channels/lark/lark.d.ts +15 -0
- package/dist/channels/lark/lark.js +10 -0
- package/dist/channels/lark/onboard.d.ts +39 -0
- package/dist/channels/lark/onboard.js +58 -0
- package/dist/channels/lark/scaffold/channel.ts +32 -0
- package/dist/channels/lark/scaffold/lark-send.ts +87 -0
- package/dist/channels/registration.d.ts +15 -0
- package/dist/channels/registration.js +1 -0
- package/dist/channels/{telegram/state.js → state.js} +6 -4
- package/dist/channels/telegram/context-buffer.js +1 -1
- package/dist/channels/telegram/register-webhook.d.ts +4 -1
- package/dist/channels/telegram/register-webhook.js +17 -26
- package/dist/channels/telegram/telegram.js +2 -2
- package/dist/channels/telegram/turn-store.d.ts +8 -21
- package/dist/channels/telegram/turn-store.js +11 -130
- package/dist/channels/{telegram/turn-queue.js → turn-queue.js} +3 -3
- package/dist/channels/turn-store.d.ts +42 -0
- package/dist/channels/turn-store.js +139 -0
- package/dist/channels/wait-health.d.ts +6 -0
- package/dist/channels/wait-health.js +27 -0
- package/dist/cli-add-feishu.d.ts +8 -0
- package/dist/cli-add-feishu.js +223 -0
- package/dist/cli.js +68 -23
- package/dist/deploy/container.js +10 -6
- package/dist/deploy/fly/plan.d.ts +1 -1
- package/dist/deploy/fly/plan.js +15 -4
- package/dist/deploy/fly/run.d.ts +7 -4
- package/dist/deploy/fly/run.js +26 -5
- package/dist/deploy/railway/plan.d.ts +1 -1
- package/dist/deploy/railway/plan.js +17 -5
- package/dist/deploy/railway/run.d.ts +6 -3
- package/dist/deploy/railway/run.js +26 -4
- package/dist/deploy/registration-gate.d.ts +20 -0
- package/dist/deploy/registration-gate.js +20 -0
- package/dist/deploy/secrets.d.ts +10 -9
- package/dist/deploy/secrets.js +15 -14
- package/dist/dev-supervisor.js +2 -1
- package/dist/engines/pi/chat.js +3 -3
- package/dist/engines/pi/create.d.ts +0 -1
- package/dist/engines/pi/create.js +8 -7
- package/dist/feishu.d.ts +2 -0
- package/dist/feishu.js +2 -0
- package/dist/lark.d.ts +3 -0
- package/dist/lark.js +3 -0
- package/dist/open-url.d.ts +2 -0
- package/dist/open-url.js +6 -0
- package/dist/scaffold/add-channel.d.ts +9 -5
- package/dist/scaffold/add-channel.js +73 -7
- package/dist/tunnel.d.ts +9 -6
- package/dist/tunnel.js +48 -31
- package/package.json +19 -8
- /package/dist/channels/{telegram/state.d.ts → state.d.ts} +0 -0
- /package/dist/channels/{telegram/turn-queue.d.ts → turn-queue.d.ts} +0 -0
|
@@ -17,6 +17,7 @@ const CHANNEL_SCAFFOLDS = {
|
|
|
17
17
|
{
|
|
18
18
|
name: "GITHUB_WEBHOOK_SECRET",
|
|
19
19
|
hint: "any random string; set the same value in the GitHub webhook",
|
|
20
|
+
required: true,
|
|
20
21
|
generate: true,
|
|
21
22
|
},
|
|
22
23
|
],
|
|
@@ -29,14 +30,75 @@ const CHANNEL_SCAFFOLDS = {
|
|
|
29
30
|
},
|
|
30
31
|
telegram: {
|
|
31
32
|
env: [
|
|
32
|
-
{ name: "TELEGRAM_BOT_TOKEN", hint: "from @BotFather → /newbot" },
|
|
33
|
-
{
|
|
33
|
+
{ name: "TELEGRAM_BOT_TOKEN", hint: "from @BotFather → /newbot", required: true },
|
|
34
|
+
{
|
|
35
|
+
name: "TELEGRAM_SECRET_TOKEN",
|
|
36
|
+
hint: "any random string; verifies inbound updates",
|
|
37
|
+
required: true,
|
|
38
|
+
generate: true,
|
|
39
|
+
},
|
|
34
40
|
],
|
|
35
41
|
steps: [
|
|
36
42
|
"edit {channel} — customise routing with route() (optional; the defaults already work)",
|
|
37
43
|
"the agent can send messages or files back by calling the scaffolded {tools}/telegram-send.ts tool",
|
|
38
44
|
],
|
|
39
45
|
},
|
|
46
|
+
// Feishu is the canonical engine/cloud; Lark international reuses its protocol through a degraded
|
|
47
|
+
// compatibility profile. Each remains its own channel KIND: route, env, state, console, onboarding.
|
|
48
|
+
// No `generate` in either: every value comes FROM the platform (a locally generated Encrypt Key
|
|
49
|
+
// would break inbound events until mirrored in the console). `add feishu` scan-creates the app;
|
|
50
|
+
// Lark lacks that control-plane capability, so `add lark` guides console credential collection.
|
|
51
|
+
feishu: {
|
|
52
|
+
env: [
|
|
53
|
+
{
|
|
54
|
+
name: "FEISHU_APP_ID",
|
|
55
|
+
hint: "created + written automatically by `add feishu` (console → Credentials & Basic Info)",
|
|
56
|
+
required: true,
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: "FEISHU_APP_SECRET",
|
|
60
|
+
hint: "created + written automatically by `add feishu` (console → Credentials & Basic Info)",
|
|
61
|
+
required: true,
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: "FEISHU_VERIFICATION_TOKEN",
|
|
65
|
+
hint: "captured automatically (console → Events & Callbacks)",
|
|
66
|
+
required: true,
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: "FEISHU_ENCRYPT_KEY",
|
|
70
|
+
hint: "optional but recommended — set one in the console and copy it here",
|
|
71
|
+
required: false,
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
steps: [
|
|
75
|
+
"PUBLISH the app version on the page the CLI opened — the switch to webhook mode takes effect on publish (one click, once ever; no API for it)",
|
|
76
|
+
"edit {channel} — routing policy (the header walks through the console setup, for hand-made apps)",
|
|
77
|
+
"the event Request URL is auto-registered by `dev --tunnel` / `deploy --run`",
|
|
78
|
+
"the agent can push messages from scheduled turns via the scaffolded {tools}/feishu-send.ts tool",
|
|
79
|
+
],
|
|
80
|
+
},
|
|
81
|
+
lark: {
|
|
82
|
+
env: [
|
|
83
|
+
{ name: "LARK_APP_ID", hint: "developer console → Credentials & Basic Info", required: true },
|
|
84
|
+
{ name: "LARK_APP_SECRET", hint: "developer console → Credentials & Basic Info", required: true },
|
|
85
|
+
{
|
|
86
|
+
name: "LARK_VERIFICATION_TOKEN",
|
|
87
|
+
hint: "console → Events & Callbacks; authenticates inbound events",
|
|
88
|
+
required: true,
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: "LARK_ENCRYPT_KEY",
|
|
92
|
+
hint: "optional but recommended — set one in the console and copy it here",
|
|
93
|
+
required: false,
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
steps: [
|
|
97
|
+
"finish the console setup: enable Bot and add the permissions + im.message.receive_v1 event listed in {channel} (do not publish yet)",
|
|
98
|
+
"run `fastagent dev --tunnel` and keep it running; if auto-registration reports a config-API 404, manually switch Subscription mode to webhook, set its printed https://…/lark Request URL, save, then create + publish a version",
|
|
99
|
+
"the agent can push messages from scheduled turns via the scaffolded {tools}/lark-send.ts tool",
|
|
100
|
+
],
|
|
101
|
+
},
|
|
40
102
|
};
|
|
41
103
|
/** The channel kinds `fastagent add <kind>` can scaffold. */
|
|
42
104
|
export const CHANNEL_KINDS = Object.keys(CHANNEL_SCAFFOLDS);
|
|
@@ -83,11 +145,13 @@ function mentionsEnvName(content, name) {
|
|
|
83
145
|
}
|
|
84
146
|
/**
|
|
85
147
|
* Append generated channel secrets to the run-root `.env` (never `.env.example`) after the CLI has
|
|
86
|
-
* verified that `.env` is gitignored. Existing non-empty values are kept
|
|
87
|
-
*
|
|
88
|
-
*
|
|
148
|
+
* verified that `.env` is gitignored. Existing non-empty values are kept — EXCEPT the names listed in
|
|
149
|
+
* `overwrite`: those are authoritative (e.g. the credentials of an app `add feishu` JUST minted —
|
|
150
|
+
* skipping them for a stale value would silently discard a fresh, unrecoverable secret). Manual values
|
|
151
|
+
* (e.g. TELEGRAM_BOT_TOKEN from BotFather) are added only as commented placeholders, so the file is
|
|
152
|
+
* ready to edit while no fake secret is committed to the user's mental model.
|
|
89
153
|
*/
|
|
90
|
-
export async function appendChannelDotEnv(dir, kind, generated) {
|
|
154
|
+
export async function appendChannelDotEnv(dir, kind, generated, overwrite = []) {
|
|
91
155
|
const file = join(dir, ".env");
|
|
92
156
|
let current = "";
|
|
93
157
|
try {
|
|
@@ -97,7 +161,9 @@ export async function appendChannelDotEnv(dir, kind, generated) {
|
|
|
97
161
|
if (e.code !== "ENOENT")
|
|
98
162
|
throw e;
|
|
99
163
|
}
|
|
100
|
-
const alreadySet = CHANNEL_SCAFFOLDS[kind].env
|
|
164
|
+
const alreadySet = CHANNEL_SCAFFOLDS[kind].env
|
|
165
|
+
.filter((e) => !overwrite.includes(e.name) && hasActiveEnvValue(current, e.name))
|
|
166
|
+
.map((e) => e.name);
|
|
101
167
|
const lines = [];
|
|
102
168
|
const written = [];
|
|
103
169
|
const contentLines = current.split("\n");
|
package/dist/tunnel.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
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 (
|
|
4
|
-
* URL to paste into repo settings). This closes the
|
|
3
|
+
* auto-register the first-party webhook channels against it (Telegram setWebhook; Feishu/Lark
|
|
4
|
+
* application-config PATCH; GitHub prints the URL to paste into repo settings). This closes the
|
|
5
|
+
* "local dev → public URL" gap webhooks need.
|
|
5
6
|
*
|
|
6
7
|
* Process orchestration, not assembly — lives outside the engine, beside dev-supervisor.ts.
|
|
7
8
|
*/
|
|
@@ -22,10 +23,12 @@ type SpawnCloudflared = (port: number) => ChildProcess;
|
|
|
22
23
|
* (Edge warmup AFTER the URL appears is handled downstream: the telegram registrar polls /health before
|
|
23
24
|
* it calls setWebhook, so a not-yet-routable tunnel just delays registration rather than failing it.)
|
|
24
25
|
*/
|
|
25
|
-
export declare function startCloudflareTunnel(port: number, spawnFn?: SpawnCloudflared): Promise<Tunnel | undefined>;
|
|
26
|
+
export declare function startCloudflareTunnel(port: number, spawnFn?: SpawnCloudflared, attemptTimeoutMs?: number): Promise<Tunnel | undefined>;
|
|
26
27
|
/**
|
|
27
|
-
* Print the public URL and wire up the first-party webhook channels found under `dir`:
|
|
28
|
-
* auto-
|
|
28
|
+
* Print the public URL and wire up the first-party webhook channels found under `dir`: Telegram and
|
|
29
|
+
* Feishu/Lark auto-register using credentials from .env; GitHub prints the URL to add in repo settings.
|
|
29
30
|
*/
|
|
30
|
-
export declare function announceWebhooks(dir: string, baseUrl: string
|
|
31
|
+
export declare function announceWebhooks(dir: string, baseUrl: string, opts?: {
|
|
32
|
+
openUrl?: (url: string) => void;
|
|
33
|
+
}): Promise<void>;
|
|
31
34
|
export {};
|
package/dist/tunnel.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
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 (
|
|
4
|
-
* URL to paste into repo settings). This closes the
|
|
3
|
+
* auto-register the first-party webhook channels against it (Telegram setWebhook; Feishu/Lark
|
|
4
|
+
* application-config PATCH; GitHub prints the URL to paste into repo settings). This closes the
|
|
5
|
+
* "local dev → public URL" gap webhooks need.
|
|
5
6
|
*
|
|
6
7
|
* Process orchestration, not assembly — lives outside the engine, beside dev-supervisor.ts.
|
|
7
8
|
*/
|
|
8
9
|
import { spawn } from "node:child_process";
|
|
9
10
|
import { readdirSync } from "node:fs";
|
|
10
11
|
import { join } from "node:path";
|
|
11
|
-
import {
|
|
12
|
+
import { registerFeishuWebhook } from "./channels/feishu/register-webhook.js";
|
|
12
13
|
import { registerTelegramWebhook } from "./channels/telegram/register-webhook.js";
|
|
13
14
|
import { loadDotEnv } from "./env.js";
|
|
14
15
|
import { log } from "./log.js";
|
|
@@ -21,8 +22,12 @@ const TUNNEL_URL_RE = /https:\/\/(?!api\.)[a-z0-9-]+\.trycloudflare\.com/i;
|
|
|
21
22
|
export function parseTunnelUrl(chunk) {
|
|
22
23
|
return chunk.match(TUNNEL_URL_RE)?.[0];
|
|
23
24
|
}
|
|
25
|
+
/** Global timer (rather than timers/promises) so timeout/retry behavior is deterministic under fake timers. */
|
|
26
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
24
27
|
const TUNNEL_ATTEMPTS = 3;
|
|
25
28
|
const TUNNEL_RETRY_MS = 2000;
|
|
29
|
+
/** cloudflared can stay alive without ever receiving/printing an assigned quick-tunnel URL. */
|
|
30
|
+
const TUNNEL_START_TIMEOUT_MS = 30_000;
|
|
26
31
|
const spawnCloudflared = (port) => spawn("cloudflared", ["tunnel", "--url", `http://localhost:${port}`], { stdio: ["ignore", "pipe", "pipe"] });
|
|
27
32
|
/**
|
|
28
33
|
* Start a Cloudflare quick tunnel to localhost:`port`, resolving once its public URL appears.
|
|
@@ -32,9 +37,9 @@ const spawnCloudflared = (port) => spawn("cloudflared", ["tunnel", "--url", `htt
|
|
|
32
37
|
* (Edge warmup AFTER the URL appears is handled downstream: the telegram registrar polls /health before
|
|
33
38
|
* it calls setWebhook, so a not-yet-routable tunnel just delays registration rather than failing it.)
|
|
34
39
|
*/
|
|
35
|
-
export async function startCloudflareTunnel(port, spawnFn = spawnCloudflared) {
|
|
40
|
+
export async function startCloudflareTunnel(port, spawnFn = spawnCloudflared, attemptTimeoutMs = TUNNEL_START_TIMEOUT_MS) {
|
|
36
41
|
for (let attempt = 1; attempt <= TUNNEL_ATTEMPTS; attempt++) {
|
|
37
|
-
const r = await spawnTunnelOnce(port, spawnFn);
|
|
42
|
+
const r = await spawnTunnelOnce(port, spawnFn, attemptTimeoutMs);
|
|
38
43
|
if (r.tunnel)
|
|
39
44
|
return r.tunnel;
|
|
40
45
|
if (r.fatal) {
|
|
@@ -50,43 +55,45 @@ export async function startCloudflareTunnel(port, spawnFn = spawnCloudflared) {
|
|
|
50
55
|
return undefined;
|
|
51
56
|
}
|
|
52
57
|
/** One cloudflared launch: a Tunnel on the first URL, or a failure (missing binary / exit before a URL). */
|
|
53
|
-
function spawnTunnelOnce(port, spawnFn) {
|
|
58
|
+
function spawnTunnelOnce(port, spawnFn, timeoutMs) {
|
|
54
59
|
return new Promise((resolve) => {
|
|
55
60
|
const child = spawnFn(port);
|
|
56
61
|
let settled = false;
|
|
62
|
+
let timer;
|
|
57
63
|
let tail = ""; // recent output, surfaced as the failure reason
|
|
58
|
-
const
|
|
59
|
-
tail = (tail + String(buf)).slice(-600);
|
|
64
|
+
const finish = (result) => {
|
|
60
65
|
if (settled)
|
|
61
66
|
return;
|
|
67
|
+
settled = true;
|
|
68
|
+
if (timer)
|
|
69
|
+
clearTimeout(timer);
|
|
70
|
+
resolve(result);
|
|
71
|
+
};
|
|
72
|
+
const onChunk = (buf) => {
|
|
73
|
+
tail = (tail + String(buf)).slice(-600);
|
|
62
74
|
const url = parseTunnelUrl(String(buf));
|
|
63
|
-
if (url)
|
|
64
|
-
|
|
65
|
-
resolve({ tunnel: { url, close: () => child.kill("SIGTERM") } });
|
|
66
|
-
}
|
|
75
|
+
if (url)
|
|
76
|
+
finish({ tunnel: { url, close: () => child.kill("SIGTERM") } });
|
|
67
77
|
};
|
|
68
78
|
child.stdout?.on("data", onChunk);
|
|
69
79
|
child.stderr?.on("data", onChunk); // cloudflared prints the URL (and its errors) on stderr
|
|
70
80
|
child.on("error", (e) => {
|
|
71
|
-
if (settled)
|
|
72
|
-
return;
|
|
73
|
-
settled = true;
|
|
74
81
|
if (e.code === "ENOENT") {
|
|
75
|
-
|
|
82
|
+
finish({
|
|
76
83
|
fatal: true,
|
|
77
84
|
message: "[fastagent] --tunnel needs cloudflared — install it (e.g. `brew install cloudflared`), then re-run. Serving without a tunnel.",
|
|
78
85
|
});
|
|
79
86
|
}
|
|
80
87
|
else {
|
|
81
|
-
|
|
88
|
+
finish({ fatal: false, detail: e.message });
|
|
82
89
|
}
|
|
83
90
|
});
|
|
84
|
-
child.on("exit", () => {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
91
|
+
child.on("exit", () => finish({ fatal: false, detail: lastErrorLine(tail) }));
|
|
92
|
+
timer = setTimeout(() => {
|
|
93
|
+
child.kill("SIGTERM");
|
|
94
|
+
finish({ fatal: false, detail: `timed out after ${Math.round(timeoutMs / 1000)}s waiting for a public URL` });
|
|
95
|
+
}, timeoutMs);
|
|
96
|
+
timer.unref();
|
|
90
97
|
});
|
|
91
98
|
}
|
|
92
99
|
/** The most informative line of cloudflared's output tail (prefer an error line) for a failure log. */
|
|
@@ -109,31 +116,41 @@ function channelBasenames(dir) {
|
|
|
109
116
|
}
|
|
110
117
|
}
|
|
111
118
|
/**
|
|
112
|
-
* Print the public URL and wire up the first-party webhook channels found under `dir`:
|
|
113
|
-
* auto-
|
|
119
|
+
* Print the public URL and wire up the first-party webhook channels found under `dir`: Telegram and
|
|
120
|
+
* Feishu/Lark auto-register using credentials from .env; GitHub prints the URL to add in repo settings.
|
|
114
121
|
*/
|
|
115
|
-
export async function announceWebhooks(dir, baseUrl) {
|
|
122
|
+
export async function announceWebhooks(dir, baseUrl, opts = {}) {
|
|
116
123
|
log.info(`[fastagent] public URL: ${baseUrl}`);
|
|
117
124
|
try {
|
|
118
|
-
loadDotEnv(dir); //
|
|
125
|
+
loadDotEnv(dir); // webhook registrars read channel credentials from .env
|
|
119
126
|
}
|
|
120
127
|
catch (error) {
|
|
121
128
|
// best-effort boundary: a MISSING .env is already tolerated by loadDotEnv; an unreadable one (EACCES,
|
|
122
129
|
// or .env is a directory) must NOT crash the long-running dev/start server — announceWebhooks is
|
|
123
130
|
// void-called with no unhandledRejection handler, so a throw here would terminate the process. Warn
|
|
124
|
-
// (surface it, rule 8) and continue best-effort;
|
|
125
|
-
//
|
|
131
|
+
// (surface it, rule 8) and continue best-effort; each registrar then surfaces its own
|
|
132
|
+
// missing-credential guidance. loadDotEnv keeps throwing for the synchronous command callers.
|
|
126
133
|
log.warn(`[fastagent] could not read ${join(dir, ".env")}: ${error.message} — continuing without it`);
|
|
127
134
|
}
|
|
128
135
|
const channels = channelBasenames(dir);
|
|
129
136
|
if (channels.length === 0)
|
|
130
137
|
return;
|
|
131
138
|
// Readiness is the registrar's job now: a fresh quick tunnel returns Cloudflare 530 for ~20-30s before
|
|
132
|
-
// its origin connects, and
|
|
133
|
-
// same wait the deploy runners rely on).
|
|
139
|
+
// its origin connects, and the automatic registrars poll /health before configuring the platform (the
|
|
140
|
+
// same wait the deploy runners rely on). GitHub needs no wait — the operator adds that webhook by hand.
|
|
134
141
|
if (channels.includes("telegram"))
|
|
135
142
|
await registerTelegramWebhook(baseUrl);
|
|
136
143
|
if (channels.includes("github")) {
|
|
137
144
|
log.info(`[fastagent] github: add a webhook in your repo (Settings → Webhooks): Payload URL = ${baseUrl}/webhook, content type application/json, secret = GITHUB_WEBHOOK_SECRET`);
|
|
138
145
|
}
|
|
146
|
+
// feishu/lark register programmatically too (application-v7 config PATCH — telegram-setWebhook
|
|
147
|
+
// parity), once per mounted kind (each kind is its own app with its own credentials); the registrar
|
|
148
|
+
// owns its own health wait and degrades to the manual console instruction.
|
|
149
|
+
const feishuOptions = {
|
|
150
|
+
onManualRegistration: ({ consoleUrl }) => opts.openUrl?.(consoleUrl),
|
|
151
|
+
};
|
|
152
|
+
if (channels.includes("feishu"))
|
|
153
|
+
await registerFeishuWebhook(baseUrl, "feishu", feishuOptions);
|
|
154
|
+
if (channels.includes("lark"))
|
|
155
|
+
await registerFeishuWebhook(baseUrl, "lark", feishuOptions);
|
|
139
156
|
}
|
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
|
|
3
|
+
"version": "0.13.0",
|
|
4
|
+
"description": "Vibe first. Then FastAgent: turn a local agent directory into a live service in your app, on GitHub, in Telegram, or behind any channel.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
7
7
|
"ai-agent",
|
|
@@ -9,13 +9,16 @@
|
|
|
9
9
|
"agents.md",
|
|
10
10
|
"agent-skills",
|
|
11
11
|
"agent-serving",
|
|
12
|
+
"telegram",
|
|
13
|
+
"github",
|
|
14
|
+
"webhook",
|
|
12
15
|
"sse",
|
|
13
16
|
"pi",
|
|
14
17
|
"fastagent"
|
|
15
18
|
],
|
|
16
19
|
"license": "MIT",
|
|
17
20
|
"author": "the fastagent authors (https://github.com/fastagent-sh/fastagent)",
|
|
18
|
-
"homepage": "https://
|
|
21
|
+
"homepage": "https://fastagent.sh",
|
|
19
22
|
"repository": {
|
|
20
23
|
"type": "git",
|
|
21
24
|
"url": "git+https://github.com/fastagent-sh/fastagent.git"
|
|
@@ -51,6 +54,14 @@
|
|
|
51
54
|
"types": "./dist/telegram.d.ts",
|
|
52
55
|
"default": "./dist/telegram.js"
|
|
53
56
|
},
|
|
57
|
+
"./feishu": {
|
|
58
|
+
"types": "./dist/feishu.d.ts",
|
|
59
|
+
"default": "./dist/feishu.js"
|
|
60
|
+
},
|
|
61
|
+
"./lark": {
|
|
62
|
+
"types": "./dist/lark.d.ts",
|
|
63
|
+
"default": "./dist/lark.js"
|
|
64
|
+
},
|
|
54
65
|
"./package.json": "./package.json"
|
|
55
66
|
},
|
|
56
67
|
"bin": {
|
|
@@ -77,13 +88,13 @@
|
|
|
77
88
|
},
|
|
78
89
|
"dependencies": {
|
|
79
90
|
"@clack/prompts": "^1.6.0",
|
|
80
|
-
"@earendil-works/pi-agent-core": "^0.80.
|
|
81
|
-
"@earendil-works/pi-ai": "^0.80.
|
|
82
|
-
"@earendil-works/pi-coding-agent": "^0.80.
|
|
91
|
+
"@earendil-works/pi-agent-core": "^0.80.7",
|
|
92
|
+
"@earendil-works/pi-ai": "^0.80.7",
|
|
93
|
+
"@earendil-works/pi-coding-agent": "^0.80.7",
|
|
83
94
|
"@octokit/webhooks-methods": "^6.0.0",
|
|
84
95
|
"@octokit/webhooks-types": "^7.6.1",
|
|
85
96
|
"chokidar": "^5.0.0",
|
|
86
|
-
"croner": "^
|
|
97
|
+
"croner": "^10.0.1",
|
|
87
98
|
"giget": "^3.3.0",
|
|
88
99
|
"ignore": "^7.0.5",
|
|
89
100
|
"undici": "^8.6.0",
|
|
@@ -91,7 +102,7 @@
|
|
|
91
102
|
},
|
|
92
103
|
"devDependencies": {
|
|
93
104
|
"@biomejs/biome": "^2.5.2",
|
|
94
|
-
"typescript": "^
|
|
105
|
+
"typescript": "^7.0.2",
|
|
95
106
|
"vitest": "^4.1.9"
|
|
96
107
|
}
|
|
97
108
|
}
|
|
File without changes
|
|
File without changes
|