@agent-team-foundation/first-tree-hub 0.12.3 → 0.12.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/cli/index.mjs +4 -4
- package/dist/{client-0RrgrMjR-DPyuu6Ls.mjs → client-0RrgrMjR-CylTJGEb.mjs} +2 -2
- package/dist/{client-D1TDiik_-gxtXN9bj.mjs → client-D1TDiik_-NV_lkhfI.mjs} +1 -1
- package/dist/{dist-DHHd2dar.mjs → dist-CMhywpXB.mjs} +2 -141
- package/dist/drizzle/0035_drop_hub_tasks.sql +7 -0
- package/dist/drizzle/meta/_journal.json +7 -0
- package/dist/{feishu-fLnwqCOs.mjs → feishu-tkZS0vvL.mjs} +1 -1
- package/dist/index.mjs +4 -4
- package/dist/{invitation-C299fxkP-B89eqDos.mjs → invitation-C299fxkP-CZRV665C.mjs} +1 -1
- package/dist/{saas-connect-_lNV0Liy.mjs → saas-connect-S71rG182.mjs} +142 -709
- package/dist/web/assets/index-BG9RRx2e.js +401 -0
- package/dist/web/assets/index-CbOOQaWp.css +1 -0
- package/dist/web/assets/{index-DcMORzyx.js → index-RNegidl2.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/dist/web/assets/index-B4EaL8S9.css +0 -1
- package/dist/web/assets/index-CJr7zpx-.js +0 -401
|
@@ -2,10 +2,10 @@ import { a as __toCommonJS, o as __toESM, t as __commonJSMin } from "./chunk-BSw
|
|
|
2
2
|
import { A as FIRST_TREE_HUB_ATTR, C as stampOrgScope, D as untrustedAttrs, E as startWsConnectionSpan, M as require_pino, O as withSpan, S as stampChatResource, _ as rootLogger$1, a as buildRateLimitError, c as currentTraceId, g as reportErrorToRoot, i as bodyCaptureOnSendHook, j as redactUrl, k as withWsMessageSpan, l as decodeJwtForTrace, m as observabilityPlugin, n as applyLoggerConfig, o as classifyJoseError, r as attachRequestContext, s as createLogger$1, t as adapterAttrs, u as endWsConnectionSpan, x as stampAgentResource, y as setWsConnectionAttrs } from "./observability-BAScT_5S-BcW9HgkG.mjs";
|
|
3
3
|
import { C as resetConfigMeta, E as setConfigValue, S as resetConfig, T as serverConfigSchema, b as migrateLegacyHome, c as resolveServerUrl, d as DEFAULT_CONFIG_DIR, f as DEFAULT_DATA_DIR$1, g as collectMissingPrompts, h as clientConfigSchema, i as ensureFreshAccessToken, l as saveAgentConfig, m as agentConfigSchema, o as loadCredentials, p as DEFAULT_HOME_DIR$1, u as saveCredentials, v as initConfig, w as resolveConfigReadonly, y as loadAgents } from "./bootstrap-C_K2CKXC.mjs";
|
|
4
4
|
import { a as print, i as blank, n as CLI_USER_AGENT, r as COMMAND_VERSION, s as status, t as cliFetch } from "./cli-fetch--tiwKm5S.mjs";
|
|
5
|
-
import { $ as
|
|
5
|
+
import { $ as runtimeStateMessageSchema, B as isReservedAgentName$1, C as createChatSchema, D as defaultRuntimeConfigPayload, E as createOrgFromMeSchema, F as inboxAckFrameSchema, G as notificationQuerySchema, H as listMeChatsQuerySchema, I as inboxDeliverFrameSchema$1, J as patchOnboardingSchema, K as onboardingEventSchema, L as inboxPollQuerySchema, M as githubDevCallbackQuerySchema, N as githubStartQuerySchema, O as delegateFeishuUserSchema, P as imageInlineContentSchema, Q as refreshTokenSchema, R as isOrgSettingNamespace, S as createAgentSchema, T as createMemberSchema, U as loginSchema, V as joinByInvitationSchema, W as messageSourceSchema$1, Z as rebindAgentSchema, _ as clientRegisterSchema, _t as updateMemberSchema, a as AGENT_VISIBILITY, at as sessionCompletionMessageSchema, b as createAdapterConfigSchema, c as ORG_SETTINGS_NAMESPACES$1, ct as sessionReconcileRequestSchema, d as addParticipantSchema, dt as submitQuestionAnswerSchema, et as safeRedirectPath, f as agentBindRequestSchema, ft as updateAdapterConfigSchema, gt as updateClientCapabilitiesSchema, h as agentTypeSchema$1, ht as updateChatSchema, i as AGENT_STATUSES, it as sendToAgentSchema, j as githubCallbackQuerySchema, k as dryRunAgentRuntimeConfigSchema, l as WS_AUTH_FRAME_TIMEOUT_MS, lt as sessionStateMessageSchema, m as agentRuntimeConfigPayloadSchema$1, mt as updateAgentSchema, n as AGENT_NAME_REGEX$1, nt as selfServiceFeishuBotSchema, ot as sessionEventMessageSchema, p as agentPinnedMessageSchema$1, pt as updateAgentRuntimeConfigSchema, q as paginationQuerySchema, r as AGENT_SELECTOR_HEADER$1, rt as sendMessageSchema, s as MENTION_REGEX, st as sessionEventSchema$1, t as AGENT_BIND_REJECT_REASONS, u as addMeChatParticipantsSchema, ut as stripCode, v as connectTokenExchangeSchema, vt as updateOrganizationSchema, w as createMeChatSchema, x as createAdapterMappingSchema, y as contextTreeSnapshotSchema, yt as wsAuthFrameSchema, z as isRedactedEnvValue } from "./dist-CMhywpXB.mjs";
|
|
6
6
|
import { a as ConflictError, c as UnauthorizedError, i as ClientUserMismatchError$1, l as organizations, n as BadRequestError, o as ForbiddenError, r as ClientOrgMismatchError$1, s as NotFoundError, t as AppError, u as users } from "./errors-CF5evtJt-B0NTIVPt.mjs";
|
|
7
7
|
import { n as init_esm, r as trace, t as esm_exports } from "./esm-iadMkGbV.mjs";
|
|
8
|
-
import { $ as pendingQuestions, A as heartbeatClient, B as listAgentsWithRuntime, C as findOrCreateDirectChat, D as getClient, E as getChatDetail, F as joinChat, G as listClientsForOrgAdmin, H as listChats, I as leaveAsParticipant, J as markStaleAgents, K as listMessages, L as leaveChat, M as inboxEntries, N as invalidateChatAudience, O as getOnlineCount, P as joinAsParticipant, Q as notifyRecipients, R as listActiveAgentsPinnedToClient, S as ensureParticipant$1, T as getCachedAudience, U as listChatsForMember, V as listChatParticipantsWithNames, W as listClients, X as members, Y as markSupersededByChat, Z as messages, _ as createNotifier, _t as updateClientCapabilities, a as agents, at as removeParticipant, b as editMessage, c as bindAgent, ct as retireClient, d as chats, dt as serverInstances, et as recomputeChatWatchers, f as claimClient, ft as setOffline, g as createChat, gt as unbindAgent, h as clients, ht as touchAgent, i as agentVisibilityCondition, it as registerClient, j as heartbeatInstance, k as getPresence, l as chatParticipants, lt as sendMessage, m as cleanupStalePresence, mt as submitAnswer, n as agentChatSessions, nt as recomputeWatchersForMember, o as assertClientOwner, ot as resetActivity, p as cleanupStaleClients, pt as setRuntimeState, r as agentPresence, rt as registerChatMessageDispatcher, s as assertParticipant, st as resolveChatMembership, t as addParticipant, tt as recomputeWatchersForAgent, u as chatSubscriptions, ut as sendToAgent$1, v as deriveAuthState, vt as upsertSessionState, w as getActivityOverview, x as ensureCanJoin, y as disconnectClient, z as listAgentsManagedByUser } from "./client-D1TDiik_-
|
|
8
|
+
import { $ as pendingQuestions, A as heartbeatClient, B as listAgentsWithRuntime, C as findOrCreateDirectChat, D as getClient, E as getChatDetail, F as joinChat, G as listClientsForOrgAdmin, H as listChats, I as leaveAsParticipant, J as markStaleAgents, K as listMessages, L as leaveChat, M as inboxEntries, N as invalidateChatAudience, O as getOnlineCount, P as joinAsParticipant, Q as notifyRecipients, R as listActiveAgentsPinnedToClient, S as ensureParticipant$1, T as getCachedAudience, U as listChatsForMember, V as listChatParticipantsWithNames, W as listClients, X as members, Y as markSupersededByChat, Z as messages, _ as createNotifier, _t as updateClientCapabilities, a as agents, at as removeParticipant, b as editMessage, c as bindAgent, ct as retireClient, d as chats, dt as serverInstances, et as recomputeChatWatchers, f as claimClient, ft as setOffline, g as createChat, gt as unbindAgent, h as clients, ht as touchAgent, i as agentVisibilityCondition, it as registerClient, j as heartbeatInstance, k as getPresence, l as chatParticipants, lt as sendMessage, m as cleanupStalePresence, mt as submitAnswer, n as agentChatSessions, nt as recomputeWatchersForMember, o as assertClientOwner, ot as resetActivity, p as cleanupStaleClients, pt as setRuntimeState, r as agentPresence, rt as registerChatMessageDispatcher, s as assertParticipant, st as resolveChatMembership, t as addParticipant, tt as recomputeWatchersForAgent, u as chatSubscriptions, ut as sendToAgent$1, v as deriveAuthState, vt as upsertSessionState, w as getActivityOverview, x as ensureCanJoin, y as disconnectClient, z as listAgentsManagedByUser } from "./client-D1TDiik_-NV_lkhfI.mjs";
|
|
9
9
|
import { a as invitationRedemptions, c as recordRedemption, i as getActiveInvitation, l as rotateInvitation, n as ensureActiveInvitation, o as invitations, r as findActiveByToken, t as buildInviteUrl, u as uuidv7 } from "./invitation-Bg0TRiyx-BsZH4GCS.mjs";
|
|
10
10
|
import { createRequire } from "node:module";
|
|
11
11
|
import { ZodError, z } from "zod";
|
|
@@ -1015,7 +1015,6 @@ const messageFormatSchema = z.enum([
|
|
|
1015
1015
|
"card",
|
|
1016
1016
|
"reference",
|
|
1017
1017
|
"file",
|
|
1018
|
-
"task",
|
|
1019
1018
|
"question",
|
|
1020
1019
|
"question_answer"
|
|
1021
1020
|
]);
|
|
@@ -1199,9 +1198,7 @@ const meChatRowSchema = z.object({
|
|
|
1199
1198
|
lastMessageAt: z.string().nullable(),
|
|
1200
1199
|
lastMessagePreview: z.string().nullable(),
|
|
1201
1200
|
unreadMentionCount: z.number().int(),
|
|
1202
|
-
canReply: z.boolean()
|
|
1203
|
-
taskId: z.string().nullable(),
|
|
1204
|
-
taskStatus: z.string().nullable()
|
|
1201
|
+
canReply: z.boolean()
|
|
1205
1202
|
});
|
|
1206
1203
|
z.object({
|
|
1207
1204
|
rows: z.array(meChatRowSchema),
|
|
@@ -1677,94 +1674,6 @@ z.object({
|
|
|
1677
1674
|
totalMessages: z.number(),
|
|
1678
1675
|
byOrganization: z.array(orgStatsSchema)
|
|
1679
1676
|
});
|
|
1680
|
-
const taskStatusSchema = z.enum([
|
|
1681
|
-
"pending",
|
|
1682
|
-
"assigned",
|
|
1683
|
-
"working",
|
|
1684
|
-
"completed",
|
|
1685
|
-
"failed",
|
|
1686
|
-
"cancelled"
|
|
1687
|
-
]);
|
|
1688
|
-
const taskCreatorTypeSchema = z.enum(["agent", "admin"]);
|
|
1689
|
-
const taskMessageEventSchema = z.enum([
|
|
1690
|
-
"assigned",
|
|
1691
|
-
"status_changed",
|
|
1692
|
-
"cancelled"
|
|
1693
|
-
]);
|
|
1694
|
-
z.object({
|
|
1695
|
-
taskId: z.string(),
|
|
1696
|
-
event: taskMessageEventSchema,
|
|
1697
|
-
title: z.string(),
|
|
1698
|
-
body: z.string().default(""),
|
|
1699
|
-
status: taskStatusSchema,
|
|
1700
|
-
fromStatus: taskStatusSchema.optional(),
|
|
1701
|
-
originRef: z.string().nullable().optional()
|
|
1702
|
-
});
|
|
1703
|
-
z.object({
|
|
1704
|
-
title: z.string().min(1).max(500),
|
|
1705
|
-
body: z.string().optional(),
|
|
1706
|
-
assigneeAgentId: z.string().optional(),
|
|
1707
|
-
originRef: z.string().max(500).optional(),
|
|
1708
|
-
metadata: z.record(z.string(), z.unknown()).optional()
|
|
1709
|
-
}).extend({ organizationId: z.string().optional() });
|
|
1710
|
-
z.object({
|
|
1711
|
-
status: z.enum([
|
|
1712
|
-
"working",
|
|
1713
|
-
"completed",
|
|
1714
|
-
"failed"
|
|
1715
|
-
]),
|
|
1716
|
-
result: z.string().optional()
|
|
1717
|
-
});
|
|
1718
|
-
z.object({
|
|
1719
|
-
assigneeAgentId: z.string().nullable().optional(),
|
|
1720
|
-
status: taskStatusSchema.optional(),
|
|
1721
|
-
result: z.string().optional()
|
|
1722
|
-
});
|
|
1723
|
-
z.object({ chatId: z.string().min(1) });
|
|
1724
|
-
const taskSchema = z.object({
|
|
1725
|
-
id: z.string(),
|
|
1726
|
-
organizationId: z.string(),
|
|
1727
|
-
title: z.string(),
|
|
1728
|
-
body: z.string(),
|
|
1729
|
-
status: taskStatusSchema,
|
|
1730
|
-
assigneeAgentId: z.string().nullable(),
|
|
1731
|
-
createdByType: taskCreatorTypeSchema,
|
|
1732
|
-
createdById: z.string(),
|
|
1733
|
-
originRef: z.string().nullable(),
|
|
1734
|
-
result: z.string().nullable(),
|
|
1735
|
-
metadata: z.record(z.string(), z.unknown()),
|
|
1736
|
-
createdAt: z.string(),
|
|
1737
|
-
updatedAt: z.string(),
|
|
1738
|
-
cancelledAt: z.string().nullable(),
|
|
1739
|
-
cancelledByType: taskCreatorTypeSchema.nullable(),
|
|
1740
|
-
cancelledById: z.string().nullable()
|
|
1741
|
-
});
|
|
1742
|
-
const taskChatLinkSchema = z.object({
|
|
1743
|
-
taskId: z.string(),
|
|
1744
|
-
chatId: z.string(),
|
|
1745
|
-
linkedByAgentId: z.string().nullable(),
|
|
1746
|
-
linkedAt: z.string()
|
|
1747
|
-
});
|
|
1748
|
-
taskSchema.extend({ chats: z.array(taskChatLinkSchema) });
|
|
1749
|
-
z.object({
|
|
1750
|
-
status: taskStatusSchema.optional(),
|
|
1751
|
-
assigneeAgentId: z.string().optional(),
|
|
1752
|
-
originRef: z.string().optional(),
|
|
1753
|
-
limit: z.coerce.number().int().min(1).max(100).default(20),
|
|
1754
|
-
cursor: z.string().optional()
|
|
1755
|
-
});
|
|
1756
|
-
const taskHealthSignalSchema = z.enum([
|
|
1757
|
-
"normal",
|
|
1758
|
-
"idle_island",
|
|
1759
|
-
"awaiting_reply",
|
|
1760
|
-
"no_chat",
|
|
1761
|
-
"not_applicable"
|
|
1762
|
-
]);
|
|
1763
|
-
z.object({
|
|
1764
|
-
taskId: z.string(),
|
|
1765
|
-
signal: taskHealthSignalSchema,
|
|
1766
|
-
reason: z.string()
|
|
1767
|
-
});
|
|
1768
1677
|
const userStatusSchema = z.enum(["active", "suspended"]);
|
|
1769
1678
|
z.object({
|
|
1770
1679
|
id: z.string(),
|
|
@@ -2876,7 +2785,126 @@ function getHandlerFactory(type) {
|
|
|
2876
2785
|
}
|
|
2877
2786
|
return factory;
|
|
2878
2787
|
}
|
|
2879
|
-
join(DEFAULT_DATA_DIR, "context-tree");
|
|
2788
|
+
const CONTEXT_TREE_DIR = join(DEFAULT_DATA_DIR, "context-tree");
|
|
2789
|
+
/**
|
|
2790
|
+
* Sync the shared Context Tree git clone.
|
|
2791
|
+
*
|
|
2792
|
+
* Clones on first run, pulls on subsequent runs.
|
|
2793
|
+
* Returns the binding on success, null on failure (graceful degradation).
|
|
2794
|
+
*/
|
|
2795
|
+
async function syncContextTree(serverUrl, getAccessToken, log, userAgent) {
|
|
2796
|
+
try {
|
|
2797
|
+
execFileSync("git", ["--version"], { stdio: "ignore" });
|
|
2798
|
+
} catch {
|
|
2799
|
+
log("Context Tree sync skipped: git is not installed");
|
|
2800
|
+
return null;
|
|
2801
|
+
}
|
|
2802
|
+
let repo;
|
|
2803
|
+
let branch;
|
|
2804
|
+
try {
|
|
2805
|
+
const config = await new FirstTreeHubSDK({
|
|
2806
|
+
serverUrl,
|
|
2807
|
+
getAccessToken,
|
|
2808
|
+
userAgent
|
|
2809
|
+
}).getContextTreeConfig();
|
|
2810
|
+
if (!config.repo) {
|
|
2811
|
+
log("Context Tree sync skipped: not configured on server");
|
|
2812
|
+
return null;
|
|
2813
|
+
}
|
|
2814
|
+
repo = config.repo;
|
|
2815
|
+
branch = config.branch ?? "main";
|
|
2816
|
+
} catch (err) {
|
|
2817
|
+
log(`Context Tree sync skipped: failed to fetch config from server (${err instanceof Error ? err.message : String(err)})`);
|
|
2818
|
+
return null;
|
|
2819
|
+
}
|
|
2820
|
+
try {
|
|
2821
|
+
if (existsSync(join(CONTEXT_TREE_DIR, ".git"))) {
|
|
2822
|
+
if (execFileSync("git", [
|
|
2823
|
+
"rev-parse",
|
|
2824
|
+
"--abbrev-ref",
|
|
2825
|
+
"HEAD"
|
|
2826
|
+
], {
|
|
2827
|
+
cwd: CONTEXT_TREE_DIR,
|
|
2828
|
+
encoding: "utf-8",
|
|
2829
|
+
timeout: 5e3
|
|
2830
|
+
}).trim() !== branch) {
|
|
2831
|
+
execFileSync("git", ["checkout", branch], {
|
|
2832
|
+
cwd: CONTEXT_TREE_DIR,
|
|
2833
|
+
stdio: "pipe",
|
|
2834
|
+
timeout: 1e4
|
|
2835
|
+
});
|
|
2836
|
+
log(`Context Tree switched to branch ${branch}`);
|
|
2837
|
+
}
|
|
2838
|
+
execFileSync("git", ["pull", "--ff-only"], {
|
|
2839
|
+
cwd: CONTEXT_TREE_DIR,
|
|
2840
|
+
stdio: "pipe",
|
|
2841
|
+
timeout: 3e4
|
|
2842
|
+
});
|
|
2843
|
+
log(`Context Tree updated (pull)`);
|
|
2844
|
+
} else {
|
|
2845
|
+
mkdirSync(CONTEXT_TREE_DIR, { recursive: true });
|
|
2846
|
+
execFileSync("git", [
|
|
2847
|
+
"clone",
|
|
2848
|
+
"--branch",
|
|
2849
|
+
branch,
|
|
2850
|
+
"--single-branch",
|
|
2851
|
+
repo,
|
|
2852
|
+
CONTEXT_TREE_DIR
|
|
2853
|
+
], {
|
|
2854
|
+
stdio: "pipe",
|
|
2855
|
+
timeout: 6e4
|
|
2856
|
+
});
|
|
2857
|
+
log(`Context Tree cloned from ${repo} (branch: ${branch})`);
|
|
2858
|
+
}
|
|
2859
|
+
return {
|
|
2860
|
+
path: CONTEXT_TREE_DIR,
|
|
2861
|
+
repoUrl: repo,
|
|
2862
|
+
branch
|
|
2863
|
+
};
|
|
2864
|
+
} catch (err) {
|
|
2865
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2866
|
+
log(`Context Tree sync failed: ${msg}`);
|
|
2867
|
+
log("Check that git credentials (SSH key or credential helper) are configured for this repo");
|
|
2868
|
+
if ((msg.includes("cannot fast-forward") || msg.includes("not possible to fast-forward") || msg.includes("CONFLICT")) && existsSync(join(CONTEXT_TREE_DIR, ".git"))) {
|
|
2869
|
+
log("Diverged history detected, attempting fresh clone...");
|
|
2870
|
+
try {
|
|
2871
|
+
rmSync(CONTEXT_TREE_DIR, {
|
|
2872
|
+
recursive: true,
|
|
2873
|
+
force: true
|
|
2874
|
+
});
|
|
2875
|
+
mkdirSync(CONTEXT_TREE_DIR, { recursive: true });
|
|
2876
|
+
execFileSync("git", [
|
|
2877
|
+
"clone",
|
|
2878
|
+
"--branch",
|
|
2879
|
+
branch,
|
|
2880
|
+
"--single-branch",
|
|
2881
|
+
repo,
|
|
2882
|
+
CONTEXT_TREE_DIR
|
|
2883
|
+
], {
|
|
2884
|
+
stdio: "pipe",
|
|
2885
|
+
timeout: 6e4
|
|
2886
|
+
});
|
|
2887
|
+
log("Context Tree re-cloned successfully");
|
|
2888
|
+
return {
|
|
2889
|
+
path: CONTEXT_TREE_DIR,
|
|
2890
|
+
repoUrl: repo,
|
|
2891
|
+
branch
|
|
2892
|
+
};
|
|
2893
|
+
} catch {
|
|
2894
|
+
log("Context Tree re-clone also failed, continuing without context");
|
|
2895
|
+
}
|
|
2896
|
+
}
|
|
2897
|
+
if (existsSync(join(CONTEXT_TREE_DIR, ".git"))) {
|
|
2898
|
+
log("Using existing Context Tree clone despite sync failure");
|
|
2899
|
+
return {
|
|
2900
|
+
path: CONTEXT_TREE_DIR,
|
|
2901
|
+
repoUrl: repo,
|
|
2902
|
+
branch
|
|
2903
|
+
};
|
|
2904
|
+
}
|
|
2905
|
+
return null;
|
|
2906
|
+
}
|
|
2907
|
+
}
|
|
2880
2908
|
/**
|
|
2881
2909
|
* Marker file written into every workspace so the Codex CLI's project-root
|
|
2882
2910
|
* detection (configured via `project_root_markers: ["first-tree-workspace"]`)
|
|
@@ -7213,6 +7241,14 @@ var ClientRuntime = class {
|
|
|
7213
7241
|
watcher = null;
|
|
7214
7242
|
debounceTimer = null;
|
|
7215
7243
|
/**
|
|
7244
|
+
* Per-org Context Tree binding resolved at `start()`. Threaded through every
|
|
7245
|
+
* `slot.start()` so handlers can copy `AGENT.md` / root `NODE.md` into the
|
|
7246
|
+
* agent workspace's `.agent/context/` and install the first-tree skill.
|
|
7247
|
+
* `null` when the user has no primary org, the org has no tree configured,
|
|
7248
|
+
* or git sync failed — handlers degrade gracefully (empty context dir).
|
|
7249
|
+
*/
|
|
7250
|
+
contextTreeBinding = null;
|
|
7251
|
+
/**
|
|
7216
7252
|
* Directory we write auto-registered agent configs into (same path that
|
|
7217
7253
|
* `first-tree-hub agent add` uses). Set by `watchAgentsDir` so the
|
|
7218
7254
|
* `agent:pinned` handler knows where to materialise new configs.
|
|
@@ -7272,6 +7308,7 @@ var ClientRuntime = class {
|
|
|
7272
7308
|
this.agentIds.add(config.agentId);
|
|
7273
7309
|
}
|
|
7274
7310
|
async start() {
|
|
7311
|
+
this.contextTreeBinding = await syncContextTree(this.serverUrl, (opts) => ensureFreshAccessToken(opts), (msg) => print.status("[context-tree]", msg), CLI_USER_AGENT);
|
|
7275
7312
|
if (this.options.currentVersion && this.options.update) this.updateManager = UpdateManager.attach(this.connection, {
|
|
7276
7313
|
currentVersion: this.options.currentVersion,
|
|
7277
7314
|
...this.options.update,
|
|
@@ -7290,7 +7327,7 @@ var ClientRuntime = class {
|
|
|
7290
7327
|
}
|
|
7291
7328
|
await Promise.allSettled(this.agents.map(async (agent) => {
|
|
7292
7329
|
try {
|
|
7293
|
-
const identity = await agent.slot.start();
|
|
7330
|
+
const identity = await agent.slot.start(this.contextTreeBinding);
|
|
7294
7331
|
print.check(true, `${agent.name}: connected`, `agent: ${identity.displayName ?? identity.agentId}`);
|
|
7295
7332
|
} catch (error) {
|
|
7296
7333
|
const msg = error instanceof Error ? error.message : String(error);
|
|
@@ -7417,7 +7454,7 @@ var ClientRuntime = class {
|
|
|
7417
7454
|
startAgent(name) {
|
|
7418
7455
|
const entry = this.agents.find((a) => a.name === name);
|
|
7419
7456
|
if (!entry) return;
|
|
7420
|
-
entry.slot.start().then((identity) => {
|
|
7457
|
+
entry.slot.start(this.contextTreeBinding).then((identity) => {
|
|
7421
7458
|
print.check(true, `${name}: connected`, `agent: ${identity.displayName ?? identity.agentId}`);
|
|
7422
7459
|
}).catch((err) => {
|
|
7423
7460
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -9054,7 +9091,7 @@ async function onboardCreate(args) {
|
|
|
9054
9091
|
}
|
|
9055
9092
|
const runtimeAgent = args.type === "human" ? args.assistant : args.id;
|
|
9056
9093
|
if (args.feishuBotAppId && args.feishuBotAppSecret) {
|
|
9057
|
-
const { bindFeishuBot } = await import("./feishu-
|
|
9094
|
+
const { bindFeishuBot } = await import("./feishu-tkZS0vvL.mjs").then((n) => n.r);
|
|
9058
9095
|
const targetAgentUuid = args.type === "human" ? assistantUuid : primary.uuid;
|
|
9059
9096
|
if (!targetAgentUuid) print.line(`Warning: Cannot bind Feishu bot — no runtime agent available for "${args.id}".\n`);
|
|
9060
9097
|
else {
|
|
@@ -10267,7 +10304,7 @@ function createFeedbackHandler(config) {
|
|
|
10267
10304
|
return { handle };
|
|
10268
10305
|
}
|
|
10269
10306
|
//#endregion
|
|
10270
|
-
//#region ../server/dist/app-
|
|
10307
|
+
//#region ../server/dist/app-D4vCx0C0.mjs
|
|
10271
10308
|
var import_fastify_opentelemetry = /* @__PURE__ */ __toESM(require_fastify_opentelemetry(), 1);
|
|
10272
10309
|
init_esm();
|
|
10273
10310
|
var __defProp = Object.defineProperty;
|
|
@@ -10292,50 +10329,6 @@ const adapterAgentMappings = pgTable("adapter_agent_mappings", {
|
|
|
10292
10329
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow()
|
|
10293
10330
|
}, (table) => [unique("uq_adapter_agent_mapping").on(table.platform, table.externalUserId)]);
|
|
10294
10331
|
/**
|
|
10295
|
-
* Tasks — lightweight work units. Process descriptors, not tickets.
|
|
10296
|
-
* Immutable status state machine: pending → assigned → working → (completed | failed | cancelled).
|
|
10297
|
-
* Sub-tasks (parent_task_id) are deferred to a later phase.
|
|
10298
|
-
*
|
|
10299
|
-
* Referential integrity (org / assignee / chat) is enforced at the service layer,
|
|
10300
|
-
* not via DB foreign keys — see `services/task.ts`.
|
|
10301
|
-
*/
|
|
10302
|
-
const tasks = pgTable("tasks", {
|
|
10303
|
-
id: text("id").primaryKey(),
|
|
10304
|
-
organizationId: text("organization_id").notNull(),
|
|
10305
|
-
title: text("title").notNull(),
|
|
10306
|
-
body: text("body").notNull().default(""),
|
|
10307
|
-
status: text("status").$type().notNull(),
|
|
10308
|
-
assigneeAgentId: text("assignee_agent_id"),
|
|
10309
|
-
createdByType: text("created_by_type").$type().notNull(),
|
|
10310
|
-
createdById: text("created_by_id").notNull(),
|
|
10311
|
-
originRef: text("origin_ref"),
|
|
10312
|
-
result: text("result"),
|
|
10313
|
-
metadata: jsonb("metadata").$type().notNull().default({}),
|
|
10314
|
-
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
10315
|
-
updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
|
|
10316
|
-
cancelledAt: timestamp("cancelled_at", { withTimezone: true }),
|
|
10317
|
-
cancelledByType: text("cancelled_by_type").$type(),
|
|
10318
|
-
cancelledById: text("cancelled_by_id")
|
|
10319
|
-
}, (table) => [
|
|
10320
|
-
index("idx_tasks_org_status").on(table.organizationId, table.status),
|
|
10321
|
-
index("idx_tasks_assignee_status").on(table.assigneeAgentId, table.status),
|
|
10322
|
-
index("idx_tasks_origin_ref").on(table.originRef),
|
|
10323
|
-
index("idx_tasks_org_created_at").on(table.organizationId, table.createdAt)
|
|
10324
|
-
]);
|
|
10325
|
-
/**
|
|
10326
|
-
* Task ↔ Chat association (M:N). A task may be executed across multiple chats;
|
|
10327
|
-
* a chat may host work for multiple tasks over its lifetime.
|
|
10328
|
-
*
|
|
10329
|
-
* No FK constraints — when a task or chat is deleted, the service layer is
|
|
10330
|
-
* responsible for deleting linked rows here first.
|
|
10331
|
-
*/
|
|
10332
|
-
const taskChats = pgTable("task_chats", {
|
|
10333
|
-
taskId: text("task_id").notNull(),
|
|
10334
|
-
chatId: text("chat_id").notNull(),
|
|
10335
|
-
linkedByAgentId: text("linked_by_agent_id"),
|
|
10336
|
-
linkedAt: timestamp("linked_at", { withTimezone: true }).notNull().defaultNow()
|
|
10337
|
-
}, (table) => [primaryKey({ columns: [table.taskId, table.chatId] }), index("idx_task_chats_chat").on(table.chatId)]);
|
|
10338
|
-
/**
|
|
10339
10332
|
* Pull the JWT-verified `UserScope` off the request. The `userAuthHook`
|
|
10340
10333
|
* middleware populates `request.user` synchronously before any handler
|
|
10341
10334
|
* runs; this helper just narrows the optional and throws a clean 401 if
|
|
@@ -10470,31 +10463,6 @@ async function assertAgentManageableByUser(db, userId, agentUuid) {
|
|
|
10470
10463
|
return scope;
|
|
10471
10464
|
}
|
|
10472
10465
|
/**
|
|
10473
|
-
* Gate access to a task. Allowed for any active member of the task's org —
|
|
10474
|
-
* mirrors the original inline gate in `api/tasks.ts` that this helper
|
|
10475
|
-
* replaces. Returns both the task's org row and the caller's resolved
|
|
10476
|
-
* `OrgScope`, so handlers can read `scope.memberId` for audit fields.
|
|
10477
|
-
*/
|
|
10478
|
-
async function requireTaskAccess(request, db) {
|
|
10479
|
-
const { userId } = requireUser(request);
|
|
10480
|
-
const { taskId } = request.params;
|
|
10481
|
-
const [task] = await db.select({ organizationId: tasks.organizationId }).from(tasks).where(eq(tasks.id, taskId)).limit(1);
|
|
10482
|
-
if (!task) throw new NotFoundError(`Task "${taskId}" not found`);
|
|
10483
|
-
const caller = await resolveCallerInOrg(db, userId, task.organizationId);
|
|
10484
|
-
const scope = {
|
|
10485
|
-
userId,
|
|
10486
|
-
organizationId: task.organizationId,
|
|
10487
|
-
memberId: caller.memberId,
|
|
10488
|
-
role: caller.role,
|
|
10489
|
-
humanAgentId: caller.humanAgentId
|
|
10490
|
-
};
|
|
10491
|
-
stampOrgScope(request, scope);
|
|
10492
|
-
return {
|
|
10493
|
-
task,
|
|
10494
|
-
scope
|
|
10495
|
-
};
|
|
10496
|
-
}
|
|
10497
|
-
/**
|
|
10498
10466
|
* Assert every agent in `agentIds` is visible to `scope` and lives in
|
|
10499
10467
|
* `scope.organizationId`. Used by chat-create to keep visibility rules out of
|
|
10500
10468
|
* the service layer's signature.
|
|
@@ -10930,10 +10898,9 @@ async function ensureDefaultOrganization(db) {
|
|
|
10930
10898
|
return org ?? existing;
|
|
10931
10899
|
}
|
|
10932
10900
|
/**
|
|
10933
|
-
* Names beginning with `__` are reserved for Hub-internal pseudo agents
|
|
10934
|
-
*
|
|
10935
|
-
*
|
|
10936
|
-
* real account.
|
|
10901
|
+
* Names beginning with `__` are reserved for Hub-internal pseudo agents.
|
|
10902
|
+
* User-facing creation must not be able to squat on them, otherwise
|
|
10903
|
+
* internal traffic could be routed through a real account.
|
|
10937
10904
|
*/
|
|
10938
10905
|
const RESERVED_AGENT_NAME_PREFIX = "__";
|
|
10939
10906
|
/**
|
|
@@ -12143,462 +12110,6 @@ async function agentSendToAgentRoutes(app) {
|
|
|
12143
12110
|
});
|
|
12144
12111
|
});
|
|
12145
12112
|
}
|
|
12146
|
-
/** Legal status transitions. Service enforces; API maps violations to 400. */
|
|
12147
|
-
const STATUS_TRANSITIONS = {
|
|
12148
|
-
pending: ["assigned", "cancelled"],
|
|
12149
|
-
assigned: ["working", "cancelled"],
|
|
12150
|
-
working: [
|
|
12151
|
-
"completed",
|
|
12152
|
-
"failed",
|
|
12153
|
-
"cancelled"
|
|
12154
|
-
],
|
|
12155
|
-
completed: [],
|
|
12156
|
-
failed: [],
|
|
12157
|
-
cancelled: []
|
|
12158
|
-
};
|
|
12159
|
-
function isLegalTransition(from, to) {
|
|
12160
|
-
return STATUS_TRANSITIONS[from]?.includes(to) ?? false;
|
|
12161
|
-
}
|
|
12162
|
-
function isTerminal(status) {
|
|
12163
|
-
return TASK_TERMINAL_STATUSES.includes(status);
|
|
12164
|
-
}
|
|
12165
|
-
/**
|
|
12166
|
-
* Reserved name for the hub-owned task notifier pseudo agent. The `__` prefix
|
|
12167
|
-
* is rejected by `createAgent`, so real users cannot squat on this identity.
|
|
12168
|
-
*/
|
|
12169
|
-
const SYSTEM_TASKS_AGENT_NAME = "__hub_system_tasks";
|
|
12170
|
-
/**
|
|
12171
|
-
* Ensure a task-notifier pseudo agent exists in the given organization and
|
|
12172
|
-
* return its UUID. Used as the sender for task notification messages so they
|
|
12173
|
-
* flow through the normal chat/inbox pipeline. Idempotent under concurrent
|
|
12174
|
-
* creation via the unique `(organization_id, name)` constraint.
|
|
12175
|
-
*/
|
|
12176
|
-
async function ensureSystemTasksAgent(db, organizationId) {
|
|
12177
|
-
const [existing] = await db.select({ uuid: agents.uuid }).from(agents).where(and(eq(agents.organizationId, organizationId), eq(agents.name, SYSTEM_TASKS_AGENT_NAME), ne(agents.status, AGENT_STATUSES.DELETED))).limit(1);
|
|
12178
|
-
if (existing) return existing.uuid;
|
|
12179
|
-
const uuid = uuidv7();
|
|
12180
|
-
const inboxId = `inbox_${uuid}`;
|
|
12181
|
-
const [adminMember] = await db.select({ id: members.id }).from(members).where(and(eq(members.organizationId, organizationId), eq(members.role, "admin"))).orderBy(asc(members.createdAt)).limit(1);
|
|
12182
|
-
if (!adminMember) throw new ConflictError(`Cannot create system tasks agent in organization "${organizationId}" — no admin member exists.`);
|
|
12183
|
-
try {
|
|
12184
|
-
const [created] = await db.insert(agents).values({
|
|
12185
|
-
uuid,
|
|
12186
|
-
name: SYSTEM_TASKS_AGENT_NAME,
|
|
12187
|
-
organizationId,
|
|
12188
|
-
type: AGENT_TYPES.AUTONOMOUS_AGENT,
|
|
12189
|
-
displayName: "System · Tasks",
|
|
12190
|
-
inboxId,
|
|
12191
|
-
status: AGENT_STATUSES.ACTIVE,
|
|
12192
|
-
source: AGENT_SOURCES.ADMIN_API,
|
|
12193
|
-
metadata: {
|
|
12194
|
-
system: true,
|
|
12195
|
-
role: "task-notifier"
|
|
12196
|
-
},
|
|
12197
|
-
managerId: adminMember.id
|
|
12198
|
-
}).returning({ uuid: agents.uuid });
|
|
12199
|
-
if (created) return created.uuid;
|
|
12200
|
-
} catch (err) {
|
|
12201
|
-
if ((err?.code ?? err?.cause?.code ?? "") !== "23505") throw err;
|
|
12202
|
-
}
|
|
12203
|
-
const [row] = await db.select({ uuid: agents.uuid }).from(agents).where(and(eq(agents.organizationId, organizationId), eq(agents.name, SYSTEM_TASKS_AGENT_NAME))).limit(1);
|
|
12204
|
-
if (!row) throw new Error("ensureSystemTasksAgent: agent missing after conflict");
|
|
12205
|
-
return row.uuid;
|
|
12206
|
-
}
|
|
12207
|
-
function resolveCreator(actor) {
|
|
12208
|
-
if (actor.type === "agent") return {
|
|
12209
|
-
type: TASK_CREATOR_TYPES.AGENT,
|
|
12210
|
-
id: actor.agentId
|
|
12211
|
-
};
|
|
12212
|
-
return {
|
|
12213
|
-
type: TASK_CREATOR_TYPES.ADMIN,
|
|
12214
|
-
id: actor.adminId
|
|
12215
|
-
};
|
|
12216
|
-
}
|
|
12217
|
-
/**
|
|
12218
|
-
* Assert the task allows the given agent actor to mutate its chat associations.
|
|
12219
|
-
* Only the creator or assignee (for agents) or any admin may do so.
|
|
12220
|
-
*/
|
|
12221
|
-
function assertCanMutateTaskChats(task, actor) {
|
|
12222
|
-
if (actor.type === "admin") return;
|
|
12223
|
-
const isAssignee = task.assigneeAgentId === actor.agentId;
|
|
12224
|
-
const isCreator = task.createdByType === TASK_CREATOR_TYPES.AGENT && task.createdById === actor.agentId;
|
|
12225
|
-
if (!isAssignee && !isCreator) throw new ForbiddenError("Only the task creator or assignee may modify its chat associations");
|
|
12226
|
-
}
|
|
12227
|
-
async function loadAssigneeOrThrow(db, assigneeAgentId, expectedOrgId) {
|
|
12228
|
-
const [assignee] = await db.select({
|
|
12229
|
-
uuid: agents.uuid,
|
|
12230
|
-
organizationId: agents.organizationId,
|
|
12231
|
-
status: agents.status
|
|
12232
|
-
}).from(agents).where(eq(agents.uuid, assigneeAgentId)).limit(1);
|
|
12233
|
-
if (!assignee || assignee.status === AGENT_STATUSES.DELETED) throw new BadRequestError(`Assignee agent "${assigneeAgentId}" not found`);
|
|
12234
|
-
if (assignee.organizationId !== expectedOrgId) throw new BadRequestError("Assignee agent belongs to a different organization");
|
|
12235
|
-
if (assignee.status === AGENT_STATUSES.SUSPENDED) throw new BadRequestError(`Assignee agent "${assigneeAgentId}" is suspended`);
|
|
12236
|
-
return assignee;
|
|
12237
|
-
}
|
|
12238
|
-
/**
|
|
12239
|
-
* Create a task.
|
|
12240
|
-
*
|
|
12241
|
-
* Initial status is determined by assignee:
|
|
12242
|
-
* - no assignee → "pending"
|
|
12243
|
-
* - assignee is an agent and equals the creator → "working" (work-first; no notification)
|
|
12244
|
-
* - assignee set and differs from creator → "assigned" (task-first; notification dispatched)
|
|
12245
|
-
*
|
|
12246
|
-
* Task-first notifications go through the regular message+inbox pipeline via a per-org
|
|
12247
|
-
* task-notifier pseudo agent. The caller is responsible for triggering notifier fan-out
|
|
12248
|
-
* using the returned notification recipients.
|
|
12249
|
-
*/
|
|
12250
|
-
async function createTask(db, actor, input) {
|
|
12251
|
-
const [org] = await db.select({ id: organizations.id }).from(organizations).where(eq(organizations.id, input.organizationId)).limit(1);
|
|
12252
|
-
if (!org) throw new NotFoundError(`Organization "${input.organizationId}" not found`);
|
|
12253
|
-
if (input.assigneeAgentId) await loadAssigneeOrThrow(db, input.assigneeAgentId, input.organizationId);
|
|
12254
|
-
if (actor.type === "agent" && actor.organizationId !== input.organizationId) throw new ForbiddenError("Cannot create tasks in a different organization");
|
|
12255
|
-
const creator = resolveCreator(actor);
|
|
12256
|
-
const selfAssigned = input.assigneeAgentId !== void 0 && actor.type === "agent" && input.assigneeAgentId === actor.agentId;
|
|
12257
|
-
let initialStatus;
|
|
12258
|
-
if (!input.assigneeAgentId) initialStatus = TASK_STATUSES.PENDING;
|
|
12259
|
-
else if (selfAssigned) initialStatus = TASK_STATUSES.WORKING;
|
|
12260
|
-
else initialStatus = TASK_STATUSES.ASSIGNED;
|
|
12261
|
-
const taskId = uuidv7();
|
|
12262
|
-
const [task] = await db.insert(tasks).values({
|
|
12263
|
-
id: taskId,
|
|
12264
|
-
organizationId: input.organizationId,
|
|
12265
|
-
title: input.title,
|
|
12266
|
-
body: input.body ?? "",
|
|
12267
|
-
status: initialStatus,
|
|
12268
|
-
assigneeAgentId: input.assigneeAgentId ?? null,
|
|
12269
|
-
createdByType: creator.type,
|
|
12270
|
-
createdById: creator.id,
|
|
12271
|
-
originRef: input.originRef ?? null,
|
|
12272
|
-
metadata: input.metadata ?? {}
|
|
12273
|
-
}).returning();
|
|
12274
|
-
if (!task) throw new Error("Unexpected: INSERT RETURNING produced no row");
|
|
12275
|
-
let notification;
|
|
12276
|
-
if (initialStatus === TASK_STATUSES.ASSIGNED && task.assigneeAgentId) notification = await dispatchTaskSystemMessage(db, task, "assigned");
|
|
12277
|
-
return {
|
|
12278
|
-
task,
|
|
12279
|
-
notification
|
|
12280
|
-
};
|
|
12281
|
-
}
|
|
12282
|
-
/** Compose and send a system message describing a task state change to the assignee's chat. */
|
|
12283
|
-
async function dispatchTaskSystemMessage(db, task, event, fromStatus) {
|
|
12284
|
-
if (!task.assigneeAgentId) return void 0;
|
|
12285
|
-
const systemAgentId = await ensureSystemTasksAgent(db, task.organizationId);
|
|
12286
|
-
if (systemAgentId === task.assigneeAgentId) return void 0;
|
|
12287
|
-
const chat = await findOrCreateDirectChat(db, systemAgentId, task.assigneeAgentId);
|
|
12288
|
-
const content = {
|
|
12289
|
-
taskId: task.id,
|
|
12290
|
-
event,
|
|
12291
|
-
title: task.title,
|
|
12292
|
-
body: task.body,
|
|
12293
|
-
status: task.status,
|
|
12294
|
-
...fromStatus ? { fromStatus } : {},
|
|
12295
|
-
originRef: task.originRef
|
|
12296
|
-
};
|
|
12297
|
-
return sendMessage(db, chat.id, systemAgentId, {
|
|
12298
|
-
format: "task",
|
|
12299
|
-
content,
|
|
12300
|
-
metadata: {
|
|
12301
|
-
taskId: task.id,
|
|
12302
|
-
event,
|
|
12303
|
-
mentions: [task.assigneeAgentId]
|
|
12304
|
-
}
|
|
12305
|
-
});
|
|
12306
|
-
}
|
|
12307
|
-
/**
|
|
12308
|
-
* Fetch a task, optionally asserting it belongs to `expectedOrgId`. Cross-org
|
|
12309
|
-
* access is reported as NotFound so we don't leak existence across tenants.
|
|
12310
|
-
*/
|
|
12311
|
-
async function getTask(db, taskId, expectedOrgId) {
|
|
12312
|
-
const [task] = await db.select().from(tasks).where(eq(tasks.id, taskId)).limit(1);
|
|
12313
|
-
if (!task) throw new NotFoundError(`Task "${taskId}" not found`);
|
|
12314
|
-
if (expectedOrgId !== void 0 && task.organizationId !== expectedOrgId) throw new NotFoundError(`Task "${taskId}" not found`);
|
|
12315
|
-
return task;
|
|
12316
|
-
}
|
|
12317
|
-
async function getTaskDetail(db, taskId, expectedOrgId) {
|
|
12318
|
-
const task = await getTask(db, taskId, expectedOrgId);
|
|
12319
|
-
const links = await db.select().from(taskChats).where(eq(taskChats.taskId, taskId));
|
|
12320
|
-
return {
|
|
12321
|
-
...task,
|
|
12322
|
-
chats: links.map((c) => ({
|
|
12323
|
-
taskId: c.taskId,
|
|
12324
|
-
chatId: c.chatId,
|
|
12325
|
-
linkedByAgentId: c.linkedByAgentId,
|
|
12326
|
-
linkedAt: c.linkedAt.toISOString()
|
|
12327
|
-
}))
|
|
12328
|
-
};
|
|
12329
|
-
}
|
|
12330
|
-
async function listTasks(db, organizationId, query) {
|
|
12331
|
-
const conditions = [eq(tasks.organizationId, organizationId)];
|
|
12332
|
-
if (query.status) conditions.push(eq(tasks.status, query.status));
|
|
12333
|
-
if (query.assigneeAgentId) conditions.push(eq(tasks.assigneeAgentId, query.assigneeAgentId));
|
|
12334
|
-
if (query.originRef) conditions.push(eq(tasks.originRef, query.originRef));
|
|
12335
|
-
if (query.cursor) conditions.push(lt(tasks.createdAt, new Date(query.cursor)));
|
|
12336
|
-
const rows = await db.select().from(tasks).where(and(...conditions)).orderBy(desc(tasks.createdAt)).limit(query.limit + 1);
|
|
12337
|
-
const hasMore = rows.length > query.limit;
|
|
12338
|
-
const items = hasMore ? rows.slice(0, query.limit) : rows;
|
|
12339
|
-
const last = items[items.length - 1];
|
|
12340
|
-
return {
|
|
12341
|
-
items,
|
|
12342
|
-
nextCursor: hasMore && last ? last.createdAt.toISOString() : null
|
|
12343
|
-
};
|
|
12344
|
-
}
|
|
12345
|
-
/** Agent self-report: working / completed / failed. */
|
|
12346
|
-
async function updateTaskStatus(db, taskId, actor, data) {
|
|
12347
|
-
const existing = await getTask(db, taskId);
|
|
12348
|
-
if (actor.type !== "agent") throw new ForbiddenError("updateTaskStatus is for agent self-report; use adminUpdateTask for admin actions");
|
|
12349
|
-
if (existing.assigneeAgentId !== actor.agentId) throw new ForbiddenError("Only the assignee may update this task");
|
|
12350
|
-
const from = existing.status;
|
|
12351
|
-
const to = data.status;
|
|
12352
|
-
if (!isLegalTransition(from, to)) throw new BadRequestError(`Illegal status transition: ${from} → ${to}`);
|
|
12353
|
-
if (to === TASK_STATUSES.COMPLETED && data.result === void 0) throw new BadRequestError("Completion requires a result (may be an empty string)");
|
|
12354
|
-
const updates = {
|
|
12355
|
-
status: to,
|
|
12356
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
12357
|
-
};
|
|
12358
|
-
if (data.result !== void 0) updates.result = data.result;
|
|
12359
|
-
const [updated] = await db.update(tasks).set(updates).where(eq(tasks.id, taskId)).returning();
|
|
12360
|
-
if (!updated) throw new Error("Unexpected: UPDATE RETURNING produced no row");
|
|
12361
|
-
return { task: updated };
|
|
12362
|
-
}
|
|
12363
|
-
/** Admin-facing update: may re-assign while pending, or force a status transition (still gated by state machine). */
|
|
12364
|
-
async function adminUpdateTask(db, taskId, actor, data) {
|
|
12365
|
-
if (actor.type !== "admin") throw new ForbiddenError("adminUpdateTask requires admin actor");
|
|
12366
|
-
const existing = await getTask(db, taskId);
|
|
12367
|
-
if (data.status === TASK_STATUSES.CANCELLED) {
|
|
12368
|
-
if (isTerminal(existing.status)) throw new ConflictError(`Task is already in terminal state "${existing.status}"`);
|
|
12369
|
-
return cancelTask(db, taskId, actor);
|
|
12370
|
-
}
|
|
12371
|
-
const updates = { updatedAt: /* @__PURE__ */ new Date() };
|
|
12372
|
-
let notify = false;
|
|
12373
|
-
if (data.assigneeAgentId !== void 0) {
|
|
12374
|
-
if (existing.status !== TASK_STATUSES.PENDING && data.assigneeAgentId !== existing.assigneeAgentId) throw new BadRequestError("Cannot reassign a task that is not pending");
|
|
12375
|
-
if (data.assigneeAgentId !== null) {
|
|
12376
|
-
await loadAssigneeOrThrow(db, data.assigneeAgentId, existing.organizationId);
|
|
12377
|
-
updates.assigneeAgentId = data.assigneeAgentId;
|
|
12378
|
-
updates.status = TASK_STATUSES.ASSIGNED;
|
|
12379
|
-
notify = true;
|
|
12380
|
-
} else {
|
|
12381
|
-
updates.assigneeAgentId = null;
|
|
12382
|
-
updates.status = TASK_STATUSES.PENDING;
|
|
12383
|
-
}
|
|
12384
|
-
}
|
|
12385
|
-
if (data.status !== void 0 && data.status !== existing.status) {
|
|
12386
|
-
const from = updates.status ?? existing.status;
|
|
12387
|
-
if (!isLegalTransition(from, data.status)) throw new BadRequestError(`Illegal status transition: ${from} → ${data.status}`);
|
|
12388
|
-
updates.status = data.status;
|
|
12389
|
-
}
|
|
12390
|
-
if (data.result !== void 0) updates.result = data.result;
|
|
12391
|
-
const resolvedStatus = updates.status ?? existing.status;
|
|
12392
|
-
const resolvedAssignee = updates.assigneeAgentId === void 0 ? existing.assigneeAgentId : updates.assigneeAgentId;
|
|
12393
|
-
if (resolvedStatus === TASK_STATUSES.ASSIGNED && !resolvedAssignee) throw new BadRequestError("Cannot set status to \"assigned\" without an assignee");
|
|
12394
|
-
const [updated] = await db.update(tasks).set(updates).where(eq(tasks.id, taskId)).returning();
|
|
12395
|
-
if (!updated) throw new Error("Unexpected: UPDATE RETURNING produced no row");
|
|
12396
|
-
let notification;
|
|
12397
|
-
if (notify && updated.assigneeAgentId) notification = await dispatchTaskSystemMessage(db, updated, "assigned");
|
|
12398
|
-
return {
|
|
12399
|
-
task: updated,
|
|
12400
|
-
notification
|
|
12401
|
-
};
|
|
12402
|
-
}
|
|
12403
|
-
async function cancelTask(db, taskId, actor) {
|
|
12404
|
-
const existing = await getTask(db, taskId);
|
|
12405
|
-
if (isTerminal(existing.status)) throw new ConflictError(`Task is already in terminal state "${existing.status}"`);
|
|
12406
|
-
if (actor.type === "agent") {
|
|
12407
|
-
const isAssignee = existing.assigneeAgentId === actor.agentId;
|
|
12408
|
-
const isCreator = existing.createdByType === TASK_CREATOR_TYPES.AGENT && existing.createdById === actor.agentId;
|
|
12409
|
-
if (!isAssignee && !isCreator) throw new ForbiddenError("Only the assignee or creator may cancel this task");
|
|
12410
|
-
}
|
|
12411
|
-
const now = /* @__PURE__ */ new Date();
|
|
12412
|
-
const { type: cancelType, id: cancelId } = resolveCreator(actor);
|
|
12413
|
-
const [updated] = await db.update(tasks).set({
|
|
12414
|
-
status: TASK_STATUSES.CANCELLED,
|
|
12415
|
-
cancelledAt: now,
|
|
12416
|
-
cancelledByType: cancelType,
|
|
12417
|
-
cancelledById: cancelId,
|
|
12418
|
-
updatedAt: now
|
|
12419
|
-
}).where(eq(tasks.id, taskId)).returning();
|
|
12420
|
-
if (!updated) throw new Error("Unexpected: UPDATE RETURNING produced no row");
|
|
12421
|
-
let notification;
|
|
12422
|
-
if (updated.assigneeAgentId && !(actor.type === "agent" && actor.agentId === updated.assigneeAgentId)) notification = await dispatchTaskSystemMessage(db, updated, "cancelled", existing.status);
|
|
12423
|
-
return {
|
|
12424
|
-
task: updated,
|
|
12425
|
-
notification
|
|
12426
|
-
};
|
|
12427
|
-
}
|
|
12428
|
-
async function linkChatToTask(db, taskId, chatId, actor) {
|
|
12429
|
-
const task = await getTask(db, taskId);
|
|
12430
|
-
if (actor.type === "agent" && task.organizationId !== actor.organizationId) throw new NotFoundError(`Task "${taskId}" not found`);
|
|
12431
|
-
assertCanMutateTaskChats(task, actor);
|
|
12432
|
-
const [chat] = await db.select({ organizationId: chats.organizationId }).from(chats).where(eq(chats.id, chatId)).limit(1);
|
|
12433
|
-
if (!chat) throw new NotFoundError(`Chat "${chatId}" not found`);
|
|
12434
|
-
if (chat.organizationId !== task.organizationId) throw new BadRequestError("Chat belongs to a different organization");
|
|
12435
|
-
if (actor.type === "agent") await assertParticipant(db, chatId, actor.agentId);
|
|
12436
|
-
const linkedBy = actor.type === "agent" ? actor.agentId : null;
|
|
12437
|
-
await db.insert(taskChats).values({
|
|
12438
|
-
taskId,
|
|
12439
|
-
chatId,
|
|
12440
|
-
linkedByAgentId: linkedBy
|
|
12441
|
-
}).onConflictDoNothing();
|
|
12442
|
-
}
|
|
12443
|
-
async function unlinkChatFromTask(db, taskId, chatId, actor) {
|
|
12444
|
-
const task = await getTask(db, taskId);
|
|
12445
|
-
if (actor.type === "agent" && task.organizationId !== actor.organizationId) throw new NotFoundError(`Task "${taskId}" not found`);
|
|
12446
|
-
assertCanMutateTaskChats(task, actor);
|
|
12447
|
-
if ((await db.delete(taskChats).where(and(eq(taskChats.taskId, taskId), eq(taskChats.chatId, chatId))).returning({ chatId: taskChats.chatId })).length === 0) throw new NotFoundError(`Chat "${chatId}" is not linked to task "${taskId}"`);
|
|
12448
|
-
}
|
|
12449
|
-
/**
|
|
12450
|
-
* Derive a health signal for a task. Only meaningful for `working` tasks.
|
|
12451
|
-
* See hub-task-design Section 9 for the rules this implements.
|
|
12452
|
-
*
|
|
12453
|
-
* Algorithm (per linked chat for the assignee):
|
|
12454
|
-
* 1. No session row OR state != 'active' → idle_island candidate
|
|
12455
|
-
* 2. Session active, last message from assignee → awaiting_reply candidate
|
|
12456
|
-
* 3. Session active, last message from other → normal candidate
|
|
12457
|
-
* Across all linked chats, normal wins over awaiting_reply, which wins over idle_island.
|
|
12458
|
-
*/
|
|
12459
|
-
async function getTaskHealth(db, taskId, expectedOrgId) {
|
|
12460
|
-
const task = await getTask(db, taskId, expectedOrgId);
|
|
12461
|
-
if (task.status !== TASK_STATUSES.WORKING) return {
|
|
12462
|
-
taskId,
|
|
12463
|
-
signal: TASK_HEALTH_SIGNALS.NOT_APPLICABLE,
|
|
12464
|
-
reason: `Task status is "${task.status}" — health is only computed for working tasks`
|
|
12465
|
-
};
|
|
12466
|
-
if (!task.assigneeAgentId) return {
|
|
12467
|
-
taskId,
|
|
12468
|
-
signal: TASK_HEALTH_SIGNALS.NO_CHAT,
|
|
12469
|
-
reason: "Task has no assignee"
|
|
12470
|
-
};
|
|
12471
|
-
const linked = await db.select({
|
|
12472
|
-
chatId: taskChats.chatId,
|
|
12473
|
-
sessionState: agentChatSessions.state
|
|
12474
|
-
}).from(taskChats).leftJoin(agentChatSessions, and(eq(agentChatSessions.chatId, taskChats.chatId), eq(agentChatSessions.agentId, task.assigneeAgentId))).where(eq(taskChats.taskId, taskId));
|
|
12475
|
-
if (linked.length === 0) return {
|
|
12476
|
-
taskId,
|
|
12477
|
-
signal: TASK_HEALTH_SIGNALS.NO_CHAT,
|
|
12478
|
-
reason: "Task has no linked chats"
|
|
12479
|
-
};
|
|
12480
|
-
const chatSignals = [];
|
|
12481
|
-
for (const row of linked) {
|
|
12482
|
-
if (row.sessionState !== "active") {
|
|
12483
|
-
chatSignals.push(TASK_HEALTH_SIGNALS.IDLE_ISLAND);
|
|
12484
|
-
continue;
|
|
12485
|
-
}
|
|
12486
|
-
const [last] = await db.select({ senderId: messages.senderId }).from(messages).where(eq(messages.chatId, row.chatId)).orderBy(desc(messages.createdAt)).limit(1);
|
|
12487
|
-
if (!last) {
|
|
12488
|
-
chatSignals.push(TASK_HEALTH_SIGNALS.IDLE_ISLAND);
|
|
12489
|
-
continue;
|
|
12490
|
-
}
|
|
12491
|
-
if (last.senderId === task.assigneeAgentId) chatSignals.push(TASK_HEALTH_SIGNALS.AWAITING_REPLY);
|
|
12492
|
-
else chatSignals.push(TASK_HEALTH_SIGNALS.NORMAL);
|
|
12493
|
-
}
|
|
12494
|
-
if (chatSignals.includes(TASK_HEALTH_SIGNALS.NORMAL)) return {
|
|
12495
|
-
taskId,
|
|
12496
|
-
signal: TASK_HEALTH_SIGNALS.NORMAL,
|
|
12497
|
-
reason: "At least one linked chat is actively progressing"
|
|
12498
|
-
};
|
|
12499
|
-
if (chatSignals.includes(TASK_HEALTH_SIGNALS.AWAITING_REPLY)) return {
|
|
12500
|
-
taskId,
|
|
12501
|
-
signal: TASK_HEALTH_SIGNALS.AWAITING_REPLY,
|
|
12502
|
-
reason: "Assignee sent the last message and is waiting for a reply"
|
|
12503
|
-
};
|
|
12504
|
-
return {
|
|
12505
|
-
taskId,
|
|
12506
|
-
signal: TASK_HEALTH_SIGNALS.IDLE_ISLAND,
|
|
12507
|
-
reason: "No active session found for the assignee in any linked chat"
|
|
12508
|
-
};
|
|
12509
|
-
}
|
|
12510
|
-
/** Serialize a task row for API output. */
|
|
12511
|
-
function serializeTask(task) {
|
|
12512
|
-
return {
|
|
12513
|
-
...task,
|
|
12514
|
-
createdAt: task.createdAt.toISOString(),
|
|
12515
|
-
updatedAt: task.updatedAt.toISOString(),
|
|
12516
|
-
cancelledAt: task.cancelledAt ? task.cancelledAt.toISOString() : null
|
|
12517
|
-
};
|
|
12518
|
-
}
|
|
12519
|
-
function dispatch$2(notifier, result) {
|
|
12520
|
-
if (!result) return;
|
|
12521
|
-
notifyRecipients(notifier, result.recipients, result.message.id);
|
|
12522
|
-
}
|
|
12523
|
-
async function agentTaskRoutes(app) {
|
|
12524
|
-
/** Create a task. Agent creator; assignee defaults to self (work-first) if omitted. */
|
|
12525
|
-
app.post("/", async (request, reply) => {
|
|
12526
|
-
const identity = requireAgent(request);
|
|
12527
|
-
const body = createTaskSchema.parse(request.body);
|
|
12528
|
-
const { task, notification } = await createTask(app.db, {
|
|
12529
|
-
type: "agent",
|
|
12530
|
-
agentId: identity.uuid,
|
|
12531
|
-
organizationId: identity.organizationId
|
|
12532
|
-
}, {
|
|
12533
|
-
...body,
|
|
12534
|
-
organizationId: identity.organizationId
|
|
12535
|
-
});
|
|
12536
|
-
dispatch$2(app.notifier, notification);
|
|
12537
|
-
return reply.status(201).send(serializeTask(task));
|
|
12538
|
-
});
|
|
12539
|
-
app.get("/", async (request) => {
|
|
12540
|
-
const identity = requireAgent(request);
|
|
12541
|
-
const query = taskListQuerySchema.parse(request.query);
|
|
12542
|
-
const result = await listTasks(app.db, identity.organizationId, query);
|
|
12543
|
-
return {
|
|
12544
|
-
items: result.items.map((t) => serializeTask(t)),
|
|
12545
|
-
nextCursor: result.nextCursor
|
|
12546
|
-
};
|
|
12547
|
-
});
|
|
12548
|
-
app.get("/:taskId", async (request) => {
|
|
12549
|
-
const identity = requireAgent(request);
|
|
12550
|
-
const detail = await getTaskDetail(app.db, request.params.taskId, identity.organizationId);
|
|
12551
|
-
return {
|
|
12552
|
-
...serializeTask(detail),
|
|
12553
|
-
chats: detail.chats
|
|
12554
|
-
};
|
|
12555
|
-
});
|
|
12556
|
-
/** Agent self-report: working / completed / failed. */
|
|
12557
|
-
app.patch("/:taskId", async (request) => {
|
|
12558
|
-
const identity = requireAgent(request);
|
|
12559
|
-
const body = updateTaskStatusSchema.parse(request.body);
|
|
12560
|
-
const { task } = await updateTaskStatus(app.db, request.params.taskId, {
|
|
12561
|
-
type: "agent",
|
|
12562
|
-
agentId: identity.uuid,
|
|
12563
|
-
organizationId: identity.organizationId
|
|
12564
|
-
}, body);
|
|
12565
|
-
return serializeTask(task);
|
|
12566
|
-
});
|
|
12567
|
-
app.post("/:taskId/cancel", async (request) => {
|
|
12568
|
-
const identity = requireAgent(request);
|
|
12569
|
-
const { task, notification } = await cancelTask(app.db, request.params.taskId, {
|
|
12570
|
-
type: "agent",
|
|
12571
|
-
agentId: identity.uuid,
|
|
12572
|
-
organizationId: identity.organizationId
|
|
12573
|
-
});
|
|
12574
|
-
dispatch$2(app.notifier, notification);
|
|
12575
|
-
return serializeTask(task);
|
|
12576
|
-
});
|
|
12577
|
-
app.post("/:taskId/chats", async (request, reply) => {
|
|
12578
|
-
const identity = requireAgent(request);
|
|
12579
|
-
const body = linkTaskChatSchema.parse(request.body);
|
|
12580
|
-
await linkChatToTask(app.db, request.params.taskId, body.chatId, {
|
|
12581
|
-
type: "agent",
|
|
12582
|
-
agentId: identity.uuid,
|
|
12583
|
-
organizationId: identity.organizationId
|
|
12584
|
-
});
|
|
12585
|
-
return reply.status(204).send();
|
|
12586
|
-
});
|
|
12587
|
-
app.delete("/:taskId/chats/:chatId", async (request, reply) => {
|
|
12588
|
-
const identity = requireAgent(request);
|
|
12589
|
-
await unlinkChatFromTask(app.db, request.params.taskId, request.params.chatId, {
|
|
12590
|
-
type: "agent",
|
|
12591
|
-
agentId: identity.uuid,
|
|
12592
|
-
organizationId: identity.organizationId
|
|
12593
|
-
});
|
|
12594
|
-
return reply.status(204).send();
|
|
12595
|
-
});
|
|
12596
|
-
/** Task health signal — only meaningful while task.status === "working". */
|
|
12597
|
-
app.get("/:taskId/health", async (request) => {
|
|
12598
|
-
const identity = requireAgent(request);
|
|
12599
|
-
return getTaskHealth(app.db, request.params.taskId, identity.organizationId);
|
|
12600
|
-
});
|
|
12601
|
-
}
|
|
12602
12113
|
/** WS close code: agent already connected from another client. */
|
|
12603
12114
|
const WS_CLOSE_ALREADY_CONNECTED = 4009;
|
|
12604
12115
|
/** Track active WS connections per agentId. At most one entry per agent. */
|
|
@@ -15174,9 +14685,7 @@ async function listMeChats(db, humanAgentId, organizationId, query) {
|
|
|
15174
14685
|
lastMessageAt: toDate(r.last_message_at)?.toISOString() ?? null,
|
|
15175
14686
|
lastMessagePreview: r.last_message_preview,
|
|
15176
14687
|
unreadMentionCount: r.unread_mention_count,
|
|
15177
|
-
canReply: r.membership_kind === "participant"
|
|
15178
|
-
taskId: null,
|
|
15179
|
-
taskStatus: null
|
|
14688
|
+
canReply: r.membership_kind === "participant"
|
|
15180
14689
|
};
|
|
15181
14690
|
}),
|
|
15182
14691
|
nextCursor
|
|
@@ -16894,7 +16403,7 @@ async function healthzRoutes(app) {
|
|
|
16894
16403
|
* `api/orgs/invitations.ts` (Class B, admin-gated).
|
|
16895
16404
|
*/
|
|
16896
16405
|
async function publicInvitationRoutes(app) {
|
|
16897
|
-
const { previewInvitation } = await import("./invitation-C299fxkP-
|
|
16406
|
+
const { previewInvitation } = await import("./invitation-C299fxkP-CZRV665C.mjs");
|
|
16898
16407
|
app.get("/:token/preview", async (request, reply) => {
|
|
16899
16408
|
if (!request.params.token) throw new UnauthorizedError("Token required");
|
|
16900
16409
|
const preview = await previewInvitation(app.db, request.params.token);
|
|
@@ -17074,7 +16583,7 @@ async function meRoutes(app) {
|
|
|
17074
16583
|
*/
|
|
17075
16584
|
app.get("/me/pinned-agents", async (request) => {
|
|
17076
16585
|
const { userId } = requireUser(request);
|
|
17077
|
-
const { listMyPinnedAgents } = await import("./client-0RrgrMjR-
|
|
16586
|
+
const { listMyPinnedAgents } = await import("./client-0RrgrMjR-CylTJGEb.mjs");
|
|
17078
16587
|
return listMyPinnedAgents(app.db, { userId });
|
|
17079
16588
|
});
|
|
17080
16589
|
/**
|
|
@@ -17887,39 +17396,6 @@ function enrichOutput(namespace, out, orgId, publicUrl) {
|
|
|
17887
17396
|
}
|
|
17888
17397
|
return out;
|
|
17889
17398
|
}
|
|
17890
|
-
function dispatch$1(notifier, result) {
|
|
17891
|
-
if (!result) return;
|
|
17892
|
-
notifyRecipients(notifier, result.recipients, result.message.id);
|
|
17893
|
-
}
|
|
17894
|
-
/** Class B — `/api/v1/orgs/:orgId/tasks`. Per-task ops live in api/tasks.ts. */
|
|
17895
|
-
async function orgTaskRoutes(app) {
|
|
17896
|
-
app.get("/", async (request) => {
|
|
17897
|
-
const scope = await requireOrgMembership(request, app.db);
|
|
17898
|
-
const query = taskListQuerySchema.parse(request.query);
|
|
17899
|
-
const result = await listTasks(app.db, scope.organizationId, query);
|
|
17900
|
-
return {
|
|
17901
|
-
items: result.items.map((t) => serializeTask(t)),
|
|
17902
|
-
nextCursor: result.nextCursor
|
|
17903
|
-
};
|
|
17904
|
-
});
|
|
17905
|
-
app.post("/", async (request, reply) => {
|
|
17906
|
-
const scope = await requireOrgMembership(request, app.db);
|
|
17907
|
-
const body = adminCreateTaskSchema.parse(request.body);
|
|
17908
|
-
const { task, notification } = await createTask(app.db, {
|
|
17909
|
-
type: "admin",
|
|
17910
|
-
adminId: scope.memberId
|
|
17911
|
-
}, {
|
|
17912
|
-
title: body.title,
|
|
17913
|
-
body: body.body,
|
|
17914
|
-
...body.assigneeAgentId !== void 0 ? { assigneeAgentId: body.assigneeAgentId } : {},
|
|
17915
|
-
...body.originRef !== void 0 ? { originRef: body.originRef } : {},
|
|
17916
|
-
...body.metadata !== void 0 ? { metadata: body.metadata } : {},
|
|
17917
|
-
organizationId: scope.organizationId
|
|
17918
|
-
});
|
|
17919
|
-
dispatch$1(app.notifier, notification);
|
|
17920
|
-
return reply.status(201).send(serializeTask(task));
|
|
17921
|
-
});
|
|
17922
|
-
}
|
|
17923
17399
|
async function loadVisibleAgentIds(db, organizationId, memberId) {
|
|
17924
17400
|
const rows = await db.select({ id: agents.uuid }).from(agents).where(and(eq(agents.organizationId, organizationId), ne(agents.status, AGENT_STATUSES.DELETED), or(eq(agents.visibility, AGENT_VISIBILITY.ORGANIZATION), eq(agents.managerId, memberId))));
|
|
17925
17401
|
return new Set(rows.map((r) => r.id));
|
|
@@ -18140,44 +17616,6 @@ async function sessionRoutes(app) {
|
|
|
18140
17616
|
});
|
|
18141
17617
|
});
|
|
18142
17618
|
}
|
|
18143
|
-
function dispatch(notifier, result) {
|
|
18144
|
-
if (!result) return;
|
|
18145
|
-
notifyRecipients(notifier, result.recipients, result.message.id);
|
|
18146
|
-
}
|
|
18147
|
-
/** Class C — `/api/v1/tasks/:taskId`. The task's `organizationId` locates the org. */
|
|
18148
|
-
async function taskRoutes(app) {
|
|
18149
|
-
app.get("/:taskId", async (request) => {
|
|
18150
|
-
await requireTaskAccess(request, app.db);
|
|
18151
|
-
const detail = await getTaskDetail(app.db, request.params.taskId);
|
|
18152
|
-
return {
|
|
18153
|
-
...serializeTask(detail),
|
|
18154
|
-
chats: detail.chats
|
|
18155
|
-
};
|
|
18156
|
-
});
|
|
18157
|
-
app.patch("/:taskId", async (request) => {
|
|
18158
|
-
const { scope } = await requireTaskAccess(request, app.db);
|
|
18159
|
-
const body = adminUpdateTaskSchema.parse(request.body);
|
|
18160
|
-
const { task, notification } = await adminUpdateTask(app.db, request.params.taskId, {
|
|
18161
|
-
type: "admin",
|
|
18162
|
-
adminId: scope.memberId
|
|
18163
|
-
}, body);
|
|
18164
|
-
dispatch(app.notifier, notification);
|
|
18165
|
-
return serializeTask(task);
|
|
18166
|
-
});
|
|
18167
|
-
app.post("/:taskId/cancel", async (request) => {
|
|
18168
|
-
const { scope } = await requireTaskAccess(request, app.db);
|
|
18169
|
-
const { task, notification } = await cancelTask(app.db, request.params.taskId, {
|
|
18170
|
-
type: "admin",
|
|
18171
|
-
adminId: scope.memberId
|
|
18172
|
-
});
|
|
18173
|
-
dispatch(app.notifier, notification);
|
|
18174
|
-
return serializeTask(task);
|
|
18175
|
-
});
|
|
18176
|
-
app.get("/:taskId/health", async (request) => {
|
|
18177
|
-
await requireTaskAccess(request, app.db);
|
|
18178
|
-
return getTaskHealth(app.db, request.params.taskId);
|
|
18179
|
-
});
|
|
18180
|
-
}
|
|
18181
17619
|
const log$1 = createLogger$1("GithubWebhook");
|
|
18182
17620
|
const GITHUB_ADAPTER_ID = "github-adapter";
|
|
18183
17621
|
function verifySignature(secret, rawBody, signatureHeader) {
|
|
@@ -18764,8 +18202,6 @@ var schema_exports = /* @__PURE__ */ __exportAll({
|
|
|
18764
18202
|
pendingQuestions: () => pendingQuestions,
|
|
18765
18203
|
serverInstances: () => serverInstances,
|
|
18766
18204
|
sessionEvents: () => sessionEvents,
|
|
18767
|
-
taskChats: () => taskChats,
|
|
18768
|
-
tasks: () => tasks,
|
|
18769
18205
|
users: () => users
|
|
18770
18206
|
});
|
|
18771
18207
|
function connectDatabase(url) {
|
|
@@ -20258,7 +19694,6 @@ async function buildApp(config) {
|
|
|
20258
19694
|
await scope.register(orgAdapterStatusRoutes, { prefix: "/adapters/status" });
|
|
20259
19695
|
await scope.register(orgOverviewRoutes, { prefix: "/overview" });
|
|
20260
19696
|
await scope.register(orgActivityRoutes, { prefix: "/activity" });
|
|
20261
|
-
await scope.register(orgTaskRoutes, { prefix: "/tasks" });
|
|
20262
19697
|
await scope.register(orgSessionRoutes, { prefix: "/sessions" });
|
|
20263
19698
|
await scope.register(orgNotificationRoutes, { prefix: "/notifications" });
|
|
20264
19699
|
await scope.register(orgClientRoutes, { prefix: "/clients" });
|
|
@@ -20274,7 +19709,6 @@ async function buildApp(config) {
|
|
|
20274
19709
|
await scope.register(agentActivityRoutes, { prefix: "/agents" });
|
|
20275
19710
|
await scope.register(sessionRoutes, { prefix: "/agents" });
|
|
20276
19711
|
await scope.register(chatRoutes, { prefix: "/chats" });
|
|
20277
|
-
await scope.register(taskRoutes, { prefix: "/tasks" });
|
|
20278
19712
|
await scope.register(adapterRoutes, { prefix: "/adapters" });
|
|
20279
19713
|
await scope.register(adapterMappingRoutes, { prefix: "/adapter-mappings" });
|
|
20280
19714
|
await scope.register(clientRoutes, { prefix: "/clients" });
|
|
@@ -20286,7 +19720,6 @@ async function buildApp(config) {
|
|
|
20286
19720
|
await scope.register(agentSendToAgentRoutes, { prefix: "/agents" });
|
|
20287
19721
|
await scope.register(agentInboxRoutes, { prefix: "/inbox" });
|
|
20288
19722
|
await scope.register(agentConfigRoutes$1);
|
|
20289
|
-
await scope.register(agentTaskRoutes, { prefix: "/tasks" });
|
|
20290
19723
|
await scope.register(agentFeishuBotRoutes);
|
|
20291
19724
|
await scope.register(agentFeishuUserRoutes, { prefix: "/delegated" });
|
|
20292
19725
|
}), { prefix: "/agent" });
|