crewly 1.20.265 → 1.20.267

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.
Files changed (125) hide show
  1. package/config/skills/_common/lib.sh +15 -2
  2. package/config/skills/agent/core/app-data/SKILL.md +13 -1
  3. package/config/skills/agent/core/app-data/execute.sh +41 -5
  4. package/config/skills/agent/core/app-data/execute.test.sh +47 -1
  5. package/config/skills/agent/core/publish-app/SKILL.md +1 -1
  6. package/config/skills/agent/core/slack-file/SKILL.md +53 -0
  7. package/config/skills/agent/core/slack-file/execute.sh +72 -0
  8. package/config/skills/agent/core/slack-file/execute.test.sh +34 -0
  9. package/dist/backend/backend/src/constants.d.ts +59 -0
  10. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  11. package/dist/backend/backend/src/constants.js +59 -0
  12. package/dist/backend/backend/src/constants.js.map +1 -1
  13. package/dist/backend/backend/src/controllers/apps/apps.controller.d.ts +7 -0
  14. package/dist/backend/backend/src/controllers/apps/apps.controller.d.ts.map +1 -1
  15. package/dist/backend/backend/src/controllers/apps/apps.controller.js +23 -0
  16. package/dist/backend/backend/src/controllers/apps/apps.controller.js.map +1 -1
  17. package/dist/backend/backend/src/controllers/apps/apps.routes.d.ts +9 -0
  18. package/dist/backend/backend/src/controllers/apps/apps.routes.d.ts.map +1 -1
  19. package/dist/backend/backend/src/controllers/apps/apps.routes.js +19 -1
  20. package/dist/backend/backend/src/controllers/apps/apps.routes.js.map +1 -1
  21. package/dist/backend/backend/src/controllers/connector/connector.routes.d.ts.map +1 -1
  22. package/dist/backend/backend/src/controllers/connector/connector.routes.js +6 -1
  23. package/dist/backend/backend/src/controllers/connector/connector.routes.js.map +1 -1
  24. package/dist/backend/backend/src/controllers/connector/remote-mcp-proxy.controller.d.ts +69 -0
  25. package/dist/backend/backend/src/controllers/connector/remote-mcp-proxy.controller.d.ts.map +1 -0
  26. package/dist/backend/backend/src/controllers/connector/remote-mcp-proxy.controller.js +203 -0
  27. package/dist/backend/backend/src/controllers/connector/remote-mcp-proxy.controller.js.map +1 -0
  28. package/dist/backend/backend/src/controllers/connector/remote-mcp.controller.d.ts +16 -0
  29. package/dist/backend/backend/src/controllers/connector/remote-mcp.controller.d.ts.map +1 -1
  30. package/dist/backend/backend/src/controllers/connector/remote-mcp.controller.js +126 -5
  31. package/dist/backend/backend/src/controllers/connector/remote-mcp.controller.js.map +1 -1
  32. package/dist/backend/backend/src/controllers/slack/slack.controller.d.ts.map +1 -1
  33. package/dist/backend/backend/src/controllers/slack/slack.controller.js +37 -0
  34. package/dist/backend/backend/src/controllers/slack/slack.controller.js.map +1 -1
  35. package/dist/backend/backend/src/index.d.ts.map +1 -1
  36. package/dist/backend/backend/src/index.js +5 -0
  37. package/dist/backend/backend/src/index.js.map +1 -1
  38. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
  39. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js +2 -1
  40. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
  41. package/dist/backend/backend/src/services/apps/apps-cloud.client.d.ts +2 -0
  42. package/dist/backend/backend/src/services/apps/apps-cloud.client.d.ts.map +1 -1
  43. package/dist/backend/backend/src/services/apps/apps-cloud.client.js +1 -0
  44. package/dist/backend/backend/src/services/apps/apps-cloud.client.js.map +1 -1
  45. package/dist/backend/backend/src/services/apps/apps.service.d.ts +17 -0
  46. package/dist/backend/backend/src/services/apps/apps.service.d.ts.map +1 -1
  47. package/dist/backend/backend/src/services/apps/apps.service.js +24 -0
  48. package/dist/backend/backend/src/services/apps/apps.service.js.map +1 -1
  49. package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.d.ts.map +1 -1
  50. package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.js +4 -3
  51. package/dist/backend/backend/src/services/cloud/mobile-api-relay.service.js.map +1 -1
  52. package/dist/backend/backend/src/services/connector/remote-mcp-auth-card.d.ts +43 -0
  53. package/dist/backend/backend/src/services/connector/remote-mcp-auth-card.d.ts.map +1 -0
  54. package/dist/backend/backend/src/services/connector/remote-mcp-auth-card.js +98 -0
  55. package/dist/backend/backend/src/services/connector/remote-mcp-auth-card.js.map +1 -0
  56. package/dist/backend/backend/src/services/connector/remote-mcp-auth.service.d.ts +277 -0
  57. package/dist/backend/backend/src/services/connector/remote-mcp-auth.service.d.ts.map +1 -0
  58. package/dist/backend/backend/src/services/connector/remote-mcp-auth.service.js +719 -0
  59. package/dist/backend/backend/src/services/connector/remote-mcp-auth.service.js.map +1 -0
  60. package/dist/backend/backend/src/services/connector/remote-mcp-launch.service.d.ts +29 -5
  61. package/dist/backend/backend/src/services/connector/remote-mcp-launch.service.d.ts.map +1 -1
  62. package/dist/backend/backend/src/services/connector/remote-mcp-launch.service.js +40 -12
  63. package/dist/backend/backend/src/services/connector/remote-mcp-launch.service.js.map +1 -1
  64. package/dist/backend/backend/src/services/connector/remote-mcp-oauth.d.ts +196 -0
  65. package/dist/backend/backend/src/services/connector/remote-mcp-oauth.d.ts.map +1 -0
  66. package/dist/backend/backend/src/services/connector/remote-mcp-oauth.js +351 -0
  67. package/dist/backend/backend/src/services/connector/remote-mcp-oauth.js.map +1 -0
  68. package/dist/backend/backend/src/services/connector/remote-mcp-probe.service.d.ts +3 -1
  69. package/dist/backend/backend/src/services/connector/remote-mcp-probe.service.d.ts.map +1 -1
  70. package/dist/backend/backend/src/services/connector/remote-mcp-probe.service.js +8 -0
  71. package/dist/backend/backend/src/services/connector/remote-mcp-probe.service.js.map +1 -1
  72. package/dist/backend/backend/src/services/core/credential-files.d.ts.map +1 -1
  73. package/dist/backend/backend/src/services/core/credential-files.js +2 -0
  74. package/dist/backend/backend/src/services/core/credential-files.js.map +1 -1
  75. package/dist/backend/backend/src/services/slack/slack-file-fetch.service.d.ts +119 -0
  76. package/dist/backend/backend/src/services/slack/slack-file-fetch.service.d.ts.map +1 -0
  77. package/dist/backend/backend/src/services/slack/slack-file-fetch.service.js +415 -0
  78. package/dist/backend/backend/src/services/slack/slack-file-fetch.service.js.map +1 -0
  79. package/dist/backend/backend/src/services/slack/slack-file-ref.d.ts +69 -0
  80. package/dist/backend/backend/src/services/slack/slack-file-ref.d.ts.map +1 -0
  81. package/dist/backend/backend/src/services/slack/slack-file-ref.js +177 -0
  82. package/dist/backend/backend/src/services/slack/slack-file-ref.js.map +1 -0
  83. package/dist/backend/backend/src/services/slack/slack-initializer.d.ts.map +1 -1
  84. package/dist/backend/backend/src/services/slack/slack-initializer.js +16 -0
  85. package/dist/backend/backend/src/services/slack/slack-initializer.js.map +1 -1
  86. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts +15 -0
  87. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
  88. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js +84 -1
  89. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
  90. package/dist/backend/backend/src/types/slack.types.d.ts +11 -0
  91. package/dist/backend/backend/src/types/slack.types.d.ts.map +1 -1
  92. package/dist/backend/backend/src/types/slack.types.js.map +1 -1
  93. package/dist/backend/build-info.json +2 -2
  94. package/dist/cli/backend/src/constants.d.ts +59 -0
  95. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  96. package/dist/cli/backend/src/constants.js +59 -0
  97. package/dist/cli/backend/src/constants.js.map +1 -1
  98. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
  99. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js +2 -1
  100. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
  101. package/dist/cli/backend/src/services/connector/remote-mcp-launch.service.d.ts +29 -5
  102. package/dist/cli/backend/src/services/connector/remote-mcp-launch.service.d.ts.map +1 -1
  103. package/dist/cli/backend/src/services/connector/remote-mcp-launch.service.js +40 -12
  104. package/dist/cli/backend/src/services/connector/remote-mcp-launch.service.js.map +1 -1
  105. package/dist/cli/backend/src/services/core/credential-files.d.ts.map +1 -1
  106. package/dist/cli/backend/src/services/core/credential-files.js +2 -0
  107. package/dist/cli/backend/src/services/core/credential-files.js.map +1 -1
  108. package/dist/cli/backend/src/services/slack/slack-file-fetch.service.d.ts +119 -0
  109. package/dist/cli/backend/src/services/slack/slack-file-fetch.service.d.ts.map +1 -0
  110. package/dist/cli/backend/src/services/slack/slack-file-fetch.service.js +415 -0
  111. package/dist/cli/backend/src/services/slack/slack-file-fetch.service.js.map +1 -0
  112. package/dist/cli/backend/src/services/slack/slack-file-ref.d.ts +69 -0
  113. package/dist/cli/backend/src/services/slack/slack-file-ref.d.ts.map +1 -0
  114. package/dist/cli/backend/src/services/slack/slack-file-ref.js +177 -0
  115. package/dist/cli/backend/src/services/slack/slack-file-ref.js.map +1 -0
  116. package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.d.ts +15 -0
  117. package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
  118. package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.js +84 -1
  119. package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
  120. package/dist/cli/backend/src/types/slack.types.d.ts +11 -0
  121. package/dist/cli/backend/src/types/slack.types.d.ts.map +1 -1
  122. package/dist/cli/backend/src/types/slack.types.js.map +1 -1
  123. package/frontend/dist/assets/{index-83188f0b.js → index-7e5ebf78.js} +111 -111
  124. package/frontend/dist/index.html +1 -1
  125. package/package.json +1 -1
