heyio 4.2.7 → 4.3.1
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/daemon/cli.js +194 -32
- package/dist/daemon/index.js +1003 -791
- package/dist/web/assets/{index-fi5rwdUX.js → index-BBx9hgnQ.js} +2 -2
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
package/dist/daemon/cli.js
CHANGED
|
@@ -80,10 +80,10 @@ var init_constants = __esm({
|
|
|
80
80
|
"packages/shared/dist/constants.js"() {
|
|
81
81
|
"use strict";
|
|
82
82
|
APP_NAME = "io";
|
|
83
|
-
APP_VERSION = "4.
|
|
83
|
+
APP_VERSION = "4.3.1";
|
|
84
84
|
API_PORT = 7777;
|
|
85
85
|
API_HOST = "0.0.0.0";
|
|
86
|
-
DEFAULT_MODEL = "gpt-
|
|
86
|
+
DEFAULT_MODEL = "gpt-4.1-mini";
|
|
87
87
|
SESSION_RESET_THRESHOLD = 50;
|
|
88
88
|
SCHEDULER_INTERVAL_MS = 6e4;
|
|
89
89
|
QA_MAX_REVISIONS = 3;
|
|
@@ -2600,6 +2600,14 @@ async function markRead(id, db) {
|
|
|
2600
2600
|
}
|
|
2601
2601
|
return getInboxItem(id, database);
|
|
2602
2602
|
}
|
|
2603
|
+
async function deleteInboxItem(id, db) {
|
|
2604
|
+
const database = db ?? await getDatabase();
|
|
2605
|
+
const result = await database.execute({
|
|
2606
|
+
sql: "DELETE FROM inbox WHERE id = ?",
|
|
2607
|
+
args: [id]
|
|
2608
|
+
});
|
|
2609
|
+
return (result.rowsAffected ?? 0) > 0;
|
|
2610
|
+
}
|
|
2603
2611
|
function mapInboxItem(row) {
|
|
2604
2612
|
return {
|
|
2605
2613
|
id: asString(row.id),
|
|
@@ -36540,6 +36548,21 @@ var init_inbox2 = __esm({
|
|
|
36540
36548
|
});
|
|
36541
36549
|
}
|
|
36542
36550
|
});
|
|
36551
|
+
router3.delete("/api/inbox/:id", async (req, res) => {
|
|
36552
|
+
try {
|
|
36553
|
+
const deleted = await deleteInboxItem(req.params.id);
|
|
36554
|
+
if (!deleted) {
|
|
36555
|
+
res.status(404).json({ error: "Inbox item not found" });
|
|
36556
|
+
return;
|
|
36557
|
+
}
|
|
36558
|
+
res.status(204).end();
|
|
36559
|
+
} catch (error51) {
|
|
36560
|
+
res.status(500).json({
|
|
36561
|
+
error: "Failed to delete inbox item",
|
|
36562
|
+
details: error51 instanceof Error ? error51.message : "Unknown error"
|
|
36563
|
+
});
|
|
36564
|
+
}
|
|
36565
|
+
});
|
|
36543
36566
|
}
|
|
36544
36567
|
});
|
|
36545
36568
|
|
|
@@ -68221,8 +68244,12 @@ var init_types = __esm({
|
|
|
68221
68244
|
});
|
|
68222
68245
|
|
|
68223
68246
|
// packages/daemon/src/models/registry.ts
|
|
68247
|
+
function stripVendorPrefix(id) {
|
|
68248
|
+
const slashIndex = id.indexOf("/");
|
|
68249
|
+
return slashIndex >= 0 ? id.slice(slashIndex + 1) : id;
|
|
68250
|
+
}
|
|
68224
68251
|
function normalizeModelName(name) {
|
|
68225
|
-
return name.toLowerCase().replace(/^openai\s+/i, "").replace(/\s+/g, "-").replace(/[^a-z0-9.\-]/g, "").trim();
|
|
68252
|
+
return stripVendorPrefix(name).toLowerCase().replace(/^openai\s+/i, "").replace(/\s+/g, "-").replace(/[^a-z0-9.\-]/g, "").trim();
|
|
68226
68253
|
}
|
|
68227
68254
|
async function fetchCatalogIntoMap(modelMap, result, logger2) {
|
|
68228
68255
|
try {
|
|
@@ -68230,7 +68257,8 @@ async function fetchCatalogIntoMap(modelMap, result, logger2) {
|
|
|
68230
68257
|
result.catalogFetched = true;
|
|
68231
68258
|
for (const m of catalogModels) {
|
|
68232
68259
|
const key = normalizeModelName(m.id);
|
|
68233
|
-
|
|
68260
|
+
const id = stripVendorPrefix(m.id);
|
|
68261
|
+
modelMap.set(key, { id, displayName: m.displayName, available: true });
|
|
68234
68262
|
}
|
|
68235
68263
|
} catch (error51) {
|
|
68236
68264
|
const msg = error51 instanceof Error ? error51.message : String(error51);
|
|
@@ -68341,12 +68369,15 @@ async function refreshModelPricing(logger2) {
|
|
|
68341
68369
|
const db = await getDatabase();
|
|
68342
68370
|
const now = nowIso();
|
|
68343
68371
|
for (const model of modelMap.values()) {
|
|
68372
|
+
if (model.tokenInputMultiplier == null) {
|
|
68373
|
+
continue;
|
|
68374
|
+
}
|
|
68344
68375
|
const tier = computeTierFromMultiplier(model.premiumMultiplier ?? null);
|
|
68345
68376
|
await upsertModel(db, {
|
|
68346
68377
|
id: model.id,
|
|
68347
68378
|
displayName: model.displayName,
|
|
68348
68379
|
premiumMultiplier: model.premiumMultiplier ?? null,
|
|
68349
|
-
tokenInputMultiplier: model.tokenInputMultiplier
|
|
68380
|
+
tokenInputMultiplier: model.tokenInputMultiplier,
|
|
68350
68381
|
tokenOutputMultiplier: model.tokenOutputMultiplier ?? null,
|
|
68351
68382
|
cachedInputMultiplier: model.cachedInputMultiplier ?? null,
|
|
68352
68383
|
tier,
|
|
@@ -68357,6 +68388,18 @@ async function refreshModelPricing(logger2) {
|
|
|
68357
68388
|
}
|
|
68358
68389
|
return result;
|
|
68359
68390
|
}
|
|
68391
|
+
async function getModelsForTier(tier) {
|
|
68392
|
+
const db = await getDatabase();
|
|
68393
|
+
const result = await db.execute({
|
|
68394
|
+
sql: "SELECT * FROM model_pricing WHERE tier = ? AND available = 1 ORDER BY premium_multiplier ASC NULLS LAST",
|
|
68395
|
+
args: [tier]
|
|
68396
|
+
});
|
|
68397
|
+
return result.rows.map(rowToModelPricing);
|
|
68398
|
+
}
|
|
68399
|
+
async function getCheapestInTier(tier) {
|
|
68400
|
+
const models = await getModelsForTier(tier);
|
|
68401
|
+
return models[0] ?? null;
|
|
68402
|
+
}
|
|
68360
68403
|
async function getModelPricing(modelId) {
|
|
68361
68404
|
const db = await getDatabase();
|
|
68362
68405
|
const result = await db.execute({
|
|
@@ -68377,6 +68420,16 @@ async function getModelPricing(modelId) {
|
|
|
68377
68420
|
}
|
|
68378
68421
|
return null;
|
|
68379
68422
|
}
|
|
68423
|
+
async function getCheapestAvailableModel() {
|
|
68424
|
+
const tiers = ["trivial", "fast", "standard", "premium", "ultra"];
|
|
68425
|
+
for (const tier of tiers) {
|
|
68426
|
+
const model = await getCheapestInTier(tier);
|
|
68427
|
+
if (model) {
|
|
68428
|
+
return model;
|
|
68429
|
+
}
|
|
68430
|
+
}
|
|
68431
|
+
return null;
|
|
68432
|
+
}
|
|
68380
68433
|
function calculateTokenUnitCost(inputTokens, outputTokens, inputMultiplier, outputMultiplier) {
|
|
68381
68434
|
if (inputMultiplier === null || outputMultiplier === null) {
|
|
68382
68435
|
return 0;
|
|
@@ -68384,6 +68437,14 @@ function calculateTokenUnitCost(inputTokens, outputTokens, inputMultiplier, outp
|
|
|
68384
68437
|
const tokenUnits = inputTokens * inputMultiplier + outputTokens * outputMultiplier;
|
|
68385
68438
|
return tokenUnits * TOKEN_UNIT_PRICE;
|
|
68386
68439
|
}
|
|
68440
|
+
function getNextTierUp(tier) {
|
|
68441
|
+
const order = ["trivial", "fast", "standard", "premium", "ultra"];
|
|
68442
|
+
const idx = order.indexOf(tier);
|
|
68443
|
+
if (idx < 0 || idx >= order.length - 1) {
|
|
68444
|
+
return null;
|
|
68445
|
+
}
|
|
68446
|
+
return order[idx + 1];
|
|
68447
|
+
}
|
|
68387
68448
|
async function upsertModel(db, model) {
|
|
68388
68449
|
await db.execute({
|
|
68389
68450
|
sql: `INSERT INTO model_pricing (id, display_name, premium_multiplier, token_input_multiplier, token_output_multiplier, cached_input_multiplier, tier, available, updated_at)
|
|
@@ -69470,6 +69531,75 @@ var init_manager2 = __esm({
|
|
|
69470
69531
|
}
|
|
69471
69532
|
});
|
|
69472
69533
|
|
|
69534
|
+
// packages/daemon/src/squad/model-selector.ts
|
|
69535
|
+
import { CopilotClient as CopilotClient2, approveAll as approveAll2 } from "@github/copilot-sdk";
|
|
69536
|
+
async function selectModelForTask(taskDescription) {
|
|
69537
|
+
const classifierModel = await getCheapestAvailableModel();
|
|
69538
|
+
if (!classifierModel) {
|
|
69539
|
+
throw new Error("No models available in pricing database");
|
|
69540
|
+
}
|
|
69541
|
+
let tier;
|
|
69542
|
+
try {
|
|
69543
|
+
tier = await classifyTaskComplexity(taskDescription, classifierModel.id);
|
|
69544
|
+
} catch {
|
|
69545
|
+
return classifierModel.id;
|
|
69546
|
+
}
|
|
69547
|
+
const selectedModel = await getCheapestInTier(tier);
|
|
69548
|
+
if (selectedModel) {
|
|
69549
|
+
return selectedModel.id;
|
|
69550
|
+
}
|
|
69551
|
+
const nextTier = getNextTierUp(tier);
|
|
69552
|
+
if (nextTier) {
|
|
69553
|
+
const escalatedModel = await getCheapestInTier(nextTier);
|
|
69554
|
+
if (escalatedModel) {
|
|
69555
|
+
return escalatedModel.id;
|
|
69556
|
+
}
|
|
69557
|
+
}
|
|
69558
|
+
return classifierModel.id;
|
|
69559
|
+
}
|
|
69560
|
+
async function classifyTaskComplexity(taskDescription, modelId) {
|
|
69561
|
+
let client2 = null;
|
|
69562
|
+
try {
|
|
69563
|
+
client2 = new CopilotClient2();
|
|
69564
|
+
await client2.start();
|
|
69565
|
+
const session = await client2.createSession({
|
|
69566
|
+
model: modelId,
|
|
69567
|
+
onPermissionRequest: approveAll2,
|
|
69568
|
+
systemMessage: { content: CLASSIFICATION_PROMPT }
|
|
69569
|
+
});
|
|
69570
|
+
try {
|
|
69571
|
+
const response = await session.sendAndWait({ prompt: `Task: ${taskDescription}` }, 15e3);
|
|
69572
|
+
const raw = (response.text ?? "").trim().toLowerCase();
|
|
69573
|
+
const tier = VALID_TIERS.find((t) => raw.includes(t));
|
|
69574
|
+
return tier ?? "standard";
|
|
69575
|
+
} finally {
|
|
69576
|
+
await session.disconnect().catch(() => void 0);
|
|
69577
|
+
}
|
|
69578
|
+
} finally {
|
|
69579
|
+
if (client2) {
|
|
69580
|
+
await client2.stop().catch(() => void 0);
|
|
69581
|
+
}
|
|
69582
|
+
}
|
|
69583
|
+
}
|
|
69584
|
+
var VALID_TIERS, CLASSIFICATION_PROMPT;
|
|
69585
|
+
var init_model_selector = __esm({
|
|
69586
|
+
"packages/daemon/src/squad/model-selector.ts"() {
|
|
69587
|
+
"use strict";
|
|
69588
|
+
init_registry();
|
|
69589
|
+
VALID_TIERS = ["trivial", "fast", "standard", "premium", "ultra"];
|
|
69590
|
+
CLASSIFICATION_PROMPT = `You are a task complexity classifier. Given a task description, classify its complexity into exactly one tier.
|
|
69591
|
+
|
|
69592
|
+
Tiers (from simplest to most complex):
|
|
69593
|
+
- trivial: Typos, renames, comment changes, config tweaks, formatting
|
|
69594
|
+
- fast: Simple bug fixes, small features, documentation updates, single-file changes
|
|
69595
|
+
- standard: Feature implementation, multi-file changes, moderate refactoring
|
|
69596
|
+
- premium: Architecture changes, complex refactoring, security work, performance optimization
|
|
69597
|
+
- ultra: System-wide redesigns, critical infrastructure, cross-cutting concerns
|
|
69598
|
+
|
|
69599
|
+
Reply with ONLY the tier name (one word, lowercase). Nothing else.`;
|
|
69600
|
+
}
|
|
69601
|
+
});
|
|
69602
|
+
|
|
69473
69603
|
// packages/daemon/src/execution/history.ts
|
|
69474
69604
|
function summarizeTaskResult(taskResult) {
|
|
69475
69605
|
const condensed = taskResult.replace(/\s+/g, " ").trim();
|
|
@@ -69507,8 +69637,8 @@ import { mkdir as mkdir9, readFile as readFile7, readdir as readdir5, stat as st
|
|
|
69507
69637
|
import { dirname as dirname8, extname as extname3, isAbsolute, join as join11, relative as relative3, resolve as resolve4 } from "node:path";
|
|
69508
69638
|
import { promisify as promisify3 } from "node:util";
|
|
69509
69639
|
import {
|
|
69510
|
-
CopilotClient as
|
|
69511
|
-
approveAll as
|
|
69640
|
+
CopilotClient as CopilotClient3,
|
|
69641
|
+
approveAll as approveAll3,
|
|
69512
69642
|
defineTool
|
|
69513
69643
|
} from "@github/copilot-sdk";
|
|
69514
69644
|
function createEmptyUsage() {
|
|
@@ -69767,14 +69897,15 @@ async function executeAgentTask(member, task, worktreePath, options2) {
|
|
|
69767
69897
|
const mcpServerNote = options2?.mcpServers?.length ? `Available MCP server labels: ${options2.mcpServers.join(", ")}.` : "No additional MCP servers were configured for this run.";
|
|
69768
69898
|
let client2 = null;
|
|
69769
69899
|
try {
|
|
69770
|
-
client2 = new
|
|
69900
|
+
client2 = new CopilotClient3({ workingDirectory: worktreePath });
|
|
69771
69901
|
await client2.start();
|
|
69902
|
+
const model = member.model ?? await selectModelForTask(task.description);
|
|
69772
69903
|
const session = await client2.createSession({
|
|
69773
|
-
model
|
|
69904
|
+
model,
|
|
69774
69905
|
workingDirectory: worktreePath,
|
|
69775
69906
|
tools,
|
|
69776
69907
|
availableTools: ["custom:*"],
|
|
69777
|
-
onPermissionRequest:
|
|
69908
|
+
onPermissionRequest: approveAll3,
|
|
69778
69909
|
systemMessage: {
|
|
69779
69910
|
content: `${member.systemPrompt}
|
|
69780
69911
|
|
|
@@ -69826,8 +69957,8 @@ var execAsync3, MAX_FILE_SIZE, MAX_LIST_RESULTS, MAX_SEARCH_RESULTS;
|
|
|
69826
69957
|
var init_agent = __esm({
|
|
69827
69958
|
"packages/daemon/src/execution/agent.ts"() {
|
|
69828
69959
|
"use strict";
|
|
69829
|
-
init_dist();
|
|
69830
69960
|
init_registry();
|
|
69961
|
+
init_model_selector();
|
|
69831
69962
|
init_store2();
|
|
69832
69963
|
init_history();
|
|
69833
69964
|
execAsync3 = promisify3(exec3);
|
|
@@ -69925,7 +70056,7 @@ import { exec as exec4 } from "node:child_process";
|
|
|
69925
70056
|
import { access, readFile as readFile8 } from "node:fs/promises";
|
|
69926
70057
|
import { join as join12 } from "node:path";
|
|
69927
70058
|
import { promisify as promisify4 } from "node:util";
|
|
69928
|
-
import { CopilotClient as
|
|
70059
|
+
import { CopilotClient as CopilotClient4, approveAll as approveAll4 } from "@github/copilot-sdk";
|
|
69929
70060
|
async function fileExists(path) {
|
|
69930
70061
|
try {
|
|
69931
70062
|
await access(path);
|
|
@@ -70019,12 +70150,13 @@ Return strict JSON in this shape:
|
|
|
70019
70150
|
}`;
|
|
70020
70151
|
let client2 = null;
|
|
70021
70152
|
try {
|
|
70022
|
-
client2 = new
|
|
70153
|
+
client2 = new CopilotClient4({ workingDirectory: repoPath });
|
|
70023
70154
|
await client2.start();
|
|
70155
|
+
const model = await selectModelForTask(`Create implementation plan: ${objective.description}`);
|
|
70024
70156
|
const session = await client2.createSession({
|
|
70025
|
-
model
|
|
70157
|
+
model,
|
|
70026
70158
|
workingDirectory: repoPath,
|
|
70027
|
-
onPermissionRequest:
|
|
70159
|
+
onPermissionRequest: approveAll4,
|
|
70028
70160
|
systemMessage: {
|
|
70029
70161
|
content: `${TEAM_LEAD_PROMPT}
|
|
70030
70162
|
|
|
@@ -70059,7 +70191,7 @@ var execAsync4, README_CANDIDATES, MAX_REPO_CONTEXT_LENGTH;
|
|
|
70059
70191
|
var init_planning = __esm({
|
|
70060
70192
|
"packages/daemon/src/execution/planning.ts"() {
|
|
70061
70193
|
"use strict";
|
|
70062
|
-
|
|
70194
|
+
init_model_selector();
|
|
70063
70195
|
init_roles();
|
|
70064
70196
|
execAsync4 = promisify4(exec4);
|
|
70065
70197
|
README_CANDIDATES = ["README.md", "readme.md"];
|
|
@@ -70144,7 +70276,7 @@ var init_pr = __esm({
|
|
|
70144
70276
|
// packages/daemon/src/execution/qa.ts
|
|
70145
70277
|
import { exec as exec6 } from "node:child_process";
|
|
70146
70278
|
import { promisify as promisify6 } from "node:util";
|
|
70147
|
-
import { CopilotClient as
|
|
70279
|
+
import { CopilotClient as CopilotClient5, approveAll as approveAll5 } from "@github/copilot-sdk";
|
|
70148
70280
|
function extractJsonObject2(content) {
|
|
70149
70281
|
const fenced = content.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
70150
70282
|
if (fenced?.[1]) {
|
|
@@ -70182,12 +70314,13 @@ Return strict JSON:
|
|
|
70182
70314
|
}`;
|
|
70183
70315
|
let client2 = null;
|
|
70184
70316
|
try {
|
|
70185
|
-
client2 = new
|
|
70317
|
+
client2 = new CopilotClient5({ workingDirectory: worktreePath });
|
|
70186
70318
|
await client2.start();
|
|
70319
|
+
const model = qaMember.model ?? await selectModelForTask(`QA review: ${objective.description}`);
|
|
70187
70320
|
const session = await client2.createSession({
|
|
70188
|
-
model
|
|
70321
|
+
model,
|
|
70189
70322
|
workingDirectory: worktreePath,
|
|
70190
|
-
onPermissionRequest:
|
|
70323
|
+
onPermissionRequest: approveAll5,
|
|
70191
70324
|
systemMessage: {
|
|
70192
70325
|
content: QA_PROMPT
|
|
70193
70326
|
}
|
|
@@ -70261,6 +70394,7 @@ var init_qa = __esm({
|
|
|
70261
70394
|
"use strict";
|
|
70262
70395
|
init_dist();
|
|
70263
70396
|
init_event_bus();
|
|
70397
|
+
init_model_selector();
|
|
70264
70398
|
init_roles();
|
|
70265
70399
|
init_store2();
|
|
70266
70400
|
execAsync6 = promisify6(exec6);
|
|
@@ -70269,7 +70403,7 @@ var init_qa = __esm({
|
|
|
70269
70403
|
});
|
|
70270
70404
|
|
|
70271
70405
|
// packages/daemon/src/execution/review.ts
|
|
70272
|
-
import { CopilotClient as
|
|
70406
|
+
import { CopilotClient as CopilotClient6, approveAll as approveAll6 } from "@github/copilot-sdk";
|
|
70273
70407
|
function extractJsonObject3(content) {
|
|
70274
70408
|
const fenced = content.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
70275
70409
|
if (fenced?.[1]) {
|
|
@@ -70314,11 +70448,12 @@ Return strict JSON:
|
|
|
70314
70448
|
}`;
|
|
70315
70449
|
let client2 = null;
|
|
70316
70450
|
try {
|
|
70317
|
-
client2 = new
|
|
70451
|
+
client2 = new CopilotClient6();
|
|
70318
70452
|
await client2.start();
|
|
70453
|
+
const model = teamLead.model ?? await selectModelForTask(`Code review: ${objective.description}`);
|
|
70319
70454
|
const session = await client2.createSession({
|
|
70320
|
-
model
|
|
70321
|
-
onPermissionRequest:
|
|
70455
|
+
model,
|
|
70456
|
+
onPermissionRequest: approveAll6,
|
|
70322
70457
|
systemMessage: {
|
|
70323
70458
|
content: `${TEAM_LEAD_PROMPT}
|
|
70324
70459
|
|
|
@@ -70352,7 +70487,7 @@ You are conducting a final coordination review before QA.`
|
|
|
70352
70487
|
var init_review = __esm({
|
|
70353
70488
|
"packages/daemon/src/execution/review.ts"() {
|
|
70354
70489
|
"use strict";
|
|
70355
|
-
|
|
70490
|
+
init_model_selector();
|
|
70356
70491
|
init_roles();
|
|
70357
70492
|
}
|
|
70358
70493
|
});
|
|
@@ -71725,13 +71860,13 @@ var init_orchestrator = __esm({
|
|
|
71725
71860
|
});
|
|
71726
71861
|
this.activeModel = model;
|
|
71727
71862
|
} catch (error51) {
|
|
71728
|
-
if (model !==
|
|
71863
|
+
if (model !== this.config.defaultModel) {
|
|
71729
71864
|
this.activeSession = await createSession({
|
|
71730
|
-
model:
|
|
71865
|
+
model: this.config.defaultModel,
|
|
71731
71866
|
systemPrompt,
|
|
71732
71867
|
tools: createBoundOrchestratorTools(this.config)
|
|
71733
71868
|
});
|
|
71734
|
-
this.activeModel =
|
|
71869
|
+
this.activeModel = this.config.defaultModel;
|
|
71735
71870
|
} else {
|
|
71736
71871
|
throw error51;
|
|
71737
71872
|
}
|
|
@@ -85183,9 +85318,16 @@ var init_bot = __esm({
|
|
|
85183
85318
|
if (this.started) {
|
|
85184
85319
|
return;
|
|
85185
85320
|
}
|
|
85321
|
+
this.bot.catch((err) => {
|
|
85322
|
+
this.logger.error({ err: err.error }, "Telegram bot error: %s", err.message);
|
|
85323
|
+
});
|
|
85186
85324
|
this.registerHandlers();
|
|
85187
|
-
this.bot.start(
|
|
85188
|
-
|
|
85325
|
+
this.bot.start({
|
|
85326
|
+
onStart: () => {
|
|
85327
|
+
this.logger.info("Telegram bot connected and polling");
|
|
85328
|
+
}
|
|
85329
|
+
}).catch((error51) => {
|
|
85330
|
+
this.logger.error({ err: error51 }, "Telegram polling failed to start");
|
|
85189
85331
|
});
|
|
85190
85332
|
this.started = true;
|
|
85191
85333
|
}
|
|
@@ -85195,11 +85337,26 @@ var init_bot = __esm({
|
|
|
85195
85337
|
}
|
|
85196
85338
|
this.bot.stop();
|
|
85197
85339
|
this.started = false;
|
|
85340
|
+
this.logger.info("Telegram bot stopped");
|
|
85198
85341
|
}
|
|
85199
85342
|
async sendText(chatId, text) {
|
|
85200
85343
|
await this.bot.api.sendMessage(chatId, text);
|
|
85201
85344
|
}
|
|
85345
|
+
isAuthorized(userId) {
|
|
85346
|
+
if (!this.config.telegramUserId) {
|
|
85347
|
+
return false;
|
|
85348
|
+
}
|
|
85349
|
+
return String(userId) === this.config.telegramUserId;
|
|
85350
|
+
}
|
|
85202
85351
|
registerHandlers() {
|
|
85352
|
+
this.bot.use(async (ctx, next) => {
|
|
85353
|
+
const userId = ctx.from?.id;
|
|
85354
|
+
if (!userId || !this.isAuthorized(userId)) {
|
|
85355
|
+
this.logger.warn({ userId }, "Unauthorized Telegram message, ignoring");
|
|
85356
|
+
return;
|
|
85357
|
+
}
|
|
85358
|
+
await next();
|
|
85359
|
+
});
|
|
85203
85360
|
this.bot.command("start", async (ctx) => {
|
|
85204
85361
|
await ctx.reply(
|
|
85205
85362
|
"Hello from Io. Send me a message and I will route it through the daemon orchestrator."
|
|
@@ -85406,8 +85563,13 @@ async function main() {
|
|
|
85406
85563
|
setChatOrchestrator(orchestrator2);
|
|
85407
85564
|
const apiServer = createApiServer(config2);
|
|
85408
85565
|
const telegramBot = createTelegramBot(config2, orchestrator2);
|
|
85409
|
-
telegramBot
|
|
85410
|
-
|
|
85566
|
+
if (telegramBot) {
|
|
85567
|
+
telegramBot.start();
|
|
85568
|
+
createTelegramNotifier(telegramBot, config2, eventBus);
|
|
85569
|
+
logger2.info("Telegram bot initialized");
|
|
85570
|
+
} else {
|
|
85571
|
+
logger2.info("Telegram bot disabled (no token configured)");
|
|
85572
|
+
}
|
|
85411
85573
|
registerShutdownHandlers(logger2, async () => {
|
|
85412
85574
|
if (pricingRefreshTimer) {
|
|
85413
85575
|
clearInterval(pricingRefreshTimer);
|