@agent-team-foundation/first-tree-hub 0.14.2 → 0.14.4
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-C15ZBOCC.mjs → bootstrap-CQQGgIx1.mjs} +0 -7
- package/dist/cli/index.mjs +8 -25
- package/dist/{client-CZ_VnbEc-CBF46cJd.mjs → client-BPRIfrOT-CoV_2o7e.mjs} +61 -44
- package/dist/{client-CDw0f-kN-BPzOVd8L.mjs → client-CEdYVnoj-BGiGcJbH.mjs} +2 -2
- package/dist/{dist-DmYxT5Kb.mjs → dist-CrdnqZjv.mjs} +20 -14
- package/dist/{feishu-CCWd-JE4.mjs → feishu-DNoBroKK.mjs} +1 -1
- package/dist/index.mjs +5 -5
- package/dist/{invitation-C9m2gQx4-CkwWteA3.mjs → invitation-C9m2gQx4-C_4f5VTs.mjs} +1 -1
- package/dist/{saas-connect-DgCSZ8Yk.mjs → saas-connect-Da55XxRX.mjs} +265 -231
- package/dist/web/assets/index-9wK0udbH.js +416 -0
- package/dist/web/assets/{index-B76SVAz8.js → index-C7x7O7dG.js} +1 -1
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
- package/dist/web/assets/index-DAAemCLz.js +0 -416
|
@@ -570,13 +570,6 @@ const serverConfigSchema = defineConfig({
|
|
|
570
570
|
refreshTokenExpiry: field(z.string().default("30d"), { env: "FIRST_TREE_HUB_AUTH_REFRESH_TOKEN_EXPIRY" }),
|
|
571
571
|
connectTokenExpiry: field(z.string().default("10m"), { env: "FIRST_TREE_HUB_AUTH_CONNECT_TOKEN_EXPIRY" })
|
|
572
572
|
},
|
|
573
|
-
contextTreeSync: optional({
|
|
574
|
-
githubToken: field(z.string(), {
|
|
575
|
-
env: "FIRST_TREE_HUB_CONTEXT_TREE_GITHUB_TOKEN",
|
|
576
|
-
secret: true
|
|
577
|
-
}),
|
|
578
|
-
githubTokenRepos: field(z.string().optional(), { env: "FIRST_TREE_HUB_CONTEXT_TREE_GITHUB_TOKEN_REPOS" })
|
|
579
|
-
}),
|
|
580
573
|
oauth: optional({ githubApp: optional({
|
|
581
574
|
appId: field(z.string().min(1), { env: "FIRST_TREE_HUB_GITHUB_APP_ID" }),
|
|
582
575
|
clientId: field(z.string().min(1), { env: "FIRST_TREE_HUB_GITHUB_APP_CLIENT_ID" }),
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import "../observability-BAScT_5S-BcW9HgkG.mjs";
|
|
3
|
-
import { $ as formatStaleReason, A as checkDocker, B as isServiceSupported, C as createApiNameResolver, D as checkBackgroundService, E as checkAgentConfigs, F as checkWebSocket, H as restartClientService, I as printResults, J as stopPostgres, L as reconcileAgentConfigs, M as checkServerConfig, N as checkServerHealth, O as checkClientConfig, P as checkServerReachable, Q as findStaleAliases, R as getClientServiceStatus, S as runHomeMigration, T as runMigrations, U as startClientService, W as stopClientService, X as handleClientOrgMismatch, Y as ClientRuntime, _ as formatCheckReport, a as declineUpdate, at as fail, b as onboardCreate, c as detectInstallMode, ct as ClientUserMismatchError, d as startServer, dt as SessionRegistry, et as removeLocalAgent, f as reconcileLocalRuntimeProviders, ft as cleanWorkspaces, g as promptMissingFields, h as promptAddAgent, ht as configureClientLoggerForService, i as createExecuteUpdate, it as resolveSenderName, j as checkNodeVersion, k as checkDatabase, l as fetchLatestVersion, lt as FirstTreeHubSDK, m as isInteractive, mt as applyClientLoggerConfig, o as promptUpdate, ot as success, p as uploadClientCapabilities, pt as probeCapabilities, r as registerSaaSConnectCommand, rt as resolveReplyToFromEnv, s as PACKAGE_NAME, st as ClientOrgMismatchError, tt as createOwner, u as installGlobalLatest, ut as SdkError, v as loadOnboardState, w as migrateLocalAgentDirs, x as saveOnboardState, y as onboardCheck, z as installClientService } from "../saas-connect-
|
|
3
|
+
import { $ as formatStaleReason, A as checkDocker, B as isServiceSupported, C as createApiNameResolver, D as checkBackgroundService, E as checkAgentConfigs, F as checkWebSocket, H as restartClientService, I as printResults, J as stopPostgres, L as reconcileAgentConfigs, M as checkServerConfig, N as checkServerHealth, O as checkClientConfig, P as checkServerReachable, Q as findStaleAliases, R as getClientServiceStatus, S as runHomeMigration, T as runMigrations, U as startClientService, W as stopClientService, X as handleClientOrgMismatch, Y as ClientRuntime, _ as formatCheckReport, a as declineUpdate, at as fail, b as onboardCreate, c as detectInstallMode, ct as ClientUserMismatchError, d as startServer, dt as SessionRegistry, et as removeLocalAgent, f as reconcileLocalRuntimeProviders, ft as cleanWorkspaces, g as promptMissingFields, h as promptAddAgent, ht as configureClientLoggerForService, i as createExecuteUpdate, it as resolveSenderName, j as checkNodeVersion, k as checkDatabase, l as fetchLatestVersion, lt as FirstTreeHubSDK, m as isInteractive, mt as applyClientLoggerConfig, o as promptUpdate, ot as success, p as uploadClientCapabilities, pt as probeCapabilities, r as registerSaaSConnectCommand, rt as resolveReplyToFromEnv, s as PACKAGE_NAME, st as ClientOrgMismatchError, tt as createOwner, u as installGlobalLatest, ut as SdkError, v as loadOnboardState, w as migrateLocalAgentDirs, x as saveOnboardState, y as onboardCheck, z as installClientService } from "../saas-connect-Da55XxRX.mjs";
|
|
4
4
|
import "../logger-core-BTmvdflj-DjW8FM4T.mjs";
|
|
5
|
-
import { C as resetConfigMeta, E as setConfigValue, S as resetConfig, T as serverConfigSchema, _ as getConfigValue, a as ensureFreshAdminToken, c as resolveServerUrl, d as DEFAULT_CONFIG_DIR, f as DEFAULT_DATA_DIR, h as clientConfigSchema, i as ensureFreshAccessToken, l as saveAgentConfig, m as agentConfigSchema, o as loadCredentials, p as DEFAULT_HOME_DIR, v as initConfig, w as resolveConfigReadonly, x as readConfigFile, y as loadAgents } from "../bootstrap-
|
|
5
|
+
import { C as resetConfigMeta, E as setConfigValue, S as resetConfig, T as serverConfigSchema, _ as getConfigValue, a as ensureFreshAdminToken, c as resolveServerUrl, d as DEFAULT_CONFIG_DIR, f as DEFAULT_DATA_DIR, h as clientConfigSchema, i as ensureFreshAccessToken, l as saveAgentConfig, m as agentConfigSchema, o as loadCredentials, p as DEFAULT_HOME_DIR, v as initConfig, w as resolveConfigReadonly, x as readConfigFile, y as loadAgents } from "../bootstrap-CQQGgIx1.mjs";
|
|
6
6
|
import { a as print, n as CLI_USER_AGENT, o as setJsonMode, r as COMMAND_VERSION, t as cliFetch } from "../cli-fetch--tiwKm5S.mjs";
|
|
7
|
-
import "../dist-
|
|
8
|
-
import { n as bindFeishuUser, t as bindFeishuBot } from "../feishu-
|
|
7
|
+
import "../dist-CrdnqZjv.mjs";
|
|
8
|
+
import { n as bindFeishuUser, t as bindFeishuBot } from "../feishu-DNoBroKK.mjs";
|
|
9
9
|
import "../uuid-DbS_4vFh-iFghv4zA.mjs";
|
|
10
10
|
import "../src-DNBS5Yjj.mjs";
|
|
11
|
-
import "../client-
|
|
11
|
+
import "../client-BPRIfrOT-CoV_2o7e.mjs";
|
|
12
12
|
import "../invitation-D_ENPHyj-5ETiae5r.mjs";
|
|
13
13
|
import { join } from "node:path";
|
|
14
14
|
import { existsSync, mkdirSync, readFileSync, readdirSync } from "node:fs";
|
|
@@ -255,11 +255,6 @@ function handleSdkError$1(error) {
|
|
|
255
255
|
if (error instanceof TypeError && "cause" in error) fail("CONNECTION_ERROR", `Cannot connect to server: ${error.message}`, 6);
|
|
256
256
|
fail("UNKNOWN_ERROR", error instanceof Error ? error.message : String(error), 1);
|
|
257
257
|
}
|
|
258
|
-
function parseLimit$1(value, max) {
|
|
259
|
-
const limit = Number.parseInt(value, 10);
|
|
260
|
-
if (Number.isNaN(limit) || limit < 1 || limit > max) fail("INVALID_LIMIT", `Limit must be between 1 and ${max}.`, 2);
|
|
261
|
-
return limit;
|
|
262
|
-
}
|
|
263
258
|
async function resolveAgent$1(serverUrl, adminToken, agentName) {
|
|
264
259
|
const res = await cliFetch(`${serverUrl}/api/v1/me/managed-agents`, {
|
|
265
260
|
headers: { Authorization: `Bearer ${adminToken}` },
|
|
@@ -693,25 +688,13 @@ function registerAgentCommands(program) {
|
|
|
693
688
|
fail("SESSION_CMD_ERROR", error instanceof Error ? error.message : String(error));
|
|
694
689
|
}
|
|
695
690
|
});
|
|
696
|
-
|
|
697
|
-
debugCmd.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) => {
|
|
691
|
+
agent.command("debug", { hidden: true }).description("Low-level SDK debug commands").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) => {
|
|
698
692
|
try {
|
|
699
693
|
success(await createSdk$1(options.agent).register());
|
|
700
694
|
} catch (error) {
|
|
701
695
|
handleSdkError$1(error);
|
|
702
696
|
}
|
|
703
697
|
});
|
|
704
|
-
debugCmd.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) => {
|
|
705
|
-
try {
|
|
706
|
-
const sdk = createSdk$1(options.agent);
|
|
707
|
-
const limit = parseLimit$1(options.limit, 50);
|
|
708
|
-
const result = await sdk.pull(limit);
|
|
709
|
-
if (options.ack && result.entries.length > 0) await Promise.all(result.entries.map((entry) => sdk.ack(entry.id)));
|
|
710
|
-
success(result);
|
|
711
|
-
} catch (error) {
|
|
712
|
-
handleSdkError$1(error);
|
|
713
|
-
}
|
|
714
|
-
});
|
|
715
698
|
}
|
|
716
699
|
//#endregion
|
|
717
700
|
//#region src/commands/chat.ts
|
|
@@ -1487,13 +1470,13 @@ function decodeJwtExpSeconds(token) {
|
|
|
1487
1470
|
//#region src/commands/onboard.ts
|
|
1488
1471
|
async function promptMissing(args) {
|
|
1489
1472
|
if (!args.server) try {
|
|
1490
|
-
const { resolveServerUrl } = await import("../bootstrap-
|
|
1473
|
+
const { resolveServerUrl } = await import("../bootstrap-CQQGgIx1.mjs").then((n) => n.r);
|
|
1491
1474
|
resolveServerUrl();
|
|
1492
1475
|
} catch {
|
|
1493
1476
|
args.server = await input({ message: "Hub server URL:" });
|
|
1494
1477
|
saveOnboardState(args);
|
|
1495
1478
|
}
|
|
1496
|
-
const { loadCredentials } = await import("../bootstrap-
|
|
1479
|
+
const { loadCredentials } = await import("../bootstrap-CQQGgIx1.mjs").then((n) => n.r);
|
|
1497
1480
|
if (!loadCredentials()) throw new Error("No saved credentials. Run `first-tree-hub connect <token>` before onboarding.");
|
|
1498
1481
|
if (!args.id) {
|
|
1499
1482
|
args.id = await input({ message: "Agent ID:" });
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { A as FIRST_TREE_HUB_ATTR, O as withSpan, f as messageAttrs, s as createLogger } from "./observability-BAScT_5S-BcW9HgkG.mjs";
|
|
2
|
-
import { L as extractMentions, N as defaultParticipantMode, P as defaultRuntimeConfigPayload, S as clientCapabilitiesSchema, St as stripCode, Z as isReservedAgentName, a as AGENT_TYPES, b as agentTypeSchema, ct as questionAnswerMessageContentSchema, d as MENTION_REGEX, i as AGENT_STATUSES, l as GITHUB_ENTITY_TYPES, lt as questionMessageContentSchema, mt as scanMentionTokens, n as AGENT_NAME_REGEX, nt as messageSourceSchema, o as AGENT_VISIBILITY, s as CHAT_ENGAGEMENT_STATUSES } from "./dist-
|
|
2
|
+
import { L as extractMentions, N as defaultParticipantMode, P as defaultRuntimeConfigPayload, S as clientCapabilitiesSchema, St as stripCode, Z as isReservedAgentName, a as AGENT_TYPES, b as agentTypeSchema, ct as questionAnswerMessageContentSchema, d as MENTION_REGEX, i as AGENT_STATUSES, l as GITHUB_ENTITY_TYPES, lt as questionMessageContentSchema, mt as scanMentionTokens, n as AGENT_NAME_REGEX, nt as messageSourceSchema, o as AGENT_VISIBILITY, s as CHAT_ENGAGEMENT_STATUSES } from "./dist-CrdnqZjv.mjs";
|
|
3
3
|
import { a as ClientUserMismatchError, c as NotFoundError, d as users, f as uuidv7, o as ConflictError, r as BadRequestError, s as ForbiddenError, t as AgentSendNonMemberError, u as organizations } from "./uuid-DbS_4vFh-iFghv4zA.mjs";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
5
|
import { and, asc, count, desc, eq, gt, gte, inArray, isNotNull, lt, ne, or, sql } from "drizzle-orm";
|
|
6
6
|
import { bigserial, boolean, customType, index, integer, jsonb, pgTable, primaryKey, serial, text, timestamp, unique } from "drizzle-orm/pg-core";
|
|
7
|
-
//#region ../server/dist/client-
|
|
7
|
+
//#region ../server/dist/client-BPRIfrOT.mjs
|
|
8
8
|
/**
|
|
9
9
|
* Client connections. A client is a single SDK process (AgentRuntime) that may
|
|
10
10
|
* host multiple agents. From the unified-user-token milestone on, a client is
|
|
@@ -401,7 +401,7 @@ async function pollInboxInner(db, inboxId, limit) {
|
|
|
401
401
|
/**
|
|
402
402
|
* Shared payload assembler for already-claimed `inbox_entries` rows.
|
|
403
403
|
*
|
|
404
|
-
* Both the
|
|
404
|
+
* Both the debug `GET /inbox` path (`pollInbox`) and the WS push path
|
|
405
405
|
* (`claimAndBuildForPush`) call this with rows they have just `UPDATE`d to
|
|
406
406
|
* `status='delivered'`. Keeping the silent-context bundling in one place is
|
|
407
407
|
* the only way to keep the two paths from drifting (proposal
|
|
@@ -473,9 +473,9 @@ const PUSH_CLAIM_BATCH_LIMIT = 8;
|
|
|
473
473
|
* WS-push path: atomically claim every pending entry the just-fired
|
|
474
474
|
* `NOTIFY (inboxId:messageId)` references and assemble their wire payloads.
|
|
475
475
|
*
|
|
476
|
-
* Returns `[]` if no row matches — benign race with
|
|
477
|
-
*
|
|
478
|
-
* (proposal §3.2).
|
|
476
|
+
* Returns `[]` if no row matches — benign race with another server instance
|
|
477
|
+
* (or the debug `GET /inbox` endpoint) that already claimed the entry.
|
|
478
|
+
* NOTIFY is fire-and-forget (proposal §3.2).
|
|
479
479
|
*
|
|
480
480
|
* Why an array, not a single row: `sendMessage` can write **two** rows for
|
|
481
481
|
* the same `(inbox, messageId)` pair when the recipient is both a chat
|
|
@@ -500,9 +500,9 @@ async function claimAndBuildForPush(db, inboxId, messageId) {
|
|
|
500
500
|
/**
|
|
501
501
|
* WS-push backlog path: on agent rebind (or once an in-flight slot frees up
|
|
502
502
|
* after an ack), drain up to `limit` pending `notify=true` entries oldest-
|
|
503
|
-
* first and assemble wire payloads. Identical claim shape to
|
|
504
|
-
*
|
|
505
|
-
*
|
|
503
|
+
* first and assemble wire payloads. Identical claim shape to `pollInbox` —
|
|
504
|
+
* they are intentionally interchangeable so a hot-path bug fixed in one
|
|
505
|
+
* shows up in the other (proposal §3.3 / §3.5).
|
|
506
506
|
*/
|
|
507
507
|
async function claimBacklogForPush(db, inboxId, limit) {
|
|
508
508
|
return withSpan("inbox.deliver.backlog", {
|
|
@@ -563,28 +563,14 @@ async function collectPrecedingContext(tx, inboxId, triggers) {
|
|
|
563
563
|
}
|
|
564
564
|
return result;
|
|
565
565
|
}
|
|
566
|
-
async function ackEntry(db, entryId, inboxId) {
|
|
567
|
-
return withSpan("inbox.ack", {
|
|
568
|
-
[FIRST_TREE_HUB_ATTR.INBOX_ENTRY_ID]: String(entryId),
|
|
569
|
-
"inbox.id": inboxId
|
|
570
|
-
}, async () => {
|
|
571
|
-
const [entry] = await db.update(inboxEntries).set({
|
|
572
|
-
status: "acked",
|
|
573
|
-
ackedAt: /* @__PURE__ */ new Date()
|
|
574
|
-
}).where(and(eq(inboxEntries.id, entryId), eq(inboxEntries.inboxId, inboxId), eq(inboxEntries.status, "delivered"))).returning();
|
|
575
|
-
if (!entry) throw new NotFoundError("Inbox entry not found or not in delivered status");
|
|
576
|
-
return entry;
|
|
577
|
-
});
|
|
578
|
-
}
|
|
579
566
|
/**
|
|
580
567
|
* Ack a delivered entry from the WS data plane, scoped to the inboxes the
|
|
581
568
|
* connected socket has bound. Returns the acked row on success, `null` if no
|
|
582
569
|
* row matches — a benign outcome the caller should ignore (the entry may
|
|
583
570
|
* have already been acked, timed out, or never belonged to this socket).
|
|
584
571
|
*
|
|
585
|
-
*
|
|
586
|
-
*
|
|
587
|
-
* are eligible. Empty `inboxIds` short-circuits to `null`.
|
|
572
|
+
* Trusts only the `inboxId` set the connected socket has bound (no `inboxId`
|
|
573
|
+
* on the wire), and short-circuits on an empty `inboxIds`.
|
|
588
574
|
*/
|
|
589
575
|
async function ackEntryByIdForBoundAgents(db, entryId, inboxIds) {
|
|
590
576
|
if (inboxIds.length === 0) return null;
|
|
@@ -596,11 +582,6 @@ async function ackEntryByIdForBoundAgents(db, entryId, inboxIds) {
|
|
|
596
582
|
return entry ?? null;
|
|
597
583
|
});
|
|
598
584
|
}
|
|
599
|
-
async function renewEntry(db, entryId, inboxId) {
|
|
600
|
-
const [entry] = await db.update(inboxEntries).set({ deliveredAt: /* @__PURE__ */ new Date() }).where(and(eq(inboxEntries.id, entryId), eq(inboxEntries.inboxId, inboxId), eq(inboxEntries.status, "delivered"))).returning();
|
|
601
|
-
if (!entry) throw new NotFoundError("Inbox entry not found or not in delivered status");
|
|
602
|
-
return entry;
|
|
603
|
-
}
|
|
604
585
|
async function resetTimedOutEntries(db, timeoutSeconds = DEFAULT_INBOX_TIMEOUT_SECONDS, maxRetries = DEFAULT_MAX_RETRY_COUNT) {
|
|
605
586
|
const reset = await db.update(inboxEntries).set({
|
|
606
587
|
status: "pending",
|
|
@@ -744,8 +725,10 @@ async function listAgentsManagedByUser(db, userId) {
|
|
|
744
725
|
inboxId: agents.inboxId,
|
|
745
726
|
visibility: agents.visibility,
|
|
746
727
|
runtimeProvider: agents.runtimeProvider,
|
|
747
|
-
clientId: agents.clientId
|
|
748
|
-
|
|
728
|
+
clientId: agents.clientId,
|
|
729
|
+
avatarImageUpdatedAt: agents.avatarImageUpdatedAt,
|
|
730
|
+
userAvatarUrl: users.avatarUrl
|
|
731
|
+
}).from(agents).innerJoin(members, eq(agents.managerId, members.id)).leftJoin(users, eq(users.id, members.userId)).where(and(eq(members.userId, userId), eq(members.status, "active"), ne(agents.status, AGENT_STATUSES.DELETED)));
|
|
749
732
|
}
|
|
750
733
|
/**
|
|
751
734
|
* Resolve the UUID of the "default" organization. Internal use only —
|
|
@@ -1185,6 +1168,36 @@ function agentAvatarImageUrl(uuid, updatedAt) {
|
|
|
1185
1168
|
return `/api/v1/agents/${uuid}/avatar?v=${updatedAt.getTime()}`;
|
|
1186
1169
|
}
|
|
1187
1170
|
/**
|
|
1171
|
+
* Resolve the public avatar image URL for an agent, considering both the
|
|
1172
|
+
* manager-uploaded image and — for human agents — the user's external
|
|
1173
|
+
* avatar URL (e.g. GitHub `users.avatar_url` injected by OAuth). Returns
|
|
1174
|
+
* `null` when neither source is available; the renderer then falls back
|
|
1175
|
+
* to color + initial.
|
|
1176
|
+
*
|
|
1177
|
+
* Priority: uploaded image > human user's avatar > null. The "upload
|
|
1178
|
+
* wins" rule gives users explicit control: once they upload a custom
|
|
1179
|
+
* avatar for their human agent it always shows, regardless of any later
|
|
1180
|
+
* GitHub avatar change.
|
|
1181
|
+
*/
|
|
1182
|
+
function resolveAvatarImageUrl(args) {
|
|
1183
|
+
const uploaded = agentAvatarImageUrl(args.uuid, args.avatarImageUpdatedAt);
|
|
1184
|
+
if (uploaded) return uploaded;
|
|
1185
|
+
if (args.type === AGENT_TYPES.HUMAN && args.userAvatarUrl) return args.userAvatarUrl;
|
|
1186
|
+
return null;
|
|
1187
|
+
}
|
|
1188
|
+
/**
|
|
1189
|
+
* Look up the external user-avatar URL backing a human agent via the
|
|
1190
|
+
* `members.agent_id → members.user_id → users.avatar_url` path. Returns
|
|
1191
|
+
* `null` for non-human agents or when the user has no avatar URL
|
|
1192
|
+
* captured (e.g. signed in without GitHub OAuth). Used by single-agent
|
|
1193
|
+
* API responses; list endpoints inline the join in their SELECT.
|
|
1194
|
+
*/
|
|
1195
|
+
async function fetchUserAvatarForHumanAgent(db, agent) {
|
|
1196
|
+
if (agent.type !== AGENT_TYPES.HUMAN) return null;
|
|
1197
|
+
const [row] = await db.select({ avatarUrl: users.avatarUrl }).from(members).innerJoin(users, eq(members.userId, users.id)).where(eq(members.agentId, agent.uuid)).limit(1);
|
|
1198
|
+
return row?.avatarUrl ?? null;
|
|
1199
|
+
}
|
|
1200
|
+
/**
|
|
1188
1201
|
* True iff `clients.metadata.capabilities` is a non-empty object — i.e. the
|
|
1189
1202
|
* client has reported at least one runtime probe result. Used to distinguish
|
|
1190
1203
|
* "we don't know what's installed yet" (empty / never reported) from
|
|
@@ -1445,13 +1458,14 @@ async function listAgentsForAdmin(db, scope, limit, cursor) {
|
|
|
1445
1458
|
runtimeProvider: agents.runtimeProvider,
|
|
1446
1459
|
avatarColorToken: agents.avatarColorToken,
|
|
1447
1460
|
avatarImageUpdatedAt: agents.avatarImageUpdatedAt,
|
|
1461
|
+
userAvatarUrl: users.avatarUrl,
|
|
1448
1462
|
createdAt: agents.createdAt,
|
|
1449
1463
|
updatedAt: agents.updatedAt,
|
|
1450
1464
|
presenceStatus: agentPresence.status,
|
|
1451
1465
|
runtimeType: agentPresence.runtimeType,
|
|
1452
1466
|
runtimeState: agentPresence.runtimeState,
|
|
1453
1467
|
activeSessions: agentPresence.activeSessions
|
|
1454
|
-
}).from(agents).leftJoin(agentPresence, eq(agents.uuid, agentPresence.agentId)).where(where).orderBy(desc(agents.createdAt)).limit(limit + 1);
|
|
1468
|
+
}).from(agents).leftJoin(agentPresence, eq(agents.uuid, agentPresence.agentId)).leftJoin(members, eq(members.agentId, agents.uuid)).leftJoin(users, eq(users.id, members.userId)).where(where).orderBy(desc(agents.createdAt)).limit(limit + 1);
|
|
1455
1469
|
const hasMore = rows.length > limit;
|
|
1456
1470
|
const items = hasMore ? rows.slice(0, limit) : rows;
|
|
1457
1471
|
const last = items[items.length - 1];
|
|
@@ -1485,13 +1499,14 @@ async function listAgentsForMember(db, scope, limit, cursor, type) {
|
|
|
1485
1499
|
runtimeProvider: agents.runtimeProvider,
|
|
1486
1500
|
avatarColorToken: agents.avatarColorToken,
|
|
1487
1501
|
avatarImageUpdatedAt: agents.avatarImageUpdatedAt,
|
|
1502
|
+
userAvatarUrl: users.avatarUrl,
|
|
1488
1503
|
createdAt: agents.createdAt,
|
|
1489
1504
|
updatedAt: agents.updatedAt,
|
|
1490
1505
|
presenceStatus: agentPresence.status,
|
|
1491
1506
|
runtimeType: agentPresence.runtimeType,
|
|
1492
1507
|
runtimeState: agentPresence.runtimeState,
|
|
1493
1508
|
activeSessions: agentPresence.activeSessions
|
|
1494
|
-
}).from(agents).leftJoin(agentPresence, eq(agents.uuid, agentPresence.agentId)).where(where).orderBy(desc(agents.createdAt)).limit(limit + 1);
|
|
1509
|
+
}).from(agents).leftJoin(agentPresence, eq(agents.uuid, agentPresence.agentId)).leftJoin(members, eq(members.agentId, agents.uuid)).leftJoin(users, eq(users.id, members.userId)).where(where).orderBy(desc(agents.createdAt)).limit(limit + 1);
|
|
1495
1510
|
const hasMore = rows.length > limit;
|
|
1496
1511
|
const items = hasMore ? rows.slice(0, limit) : rows;
|
|
1497
1512
|
const last = items[items.length - 1];
|
|
@@ -2298,15 +2313,9 @@ function createNotifier(listenClient) {
|
|
|
2298
2313
|
const messageId = payload.slice(sepIdx + 1);
|
|
2299
2314
|
const sockets = subscriptions.get(inboxId);
|
|
2300
2315
|
if (!sockets) return;
|
|
2301
|
-
const doorbellFrame = JSON.stringify({
|
|
2302
|
-
type: "new_message",
|
|
2303
|
-
inboxId,
|
|
2304
|
-
messageId
|
|
2305
|
-
});
|
|
2306
2316
|
for (const [ws, pushHandler] of sockets) {
|
|
2307
2317
|
if (ws.readyState !== ws.OPEN) continue;
|
|
2308
|
-
|
|
2309
|
-
else ws.send(doorbellFrame);
|
|
2318
|
+
Promise.resolve(pushHandler(messageId)).catch(() => {});
|
|
2310
2319
|
}
|
|
2311
2320
|
}
|
|
2312
2321
|
return {
|
|
@@ -2316,7 +2325,7 @@ function createNotifier(listenClient) {
|
|
|
2316
2325
|
map = /* @__PURE__ */ new Map();
|
|
2317
2326
|
subscriptions.set(inboxId, map);
|
|
2318
2327
|
}
|
|
2319
|
-
map.set(ws, pushHandler
|
|
2328
|
+
map.set(ws, pushHandler);
|
|
2320
2329
|
},
|
|
2321
2330
|
unsubscribe(inboxId, ws) {
|
|
2322
2331
|
const map = subscriptions.get(inboxId);
|
|
@@ -3516,13 +3525,21 @@ async function getChatDetail(db, chatId, selfAgentId = null) {
|
|
|
3516
3525
|
displayName: p.displayName,
|
|
3517
3526
|
type: p.type
|
|
3518
3527
|
}));
|
|
3528
|
+
const viewerMembershipKind = await resolveViewerMembershipKind(db, chatId, selfAgentId);
|
|
3519
3529
|
return {
|
|
3520
3530
|
...chat,
|
|
3521
3531
|
participants,
|
|
3522
3532
|
title,
|
|
3523
|
-
firstMessagePreview
|
|
3533
|
+
firstMessagePreview,
|
|
3534
|
+
viewerMembershipKind
|
|
3524
3535
|
};
|
|
3525
3536
|
}
|
|
3537
|
+
async function resolveViewerMembershipKind(db, chatId, viewerAgentId) {
|
|
3538
|
+
if (!viewerAgentId) return null;
|
|
3539
|
+
const [row] = await db.select({ accessMode: chatMembership.accessMode }).from(chatMembership).where(and(eq(chatMembership.chatId, chatId), eq(chatMembership.agentId, viewerAgentId))).limit(1);
|
|
3540
|
+
if (!row) return null;
|
|
3541
|
+
return row.accessMode === "speaker" ? "participant" : "watching";
|
|
3542
|
+
}
|
|
3526
3543
|
async function listChats(db, agentId, limit, cursor) {
|
|
3527
3544
|
const chatIds = (await db.select({ chatId: chatMembership.chatId }).from(chatMembership).where(and(eq(chatMembership.agentId, agentId), eq(chatMembership.accessMode, "speaker")))).map((r) => r.chatId);
|
|
3528
3545
|
if (chatIds.length === 0) return {
|
|
@@ -4210,4 +4227,4 @@ async function cleanupStaleClients(db, staleSeconds = 60) {
|
|
|
4210
4227
|
return result.length;
|
|
4211
4228
|
}
|
|
4212
4229
|
//#endregion
|
|
4213
|
-
export { getSession as $, suspendSession as $t,
|
|
4230
|
+
export { getSession as $, suspendSession as $t, createChat as A, pollInbox as At, fetchUserAvatarForHumanAgent as B, resolveAvatarImageUrl as Bt, claimBacklogForPush as C, markMeChatRead as Ct, clearAgentAvatarImage as D, messages as Dt, cleanupStalePresence as E, members as Et, disconnectClient as F, registerChatMessageDispatcher as Ft, getAgentAvatarImage as G, sendToAgent as Gt, findOrCreateDirectChat as H, resolveDefaultOrgId as Ht, editMessage as I, registerClient as It, getChatDetail as J, setChatEngagement as Jt, getCachedAudience as K, serverInstances as Kt, ensureDefaultOrganization as L, removeParticipant as Lt, createNotifier as M, reactivateAgent as Mt, deleteAgent as N, rebindAgent as Nt, clients as O, notifyRecipients as Ot, deriveAuthState as P, recomputeWatchersForMember as Pt, getPresence as Q, suspendAgent as Qt, ensureParticipant as R, resetActivity as Rt, claimAndBuildForPush as S, listMyPinnedAgents as St, cleanupStaleClients as T, markStaleAgents as Tt, getActivityOverview as U, retireClient as Ut, filterSessionsByParticipant as V, resolveChatTitle as Vt, getAgent as W, sendMessage as Wt, getOnlineCount as X, setRuntimeState as Xt, getClient as Y, setOffline as Yt, getOrganization as Z, submitAnswer as Zt, bindAgent as _, listClients as _t, adapterConfigs as a, upsertSessionState as an, leaveChat as at, chats as b, listMeChats as bt, addParticipant as c, listAgentSessions as ct, agentConfigs as d, listAgentsManagedByUser as dt, touchAgent as en, heartbeatClient as et, agentPresence as f, listAgentsWithRuntime as ft, assertParticipant as g, listChatsForMember as gt, assertClientOwner as h, listChats as ht, adapterAgentMappings as i, updateOrganization as in, joinMeChat as it, createMeChat as j, pruneStaleSilentEntries as jt, createAgent as k, pendingQuestions as kt, agentAvatarImageUrl as l, listAgentsForAdmin as lt, archiveSession as m, listChatParticipantsWithNames as mt, SUPPORTED_AVATAR_IMAGE_MIMES as n, updateAgent as nn, inboxEntries as nt, addChatParticipants as o, leaveMeChat as ot, agents as p, listAllSessions as pt, getCallerEngagement as q, setAgentAvatarImage as qt, ackEntryByIdForBoundAgents as r, updateClientCapabilities as rn, joinChat as rt, addMeChatParticipants as s, listActiveAgentsPinnedToClient as st, MAX_AVATAR_IMAGE_BYTES as t, unbindAgent as tn, heartbeatInstance as tt, agentChatSessions as u, listAgentsForMember as ut, chatMembership as v, listClientsForOrgAdmin as vt, claimClient as w, markMeChatUnread as wt, checkAgentNameAvailability as x, listMessages as xt, chatUserState as y, listMeChatSourceCounts as yt, extractSummary as z, resetTimedOutEntries as zt };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "./observability-BAScT_5S-BcW9HgkG.mjs";
|
|
2
2
|
import "./logger-core-BTmvdflj-DjW8FM4T.mjs";
|
|
3
|
-
import "./dist-
|
|
3
|
+
import "./dist-CrdnqZjv.mjs";
|
|
4
4
|
import "./uuid-DbS_4vFh-iFghv4zA.mjs";
|
|
5
5
|
import "./src-DNBS5Yjj.mjs";
|
|
6
|
-
import { St as listMyPinnedAgents } from "./client-
|
|
6
|
+
import { St as listMyPinnedAgents } from "./client-BPRIfrOT-CoV_2o7e.mjs";
|
|
7
7
|
export { listMyPinnedAgents };
|
|
@@ -756,7 +756,8 @@ z.object({
|
|
|
756
756
|
participants: z.array(chatParticipantDetailSchema),
|
|
757
757
|
title: z.string(),
|
|
758
758
|
firstMessagePreview: z.string().nullable(),
|
|
759
|
-
engagementStatus: chatEngagementStatusSchema
|
|
759
|
+
engagementStatus: chatEngagementStatusSchema,
|
|
760
|
+
viewerMembershipKind: z.enum(["participant", "watching"]).nullable()
|
|
760
761
|
});
|
|
761
762
|
const updateChatSchema = z.object({ topic: z.string().trim().max(500).nullable() });
|
|
762
763
|
/**
|
|
@@ -803,9 +804,13 @@ z.object({
|
|
|
803
804
|
* Optional opt-in flags the client carries on `client:register` to advertise
|
|
804
805
|
* which negotiable wire-protocol features it implements. Distinct from
|
|
805
806
|
* `clientCapabilitiesSchema` (per-runtime-provider availability — different
|
|
806
|
-
* concept).
|
|
807
|
-
*
|
|
808
|
-
*
|
|
807
|
+
* concept).
|
|
808
|
+
*
|
|
809
|
+
* 0.10.4 ~ 0.14.2 clients still send this block (with `wsInboxDeliver: true`
|
|
810
|
+
* hard-coded). The 0.14.3+ runtime omits it. The schema is retained so that
|
|
811
|
+
* middle-version `client:register` frames still parse, even though the
|
|
812
|
+
* server no longer reads any of these fields — the WS inbox data plane is
|
|
813
|
+
* mandatory on this server build.
|
|
809
814
|
*/
|
|
810
815
|
const clientWireCapabilitiesSchema = z.object({ wsInboxDeliver: z.boolean().default(false) }).partial();
|
|
811
816
|
const clientRegisterSchema = z.object({
|
|
@@ -1196,14 +1201,11 @@ z.object({
|
|
|
1196
1201
|
}).extend({ message: clientMessageSchema });
|
|
1197
1202
|
const inboxPollQuerySchema = z.object({ limit: z.coerce.number().int().min(1).max(50).default(10) });
|
|
1198
1203
|
/**
|
|
1199
|
-
* server → client: a single inbox entry pushed over the active WS connection
|
|
1200
|
-
* replacing the legacy `new_message` doorbell + HTTP `/inbox` poll round-trip.
|
|
1204
|
+
* server → client: a single inbox entry pushed over the active WS connection.
|
|
1201
1205
|
*
|
|
1202
1206
|
* `entryId` is the server-side `inbox_entries.id` the client must echo back
|
|
1203
|
-
* in `inbox:ack`. `
|
|
1204
|
-
*
|
|
1205
|
-
* side dispatch logic is reused verbatim (see proposal
|
|
1206
|
-
* hub-inbox-ws-data-plane §3.1).
|
|
1207
|
+
* in `inbox:ack`. `clientMessageSchema` carries `precedingMessages`, so the
|
|
1208
|
+
* client-side dispatch logic handles the silent-context bundle uniformly.
|
|
1207
1209
|
*
|
|
1208
1210
|
* `.passthrough()` so a forward-rolling server may extend the frame without
|
|
1209
1211
|
* breaking older clients that validate strictly. Older clients drop unknown
|
|
@@ -1217,8 +1219,7 @@ const inboxDeliverFrameSchema = z.object({
|
|
|
1217
1219
|
message: clientMessageSchema
|
|
1218
1220
|
}).passthrough();
|
|
1219
1221
|
/**
|
|
1220
|
-
* client → server: ack for an `inbox:deliver` frame.
|
|
1221
|
-
* `POST /inbox/:id/ack` HTTP endpoint when the WS data plane is active.
|
|
1222
|
+
* client → server: ack for an `inbox:deliver` frame.
|
|
1222
1223
|
*/
|
|
1223
1224
|
const inboxAckFrameSchema = z.object({
|
|
1224
1225
|
type: z.literal("inbox:ack"),
|
|
@@ -1994,8 +1995,13 @@ const WS_AUTH_FRAME_TIMEOUT_MS = 5e3;
|
|
|
1994
1995
|
/**
|
|
1995
1996
|
* Negotiable wire-protocol features the server advertises in its `welcome`
|
|
1996
1997
|
* frame. Older clients drop the `capabilities` field silently because the
|
|
1997
|
-
* frame is `.passthrough()`.
|
|
1998
|
-
*
|
|
1998
|
+
* frame is `.passthrough()`.
|
|
1999
|
+
*
|
|
2000
|
+
* Required by clients in the 0.10.4 ~ 0.14.2 range: those builds read
|
|
2001
|
+
* `wsInboxDeliver` here to decide whether to skip the local HTTP poll loop
|
|
2002
|
+
* and rely on `inbox:deliver` push frames. The 0.14.3+ runtime ignores the
|
|
2003
|
+
* field (push is the only path) but the server still emits it so middle-
|
|
2004
|
+
* version clients keep working.
|
|
1999
2005
|
*/
|
|
2000
2006
|
const serverCapabilitiesSchema = z.object({ wsInboxDeliver: z.boolean().default(false) }).partial();
|
|
2001
2007
|
z.object({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { r as __exportAll } from "./chunk-BSw8zbkd.mjs";
|
|
2
2
|
import { t as cliFetch } from "./cli-fetch--tiwKm5S.mjs";
|
|
3
|
-
import { r as AGENT_SELECTOR_HEADER } from "./dist-
|
|
3
|
+
import { r as AGENT_SELECTOR_HEADER } from "./dist-CrdnqZjv.mjs";
|
|
4
4
|
//#region src/core/feishu.ts
|
|
5
5
|
var feishu_exports = /* @__PURE__ */ __exportAll({
|
|
6
6
|
bindFeishuBot: () => bindFeishuBot,
|
package/dist/index.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import "./observability-BAScT_5S-BcW9HgkG.mjs";
|
|
2
|
-
import { A as checkDocker, B as isServiceSupported, E as checkAgentConfigs, F as checkWebSocket, G as uninstallClientService, H as restartClientService, I as printResults, J as stopPostgres, K as ensurePostgres, M as checkServerConfig, N as checkServerHealth, O as checkClientConfig, P as checkServerReachable, R as getClientServiceStatus, S as runHomeMigration, T as runMigrations, U as startClientService, V as resolveCliInvocation, W as stopClientService, X as handleClientOrgMismatch, Y as ClientRuntime, Z as rotateClientIdWithBackup, _ as formatCheckReport, b as onboardCreate, d as startServer, g as promptMissingFields, h as promptAddAgent, j as checkNodeVersion, k as checkDatabase, lt as FirstTreeHubSDK, m as isInteractive, n as deriveHubUrlFromToken, nt as hasUser, q as isDockerAvailable, t as HubUrlDerivationError, tt as createOwner, ut as SdkError, y as onboardCheck, z as installClientService } from "./saas-connect-
|
|
2
|
+
import { A as checkDocker, B as isServiceSupported, E as checkAgentConfigs, F as checkWebSocket, G as uninstallClientService, H as restartClientService, I as printResults, J as stopPostgres, K as ensurePostgres, M as checkServerConfig, N as checkServerHealth, O as checkClientConfig, P as checkServerReachable, R as getClientServiceStatus, S as runHomeMigration, T as runMigrations, U as startClientService, V as resolveCliInvocation, W as stopClientService, X as handleClientOrgMismatch, Y as ClientRuntime, Z as rotateClientIdWithBackup, _ as formatCheckReport, b as onboardCreate, d as startServer, g as promptMissingFields, h as promptAddAgent, j as checkNodeVersion, k as checkDatabase, lt as FirstTreeHubSDK, m as isInteractive, n as deriveHubUrlFromToken, nt as hasUser, q as isDockerAvailable, t as HubUrlDerivationError, tt as createOwner, ut as SdkError, y as onboardCheck, z as installClientService } from "./saas-connect-Da55XxRX.mjs";
|
|
3
3
|
import "./logger-core-BTmvdflj-DjW8FM4T.mjs";
|
|
4
|
-
import { a as ensureFreshAdminToken, c as resolveServerUrl, i as ensureFreshAccessToken, n as AuthRefreshRateLimitedError, s as resolveAccessToken, t as AuthRefreshFailedError } from "./bootstrap-
|
|
4
|
+
import { a as ensureFreshAdminToken, c as resolveServerUrl, i as ensureFreshAccessToken, n as AuthRefreshRateLimitedError, s as resolveAccessToken, t as AuthRefreshFailedError } from "./bootstrap-CQQGgIx1.mjs";
|
|
5
5
|
import { i as blank, s as status } from "./cli-fetch--tiwKm5S.mjs";
|
|
6
|
-
import "./dist-
|
|
7
|
-
import { n as bindFeishuUser, t as bindFeishuBot } from "./feishu-
|
|
6
|
+
import "./dist-CrdnqZjv.mjs";
|
|
7
|
+
import { n as bindFeishuUser, t as bindFeishuBot } from "./feishu-DNoBroKK.mjs";
|
|
8
8
|
import "./uuid-DbS_4vFh-iFghv4zA.mjs";
|
|
9
9
|
import "./src-DNBS5Yjj.mjs";
|
|
10
|
-
import "./client-
|
|
10
|
+
import "./client-BPRIfrOT-CoV_2o7e.mjs";
|
|
11
11
|
import "./invitation-D_ENPHyj-5ETiae5r.mjs";
|
|
12
12
|
export { AuthRefreshFailedError, AuthRefreshRateLimitedError, ClientRuntime, FirstTreeHubSDK, HubUrlDerivationError, SdkError, bindFeishuBot, bindFeishuUser, blank, checkAgentConfigs, checkClientConfig, checkDatabase, checkDocker, checkNodeVersion, checkServerConfig, checkServerHealth, checkServerReachable, checkWebSocket, createOwner, deriveHubUrlFromToken, ensureFreshAccessToken, ensureFreshAdminToken, ensurePostgres, formatCheckReport, getClientServiceStatus, handleClientOrgMismatch, hasUser, installClientService, isDockerAvailable, isInteractive, isServiceSupported, onboardCheck, onboardCreate, printResults, promptAddAgent, promptMissingFields, resolveAccessToken, resolveCliInvocation, resolveServerUrl, restartClientService, rotateClientIdWithBackup, runHomeMigration, runMigrations, startClientService, startServer, status, stopClientService, stopPostgres, uninstallClientService };
|