@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/README.md +6 -0
- package/dist/index.cjs +281 -170
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +100 -63
- package/dist/index.d.ts +100 -63
- package/dist/index.js +281 -170
- package/dist/index.js.map +1 -1
- package/package.json +5 -3
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
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
|
-
|
|
3284
|
-
|
|
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.
|
|
3333
|
-
await this.bot.api.sendMessage(chatId, text, { parse_mode: "
|
|
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.
|
|
3338
|
-
await this.bot.api.sendMessage(chatId, code, { parse_mode: "
|
|
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.
|
|
3343
|
-
|
|
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
|
|
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
|
-
|
|
16583
|
-
|
|
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
|
|
16586
|
-
|
|
16587
|
-
|
|
16588
|
-
|
|
16589
|
-
|
|
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
|
-
|
|
16593
|
-
|
|
16594
|
-
|
|
16595
|
-
|
|
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
|
-
|
|
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 ?
|
|
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();
|