import { getSlackClient, handleSlackError } from "../slack-client.js";
import type { SlackFile } from "../types/slack.js";
export async function listFiles(options?: {
channel?: string;
user?: string;
types?: string;
count?: number;
page?: number;
}): Promise<{
files: SlackFile[];
total: number;
page: number;
pages: number;
}> {
const client = getSlackClient();
try {
const result = await client.files.list({
channel: options?.channel,
user: options?.user,
types: options?.types,
count: options?.count || 20,
page: options?.page || 1,
});
const files: SlackFile[] = (result.files || []).map((f) => ({
id: f.id!,
name: f.name || "",
title: f.title,
mimetype: f.mimetype || "",
filetype: f.filetype || "",
size: f.size || 0,
url_private: f.url_private,
url_private_download: f.url_private_download,
permalink: f.permalink,
created: f.created,
user: f.user,
}));
return {
files,
total: result.paging?.total || 0,
page: result.paging?.page || 1,
pages: result.paging?.pages || 1,
};
} catch (error) {
handleSlackError(error);
}
}
export async function getFileInfo(fileId: string): Promise<SlackFile> {
const client = getSlackClient();
try {
const result = await client.files.info({
file: fileId,
});
const f = result.file!;
return {
id: f.id!,
name: f.name || "",
title: f.title,
mimetype: f.mimetype || "",
filetype: f.filetype || "",
size: f.size || 0,
url_private: f.url_private,
url_private_download: f.url_private_download,
permalink: f.permalink,
created: f.created,
user: f.user,
};
} catch (error) {
handleSlackError(error);
}
}
export async function uploadFile(options: {
channels?: string;
content: string;
filename?: string;
title?: string;
initialComment?: string;
threadTs?: string;
}): Promise<{
file: SlackFile;
}> {
const client = getSlackClient();
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const uploadArgs: any = {
content: options.content,
filename: options.filename || "file.txt",
};
if (options.channels) {
uploadArgs.channel_id = options.channels;
}
if (options.title) {
uploadArgs.title = options.title;
}
if (options.initialComment) {
uploadArgs.initial_comment = options.initialComment;
}
if (options.threadTs) {
uploadArgs.thread_ts = options.threadTs;
}
const result = await client.files.uploadV2(uploadArgs);
// uploadV2 returns files array, get the first one
const uploadResult = result as { files?: Array<{ id: string; name?: string; title?: string; mimetype?: string; filetype?: string; size?: number; url_private?: string; url_private_download?: string; permalink?: string; created?: number; user?: string }> };
const f = uploadResult.files?.[0];
if (!f) {
throw new Error("File upload failed - no file returned");
}
return {
file: {
id: f.id,
name: f.name || "",
title: f.title,
mimetype: f.mimetype || "",
filetype: f.filetype || "",
size: f.size || 0,
url_private: f.url_private,
url_private_download: f.url_private_download,
permalink: f.permalink,
created: f.created,
user: f.user,
},
};
} catch (error) {
handleSlackError(error);
}
}
export const fileToolDefinitions = [
{
name: "slack_list_files",
description: "List files shared in the workspace",
inputSchema: {
type: "object" as const,
properties: {
channel: {
type: "string",
description: "Filter files by channel ID",
},
user: {
type: "string",
description: "Filter files by user ID",
},
types: {
type: "string",
description:
"Filter by file types (comma-separated): all, spaces, snippets, images, gdocs, zips, pdfs",
},
count: {
type: "number",
description: "Number of files per page (max 100)",
default: 20,
},
page: {
type: "number",
description: "Page number",
default: 1,
},
},
required: [],
},
},
{
name: "slack_get_file_info",
description: "Get detailed information about a specific file",
inputSchema: {
type: "object" as const,
properties: {
file_id: {
type: "string",
description: "The ID of the file (e.g., F1234567890)",
},
},
required: ["file_id"],
},
},
{
name: "slack_upload_file",
description: "Upload a file to a Slack channel",
inputSchema: {
type: "object" as const,
properties: {
channel_id: {
type: "string",
description: "The ID of the channel to upload to",
},
content: {
type: "string",
description: "File content as text",
},
filename: {
type: "string",
description: "Filename with extension (e.g., report.txt)",
default: "file.txt",
},
title: {
type: "string",
description: "Title of the file",
},
initial_comment: {
type: "string",
description: "Message to post along with the file",
},
thread_ts: {
type: "string",
description: "Thread timestamp to upload file as a reply",
},
},
required: ["content"],
},
},
];