@agent-team-foundation/first-tree-hub 0.9.10 → 0.10.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/dist/{bootstrap-hh_PkTu6.mjs → bootstrap-CtVqQA8a.mjs} +1 -1
- package/dist/cli/index.mjs +42 -81
- package/dist/{core-BWaSYpXv.mjs → core-BgiFGT7Y.mjs} +1122 -834
- package/dist/drizzle/0024_display_name_not_null.sql +31 -0
- package/dist/drizzle/0025_inbox_silent_entries.sql +53 -0
- package/dist/drizzle/meta/_journal.json +14 -0
- package/dist/{feishu-BJaN64iR.mjs → feishu-DEmwoNn_.mjs} +70 -9
- package/dist/index.mjs +5 -5
- package/dist/{logger-core-BTmvdflj-DhdipBkV.mjs → logger-core-BTmvdflj-DjW8FM4T.mjs} +1 -1
- package/dist/{observability-hDEdrmMS.mjs → observability-DDkJwSKv.mjs} +2 -2
- package/dist/{observability-DV_fQKqV-CuLWzBxQ.mjs → observability-DV_fQKqV-oxfXX6Z2.mjs} +1 -1
- package/dist/web/assets/index-DStPeqrX.css +1 -0
- package/dist/web/assets/index-Wgxk3V_m.js +371 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/web/assets/index-Cyvhyw0R.js +0 -361
- package/dist/web/assets/index-DEwlT6PE.css +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { d as __exportAll } from "./esm-CYu4tXXn.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { o as logFormatSchema, s as logLevelSchema } from "./logger-core-BTmvdflj-DjW8FM4T.mjs";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { dirname, join } from "node:path";
|
|
5
5
|
import { homedir } from "node:os";
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "../observability-DV_fQKqV-
|
|
3
|
-
import { $ as configureClientLoggerForService, A as
|
|
4
|
-
import "../logger-core-BTmvdflj-
|
|
5
|
-
import { C as serverConfigSchema, _ as loadAgents, b as resetConfig, c as saveCredentials, d as DEFAULT_HOME_DIR, f as agentConfigSchema, g as initConfig, h as getConfigValue, i as loadCredentials, l as DEFAULT_CONFIG_DIR, n as ensureFreshAccessToken, o as resolveServerUrl, p as clientConfigSchema, r as ensureFreshAdminToken, s as saveAgentConfig, u as DEFAULT_DATA_DIR, w as setConfigValue, x as resetConfigMeta, y as readConfigFile } from "../bootstrap-
|
|
6
|
-
import { n as bindFeishuUser, t as bindFeishuBot } from "../feishu-
|
|
2
|
+
import "../observability-DV_fQKqV-oxfXX6Z2.mjs";
|
|
3
|
+
import { $ as configureClientLoggerForService, A as installClientService, B as createOwner, C as checkNodeVersion, D as checkWebSocket, E as checkServerReachable, G as setJsonMode, H as resolveReplyToFromEnv, I as stopPostgres, J as FirstTreeHubSDK, L as ClientRuntime, O as printResults, Q as applyClientLoggerConfig, R as handleClientOrgMismatch, S as checkDocker, T as checkServerHealth, W as print, X as SessionRegistry, Y as SdkError, Z as cleanWorkspaces, _ as runMigrations, a as COMMAND_VERSION, b as checkClientConfig, c as promptMissingFields, d as onboardCheck, f as onboardCreate, g as migrateLocalAgentDirs, h as createApiNameResolver, i as startServer, j as isServiceSupported, k as getClientServiceStatus, l as formatCheckReport, m as runHomeMigration, n as declineUpdate, o as isInteractive, p as saveOnboardState, q as ClientOrgMismatchError, r as promptUpdate, s as promptAddAgent, t as createExecuteUpdate, u as loadOnboardState, v as checkAgentConfigs, w as checkServerConfig, x as checkDatabase, y as checkBackgroundService } from "../core-BgiFGT7Y.mjs";
|
|
4
|
+
import "../logger-core-BTmvdflj-DjW8FM4T.mjs";
|
|
5
|
+
import { C as serverConfigSchema, _ as loadAgents, b as resetConfig, c as saveCredentials, d as DEFAULT_HOME_DIR, f as agentConfigSchema, g as initConfig, h as getConfigValue, i as loadCredentials, l as DEFAULT_CONFIG_DIR, n as ensureFreshAccessToken, o as resolveServerUrl, p as clientConfigSchema, r as ensureFreshAdminToken, s as saveAgentConfig, u as DEFAULT_DATA_DIR, w as setConfigValue, x as resetConfigMeta, y as readConfigFile } from "../bootstrap-CtVqQA8a.mjs";
|
|
6
|
+
import { n as bindFeishuUser, t as bindFeishuBot } from "../feishu-DEmwoNn_.mjs";
|
|
7
7
|
import { join } from "node:path";
|
|
8
8
|
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync } from "node:fs";
|
|
9
9
|
import { Command } from "commander";
|
|
@@ -295,16 +295,10 @@ async function resolveAgent(serverUrl, adminToken, agentName) {
|
|
|
295
295
|
function registerAgentCommands(program) {
|
|
296
296
|
const agent = program.command("agent").description("Agent management — config, bindings, messaging");
|
|
297
297
|
registerAgentConfigCommands(agent);
|
|
298
|
-
agent.command("add
|
|
298
|
+
agent.command("add").description("Register an existing Hub agent on this client (uses the agent name from the Hub)").option("--agent-id <id>", "Agent UUID on the Hub").action(async (options) => {
|
|
299
299
|
try {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
if (!agentName || !agentId) {
|
|
303
|
-
const result = await promptAddAgent();
|
|
304
|
-
agentName = agentName ?? result.name;
|
|
305
|
-
agentId = agentId ?? result.agentId;
|
|
306
|
-
}
|
|
307
|
-
if (!agentName || !agentId) fail("MISSING_AGENT_ARGS", "Both agent name and agent-id are required.", 2);
|
|
300
|
+
const { name: agentName, agentId } = await promptAddAgent({ agentId: options?.agentId });
|
|
301
|
+
if (!agentName || !agentId) fail("MISSING_AGENT_ARGS", "Agent UUID (and a hub name for that UUID) are required.", 2);
|
|
308
302
|
const agentDir = join(DEFAULT_CONFIG_DIR, "agents", agentName);
|
|
309
303
|
mkdirSync(agentDir, {
|
|
310
304
|
recursive: true,
|
|
@@ -323,7 +317,7 @@ function registerAgentCommands(program) {
|
|
|
323
317
|
process.exit(1);
|
|
324
318
|
}
|
|
325
319
|
});
|
|
326
|
-
agent.command("remove <name>").description("Remove
|
|
320
|
+
agent.command("remove <name>").description("Remove an agent from this client and delete its local runtime data (config dir, workspace, session state)").action((name) => {
|
|
327
321
|
const agentDir = join(DEFAULT_CONFIG_DIR, "agents", name);
|
|
328
322
|
if (!existsSync(agentDir)) {
|
|
329
323
|
print.line(` Agent "${name}" not found.\n`);
|
|
@@ -458,7 +452,7 @@ function registerAgentCommands(program) {
|
|
|
458
452
|
fail("BIND_CLIENT_ERROR", error instanceof Error ? error.message : String(error));
|
|
459
453
|
}
|
|
460
454
|
});
|
|
461
|
-
bind.command("bot").description("Bind a Feishu bot to this agent (self-service)").requiredOption("--platform <platform>", "Platform: feishu").requiredOption("--app-id <id>", "Feishu bot App ID").requiredOption("--app-secret <secret>", "Feishu bot App Secret").option("--agent <name>", "
|
|
455
|
+
bind.command("bot").description("Bind a Feishu bot to this agent (self-service)").requiredOption("--platform <platform>", "Platform: feishu").requiredOption("--app-id <id>", "Feishu bot App ID").requiredOption("--app-secret <secret>", "Feishu bot App Secret").option("--agent <name>", "Agent name on the Hub (default: first configured on this client)").option("--server <url>", "Hub server URL").action(async (options) => {
|
|
462
456
|
try {
|
|
463
457
|
if (options.platform !== "feishu") fail("UNSUPPORTED_PLATFORM", `Platform "${options.platform}" is not supported. Use "feishu".`);
|
|
464
458
|
const serverUrl = resolveServerUrl(options.server);
|
|
@@ -473,7 +467,7 @@ function registerAgentCommands(program) {
|
|
|
473
467
|
fail("BIND_BOT_ERROR", error instanceof Error ? error.message : String(error));
|
|
474
468
|
}
|
|
475
469
|
});
|
|
476
|
-
bind.command("user <humanAgentId>").description("Bind a Feishu user to a human agent (via delegate_mention)").requiredOption("--platform <platform>", "Platform: feishu").requiredOption("--feishu-id <id>", "Feishu user ID (ou_xxx)").option("--agent <name>", "
|
|
470
|
+
bind.command("user <humanAgentId>").description("Bind a Feishu user to a human agent (via delegate_mention)").requiredOption("--platform <platform>", "Platform: feishu").requiredOption("--feishu-id <id>", "Feishu user ID (ou_xxx)").option("--agent <name>", "Agent name on the Hub (default: first configured on this client)").option("--server <url>", "Hub server URL").action(async (humanAgentId, options) => {
|
|
477
471
|
try {
|
|
478
472
|
if (options.platform !== "feishu") fail("UNSUPPORTED_PLATFORM", `Platform "${options.platform}" is not supported. Use "feishu".`);
|
|
479
473
|
const serverUrl = resolveServerUrl(options.server);
|
|
@@ -489,7 +483,7 @@ function registerAgentCommands(program) {
|
|
|
489
483
|
fail("BIND_USER_ERROR", error instanceof Error ? error.message : String(error));
|
|
490
484
|
}
|
|
491
485
|
});
|
|
492
|
-
agent.command("send <target> [message]").description("Send a message to an agent or chat").option("-f, --format <format>", "Message format (text|markdown|card)", "text").option("--chat", "Treat target as chat ID instead of agent ID").option("-m, --metadata <json>", "JSON metadata to attach").option("--reply-to <messageId>", "Message ID to reply to").option("--reply-to-inbox <inboxId>", "Cross-chat reply target inbox").option("--reply-to-chat <chatId>", "Cross-chat reply target chat").option("--agent <name>", "
|
|
486
|
+
agent.command("send <target> [message]").description("Send a message to an agent or chat").option("-f, --format <format>", "Message format (text|markdown|card)", "text").option("--chat", "Treat target as chat ID instead of agent ID").option("-m, --metadata <json>", "JSON metadata to attach").option("--reply-to <messageId>", "Message ID to reply to").option("--reply-to-inbox <inboxId>", "Cross-chat reply target inbox").option("--reply-to-chat <chatId>", "Cross-chat reply target chat").option("--agent <name>", "Agent name on the Hub (default: first configured on this client)").action(async (target, message, options) => {
|
|
493
487
|
try {
|
|
494
488
|
const content = message ?? await readStdin();
|
|
495
489
|
if (!content) fail("NO_MESSAGE", "No message provided. Pass as argument or pipe via stdin.", 2);
|
|
@@ -523,7 +517,7 @@ function registerAgentCommands(program) {
|
|
|
523
517
|
handleSdkError(error);
|
|
524
518
|
}
|
|
525
519
|
});
|
|
526
|
-
agent.command("chats").description("List chats this agent participates in").option("-l, --limit <number>", "Maximum chats to return (1-100)", "20").option("--cursor <cursor>", "Pagination cursor from previous response").option("--agent <name>", "
|
|
520
|
+
agent.command("chats").description("List chats this agent participates in").option("-l, --limit <number>", "Maximum chats to return (1-100)", "20").option("--cursor <cursor>", "Pagination cursor from previous response").option("--agent <name>", "Agent name on the Hub (default: first configured on this client)").action(async (options) => {
|
|
527
521
|
try {
|
|
528
522
|
const limit = parseLimit(options.limit, 100);
|
|
529
523
|
success(await createSdk(options.agent).listChats({
|
|
@@ -534,7 +528,7 @@ function registerAgentCommands(program) {
|
|
|
534
528
|
handleSdkError(error);
|
|
535
529
|
}
|
|
536
530
|
});
|
|
537
|
-
agent.command("history <chatId>").description("View message history in a chat").option("-l, --limit <number>", "Maximum messages to return (1-100)", "20").option("--cursor <cursor>", "Pagination cursor from previous response").option("--agent <name>", "
|
|
531
|
+
agent.command("history <chatId>").description("View message history in a chat").option("-l, --limit <number>", "Maximum messages to return (1-100)", "20").option("--cursor <cursor>", "Pagination cursor from previous response").option("--agent <name>", "Agent name on the Hub (default: first configured on this client)").action(async (chatId, options) => {
|
|
538
532
|
try {
|
|
539
533
|
const limit = parseLimit(options.limit, 100);
|
|
540
534
|
success(await createSdk(options.agent).listMessages(chatId, {
|
|
@@ -738,14 +732,14 @@ function registerAgentCommands(program) {
|
|
|
738
732
|
fail("CHAT_ERROR", error instanceof Error ? error.message : String(error));
|
|
739
733
|
}
|
|
740
734
|
});
|
|
741
|
-
agent.command("register").description("Register this agent and return identity info").option("--agent <name>", "
|
|
735
|
+
agent.command("register").description("Register this agent and return identity info").option("--agent <name>", "Agent name on the Hub (default: first configured on this client)").action(async (options) => {
|
|
742
736
|
try {
|
|
743
737
|
success(await createSdk(options.agent).register());
|
|
744
738
|
} catch (error) {
|
|
745
739
|
handleSdkError(error);
|
|
746
740
|
}
|
|
747
741
|
});
|
|
748
|
-
agent.command("pull").description("Pull pending messages from inbox").option("-l, --limit <number>", "Maximum entries to return", "10").option("-a, --ack", "Automatically ACK entries after pulling").option("--agent <name>", "
|
|
742
|
+
agent.command("pull").description("Pull pending messages from inbox").option("-l, --limit <number>", "Maximum entries to return", "10").option("-a, --ack", "Automatically ACK entries after pulling").option("--agent <name>", "Agent name on the Hub (default: first configured on this client)").action(async (options) => {
|
|
749
743
|
try {
|
|
750
744
|
const sdk = createSdk(options.agent);
|
|
751
745
|
const limit = parseLimit(options.limit, 50);
|
|
@@ -922,6 +916,17 @@ function registerConnectCommand(parent) {
|
|
|
922
916
|
if (options.service === false) print.line(" (--no-service) running inline — Ctrl+C to stop\n");
|
|
923
917
|
else print.line(` Background service not supported on ${process.platform}; running inline.\n`);
|
|
924
918
|
const agentsDir = join(DEFAULT_CONFIG_DIR, "agents");
|
|
919
|
+
try {
|
|
920
|
+
await migrateLocalAgentDirs({
|
|
921
|
+
agentsDir,
|
|
922
|
+
workspacesDir: join(DEFAULT_DATA_DIR, "workspaces"),
|
|
923
|
+
sessionsDir: join(DEFAULT_DATA_DIR, "sessions"),
|
|
924
|
+
resolver: createApiNameResolver(config.server.url, () => ensureFreshAccessToken())
|
|
925
|
+
});
|
|
926
|
+
} catch (err) {
|
|
927
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
928
|
+
print.status("⚠️", `agent-dir migration skipped: ${msg}`);
|
|
929
|
+
}
|
|
925
930
|
const agents = loadAgents({
|
|
926
931
|
schema: agentConfigSchema,
|
|
927
932
|
agentsDir
|
|
@@ -984,6 +989,17 @@ function registerClientCommands(program) {
|
|
|
984
989
|
applyClientLoggerConfig({ level: config.logLevel });
|
|
985
990
|
if (process.env.FIRST_TREE_HUB_SERVICE_MODE === "1") configureClientLoggerForService(join(DEFAULT_HOME_DIR, "logs"));
|
|
986
991
|
const agentsDir = join(DEFAULT_CONFIG_DIR, "agents");
|
|
992
|
+
try {
|
|
993
|
+
await migrateLocalAgentDirs({
|
|
994
|
+
agentsDir,
|
|
995
|
+
workspacesDir: join(DEFAULT_DATA_DIR, "workspaces"),
|
|
996
|
+
sessionsDir: join(DEFAULT_DATA_DIR, "sessions"),
|
|
997
|
+
resolver: createApiNameResolver(config.server.url, () => ensureFreshAccessToken())
|
|
998
|
+
});
|
|
999
|
+
} catch (err) {
|
|
1000
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1001
|
+
print.status("⚠️", `agent-dir migration skipped: ${msg}`);
|
|
1002
|
+
}
|
|
987
1003
|
const agents = loadAgents({
|
|
988
1004
|
schema: agentConfigSchema,
|
|
989
1005
|
agentsDir
|
|
@@ -1031,7 +1047,8 @@ function registerClientCommands(program) {
|
|
|
1031
1047
|
checkClientConfig(),
|
|
1032
1048
|
await checkServerReachable(),
|
|
1033
1049
|
checkAgentConfigs(),
|
|
1034
|
-
await checkWebSocket()
|
|
1050
|
+
await checkWebSocket(),
|
|
1051
|
+
checkBackgroundService()
|
|
1035
1052
|
]);
|
|
1036
1053
|
});
|
|
1037
1054
|
client.command("stop").description("Stop the client (sends SIGTERM to running process)").action(() => {
|
|
@@ -1056,62 +1073,6 @@ function registerClientCommands(program) {
|
|
|
1056
1073
|
print.line(" No agents directory found.\n");
|
|
1057
1074
|
}
|
|
1058
1075
|
});
|
|
1059
|
-
const service = client.command("service").description("Install/uninstall the background service that keeps this computer online");
|
|
1060
|
-
service.command("install").description("Install as a background service — auto-starts on login/boot").action(() => {
|
|
1061
|
-
if (!isServiceSupported()) {
|
|
1062
|
-
print.line(` Background service is not supported on ${process.platform}.\n Run \`first-tree-hub client start\` manually to keep the computer online.
|
|
1063
|
-
`);
|
|
1064
|
-
process.exit(1);
|
|
1065
|
-
}
|
|
1066
|
-
try {
|
|
1067
|
-
const info = installClientService();
|
|
1068
|
-
print.line(`\n \u2713 Installed as a background service (${info.platform}).\n`);
|
|
1069
|
-
print.line(` Unit: ${info.unitPath}\n`);
|
|
1070
|
-
print.line(` Logs: ${info.logDir}\n`);
|
|
1071
|
-
if (info.state === "active") print.line(` State: running${info.detail ? ` (${info.detail})` : ""}\n`);
|
|
1072
|
-
else print.line(` State: ${info.state}${info.detail ? ` (${info.detail})` : ""}\n`);
|
|
1073
|
-
print.line("\n You can close this terminal — the computer stays online.\n");
|
|
1074
|
-
} catch (error) {
|
|
1075
|
-
fail("SERVICE_INSTALL_ERROR", error instanceof Error ? error.message : String(error));
|
|
1076
|
-
}
|
|
1077
|
-
});
|
|
1078
|
-
service.command("status").description("Show background service state").action(() => {
|
|
1079
|
-
const info = getClientServiceStatus();
|
|
1080
|
-
if (info.platform === "unsupported") {
|
|
1081
|
-
print.line(` Not supported on ${process.platform}.\n`);
|
|
1082
|
-
return;
|
|
1083
|
-
}
|
|
1084
|
-
print.line(`\n ${info.platform}: ${info.label}\n`);
|
|
1085
|
-
print.line(` Unit: ${info.unitPath}\n`);
|
|
1086
|
-
print.line(` Logs: ${info.logDir}\n`);
|
|
1087
|
-
print.line(` State: ${info.state}${info.detail ? ` (${info.detail})` : ""}\n\n`);
|
|
1088
|
-
});
|
|
1089
|
-
service.command("uninstall").description("Stop and remove the background service").action(() => {
|
|
1090
|
-
if (!isServiceSupported()) {
|
|
1091
|
-
print.line(` Not supported on ${process.platform}.\n`);
|
|
1092
|
-
return;
|
|
1093
|
-
}
|
|
1094
|
-
try {
|
|
1095
|
-
const info = uninstallClientService();
|
|
1096
|
-
print.line(`\n \u2713 Uninstalled background service (${info.platform}).\n\n`);
|
|
1097
|
-
} catch (error) {
|
|
1098
|
-
fail("SERVICE_UNINSTALL_ERROR", error instanceof Error ? error.message : String(error));
|
|
1099
|
-
}
|
|
1100
|
-
});
|
|
1101
|
-
service.command("logs").description("Read background-service logs (pretty by default)").option("-f, --tail", "follow new lines as they arrive (Ctrl+C to stop)", false).option("--since <duration>", "only show records newer than duration (e.g. 10s, 5m, 2h, 1d)").option("--level <level>", "minimum level (trace|debug|info|warn|error|fatal)").option("--json", "emit raw NDJSON lines instead of pretty formatting", false).action(async (options) => {
|
|
1102
|
-
try {
|
|
1103
|
-
const level = validateLevel(options.level);
|
|
1104
|
-
const sinceMs = options.since ? parseDuration(options.since) : void 0;
|
|
1105
|
-
await showServiceLogs({
|
|
1106
|
-
tail: options.tail === true,
|
|
1107
|
-
level,
|
|
1108
|
-
sinceMs,
|
|
1109
|
-
json: options.json === true
|
|
1110
|
-
});
|
|
1111
|
-
} catch (error) {
|
|
1112
|
-
fail("SERVICE_LOGS_ERROR", error instanceof Error ? error.message : String(error));
|
|
1113
|
-
}
|
|
1114
|
-
});
|
|
1115
1076
|
client.command("hub-list").description("List clients on the Hub server").option("--server <url>", "Hub server URL").action(async (options) => {
|
|
1116
1077
|
try {
|
|
1117
1078
|
const serverUrl = resolveServerUrl(options.server);
|
|
@@ -1262,13 +1223,13 @@ function isSecretField(schema, dotPath) {
|
|
|
1262
1223
|
//#region src/commands/onboard.ts
|
|
1263
1224
|
async function promptMissing(args) {
|
|
1264
1225
|
if (!args.server) try {
|
|
1265
|
-
const { resolveServerUrl } = await import("../bootstrap-
|
|
1226
|
+
const { resolveServerUrl } = await import("../bootstrap-CtVqQA8a.mjs").then((n) => n.t);
|
|
1266
1227
|
resolveServerUrl();
|
|
1267
1228
|
} catch {
|
|
1268
1229
|
args.server = await input({ message: "Hub server URL:" });
|
|
1269
1230
|
saveOnboardState(args);
|
|
1270
1231
|
}
|
|
1271
|
-
const { loadCredentials } = await import("../bootstrap-
|
|
1232
|
+
const { loadCredentials } = await import("../bootstrap-CtVqQA8a.mjs").then((n) => n.t);
|
|
1272
1233
|
if (!loadCredentials()) throw new Error("No saved credentials. Run `first-tree-hub client connect <server-url>` before onboarding.");
|
|
1273
1234
|
if (!args.id) {
|
|
1274
1235
|
args.id = await input({ message: "Agent ID:" });
|