@@ -0,0 +1,415 @@
1
+ /**
2
+ * Slack file fetch — get a Slack file by link or id, even one your own bot
3
+ * cannot see.
4
+ *
5
+ * Slack serves a file only to members of a channel it was shared in. An
6
+ * agent asked to work on a colleague's file from another channel, often
7
+ * posted from another machine so the event never reached this one, had no
8
+ * way to open it. Rex asked Ella to "paste the text into the thread"
9
+ * instead (2026-10-08, `longform-en.md` in #pro-crewly-marketing).
10
+ *
11
+ * Order:
12
+ * 1. Locally, with the bot tokens this instance holds: the requesting
13
+ * agent's own bot, the uploader's bot, bots of agents in the channel,
14
+ * the workspace bot, then any other installed identity. The first one
15
+ * `files.info` answers for downloads the file.
16
+ * 2. Otherwise Crewly Cloud (`POST /api/cloud/slack/files/fetch`), which
17
+ * holds every bot of the account and tries them the same way.
18
+ *
19
+ * Files land in the same directory as inbound Slack attachments
20
+ * (`~/.crewly/tmp/slack-files/<id>-<name>`).
21
+ *
22
+ * @module services/slack/slack-file-fetch
23
+ */
24
+ import { promises as fs } from 'fs';
25
+ import os from 'os';
26
+ import path from 'path';
27
+ import { LoggerService } from '../core/logger.service.js';
28
+ import { SLACK_FILE_DOWNLOAD_CONSTANTS, SLACK_FILE_FETCH_CONSTANTS } from '../../constants.js';
29
+ import { isSlackDownloadHost, isTextFile, parseSlackFileRef } from './slack-file-ref.js';
30
+ /** HTTP status per code. */
31
+ export const SLACK_FILE_GET_STATUS = {
32
+ validation: 400,
33
+ not_visible: 404,
34
+ no_file_in_message: 404,
35
+ file_deleted: 410,
36
+ too_large: 413,
37
+ foreign_workspace: 403,
38
+ cloud_unavailable: 503,
39
+ slack_error: 502,
40
+ };
41
+ /** A failure with a stable code. */
42
+ export class SlackFileGetError extends Error {
43
+ code;
44
+ constructor(code, message) {
45
+ super(message);
46
+ this.code = code;
47
+ this.name = 'SlackFileGetError';
48
+ }
49
+ }
50
+ /**
51
+ * The service — see module docs.
52
+ */
53
+ export class SlackFileFetchService {
54
+ deps;
55
+ logger;
56
+ fetchImpl;
57
+ apiBase;
58
+ saveDir;
59
+ constructor(deps) {
60
+ this.deps = deps;
61
+ this.logger = LoggerService.getInstance().createComponentLogger('SlackFileFetch');
62
+ this.fetchImpl = deps.fetchImpl ?? fetch;
63
+ this.apiBase = deps.slackApiBase ?? 'https://slack.com/api';
64
+ this.saveDir = deps.saveDir ?? path.join(os.homedir(), '.crewly', SLACK_FILE_DOWNLOAD_CONSTANTS.TEMP_DIR);
65
+ }
66
+ /**
67
+ * Fetch a file: locally first, then through Cloud.
68
+ *
69
+ * @param fileRef - File id, permalink, download URL or message link
70
+ * @param opts - `requesterAgent` (preferred bot, audit), `maxBytes` (default 25 MB)
71
+ * @returns Metadata and the saved path
72
+ * @throws {SlackFileGetError}
73
+ */
74
+ async get(fileRef, opts = {}) {
75
+ const ref = parseSlackFileRef(fileRef);
76
+ if (!ref || (!ref.fileId && !ref.messageTs)) {
77
+ throw new SlackFileGetError('validation', 'Not a Slack file reference: pass a file id (F…), a file link, or a message link');
78
+ }
79
+ const maxBytes = Math.min(opts.maxBytes ?? SLACK_FILE_FETCH_CONSTANTS.MAX_BYTES, SLACK_FILE_FETCH_CONSTANTS.MAX_BYTES);
80
+ let localError = null;
81
+ try {
82
+ const local = await this.getLocal(ref, opts.requesterAgent, maxBytes);
83
+ if (local)
84
+ return local;
85
+ }
86
+ catch (err) {
87
+ if (!(err instanceof SlackFileGetError))
88
+ throw err;
89
+ // Final answers: the file is gone, too big, or not a file at all.
90
+ if (err.code === 'file_deleted' || err.code === 'too_large' || err.code === 'validation')
91
+ throw err;
92
+ localError = err;
93
+ }
94
+ const cloud = this.deps.cloud();
95
+ if (!cloud) {
96
+ throw localError ??
97
+ new SlackFileGetError('not_visible', 'No bot on this machine can see that file, and this machine is not signed in to Crewly Cloud (which could try the account\'s other bots).');
98
+ }
99
+ return this.getViaCloud(fileRef, cloud, opts.requesterAgent, maxBytes);
100
+ }
101
+ // ---------------------------------------------------------------------------
102
+ // Local
103
+ // ---------------------------------------------------------------------------
104
+ async getLocal(ref, requesterAgent, maxBytes) {
105
+ const candidates = (await this.deps.localCandidates(ref, requesterAgent)).slice(0, SLACK_FILE_FETCH_CONSTANTS.MAX_LOCAL_CANDIDATES);
106
+ if (candidates.length === 0)
107
+ return null;
108
+ let fileId = ref.fileId;
109
+ let otherFileIds;
110
+ if (!fileId) {
111
+ const found = await this.fileFromMessage(candidates, ref);
112
+ if (!found)
113
+ return null;
114
+ fileId = found.fileId;
115
+ otherFileIds = found.others.length > 0 ? found.others : undefined;
116
+ }
117
+ for (const c of candidates) {
118
+ const info = await this.slack('files.info', c.token, { file: fileId });
119
+ if (info.ok && info.data.file) {
120
+ const file = info.data.file;
121
+ const name = file.name || file.title || fileId;
122
+ const size = typeof file.size === 'number' ? file.size : 0;
123
+ if (size > maxBytes) {
124
+ throw new SlackFileGetError('too_large', `File is ${size} bytes; the limit is ${maxBytes}`);
125
+ }
126
+ const bytes = await this.download(file, c.token, maxBytes);
127
+ const meta = {
128
+ id: file.id || fileId,
129
+ name,
130
+ mimetype: file.mimetype || 'application/octet-stream',
131
+ size: bytes.length,
132
+ user: file.user ?? null,
133
+ channels: [...(file.channels ?? []), ...(file.groups ?? []), ...(file.ims ?? [])],
134
+ permalink: file.permalink ?? null,
135
+ isText: isTextFile(file.mimetype, name),
136
+ via: `local:${c.label}`,
137
+ ...(otherFileIds ? { otherFileIds } : {}),
138
+ };
139
+ const localPath = await this.save(meta, bytes);
140
+ this.logger.info('Slack file fetched', { fileId: meta.id, via: meta.via, bytes: bytes.length });
141
+ return { meta, localPath };
142
+ }
143
+ if (!info.ok && info.error === 'file_deleted') {
144
+ throw new SlackFileGetError('file_deleted', 'That Slack file was deleted');
145
+ }
146
+ }
147
+ this.logger.debug('No local bot can see the Slack file', { fileId, tried: candidates.length });
148
+ return null;
149
+ }
150
+ async fileFromMessage(candidates, ref) {
151
+ const ts = ref.messageTs;
152
+ for (const c of candidates) {
153
+ const threaded = !!ref.threadTs && ref.threadTs !== ts;
154
+ const res = await this.slack(threaded ? 'conversations.replies' : 'conversations.history', c.token, {
155
+ channel: ref.channelId,
156
+ ...(threaded ? { ts: ref.threadTs } : {}),
157
+ latest: ts,
158
+ oldest: ts,
159
+ inclusive: 'true',
160
+ limit: threaded ? '5' : '1',
161
+ });
162
+ if (!res.ok)
163
+ continue;
164
+ const message = (res.data.messages ?? []).find((m) => m.ts === ts);
165
+ if (!message)
166
+ continue;
167
+ const ids = (message.files ?? []).map((f) => f.id).filter((id) => !!id);
168
+ if (ids.length === 0)
169
+ throw new SlackFileGetError('no_file_in_message', 'That message has no file attached');
170
+ return { fileId: ids[0], others: ids.slice(1) };
171
+ }
172
+ return null;
173
+ }
174
+ async download(file, token, maxBytes) {
175
+ let url = file.url_private_download || file.url_private;
176
+ if (!url)
177
+ throw new SlackFileGetError('slack_error', 'Slack returned no download URL for that file');
178
+ const controller = new AbortController();
179
+ const timer = setTimeout(() => controller.abort(), SLACK_FILE_FETCH_CONSTANTS.DOWNLOAD_TIMEOUT_MS);
180
+ try {
181
+ for (let hop = 0; hop <= SLACK_FILE_FETCH_CONSTANTS.MAX_REDIRECTS; hop++) {
182
+ const target = new URL(url);
183
+ if (target.protocol !== 'https:' || !isSlackDownloadHost(target.hostname)) {
184
+ throw new SlackFileGetError('slack_error', 'Slack redirected the download somewhere unexpected');
185
+ }
186
+ const sendAuth = target.hostname === 'slack.com' || target.hostname.endsWith('.slack.com');
187
+ const response = await this.fetchImpl(url, {
188
+ headers: sendAuth ? { Authorization: `Bearer ${token}` } : {},
189
+ redirect: 'manual',
190
+ signal: controller.signal,
191
+ });
192
+ if (response.status >= 300 && response.status < 400) {
193
+ const location = response.headers.get('location');
194
+ await response.body?.cancel().catch(() => undefined);
195
+ if (!location)
196
+ throw new SlackFileGetError('slack_error', 'Slack redirect without a location');
197
+ url = new URL(location, url).toString();
198
+ continue;
199
+ }
200
+ if (!response.ok)
201
+ throw new SlackFileGetError('slack_error', `Slack download failed with HTTP ${response.status}`);
202
+ const type = (response.headers.get('content-type') ?? '').toLowerCase();
203
+ if (type.startsWith('text/html') && !(file.mimetype ?? '').toLowerCase().startsWith('text/html')) {
204
+ await response.body?.cancel().catch(() => undefined);
205
+ throw new SlackFileGetError('slack_error', 'Slack served a sign-in page instead of the file');
206
+ }
207
+ return await readCapped(response, maxBytes);
208
+ }
209
+ throw new SlackFileGetError('slack_error', 'Too many redirects downloading the file');
210
+ }
211
+ catch (err) {
212
+ if (err instanceof SlackFileGetError)
213
+ throw err;
214
+ throw new SlackFileGetError('slack_error', `Download failed: ${err instanceof Error ? err.message : String(err)}`);
215
+ }
216
+ finally {
217
+ clearTimeout(timer);
218
+ }
219
+ }
220
+ // ---------------------------------------------------------------------------
221
+ // Cloud
222
+ // ---------------------------------------------------------------------------
223
+ async getViaCloud(fileRef, cloud, requesterAgent, maxBytes) {
224
+ const controller = new AbortController();
225
+ const timer = setTimeout(() => controller.abort(), SLACK_FILE_FETCH_CONSTANTS.DOWNLOAD_TIMEOUT_MS);
226
+ let response;
227
+ try {
228
+ response = await this.fetchImpl(`${cloud.baseUrl.replace(/\/$/, '')}${SLACK_FILE_FETCH_CONSTANTS.CLOUD_FETCH_PATH}`, {
229
+ method: 'POST',
230
+ headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${cloud.token}` },
231
+ body: JSON.stringify({ fileRef, ...(requesterAgent ? { requesterAgent } : {}) }),
232
+ signal: controller.signal,
233
+ });
234
+ }
235
+ catch (err) {
236
+ clearTimeout(timer);
237
+ throw new SlackFileGetError('cloud_unavailable', `Crewly Cloud did not answer: ${err instanceof Error ? err.message : String(err)}`);
238
+ }
239
+ try {
240
+ if (!response.ok) {
241
+ const body = (await response.json().catch(() => null));
242
+ const code = body?.code;
243
+ const known = ['validation', 'not_visible', 'no_file_in_message', 'file_deleted', 'too_large', 'foreign_workspace'];
244
+ if (code && known.includes(code)) {
245
+ throw new SlackFileGetError(code, body?.error ?? code);
246
+ }
247
+ // 404 without a code = a Cloud that does not have this endpoint yet.
248
+ throw new SlackFileGetError('cloud_unavailable', `Crewly Cloud could not fetch the file (HTTP ${response.status}${body?.error ? `: ${body.error}` : ''})`);
249
+ }
250
+ const metaHeader = response.headers.get(SLACK_FILE_FETCH_CONSTANTS.CLOUD_META_HEADER);
251
+ let cloudMeta = {};
252
+ if (metaHeader) {
253
+ try {
254
+ cloudMeta = JSON.parse(Buffer.from(metaHeader, 'base64url').toString('utf8'));
255
+ }
256
+ catch {
257
+ cloudMeta = {};
258
+ }
259
+ }
260
+ const bytes = await readCapped(response, maxBytes);
261
+ const id = typeof cloudMeta.id === 'string' && /^F[A-Z0-9]+$/.test(cloudMeta.id) ? cloudMeta.id : parseSlackFileRef(fileRef)?.fileId ?? 'file';
262
+ const name = typeof cloudMeta.name === 'string' && cloudMeta.name ? cloudMeta.name : id;
263
+ const mimetype = typeof cloudMeta.mimetype === 'string' && cloudMeta.mimetype ? cloudMeta.mimetype : 'application/octet-stream';
264
+ const meta = {
265
+ id,
266
+ name,
267
+ mimetype,
268
+ size: bytes.length,
269
+ user: typeof cloudMeta.user === 'string' ? cloudMeta.user : null,
270
+ channels: Array.isArray(cloudMeta.channels) ? cloudMeta.channels.filter((c) => typeof c === 'string') : [],
271
+ permalink: typeof cloudMeta.permalink === 'string' ? cloudMeta.permalink : null,
272
+ isText: isTextFile(mimetype, name),
273
+ via: `cloud:${typeof cloudMeta.via === 'string' ? cloudMeta.via : 'unknown'}`,
274
+ ...(Array.isArray(cloudMeta.otherFileIds) ? { otherFileIds: cloudMeta.otherFileIds.filter((c) => typeof c === 'string') } : {}),
275
+ };
276
+ const localPath = await this.save(meta, bytes);
277
+ this.logger.info('Slack file fetched through Cloud', { fileId: meta.id, via: meta.via, bytes: bytes.length });
278
+ return { meta, localPath };
279
+ }
280
+ finally {
281
+ clearTimeout(timer);
282
+ }
283
+ }
284
+ // ---------------------------------------------------------------------------
285
+ // Helpers
286
+ // ---------------------------------------------------------------------------
287
+ async save(meta, bytes) {
288
+ await fs.mkdir(this.saveDir, { recursive: true });
289
+ const safeName = path.basename(meta.name).replace(/[^a-zA-Z0-9._-]/g, '_').slice(0, 120) || 'file';
290
+ const safeId = meta.id.replace(/[^A-Za-z0-9]/g, '');
291
+ const localPath = path.join(this.saveDir, `${safeId}-${safeName}`);
292
+ await fs.writeFile(localPath, bytes);
293
+ return localPath;
294
+ }
295
+ async slack(method, token, params) {
296
+ const controller = new AbortController();
297
+ const timer = setTimeout(() => controller.abort(), SLACK_FILE_FETCH_CONSTANTS.API_TIMEOUT_MS);
298
+ try {
299
+ const res = await this.fetchImpl(`${this.apiBase}/${method}`, {
300
+ method: 'POST',
301
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded', Authorization: `Bearer ${token}` },
302
+ body: new URLSearchParams(params),
303
+ signal: controller.signal,
304
+ });
305
+ const body = (await res.json().catch(() => null));
306
+ if (!body || body.ok !== true)
307
+ return { ok: false, error: body?.error ?? `http_${res.status}` };
308
+ return { ok: true, data: body };
309
+ }
310
+ catch (err) {
311
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
312
+ }
313
+ finally {
314
+ clearTimeout(timer);
315
+ }
316
+ }
317
+ }
318
+ /**
319
+ * Read a response body, refusing more than `maxBytes`.
320
+ *
321
+ * @param response - Fetch response
322
+ * @param maxBytes - Cap
323
+ * @returns The bytes
324
+ * @throws {SlackFileGetError} `too_large`
325
+ */
326
+ async function readCapped(response, maxBytes) {
327
+ const declared = Number(response.headers.get('content-length') ?? '');
328
+ if (Number.isFinite(declared) && declared > maxBytes) {
329
+ await response.body?.cancel().catch(() => undefined);
330
+ throw new SlackFileGetError('too_large', `File is ${declared} bytes; the limit is ${maxBytes}`);
331
+ }
332
+ if (!response.body)
333
+ return Buffer.from(await response.arrayBuffer());
334
+ const reader = response.body.getReader();
335
+ const chunks = [];
336
+ let total = 0;
337
+ for (;;) {
338
+ const { done, value } = await reader.read();
339
+ if (done)
340
+ break;
341
+ total += value.byteLength;
342
+ if (total > maxBytes) {
343
+ await reader.cancel().catch(() => undefined);
344
+ throw new SlackFileGetError('too_large', `File is over the ${maxBytes}-byte limit`);
345
+ }
346
+ chunks.push(Buffer.from(value));
347
+ }
348
+ return Buffer.concat(chunks);
349
+ }
350
+ /**
351
+ * The first lines of a text file, for a one-glance preview.
352
+ *
353
+ * @param localPath - Saved file
354
+ * @returns Up to PREVIEW_LINES lines / PREVIEW_CHARS characters
355
+ */
356
+ export async function previewTextFile(localPath) {
357
+ const text = await fs.readFile(localPath, 'utf8');
358
+ const lines = text.split('\n').slice(0, SLACK_FILE_FETCH_CONSTANTS.PREVIEW_LINES).join('\n');
359
+ return lines.length > SLACK_FILE_FETCH_CONSTANTS.PREVIEW_CHARS ? `${lines.slice(0, SLACK_FILE_FETCH_CONSTANTS.PREVIEW_CHARS)}…` : lines;
360
+ }
361
+ let instance = null;
362
+ /**
363
+ * The process-wide service, wired to this instance's Slack identities and
364
+ * Cloud sign-in. Built on first use.
365
+ *
366
+ * @returns The service
367
+ */
368
+ export async function getSlackFileFetchService() {
369
+ if (instance)
370
+ return instance;
371
+ const { getSlackService } = await import('./slack.service.js');
372
+ const { getSlackAgentIdentityService } = await import('./slack-agent-identity.service.js');
373
+ const { getSlackTeamChannelService } = await import('./slack-team-channel.service.js');
374
+ const { CloudClientService } = await import('../cloud/cloud-client.service.js');
375
+ instance = new SlackFileFetchService({
376
+ localCandidates: async (ref, requesterAgent) => {
377
+ const identities = getSlackAgentIdentityService();
378
+ const out = [];
379
+ const push = (token, label) => {
380
+ if (token && !out.some((c) => c.token === token))
381
+ out.push({ token, label });
382
+ };
383
+ const tokenOf = (session) => session ? identities?.getInstalled(session)?.botToken ?? undefined : undefined;
384
+ if (requesterAgent)
385
+ push(tokenOf(requesterAgent), requesterAgent);
386
+ if (ref.uploaderUserId) {
387
+ const uploader = identities?.findByBotUserId(ref.uploaderUserId) ?? null;
388
+ if (uploader)
389
+ push(tokenOf(uploader), uploader);
390
+ }
391
+ if (ref.channelId) {
392
+ for (const session of getSlackTeamChannelService()?.rosterSessions(ref.channelId) ?? [])
393
+ push(tokenOf(session), session);
394
+ }
395
+ push(getSlackService().getBotToken(), 'workspace');
396
+ for (const r of (await identities?.list().catch(() => [])) ?? []) {
397
+ if (r.status === 'installed' && r.botToken)
398
+ push(r.botToken, r.agentSession);
399
+ }
400
+ return out;
401
+ },
402
+ cloud: () => {
403
+ const cloud = CloudClientService.getInstance();
404
+ const token = cloud.getToken();
405
+ const baseUrl = cloud.getCloudUrl();
406
+ return token && baseUrl ? { baseUrl, token } : null;
407
+ },
408
+ });
409
+ return instance;
410
+ }
411
+ /** Replace the process-wide service (tests). */
412
+ export function setSlackFileFetchService(service) {
413
+ instance = service;
414
+ }
415
+ //# sourceMappingURL=slack-file-fetch.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack-file-fetch.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/slack/slack-file-fetch.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Slack file references — turn whatever an agent was handed (a file id, a
3
+ * file permalink, a download URL, a message link) into the ids Slack's API
4
+ * needs.
5
+ *
6
+ * Kept in step with the Cloud copy in
7
+ * `crewly-services/auth/src/slack-file-ref.ts`; both sides parse
8
+ * the same links.
9
+ *
10
+ * @module services/slack/slack-file-ref
11
+ */
12
+ /** What a reference names. */
13
+ export interface SlackFileRef {
14
+ /** Slack file id (`F…`), when the reference names one. */
15
+ fileId?: string;
16
+ /** Uploader's Slack user id, from `/files/<user>/<file>` permalinks. */
17
+ uploaderUserId?: string;
18
+ /** Slack team id embedded in `files-pri` / `files-tmb` / `slack-files.com` URLs. */
19
+ slackTeamId?: string;
20
+ /** Workspace host of a permalink (`acme.slack.com`). */
21
+ workspaceHost?: string;
22
+ /** Channel of a message link (`/archives/<channel>/p<ts>`). */
23
+ channelId?: string;
24
+ /** Message ts of a message link (`1696771234.567890`). */
25
+ messageTs?: string;
26
+ /** Thread parent ts of a message link (`?thread_ts=`). */
27
+ threadTs?: string;
28
+ }
29
+ /**
30
+ * Parse a file reference.
31
+ *
32
+ * Accepted:
33
+ * - `F0123ABCD` (a bare file id)
34
+ * - `https://<ws>.slack.com/files/<user>/<FILE>/<name>` (file permalink)
35
+ * - `https://files.slack.com/files-pri/<TEAM>-<FILE>/<name>` (+ `/download/`)
36
+ * - `https://files.slack.com/files-tmb/<TEAM>-<FILE>-<hash>/<name>`
37
+ * - `https://slack-files.com/<TEAM>-<FILE>-<secret>` (public permalink)
38
+ * - `https://<ws>.slack.com/archives/<CHANNEL>/p<ts>[?thread_ts=…]` (a message carrying files)
39
+ * - any of the above wrapped Slack-style as `<url|label>`
40
+ *
41
+ * @param input - What the agent passed
42
+ * @returns The parsed reference, or null when it is not a Slack file reference
43
+ */
44
+ export declare function parseSlackFileRef(input: string): SlackFileRef | null;
45
+ /**
46
+ * Slack file and message links in a piece of text (deduplicated, in order).
47
+ *
48
+ * @param text - Message text
49
+ * @returns Links that {@link parseSlackFileRef} accepts
50
+ */
51
+ export declare function findSlackFileLinks(text: string): string[];
52
+ /** Hosts a Slack file download may be served from (redirects included). */
53
+ export declare function isSlackDownloadHost(host: string): boolean;
54
+ /**
55
+ * Whether a file is text (so it can be handed back as a string).
56
+ *
57
+ * @param mimetype - Slack mimetype
58
+ * @param name - File name
59
+ * @returns True for text-like files
60
+ */
61
+ export declare function isTextFile(mimetype: string | undefined, name: string | undefined): boolean;
62
+ /** Exposed for tests. */
63
+ export declare const SLACK_ID_PATTERNS: {
64
+ readonly FILE_ID: RegExp;
65
+ readonly USER_ID: RegExp;
66
+ readonly TEAM_ID: RegExp;
67
+ readonly CHANNEL_ID: RegExp;
68
+ };
69
+ //# sourceMappingURL=slack-file-ref.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack-file-ref.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/slack/slack-file-ref.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,8BAA8B;AAC9B,MAAM,WAAW,YAAY;IAC3B,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oFAAoF;IACpF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wDAAwD;IACxD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAuBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CA8DpE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAOzD;AAcD,2EAA2E;AAC3E,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAUzD;AAoBD;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAM1F;AAED,yBAAyB;AACzB,eAAO,MAAM,iBAAiB;;;;;CAAqD,CAAC"}