@mastra/slack 1.5.1 → 1.6.0-alpha.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @mastra/slack
2
2
 
3
+ ## 1.6.0-alpha.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Slack connections can now be owned by an `AgentController`, not just a registered `Agent`. Call `connect` with an options object to connect an owner that has no registered agent: ([#19289](https://github.com/mastra-ai/mastra/pull/19289))
8
+
9
+ ```typescript
10
+ await mastra.channels.slack.connect({
11
+ id: 'my-controller',
12
+ name: 'Support Bot',
13
+ });
14
+ ```
15
+
16
+ Installations record an `ownerType` (`'agent'` by default, or `'agentController'`). Inbound Slack events and OAuth callbacks route to the owning `AgentController`'s channels when `ownerType` is `'agentController'`, so mentions and messages drive a controller session. Existing agent-owned installations are unaffected.
17
+
18
+ ### Patch Changes
19
+
20
+ - Updated dependencies [[`ce93a3c`](https://github.com/mastra-ai/mastra/commit/ce93a3c114ea1cbfbd576f3db41d7c26c9844f5b), [`5718a22`](https://github.com/mastra-ai/mastra/commit/5718a229281dcfd36bcd1f42a242e3717e510a33), [`5807d3a`](https://github.com/mastra-ai/mastra/commit/5807d3ae1d259b8b7d6df7e5bf2b485c694af9c8), [`57661af`](https://github.com/mastra-ai/mastra/commit/57661afeca52ff9af4e72675ede2134fa503d5a5), [`57661af`](https://github.com/mastra-ai/mastra/commit/57661afeca52ff9af4e72675ede2134fa503d5a5), [`57661af`](https://github.com/mastra-ai/mastra/commit/57661afeca52ff9af4e72675ede2134fa503d5a5), [`5718a22`](https://github.com/mastra-ai/mastra/commit/5718a229281dcfd36bcd1f42a242e3717e510a33), [`57661af`](https://github.com/mastra-ai/mastra/commit/57661afeca52ff9af4e72675ede2134fa503d5a5), [`d1b7e3a`](https://github.com/mastra-ai/mastra/commit/d1b7e3a978a309a5653eeaa490d2d6c7c53bd093), [`c093146`](https://github.com/mastra-ai/mastra/commit/c0931466404d3c521308ea119cb165bb7e695155)]:
21
+ - @mastra/core@1.54.0-alpha.1
22
+
3
23
  ## 1.5.1
4
24
 
5
25
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -181,6 +181,33 @@ var SlackManifestClient = class {
181
181
  throw new Error(`App deletion failed: ${data.error}`);
182
182
  }
183
183
  }
184
+ /**
185
+ * Check whether a Slack app still exists.
186
+ *
187
+ * Uses the read-only `apps.manifest.export` endpoint as an existence probe.
188
+ * Returns `false` when Slack reports the app is missing/inaccessible
189
+ * (e.g. it was deleted from the Slack admin UI), `true` when it exports
190
+ * successfully. Network/transport errors are re-thrown so callers can
191
+ * distinguish "app is gone" from "couldn't reach Slack".
192
+ */
193
+ async appExists(appId) {
194
+ await this.rotateToken();
195
+ const response = await fetch(`${SLACK_API_BASE}/apps.manifest.export`, {
196
+ method: "POST",
197
+ headers: {
198
+ "Content-Type": "application/json",
199
+ Authorization: `Bearer ${this.#token}`
200
+ },
201
+ body: JSON.stringify({ app_id: appId }),
202
+ signal: AbortSignal.timeout(SLACK_API_TIMEOUT_MS)
203
+ });
204
+ const data = await response.json();
205
+ if (data.ok) return true;
206
+ if (data.error === "app_not_found" || data.error === "invalid_app_id") {
207
+ return false;
208
+ }
209
+ throw new Error(`Failed to check whether Slack app exists: ${data.error ?? "unknown_error"}`);
210
+ }
184
211
  /**
185
212
  * Update an existing Slack app's manifest.
186
213
  */
@@ -228,7 +255,7 @@ var SlackManifestClient = class {
228
255
  };
229
256
 
230
257
  // src/crypto.ts
231
- var import_crypto = require("crypto");
258
+ var import_node_crypto = require("crypto");
232
259
  function verifySlackRequest(params) {
233
260
  const { signingSecret, timestamp, body, signature } = params;
234
261
  const now = Math.floor(Date.now() / 1e3);
@@ -237,9 +264,9 @@ function verifySlackRequest(params) {
237
264
  return false;
238
265
  }
239
266
  const sigBasestring = `v0:${timestamp}:${body}`;
240
- const expectedSignature = `v0=${(0, import_crypto.createHmac)("sha256", signingSecret).update(sigBasestring).digest("hex")}`;
267
+ const expectedSignature = `v0=${(0, import_node_crypto.createHmac)("sha256", signingSecret).update(sigBasestring).digest("hex")}`;
241
268
  try {
242
- return (0, import_crypto.timingSafeEqual)(Buffer.from(signature), Buffer.from(expectedSignature));
269
+ return (0, import_node_crypto.timingSafeEqual)(Buffer.from(signature), Buffer.from(expectedSignature));
243
270
  } catch {
244
271
  return false;
245
272
  }
@@ -253,10 +280,10 @@ function parseSlackFormBody(body) {
253
280
  }
254
281
  var ALGO_PREFIX = "aes-256-gcm-hkdf";
255
282
  function encrypt(plaintext, key) {
256
- const salt = (0, import_crypto.randomBytes)(16);
257
- const derived = Buffer.from((0, import_crypto.hkdfSync)("sha256", key, salt, "mastra-slack-encryption", 32));
258
- const iv = (0, import_crypto.randomBytes)(12);
259
- const cipher = (0, import_crypto.createCipheriv)("aes-256-gcm", derived, iv);
283
+ const salt = (0, import_node_crypto.randomBytes)(16);
284
+ const derived = Buffer.from((0, import_node_crypto.hkdfSync)("sha256", key, salt, "mastra-slack-encryption", 32));
285
+ const iv = (0, import_node_crypto.randomBytes)(12);
286
+ const cipher = (0, import_node_crypto.createCipheriv)("aes-256-gcm", derived, iv);
260
287
  const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
261
288
  const authTag = cipher.getAuthTag();
262
289
  return `${ALGO_PREFIX}:${salt.toString("base64")}:${iv.toString("base64")}:${authTag.toString("base64")}:${encrypted.toString("base64")}`;
@@ -276,11 +303,11 @@ function decrypt(ciphertext, key) {
276
303
  throw new Error("Invalid ciphertext payload");
277
304
  }
278
305
  const salt = Buffer.from(saltB64, "base64");
279
- const derived = Buffer.from((0, import_crypto.hkdfSync)("sha256", key, salt, "mastra-slack-encryption", 32));
306
+ const derived = Buffer.from((0, import_node_crypto.hkdfSync)("sha256", key, salt, "mastra-slack-encryption", 32));
280
307
  const iv = Buffer.from(ivB64, "base64");
281
308
  const authTag = Buffer.from(authTagB64, "base64");
282
309
  const encrypted = Buffer.from(encryptedB64, "base64");
283
- const decipher = (0, import_crypto.createDecipheriv)("aes-256-gcm", derived, iv);
310
+ const decipher = (0, import_node_crypto.createDecipheriv)("aes-256-gcm", derived, iv);
284
311
  decipher.setAuthTag(authTag);
285
312
  return Buffer.concat([decipher.update(encrypted), decipher.final()]).toString("utf8");
286
313
  }
@@ -14899,7 +14926,9 @@ var SlashCommandSchema = external_exports.object({
14899
14926
  usageHint: external_exports.string().optional(),
14900
14927
  prompt: external_exports.string().optional()
14901
14928
  });
14929
+ var OwnerTypeSchema = external_exports.enum(["agent", "agentController"]);
14902
14930
  var SlackInstallationDataSchema = external_exports.object({
14931
+ ownerType: OwnerTypeSchema.optional(),
14903
14932
  appId: external_exports.string(),
14904
14933
  clientId: external_exports.string(),
14905
14934
  clientSecret: external_exports.string(),
@@ -14916,6 +14945,7 @@ var SlackInstallationDataSchema = external_exports.object({
14916
14945
  slashCommands: external_exports.array(SlashCommandSchema).optional()
14917
14946
  });
14918
14947
  var SlackPendingDataSchema = external_exports.object({
14948
+ ownerType: OwnerTypeSchema.optional(),
14919
14949
  appId: external_exports.string(),
14920
14950
  clientId: external_exports.string(),
14921
14951
  clientSecret: external_exports.string(),
@@ -15245,6 +15275,7 @@ var SlackProvider = class {
15245
15275
  webhookId: installation.webhookId,
15246
15276
  configHash: installation.configHash,
15247
15277
  data: {
15278
+ ownerType: installation.ownerType,
15248
15279
  appId: installation.appId,
15249
15280
  clientId: installation.clientId,
15250
15281
  clientSecret: installation.clientSecret,
@@ -15291,6 +15322,7 @@ var SlackProvider = class {
15291
15322
  webhookId: pending.webhookId,
15292
15323
  configHash: pending.configHash,
15293
15324
  data: {
15325
+ ownerType: pending.ownerType,
15294
15326
  appId: pending.appId,
15295
15327
  clientId: pending.clientId,
15296
15328
  clientSecret: pending.clientSecret,
@@ -15418,7 +15450,7 @@ var SlackProvider = class {
15418
15450
  await this.#checkConfigDrift(installation, baseUrl);
15419
15451
  }
15420
15452
  console.log(
15421
- `[Slack] \u2713 Agent "${installation.agentId}" connected to workspace "${installation.teamName ?? installation.teamId}"`
15453
+ `[Slack] \u2713 App "${installation.name ?? installation.agentId}" (${installation.appId}) connected to workspace "${installation.teamName ?? installation.teamId}"`
15422
15454
  );
15423
15455
  } catch (err) {
15424
15456
  console.error(`[Slack] Failed to restore installation "${installationEncrypted.id}":`, err);
@@ -15430,7 +15462,9 @@ var SlackProvider = class {
15430
15462
  * Creates and injects AgentChannels into the Agent if needed.
15431
15463
  */
15432
15464
  async #activateAdapter(installation) {
15433
- const agent = this.#mastra?.getAgentById(installation.agentId);
15465
+ const isController = installation.ownerType === "agentController";
15466
+ const controller = isController ? this.#resolveAgentController(installation.agentId) : void 0;
15467
+ const agent = isController ? void 0 : this.#resolveAgent(installation.agentId);
15434
15468
  const displayName = installation.name || agent?.name || installation.agentId;
15435
15469
  const adapter = (0, import_slack.createSlackAdapter)({
15436
15470
  ...this.#forwardedAdapterOptions(),
@@ -15443,7 +15477,10 @@ var SlackProvider = class {
15443
15477
  if (installation.slashCommands?.length) {
15444
15478
  this.#slashCommands.set(installation.webhookId, installation.slashCommands);
15445
15479
  }
15446
- if (agent && this.#mastra) {
15480
+ if (controller && this.#mastra) {
15481
+ const controllerChannels = this.#createAgentControllerChannels(controller, adapter);
15482
+ await controllerChannels.initialize(this.#mastra);
15483
+ } else if (agent && this.#mastra) {
15447
15484
  const agentChannels = this.#createAgentChannels(agent, adapter);
15448
15485
  await agentChannels.initialize(this.#mastra);
15449
15486
  }
@@ -15453,7 +15490,8 @@ var SlackProvider = class {
15453
15490
  * If it has, update the Slack app manifest to match the current agent state.
15454
15491
  */
15455
15492
  async #checkConfigDrift(installation, baseUrl) {
15456
- const agent = this.#mastra?.getAgentById(installation.agentId);
15493
+ if (installation.ownerType === "agentController") return;
15494
+ const agent = this.#resolveAgent(installation.agentId);
15457
15495
  if (!agent) return;
15458
15496
  const resolvedAppName = installation.name ?? agent.name ?? installation.agentId;
15459
15497
  const resolvedDescription = installation.description || agent.getDescription() || "AI assistant powered by Mastra";
@@ -15481,7 +15519,9 @@ var SlackProvider = class {
15481
15519
  await this.#requireManifestClient().updateApp(installation.appId, manifest);
15482
15520
  const updated = { ...installation, configHash: currentHash };
15483
15521
  await this.#saveInstallation(this.#encryptInstallation(updated));
15484
- console.log(`[Slack] \u2713 Manifest updated for "${installation.agentId}" (app: ${installation.appId})`);
15522
+ console.log(
15523
+ `[Slack] \u2713 Manifest updated for app "${installation.name ?? installation.agentId}" (${installation.appId})`
15524
+ );
15485
15525
  } catch (err) {
15486
15526
  const errMsg = err instanceof Error ? err.message : String(err);
15487
15527
  const isAppGone = errMsg.includes("app_not_found") || errMsg.includes("no_permission");
@@ -15514,7 +15554,15 @@ var SlackProvider = class {
15514
15554
  */
15515
15555
  #forwardedChannelOptions() {
15516
15556
  const { handlers, inlineMedia, inlineLinks, state, threadContext, tools, chatOptions } = this.#channelConfig;
15517
- const candidate = { handlers, inlineMedia, inlineLinks, state, threadContext, tools, chatOptions };
15557
+ const candidate = {
15558
+ handlers,
15559
+ inlineMedia,
15560
+ inlineLinks,
15561
+ state,
15562
+ threadContext,
15563
+ tools,
15564
+ chatOptions
15565
+ };
15518
15566
  return Object.fromEntries(Object.entries(candidate).filter(([, value]) => value !== void 0));
15519
15567
  }
15520
15568
  /**
@@ -15579,6 +15627,68 @@ var SlackProvider = class {
15579
15627
  agent.setChannels(agentChannels);
15580
15628
  return agentChannels;
15581
15629
  }
15630
+ /**
15631
+ * Controller-parallel of {@link #createAgentChannels}: build a fresh
15632
+ * {@link AgentControllerChannels} that preserves any config the controller
15633
+ * already had (including other adapters) and layers this Slack adapter on,
15634
+ * then swap it onto the controller via `setChannels`. Mirrors the agent path
15635
+ * — a superset merge, not a mutation of the live instance.
15636
+ *
15637
+ * The swap discards the old instance's in-memory `autoApproveResourceIds`
15638
+ * tracking. That's fine: the set is refreshed on every inbound message, and
15639
+ * Slack renders approval buttons anyway so it stays empty here.
15640
+ */
15641
+ #createAgentControllerChannels(controller, adapter) {
15642
+ const adapterConfig = this.#resolveSlackAdapterConfig();
15643
+ const slackEntry = Object.keys(adapterConfig).length > 0 ? { adapter, ...adapterConfig } : adapter;
15644
+ const existing = controller.getChannels();
15645
+ const existingConfig = existing?.channelConfig;
15646
+ const controllerChannels = new import_channels.AgentControllerChannels({
15647
+ ...existingConfig,
15648
+ ...this.#forwardedChannelOptions(),
15649
+ adapters: { ...existingConfig?.adapters, slack: slackEntry },
15650
+ userName: controller.id
15651
+ });
15652
+ controller.setChannels(controllerChannels);
15653
+ return controllerChannels;
15654
+ }
15655
+ /**
15656
+ * Resolve the live channels instance that should handle an incoming webhook
15657
+ * for this installation, branching on `ownerType`. Reuses an existing
15658
+ * instance when it already carries the current adapter (e.g. from startup
15659
+ * activation), otherwise builds a fresh one and initializes it. Returns null
15660
+ * when the owner (agent or controller) can't be resolved.
15661
+ */
15662
+ async #resolveChannelsForInstallation(installation, currentAdapter) {
15663
+ if (!this.#mastra) {
15664
+ console.error("[Slack] Mastra not attached");
15665
+ return null;
15666
+ }
15667
+ if (installation.ownerType === "agentController") {
15668
+ const controller = this.#resolveAgentController(installation.agentId);
15669
+ if (!controller) {
15670
+ console.error(`[Slack] Agent controller "${installation.agentId}" not found`);
15671
+ return null;
15672
+ }
15673
+ let channels2 = controller.getChannels();
15674
+ if (!channels2 || channels2.adapters.slack !== currentAdapter) {
15675
+ channels2 = this.#createAgentControllerChannels(controller, currentAdapter);
15676
+ await channels2.initialize(this.#mastra);
15677
+ }
15678
+ return channels2;
15679
+ }
15680
+ const agent = this.#resolveAgent(installation.agentId);
15681
+ if (!agent) {
15682
+ console.error(`[Slack] Agent "${installation.agentId}" not found`);
15683
+ return null;
15684
+ }
15685
+ let channels = agent.getChannels();
15686
+ if (!channels || channels.adapters.slack !== currentAdapter) {
15687
+ channels = this.#createAgentChannels(agent, currentAdapter);
15688
+ await channels.initialize(this.#mastra);
15689
+ }
15690
+ return channels;
15691
+ }
15582
15692
  /**
15583
15693
  * Auto-initialize on first route hit.
15584
15694
  * Delegates to initialize() which handles idempotency.
@@ -15642,15 +15752,13 @@ var SlackProvider = class {
15642
15752
  }
15643
15753
  ];
15644
15754
  }
15645
- // ===========================================================================
15646
- // Public API
15647
- // ===========================================================================
15648
- /**
15649
- * Connect an agent to Slack by creating a new Slack app.
15650
- *
15651
- * @returns OAuth connect result with authorization URL for user redirect
15652
- */
15653
- async connect(agentId, options) {
15755
+ async connect(agentIdOrOptions, maybeOptions) {
15756
+ const isAgentIdForm = typeof agentIdOrOptions === "string";
15757
+ const agentId = isAgentIdForm ? agentIdOrOptions : agentIdOrOptions.id;
15758
+ const options = isAgentIdForm ? maybeOptions : agentIdOrOptions;
15759
+ if (!isAgentIdForm && !agentIdOrOptions.name) {
15760
+ throw new Error('connect({ id, name }): "name" is required when connecting without an agent id');
15761
+ }
15654
15762
  const client = this.#requireManifestClient();
15655
15763
  const baseUrl = this.#getBaseUrl();
15656
15764
  if (!baseUrl) {
@@ -15659,26 +15767,45 @@ var SlackProvider = class {
15659
15767
  );
15660
15768
  }
15661
15769
  const agent = this.#resolveAgent(agentId);
15662
- if (!agent) {
15770
+ if (isAgentIdForm && !agent) {
15663
15771
  throw new Error(`Agent "${agentId}" not found`);
15664
15772
  }
15773
+ let ownerType = "agent";
15774
+ if (!isAgentIdForm && !agent) {
15775
+ const controller = this.#resolveAgentController(agentId);
15776
+ if (!controller) {
15777
+ throw new Error(`No agent or agent controller found with id "${agentId}"`);
15778
+ }
15779
+ ownerType = "agentController";
15780
+ }
15665
15781
  const storage = await this.#getStorage();
15666
15782
  const existingRecord = await storage.getInstallationByAgent(PLATFORM, agentId);
15667
15783
  if (existingRecord?.status === "pending") {
15668
15784
  try {
15669
15785
  const pending = this.#parsePendingInstallation(existingRecord);
15670
15786
  const decrypted = this.#decryptPendingInstallation(pending);
15671
- if (options?.redirectUrl && decrypted.redirectUrl !== options.redirectUrl) {
15672
- await this.#savePendingInstallation(
15673
- this.#encryptPendingInstallation({ ...decrypted, redirectUrl: options.redirectUrl })
15674
- );
15787
+ let appStillExists = true;
15788
+ try {
15789
+ appStillExists = await client.appExists(decrypted.appId);
15790
+ } catch (err) {
15791
+ console.warn(`[Slack] Could not verify existing app for "${agentId}", reusing pending installation:`, err);
15792
+ }
15793
+ if (!appStillExists) {
15794
+ console.warn(`[Slack] Stored app for "${agentId}" no longer exists on Slack, creating a fresh installation`);
15795
+ await storage.deleteInstallation(existingRecord.id);
15796
+ } else {
15797
+ if (options?.redirectUrl && decrypted.redirectUrl !== options.redirectUrl) {
15798
+ await this.#savePendingInstallation(
15799
+ this.#encryptPendingInstallation({ ...decrypted, redirectUrl: options.redirectUrl })
15800
+ );
15801
+ }
15802
+ console.log(`[Slack] Reusing existing pending installation for "${agentId}"`);
15803
+ return {
15804
+ type: "oauth",
15805
+ installationId: decrypted.id,
15806
+ authorizationUrl: decrypted.authorizationUrl
15807
+ };
15675
15808
  }
15676
- console.log(`[Slack] Reusing existing pending installation for "${agentId}"`);
15677
- return {
15678
- type: "oauth",
15679
- installationId: decrypted.id,
15680
- authorizationUrl: decrypted.authorizationUrl
15681
- };
15682
15809
  } catch {
15683
15810
  console.warn(`[Slack] Corrupt pending installation for "${agentId}", replacing it`);
15684
15811
  await storage.deleteInstallation(existingRecord.id);
@@ -15689,8 +15816,8 @@ var SlackProvider = class {
15689
15816
  }
15690
15817
  const config2 = options ?? {};
15691
15818
  const webhookId = crypto.randomUUID();
15692
- const appName = config2.name ?? agent.name ?? agentId;
15693
- const appDescription = config2.description || agent.getDescription() || "AI assistant powered by Mastra";
15819
+ const appName = config2.name ?? agent?.name ?? agentId;
15820
+ const appDescription = config2.description || agent?.getDescription() || "AI assistant powered by Mastra";
15694
15821
  const normalizedCommands = this.#normalizeCommands(config2.slashCommands);
15695
15822
  let manifest = buildManifest({
15696
15823
  name: appName,
@@ -15733,6 +15860,7 @@ var SlackProvider = class {
15733
15860
  const pendingInstallation = this.#encryptPendingInstallation({
15734
15861
  id: installationId,
15735
15862
  agentId,
15863
+ ownerType,
15736
15864
  webhookId,
15737
15865
  appId: appCredentials.appId,
15738
15866
  clientId: appCredentials.clientId,
@@ -15941,6 +16069,7 @@ var SlackProvider = class {
15941
16069
  const installation = {
15942
16070
  id: pending.id,
15943
16071
  agentId: pending.agentId,
16072
+ ownerType: pending.ownerType ?? "agent",
15944
16073
  webhookId: pending.webhookId,
15945
16074
  appId: pending.appId,
15946
16075
  clientId: pending.clientId,
@@ -15958,7 +16087,11 @@ var SlackProvider = class {
15958
16087
  };
15959
16088
  const encryptedInstallation = this.#encryptInstallation(installation);
15960
16089
  await this.#saveInstallation(encryptedInstallation);
15961
- const agent = this.#mastra?.getAgentById(pending.agentId);
16090
+ let agent;
16091
+ try {
16092
+ agent = installation.ownerType === "agent" ? this.#mastra?.getAgentById(pending.agentId) : void 0;
16093
+ } catch {
16094
+ }
15962
16095
  const displayName = installation.name || agent?.name || pending.agentId;
15963
16096
  const adapter = (0, import_slack.createSlackAdapter)({
15964
16097
  ...this.#forwardedAdapterOptions(),
@@ -15975,7 +16108,9 @@ var SlackProvider = class {
15975
16108
  await this.#channelConfig.onInstall(installation);
15976
16109
  }
15977
16110
  const teamName = tokenData.team?.name ?? "";
15978
- console.log(`[Slack] \u2713 Agent "${pending.agentId}" installed to team "${teamName}"`);
16111
+ console.log(
16112
+ `[Slack] \u2713 App "${installation.name ?? installation.agentId}" (${installation.appId}) installed to workspace "${teamName || installation.teamId}"`
16113
+ );
15979
16114
  const successUrl = pending.redirectUrl ?? this.#channelConfig.redirectPath ?? "/";
15980
16115
  const redirect = new URL(successUrl, c.req.url);
15981
16116
  redirect.searchParams.set("channel_connected", "true");
@@ -16030,16 +16165,11 @@ var SlackProvider = class {
16030
16165
  return c.json({ challenge: event.challenge });
16031
16166
  }
16032
16167
  }
16033
- const agent = this.#resolveAgent(installation.agentId);
16034
- if (!agent) {
16035
- console.error(`[Slack] Agent "${installation.agentId}" not found`);
16036
- return c.json({ ok: true });
16037
- }
16038
16168
  if (!this.#mastra) {
16039
16169
  console.error("[Slack] Mastra not attached");
16040
16170
  return c.json({ ok: true });
16041
16171
  }
16042
- const displayName = installation.name || agent.name || installation.agentId;
16172
+ const displayName = installation.name || installation.agentId;
16043
16173
  const currentAdapter = this.#adapters.get(installation.id) ?? (0, import_slack.createSlackAdapter)({
16044
16174
  ...this.#forwardedAdapterOptions(),
16045
16175
  botToken: installation.botToken,
@@ -16047,10 +16177,9 @@ var SlackProvider = class {
16047
16177
  signingSecret: installation.signingSecret,
16048
16178
  userName: displayName
16049
16179
  });
16050
- let agentChannels = agent.getChannels();
16051
- if (!agentChannels || agentChannels.adapters.slack !== currentAdapter) {
16052
- agentChannels = this.#createAgentChannels(agent, currentAdapter);
16053
- await agentChannels.initialize(this.#mastra);
16180
+ const agentChannels = await this.#resolveChannelsForInstallation(installation, currentAdapter);
16181
+ if (!agentChannels) {
16182
+ return c.json({ ok: true });
16054
16183
  }
16055
16184
  const delegateRequest = new Request(c.req.url, {
16056
16185
  method: c.req.method,
@@ -16101,6 +16230,12 @@ var SlackProvider = class {
16101
16230
  if (!commandConfig) {
16102
16231
  return c.json({ response_type: "ephemeral", text: `Unknown command: ${command}` });
16103
16232
  }
16233
+ if (installation.ownerType === "agentController") {
16234
+ return c.json({
16235
+ response_type: "ephemeral",
16236
+ text: "Slash commands are not supported for this app yet. Mention the bot in a thread to start a session."
16237
+ });
16238
+ }
16104
16239
  const agent = this.#resolveAgent(installation.agentId);
16105
16240
  if (!agent) {
16106
16241
  return c.json({ response_type: "ephemeral", text: "Agent not available" });
@@ -16142,6 +16277,13 @@ var SlackProvider = class {
16142
16277
  return void 0;
16143
16278
  }
16144
16279
  }
16280
+ #resolveAgentController(controllerId) {
16281
+ try {
16282
+ return this.#mastra?.getAgentControllerById(controllerId);
16283
+ } catch {
16284
+ return void 0;
16285
+ }
16286
+ }
16145
16287
  };
16146
16288
 
16147
16289
  // src/index.ts