@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 +20 -0
- package/dist/index.cjs +191 -49
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +41 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +183 -40
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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
|
|
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
|
|
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 (
|
|
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
|
-
|
|
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(
|
|
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 = {
|
|
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
|
-
|
|
15610
|
-
|
|
15611
|
-
|
|
15612
|
-
|
|
15613
|
-
|
|
15614
|
-
|
|
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
|
-
|
|
15635
|
-
|
|
15636
|
-
|
|
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
|
|
15656
|
-
const appDescription = config2.description || agent
|
|
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
|
-
|
|
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(
|
|
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 ||
|
|
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
|
-
|
|
16014
|
-
if (!agentChannels
|
|
16015
|
-
|
|
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
|