@probelabs/visor 0.1.154-ee → 0.1.155-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 (24) hide show
  1. package/dist/cli-main.d.ts.map +1 -1
  2. package/dist/index.js +364 -108
  3. package/dist/sdk/{check-provider-registry-PZ6K7G4G.mjs → check-provider-registry-OBUYAPPC.mjs} +2 -2
  4. package/dist/sdk/{chunk-LIRIQICI.mjs → chunk-2XSKH755.mjs} +8 -8
  5. package/dist/sdk/{host-7Y25DDOR.mjs → host-MIHKJ63G.mjs} +2 -2
  6. package/dist/sdk/{schedule-tool-KZ36XTW4.mjs → schedule-tool-M2H7O5WL.mjs} +2 -2
  7. package/dist/sdk/{schedule-tool-handler-2V4EJEQT.mjs → schedule-tool-handler-J3CJWB6A.mjs} +2 -2
  8. package/dist/sdk/sdk.js +21 -0
  9. package/dist/sdk/sdk.js.map +1 -1
  10. package/dist/sdk/sdk.mjs +1 -1
  11. package/dist/sdk/slack-frontend-6KDUMDDI.mjs +896 -0
  12. package/dist/sdk/slack-frontend-6KDUMDDI.mjs.map +1 -0
  13. package/dist/sdk/{workflow-check-provider-TXAEY7OU.mjs → workflow-check-provider-7RLM3T2I.mjs} +2 -2
  14. package/dist/slack/client.d.ts +9 -0
  15. package/dist/slack/client.d.ts.map +1 -1
  16. package/dist/slack/socket-runner.d.ts +27 -0
  17. package/dist/slack/socket-runner.d.ts.map +1 -1
  18. package/package.json +1 -1
  19. /package/dist/sdk/{check-provider-registry-PZ6K7G4G.mjs.map → check-provider-registry-OBUYAPPC.mjs.map} +0 -0
  20. /package/dist/sdk/{chunk-LIRIQICI.mjs.map → chunk-2XSKH755.mjs.map} +0 -0
  21. /package/dist/sdk/{host-7Y25DDOR.mjs.map → host-MIHKJ63G.mjs.map} +0 -0
  22. /package/dist/sdk/{schedule-tool-KZ36XTW4.mjs.map → schedule-tool-M2H7O5WL.mjs.map} +0 -0
  23. /package/dist/sdk/{schedule-tool-handler-2V4EJEQT.mjs.map → schedule-tool-handler-J3CJWB6A.mjs.map} +0 -0
  24. /package/dist/sdk/{workflow-check-provider-TXAEY7OU.mjs.map → workflow-check-provider-7RLM3T2I.mjs.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"","sourceRoot":"","sources":["file:///home/runner/work/visor/visor/src/cli-main.ts"],"names":[],"mappings":"AA6zBA;;GAEG;AACH,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAg8C1C"}
1
+ {"version":3,"file":"","sourceRoot":"","sources":["file:///home/runner/work/visor/visor/src/cli-main.ts"],"names":[],"mappings":"AA6zBA;;GAEG;AACH,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CA08C1C"}
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- process.env.VISOR_VERSION = '0.1.154';
2
+ process.env.VISOR_VERSION = '0.1.155';
3
3
  process.env.PROBE_VERSION = '0.6.0-rc271';
