@agent-team-foundation/first-tree-hub 0.7.2 → 0.8.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/cli/index.mjs +2 -2
- package/dist/{core-6-paFwyo.mjs → core-BXS5ppsG.mjs} +171 -4
- package/dist/{feishu-CJ08ntOD.mjs → feishu-D9JkMZnU.mjs} +14 -1
- package/dist/index.mjs +2 -2
- package/dist/web/assets/{index-30C-bada.js → index-KhUJU9Uf.js} +22 -22
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { C as setConfigValue, S as serverConfigSchema, _ as loadAgents, b as resetConfigMeta, c as saveCredentials, f as agentConfigSchema, g as initConfig, h as getConfigValue, 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, v as readConfigFile, y as resetConfig } from "../bootstrap-CRDR6NwE.mjs";
|
|
3
|
-
import { A as stopPostgres, C as checkServerReachable, F as SdkError, I as SessionRegistry, L as cleanWorkspaces, M as createOwner, P as FirstTreeHubSDK, S as checkServerHealth, T as printResults, _ as checkClientConfig, a as uninstallClientService, b as checkNodeVersion, c as promptAddAgent, d as loadOnboardState, f as onboardCheck, g as checkAgentConfigs, h as runMigrations, j as ClientRuntime, l as promptMissingFields, m as saveOnboardState, n as installClientService, o as startServer, p as onboardCreate, r as isServiceSupported, s as isInteractive, t as getClientServiceStatus, u as formatCheckReport, v as checkDatabase, w as checkWebSocket, x as checkServerConfig, y as checkDocker } from "../core-
|
|
4
|
-
import { n as bindFeishuUser, t as bindFeishuBot } from "../feishu-
|
|
3
|
+
import { A as stopPostgres, C as checkServerReachable, F as SdkError, I as SessionRegistry, L as cleanWorkspaces, M as createOwner, P as FirstTreeHubSDK, S as checkServerHealth, T as printResults, _ as checkClientConfig, a as uninstallClientService, b as checkNodeVersion, c as promptAddAgent, d as loadOnboardState, f as onboardCheck, g as checkAgentConfigs, h as runMigrations, j as ClientRuntime, l as promptMissingFields, m as saveOnboardState, n as installClientService, o as startServer, p as onboardCreate, r as isServiceSupported, s as isInteractive, t as getClientServiceStatus, u as formatCheckReport, v as checkDatabase, w as checkWebSocket, x as checkServerConfig, y as checkDocker } from "../core-BXS5ppsG.mjs";
|
|
4
|
+
import { n as bindFeishuUser, t as bindFeishuBot } from "../feishu-D9JkMZnU.mjs";
|
|
5
5
|
import { createRequire } from "node:module";
|
|
6
6
|
import { Command } from "commander";
|
|
7
7
|
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync } from "node:fs";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { C as setConfigValue, S as serverConfigSchema, _ as loadAgents, d as DEFAULT_HOME_DIR$1, f as agentConfigSchema, g as initConfig, i as loadCredentials, l as DEFAULT_CONFIG_DIR, m as collectMissingPrompts, n as ensureFreshAccessToken, o as resolveServerUrl, p as clientConfigSchema, s as saveAgentConfig, u as DEFAULT_DATA_DIR$1, x as resolveConfigReadonly } from "./bootstrap-CRDR6NwE.mjs";
|
|
2
|
-
import { $ as
|
|
2
|
+
import { $ as updateAgentRuntimeConfigSchema, A as createMemberSchema, B as notificationQuerySchema, C as agentTypeSchema$1, D as createAdapterMappingSchema, E as createAdapterConfigSchema, F as inboxPollQuerySchema, G as sendMessageSchema, H as refreshTokenSchema, I as isRedactedEnvValue, J as sessionEventMessageSchema, K as sendToAgentSchema, L as linkTaskChatSchema, M as createTaskSchema, N as delegateFeishuUserSchema, O as createAgentSchema, P as dryRunAgentRuntimeConfigSchema, Q as updateAdapterConfigSchema, R as loginSchema, S as agentRuntimeConfigPayloadSchema$1, T as connectTokenExchangeSchema, U as runtimeStateMessageSchema, V as paginationQuerySchema, W as selfServiceFeishuBotSchema, X as sessionStateMessageSchema, Y as sessionEventSchema$1, Z as taskListQuerySchema, _ as addParticipantSchema, a as AGENT_SELECTOR_HEADER$1, at as wsAuthFrameSchema, b as agentBindRequestSchema, c as AGENT_TYPES, d as SYSTEM_CONFIG_DEFAULTS, et as updateAgentSchema, f as TASK_CREATOR_TYPES, g as WS_AUTH_FRAME_TIMEOUT_MS, h as TASK_TERMINAL_STATUSES, i as AGENT_BIND_REJECT_REASONS, it as updateTaskStatusSchema, j as createOrganizationSchema, k as createChatSchema, l as AGENT_VISIBILITY, m as TASK_STATUSES, nt as updateOrganizationSchema, o as AGENT_SOURCES, p as TASK_HEALTH_SIGNALS, q as sessionCompletionMessageSchema, rt as updateSystemConfigSchema, s as AGENT_STATUSES, tt as updateMemberSchema, u as DEFAULT_AGENT_RUNTIME_CONFIG_PAYLOAD, v as adminCreateTaskSchema, w as clientRegisterSchema, x as agentPinnedMessageSchema$1, y as adminUpdateTaskSchema, z as messageSourceSchema$1 } from "./feishu-D9JkMZnU.mjs";
|
|
3
3
|
import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, watch, writeFileSync } from "node:fs";
|
|
4
4
|
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
5
5
|
import { ZodError, z } from "zod";
|
|
6
|
-
import "yaml";
|
|
6
|
+
import { stringify } from "yaml";
|
|
7
7
|
import { createCipheriv, createDecipheriv, createHash, createHmac, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
|
|
8
8
|
import { homedir, hostname, platform, userInfo } from "node:os";
|
|
9
9
|
import { EventEmitter } from "node:events";
|
|
@@ -198,6 +198,19 @@ z.object({
|
|
|
198
198
|
branch: z.string().nullable()
|
|
199
199
|
});
|
|
200
200
|
/**
|
|
201
|
+
* Server → client WebSocket frame announcing that an agent has just been
|
|
202
|
+
* pinned to the connected client (either created with `clientId` or bound via
|
|
203
|
+
* PATCH NULL → ID). The client can auto-register a local config from this so
|
|
204
|
+
* the operator doesn't have to run `first-tree-hub agent add` manually.
|
|
205
|
+
*/
|
|
206
|
+
const agentPinnedMessageSchema = z.object({
|
|
207
|
+
type: z.literal("agent:pinned"),
|
|
208
|
+
agentId: z.string(),
|
|
209
|
+
name: z.string().nullable(),
|
|
210
|
+
displayName: z.string().nullable(),
|
|
211
|
+
agentType: agentTypeSchema
|
|
212
|
+
});
|
|
213
|
+
/**
|
|
201
214
|
* Agent runtime configuration — M1 (Claude Code only).
|
|
202
215
|
*
|
|
203
216
|
* Defines the 5 user-tunable field groups that the Hub centrally manages
|
|
@@ -1165,6 +1178,11 @@ var ClientConnection = class extends EventEmitter {
|
|
|
1165
1178
|
this.emit("agent:unbound", agentId);
|
|
1166
1179
|
return;
|
|
1167
1180
|
}
|
|
1181
|
+
if (type === "agent:pinned") {
|
|
1182
|
+
const parsed = agentPinnedMessageSchema.safeParse(msg);
|
|
1183
|
+
if (parsed.success) this.emit("agent:pinned", parsed.data);
|
|
1184
|
+
return;
|
|
1185
|
+
}
|
|
1168
1186
|
if (type === "agent:force_disconnect") {
|
|
1169
1187
|
const agentId = msg.agentId;
|
|
1170
1188
|
if (agentId && this.boundAgents.has(agentId)) {
|
|
@@ -3445,8 +3463,15 @@ var ClientRuntime = class {
|
|
|
3445
3463
|
connection;
|
|
3446
3464
|
agents = [];
|
|
3447
3465
|
agentNames = /* @__PURE__ */ new Set();
|
|
3466
|
+
agentIds = /* @__PURE__ */ new Set();
|
|
3448
3467
|
watcher = null;
|
|
3449
3468
|
debounceTimer = null;
|
|
3469
|
+
/**
|
|
3470
|
+
* Directory we write auto-registered agent configs into (same path that
|
|
3471
|
+
* `first-tree-hub agent add` uses). Set by `watchAgentsDir` so the
|
|
3472
|
+
* `agent:pinned` handler knows where to materialise new configs.
|
|
3473
|
+
*/
|
|
3474
|
+
agentsDir = null;
|
|
3450
3475
|
constructor(serverUrl, clientId) {
|
|
3451
3476
|
this.serverUrl = serverUrl;
|
|
3452
3477
|
this.connection = new ClientConnection({
|
|
@@ -3458,6 +3483,9 @@ var ClientRuntime = class {
|
|
|
3458
3483
|
this.connection.on("auth:expired", () => {
|
|
3459
3484
|
process.stderr.write(" ⚠️ Access token expired — reconnecting after refresh...\n");
|
|
3460
3485
|
});
|
|
3486
|
+
this.connection.on("agent:pinned", (message) => {
|
|
3487
|
+
this.handleAgentPinned(message);
|
|
3488
|
+
});
|
|
3461
3489
|
}
|
|
3462
3490
|
addAgent(name, config) {
|
|
3463
3491
|
if (this.agentNames.has(name)) return;
|
|
@@ -3480,6 +3508,7 @@ var ClientRuntime = class {
|
|
|
3480
3508
|
slot
|
|
3481
3509
|
});
|
|
3482
3510
|
this.agentNames.add(name);
|
|
3511
|
+
this.agentIds.add(config.agentId);
|
|
3483
3512
|
}
|
|
3484
3513
|
async start() {
|
|
3485
3514
|
await this.connection.connect();
|
|
@@ -3502,6 +3531,7 @@ var ClientRuntime = class {
|
|
|
3502
3531
|
process.stderr.write(`\n ${connected} agent(s) running. Press Ctrl+C to stop.\n`);
|
|
3503
3532
|
}
|
|
3504
3533
|
watchAgentsDir(agentsDir) {
|
|
3534
|
+
this.agentsDir = agentsDir;
|
|
3505
3535
|
if (this.watcher) return;
|
|
3506
3536
|
if (!existsSync(agentsDir)) return;
|
|
3507
3537
|
this.watcher = watch(agentsDir, { recursive: true }, () => {
|
|
@@ -3535,12 +3565,68 @@ var ClientRuntime = class {
|
|
|
3535
3565
|
});
|
|
3536
3566
|
for (const [name, config] of all) {
|
|
3537
3567
|
if (this.agentNames.has(name)) continue;
|
|
3568
|
+
if (this.agentIds.has(config.agentId)) continue;
|
|
3538
3569
|
process.stderr.write(`\n New agent detected: ${name}\n`);
|
|
3539
3570
|
this.addAgent(name, config);
|
|
3540
3571
|
this.startAgent(name);
|
|
3541
3572
|
}
|
|
3542
3573
|
} catch {}
|
|
3543
3574
|
}
|
|
3575
|
+
/**
|
|
3576
|
+
* React to an `agent:pinned` server push by writing the local config file
|
|
3577
|
+
* (same shape `first-tree-hub agent add` produces) and scheduling the new
|
|
3578
|
+
* slot — so the operator doesn't have to run `agent add` manually after
|
|
3579
|
+
* creating an agent from the admin UI or API.
|
|
3580
|
+
*/
|
|
3581
|
+
handleAgentPinned(message) {
|
|
3582
|
+
if (this.agentIds.has(message.agentId)) return;
|
|
3583
|
+
if (!this.agentsDir) {
|
|
3584
|
+
process.stderr.write(` \u26A0\uFE0F Agent pinned (${message.agentId}) but no agents dir set — cannot auto-register.\n`);
|
|
3585
|
+
return;
|
|
3586
|
+
}
|
|
3587
|
+
const localName = this.pickLocalName(message);
|
|
3588
|
+
const agentDir = join(this.agentsDir, localName);
|
|
3589
|
+
try {
|
|
3590
|
+
mkdirSync(agentDir, {
|
|
3591
|
+
recursive: true,
|
|
3592
|
+
mode: 448
|
|
3593
|
+
});
|
|
3594
|
+
const yaml = stringify({
|
|
3595
|
+
agentId: message.agentId,
|
|
3596
|
+
runtime: "claude-code"
|
|
3597
|
+
});
|
|
3598
|
+
writeFileSync(join(agentDir, "agent.yaml"), yaml, { mode: 384 });
|
|
3599
|
+
process.stderr.write(` \u2713 Auto-added agent "${localName}" (${message.agentId}) from server push.\n`);
|
|
3600
|
+
} catch (err) {
|
|
3601
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
3602
|
+
process.stderr.write(` \u2717 Failed to auto-add agent "${localName}": ${msg}\n`);
|
|
3603
|
+
return;
|
|
3604
|
+
}
|
|
3605
|
+
this.scanForNewAgents(this.agentsDir);
|
|
3606
|
+
}
|
|
3607
|
+
/**
|
|
3608
|
+
* Choose the directory name under `agents/<name>/agent.yaml` for an agent
|
|
3609
|
+
* pushed by the server. Prefer the server-side `name` when set and not
|
|
3610
|
+
* already claimed; otherwise fall back to a UUID-derived name with a numeric
|
|
3611
|
+
* suffix on collision.
|
|
3612
|
+
*
|
|
3613
|
+
* UUID v7 packs the unix-ms timestamp in the high bits, so two agents
|
|
3614
|
+
* created in the same millisecond share the first 8 hex chars. Take 16 chars
|
|
3615
|
+
* (the full ms-timestamp segment plus the random tail) to make accidental
|
|
3616
|
+
* collisions astronomically unlikely, and re-check `agentNames` so even an
|
|
3617
|
+
* adversarial collision falls through to a `-2`, `-3`, … suffix.
|
|
3618
|
+
*/
|
|
3619
|
+
pickLocalName(message) {
|
|
3620
|
+
const preferred = message.name;
|
|
3621
|
+
if (preferred && !this.agentNames.has(preferred)) return preferred;
|
|
3622
|
+
const base = `agent-${message.agentId.replace(/[^a-z0-9]/gi, "").slice(0, 16).toLowerCase()}`;
|
|
3623
|
+
if (!this.agentNames.has(base)) return base;
|
|
3624
|
+
for (let suffix = 2; suffix < 1e3; suffix++) {
|
|
3625
|
+
const candidate = `${base}-${suffix}`;
|
|
3626
|
+
if (!this.agentNames.has(candidate)) return candidate;
|
|
3627
|
+
}
|
|
3628
|
+
return `agent-${message.agentId.replace(/[^a-z0-9]/gi, "").toLowerCase()}`;
|
|
3629
|
+
}
|
|
3544
3630
|
startAgent(name) {
|
|
3545
3631
|
const entry = this.agents.find((a) => a.name === name);
|
|
3546
3632
|
if (!entry) return;
|
|
@@ -4206,7 +4292,7 @@ async function onboardCreate(args) {
|
|
|
4206
4292
|
}
|
|
4207
4293
|
const runtimeAgent = args.type === "human" ? args.assistant : args.id;
|
|
4208
4294
|
if (args.feishuBotAppId && args.feishuBotAppSecret) {
|
|
4209
|
-
const { bindFeishuBot } = await import("./feishu-
|
|
4295
|
+
const { bindFeishuBot } = await import("./feishu-D9JkMZnU.mjs").then((n) => n.r);
|
|
4210
4296
|
const targetAgentUuid = args.type === "human" ? assistantUuid : primary.uuid;
|
|
4211
4297
|
if (!targetAgentUuid) process.stderr.write(`Warning: Cannot bind Feishu bot — no runtime agent available for "${args.id}".\n`);
|
|
4212
4298
|
else {
|
|
@@ -4347,7 +4433,7 @@ function setNestedByDot(obj, dotPath, value) {
|
|
|
4347
4433
|
if (lastKey !== void 0) current[lastKey] = value;
|
|
4348
4434
|
}
|
|
4349
4435
|
//#endregion
|
|
4350
|
-
//#region ../server/dist/app-
|
|
4436
|
+
//#region ../server/dist/app-TMhTLXuz.mjs
|
|
4351
4437
|
var __defProp = Object.defineProperty;
|
|
4352
4438
|
var __exportAll = (all, no_symbols) => {
|
|
4353
4439
|
let target = {};
|
|
@@ -5947,6 +6033,23 @@ async function getClient(db, clientId) {
|
|
|
5947
6033
|
const [row] = await db.select().from(clients).where(eq(clients.id, clientId)).limit(1);
|
|
5948
6034
|
return row ?? null;
|
|
5949
6035
|
}
|
|
6036
|
+
/**
|
|
6037
|
+
* List the active agents currently pinned to a client. Used by the WS
|
|
6038
|
+
* registration handshake to backfill `agent:pinned` notifications missed while
|
|
6039
|
+
* the client was offline — without it, an admin who pinned an agent during a
|
|
6040
|
+
* client outage would still need a manual `first-tree-hub agent add`.
|
|
6041
|
+
*
|
|
6042
|
+
* Excludes soft-deleted agents (status = "deleted"). Human agents are
|
|
6043
|
+
* naturally excluded by the `clientId` filter — they never carry a clientId.
|
|
6044
|
+
*/
|
|
6045
|
+
async function listActiveAgentsPinnedToClient(db, clientId) {
|
|
6046
|
+
return db.select({
|
|
6047
|
+
uuid: agents.uuid,
|
|
6048
|
+
name: agents.name,
|
|
6049
|
+
displayName: agents.displayName,
|
|
6050
|
+
type: agents.type
|
|
6051
|
+
}).from(agents).where(and(eq(agents.clientId, clientId), ne(agents.status, "deleted")));
|
|
6052
|
+
}
|
|
5950
6053
|
async function listClients(db, userId) {
|
|
5951
6054
|
const rows = await db.select().from(clients).where(eq(clients.userId, userId));
|
|
5952
6055
|
const counts = await db.select({
|
|
@@ -6084,6 +6187,13 @@ function removeClientConnection(clientId, ws) {
|
|
|
6084
6187
|
clientConnections.delete(clientId);
|
|
6085
6188
|
return agentIds;
|
|
6086
6189
|
}
|
|
6190
|
+
/** Send a message to a client's WebSocket. Returns true if delivered. */
|
|
6191
|
+
function sendToClient(clientId, message) {
|
|
6192
|
+
const entry = clientConnections.get(clientId);
|
|
6193
|
+
if (!entry || entry.ws.readyState !== 1) return false;
|
|
6194
|
+
entry.ws.send(JSON.stringify(message));
|
|
6195
|
+
return true;
|
|
6196
|
+
}
|
|
6087
6197
|
/** Send a message to a specific agent via its client's WebSocket. Returns true if delivered. */
|
|
6088
6198
|
function sendToAgent$1(agentId, message) {
|
|
6089
6199
|
const clientId = agentToClient.get(agentId);
|
|
@@ -6350,6 +6460,34 @@ function notifyRecipients(notifier, recipients, messageId) {
|
|
|
6350
6460
|
for (const inboxId of recipients) notifier.notify(inboxId, messageId).catch(() => {});
|
|
6351
6461
|
}
|
|
6352
6462
|
async function adminAgentRoutes(app) {
|
|
6463
|
+
/**
|
|
6464
|
+
* Push an `agent:pinned` frame to the connected client so it can auto-register
|
|
6465
|
+
* the agent locally without the operator running `first-tree-hub agent add`.
|
|
6466
|
+
*
|
|
6467
|
+
* Best-effort: if the client is not currently connected to this server
|
|
6468
|
+
* instance, the notification is silently dropped here — the client picks the
|
|
6469
|
+
* pinning up on its next `client:register` handshake via the backfill path
|
|
6470
|
+
* in `api/agent/ws-client.ts`.
|
|
6471
|
+
*/
|
|
6472
|
+
function notifyClientAgentPinned(agent) {
|
|
6473
|
+
if (!agent.clientId) return;
|
|
6474
|
+
const parsed = agentPinnedMessageSchema$1.safeParse({
|
|
6475
|
+
type: "agent:pinned",
|
|
6476
|
+
agentId: agent.uuid,
|
|
6477
|
+
name: agent.name,
|
|
6478
|
+
displayName: agent.displayName,
|
|
6479
|
+
agentType: agent.type
|
|
6480
|
+
});
|
|
6481
|
+
if (!parsed.success) {
|
|
6482
|
+
app.log.warn({
|
|
6483
|
+
err: parsed.error.flatten(),
|
|
6484
|
+
agentId: agent.uuid,
|
|
6485
|
+
clientId: agent.clientId
|
|
6486
|
+
}, "agent:pinned frame failed schema validation — not sending");
|
|
6487
|
+
return;
|
|
6488
|
+
}
|
|
6489
|
+
sendToClient(agent.clientId, parsed.data);
|
|
6490
|
+
}
|
|
6353
6491
|
const listAgentsFilterSchema = z.object({ type: agentTypeSchema$1.optional() });
|
|
6354
6492
|
app.get("/", async (request) => {
|
|
6355
6493
|
const query = paginationQuerySchema.parse(request.query);
|
|
@@ -6380,6 +6518,7 @@ async function adminAgentRoutes(app) {
|
|
|
6380
6518
|
source: body.source ?? "admin-api",
|
|
6381
6519
|
managerId
|
|
6382
6520
|
});
|
|
6521
|
+
notifyClientAgentPinned(agent);
|
|
6383
6522
|
return reply.status(201).send({
|
|
6384
6523
|
...agent,
|
|
6385
6524
|
createdAt: agent.createdAt.toISOString(),
|
|
@@ -6392,7 +6531,9 @@ async function adminAgentRoutes(app) {
|
|
|
6392
6531
|
const body = updateAgentSchema.parse(request.body);
|
|
6393
6532
|
const member = requireMember(request);
|
|
6394
6533
|
if (body.managerId !== void 0 && member.role !== "admin") throw new ForbiddenError("Only admins can reassign an agent's manager");
|
|
6534
|
+
const before = body.clientId !== void 0 ? await getAgent(app.db, request.params.uuid) : null;
|
|
6395
6535
|
const agent = await updateAgent(app.db, request.params.uuid, body);
|
|
6536
|
+
if (before && before.clientId === null && agent.clientId !== null) notifyClientAgentPinned(agent);
|
|
6396
6537
|
return {
|
|
6397
6538
|
...agent,
|
|
6398
6539
|
createdAt: agent.createdAt.toISOString(),
|
|
@@ -8785,6 +8926,32 @@ function clientWsRoutes(notifier, instanceId) {
|
|
|
8785
8926
|
type: "client:registered",
|
|
8786
8927
|
clientId: data.clientId
|
|
8787
8928
|
}));
|
|
8929
|
+
try {
|
|
8930
|
+
const pinned = await listActiveAgentsPinnedToClient(app.db, data.clientId);
|
|
8931
|
+
for (const agent of pinned) {
|
|
8932
|
+
const parsed = agentPinnedMessageSchema$1.safeParse({
|
|
8933
|
+
type: "agent:pinned",
|
|
8934
|
+
agentId: agent.uuid,
|
|
8935
|
+
name: agent.name,
|
|
8936
|
+
displayName: agent.displayName,
|
|
8937
|
+
agentType: agent.type
|
|
8938
|
+
});
|
|
8939
|
+
if (!parsed.success) {
|
|
8940
|
+
app.log.warn({
|
|
8941
|
+
err: parsed.error.flatten(),
|
|
8942
|
+
agentId: agent.uuid,
|
|
8943
|
+
clientId: data.clientId
|
|
8944
|
+
}, "agent:pinned backfill frame failed schema validation — skipping");
|
|
8945
|
+
continue;
|
|
8946
|
+
}
|
|
8947
|
+
socket.send(JSON.stringify(parsed.data));
|
|
8948
|
+
}
|
|
8949
|
+
} catch (err) {
|
|
8950
|
+
app.log.error({
|
|
8951
|
+
err,
|
|
8952
|
+
clientId: data.clientId
|
|
8953
|
+
}, "agent:pinned backfill on client:register failed — client may need manual `agent add`");
|
|
8954
|
+
}
|
|
8788
8955
|
} else if (type === "agent:bind") {
|
|
8789
8956
|
if (!clientId) {
|
|
8790
8957
|
socket.send(JSON.stringify({
|
|
@@ -199,6 +199,19 @@ z.object({
|
|
|
199
199
|
branch: z.string().nullable()
|
|
200
200
|
});
|
|
201
201
|
/**
|
|
202
|
+
* Server → client WebSocket frame announcing that an agent has just been
|
|
203
|
+
* pinned to the connected client (either created with `clientId` or bound via
|
|
204
|
+
* PATCH NULL → ID). The client can auto-register a local config from this so
|
|
205
|
+
* the operator doesn't have to run `first-tree-hub agent add` manually.
|
|
206
|
+
*/
|
|
207
|
+
const agentPinnedMessageSchema = z.object({
|
|
208
|
+
type: z.literal("agent:pinned"),
|
|
209
|
+
agentId: z.string(),
|
|
210
|
+
name: z.string().nullable(),
|
|
211
|
+
displayName: z.string().nullable(),
|
|
212
|
+
agentType: agentTypeSchema
|
|
213
|
+
});
|
|
214
|
+
/**
|
|
202
215
|
* Agent runtime configuration — M1 (Claude Code only).
|
|
203
216
|
*
|
|
204
217
|
* Defines the 5 user-tunable field groups that the Hub centrally manages
|
|
@@ -877,4 +890,4 @@ async function bindFeishuUser(serverUrl, accessToken, agentId, humanAgentId, fei
|
|
|
877
890
|
}
|
|
878
891
|
}
|
|
879
892
|
//#endregion
|
|
880
|
-
export {
|
|
893
|
+
export { updateAgentRuntimeConfigSchema as $, createMemberSchema as A, notificationQuerySchema as B, agentTypeSchema as C, createAdapterMappingSchema as D, createAdapterConfigSchema as E, inboxPollQuerySchema as F, sendMessageSchema as G, refreshTokenSchema as H, isRedactedEnvValue as I, sessionEventMessageSchema as J, sendToAgentSchema as K, linkTaskChatSchema as L, createTaskSchema as M, delegateFeishuUserSchema as N, createAgentSchema as O, dryRunAgentRuntimeConfigSchema as P, updateAdapterConfigSchema as Q, loginSchema as R, agentRuntimeConfigPayloadSchema as S, connectTokenExchangeSchema as T, runtimeStateMessageSchema as U, paginationQuerySchema as V, selfServiceFeishuBotSchema as W, sessionStateMessageSchema as X, sessionEventSchema as Y, taskListQuerySchema as Z, addParticipantSchema as _, AGENT_SELECTOR_HEADER as a, wsAuthFrameSchema as at, agentBindRequestSchema as b, AGENT_TYPES as c, SYSTEM_CONFIG_DEFAULTS as d, updateAgentSchema as et, TASK_CREATOR_TYPES as f, WS_AUTH_FRAME_TIMEOUT_MS as g, TASK_TERMINAL_STATUSES as h, AGENT_BIND_REJECT_REASONS as i, updateTaskStatusSchema as it, createOrganizationSchema as j, createChatSchema as k, AGENT_VISIBILITY as l, TASK_STATUSES as m, bindFeishuUser as n, updateOrganizationSchema as nt, AGENT_SOURCES as o, TASK_HEALTH_SIGNALS as p, sessionCompletionMessageSchema as q, feishu_exports as r, updateSystemConfigSchema as rt, AGENT_STATUSES as s, bindFeishuBot as t, updateMemberSchema as tt, DEFAULT_AGENT_RUNTIME_CONFIG_PAYLOAD as u, adminCreateTaskSchema as v, clientRegisterSchema as w, agentPinnedMessageSchema as x, adminUpdateTaskSchema as y, messageSourceSchema as z };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { a as resolveAccessToken, n as ensureFreshAccessToken, o as resolveServerUrl, r as ensureFreshAdminToken } from "./bootstrap-CRDR6NwE.mjs";
|
|
2
|
-
import { A as stopPostgres, C as checkServerReachable, D as status, E as blank, F as SdkError, M as createOwner, N as hasUser, O as ensurePostgres, P as FirstTreeHubSDK, S as checkServerHealth, T as printResults, _ as checkClientConfig, a as uninstallClientService, b as checkNodeVersion, c as promptAddAgent, f as onboardCheck, g as checkAgentConfigs, h as runMigrations, i as resolveCliInvocation, j as ClientRuntime, k as isDockerAvailable, l as promptMissingFields, n as installClientService, o as startServer, p as onboardCreate, r as isServiceSupported, s as isInteractive, t as getClientServiceStatus, u as formatCheckReport, v as checkDatabase, w as checkWebSocket, x as checkServerConfig, y as checkDocker } from "./core-
|
|
3
|
-
import { n as bindFeishuUser, t as bindFeishuBot } from "./feishu-
|
|
2
|
+
import { A as stopPostgres, C as checkServerReachable, D as status, E as blank, F as SdkError, M as createOwner, N as hasUser, O as ensurePostgres, P as FirstTreeHubSDK, S as checkServerHealth, T as printResults, _ as checkClientConfig, a as uninstallClientService, b as checkNodeVersion, c as promptAddAgent, f as onboardCheck, g as checkAgentConfigs, h as runMigrations, i as resolveCliInvocation, j as ClientRuntime, k as isDockerAvailable, l as promptMissingFields, n as installClientService, o as startServer, p as onboardCreate, r as isServiceSupported, s as isInteractive, t as getClientServiceStatus, u as formatCheckReport, v as checkDatabase, w as checkWebSocket, x as checkServerConfig, y as checkDocker } from "./core-BXS5ppsG.mjs";
|
|
3
|
+
import { n as bindFeishuUser, t as bindFeishuBot } from "./feishu-D9JkMZnU.mjs";
|
|
4
4
|
export { ClientRuntime, FirstTreeHubSDK, SdkError, bindFeishuBot, bindFeishuUser, blank, checkAgentConfigs, checkClientConfig, checkDatabase, checkDocker, checkNodeVersion, checkServerConfig, checkServerHealth, checkServerReachable, checkWebSocket, createOwner, ensureFreshAccessToken, ensureFreshAdminToken, ensurePostgres, formatCheckReport, getClientServiceStatus, hasUser, installClientService, isDockerAvailable, isInteractive, isServiceSupported, onboardCheck, onboardCreate, printResults, promptAddAgent, promptMissingFields, resolveAccessToken, resolveCliInvocation, resolveServerUrl, runMigrations, startServer, status, stopPostgres, uninstallClientService };
|