@agent-team-foundation/first-tree-hub 0.3.4 → 0.3.5
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/dist/{bootstrap-CPdLNPme.mjs → bootstrap-mhkpeOEc.mjs} +10 -2
- package/dist/cli/index.mjs +7 -7
- package/dist/{core-CZjUVAU-.mjs → core-CHL_dgzu.mjs} +261 -39
- package/dist/index.mjs +2 -2
- package/dist/web/assets/{index-BHn3RVzY.js → index-DhpjUi0Y.js} +68 -68
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
|
@@ -72,7 +72,7 @@ const clientConfigSchema = defineConfig({
|
|
|
72
72
|
function getClientConfig() {
|
|
73
73
|
return getConfig();
|
|
74
74
|
}
|
|
75
|
-
const DEFAULT_HOME_DIR = join(homedir(), ".first-tree-hub");
|
|
75
|
+
const DEFAULT_HOME_DIR = process.env.FIRST_TREE_HUB_HOME ?? join(homedir(), ".first-tree-hub");
|
|
76
76
|
const DEFAULT_CONFIG_DIR = join(DEFAULT_HOME_DIR, "config");
|
|
77
77
|
const DEFAULT_DATA_DIR = join(DEFAULT_HOME_DIR, "data");
|
|
78
78
|
function isFieldDef(value) {
|
|
@@ -477,6 +477,14 @@ const serverConfigSchema = defineConfig({
|
|
|
477
477
|
max: field(z.number().default(100), { env: "FIRST_TREE_HUB_RATE_LIMIT_MAX" }),
|
|
478
478
|
loginMax: field(z.number().default(5), { env: "FIRST_TREE_HUB_RATE_LIMIT_LOGIN_MAX" }),
|
|
479
479
|
webhookMax: field(z.number().default(60), { env: "FIRST_TREE_HUB_RATE_LIMIT_WEBHOOK_MAX" })
|
|
480
|
+
}),
|
|
481
|
+
kael: optional({
|
|
482
|
+
endpoint: field(z.string(), { env: "KAEL_ENDPOINT" }),
|
|
483
|
+
apiKey: field(z.string(), {
|
|
484
|
+
env: "KAEL_API_KEY",
|
|
485
|
+
secret: true
|
|
486
|
+
}),
|
|
487
|
+
hubPublicUrl: field(z.string(), { env: "FIRST_TREE_HUB_PUBLIC_URL" })
|
|
480
488
|
})
|
|
481
489
|
});
|
|
482
490
|
//#endregion
|
|
@@ -580,4 +588,4 @@ async function checkBootstrapStatus(serverUrl, agentId) {
|
|
|
580
588
|
return await res.json();
|
|
581
589
|
}
|
|
582
590
|
//#endregion
|
|
583
|
-
export {
|
|
591
|
+
export { setConfigValue as S, readConfigFile as _, getGitHubUsername as a, resolveConfigReadonly as b, DEFAULT_CONFIG_DIR as c, agentConfigSchema as d, clientConfigSchema as f, loadAgents as g, initConfig as h, getGitHubToken as i, DEFAULT_DATA_DIR as l, getConfigValue as m, bootstrap_exports as n, resolveAgentToken as o, collectMissingPrompts as p, checkBootstrapStatus as r, resolveServerUrl as s, bootstrapToken as t, DEFAULT_HOME_DIR as u, resetConfig as v, serverConfigSchema as x, resetConfigMeta as y };
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { A as ClientRuntime, C as checkWebSocket, F as SessionRegistry, I as cleanWorkspaces, N as FirstTreeHubSDK, P as SdkError, S as checkServerReachable, _ as checkDocker, a as formatCheckReport, b as checkServerConfig, c as onboardContinue, d as runMigrations, f as checkAgentConfigs, g as checkDatabase, h as checkContextTreeRepo, i as promptMissingFields, j as createAdminUser, k as stopPostgres, l as onboardCreate, m as checkClientConfig, n as isInteractive, o as loadOnboardState, p as checkAgentTokens, r as promptAddAgent, s as onboardCheck, t as startServer, u as saveOnboardState, v as checkGitHubToken, w as printResults, x as checkServerHealth, y as checkNodeVersion } from "../core-
|
|
3
|
-
import {
|
|
2
|
+
import { A as ClientRuntime, C as checkWebSocket, F as SessionRegistry, I as cleanWorkspaces, N as FirstTreeHubSDK, P as SdkError, S as checkServerReachable, _ as checkDocker, a as formatCheckReport, b as checkServerConfig, c as onboardContinue, d as runMigrations, f as checkAgentConfigs, g as checkDatabase, h as checkContextTreeRepo, i as promptMissingFields, j as createAdminUser, k as stopPostgres, l as onboardCreate, m as checkClientConfig, n as isInteractive, o as loadOnboardState, p as checkAgentTokens, r as promptAddAgent, s as onboardCheck, t as startServer, u as saveOnboardState, v as checkGitHubToken, w as printResults, x as checkServerHealth, y as checkNodeVersion } from "../core-CHL_dgzu.mjs";
|
|
3
|
+
import { S as setConfigValue, _ as readConfigFile, c as DEFAULT_CONFIG_DIR, d as agentConfigSchema, f as clientConfigSchema, g as loadAgents, h as initConfig, l as DEFAULT_DATA_DIR, m as getConfigValue, o as resolveAgentToken, s as resolveServerUrl, t as bootstrapToken, u as DEFAULT_HOME_DIR, v as resetConfig, x as serverConfigSchema, y as resetConfigMeta } from "../bootstrap-mhkpeOEc.mjs";
|
|
4
4
|
import { n as bindFeishuUser, t as bindFeishuBot } from "../feishu-Y4m2zFc3.mjs";
|
|
5
5
|
import { createRequire } from "node:module";
|
|
6
6
|
import { Command } from "commander";
|
|
@@ -168,7 +168,7 @@ function registerAgentCommands(program) {
|
|
|
168
168
|
agent.command("token").description("Agent token management").command("bootstrap <agentId>").description("Bootstrap a token using GitHub identity (requires gh CLI)").option("--save-to <target>", "Save token to: \"agent\" (default) or a file path", "agent").option("--server <url>", "Hub server URL").action(async (agentId, options) => {
|
|
169
169
|
try {
|
|
170
170
|
const result = await bootstrapToken(resolveServerUrl(options.server), agentId, { saveTo: options.saveTo });
|
|
171
|
-
if (options.saveTo === "agent") process.stderr.write(`Token saved to
|
|
171
|
+
if (options.saveTo === "agent") process.stderr.write(`Token saved to ${DEFAULT_HOME_DIR}/config/agents/${agentId}/agent.yaml\n`);
|
|
172
172
|
else process.stderr.write(`Token saved to ${options.saveTo}\n`);
|
|
173
173
|
success({
|
|
174
174
|
agentId: result.agentId,
|
|
@@ -457,7 +457,7 @@ function isSecretField(schema, dotPath) {
|
|
|
457
457
|
async function promptMissing(args) {
|
|
458
458
|
let ghUsername = null;
|
|
459
459
|
try {
|
|
460
|
-
const { getGitHubUsername } = await import("../bootstrap-
|
|
460
|
+
const { getGitHubUsername } = await import("../bootstrap-mhkpeOEc.mjs").then((n) => n.n);
|
|
461
461
|
ghUsername = getGitHubUsername();
|
|
462
462
|
} catch {}
|
|
463
463
|
if (!args.id) {
|
|
@@ -502,7 +502,7 @@ async function promptMissing(args) {
|
|
|
502
502
|
saveOnboardState(args);
|
|
503
503
|
}
|
|
504
504
|
}
|
|
505
|
-
if (!args.assistant) {
|
|
505
|
+
if (!args.assistant && args.type === "human") {
|
|
506
506
|
if (await confirm({
|
|
507
507
|
message: "Create a personal assistant?",
|
|
508
508
|
default: false
|
|
@@ -515,13 +515,13 @@ async function promptMissing(args) {
|
|
|
515
515
|
}
|
|
516
516
|
}
|
|
517
517
|
if (!args.server) try {
|
|
518
|
-
const { resolveServerUrl } = await import("../bootstrap-
|
|
518
|
+
const { resolveServerUrl } = await import("../bootstrap-mhkpeOEc.mjs").then((n) => n.n);
|
|
519
519
|
resolveServerUrl();
|
|
520
520
|
} catch {
|
|
521
521
|
args.server = await input({ message: "Hub server URL:" });
|
|
522
522
|
saveOnboardState(args);
|
|
523
523
|
}
|
|
524
|
-
if (!args.feishuBotAppId) {
|
|
524
|
+
if (!args.feishuBotAppId && (args.type !== "human" || args.assistant)) {
|
|
525
525
|
if (await confirm({
|
|
526
526
|
message: "Bind Feishu bot?",
|
|
527
527
|
default: false
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as getGitHubUsername, b as
|
|
1
|
+
import { S as setConfigValue, a as getGitHubUsername, b as resolveConfigReadonly, c as DEFAULT_CONFIG_DIR, d as agentConfigSchema, f as clientConfigSchema, g as loadAgents, h as initConfig, p as collectMissingPrompts, r as checkBootstrapStatus, s as resolveServerUrl, t as bootstrapToken$1, u as DEFAULT_HOME_DIR$1, x as serverConfigSchema } from "./bootstrap-mhkpeOEc.mjs";
|
|
2
2
|
import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { dirname, join, resolve } from "node:path";
|
|
4
4
|
import { EventEmitter } from "node:events";
|
|
@@ -395,7 +395,7 @@ defineConfig({
|
|
|
395
395
|
"error"
|
|
396
396
|
]).default("info"), { env: "FIRST_TREE_HUB_LOG_LEVEL" })
|
|
397
397
|
});
|
|
398
|
-
const DEFAULT_HOME_DIR = join(homedir(), ".first-tree-hub");
|
|
398
|
+
const DEFAULT_HOME_DIR = process.env.FIRST_TREE_HUB_HOME ?? join(homedir(), ".first-tree-hub");
|
|
399
399
|
join(DEFAULT_HOME_DIR, "config");
|
|
400
400
|
const DEFAULT_DATA_DIR = join(DEFAULT_HOME_DIR, "data");
|
|
401
401
|
defineConfig({
|
|
@@ -460,6 +460,14 @@ defineConfig({
|
|
|
460
460
|
max: field(z.number().default(100), { env: "FIRST_TREE_HUB_RATE_LIMIT_MAX" }),
|
|
461
461
|
loginMax: field(z.number().default(5), { env: "FIRST_TREE_HUB_RATE_LIMIT_LOGIN_MAX" }),
|
|
462
462
|
webhookMax: field(z.number().default(60), { env: "FIRST_TREE_HUB_RATE_LIMIT_WEBHOOK_MAX" })
|
|
463
|
+
}),
|
|
464
|
+
kael: optional({
|
|
465
|
+
endpoint: field(z.string(), { env: "KAEL_ENDPOINT" }),
|
|
466
|
+
apiKey: field(z.string(), {
|
|
467
|
+
env: "KAEL_API_KEY",
|
|
468
|
+
secret: true
|
|
469
|
+
}),
|
|
470
|
+
hubPublicUrl: field(z.string(), { env: "FIRST_TREE_HUB_PUBLIC_URL" })
|
|
463
471
|
})
|
|
464
472
|
});
|
|
465
473
|
join(DEFAULT_DATA_DIR, "context-tree");
|
|
@@ -2003,10 +2011,10 @@ async function runMigrations(databaseUrl) {
|
|
|
2003
2011
|
}
|
|
2004
2012
|
//#endregion
|
|
2005
2013
|
//#region src/core/onboard.ts
|
|
2006
|
-
const STATE_FILE = join(
|
|
2014
|
+
const STATE_FILE = join(DEFAULT_HOME_DIR$1, ".onboard-state.json");
|
|
2007
2015
|
/** Save current onboard args to state file for resume. */
|
|
2008
2016
|
function saveOnboardState(args) {
|
|
2009
|
-
mkdirSync(
|
|
2017
|
+
mkdirSync(DEFAULT_HOME_DIR$1, { recursive: true });
|
|
2010
2018
|
writeFileSync(STATE_FILE, JSON.stringify({ args }, null, 2));
|
|
2011
2019
|
}
|
|
2012
2020
|
/** Load saved onboard args from state file. */
|
|
@@ -2139,7 +2147,7 @@ async function onboardCheck(args) {
|
|
|
2139
2147
|
status: "missing_optional",
|
|
2140
2148
|
hint: `defaults to "${args.id ?? ""}"`
|
|
2141
2149
|
});
|
|
2142
|
-
items.push(args.assistant ? {
|
|
2150
|
+
if (args.type === "human") items.push(args.assistant ? {
|
|
2143
2151
|
key: "assistant",
|
|
2144
2152
|
label: "assistant",
|
|
2145
2153
|
status: "ok",
|
|
@@ -2150,7 +2158,7 @@ async function onboardCheck(args) {
|
|
|
2150
2158
|
status: "missing_optional",
|
|
2151
2159
|
hint: "Also create a personal_assistant"
|
|
2152
2160
|
});
|
|
2153
|
-
items.push(args.feishuBotAppId ? {
|
|
2161
|
+
if (args.type !== "human" || args.assistant) items.push(args.feishuBotAppId ? {
|
|
2154
2162
|
key: "feishu_bot",
|
|
2155
2163
|
label: "feishu-bot-app-id",
|
|
2156
2164
|
status: "ok",
|
|
@@ -2159,7 +2167,7 @@ async function onboardCheck(args) {
|
|
|
2159
2167
|
key: "feishu_bot",
|
|
2160
2168
|
label: "feishu-bot-app-id",
|
|
2161
2169
|
status: "missing_optional",
|
|
2162
|
-
hint: "Feishu bot App ID
|
|
2170
|
+
hint: "Feishu bot App ID"
|
|
2163
2171
|
});
|
|
2164
2172
|
if (args.id && repoPath) if (existsSync(join(repoPath, "members", args.id))) try {
|
|
2165
2173
|
execSync(`git ls-files --error-unmatch members/${args.id}/NODE.md`, {
|
|
@@ -2201,6 +2209,7 @@ function formatCheckReport(items) {
|
|
|
2201
2209
|
async function onboardCreate(args) {
|
|
2202
2210
|
const repoPath = await resolveContextTreeRepo(args.server);
|
|
2203
2211
|
if (!repoPath) throw new Error("Context Tree repo not available. Ensure --server is configured and the server is running.");
|
|
2212
|
+
if (args.assistant && args.type !== "human") throw new Error(`--assistant is only valid for human agents, not ${args.type}`);
|
|
2204
2213
|
const ghUsername = getGitHubUsername();
|
|
2205
2214
|
const githubField = args.type === "human" ? ghUsername : null;
|
|
2206
2215
|
const humanNodePath = join(repoPath, "members", args.id, "NODE.md");
|
|
@@ -2323,7 +2332,7 @@ async function onboardCreate(args) {
|
|
|
2323
2332
|
branch,
|
|
2324
2333
|
prUrl: prOutput
|
|
2325
2334
|
};
|
|
2326
|
-
mkdirSync(
|
|
2335
|
+
mkdirSync(DEFAULT_HOME_DIR$1, { recursive: true });
|
|
2327
2336
|
writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
|
|
2328
2337
|
return { prUrl: prOutput };
|
|
2329
2338
|
}
|
|
@@ -2366,7 +2375,7 @@ async function onboardContinue(args) {
|
|
|
2366
2375
|
first-tree-hub onboard --continue`);
|
|
2367
2376
|
throw err;
|
|
2368
2377
|
}
|
|
2369
|
-
process.stderr.write(`Token saved to
|
|
2378
|
+
process.stderr.write(`Token saved to ${DEFAULT_HOME_DIR$1}/config/agents/${agentToBootstrap}/agent.yaml\n`);
|
|
2370
2379
|
if (mergedArgs.feishuBotAppId && mergedArgs.feishuBotAppSecret) {
|
|
2371
2380
|
const { bindFeishuBot } = await import("./feishu-Y4m2zFc3.mjs").then((n) => n.r);
|
|
2372
2381
|
process.stderr.write("Binding Feishu bot...\n");
|
|
@@ -2377,10 +2386,11 @@ async function onboardContinue(args) {
|
|
|
2377
2386
|
const { unlinkSync } = await import("node:fs");
|
|
2378
2387
|
unlinkSync(STATE_FILE);
|
|
2379
2388
|
} catch {}
|
|
2389
|
+
const typeLabel = mergedArgs.type === "human" ? "Human" : mergedArgs.type === "autonomous_agent" ? "Agent" : "Assistant";
|
|
2380
2390
|
process.stderr.write("\n✅ Onboard complete!\n\n");
|
|
2381
|
-
process.stderr.write(`
|
|
2391
|
+
process.stderr.write(` ${typeLabel}:${" ".repeat(Math.max(1, 10 - typeLabel.length))}${mergedArgs.id}\n`);
|
|
2382
2392
|
if (mergedArgs.assistant) process.stderr.write(` Assistant: ${mergedArgs.assistant}\n`);
|
|
2383
|
-
process.stderr.write(` Token:
|
|
2393
|
+
process.stderr.write(` Token: ${DEFAULT_HOME_DIR$1}/config/agents/${agentToBootstrap}/agent.yaml\n`);
|
|
2384
2394
|
if (mergedArgs.feishuBotAppId) process.stderr.write(` Feishu: bot bound (${mergedArgs.feishuBotAppId})\n`);
|
|
2385
2395
|
setConfigValue(join(DEFAULT_CONFIG_DIR, "client.yaml"), "server.url", serverUrl);
|
|
2386
2396
|
if (mergedArgs.type === "human") {
|
|
@@ -2397,7 +2407,16 @@ function createMemberNodeMd(repoPath, data) {
|
|
|
2397
2407
|
mkdirSync(memberDir, { recursive: true });
|
|
2398
2408
|
const domainsList = data.domains.map((d) => ` - "${d}"`).join("\n");
|
|
2399
2409
|
const githubLine = data.github ? `\ngithub: ${data.github}` : "";
|
|
2400
|
-
const delegateLine = data.delegateMention ? `\ndelegate_mention: ${data.delegateMention}` : "";
|
|
2410
|
+
const delegateLine = data.delegateMention && data.type === "human" ? `\ndelegate_mention: ${data.delegateMention}` : "";
|
|
2411
|
+
const bodySections = data.type === "autonomous_agent" ? `## About
|
|
2412
|
+
|
|
2413
|
+
## Capabilities
|
|
2414
|
+
|
|
2415
|
+
## Current Focus
|
|
2416
|
+
` : `## About
|
|
2417
|
+
|
|
2418
|
+
## Current Focus
|
|
2419
|
+
`;
|
|
2401
2420
|
const content = `---
|
|
2402
2421
|
title: "${data.displayName}"
|
|
2403
2422
|
owners: [${data.owner}]
|
|
@@ -2409,10 +2428,7 @@ ${domainsList}${githubLine}${delegateLine}
|
|
|
2409
2428
|
|
|
2410
2429
|
# ${data.displayName}
|
|
2411
2430
|
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
## Current Focus
|
|
2415
|
-
`;
|
|
2431
|
+
${bodySections}`;
|
|
2416
2432
|
writeFileSync(join(memberDir, "NODE.md"), content);
|
|
2417
2433
|
}
|
|
2418
2434
|
function isTrackedByGit(repoPath, filePath) {
|
|
@@ -2426,9 +2442,9 @@ function isTrackedByGit(repoPath, filePath) {
|
|
|
2426
2442
|
return false;
|
|
2427
2443
|
}
|
|
2428
2444
|
}
|
|
2429
|
-
const CONTEXT_TREE_DIR = join(
|
|
2445
|
+
const CONTEXT_TREE_DIR = join(DEFAULT_HOME_DIR$1, "context-tree");
|
|
2430
2446
|
/**
|
|
2431
|
-
* Resolve Context Tree to a **local path** at
|
|
2447
|
+
* Resolve Context Tree to a **local path** at $FIRST_TREE_HUB_HOME/context-tree/.
|
|
2432
2448
|
*
|
|
2433
2449
|
* Repo URL is obtained from the Hub server. The local clone is always
|
|
2434
2450
|
* managed in the standard location — no custom paths allowed.
|
|
@@ -2475,13 +2491,13 @@ async function resolveContextTreeRepo(serverUrl) {
|
|
|
2475
2491
|
return CONTEXT_TREE_DIR;
|
|
2476
2492
|
}
|
|
2477
2493
|
} catch {}
|
|
2478
|
-
const safePrefix =
|
|
2494
|
+
const safePrefix = DEFAULT_HOME_DIR$1;
|
|
2479
2495
|
if (!CONTEXT_TREE_DIR.startsWith(safePrefix) || CONTEXT_TREE_DIR === safePrefix) throw new Error(`Refusing to delete unsafe path: ${CONTEXT_TREE_DIR}`);
|
|
2480
2496
|
execSync(`rm -rf ${CONTEXT_TREE_DIR}`);
|
|
2481
2497
|
}
|
|
2482
2498
|
try {
|
|
2483
2499
|
process.stderr.write(`Cloning Context Tree to ${CONTEXT_TREE_DIR}...\n`);
|
|
2484
|
-
mkdirSync(
|
|
2500
|
+
mkdirSync(DEFAULT_HOME_DIR$1, { recursive: true });
|
|
2485
2501
|
execSync(`git ${gitConfigArgs} clone ${repoUrl} ${CONTEXT_TREE_DIR}`, {
|
|
2486
2502
|
stdio: "pipe",
|
|
2487
2503
|
env: gitEnv
|
|
@@ -2546,8 +2562,7 @@ async function promptMissingFields(options) {
|
|
|
2546
2562
|
const envStr = envHint ? ` (env: ${envHint})` : "";
|
|
2547
2563
|
return ` ${m.dotPath}${envStr}`;
|
|
2548
2564
|
});
|
|
2549
|
-
throw new Error(`Missing required configuration:\n${lines.join("\n")}\n\nProvide values via environment variables, config file (
|
|
2550
|
-
or run without --no-interactive to use the interactive setup wizard.`);
|
|
2565
|
+
throw new Error(`Missing required configuration:\n${lines.join("\n")}\n\nProvide values via environment variables, config file (${DEFAULT_HOME_DIR$1}/server.yaml),\nor run without --no-interactive to use the interactive setup wizard.`);
|
|
2551
2566
|
}
|
|
2552
2567
|
const configPath = join(options.configDir ?? DEFAULT_CONFIG_DIR, `${options.role}.yaml`);
|
|
2553
2568
|
const results = {};
|
|
@@ -2627,7 +2642,11 @@ function setNestedByDot(obj, dotPath, value) {
|
|
|
2627
2642
|
}
|
|
2628
2643
|
//#endregion
|
|
2629
2644
|
//#region ../shared/dist/index.mjs
|
|
2630
|
-
const adapterPlatformSchema = z.enum([
|
|
2645
|
+
const adapterPlatformSchema = z.enum([
|
|
2646
|
+
"feishu",
|
|
2647
|
+
"slack",
|
|
2648
|
+
"kael"
|
|
2649
|
+
]);
|
|
2631
2650
|
const adapterStatusSchema = z.enum(["active", "inactive"]);
|
|
2632
2651
|
const createAdapterConfigSchema = z.object({
|
|
2633
2652
|
platform: adapterPlatformSchema,
|
|
@@ -2900,7 +2919,7 @@ const SYSTEM_CONFIG_DEFAULTS = {
|
|
|
2900
2919
|
[SYSTEM_CONFIG_KEYS.PRESENCE_CLEANUP_SECONDS]: 60
|
|
2901
2920
|
};
|
|
2902
2921
|
//#endregion
|
|
2903
|
-
//#region ../server/dist/app-
|
|
2922
|
+
//#region ../server/dist/app-CurdzcN2.mjs
|
|
2904
2923
|
var __defProp = Object.defineProperty;
|
|
2905
2924
|
var __exportAll = (all, no_symbols) => {
|
|
2906
2925
|
let target = {};
|
|
@@ -4832,7 +4851,7 @@ async function pollInbox(db, inboxId, limit) {
|
|
|
4832
4851
|
});
|
|
4833
4852
|
});
|
|
4834
4853
|
}
|
|
4835
|
-
async function ackEntry$
|
|
4854
|
+
async function ackEntry$2(db, entryId, inboxId) {
|
|
4836
4855
|
const [entry] = await db.update(inboxEntries).set({
|
|
4837
4856
|
status: "acked",
|
|
4838
4857
|
ackedAt: /* @__PURE__ */ new Date()
|
|
@@ -4874,7 +4893,7 @@ async function agentInboxRoutes(app) {
|
|
|
4874
4893
|
app.post("/:entryId/ack", async (request, reply) => {
|
|
4875
4894
|
const identity = requireAgent(request);
|
|
4876
4895
|
const entryId = Number(request.params.entryId);
|
|
4877
|
-
await ackEntry$
|
|
4896
|
+
await ackEntry$2(app.db, entryId, identity.inboxId);
|
|
4878
4897
|
return reply.status(204).send();
|
|
4879
4898
|
});
|
|
4880
4899
|
app.post("/:entryId/renew", async (request, reply) => {
|
|
@@ -5647,7 +5666,7 @@ async function withoutProxy(fn) {
|
|
|
5647
5666
|
for (const [key, val] of Object.entries(saved)) process.env[key] = val;
|
|
5648
5667
|
}
|
|
5649
5668
|
}
|
|
5650
|
-
const OUTBOUND_BATCH_SIZE = 10;
|
|
5669
|
+
const OUTBOUND_BATCH_SIZE$1 = 10;
|
|
5651
5670
|
/** Wrap an SDK API call with proxy bypass if needed. */
|
|
5652
5671
|
function botApiCall(bot, fn) {
|
|
5653
5672
|
return bot.bypassProxy ? withoutProxy(fn) : fn();
|
|
@@ -5822,6 +5841,8 @@ function parseEventData(appId, data) {
|
|
|
5822
5841
|
const sender = data.sender;
|
|
5823
5842
|
const message = data.message;
|
|
5824
5843
|
if (!sender?.sender_id?.open_id || !message) return null;
|
|
5844
|
+
if (!sender.sender_id.union_id) process.stderr.write(`[warn] Feishu event missing union_id for sender ${sender.sender_id.open_id}, falling back to open_id\n`);
|
|
5845
|
+
const resolvedSenderId = sender.sender_id.union_id ?? sender.sender_id.open_id;
|
|
5825
5846
|
const eventId = data.event_id ?? `ws_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
5826
5847
|
let parsedContent;
|
|
5827
5848
|
try {
|
|
@@ -5838,7 +5859,8 @@ function parseEventData(appId, data) {
|
|
|
5838
5859
|
eventId,
|
|
5839
5860
|
platform: "feishu",
|
|
5840
5861
|
appId,
|
|
5841
|
-
senderId:
|
|
5862
|
+
senderId: resolvedSenderId,
|
|
5863
|
+
senderOpenId: sender.sender_id.open_id,
|
|
5842
5864
|
senderType: sender.sender_type ?? "user",
|
|
5843
5865
|
externalChannelId: message.chat_id ?? "",
|
|
5844
5866
|
chatType: message.chat_type ?? "group",
|
|
@@ -6011,7 +6033,7 @@ async function processFeishuOutbound(db, findBotByAgentId, log) {
|
|
|
6011
6033
|
JOIN adapter_agent_mappings aam ON a.id = aam.agent_id
|
|
6012
6034
|
WHERE aam.platform = 'feishu' AND ie.status = 'pending'
|
|
6013
6035
|
ORDER BY ie.created_at
|
|
6014
|
-
LIMIT ${OUTBOUND_BATCH_SIZE}
|
|
6036
|
+
LIMIT ${OUTBOUND_BATCH_SIZE$1}
|
|
6015
6037
|
FOR UPDATE SKIP LOCKED
|
|
6016
6038
|
)
|
|
6017
6039
|
RETURNING id, inbox_id, message_id, chat_id
|
|
@@ -6020,21 +6042,21 @@ async function processFeishuOutbound(db, findBotByAgentId, log) {
|
|
|
6020
6042
|
for (const entry of claimed) try {
|
|
6021
6043
|
const [msg] = await db.select().from(messages).where(eq(messages.id, entry.message_id)).limit(1);
|
|
6022
6044
|
if (!msg) {
|
|
6023
|
-
await ackEntry(db, entry.id);
|
|
6045
|
+
await ackEntry$1(db, entry.id);
|
|
6024
6046
|
continue;
|
|
6025
6047
|
}
|
|
6026
6048
|
if (msg.metadata?.source === "feishu") {
|
|
6027
|
-
await ackEntry(db, entry.id);
|
|
6049
|
+
await ackEntry$1(db, entry.id);
|
|
6028
6050
|
continue;
|
|
6029
6051
|
}
|
|
6030
6052
|
const channelMapping = await findExternalChannelByChat(db, "feishu", entry.chat_id ?? msg.chatId);
|
|
6031
6053
|
if (!channelMapping) {
|
|
6032
|
-
await ackEntry(db, entry.id);
|
|
6054
|
+
await ackEntry$1(db, entry.id);
|
|
6033
6055
|
continue;
|
|
6034
6056
|
}
|
|
6035
6057
|
const dedupKey = `${msg.id}:${channelMapping.externalChannelId}`;
|
|
6036
6058
|
if (sentMessages.has(dedupKey)) {
|
|
6037
|
-
await ackEntry(db, entry.id);
|
|
6059
|
+
await ackEntry$1(db, entry.id);
|
|
6038
6060
|
continue;
|
|
6039
6061
|
}
|
|
6040
6062
|
const bot = findBotByAgentId(msg.senderId);
|
|
@@ -6043,7 +6065,7 @@ async function processFeishuOutbound(db, findBotByAgentId, log) {
|
|
|
6043
6065
|
messageId: msg.id,
|
|
6044
6066
|
senderId: msg.senderId
|
|
6045
6067
|
}, "Outbound skip: sender has no feishu bot binding");
|
|
6046
|
-
await ackEntry(db, entry.id);
|
|
6068
|
+
await ackEntry$1(db, entry.id);
|
|
6047
6069
|
continue;
|
|
6048
6070
|
}
|
|
6049
6071
|
const { msgType, content } = formatForFeishu(msg.format, msg.content);
|
|
@@ -6063,7 +6085,7 @@ async function processFeishuOutbound(db, findBotByAgentId, log) {
|
|
|
6063
6085
|
externalMessageId: externalMsgId,
|
|
6064
6086
|
externalChannelId: channelMapping.externalChannelId
|
|
6065
6087
|
});
|
|
6066
|
-
await ackEntry(db, entry.id);
|
|
6088
|
+
await ackEntry$1(db, entry.id);
|
|
6067
6089
|
bot.lastActiveAt = /* @__PURE__ */ new Date();
|
|
6068
6090
|
sent++;
|
|
6069
6091
|
} catch (err) {
|
|
@@ -6078,7 +6100,7 @@ async function processFeishuOutbound(db, findBotByAgentId, log) {
|
|
|
6078
6100
|
errors: errorCount
|
|
6079
6101
|
};
|
|
6080
6102
|
}
|
|
6081
|
-
async function ackEntry(db, entryId) {
|
|
6103
|
+
async function ackEntry$1(db, entryId) {
|
|
6082
6104
|
await db.update(inboxEntries).set({
|
|
6083
6105
|
status: "acked",
|
|
6084
6106
|
ackedAt: /* @__PURE__ */ new Date()
|
|
@@ -6116,10 +6138,11 @@ function formatForFeishu(format, content) {
|
|
|
6116
6138
|
content: JSON.stringify({ text })
|
|
6117
6139
|
};
|
|
6118
6140
|
}
|
|
6119
|
-
function createBackgroundTasks(app, instanceId, adapterManager) {
|
|
6141
|
+
function createBackgroundTasks(app, instanceId, adapterManager, kaelRuntime) {
|
|
6120
6142
|
let inboxTimer = null;
|
|
6121
6143
|
let heartbeatTimer = null;
|
|
6122
6144
|
let adapterOutboundTimer = null;
|
|
6145
|
+
let kaelOutboundTimer = null;
|
|
6123
6146
|
return {
|
|
6124
6147
|
start() {
|
|
6125
6148
|
inboxTimer = setInterval(async () => {
|
|
@@ -6148,6 +6171,13 @@ function createBackgroundTasks(app, instanceId, adapterManager) {
|
|
|
6148
6171
|
app.log.error(err, "Adapter outbound processing failed");
|
|
6149
6172
|
}
|
|
6150
6173
|
}, 5e3);
|
|
6174
|
+
if (kaelRuntime) kaelOutboundTimer = setInterval(async () => {
|
|
6175
|
+
try {
|
|
6176
|
+
await kaelRuntime.processOutbound();
|
|
6177
|
+
} catch (err) {
|
|
6178
|
+
app.log.error(err, "Kael outbound processing failed");
|
|
6179
|
+
}
|
|
6180
|
+
}, 5e3);
|
|
6151
6181
|
heartbeatInstance(app.db, instanceId).catch((err) => {
|
|
6152
6182
|
app.log.error(err, "Failed initial heartbeat");
|
|
6153
6183
|
});
|
|
@@ -6165,9 +6195,195 @@ function createBackgroundTasks(app, instanceId, adapterManager) {
|
|
|
6165
6195
|
clearInterval(adapterOutboundTimer);
|
|
6166
6196
|
adapterOutboundTimer = null;
|
|
6167
6197
|
}
|
|
6198
|
+
if (kaelOutboundTimer) {
|
|
6199
|
+
clearInterval(kaelOutboundTimer);
|
|
6200
|
+
kaelOutboundTimer = null;
|
|
6201
|
+
}
|
|
6168
6202
|
}
|
|
6169
6203
|
};
|
|
6170
6204
|
}
|
|
6205
|
+
const OUTBOUND_BATCH_SIZE = 10;
|
|
6206
|
+
function createKaelRuntime(db, encryptionKey, kaelEndpoint, kaelApiKey, serverUrl, log) {
|
|
6207
|
+
const agentConfigs = /* @__PURE__ */ new Map();
|
|
6208
|
+
const inboxToConfig = /* @__PURE__ */ new Map();
|
|
6209
|
+
let aborted = false;
|
|
6210
|
+
return {
|
|
6211
|
+
async reload() {
|
|
6212
|
+
if (!encryptionKey) {
|
|
6213
|
+
log.warn("Encryption key not set — Kael runtime disabled");
|
|
6214
|
+
return;
|
|
6215
|
+
}
|
|
6216
|
+
if (!kaelEndpoint) {
|
|
6217
|
+
log.debug("KAEL_ENDPOINT not configured — Kael runtime idle");
|
|
6218
|
+
agentConfigs.clear();
|
|
6219
|
+
inboxToConfig.clear();
|
|
6220
|
+
return;
|
|
6221
|
+
}
|
|
6222
|
+
const configs = await db.select().from(adapterConfigs).where(and(eq(adapterConfigs.platform, "kael"), eq(adapterConfigs.status, "active")));
|
|
6223
|
+
const configAgentIds = configs.filter((c) => c.credentials).map((c) => c.agentId);
|
|
6224
|
+
const agentRows = configAgentIds.length > 0 ? await db.execute(sql`SELECT id, inbox_id FROM agents WHERE id IN (${sql.join(configAgentIds.map((id) => sql`${id}`), sql`, `)}) AND status = 'active'`) : [];
|
|
6225
|
+
const agentInboxMap = new Map(agentRows.map((a) => [a.id, a.inbox_id]));
|
|
6226
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6227
|
+
for (const config of configs) {
|
|
6228
|
+
if (!config.credentials) continue;
|
|
6229
|
+
let creds;
|
|
6230
|
+
try {
|
|
6231
|
+
creds = decryptCredentials(config.credentials, encryptionKey);
|
|
6232
|
+
} catch (err) {
|
|
6233
|
+
log.error({
|
|
6234
|
+
configId: config.id,
|
|
6235
|
+
err
|
|
6236
|
+
}, "Failed to decrypt Kael adapter credentials");
|
|
6237
|
+
continue;
|
|
6238
|
+
}
|
|
6239
|
+
seen.add(config.agentId);
|
|
6240
|
+
const inboxId = agentInboxMap.get(config.agentId);
|
|
6241
|
+
if (!inboxId) {
|
|
6242
|
+
log.warn({
|
|
6243
|
+
configId: config.id,
|
|
6244
|
+
agentId: config.agentId
|
|
6245
|
+
}, "Kael config agent not found or inactive");
|
|
6246
|
+
continue;
|
|
6247
|
+
}
|
|
6248
|
+
const entry = {
|
|
6249
|
+
configId: config.id,
|
|
6250
|
+
agentId: config.agentId,
|
|
6251
|
+
inboxId,
|
|
6252
|
+
kaelUserId: creds.kaelUserId,
|
|
6253
|
+
kaelProjectId: creds.kaelProjectId,
|
|
6254
|
+
agentToken: creds.agentToken
|
|
6255
|
+
};
|
|
6256
|
+
agentConfigs.set(config.agentId, entry);
|
|
6257
|
+
inboxToConfig.set(inboxId, entry);
|
|
6258
|
+
log.info({
|
|
6259
|
+
configId: config.id,
|
|
6260
|
+
agentId: config.agentId
|
|
6261
|
+
}, "Loaded Kael adapter config");
|
|
6262
|
+
}
|
|
6263
|
+
for (const agentId of agentConfigs.keys()) if (!seen.has(agentId)) {
|
|
6264
|
+
const old = agentConfigs.get(agentId);
|
|
6265
|
+
if (old) inboxToConfig.delete(old.inboxId);
|
|
6266
|
+
agentConfigs.delete(agentId);
|
|
6267
|
+
log.info({ agentId }, "Removed inactive Kael adapter config");
|
|
6268
|
+
}
|
|
6269
|
+
},
|
|
6270
|
+
async processOutbound() {
|
|
6271
|
+
if (agentConfigs.size === 0 || !kaelEndpoint || aborted) return {
|
|
6272
|
+
sent: 0,
|
|
6273
|
+
errors: 0
|
|
6274
|
+
};
|
|
6275
|
+
let sent = 0;
|
|
6276
|
+
let errorCount = 0;
|
|
6277
|
+
try {
|
|
6278
|
+
const agentIds = [...agentConfigs.keys()];
|
|
6279
|
+
const claimed = await db.execute(sql`
|
|
6280
|
+
UPDATE inbox_entries
|
|
6281
|
+
SET status = 'delivered', delivered_at = NOW()
|
|
6282
|
+
WHERE id IN (
|
|
6283
|
+
SELECT ie.id FROM inbox_entries ie
|
|
6284
|
+
JOIN agents a ON ie.inbox_id = a.inbox_id
|
|
6285
|
+
JOIN adapter_configs ac ON a.id = ac.agent_id
|
|
6286
|
+
WHERE ac.platform = 'kael' AND ac.status = 'active'
|
|
6287
|
+
AND ie.status = 'pending'
|
|
6288
|
+
AND a.id IN (${sql.join(agentIds.map((id) => sql`${id}`), sql`, `)})
|
|
6289
|
+
ORDER BY ie.created_at
|
|
6290
|
+
LIMIT ${OUTBOUND_BATCH_SIZE}
|
|
6291
|
+
FOR UPDATE OF ie SKIP LOCKED
|
|
6292
|
+
)
|
|
6293
|
+
RETURNING id, inbox_id, message_id, chat_id
|
|
6294
|
+
`);
|
|
6295
|
+
for (const entry of claimed) try {
|
|
6296
|
+
const [msg] = await db.select().from(messages).where(eq(messages.id, entry.message_id)).limit(1);
|
|
6297
|
+
if (!msg) {
|
|
6298
|
+
await ackEntry(db, entry.id);
|
|
6299
|
+
continue;
|
|
6300
|
+
}
|
|
6301
|
+
const config = inboxToConfig.get(entry.inbox_id);
|
|
6302
|
+
if (!config) {
|
|
6303
|
+
await ackEntry(db, entry.id);
|
|
6304
|
+
continue;
|
|
6305
|
+
}
|
|
6306
|
+
const messageContent = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
|
|
6307
|
+
const payload = {
|
|
6308
|
+
hub_chat_id: entry.chat_id ?? msg.chatId,
|
|
6309
|
+
hub_agent_id: config.agentId,
|
|
6310
|
+
hub_server_url: serverUrl,
|
|
6311
|
+
hub_agent_token: config.agentToken,
|
|
6312
|
+
user_id: config.kaelUserId,
|
|
6313
|
+
project_id: config.kaelProjectId,
|
|
6314
|
+
message: messageContent,
|
|
6315
|
+
sender_id: msg.senderId,
|
|
6316
|
+
format: msg.format
|
|
6317
|
+
};
|
|
6318
|
+
const response = await fetch(`${kaelEndpoint}/api/v1/hub/messages`, {
|
|
6319
|
+
method: "POST",
|
|
6320
|
+
headers: {
|
|
6321
|
+
"Content-Type": "application/json",
|
|
6322
|
+
...kaelApiKey ? { "X-Internal-API-Key": kaelApiKey } : {}
|
|
6323
|
+
},
|
|
6324
|
+
body: JSON.stringify(payload)
|
|
6325
|
+
});
|
|
6326
|
+
if (!response.ok) {
|
|
6327
|
+
const body = await response.text().catch(() => "");
|
|
6328
|
+
log.error({
|
|
6329
|
+
entryId: entry.id,
|
|
6330
|
+
status: response.status,
|
|
6331
|
+
body
|
|
6332
|
+
}, "Kael API rejected outbound message");
|
|
6333
|
+
await nackEntry(db, entry.id);
|
|
6334
|
+
errorCount++;
|
|
6335
|
+
continue;
|
|
6336
|
+
}
|
|
6337
|
+
await ackEntry(db, entry.id);
|
|
6338
|
+
sent++;
|
|
6339
|
+
} catch (err) {
|
|
6340
|
+
log.error({
|
|
6341
|
+
entryId: entry.id,
|
|
6342
|
+
err
|
|
6343
|
+
}, "Failed to send outbound Kael message");
|
|
6344
|
+
await nackEntry(db, entry.id).catch((nackErr) => {
|
|
6345
|
+
log.error({
|
|
6346
|
+
entryId: entry.id,
|
|
6347
|
+
err: nackErr
|
|
6348
|
+
}, "Failed to NACK entry");
|
|
6349
|
+
});
|
|
6350
|
+
errorCount++;
|
|
6351
|
+
}
|
|
6352
|
+
} catch (err) {
|
|
6353
|
+
log.error({ err }, "Kael outbound processing error");
|
|
6354
|
+
return {
|
|
6355
|
+
sent: 0,
|
|
6356
|
+
errors: 1
|
|
6357
|
+
};
|
|
6358
|
+
}
|
|
6359
|
+
return {
|
|
6360
|
+
sent,
|
|
6361
|
+
errors: errorCount
|
|
6362
|
+
};
|
|
6363
|
+
},
|
|
6364
|
+
shutdown() {
|
|
6365
|
+
aborted = true;
|
|
6366
|
+
agentConfigs.clear();
|
|
6367
|
+
inboxToConfig.clear();
|
|
6368
|
+
}
|
|
6369
|
+
};
|
|
6370
|
+
}
|
|
6371
|
+
async function ackEntry(db, entryId) {
|
|
6372
|
+
await db.update(inboxEntries).set({
|
|
6373
|
+
status: "acked",
|
|
6374
|
+
ackedAt: /* @__PURE__ */ new Date()
|
|
6375
|
+
}).where(eq(inboxEntries.id, entryId));
|
|
6376
|
+
}
|
|
6377
|
+
const MAX_RETRY_COUNT = 3;
|
|
6378
|
+
async function nackEntry(db, entryId) {
|
|
6379
|
+
await db.execute(sql`
|
|
6380
|
+
UPDATE inbox_entries
|
|
6381
|
+
SET
|
|
6382
|
+
status = CASE WHEN retry_count >= ${MAX_RETRY_COUNT} THEN 'failed' ELSE 'pending' END,
|
|
6383
|
+
retry_count = retry_count + 1
|
|
6384
|
+
WHERE id = ${entryId}
|
|
6385
|
+
`);
|
|
6386
|
+
}
|
|
6171
6387
|
async function buildApp(config) {
|
|
6172
6388
|
const app = Fastify({ logger: config.logger ?? true });
|
|
6173
6389
|
const db = connectDatabase(config.database.url);
|
|
@@ -6274,14 +6490,19 @@ async function buildApp(config) {
|
|
|
6274
6490
|
app.decorate("notifier", notifier);
|
|
6275
6491
|
const adapterManager = createAdapterManager(db, config.secrets.encryptionKey, app.log, notifier);
|
|
6276
6492
|
app.decorate("adapterManager", adapterManager);
|
|
6277
|
-
const
|
|
6493
|
+
const kaelRuntime = config.kael?.endpoint ? createKaelRuntime(db, config.secrets.encryptionKey, config.kael.endpoint, config.kael.apiKey, config.kael.hubPublicUrl, app.log) : void 0;
|
|
6494
|
+
const backgroundTasks = createBackgroundTasks(app, config.instanceId, adapterManager, kaelRuntime);
|
|
6278
6495
|
notifier.onConfigChange((configType) => {
|
|
6279
|
-
if (configType === "adapter_configs")
|
|
6496
|
+
if (configType === "adapter_configs") {
|
|
6497
|
+
adapterManager.reload().catch((err) => app.log.error(err, "Adapter hot-reload failed (PG NOTIFY)"));
|
|
6498
|
+
kaelRuntime?.reload().catch((err) => app.log.error(err, "Kael hot-reload failed (PG NOTIFY)"));
|
|
6499
|
+
}
|
|
6280
6500
|
});
|
|
6281
6501
|
app.addHook("onReady", async () => {
|
|
6282
6502
|
await notifier.start();
|
|
6283
6503
|
backgroundTasks.start();
|
|
6284
6504
|
await adapterManager.reload();
|
|
6505
|
+
await kaelRuntime?.reload();
|
|
6285
6506
|
const { repo: ctRepo, branch: ctBranch, syncInterval } = config.contextTree;
|
|
6286
6507
|
const { token: ghToken } = config.github;
|
|
6287
6508
|
try {
|
|
@@ -6299,6 +6520,7 @@ async function buildApp(config) {
|
|
|
6299
6520
|
app.addHook("onClose", async () => {
|
|
6300
6521
|
backgroundTasks.stop();
|
|
6301
6522
|
adapterManager.shutdown();
|
|
6523
|
+
kaelRuntime?.shutdown();
|
|
6302
6524
|
await notifier.stop();
|
|
6303
6525
|
await listenClient.end();
|
|
6304
6526
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as ClientRuntime, C as checkWebSocket, D as ensurePostgres, E as status, M as hasAdminUser, N as FirstTreeHubSDK, O as isDockerAvailable, P as SdkError, S as checkServerReachable, T as blank, _ as checkDocker, a as formatCheckReport, b as checkServerConfig, c as onboardContinue, d as runMigrations, f as checkAgentConfigs, g as checkDatabase, h as checkContextTreeRepo, i as promptMissingFields, j as createAdminUser, k as stopPostgres, l as onboardCreate, m as checkClientConfig, n as isInteractive, p as checkAgentTokens, r as promptAddAgent, s as onboardCheck, t as startServer, v as checkGitHubToken, w as printResults, x as checkServerHealth, y as checkNodeVersion } from "./core-
|
|
2
|
-
import { a as getGitHubUsername, i as getGitHubToken, o as resolveAgentToken, r as checkBootstrapStatus, s as resolveServerUrl, t as bootstrapToken } from "./bootstrap-
|
|
1
|
+
import { A as ClientRuntime, C as checkWebSocket, D as ensurePostgres, E as status, M as hasAdminUser, N as FirstTreeHubSDK, O as isDockerAvailable, P as SdkError, S as checkServerReachable, T as blank, _ as checkDocker, a as formatCheckReport, b as checkServerConfig, c as onboardContinue, d as runMigrations, f as checkAgentConfigs, g as checkDatabase, h as checkContextTreeRepo, i as promptMissingFields, j as createAdminUser, k as stopPostgres, l as onboardCreate, m as checkClientConfig, n as isInteractive, p as checkAgentTokens, r as promptAddAgent, s as onboardCheck, t as startServer, v as checkGitHubToken, w as printResults, x as checkServerHealth, y as checkNodeVersion } from "./core-CHL_dgzu.mjs";
|
|
2
|
+
import { a as getGitHubUsername, i as getGitHubToken, o as resolveAgentToken, r as checkBootstrapStatus, s as resolveServerUrl, t as bootstrapToken } from "./bootstrap-mhkpeOEc.mjs";
|
|
3
3
|
import { n as bindFeishuUser, t as bindFeishuBot } from "./feishu-Y4m2zFc3.mjs";
|
|
4
4
|
export { ClientRuntime, FirstTreeHubSDK, SdkError, bindFeishuBot, bindFeishuUser, blank, bootstrapToken, checkAgentConfigs, checkAgentTokens, checkBootstrapStatus, checkClientConfig, checkContextTreeRepo, checkDatabase, checkDocker, checkGitHubToken, checkNodeVersion, checkServerConfig, checkServerHealth, checkServerReachable, checkWebSocket, createAdminUser, ensurePostgres, formatCheckReport, getGitHubToken, getGitHubUsername, hasAdminUser, isDockerAvailable, isInteractive, onboardCheck, onboardContinue, onboardCreate, printResults, promptAddAgent, promptMissingFields, resolveAgentToken, resolveServerUrl, runMigrations, startServer, status, stopPostgres };
|