@probelabs/visor 0.1.154 → 0.1.155

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 (54) hide show
  1. package/dist/cli-main.d.ts.map +1 -1
  2. package/dist/index.js +365 -109
  3. package/dist/output/traces/{run-2026-03-04T15-57-32-312Z.ndjson → run-2026-03-04T18-12-39-729Z.ndjson} +84 -84
  4. package/dist/output/traces/{run-2026-03-04T15-58-17-868Z.ndjson → run-2026-03-04T18-13-23-673Z.ndjson} +1761 -1761
  5. package/dist/sdk/{check-provider-registry-2HT3USLQ.mjs → check-provider-registry-7ZHNM7YO.mjs} +5 -5
  6. package/dist/sdk/{check-provider-registry-CQTR5OVS.mjs → check-provider-registry-GJ4EZAIO.mjs} +2 -2
  7. package/dist/sdk/{chunk-PW3RK2IS.mjs → chunk-D7STLGAD.mjs} +8 -8
  8. package/dist/sdk/{chunk-RH7C77KY.mjs → chunk-E7QWTDTC.mjs} +15 -15
  9. package/dist/sdk/{chunk-ZPRIWRM2.mjs → chunk-JBLYMLQJ.mjs} +3 -3
  10. package/dist/sdk/{chunk-AU6RDTY4.mjs → chunk-MLMI3N35.mjs} +2 -2
  11. package/dist/sdk/{chunk-S6MIZBKN.mjs → chunk-POPHHNHJ.mjs} +2 -2
  12. package/dist/sdk/{chunk-S6MIZBKN.mjs.map → chunk-POPHHNHJ.mjs.map} +1 -1
  13. package/dist/sdk/{failure-condition-evaluator-TCB66TZU.mjs → failure-condition-evaluator-NZGTI5SZ.mjs} +3 -3
  14. package/dist/sdk/{github-frontend-6C7WVBEL.mjs → github-frontend-6U46M2ZI.mjs} +3 -3
  15. package/dist/sdk/{host-LKPQXXCY.mjs → host-4ONWAJ6Q.mjs} +3 -3
  16. package/dist/sdk/host-OXBUPRSC.mjs +63 -0
  17. package/dist/sdk/host-OXBUPRSC.mjs.map +1 -0
  18. package/dist/sdk/{routing-5U4Z5KI2.mjs → routing-PTYHW3IU.mjs} +4 -4
  19. package/dist/sdk/{schedule-tool-MVXQWDE2.mjs → schedule-tool-K5LTUYHP.mjs} +5 -5
  20. package/dist/sdk/{schedule-tool-7VHYOB5O.mjs → schedule-tool-SLR7ZHBZ.mjs} +2 -2
  21. package/dist/sdk/{schedule-tool-handler-VYXBBOB6.mjs → schedule-tool-handler-5HKGK5IL.mjs} +5 -5
  22. package/dist/sdk/{schedule-tool-handler-NY67TD3Y.mjs → schedule-tool-handler-XVHYK4KT.mjs} +2 -2
  23. package/dist/sdk/sdk.js +22 -1
  24. package/dist/sdk/sdk.js.map +1 -1
  25. package/dist/sdk/sdk.mjs +4 -4
  26. package/dist/sdk/slack-frontend-6KDUMDDI.mjs +896 -0
  27. package/dist/sdk/slack-frontend-6KDUMDDI.mjs.map +1 -0
  28. package/dist/sdk/{trace-helpers-GI65SVE2.mjs → trace-helpers-NSPBKLBU.mjs} +2 -2
  29. package/dist/sdk/{workflow-check-provider-6QS4QI55.mjs → workflow-check-provider-KWXTBIV2.mjs} +5 -5
  30. package/dist/sdk/{workflow-check-provider-PJSFGBCM.mjs → workflow-check-provider-NYBQAYVH.mjs} +2 -2
  31. package/dist/slack/client.d.ts +9 -0
  32. package/dist/slack/client.d.ts.map +1 -1
  33. package/dist/slack/socket-runner.d.ts +27 -0
  34. package/dist/slack/socket-runner.d.ts.map +1 -1
  35. package/dist/traces/{run-2026-03-04T15-57-32-312Z.ndjson → run-2026-03-04T18-12-39-729Z.ndjson} +84 -84
  36. package/dist/traces/{run-2026-03-04T15-58-17-868Z.ndjson → run-2026-03-04T18-13-23-673Z.ndjson} +1761 -1761
  37. package/package.json +1 -1
  38. /package/dist/sdk/{check-provider-registry-2HT3USLQ.mjs.map → check-provider-registry-7ZHNM7YO.mjs.map} +0 -0
  39. /package/dist/sdk/{check-provider-registry-CQTR5OVS.mjs.map → check-provider-registry-GJ4EZAIO.mjs.map} +0 -0
  40. /package/dist/sdk/{chunk-PW3RK2IS.mjs.map → chunk-D7STLGAD.mjs.map} +0 -0
  41. /package/dist/sdk/{chunk-RH7C77KY.mjs.map → chunk-E7QWTDTC.mjs.map} +0 -0
  42. /package/dist/sdk/{chunk-ZPRIWRM2.mjs.map → chunk-JBLYMLQJ.mjs.map} +0 -0
  43. /package/dist/sdk/{chunk-AU6RDTY4.mjs.map → chunk-MLMI3N35.mjs.map} +0 -0
  44. /package/dist/sdk/{failure-condition-evaluator-TCB66TZU.mjs.map → failure-condition-evaluator-NZGTI5SZ.mjs.map} +0 -0
  45. /package/dist/sdk/{github-frontend-6C7WVBEL.mjs.map → github-frontend-6U46M2ZI.mjs.map} +0 -0
  46. /package/dist/sdk/{host-LKPQXXCY.mjs.map → host-4ONWAJ6Q.mjs.map} +0 -0
  47. /package/dist/sdk/{routing-5U4Z5KI2.mjs.map → routing-PTYHW3IU.mjs.map} +0 -0
  48. /package/dist/sdk/{schedule-tool-7VHYOB5O.mjs.map → schedule-tool-K5LTUYHP.mjs.map} +0 -0
  49. /package/dist/sdk/{schedule-tool-MVXQWDE2.mjs.map → schedule-tool-SLR7ZHBZ.mjs.map} +0 -0
  50. /package/dist/sdk/{schedule-tool-handler-NY67TD3Y.mjs.map → schedule-tool-handler-5HKGK5IL.mjs.map} +0 -0
  51. /package/dist/sdk/{schedule-tool-handler-VYXBBOB6.mjs.map → schedule-tool-handler-XVHYK4KT.mjs.map} +0 -0
  52. /package/dist/sdk/{trace-helpers-GI65SVE2.mjs.map → trace-helpers-NSPBKLBU.mjs.map} +0 -0
  53. /package/dist/sdk/{workflow-check-provider-6QS4QI55.mjs.map → workflow-check-provider-KWXTBIV2.mjs.map} +0 -0
  54. /package/dist/sdk/{workflow-check-provider-PJSFGBCM.mjs.map → workflow-check-provider-NYBQAYVH.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 = '1ceb9f80';
4
+ process.env.VISOR_COMMIT_SHA = '37220799c91e64df29a72348ad88a26bd94f6214';
5
+ process.env.VISOR_COMMIT_SHORT = '37220799';
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
  }