4
- process.env.VISOR_COMMIT_SHA = '1ceb9f8073c3ec36e82c277d3e4bfcbf3320ba3b';
5
- process.env.VISOR_COMMIT_SHORT = '1ceb9f8';
4
+ process.env.VISOR_COMMIT_SHA = '37220799c91e64df29a72348ad88a26bd94f6214';
5
+ process.env.VISOR_COMMIT_SHORT = '3722079';
6
6
  /******/ (() => { // webpackBootstrap
7
7
  /******/ var __webpack_modules__ = ({
8
8
 
@@ -162275,6 +162275,8 @@ async function main() {
162275
162275
  await runner.start();
162276
162276
  console.log('✅ Slack Socket Mode is running. Press Ctrl+C to exit.');
162277
162277
  // Start config file watcher if --watch is enabled
162278
+ let configWatcher;
162279
+ let configWatchStore;
162278
162280
  if (options.watch) {
162279
162281
  if (!options.configPath) {
162280
162282
  console.error('❌ --watch requires --config <path>');
@@ -162298,23 +162300,34 @@ async function main() {
162298
162300
  });
162299
162301
  const watcher = new ConfigWatcher(options.configPath, reloader);
162300
162302
  watcher.start();
162303
+ configWatcher = watcher;
162304
+ configWatchStore = watchStore;
162301
162305
  logger_1.logger.info('Config watching enabled');
162302
- // Clean up watcher resources on process shutdown, then re-raise
162303
- // the signal so the default handler (or other listeners) can terminate.
162304
- const onSignal = (sig) => {
162305
- watcher.stop();
162306
- watchStore.shutdown().catch(() => { });
162307
- process.removeListener('SIGINT', onSignal);
162308
- process.removeListener('SIGTERM', onSignal);
162309
- process.kill(process.pid, sig);
162310
- };
162311
- process.on('SIGINT', onSignal);
162312
- process.on('SIGTERM', onSignal);
162313
162306
  }
162314
162307
  catch (watchErr) {
162315
162308
  logger_1.logger.warn(`Config watch setup failed (Slack mode continues without it): ${watchErr}`);
162316
162309
  }
162317
162310
  }
162311
+ // Graceful shutdown: notify active threads before exiting
162312
+ let shuttingDown = false;
162313
+ const onShutdown = async (sig) => {
162314
+ if (shuttingDown)
162315
+ return;
162316
+ shuttingDown = true;
162317
+ logger_1.logger.info(`[Slack] Received ${sig}, shutting down gracefully…`);
162318
+ if (configWatcher)
162319
+ configWatcher.stop();
162320
+ if (configWatchStore)
162321
+ configWatchStore.shutdown().catch(() => { });
162322
+ await runner.stop();
162323
+ process.exit(0);
162324
+ };
162325
+ process.on('SIGINT', sig => {
162326
+ onShutdown(sig);
162327
+ });
162328
+ process.on('SIGTERM', sig => {
162329
+ onShutdown(sig);
162330
+ });
162318
162331
  process.stdin.resume();
162319
162332
  return;
162320
162333
  }
@@ -199087,6 +199100,23 @@ class SlackClient {
199087
199100
  }
199088
199101
  },
199089
199102
  };
199103
+ views = {
199104
+ publish: async ({ user_id, view, }) => {
199105
+ try {
199106
+ const resp = await this.api('views.publish', { user_id, view });
199107
+ if (!resp || resp.ok !== true) {
199108
+ const err = (resp && resp.error) || 'unknown_error';
199109
+ console.warn(`Slack views.publish failed (non-fatal): ${err}`);
199110
+ return { ok: false, error: err };
199111
+ }
199112
+ return { ok: true };
199113
+ }
199114
+ catch (e) {
199115
+ console.warn(`Slack views.publish threw (non-fatal): ${e instanceof Error ? e.message : String(e)}`);
199116
+ return { ok: false, error: e instanceof Error ? e.message : String(e) };
199117
+ }
199118
+ },
199119
+ };
199090
199120
  getWebClient() {
199091
199121
  return {
199092
199122
  conversations: {
@@ -200214,6 +200244,7 @@ class SlackSocketRunner {
200214
200244
  retryCount = 0;
200215
200245
  genericScheduler;
200216
200246
  messageTriggerEvaluator;
200247
+ activeThreads = new Set();
200217
200248
  constructor(engine, cfg, opts) {
200218
200249
  const app = opts.appToken || process.env.SLACK_APP_TOKEN || '';
200219
200250
  if (!app)
@@ -200521,6 +200552,11 @@ class SlackSocketRunner {
200521
200552
  await this.ensureClient();
200522
200553
  }
200523
200554
  catch { }
200555
+ // Handle app_home_opened — publish Home tab view and return early
200556
+ if (type === 'app_home_opened') {
200557
+ await this.publishAppHome(String(ev.user || ''));
200558
+ return;
200559
+ }
200524
200560
  // Ignore edited/changed events to prevent loops (allow file_share — users can share attachments)
200525
200561
  if (subtype &&
200526
200562
  subtype !== 'thread_broadcast' &&
@@ -200751,6 +200787,9 @@ class SlackSocketRunner {
200751
200787
  }
200752
200788
  catch { }
200753
200789
  logger_1.logger.info('[SlackSocket] Dispatching engine run for Slack event');
200790
+ const trackChannel = String(ev.channel || '');
200791
+ const trackThreadTs = String(ev.thread_ts || ev.ts || ev.event_ts || '');
200792
+ const threadKey = trackChannel && trackThreadTs ? this.trackThread(trackChannel, trackThreadTs) : '';
200754
200793
  try {
200755
200794
  // Rate limiting (optional)
200756
200795
  const userId = String(ev.user || 'unknown');
@@ -200837,6 +200876,10 @@ class SlackSocketRunner {
200837
200876
  catch (e) {
200838
200877
  logger_1.logger.error(`[SlackSocket] Engine execution failed: ${e instanceof Error ? e.message : String(e)}`);
200839
200878
  }
200879
+ finally {
200880
+ if (threadKey)
200881
+ this.untrackThread(threadKey);
200882
+ }
200840
200883
  }
200841
200884
  /**
200842
200885
  * Dispatch a matched message trigger as an asynchronous workflow execution.
@@ -200848,121 +200891,334 @@ class SlackSocketRunner {
200848
200891
  const ts = String(ev.ts || ev.event_ts || '');
200849
200892
  const threadTs = ev.thread_ts ? String(ev.thread_ts) : undefined;
200850
200893
  const user = String(ev.user || 'unknown');
200894
+ const replyTs = threadTs || ts;
200895
+ const threadKey = channel && replyTs ? this.trackThread(channel, replyTs) : '';
200851
200896
  logger_1.logger.info(`[SlackSocket] Message trigger '${id}' matched → workflow="${trigger.workflow}" channel=${channel} ts=${ts}`);
200852
- // Verify workflow exists
200853
- const allChecks = Object.keys(this.cfg.checks || {});
200854
- if (!allChecks.includes(trigger.workflow)) {
200855
- logger_1.logger.error(`[SlackSocket] Message trigger '${id}': workflow "${trigger.workflow}" not found in configuration`);
200856
- return;
200857
- }
200858
- // Build conversation context (for thread replies, fetch full thread)
200859
- let conversationContext = undefined;
200860
200897
  try {
200861
- const isThreadReply = !!threadTs && threadTs !== ts;
200862
- if (isThreadReply) {
200863
- const adapter = this.getSlackAdapter();
200864
- if (adapter && channel && threadTs) {
200865
- const cleanedText = String(ev.text || '')
200866
- .replace(/<@[A-Z0-9]+>/g, '')
200867
- .trim();
200868
- conversationContext = await adapter.fetchConversation(channel, threadTs, {
200869
- ts,
200870
- user,
200871
- text: cleanedText || String(ev.text || ''),
200872
- timestamp: Date.now(),
200873
- files: Array.isArray(ev.files) ? ev.files : undefined,
200874
- });
200898
+ // Verify workflow exists
200899
+ const allChecks = Object.keys(this.cfg.checks || {});
200900
+ if (!allChecks.includes(trigger.workflow)) {
200901
+ logger_1.logger.error(`[SlackSocket] Message trigger '${id}': workflow "${trigger.workflow}" not found in configuration`);
200902
+ return;
200903
+ }
200904
+ // Build conversation context (for thread replies, fetch full thread)
200905
+ let conversationContext = undefined;
200906
+ try {
200907
+ const isThreadReply = !!threadTs && threadTs !== ts;
200908
+ if (isThreadReply) {
200909
+ const adapter = this.getSlackAdapter();
200910
+ if (adapter && channel && threadTs) {
200911
+ const cleanedText = String(ev.text || '')
200912
+ .replace(/<@[A-Z0-9]+>/g, '')
200913
+ .trim();
200914
+ conversationContext = await adapter.fetchConversation(channel, threadTs, {
200915
+ ts,
200916
+ user,
200917
+ text: cleanedText || String(ev.text || ''),
200918
+ timestamp: Date.now(),
200919
+ files: Array.isArray(ev.files) ? ev.files : undefined,
200920
+ });
200921
+ }
200922
+ }
200923
+ }
200924
+ catch (err) {
200925
+ logger_1.logger.warn(`[SlackSocket] Message trigger '${id}': conversation context fetch failed: ${err instanceof Error ? err.message : err}`);
200926
+ }
200927
+ // Build synthetic webhook payload
200928
+ const triggerPayload = {
200929
+ ...payload,
200930
+ trigger: {
200931
+ id,
200932
+ type: 'on_message',
200933
+ workflow: trigger.workflow,
200934
+ },
200935
+ ...(conversationContext ? { slack_conversation: conversationContext } : {}),
200936
+ };
200937
+ const webhookData = new Map();
200938
+ webhookData.set(this.endpoint, triggerPayload);
200939
+ // Clone config for this run with Slack frontend
200940
+ const cfgForRun = (() => {
200941
+ try {
200942
+ const cfg = JSON.parse(JSON.stringify(this.cfg));
200943
+ const fronts = Array.isArray(cfg.frontends) ? cfg.frontends : [];
200944
+ if (!fronts.some((f) => f && f.name === 'slack'))
200945
+ fronts.push({ name: 'slack' });
200946
+ cfg.frontends = fronts;
200947
+ return cfg;
200948
+ }
200949
+ catch {
200950
+ return this.cfg;
200875
200951
  }
200952
+ })();
200953
+ // Derive stable workspace name from thread identity
200954
+ const wsThreadTs = threadTs || ts;
200955
+ if (channel && wsThreadTs) {
200956
+ const hash = (0, crypto_1.createHash)('sha256')
200957
+ .update(`${channel}:${wsThreadTs}`)
200958
+ .digest('hex')
200959
+ .slice(0, 8);
200960
+ const workspaceName = `slack-trigger-${hash}`;
200961
+ if (!cfgForRun.workspace) {
200962
+ cfgForRun.workspace = {};
200963
+ }
200964
+ cfgForRun.workspace.name = workspaceName;
200965
+ cfgForRun.workspace.cleanup_on_exit = false;
200966
+ }
200967
+ // Create a dedicated engine instance for this trigger
200968
+ const runEngine = new state_machine_execution_engine_1.StateMachineExecutionEngine();
200969
+ await this.ensureClient();
200970
+ try {
200971
+ const parentCtx = this.engine.getExecutionContext?.() || {};
200972
+ const prevCtx = runEngine.getExecutionContext?.() || {};
200973
+ runEngine.setExecutionContext?.({
200974
+ ...parentCtx,
200975
+ ...prevCtx,
200976
+ slack: this.client || parentCtx.slack,
200977
+ slackClient: this.client || parentCtx.slackClient,
200978
+ });
200876
200979
  }
200980
+ catch { }
200981
+ // Refresh GitHub credentials
200982
+ try {
200983
+ const { refreshGitHubCredentials } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(11347)));
200984
+ await refreshGitHubCredentials();
200985
+ }
200986
+ catch { }
200987
+ await (0, trace_helpers_1.withActiveSpan)('visor.run', {
200988
+ ...(0, trace_helpers_1.getVisorRunAttributes)(),
200989
+ 'visor.run.source': 'slack_message_trigger',
200990
+ 'visor.trigger.id': id,
200991
+ 'visor.trigger.workflow': trigger.workflow,
200992
+ 'slack.channel_id': channel,
200993
+ 'slack.thread_ts': threadTs || ts,
200994
+ 'slack.user_id': user,
200995
+ }, async () => {
200996
+ await runEngine.executeChecks({
200997
+ checks: [trigger.workflow],
200998
+ showDetails: true,
200999
+ outputFormat: 'json',
201000
+ config: cfgForRun,
201001
+ webhookContext: { webhookData, eventType: 'slack_message' },
201002
+ debug: process.env.VISOR_DEBUG === 'true',
201003
+ inputs: trigger.inputs,
201004
+ });
201005
+ });
201006
+ logger_1.logger.info(`[SlackSocket] Message trigger '${id}' workflow completed`);
200877
201007
  }
200878
- catch (err) {
200879
- logger_1.logger.warn(`[SlackSocket] Message trigger '${id}': conversation context fetch failed: ${err instanceof Error ? err.message : err}`);
201008
+ finally {
201009
+ if (threadKey)
201010
+ this.untrackThread(threadKey);
200880
201011
  }
200881
- // Build synthetic webhook payload
200882
- const triggerPayload = {
200883
- ...payload,
200884
- trigger: {
200885
- id,
200886
- type: 'on_message',
200887
- workflow: trigger.workflow,
200888
- },
200889
- ...(conversationContext ? { slack_conversation: conversationContext } : {}),
200890
- };
200891
- const webhookData = new Map();
200892
- webhookData.set(this.endpoint, triggerPayload);
200893
- // Clone config for this run with Slack frontend
200894
- const cfgForRun = (() => {
201012
+ }
201013
+ trackThread(channel, threadTs) {
201014
+ const key = `${channel}:${threadTs}`;
201015
+ this.activeThreads.add(key);
201016
+ return key;
201017
+ }
201018
+ untrackThread(key) {
201019
+ this.activeThreads.delete(key);
201020
+ }
201021
+ /**
201022
+ * Send a best-effort shutdown notice to all active Slack threads.
201023
+ * Bounded by timeoutMs so we never block process exit indefinitely.
201024
+ */
201025
+ async notifyActiveThreadsOfShutdown(timeoutMs = 5000) {
201026
+ if (this.activeThreads.size === 0 || !this.client)
201027
+ return;
201028
+ const msg = ':warning: The bot was restarted. Your request was interrupted and could not be completed. Please retry by sending your message again.';
201029
+ const promises = [...this.activeThreads].map(key => {
201030
+ const [channel, threadTs] = key.split(':');
201031
+ return this.client.chat.postMessage({ channel, thread_ts: threadTs, text: msg }).catch(err => {
201032
+ logger_1.logger.warn(`[SlackSocket] Failed to notify thread ${key} of shutdown: ${err instanceof Error ? err.message : err}`);
201033
+ });
201034
+ });
201035
+ try {
201036
+ let timer;
201037
+ await Promise.race([
201038
+ Promise.allSettled(promises),
201039
+ new Promise(resolve => {
201040
+ timer = setTimeout(resolve, timeoutMs);
201041
+ }),
201042
+ ]);
201043
+ if (timer)
201044
+ clearTimeout(timer);
201045
+ }
201046
+ catch {
201047
+ // best effort
201048
+ }
201049
+ }
201050
+ /**
201051
+ * Publish the App Home tab for the given user.
201052
+ * Shows the user's schedules, message triggers, and available workflows.
201053
+ */
201054
+ async publishAppHome(userId) {
201055
+ if (!userId || !this.client)
201056
+ return;
201057
+ try {
201058
+ const userInfo = await this.fetchUserInfo(userId);
201059
+ // Fetch user's schedules and triggers from the store (best-effort)
201060
+ let schedules = [];
201061
+ let triggers = [];
200895
201062
  try {
200896
- const cfg = JSON.parse(JSON.stringify(this.cfg));
200897
- const fronts = Array.isArray(cfg.frontends) ? cfg.frontends : [];
200898
- if (!fronts.some((f) => f && f.name === 'slack'))
200899
- fronts.push({ name: 'slack' });
200900
- cfg.frontends = fronts;
200901
- return cfg;
201063
+ const store = schedule_store_1.ScheduleStore.getInstance();
201064
+ if (store.isInitialized()) {
201065
+ schedules = await store.getByCreatorAsync(userId);
201066
+ triggers = await store.getTriggersByCreatorAsync(userId);
201067
+ }
200902
201068
  }
200903
- catch {
200904
- return this.cfg;
201069
+ catch (err) {
201070
+ logger_1.logger.warn(`[SlackSocket] Failed to fetch schedules/triggers for Home tab: ${err instanceof Error ? err.message : err}`);
200905
201071
  }
200906
- })();
200907
- // Derive stable workspace name from thread identity
200908
- const wsThreadTs = threadTs || ts;
200909
- if (channel && wsThreadTs) {
200910
- const hash = (0, crypto_1.createHash)('sha256')
200911
- .update(`${channel}:${wsThreadTs}`)
200912
- .digest('hex')
200913
- .slice(0, 8);
200914
- const workspaceName = `slack-trigger-${hash}`;
200915
- if (!cfgForRun.workspace) {
200916
- cfgForRun.workspace = {};
201072
+ // Get available workflows
201073
+ let workflows = [];
201074
+ try {
201075
+ const { WorkflowRegistry } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(82824)));
201076
+ const registry = WorkflowRegistry.getInstance();
201077
+ workflows = registry
201078
+ .list()
201079
+ .map(w => ({ id: w.id, name: w.name, description: w.description }));
200917
201080
  }
200918
- cfgForRun.workspace.name = workspaceName;
200919
- cfgForRun.workspace.cleanup_on_exit = false;
201081
+ catch (err) {
201082
+ logger_1.logger.warn(`[SlackSocket] Failed to fetch workflows for Home tab: ${err instanceof Error ? err.message : err}`);
201083
+ }
201084
+ const blocks = this.buildHomeBlocks(userInfo, schedules, triggers, workflows);
201085
+ await this.client.views.publish({
201086
+ user_id: userId,
201087
+ view: { type: 'home', blocks },
201088
+ });
200920
201089
  }
200921
- // Create a dedicated engine instance for this trigger
200922
- const runEngine = new state_machine_execution_engine_1.StateMachineExecutionEngine();
200923
- await this.ensureClient();
200924
- try {
200925
- const parentCtx = this.engine.getExecutionContext?.() || {};
200926
- const prevCtx = runEngine.getExecutionContext?.() || {};
200927
- runEngine.setExecutionContext?.({
200928
- ...parentCtx,
200929
- ...prevCtx,
200930
- slack: this.client || parentCtx.slack,
200931
- slackClient: this.client || parentCtx.slackClient,
201090
+ catch (err) {
201091
+ logger_1.logger.error(`[SlackSocket] app_home_opened failed: ${err instanceof Error ? err.message : err}`);
201092
+ }
201093
+ }
201094
+ /**
201095
+ * Build Slack Block Kit blocks for the App Home tab.
201096
+ * Exposed as a separate method for testability.
201097
+ */
201098
+ buildHomeBlocks(userInfo, schedules, triggers, workflows) {
201099
+ const blocks = [];
201100
+ // Header
201101
+ const greeting = userInfo?.realName || userInfo?.name || 'there';
201102
+ blocks.push({
201103
+ type: 'header',
201104
+ text: { type: 'plain_text', text: `Hi, ${greeting}!` },
201105
+ });
201106
+ blocks.push({
201107
+ type: 'section',
201108
+ text: { type: 'mrkdwn', text: "Here's an overview of your Visor activity." },
201109
+ });
201110
+ blocks.push({ type: 'divider' });
201111
+ // --- Schedules section ---
201112
+ blocks.push({
201113
+ type: 'header',
201114
+ text: { type: 'plain_text', text: 'Your Schedules' },
201115
+ });
201116
+ const activeSchedules = schedules.filter(s => s.status === 'active' || s.status === 'paused');
201117
+ if (activeSchedules.length === 0) {
201118
+ blocks.push({
201119
+ type: 'section',
201120
+ text: { type: 'mrkdwn', text: '_No active schedules. Message the bot to create one._' },
200932
201121
  });
200933
201122
  }
200934
- catch { }
200935
- // Refresh GitHub credentials
200936
- try {
200937
- const { refreshGitHubCredentials } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(11347)));
200938
- await refreshGitHubCredentials();
201123
+ else {
201124
+ for (const s of activeSchedules.slice(0, 15)) {
201125
+ const statusIcon = s.status === 'paused' ? ':double_vertical_bar:' : ':clock1:';
201126
+ const desc = s.originalExpression || s.workflow || s.id;
201127
+ const nextRun = s.nextRunAt
201128
+ ? `<!date^${Math.floor(s.nextRunAt / 1000)}^{date_short_pretty} at {time}|${new Date(s.nextRunAt).toISOString()}>`
201129
+ : 'N/A';
201130
+ const recurring = s.isRecurring ? `\`${s.schedule}\`` : 'one-time';
201131
+ blocks.push({
201132
+ type: 'section',
201133
+ text: {
201134
+ type: 'mrkdwn',
201135
+ text: `${statusIcon} *${desc}*\n${recurring} · Next: ${nextRun} · Status: \`${s.status}\``,
201136
+ },
201137
+ });
201138
+ }
201139
+ if (activeSchedules.length > 15) {
201140
+ blocks.push({
201141
+ type: 'context',
201142
+ elements: [{ type: 'mrkdwn', text: `_…and ${activeSchedules.length - 15} more_` }],
201143
+ });
201144
+ }
200939
201145
  }
200940
- catch { }
200941
- await (0, trace_helpers_1.withActiveSpan)('visor.run', {
200942
- ...(0, trace_helpers_1.getVisorRunAttributes)(),
200943
- 'visor.run.source': 'slack_message_trigger',
200944
- 'visor.trigger.id': id,
200945
- 'visor.trigger.workflow': trigger.workflow,
200946
- 'slack.channel_id': channel,
200947
- 'slack.thread_ts': threadTs || ts,
200948
- 'slack.user_id': user,
200949
- }, async () => {
200950
- await runEngine.executeChecks({
200951
- checks: [trigger.workflow],
200952
- showDetails: true,
200953
- outputFormat: 'json',
200954
- config: cfgForRun,
200955
- webhookContext: { webhookData, eventType: 'slack_message' },
200956
- debug: process.env.VISOR_DEBUG === 'true',
200957
- inputs: trigger.inputs,
201146
+ blocks.push({ type: 'divider' });
201147
+ // --- Triggers section ---
201148
+ blocks.push({
201149
+ type: 'header',
201150
+ text: { type: 'plain_text', text: 'Your Message Triggers' },
201151
+ });
201152
+ const activeTriggers = triggers.filter(t => t.status === 'active');
201153
+ if (activeTriggers.length === 0) {
201154
+ blocks.push({
201155
+ type: 'section',
201156
+ text: { type: 'mrkdwn', text: '_No active message triggers._' },
200958
201157
  });
201158
+ }
201159
+ else {
201160
+ for (const t of activeTriggers.slice(0, 10)) {
201161
+ const enabledIcon = t.enabled ? ':large_green_circle:' : ':white_circle:';
201162
+ const desc = t.description || t.workflow;
201163
+ const filters = [];
201164
+ if (t.channels?.length)
201165
+ filters.push(`channels: ${t.channels.join(', ')}`);
201166
+ if (t.contains?.length)
201167
+ filters.push(`contains: ${t.contains.join(', ')}`);
201168
+ if (t.matchPattern)
201169
+ filters.push(`pattern: \`${t.matchPattern}\``);
201170
+ blocks.push({
201171
+ type: 'section',
201172
+ text: {
201173
+ type: 'mrkdwn',
201174
+ text: `${enabledIcon} *${desc}*\n${filters.join(' · ') || 'no filters'} → \`${t.workflow}\``,
201175
+ },
201176
+ });
201177
+ }
201178
+ if (activeTriggers.length > 10) {
201179
+ blocks.push({
201180
+ type: 'context',
201181
+ elements: [{ type: 'mrkdwn', text: `_…and ${activeTriggers.length - 10} more_` }],
201182
+ });
201183
+ }
201184
+ }
201185
+ blocks.push({ type: 'divider' });
201186
+ // --- Workflows section ---
201187
+ blocks.push({
201188
+ type: 'header',
201189
+ text: { type: 'plain_text', text: 'Available Workflows' },
200959
201190
  });
200960
- logger_1.logger.info(`[SlackSocket] Message trigger '${id}' workflow completed`);
201191
+ if (workflows.length === 0) {
201192
+ blocks.push({
201193
+ type: 'section',
201194
+ text: { type: 'mrkdwn', text: '_No workflows registered._' },
201195
+ });
201196
+ }
201197
+ else {
201198
+ for (const w of workflows.slice(0, 15)) {
201199
+ blocks.push({
201200
+ type: 'section',
201201
+ text: {
201202
+ type: 'mrkdwn',
201203
+ text: `*${w.name || w.id}*${w.description ? `\n${w.description}` : ''}`,
201204
+ },
201205
+ });
201206
+ }
201207
+ if (workflows.length > 15) {
201208
+ blocks.push({
201209
+ type: 'context',
201210
+ elements: [{ type: 'mrkdwn', text: `_…and ${workflows.length - 15} more_` }],
201211
+ });
201212
+ }
201213
+ }
201214
+ return blocks;
200961
201215
  }
200962
201216
  /**
200963
201217
  * Stop the socket runner and clean up resources
200964
201218
  */
200965
201219
  async stop() {
201220
+ // Notify active threads before tearing down
201221
+ await this.notifyActiveThreadsOfShutdown();
200966
201222
  // Stop background GitHub App token refresh
200967
201223
  try {
200968
201224
  const { stopTokenRefreshTimer } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(11347)));
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  CheckProviderRegistry,
3
3
  init_check_provider_registry
4
- } from "./chunk-LIRIQICI.mjs";
4
+ } from "./chunk-2XSKH755.mjs";
5
5
  import "./chunk-KFKHU6CM.mjs";
6
6
  import "./chunk-M3BYMES6.mjs";
7
7
  import "./chunk-LG4AUKHB.mjs";
@@ -26,4 +26,4 @@ init_check_provider_registry();
26
26
  export {
27
27
  CheckProviderRegistry
28
28
  };
29
- //# sourceMappingURL=check-provider-registry-PZ6K7G4G.mjs.map
29
+ //# sourceMappingURL=check-provider-registry-OBUYAPPC.mjs.map
@@ -3959,7 +3959,7 @@ async function executeWorkflowAsTool(workflowId, args, context2, argsOverrides)
3959
3959
  ...args,
3960
3960
  ...argsOverrides
3961
3961
  };
3962
- const { WorkflowCheckProvider: WorkflowCheckProvider2 } = await import("./workflow-check-provider-TXAEY7OU.mjs");
3962
+ const { WorkflowCheckProvider: WorkflowCheckProvider2 } = await import("./workflow-check-provider-7RLM3T2I.mjs");
3963
3963
  const provider = new WorkflowCheckProvider2();
3964
3964
  const checkConfig = {
3965
3965
  type: "workflow",
@@ -13027,7 +13027,7 @@ var init_state_machine_execution_engine = __esm({
13027
13027
  try {
13028
13028
  const map = options?.webhookContext?.webhookData;
13029
13029
  if (map) {
13030
- const { CheckProviderRegistry: CheckProviderRegistry2 } = await import("./check-provider-registry-PZ6K7G4G.mjs");
13030
+ const { CheckProviderRegistry: CheckProviderRegistry2 } = await import("./check-provider-registry-OBUYAPPC.mjs");
13031
13031
  const reg = CheckProviderRegistry2.getInstance();
13032
13032
  const p = reg.getProvider("http_input");
13033
13033
  if (p && typeof p.setWebhookContext === "function") p.setWebhookContext(map);
@@ -13150,7 +13150,7 @@ var init_state_machine_execution_engine = __esm({
13150
13150
  tag_filter: tagFilter
13151
13151
  } : config;
13152
13152
  try {
13153
- const { CheckProviderRegistry: CheckProviderRegistry2 } = await import("./check-provider-registry-PZ6K7G4G.mjs");
13153
+ const { CheckProviderRegistry: CheckProviderRegistry2 } = await import("./check-provider-registry-OBUYAPPC.mjs");
13154
13154
  const registry = CheckProviderRegistry2.getInstance();
13155
13155
  registry.setCustomTools(configWithTagFilter.tools || {});
13156
13156
  } catch (error) {
@@ -13214,7 +13214,7 @@ var init_state_machine_execution_engine = __esm({
13214
13214
  try {
13215
13215
  const webhookData = this.executionContext?.webhookContext?.webhookData;
13216
13216
  if (webhookData instanceof Map) {
13217
- const { extractSlackContext: extractSlackContext2 } = await import("./schedule-tool-handler-2V4EJEQT.mjs");
13217
+ const { extractSlackContext: extractSlackContext2 } = await import("./schedule-tool-handler-J3CJWB6A.mjs");
13218
13218
  const slackCtx = extractSlackContext2(webhookData);
13219
13219
  if (slackCtx) {
13220
13220
  const payload = Array.from(webhookData.values())[0];
@@ -13243,7 +13243,7 @@ var init_state_machine_execution_engine = __esm({
13243
13243
  if (Array.isArray(configWithTagFilter.frontends) && configWithTagFilter.frontends.length > 0) {
13244
13244
  try {
13245
13245
  const { EventBus } = await import("./event-bus-5K3Y2FCS.mjs");
13246
- const { FrontendsHost } = await import("./host-7Y25DDOR.mjs");
13246
+ const { FrontendsHost } = await import("./host-MIHKJ63G.mjs");
13247
13247
  const bus = new EventBus();
13248
13248
  context2.eventBus = bus;
13249
13249
  frontendsHost = new FrontendsHost(bus, logger);
@@ -40722,8 +40722,8 @@ function buildBuiltinGlobals(opts) {
40722
40722
  const asyncFunctionNames = /* @__PURE__ */ new Set();
40723
40723
  const scheduleFn = async (args = {}) => {
40724
40724
  try {
40725
- const { handleScheduleAction: handleScheduleAction2, buildScheduleToolContext: buildScheduleToolContext2 } = await import("./schedule-tool-KZ36XTW4.mjs");
40726
- const { extractSlackContext: extractSlackContext2 } = await import("./schedule-tool-handler-2V4EJEQT.mjs");
40725
+ const { handleScheduleAction: handleScheduleAction2, buildScheduleToolContext: buildScheduleToolContext2 } = await import("./schedule-tool-M2H7O5WL.mjs");
40726
+ const { extractSlackContext: extractSlackContext2 } = await import("./schedule-tool-handler-J3CJWB6A.mjs");
40727
40727
  const parentCtx = opts.sessionInfo?._parentContext;
40728
40728
  const webhookData = parentCtx?.prInfo?.eventContext?.webhookData;
40729
40729
  const visorCfg = parentCtx?.config;
@@ -43771,4 +43771,4 @@ undici/lib/fetch/body.js:
43771
43771
  undici/lib/websocket/frame.js:
43772
43772
  (*! ws. MIT License. Einar Otto Stangvik <einaros@gmail.com> *)
43773
43773
  */
43774
- //# sourceMappingURL=chunk-LIRIQICI.mjs.map
43774
+ //# sourceMappingURL=chunk-2XSKH755.mjs.map
@@ -24,7 +24,7 @@ var init_host = __esm({
24
24
  const { GitHubFrontend } = await import("./github-frontend-XKPAYXOT.mjs");
25
25
  this.frontends.push(new GitHubFrontend());
26
26
  } else if (spec.name === "slack") {
27
- const { SlackFrontend } = await import("./slack-frontend-TZU2HIK7.mjs");
27
+ const { SlackFrontend } = await import("./slack-frontend-6KDUMDDI.mjs");
28
28
  this.frontends.push(new SlackFrontend(spec.config));
29
29
  } else if (spec.name === "tui") {
30
30
  const { TuiFrontend } = await import("./tui-frontend-T56PZB67.mjs");
@@ -60,4 +60,4 @@ init_host();
60
60
  export {
61
61
  FrontendsHost
62
62
  };
63
- //# sourceMappingURL=host-7Y25DDOR.mjs.map
63
+ //# sourceMappingURL=host-MIHKJ63G.mjs.map