agent-messenger 2.10.2 → 2.11.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/.claude-plugin/plugin.json +1 -1
- package/.env.template +4 -1
- package/README.md +77 -27
- package/bun.lock +26 -0
- package/dist/package.json +21 -1
- package/dist/src/platforms/channeltalk/commands/auth.d.ts +2 -1
- package/dist/src/platforms/channeltalk/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/channeltalk/commands/auth.js +5 -3
- package/dist/src/platforms/channeltalk/commands/auth.js.map +1 -1
- package/dist/src/platforms/channeltalk/token-extractor.d.ts +2 -1
- package/dist/src/platforms/channeltalk/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/channeltalk/token-extractor.js +22 -6
- package/dist/src/platforms/channeltalk/token-extractor.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/cli.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/cli.js +11 -1
- package/dist/src/platforms/channeltalkbot/cli.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/auth.js +1 -5
- package/dist/src/platforms/channeltalkbot/commands/auth.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/bot.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/bot.js +1 -6
- package/dist/src/platforms/channeltalkbot/commands/bot.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/chat.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/chat.js +1 -6
- package/dist/src/platforms/channeltalkbot/commands/chat.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/group.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/group.js +1 -6
- package/dist/src/platforms/channeltalkbot/commands/group.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/manager.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/manager.js +1 -6
- package/dist/src/platforms/channeltalkbot/commands/manager.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/message.js +1 -6
- package/dist/src/platforms/channeltalkbot/commands/message.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/commands/whoami.js +1 -6
- package/dist/src/platforms/channeltalkbot/commands/whoami.js.map +1 -1
- package/dist/src/platforms/channeltalkbot/credential-manager.d.ts +5 -0
- package/dist/src/platforms/channeltalkbot/credential-manager.d.ts.map +1 -1
- package/dist/src/platforms/channeltalkbot/credential-manager.js +34 -4
- package/dist/src/platforms/channeltalkbot/credential-manager.js.map +1 -1
- package/dist/src/platforms/discord/commands/auth.d.ts +1 -0
- package/dist/src/platforms/discord/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/auth.js +3 -1
- package/dist/src/platforms/discord/commands/auth.js.map +1 -1
- package/dist/src/platforms/discord/listener.d.ts +2 -0
- package/dist/src/platforms/discord/listener.d.ts.map +1 -1
- package/dist/src/platforms/discord/listener.js +51 -21
- package/dist/src/platforms/discord/listener.js.map +1 -1
- package/dist/src/platforms/discord/token-extractor.d.ts +2 -1
- package/dist/src/platforms/discord/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/discord/token-extractor.js +21 -6
- package/dist/src/platforms/discord/token-extractor.js.map +1 -1
- package/dist/src/platforms/discordbot/cli.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/cli.js +12 -1
- package/dist/src/platforms/discordbot/cli.js.map +1 -1
- package/dist/src/platforms/discordbot/client.d.ts +3 -0
- package/dist/src/platforms/discordbot/client.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/client.js +3 -0
- package/dist/src/platforms/discordbot/client.js.map +1 -1
- package/dist/src/platforms/discordbot/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/commands/auth.js +1 -5
- package/dist/src/platforms/discordbot/commands/auth.js.map +1 -1
- package/dist/src/platforms/discordbot/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/commands/message.js +1 -6
- package/dist/src/platforms/discordbot/commands/message.js.map +1 -1
- package/dist/src/platforms/discordbot/commands/server.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/commands/server.js +1 -4
- package/dist/src/platforms/discordbot/commands/server.js.map +1 -1
- package/dist/src/platforms/discordbot/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/commands/whoami.js +1 -6
- package/dist/src/platforms/discordbot/commands/whoami.js.map +1 -1
- package/dist/src/platforms/discordbot/index.d.ts +3 -1
- package/dist/src/platforms/discordbot/index.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/index.js +2 -1
- package/dist/src/platforms/discordbot/index.js.map +1 -1
- package/dist/src/platforms/discordbot/listener.d.ts +43 -0
- package/dist/src/platforms/discordbot/listener.d.ts.map +1 -0
- package/dist/src/platforms/discordbot/listener.js +292 -0
- package/dist/src/platforms/discordbot/listener.js.map +1 -0
- package/dist/src/platforms/discordbot/types.d.ts +161 -0
- package/dist/src/platforms/discordbot/types.d.ts.map +1 -1
- package/dist/src/platforms/discordbot/types.js +34 -0
- package/dist/src/platforms/discordbot/types.js.map +1 -1
- package/dist/src/platforms/instagram/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/instagram/commands/auth.js +3 -1
- package/dist/src/platforms/instagram/commands/auth.js.map +1 -1
- package/dist/src/platforms/instagram/token-extractor.d.ts +2 -1
- package/dist/src/platforms/instagram/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/instagram/token-extractor.js +11 -2
- package/dist/src/platforms/instagram/token-extractor.js.map +1 -1
- package/dist/src/platforms/slack/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/slack/commands/auth.js +4 -2
- package/dist/src/platforms/slack/commands/auth.js.map +1 -1
- package/dist/src/platforms/slack/token-extractor.d.ts +4 -1
- package/dist/src/platforms/slack/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/slack/token-extractor.js +64 -15
- package/dist/src/platforms/slack/token-extractor.js.map +1 -1
- package/dist/src/platforms/slackbot/cli.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/cli.js +15 -3
- package/dist/src/platforms/slackbot/cli.js.map +1 -1
- package/dist/src/platforms/slackbot/client.d.ts +22 -1
- package/dist/src/platforms/slackbot/client.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/client.js +104 -1
- package/dist/src/platforms/slackbot/client.js.map +1 -1
- package/dist/src/platforms/slackbot/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/commands/auth.js +1 -5
- package/dist/src/platforms/slackbot/commands/auth.js.map +1 -1
- package/dist/src/platforms/slackbot/commands/file.d.ts +3 -0
- package/dist/src/platforms/slackbot/commands/file.d.ts.map +1 -0
- package/dist/src/platforms/slackbot/commands/file.js +164 -0
- package/dist/src/platforms/slackbot/commands/file.js.map +1 -0
- package/dist/src/platforms/slackbot/commands/index.d.ts +1 -0
- package/dist/src/platforms/slackbot/commands/index.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/commands/index.js +1 -0
- package/dist/src/platforms/slackbot/commands/index.js.map +1 -1
- package/dist/src/platforms/slackbot/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/commands/message.js +19 -0
- package/dist/src/platforms/slackbot/commands/message.js.map +1 -1
- package/dist/src/platforms/slackbot/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/commands/whoami.js +1 -6
- package/dist/src/platforms/slackbot/commands/whoami.js.map +1 -1
- package/dist/src/platforms/slackbot/credential-manager.d.ts +1 -0
- package/dist/src/platforms/slackbot/credential-manager.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/credential-manager.js +30 -2
- package/dist/src/platforms/slackbot/credential-manager.js.map +1 -1
- package/dist/src/platforms/slackbot/index.d.ts +4 -1
- package/dist/src/platforms/slackbot/index.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/index.js +1 -0
- package/dist/src/platforms/slackbot/index.js.map +1 -1
- package/dist/src/platforms/slackbot/listener.d.ts +44 -0
- package/dist/src/platforms/slackbot/listener.d.ts.map +1 -0
- package/dist/src/platforms/slackbot/listener.js +313 -0
- package/dist/src/platforms/slackbot/listener.js.map +1 -0
- package/dist/src/platforms/slackbot/types.d.ts +196 -1
- package/dist/src/platforms/slackbot/types.d.ts.map +1 -1
- package/dist/src/platforms/slackbot/types.js +4 -1
- package/dist/src/platforms/slackbot/types.js.map +1 -1
- package/dist/src/platforms/teams/commands/auth.d.ts +1 -0
- package/dist/src/platforms/teams/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/teams/commands/auth.js +37 -6
- package/dist/src/platforms/teams/commands/auth.js.map +1 -1
- package/dist/src/platforms/teams/ensure-auth.js +31 -9
- package/dist/src/platforms/teams/ensure-auth.js.map +1 -1
- package/dist/src/platforms/teams/token-extractor.d.ts +4 -1
- package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/teams/token-extractor.js +71 -29
- package/dist/src/platforms/teams/token-extractor.js.map +1 -1
- package/dist/src/platforms/webex/commands/auth.d.ts +1 -0
- package/dist/src/platforms/webex/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/webex/commands/auth.js +3 -1
- package/dist/src/platforms/webex/commands/auth.js.map +1 -1
- package/dist/src/platforms/webex/token-extractor.d.ts +3 -1
- package/dist/src/platforms/webex/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/webex/token-extractor.js +16 -2
- package/dist/src/platforms/webex/token-extractor.js.map +1 -1
- package/dist/src/platforms/wechatbot/cli.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/cli.js +11 -1
- package/dist/src/platforms/wechatbot/cli.js.map +1 -1
- package/dist/src/platforms/wechatbot/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/commands/auth.js +1 -5
- package/dist/src/platforms/wechatbot/commands/auth.js.map +1 -1
- package/dist/src/platforms/wechatbot/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/commands/message.js +1 -6
- package/dist/src/platforms/wechatbot/commands/message.js.map +1 -1
- package/dist/src/platforms/wechatbot/commands/template.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/commands/template.js +1 -6
- package/dist/src/platforms/wechatbot/commands/template.js.map +1 -1
- package/dist/src/platforms/wechatbot/commands/user.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/commands/user.js +1 -6
- package/dist/src/platforms/wechatbot/commands/user.js.map +1 -1
- package/dist/src/platforms/wechatbot/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/wechatbot/commands/whoami.js +1 -6
- package/dist/src/platforms/wechatbot/commands/whoami.js.map +1 -1
- package/dist/src/platforms/whatsappbot/cli.d.ts.map +1 -1
- package/dist/src/platforms/whatsappbot/cli.js +11 -1
- package/dist/src/platforms/whatsappbot/cli.js.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/auth.js +1 -5
- package/dist/src/platforms/whatsappbot/commands/auth.js.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/message.d.ts.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/message.js +1 -6
- package/dist/src/platforms/whatsappbot/commands/message.js.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/template.d.ts.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/template.js +1 -6
- package/dist/src/platforms/whatsappbot/commands/template.js.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/whoami.d.ts.map +1 -1
- package/dist/src/platforms/whatsappbot/commands/whoami.js +1 -6
- package/dist/src/platforms/whatsappbot/commands/whoami.js.map +1 -1
- package/dist/src/shared/chromium/browsers.d.ts +8 -0
- package/dist/src/shared/chromium/browsers.d.ts.map +1 -1
- package/dist/src/shared/chromium/browsers.js +58 -3
- package/dist/src/shared/chromium/browsers.js.map +1 -1
- package/dist/src/shared/chromium/cli-options.d.ts +5 -0
- package/dist/src/shared/chromium/cli-options.d.ts.map +1 -0
- package/dist/src/shared/chromium/cli-options.js +8 -0
- package/dist/src/shared/chromium/cli-options.js.map +1 -0
- package/dist/src/shared/chromium/index.d.ts +3 -1
- package/dist/src/shared/chromium/index.d.ts.map +1 -1
- package/dist/src/shared/chromium/index.js +2 -1
- package/dist/src/shared/chromium/index.js.map +1 -1
- package/dist/src/shared/utils/cli-output.d.ts +7 -0
- package/dist/src/shared/utils/cli-output.d.ts.map +1 -0
- package/dist/src/shared/utils/cli-output.js +7 -0
- package/dist/src/shared/utils/cli-output.js.map +1 -0
- package/dist/src/tui/app.d.ts.map +1 -1
- package/dist/src/tui/app.js +73 -20
- package/dist/src/tui/app.js.map +1 -1
- package/docs/content/docs/cli/channeltalk.mdx +4 -0
- package/docs/content/docs/cli/discord.mdx +5 -0
- package/docs/content/docs/cli/instagram.mdx +3 -0
- package/docs/content/docs/cli/slack.mdx +5 -0
- package/docs/content/docs/cli/slackbot.mdx +60 -22
- package/docs/content/docs/cli/teams.mdx +5 -0
- package/docs/content/docs/cli/webex.mdx +3 -0
- package/docs/content/docs/sdk/channeltalkbot.mdx +38 -1
- package/docs/content/docs/sdk/discordbot.mdx +501 -0
- package/docs/content/docs/sdk/meta.json +2 -0
- package/docs/content/docs/sdk/slackbot.mdx +576 -0
- package/e2e/README.md +1 -1
- package/e2e/config.ts +9 -4
- package/examples/discordbot-listen.ts +65 -0
- package/examples/slackbot-listen.ts +65 -0
- package/package.json +21 -1
- package/skills/agent-channeltalk/SKILL.md +5 -1
- package/skills/agent-channeltalk/references/authentication.md +5 -1
- package/skills/agent-channeltalkbot/SKILL.md +17 -3
- package/skills/agent-channeltalkbot/references/authentication.md +7 -5
- package/skills/agent-discord/SKILL.md +5 -1
- package/skills/agent-discord/references/authentication.md +7 -1
- package/skills/agent-discordbot/SKILL.md +13 -2
- package/skills/agent-discordbot/references/common-patterns.md +1 -1
- package/skills/agent-instagram/SKILL.md +7 -1
- package/skills/agent-instagram/references/authentication.md +6 -0
- package/skills/agent-kakaotalk/SKILL.md +1 -1
- package/skills/agent-line/SKILL.md +1 -1
- package/skills/agent-slack/SKILL.md +5 -1
- package/skills/agent-slack/references/authentication.md +7 -1
- package/skills/agent-slackbot/SKILL.md +56 -4
- package/skills/agent-slackbot/references/authentication.md +4 -0
- package/skills/agent-teams/SKILL.md +5 -1
- package/skills/agent-teams/references/authentication.md +7 -1
- package/skills/agent-telegram/SKILL.md +1 -1
- package/skills/agent-webex/SKILL.md +7 -1
- package/skills/agent-webex/references/authentication.md +6 -0
- package/skills/agent-wechatbot/SKILL.md +16 -1
- package/skills/agent-wechatbot/references/authentication.md +219 -0
- package/skills/agent-wechatbot/references/common-patterns.md +358 -0
- package/skills/agent-wechatbot/templates/account-summary.sh +122 -0
- package/skills/agent-wechatbot/templates/post-message.sh +122 -0
- package/skills/agent-wechatbot/templates/send-template.sh +152 -0
- package/skills/agent-whatsapp/SKILL.md +1 -1
- package/skills/agent-whatsappbot/SKILL.md +30 -1
- package/src/platforms/channeltalk/commands/auth.test.ts +15 -3
- package/src/platforms/channeltalk/commands/auth.ts +15 -5
- package/src/platforms/channeltalk/token-extractor.ts +24 -5
- package/src/platforms/channeltalkbot/cli.ts +9 -0
- package/src/platforms/channeltalkbot/commands/auth.ts +1 -5
- package/src/platforms/channeltalkbot/commands/bot.ts +1 -6
- package/src/platforms/channeltalkbot/commands/chat.ts +1 -6
- package/src/platforms/channeltalkbot/commands/group.ts +1 -6
- package/src/platforms/channeltalkbot/commands/manager.ts +1 -6
- package/src/platforms/channeltalkbot/commands/message.ts +1 -6
- package/src/platforms/channeltalkbot/commands/whoami.test.ts +2 -0
- package/src/platforms/channeltalkbot/commands/whoami.ts +1 -6
- package/src/platforms/channeltalkbot/credential-manager.test.ts +96 -2
- package/src/platforms/channeltalkbot/credential-manager.ts +37 -4
- package/src/platforms/discord/commands/auth.ts +13 -2
- package/src/platforms/discord/listener.test.ts +59 -1
- package/src/platforms/discord/listener.ts +43 -19
- package/src/platforms/discord/token-extractor.ts +30 -6
- package/src/platforms/discordbot/cli.ts +10 -0
- package/src/platforms/discordbot/client.ts +4 -0
- package/src/platforms/discordbot/commands/auth.ts +1 -5
- package/src/platforms/discordbot/commands/message.ts +1 -6
- package/src/platforms/discordbot/commands/server.ts +1 -5
- package/src/platforms/discordbot/commands/whoami.ts +1 -6
- package/src/platforms/discordbot/index.test.ts +82 -0
- package/src/platforms/discordbot/index.ts +27 -9
- package/src/platforms/discordbot/listener.test.ts +1002 -0
- package/src/platforms/discordbot/listener.ts +321 -0
- package/src/platforms/discordbot/types.ts +163 -0
- package/src/platforms/instagram/commands/auth.ts +9 -1
- package/src/platforms/instagram/token-extractor.ts +13 -1
- package/src/platforms/slack/commands/auth.ts +11 -2
- package/src/platforms/slack/token-extractor.test.ts +96 -0
- package/src/platforms/slack/token-extractor.ts +76 -13
- package/src/platforms/slackbot/cli.ts +13 -1
- package/src/platforms/slackbot/client.test.ts +274 -0
- package/src/platforms/slackbot/client.ts +130 -2
- package/src/platforms/slackbot/commands/auth.ts +1 -5
- package/src/platforms/slackbot/commands/file.test.ts +201 -0
- package/src/platforms/slackbot/commands/file.ts +212 -0
- package/src/platforms/slackbot/commands/index.ts +1 -0
- package/src/platforms/slackbot/commands/message.ts +22 -0
- package/src/platforms/slackbot/commands/whoami.ts +1 -6
- package/src/platforms/slackbot/credential-manager.test.ts +62 -2
- package/src/platforms/slackbot/credential-manager.ts +32 -2
- package/src/platforms/slackbot/index.test.ts +59 -0
- package/src/platforms/slackbot/index.ts +31 -7
- package/src/platforms/slackbot/listener.test.ts +1012 -0
- package/src/platforms/slackbot/listener.ts +362 -0
- package/src/platforms/slackbot/types.ts +224 -1
- package/src/platforms/teams/commands/auth.test.ts +1 -1
- package/src/platforms/teams/commands/auth.ts +66 -7
- package/src/platforms/teams/ensure-auth.test.ts +56 -5
- package/src/platforms/teams/ensure-auth.ts +39 -11
- package/src/platforms/teams/token-extractor.test.ts +146 -24
- package/src/platforms/teams/token-extractor.ts +87 -29
- package/src/platforms/webex/commands/auth.ts +13 -2
- package/src/platforms/webex/token-extractor.ts +25 -3
- package/src/platforms/wechatbot/cli.ts +9 -0
- package/src/platforms/wechatbot/commands/auth.ts +1 -5
- package/src/platforms/wechatbot/commands/message.ts +1 -6
- package/src/platforms/wechatbot/commands/template.ts +1 -6
- package/src/platforms/wechatbot/commands/user.ts +1 -6
- package/src/platforms/wechatbot/commands/whoami.ts +1 -6
- package/src/platforms/whatsappbot/cli.ts +9 -0
- package/src/platforms/whatsappbot/commands/auth.ts +1 -5
- package/src/platforms/whatsappbot/commands/message.ts +1 -6
- package/src/platforms/whatsappbot/commands/template.ts +1 -6
- package/src/platforms/whatsappbot/commands/whoami.ts +1 -6
- package/src/shared/chromium/browsers.test.ts +80 -0
- package/src/shared/chromium/browsers.ts +72 -3
- package/src/shared/chromium/cli-options.test.ts +22 -0
- package/src/shared/chromium/cli-options.ts +12 -0
- package/src/shared/chromium/index.ts +3 -0
- package/src/shared/utils/cli-output.test.ts +57 -0
- package/src/shared/utils/cli-output.ts +8 -0
- package/src/tui/app.ts +129 -20
|
@@ -1,13 +1,28 @@
|
|
|
1
1
|
import { WebClient } from '@slack/web-api'
|
|
2
2
|
|
|
3
3
|
import { SlackBotCredentialManager } from './credential-manager'
|
|
4
|
-
import { SlackBotError, type SlackChannel, type SlackMessage, type SlackUser } from './types'
|
|
4
|
+
import { SlackBotError, type SlackChannel, type SlackFile, type SlackMessage, type SlackUser } from './types'
|
|
5
5
|
|
|
6
6
|
const MAX_RETRIES = 3
|
|
7
7
|
const RATE_LIMIT_ERROR_CODE = 'slack_webapi_rate_limited_error'
|
|
8
8
|
|
|
9
|
+
function mapSlackFile(f: any): SlackFile {
|
|
10
|
+
return {
|
|
11
|
+
id: f?.id || '',
|
|
12
|
+
name: f?.name || '',
|
|
13
|
+
title: f?.title || f?.name || '',
|
|
14
|
+
mimetype: f?.mimetype || 'application/octet-stream',
|
|
15
|
+
size: f?.size || 0,
|
|
16
|
+
url_private: f?.url_private || '',
|
|
17
|
+
created: f?.created || 0,
|
|
18
|
+
user: f?.user || '',
|
|
19
|
+
channels: f?.channels,
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
9
23
|
export class SlackBotClient {
|
|
10
24
|
private client: WebClient | null = null
|
|
25
|
+
private token: string | null = null
|
|
11
26
|
|
|
12
27
|
async login(credentials?: { token: string }): Promise<this> {
|
|
13
28
|
if (credentials) {
|
|
@@ -18,6 +33,7 @@ export class SlackBotClient {
|
|
|
18
33
|
if (!token.startsWith('xoxb-')) {
|
|
19
34
|
throw new SlackBotError('Token must be a bot token (xoxb-)', 'invalid_token_type')
|
|
20
35
|
}
|
|
36
|
+
this.token = token
|
|
21
37
|
this.client = new WebClient(token)
|
|
22
38
|
} else {
|
|
23
39
|
const credManager = new SlackBotCredentialManager()
|
|
@@ -52,7 +68,9 @@ export class SlackBotClient {
|
|
|
52
68
|
break
|
|
53
69
|
}
|
|
54
70
|
}
|
|
55
|
-
|
|
71
|
+
const code = (lastError as any)?.code || 'unknown_error'
|
|
72
|
+
const retryAfter = code === RATE_LIMIT_ERROR_CODE ? (lastError as any)?.retryAfter : undefined
|
|
73
|
+
throw new SlackBotError(lastError?.message || 'Unknown error', code, retryAfter)
|
|
56
74
|
}
|
|
57
75
|
|
|
58
76
|
private sleep(ms: number): Promise<void> {
|
|
@@ -451,6 +469,17 @@ export class SlackBotClient {
|
|
|
451
469
|
})
|
|
452
470
|
}
|
|
453
471
|
|
|
472
|
+
async setAssistantStatus(channel: string, threadTs: string, status: string): Promise<void> {
|
|
473
|
+
return this.withRetry(async () => {
|
|
474
|
+
const response = await this.ensureAuth().assistant.threads.setStatus({
|
|
475
|
+
channel_id: channel,
|
|
476
|
+
thread_ts: threadTs,
|
|
477
|
+
status,
|
|
478
|
+
})
|
|
479
|
+
this.checkResponse(response)
|
|
480
|
+
})
|
|
481
|
+
}
|
|
482
|
+
|
|
454
483
|
async joinChannel(channel: string): Promise<void> {
|
|
455
484
|
return this.withRetry(async () => {
|
|
456
485
|
const response = await this.ensureAuth().conversations.join({ channel })
|
|
@@ -464,4 +493,103 @@ export class SlackBotClient {
|
|
|
464
493
|
this.checkResponse(response)
|
|
465
494
|
})
|
|
466
495
|
}
|
|
496
|
+
|
|
497
|
+
async uploadFile(
|
|
498
|
+
channel: string,
|
|
499
|
+
file: Buffer,
|
|
500
|
+
filename: string,
|
|
501
|
+
options?: { thread_ts?: string; title?: string; initial_comment?: string },
|
|
502
|
+
): Promise<SlackFile> {
|
|
503
|
+
return this.withRetry(async () => {
|
|
504
|
+
const response = await this.ensureAuth().files.uploadV2({
|
|
505
|
+
channel_id: channel,
|
|
506
|
+
file,
|
|
507
|
+
filename,
|
|
508
|
+
thread_ts: options?.thread_ts,
|
|
509
|
+
title: options?.title,
|
|
510
|
+
initial_comment: options?.initial_comment,
|
|
511
|
+
})
|
|
512
|
+
this.checkResponse(response)
|
|
513
|
+
|
|
514
|
+
const completionFiles = (response as any).files?.[0]?.files
|
|
515
|
+
const f = completionFiles?.[0]
|
|
516
|
+
if (!f) {
|
|
517
|
+
throw new SlackBotError('No file returned in upload response', 'file_not_found')
|
|
518
|
+
}
|
|
519
|
+
return mapSlackFile(f)
|
|
520
|
+
})
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
async listFiles(options?: { channel?: string; user?: string; limit?: number }): Promise<SlackFile[]> {
|
|
524
|
+
return this.withRetry(async () => {
|
|
525
|
+
const response = await this.ensureAuth().files.list({
|
|
526
|
+
channel: options?.channel,
|
|
527
|
+
user: options?.user,
|
|
528
|
+
count: options?.limit,
|
|
529
|
+
})
|
|
530
|
+
this.checkResponse(response)
|
|
531
|
+
|
|
532
|
+
return (response.files || []).map((f) => mapSlackFile(f))
|
|
533
|
+
})
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
async getFileInfo(fileId: string): Promise<SlackFile> {
|
|
537
|
+
return this.withRetry(async () => {
|
|
538
|
+
const response = await this.ensureAuth().files.info({ file: fileId })
|
|
539
|
+
this.checkResponse(response)
|
|
540
|
+
|
|
541
|
+
return mapSlackFile(response.file)
|
|
542
|
+
})
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
async downloadFile(fileId: string): Promise<{ buffer: Buffer; file: SlackFile }> {
|
|
546
|
+
const file = await this.getFileInfo(fileId)
|
|
547
|
+
|
|
548
|
+
if (!file.url_private) {
|
|
549
|
+
throw new SlackBotError('File has no download URL', 'no_download_url')
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
if (!this.token) {
|
|
553
|
+
throw new SlackBotError('Not authenticated. Call .login() first.', 'not_authenticated')
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
const response = await fetch(file.url_private, {
|
|
557
|
+
headers: { Authorization: `Bearer ${this.token}` },
|
|
558
|
+
})
|
|
559
|
+
|
|
560
|
+
if (!response.ok) {
|
|
561
|
+
throw new SlackBotError(`Failed to download file: ${response.statusText}`, 'download_failed')
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
const arrayBuffer = await response.arrayBuffer()
|
|
565
|
+
return {
|
|
566
|
+
buffer: Buffer.from(arrayBuffer),
|
|
567
|
+
file,
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
async deleteFile(fileId: string): Promise<void> {
|
|
572
|
+
return this.withRetry(async () => {
|
|
573
|
+
const response = await this.ensureAuth().files.delete({ file: fileId })
|
|
574
|
+
this.checkResponse(response)
|
|
575
|
+
})
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
async appsConnectionsOpen(appToken: string): Promise<{ url: string }> {
|
|
579
|
+
if (!appToken) {
|
|
580
|
+
throw new SlackBotError('App-level token is required for Socket Mode', 'missing_app_token')
|
|
581
|
+
}
|
|
582
|
+
if (!appToken.startsWith('xapp-')) {
|
|
583
|
+
throw new SlackBotError(
|
|
584
|
+
'Token must be an app-level token (xapp-) with connections:write scope',
|
|
585
|
+
'invalid_app_token_type',
|
|
586
|
+
)
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
return this.withRetry(async () => {
|
|
590
|
+
const response = await new WebClient(appToken).apps.connections.open()
|
|
591
|
+
this.checkResponse(response)
|
|
592
|
+
return { url: (response as { url: string }).url }
|
|
593
|
+
})
|
|
594
|
+
}
|
|
467
595
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Command } from 'commander'
|
|
2
2
|
|
|
3
|
+
import { cliOutput } from '@/shared/utils/cli-output'
|
|
3
4
|
import { formatOutput } from '@/shared/utils/output'
|
|
4
5
|
|
|
5
6
|
import { SlackBotClient } from '../client'
|
|
@@ -177,11 +178,6 @@ export async function removeAction(botId: string, options: ActionOptions): Promi
|
|
|
177
178
|
}
|
|
178
179
|
}
|
|
179
180
|
|
|
180
|
-
function cliOutput(result: ActionResult, pretty?: boolean, exitOnError = true): void {
|
|
181
|
-
console.log(formatOutput(result, pretty))
|
|
182
|
-
if (result.error && exitOnError) process.exit(1)
|
|
183
|
-
}
|
|
184
|
-
|
|
185
181
|
export const authCommand = new Command('auth')
|
|
186
182
|
.description('Bot authentication commands')
|
|
187
183
|
.addCommand(
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, mock, it } from 'bun:test'
|
|
2
|
+
|
|
3
|
+
const mockResolveChannel = mock((_channel: string) => Promise.resolve('C123456'))
|
|
4
|
+
const mockUploadFile = mock(() =>
|
|
5
|
+
Promise.resolve({
|
|
6
|
+
id: 'F123',
|
|
7
|
+
name: 'test.txt',
|
|
8
|
+
title: 'test.txt',
|
|
9
|
+
mimetype: 'text/plain',
|
|
10
|
+
size: 12,
|
|
11
|
+
url_private: 'https://files.slack.com/files-pri/T123-F123/test.txt',
|
|
12
|
+
created: 1234567890,
|
|
13
|
+
user: 'U123',
|
|
14
|
+
channels: ['C123456'],
|
|
15
|
+
}),
|
|
16
|
+
)
|
|
17
|
+
const mockListFiles = mock(() =>
|
|
18
|
+
Promise.resolve([
|
|
19
|
+
{
|
|
20
|
+
id: 'F123',
|
|
21
|
+
name: 'test.txt',
|
|
22
|
+
title: 'test.txt',
|
|
23
|
+
mimetype: 'text/plain',
|
|
24
|
+
size: 1024,
|
|
25
|
+
url_private: 'https://files.slack.com/files-pri/T123-F123/test.txt',
|
|
26
|
+
created: 1234567890,
|
|
27
|
+
user: 'U123',
|
|
28
|
+
channels: ['C123456'],
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: 'F456',
|
|
32
|
+
name: 'document.pdf',
|
|
33
|
+
title: 'document.pdf',
|
|
34
|
+
mimetype: 'application/pdf',
|
|
35
|
+
size: 2048,
|
|
36
|
+
url_private: 'https://files.slack.com/files-pri/T123-F456/document.pdf',
|
|
37
|
+
created: 1234567891,
|
|
38
|
+
user: 'U456',
|
|
39
|
+
channels: ['C123456'],
|
|
40
|
+
},
|
|
41
|
+
]),
|
|
42
|
+
)
|
|
43
|
+
const mockGetFileInfo = mock(() =>
|
|
44
|
+
Promise.resolve({
|
|
45
|
+
id: 'F123',
|
|
46
|
+
name: 'test.txt',
|
|
47
|
+
title: 'test.txt',
|
|
48
|
+
mimetype: 'text/plain',
|
|
49
|
+
size: 1024,
|
|
50
|
+
url_private: 'https://files.slack.com/files-pri/T123-F123/test.txt',
|
|
51
|
+
created: 1234567890,
|
|
52
|
+
user: 'U123',
|
|
53
|
+
channels: ['C123456'],
|
|
54
|
+
}),
|
|
55
|
+
)
|
|
56
|
+
const mockDownloadFile = mock(() =>
|
|
57
|
+
Promise.resolve({
|
|
58
|
+
buffer: Buffer.from('downloaded content'),
|
|
59
|
+
file: {
|
|
60
|
+
id: 'F123',
|
|
61
|
+
name: 'test.txt',
|
|
62
|
+
title: 'test.txt',
|
|
63
|
+
mimetype: 'text/plain',
|
|
64
|
+
size: 18,
|
|
65
|
+
url_private: 'https://files.slack.com/files-pri/T123-F123/test.txt',
|
|
66
|
+
created: 1234567890,
|
|
67
|
+
user: 'U123',
|
|
68
|
+
channels: ['C123456'],
|
|
69
|
+
},
|
|
70
|
+
}),
|
|
71
|
+
)
|
|
72
|
+
const mockDeleteFile = mock(() => Promise.resolve())
|
|
73
|
+
|
|
74
|
+
mock.module('../client', () => ({
|
|
75
|
+
SlackBotClient: class MockSlackBotClient {
|
|
76
|
+
async login(_credentials?: { token: string }) {
|
|
77
|
+
return this
|
|
78
|
+
}
|
|
79
|
+
resolveChannel = mockResolveChannel
|
|
80
|
+
uploadFile = mockUploadFile
|
|
81
|
+
listFiles = mockListFiles
|
|
82
|
+
getFileInfo = mockGetFileInfo
|
|
83
|
+
downloadFile = mockDownloadFile
|
|
84
|
+
deleteFile = mockDeleteFile
|
|
85
|
+
},
|
|
86
|
+
}))
|
|
87
|
+
|
|
88
|
+
import { SlackBotClient } from '../client'
|
|
89
|
+
|
|
90
|
+
describe('file commands', () => {
|
|
91
|
+
beforeEach(() => {
|
|
92
|
+
mockResolveChannel.mockClear()
|
|
93
|
+
mockUploadFile.mockClear()
|
|
94
|
+
mockListFiles.mockClear()
|
|
95
|
+
mockGetFileInfo.mockClear()
|
|
96
|
+
mockDownloadFile.mockClear()
|
|
97
|
+
mockDeleteFile.mockClear()
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
describe('uploadFile', () => {
|
|
101
|
+
it('uploads a file to a channel', async () => {
|
|
102
|
+
// given
|
|
103
|
+
const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
|
|
104
|
+
|
|
105
|
+
// when
|
|
106
|
+
const file = await client.uploadFile('C123456', Buffer.from('test content'), 'test.txt')
|
|
107
|
+
|
|
108
|
+
// then
|
|
109
|
+
expect(file.id).toBe('F123')
|
|
110
|
+
expect(file.name).toBe('test.txt')
|
|
111
|
+
expect(file.channels).toContain('C123456')
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('forwards thread, title, and initial_comment options', async () => {
|
|
115
|
+
// given
|
|
116
|
+
const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
|
|
117
|
+
|
|
118
|
+
// when
|
|
119
|
+
await client.uploadFile('C123456', Buffer.from('x'), 'test.txt', {
|
|
120
|
+
thread_ts: '1234567890.000100',
|
|
121
|
+
title: 'My Title',
|
|
122
|
+
initial_comment: 'Here you go',
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
// then
|
|
126
|
+
expect(mockUploadFile).toHaveBeenCalledWith('C123456', Buffer.from('x'), 'test.txt', {
|
|
127
|
+
thread_ts: '1234567890.000100',
|
|
128
|
+
title: 'My Title',
|
|
129
|
+
initial_comment: 'Here you go',
|
|
130
|
+
})
|
|
131
|
+
})
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
describe('listFiles', () => {
|
|
135
|
+
it('returns all files visible to the bot', async () => {
|
|
136
|
+
// given
|
|
137
|
+
const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
|
|
138
|
+
|
|
139
|
+
// when
|
|
140
|
+
const files = await client.listFiles()
|
|
141
|
+
|
|
142
|
+
// then
|
|
143
|
+
expect(files).toHaveLength(2)
|
|
144
|
+
expect(files[0].name).toBe('test.txt')
|
|
145
|
+
expect(files[1].name).toBe('document.pdf')
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
it('forwards channel/user/limit filters', async () => {
|
|
149
|
+
// given
|
|
150
|
+
const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
|
|
151
|
+
|
|
152
|
+
// when
|
|
153
|
+
await client.listFiles({ channel: 'C123456', user: 'U123', limit: 50 })
|
|
154
|
+
|
|
155
|
+
// then
|
|
156
|
+
expect(mockListFiles).toHaveBeenCalledWith({ channel: 'C123456', user: 'U123', limit: 50 })
|
|
157
|
+
})
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
describe('getFileInfo', () => {
|
|
161
|
+
it('returns file metadata', async () => {
|
|
162
|
+
// given
|
|
163
|
+
const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
|
|
164
|
+
|
|
165
|
+
// when
|
|
166
|
+
const file = await client.getFileInfo('F123')
|
|
167
|
+
|
|
168
|
+
// then
|
|
169
|
+
expect(file.id).toBe('F123')
|
|
170
|
+
expect(file.name).toBe('test.txt')
|
|
171
|
+
expect(file.url_private).toBe('https://files.slack.com/files-pri/T123-F123/test.txt')
|
|
172
|
+
})
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
describe('downloadFile', () => {
|
|
176
|
+
it('returns buffer and file metadata', async () => {
|
|
177
|
+
// given
|
|
178
|
+
const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
|
|
179
|
+
|
|
180
|
+
// when
|
|
181
|
+
const result = await client.downloadFile('F123')
|
|
182
|
+
|
|
183
|
+
// then
|
|
184
|
+
expect(result.file.id).toBe('F123')
|
|
185
|
+
expect(result.buffer.toString()).toBe('downloaded content')
|
|
186
|
+
})
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
describe('deleteFile', () => {
|
|
190
|
+
it("deletes the bot's file", async () => {
|
|
191
|
+
// given
|
|
192
|
+
const client = await new SlackBotClient().login({ token: 'xoxb-test-token' })
|
|
193
|
+
|
|
194
|
+
// when
|
|
195
|
+
await client.deleteFile('F123')
|
|
196
|
+
|
|
197
|
+
// then
|
|
198
|
+
expect(mockDeleteFile).toHaveBeenCalledWith('F123')
|
|
199
|
+
})
|
|
200
|
+
})
|
|
201
|
+
})
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { readFileSync, statSync, writeFileSync } from 'node:fs'
|
|
2
|
+
import { basename, join, resolve } from 'node:path'
|
|
3
|
+
|
|
4
|
+
import { Command } from 'commander'
|
|
5
|
+
|
|
6
|
+
import { handleError } from '@/shared/utils/error-handler'
|
|
7
|
+
import { formatOutput } from '@/shared/utils/output'
|
|
8
|
+
|
|
9
|
+
import { type BotOption, getClient } from './shared'
|
|
10
|
+
|
|
11
|
+
async function uploadAction(
|
|
12
|
+
channelInput: string,
|
|
13
|
+
path: string,
|
|
14
|
+
options: BotOption & { filename?: string; thread?: string; title?: string; comment?: string },
|
|
15
|
+
): Promise<void> {
|
|
16
|
+
try {
|
|
17
|
+
const client = await getClient(options)
|
|
18
|
+
const channel = await client.resolveChannel(channelInput)
|
|
19
|
+
|
|
20
|
+
const filePath = resolve(path)
|
|
21
|
+
const fileBuffer = readFileSync(filePath)
|
|
22
|
+
const filename = options.filename || basename(filePath) || 'file'
|
|
23
|
+
|
|
24
|
+
const file = await client.uploadFile(channel, fileBuffer, filename, {
|
|
25
|
+
thread_ts: options.thread,
|
|
26
|
+
title: options.title,
|
|
27
|
+
initial_comment: options.comment,
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
console.log(
|
|
31
|
+
formatOutput(
|
|
32
|
+
{
|
|
33
|
+
id: file.id,
|
|
34
|
+
name: file.name,
|
|
35
|
+
title: file.title,
|
|
36
|
+
mimetype: file.mimetype,
|
|
37
|
+
size: file.size,
|
|
38
|
+
url_private: file.url_private,
|
|
39
|
+
created: file.created,
|
|
40
|
+
user: file.user,
|
|
41
|
+
channels: file.channels,
|
|
42
|
+
},
|
|
43
|
+
options.pretty,
|
|
44
|
+
),
|
|
45
|
+
)
|
|
46
|
+
} catch (error) {
|
|
47
|
+
handleError(error as Error)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function listAction(options: BotOption & { channel?: string; user?: string; limit?: string }): Promise<void> {
|
|
52
|
+
try {
|
|
53
|
+
const client = await getClient(options)
|
|
54
|
+
const channel = options.channel ? await client.resolveChannel(options.channel) : undefined
|
|
55
|
+
const limit = options.limit ? parseInt(options.limit, 10) : undefined
|
|
56
|
+
|
|
57
|
+
const files = await client.listFiles({ channel, user: options.user, limit })
|
|
58
|
+
|
|
59
|
+
console.log(
|
|
60
|
+
formatOutput(
|
|
61
|
+
files.map((file) => ({
|
|
62
|
+
id: file.id,
|
|
63
|
+
name: file.name,
|
|
64
|
+
title: file.title,
|
|
65
|
+
mimetype: file.mimetype,
|
|
66
|
+
size: file.size,
|
|
67
|
+
url_private: file.url_private,
|
|
68
|
+
created: file.created,
|
|
69
|
+
user: file.user,
|
|
70
|
+
channels: file.channels,
|
|
71
|
+
})),
|
|
72
|
+
options.pretty,
|
|
73
|
+
),
|
|
74
|
+
)
|
|
75
|
+
} catch (error) {
|
|
76
|
+
handleError(error as Error)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function infoAction(fileId: string, options: BotOption): Promise<void> {
|
|
81
|
+
try {
|
|
82
|
+
const client = await getClient(options)
|
|
83
|
+
const file = await client.getFileInfo(fileId)
|
|
84
|
+
|
|
85
|
+
console.log(
|
|
86
|
+
formatOutput(
|
|
87
|
+
{
|
|
88
|
+
id: file.id,
|
|
89
|
+
name: file.name,
|
|
90
|
+
title: file.title,
|
|
91
|
+
mimetype: file.mimetype,
|
|
92
|
+
size: file.size,
|
|
93
|
+
url_private: file.url_private,
|
|
94
|
+
created: file.created,
|
|
95
|
+
user: file.user,
|
|
96
|
+
channels: file.channels,
|
|
97
|
+
},
|
|
98
|
+
options.pretty,
|
|
99
|
+
),
|
|
100
|
+
)
|
|
101
|
+
} catch (error) {
|
|
102
|
+
handleError(error as Error)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function downloadAction(fileId: string, outputPath: string | undefined, options: BotOption): Promise<void> {
|
|
107
|
+
try {
|
|
108
|
+
const client = await getClient(options)
|
|
109
|
+
const { buffer, file } = await client.downloadFile(fileId)
|
|
110
|
+
|
|
111
|
+
const safeName = basename(file.name.replace(/\\/g, '/'))
|
|
112
|
+
let destPath = outputPath ? resolve(outputPath) : resolve(safeName)
|
|
113
|
+
let isDirectory = false
|
|
114
|
+
try {
|
|
115
|
+
isDirectory = statSync(destPath).isDirectory()
|
|
116
|
+
} catch (error) {
|
|
117
|
+
const err = error as NodeJS.ErrnoException
|
|
118
|
+
if (err.code !== 'ENOENT') {
|
|
119
|
+
throw error
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (isDirectory) {
|
|
124
|
+
destPath = join(destPath, safeName)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
writeFileSync(destPath, buffer)
|
|
128
|
+
|
|
129
|
+
console.log(
|
|
130
|
+
formatOutput(
|
|
131
|
+
{
|
|
132
|
+
id: file.id,
|
|
133
|
+
name: file.name,
|
|
134
|
+
mimetype: file.mimetype,
|
|
135
|
+
size: file.size,
|
|
136
|
+
path: destPath,
|
|
137
|
+
},
|
|
138
|
+
options.pretty,
|
|
139
|
+
),
|
|
140
|
+
)
|
|
141
|
+
} catch (error) {
|
|
142
|
+
handleError(error as Error)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async function deleteAction(fileId: string, options: BotOption & { force?: boolean }): Promise<void> {
|
|
147
|
+
try {
|
|
148
|
+
if (!options.force) {
|
|
149
|
+
console.log(formatOutput({ warning: 'Use --force to confirm deletion', file_id: fileId }, options.pretty))
|
|
150
|
+
process.exit(1)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const client = await getClient(options)
|
|
154
|
+
await client.deleteFile(fileId)
|
|
155
|
+
|
|
156
|
+
console.log(formatOutput({ deleted: fileId }, options.pretty))
|
|
157
|
+
} catch (error) {
|
|
158
|
+
handleError(error as Error)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export const fileCommand = new Command('file')
|
|
163
|
+
.description('File commands')
|
|
164
|
+
.addCommand(
|
|
165
|
+
new Command('upload')
|
|
166
|
+
.description('Upload file to a channel')
|
|
167
|
+
.argument('<channel>', 'Channel ID or name')
|
|
168
|
+
.argument('<path>', 'File path')
|
|
169
|
+
.option('--filename <name>', 'Override filename')
|
|
170
|
+
.option('--thread <ts>', 'Upload as a reply to a thread')
|
|
171
|
+
.option('--title <title>', 'File title')
|
|
172
|
+
.option('--comment <text>', 'Initial comment posted with the file')
|
|
173
|
+
.option('--bot <id>', 'Use specific bot')
|
|
174
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
175
|
+
.action(uploadAction),
|
|
176
|
+
)
|
|
177
|
+
.addCommand(
|
|
178
|
+
new Command('list')
|
|
179
|
+
.description('List files visible to the bot')
|
|
180
|
+
.option('--channel <id>', 'Filter by channel ID or name')
|
|
181
|
+
.option('--user <id>', 'Filter by user ID')
|
|
182
|
+
.option('--limit <n>', 'Number of files to fetch')
|
|
183
|
+
.option('--bot <id>', 'Use specific bot')
|
|
184
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
185
|
+
.action(listAction),
|
|
186
|
+
)
|
|
187
|
+
.addCommand(
|
|
188
|
+
new Command('info')
|
|
189
|
+
.description('Show file details')
|
|
190
|
+
.argument('<file>', 'File ID')
|
|
191
|
+
.option('--bot <id>', 'Use specific bot')
|
|
192
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
193
|
+
.action(infoAction),
|
|
194
|
+
)
|
|
195
|
+
.addCommand(
|
|
196
|
+
new Command('download')
|
|
197
|
+
.description('Download a file by ID')
|
|
198
|
+
.argument('<file>', 'File ID')
|
|
199
|
+
.argument('[output-path]', 'Output file path or directory')
|
|
200
|
+
.option('--bot <id>', 'Use specific bot')
|
|
201
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
202
|
+
.action(downloadAction),
|
|
203
|
+
)
|
|
204
|
+
.addCommand(
|
|
205
|
+
new Command('delete')
|
|
206
|
+
.description("Delete a file (bot's own files only)")
|
|
207
|
+
.argument('<file>', 'File ID')
|
|
208
|
+
.option('--force', 'Skip confirmation')
|
|
209
|
+
.option('--bot <id>', 'Use specific bot')
|
|
210
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
211
|
+
.action(deleteAction),
|
|
212
|
+
)
|
|
@@ -98,6 +98,18 @@ async function deleteAction(channelInput: string, ts: string, options: BotOption
|
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
async function typingAction(channelInput: string, threadTs: string, status: string, options: BotOption): Promise<void> {
|
|
102
|
+
try {
|
|
103
|
+
const client = await getClient(options)
|
|
104
|
+
const channel = await client.resolveChannel(channelInput)
|
|
105
|
+
await client.setAssistantStatus(channel, threadTs, status)
|
|
106
|
+
|
|
107
|
+
console.log(formatOutput({ channel, thread_ts: threadTs, status }, options.pretty))
|
|
108
|
+
} catch (error) {
|
|
109
|
+
handleError(error as Error)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
101
113
|
async function repliesAction(
|
|
102
114
|
channelInput: string,
|
|
103
115
|
threadTs: string,
|
|
@@ -165,6 +177,16 @@ export const messageCommand = new Command('message')
|
|
|
165
177
|
.option('--pretty', 'Pretty print JSON output')
|
|
166
178
|
.action(deleteAction),
|
|
167
179
|
)
|
|
180
|
+
.addCommand(
|
|
181
|
+
new Command('typing')
|
|
182
|
+
.description('Set typing status in an AI Assistant thread (e.g. "is typing...")')
|
|
183
|
+
.argument('<channel>', 'Channel ID or name')
|
|
184
|
+
.argument('<thread_ts>', 'Thread timestamp')
|
|
185
|
+
.argument('[status]', 'Status text (pass empty string to clear)', 'is typing...')
|
|
186
|
+
.option('--bot <id>', 'Use specific bot')
|
|
187
|
+
.option('--pretty', 'Pretty print JSON output')
|
|
188
|
+
.action(typingAction),
|
|
189
|
+
)
|
|
168
190
|
.addCommand(
|
|
169
191
|
new Command('replies')
|
|
170
192
|
.description('Get thread replies')
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command } from 'commander'
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { cliOutput } from '@/shared/utils/cli-output'
|
|
4
4
|
|
|
5
5
|
import type { BotOption } from './shared'
|
|
6
6
|
import { getClient } from './shared'
|
|
@@ -30,11 +30,6 @@ export async function whoamiAction(options: BotOption): Promise<WhoamiResult> {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
function cliOutput(result: WhoamiResult, pretty?: boolean): void {
|
|
34
|
-
console.log(formatOutput(result, pretty))
|
|
35
|
-
if (result.error) process.exit(1)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
33
|
export const whoamiCommand = new Command('whoami')
|
|
39
34
|
.description('Show current authenticated bot')
|
|
40
35
|
.option('--bot <id>', 'Bot ID to use')
|