heyio 4.2.5 → 4.3.0
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
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.0";
|
|
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;
|
|
@@ -2121,6 +2121,11 @@ var init_db = __esm({
|
|
|
2121
2121
|
agent_name = (SELECT sm.name FROM squad_members sm WHERE sm.id = token_usage.agent_id)
|
|
2122
2122
|
WHERE squad_id IS NOT NULL OR agent_id IS NOT NULL`
|
|
2123
2123
|
]
|
|
2124
|
+
},
|
|
2125
|
+
{
|
|
2126
|
+
version: 5,
|
|
2127
|
+
name: "add-squad-soft-delete",
|
|
2128
|
+
statements: ["ALTER TABLE squads ADD COLUMN deleted_at TEXT"]
|
|
2124
2129
|
}
|
|
2125
2130
|
];
|
|
2126
2131
|
client = null;
|
|
@@ -2144,7 +2149,8 @@ async function createSquad(data, db) {
|
|
|
2144
2149
|
status: data.status ?? "active",
|
|
2145
2150
|
config: data.config,
|
|
2146
2151
|
createdAt: timestamp,
|
|
2147
|
-
updatedAt: timestamp
|
|
2152
|
+
updatedAt: timestamp,
|
|
2153
|
+
deletedAt: null
|
|
2148
2154
|
};
|
|
2149
2155
|
await database.execute({
|
|
2150
2156
|
sql: `INSERT INTO squads (id, name, repo_url, repo_owner, repo_name, status, config, created_at, updated_at)
|
|
@@ -2166,7 +2172,7 @@ async function createSquad(data, db) {
|
|
|
2166
2172
|
async function getSquad(id, db) {
|
|
2167
2173
|
const database = db ?? await getDatabase();
|
|
2168
2174
|
const squadResult = await database.execute({
|
|
2169
|
-
sql: "SELECT * FROM squads WHERE id = ? LIMIT 1",
|
|
2175
|
+
sql: "SELECT * FROM squads WHERE id = ? AND deleted_at IS NULL LIMIT 1",
|
|
2170
2176
|
args: [id]
|
|
2171
2177
|
});
|
|
2172
2178
|
const row = squadResult.rows[0];
|
|
@@ -2182,7 +2188,7 @@ async function getSquad(id, db) {
|
|
|
2182
2188
|
async function getSquadByName(name, db) {
|
|
2183
2189
|
const database = db ?? await getDatabase();
|
|
2184
2190
|
const result = await database.execute({
|
|
2185
|
-
sql: "SELECT * FROM squads WHERE name = ? LIMIT 1",
|
|
2191
|
+
sql: "SELECT * FROM squads WHERE name = ? AND deleted_at IS NULL LIMIT 1",
|
|
2186
2192
|
args: [name]
|
|
2187
2193
|
});
|
|
2188
2194
|
const row = result.rows[0];
|
|
@@ -2195,7 +2201,9 @@ async function getSquadByName(name, db) {
|
|
|
2195
2201
|
}
|
|
2196
2202
|
async function listSquads(db) {
|
|
2197
2203
|
const database = db ?? await getDatabase();
|
|
2198
|
-
const result = await database.execute(
|
|
2204
|
+
const result = await database.execute(
|
|
2205
|
+
"SELECT * FROM squads WHERE deleted_at IS NULL ORDER BY created_at DESC, id DESC"
|
|
2206
|
+
);
|
|
2199
2207
|
return result.rows.map((row) => mapSquad(row));
|
|
2200
2208
|
}
|
|
2201
2209
|
async function updateSquad(id, data, db) {
|
|
@@ -2214,7 +2222,8 @@ async function updateSquad(id, data, db) {
|
|
|
2214
2222
|
status: data.status ?? existing.status,
|
|
2215
2223
|
config: data.config ?? existing.config,
|
|
2216
2224
|
createdAt: existing.createdAt,
|
|
2217
|
-
updatedAt
|
|
2225
|
+
updatedAt,
|
|
2226
|
+
deletedAt: existing.deletedAt
|
|
2218
2227
|
};
|
|
2219
2228
|
await database.execute({
|
|
2220
2229
|
sql: `UPDATE squads
|
|
@@ -2235,16 +2244,34 @@ async function updateSquad(id, data, db) {
|
|
|
2235
2244
|
}
|
|
2236
2245
|
async function deleteSquad(id, db) {
|
|
2237
2246
|
const database = db ?? await getDatabase();
|
|
2247
|
+
const now = nowIso();
|
|
2238
2248
|
const result = await database.execute({
|
|
2239
|
-
sql: "
|
|
2240
|
-
args: [id]
|
|
2249
|
+
sql: "UPDATE squads SET status = 'deleted', deleted_at = ?, updated_at = ? WHERE id = ? AND deleted_at IS NULL",
|
|
2250
|
+
args: [now, now, id]
|
|
2241
2251
|
});
|
|
2242
2252
|
return result.rowsAffected > 0;
|
|
2243
2253
|
}
|
|
2254
|
+
async function restoreSquad(id, db) {
|
|
2255
|
+
const database = db ?? await getDatabase();
|
|
2256
|
+
const now = nowIso();
|
|
2257
|
+
const result = await database.execute({
|
|
2258
|
+
sql: "UPDATE squads SET status = 'active', deleted_at = NULL, updated_at = ? WHERE id = ? AND deleted_at IS NOT NULL",
|
|
2259
|
+
args: [now, id]
|
|
2260
|
+
});
|
|
2261
|
+
if (result.rowsAffected === 0) return null;
|
|
2262
|
+
return getSquadRow(id, database);
|
|
2263
|
+
}
|
|
2264
|
+
async function listDeletedSquads(db) {
|
|
2265
|
+
const database = db ?? await getDatabase();
|
|
2266
|
+
const result = await database.execute(
|
|
2267
|
+
"SELECT * FROM squads WHERE deleted_at IS NOT NULL ORDER BY deleted_at DESC, id DESC"
|
|
2268
|
+
);
|
|
2269
|
+
return result.rows.map((row) => mapSquad(row));
|
|
2270
|
+
}
|
|
2244
2271
|
async function getSquadByRepo(repoOwner, repoName, db) {
|
|
2245
2272
|
const database = db ?? await getDatabase();
|
|
2246
2273
|
const result = await database.execute({
|
|
2247
|
-
sql: "SELECT * FROM squads WHERE repo_owner = ? AND repo_name = ? LIMIT 1",
|
|
2274
|
+
sql: "SELECT * FROM squads WHERE repo_owner = ? AND repo_name = ? AND deleted_at IS NULL LIMIT 1",
|
|
2248
2275
|
args: [repoOwner, repoName]
|
|
2249
2276
|
});
|
|
2250
2277
|
const row = result.rows[0];
|
|
@@ -2348,7 +2375,8 @@ function mapSquad(row) {
|
|
|
2348
2375
|
status: asString(row.status),
|
|
2349
2376
|
config: parseJson(asString(row.config)),
|
|
2350
2377
|
createdAt: asString(row.created_at),
|
|
2351
|
-
updatedAt: asString(row.updated_at)
|
|
2378
|
+
updatedAt: asString(row.updated_at),
|
|
2379
|
+
deletedAt: asNullableString(row.deleted_at)
|
|
2352
2380
|
};
|
|
2353
2381
|
}
|
|
2354
2382
|
function mapMember(row) {
|
|
@@ -52850,6 +52878,39 @@ var init_squads2 = __esm({
|
|
|
52850
52878
|
});
|
|
52851
52879
|
}
|
|
52852
52880
|
});
|
|
52881
|
+
router7.get("/api/squads/deleted", async (_req, res) => {
|
|
52882
|
+
try {
|
|
52883
|
+
const squads = await listDeletedSquads();
|
|
52884
|
+
res.status(200).json({ squads });
|
|
52885
|
+
} catch (error51) {
|
|
52886
|
+
res.status(500).json({
|
|
52887
|
+
error: "Failed to list deleted squads",
|
|
52888
|
+
details: error51 instanceof Error ? error51.message : "Unknown error"
|
|
52889
|
+
});
|
|
52890
|
+
}
|
|
52891
|
+
});
|
|
52892
|
+
router7.post("/api/squads/:id/restore", async (req, res) => {
|
|
52893
|
+
try {
|
|
52894
|
+
const restored = await restoreSquad(req.params.id);
|
|
52895
|
+
if (!restored) {
|
|
52896
|
+
res.status(404).json({ error: "Squad not found or not deleted" });
|
|
52897
|
+
return;
|
|
52898
|
+
}
|
|
52899
|
+
await logActivity({
|
|
52900
|
+
squadId: restored.id,
|
|
52901
|
+
event: EVENT_NAMES.SQUAD_UPDATED,
|
|
52902
|
+
description: `Restored squad ${restored.name}`,
|
|
52903
|
+
metadata: { repoUrl: restored.repoUrl }
|
|
52904
|
+
});
|
|
52905
|
+
eventBus.emit(EVENT_NAMES.SQUAD_UPDATED, { squad: restored });
|
|
52906
|
+
res.status(200).json({ squad: restored });
|
|
52907
|
+
} catch (error51) {
|
|
52908
|
+
res.status(500).json({
|
|
52909
|
+
error: "Failed to restore squad",
|
|
52910
|
+
details: error51 instanceof Error ? error51.message : "Unknown error"
|
|
52911
|
+
});
|
|
52912
|
+
}
|
|
52913
|
+
});
|
|
52853
52914
|
router7.get("/api/squads/:id/members", async (req, res) => {
|
|
52854
52915
|
try {
|
|
52855
52916
|
const squad = await resolveSquad(req.params.id);
|
|
@@ -68132,226 +68193,6 @@ var init_pricing_scraper = __esm({
|
|
|
68132
68193
|
}
|
|
68133
68194
|
});
|
|
68134
68195
|
|
|
68135
|
-
// packages/daemon/src/models/seed.ts
|
|
68136
|
-
var SEED_MODELS;
|
|
68137
|
-
var init_seed = __esm({
|
|
68138
|
-
"packages/daemon/src/models/seed.ts"() {
|
|
68139
|
-
"use strict";
|
|
68140
|
-
SEED_MODELS = [
|
|
68141
|
-
{
|
|
68142
|
-
id: "gpt-4o-mini",
|
|
68143
|
-
displayName: "OpenAI GPT-4o mini",
|
|
68144
|
-
premiumMultiplier: 0.33,
|
|
68145
|
-
tokenInputMultiplier: 0.015,
|
|
68146
|
-
tokenOutputMultiplier: 0.06,
|
|
68147
|
-
cachedInputMultiplier: 75e-4,
|
|
68148
|
-
tier: "trivial",
|
|
68149
|
-
available: true
|
|
68150
|
-
},
|
|
68151
|
-
{
|
|
68152
|
-
id: "gpt-4o",
|
|
68153
|
-
displayName: "OpenAI GPT-4o",
|
|
68154
|
-
premiumMultiplier: 0.33,
|
|
68155
|
-
tokenInputMultiplier: 0.25,
|
|
68156
|
-
tokenOutputMultiplier: 1,
|
|
68157
|
-
cachedInputMultiplier: 0.125,
|
|
68158
|
-
tier: "trivial",
|
|
68159
|
-
available: true
|
|
68160
|
-
},
|
|
68161
|
-
{
|
|
68162
|
-
id: "gpt-5-mini",
|
|
68163
|
-
displayName: "GPT-5 mini",
|
|
68164
|
-
premiumMultiplier: 0.33,
|
|
68165
|
-
tokenInputMultiplier: 0.025,
|
|
68166
|
-
tokenOutputMultiplier: 0.2,
|
|
68167
|
-
cachedInputMultiplier: 25e-4,
|
|
68168
|
-
tier: "trivial",
|
|
68169
|
-
available: true
|
|
68170
|
-
},
|
|
68171
|
-
{
|
|
68172
|
-
id: "gpt-5.3-codex",
|
|
68173
|
-
displayName: "GPT-5.3-Codex",
|
|
68174
|
-
premiumMultiplier: 6,
|
|
68175
|
-
tokenInputMultiplier: 0.175,
|
|
68176
|
-
tokenOutputMultiplier: 1.4,
|
|
68177
|
-
cachedInputMultiplier: 0.0175,
|
|
68178
|
-
tier: "premium",
|
|
68179
|
-
available: true
|
|
68180
|
-
},
|
|
68181
|
-
{
|
|
68182
|
-
id: "gpt-5.4",
|
|
68183
|
-
displayName: "GPT-5.4",
|
|
68184
|
-
premiumMultiplier: 6,
|
|
68185
|
-
tokenInputMultiplier: 0.25,
|
|
68186
|
-
tokenOutputMultiplier: 1.5,
|
|
68187
|
-
cachedInputMultiplier: 0.025,
|
|
68188
|
-
tier: "premium",
|
|
68189
|
-
available: true
|
|
68190
|
-
},
|
|
68191
|
-
{
|
|
68192
|
-
id: "gpt-5.4-mini",
|
|
68193
|
-
displayName: "GPT-5.4 mini",
|
|
68194
|
-
premiumMultiplier: 6,
|
|
68195
|
-
tokenInputMultiplier: 0.075,
|
|
68196
|
-
tokenOutputMultiplier: 0.45,
|
|
68197
|
-
cachedInputMultiplier: 75e-4,
|
|
68198
|
-
tier: "premium",
|
|
68199
|
-
available: true
|
|
68200
|
-
},
|
|
68201
|
-
{
|
|
68202
|
-
id: "gpt-5.5",
|
|
68203
|
-
displayName: "GPT-5.5",
|
|
68204
|
-
premiumMultiplier: 57,
|
|
68205
|
-
tokenInputMultiplier: 0.5,
|
|
68206
|
-
tokenOutputMultiplier: 3,
|
|
68207
|
-
cachedInputMultiplier: 0.05,
|
|
68208
|
-
tier: "ultra",
|
|
68209
|
-
available: true
|
|
68210
|
-
},
|
|
68211
|
-
{
|
|
68212
|
-
id: "claude-sonnet-4",
|
|
68213
|
-
displayName: "Claude Sonnet 4",
|
|
68214
|
-
premiumMultiplier: 6,
|
|
68215
|
-
tokenInputMultiplier: 0.3,
|
|
68216
|
-
tokenOutputMultiplier: 1.5,
|
|
68217
|
-
cachedInputMultiplier: 0.03,
|
|
68218
|
-
tier: "premium",
|
|
68219
|
-
available: true
|
|
68220
|
-
},
|
|
68221
|
-
{
|
|
68222
|
-
id: "claude-sonnet-4.5",
|
|
68223
|
-
displayName: "Claude Sonnet 4.5",
|
|
68224
|
-
premiumMultiplier: 6,
|
|
68225
|
-
tokenInputMultiplier: 0.3,
|
|
68226
|
-
tokenOutputMultiplier: 1.5,
|
|
68227
|
-
cachedInputMultiplier: 0.03,
|
|
68228
|
-
tier: "premium",
|
|
68229
|
-
available: true
|
|
68230
|
-
},
|
|
68231
|
-
{
|
|
68232
|
-
id: "claude-sonnet-4.6",
|
|
68233
|
-
displayName: "Claude Sonnet 4.6",
|
|
68234
|
-
premiumMultiplier: 9,
|
|
68235
|
-
tokenInputMultiplier: 0.3,
|
|
68236
|
-
tokenOutputMultiplier: 1.5,
|
|
68237
|
-
cachedInputMultiplier: 0.03,
|
|
68238
|
-
tier: "premium",
|
|
68239
|
-
available: true
|
|
68240
|
-
},
|
|
68241
|
-
{
|
|
68242
|
-
id: "claude-haiku-4.5",
|
|
68243
|
-
displayName: "Claude Haiku 4.5",
|
|
68244
|
-
premiumMultiplier: 0.33,
|
|
68245
|
-
tokenInputMultiplier: 0.1,
|
|
68246
|
-
tokenOutputMultiplier: 0.5,
|
|
68247
|
-
cachedInputMultiplier: 0.01,
|
|
68248
|
-
tier: "trivial",
|
|
68249
|
-
available: true
|
|
68250
|
-
},
|
|
68251
|
-
{
|
|
68252
|
-
id: "claude-opus-4.5",
|
|
68253
|
-
displayName: "Claude Opus 4.5",
|
|
68254
|
-
premiumMultiplier: 15,
|
|
68255
|
-
tokenInputMultiplier: 0.5,
|
|
68256
|
-
tokenOutputMultiplier: 2.5,
|
|
68257
|
-
cachedInputMultiplier: 0.05,
|
|
68258
|
-
tier: "premium",
|
|
68259
|
-
available: true
|
|
68260
|
-
},
|
|
68261
|
-
{
|
|
68262
|
-
id: "claude-opus-4.6",
|
|
68263
|
-
displayName: "Claude Opus 4.6",
|
|
68264
|
-
premiumMultiplier: 27,
|
|
68265
|
-
tokenInputMultiplier: 0.5,
|
|
68266
|
-
tokenOutputMultiplier: 2.5,
|
|
68267
|
-
cachedInputMultiplier: 0.05,
|
|
68268
|
-
tier: "ultra",
|
|
68269
|
-
available: true
|
|
68270
|
-
},
|
|
68271
|
-
{
|
|
68272
|
-
id: "claude-opus-4.7",
|
|
68273
|
-
displayName: "Claude Opus 4.7",
|
|
68274
|
-
premiumMultiplier: 27,
|
|
68275
|
-
tokenInputMultiplier: 0.5,
|
|
68276
|
-
tokenOutputMultiplier: 2.5,
|
|
68277
|
-
cachedInputMultiplier: 0.05,
|
|
68278
|
-
tier: "ultra",
|
|
68279
|
-
available: true
|
|
68280
|
-
},
|
|
68281
|
-
{
|
|
68282
|
-
id: "claude-opus-4.8",
|
|
68283
|
-
displayName: "Claude Opus 4.8",
|
|
68284
|
-
premiumMultiplier: 27,
|
|
68285
|
-
tokenInputMultiplier: 0.5,
|
|
68286
|
-
tokenOutputMultiplier: 2.5,
|
|
68287
|
-
cachedInputMultiplier: 0.05,
|
|
68288
|
-
tier: "ultra",
|
|
68289
|
-
available: true
|
|
68290
|
-
},
|
|
68291
|
-
{
|
|
68292
|
-
id: "gemini-2.5-pro",
|
|
68293
|
-
displayName: "Gemini 2.5 Pro",
|
|
68294
|
-
premiumMultiplier: 1,
|
|
68295
|
-
tokenInputMultiplier: 0.125,
|
|
68296
|
-
tokenOutputMultiplier: 1,
|
|
68297
|
-
cachedInputMultiplier: 0.0125,
|
|
68298
|
-
tier: "fast",
|
|
68299
|
-
available: true
|
|
68300
|
-
},
|
|
68301
|
-
{
|
|
68302
|
-
id: "gemini-3-flash",
|
|
68303
|
-
displayName: "Gemini 3 Flash",
|
|
68304
|
-
premiumMultiplier: 0.33,
|
|
68305
|
-
tokenInputMultiplier: 0.05,
|
|
68306
|
-
tokenOutputMultiplier: 0.3,
|
|
68307
|
-
cachedInputMultiplier: 5e-3,
|
|
68308
|
-
tier: "trivial",
|
|
68309
|
-
available: true
|
|
68310
|
-
},
|
|
68311
|
-
{
|
|
68312
|
-
id: "gemini-3.1-pro",
|
|
68313
|
-
displayName: "Gemini 3.1 Pro",
|
|
68314
|
-
premiumMultiplier: 6,
|
|
68315
|
-
tokenInputMultiplier: 0.2,
|
|
68316
|
-
tokenOutputMultiplier: 1.2,
|
|
68317
|
-
cachedInputMultiplier: 0.02,
|
|
68318
|
-
tier: "premium",
|
|
68319
|
-
available: true
|
|
68320
|
-
},
|
|
68321
|
-
{
|
|
68322
|
-
id: "gemini-3.5-flash",
|
|
68323
|
-
displayName: "Gemini 3.5 Flash",
|
|
68324
|
-
premiumMultiplier: 14,
|
|
68325
|
-
tokenInputMultiplier: 0.15,
|
|
68326
|
-
tokenOutputMultiplier: 0.9,
|
|
68327
|
-
cachedInputMultiplier: 0.015,
|
|
68328
|
-
tier: "premium",
|
|
68329
|
-
available: true
|
|
68330
|
-
},
|
|
68331
|
-
{
|
|
68332
|
-
id: "raptor-mini",
|
|
68333
|
-
displayName: "Raptor mini",
|
|
68334
|
-
premiumMultiplier: 0.33,
|
|
68335
|
-
tokenInputMultiplier: 0.025,
|
|
68336
|
-
tokenOutputMultiplier: 0.2,
|
|
68337
|
-
cachedInputMultiplier: 25e-4,
|
|
68338
|
-
tier: "trivial",
|
|
68339
|
-
available: true
|
|
68340
|
-
},
|
|
68341
|
-
{
|
|
68342
|
-
id: "mai-code-1-flash",
|
|
68343
|
-
displayName: "MAI-Code-1-Flash",
|
|
68344
|
-
premiumMultiplier: 0.33,
|
|
68345
|
-
tokenInputMultiplier: 0.075,
|
|
68346
|
-
tokenOutputMultiplier: 0.45,
|
|
68347
|
-
cachedInputMultiplier: 75e-4,
|
|
68348
|
-
tier: "trivial",
|
|
68349
|
-
available: true
|
|
68350
|
-
}
|
|
68351
|
-
];
|
|
68352
|
-
}
|
|
68353
|
-
});
|
|
68354
|
-
|
|
68355
68196
|
// packages/daemon/src/models/types.ts
|
|
68356
68197
|
function computeTierFromMultiplier(premiumMultiplier) {
|
|
68357
68198
|
if (premiumMultiplier === null) {
|
|
@@ -68494,20 +68335,21 @@ async function refreshModelPricing(logger2) {
|
|
|
68494
68335
|
await scrapeCopilotPricingIntoMap(modelMap, result, logger2);
|
|
68495
68336
|
await scrapePremiumPricingIntoMap(modelMap, result, logger2);
|
|
68496
68337
|
if (!result.catalogFetched && !result.tokenPricingScraped && !result.premiumPricingScraped && !result.copilotPricingScraped) {
|
|
68497
|
-
logger2?.warn("All pricing sources failed,
|
|
68498
|
-
await seedFromFallback();
|
|
68499
|
-
result.modelsUpdated = SEED_MODELS.length;
|
|
68338
|
+
logger2?.warn("All pricing sources failed, no models available");
|
|
68500
68339
|
return result;
|
|
68501
68340
|
}
|
|
68502
68341
|
const db = await getDatabase();
|
|
68503
68342
|
const now = nowIso();
|
|
68504
68343
|
for (const model of modelMap.values()) {
|
|
68344
|
+
if (model.tokenInputMultiplier == null) {
|
|
68345
|
+
continue;
|
|
68346
|
+
}
|
|
68505
68347
|
const tier = computeTierFromMultiplier(model.premiumMultiplier ?? null);
|
|
68506
68348
|
await upsertModel(db, {
|
|
68507
68349
|
id: model.id,
|
|
68508
68350
|
displayName: model.displayName,
|
|
68509
68351
|
premiumMultiplier: model.premiumMultiplier ?? null,
|
|
68510
|
-
tokenInputMultiplier: model.tokenInputMultiplier
|
|
68352
|
+
tokenInputMultiplier: model.tokenInputMultiplier,
|
|
68511
68353
|
tokenOutputMultiplier: model.tokenOutputMultiplier ?? null,
|
|
68512
68354
|
cachedInputMultiplier: model.cachedInputMultiplier ?? null,
|
|
68513
68355
|
tier,
|
|
@@ -68518,12 +68360,17 @@ async function refreshModelPricing(logger2) {
|
|
|
68518
68360
|
}
|
|
68519
68361
|
return result;
|
|
68520
68362
|
}
|
|
68521
|
-
async function
|
|
68363
|
+
async function getModelsForTier(tier) {
|
|
68522
68364
|
const db = await getDatabase();
|
|
68523
|
-
const
|
|
68524
|
-
|
|
68525
|
-
|
|
68526
|
-
}
|
|
68365
|
+
const result = await db.execute({
|
|
68366
|
+
sql: "SELECT * FROM model_pricing WHERE tier = ? AND available = 1 ORDER BY premium_multiplier ASC NULLS LAST",
|
|
68367
|
+
args: [tier]
|
|
68368
|
+
});
|
|
68369
|
+
return result.rows.map(rowToModelPricing);
|
|
68370
|
+
}
|
|
68371
|
+
async function getCheapestInTier(tier) {
|
|
68372
|
+
const models = await getModelsForTier(tier);
|
|
68373
|
+
return models[0] ?? null;
|
|
68527
68374
|
}
|
|
68528
68375
|
async function getModelPricing(modelId) {
|
|
68529
68376
|
const db = await getDatabase();
|
|
@@ -68545,6 +68392,16 @@ async function getModelPricing(modelId) {
|
|
|
68545
68392
|
}
|
|
68546
68393
|
return null;
|
|
68547
68394
|
}
|
|
68395
|
+
async function getCheapestAvailableModel() {
|
|
68396
|
+
const tiers = ["trivial", "fast", "standard", "premium", "ultra"];
|
|
68397
|
+
for (const tier of tiers) {
|
|
68398
|
+
const model = await getCheapestInTier(tier);
|
|
68399
|
+
if (model) {
|
|
68400
|
+
return model;
|
|
68401
|
+
}
|
|
68402
|
+
}
|
|
68403
|
+
return null;
|
|
68404
|
+
}
|
|
68548
68405
|
function calculateTokenUnitCost(inputTokens, outputTokens, inputMultiplier, outputMultiplier) {
|
|
68549
68406
|
if (inputMultiplier === null || outputMultiplier === null) {
|
|
68550
68407
|
return 0;
|
|
@@ -68552,6 +68409,14 @@ function calculateTokenUnitCost(inputTokens, outputTokens, inputMultiplier, outp
|
|
|
68552
68409
|
const tokenUnits = inputTokens * inputMultiplier + outputTokens * outputMultiplier;
|
|
68553
68410
|
return tokenUnits * TOKEN_UNIT_PRICE;
|
|
68554
68411
|
}
|
|
68412
|
+
function getNextTierUp(tier) {
|
|
68413
|
+
const order = ["trivial", "fast", "standard", "premium", "ultra"];
|
|
68414
|
+
const idx = order.indexOf(tier);
|
|
68415
|
+
if (idx < 0 || idx >= order.length - 1) {
|
|
68416
|
+
return null;
|
|
68417
|
+
}
|
|
68418
|
+
return order[idx + 1];
|
|
68419
|
+
}
|
|
68555
68420
|
async function upsertModel(db, model) {
|
|
68556
68421
|
await db.execute({
|
|
68557
68422
|
sql: `INSERT INTO model_pricing (id, display_name, premium_multiplier, token_input_multiplier, token_output_multiplier, cached_input_multiplier, tier, available, updated_at)
|
|
@@ -68605,7 +68470,6 @@ var init_registry = __esm({
|
|
|
68605
68470
|
init_db();
|
|
68606
68471
|
init_catalog();
|
|
68607
68472
|
init_pricing_scraper();
|
|
68608
|
-
init_seed();
|
|
68609
68473
|
init_types();
|
|
68610
68474
|
}
|
|
68611
68475
|
});
|
|
@@ -68616,7 +68480,6 @@ var init_models = __esm({
|
|
|
68616
68480
|
"use strict";
|
|
68617
68481
|
init_catalog();
|
|
68618
68482
|
init_registry();
|
|
68619
|
-
init_seed();
|
|
68620
68483
|
init_types();
|
|
68621
68484
|
}
|
|
68622
68485
|
});
|
|
@@ -69640,6 +69503,75 @@ var init_manager2 = __esm({
|
|
|
69640
69503
|
}
|
|
69641
69504
|
});
|
|
69642
69505
|
|
|
69506
|
+
// packages/daemon/src/squad/model-selector.ts
|
|
69507
|
+
import { CopilotClient as CopilotClient2, approveAll as approveAll2 } from "@github/copilot-sdk";
|
|
69508
|
+
async function selectModelForTask(taskDescription) {
|
|
69509
|
+
const classifierModel = await getCheapestAvailableModel();
|
|
69510
|
+
if (!classifierModel) {
|
|
69511
|
+
throw new Error("No models available in pricing database");
|
|
69512
|
+
}
|
|
69513
|
+
let tier;
|
|
69514
|
+
try {
|
|
69515
|
+
tier = await classifyTaskComplexity(taskDescription, classifierModel.id);
|
|
69516
|
+
} catch {
|
|
69517
|
+
return classifierModel.id;
|
|
69518
|
+
}
|
|
69519
|
+
const selectedModel = await getCheapestInTier(tier);
|
|
69520
|
+
if (selectedModel) {
|
|
69521
|
+
return selectedModel.id;
|
|
69522
|
+
}
|
|
69523
|
+
const nextTier = getNextTierUp(tier);
|
|
69524
|
+
if (nextTier) {
|
|
69525
|
+
const escalatedModel = await getCheapestInTier(nextTier);
|
|
69526
|
+
if (escalatedModel) {
|
|
69527
|
+
return escalatedModel.id;
|
|
69528
|
+
}
|
|
69529
|
+
}
|
|
69530
|
+
return classifierModel.id;
|
|
69531
|
+
}
|
|
69532
|
+
async function classifyTaskComplexity(taskDescription, modelId) {
|
|
69533
|
+
let client2 = null;
|
|
69534
|
+
try {
|
|
69535
|
+
client2 = new CopilotClient2();
|
|
69536
|
+
await client2.start();
|
|
69537
|
+
const session = await client2.createSession({
|
|
69538
|
+
model: modelId,
|
|
69539
|
+
onPermissionRequest: approveAll2,
|
|
69540
|
+
systemMessage: { content: CLASSIFICATION_PROMPT }
|
|
69541
|
+
});
|
|
69542
|
+
try {
|
|
69543
|
+
const response = await session.sendAndWait({ prompt: `Task: ${taskDescription}` }, 15e3);
|
|
69544
|
+
const raw = (response.text ?? "").trim().toLowerCase();
|
|
69545
|
+
const tier = VALID_TIERS.find((t) => raw.includes(t));
|
|
69546
|
+
return tier ?? "standard";
|
|
69547
|
+
} finally {
|
|
69548
|
+
await session.disconnect().catch(() => void 0);
|
|
69549
|
+
}
|
|
69550
|
+
} finally {
|
|
69551
|
+
if (client2) {
|
|
69552
|
+
await client2.stop().catch(() => void 0);
|
|
69553
|
+
}
|
|
69554
|
+
}
|
|
69555
|
+
}
|
|
69556
|
+
var VALID_TIERS, CLASSIFICATION_PROMPT;
|
|
69557
|
+
var init_model_selector = __esm({
|
|
69558
|
+
"packages/daemon/src/squad/model-selector.ts"() {
|
|
69559
|
+
"use strict";
|
|
69560
|
+
init_registry();
|
|
69561
|
+
VALID_TIERS = ["trivial", "fast", "standard", "premium", "ultra"];
|
|
69562
|
+
CLASSIFICATION_PROMPT = `You are a task complexity classifier. Given a task description, classify its complexity into exactly one tier.
|
|
69563
|
+
|
|
69564
|
+
Tiers (from simplest to most complex):
|
|
69565
|
+
- trivial: Typos, renames, comment changes, config tweaks, formatting
|
|
69566
|
+
- fast: Simple bug fixes, small features, documentation updates, single-file changes
|
|
69567
|
+
- standard: Feature implementation, multi-file changes, moderate refactoring
|
|
69568
|
+
- premium: Architecture changes, complex refactoring, security work, performance optimization
|
|
69569
|
+
- ultra: System-wide redesigns, critical infrastructure, cross-cutting concerns
|
|
69570
|
+
|
|
69571
|
+
Reply with ONLY the tier name (one word, lowercase). Nothing else.`;
|
|
69572
|
+
}
|
|
69573
|
+
});
|
|
69574
|
+
|
|
69643
69575
|
// packages/daemon/src/execution/history.ts
|
|
69644
69576
|
function summarizeTaskResult(taskResult) {
|
|
69645
69577
|
const condensed = taskResult.replace(/\s+/g, " ").trim();
|
|
@@ -69677,8 +69609,8 @@ import { mkdir as mkdir9, readFile as readFile7, readdir as readdir5, stat as st
|
|
|
69677
69609
|
import { dirname as dirname8, extname as extname3, isAbsolute, join as join11, relative as relative3, resolve as resolve4 } from "node:path";
|
|
69678
69610
|
import { promisify as promisify3 } from "node:util";
|
|
69679
69611
|
import {
|
|
69680
|
-
CopilotClient as
|
|
69681
|
-
approveAll as
|
|
69612
|
+
CopilotClient as CopilotClient3,
|
|
69613
|
+
approveAll as approveAll3,
|
|
69682
69614
|
defineTool
|
|
69683
69615
|
} from "@github/copilot-sdk";
|
|
69684
69616
|
function createEmptyUsage() {
|
|
@@ -69937,14 +69869,15 @@ async function executeAgentTask(member, task, worktreePath, options2) {
|
|
|
69937
69869
|
const mcpServerNote = options2?.mcpServers?.length ? `Available MCP server labels: ${options2.mcpServers.join(", ")}.` : "No additional MCP servers were configured for this run.";
|
|
69938
69870
|
let client2 = null;
|
|
69939
69871
|
try {
|
|
69940
|
-
client2 = new
|
|
69872
|
+
client2 = new CopilotClient3({ workingDirectory: worktreePath });
|
|
69941
69873
|
await client2.start();
|
|
69874
|
+
const model = member.model ?? await selectModelForTask(task.description);
|
|
69942
69875
|
const session = await client2.createSession({
|
|
69943
|
-
model
|
|
69876
|
+
model,
|
|
69944
69877
|
workingDirectory: worktreePath,
|
|
69945
69878
|
tools,
|
|
69946
69879
|
availableTools: ["custom:*"],
|
|
69947
|
-
onPermissionRequest:
|
|
69880
|
+
onPermissionRequest: approveAll3,
|
|
69948
69881
|
systemMessage: {
|
|
69949
69882
|
content: `${member.systemPrompt}
|
|
69950
69883
|
|
|
@@ -69996,8 +69929,8 @@ var execAsync3, MAX_FILE_SIZE, MAX_LIST_RESULTS, MAX_SEARCH_RESULTS;
|
|
|
69996
69929
|
var init_agent = __esm({
|
|
69997
69930
|
"packages/daemon/src/execution/agent.ts"() {
|
|
69998
69931
|
"use strict";
|
|
69999
|
-
init_dist();
|
|
70000
69932
|
init_registry();
|
|
69933
|
+
init_model_selector();
|
|
70001
69934
|
init_store2();
|
|
70002
69935
|
init_history();
|
|
70003
69936
|
execAsync3 = promisify3(exec3);
|
|
@@ -70095,7 +70028,7 @@ import { exec as exec4 } from "node:child_process";
|
|
|
70095
70028
|
import { access, readFile as readFile8 } from "node:fs/promises";
|
|
70096
70029
|
import { join as join12 } from "node:path";
|
|
70097
70030
|
import { promisify as promisify4 } from "node:util";
|
|
70098
|
-
import { CopilotClient as
|
|
70031
|
+
import { CopilotClient as CopilotClient4, approveAll as approveAll4 } from "@github/copilot-sdk";
|
|
70099
70032
|
async function fileExists(path) {
|
|
70100
70033
|
try {
|
|
70101
70034
|
await access(path);
|
|
@@ -70189,12 +70122,13 @@ Return strict JSON in this shape:
|
|
|
70189
70122
|
}`;
|
|
70190
70123
|
let client2 = null;
|
|
70191
70124
|
try {
|
|
70192
|
-
client2 = new
|
|
70125
|
+
client2 = new CopilotClient4({ workingDirectory: repoPath });
|
|
70193
70126
|
await client2.start();
|
|
70127
|
+
const model = await selectModelForTask(`Create implementation plan: ${objective.description}`);
|
|
70194
70128
|
const session = await client2.createSession({
|
|
70195
|
-
model
|
|
70129
|
+
model,
|
|
70196
70130
|
workingDirectory: repoPath,
|
|
70197
|
-
onPermissionRequest:
|
|
70131
|
+
onPermissionRequest: approveAll4,
|
|
70198
70132
|
systemMessage: {
|
|
70199
70133
|
content: `${TEAM_LEAD_PROMPT}
|
|
70200
70134
|
|
|
@@ -70229,7 +70163,7 @@ var execAsync4, README_CANDIDATES, MAX_REPO_CONTEXT_LENGTH;
|
|
|
70229
70163
|
var init_planning = __esm({
|
|
70230
70164
|
"packages/daemon/src/execution/planning.ts"() {
|
|
70231
70165
|
"use strict";
|
|
70232
|
-
|
|
70166
|
+
init_model_selector();
|
|
70233
70167
|
init_roles();
|
|
70234
70168
|
execAsync4 = promisify4(exec4);
|
|
70235
70169
|
README_CANDIDATES = ["README.md", "readme.md"];
|
|
@@ -70314,7 +70248,7 @@ var init_pr = __esm({
|
|
|
70314
70248
|
// packages/daemon/src/execution/qa.ts
|
|
70315
70249
|
import { exec as exec6 } from "node:child_process";
|
|
70316
70250
|
import { promisify as promisify6 } from "node:util";
|
|
70317
|
-
import { CopilotClient as
|
|
70251
|
+
import { CopilotClient as CopilotClient5, approveAll as approveAll5 } from "@github/copilot-sdk";
|
|
70318
70252
|
function extractJsonObject2(content) {
|
|
70319
70253
|
const fenced = content.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
70320
70254
|
if (fenced?.[1]) {
|
|
@@ -70352,12 +70286,13 @@ Return strict JSON:
|
|
|
70352
70286
|
}`;
|
|
70353
70287
|
let client2 = null;
|
|
70354
70288
|
try {
|
|
70355
|
-
client2 = new
|
|
70289
|
+
client2 = new CopilotClient5({ workingDirectory: worktreePath });
|
|
70356
70290
|
await client2.start();
|
|
70291
|
+
const model = qaMember.model ?? await selectModelForTask(`QA review: ${objective.description}`);
|
|
70357
70292
|
const session = await client2.createSession({
|
|
70358
|
-
model
|
|
70293
|
+
model,
|
|
70359
70294
|
workingDirectory: worktreePath,
|
|
70360
|
-
onPermissionRequest:
|
|
70295
|
+
onPermissionRequest: approveAll5,
|
|
70361
70296
|
systemMessage: {
|
|
70362
70297
|
content: QA_PROMPT
|
|
70363
70298
|
}
|
|
@@ -70431,6 +70366,7 @@ var init_qa = __esm({
|
|
|
70431
70366
|
"use strict";
|
|
70432
70367
|
init_dist();
|
|
70433
70368
|
init_event_bus();
|
|
70369
|
+
init_model_selector();
|
|
70434
70370
|
init_roles();
|
|
70435
70371
|
init_store2();
|
|
70436
70372
|
execAsync6 = promisify6(exec6);
|
|
@@ -70439,7 +70375,7 @@ var init_qa = __esm({
|
|
|
70439
70375
|
});
|
|
70440
70376
|
|
|
70441
70377
|
// packages/daemon/src/execution/review.ts
|
|
70442
|
-
import { CopilotClient as
|
|
70378
|
+
import { CopilotClient as CopilotClient6, approveAll as approveAll6 } from "@github/copilot-sdk";
|
|
70443
70379
|
function extractJsonObject3(content) {
|
|
70444
70380
|
const fenced = content.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
70445
70381
|
if (fenced?.[1]) {
|
|
@@ -70484,11 +70420,12 @@ Return strict JSON:
|
|
|
70484
70420
|
}`;
|
|
70485
70421
|
let client2 = null;
|
|
70486
70422
|
try {
|
|
70487
|
-
client2 = new
|
|
70423
|
+
client2 = new CopilotClient6();
|
|
70488
70424
|
await client2.start();
|
|
70425
|
+
const model = teamLead.model ?? await selectModelForTask(`Code review: ${objective.description}`);
|
|
70489
70426
|
const session = await client2.createSession({
|
|
70490
|
-
model
|
|
70491
|
-
onPermissionRequest:
|
|
70427
|
+
model,
|
|
70428
|
+
onPermissionRequest: approveAll6,
|
|
70492
70429
|
systemMessage: {
|
|
70493
70430
|
content: `${TEAM_LEAD_PROMPT}
|
|
70494
70431
|
|
|
@@ -70522,7 +70459,7 @@ You are conducting a final coordination review before QA.`
|
|
|
70522
70459
|
var init_review = __esm({
|
|
70523
70460
|
"packages/daemon/src/execution/review.ts"() {
|
|
70524
70461
|
"use strict";
|
|
70525
|
-
|
|
70462
|
+
init_model_selector();
|
|
70526
70463
|
init_roles();
|
|
70527
70464
|
}
|
|
70528
70465
|
});
|
|
@@ -71056,7 +70993,7 @@ async function processQueue2(squadId) {
|
|
|
71056
70993
|
const next = await getNextQueued(squadId);
|
|
71057
70994
|
if (next) {
|
|
71058
70995
|
const freshSquad = await getSquad(squadId);
|
|
71059
|
-
if (freshSquad) {
|
|
70996
|
+
if (freshSquad && next.objectiveId) {
|
|
71060
70997
|
void startAndExecuteInstance(next.id, freshSquad, next.objectiveId);
|
|
71061
70998
|
}
|
|
71062
70999
|
}
|
|
@@ -71191,13 +71128,28 @@ async function handleFireSquad(rawArgs) {
|
|
|
71191
71128
|
if (activeObjectives.length > 0) {
|
|
71192
71129
|
const updated = await updateSquad(squadId, { status: "inactive" });
|
|
71193
71130
|
return {
|
|
71194
|
-
message: `Squad ${squadId} was deactivated because it still has active objectives.`,
|
|
71131
|
+
message: `Squad ${squadId} was deactivated because it still has active objectives. Use fire_squad again after objectives complete to delete it.`,
|
|
71195
71132
|
squad: updated,
|
|
71196
71133
|
activeObjectives
|
|
71197
71134
|
};
|
|
71198
71135
|
}
|
|
71199
71136
|
await deleteSquad(squadId);
|
|
71200
|
-
return {
|
|
71137
|
+
return {
|
|
71138
|
+
message: `Squad "${squad.name}" has been deleted. It can be restored with restore_squad if needed.`,
|
|
71139
|
+
squadId
|
|
71140
|
+
};
|
|
71141
|
+
}
|
|
71142
|
+
async function handleRestoreSquad(rawArgs) {
|
|
71143
|
+
const { squadId } = squadIdSchema.parse(rawArgs);
|
|
71144
|
+
const restored = await restoreSquad(squadId);
|
|
71145
|
+
if (!restored) {
|
|
71146
|
+
throw new Error(`Squad ${squadId} was not found or is not deleted.`);
|
|
71147
|
+
}
|
|
71148
|
+
eventBus.emit(EVENT_NAMES.SQUAD_UPDATED, { squad: restored });
|
|
71149
|
+
return {
|
|
71150
|
+
message: `Squad "${restored.name}" has been restored.`,
|
|
71151
|
+
squad: restored
|
|
71152
|
+
};
|
|
71201
71153
|
}
|
|
71202
71154
|
async function handleDelegateToSquad(rawArgs) {
|
|
71203
71155
|
const { squadId, objective } = delegateToSquadSchema.parse(rawArgs);
|
|
@@ -71262,11 +71214,26 @@ function createSquadToolExecutor(_config) {
|
|
|
71262
71214
|
return handleAnalyzeRepo(rawArgs);
|
|
71263
71215
|
case "fire_squad":
|
|
71264
71216
|
return handleFireSquad(rawArgs);
|
|
71217
|
+
case "restore_squad":
|
|
71218
|
+
return handleRestoreSquad(rawArgs);
|
|
71219
|
+
case "list_deleted_squads": {
|
|
71220
|
+
const deletedSquads = await listDeletedSquads();
|
|
71221
|
+
if (deletedSquads.length === 0) {
|
|
71222
|
+
return { message: "No deleted squads.", squads: [] };
|
|
71223
|
+
}
|
|
71224
|
+
const list = deletedSquads.map((s) => `${s.id}: ${s.name} (${s.repoOwner}/${s.repoName}) [deleted ${s.deletedAt}]`).join("\n");
|
|
71225
|
+
return { message: list, squads: deletedSquads };
|
|
71226
|
+
}
|
|
71265
71227
|
case "list_squads": {
|
|
71266
71228
|
const squads = await listSquads();
|
|
71229
|
+
const deletedCount = (await listDeletedSquads()).length;
|
|
71230
|
+
const suffix = deletedCount > 0 ? `
|
|
71231
|
+
|
|
71232
|
+
${deletedCount} deleted squad(s) available for restore (use list_deleted_squads to view).` : "";
|
|
71267
71233
|
return {
|
|
71268
|
-
message: formatSquadList(squads),
|
|
71269
|
-
squads
|
|
71234
|
+
message: formatSquadList(squads) + suffix,
|
|
71235
|
+
squads,
|
|
71236
|
+
deletedCount
|
|
71270
71237
|
};
|
|
71271
71238
|
}
|
|
71272
71239
|
case "get_squad_status": {
|
|
@@ -71398,10 +71365,22 @@ var init_squad2 = __esm({
|
|
|
71398
71365
|
},
|
|
71399
71366
|
{
|
|
71400
71367
|
name: "fire_squad",
|
|
71401
|
-
description: "
|
|
71368
|
+
description: "Soft-delete a squad. The squad can be restored later with restore_squad.",
|
|
71402
71369
|
parameters: squadIdSchema,
|
|
71403
71370
|
skipPermission: true
|
|
71404
71371
|
},
|
|
71372
|
+
{
|
|
71373
|
+
name: "restore_squad",
|
|
71374
|
+
description: "Restore a previously deleted squad and all its members.",
|
|
71375
|
+
parameters: squadIdSchema,
|
|
71376
|
+
skipPermission: true
|
|
71377
|
+
},
|
|
71378
|
+
{
|
|
71379
|
+
name: "list_deleted_squads",
|
|
71380
|
+
description: "List all soft-deleted squads that can be restored.",
|
|
71381
|
+
parameters: external_exports.object({}),
|
|
71382
|
+
skipPermission: true
|
|
71383
|
+
},
|
|
71405
71384
|
{
|
|
71406
71385
|
name: "list_squads",
|
|
71407
71386
|
description: "List all squads and their status.",
|
|
@@ -71853,13 +71832,13 @@ var init_orchestrator = __esm({
|
|
|
71853
71832
|
});
|
|
71854
71833
|
this.activeModel = model;
|
|
71855
71834
|
} catch (error51) {
|
|
71856
|
-
if (model !==
|
|
71835
|
+
if (model !== this.config.defaultModel) {
|
|
71857
71836
|
this.activeSession = await createSession({
|
|
71858
|
-
model:
|
|
71837
|
+
model: this.config.defaultModel,
|
|
71859
71838
|
systemPrompt,
|
|
71860
71839
|
tools: createBoundOrchestratorTools(this.config)
|
|
71861
71840
|
});
|
|
71862
|
-
this.activeModel =
|
|
71841
|
+
this.activeModel = this.config.defaultModel;
|
|
71863
71842
|
} else {
|
|
71864
71843
|
throw error51;
|
|
71865
71844
|
}
|
|
@@ -85311,9 +85290,16 @@ var init_bot = __esm({
|
|
|
85311
85290
|
if (this.started) {
|
|
85312
85291
|
return;
|
|
85313
85292
|
}
|
|
85293
|
+
this.bot.catch((err) => {
|
|
85294
|
+
this.logger.error({ err: err.error }, "Telegram bot error: %s", err.message);
|
|
85295
|
+
});
|
|
85314
85296
|
this.registerHandlers();
|
|
85315
|
-
this.bot.start(
|
|
85316
|
-
|
|
85297
|
+
this.bot.start({
|
|
85298
|
+
onStart: () => {
|
|
85299
|
+
this.logger.info("Telegram bot connected and polling");
|
|
85300
|
+
}
|
|
85301
|
+
}).catch((error51) => {
|
|
85302
|
+
this.logger.error({ err: error51 }, "Telegram polling failed to start");
|
|
85317
85303
|
});
|
|
85318
85304
|
this.started = true;
|
|
85319
85305
|
}
|
|
@@ -85323,11 +85309,26 @@ var init_bot = __esm({
|
|
|
85323
85309
|
}
|
|
85324
85310
|
this.bot.stop();
|
|
85325
85311
|
this.started = false;
|
|
85312
|
+
this.logger.info("Telegram bot stopped");
|
|
85326
85313
|
}
|
|
85327
85314
|
async sendText(chatId, text) {
|
|
85328
85315
|
await this.bot.api.sendMessage(chatId, text);
|
|
85329
85316
|
}
|
|
85317
|
+
isAuthorized(userId) {
|
|
85318
|
+
if (!this.config.telegramUserId) {
|
|
85319
|
+
return false;
|
|
85320
|
+
}
|
|
85321
|
+
return String(userId) === this.config.telegramUserId;
|
|
85322
|
+
}
|
|
85330
85323
|
registerHandlers() {
|
|
85324
|
+
this.bot.use(async (ctx, next) => {
|
|
85325
|
+
const userId = ctx.from?.id;
|
|
85326
|
+
if (!userId || !this.isAuthorized(userId)) {
|
|
85327
|
+
this.logger.warn({ userId }, "Unauthorized Telegram message, ignoring");
|
|
85328
|
+
return;
|
|
85329
|
+
}
|
|
85330
|
+
await next();
|
|
85331
|
+
});
|
|
85331
85332
|
this.bot.command("start", async (ctx) => {
|
|
85332
85333
|
await ctx.reply(
|
|
85333
85334
|
"Hello from Io. Send me a message and I will route it through the daemon orchestrator."
|
|
@@ -85514,8 +85515,7 @@ async function main() {
|
|
|
85514
85515
|
logger2.info("Database initialized");
|
|
85515
85516
|
const pricingResult = await refreshModelPricing(logger2);
|
|
85516
85517
|
if (pricingResult.modelsUpdated === 0) {
|
|
85517
|
-
logger2.warn("Model pricing refresh returned 0 models
|
|
85518
|
-
await seedFromFallback();
|
|
85518
|
+
logger2.warn("Model pricing refresh returned 0 models");
|
|
85519
85519
|
}
|
|
85520
85520
|
logger2.info({ modelsUpdated: pricingResult.modelsUpdated }, "Model pricing initialized");
|
|
85521
85521
|
await scanSkills();
|
|
@@ -85535,8 +85535,13 @@ async function main() {
|
|
|
85535
85535
|
setChatOrchestrator(orchestrator2);
|
|
85536
85536
|
const apiServer = createApiServer(config2);
|
|
85537
85537
|
const telegramBot = createTelegramBot(config2, orchestrator2);
|
|
85538
|
-
telegramBot
|
|
85539
|
-
|
|
85538
|
+
if (telegramBot) {
|
|
85539
|
+
telegramBot.start();
|
|
85540
|
+
createTelegramNotifier(telegramBot, config2, eventBus);
|
|
85541
|
+
logger2.info("Telegram bot initialized");
|
|
85542
|
+
} else {
|
|
85543
|
+
logger2.info("Telegram bot disabled (no token configured)");
|
|
85544
|
+
}
|
|
85540
85545
|
registerShutdownHandlers(logger2, async () => {
|
|
85541
85546
|
if (pricingRefreshTimer) {
|
|
85542
85547
|
clearInterval(pricingRefreshTimer);
|