@probelabs/visor 0.1.177 → 0.1.178-ee

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/defaults/code-talk.yaml +10 -5
  2. package/dist/defaults/code-talk.yaml +10 -5
  3. package/dist/docs/ai-custom-tools.md +49 -0
  4. package/dist/docs/http.md +23 -0
  5. package/dist/docs/testing/cookbook.md +48 -0
  6. package/dist/docs/testing/dsl-reference.md +4 -2
  7. package/dist/docs/testing/flows.md +33 -1
  8. package/dist/examples/http-integration-config.yaml +16 -0
  9. package/dist/generated/config-schema.d.ts +51 -6
  10. package/dist/generated/config-schema.d.ts.map +1 -1
  11. package/dist/generated/config-schema.json +61 -6
  12. package/dist/github-comments.d.ts +5 -1
  13. package/dist/github-comments.d.ts.map +1 -1
  14. package/dist/index.js +2224 -93
  15. package/dist/providers/api-tool-executor.d.ts +2 -0
  16. package/dist/providers/api-tool-executor.d.ts.map +1 -1
  17. package/dist/providers/http-client-provider.d.ts.map +1 -1
  18. package/dist/providers/mcp-custom-sse-server.d.ts.map +1 -1
  19. package/dist/providers/workflow-check-provider.d.ts.map +1 -1
  20. package/dist/sdk/{a2a-frontend-FUJRKHJB.mjs → a2a-frontend-U3PTNCLR.mjs} +2 -2
  21. package/dist/sdk/{check-provider-registry-HW4QPPSA.mjs → check-provider-registry-SRASECAR.mjs} +6 -6
  22. package/dist/sdk/{check-provider-registry-OY2EESIO.mjs → check-provider-registry-ZX76MY2L.mjs} +6 -6
  23. package/dist/sdk/{chunk-OPI632LK.mjs → chunk-4ECMTCOM.mjs} +2 -2
  24. package/dist/sdk/{chunk-GVTWESYN.mjs → chunk-6YGCACBF.mjs} +2 -2
  25. package/dist/sdk/{chunk-65SHRIQF.mjs.map → chunk-6YGCACBF.mjs.map} +1 -1
  26. package/dist/sdk/{chunk-Y6PVSFCS.mjs → chunk-B7XHSG3L.mjs} +237 -47
  27. package/dist/sdk/chunk-B7XHSG3L.mjs.map +1 -0
  28. package/dist/sdk/{chunk-MM3TGVQ4.mjs → chunk-BMXVAJ2M.mjs} +52 -7
  29. package/dist/sdk/chunk-BMXVAJ2M.mjs.map +1 -0
  30. package/dist/sdk/{chunk-OHOBWVPP.mjs → chunk-ENSZDV3O.mjs} +3 -3
  31. package/dist/sdk/{chunk-2LCF5H5K.mjs → chunk-MGY5JAN2.mjs} +222 -37
  32. package/dist/sdk/chunk-MGY5JAN2.mjs.map +1 -0
  33. package/dist/sdk/{config-OOUMTCEA.mjs → config-DFOF7LP4.mjs} +2 -2
  34. package/dist/sdk/{failure-condition-evaluator-DL6H57NX.mjs → failure-condition-evaluator-P3MS5DRL.mjs} +3 -3
  35. package/dist/sdk/{github-frontend-FP6WKNZR.mjs → github-frontend-QTKOYB56.mjs} +11 -3
  36. package/dist/sdk/github-frontend-QTKOYB56.mjs.map +1 -0
  37. package/dist/sdk/{host-6SBCE4VK.mjs → host-I2TBBKD5.mjs} +3 -3
  38. package/dist/sdk/{host-NYUSWEE4.mjs → host-THORKOEL.mjs} +3 -3
  39. package/dist/sdk/knex-store-QCEW4I4R.mjs +527 -0
  40. package/dist/sdk/knex-store-QCEW4I4R.mjs.map +1 -0
  41. package/dist/sdk/loader-Q7K76ZIY.mjs +89 -0
  42. package/dist/sdk/loader-Q7K76ZIY.mjs.map +1 -0
  43. package/dist/sdk/opa-policy-engine-QCSSIMUF.mjs +655 -0
  44. package/dist/sdk/opa-policy-engine-QCSSIMUF.mjs.map +1 -0
  45. package/dist/sdk/{routing-PFFCQJV2.mjs → routing-2X6QF5IW.mjs} +4 -4
  46. package/dist/sdk/{schedule-tool-DN2DSXIX.mjs → schedule-tool-M6Y4YTXR.mjs} +6 -6
  47. package/dist/sdk/{schedule-tool-KVZN5LP6.mjs → schedule-tool-R6JJIDZ6.mjs} +6 -6
  48. package/dist/sdk/{schedule-tool-handler-57JBEICD.mjs → schedule-tool-handler-AOMZV3Q3.mjs} +6 -6
  49. package/dist/sdk/{schedule-tool-handler-6MPP5DXK.mjs → schedule-tool-handler-JYCVH377.mjs} +6 -6
  50. package/dist/sdk/sdk.d.mts +21 -0
  51. package/dist/sdk/sdk.d.ts +21 -0
  52. package/dist/sdk/sdk.js +1919 -307
  53. package/dist/sdk/sdk.js.map +1 -1
  54. package/dist/sdk/sdk.mjs +5 -5
  55. package/dist/sdk/{trace-helpers-L3EOYW5P.mjs → trace-helpers-K47ZVJSU.mjs} +2 -2
  56. package/dist/sdk/validator-XTZJZZJH.mjs +134 -0
  57. package/dist/sdk/validator-XTZJZZJH.mjs.map +1 -0
  58. package/dist/sdk/{workflow-check-provider-OA33MESM.mjs → workflow-check-provider-A3YH2UZJ.mjs} +6 -6
  59. package/dist/sdk/{workflow-check-provider-U3UIYLU7.mjs → workflow-check-provider-EMFC7A5K.mjs} +6 -6
  60. package/dist/state-machine/context/build-engine-context.d.ts.map +1 -1
  61. package/dist/test-runner/conversation-sugar.d.ts +3 -0
  62. package/dist/test-runner/conversation-sugar.d.ts.map +1 -1
  63. package/dist/test-runner/validator.d.ts.map +1 -1
  64. package/dist/types/config.d.ts +21 -0
  65. package/dist/types/config.d.ts.map +1 -1
  66. package/dist/utils/rate-limiter.d.ts +61 -0
  67. package/dist/utils/rate-limiter.d.ts.map +1 -0
  68. package/package.json +2 -2
  69. package/dist/output/traces/run-2026-03-10T16-21-38-082Z.ndjson +0 -138
  70. package/dist/output/traces/run-2026-03-10T16-22-15-059Z.ndjson +0 -2296
  71. package/dist/sdk/a2a-frontend-BPWLYLCG.mjs +0 -1658
  72. package/dist/sdk/a2a-frontend-FUJRKHJB.mjs.map +0 -1
  73. package/dist/sdk/a2a-frontend-HBUSNE3K.mjs +0 -1658
  74. package/dist/sdk/a2a-frontend-HBUSNE3K.mjs.map +0 -1
  75. package/dist/sdk/check-provider-registry-TRHN5ZBY.mjs +0 -30
  76. package/dist/sdk/chunk-2LCF5H5K.mjs.map +0 -1
  77. package/dist/sdk/chunk-65SHRIQF.mjs +0 -516
  78. package/dist/sdk/chunk-ADQVGGKA.mjs +0 -1502
  79. package/dist/sdk/chunk-BWC5R2UB.mjs +0 -739
  80. package/dist/sdk/chunk-EFNNJIMY.mjs +0 -739
  81. package/dist/sdk/chunk-EFNNJIMY.mjs.map +0 -1
  82. package/dist/sdk/chunk-FNBSDOQM.mjs +0 -516
  83. package/dist/sdk/chunk-FNBSDOQM.mjs.map +0 -1
  84. package/dist/sdk/chunk-GVTWESYN.mjs.map +0 -1
  85. package/dist/sdk/chunk-MM3TGVQ4.mjs.map +0 -1
  86. package/dist/sdk/chunk-OHOBWVPP.mjs.map +0 -1
  87. package/dist/sdk/chunk-OPI632LK.mjs.map +0 -1
  88. package/dist/sdk/chunk-WJIV7MKY.mjs +0 -1502
  89. package/dist/sdk/chunk-WJIV7MKY.mjs.map +0 -1
  90. package/dist/sdk/chunk-XLDVWRKQ.mjs +0 -45239
  91. package/dist/sdk/chunk-XLDVWRKQ.mjs.map +0 -1
  92. package/dist/sdk/chunk-Y6PVSFCS.mjs.map +0 -1
  93. package/dist/sdk/failure-condition-evaluator-63BECZYF.mjs +0 -18
  94. package/dist/sdk/failure-condition-evaluator-HL33X7MH.mjs +0 -18
  95. package/dist/sdk/github-frontend-F2YCPK6H.mjs +0 -1386
  96. package/dist/sdk/github-frontend-F2YCPK6H.mjs.map +0 -1
  97. package/dist/sdk/github-frontend-FP6WKNZR.mjs.map +0 -1
  98. package/dist/sdk/github-frontend-U2U42CKV.mjs +0 -1386
  99. package/dist/sdk/github-frontend-U2U42CKV.mjs.map +0 -1
  100. package/dist/sdk/host-6TBS44ER.mjs +0 -87
  101. package/dist/sdk/host-NYUSWEE4.mjs.map +0 -1
  102. package/dist/sdk/routing-GF2CF3JT.mjs +0 -26
  103. package/dist/sdk/routing-SFP4D6O3.mjs +0 -26
  104. package/dist/sdk/schedule-tool-45NAALKS.mjs +0 -36
  105. package/dist/sdk/schedule-tool-KVZN5LP6.mjs.map +0 -1
  106. package/dist/sdk/schedule-tool-handler-57JBEICD.mjs.map +0 -1
  107. package/dist/sdk/schedule-tool-handler-6MPP5DXK.mjs.map +0 -1
  108. package/dist/sdk/schedule-tool-handler-GEXHYH3X.mjs +0 -40
  109. package/dist/sdk/schedule-tool-handler-GEXHYH3X.mjs.map +0 -1
  110. package/dist/sdk/slack-frontend-6SXPTQDI.mjs +0 -895
  111. package/dist/sdk/slack-frontend-6SXPTQDI.mjs.map +0 -1
  112. package/dist/sdk/trace-helpers-FKM2MEDW.mjs +0 -29
  113. package/dist/sdk/trace-helpers-FKM2MEDW.mjs.map +0 -1
  114. package/dist/sdk/trace-helpers-L3EOYW5P.mjs.map +0 -1
  115. package/dist/sdk/trace-helpers-MYH2GPXF.mjs +0 -29
  116. package/dist/sdk/trace-helpers-MYH2GPXF.mjs.map +0 -1
  117. package/dist/sdk/workflow-check-provider-JNEFAECH.mjs +0 -30
  118. package/dist/sdk/workflow-check-provider-JNEFAECH.mjs.map +0 -1
  119. package/dist/sdk/workflow-check-provider-OA33MESM.mjs.map +0 -1
  120. package/dist/sdk/workflow-check-provider-U3UIYLU7.mjs.map +0 -1
  121. package/dist/traces/run-2026-03-10T16-21-38-082Z.ndjson +0 -138
  122. package/dist/traces/run-2026-03-10T16-22-15-059Z.ndjson +0 -2296
  123. /package/dist/sdk/{a2a-frontend-BPWLYLCG.mjs.map → a2a-frontend-U3PTNCLR.mjs.map} +0 -0
  124. /package/dist/sdk/{check-provider-registry-HW4QPPSA.mjs.map → check-provider-registry-SRASECAR.mjs.map} +0 -0
  125. /package/dist/sdk/{check-provider-registry-OY2EESIO.mjs.map → check-provider-registry-ZX76MY2L.mjs.map} +0 -0
  126. /package/dist/sdk/{chunk-BWC5R2UB.mjs.map → chunk-4ECMTCOM.mjs.map} +0 -0
  127. /package/dist/sdk/{chunk-ADQVGGKA.mjs.map → chunk-ENSZDV3O.mjs.map} +0 -0
  128. /package/dist/sdk/{check-provider-registry-TRHN5ZBY.mjs.map → config-DFOF7LP4.mjs.map} +0 -0
  129. /package/dist/sdk/{config-OOUMTCEA.mjs.map → failure-condition-evaluator-P3MS5DRL.mjs.map} +0 -0
  130. /package/dist/sdk/{host-6SBCE4VK.mjs.map → host-I2TBBKD5.mjs.map} +0 -0
  131. /package/dist/sdk/{host-6TBS44ER.mjs.map → host-THORKOEL.mjs.map} +0 -0
  132. /package/dist/sdk/{failure-condition-evaluator-63BECZYF.mjs.map → routing-2X6QF5IW.mjs.map} +0 -0
  133. /package/dist/sdk/{failure-condition-evaluator-DL6H57NX.mjs.map → schedule-tool-M6Y4YTXR.mjs.map} +0 -0
  134. /package/dist/sdk/{failure-condition-evaluator-HL33X7MH.mjs.map → schedule-tool-R6JJIDZ6.mjs.map} +0 -0
  135. /package/dist/sdk/{routing-GF2CF3JT.mjs.map → schedule-tool-handler-AOMZV3Q3.mjs.map} +0 -0
  136. /package/dist/sdk/{routing-PFFCQJV2.mjs.map → schedule-tool-handler-JYCVH377.mjs.map} +0 -0
  137. /package/dist/sdk/{routing-SFP4D6O3.mjs.map → trace-helpers-K47ZVJSU.mjs.map} +0 -0
  138. /package/dist/sdk/{schedule-tool-45NAALKS.mjs.map → workflow-check-provider-A3YH2UZJ.mjs.map} +0 -0
  139. /package/dist/sdk/{schedule-tool-DN2DSXIX.mjs.map → workflow-check-provider-EMFC7A5K.mjs.map} +0 -0
