forked from EduCraft/curriculum-project-hub
fix: confine Agent and MCP data access
This commit is contained in:
+35
-11
@@ -72,7 +72,7 @@ interface TriggerDeps {
|
||||
readonly authorizer?: PermissionAuthorizer | undefined;
|
||||
readonly messageBatcherOptions?: MessageBatcherOptions | undefined;
|
||||
readonly triggerQueue?: TriggerQueue | undefined;
|
||||
readonly projectWorkspaceRoot?: string | undefined;
|
||||
readonly projectWorkspaceRoot: string;
|
||||
}
|
||||
|
||||
interface TriggerActor {
|
||||
@@ -103,6 +103,8 @@ export interface TriggerHandler {
|
||||
* agent run is the long leg); the lock guarantees one run per project at a time.
|
||||
*/
|
||||
export function makeTriggerHandler(deps: TriggerDeps): TriggerHandler {
|
||||
const projectWorkspaceRoot = deps.projectWorkspaceRoot.trim();
|
||||
if (projectWorkspaceRoot === "") throw new Error("projectWorkspaceRoot is required");
|
||||
const authorizer = deps.authorizer ?? createPermissionAuthorizer(deps.prisma);
|
||||
const runAgent = deps.runAgent ?? defaultRunAgent;
|
||||
const approvalManager = new ApprovalManager();
|
||||
@@ -288,6 +290,7 @@ export function makeTriggerHandler(deps: TriggerDeps): TriggerHandler {
|
||||
const projectCtx: ProjectContext = {
|
||||
projectId,
|
||||
boundChatId: chatId, // ADR-0003: Feishu reads stay in this chat
|
||||
workspaceRoot: projectWorkspaceRoot,
|
||||
workspaceDir: project.workspaceDir,
|
||||
};
|
||||
|
||||
@@ -314,6 +317,7 @@ export function makeTriggerHandler(deps: TriggerDeps): TriggerHandler {
|
||||
chatId,
|
||||
projectId,
|
||||
runId: run.id,
|
||||
workspaceRoot: projectWorkspaceRoot,
|
||||
workspaceDir: project.workspaceDir,
|
||||
sendOptions,
|
||||
approvalManager,
|
||||
@@ -566,16 +570,13 @@ export function makeTriggerHandler(deps: TriggerDeps): TriggerHandler {
|
||||
|
||||
try {
|
||||
if (action.action === "create_project_from_chat") {
|
||||
if (deps.projectWorkspaceRoot === undefined || deps.projectWorkspaceRoot.trim() === "") {
|
||||
throw new Error("HUB_PROJECT_WORKSPACE_ROOT is required for Feishu project creation");
|
||||
}
|
||||
const name = defaultProjectNameForChat(chatId);
|
||||
const project = await createProjectFromFeishuChat(deps.prisma, {
|
||||
organizationId: action.organization_id,
|
||||
actorFeishuOpenId: operatorOpenId,
|
||||
chatId,
|
||||
name,
|
||||
workspaceRoot: deps.projectWorkspaceRoot,
|
||||
workspaceRoot: projectWorkspaceRoot,
|
||||
folderId: action.folder_id,
|
||||
});
|
||||
await resolveProjectOnboardingCard(rt, messageId, {
|
||||
@@ -771,6 +772,7 @@ export function makeTriggerHandler(deps: TriggerDeps): TriggerHandler {
|
||||
const downloadedResources = await downloadPostMessageFiles({
|
||||
rt,
|
||||
msg,
|
||||
workspaceRoot: projectWorkspaceRoot,
|
||||
workspaceDir: project.workspaceDir,
|
||||
imageKeys: parsed.imageKeys,
|
||||
fileKeys: parsed.fileKeys,
|
||||
@@ -797,8 +799,15 @@ export function makeTriggerHandler(deps: TriggerDeps): TriggerHandler {
|
||||
const key = content.file_key ?? content.image_key ?? "";
|
||||
if (key !== "") {
|
||||
const fileName = `${msg.message_type}-${Date.now()}.${msg.message_type === "image" ? "png" : "bin"}`;
|
||||
const savePath = `${project.workspaceDir}/.cph/inbox/${fileName}`;
|
||||
await downloadMessageFile(rt, msg.message_id, key, savePath, msg.message_type);
|
||||
const savePath = await downloadMessageFile(
|
||||
rt,
|
||||
msg.message_id,
|
||||
key,
|
||||
projectWorkspaceRoot,
|
||||
project.workspaceDir,
|
||||
`.cph/inbox/${fileName}`,
|
||||
msg.message_type,
|
||||
);
|
||||
cleanPrompt = `用户发来一个文件: ${savePath}`;
|
||||
}
|
||||
}
|
||||
@@ -1298,6 +1307,7 @@ interface DownloadedMessageResource {
|
||||
async function downloadPostMessageFiles(args: {
|
||||
readonly rt: FeishuRuntime;
|
||||
readonly msg: MessageReceiveEvent["message"];
|
||||
readonly workspaceRoot: string;
|
||||
readonly workspaceDir: string;
|
||||
readonly imageKeys: readonly string[];
|
||||
readonly fileKeys: readonly string[];
|
||||
@@ -1305,13 +1315,27 @@ async function downloadPostMessageFiles(args: {
|
||||
const timestamp = Date.now();
|
||||
const downloadedResources: DownloadedMessageResource[] = [];
|
||||
for (const [index, imageKey] of args.imageKeys.entries()) {
|
||||
const savePath = `${args.workspaceDir}/.cph/inbox/post-image-${timestamp}-${index}.png`;
|
||||
await downloadMessageFile(args.rt, args.msg.message_id, imageKey, savePath, "image");
|
||||
const savePath = await downloadMessageFile(
|
||||
args.rt,
|
||||
args.msg.message_id,
|
||||
imageKey,
|
||||
args.workspaceRoot,
|
||||
args.workspaceDir,
|
||||
`.cph/inbox/post-image-${timestamp}-${index}.png`,
|
||||
"image",
|
||||
);
|
||||
downloadedResources.push({ resourceType: "image", path: savePath });
|
||||
}
|
||||
for (const [index, fileKey] of args.fileKeys.entries()) {
|
||||
const savePath = `${args.workspaceDir}/.cph/inbox/post-file-${timestamp}-${index}.bin`;
|
||||
await downloadMessageFile(args.rt, args.msg.message_id, fileKey, savePath, "file");
|
||||
const savePath = await downloadMessageFile(
|
||||
args.rt,
|
||||
args.msg.message_id,
|
||||
fileKey,
|
||||
args.workspaceRoot,
|
||||
args.workspaceDir,
|
||||
`.cph/inbox/post-file-${timestamp}-${index}.bin`,
|
||||
"file",
|
||||
);
|
||||
downloadedResources.push({ resourceType: "file", path: savePath });
|
||||
}
|
||||
return downloadedResources;
|
||||
|
||||
Reference in New Issue
Block a user