@hazeljs/ops-agent 0.7.9 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,12 +24,7 @@ npm install @hazeljs/ops-agent @hazeljs/ai @hazeljs/agent @hazeljs/rag
24
24
 
25
25
  ```ts
26
26
  import { AIEnhancedService } from '@hazeljs/ai';
27
- import {
28
- createOpsRuntime,
29
- runOpsAgent,
30
- createJiraTool,
31
- createSlackTool,
32
- } from '@hazeljs/ops-agent';
27
+ import { createOpsRuntime, runOpsAgent, createJiraTool, createSlackTool } from '@hazeljs/ops-agent';
33
28
 
34
29
  // Configure tools (uses env vars when omitted)
35
30
  const jiraTool = createJiraTool(); // JIRA_HOST, JIRA_EMAIL, JIRA_API_TOKEN
@@ -45,7 +40,8 @@ const runtime = createOpsRuntime({
45
40
  });
46
41
 
47
42
  const result = await runOpsAgent(runtime, {
48
- input: 'Create a Jira ticket in PROJ for "Payment API timeout in prod" and post a summary to #incidents',
43
+ input:
44
+ 'Create a Jira ticket in PROJ for "Payment API timeout in prod" and post a summary to #incidents',
49
45
  sessionId: 'incident-2024-01',
50
46
  });
51
47
 
@@ -54,23 +50,23 @@ console.log(result.response);
54
50
 
55
51
  ## Environment Variables
56
52
 
57
- | Variable | Description |
58
- |----------|-------------|
59
- | `JIRA_HOST` | Jira host (e.g. https://your-domain.atlassian.net) |
60
- | `JIRA_EMAIL` | Email for Basic auth |
61
- | `JIRA_API_TOKEN` | API token from [Atlassian](https://id.atlassian.com/manage-profile/security/api-tokens) |
62
- | `SLACK_BOT_TOKEN` | Slack bot token (xoxb-...) from app OAuth |
53
+ | Variable | Description |
54
+ | ----------------- | --------------------------------------------------------------------------------------- |
55
+ | `JIRA_HOST` | Jira host (e.g. https://your-domain.atlassian.net) |
56
+ | `JIRA_EMAIL` | Email for Basic auth |
57
+ | `JIRA_API_TOKEN` | API token from [Atlassian](https://id.atlassian.com/manage-profile/security/api-tokens) |
58
+ | `SLACK_BOT_TOKEN` | Slack bot token (xoxb-...) from app OAuth |
63
59
 
64
60
  When not configured, tools return placeholder responses so you can develop without credentials.
65
61
 
66
62
  ## Tools
67
63
 
68
- | Tool | Description | Approval |
69
- |------|-------------|----------|
70
- | `create_jira_ticket` | Create Jira issue (project, summary, description, type) | Yes |
71
- | `add_jira_comment` | Add comment to existing issue | No |
72
- | `get_jira_ticket` | Get issue details by key | No |
73
- | `post_to_slack` | Post message to channel (optionally in thread) | Yes |
64
+ | Tool | Description | Approval |
65
+ | -------------------- | ------------------------------------------------------- | -------- |
66
+ | `create_jira_ticket` | Create Jira issue (project, summary, description, type) | Yes |
67
+ | `add_jira_comment` | Add comment to existing issue | No |
68
+ | `get_jira_ticket` | Get issue details by key | No |
69
+ | `post_to_slack` | Post message to channel (optionally in thread) | Yes |
74
70
 
75
71
  ## Memory
76
72
 
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Jira tool adapter - create tickets, add comments, get ticket details.
3
+ * Uses Jira Cloud REST API v3.
4
+ * Requires: JIRA_HOST, JIRA_EMAIL, JIRA_API_TOKEN env vars (or pass via config).
5
+ */
6
+ import type { JiraToolLike } from '../types';
7
+ export interface JiraConfig {
8
+ /** Jira host (e.g. https://your-domain.atlassian.net) */
9
+ host: string;
10
+ /** Email for Basic auth */
11
+ email: string;
12
+ /** API token from https://id.atlassian.com/manage-profile/security/api-tokens */
13
+ apiToken: string;
14
+ /** Optional timeout in ms */
15
+ timeoutMs?: number;
16
+ }
17
+ /**
18
+ * Create a Jira tool from config.
19
+ * Env vars: JIRA_HOST, JIRA_EMAIL, JIRA_API_TOKEN (used when config not provided).
20
+ */
21
+ export declare function createJiraTool(config?: Partial<JiraConfig>): JiraToolLike;
22
+ //# sourceMappingURL=jira.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jira.d.ts","sourceRoot":"","sources":["../../src/adapters/jira.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,MAAM,WAAW,UAAU;IACzB,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAC;IACjB,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAiCD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,YAAY,CAwHzE"}
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+ /**
3
+ * Jira tool adapter - create tickets, add comments, get ticket details.
4
+ * Uses Jira Cloud REST API v3.
5
+ * Requires: JIRA_HOST, JIRA_EMAIL, JIRA_API_TOKEN env vars (or pass via config).
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.createJiraTool = createJiraTool;
9
+ function getAuthHeader(email, apiToken) {
10
+ const token = Buffer.from(`${email}:${apiToken}`).toString('base64');
11
+ return `Basic ${token}`;
12
+ }
13
+ async function jiraFetch(host, path, auth, options = {}, timeoutMs = 15000) {
14
+ const url = `${host.replace(/\/$/, '')}${path}`;
15
+ const controller = new AbortController();
16
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
17
+ try {
18
+ const res = await fetch(url, {
19
+ ...options,
20
+ headers: {
21
+ 'Content-Type': 'application/json',
22
+ Authorization: auth,
23
+ ...options.headers,
24
+ },
25
+ signal: controller.signal,
26
+ });
27
+ return res;
28
+ }
29
+ finally {
30
+ clearTimeout(timeout);
31
+ }
32
+ }
33
+ /**
34
+ * Create a Jira tool from config.
35
+ * Env vars: JIRA_HOST, JIRA_EMAIL, JIRA_API_TOKEN (used when config not provided).
36
+ */
37
+ function createJiraTool(config) {
38
+ const host = config?.host ?? process.env.JIRA_HOST ?? '';
39
+ const email = config?.email ?? process.env.JIRA_EMAIL ?? '';
40
+ const apiToken = config?.apiToken ?? process.env.JIRA_API_TOKEN ?? '';
41
+ const timeoutMs = config?.timeoutMs ?? 15000;
42
+ if (!host || !email || !apiToken) {
43
+ return createPlaceholderJiraTool();
44
+ }
45
+ const auth = getAuthHeader(email, apiToken);
46
+ return {
47
+ async createTicket(input) {
48
+ const res = await jiraFetch(host, '/rest/api/3/issue', auth, {
49
+ method: 'POST',
50
+ body: JSON.stringify({
51
+ fields: {
52
+ project: { key: input.project },
53
+ summary: input.summary,
54
+ description: input.description
55
+ ? {
56
+ type: 'doc',
57
+ version: 1,
58
+ content: [
59
+ { type: 'paragraph', content: [{ type: 'text', text: input.description }] },
60
+ ],
61
+ }
62
+ : undefined,
63
+ issuetype: { name: input.issueType ?? 'Task' },
64
+ labels: input.labels ?? [],
65
+ },
66
+ }),
67
+ }, timeoutMs);
68
+ if (!res.ok) {
69
+ const err = await res.text();
70
+ throw new Error(`Jira create issue failed: ${res.status} ${err}`);
71
+ }
72
+ const data = (await res.json());
73
+ const browseUrl = `${host}/browse/${data.key}`;
74
+ return { key: data.key, id: data.id, url: browseUrl };
75
+ },
76
+ async addComment(input) {
77
+ const res = await jiraFetch(host, `/rest/api/3/issue/${encodeURIComponent(input.issueKey)}/comment`, auth, {
78
+ method: 'POST',
79
+ body: JSON.stringify({
80
+ body: {
81
+ type: 'doc',
82
+ version: 1,
83
+ content: [{ type: 'paragraph', content: [{ type: 'text', text: input.body }] }],
84
+ },
85
+ }),
86
+ }, timeoutMs);
87
+ if (!res.ok) {
88
+ const err = await res.text();
89
+ throw new Error(`Jira add comment failed: ${res.status} ${err}`);
90
+ }
91
+ const data = (await res.json());
92
+ return { id: data.id };
93
+ },
94
+ async getTicket(input) {
95
+ const res = await jiraFetch(host, `/rest/api/3/issue/${encodeURIComponent(input.issueKey)}?fields=summary,status,description`, auth, { method: 'GET' }, timeoutMs);
96
+ if (!res.ok) {
97
+ if (res.status === 404) {
98
+ throw new Error(`Jira issue not found: ${input.issueKey}`);
99
+ }
100
+ const err = await res.text();
101
+ throw new Error(`Jira get issue failed: ${res.status} ${err}`);
102
+ }
103
+ const data = (await res.json());
104
+ const desc = data.fields?.description?.content?.[0]?.content?.[0]?.text;
105
+ const browseUrl = `${host}/browse/${data.key}`;
106
+ return {
107
+ key: data.key,
108
+ summary: data.fields?.summary ?? '',
109
+ status: data.fields?.status?.name,
110
+ description: desc,
111
+ url: browseUrl,
112
+ };
113
+ },
114
+ };
115
+ }
116
+ /** Placeholder when Jira credentials are not configured */
117
+ function createPlaceholderJiraTool() {
118
+ return {
119
+ async createTicket(input) {
120
+ const key = `${input.project}-${Date.now()}`;
121
+ return {
122
+ key,
123
+ id: key,
124
+ url: `https://example.atlassian.net/browse/${key}`,
125
+ };
126
+ },
127
+ async addComment(_input) {
128
+ return { id: `comment-${Date.now()}` };
129
+ },
130
+ async getTicket(input) {
131
+ return {
132
+ key: input.issueKey,
133
+ summary: 'Placeholder - configure JIRA_HOST, JIRA_EMAIL, JIRA_API_TOKEN for real data',
134
+ status: 'Unknown',
135
+ };
136
+ },
137
+ };
138
+ }
139
+ //# sourceMappingURL=jira.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jira.js","sourceRoot":"","sources":["../../src/adapters/jira.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Jira adapter tests
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=jira.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jira.test.d.ts","sourceRoot":"","sources":["../../src/adapters/jira.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,193 @@
1
+ "use strict";
2
+ /**
3
+ * Jira adapter tests
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const jira_1 = require("./jira");
7
+ describe('createJiraTool', () => {
8
+ const originalEnv = process.env;
9
+ beforeEach(() => {
10
+ jest.restoreAllMocks();
11
+ process.env = { ...originalEnv };
12
+ delete process.env.JIRA_HOST;
13
+ delete process.env.JIRA_EMAIL;
14
+ delete process.env.JIRA_API_TOKEN;
15
+ });
16
+ afterAll(() => {
17
+ process.env = originalEnv;
18
+ });
19
+ describe('placeholder mode (no credentials)', () => {
20
+ it('returns placeholder tool when env vars are not set', () => {
21
+ const tool = (0, jira_1.createJiraTool)();
22
+ expect(tool).toBeDefined();
23
+ expect(tool.createTicket).toBeDefined();
24
+ expect(tool.addComment).toBeDefined();
25
+ expect(tool.getTicket).toBeDefined();
26
+ });
27
+ it('createTicket returns placeholder key with project and timestamp', async () => {
28
+ const tool = (0, jira_1.createJiraTool)();
29
+ const result = await tool.createTicket({
30
+ project: 'PROJ',
31
+ summary: 'Test issue',
32
+ });
33
+ expect(result.key).toMatch(/^PROJ-\d+$/);
34
+ expect(result.id).toBe(result.key);
35
+ expect(result.url).toContain('example.atlassian.net');
36
+ expect(result.url).toContain(result.key);
37
+ });
38
+ it('addComment returns placeholder id', async () => {
39
+ const tool = (0, jira_1.createJiraTool)();
40
+ const result = await tool.addComment({
41
+ issueKey: 'PROJ-123',
42
+ body: 'Test comment',
43
+ });
44
+ expect(result.id).toMatch(/^comment-\d+$/);
45
+ });
46
+ it('getTicket returns placeholder with issueKey', async () => {
47
+ const tool = (0, jira_1.createJiraTool)();
48
+ const result = await tool.getTicket({ issueKey: 'PROJ-123' });
49
+ expect(result.key).toBe('PROJ-123');
50
+ expect(result.summary).toContain('Placeholder');
51
+ expect(result.status).toBe('Unknown');
52
+ });
53
+ it('returns placeholder when config is empty', () => {
54
+ const tool = (0, jira_1.createJiraTool)({});
55
+ expect(tool).toBeDefined();
56
+ });
57
+ it('returns placeholder when config has empty strings', () => {
58
+ const tool = (0, jira_1.createJiraTool)({ host: '', email: '', apiToken: '' });
59
+ expect(tool).toBeDefined();
60
+ });
61
+ });
62
+ describe('real mode (with mocked fetch)', () => {
63
+ let fetchMock;
64
+ beforeEach(() => {
65
+ fetchMock = jest.spyOn(globalThis, 'fetch');
66
+ });
67
+ afterEach(() => {
68
+ fetchMock.mockRestore();
69
+ });
70
+ it('createTicket calls Jira API and returns issue', async () => {
71
+ fetchMock.mockResolvedValueOnce({
72
+ ok: true,
73
+ status: 201,
74
+ json: async () => ({ key: 'PROJ-42', id: '12345' }),
75
+ });
76
+ const tool = (0, jira_1.createJiraTool)({
77
+ host: 'https://test.atlassian.net',
78
+ email: 'test@example.com',
79
+ apiToken: 'token',
80
+ });
81
+ const result = await tool.createTicket({
82
+ project: 'PROJ',
83
+ summary: 'DB issue',
84
+ description: 'Connection pool exhaustion',
85
+ });
86
+ expect(result.key).toBe('PROJ-42');
87
+ expect(result.id).toBe('12345');
88
+ expect(result.url).toBe('https://test.atlassian.net/browse/PROJ-42');
89
+ expect(fetchMock).toHaveBeenCalledWith('https://test.atlassian.net/rest/api/3/issue', expect.objectContaining({
90
+ method: 'POST',
91
+ headers: expect.objectContaining({
92
+ Authorization: expect.stringMatching(/^Basic /),
93
+ 'Content-Type': 'application/json',
94
+ }),
95
+ }));
96
+ });
97
+ it('createTicket throws when API fails', async () => {
98
+ fetchMock.mockResolvedValueOnce({
99
+ ok: false,
100
+ status: 401,
101
+ text: async () => 'Unauthorized',
102
+ });
103
+ const tool = (0, jira_1.createJiraTool)({
104
+ host: 'https://test.atlassian.net',
105
+ email: 'test@example.com',
106
+ apiToken: 'bad',
107
+ });
108
+ await expect(tool.createTicket({ project: 'PROJ', summary: 'Test' })).rejects.toThrow('Jira create issue failed: 401');
109
+ });
110
+ it('addComment calls Jira API and returns comment id', async () => {
111
+ fetchMock.mockResolvedValueOnce({
112
+ ok: true,
113
+ json: async () => ({ id: 'comment-1' }),
114
+ });
115
+ const tool = (0, jira_1.createJiraTool)({
116
+ host: 'https://test.atlassian.net',
117
+ email: 'test@example.com',
118
+ apiToken: 'token',
119
+ });
120
+ const result = await tool.addComment({
121
+ issueKey: 'PROJ-123',
122
+ body: 'Status update',
123
+ });
124
+ expect(result.id).toBe('comment-1');
125
+ expect(fetchMock).toHaveBeenCalledWith('https://test.atlassian.net/rest/api/3/issue/PROJ-123/comment', expect.objectContaining({ method: 'POST' }));
126
+ });
127
+ it('getTicket fetches issue and returns parsed fields', async () => {
128
+ fetchMock.mockResolvedValueOnce({
129
+ ok: true,
130
+ json: async () => ({
131
+ key: 'PROJ-123',
132
+ fields: {
133
+ summary: 'Test issue',
134
+ status: { name: 'In Progress' },
135
+ description: {
136
+ content: [{ content: [{ text: 'Description text' }] }],
137
+ },
138
+ },
139
+ }),
140
+ });
141
+ const tool = (0, jira_1.createJiraTool)({
142
+ host: 'https://test.atlassian.net',
143
+ email: 'test@example.com',
144
+ apiToken: 'token',
145
+ });
146
+ const result = await tool.getTicket({ issueKey: 'PROJ-123' });
147
+ expect(result.key).toBe('PROJ-123');
148
+ expect(result.summary).toBe('Test issue');
149
+ expect(result.status).toBe('In Progress');
150
+ expect(result.description).toBe('Description text');
151
+ expect(result.url).toBe('https://test.atlassian.net/browse/PROJ-123');
152
+ });
153
+ it('getTicket throws 404 when issue not found', async () => {
154
+ fetchMock.mockResolvedValueOnce({
155
+ ok: false,
156
+ status: 404,
157
+ text: async () => 'Not found',
158
+ });
159
+ const tool = (0, jira_1.createJiraTool)({
160
+ host: 'https://test.atlassian.net',
161
+ email: 'test@example.com',
162
+ apiToken: 'token',
163
+ });
164
+ await expect(tool.getTicket({ issueKey: 'PROJ-999' })).rejects.toThrow('Jira issue not found: PROJ-999');
165
+ });
166
+ it('strips trailing slash from host', async () => {
167
+ fetchMock.mockResolvedValueOnce({
168
+ ok: true,
169
+ json: async () => ({ key: 'PROJ-1', id: '1' }),
170
+ });
171
+ const tool = (0, jira_1.createJiraTool)({
172
+ host: 'https://test.atlassian.net/',
173
+ email: 'test@example.com',
174
+ apiToken: 'token',
175
+ });
176
+ await tool.createTicket({ project: 'PROJ', summary: 'Test' });
177
+ expect(fetchMock).toHaveBeenCalledWith('https://test.atlassian.net/rest/api/3/issue', expect.any(Object));
178
+ });
179
+ it('uses env vars when config not provided', async () => {
180
+ process.env.JIRA_HOST = 'https://env.atlassian.net';
181
+ process.env.JIRA_EMAIL = 'env@example.com';
182
+ process.env.JIRA_API_TOKEN = 'env-token';
183
+ fetchMock.mockResolvedValueOnce({
184
+ ok: true,
185
+ json: async () => ({ key: 'PROJ-1', id: '1' }),
186
+ });
187
+ const tool = (0, jira_1.createJiraTool)();
188
+ await tool.createTicket({ project: 'PROJ', summary: 'Test' });
189
+ expect(fetchMock).toHaveBeenCalledWith('https://env.atlassian.net/rest/api/3/issue', expect.any(Object));
190
+ });
191
+ });
192
+ });
193
+ //# sourceMappingURL=jira.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jira.test.js","sourceRoot":"","sources":["../../src/adapters/jira.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Slack tool adapter - post messages to channels and threads.
3
+ * Uses Slack Web API (chat.postMessage).
4
+ * Requires: SLACK_BOT_TOKEN env var (or pass via config).
5
+ */
6
+ import type { SlackToolLike } from '../types';
7
+ export interface SlackConfig {
8
+ /** Bot token (xoxb-...) from Slack app OAuth */
9
+ token: string;
10
+ /** Optional timeout in ms */
11
+ timeoutMs?: number;
12
+ }
13
+ /**
14
+ * Create a Slack tool from config.
15
+ * Env var: SLACK_BOT_TOKEN (used when config not provided).
16
+ */
17
+ export declare function createSlackTool(config?: Partial<SlackConfig>): SlackToolLike;
18
+ //# sourceMappingURL=slack.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../../src/adapters/slack.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,MAAM,WAAW,WAAW;IAC1B,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA4BD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,aAAa,CAsC5E"}
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ /**
3
+ * Slack tool adapter - post messages to channels and threads.
4
+ * Uses Slack Web API (chat.postMessage).
5
+ * Requires: SLACK_BOT_TOKEN env var (or pass via config).
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.createSlackTool = createSlackTool;
9
+ const SLACK_API = 'https://slack.com/api';
10
+ async function slackFetch(path, token, body, timeoutMs = 10000) {
11
+ const controller = new AbortController();
12
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
13
+ try {
14
+ const res = await fetch(`${SLACK_API}${path}`, {
15
+ method: 'POST',
16
+ headers: {
17
+ 'Content-Type': 'application/json',
18
+ Authorization: `Bearer ${token}`,
19
+ },
20
+ body: JSON.stringify(body),
21
+ signal: controller.signal,
22
+ });
23
+ return res;
24
+ }
25
+ finally {
26
+ clearTimeout(timeout);
27
+ }
28
+ }
29
+ /**
30
+ * Create a Slack tool from config.
31
+ * Env var: SLACK_BOT_TOKEN (used when config not provided).
32
+ */
33
+ function createSlackTool(config) {
34
+ const token = config?.token ?? process.env.SLACK_BOT_TOKEN ?? '';
35
+ const timeoutMs = config?.timeoutMs ?? 10000;
36
+ if (!token) {
37
+ return createPlaceholderSlackTool();
38
+ }
39
+ return {
40
+ async postToChannel(input) {
41
+ const body = {
42
+ channel: input.channel,
43
+ text: input.text,
44
+ };
45
+ if (input.threadTs) {
46
+ body.thread_ts = input.threadTs;
47
+ }
48
+ const res = await slackFetch('/chat.postMessage', token, body, timeoutMs);
49
+ if (!res.ok) {
50
+ const err = await res.text();
51
+ throw new Error(`Slack post failed: ${res.status} ${err}`);
52
+ }
53
+ const data = (await res.json());
54
+ if (!data.ok) {
55
+ throw new Error(`Slack API error: ${data.error ?? 'unknown'}`);
56
+ }
57
+ return { ts: data.ts ?? '', channel: data.channel ?? input.channel };
58
+ },
59
+ };
60
+ }
61
+ /** Placeholder when Slack token is not configured */
62
+ function createPlaceholderSlackTool() {
63
+ return {
64
+ async postToChannel(input) {
65
+ return { ts: `ts-${Date.now()}`, channel: input.channel };
66
+ },
67
+ };
68
+ }
69
+ //# sourceMappingURL=slack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack.js","sourceRoot":"","sources":["../../src/adapters/slack.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;AAyCH,0CAsCC;AApED,MAAM,SAAS,GAAG,uBAAuB,CAAC;AAE1C,KAAK,UAAU,UAAU,CACvB,IAAY,EACZ,KAAa,EACb,IAA6B,EAC7B,SAAS,GAAG,KAAK;IAEjB,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;IAChE,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,SAAS,GAAG,IAAI,EAAE,EAAE;YAC7C,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,KAAK,EAAE;aACjC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;YAC1B,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;QACH,OAAO,GAAG,CAAC;IACb,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAgB,eAAe,CAAC,MAA6B;IAC3D,MAAM,KAAK,GAAG,MAAM,EAAE,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC;IACjE,MAAM,SAAS,GAAG,MAAM,EAAE,SAAS,IAAI,KAAK,CAAC;IAE7C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,0BAA0B,EAAE,CAAC;IACtC,CAAC;IAED,OAAO;QACL,KAAK,CAAC,aAAa,CAAC,KAAK;YACvB,MAAM,IAAI,GAA4B;gBACpC,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,IAAI,EAAE,KAAK,CAAC,IAAI;aACjB,CAAC;YACF,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACnB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC;YAClC,CAAC;YAED,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,mBAAmB,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;YAE1E,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;gBAC7B,MAAM,IAAI,KAAK,CAAC,sBAAsB,GAAG,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC,CAAC;YAC7D,CAAC;YAED,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAK7B,CAAC;YACF,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;gBACb,MAAM,IAAI,KAAK,CAAC,oBAAoB,IAAI,CAAC,KAAK,IAAI,SAAS,EAAE,CAAC,CAAC;YACjE,CAAC;YAED,OAAO,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;QACvE,CAAC;KACF,CAAC;AACJ,CAAC;AAED,qDAAqD;AACrD,SAAS,0BAA0B;IACjC,OAAO;QACL,KAAK,CAAC,aAAa,CAAC,KAAK;YACvB,OAAO,EAAE,EAAE,EAAE,MAAM,IAAI,CAAC,GAAG,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC;QAC5D,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Slack adapter tests
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=slack.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slack.test.d.ts","sourceRoot":"","sources":["../../src/adapters/slack.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}