@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/dist/index.d.cts CHANGED
@@ -16,7 +16,17 @@ declare const SlashCommandSchema: z.ZodObject<{
16
16
  usageHint: z.ZodOptional<z.ZodString>;
17
17
  prompt: z.ZodOptional<z.ZodString>;
18
18
  }, z.core.$strip>;
19
+ /** Who owns an installation: a registered Agent (default) or an AgentController. */
20
+ declare const OwnerTypeSchema: z.ZodEnum<{
21
+ agent: "agent";
22
+ agentController: "agentController";
23
+ }>;
24
+ type SlackOwnerType = z.infer<typeof OwnerTypeSchema>;
19
25
  declare const SlackInstallationDataSchema: z.ZodObject<{
26
+ ownerType: z.ZodOptional<z.ZodEnum<{
27
+ agent: "agent";
28
+ agentController: "agentController";
29
+ }>>;
20
30
  appId: z.ZodString;
21
31
  clientId: z.ZodString;
22
32
  clientSecret: z.ZodString;
@@ -36,6 +46,10 @@ declare const SlackInstallationDataSchema: z.ZodObject<{
36
46
  }, z.core.$strip>;
37
47
  type SlackInstallationData = z.infer<typeof SlackInstallationDataSchema>;
38
48
  declare const SlackPendingDataSchema: z.ZodObject<{
49
+ ownerType: z.ZodOptional<z.ZodEnum<{
50
+ agent: "agent";
51
+ agentController: "agentController";
52
+ }>>;
39
53
  appId: z.ZodString;
40
54
  clientId: z.ZodString;
41
55
  clientSecret: z.ZodString;
@@ -61,7 +75,10 @@ type SlackConfigData = z.infer<typeof SlackConfigDataSchema>;
61
75
  type StoredSlashCommand = z.infer<typeof SlashCommandSchema>;
62
76
  interface SlackInstallation {
63
77
  id: string;
78
+ /** Owner key: an agent id when ownerType is 'agent' (default), or an AgentController id. */
64
79
  agentId: string;
80
+ /** Defaults to 'agent' when absent (pre-existing installations). */
81
+ ownerType?: SlackOwnerType;
65
82
  webhookId: string;
66
83
  configHash: string;
67
84
  installedAt: Date;
@@ -81,7 +98,10 @@ interface SlackInstallation {
81
98
  }
82
99
  interface SlackPendingInstallation {
83
100
  id: string;
101
+ /** Owner key: an agent id when ownerType is 'agent' (default), or an AgentController id. */
84
102
  agentId: string;
103
+ /** Defaults to 'agent' when absent (pre-existing installations). */
104
+ ownerType?: SlackOwnerType;
85
105
  webhookId: string;
86
106
  configHash: string;
87
107
  createdAt: Date;
@@ -665,6 +685,17 @@ declare class SlackProvider implements ChannelProvider {
665
685
  * @returns OAuth connect result with authorization URL for user redirect
666
686
  */
667
687
  connect(agentId: string, options?: SlackConnectOptions): Promise<ChannelConnectResult>;
688
+ /**
689
+ * Connect to Slack by creating a new Slack app for an arbitrary connection id
690
+ * (no registered agent required — e.g. an AgentController or custom owner).
691
+ * Since there is no agent to derive a display name from, `name` is required.
692
+ *
693
+ * @returns OAuth connect result with authorization URL for user redirect
694
+ */
695
+ connect(options: SlackConnectOptions & {
696
+ id: string;
697
+ name: string;
698
+ }): Promise<ChannelConnectResult>;
668
699
  /**
669
700
  * Disconnect an agent from Slack by deleting its app.
670
701
  */
@@ -740,6 +771,16 @@ declare class SlackManifestClient {
740
771
  * Delete a Slack app.
741
772
  */
742
773
  deleteApp(appId: string): Promise<void>;
774
+ /**
775
+ * Check whether a Slack app still exists.
776
+ *
777
+ * Uses the read-only `apps.manifest.export` endpoint as an existence probe.
778
+ * Returns `false` when Slack reports the app is missing/inaccessible
779
+ * (e.g. it was deleted from the Slack admin UI), `true` when it exports
780
+ * successfully. Network/transport errors are re-thrown so callers can
781
+ * distinguish "app is gone" from "couldn't reach Slack".
782
+ */
783
+ appExists(appId: string): Promise<boolean>;
743
784
  /**
744
785
  * Update an existing Slack app's manifest.
745
786
  */
package/dist/index.d.ts CHANGED
@@ -16,7 +16,17 @@ declare const SlashCommandSchema: z.ZodObject<{
16
16
  usageHint: z.ZodOptional<z.ZodString>;
17
17
  prompt: z.ZodOptional<z.ZodString>;
18
18
  }, z.core.$strip>;
19
+ /** Who owns an installation: a registered Agent (default) or an AgentController. */
20
+ declare const OwnerTypeSchema: z.ZodEnum<{
21
+ agent: "agent";
22
+ agentController: "agentController";
23
+ }>;
24
+ type SlackOwnerType = z.infer<typeof OwnerTypeSchema>;
19
25
  declare const SlackInstallationDataSchema: z.ZodObject<{
26
+ ownerType: z.ZodOptional<z.ZodEnum<{
27
+ agent: "agent";
28
+ agentController: "agentController";
29
+ }>>;
20
30
  appId: z.ZodString;
21
31
  clientId: z.ZodString;
22
32
  clientSecret: z.ZodString;
@@ -36,6 +46,10 @@ declare const SlackInstallationDataSchema: z.ZodObject<{
36
46
  }, z.core.$strip>;
37
47
  type SlackInstallationData = z.infer<typeof SlackInstallationDataSchema>;
38
48
  declare const SlackPendingDataSchema: z.ZodObject<{
49
+ ownerType: z.ZodOptional<z.ZodEnum<{
50
+ agent: "agent";
51
+ agentController: "agentController";
52
+ }>>;
39
53
  appId: z.ZodString;
40
54
  clientId: z.ZodString;
41
55
  clientSecret: z.ZodString;
@@ -61,7 +75,10 @@ type SlackConfigData = z.infer<typeof SlackConfigDataSchema>;
61
75
  type StoredSlashCommand = z.infer<typeof SlashCommandSchema>;
62
76
  interface SlackInstallation {
63
77
  id: string;
78
+ /** Owner key: an agent id when ownerType is 'agent' (default), or an AgentController id. */
64
79
  agentId: string;
80
+ /** Defaults to 'agent' when absent (pre-existing installations). */
81
+ ownerType?: SlackOwnerType;
65
82
  webhookId: string;
66
83
  configHash: string;
67
84
  installedAt: Date;
@@ -81,7 +98,10 @@ interface SlackInstallation {
81
98
  }
82
99
  interface SlackPendingInstallation {
83
100
  id: string;
101
+ /** Owner key: an agent id when ownerType is 'agent' (default), or an AgentController id. */
84
102
  agentId: string;
103
+ /** Defaults to 'agent' when absent (pre-existing installations). */
104
+ ownerType?: SlackOwnerType;
85
105
  webhookId: string;
86
106
  configHash: string;
87
107
  createdAt: Date;
@@ -665,6 +685,17 @@ declare class SlackProvider implements ChannelProvider {
665
685
  * @returns OAuth connect result with authorization URL for user redirect
666
686
  */
667
687
  connect(agentId: string, options?: SlackConnectOptions): Promise<ChannelConnectResult>;
688
+ /**
689
+ * Connect to Slack by creating a new Slack app for an arbitrary connection id
690
+ * (no registered agent required — e.g. an AgentController or custom owner).
691
+ * Since there is no agent to derive a display name from, `name` is required.
692
+ *
693
+ * @returns OAuth connect result with authorization URL for user redirect
694
+ */
695
+ connect(options: SlackConnectOptions & {
696
+ id: string;
697
+ name: string;
698
+ }): Promise<ChannelConnectResult>;
668
699
  /**
669
700
  * Disconnect an agent from Slack by deleting its app.
670
701
  */
@@ -740,6 +771,16 @@ declare class SlackManifestClient {
740
771
  * Delete a Slack app.
741
772
  */
742
773
  deleteApp(appId: string): Promise<void>;
774
+ /**
775
+ * Check whether a Slack app still exists.
776
+ *
777
+ * Uses the read-only `apps.manifest.export` endpoint as an existence probe.
778
+ * Returns `false` when Slack reports the app is missing/inaccessible
779
+ * (e.g. it was deleted from the Slack admin UI), `true` when it exports
780
+ * successfully. Network/transport errors are re-thrown so callers can
781
+ * distinguish "app is gone" from "couldn't reach Slack".
782
+ */
783
+ appExists(appId: string): Promise<boolean>;
743
784
  /**
744
785
  * Update an existing Slack app's manifest.
745
786
  */
package/dist/index.js CHANGED
@@ -8,6 +8,7 @@ var __export = (target, all) => {
8
8
  import * as crypto from "crypto";
9
9
  import {
10
10
  AgentChannels,
11
+ AgentControllerChannels,
11
12
  resolveWaitUntil
12
13
  } from "@mastra/core/channels";
13
14
  import "@mastra/core/storage";
@@ -144,6 +145,33 @@ var SlackManifestClient = class {
144
145
  throw new Error(`App deletion failed: ${data.error}`);
145
146
  }
146
147
  }
148
+ /**
149
+ * Check whether a Slack app still exists.
150
+ *
151
+ * Uses the read-only `apps.manifest.export` endpoint as an existence probe.
152
+ * Returns `false` when Slack reports the app is missing/inaccessible
153
+ * (e.g. it was deleted from the Slack admin UI), `true` when it exports
154
+ * successfully. Network/transport errors are re-thrown so callers can
155
+ * distinguish "app is gone" from "couldn't reach Slack".
156
+ */
157
+ async appExists(appId) {
158
+ await this.rotateToken();
159
+ const response = await fetch(`${SLACK_API_BASE}/apps.manifest.export`, {
160
+ method: "POST",
161
+ headers: {
162
+ "Content-Type": "application/json",
163
+ Authorization: `Bearer ${this.#token}`
164
+ },
165
+ body: JSON.stringify({ app_id: appId }),
166
+ signal: AbortSignal.timeout(SLACK_API_TIMEOUT_MS)
167
+ });
168
+ const data = await response.json();
169
+ if (data.ok) return true;
170
+ if (data.error === "app_not_found" || data.error === "invalid_app_id") {
171
+ return false;
172
+ }
173
+ throw new Error(`Failed to check whether Slack app exists: ${data.error ?? "unknown_error"}`);
174
+ }
147
175
  /**
148
176
  * Update an existing Slack app's manifest.
149
177
  */
@@ -14862,7 +14890,9 @@ var SlashCommandSchema = external_exports.object({
14862
14890
  usageHint: external_exports.string().optional(),
14863
14891
  prompt: external_exports.string().optional()
14864
14892
  });
14893
+ var OwnerTypeSchema = external_exports.enum(["agent", "agentController"]);
14865
14894
  var SlackInstallationDataSchema = external_exports.object({
14895
+ ownerType: OwnerTypeSchema.optional(),
14866
14896
  appId: external_exports.string(),
14867
14897
  clientId: external_exports.string(),
14868
14898
  clientSecret: external_exports.string(),
@@ -14879,6 +14909,7 @@ var SlackInstallationDataSchema = external_exports.object({
14879
14909
  slashCommands: external_exports.array(SlashCommandSchema).optional()
14880
14910
  });
14881
14911
  var SlackPendingDataSchema = external_exports.object({
14912
+ ownerType: OwnerTypeSchema.optional(),
14882
14913
  appId: external_exports.string(),
14883
14914
  clientId: external_exports.string(),
14884
14915
  clientSecret: external_exports.string(),
@@ -15208,6 +15239,7 @@ var SlackProvider = class {
15208
15239
  webhookId: installation.webhookId,
15209
15240
  configHash: installation.configHash,
15210
15241
  data: {
15242
+ ownerType: installation.ownerType,
15211
15243
  appId: installation.appId,
15212
15244
  clientId: installation.clientId,
15213
15245
  clientSecret: installation.clientSecret,
@@ -15254,6 +15286,7 @@ var SlackProvider = class {
15254
15286
  webhookId: pending.webhookId,
15255
15287
  configHash: pending.configHash,
15256
15288
  data: {
15289
+ ownerType: pending.ownerType,
15257
15290
  appId: pending.appId,
15258
15291
  clientId: pending.clientId,
15259
15292
  clientSecret: pending.clientSecret,
@@ -15381,7 +15414,7 @@ var SlackProvider = class {
15381
15414
  await this.#checkConfigDrift(installation, baseUrl);
15382
15415
  }
15383
15416
  console.log(
15384
- `[Slack] \u2713 Agent "${installation.agentId}" connected to workspace "${installation.teamName ?? installation.teamId}"`
15417
+ `[Slack] \u2713 App "${installation.name ?? installation.agentId}" (${installation.appId}) connected to workspace "${installation.teamName ?? installation.teamId}"`
15385
15418
  );
15386
15419
  } catch (err) {
15387
15420
  console.error(`[Slack] Failed to restore installation "${installationEncrypted.id}":`, err);
@@ -15393,7 +15426,9 @@ var SlackProvider = class {
15393
15426
  * Creates and injects AgentChannels into the Agent if needed.
15394
15427
  */
15395
15428
  async #activateAdapter(installation) {
15396
- const agent = this.#mastra?.getAgentById(installation.agentId);
15429
+ const isController = installation.ownerType === "agentController";
15430
+ const controller = isController ? this.#resolveAgentController(installation.agentId) : void 0;
15431
+ const agent = isController ? void 0 : this.#resolveAgent(installation.agentId);
15397
15432
  const displayName = installation.name || agent?.name || installation.agentId;
15398
15433
  const adapter = createSlackAdapter({
15399
15434
  ...this.#forwardedAdapterOptions(),
@@ -15406,7 +15441,10 @@ var SlackProvider = class {
15406
15441
  if (installation.slashCommands?.length) {
15407
15442
  this.#slashCommands.set(installation.webhookId, installation.slashCommands);
15408
15443
  }
15409
- if (agent && this.#mastra) {
15444
+ if (controller && this.#mastra) {
15445
+ const controllerChannels = this.#createAgentControllerChannels(controller, adapter);
15446
+ await controllerChannels.initialize(this.#mastra);
15447
+ } else if (agent && this.#mastra) {
15410
15448
  const agentChannels = this.#createAgentChannels(agent, adapter);
15411
15449
  await agentChannels.initialize(this.#mastra);
15412
15450
  }
@@ -15416,7 +15454,8 @@ var SlackProvider = class {
15416
15454
  * If it has, update the Slack app manifest to match the current agent state.
15417
15455
  */
15418
15456
  async #checkConfigDrift(installation, baseUrl) {
15419
- const agent = this.#mastra?.getAgentById(installation.agentId);
15457
+ if (installation.ownerType === "agentController") return;
15458
+ const agent = this.#resolveAgent(installation.agentId);
15420
15459
  if (!agent) return;
15421
15460
  const resolvedAppName = installation.name ?? agent.name ?? installation.agentId;
15422
15461
  const resolvedDescription = installation.description || agent.getDescription() || "AI assistant powered by Mastra";
@@ -15444,7 +15483,9 @@ var SlackProvider = class {
15444
15483
  await this.#requireManifestClient().updateApp(installation.appId, manifest);
15445
15484
  const updated = { ...installation, configHash: currentHash };
15446
15485
  await this.#saveInstallation(this.#encryptInstallation(updated));
15447
- console.log(`[Slack] \u2713 Manifest updated for "${installation.agentId}" (app: ${installation.appId})`);
15486
+ console.log(
15487
+ `[Slack] \u2713 Manifest updated for app "${installation.name ?? installation.agentId}" (${installation.appId})`
15488
+ );
15448
15489
  } catch (err) {
15449
15490
  const errMsg = err instanceof Error ? err.message : String(err);
15450
15491
  const isAppGone = errMsg.includes("app_not_found") || errMsg.includes("no_permission");
@@ -15477,7 +15518,15 @@ var SlackProvider = class {
15477
15518
  */
15478
15519
  #forwardedChannelOptions() {
15479
15520
  const { handlers, inlineMedia, inlineLinks, state, threadContext, tools, chatOptions } = this.#channelConfig;
15480
- const candidate = { handlers, inlineMedia, inlineLinks, state, threadContext, tools, chatOptions };
15521
+ const candidate = {
15522
+ handlers,
15523
+ inlineMedia,
15524
+ inlineLinks,
15525
+ state,
15526
+ threadContext,
15527
+ tools,
15528
+ chatOptions
15529
+ };
15481
15530
  return Object.fromEntries(Object.entries(candidate).filter(([, value]) => value !== void 0));
15482
15531
  }
15483
15532
  /**
@@ -15542,6 +15591,68 @@ var SlackProvider = class {
15542
15591
  agent.setChannels(agentChannels);
15543
15592
  return agentChannels;
15544
15593
  }
15594
+ /**
15595
+ * Controller-parallel of {@link #createAgentChannels}: build a fresh
15596
+ * {@link AgentControllerChannels} that preserves any config the controller
15597
+ * already had (including other adapters) and layers this Slack adapter on,
15598
+ * then swap it onto the controller via `setChannels`. Mirrors the agent path
15599
+ * — a superset merge, not a mutation of the live instance.
15600
+ *
15601
+ * The swap discards the old instance's in-memory `autoApproveResourceIds`
15602
+ * tracking. That's fine: the set is refreshed on every inbound message, and
15603
+ * Slack renders approval buttons anyway so it stays empty here.
15604
+ */
15605
+ #createAgentControllerChannels(controller, adapter) {
15606
+ const adapterConfig = this.#resolveSlackAdapterConfig();
15607
+ const slackEntry = Object.keys(adapterConfig).length > 0 ? { adapter, ...adapterConfig } : adapter;
15608
+ const existing = controller.getChannels();
15609
+ const existingConfig = existing?.channelConfig;
15610
+ const controllerChannels = new AgentControllerChannels({
15611
+ ...existingConfig,
15612
+ ...this.#forwardedChannelOptions(),
15613
+ adapters: { ...existingConfig?.adapters, slack: slackEntry },
15614
+ userName: controller.id
15615
+ });
15616
+ controller.setChannels(controllerChannels);
15617
+ return controllerChannels;
15618
+ }
15619
+ /**
15620
+ * Resolve the live channels instance that should handle an incoming webhook
15621
+ * for this installation, branching on `ownerType`. Reuses an existing
15622
+ * instance when it already carries the current adapter (e.g. from startup
15623
+ * activation), otherwise builds a fresh one and initializes it. Returns null
15624
+ * when the owner (agent or controller) can't be resolved.
15625
+ */
15626
+ async #resolveChannelsForInstallation(installation, currentAdapter) {
15627
+ if (!this.#mastra) {
15628
+ console.error("[Slack] Mastra not attached");
15629
+ return null;
15630
+ }
15631
+ if (installation.ownerType === "agentController") {
15632
+ const controller = this.#resolveAgentController(installation.agentId);
15633
+ if (!controller) {
15634
+ console.error(`[Slack] Agent controller "${installation.agentId}" not found`);
15635
+ return null;
15636
+ }
15637
+ let channels2 = controller.getChannels();
15638
+ if (!channels2 || channels2.adapters.slack !== currentAdapter) {
15639
+ channels2 = this.#createAgentControllerChannels(controller, currentAdapter);
15640
+ await channels2.initialize(this.#mastra);
15641
+ }
15642
+ return channels2;
15643
+ }
15644
+ const agent = this.#resolveAgent(installation.agentId);
15645
+ if (!agent) {
15646
+ console.error(`[Slack] Agent "${installation.agentId}" not found`);
15647
+ return null;
15648
+ }
15649
+ let channels = agent.getChannels();
15650
+ if (!channels || channels.adapters.slack !== currentAdapter) {
15651
+ channels = this.#createAgentChannels(agent, currentAdapter);
15652
+ await channels.initialize(this.#mastra);
15653
+ }
15654
+ return channels;
15655
+ }
15545
15656
  /**
15546
15657
  * Auto-initialize on first route hit.
15547
15658
  * Delegates to initialize() which handles idempotency.
@@ -15605,15 +15716,13 @@ var SlackProvider = class {
15605
15716
  }
15606
15717
  ];
15607
15718
  }
15608
- // ===========================================================================
15609
- // Public API
15610
- // ===========================================================================
15611
- /**
15612
- * Connect an agent to Slack by creating a new Slack app.
15613
- *
15614
- * @returns OAuth connect result with authorization URL for user redirect
15615
- */
15616
- async connect(agentId, options) {
15719
+ async connect(agentIdOrOptions, maybeOptions) {
15720
+ const isAgentIdForm = typeof agentIdOrOptions === "string";
15721
+ const agentId = isAgentIdForm ? agentIdOrOptions : agentIdOrOptions.id;
15722
+ const options = isAgentIdForm ? maybeOptions : agentIdOrOptions;
15723
+ if (!isAgentIdForm && !agentIdOrOptions.name) {
15724
+ throw new Error('connect({ id, name }): "name" is required when connecting without an agent id');
15725
+ }
15617
15726
  const client = this.#requireManifestClient();
15618
15727
  const baseUrl = this.#getBaseUrl();
15619
15728
  if (!baseUrl) {
@@ -15622,26 +15731,45 @@ var SlackProvider = class {
15622
15731
  );
15623
15732
  }
15624
15733
  const agent = this.#resolveAgent(agentId);
15625
- if (!agent) {
15734
+ if (isAgentIdForm && !agent) {
15626
15735
  throw new Error(`Agent "${agentId}" not found`);
15627
15736
  }
15737
+ let ownerType = "agent";
15738
+ if (!isAgentIdForm && !agent) {
15739
+ const controller = this.#resolveAgentController(agentId);
15740
+ if (!controller) {
15741
+ throw new Error(`No agent or agent controller found with id "${agentId}"`);
15742
+ }
15743
+ ownerType = "agentController";
15744
+ }
15628
15745
  const storage = await this.#getStorage();
15629
15746
  const existingRecord = await storage.getInstallationByAgent(PLATFORM, agentId);
15630
15747
  if (existingRecord?.status === "pending") {
15631
15748
  try {
15632
15749
  const pending = this.#parsePendingInstallation(existingRecord);
15633
15750
  const decrypted = this.#decryptPendingInstallation(pending);
15634
- if (options?.redirectUrl && decrypted.redirectUrl !== options.redirectUrl) {
15635
- await this.#savePendingInstallation(
15636
- this.#encryptPendingInstallation({ ...decrypted, redirectUrl: options.redirectUrl })
15637
- );
15751
+ let appStillExists = true;
15752
+ try {
15753
+ appStillExists = await client.appExists(decrypted.appId);
15754
+ } catch (err) {
15755
+ console.warn(`[Slack] Could not verify existing app for "${agentId}", reusing pending installation:`, err);
15756
+ }
15757
+ if (!appStillExists) {
15758
+ console.warn(`[Slack] Stored app for "${agentId}" no longer exists on Slack, creating a fresh installation`);
15759
+ await storage.deleteInstallation(existingRecord.id);
15760
+ } else {
15761
+ if (options?.redirectUrl && decrypted.redirectUrl !== options.redirectUrl) {
15762
+ await this.#savePendingInstallation(
15763
+ this.#encryptPendingInstallation({ ...decrypted, redirectUrl: options.redirectUrl })
15764
+ );
15765
+ }
15766
+ console.log(`[Slack] Reusing existing pending installation for "${agentId}"`);
15767
+ return {
15768
+ type: "oauth",
15769
+ installationId: decrypted.id,
15770
+ authorizationUrl: decrypted.authorizationUrl
15771
+ };
15638
15772
  }
15639
- console.log(`[Slack] Reusing existing pending installation for "${agentId}"`);
15640
- return {
15641
- type: "oauth",
15642
- installationId: decrypted.id,
15643
- authorizationUrl: decrypted.authorizationUrl
15644
- };
15645
15773
  } catch {
15646
15774
  console.warn(`[Slack] Corrupt pending installation for "${agentId}", replacing it`);
15647
15775
  await storage.deleteInstallation(existingRecord.id);
@@ -15652,8 +15780,8 @@ var SlackProvider = class {
15652
15780
  }
15653
15781
  const config2 = options ?? {};
15654
15782
  const webhookId = crypto.randomUUID();
15655
- const appName = config2.name ?? agent.name ?? agentId;
15656
- const appDescription = config2.description || agent.getDescription() || "AI assistant powered by Mastra";
15783
+ const appName = config2.name ?? agent?.name ?? agentId;
15784
+ const appDescription = config2.description || agent?.getDescription() || "AI assistant powered by Mastra";
15657
15785
  const normalizedCommands = this.#normalizeCommands(config2.slashCommands);
15658
15786
  let manifest = buildManifest({
15659
15787
  name: appName,
@@ -15696,6 +15824,7 @@ var SlackProvider = class {
15696
15824
  const pendingInstallation = this.#encryptPendingInstallation({
15697
15825
  id: installationId,
15698
15826
  agentId,
15827
+ ownerType,
15699
15828
  webhookId,
15700
15829
  appId: appCredentials.appId,
15701
15830
  clientId: appCredentials.clientId,
@@ -15904,6 +16033,7 @@ var SlackProvider = class {
15904
16033
  const installation = {
15905
16034
  id: pending.id,
15906
16035
  agentId: pending.agentId,
16036
+ ownerType: pending.ownerType ?? "agent",
15907
16037
  webhookId: pending.webhookId,
15908
16038
  appId: pending.appId,
15909
16039
  clientId: pending.clientId,
@@ -15921,7 +16051,11 @@ var SlackProvider = class {
15921
16051
  };
15922
16052
  const encryptedInstallation = this.#encryptInstallation(installation);
15923
16053
  await this.#saveInstallation(encryptedInstallation);
15924
- const agent = this.#mastra?.getAgentById(pending.agentId);
16054
+ let agent;
16055
+ try {
16056
+ agent = installation.ownerType === "agent" ? this.#mastra?.getAgentById(pending.agentId) : void 0;
16057
+ } catch {
16058
+ }
15925
16059
  const displayName = installation.name || agent?.name || pending.agentId;
15926
16060
  const adapter = createSlackAdapter({
15927
16061
  ...this.#forwardedAdapterOptions(),
@@ -15938,7 +16072,9 @@ var SlackProvider = class {
15938
16072
  await this.#channelConfig.onInstall(installation);
15939
16073
  }
15940
16074
  const teamName = tokenData.team?.name ?? "";
15941
- console.log(`[Slack] \u2713 Agent "${pending.agentId}" installed to team "${teamName}"`);
16075
+ console.log(
16076
+ `[Slack] \u2713 App "${installation.name ?? installation.agentId}" (${installation.appId}) installed to workspace "${teamName || installation.teamId}"`
16077
+ );
15942
16078
  const successUrl = pending.redirectUrl ?? this.#channelConfig.redirectPath ?? "/";
15943
16079
  const redirect = new URL(successUrl, c.req.url);
15944
16080
  redirect.searchParams.set("channel_connected", "true");
@@ -15993,16 +16129,11 @@ var SlackProvider = class {
15993
16129
  return c.json({ challenge: event.challenge });
15994
16130
  }
15995
16131
  }
15996
- const agent = this.#resolveAgent(installation.agentId);
15997
- if (!agent) {
15998
- console.error(`[Slack] Agent "${installation.agentId}" not found`);
15999
- return c.json({ ok: true });
16000
- }
16001
16132
  if (!this.#mastra) {
16002
16133
  console.error("[Slack] Mastra not attached");
16003
16134
  return c.json({ ok: true });
16004
16135
  }
16005
- const displayName = installation.name || agent.name || installation.agentId;
16136
+ const displayName = installation.name || installation.agentId;
16006
16137
  const currentAdapter = this.#adapters.get(installation.id) ?? createSlackAdapter({
16007
16138
  ...this.#forwardedAdapterOptions(),
16008
16139
  botToken: installation.botToken,
@@ -16010,10 +16141,9 @@ var SlackProvider = class {
16010
16141
  signingSecret: installation.signingSecret,
16011
16142
  userName: displayName
16012
16143
  });
16013
- let agentChannels = agent.getChannels();
16014
- if (!agentChannels || agentChannels.adapters.slack !== currentAdapter) {
16015
- agentChannels = this.#createAgentChannels(agent, currentAdapter);
16016
- await agentChannels.initialize(this.#mastra);
16144
+ const agentChannels = await this.#resolveChannelsForInstallation(installation, currentAdapter);
16145
+ if (!agentChannels) {
16146
+ return c.json({ ok: true });
16017
16147
  }
16018
16148
  const delegateRequest = new Request(c.req.url, {
16019
16149
  method: c.req.method,
@@ -16064,6 +16194,12 @@ var SlackProvider = class {
16064
16194
  if (!commandConfig) {
16065
16195
  return c.json({ response_type: "ephemeral", text: `Unknown command: ${command}` });
16066
16196
  }
16197
+ if (installation.ownerType === "agentController") {
16198
+ return c.json({
16199
+ response_type: "ephemeral",
16200
+ text: "Slash commands are not supported for this app yet. Mention the bot in a thread to start a session."
16201
+ });
16202
+ }
16067
16203
  const agent = this.#resolveAgent(installation.agentId);
16068
16204
  if (!agent) {
16069
16205
  return c.json({ response_type: "ephemeral", text: "Agent not available" });
@@ -16105,6 +16241,13 @@ var SlackProvider = class {
16105
16241
  return void 0;
16106
16242
  }
16107
16243
  }
16244
+ #resolveAgentController(controllerId) {
16245
+ try {
16246
+ return this.#mastra?.getAgentControllerById(controllerId);
16247
+ } catch {
16248
+ return void 0;
16249
+ }
16250
+ }
16108
16251
  };
16109
16252
 
16110
16253
  // src/index.ts