@@ -197254,6 +197267,23 @@ class SlackClient {
197254
197267
  }
197255
197268
  },
197256
197269
  };
197270
+ views = {
197271
+ publish: async ({ user_id, view, }) => {
197272
+ try {
197273
+ const resp = await this.api('views.publish', { user_id, view });
197274
+ if (!resp || resp.ok !== true) {
197275
+ const err = (resp && resp.error) || 'unknown_error';
197276
+ console.warn(`Slack views.publish failed (non-fatal): ${err}`);
197277
+ return { ok: false, error: err };
197278
+ }
197279
+ return { ok: true };
197280
+ }
197281
+ catch (e) {
197282
+ console.warn(`Slack views.publish threw (non-fatal): ${e instanceof Error ? e.message : String(e)}`);
197283
+ return { ok: false, error: e instanceof Error ? e.message : String(e) };
197284
+ }
197285
+ },
197286
+ };
197257
197287
  getWebClient() {
197258
197288
  return {
197259
197289
  conversations: {
@@ -198381,6 +198411,7 @@ class SlackSocketRunner {
198381
198411
  retryCount = 0;
198382
198412
  genericScheduler;
198383
198413
  messageTriggerEvaluator;
198414
+ activeThreads = new Set();
198384
198415
  constructor(engine, cfg, opts) {
198385
198416
  const app = opts.appToken || process.env.SLACK_APP_TOKEN || '';
198386
198417
  if (!app)
@@ -198688,6 +198719,11 @@ class SlackSocketRunner {
198688
198719
  await this.ensureClient();
198689
198720
  }
198690
198721
  catch { }
198722
+ // Handle app_home_opened — publish Home tab view and return early
198723
+ if (type === 'app_home_opened') {
198724
+ await this.publishAppHome(String(ev.user || ''));
198725
+ return;
198726
+ }
198691
198727
  // Ignore edited/changed events to prevent loops (allow file_share — users can share attachments)
198692
198728
  if (subtype &&
198693
198729
  subtype !== 'thread_broadcast' &&
@@ -198918,6 +198954,9 @@ class SlackSocketRunner {
198918
198954
  }
198919
198955
  catch { }
198920
198956
  logger_1.logger.info('[SlackSocket] Dispatching engine run for Slack event');
198957
+ const trackChannel = String(ev.channel || '');
198958
+ const trackThreadTs = String(ev.thread_ts || ev.ts || ev.event_ts || '');
198959
+ const threadKey = trackChannel && trackThreadTs ? this.trackThread(trackChannel, trackThreadTs) : '';
198921
198960
  try {
198922
198961
  // Rate limiting (optional)
198923
198962
  const userId = String(ev.user || 'unknown');
@@ -199004,6 +199043,10 @@ class SlackSocketRunner {
199004
199043
  catch (e) {
199005
199044
  logger_1.logger.error(`[SlackSocket] Engine execution failed: ${e instanceof Error ? e.message : String(e)}`);
199006
199045
  }
199046
+ finally {
199047
+ if (threadKey)
199048
+ this.untrackThread(threadKey);
199049
+ }
199007
199050
  }
199008
199051
  /**
199009
199052
  * Dispatch a matched message trigger as an asynchronous workflow execution.
@@ -199015,121 +199058,334 @@ class SlackSocketRunner {
199015
199058
  const ts = String(ev.ts || ev.event_ts || '');
199016
199059
  const threadTs = ev.thread_ts ? String(ev.thread_ts) : undefined;
199017
199060
  const user = String(ev.user || 'unknown');
199061
+ const replyTs = threadTs || ts;
199062
+ const threadKey = channel && replyTs ? this.trackThread(channel, replyTs) : '';
199018
199063
  logger_1.logger.info(`[SlackSocket] Message trigger '${id}' matched → workflow="${trigger.workflow}" channel=${channel} ts=${ts}`);
199019
- // Verify workflow exists
199020
- const allChecks = Object.keys(this.cfg.checks || {});
199021
- if (!allChecks.includes(trigger.workflow)) {
199022
- logger_1.logger.error(`[SlackSocket] Message trigger '${id}': workflow "${trigger.workflow}" not found in configuration`);
199023
- return;
199024
- }
199025
- // Build conversation context (for thread replies, fetch full thread)
199026
- let conversationContext = undefined;
199027
199064
  try {
199028
- const isThreadReply = !!threadTs && threadTs !== ts;
199029
- if (isThreadReply) {
199030
- const adapter = this.getSlackAdapter();
199031
- if (adapter && channel && threadTs) {
199032
- const cleanedText = String(ev.text || '')
199033
- .replace(/<@[A-Z0-9]+>/g, '')
199034
- .trim();
199035
- conversationContext = await adapter.fetchConversation(channel, threadTs, {
199036
- ts,
199037
- user,
199038
- text: cleanedText || String(ev.text || ''),
199039
- timestamp: Date.now(),
199040
- files: Array.isArray(ev.files) ? ev.files : undefined,
199041
- });
199065
+ // Verify workflow exists
199066
+ const allChecks = Object.keys(this.cfg.checks || {});
199067
+ if (!allChecks.includes(trigger.workflow)) {
199068
+ logger_1.logger.error(`[SlackSocket] Message trigger '${id}': workflow "${trigger.workflow}" not found in configuration`);
199069
+ return;
199070
+ }
199071
+ // Build conversation context (for thread replies, fetch full thread)
199072
+ let conversationContext = undefined;
199073
+ try {
199074
+ const isThreadReply = !!threadTs && threadTs !== ts;
199075
+ if (isThreadReply) {
199076
+ const adapter = this.getSlackAdapter();
199077
+ if (adapter && channel && threadTs) {
199078
+ const cleanedText = String(ev.text || '')
199079
+ .replace(/<@[A-Z0-9]+>/g, '')
199080
+ .trim();
199081
+ conversationContext = await adapter.fetchConversation(channel, threadTs, {
199082
+ ts,
199083
+ user,
199084
+ text: cleanedText || String(ev.text || ''),
199085
+ timestamp: Date.now(),
199086
+ files: Array.isArray(ev.files) ? ev.files : undefined,
199087
+ });
199088
+ }
199042
199089
  }
199043
199090
  }
199091
+ catch (err) {
199092
+ logger_1.logger.warn(`[SlackSocket] Message trigger '${id}': conversation context fetch failed: ${err instanceof Error ? err.message : err}`);
199093
+ }
199094
+ // Build synthetic webhook payload
199095
+ const triggerPayload = {
199096
+ ...payload,
199097
+ trigger: {
199098
+ id,
199099
+ type: 'on_message',
199100
+ workflow: trigger.workflow,
199101
+ },
199102
+ ...(conversationContext ? { slack_conversation: conversationContext } : {}),
199103
+ };
199104
+ const webhookData = new Map();
199105
+ webhookData.set(this.endpoint, triggerPayload);
199106
+ // Clone config for this run with Slack frontend
199107
+ const cfgForRun = (() => {
199108
+ try {
199109
+ const cfg = JSON.parse(JSON.stringify(this.cfg));
199110
+ const fronts = Array.isArray(cfg.frontends) ? cfg.frontends : [];
199111
+ if (!fronts.some((f) => f && f.name === 'slack'))
199112
+ fronts.push({ name: 'slack' });
199113
+ cfg.frontends = fronts;
199114
+ return cfg;
199115
+ }
199116
+ catch {
199117
+ return this.cfg;
199118
+ }
199119
+ })();
199120
+ // Derive stable workspace name from thread identity
199121
+ const wsThreadTs = threadTs || ts;
199122
+ if (channel && wsThreadTs) {
199123
+ const hash = (0, crypto_1.createHash)('sha256')
199124
+ .update(`${channel}:${wsThreadTs}`)
199125
+ .digest('hex')
199126
+ .slice(0, 8);
199127
+ const workspaceName = `slack-trigger-${hash}`;
199128
+ if (!cfgForRun.workspace) {
199129
+ cfgForRun.workspace = {};
199130
+ }
199131
+ cfgForRun.workspace.name = workspaceName;
199132
+ cfgForRun.workspace.cleanup_on_exit = false;
199133
+ }
199134
+ // Create a dedicated engine instance for this trigger
199135
+ const runEngine = new state_machine_execution_engine_1.StateMachineExecutionEngine();
199136
+ await this.ensureClient();
199137
+ try {
199138
+ const parentCtx = this.engine.getExecutionContext?.() || {};
199139
+ const prevCtx = runEngine.getExecutionContext?.() || {};
199140
+ runEngine.setExecutionContext?.({
199141
+ ...parentCtx,
199142
+ ...prevCtx,
199143
+ slack: this.client || parentCtx.slack,
199144
+ slackClient: this.client || parentCtx.slackClient,
199145
+ });
199146
+ }
199147
+ catch { }
199148
+ // Refresh GitHub credentials
199149
+ try {
199150
+ const { refreshGitHubCredentials } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(11347)));
199151
+ await refreshGitHubCredentials();
199152
+ }
199153
+ catch { }
199154
+ await (0, trace_helpers_1.withActiveSpan)('visor.run', {
199155
+ ...(0, trace_helpers_1.getVisorRunAttributes)(),
199156
+ 'visor.run.source': 'slack_message_trigger',
199157
+ 'visor.trigger.id': id,
199158
+ 'visor.trigger.workflow': trigger.workflow,
199159
+ 'slack.channel_id': channel,
199160
+ 'slack.thread_ts': threadTs || ts,
199161
+ 'slack.user_id': user,
199162
+ }, async () => {
199163
+ await runEngine.executeChecks({
199164
+ checks: [trigger.workflow],
199165
+ showDetails: true,
199166
+ outputFormat: 'json',
199167
+ config: cfgForRun,
199168
+ webhookContext: { webhookData, eventType: 'slack_message' },
199169
+ debug: process.env.VISOR_DEBUG === 'true',
199170
+ inputs: trigger.inputs,
199171
+ });
199172
+ });
199173
+ logger_1.logger.info(`[SlackSocket] Message trigger '${id}' workflow completed`);
199044
199174
  }
199045
- catch (err) {
199046
- logger_1.logger.warn(`[SlackSocket] Message trigger '${id}': conversation context fetch failed: ${err instanceof Error ? err.message : err}`);
199175
+ finally {
199176
+ if (threadKey)
199177
+ this.untrackThread(threadKey);
199047
199178
  }
199048
- // Build synthetic webhook payload
199049
- const triggerPayload = {
199050
- ...payload,
199051
- trigger: {
199052
- id,
199053
- type: 'on_message',
199054
- workflow: trigger.workflow,
199055
- },
199056
- ...(conversationContext ? { slack_conversation: conversationContext } : {}),
199057
- };
199058
- const webhookData = new Map();
199059
- webhookData.set(this.endpoint, triggerPayload);
199060
- // Clone config for this run with Slack frontend
199061
- const cfgForRun = (() => {
199179
+ }
199180
+ trackThread(channel, threadTs) {
199181
+ const key = `${channel}:${threadTs}`;
199182
+ this.activeThreads.add(key);
199183
+ return key;
199184
+ }
199185
+ untrackThread(key) {
199186
+ this.activeThreads.delete(key);
199187
+ }
199188
+ /**
199189
+ * Send a best-effort shutdown notice to all active Slack threads.
199190
+ * Bounded by timeoutMs so we never block process exit indefinitely.
199191
+ */
199192
+ async notifyActiveThreadsOfShutdown(timeoutMs = 5000) {
199193
+ if (this.activeThreads.size === 0 || !this.client)
199194
+ return;
199195
+ const msg = ':warning: The bot was restarted. Your request was interrupted and could not be completed. Please retry by sending your message again.';
199196
+ const promises = [...this.activeThreads].map(key => {
199197
+ const [channel, threadTs] = key.split(':');
199198
+ return this.client.chat.postMessage({ channel, thread_ts: threadTs, text: msg }).catch(err => {
199199
+ logger_1.logger.warn(`[SlackSocket] Failed to notify thread ${key} of shutdown: ${err instanceof Error ? err.message : err}`);
199200
+ });
199201
+ });
199202
+ try {
199203
+ let timer;
199204
+ await Promise.race([
199205
+ Promise.allSettled(promises),
199206
+ new Promise(resolve => {
199207
+ timer = setTimeout(resolve, timeoutMs);
199208
+ }),
199209
+ ]);
199210
+ if (timer)
199211
+ clearTimeout(timer);
199212
+ }
199213
+ catch {
199214
+ // best effort
199215
+ }
199216
+ }
199217
+ /**
199218
+ * Publish the App Home tab for the given user.
199219
+ * Shows the user's schedules, message triggers, and available workflows.
199220
+ */
199221
+ async publishAppHome(userId) {
199222
+ if (!userId || !this.client)
199223
+ return;
199224
+ try {
199225
+ const userInfo = await this.fetchUserInfo(userId);
199226
+ // Fetch user's schedules and triggers from the store (best-effort)
199227
+ let schedules = [];
199228
+ let triggers = [];
199062
199229
  try {
199063
- const cfg = JSON.parse(JSON.stringify(this.cfg));
199064
- const fronts = Array.isArray(cfg.frontends) ? cfg.frontends : [];
199065
- if (!fronts.some((f) => f && f.name === 'slack'))
199066
- fronts.push({ name: 'slack' });
199067
- cfg.frontends = fronts;
199068
- return cfg;
199230
+ const store = schedule_store_1.ScheduleStore.getInstance();
199231
+ if (store.isInitialized()) {
199232
+ schedules = await store.getByCreatorAsync(userId);
199233
+ triggers = await store.getTriggersByCreatorAsync(userId);
199234
+ }
199069
199235
  }
199070
- catch {
199071
- return this.cfg;
199236
+ catch (err) {
199237
+ logger_1.logger.warn(`[SlackSocket] Failed to fetch schedules/triggers for Home tab: ${err instanceof Error ? err.message : err}`);
199072
199238
  }
199073
- })();
199074
- // Derive stable workspace name from thread identity
199075
- const wsThreadTs = threadTs || ts;
199076
- if (channel && wsThreadTs) {
199077
- const hash = (0, crypto_1.createHash)('sha256')
199078
- .update(`${channel}:${wsThreadTs}`)
199079
- .digest('hex')
199080
- .slice(0, 8);
199081
- const workspaceName = `slack-trigger-${hash}`;
199082
- if (!cfgForRun.workspace) {
199083
- cfgForRun.workspace = {};
199239
+ // Get available workflows
199240
+ let workflows = [];
199241
+ try {
199242
+ const { WorkflowRegistry } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(82824)));
199243
+ const registry = WorkflowRegistry.getInstance();
199244
+ workflows = registry
199245
+ .list()
199246
+ .map(w => ({ id: w.id, name: w.name, description: w.description }));
199084
199247
  }
199085
- cfgForRun.workspace.name = workspaceName;
199086
- cfgForRun.workspace.cleanup_on_exit = false;
199248
+ catch (err) {
199249
+ logger_1.logger.warn(`[SlackSocket] Failed to fetch workflows for Home tab: ${err instanceof Error ? err.message : err}`);
199250
+ }
199251
+ const blocks = this.buildHomeBlocks(userInfo, schedules, triggers, workflows);
199252
+ await this.client.views.publish({
199253
+ user_id: userId,
199254
+ view: { type: 'home', blocks },
199255
+ });
199087
199256
  }
199088
- // Create a dedicated engine instance for this trigger
199089
- const runEngine = new state_machine_execution_engine_1.StateMachineExecutionEngine();
199090
- await this.ensureClient();
199091
- try {
199092
- const parentCtx = this.engine.getExecutionContext?.() || {};
199093
- const prevCtx = runEngine.getExecutionContext?.() || {};
199094
- runEngine.setExecutionContext?.({
199095
- ...parentCtx,
199096
- ...prevCtx,
199097
- slack: this.client || parentCtx.slack,
199098
- slackClient: this.client || parentCtx.slackClient,
199257
+ catch (err) {
199258
+ logger_1.logger.error(`[SlackSocket] app_home_opened failed: ${err instanceof Error ? err.message : err}`);
199259
+ }
199260
+ }
199261
+ /**
199262
+ * Build Slack Block Kit blocks for the App Home tab.
199263
+ * Exposed as a separate method for testability.
199264
+ */
199265
+ buildHomeBlocks(userInfo, schedules, triggers, workflows) {
199266
+ const blocks = [];
199267
+ // Header
199268
+ const greeting = userInfo?.realName || userInfo?.name || 'there';
199269
+ blocks.push({
199270
+ type: 'header',
199271
+ text: { type: 'plain_text', text: `Hi, ${greeting}!` },
199272
+ });
199273
+ blocks.push({
199274
+ type: 'section',
199275
+ text: { type: 'mrkdwn', text: "Here's an overview of your Visor activity." },
199276
+ });
199277
+ blocks.push({ type: 'divider' });
199278
+ // --- Schedules section ---
199279
+ blocks.push({
199280
+ type: 'header',
199281
+ text: { type: 'plain_text', text: 'Your Schedules' },
199282
+ });
199283
+ const activeSchedules = schedules.filter(s => s.status === 'active' || s.status === 'paused');
199284
+ if (activeSchedules.length === 0) {
199285
+ blocks.push({
199286
+ type: 'section',
199287
+ text: { type: 'mrkdwn', text: '_No active schedules. Message the bot to create one._' },
199099
199288
  });
199100
199289
  }
199101
- catch { }
199102
- // Refresh GitHub credentials
199103
- try {
199104
- const { refreshGitHubCredentials } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(11347)));
199105
- await refreshGitHubCredentials();
199290
+ else {
199291
+ for (const s of activeSchedules.slice(0, 15)) {
199292
+ const statusIcon = s.status === 'paused' ? ':double_vertical_bar:' : ':clock1:';
199293
+ const desc = s.originalExpression || s.workflow || s.id;
199294
+ const nextRun = s.nextRunAt
199295
+ ? `<!date^${Math.floor(s.nextRunAt / 1000)}^{date_short_pretty} at {time}|${new Date(s.nextRunAt).toISOString()}>`
199296
+ : 'N/A';
199297
+ const recurring = s.isRecurring ? `\`${s.schedule}\`` : 'one-time';
199298
+ blocks.push({
199299
+ type: 'section',
199300
+ text: {
199301
+ type: 'mrkdwn',
199302
+ text: `${statusIcon} *${desc}*\n${recurring} · Next: ${nextRun} · Status: \`${s.status}\``,
199303
+ },
199304
+ });
199305
+ }
199306
+ if (activeSchedules.length > 15) {
199307
+ blocks.push({
199308
+ type: 'context',
199309
+ elements: [{ type: 'mrkdwn', text: `_…and ${activeSchedules.length - 15} more_` }],
199310
+ });
199311
+ }
199106
199312
  }
199107
- catch { }
199108
- await (0, trace_helpers_1.withActiveSpan)('visor.run', {
199109
- ...(0, trace_helpers_1.getVisorRunAttributes)(),
199110
- 'visor.run.source': 'slack_message_trigger',
199111
- 'visor.trigger.id': id,
199112
- 'visor.trigger.workflow': trigger.workflow,
199113
- 'slack.channel_id': channel,
199114
- 'slack.thread_ts': threadTs || ts,
199115
- 'slack.user_id': user,
199116
- }, async () => {
199117
- await runEngine.executeChecks({
199118
- checks: [trigger.workflow],
199119
- showDetails: true,
199120
- outputFormat: 'json',
199121
- config: cfgForRun,
199122
- webhookContext: { webhookData, eventType: 'slack_message' },
199123
- debug: process.env.VISOR_DEBUG === 'true',
199124
- inputs: trigger.inputs,
199313
+ blocks.push({ type: 'divider' });
199314
+ // --- Triggers section ---
199315
+ blocks.push({
199316
+ type: 'header',
199317
+ text: { type: 'plain_text', text: 'Your Message Triggers' },
199318
+ });
199319
+ const activeTriggers = triggers.filter(t => t.status === 'active');
199320
+ if (activeTriggers.length === 0) {
199321
+ blocks.push({
199322
+ type: 'section',
199323
+ text: { type: 'mrkdwn', text: '_No active message triggers._' },
199125
199324
  });
199325
+ }
199326
+ else {
199327
+ for (const t of activeTriggers.slice(0, 10)) {
199328
+ const enabledIcon = t.enabled ? ':large_green_circle:' : ':white_circle:';
199329
+ const desc = t.description || t.workflow;
199330
+ const filters = [];
199331
+ if (t.channels?.length)
199332
+ filters.push(`channels: ${t.channels.join(', ')}`);
199333
+ if (t.contains?.length)
199334
+ filters.push(`contains: ${t.contains.join(', ')}`);
199335
+ if (t.matchPattern)
199336
+ filters.push(`pattern: \`${t.matchPattern}\``);
199337
+ blocks.push({
199338
+ type: 'section',
199339
+ text: {
199340
+ type: 'mrkdwn',
199341
+ text: `${enabledIcon} *${desc}*\n${filters.join(' · ') || 'no filters'} → \`${t.workflow}\``,
199342
+ },
199343
+ });
199344
+ }
199345
+ if (activeTriggers.length > 10) {
199346
+ blocks.push({
199347
+ type: 'context',
199348
+ elements: [{ type: 'mrkdwn', text: `_…and ${activeTriggers.length - 10} more_` }],
199349
+ });
199350
+ }
199351
+ }
199352
+ blocks.push({ type: 'divider' });
199353
+ // --- Workflows section ---
199354
+ blocks.push({
199355
+ type: 'header',
199356
+ text: { type: 'plain_text', text: 'Available Workflows' },
199126
199357
  });
199127
- logger_1.logger.info(`[SlackSocket] Message trigger '${id}' workflow completed`);
199358
+ if (workflows.length === 0) {
199359
+ blocks.push({
199360
+ type: 'section',
199361
+ text: { type: 'mrkdwn', text: '_No workflows registered._' },
199362
+ });
199363
+ }
199364
+ else {
199365
+ for (const w of workflows.slice(0, 15)) {
199366
+ blocks.push({
199367
+ type: 'section',
199368
+ text: {
199369
+ type: 'mrkdwn',
199370
+ text: `*${w.name || w.id}*${w.description ? `\n${w.description}` : ''}`,
199371
+ },
199372
+ });
199373
+ }
199374
+ if (workflows.length > 15) {
199375
+ blocks.push({
199376
+ type: 'context',
199377
+ elements: [{ type: 'mrkdwn', text: `_…and ${workflows.length - 15} more_` }],
199378
+ });
199379
+ }
199380
+ }
199381
+ return blocks;
199128
199382
  }
199129
199383
  /**
199130
199384
  * Stop the socket runner and clean up resources
199131
199385
  */
199132
199386
  async stop() {
199387
+ // Notify active threads before tearing down
199388
+ await this.notifyActiveThreadsOfShutdown();
199133
199389
  // Stop background GitHub App token refresh
199134
199390
  try {
199135
199391
  const { stopTokenRefreshTimer } = await Promise.resolve().then(() => __importStar(__nccwpck_require__(11347)));
@@ -395353,7 +395609,7 @@ module.exports = /*#__PURE__*/JSON.parse('{"100":"Continue","101":"Switching Pro
395353
395609
  /***/ ((module) => {
395354
395610
 
395355
395611
  "use strict";
395356
- module.exports = /*#__PURE__*/JSON.parse('{"name":"@probelabs/visor","version":"0.1.154","main":"dist/index.js","bin":{"visor":"./dist/index.js"},"exports":{".":{"require":"./dist/index.js","import":"./dist/index.js"},"./sdk":{"types":"./dist/sdk/sdk.d.ts","import":"./dist/sdk/sdk.mjs","require":"./dist/sdk/sdk.js"},"./cli":{"require":"./dist/index.js"}},"files":["dist/","defaults/","action.yml","README.md","LICENSE"],"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"scripts":{"build:cli":"ncc build src/index.ts -o dist && cp -r defaults dist/ && cp -r output dist/ && cp -r docs dist/ && cp -r examples dist/ && cp -r src/debug-visualizer/ui dist/debug-visualizer/ && node scripts/inject-version.js && echo \'#!/usr/bin/env node\' | cat - dist/index.js > temp && mv temp dist/index.js && chmod +x dist/index.js","build:sdk":"tsup src/sdk.ts --dts --sourcemap --format esm,cjs --out-dir dist/sdk","build":"./scripts/build-oss.sh","build:ee":"npm run build:cli && npm run build:sdk","test":"jest && npm run test:yaml","test:unit":"jest","prepublishOnly":"npm run build","test:watch":"jest --watch","test:coverage":"jest --coverage","test:ee":"jest --testPathPatterns=\'tests/ee\' --testPathIgnorePatterns=\'/node_modules/\' --no-coverage","test:manual:bash":"RUN_MANUAL_TESTS=true jest tests/manual/bash-config-manual.test.ts","lint":"eslint src tests --ext .ts","lint:fix":"eslint src tests --ext .ts --fix","format":"prettier --write src tests","format:check":"prettier --check src tests","clean":"","clean:traces":"node scripts/clean-traces.js","prebuild":"npm run clean && node scripts/generate-config-schema.js","pretest":"npm run clean:traces && node scripts/generate-config-schema.js && npm run build:cli","pretest:unit":"npm run clean:traces && node scripts/generate-config-schema.js && npm run build:cli","test:with-build":"npm run build:cli && jest","test:yaml":"node dist/index.js test --progress compact","test:yaml:parallel":"node dist/index.js test --progress compact --max-parallel 4","prepare":"husky","pre-commit":"lint-staged","deploy:site":"cd site && npx wrangler pages deploy . --project-name=visor-site --commit-dirty=true","deploy:worker":"npx wrangler deploy","deploy":"npm run deploy:site && npm run deploy:worker","publish:ee":"./scripts/publish-ee.sh","release":"./scripts/release.sh","release:patch":"./scripts/release.sh patch","release:minor":"./scripts/release.sh minor","release:major":"./scripts/release.sh major","release:prerelease":"./scripts/release.sh prerelease","docs:validate":"node scripts/validate-readme-links.js","workshop:setup":"npm install -D reveal-md@6.1.2","workshop:serve":"cd workshop && reveal-md slides.md -w","workshop:export":"reveal-md workshop/slides.md --static workshop/build","workshop:pdf":"reveal-md workshop/slides.md --print workshop/Visor-Workshop.pdf --print-size letter","workshop:pdf:ci":"reveal-md workshop/slides.md --print workshop/Visor-Workshop.pdf --print-size letter --puppeteer-launch-args=\\"--no-sandbox --disable-dev-shm-usage\\"","workshop:pdf:a4":"reveal-md workshop/slides.md --print workshop/Visor-Workshop-A4.pdf --print-size A4","workshop:build":"npm run workshop:export && npm run workshop:pdf","simulate:issue":"TS_NODE_TRANSPILE_ONLY=1 ts-node scripts/simulate-gh-run.ts --event issues --action opened --debug","simulate:comment":"TS_NODE_TRANSPILE_ONLY=1 ts-node scripts/simulate-gh-run.ts --event issue_comment --action created --debug"},"keywords":["code-review","ai","github-action","cli","pr-review","visor"],"author":"Probe Labs","license":"MIT","description":"AI workflow engine for code review, assistants, and automation — orchestrate checks, MCP tools, and AI providers with YAML-driven pipelines","repository":{"type":"git","url":"git+https://github.com/probelabs/visor.git"},"bugs":{"url":"https://github.com/probelabs/visor/issues"},"homepage":"https://github.com/probelabs/visor#readme","dependencies":{"@actions/core":"^1.11.1","@apidevtools/swagger-parser":"^12.1.0","@modelcontextprotocol/sdk":"^1.25.3","@nyariv/sandboxjs":"github:probelabs/SandboxJS#f1c13b8eee98734a8ea024061eada4aa9a9ff2e9","@octokit/action":"^8.0.2","@octokit/auth-app":"^8.1.0","@octokit/core":"^7.0.3","@octokit/rest":"^22.0.0","@opentelemetry/api":"^1.9.0","@opentelemetry/core":"^1.30.1","@opentelemetry/exporter-trace-otlp-grpc":"^0.203.0","@opentelemetry/exporter-trace-otlp-http":"^0.203.0","@opentelemetry/instrumentation":"^0.203.0","@opentelemetry/resources":"^1.30.1","@opentelemetry/sdk-metrics":"^1.30.1","@opentelemetry/sdk-node":"^0.203.0","@opentelemetry/sdk-trace-base":"^1.30.1","@opentelemetry/semantic-conventions":"^1.30.1","@probelabs/probe":"^0.6.0-rc271","@types/commander":"^2.12.0","@types/uuid":"^10.0.0","acorn":"^8.16.0","acorn-walk":"^8.3.5","ajv":"^8.17.1","ajv-formats":"^3.0.1","better-sqlite3":"^11.0.0","blessed":"^0.1.81","cli-table3":"^0.6.5","commander":"^14.0.0","deepmerge":"^4.3.1","dotenv":"^17.2.3","ignore":"^7.0.5","js-yaml":"^4.1.0","jsonpath-plus":"^10.4.0","liquidjs":"^10.21.1","minimatch":"^10.2.2","node-cron":"^3.0.3","open":"^9.1.0","simple-git":"^3.28.0","uuid":"^11.1.0","ws":"^8.18.3"},"optionalDependencies":{"@anthropic/claude-code-sdk":"npm:null@*","@open-policy-agent/opa-wasm":"^1.10.0","knex":"^3.1.0","mysql2":"^3.11.0","pg":"^8.13.0","tedious":"^19.0.0"},"devDependencies":{"@eslint/js":"^9.34.0","@kie/act-js":"^2.6.2","@kie/mock-github":"^2.0.1","@swc/core":"^1.13.2","@swc/jest":"^0.2.37","@types/better-sqlite3":"^7.6.0","@types/blessed":"^0.1.27","@types/jest":"^30.0.0","@types/js-yaml":"^4.0.9","@types/node":"^24.3.0","@types/node-cron":"^3.0.11","@types/ws":"^8.18.1","@typescript-eslint/eslint-plugin":"^8.42.0","@typescript-eslint/parser":"^8.42.0","@vercel/ncc":"^0.38.4","eslint":"^9.34.0","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.4","husky":"^9.1.7","jest":"^30.1.3","lint-staged":"^16.1.6","prettier":"^3.6.2","reveal-md":"^6.1.2","ts-json-schema-generator":"^1.5.1","ts-node":"^10.9.2","tsup":"^8.5.0","typescript":"^5.9.2","wrangler":"^3.0.0"},"peerDependenciesMeta":{"@anthropic/claude-code-sdk":{"optional":true}},"directories":{"test":"tests"},"lint-staged":{"src/**/*.{ts,js}":["eslint --fix","prettier --write"],"tests/**/*.{ts,js}":["eslint --fix","prettier --write"],"*.{json,md,yml,yaml}":["prettier --write"]}}');
395612
+ module.exports = /*#__PURE__*/JSON.parse('{"name":"@probelabs/visor","version":"0.1.155","main":"dist/index.js","bin":{"visor":"./dist/index.js"},"exports":{".":{"require":"./dist/index.js","import":"./dist/index.js"},"./sdk":{"types":"./dist/sdk/sdk.d.ts","import":"./dist/sdk/sdk.mjs","require":"./dist/sdk/sdk.js"},"./cli":{"require":"./dist/index.js"}},"files":["dist/","defaults/","action.yml","README.md","LICENSE"],"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"scripts":{"build:cli":"ncc build src/index.ts -o dist && cp -r defaults dist/ && cp -r output dist/ && cp -r docs dist/ && cp -r examples dist/ && cp -r src/debug-visualizer/ui dist/debug-visualizer/ && node scripts/inject-version.js && echo \'#!/usr/bin/env node\' | cat - dist/index.js > temp && mv temp dist/index.js && chmod +x dist/index.js","build:sdk":"tsup src/sdk.ts --dts --sourcemap --format esm,cjs --out-dir dist/sdk","build":"./scripts/build-oss.sh","build:ee":"npm run build:cli && npm run build:sdk","test":"jest && npm run test:yaml","test:unit":"jest","prepublishOnly":"npm run build","test:watch":"jest --watch","test:coverage":"jest --coverage","test:ee":"jest --testPathPatterns=\'tests/ee\' --testPathIgnorePatterns=\'/node_modules/\' --no-coverage","test:manual:bash":"RUN_MANUAL_TESTS=true jest tests/manual/bash-config-manual.test.ts","lint":"eslint src tests --ext .ts","lint:fix":"eslint src tests --ext .ts --fix","format":"prettier --write src tests","format:check":"prettier --check src tests","clean":"","clean:traces":"node scripts/clean-traces.js","prebuild":"npm run clean && node scripts/generate-config-schema.js","pretest":"npm run clean:traces && node scripts/generate-config-schema.js && npm run build:cli","pretest:unit":"npm run clean:traces && node scripts/generate-config-schema.js && npm run build:cli","test:with-build":"npm run build:cli && jest","test:yaml":"node dist/index.js test --progress compact","test:yaml:parallel":"node dist/index.js test --progress compact --max-parallel 4","prepare":"husky","pre-commit":"lint-staged","deploy:site":"cd site && npx wrangler pages deploy . --project-name=visor-site --commit-dirty=true","deploy:worker":"npx wrangler deploy","deploy":"npm run deploy:site && npm run deploy:worker","publish:ee":"./scripts/publish-ee.sh","release":"./scripts/release.sh","release:patch":"./scripts/release.sh patch","release:minor":"./scripts/release.sh minor","release:major":"./scripts/release.sh major","release:prerelease":"./scripts/release.sh prerelease","docs:validate":"node scripts/validate-readme-links.js","workshop:setup":"npm install -D reveal-md@6.1.2","workshop:serve":"cd workshop && reveal-md slides.md -w","workshop:export":"reveal-md workshop/slides.md --static workshop/build","workshop:pdf":"reveal-md workshop/slides.md --print workshop/Visor-Workshop.pdf --print-size letter","workshop:pdf:ci":"reveal-md workshop/slides.md --print workshop/Visor-Workshop.pdf --print-size letter --puppeteer-launch-args=\\"--no-sandbox --disable-dev-shm-usage\\"","workshop:pdf:a4":"reveal-md workshop/slides.md --print workshop/Visor-Workshop-A4.pdf --print-size A4","workshop:build":"npm run workshop:export && npm run workshop:pdf","simulate:issue":"TS_NODE_TRANSPILE_ONLY=1 ts-node scripts/simulate-gh-run.ts --event issues --action opened --debug","simulate:comment":"TS_NODE_TRANSPILE_ONLY=1 ts-node scripts/simulate-gh-run.ts --event issue_comment --action created --debug"},"keywords":["code-review","ai","github-action","cli","pr-review","visor"],"author":"Probe Labs","license":"MIT","description":"AI workflow engine for code review, assistants, and automation — orchestrate checks, MCP tools, and AI providers with YAML-driven pipelines","repository":{"type":"git","url":"git+https://github.com/probelabs/visor.git"},"bugs":{"url":"https://github.com/probelabs/visor/issues"},"homepage":"https://github.com/probelabs/visor#readme","dependencies":{"@actions/core":"^1.11.1","@apidevtools/swagger-parser":"^12.1.0","@modelcontextprotocol/sdk":"^1.25.3","@nyariv/sandboxjs":"github:probelabs/SandboxJS#f1c13b8eee98734a8ea024061eada4aa9a9ff2e9","@octokit/action":"^8.0.2","@octokit/auth-app":"^8.1.0","@octokit/core":"^7.0.3","@octokit/rest":"^22.0.0","@opentelemetry/api":"^1.9.0","@opentelemetry/core":"^1.30.1","@opentelemetry/exporter-trace-otlp-grpc":"^0.203.0","@opentelemetry/exporter-trace-otlp-http":"^0.203.0","@opentelemetry/instrumentation":"^0.203.0","@opentelemetry/resources":"^1.30.1","@opentelemetry/sdk-metrics":"^1.30.1","@opentelemetry/sdk-node":"^0.203.0","@opentelemetry/sdk-trace-base":"^1.30.1","@opentelemetry/semantic-conventions":"^1.30.1","@probelabs/probe":"^0.6.0-rc271","@types/commander":"^2.12.0","@types/uuid":"^10.0.0","acorn":"^8.16.0","acorn-walk":"^8.3.5","ajv":"^8.17.1","ajv-formats":"^3.0.1","better-sqlite3":"^11.0.0","blessed":"^0.1.81","cli-table3":"^0.6.5","commander":"^14.0.0","deepmerge":"^4.3.1","dotenv":"^17.2.3","ignore":"^7.0.5","js-yaml":"^4.1.0","jsonpath-plus":"^10.4.0","liquidjs":"^10.21.1","minimatch":"^10.2.2","node-cron":"^3.0.3","open":"^9.1.0","simple-git":"^3.28.0","uuid":"^11.1.0","ws":"^8.18.3"},"optionalDependencies":{"@anthropic/claude-code-sdk":"npm:null@*","@open-policy-agent/opa-wasm":"^1.10.0","knex":"^3.1.0","mysql2":"^3.11.0","pg":"^8.13.0","tedious":"^19.0.0"},"devDependencies":{"@eslint/js":"^9.34.0","@kie/act-js":"^2.6.2","@kie/mock-github":"^2.0.1","@swc/core":"^1.13.2","@swc/jest":"^0.2.37","@types/better-sqlite3":"^7.6.0","@types/blessed":"^0.1.27","@types/jest":"^30.0.0","@types/js-yaml":"^4.0.9","@types/node":"^24.3.0","@types/node-cron":"^3.0.11","@types/ws":"^8.18.1","@typescript-eslint/eslint-plugin":"^8.42.0","@typescript-eslint/parser":"^8.42.0","@vercel/ncc":"^0.38.4","eslint":"^9.34.0","eslint-config-prettier":"^10.1.8","eslint-plugin-prettier":"^5.5.4","husky":"^9.1.7","jest":"^30.1.3","lint-staged":"^16.1.6","prettier":"^3.6.2","reveal-md":"^6.1.2","ts-json-schema-generator":"^1.5.1","ts-node":"^10.9.2","tsup":"^8.5.0","typescript":"^5.9.2","wrangler":"^3.0.0"},"peerDependenciesMeta":{"@anthropic/claude-code-sdk":{"optional":true}},"directories":{"test":"tests"},"lint-staged":{"src/**/*.{ts,js}":["eslint --fix","prettier --write"],"tests/**/*.{ts,js}":["eslint --fix","prettier --write"],"*.{json,md,yml,yaml}":["prettier --write"]}}');
395357
395613
 
395358
395614
  /***/ })
395359
395615