@cmdop/bot 2026.2.26 → 2026.2.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import { Bot } from 'grammy';
3
3
  import { Client, GatewayIntentBits, Events, REST, Routes } from 'discord.js';
4
4
  import { App, Assistant } from '@slack/bolt';
5
5
  import { CMDOPClient } from '@cmdop/node';
6
+ import { createConsola } from 'consola';
6
7
 
7
8
  var __create = Object.create;
8
9
  var __defProp = Object.defineProperty;
@@ -159,6 +160,95 @@ var init_errors = __esm({
159
160
  }
160
161
  });
161
162
 
163
+ // src/models/command.ts
164
+ var command_exports = {};
165
+ __export(command_exports, {
166
+ ParsedCommandSchema: () => ParsedCommandSchema,
167
+ parseCommand: () => parseCommand
168
+ });
169
+ function parseCommand(text) {
170
+ const trimmed = text.trim();
171
+ const match = /^[/!](\w+)(?:\s+(.*))?$/s.exec(trimmed);
172
+ if (!match) return null;
173
+ const name = (match[1] ?? "").toLowerCase();
174
+ const rest = (match[2] ?? "").trim();
175
+ const args = rest ? rest.split(/\s+/) : [];
176
+ return ParsedCommandSchema.parse({ name, args, rawText: trimmed });
177
+ }
178
+ var ParsedCommandSchema;
179
+ var init_command = __esm({
180
+ "src/models/command.ts"() {
181
+ ParsedCommandSchema = z.object({
182
+ name: z.string().min(1),
183
+ args: z.array(z.string()),
184
+ rawText: z.string()
185
+ });
186
+ }
187
+ });
188
+
189
+ // src/core/base-channel.ts
190
+ var BaseChannel;
191
+ var init_base_channel = __esm({
192
+ "src/core/base-channel.ts"() {
193
+ init_command();
194
+ init_errors();
195
+ BaseChannel = class {
196
+ constructor(id, name, permissions, dispatcher, logger) {
197
+ this.id = id;
198
+ this.name = name;
199
+ this.permissions = permissions;
200
+ this.dispatcher = dispatcher;
201
+ this.logger = logger;
202
+ }
203
+ /**
204
+ * Process an incoming message: parse command → check permission → dispatch → send result.
205
+ * Plain text (non-command) is routed to the agent handler automatically.
206
+ * Channels call this from their platform event handler.
207
+ */
208
+ async processMessage(msg) {
209
+ const parsed = parseCommand(msg.text);
210
+ const ctx = parsed ? {
211
+ userId: msg.userId,
212
+ command: parsed.name,
213
+ args: parsed.args,
214
+ channelId: msg.channelId,
215
+ message: msg
216
+ } : {
217
+ userId: msg.userId,
218
+ command: "agent",
219
+ args: [msg.text],
220
+ channelId: msg.channelId,
221
+ message: msg
222
+ };
223
+ let result;
224
+ try {
225
+ result = await this.dispatcher.dispatch(ctx);
226
+ } catch (err2) {
227
+ const botErr = err2 instanceof BotError ? err2 : new BotError("Unexpected error", { cause: err2 instanceof Error ? err2 : void 0 });
228
+ result = { ok: false, error: botErr };
229
+ }
230
+ if (result.ok) {
231
+ await this.send(msg.userId, result.value);
232
+ } else {
233
+ await this.send(msg.userId, {
234
+ type: "error",
235
+ message: this.formatErrorMessage(result.error)
236
+ });
237
+ }
238
+ }
239
+ formatErrorMessage(error) {
240
+ if (error instanceof CommandNotFoundError) {
241
+ return `Unknown command. Type /help for available commands.`;
242
+ }
243
+ return error.message;
244
+ }
245
+ logEvent(event, meta = {}) {
246
+ this.logger.info(`[${this.name}] ${event}`, { channel: this.id, ...meta });
247
+ }
248
+ };
249
+ }
250
+ });
251
+
162
252
  // ../../node_modules/.pnpm/bottleneck@2.19.5/node_modules/bottleneck/lib/parser.js
