@agent-team-foundation/first-tree-hub 0.13.0 → 0.14.1
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-Cya2OoHz.mjs → bootstrap-C15ZBOCC.mjs} +1 -0
- package/dist/cli/index.mjs +7 -7
- package/dist/{client-h4KZ3b9o-CQyibXig.mjs → client-CREn8bJ0-C5fHJir6.mjs} +2 -2
- package/dist/{client-BH4CmUL0-CybE3kuP.mjs → client-CzXmweS9-DhUiuQvL.mjs} +59 -6
- package/dist/{dist-C8yStx2L.mjs → dist-1XGLJMOq.mjs} +109 -9
- package/dist/drizzle/0044_agent_avatar_color.sql +11 -0
- package/dist/drizzle/0045_agent_avatar_image.sql +17 -0
- package/dist/drizzle/meta/_journal.json +14 -0
- package/dist/{feishu-D_vnqC6a.mjs → feishu-BGx71p5s.mjs} +1 -1
- package/dist/index.mjs +5 -5
- package/dist/{invitation-CNv7gfFF-D93KQte0.mjs → invitation-CNv7gfFF-DOFZ75wb.mjs} +1 -1
- package/dist/{saas-connect-Bb5LR4y6.mjs → saas-connect-BBRxjmBS.mjs} +635 -113
- package/dist/web/assets/index-BOK7e_td.css +1 -0
- package/dist/web/assets/{index-CJcRUZ8l.js → index-DMqnX4IR.js} +1 -1
- package/dist/web/assets/index-QDcpYpEa.js +416 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/web/assets/index-DL_9NFkt.js +0 -421
- package/dist/web/assets/index-DaWEZnjh.css +0 -1
|
@@ -552,6 +552,7 @@ const serverConfigSchema = defineConfig({
|
|
|
552
552
|
host: field(z.string().default("127.0.0.1"), { env: "FIRST_TREE_HUB_HOST" }),
|
|
553
553
|
publicUrl: field(z.string().optional(), { env: "FIRST_TREE_HUB_PUBLIC_URL" })
|
|
554
554
|
},
|
|
555
|
+
workspace: { root: field(z.string().default(join(DEFAULT_DATA_DIR, "workspaces")), { env: "FIRST_TREE_HUB_WORKSPACES_ROOT" }) },
|
|
555
556
|
secrets: {
|
|
556
557
|
jwtSecret: field(z.string(), {
|
|
557
558
|
env: "FIRST_TREE_HUB_JWT_SECRET",
|
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-BBRxjmBS.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-C15ZBOCC.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-1XGLJMOq.mjs";
|
|
8
|
+
import { n as bindFeishuUser, t as bindFeishuBot } from "../feishu-BGx71p5s.mjs";
|
|
9
9
|
import "../errors-LPcARA4K-Dbrptiyz.mjs";
|
|
10
10
|
import "../src-DNBS5Yjj.mjs";
|
|
11
|
-
import "../client-
|
|
11
|
+
import "../client-CzXmweS9-DhUiuQvL.mjs";
|
|
12
12
|
import "../invitation-DZO4NX3P-BPxTeHf-.mjs";
|
|
13
13
|
import { join } from "node:path";
|
|
14
14
|
import { existsSync, mkdirSync, readFileSync, readdirSync } from "node:fs";
|
|
@@ -1495,13 +1495,13 @@ function decodeJwtExpSeconds(token) {
|
|
|
1495
1495
|
//#region src/commands/onboard.ts
|
|
1496
1496
|
async function promptMissing(args) {
|
|
1497
1497
|
if (!args.server) try {
|
|
1498
|
-
const { resolveServerUrl } = await import("../bootstrap-
|
|
1498
|
+
const { resolveServerUrl } = await import("../bootstrap-C15ZBOCC.mjs").then((n) => n.r);
|
|
1499
1499
|
resolveServerUrl();
|
|
1500
1500
|
} catch {
|
|
1501
1501
|
args.server = await input({ message: "Hub server URL:" });
|
|
1502
1502
|
saveOnboardState(args);
|
|
1503
1503
|
}
|
|
1504
|
-
const { loadCredentials } = await import("../bootstrap-
|
|
1504
|
+
const { loadCredentials } = await import("../bootstrap-C15ZBOCC.mjs").then((n) => n.r);
|
|
1505
1505
|
if (!loadCredentials()) throw new Error("No saved credentials. Run `first-tree-hub connect <token>` before onboarding.");
|
|
1506
1506
|
if (!args.id) {
|
|
1507
1507
|
args.id = await input({ message: "Agent ID:" });
|
|
@@ -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-1XGLJMOq.mjs";
|
|
4
4
|
import "./errors-LPcARA4K-Dbrptiyz.mjs";
|
|
5
5
|
import "./src-DNBS5Yjj.mjs";
|
|
6
|
-
import { J as listMyPinnedAgents } from "./client-
|
|
6
|
+
import { J as listMyPinnedAgents } from "./client-CzXmweS9-DhUiuQvL.mjs";
|
|
7
7
|
export { listMyPinnedAgents };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { O as withSpan, f as messageAttrs, s as createLogger } from "./observability-BAScT_5S-BcW9HgkG.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { L as extractMentions, N as defaultParticipantMode, S as clientCapabilitiesSchema, b as agentTypeSchema, ct as questionAnswerMessageContentSchema, i as AGENT_STATUSES, lt as questionMessageContentSchema, mt as scanMentionTokens, o as AGENT_VISIBILITY, s as CHAT_ENGAGEMENT_STATUSES } from "./dist-1XGLJMOq.mjs";
|
|
3
3
|
import { a as ConflictError, i as ClientUserMismatchError, l as organizations, n as BadRequestError, o as ForbiddenError, s as NotFoundError, u as users } from "./errors-LPcARA4K-Dbrptiyz.mjs";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
5
|
import { and, desc, eq, inArray, isNotNull, lt, ne, or, sql } from "drizzle-orm";
|
|
6
|
-
import { bigserial, boolean, index, integer, jsonb, pgTable, primaryKey, text, timestamp, unique } from "drizzle-orm/pg-core";
|
|
7
|
-
//#region ../server/dist/client-
|
|
6
|
+
import { bigserial, boolean, customType, index, integer, jsonb, pgTable, primaryKey, text, timestamp, unique } from "drizzle-orm/pg-core";
|
|
7
|
+
//#region ../server/dist/client-CzXmweS9.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
|
|
@@ -33,6 +33,13 @@ const clients = pgTable("clients", {
|
|
|
33
33
|
lastSeenAt: timestamp("last_seen_at", { withTimezone: true }).notNull().defaultNow(),
|
|
34
34
|
metadata: jsonb("metadata").$type()
|
|
35
35
|
}, (table) => [index("idx_clients_user").on(table.userId), index("idx_clients_org").on(table.organizationId)]);
|
|
36
|
+
/**
|
|
37
|
+
* `bytea` column type — Drizzle ships pg primitives but not bytea out of the
|
|
38
|
+
* box. Reads come back as Node `Buffer` (postgres-js); writes accept any
|
|
39
|
+
* `Uint8Array`. Used for the small inline avatar image blob; no streaming
|
|
40
|
+
* needed at this size (≤ ~50 KB after client-side resize).
|
|
41
|
+
*/
|
|
42
|
+
const bytea = customType({ dataType: () => "bytea" });
|
|
36
43
|
/** Agent registration. Each agent owns a unique inboxId for message delivery. */
|
|
37
44
|
const agents = pgTable("agents", {
|
|
38
45
|
uuid: text("uuid").primaryKey(),
|
|
@@ -49,6 +56,10 @@ const agents = pgTable("agents", {
|
|
|
49
56
|
managerId: text("manager_id").notNull(),
|
|
50
57
|
clientId: text("client_id").references(() => clients.id, { onDelete: "restrict" }),
|
|
51
58
|
runtimeProvider: text("runtime_provider").notNull().default("claude-code"),
|
|
59
|
+
avatarColorToken: text("avatar_color_token"),
|
|
60
|
+
avatarImageData: bytea("avatar_image_data"),
|
|
61
|
+
avatarImageMime: text("avatar_image_mime"),
|
|
62
|
+
avatarImageUpdatedAt: timestamp("avatar_image_updated_at", { withTimezone: true }),
|
|
52
63
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
53
64
|
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow()
|
|
54
65
|
}, (table) => [
|
|
@@ -1764,18 +1775,31 @@ async function sendMessageInner(db, chatId, senderId, data, options) {
|
|
|
1764
1775
|
tx.select({ type: chats.type }).from(chats).where(eq(chats.id, chatId)).limit(1),
|
|
1765
1776
|
tx.select({
|
|
1766
1777
|
inboxId: agents.inboxId,
|
|
1767
|
-
organizationId: agents.organizationId
|
|
1778
|
+
organizationId: agents.organizationId,
|
|
1779
|
+
type: agents.type
|
|
1768
1780
|
}).from(agents).where(eq(agents.uuid, senderId)).limit(1)
|
|
1769
1781
|
]);
|
|
1770
1782
|
const chatType = chatRow?.type ?? null;
|
|
1771
1783
|
if (!senderRow) throw new NotFoundError(`Sender agent "${senderId}" not found`);
|
|
1784
|
+
let effectiveContent = data.content;
|
|
1785
|
+
if (senderRow.type !== "human" && typeof effectiveContent === "string") {
|
|
1786
|
+
const unwrapped = maybeUnwrapDoubleEncoded(effectiveContent);
|
|
1787
|
+
if (unwrapped !== null) {
|
|
1788
|
+
log.warn({
|
|
1789
|
+
metric: "double_encoded_content_unwrapped_total",
|
|
1790
|
+
chatId,
|
|
1791
|
+
senderId
|
|
1792
|
+
}, "agent sent JSON-encoded string content — unwrapping to restore markdown rendering");
|
|
1793
|
+
effectiveContent = unwrapped;
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1772
1796
|
if (data.replyToInbox !== void 0 && data.replyToInbox !== null) {
|
|
1773
1797
|
if (senderRow.inboxId !== data.replyToInbox) throw new BadRequestError("replyToInbox must reference the sender's own inbox");
|
|
1774
1798
|
}
|
|
1775
1799
|
const incomingMeta = data.metadata ?? {};
|
|
1776
1800
|
const explicitMentionsRaw = incomingMeta.mentions;
|
|
1777
1801
|
const explicitMentions = Array.isArray(explicitMentionsRaw) ? explicitMentionsRaw.filter((m) => typeof m === "string") : [];
|
|
1778
|
-
const contentText = typeof
|
|
1802
|
+
const contentText = typeof effectiveContent === "string" ? effectiveContent : "";
|
|
1779
1803
|
const resolved = contentText ? extractMentions(contentText, participants) : [];
|
|
1780
1804
|
const mergedMentions = [...new Set([...explicitMentions, ...resolved])];
|
|
1781
1805
|
const metadataToStore = mergedMentions.length > 0 ? {
|
|
@@ -1786,7 +1810,7 @@ async function sendMessageInner(db, chatId, senderId, data, options) {
|
|
|
1786
1810
|
if (options.enforceGroupMention && chatType === "group") {
|
|
1787
1811
|
if (mergedMentions.filter((id) => id !== senderId).length === 0) throw new BadRequestError("Sending to a group chat requires an explicit @mention. Use `first-tree-hub chat send <name>` to message a single agent, or @<name> in the content to address one or more group members.");
|
|
1788
1812
|
}
|
|
1789
|
-
let outboundContent =
|
|
1813
|
+
let outboundContent = effectiveContent;
|
|
1790
1814
|
if (options.normalizeMentionsInContent && typeof outboundContent === "string") {
|
|
1791
1815
|
const present = new Set(scanMentionTokens(outboundContent));
|
|
1792
1816
|
const missingNames = [];
|
|
@@ -1898,6 +1922,35 @@ async function sendMessageInner(db, chatId, senderId, data, options) {
|
|
|
1898
1922
|
recipients: txResult.recipients
|
|
1899
1923
|
};
|
|
1900
1924
|
}
|
|
1925
|
+
/**
|
|
1926
|
+
* Detect agent-sent content that was JSON.stringify-ed once before reaching
|
|
1927
|
+
* the CLI / API. The bad shape is an outer `"..."` wrapper + interior `\n` /
|
|
1928
|
+
* `\"` escape sequences, which the UI renders as a quoted literal instead of
|
|
1929
|
+
* markdown (issue #389). Returns the unwrapped inner string on a confident
|
|
1930
|
+
* match, or `null` to leave the content alone.
|
|
1931
|
+
*
|
|
1932
|
+
* Match conditions (all required) — kept strict so legitimate human content
|
|
1933
|
+
* that happens to look like a quoted phrase is never touched. The caller is
|
|
1934
|
+
* additionally responsible for restricting this to non-human senders.
|
|
1935
|
+
*
|
|
1936
|
+
* - first and last char are `"`
|
|
1937
|
+
* - body contains at least one typical JSON escape sequence
|
|
1938
|
+
* (`\n`, `\r`, `\t`, `\"`, or `\\`)
|
|
1939
|
+
* - `JSON.parse` succeeds
|
|
1940
|
+
* - the parse result is a `string` (excludes `{...}`, `[...]`, numbers)
|
|
1941
|
+
*/
|
|
1942
|
+
function maybeUnwrapDoubleEncoded(content) {
|
|
1943
|
+
if (content.length < 4) return null;
|
|
1944
|
+
if (content.charCodeAt(0) !== 34) return null;
|
|
1945
|
+
if (content.charCodeAt(content.length - 1) !== 34) return null;
|
|
1946
|
+
if (!/\\[nrt"\\]/.test(content)) return null;
|
|
1947
|
+
try {
|
|
1948
|
+
const parsed = JSON.parse(content);
|
|
1949
|
+
return typeof parsed === "string" ? parsed : null;
|
|
1950
|
+
} catch {
|
|
1951
|
+
return null;
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1901
1954
|
function stripMentionPrefix(content) {
|
|
1902
1955
|
return content.replace(/^(@\S+\s*)+/, "").trim();
|
|
1903
1956
|
}
|
|
@@ -520,6 +520,16 @@ const AGENT_VISIBILITY = {
|
|
|
520
520
|
ORGANIZATION: "organization"
|
|
521
521
|
};
|
|
522
522
|
const agentVisibilitySchema = z.enum(["private", "organization"]);
|
|
523
|
+
const avatarColorTokenSchema = z.enum([
|
|
524
|
+
"hue-0",
|
|
525
|
+
"hue-1",
|
|
526
|
+
"hue-2",
|
|
527
|
+
"hue-3",
|
|
528
|
+
"hue-4",
|
|
529
|
+
"hue-5",
|
|
530
|
+
"hue-6",
|
|
531
|
+
"hue-7"
|
|
532
|
+
]);
|
|
523
533
|
const AGENT_STATUSES = {
|
|
524
534
|
ACTIVE: "active",
|
|
525
535
|
SUSPENDED: "suspended",
|
|
@@ -571,7 +581,8 @@ const updateAgentSchema = z.object({
|
|
|
571
581
|
visibility: agentVisibilitySchema.optional(),
|
|
572
582
|
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
573
583
|
managerId: z.string().nullable().optional(),
|
|
574
|
-
clientId: z.string().min(1).max(100).nullable().optional()
|
|
584
|
+
clientId: z.string().min(1).max(100).nullable().optional(),
|
|
585
|
+
avatarColorToken: avatarColorTokenSchema.nullable().optional()
|
|
575
586
|
});
|
|
576
587
|
/**
|
|
577
588
|
* Service-level rebind input. Admin / owner re-binds an agent to a new
|
|
@@ -600,6 +611,8 @@ z.object({
|
|
|
600
611
|
managerId: z.string().nullable(),
|
|
601
612
|
clientId: z.string().nullable(),
|
|
602
613
|
runtimeProvider: runtimeProviderSchema,
|
|
614
|
+
avatarColorToken: z.string().nullable(),
|
|
615
|
+
avatarImageUrl: z.string().nullable(),
|
|
603
616
|
presenceStatus: presenceStatusSchema.optional(),
|
|
604
617
|
createdAt: z.string(),
|
|
605
618
|
updatedAt: z.string()
|
|
@@ -637,12 +650,30 @@ z.object({
|
|
|
637
650
|
expiresIn: z.number(),
|
|
638
651
|
command: z.string()
|
|
639
652
|
});
|
|
640
|
-
|
|
653
|
+
/**
|
|
654
|
+
* `chats.metadata` is `jsonb` at the DB layer. Without a typed contract every
|
|
655
|
+
* writer was free to invent their own keys, so a GitHub webhook writing
|
|
656
|
+
* `{ source: "github", entityKey: "..." }` and a Feishu adapter writing
|
|
657
|
+
* `{ source: "feishu", externalChannelId: "..." }` could collide on shared
|
|
658
|
+
* keys (`source`, `title`). The discriminated union below pins both writers
|
|
659
|
+
* to a single shape and lets TypeScript narrow on `metadata.source`.
|
|
660
|
+
*
|
|
661
|
+
* Add new variants here; do not extend with free-form `Record<string, unknown>`.
|
|
662
|
+
*/
|
|
663
|
+
/**
|
|
664
|
+
* Source of truth for which github entities get their own tag in the
|
|
665
|
+
* conversation list. Adding a new entry here extends `ChatSource`
|
|
666
|
+
* (`github_${entityType}`) and the SQL CASE/IN-list in
|
|
667
|
+
* `server/services/me-chat.ts` without touching them — both derive from
|
|
668
|
+
* this constant.
|
|
669
|
+
*/
|
|
670
|
+
const GITHUB_ENTITY_TYPES = [
|
|
641
671
|
"issue",
|
|
642
672
|
"pull_request",
|
|
643
673
|
"discussion",
|
|
644
674
|
"commit"
|
|
645
|
-
]
|
|
675
|
+
];
|
|
676
|
+
const githubEntityTypeSchema = z.enum(GITHUB_ENTITY_TYPES);
|
|
646
677
|
const githubChatMetadataSchema = z.object({
|
|
647
678
|
source: z.literal("github"),
|
|
648
679
|
entityType: githubEntityTypeSchema,
|
|
@@ -661,6 +692,14 @@ const chatMetadataSchema = z.discriminatedUnion("source", [githubChatMetadataSch
|
|
|
661
692
|
* sneak through `{ source: "github" }` without the required fields.
|
|
662
693
|
*/
|
|
663
694
|
const optionalChatMetadataSchema = z.union([z.object({}).strict(), chatMetadataSchema]);
|
|
695
|
+
const chatSourceSchema = z.enum([
|
|
696
|
+
"manual",
|
|
697
|
+
"github_issue",
|
|
698
|
+
"github_pull_request",
|
|
699
|
+
"github_discussion",
|
|
700
|
+
"github_commit",
|
|
701
|
+
"feishu"
|
|
702
|
+
]);
|
|
664
703
|
const chatTypeSchema = z.enum(["direct", "group"]);
|
|
665
704
|
/**
|
|
666
705
|
* Per-(chat, user) engagement state. Stored on `chat_user_state` so each
|
|
@@ -897,6 +936,11 @@ const contextTreeSummarySchema = z.object({
|
|
|
897
936
|
removedCount: z.number().int().nonnegative(),
|
|
898
937
|
changedNodeCount: z.number().int().nonnegative()
|
|
899
938
|
});
|
|
939
|
+
const contextTreeUsageSummarySchema = z.object({
|
|
940
|
+
windowDays: z.number().int().positive(),
|
|
941
|
+
agentCount: z.number().int().nonnegative(),
|
|
942
|
+
usageCount: z.number().int().nonnegative()
|
|
943
|
+
});
|
|
900
944
|
const contextTreeSnapshotSchema = z.object({
|
|
901
945
|
repo: z.string().nullable(),
|
|
902
946
|
branch: z.string().nullable(),
|
|
@@ -905,6 +949,7 @@ const contextTreeSnapshotSchema = z.object({
|
|
|
905
949
|
snapshotStatus: contextTreeSnapshotStatusSchema,
|
|
906
950
|
contextStatus: contextTreeStatusSchema,
|
|
907
951
|
summary: contextTreeSummarySchema,
|
|
952
|
+
usage: contextTreeUsageSummarySchema,
|
|
908
953
|
updates: z.array(contextTreeUpdateSchema),
|
|
909
954
|
nodes: z.array(contextTreeNodeSchema),
|
|
910
955
|
edges: z.array(contextTreeEdgeSchema),
|
|
@@ -1190,12 +1235,15 @@ const listMeChatsQuerySchema = z.object({
|
|
|
1190
1235
|
cursor: z.string().optional(),
|
|
1191
1236
|
limit: z.coerce.number().int().min(1).max(200).default(50),
|
|
1192
1237
|
filter: meChatFilterSchema.default("all"),
|
|
1193
|
-
engagement: chatEngagementViewSchema.default("active")
|
|
1238
|
+
engagement: chatEngagementViewSchema.default("active"),
|
|
1239
|
+
source: chatSourceSchema.optional()
|
|
1194
1240
|
});
|
|
1195
1241
|
const meChatParticipantSchema = z.object({
|
|
1196
1242
|
agentId: z.string(),
|
|
1197
1243
|
displayName: z.string(),
|
|
1198
|
-
type: z.string()
|
|
1244
|
+
type: z.string(),
|
|
1245
|
+
avatarColorToken: z.string().nullable(),
|
|
1246
|
+
avatarImageUrl: z.string().nullable()
|
|
1199
1247
|
});
|
|
1200
1248
|
/**
|
|
1201
1249
|
* Live activity hint surfaced in the conversation row's time slot. Derived
|
|
@@ -1257,6 +1305,47 @@ z.object({
|
|
|
1257
1305
|
type: z.literal("chat:message"),
|
|
1258
1306
|
chatId: z.string()
|
|
1259
1307
|
});
|
|
1308
|
+
/**
|
|
1309
|
+
* Per-source aggregate for the conversation-list tag bar.
|
|
1310
|
+
*
|
|
1311
|
+
* - `chatCount` — number of chats the caller is in for this source. Used
|
|
1312
|
+
* to hide tags whose count is 0 ("don't render a PR tag if there are no
|
|
1313
|
+
* PRs").
|
|
1314
|
+
* - `unreadChatCount` — number of chats whose `unread_mention_count > 0`.
|
|
1315
|
+
* This is "chats with unread mentions", NOT "total mention count", so
|
|
1316
|
+
* the badge on each tag matches the semantics of the existing `unread`
|
|
1317
|
+
* filter pill (`totalUnread` in `pages/workspace/conversations`) — a
|
|
1318
|
+
* `2` on the PR tag means "2 PR chats have unread mentions", which is
|
|
1319
|
+
* what a user expects to click into.
|
|
1320
|
+
*
|
|
1321
|
+
* The map ALWAYS contains the `manual` key (the default tab is always
|
|
1322
|
+
* available, even at zero counts); other keys are present only when the
|
|
1323
|
+
* caller has at least one chat for that source.
|
|
1324
|
+
*/
|
|
1325
|
+
const chatSourceCountSchema = z.object({
|
|
1326
|
+
chatCount: z.number().int().nonnegative(),
|
|
1327
|
+
unreadChatCount: z.number().int().nonnegative()
|
|
1328
|
+
});
|
|
1329
|
+
const listMeChatSourceCountsQuerySchema = z.object({ engagement: chatEngagementViewSchema.default("active") });
|
|
1330
|
+
z.object({ counts: z.partialRecord(chatSourceSchema, chatSourceCountSchema) });
|
|
1331
|
+
const workspaceDocRefSchema = z.object({
|
|
1332
|
+
type: z.literal("workspace"),
|
|
1333
|
+
chatId: z.string().trim().min(1),
|
|
1334
|
+
agentId: z.string().trim().min(1),
|
|
1335
|
+
basePath: z.string().trim().optional(),
|
|
1336
|
+
path: z.string().trim().min(1)
|
|
1337
|
+
});
|
|
1338
|
+
z.object({ basePath: z.string().trim().min(1) });
|
|
1339
|
+
const getMeDocSchema = z.object({
|
|
1340
|
+
agentId: z.string().trim().min(1),
|
|
1341
|
+
basePath: z.string().trim().optional(),
|
|
1342
|
+
path: z.string().trim().min(1)
|
|
1343
|
+
});
|
|
1344
|
+
const getMeDocResponseSchema = z.object({
|
|
1345
|
+
ref: workspaceDocRefSchema,
|
|
1346
|
+
path: z.string(),
|
|
1347
|
+
content: z.string()
|
|
1348
|
+
});
|
|
1260
1349
|
z.enum([
|
|
1261
1350
|
"connect",
|
|
1262
1351
|
"create_agent",
|
|
@@ -1315,7 +1404,8 @@ z.object({
|
|
|
1315
1404
|
organizationId: z.string(),
|
|
1316
1405
|
organizationName: z.string(),
|
|
1317
1406
|
role: z.enum(["admin", "member"]),
|
|
1318
|
-
agentId: z.string()
|
|
1407
|
+
agentId: z.string(),
|
|
1408
|
+
orgHasOtherMembers: z.boolean()
|
|
1319
1409
|
});
|
|
1320
1410
|
const memberRoleSchema = z.enum(["admin", "member"]);
|
|
1321
1411
|
const memberSchema = z.object({
|
|
@@ -1726,7 +1816,8 @@ const sessionEventKind = z.enum([
|
|
|
1726
1816
|
"error",
|
|
1727
1817
|
"assistant_text",
|
|
1728
1818
|
"thinking",
|
|
1729
|
-
"turn_end"
|
|
1819
|
+
"turn_end",
|
|
1820
|
+
"context_tree_usage"
|
|
1730
1821
|
]);
|
|
1731
1822
|
const toolCallEventPayload = z.object({
|
|
1732
1823
|
toolUseId: z.string(),
|
|
@@ -1768,6 +1859,10 @@ const thinkingEventPayload = z.object({});
|
|
|
1768
1859
|
* completed turns to show only the final result message.
|
|
1769
1860
|
*/
|
|
1770
1861
|
const turnEndEventPayload = z.object({ status: z.enum(["success", "error"]) });
|
|
1862
|
+
const contextTreeUsageEventPayload = z.object({
|
|
1863
|
+
purpose: z.literal("design_decision"),
|
|
1864
|
+
treeRepoUrl: z.string().nullable()
|
|
1865
|
+
});
|
|
1771
1866
|
const sessionEventSchema = z.discriminatedUnion("kind", [
|
|
1772
1867
|
z.object({
|
|
1773
1868
|
kind: z.literal("tool_call"),
|
|
@@ -1788,6 +1883,10 @@ const sessionEventSchema = z.discriminatedUnion("kind", [
|
|
|
1788
1883
|
z.object({
|
|
1789
1884
|
kind: z.literal("turn_end"),
|
|
1790
1885
|
payload: turnEndEventPayload
|
|
1886
|
+
}),
|
|
1887
|
+
z.object({
|
|
1888
|
+
kind: z.literal("context_tree_usage"),
|
|
1889
|
+
payload: contextTreeUsageEventPayload
|
|
1791
1890
|
})
|
|
1792
1891
|
]);
|
|
1793
1892
|
z.object({
|
|
@@ -1801,7 +1900,8 @@ z.object({
|
|
|
1801
1900
|
errorEventPayload,
|
|
1802
1901
|
assistantTextEventPayload,
|
|
1803
1902
|
thinkingEventPayload,
|
|
1804
|
-
turnEndEventPayload
|
|
1903
|
+
turnEndEventPayload,
|
|
1904
|
+
contextTreeUsageEventPayload
|
|
1805
1905
|
]),
|
|
1806
1906
|
createdAt: z.string()
|
|
1807
1907
|
});
|
|
@@ -1878,4 +1978,4 @@ z.object({
|
|
|
1878
1978
|
capabilities: serverCapabilitiesSchema.optional()
|
|
1879
1979
|
}).passthrough();
|
|
1880
1980
|
//#endregion
|
|
1881
|
-
export {
|
|
1981
|
+
export { listMeChatSourceCountsQuerySchema as $, createMeChatSchema as A, updateOrganizationSchema as At, githubAppInstallationClaimBodySchema as B, clientRegisterSchema as C, submitQuestionAnswerSchema as Ct, createAdapterMappingSchema as D, updateChatSchema as Dt, createAdapterConfigSchema as E, updateAgentSchema as Et, delegateFeishuUserSchema as F, imageInlineContentSchema as G, githubCallbackQuerySchema as H, dryRunAgentRuntimeConfigSchema as I, inboxPollQuerySchema as J, inboxAckFrameSchema as K, extractMentions as L, createOrgFromMeSchema as M, defaultParticipantMode as N, createAgentSchema as O, updateClientCapabilitiesSchema as Ot, defaultRuntimeConfigPayload as P, joinByInvitationSchema as Q, getMeDocResponseSchema as R, clientCapabilitiesSchema as S, stripCode as St, contextTreeSnapshotSchema as T, updateAgentRuntimeConfigSchema as Tt, githubDevCallbackQuerySchema as U, githubAppInstallationPermissionsSchema as V, githubStartQuerySchema as W, isRedactedEnvValue as X, isOrgSettingNamespace as Y, isReservedAgentName as Z, agentBindRequestSchema as _, sendToAgentSchema as _t, AGENT_TYPES as a, paginationQuerySchema as at, agentTypeSchema as b, sessionReconcileRequestSchema as bt, DEFAULT_RUNTIME_PROVIDER as c, questionAnswerMessageContentSchema as ct, MENTION_REGEX as d, refreshTokenSchema as dt, listMeChatsQuerySchema as et, NOTIFICATION_TYPES as f, runtimeStateMessageSchema as ft, addParticipantSchema as g, sendMessageSchema as gt, addMeChatParticipantsSchema as h, selfServiceFeishuBotSchema as ht, AGENT_STATUSES as i, onboardingEventSchema as it, createMemberSchema as j, wsAuthFrameSchema as jt, createChatSchema as k, updateMemberSchema as kt, GITHUB_ENTITY_TYPES as l, questionMessageContentSchema as lt, WS_AUTH_FRAME_TIMEOUT_MS as m, scanMentionTokens as mt, AGENT_NAME_REGEX as n, messageSourceSchema as nt, AGENT_VISIBILITY as o, patchChatEngagementSchema as ot, ORG_SETTINGS_NAMESPACES as p, safeRedirectPath as pt, inboxDeliverFrameSchema as q, AGENT_SELECTOR_HEADER as r, notificationQuerySchema as rt, CHAT_ENGAGEMENT_STATUSES as s, patchOnboardingSchema as st, AGENT_BIND_REJECT_REASONS as t, loginSchema as tt, LIVE_ACTIVITY_STALE_MS as u, rebindAgentSchema as ut, agentPinnedMessageSchema as v, sessionEventMessageSchema as vt, connectTokenExchangeSchema as w, updateAdapterConfigSchema as wt, chatMetadataSchema as x, sessionStateMessageSchema as xt, agentRuntimeConfigPayloadSchema as y, sessionEventSchema as yt, getMeDocSchema as z };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
-- Add avatar_color_token to agents.
|
|
2
|
+
--
|
|
3
|
+
-- Manager-selected avatar fill color override for the web client. One of
|
|
4
|
+
-- "hue-0".."hue-7", matching the `--avatar-hue-*` CSS tokens in
|
|
5
|
+
-- `packages/web/src/index.css`. NULL means "auto" — the renderer falls
|
|
6
|
+
-- back to the deterministic djb2 hash of `uuid` (the previous default).
|
|
7
|
+
--
|
|
8
|
+
-- Nullable, no default, no backfill: existing rows continue to render the
|
|
9
|
+
-- hashed color until their manager picks something explicit. This is a
|
|
10
|
+
-- pure additive change; no NOT NULL constraint, no enum, no FK.
|
|
11
|
+
ALTER TABLE "agents" ADD COLUMN "avatar_color_token" text;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
-- Add inline avatar image storage to agents.
|
|
2
|
+
--
|
|
3
|
+
-- The PRD chose PG bytea over object storage for the first cut: clients
|
|
4
|
+
-- always pre-resize to 256×256 WEBP (typically < 50 KB), and a few KB ×
|
|
5
|
+
-- N agents per org sits well within row-size budgets. Switching to S3/R2
|
|
6
|
+
-- later is a follow-up migration; the column shape stays the same except
|
|
7
|
+
-- avatar_image_data flips to NULL and avatar_image_url moves to a real
|
|
8
|
+
-- external URL.
|
|
9
|
+
--
|
|
10
|
+
-- All three columns are nullable and move together — either all three
|
|
11
|
+
-- carry an image (data + mime + updated_at) or all are NULL. The service
|
|
12
|
+
-- layer enforces that invariant on writes; SQL keeps it loose so a partial
|
|
13
|
+
-- backfill / restore doesn't break inserts.
|
|
14
|
+
ALTER TABLE "agents"
|
|
15
|
+
ADD COLUMN "avatar_image_data" bytea,
|
|
16
|
+
ADD COLUMN "avatar_image_mime" text,
|
|
17
|
+
ADD COLUMN "avatar_image_updated_at" timestamp with time zone;
|
|
@@ -309,6 +309,20 @@
|
|
|
309
309
|
"when": 1779494400000,
|
|
310
310
|
"tag": "0043_onboarding_completed_at",
|
|
311
311
|
"breakpoints": true
|
|
312
|
+
},
|
|
313
|
+
{
|
|
314
|
+
"idx": 44,
|
|
315
|
+
"version": "7",
|
|
316
|
+
"when": 1779580800000,
|
|
317
|
+
"tag": "0044_agent_avatar_color",
|
|
318
|
+
"breakpoints": true
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
"idx": 45,
|
|
322
|
+
"version": "7",
|
|
323
|
+
"when": 1779667200000,
|
|
324
|
+
"tag": "0045_agent_avatar_image",
|
|
325
|
+
"breakpoints": true
|
|
312
326
|
}
|
|
313
327
|
]
|
|
314
328
|
}
|
|
@@ -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-1XGLJMOq.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-BBRxjmBS.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-C15ZBOCC.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-1XGLJMOq.mjs";
|
|
7
|
+
import { n as bindFeishuUser, t as bindFeishuBot } from "./feishu-BGx71p5s.mjs";
|
|
8
8
|
import "./errors-LPcARA4K-Dbrptiyz.mjs";
|
|
9
9
|
import "./src-DNBS5Yjj.mjs";
|
|
10
|
-
import "./client-
|
|
10
|
+
import "./client-CzXmweS9-DhUiuQvL.mjs";
|
|
11
11
|
import "./invitation-DZO4NX3P-BPxTeHf-.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 };
|