@@ -1,895 +0,0 @@
1
- import {
2
- extractFileSections,
3
- formatSlackText,
4
- init_markdown,
5
- renderMermaidToPng,
6
- replaceFileSections,
7
- replaceMermaidBlocks
8
- } from "./chunk-PDQTEBOJ.mjs";
9
- import {
10
- context,
11
- init_lazy_otel,
12
- trace
13
- } from "./chunk-UCMJJ3IM.mjs";
14
- import {
15
- __esm
16
- } from "./chunk-J7LXIPZS.mjs";
17
-
18
- // src/slack/client.ts
19
- var SlackClient;
20
- var init_client = __esm({
21
- "src/slack/client.ts"() {
22
- "use strict";
23
- SlackClient = class {
24
- token;
25
- constructor(botToken) {
26
- if (!botToken || typeof botToken !== "string") {
27
- throw new Error("SlackClient: botToken is required");
28
- }
29
- this.token = botToken;
30
- }
31
- reactions = {
32
- add: async ({
33
- channel,
34
- timestamp,
35
- name
36
- }) => {
37
- const resp = await this.api("reactions.add", { channel, timestamp, name });
38
- if (!resp || resp.ok !== true) {
39
- const err = resp && resp.error || "unknown_error";
40
- console.warn(`Slack reactions.add failed (non-fatal): ${err}`);
41
- return { ok: false };
42
- }
43
- return { ok: true };
44
- },
45
- remove: async ({
46
- channel,
47
- timestamp,
48
- name
49
- }) => {
50
- const resp = await this.api("reactions.remove", { channel, timestamp, name });
51
- if (!resp || resp.ok !== true) {
52
- const err = resp && resp.error || "unknown_error";
53
- console.warn(`Slack reactions.remove failed (non-fatal): ${err}`);
54
- return { ok: false };
55
- }
56
- return { ok: true };
57
- }
58
- };
59
- chat = {
60
- postMessage: async ({
61
- channel,
62
- text,
63
- thread_ts
64
- }) => {
65
- try {
66
- const resp = await this.api("chat.postMessage", { channel, text, thread_ts });
67
- if (!resp || resp.ok !== true) {
68
- const err = resp && resp.error || "unknown_error";
69
- const warnings = Array.isArray(resp?.response_metadata?.warnings) ? resp.response_metadata.warnings.join(",") : "";
70
- console.warn(
71
- `Slack chat.postMessage failed (non-fatal): error=${err} channel=${channel} thread_ts=${thread_ts || "-"} text_len=${text.length}${warnings ? ` warnings=${warnings}` : ""}`
72
- );
73
- return {
74
- ok: false,
75
- ts: void 0,
76
- message: void 0,
77
- data: resp,
78
- error: err
79
- };
80
- }
81
- return {
82
- ok: true,
83
- ts: resp.ts || resp.message && resp.message.ts || void 0,
84
- message: resp.message,
85
- data: resp,
86
- error: void 0
87
- };
88
- } catch (e) {
89
- console.warn(
90
- `Slack chat.postMessage threw (non-fatal): channel=${channel} thread_ts=${thread_ts || "-"} text_len=${text.length} error=${e instanceof Error ? e.message : String(e)}`
91
- );
92
- return {
93
- ok: false,
94
- ts: void 0,
95
- message: void 0,
96
- data: void 0,
97
- error: e instanceof Error ? e.message : String(e)
98
- };
99
- }
100
- },
101
- update: async ({ channel, ts, text }) => {
102
- try {
103
- const resp = await this.api("chat.update", { channel, ts, text });
104
- if (!resp || resp.ok !== true) {
105
- const err = resp && resp.error || "unknown_error";
106
- const warnings = Array.isArray(resp?.response_metadata?.warnings) ? resp.response_metadata.warnings.join(",") : "";
107
- console.warn(
108
- `Slack chat.update failed (non-fatal): error=${err} channel=${channel} ts=${ts} text_len=${text.length}${warnings ? ` warnings=${warnings}` : ""}`
109
- );
110
- return { ok: false, ts, error: err, data: resp };
111
- }
112
- return { ok: true, ts: resp.ts || ts, error: void 0, data: resp };
113
- } catch (e) {
114
- console.warn(
115
- `Slack chat.update threw (non-fatal): channel=${channel} ts=${ts} text_len=${text.length} error=${e instanceof Error ? e.message : String(e)}`
116
- );
117
- return {
118
- ok: false,
119
- ts,
120
- error: e instanceof Error ? e.message : String(e),
121
- data: void 0
122
- };
123
- }
124
- }
125
- };
126
- async getBotUserId() {
127
- const resp = await this.api("auth.test", {});
128
- if (!resp || resp.ok !== true || !resp.user_id) {
129
- console.warn("Slack auth.test failed (non-fatal); bot user id unavailable");
130
- return "UNKNOWN_BOT";
131
- }
132
- return String(resp.user_id);
133
- }
134
- /**
135
- * Fetch user info from Slack API.
136
- * Returns user profile including guest status flags, email, display name, and timezone.
137
- */
138
- async getUserInfo(userId) {
139
- try {
140
- const resp = await this.api("users.info", { user: userId });
141
- if (!resp || resp.ok !== true || !resp.user) {
142
- return { ok: false };
143
- }
144
- return {
145
- ok: true,
146
- user: {
147
- id: resp.user.id,
148
- name: resp.user.name,
149
- real_name: resp.user.real_name || resp.user.profile?.real_name,
150
- email: resp.user.profile?.email,
151
- is_restricted: resp.user.is_restricted,
152
- is_ultra_restricted: resp.user.is_ultra_restricted,
153
- is_bot: resp.user.is_bot,
154
- is_app_user: resp.user.is_app_user,
155
- deleted: resp.user.deleted,
156
- tz: resp.user.tz,
157
- tz_offset: resp.user.tz_offset
158
- }
159
- };
160
- } catch (e) {
161
- console.warn(`Slack users.info failed: ${e instanceof Error ? e.message : String(e)}`);
162
- return { ok: false };
163
- }
164
- }
165
- /**
166
- * Open a DM channel with a user.
167
- * Returns the DM channel ID.
168
- */
169
- async openDM(userId) {
170
- try {
171
- const resp = await this.api("conversations.open", { users: userId });
172
- if (!resp || resp.ok !== true || !resp.channel?.id) {
173
- console.warn(`Slack conversations.open failed: ${resp?.error || "unknown_error"}`);
174
- return { ok: false };
175
- }
176
- return { ok: true, channel: resp.channel.id };
177
- } catch (e) {
178
- console.warn(
179
- `Slack conversations.open failed: ${e instanceof Error ? e.message : String(e)}`
180
- );
181
- return { ok: false };
182
- }
183
- }
184
- async fetchThreadReplies(channel, thread_ts, limit = 40) {
185
- try {
186
- const params = new URLSearchParams({
187
- channel,
188
- ts: thread_ts,
189
- limit: String(limit)
190
- });
191
- const res = await fetch(`https://slack.com/api/conversations.replies?${params.toString()}`, {
192
- method: "GET",
193
- headers: {
194
- Authorization: `Bearer ${this.token}`
195
- }
196
- });
197
- const resp = await res.json();
198
- if (!resp || resp.ok !== true || !Array.isArray(resp.messages)) {
199
- const err = resp && resp.error || "unknown_error";
200
- console.warn(
201
- `Slack conversations.replies failed (non-fatal): ${err} (channel=${channel}, ts=${thread_ts}, limit=${limit})`
202
- );
203
- return [];
204
- }
205
- return resp.messages.map((m) => ({
206
- ts: String(m.ts || ""),
207
- user: m.user,
208
- text: m.text,
209
- bot_id: m.bot_id,
210
- thread_ts: m.thread_ts,
211
- files: Array.isArray(m.files) ? m.files : void 0
212
- }));
213
- } catch (e) {
214
- console.warn(
215
- `Slack conversations.replies failed (non-fatal): ${e instanceof Error ? e.message : String(e)} (channel=${channel}, ts=${thread_ts}, limit=${limit})`
216
- );
217
- return [];
218
- }
219
- }
220
- files = {
221
- /**
222
- * Upload a file to Slack using files.uploadV2 API
223
- * @param options Upload options including file content, filename, channel, and thread_ts
224
- */
225
- uploadV2: async ({
226
- content,
227
- filename,
228
- channel,
229
- thread_ts,
230
- title,
231
- initial_comment
232
- }) => {
233
- try {
234
- const getUrlResp = await this.apiForm("files.getUploadURLExternal", {
235
- filename,
236
- length: String(content.length)
237
- });
238
- if (!getUrlResp || getUrlResp.ok !== true || !getUrlResp.upload_url) {
239
- console.warn(
240
- `Slack files.getUploadURLExternal failed: ${getUrlResp?.error || "unknown"}`
241
- );
242
- return { ok: false };
243
- }
244
- const uploadResp = await fetch(getUrlResp.upload_url, {
245
- method: "POST",
246
- body: content
247
- });
248
- if (!uploadResp.ok) {
249
- console.warn(`Slack file upload to URL failed: ${uploadResp.status}`);
250
- return { ok: false };
251
- }
252
- const completeResp = await this.api("files.completeUploadExternal", {
253
- files: [{ id: getUrlResp.file_id, title: title || filename }],
254
- channel_id: channel,
255
- thread_ts,
256
- initial_comment
257
- });
258
- if (!completeResp || completeResp.ok !== true) {
259
- console.warn(
260
- `Slack files.completeUploadExternal failed: ${completeResp?.error || "unknown"}`
261
- );
262
- return { ok: false };
263
- }
264
- return {
265
- ok: true,
266
- file: completeResp.files?.[0] || { id: getUrlResp.file_id }
267
- };
268
- } catch (e) {
269
- console.warn(`Slack file upload failed: ${e instanceof Error ? e.message : String(e)}`);
270
- return { ok: false };
271
- }
272
- }
273
- };
274
- views = {
275
- publish: async ({
276
- user_id,
277
- view
278
- }) => {
279
- try {
280
- const resp = await this.api("views.publish", { user_id, view });
281
- if (!resp || resp.ok !== true) {
282
- const err = resp && resp.error || "unknown_error";
283
- console.warn(`Slack views.publish failed (non-fatal): ${err}`);
284
- return { ok: false, error: err };
285
- }
286
- return { ok: true };
287
- } catch (e) {
288
- console.warn(
289
- `Slack views.publish threw (non-fatal): ${e instanceof Error ? e.message : String(e)}`
290
- );
291
- return { ok: false, error: e instanceof Error ? e.message : String(e) };
292
- }
293
- }
294
- };
295
- getWebClient() {
296
- return {
297
- conversations: {
298
- history: async ({ channel, limit }) => await this.api("conversations.history", { channel, limit }),
299
- open: async ({ users }) => await this.api("conversations.open", { users }),
300
- replies: async ({ channel, ts, limit }) => await this.api("conversations.replies", { channel, ts, limit })
301
- }
302
- };
303
- }
304
- async api(method, body) {
305
- const res = await fetch(`https://slack.com/api/${method}`, {
306
- method: "POST",
307
- headers: {
308
- "Content-Type": "application/json; charset=utf-8",
309
- Authorization: `Bearer ${this.token}`
310
- },
311
- body: JSON.stringify(body)
312
- });
313
- return await res.json();
314
- }
315
- /** Send a Slack API request as application/x-www-form-urlencoded (required by some file methods). */
316
- async apiForm(method, params) {
317
- const body = new URLSearchParams(params);
318
- const res = await fetch(`https://slack.com/api/${method}`, {
319
- method: "POST",
320
- headers: {
321
- "Content-Type": "application/x-www-form-urlencoded",
322
- Authorization: `Bearer ${this.token}`
323
- },
324
- body: body.toString()
325
- });
326
- return await res.json();
327
- }
328
- };
329
- }
330
- });
331
-
332
- // src/frontends/slack-frontend.ts
333
- var SlackFrontend;
334
- var init_slack_frontend = __esm({
335
- "src/frontends/slack-frontend.ts"() {
336
- init_client();
337
- init_markdown();
338
- init_lazy_otel();
339
- SlackFrontend = class {
340
- name = "slack";
341
- subs = [];
342
- cfg;
343
- // Reactions ack/done per run (inbound Slack events only)
344
- acked = false;
345
- ackRef = null;
346
- ackName = "eyes";
347
- doneName = "thumbsup";
348
- errorNotified = false;
349
- cachedTraceInfo = null;
350
- constructor(config) {
351
- this.cfg = config || {};
352
- }
353
- start(ctx) {
354
- const bus = ctx.eventBus;
355
- if (!this.cachedTraceInfo) {
356
- this.cachedTraceInfo = this.getTraceInfo();
357
- }
358
- if (!this.cachedTraceInfo) {
359
- const runTraceId = ctx?.run?.traceId;
360
- if (typeof runTraceId === "string" && runTraceId) {
361
- this.cachedTraceInfo = { traceId: runTraceId, spanId: "" };
362
- }
363
- }
364
- try {
365
- const hasClient = !!(ctx.slack || ctx.slackClient || this.cfg?.botToken || process.env.SLACK_BOT_TOKEN);
366
- ctx.logger.info(`[slack-frontend] started; hasClient=${hasClient} defaultChannel=unset`);
367
- } catch {
368
- }
369
- try {
370
- const payload = this.getInboundSlackPayload(ctx);
371
- if (payload) {
372
- const ev = payload.event || {};
373
- const ch = String(ev.channel || "-");
374
- const ts = String(ev.ts || ev.event_ts || "-");
375
- const user = String(ev.user || ev.bot_id || "-");
376
- const type = String(ev.type || "-");
377
- const thread = String(ev.thread_ts || "");
378
- ctx.logger.info(
379
- `[slack-frontend] inbound event received: type=${type} channel=${ch} ts=${ts}` + (thread ? ` thread_ts=${thread}` : "") + ` user=${user}`
380
- );
381
- }
382
- } catch {
383
- }
384
- this.subs.push(
385
- bus.on("CheckCompleted", async (env) => {
386
- const ev = env && env.payload || env;
387
- await this.maybePostDirectReply(ctx, ev.checkId, ev.result).catch(() => {
388
- });
389
- await this.maybePostExecutionFailure(ctx, ev.checkId, ev.result).catch(() => {
390
- });
391
- })
392
- );
393
- this.subs.push(
394
- bus.on("CheckErrored", async (env) => {
395
- const ev = env && env.payload || env;
396
- const message = ev?.error?.message || "Execution error";
397
- await this.maybePostError(ctx, "Check failed", message, ev?.checkId).catch(() => {
398
- });
399
- })
400
- );
401
- this.subs.push(
402
- bus.on("StateTransition", async (env) => {
403
- const ev = env && env.payload || env;
404
- if (ev && (ev.to === "Completed" || ev.to === "Error")) {
405
- await this.finalizeReactions(ctx).catch(() => {
406
- });
407
- }
408
- })
409
- );
410
- this.subs.push(
411
- bus.on("Shutdown", async (env) => {
412
- const ev = env && env.payload || env;
413
- const message = ev?.error?.message || "Fatal error";
414
- await this.maybePostError(ctx, "Run failed", message).catch(() => {
415
- });
416
- })
417
- );
418
- this.subs.push(
419
- bus.on("CheckScheduled", async () => {
420
- await this.ensureAcknowledgement(ctx).catch(() => {
421
- });
422
- })
423
- );
424
- this.subs.push(
425
- bus.on("HumanInputRequested", async (env) => {
426
- try {
427
- const ev = env && env.payload || env;
428
- if (!ev || typeof ev.prompt !== "string" || !ev.checkId) return;
429
- let channel = ev.channel;
430
- let threadTs = ev.threadTs;
431
- if (!channel || !threadTs) {
432
- const payload = this.getInboundSlackPayload(ctx);
433
- const e = payload?.event;
434
- const derivedTs = String(e?.thread_ts || e?.ts || e?.event_ts || "");
435
- const derivedCh = String(e?.channel || "");
436
- if (derivedCh && derivedTs) {
437
- channel = channel || derivedCh;
438
- threadTs = threadTs || derivedTs;
439
- }
440
- }
441
- if (!channel || !threadTs) return;
442
- const { getPromptStateManager } = await import("./prompt-state-YPICX7PI.mjs");
443
- const mgr = getPromptStateManager();
444
- const prev = mgr.getWaiting(channel, threadTs);
445
- const text = String(ev.prompt);
446
- mgr.setWaiting(channel, threadTs, {
447
- checkName: String(ev.checkId),
448
- prompt: text,
449
- promptMessageTs: prev?.promptMessageTs,
450
- promptsPosted: (prev?.promptsPosted || 0) + 1
451
- });
452
- try {
453
- ctx.logger.info(
454
- `[slack-frontend] registered human-input waiting state for ${channel} thread=${threadTs}`
455
- );
456
- } catch {
457
- }
458
- } catch (e) {
459
- try {
460
- ctx.logger.warn(
461
- `[slack-frontend] HumanInputRequested handling failed: ${e instanceof Error ? e.message : String(e)}`
462
- );
463
- } catch {
464
- }
465
- }
466
- })
467
- );
468
- this.subs.push(
469
- bus.on("SnapshotSaved", async (env) => {
470
- try {
471
- const ev = env && env.payload || env;
472
- const channel = String(ev?.channel || "");
473
- const threadTs = String(ev?.threadTs || "");
474
- const filePath = String(ev?.filePath || "");
475
- if (!channel || !threadTs || !filePath) return;
476
- const { getPromptStateManager } = await import("./prompt-state-YPICX7PI.mjs");
477
- const mgr = getPromptStateManager();
478
- mgr.update(channel, threadTs, { snapshotPath: filePath });
479
- try {
480
- ctx.logger.info(
481
- `[slack-frontend] snapshot path attached to waiting prompt: ${filePath}`
482
- );
483
- } catch {
484
- }
485
- } catch {
486
- }
487
- })
488
- );
489
- }
490
- stop() {
491
- for (const s of this.subs) s.unsubscribe();
492
- this.subs = [];
493
- }
494
- getSlack(ctx) {
495
- const injected = ctx.slack || ctx.slackClient;
496
- if (injected) return injected;
497
- try {
498
- const token = this.cfg?.botToken || process.env.SLACK_BOT_TOKEN;
499
- if (typeof token === "string" && token.trim()) {
500
- return new SlackClient(token.trim());
501
- }
502
- } catch {
503
- }
504
- return void 0;
505
- }
506
- getInboundSlackPayload(ctx) {
507
- try {
508
- const anyCfg = ctx.config || {};
509
- const slackCfg = anyCfg.slack || {};
510
- const endpoint = slackCfg.endpoint || "/bots/slack/support";
511
- const payload = ctx.webhookContext?.webhookData?.get(endpoint);
512
- return payload || null;
513
- } catch {
514
- return null;
515
- }
516
- }
517
- getInboundSlackEvent(ctx) {
518
- try {
519
- const payload = this.getInboundSlackPayload(ctx);
520
- const ev = payload?.event;
521
- const channel = String(ev?.channel || "");
522
- const ts = String(ev?.ts || ev?.event_ts || "");
523
- if (channel && ts) return { channel, ts };
524
- } catch {
525
- }
526
- return null;
527
- }
528
- isTelemetryEnabled(ctx) {
529
- try {
530
- const anyCfg = ctx.config || {};
531
- const slackCfg = anyCfg.slack || {};
532
- const telemetryCfg = slackCfg.telemetry ?? this.cfg?.telemetry;
533
- return telemetryCfg === true || telemetryCfg && typeof telemetryCfg === "object" && telemetryCfg.enabled === true;
534
- } catch {
535
- return false;
536
- }
537
- }
538
- async maybePostError(ctx, title, message, checkId) {
539
- if (this.errorNotified) return;
540
- const slack = this.getSlack(ctx);
541
- if (!slack) return;
542
- const payload = this.getInboundSlackPayload(ctx);
543
- const ev = payload?.event;
544
- const channel = String(ev?.channel || "");
545
- const threadTs = String(ev?.thread_ts || ev?.ts || ev?.event_ts || "");
546
- if (!channel || !threadTs) {
547
- try {
548
- ctx.logger.warn(
549
- `[slack-frontend] skip posting error notice: missing channel/thread (channel=${channel || "-"} thread=${threadTs || "-"})`
550
- );
551
- } catch {
552
- }
553
- return;
554
- }
555
- let text = `\u274C ${title}`;
556
- if (checkId) text += `
557
- Check: ${checkId}`;
558
- if (message) text += `
559
- ${message}`;
560
- if (this.isTelemetryEnabled(ctx)) {
561
- const traceInfo = this.getTraceInfo() || this.cachedTraceInfo;
562
- if (traceInfo?.traceId) {
563
- text += `
564
-
565
- \`trace_id: ${traceInfo.traceId}\``;
566
- }
567
- }
568
- const formattedText = formatSlackText(text);
569
- const postResult = await slack.chat.postMessage({
570
- channel,
571
- text: formattedText,
572
- thread_ts: threadTs
573
- });
574
- if (!postResult?.ok) {
575
- try {
576
- ctx.logger.warn(
577
- `[slack-frontend] failed to post error notice to ${channel} thread=${threadTs} check=${checkId || "run"} error=${postResult?.error || "unknown_error"}`
578
- );
579
- } catch {
580
- }
581
- return;
582
- }
583
- try {
584
- ctx.logger.info(
585
- `[slack-frontend] posted error notice to ${channel} thread=${threadTs} check=${checkId || "run"}`
586
- );
587
- } catch {
588
- }
589
- this.errorNotified = true;
590
- }
591
- isExecutionFailureIssue(issue) {
592
- const ruleId = String(issue?.ruleId || "");
593
- const msg = String(issue?.message || "");
594
- const msgLower = msg.toLowerCase();
595
- return ruleId.endsWith("/error") || ruleId.includes("/execution_error") || ruleId.includes("timeout") || ruleId.includes("sandbox_runner_error") || msgLower.includes("timed out") || msg.includes("Command execution failed");
596
- }
597
- async maybePostExecutionFailure(ctx, checkId, result) {
598
- try {
599
- if (this.errorNotified) return;
600
- const cfg = ctx.config || {};
601
- const checkCfg = cfg.checks?.[checkId];
602
- if (!checkCfg) return;
603
- if (checkCfg.type === "human-input") return;
604
- if (checkCfg.criticality === "internal") return;
605
- const issues = result?.issues;
606
- if (!Array.isArray(issues) || issues.length === 0) return;
607
- const failureIssue = issues.find((issue) => this.isExecutionFailureIssue(issue));
608
- if (!failureIssue) return;
609
- if (typeof failureIssue.message === "string" && failureIssue.message.toLowerCase().includes("awaiting human input")) {
610
- return;
611
- }
612
- const msg = typeof failureIssue.message === "string" && failureIssue.message.trim().length > 0 ? failureIssue.message.trim() : `Execution failed (${String(failureIssue.ruleId || "unknown")})`;
613
- await this.maybePostError(ctx, "Check failed", msg, checkId);
614
- } catch {
615
- }
616
- }
617
- async ensureAcknowledgement(ctx) {
618
- if (this.acked) return;
619
- const ref = this.getInboundSlackEvent(ctx);
620
- if (!ref) return;
621
- const slack = this.getSlack(ctx);
622
- if (!slack) return;
623
- try {
624
- const payload = this.getInboundSlackPayload(ctx);
625
- const ev = payload?.event;
626
- try {
627
- const botId = await slack.getBotUserId?.();
628
- if (botId && ev?.user && String(ev.user) === String(botId)) return;
629
- } catch {
630
- }
631
- } catch {
632
- }
633
- try {
634
- const anyCfg = ctx.config || {};
635
- const slackCfg = anyCfg.slack || {};
636
- if (slackCfg?.reactions?.enabled === false) return;
637
- this.ackName = slackCfg?.reactions?.ack || this.ackName;
638
- this.doneName = slackCfg?.reactions?.done || this.doneName;
639
- } catch {
640
- }
641
- await slack.reactions.add({ channel: ref.channel, timestamp: ref.ts, name: this.ackName });
642
- try {
643
- ctx.logger.info(
644
- `[slack-frontend] added acknowledgement reaction :${this.ackName}: channel=${ref.channel} ts=${ref.ts}`
645
- );
646
- } catch {
647
- }
648
- this.acked = true;
649
- this.ackRef = ref;
650
- if (!this.cachedTraceInfo) {
651
- this.cachedTraceInfo = this.getTraceInfo();
652
- }
653
- }
654
- async finalizeReactions(ctx) {
655
- if (!this.acked || !this.ackRef) return;
656
- const slack = this.getSlack(ctx);
657
- if (!slack) return;
658
- try {
659
- try {
660
- await slack.reactions.remove({
661
- channel: this.ackRef.channel,
662
- timestamp: this.ackRef.ts,
663
- name: this.ackName
664
- });
665
- } catch {
666
- }
667
- await slack.reactions.add({
668
- channel: this.ackRef.channel,
669
- timestamp: this.ackRef.ts,
670
- name: this.doneName
671
- });
672
- try {
673
- ctx.logger.info(
674
- `[slack-frontend] replaced acknowledgement with completion reaction :${this.doneName}: channel=${this.ackRef.channel} ts=${this.ackRef.ts}`
675
- );
676
- } catch {
677
- }
678
- } finally {
679
- this.acked = false;
680
- this.ackRef = null;
681
- }
682
- }
683
- /**
684
- * Post direct replies into the originating Slack thread when appropriate.
685
- * This is independent of summary messages and is intended for chat-style flows
686
- * (e.g., AI answers and explicit chat/notify steps).
687
- */
688
- async maybePostDirectReply(ctx, checkId, result) {
689
- try {
690
- const cfg = ctx.config || {};
691
- const checkCfg = cfg.checks?.[checkId];
692
- if (!checkCfg) return;
693
- const slackRoot = cfg.slack || {};
694
- const showRawOutput = slackRoot.show_raw_output === true || this.cfg?.showRawOutput === true;
695
- const telemetryCfg = slackRoot.telemetry ?? this.cfg?.telemetry;
696
- const providerType = checkCfg.type || "";
697
- const isAi = providerType === "ai";
698
- const isLogChat = providerType === "log" && checkCfg.group === "chat";
699
- const isWorkflow = providerType === "workflow";
700
- if (!isAi && !isLogChat && !isWorkflow) return;
701
- if (checkCfg.criticality === "internal") return;
702
- if (isAi) {
703
- const schema = checkCfg.schema;
704
- if (typeof schema === "string") {
705
- const simpleSchemas = ["code-review", "markdown", "text", "plain"];
706
- if (!simpleSchemas.includes(schema)) return;
707
- }
708
- }
709
- const slack = this.getSlack(ctx);
710
- if (!slack) return;
711
- const payload = this.getInboundSlackPayload(ctx);
712
- const ev = payload?.event;
713
- const channel = String(ev?.channel || "");
714
- const threadTs = String(ev?.thread_ts || ev?.ts || ev?.event_ts || "");
715
- if (!channel || !threadTs) {
716
- ctx.logger.warn(
717
- `[slack-frontend] skip posting AI reply for ${checkId}: missing channel/thread (channel=${channel || "-"} thread=${threadTs || "-"})`
718
- );
719
- return;
720
- }
721
- const out = result?.output;
722
- let text;
723
- if (out && typeof out.text === "string" && out.text.trim().length > 0) {
724
- text = out.text.trim();
725
- } else if (isAi && typeof checkCfg.schema === "string") {
726
- if (typeof result?.content === "string" && result.content.trim().length > 0) {
727
- text = result.content.trim();
728
- }
729
- } else if (isLogChat && typeof result?.logOutput === "string") {
730
- const raw = result.logOutput;
731
- if (raw.trim().length > 0) {
732
- text = raw.trim();
733
- }
734
- } else if (isAi && showRawOutput && out !== void 0) {
735
- try {
736
- text = JSON.stringify(out, null, 2);
737
- } catch {
738
- text = String(out);
739
- }
740
- }
741
- if (out && typeof out._rawOutput === "string" && out._rawOutput.trim().length > 0) {
742
- text = (text || "") + "\n\n" + out._rawOutput.trim();
743
- }
744
- if (!text) {
745
- ctx.logger.info(
746
- `[slack-frontend] skip posting AI reply for ${checkId}: no renderable text in check output`
747
- );
748
- return;
749
- }
750
- const diagrams = [];
751
- let processedText = text;
752
- if (diagrams.length > 0) {
753
- try {
754
- ctx.logger.info(
755
- `[slack-frontend] found ${diagrams.length} mermaid diagram(s) to render for ${checkId}`
756
- );
757
- } catch {
758
- }
759
- const uploadedCount = [];
760
- for (let i = 0; i < diagrams.length; i++) {
761
- const diagram = diagrams[i];
762
- try {
763
- ctx.logger.info(`[slack-frontend] rendering mermaid diagram ${i + 1}...`);
764
- const pngBuffer = await renderMermaidToPng(diagram.code);
765
- if (pngBuffer) {
766
- ctx.logger.info(
767
- `[slack-frontend] rendered diagram ${i + 1}, size=${pngBuffer.length} bytes, uploading...`
768
- );
769
- const filename = `diagram-${i + 1}.png`;
770
- const uploadResult = await slack.files.uploadV2({
771
- content: pngBuffer,
772
- filename,
773
- channel,
774
- thread_ts: threadTs,
775
- title: `Diagram ${i + 1}`
776
- });
777
- if (uploadResult.ok) {
778
- uploadedCount.push(i);
779
- ctx.logger.info(`[slack-frontend] uploaded mermaid diagram ${i + 1} to ${channel}`);
780
- } else {
781
- ctx.logger.warn(`[slack-frontend] upload failed for diagram ${i + 1}`);
782
- }
783
- } else {
784
- ctx.logger.warn(
785
- `[slack-frontend] mermaid rendering returned null for diagram ${i + 1} (mmdc failed or not installed)`
786
- );
787
- }
788
- } catch (e) {
789
- ctx.logger.warn(
790
- `[slack-frontend] failed to render/upload mermaid diagram ${i + 1}: ${e instanceof Error ? e.message : String(e)}`
791
- );
792
- }
793
- }
794
- if (uploadedCount.length > 0) {
795
- processedText = replaceMermaidBlocks(
796
- text,
797
- diagrams,
798
- (idx) => uploadedCount.includes(idx) ? "_(See diagram above)_" : "_(Diagram rendering failed)_"
799
- );
800
- }
801
- }
802
- processedText = processedText.replace(/\\n/g, "\n");
803
- const fileSections = extractFileSections(processedText);
804
- if (fileSections.length > 0) {
805
- const uploadedFileIndices = [];
806
- for (let i = 0; i < fileSections.length; i++) {
807
- const section = fileSections[i];
808
- try {
809
- const buffer = Buffer.from(section.content, "utf-8");
810
- const uploadResult = await slack.files.uploadV2({
811
- content: buffer,
812
- filename: section.filename,
813
- channel,
814
- thread_ts: threadTs,
815
- title: section.filename
816
- });
817
- if (uploadResult.ok) {
818
- uploadedFileIndices.push(i);
819
- ctx.logger.info(`[slack-frontend] uploaded file ${section.filename} to ${channel}`);
820
- } else {
821
- ctx.logger.warn(`[slack-frontend] upload failed for file ${section.filename}`);
822
- }
823
- } catch (e) {
824
- ctx.logger.warn(
825
- `[slack-frontend] failed to upload file ${section.filename}: ${e instanceof Error ? e.message : String(e)}`
826
- );
827
- }
828
- }
829
- processedText = replaceFileSections(
830
- processedText,
831
- fileSections,
832
- (idx) => uploadedFileIndices.includes(idx) ? `_(See file: ${fileSections[idx].filename} above)_` : `_(File upload failed: ${fileSections[idx].filename})_`
833
- );
834
- }
835
- let decoratedText = processedText;
836
- const telemetryEnabled = telemetryCfg === true || telemetryCfg && typeof telemetryCfg === "object" && telemetryCfg.enabled === true;
837
- if (telemetryEnabled) {
838
- const traceInfo = this.getTraceInfo() || this.cachedTraceInfo;
839
- if (traceInfo?.traceId) {
840
- const suffix = `\`trace_id: ${traceInfo.traceId}\``;
841
- decoratedText = `${decoratedText}
842
-
843
- ${suffix}`;
844
- }
845
- }
846
- const formattedText = formatSlackText(decoratedText);
847
- const postResult = await slack.chat.postMessage({
848
- channel,
849
- text: formattedText,
850
- thread_ts: threadTs
851
- });
852
- if (!postResult?.ok) {
853
- ctx.logger.warn(
854
- `[slack-frontend] failed to post AI reply for ${checkId} to ${channel} thread=${threadTs} error=${postResult?.error || "unknown_error"}`
855
- );
856
- return;
857
- }
858
- ctx.logger.info(
859
- `[slack-frontend] posted AI reply for ${checkId} to ${channel} thread=${threadTs} ts=${postResult.ts || "-"}`
860
- );
861
- const responseCapture = ctx.responseCapture;
862
- if (responseCapture && typeof responseCapture === "function") {
863
- try {
864
- responseCapture(processedText);
865
- } catch {
866
- }
867
- }
868
- } catch (outerErr) {
869
- try {
870
- ctx.logger.warn(
871
- `[slack-frontend] maybePostDirectReply failed for ${checkId}: ${outerErr instanceof Error ? outerErr.message : String(outerErr)}`
872
- );
873
- } catch {
874
- }
875
- }
876
- }
877
- getTraceInfo() {
878
- try {
879
- const span = trace.getSpan(context.active());
880
- if (!span) return null;
881
- const ctx = span.spanContext();
882
- if (!ctx || !ctx.traceId) return null;
883
- return { traceId: ctx.traceId, spanId: ctx.spanId };
884
- } catch {
885
- return null;
886
- }
887
- }
888
- };
889
- }
890
- });
891
- init_slack_frontend();
892
- export {
893
- SlackFrontend
894
- };
895
- //# sourceMappingURL=slack-frontend-6SXPTQDI.mjs.map