163
253
  var require_parser = __commonJS({
164
254
  "../../node_modules/.pnpm/bottleneck@2.19.5/node_modules/bottleneck/lib/parser.js"(exports2) {
@@ -3009,9 +3099,9 @@ var require_lib = __commonJS({
3009
3099
  }
3010
3100
  });
3011
3101
 
3012
- // ../../node_modules/.pnpm/@grammyjs+transformer-throttler@1.2.1_grammy@1.40.0/node_modules/@grammyjs/transformer-throttler/dist/deps.node.js
3102
+ // ../../node_modules/.pnpm/@grammyjs+transformer-throttler@1.2.1_grammy@1.40.1/node_modules/@grammyjs/transformer-throttler/dist/deps.node.js
3013
3103
  var require_deps_node = __commonJS({
3014
- "../../node_modules/.pnpm/@grammyjs+transformer-throttler@1.2.1_grammy@1.40.0/node_modules/@grammyjs/transformer-throttler/dist/deps.node.js"(exports2) {
3104
+ "../../node_modules/.pnpm/@grammyjs+transformer-throttler@1.2.1_grammy@1.40.1/node_modules/@grammyjs/transformer-throttler/dist/deps.node.js"(exports2) {
3015
3105
  var __importDefault = exports2 && exports2.__importDefault || function(mod2) {
3016
3106
  return mod2 && mod2.__esModule ? mod2 : { "default": mod2 };
3017
3107
  };
@@ -3024,9 +3114,9 @@ var require_deps_node = __commonJS({
3024
3114
  }
3025
3115
  });
3026
3116
 
3027
- // ../../node_modules/.pnpm/@grammyjs+transformer-throttler@1.2.1_grammy@1.40.0/node_modules/@grammyjs/transformer-throttler/dist/mod.js
3117
+ // ../../node_modules/.pnpm/@grammyjs+transformer-throttler@1.2.1_grammy@1.40.1/node_modules/@grammyjs/transformer-throttler/dist/mod.js
3028
3118
  var require_mod = __commonJS({
3029
- "../../node_modules/.pnpm/@grammyjs+transformer-throttler@1.2.1_grammy@1.40.0/node_modules/@grammyjs/transformer-throttler/dist/mod.js"(exports2) {
3119
+ "../../node_modules/.pnpm/@grammyjs+transformer-throttler@1.2.1_grammy@1.40.1/node_modules/@grammyjs/transformer-throttler/dist/mod.js"(exports2) {
3030
3120
  Object.defineProperty(exports2, "__esModule", { value: true });
3031
3121
  exports2.bypassThrottler = exports2.apiThrottler = exports2.BottleneckStrategy = void 0;
3032
3122
  var deps_node_js_1 = require_deps_node();
@@ -3089,90 +3179,10 @@ var require_mod = __commonJS({
3089
3179
  }
3090
3180
  });
3091
3181
 
3092
- // src/models/command.ts
3093
- var command_exports = {};
3094
- __export(command_exports, {
3095
- ParsedCommandSchema: () => ParsedCommandSchema,
3096
- parseCommand: () => parseCommand
3097
- });
3098
- function parseCommand(text) {
3099
- const trimmed = text.trim();
3100
- const match = /^[/!](\w+)(?:\s+(.*))?$/s.exec(trimmed);
3101
- if (!match) return null;
3102
- const name = (match[1] ?? "").toLowerCase();
3103
- const rest = (match[2] ?? "").trim();
3104
- const args = rest ? rest.split(/\s+/) : [];
3105
- return ParsedCommandSchema.parse({ name, args, rawText: trimmed });
3106
- }
3107
- var ParsedCommandSchema;
3108
- var init_command = __esm({
3109
- "src/models/command.ts"() {
3110
- ParsedCommandSchema = z.object({
3111
- name: z.string().min(1),
3112
- args: z.array(z.string()),
3113
- rawText: z.string()
3114
- });
3115
- }
3116
- });
3117
-
3118
- // src/core/base-channel.ts
3119
- var BaseChannel;
3120
- var init_base_channel = __esm({
3121
- "src/core/base-channel.ts"() {
3122
- init_command();
3123
- init_errors();
3124
- BaseChannel = class {
3125
- constructor(id, name, permissions, dispatcher, logger) {
3126
- this.id = id;
3127
- this.name = name;
3128
- this.permissions = permissions;
3129
- this.dispatcher = dispatcher;
3130
- this.logger = logger;
3131
- }
3132
- /**
3133
- * Process an incoming message: parse command → check permission → dispatch → send result.
3134
- * Channels call this from their platform event handler.
3135
- */
3136
- async processMessage(msg) {
3137
- const parsed = parseCommand(msg.text);
3138
- if (!parsed) return;
3139
- const ctx = {
3140
- userId: msg.userId,
3141
- command: parsed.name,
3142
- args: parsed.args,
3143
- channelId: msg.channelId,
3144
- message: msg
3145
- };
3146
- let result;
3147
- try {
3148
- result = await this.dispatcher.dispatch(ctx);
3149
- } catch (err2) {
3150
- const botErr = err2 instanceof BotError ? err2 : new BotError("Unexpected error", { cause: err2 instanceof Error ? err2 : void 0 });
3151
- result = { ok: false, error: botErr };
3152
- }
3153
- if (result.ok) {
3154
- await this.send(msg.userId, result.value);
3155
- } else {
3156
- await this.send(msg.userId, {
3157
- type: "error",
3158
- message: this.formatErrorMessage(result.error)
3159
- });
3160
- }
3161
- }
3162
- formatErrorMessage(error) {
3163
- if (error instanceof CommandNotFoundError) {
3164
- return `Unknown command. Type /help for available commands.`;
3165
- }
3166
- return error.message;
3167
- }
3168
- logEvent(event, meta = {}) {
3169
- this.logger.info(`[${this.name}] ${event}`, { channel: this.id, ...meta });
3170
- }
3171
- };
3172
- }
3173
- });
3174
-
3175
3182
  // src/channels/telegram/formatter.ts
3183
+ function escapeHtml(text) {
3184
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
3185
+ }
3176
3186
  function formatBytes(bytes) {
3177
3187
  if (bytes < 1024) return `${bytes}B`;
3178
3188
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}K`;
@@ -3242,6 +3252,51 @@ ${this.formatText(error.message)}`;
3242
3252
  const sizeStr = size !== void 0 && !isDir ? ` \\(${this.formatText(formatBytes(size))}\\)` : "";
3243
3253
  return `${icon} \`${this.escapeInline(name)}\`${sizeStr}`;
3244
3254
  }
3255
+ // ─── HTML formatting (preferred — avoids MarkdownV2 escaping hell) ────────
3256
+ /**
3257
+ * Escape HTML special chars, then convert basic markdown to HTML tags.
3258
+ * Handles: **bold**, `code`, ```code blocks```, _italic_
3259
+ */
3260
+ formatTextHtml(text) {
3261
+ let html = escapeHtml(text);
3262
+ html = html.replace(/```(\w*)\n([\s\S]*?)```/g, (_m, lang, code) => {
3263
+ const cls = lang ? ` class="language-${lang}"` : "";
3264
+ return `<pre><code${cls}>${code}</code></pre>`;
3265
+ });
3266
+ html = html.replace(/`([^`]+)`/g, "<code>$1</code>");
3267
+ html = html.replace(/\*\*(.+?)\*\*/g, "<b>$1</b>");
3268
+ html = html.replace(/__(.+?)__/g, "<b>$1</b>");
3269
+ html = html.replace(/(?<!\w)\*([^*]+?)\*(?!\w)/g, "<i>$1</i>");
3270
+ html = html.replace(/(?<!\w)_([^_]+?)_(?!\w)/g, "<i>$1</i>");
3271
+ return html;
3272
+ }
3273
+ /**
3274
+ * Format code block as HTML <pre>.
3275
+ */
3276
+ formatCodeHtml(code, language) {
3277
+ const escaped = escapeHtml(code);
3278
+ const cls = language ? ` class="language-${language}"` : "";
3279
+ const wrapped = `<pre><code${cls}>${escaped}</code></pre>`;
3280
+ if (wrapped.length <= TELEGRAM_MAX_MESSAGE_LENGTH) return wrapped;
3281
+ const overhead = 40 + (language?.length ?? 0);
3282
+ const maxCode = TELEGRAM_MAX_MESSAGE_LENGTH - overhead;
3283
+ return `<pre><code${cls}>${escaped.slice(0, maxCode)}
3284
+ \u2026(truncated)</code></pre>`;
3285
+ }
3286
+ /**
3287
+ * Format error message as HTML.
3288
+ */
3289
+ formatErrorHtml(message) {
3290
+ return `\u274C <b>Error:</b> ${escapeHtml(message)}`;
3291
+ }
3292
+ /**
3293
+ * Format file entry as HTML.
3294
+ */
3295
+ formatFileEntryHtml(name, isDir, size) {
3296
+ const icon = isDir ? "\u{1F4C1}" : "\u{1F4C4}";
3297
+ const sizeStr = size !== void 0 && !isDir ? ` (${formatBytes(size)})` : "";
3298
+ return `${icon} <code>${escapeHtml(name)}</code>${sizeStr}`;
3299
+ }
3245
3300
  // Escape text that appears inside inline code (backtick context)
3246
3301
  escapeInline(text) {
3247
3302
  return text.replace(/`/g, "'");
@@ -3280,8 +3335,18 @@ var init_channel = __esm({
3280
3335
  bot.on("message:text", async (ctx) => {
3281
3336
  const msg = this.normalizeContext(ctx);
3282
3337
  if (!msg) return;
3283
- for (const h3 of this.messageHandlers) await h3(msg);
3284
- await this.processMessage(msg);
3338
+ const typingInterval = setInterval(() => {
3339
+ ctx.api.sendChatAction(ctx.chat.id, "typing").catch(() => {
3340
+ });
3341
+ }, 4e3);
3342
+ await ctx.api.sendChatAction(ctx.chat.id, "typing").catch(() => {
3343
+ });
3344
+ try {
3345
+ for (const h3 of this.messageHandlers) await h3(msg);
3346
+ await this.processMessage(msg);
3347
+ } finally {
3348
+ clearInterval(typingInterval);
3349
+ }
3285
3350
  });
3286
3351
  bot.on("callback_query:data", async (ctx) => {
3287
3352
  await ctx.answerCallbackQuery();
@@ -3329,20 +3394,18 @@ var init_channel = __esm({
3329
3394
  try {
3330
3395
  switch (message.type) {
3331
3396
  case "text": {
3332
- const text = this.truncate(this.formatter.formatText(message.text));
3333
- await this.bot.api.sendMessage(chatId, text, { parse_mode: "MarkdownV2" });
3397
+ const text = this.truncate(this.formatter.formatTextHtml(message.text));
3398
+ await this.bot.api.sendMessage(chatId, text, { parse_mode: "HTML" });
3334
3399
  break;
3335
3400
  }
3336
3401
  case "code": {
3337
- const code = this.formatter.formatCode(message.code, message.language);
3338
- await this.bot.api.sendMessage(chatId, code, { parse_mode: "MarkdownV2" });
3402
+ const code = this.formatter.formatCodeHtml(message.code, message.language);
3403
+ await this.bot.api.sendMessage(chatId, code, { parse_mode: "HTML" });
3339
3404
  break;
3340
3405
  }
3341
3406
  case "error": {
3342
- const errText = this.formatter.formatError(
3343
- Object.assign(new Error(message.message), { code: "BOT_ERROR", context: {}, toLog: () => ({}) })
3344
- );
3345
- await this.bot.api.sendMessage(chatId, errText, { parse_mode: "MarkdownV2" });
3407
+ const errText = this.formatter.formatErrorHtml(message.message);
3408
+ await this.bot.api.sendMessage(chatId, errText, { parse_mode: "HTML" });
3346
3409
  break;
3347
3410
  }
3348
3411
  }
@@ -3369,7 +3432,7 @@ var init_channel = __esm({
3369
3432
  }
3370
3433
  truncate(text) {
3371
3434
  if (text.length <= this.maxLength) return text;
3372
- return text.slice(0, this.maxLength - 20) + "\n\\.\\.\\. *\\(truncated\\)*";
3435
+ return text.slice(0, this.maxLength - 20) + "\n... <i>(truncated)</i>";
3373
3436
  }
3374
3437
  };
3375
3438
  }
@@ -16578,21 +16641,34 @@ var PermissionManager = class {
16578
16641
  return this.identityMap;
16579
16642
  }
16580
16643
  };
16581
-
16582
- // src/core/logger.ts
16583
- var LEVELS = { debug: 0, info: 1, warn: 2, error: 3 };
16644
+ var CONSOLA_LEVELS = {
16645
+ debug: 4,
16646
+ info: 3,
16647
+ warn: 2,
16648
+ error: 1
16649
+ };
16584
16650
  function createLogger(level = "info") {
16585
- const minLevel = LEVELS[level];
16586
- function log(lvl, msg, meta = {}) {
16587
- if (LEVELS[lvl] < minLevel) return;
16588
- const entry = { ts: (/* @__PURE__ */ new Date()).toISOString(), level: lvl, msg, ...meta };
16589
- process.stderr.write(JSON.stringify(entry) + "\n");
16590
- }
16651
+ const consola = createConsola({
16652
+ level: CONSOLA_LEVELS[level],
16653
+ formatOptions: {
16654
+ date: true,
16655
+ colors: true
16656
+ }
16657
+ }).withTag("bot");
16591
16658
  return {
16592
- debug: (msg, meta) => log("debug", msg, meta ?? {}),
16593
- info: (msg, meta) => log("info", msg, meta ?? {}),
16594
- warn: (msg, meta) => log("warn", msg, meta ?? {}),
16595
- error: (msg, meta) => log("error", msg, meta ?? {})
16659
+ consola,
16660
+ debug(msg, meta) {
16661
+ meta ? consola.debug(msg, meta) : consola.debug(msg);
16662
+ },
16663
+ info(msg, meta) {
16664
+ meta ? consola.info(msg, meta) : consola.info(msg);
16665
+ },
16666
+ warn(msg, meta) {
16667
+ meta ? consola.warn(msg, meta) : consola.warn(msg);
16668
+ },
16669
+ error(msg, meta) {
16670
+ meta ? consola.error(msg, meta) : consola.error(msg);
16671
+ }
16596
16672
  };
16597
16673
  }
16598
16674
 
@@ -16699,7 +16775,21 @@ var AgentHandler = class extends BaseHandler {
16699
16775
  const text = result.text.length > this.maxOutput ? result.text.slice(0, this.maxOutput) + "\n...(truncated)" : result.text;
16700
16776
  return ok({ type: "text", text });
16701
16777
  } catch (e3) {
16702
- return err(new CMDOPError("Agent execution failed", e3 instanceof Error ? e3 : void 0));
16778
+ const errMsg = e3 instanceof Error ? e3.message : String(e3);
16779
+ this.logger.error("Agent execution failed", { error: errMsg });
16780
+ if (errMsg.includes("session_id") || errMsg.includes("No active session")) {
16781
+ return err(new CMDOPError("Machine is offline or CMDOP agent is not running.\nhttps://cmdop.com/downloads/"));
16782
+ }
16783
+ if (errMsg.includes("context canceled") || errMsg.includes("CANCELLED")) {
16784
+ return err(new CMDOPError("Request was interrupted. Please try again."));
16785
+ }
16786
+ if (errMsg.includes("DEADLINE_EXCEEDED") || errMsg.includes("timeout")) {
16787
+ return err(new CMDOPError("Request timed out. The task may be too complex \u2014 try a simpler prompt."));
16788
+ }
16789
+ if (errMsg.includes("UNAVAILABLE") || errMsg.includes("Connection refused")) {
16790
+ return err(new CMDOPError("Server unavailable. Check your connection and try again."));
16791
+ }
16792
+ return err(new CMDOPError(`Agent error: ${errMsg}`, e3 instanceof Error ? e3 : void 0));
16703
16793
  }
16704
16794
  }
16705
16795
  };
@@ -16820,6 +16910,63 @@ function loadSettings(env = process.env) {
16820
16910
  return result.data;
16821
16911
  }
16822
16912
 
16913
+ // src/channels/demo/channel.ts
16914
+ init_base_channel();
16915
+ var DemoChannel = class extends BaseChannel {
16916
+ messageHandlers = [];
16917
+ onOutput;
16918
+ constructor(permissions, dispatcher, logger, options2 = {}) {
16919
+ super("demo", "Demo", permissions, dispatcher, logger);
16920
+ this.onOutput = options2.onOutput ?? ((text) => process.stdout.write(text + "\n"));
16921
+ }
16922
+ async start() {
16923
+ this.logEvent("started");
16924
+ }
16925
+ async stop() {
16926
+ this.messageHandlers = [];
16927
+ this.logEvent("stopped");
16928
+ }
16929
+ send(_userId, message) {
16930
+ const text = formatOutgoing(message);
16931
+ this.onOutput(text, message);
16932
+ return Promise.resolve();
16933
+ }
16934
+ onMessage(handler) {
16935
+ this.messageHandlers.push(handler);
16936
+ }
16937
+ /**
16938
+ * Inject a message as if it came from a real platform user.
16939
+ * Primarily used in tests and CLI demos.
16940
+ */
16941
+ async injectMessage(input) {
16942
+ const msg = {
16943
+ id: `demo-${Date.now()}`,
16944
+ userId: input.userId ?? "demo-user",
16945
+ channelId: this.id,
16946
+ text: input.text,
16947
+ timestamp: /* @__PURE__ */ new Date(),
16948
+ attachments: []
16949
+ };
16950
+ for (const handler of this.messageHandlers) {
16951
+ await handler(msg);
16952
+ }
16953
+ await this.processMessage(msg);
16954
+ }
16955
+ };
16956
+ function formatOutgoing(message) {
16957
+ switch (message.type) {
16958
+ case "text":
16959
+ return message.text;
16960
+ case "code":
16961
+ return `\`\`\`${message.language ?? ""}
16962
+ ${message.code}
16963
+ \`\`\``;
16964
+ case "error":
16965
+ return `\u274C ${message.message}${message.hint ? `
16966
+ \u{1F4A1} ${message.hint}` : ""}`;
16967
+ }
16968
+ }
16969
+
16823
16970
  // src/hub.ts
16824
16971
  var IntegrationHub = class _IntegrationHub {
16825
16972
  constructor(_client, _logger, _settings, permissions, dispatcher, channelStartMode) {
@@ -16845,11 +16992,12 @@ var IntegrationHub = class _IntegrationHub {
16845
16992
  Object.assign(settings2, options2.settings ?? {});
16846
16993
  if (options2.defaultMachine) settings2.defaultMachine = options2.defaultMachine;
16847
16994
  const logger = options2.logger ?? createLogger(settings2.logLevel);
16848
- const client = options2.apiKey ? await CMDOPClient.remote(options2.apiKey) : await CMDOPClient.local();
16995
+ const client = options2.apiKey ? CMDOPClient.remote(options2.apiKey) : CMDOPClient.local();
16849
16996
  const store = options2.permissionStore ?? new InMemoryPermissionStore();
16850
16997
  const identityMap = new IdentityMap();
16851
16998
  const permissions = new PermissionManager(store, {
16852
16999
  adminUsers: [...options2.adminUsers ?? [], ...settings2.allowedUsers],
17000
+ defaultLevel: options2.defaultPermission,
16853
17001
  identityMap
16854
17002
  });
16855
17003
  const dispatcher = new MessageDispatcher(permissions, logger);
@@ -16896,6 +17044,15 @@ var IntegrationHub = class _IntegrationHub {
16896
17044
  const channel = new SlackChannel2(options2, this._permissions, this._dispatcher, this._logger);
16897
17045
  return this.registerChannel(channel);
16898
17046
  }
17047
+ /**
17048
+ * Create and register a DemoChannel for CLI testing.
17049
+ * No external dependencies — messages are injected via the returned channel's `injectMessage()`.
17050
+ */
17051
+ addDemo(options2) {
17052
+ const channel = new DemoChannel(this._permissions, this._dispatcher, this._logger, options2);
17053
+ this.registerChannel(channel);
17054
+ return channel;
17055
+ }
16899
17056
  registerHandler(handler) {
16900
17057
  this._dispatcher.register(handler);
16901
17058
  return this;
@@ -16904,6 +17061,17 @@ var IntegrationHub = class _IntegrationHub {
16904
17061
  async start() {
16905
17062
  if (this.started) return;
16906
17063
  this.started = true;
17064
+ if (this._settings.defaultMachine) {
17065
+ try {
17066
+ await this._client.setMachine(this._settings.defaultMachine);
17067
+ this._logger.info("Machine routing initialized", { machine: this._settings.defaultMachine });
17068
+ } catch (err2) {
17069
+ this._logger.error("Failed to initialize machine routing", {
17070
+ machine: this._settings.defaultMachine,
17071
+ err: err2 instanceof Error ? err2.message : String(err2)
17072
+ });
17073
+ }
17074
+ }
16907
17075
  if (this.channelStartMode === "strict") {
16908
17076
  await Promise.all([...this.channels.values()].map(async (ch) => {
16909
17077
  await ch.start();
@@ -17166,63 +17334,6 @@ var SlackStream = class _SlackStream {
17166
17334
  }
17167
17335
  };
17168
17336
 
17169
- // src/channels/demo/channel.ts
17170
- init_base_channel();
17171
- var DemoChannel = class extends BaseChannel {
17172
- messageHandlers = [];
17173
- onOutput;
17174
- constructor(permissions, dispatcher, logger, options2 = {}) {
17175
- super("demo", "Demo", permissions, dispatcher, logger);
17176
- this.onOutput = options2.onOutput ?? ((text) => process.stdout.write(text + "\n"));
17177
- }
17178
- async start() {
17179
- this.logEvent("started");
17180
- }
17181
- async stop() {
17182
- this.messageHandlers = [];
17183
- this.logEvent("stopped");
17184
- }
17185
- send(_userId, message) {
17186
- const text = formatOutgoing(message);
17187
- this.onOutput(text, message);
17188
- return Promise.resolve();
17189
- }
17190
- onMessage(handler) {
17191
- this.messageHandlers.push(handler);
17192
- }
17193
- /**
17194
- * Inject a message as if it came from a real platform user.
17195
- * Primarily used in tests and CLI demos.
17196
- */
17197
- async injectMessage(input) {
17198
- const msg = {
17199
- id: `demo-${Date.now()}`,
17200
- userId: input.userId ?? "demo-user",
17201
- channelId: this.id,
17202
- text: input.text,
17203
- timestamp: /* @__PURE__ */ new Date(),
17204
- attachments: []
17205
- };
17206
- for (const handler of this.messageHandlers) {
17207
- await handler(msg);
17208
- }
17209
- await this.processMessage(msg);
17210
- }
17211
- };
17212
- function formatOutgoing(message) {
17213
- switch (message.type) {
17214
- case "text":
17215
- return message.text;
17216
- case "code":
17217
- return `\`\`\`${message.language ?? ""}
17218
- ${message.code}
17219
- \`\`\``;
17220
- case "error":
17221
- return `\u274C ${message.message}${message.hint ? `
17222
- \u{1F4A1} ${message.hint}` : ""}`;
17223
- }
17224
- }
17225
-
17226
17337
  // src/channels/telegram/index.ts
17227
17338
  init_channel();
17228
17339
  init_formatter();