heyio 4.3.3 → 4.3.4
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 +83 -109
- package/dist/daemon/index.js +882 -971
- package/package.json +1 -1
package/dist/daemon/index.js
CHANGED
|
@@ -79,7 +79,7 @@ var init_constants = __esm({
|
|
|
79
79
|
"packages/shared/dist/constants.js"() {
|
|
80
80
|
"use strict";
|
|
81
81
|
APP_NAME = "io";
|
|
82
|
-
APP_VERSION = "4.3.
|
|
82
|
+
APP_VERSION = "4.3.4";
|
|
83
83
|
API_PORT = 7777;
|
|
84
84
|
API_HOST = "0.0.0.0";
|
|
85
85
|
DEFAULT_MODEL = "gpt-4.1-mini";
|
|
@@ -152,349 +152,6 @@ var init_paths = __esm({
|
|
|
152
152
|
}
|
|
153
153
|
});
|
|
154
154
|
|
|
155
|
-
// packages/daemon/src/store/db.ts
|
|
156
|
-
import { mkdir } from "node:fs/promises";
|
|
157
|
-
import { dirname } from "node:path";
|
|
158
|
-
import { pathToFileURL } from "node:url";
|
|
159
|
-
import { createClient } from "@libsql/client";
|
|
160
|
-
function asString(value) {
|
|
161
|
-
if (typeof value === "string") {
|
|
162
|
-
return value;
|
|
163
|
-
}
|
|
164
|
-
if (value === null || value === void 0) {
|
|
165
|
-
throw new Error("Expected string value but received null or undefined");
|
|
166
|
-
}
|
|
167
|
-
return String(value);
|
|
168
|
-
}
|
|
169
|
-
function asNullableString(value) {
|
|
170
|
-
if (value === null || value === void 0) {
|
|
171
|
-
return null;
|
|
172
|
-
}
|
|
173
|
-
return typeof value === "string" ? value : String(value);
|
|
174
|
-
}
|
|
175
|
-
function asNumber(value) {
|
|
176
|
-
if (typeof value === "number") {
|
|
177
|
-
return value;
|
|
178
|
-
}
|
|
179
|
-
if (typeof value === "bigint") {
|
|
180
|
-
return Number(value);
|
|
181
|
-
}
|
|
182
|
-
if (typeof value === "string") {
|
|
183
|
-
return Number(value);
|
|
184
|
-
}
|
|
185
|
-
throw new Error(`Expected numeric value but received ${typeof value}`);
|
|
186
|
-
}
|
|
187
|
-
function asNullableNumber(value) {
|
|
188
|
-
if (value === null || value === void 0) {
|
|
189
|
-
return null;
|
|
190
|
-
}
|
|
191
|
-
return asNumber(value);
|
|
192
|
-
}
|
|
193
|
-
function asBoolean(value) {
|
|
194
|
-
return asNumber(value) === 1;
|
|
195
|
-
}
|
|
196
|
-
function toSqliteBoolean(value) {
|
|
197
|
-
return value ? 1 : 0;
|
|
198
|
-
}
|
|
199
|
-
function parseJson(value) {
|
|
200
|
-
if (typeof value !== "string") {
|
|
201
|
-
return value;
|
|
202
|
-
}
|
|
203
|
-
return JSON.parse(value);
|
|
204
|
-
}
|
|
205
|
-
function serializeJson(value) {
|
|
206
|
-
return JSON.stringify(value);
|
|
207
|
-
}
|
|
208
|
-
async function initDatabase() {
|
|
209
|
-
if (client && !client.closed) {
|
|
210
|
-
return client;
|
|
211
|
-
}
|
|
212
|
-
if (initPromise) {
|
|
213
|
-
return initPromise;
|
|
214
|
-
}
|
|
215
|
-
initPromise = initializeDatabase(defaultConnectionOptions);
|
|
216
|
-
try {
|
|
217
|
-
client = await initPromise;
|
|
218
|
-
return client;
|
|
219
|
-
} finally {
|
|
220
|
-
initPromise = null;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
async function getDatabase() {
|
|
224
|
-
return initDatabase();
|
|
225
|
-
}
|
|
226
|
-
async function initializeDatabase(options2 = {}) {
|
|
227
|
-
const url2 = await resolveDatabaseUrl(options2);
|
|
228
|
-
const databaseClient = createClient({ url: url2 });
|
|
229
|
-
await databaseClient.execute("PRAGMA foreign_keys = ON");
|
|
230
|
-
await databaseClient.execute("PRAGMA journal_mode = WAL");
|
|
231
|
-
await ensureMigrationTable(databaseClient);
|
|
232
|
-
await applyMigrations(databaseClient);
|
|
233
|
-
return databaseClient;
|
|
234
|
-
}
|
|
235
|
-
async function resolveDatabaseUrl(options2) {
|
|
236
|
-
if (options2.url) {
|
|
237
|
-
return options2.url;
|
|
238
|
-
}
|
|
239
|
-
const databasePath = options2.path ?? DB_PATH;
|
|
240
|
-
await mkdir(dirname(databasePath), { recursive: true });
|
|
241
|
-
return pathToFileURL(databasePath).href;
|
|
242
|
-
}
|
|
243
|
-
async function ensureMigrationTable(databaseClient) {
|
|
244
|
-
await databaseClient.executeMultiple(`
|
|
245
|
-
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
246
|
-
version INTEGER PRIMARY KEY,
|
|
247
|
-
name TEXT NOT NULL,
|
|
248
|
-
applied_at TEXT NOT NULL
|
|
249
|
-
);
|
|
250
|
-
`);
|
|
251
|
-
}
|
|
252
|
-
async function applyMigrations(databaseClient) {
|
|
253
|
-
const appliedVersions = await getAppliedVersions(databaseClient);
|
|
254
|
-
for (const migration of MIGRATIONS) {
|
|
255
|
-
if (appliedVersions.has(migration.version)) {
|
|
256
|
-
continue;
|
|
257
|
-
}
|
|
258
|
-
const transaction = await databaseClient.transaction("write");
|
|
259
|
-
try {
|
|
260
|
-
for (const statement of migration.statements) {
|
|
261
|
-
await transaction.execute(statement);
|
|
262
|
-
}
|
|
263
|
-
await transaction.execute({
|
|
264
|
-
sql: "INSERT INTO schema_migrations (version, name, applied_at) VALUES (?, ?, ?)",
|
|
265
|
-
args: [migration.version, migration.name, nowIso()]
|
|
266
|
-
});
|
|
267
|
-
await transaction.commit();
|
|
268
|
-
} catch (error51) {
|
|
269
|
-
if (!transaction.closed) {
|
|
270
|
-
await transaction.rollback();
|
|
271
|
-
}
|
|
272
|
-
throw error51;
|
|
273
|
-
} finally {
|
|
274
|
-
if (!transaction.closed) {
|
|
275
|
-
transaction.close();
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
async function getAppliedVersions(databaseClient) {
|
|
281
|
-
const result = await databaseClient.execute(
|
|
282
|
-
"SELECT version FROM schema_migrations ORDER BY version ASC"
|
|
283
|
-
);
|
|
284
|
-
return new Set(result.rows.map((row) => asNumber(row.version)));
|
|
285
|
-
}
|
|
286
|
-
var MIGRATIONS, client, initPromise, defaultConnectionOptions, generateId, nowIso;
|
|
287
|
-
var init_db = __esm({
|
|
288
|
-
"packages/daemon/src/store/db.ts"() {
|
|
289
|
-
"use strict";
|
|
290
|
-
init_paths();
|
|
291
|
-
MIGRATIONS = [
|
|
292
|
-
{
|
|
293
|
-
version: 1,
|
|
294
|
-
name: "create-store-schema",
|
|
295
|
-
statements: [
|
|
296
|
-
`CREATE TABLE IF NOT EXISTS squads (
|
|
297
|
-
id TEXT PRIMARY KEY,
|
|
298
|
-
name TEXT NOT NULL,
|
|
299
|
-
repo_url TEXT NOT NULL,
|
|
300
|
-
repo_owner TEXT NOT NULL,
|
|
301
|
-
repo_name TEXT NOT NULL,
|
|
302
|
-
status TEXT NOT NULL,
|
|
303
|
-
config TEXT NOT NULL,
|
|
304
|
-
created_at TEXT NOT NULL,
|
|
305
|
-
updated_at TEXT NOT NULL,
|
|
306
|
-
UNIQUE (repo_owner, repo_name)
|
|
307
|
-
)`,
|
|
308
|
-
`CREATE TABLE IF NOT EXISTS squad_members (
|
|
309
|
-
id TEXT PRIMARY KEY,
|
|
310
|
-
squad_id TEXT NOT NULL REFERENCES squads(id) ON DELETE CASCADE,
|
|
311
|
-
role TEXT NOT NULL,
|
|
312
|
-
name TEXT NOT NULL,
|
|
313
|
-
system_prompt TEXT NOT NULL,
|
|
314
|
-
model TEXT,
|
|
315
|
-
created_at TEXT NOT NULL
|
|
316
|
-
)`,
|
|
317
|
-
`CREATE TABLE IF NOT EXISTS objectives (
|
|
318
|
-
id TEXT PRIMARY KEY,
|
|
319
|
-
squad_id TEXT NOT NULL REFERENCES squads(id) ON DELETE CASCADE,
|
|
320
|
-
description TEXT NOT NULL,
|
|
321
|
-
status TEXT NOT NULL,
|
|
322
|
-
plan TEXT,
|
|
323
|
-
revision_count INTEGER NOT NULL DEFAULT 0,
|
|
324
|
-
branch TEXT,
|
|
325
|
-
pr_url TEXT,
|
|
326
|
-
created_at TEXT NOT NULL,
|
|
327
|
-
updated_at TEXT NOT NULL
|
|
328
|
-
)`,
|
|
329
|
-
`CREATE TABLE IF NOT EXISTS tasks (
|
|
330
|
-
id TEXT PRIMARY KEY,
|
|
331
|
-
objective_id TEXT NOT NULL REFERENCES objectives(id) ON DELETE CASCADE,
|
|
332
|
-
assignee_id TEXT REFERENCES squad_members(id) ON DELETE SET NULL,
|
|
333
|
-
title TEXT NOT NULL,
|
|
334
|
-
description TEXT NOT NULL,
|
|
335
|
-
status TEXT NOT NULL,
|
|
336
|
-
result TEXT,
|
|
337
|
-
created_at TEXT NOT NULL,
|
|
338
|
-
updated_at TEXT NOT NULL
|
|
339
|
-
)`,
|
|
340
|
-
`CREATE TABLE IF NOT EXISTS conversations (
|
|
341
|
-
id TEXT PRIMARY KEY,
|
|
342
|
-
title TEXT,
|
|
343
|
-
source TEXT NOT NULL,
|
|
344
|
-
created_at TEXT NOT NULL,
|
|
345
|
-
updated_at TEXT NOT NULL
|
|
346
|
-
)`,
|
|
347
|
-
`CREATE TABLE IF NOT EXISTS messages (
|
|
348
|
-
id TEXT PRIMARY KEY,
|
|
349
|
-
conversation_id TEXT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
|
|
350
|
-
role TEXT NOT NULL,
|
|
351
|
-
content TEXT NOT NULL,
|
|
352
|
-
model TEXT,
|
|
353
|
-
input_tokens INTEGER,
|
|
354
|
-
output_tokens INTEGER,
|
|
355
|
-
created_at TEXT NOT NULL
|
|
356
|
-
)`,
|
|
357
|
-
`CREATE TABLE IF NOT EXISTS inbox (
|
|
358
|
-
id TEXT PRIMARY KEY,
|
|
359
|
-
squad_id TEXT REFERENCES squads(id) ON DELETE SET NULL,
|
|
360
|
-
objective_id TEXT REFERENCES objectives(id) ON DELETE SET NULL,
|
|
361
|
-
type TEXT NOT NULL,
|
|
362
|
-
title TEXT NOT NULL,
|
|
363
|
-
content TEXT NOT NULL,
|
|
364
|
-
status TEXT NOT NULL,
|
|
365
|
-
reply TEXT,
|
|
366
|
-
created_at TEXT NOT NULL,
|
|
367
|
-
updated_at TEXT NOT NULL
|
|
368
|
-
)`,
|
|
369
|
-
`CREATE TABLE IF NOT EXISTS schedules (
|
|
370
|
-
id TEXT PRIMARY KEY,
|
|
371
|
-
name TEXT NOT NULL,
|
|
372
|
-
cron_expression TEXT NOT NULL,
|
|
373
|
-
prompt TEXT NOT NULL,
|
|
374
|
-
enabled INTEGER NOT NULL DEFAULT 1,
|
|
375
|
-
last_run_at TEXT,
|
|
376
|
-
next_run_at TEXT,
|
|
377
|
-
created_at TEXT NOT NULL,
|
|
378
|
-
updated_at TEXT NOT NULL
|
|
379
|
-
)`,
|
|
380
|
-
`CREATE TABLE IF NOT EXISTS token_usage (
|
|
381
|
-
id TEXT PRIMARY KEY,
|
|
382
|
-
squad_id TEXT REFERENCES squads(id) ON DELETE SET NULL,
|
|
383
|
-
agent_id TEXT,
|
|
384
|
-
model TEXT NOT NULL,
|
|
385
|
-
input_tokens INTEGER NOT NULL,
|
|
386
|
-
output_tokens INTEGER NOT NULL,
|
|
387
|
-
cost REAL NOT NULL,
|
|
388
|
-
created_at TEXT NOT NULL
|
|
389
|
-
)`,
|
|
390
|
-
`CREATE TABLE IF NOT EXISTS activity (
|
|
391
|
-
id TEXT PRIMARY KEY,
|
|
392
|
-
squad_id TEXT REFERENCES squads(id) ON DELETE SET NULL,
|
|
393
|
-
objective_id TEXT REFERENCES objectives(id) ON DELETE SET NULL,
|
|
394
|
-
event TEXT NOT NULL,
|
|
395
|
-
description TEXT NOT NULL,
|
|
396
|
-
metadata TEXT,
|
|
397
|
-
created_at TEXT NOT NULL
|
|
398
|
-
)`,
|
|
399
|
-
`CREATE TABLE IF NOT EXISTS agent_history (
|
|
400
|
-
id TEXT PRIMARY KEY,
|
|
401
|
-
agent_id TEXT NOT NULL,
|
|
402
|
-
squad_id TEXT REFERENCES squads(id) ON DELETE SET NULL,
|
|
403
|
-
content TEXT NOT NULL,
|
|
404
|
-
created_at TEXT NOT NULL
|
|
405
|
-
)`,
|
|
406
|
-
`CREATE TABLE IF NOT EXISTS settings (
|
|
407
|
-
key TEXT PRIMARY KEY,
|
|
408
|
-
value TEXT
|
|
409
|
-
)`,
|
|
410
|
-
"CREATE INDEX IF NOT EXISTS idx_squad_members_squad_id ON squad_members(squad_id)",
|
|
411
|
-
"CREATE INDEX IF NOT EXISTS idx_objectives_squad_id ON objectives(squad_id)",
|
|
412
|
-
"CREATE INDEX IF NOT EXISTS idx_objectives_status ON objectives(status)",
|
|
413
|
-
"CREATE INDEX IF NOT EXISTS idx_tasks_objective_id ON tasks(objective_id)",
|
|
414
|
-
"CREATE INDEX IF NOT EXISTS idx_tasks_assignee_id ON tasks(assignee_id)",
|
|
415
|
-
"CREATE INDEX IF NOT EXISTS idx_messages_conversation_id_created_at ON messages(conversation_id, created_at)",
|
|
416
|
-
"CREATE INDEX IF NOT EXISTS idx_inbox_status_created_at ON inbox(status, created_at)",
|
|
417
|
-
"CREATE INDEX IF NOT EXISTS idx_inbox_squad_id ON inbox(squad_id)",
|
|
418
|
-
"CREATE INDEX IF NOT EXISTS idx_inbox_objective_id ON inbox(objective_id)",
|
|
419
|
-
"CREATE INDEX IF NOT EXISTS idx_schedules_enabled_next_run_at ON schedules(enabled, next_run_at)",
|
|
420
|
-
"CREATE INDEX IF NOT EXISTS idx_token_usage_created_at ON token_usage(created_at)",
|
|
421
|
-
"CREATE INDEX IF NOT EXISTS idx_token_usage_squad_id ON token_usage(squad_id)",
|
|
422
|
-
"CREATE INDEX IF NOT EXISTS idx_token_usage_agent_id ON token_usage(agent_id)",
|
|
423
|
-
"CREATE INDEX IF NOT EXISTS idx_token_usage_model ON token_usage(model)",
|
|
424
|
-
"CREATE INDEX IF NOT EXISTS idx_activity_created_at ON activity(created_at)",
|
|
425
|
-
"CREATE INDEX IF NOT EXISTS idx_activity_squad_id ON activity(squad_id)",
|
|
426
|
-
"CREATE INDEX IF NOT EXISTS idx_activity_objective_id ON activity(objective_id)",
|
|
427
|
-
"CREATE INDEX IF NOT EXISTS idx_agent_history_agent_id_created_at ON agent_history(agent_id, created_at)"
|
|
428
|
-
]
|
|
429
|
-
},
|
|
430
|
-
{
|
|
431
|
-
version: 2,
|
|
432
|
-
name: "add-model-pricing-and-dual-costs",
|
|
433
|
-
statements: [
|
|
434
|
-
`CREATE TABLE IF NOT EXISTS model_pricing (
|
|
435
|
-
id TEXT PRIMARY KEY,
|
|
436
|
-
display_name TEXT NOT NULL,
|
|
437
|
-
premium_multiplier REAL,
|
|
438
|
-
token_input_multiplier REAL,
|
|
439
|
-
token_output_multiplier REAL,
|
|
440
|
-
cached_input_multiplier REAL,
|
|
441
|
-
tier TEXT NOT NULL,
|
|
442
|
-
available INTEGER NOT NULL DEFAULT 1,
|
|
443
|
-
updated_at TEXT NOT NULL
|
|
444
|
-
)`,
|
|
445
|
-
"CREATE INDEX IF NOT EXISTS idx_model_pricing_tier ON model_pricing(tier)",
|
|
446
|
-
"CREATE INDEX IF NOT EXISTS idx_model_pricing_available ON model_pricing(available)",
|
|
447
|
-
"ALTER TABLE token_usage ADD COLUMN premium_request_cost REAL",
|
|
448
|
-
"ALTER TABLE token_usage ADD COLUMN token_unit_cost REAL"
|
|
449
|
-
]
|
|
450
|
-
},
|
|
451
|
-
{
|
|
452
|
-
version: 3,
|
|
453
|
-
name: "add-squad-instances",
|
|
454
|
-
statements: [
|
|
455
|
-
`CREATE TABLE IF NOT EXISTS squad_instances (
|
|
456
|
-
id TEXT PRIMARY KEY,
|
|
457
|
-
squad_id TEXT NOT NULL REFERENCES squads(id) ON DELETE CASCADE,
|
|
458
|
-
objective_id TEXT REFERENCES objectives(id) ON DELETE SET NULL,
|
|
459
|
-
status TEXT NOT NULL DEFAULT 'queued',
|
|
460
|
-
branch TEXT,
|
|
461
|
-
worktree_path TEXT,
|
|
462
|
-
created_at TEXT NOT NULL,
|
|
463
|
-
started_at TEXT,
|
|
464
|
-
completed_at TEXT,
|
|
465
|
-
error TEXT
|
|
466
|
-
)`,
|
|
467
|
-
"CREATE INDEX IF NOT EXISTS idx_squad_instances_squad_status ON squad_instances(squad_id, status)",
|
|
468
|
-
"CREATE INDEX IF NOT EXISTS idx_squad_instances_status ON squad_instances(status)",
|
|
469
|
-
"CREATE INDEX IF NOT EXISTS idx_squad_instances_objective_id ON squad_instances(objective_id)"
|
|
470
|
-
]
|
|
471
|
-
},
|
|
472
|
-
{
|
|
473
|
-
version: 4,
|
|
474
|
-
name: "denormalize-usage-names",
|
|
475
|
-
statements: [
|
|
476
|
-
"ALTER TABLE token_usage ADD COLUMN squad_name TEXT",
|
|
477
|
-
"ALTER TABLE token_usage ADD COLUMN agent_name TEXT",
|
|
478
|
-
`UPDATE token_usage SET
|
|
479
|
-
squad_name = (SELECT s.name FROM squads s WHERE s.id = token_usage.squad_id),
|
|
480
|
-
agent_name = (SELECT sm.name FROM squad_members sm WHERE sm.id = token_usage.agent_id)
|
|
481
|
-
WHERE squad_id IS NOT NULL OR agent_id IS NOT NULL`
|
|
482
|
-
]
|
|
483
|
-
},
|
|
484
|
-
{
|
|
485
|
-
version: 5,
|
|
486
|
-
name: "add-squad-soft-delete",
|
|
487
|
-
statements: ["ALTER TABLE squads ADD COLUMN deleted_at TEXT"]
|
|
488
|
-
}
|
|
489
|
-
];
|
|
490
|
-
client = null;
|
|
491
|
-
initPromise = null;
|
|
492
|
-
defaultConnectionOptions = {};
|
|
493
|
-
generateId = () => crypto.randomUUID();
|
|
494
|
-
nowIso = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
495
|
-
}
|
|
496
|
-
});
|
|
497
|
-
|
|
498
155
|
// node_modules/cron-parser/dist/fields/types.js
|
|
499
156
|
var require_types = __commonJS({
|
|
500
157
|
"node_modules/cron-parser/dist/fields/types.js"(exports2) {
|
|
@@ -62549,499 +62206,6 @@ var require_websocket_server = __commonJS({
|
|
|
62549
62206
|
}
|
|
62550
62207
|
});
|
|
62551
62208
|
|
|
62552
|
-
// packages/daemon/src/models/catalog.ts
|
|
62553
|
-
import { execFileSync } from "node:child_process";
|
|
62554
|
-
function resolveGitHubToken() {
|
|
62555
|
-
const envToken = process.env.GITHUB_TOKEN?.trim();
|
|
62556
|
-
if (envToken && envToken.length > 0) {
|
|
62557
|
-
return envToken;
|
|
62558
|
-
}
|
|
62559
|
-
try {
|
|
62560
|
-
const token = execFileSync("gh", ["auth", "token"], {
|
|
62561
|
-
encoding: "utf8",
|
|
62562
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
62563
|
-
}).trim();
|
|
62564
|
-
return token.length > 0 ? token : void 0;
|
|
62565
|
-
} catch {
|
|
62566
|
-
return void 0;
|
|
62567
|
-
}
|
|
62568
|
-
}
|
|
62569
|
-
async function fetchModelCatalog() {
|
|
62570
|
-
const token = resolveGitHubToken();
|
|
62571
|
-
if (!token) {
|
|
62572
|
-
throw new Error("No GitHub token available for model catalog fetch");
|
|
62573
|
-
}
|
|
62574
|
-
const response = await fetch(CATALOG_URL, {
|
|
62575
|
-
headers: {
|
|
62576
|
-
Accept: "application/json",
|
|
62577
|
-
Authorization: `Bearer ${token}`,
|
|
62578
|
-
"X-GitHub-Api-Version": "2024-12-01"
|
|
62579
|
-
}
|
|
62580
|
-
});
|
|
62581
|
-
if (!response.ok) {
|
|
62582
|
-
throw new Error(`Model catalog fetch failed: ${response.status} ${response.statusText}`);
|
|
62583
|
-
}
|
|
62584
|
-
const data = await response.json();
|
|
62585
|
-
if (!Array.isArray(data)) {
|
|
62586
|
-
throw new Error("Model catalog response is not an array");
|
|
62587
|
-
}
|
|
62588
|
-
const models = [];
|
|
62589
|
-
for (const entry of data) {
|
|
62590
|
-
const id = entry.id ?? entry.name;
|
|
62591
|
-
const displayName = entry.friendly_name ?? entry.name ?? id;
|
|
62592
|
-
if (id && typeof id === "string") {
|
|
62593
|
-
models.push({ id, displayName: displayName ?? id });
|
|
62594
|
-
}
|
|
62595
|
-
}
|
|
62596
|
-
return models;
|
|
62597
|
-
}
|
|
62598
|
-
var CATALOG_URL;
|
|
62599
|
-
var init_catalog = __esm({
|
|
62600
|
-
"packages/daemon/src/models/catalog.ts"() {
|
|
62601
|
-
"use strict";
|
|
62602
|
-
CATALOG_URL = "https://models.github.ai/catalog/models";
|
|
62603
|
-
}
|
|
62604
|
-
});
|
|
62605
|
-
|
|
62606
|
-
// packages/daemon/src/models/pricing-scraper.ts
|
|
62607
|
-
async function scrapeTokenUnitPricing() {
|
|
62608
|
-
const html = await fetchPage(TOKEN_UNIT_COSTS_URL);
|
|
62609
|
-
return parseTokenUnitTable(html);
|
|
62610
|
-
}
|
|
62611
|
-
async function scrapeCopilotPricing() {
|
|
62612
|
-
const markdown = await fetchMarkdown(COPILOT_PRICING_URL);
|
|
62613
|
-
return parseCopilotPricingMarkdown(markdown);
|
|
62614
|
-
}
|
|
62615
|
-
async function scrapePremiumRequestPricing() {
|
|
62616
|
-
const html = await fetchPage(PREMIUM_MULTIPLIERS_URL);
|
|
62617
|
-
return parsePremiumMultiplierTable(html);
|
|
62618
|
-
}
|
|
62619
|
-
async function fetchPage(url2) {
|
|
62620
|
-
const response = await fetch(url2, {
|
|
62621
|
-
headers: {
|
|
62622
|
-
Accept: "text/html",
|
|
62623
|
-
"User-Agent": "IO-Daemon/4.0 (pricing-refresh)"
|
|
62624
|
-
},
|
|
62625
|
-
redirect: "follow"
|
|
62626
|
-
});
|
|
62627
|
-
if (!response.ok) {
|
|
62628
|
-
throw new Error(`Failed to fetch ${url2}: ${response.status} ${response.statusText}`);
|
|
62629
|
-
}
|
|
62630
|
-
return response.text();
|
|
62631
|
-
}
|
|
62632
|
-
async function fetchMarkdown(url2) {
|
|
62633
|
-
const response = await fetch(url2, {
|
|
62634
|
-
headers: {
|
|
62635
|
-
Accept: "text/markdown, text/plain, */*",
|
|
62636
|
-
"User-Agent": "IO-Daemon/4.0 (pricing-refresh)"
|
|
62637
|
-
},
|
|
62638
|
-
redirect: "follow"
|
|
62639
|
-
});
|
|
62640
|
-
if (!response.ok) {
|
|
62641
|
-
throw new Error(`Failed to fetch ${url2}: ${response.status} ${response.statusText}`);
|
|
62642
|
-
}
|
|
62643
|
-
return response.text();
|
|
62644
|
-
}
|
|
62645
|
-
function parseTokenUnitTable(html) {
|
|
62646
|
-
const results = [];
|
|
62647
|
-
const tableRowPattern = /<tr[^>]*>\s*<td[^>]*>([^<]+)<\/td>\s*<td[^>]*>([^<]+)<\/td>\s*<td[^>]*>([^<]*)<\/td>\s*<td[^>]*>([^<]+)<\/td>/gi;
|
|
62648
|
-
for (const match of html.matchAll(tableRowPattern)) {
|
|
62649
|
-
const modelName = cleanCellText(match[1]);
|
|
62650
|
-
const inputMultiplier = Number.parseFloat(match[2]);
|
|
62651
|
-
const cachedInput = match[3].trim().toLowerCase();
|
|
62652
|
-
const outputMultiplier = Number.parseFloat(match[4]);
|
|
62653
|
-
if (modelName && !Number.isNaN(inputMultiplier) && !Number.isNaN(outputMultiplier)) {
|
|
62654
|
-
results.push({
|
|
62655
|
-
modelName,
|
|
62656
|
-
inputMultiplier,
|
|
62657
|
-
cachedInputMultiplier: cachedInput === "n/a" || cachedInput === "" ? null : Number.parseFloat(cachedInput) || null,
|
|
62658
|
-
outputMultiplier
|
|
62659
|
-
});
|
|
62660
|
-
}
|
|
62661
|
-
}
|
|
62662
|
-
return results;
|
|
62663
|
-
}
|
|
62664
|
-
function parsePremiumMultiplierTable(html) {
|
|
62665
|
-
const results = [];
|
|
62666
|
-
const tableRowPattern = /<tr[^>]*>\s*<td[^>]*>([^<]+)<\/td>\s*<td[^>]*>([^<]+)<\/td>\s*<\/tr>/gi;
|
|
62667
|
-
for (const match of html.matchAll(tableRowPattern)) {
|
|
62668
|
-
const modelName = cleanCellText(match[1]);
|
|
62669
|
-
const multiplier = Number.parseFloat(match[2]);
|
|
62670
|
-
if (modelName && !Number.isNaN(multiplier) && multiplier > 0) {
|
|
62671
|
-
results.push({ modelName, multiplier });
|
|
62672
|
-
}
|
|
62673
|
-
}
|
|
62674
|
-
return results;
|
|
62675
|
-
}
|
|
62676
|
-
function cleanCellText(text) {
|
|
62677
|
-
return text.replace(/<[^>]*>/g, "").replace(/&[^;]+;/g, " ").trim();
|
|
62678
|
-
}
|
|
62679
|
-
function parseCopilotPricingMarkdown(markdown) {
|
|
62680
|
-
const results = [];
|
|
62681
|
-
const seenModels = /* @__PURE__ */ new Set();
|
|
62682
|
-
const lines = markdown.split("\n");
|
|
62683
|
-
let columnIndices = null;
|
|
62684
|
-
for (const line of lines) {
|
|
62685
|
-
const trimmed = line.trim();
|
|
62686
|
-
if (!trimmed.startsWith("|")) continue;
|
|
62687
|
-
if (/\|\s*Model\s/i.test(trimmed)) {
|
|
62688
|
-
columnIndices = parseHeaderColumns(trimmed);
|
|
62689
|
-
continue;
|
|
62690
|
-
}
|
|
62691
|
-
if (/^[\s|:-]+$/.test(trimmed) || !columnIndices) continue;
|
|
62692
|
-
const entry = parseDataRow(trimmed, columnIndices);
|
|
62693
|
-
if (entry && !seenModels.has(entry.modelName.toLowerCase())) {
|
|
62694
|
-
seenModels.add(entry.modelName.toLowerCase());
|
|
62695
|
-
results.push(entry);
|
|
62696
|
-
}
|
|
62697
|
-
}
|
|
62698
|
-
return results;
|
|
62699
|
-
}
|
|
62700
|
-
function parseDataRow(line, columnIndices) {
|
|
62701
|
-
const cells = splitMarkdownRow(line);
|
|
62702
|
-
if (cells.length <= columnIndices.output) return null;
|
|
62703
|
-
const modelName = cells[columnIndices.model].trim();
|
|
62704
|
-
const inputPrice = parseDollarValue(cells[columnIndices.input]);
|
|
62705
|
-
const cachedPrice = columnIndices.cached >= 0 ? parseDollarValue(cells[columnIndices.cached]) : null;
|
|
62706
|
-
const outputPrice = parseDollarValue(cells[columnIndices.output]);
|
|
62707
|
-
if (!modelName || inputPrice === null || outputPrice === null) return null;
|
|
62708
|
-
return {
|
|
62709
|
-
modelName,
|
|
62710
|
-
inputMultiplier: inputPrice * PRICE_TO_MULTIPLIER,
|
|
62711
|
-
cachedInputMultiplier: cachedPrice !== null ? cachedPrice * PRICE_TO_MULTIPLIER : null,
|
|
62712
|
-
outputMultiplier: outputPrice * PRICE_TO_MULTIPLIER
|
|
62713
|
-
};
|
|
62714
|
-
}
|
|
62715
|
-
function parseHeaderColumns(headerLine) {
|
|
62716
|
-
const cells = splitMarkdownRow(headerLine).map((c) => c.trim().toLowerCase());
|
|
62717
|
-
const model = cells.findIndex((c) => c === "model" || c === "model name");
|
|
62718
|
-
const input = cells.findIndex(
|
|
62719
|
-
(c) => (c === "input" || c === "input multiplier") && !c.includes("cached")
|
|
62720
|
-
);
|
|
62721
|
-
const cached2 = cells.findIndex(
|
|
62722
|
-
(c) => c.includes("cached input") || c === "cached input multiplier"
|
|
62723
|
-
);
|
|
62724
|
-
const output = cells.findIndex(
|
|
62725
|
-
(c) => (c === "output" || c === "output multiplier") && !c.includes("cached")
|
|
62726
|
-
);
|
|
62727
|
-
if (model < 0 || input < 0 || output < 0) {
|
|
62728
|
-
return null;
|
|
62729
|
-
}
|
|
62730
|
-
return { model, input, cached: cached2 >= 0 ? cached2 : -1, output };
|
|
62731
|
-
}
|
|
62732
|
-
function splitMarkdownRow(line) {
|
|
62733
|
-
const parts = line.split("|");
|
|
62734
|
-
if (parts[0].trim() === "") parts.shift();
|
|
62735
|
-
if (parts[parts.length - 1]?.trim() === "") parts.pop();
|
|
62736
|
-
return parts;
|
|
62737
|
-
}
|
|
62738
|
-
function parseDollarValue(cell) {
|
|
62739
|
-
if (!cell) return null;
|
|
62740
|
-
const cleaned = cell.trim().replace(/[$,]/g, "");
|
|
62741
|
-
if (cleaned.toLowerCase() === "n/a" || cleaned === "" || cleaned === "-") {
|
|
62742
|
-
return null;
|
|
62743
|
-
}
|
|
62744
|
-
const value = Number.parseFloat(cleaned);
|
|
62745
|
-
return Number.isNaN(value) ? null : value;
|
|
62746
|
-
}
|
|
62747
|
-
var TOKEN_UNIT_COSTS_URL, PREMIUM_MULTIPLIERS_URL, COPILOT_PRICING_URL, PRICE_TO_MULTIPLIER;
|
|
62748
|
-
var init_pricing_scraper = __esm({
|
|
62749
|
-
"packages/daemon/src/models/pricing-scraper.ts"() {
|
|
62750
|
-
"use strict";
|
|
62751
|
-
TOKEN_UNIT_COSTS_URL = "https://docs.github.com/en/billing/reference/costs-for-github-models";
|
|
62752
|
-
PREMIUM_MULTIPLIERS_URL = "https://docs.github.com/en/copilot/reference/copilot-billing/request-based-billing-legacy/model-multipliers-for-annual-plans";
|
|
62753
|
-
COPILOT_PRICING_URL = "https://docs.github.com/api/article/body?pathname=/en/copilot/reference/copilot-billing/models-and-pricing";
|
|
62754
|
-
PRICE_TO_MULTIPLIER = 0.1;
|
|
62755
|
-
}
|
|
62756
|
-
});
|
|
62757
|
-
|
|
62758
|
-
// packages/daemon/src/models/types.ts
|
|
62759
|
-
function computeTierFromMultiplier(premiumMultiplier) {
|
|
62760
|
-
if (premiumMultiplier === null) {
|
|
62761
|
-
return "standard";
|
|
62762
|
-
}
|
|
62763
|
-
for (const [tier, range] of Object.entries(TIER_RANGES)) {
|
|
62764
|
-
if (premiumMultiplier >= range.min && premiumMultiplier <= range.max) {
|
|
62765
|
-
return tier;
|
|
62766
|
-
}
|
|
62767
|
-
}
|
|
62768
|
-
return "ultra";
|
|
62769
|
-
}
|
|
62770
|
-
var TIER_RANGES, TOKEN_UNIT_PRICE;
|
|
62771
|
-
var init_types = __esm({
|
|
62772
|
-
"packages/daemon/src/models/types.ts"() {
|
|
62773
|
-
"use strict";
|
|
62774
|
-
TIER_RANGES = {
|
|
62775
|
-
trivial: { min: 0, max: 0.33 },
|
|
62776
|
-
fast: { min: 0.34, max: 1 },
|
|
62777
|
-
standard: { min: 1.1, max: 5 },
|
|
62778
|
-
premium: { min: 5.1, max: 15 },
|
|
62779
|
-
ultra: { min: 15.1, max: Number.POSITIVE_INFINITY }
|
|
62780
|
-
};
|
|
62781
|
-
TOKEN_UNIT_PRICE = 1e-5;
|
|
62782
|
-
}
|
|
62783
|
-
});
|
|
62784
|
-
|
|
62785
|
-
// packages/daemon/src/models/registry.ts
|
|
62786
|
-
function stripVendorPrefix(id) {
|
|
62787
|
-
const slashIndex = id.indexOf("/");
|
|
62788
|
-
return slashIndex >= 0 ? id.slice(slashIndex + 1) : id;
|
|
62789
|
-
}
|
|
62790
|
-
function normalizeModelName(name) {
|
|
62791
|
-
return stripVendorPrefix(name).toLowerCase().replace(/^openai\s+/i, "").replace(/\s+/g, "-").replace(/[^a-z0-9.\-]/g, "").trim();
|
|
62792
|
-
}
|
|
62793
|
-
async function fetchCatalogIntoMap(modelMap, result, logger2) {
|
|
62794
|
-
try {
|
|
62795
|
-
const catalogModels = await fetchModelCatalog();
|
|
62796
|
-
result.catalogFetched = true;
|
|
62797
|
-
for (const m of catalogModels) {
|
|
62798
|
-
const key = normalizeModelName(m.id);
|
|
62799
|
-
const id = stripVendorPrefix(m.id);
|
|
62800
|
-
modelMap.set(key, { id, displayName: m.displayName, available: true });
|
|
62801
|
-
}
|
|
62802
|
-
} catch (error51) {
|
|
62803
|
-
const msg = error51 instanceof Error ? error51.message : String(error51);
|
|
62804
|
-
result.errors.push(`Catalog fetch failed: ${msg}`);
|
|
62805
|
-
logger2?.warn(`Model catalog fetch failed: ${msg}`);
|
|
62806
|
-
}
|
|
62807
|
-
}
|
|
62808
|
-
async function scrapeTokenPricingIntoMap(modelMap, result, logger2) {
|
|
62809
|
-
try {
|
|
62810
|
-
const tokenPricing = await scrapeTokenUnitPricing();
|
|
62811
|
-
result.tokenPricingScraped = true;
|
|
62812
|
-
for (const tp of tokenPricing) {
|
|
62813
|
-
const key = normalizeModelName(tp.modelName);
|
|
62814
|
-
const existing = modelMap.get(key) ?? findClosestKey(modelMap, key);
|
|
62815
|
-
if (existing) {
|
|
62816
|
-
existing.tokenInputMultiplier = tp.inputMultiplier;
|
|
62817
|
-
existing.tokenOutputMultiplier = tp.outputMultiplier;
|
|
62818
|
-
existing.cachedInputMultiplier = tp.cachedInputMultiplier;
|
|
62819
|
-
} else {
|
|
62820
|
-
modelMap.set(key, {
|
|
62821
|
-
id: key,
|
|
62822
|
-
displayName: tp.modelName,
|
|
62823
|
-
tokenInputMultiplier: tp.inputMultiplier,
|
|
62824
|
-
tokenOutputMultiplier: tp.outputMultiplier,
|
|
62825
|
-
cachedInputMultiplier: tp.cachedInputMultiplier,
|
|
62826
|
-
available: true
|
|
62827
|
-
});
|
|
62828
|
-
}
|
|
62829
|
-
}
|
|
62830
|
-
} catch (error51) {
|
|
62831
|
-
const msg = error51 instanceof Error ? error51.message : String(error51);
|
|
62832
|
-
result.errors.push(`Token pricing scrape failed: ${msg}`);
|
|
62833
|
-
logger2?.warn(`Token pricing scrape failed: ${msg}`);
|
|
62834
|
-
}
|
|
62835
|
-
}
|
|
62836
|
-
async function scrapePremiumPricingIntoMap(modelMap, result, logger2) {
|
|
62837
|
-
try {
|
|
62838
|
-
const premiumPricing = await scrapePremiumRequestPricing();
|
|
62839
|
-
result.premiumPricingScraped = true;
|
|
62840
|
-
for (const pp of premiumPricing) {
|
|
62841
|
-
const key = normalizeModelName(pp.modelName);
|
|
62842
|
-
const existing = modelMap.get(key) ?? findClosestKey(modelMap, key);
|
|
62843
|
-
if (existing) {
|
|
62844
|
-
existing.premiumMultiplier = pp.multiplier;
|
|
62845
|
-
} else {
|
|
62846
|
-
modelMap.set(key, {
|
|
62847
|
-
id: key,
|
|
62848
|
-
displayName: pp.modelName,
|
|
62849
|
-
premiumMultiplier: pp.multiplier,
|
|
62850
|
-
available: true
|
|
62851
|
-
});
|
|
62852
|
-
}
|
|
62853
|
-
}
|
|
62854
|
-
} catch (error51) {
|
|
62855
|
-
const msg = error51 instanceof Error ? error51.message : String(error51);
|
|
62856
|
-
result.errors.push(`Premium pricing scrape failed: ${msg}`);
|
|
62857
|
-
logger2?.warn(`Premium pricing scrape failed: ${msg}`);
|
|
62858
|
-
}
|
|
62859
|
-
}
|
|
62860
|
-
async function scrapeCopilotPricingIntoMap(modelMap, result, logger2) {
|
|
62861
|
-
try {
|
|
62862
|
-
const copilotPricing = await scrapeCopilotPricing();
|
|
62863
|
-
result.copilotPricingScraped = true;
|
|
62864
|
-
for (const cp of copilotPricing) {
|
|
62865
|
-
const key = normalizeModelName(cp.modelName);
|
|
62866
|
-
const existing = modelMap.get(key) ?? findClosestKey(modelMap, key);
|
|
62867
|
-
if (existing) {
|
|
62868
|
-
existing.tokenInputMultiplier = cp.inputMultiplier;
|
|
62869
|
-
existing.tokenOutputMultiplier = cp.outputMultiplier;
|
|
62870
|
-
if (cp.cachedInputMultiplier !== null) {
|
|
62871
|
-
existing.cachedInputMultiplier = cp.cachedInputMultiplier;
|
|
62872
|
-
}
|
|
62873
|
-
} else {
|
|
62874
|
-
modelMap.set(key, {
|
|
62875
|
-
id: key,
|
|
62876
|
-
displayName: cp.modelName,
|
|
62877
|
-
tokenInputMultiplier: cp.inputMultiplier,
|
|
62878
|
-
tokenOutputMultiplier: cp.outputMultiplier,
|
|
62879
|
-
cachedInputMultiplier: cp.cachedInputMultiplier,
|
|
62880
|
-
available: true
|
|
62881
|
-
});
|
|
62882
|
-
}
|
|
62883
|
-
}
|
|
62884
|
-
} catch (error51) {
|
|
62885
|
-
const msg = error51 instanceof Error ? error51.message : String(error51);
|
|
62886
|
-
result.errors.push(`Copilot pricing scrape failed: ${msg}`);
|
|
62887
|
-
logger2?.warn(`Copilot pricing scrape failed: ${msg}`);
|
|
62888
|
-
}
|
|
62889
|
-
}
|
|
62890
|
-
async function refreshModelPricing(logger2) {
|
|
62891
|
-
const result = {
|
|
62892
|
-
modelsUpdated: 0,
|
|
62893
|
-
catalogFetched: false,
|
|
62894
|
-
tokenPricingScraped: false,
|
|
62895
|
-
premiumPricingScraped: false,
|
|
62896
|
-
copilotPricingScraped: false,
|
|
62897
|
-
errors: []
|
|
62898
|
-
};
|
|
62899
|
-
const modelMap = /* @__PURE__ */ new Map();
|
|
62900
|
-
await fetchCatalogIntoMap(modelMap, result, logger2);
|
|
62901
|
-
await scrapeTokenPricingIntoMap(modelMap, result, logger2);
|
|
62902
|
-
await scrapeCopilotPricingIntoMap(modelMap, result, logger2);
|
|
62903
|
-
await scrapePremiumPricingIntoMap(modelMap, result, logger2);
|
|
62904
|
-
if (!result.catalogFetched && !result.tokenPricingScraped && !result.premiumPricingScraped && !result.copilotPricingScraped) {
|
|
62905
|
-
logger2?.warn("All pricing sources failed, no models available");
|
|
62906
|
-
return result;
|
|
62907
|
-
}
|
|
62908
|
-
const db = await getDatabase();
|
|
62909
|
-
const now = nowIso();
|
|
62910
|
-
await db.execute("DELETE FROM model_pricing WHERE id LIKE '%/%'");
|
|
62911
|
-
for (const model of modelMap.values()) {
|
|
62912
|
-
if (model.tokenInputMultiplier == null) {
|
|
62913
|
-
continue;
|
|
62914
|
-
}
|
|
62915
|
-
const tier = computeTierFromMultiplier(model.premiumMultiplier ?? null);
|
|
62916
|
-
await upsertModel(db, {
|
|
62917
|
-
id: model.id,
|
|
62918
|
-
displayName: model.displayName,
|
|
62919
|
-
premiumMultiplier: model.premiumMultiplier ?? null,
|
|
62920
|
-
tokenInputMultiplier: model.tokenInputMultiplier,
|
|
62921
|
-
tokenOutputMultiplier: model.tokenOutputMultiplier ?? null,
|
|
62922
|
-
cachedInputMultiplier: model.cachedInputMultiplier ?? null,
|
|
62923
|
-
tier,
|
|
62924
|
-
available: model.available ?? true,
|
|
62925
|
-
updatedAt: now
|
|
62926
|
-
});
|
|
62927
|
-
result.modelsUpdated++;
|
|
62928
|
-
}
|
|
62929
|
-
return result;
|
|
62930
|
-
}
|
|
62931
|
-
async function getModelsForTier(tier) {
|
|
62932
|
-
const db = await getDatabase();
|
|
62933
|
-
const result = await db.execute({
|
|
62934
|
-
sql: "SELECT * FROM model_pricing WHERE tier = ? AND available = 1 ORDER BY premium_multiplier ASC NULLS LAST",
|
|
62935
|
-
args: [tier]
|
|
62936
|
-
});
|
|
62937
|
-
return result.rows.map(rowToModelPricing);
|
|
62938
|
-
}
|
|
62939
|
-
async function getCheapestInTier(tier) {
|
|
62940
|
-
const models = await getModelsForTier(tier);
|
|
62941
|
-
return models[0] ?? null;
|
|
62942
|
-
}
|
|
62943
|
-
async function getModelPricing(modelId) {
|
|
62944
|
-
const db = await getDatabase();
|
|
62945
|
-
const result = await db.execute({
|
|
62946
|
-
sql: "SELECT * FROM model_pricing WHERE id = ?",
|
|
62947
|
-
args: [modelId]
|
|
62948
|
-
});
|
|
62949
|
-
if (result.rows.length > 0) {
|
|
62950
|
-
return rowToModelPricing(result.rows[0]);
|
|
62951
|
-
}
|
|
62952
|
-
const allModels = await db.execute(
|
|
62953
|
-
"SELECT * FROM model_pricing WHERE token_input_multiplier IS NOT NULL ORDER BY length(id) DESC"
|
|
62954
|
-
);
|
|
62955
|
-
for (const row of allModels.rows) {
|
|
62956
|
-
const storedId = asString(row.id);
|
|
62957
|
-
if (modelId.startsWith(storedId) || storedId.startsWith(modelId)) {
|
|
62958
|
-
return rowToModelPricing(row);
|
|
62959
|
-
}
|
|
62960
|
-
}
|
|
62961
|
-
return null;
|
|
62962
|
-
}
|
|
62963
|
-
async function getCheapestAvailableModel() {
|
|
62964
|
-
const tiers = ["trivial", "fast", "standard", "premium", "ultra"];
|
|
62965
|
-
for (const tier of tiers) {
|
|
62966
|
-
const model = await getCheapestInTier(tier);
|
|
62967
|
-
if (model) {
|
|
62968
|
-
return model;
|
|
62969
|
-
}
|
|
62970
|
-
}
|
|
62971
|
-
return null;
|
|
62972
|
-
}
|
|
62973
|
-
function calculateTokenUnitCost(inputTokens, outputTokens, inputMultiplier, outputMultiplier) {
|
|
62974
|
-
if (inputMultiplier === null || outputMultiplier === null) {
|
|
62975
|
-
return 0;
|
|
62976
|
-
}
|
|
62977
|
-
const tokenUnits = inputTokens * inputMultiplier + outputTokens * outputMultiplier;
|
|
62978
|
-
return tokenUnits * TOKEN_UNIT_PRICE;
|
|
62979
|
-
}
|
|
62980
|
-
function getNextTierUp(tier) {
|
|
62981
|
-
const order = ["trivial", "fast", "standard", "premium", "ultra"];
|
|
62982
|
-
const idx = order.indexOf(tier);
|
|
62983
|
-
if (idx < 0 || idx >= order.length - 1) {
|
|
62984
|
-
return null;
|
|
62985
|
-
}
|
|
62986
|
-
return order[idx + 1];
|
|
62987
|
-
}
|
|
62988
|
-
async function upsertModel(db, model) {
|
|
62989
|
-
await db.execute({
|
|
62990
|
-
sql: `INSERT INTO model_pricing (id, display_name, premium_multiplier, token_input_multiplier, token_output_multiplier, cached_input_multiplier, tier, available, updated_at)
|
|
62991
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
62992
|
-
ON CONFLICT(id) DO UPDATE SET
|
|
62993
|
-
display_name = excluded.display_name,
|
|
62994
|
-
premium_multiplier = COALESCE(excluded.premium_multiplier, model_pricing.premium_multiplier),
|
|
62995
|
-
token_input_multiplier = COALESCE(excluded.token_input_multiplier, model_pricing.token_input_multiplier),
|
|
62996
|
-
token_output_multiplier = COALESCE(excluded.token_output_multiplier, model_pricing.token_output_multiplier),
|
|
62997
|
-
cached_input_multiplier = COALESCE(excluded.cached_input_multiplier, model_pricing.cached_input_multiplier),
|
|
62998
|
-
tier = excluded.tier,
|
|
62999
|
-
available = excluded.available,
|
|
63000
|
-
updated_at = excluded.updated_at`,
|
|
63001
|
-
args: [
|
|
63002
|
-
model.id,
|
|
63003
|
-
model.displayName,
|
|
63004
|
-
model.premiumMultiplier,
|
|
63005
|
-
model.tokenInputMultiplier,
|
|
63006
|
-
model.tokenOutputMultiplier,
|
|
63007
|
-
model.cachedInputMultiplier,
|
|
63008
|
-
model.tier,
|
|
63009
|
-
model.available ? 1 : 0,
|
|
63010
|
-
model.updatedAt
|
|
63011
|
-
]
|
|
63012
|
-
});
|
|
63013
|
-
}
|
|
63014
|
-
function rowToModelPricing(row) {
|
|
63015
|
-
return {
|
|
63016
|
-
id: stripVendorPrefix(asString(row.id)),
|
|
63017
|
-
displayName: asString(row.display_name),
|
|
63018
|
-
premiumMultiplier: asNullableNumber(row.premium_multiplier),
|
|
63019
|
-
tokenInputMultiplier: asNullableNumber(row.token_input_multiplier),
|
|
63020
|
-
tokenOutputMultiplier: asNullableNumber(row.token_output_multiplier),
|
|
63021
|
-
cachedInputMultiplier: asNullableNumber(row.cached_input_multiplier),
|
|
63022
|
-
tier: asString(row.tier),
|
|
63023
|
-
available: asNumber(row.available) === 1,
|
|
63024
|
-
updatedAt: asString(row.updated_at)
|
|
63025
|
-
};
|
|
63026
|
-
}
|
|
63027
|
-
function findClosestKey(map2, targetKey) {
|
|
63028
|
-
for (const [key, value] of map2) {
|
|
63029
|
-
if (key.includes(targetKey) || targetKey.includes(key)) {
|
|
63030
|
-
return value;
|
|
63031
|
-
}
|
|
63032
|
-
}
|
|
63033
|
-
return void 0;
|
|
63034
|
-
}
|
|
63035
|
-
var init_registry = __esm({
|
|
63036
|
-
"packages/daemon/src/models/registry.ts"() {
|
|
63037
|
-
"use strict";
|
|
63038
|
-
init_db();
|
|
63039
|
-
init_catalog();
|
|
63040
|
-
init_pricing_scraper();
|
|
63041
|
-
init_types();
|
|
63042
|
-
}
|
|
63043
|
-
});
|
|
63044
|
-
|
|
63045
62209
|
// node_modules/grammy/out/filter.js
|
|
63046
62210
|
var require_filter = __commonJS({
|
|
63047
62211
|
"node_modules/grammy/out/filter.js"(exports2) {
|
|
@@ -77768,11 +76932,344 @@ var TypedEventBus = class extends EventEmitter {
|
|
|
77768
76932
|
};
|
|
77769
76933
|
var eventBus = new TypedEventBus();
|
|
77770
76934
|
|
|
77771
|
-
// packages/daemon/src/store/
|
|
77772
|
-
|
|
76935
|
+
// packages/daemon/src/store/db.ts
|
|
76936
|
+
init_paths();
|
|
76937
|
+
import { mkdir } from "node:fs/promises";
|
|
76938
|
+
import { dirname } from "node:path";
|
|
76939
|
+
import { pathToFileURL } from "node:url";
|
|
76940
|
+
import { createClient } from "@libsql/client";
|
|
76941
|
+
var MIGRATIONS = [
|
|
76942
|
+
{
|
|
76943
|
+
version: 1,
|
|
76944
|
+
name: "create-store-schema",
|
|
76945
|
+
statements: [
|
|
76946
|
+
`CREATE TABLE IF NOT EXISTS squads (
|
|
76947
|
+
id TEXT PRIMARY KEY,
|
|
76948
|
+
name TEXT NOT NULL,
|
|
76949
|
+
repo_url TEXT NOT NULL,
|
|
76950
|
+
repo_owner TEXT NOT NULL,
|
|
76951
|
+
repo_name TEXT NOT NULL,
|
|
76952
|
+
status TEXT NOT NULL,
|
|
76953
|
+
config TEXT NOT NULL,
|
|
76954
|
+
created_at TEXT NOT NULL,
|
|
76955
|
+
updated_at TEXT NOT NULL,
|
|
76956
|
+
UNIQUE (repo_owner, repo_name)
|
|
76957
|
+
)`,
|
|
76958
|
+
`CREATE TABLE IF NOT EXISTS squad_members (
|
|
76959
|
+
id TEXT PRIMARY KEY,
|
|
76960
|
+
squad_id TEXT NOT NULL REFERENCES squads(id) ON DELETE CASCADE,
|
|
76961
|
+
role TEXT NOT NULL,
|
|
76962
|
+
name TEXT NOT NULL,
|
|
76963
|
+
system_prompt TEXT NOT NULL,
|
|
76964
|
+
model TEXT,
|
|
76965
|
+
created_at TEXT NOT NULL
|
|
76966
|
+
)`,
|
|
76967
|
+
`CREATE TABLE IF NOT EXISTS objectives (
|
|
76968
|
+
id TEXT PRIMARY KEY,
|
|
76969
|
+
squad_id TEXT NOT NULL REFERENCES squads(id) ON DELETE CASCADE,
|
|
76970
|
+
description TEXT NOT NULL,
|
|
76971
|
+
status TEXT NOT NULL,
|
|
76972
|
+
plan TEXT,
|
|
76973
|
+
revision_count INTEGER NOT NULL DEFAULT 0,
|
|
76974
|
+
branch TEXT,
|
|
76975
|
+
pr_url TEXT,
|
|
76976
|
+
created_at TEXT NOT NULL,
|
|
76977
|
+
updated_at TEXT NOT NULL
|
|
76978
|
+
)`,
|
|
76979
|
+
`CREATE TABLE IF NOT EXISTS tasks (
|
|
76980
|
+
id TEXT PRIMARY KEY,
|
|
76981
|
+
objective_id TEXT NOT NULL REFERENCES objectives(id) ON DELETE CASCADE,
|
|
76982
|
+
assignee_id TEXT REFERENCES squad_members(id) ON DELETE SET NULL,
|
|
76983
|
+
title TEXT NOT NULL,
|
|
76984
|
+
description TEXT NOT NULL,
|
|
76985
|
+
status TEXT NOT NULL,
|
|
76986
|
+
result TEXT,
|
|
76987
|
+
created_at TEXT NOT NULL,
|
|
76988
|
+
updated_at TEXT NOT NULL
|
|
76989
|
+
)`,
|
|
76990
|
+
`CREATE TABLE IF NOT EXISTS conversations (
|
|
76991
|
+
id TEXT PRIMARY KEY,
|
|
76992
|
+
title TEXT,
|
|
76993
|
+
source TEXT NOT NULL,
|
|
76994
|
+
created_at TEXT NOT NULL,
|
|
76995
|
+
updated_at TEXT NOT NULL
|
|
76996
|
+
)`,
|
|
76997
|
+
`CREATE TABLE IF NOT EXISTS messages (
|
|
76998
|
+
id TEXT PRIMARY KEY,
|
|
76999
|
+
conversation_id TEXT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
|
|
77000
|
+
role TEXT NOT NULL,
|
|
77001
|
+
content TEXT NOT NULL,
|
|
77002
|
+
model TEXT,
|
|
77003
|
+
input_tokens INTEGER,
|
|
77004
|
+
output_tokens INTEGER,
|
|
77005
|
+
created_at TEXT NOT NULL
|
|
77006
|
+
)`,
|
|
77007
|
+
`CREATE TABLE IF NOT EXISTS inbox (
|
|
77008
|
+
id TEXT PRIMARY KEY,
|
|
77009
|
+
squad_id TEXT REFERENCES squads(id) ON DELETE SET NULL,
|
|
77010
|
+
objective_id TEXT REFERENCES objectives(id) ON DELETE SET NULL,
|
|
77011
|
+
type TEXT NOT NULL,
|
|
77012
|
+
title TEXT NOT NULL,
|
|
77013
|
+
content TEXT NOT NULL,
|
|
77014
|
+
status TEXT NOT NULL,
|
|
77015
|
+
reply TEXT,
|
|
77016
|
+
created_at TEXT NOT NULL,
|
|
77017
|
+
updated_at TEXT NOT NULL
|
|
77018
|
+
)`,
|
|
77019
|
+
`CREATE TABLE IF NOT EXISTS schedules (
|
|
77020
|
+
id TEXT PRIMARY KEY,
|
|
77021
|
+
name TEXT NOT NULL,
|
|
77022
|
+
cron_expression TEXT NOT NULL,
|
|
77023
|
+
prompt TEXT NOT NULL,
|
|
77024
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
77025
|
+
last_run_at TEXT,
|
|
77026
|
+
next_run_at TEXT,
|
|
77027
|
+
created_at TEXT NOT NULL,
|
|
77028
|
+
updated_at TEXT NOT NULL
|
|
77029
|
+
)`,
|
|
77030
|
+
`CREATE TABLE IF NOT EXISTS token_usage (
|
|
77031
|
+
id TEXT PRIMARY KEY,
|
|
77032
|
+
squad_id TEXT REFERENCES squads(id) ON DELETE SET NULL,
|
|
77033
|
+
agent_id TEXT,
|
|
77034
|
+
model TEXT NOT NULL,
|
|
77035
|
+
input_tokens INTEGER NOT NULL,
|
|
77036
|
+
output_tokens INTEGER NOT NULL,
|
|
77037
|
+
cost REAL NOT NULL,
|
|
77038
|
+
created_at TEXT NOT NULL
|
|
77039
|
+
)`,
|
|
77040
|
+
`CREATE TABLE IF NOT EXISTS activity (
|
|
77041
|
+
id TEXT PRIMARY KEY,
|
|
77042
|
+
squad_id TEXT REFERENCES squads(id) ON DELETE SET NULL,
|
|
77043
|
+
objective_id TEXT REFERENCES objectives(id) ON DELETE SET NULL,
|
|
77044
|
+
event TEXT NOT NULL,
|
|
77045
|
+
description TEXT NOT NULL,
|
|
77046
|
+
metadata TEXT,
|
|
77047
|
+
created_at TEXT NOT NULL
|
|
77048
|
+
)`,
|
|
77049
|
+
`CREATE TABLE IF NOT EXISTS agent_history (
|
|
77050
|
+
id TEXT PRIMARY KEY,
|
|
77051
|
+
agent_id TEXT NOT NULL,
|
|
77052
|
+
squad_id TEXT REFERENCES squads(id) ON DELETE SET NULL,
|
|
77053
|
+
content TEXT NOT NULL,
|
|
77054
|
+
created_at TEXT NOT NULL
|
|
77055
|
+
)`,
|
|
77056
|
+
`CREATE TABLE IF NOT EXISTS settings (
|
|
77057
|
+
key TEXT PRIMARY KEY,
|
|
77058
|
+
value TEXT
|
|
77059
|
+
)`,
|
|
77060
|
+
"CREATE INDEX IF NOT EXISTS idx_squad_members_squad_id ON squad_members(squad_id)",
|
|
77061
|
+
"CREATE INDEX IF NOT EXISTS idx_objectives_squad_id ON objectives(squad_id)",
|
|
77062
|
+
"CREATE INDEX IF NOT EXISTS idx_objectives_status ON objectives(status)",
|
|
77063
|
+
"CREATE INDEX IF NOT EXISTS idx_tasks_objective_id ON tasks(objective_id)",
|
|
77064
|
+
"CREATE INDEX IF NOT EXISTS idx_tasks_assignee_id ON tasks(assignee_id)",
|
|
77065
|
+
"CREATE INDEX IF NOT EXISTS idx_messages_conversation_id_created_at ON messages(conversation_id, created_at)",
|
|
77066
|
+
"CREATE INDEX IF NOT EXISTS idx_inbox_status_created_at ON inbox(status, created_at)",
|
|
77067
|
+
"CREATE INDEX IF NOT EXISTS idx_inbox_squad_id ON inbox(squad_id)",
|
|
77068
|
+
"CREATE INDEX IF NOT EXISTS idx_inbox_objective_id ON inbox(objective_id)",
|
|
77069
|
+
"CREATE INDEX IF NOT EXISTS idx_schedules_enabled_next_run_at ON schedules(enabled, next_run_at)",
|
|
77070
|
+
"CREATE INDEX IF NOT EXISTS idx_token_usage_created_at ON token_usage(created_at)",
|
|
77071
|
+
"CREATE INDEX IF NOT EXISTS idx_token_usage_squad_id ON token_usage(squad_id)",
|
|
77072
|
+
"CREATE INDEX IF NOT EXISTS idx_token_usage_agent_id ON token_usage(agent_id)",
|
|
77073
|
+
"CREATE INDEX IF NOT EXISTS idx_token_usage_model ON token_usage(model)",
|
|
77074
|
+
"CREATE INDEX IF NOT EXISTS idx_activity_created_at ON activity(created_at)",
|
|
77075
|
+
"CREATE INDEX IF NOT EXISTS idx_activity_squad_id ON activity(squad_id)",
|
|
77076
|
+
"CREATE INDEX IF NOT EXISTS idx_activity_objective_id ON activity(objective_id)",
|
|
77077
|
+
"CREATE INDEX IF NOT EXISTS idx_agent_history_agent_id_created_at ON agent_history(agent_id, created_at)"
|
|
77078
|
+
]
|
|
77079
|
+
},
|
|
77080
|
+
{
|
|
77081
|
+
version: 2,
|
|
77082
|
+
name: "add-model-pricing-and-dual-costs",
|
|
77083
|
+
statements: [
|
|
77084
|
+
`CREATE TABLE IF NOT EXISTS model_pricing (
|
|
77085
|
+
id TEXT PRIMARY KEY,
|
|
77086
|
+
display_name TEXT NOT NULL,
|
|
77087
|
+
premium_multiplier REAL,
|
|
77088
|
+
token_input_multiplier REAL,
|
|
77089
|
+
token_output_multiplier REAL,
|
|
77090
|
+
cached_input_multiplier REAL,
|
|
77091
|
+
tier TEXT NOT NULL,
|
|
77092
|
+
available INTEGER NOT NULL DEFAULT 1,
|
|
77093
|
+
updated_at TEXT NOT NULL
|
|
77094
|
+
)`,
|
|
77095
|
+
"CREATE INDEX IF NOT EXISTS idx_model_pricing_tier ON model_pricing(tier)",
|
|
77096
|
+
"CREATE INDEX IF NOT EXISTS idx_model_pricing_available ON model_pricing(available)",
|
|
77097
|
+
"ALTER TABLE token_usage ADD COLUMN premium_request_cost REAL",
|
|
77098
|
+
"ALTER TABLE token_usage ADD COLUMN token_unit_cost REAL"
|
|
77099
|
+
]
|
|
77100
|
+
},
|
|
77101
|
+
{
|
|
77102
|
+
version: 3,
|
|
77103
|
+
name: "add-squad-instances",
|
|
77104
|
+
statements: [
|
|
77105
|
+
`CREATE TABLE IF NOT EXISTS squad_instances (
|
|
77106
|
+
id TEXT PRIMARY KEY,
|
|
77107
|
+
squad_id TEXT NOT NULL REFERENCES squads(id) ON DELETE CASCADE,
|
|
77108
|
+
objective_id TEXT REFERENCES objectives(id) ON DELETE SET NULL,
|
|
77109
|
+
status TEXT NOT NULL DEFAULT 'queued',
|
|
77110
|
+
branch TEXT,
|
|
77111
|
+
worktree_path TEXT,
|
|
77112
|
+
created_at TEXT NOT NULL,
|
|
77113
|
+
started_at TEXT,
|
|
77114
|
+
completed_at TEXT,
|
|
77115
|
+
error TEXT
|
|
77116
|
+
)`,
|
|
77117
|
+
"CREATE INDEX IF NOT EXISTS idx_squad_instances_squad_status ON squad_instances(squad_id, status)",
|
|
77118
|
+
"CREATE INDEX IF NOT EXISTS idx_squad_instances_status ON squad_instances(status)",
|
|
77119
|
+
"CREATE INDEX IF NOT EXISTS idx_squad_instances_objective_id ON squad_instances(objective_id)"
|
|
77120
|
+
]
|
|
77121
|
+
},
|
|
77122
|
+
{
|
|
77123
|
+
version: 4,
|
|
77124
|
+
name: "denormalize-usage-names",
|
|
77125
|
+
statements: [
|
|
77126
|
+
"ALTER TABLE token_usage ADD COLUMN squad_name TEXT",
|
|
77127
|
+
"ALTER TABLE token_usage ADD COLUMN agent_name TEXT",
|
|
77128
|
+
`UPDATE token_usage SET
|
|
77129
|
+
squad_name = (SELECT s.name FROM squads s WHERE s.id = token_usage.squad_id),
|
|
77130
|
+
agent_name = (SELECT sm.name FROM squad_members sm WHERE sm.id = token_usage.agent_id)
|
|
77131
|
+
WHERE squad_id IS NOT NULL OR agent_id IS NOT NULL`
|
|
77132
|
+
]
|
|
77133
|
+
},
|
|
77134
|
+
{
|
|
77135
|
+
version: 5,
|
|
77136
|
+
name: "add-squad-soft-delete",
|
|
77137
|
+
statements: ["ALTER TABLE squads ADD COLUMN deleted_at TEXT"]
|
|
77138
|
+
}
|
|
77139
|
+
];
|
|
77140
|
+
var client = null;
|
|
77141
|
+
var initPromise = null;
|
|
77142
|
+
var defaultConnectionOptions = {};
|
|
77143
|
+
var generateId = () => crypto.randomUUID();
|
|
77144
|
+
var nowIso = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
77145
|
+
function asString(value) {
|
|
77146
|
+
if (typeof value === "string") {
|
|
77147
|
+
return value;
|
|
77148
|
+
}
|
|
77149
|
+
if (value === null || value === void 0) {
|
|
77150
|
+
throw new Error("Expected string value but received null or undefined");
|
|
77151
|
+
}
|
|
77152
|
+
return String(value);
|
|
77153
|
+
}
|
|
77154
|
+
function asNullableString(value) {
|
|
77155
|
+
if (value === null || value === void 0) {
|
|
77156
|
+
return null;
|
|
77157
|
+
}
|
|
77158
|
+
return typeof value === "string" ? value : String(value);
|
|
77159
|
+
}
|
|
77160
|
+
function asNumber(value) {
|
|
77161
|
+
if (typeof value === "number") {
|
|
77162
|
+
return value;
|
|
77163
|
+
}
|
|
77164
|
+
if (typeof value === "bigint") {
|
|
77165
|
+
return Number(value);
|
|
77166
|
+
}
|
|
77167
|
+
if (typeof value === "string") {
|
|
77168
|
+
return Number(value);
|
|
77169
|
+
}
|
|
77170
|
+
throw new Error(`Expected numeric value but received ${typeof value}`);
|
|
77171
|
+
}
|
|
77172
|
+
function asNullableNumber(value) {
|
|
77173
|
+
if (value === null || value === void 0) {
|
|
77174
|
+
return null;
|
|
77175
|
+
}
|
|
77176
|
+
return asNumber(value);
|
|
77177
|
+
}
|
|
77178
|
+
function asBoolean(value) {
|
|
77179
|
+
return asNumber(value) === 1;
|
|
77180
|
+
}
|
|
77181
|
+
function toSqliteBoolean(value) {
|
|
77182
|
+
return value ? 1 : 0;
|
|
77183
|
+
}
|
|
77184
|
+
function parseJson(value) {
|
|
77185
|
+
if (typeof value !== "string") {
|
|
77186
|
+
return value;
|
|
77187
|
+
}
|
|
77188
|
+
return JSON.parse(value);
|
|
77189
|
+
}
|
|
77190
|
+
function serializeJson(value) {
|
|
77191
|
+
return JSON.stringify(value);
|
|
77192
|
+
}
|
|
77193
|
+
async function initDatabase() {
|
|
77194
|
+
if (client && !client.closed) {
|
|
77195
|
+
return client;
|
|
77196
|
+
}
|
|
77197
|
+
if (initPromise) {
|
|
77198
|
+
return initPromise;
|
|
77199
|
+
}
|
|
77200
|
+
initPromise = initializeDatabase(defaultConnectionOptions);
|
|
77201
|
+
try {
|
|
77202
|
+
client = await initPromise;
|
|
77203
|
+
return client;
|
|
77204
|
+
} finally {
|
|
77205
|
+
initPromise = null;
|
|
77206
|
+
}
|
|
77207
|
+
}
|
|
77208
|
+
async function getDatabase() {
|
|
77209
|
+
return initDatabase();
|
|
77210
|
+
}
|
|
77211
|
+
async function initializeDatabase(options2 = {}) {
|
|
77212
|
+
const url2 = await resolveDatabaseUrl(options2);
|
|
77213
|
+
const databaseClient = createClient({ url: url2 });
|
|
77214
|
+
await databaseClient.execute("PRAGMA foreign_keys = ON");
|
|
77215
|
+
await databaseClient.execute("PRAGMA journal_mode = WAL");
|
|
77216
|
+
await ensureMigrationTable(databaseClient);
|
|
77217
|
+
await applyMigrations(databaseClient);
|
|
77218
|
+
return databaseClient;
|
|
77219
|
+
}
|
|
77220
|
+
async function resolveDatabaseUrl(options2) {
|
|
77221
|
+
if (options2.url) {
|
|
77222
|
+
return options2.url;
|
|
77223
|
+
}
|
|
77224
|
+
const databasePath = options2.path ?? DB_PATH;
|
|
77225
|
+
await mkdir(dirname(databasePath), { recursive: true });
|
|
77226
|
+
return pathToFileURL(databasePath).href;
|
|
77227
|
+
}
|
|
77228
|
+
async function ensureMigrationTable(databaseClient) {
|
|
77229
|
+
await databaseClient.executeMultiple(`
|
|
77230
|
+
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
77231
|
+
version INTEGER PRIMARY KEY,
|
|
77232
|
+
name TEXT NOT NULL,
|
|
77233
|
+
applied_at TEXT NOT NULL
|
|
77234
|
+
);
|
|
77235
|
+
`);
|
|
77236
|
+
}
|
|
77237
|
+
async function applyMigrations(databaseClient) {
|
|
77238
|
+
const appliedVersions = await getAppliedVersions(databaseClient);
|
|
77239
|
+
for (const migration of MIGRATIONS) {
|
|
77240
|
+
if (appliedVersions.has(migration.version)) {
|
|
77241
|
+
continue;
|
|
77242
|
+
}
|
|
77243
|
+
const transaction = await databaseClient.transaction("write");
|
|
77244
|
+
try {
|
|
77245
|
+
for (const statement of migration.statements) {
|
|
77246
|
+
await transaction.execute(statement);
|
|
77247
|
+
}
|
|
77248
|
+
await transaction.execute({
|
|
77249
|
+
sql: "INSERT INTO schema_migrations (version, name, applied_at) VALUES (?, ?, ?)",
|
|
77250
|
+
args: [migration.version, migration.name, nowIso()]
|
|
77251
|
+
});
|
|
77252
|
+
await transaction.commit();
|
|
77253
|
+
} catch (error51) {
|
|
77254
|
+
if (!transaction.closed) {
|
|
77255
|
+
await transaction.rollback();
|
|
77256
|
+
}
|
|
77257
|
+
throw error51;
|
|
77258
|
+
} finally {
|
|
77259
|
+
if (!transaction.closed) {
|
|
77260
|
+
transaction.close();
|
|
77261
|
+
}
|
|
77262
|
+
}
|
|
77263
|
+
}
|
|
77264
|
+
}
|
|
77265
|
+
async function getAppliedVersions(databaseClient) {
|
|
77266
|
+
const result = await databaseClient.execute(
|
|
77267
|
+
"SELECT version FROM schema_migrations ORDER BY version ASC"
|
|
77268
|
+
);
|
|
77269
|
+
return new Set(result.rows.map((row) => asNumber(row.version)));
|
|
77270
|
+
}
|
|
77773
77271
|
|
|
77774
77272
|
// packages/daemon/src/store/squads.ts
|
|
77775
|
-
init_db();
|
|
77776
77273
|
async function createSquad(data, db) {
|
|
77777
77274
|
const database = db ?? await getDatabase();
|
|
77778
77275
|
const timestamp = nowIso();
|
|
@@ -78028,7 +77525,6 @@ function mapMember(row) {
|
|
|
78028
77525
|
}
|
|
78029
77526
|
|
|
78030
77527
|
// packages/daemon/src/store/conversations.ts
|
|
78031
|
-
init_db();
|
|
78032
77528
|
async function createConversation(source, title, db) {
|
|
78033
77529
|
const database = db ?? await getDatabase();
|
|
78034
77530
|
const createdAt = nowIso();
|
|
@@ -78147,7 +77643,6 @@ function mapMessage(row) {
|
|
|
78147
77643
|
}
|
|
78148
77644
|
|
|
78149
77645
|
// packages/daemon/src/store/inbox.ts
|
|
78150
|
-
init_db();
|
|
78151
77646
|
async function createInboxItem(data, db) {
|
|
78152
77647
|
const database = db ?? await getDatabase();
|
|
78153
77648
|
const timestamp = nowIso();
|
|
@@ -78251,7 +77746,6 @@ function mapInboxItem(row) {
|
|
|
78251
77746
|
|
|
78252
77747
|
// packages/daemon/src/store/schedules.ts
|
|
78253
77748
|
var import_cron_parser = __toESM(require_dist(), 1);
|
|
78254
|
-
init_db();
|
|
78255
77749
|
var parseExpression = import_cron_parser.CronExpressionParser.parse;
|
|
78256
77750
|
async function createSchedule(data, db) {
|
|
78257
77751
|
const database = db ?? await getDatabase();
|
|
@@ -78390,7 +77884,6 @@ function mapSchedule(row) {
|
|
|
78390
77884
|
}
|
|
78391
77885
|
|
|
78392
77886
|
// packages/daemon/src/store/token-usage.ts
|
|
78393
|
-
init_db();
|
|
78394
77887
|
async function recordUsage(data, db) {
|
|
78395
77888
|
const database = db ?? await getDatabase();
|
|
78396
77889
|
const usage = {
|
|
@@ -78520,7 +78013,6 @@ async function getUsageRecords(params = {}, db) {
|
|
|
78520
78013
|
}
|
|
78521
78014
|
|
|
78522
78015
|
// packages/daemon/src/store/activity.ts
|
|
78523
|
-
init_db();
|
|
78524
78016
|
async function logActivity(data, db) {
|
|
78525
78017
|
const database = db ?? await getDatabase();
|
|
78526
78018
|
const activity = {
|
|
@@ -78576,7 +78068,6 @@ function mapActivity(row) {
|
|
|
78576
78068
|
}
|
|
78577
78069
|
|
|
78578
78070
|
// packages/daemon/src/store/agent-history.ts
|
|
78579
|
-
init_db();
|
|
78580
78071
|
async function appendHistory(agentId, squadId, content, db) {
|
|
78581
78072
|
const database = db ?? await getDatabase();
|
|
78582
78073
|
const entry = {
|
|
@@ -78612,7 +78103,6 @@ function mapAgentHistory(row) {
|
|
|
78612
78103
|
}
|
|
78613
78104
|
|
|
78614
78105
|
// packages/daemon/src/store/objectives.ts
|
|
78615
|
-
init_db();
|
|
78616
78106
|
async function createObjective(squadId, description, db) {
|
|
78617
78107
|
const database = db ?? await getDatabase();
|
|
78618
78108
|
const timestamp = nowIso();
|
|
@@ -78805,7 +78295,6 @@ function mapTask(row) {
|
|
|
78805
78295
|
}
|
|
78806
78296
|
|
|
78807
78297
|
// packages/daemon/src/store/instances.ts
|
|
78808
|
-
init_db();
|
|
78809
78298
|
async function createInstance(input, db) {
|
|
78810
78299
|
const database = db ?? await getDatabase();
|
|
78811
78300
|
const instance = {
|
|
@@ -80114,7 +79603,6 @@ function emitInstanceEvent(event, instance) {
|
|
|
80114
79603
|
}
|
|
80115
79604
|
|
|
80116
79605
|
// packages/daemon/src/api/routes/squads.ts
|
|
80117
|
-
init_db();
|
|
80118
79606
|
var router7 = (0, import_express7.Router)();
|
|
80119
79607
|
var DEFAULT_CONFIG = {
|
|
80120
79608
|
prMode: "draft-pr",
|
|
@@ -81373,10 +80861,471 @@ function ensureDataDirectories() {
|
|
|
81373
80861
|
}
|
|
81374
80862
|
}
|
|
81375
80863
|
|
|
81376
|
-
// packages/daemon/src/models/
|
|
81377
|
-
|
|
81378
|
-
|
|
81379
|
-
|
|
80864
|
+
// packages/daemon/src/models/catalog.ts
|
|
80865
|
+
import { execFileSync } from "node:child_process";
|
|
80866
|
+
var CATALOG_URL = "https://models.github.ai/catalog/models";
|
|
80867
|
+
function resolveGitHubToken() {
|
|
80868
|
+
const envToken = process.env.GITHUB_TOKEN?.trim();
|
|
80869
|
+
if (envToken && envToken.length > 0) {
|
|
80870
|
+
return envToken;
|
|
80871
|
+
}
|
|
80872
|
+
try {
|
|
80873
|
+
const token = execFileSync("gh", ["auth", "token"], {
|
|
80874
|
+
encoding: "utf8",
|
|
80875
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
80876
|
+
}).trim();
|
|
80877
|
+
return token.length > 0 ? token : void 0;
|
|
80878
|
+
} catch {
|
|
80879
|
+
return void 0;
|
|
80880
|
+
}
|
|
80881
|
+
}
|
|
80882
|
+
async function fetchModelCatalog() {
|
|
80883
|
+
const token = resolveGitHubToken();
|
|
80884
|
+
if (!token) {
|
|
80885
|
+
throw new Error("No GitHub token available for model catalog fetch");
|
|
80886
|
+
}
|
|
80887
|
+
const response = await fetch(CATALOG_URL, {
|
|
80888
|
+
headers: {
|
|
80889
|
+
Accept: "application/json",
|
|
80890
|
+
Authorization: `Bearer ${token}`,
|
|
80891
|
+
"X-GitHub-Api-Version": "2024-12-01"
|
|
80892
|
+
}
|
|
80893
|
+
});
|
|
80894
|
+
if (!response.ok) {
|
|
80895
|
+
throw new Error(`Model catalog fetch failed: ${response.status} ${response.statusText}`);
|
|
80896
|
+
}
|
|
80897
|
+
const data = await response.json();
|
|
80898
|
+
if (!Array.isArray(data)) {
|
|
80899
|
+
throw new Error("Model catalog response is not an array");
|
|
80900
|
+
}
|
|
80901
|
+
const models = [];
|
|
80902
|
+
for (const entry of data) {
|
|
80903
|
+
const id = entry.id ?? entry.name;
|
|
80904
|
+
const displayName = entry.friendly_name ?? entry.name ?? id;
|
|
80905
|
+
if (id && typeof id === "string") {
|
|
80906
|
+
models.push({ id, displayName: displayName ?? id });
|
|
80907
|
+
}
|
|
80908
|
+
}
|
|
80909
|
+
return models;
|
|
80910
|
+
}
|
|
80911
|
+
|
|
80912
|
+
// packages/daemon/src/models/pricing-scraper.ts
|
|
80913
|
+
var TOKEN_UNIT_COSTS_URL = "https://docs.github.com/en/billing/reference/costs-for-github-models";
|
|
80914
|
+
var PREMIUM_MULTIPLIERS_URL = "https://docs.github.com/en/copilot/reference/copilot-billing/request-based-billing-legacy/model-multipliers-for-annual-plans";
|
|
80915
|
+
var COPILOT_PRICING_URL = "https://docs.github.com/api/article/body?pathname=/en/copilot/reference/copilot-billing/models-and-pricing";
|
|
80916
|
+
var PRICE_TO_MULTIPLIER = 0.1;
|
|
80917
|
+
async function scrapeTokenUnitPricing() {
|
|
80918
|
+
const html = await fetchPage(TOKEN_UNIT_COSTS_URL);
|
|
80919
|
+
return parseTokenUnitTable(html);
|
|
80920
|
+
}
|
|
80921
|
+
async function scrapeCopilotPricing() {
|
|
80922
|
+
const markdown = await fetchMarkdown(COPILOT_PRICING_URL);
|
|
80923
|
+
return parseCopilotPricingMarkdown(markdown);
|
|
80924
|
+
}
|
|
80925
|
+
async function scrapePremiumRequestPricing() {
|
|
80926
|
+
const html = await fetchPage(PREMIUM_MULTIPLIERS_URL);
|
|
80927
|
+
return parsePremiumMultiplierTable(html);
|
|
80928
|
+
}
|
|
80929
|
+
async function fetchPage(url2) {
|
|
80930
|
+
const response = await fetch(url2, {
|
|
80931
|
+
headers: {
|
|
80932
|
+
Accept: "text/html",
|
|
80933
|
+
"User-Agent": "IO-Daemon/4.0 (pricing-refresh)"
|
|
80934
|
+
},
|
|
80935
|
+
redirect: "follow"
|
|
80936
|
+
});
|
|
80937
|
+
if (!response.ok) {
|
|
80938
|
+
throw new Error(`Failed to fetch ${url2}: ${response.status} ${response.statusText}`);
|
|
80939
|
+
}
|
|
80940
|
+
return response.text();
|
|
80941
|
+
}
|
|
80942
|
+
async function fetchMarkdown(url2) {
|
|
80943
|
+
const response = await fetch(url2, {
|
|
80944
|
+
headers: {
|
|
80945
|
+
Accept: "text/markdown, text/plain, */*",
|
|
80946
|
+
"User-Agent": "IO-Daemon/4.0 (pricing-refresh)"
|
|
80947
|
+
},
|
|
80948
|
+
redirect: "follow"
|
|
80949
|
+
});
|
|
80950
|
+
if (!response.ok) {
|
|
80951
|
+
throw new Error(`Failed to fetch ${url2}: ${response.status} ${response.statusText}`);
|
|
80952
|
+
}
|
|
80953
|
+
return response.text();
|
|
80954
|
+
}
|
|
80955
|
+
function parseTokenUnitTable(html) {
|
|
80956
|
+
const results = [];
|
|
80957
|
+
const tableRowPattern = /<tr[^>]*>\s*<td[^>]*>([^<]+)<\/td>\s*<td[^>]*>([^<]+)<\/td>\s*<td[^>]*>([^<]*)<\/td>\s*<td[^>]*>([^<]+)<\/td>/gi;
|
|
80958
|
+
for (const match of html.matchAll(tableRowPattern)) {
|
|
80959
|
+
const modelName = cleanCellText(match[1]);
|
|
80960
|
+
const inputMultiplier = Number.parseFloat(match[2]);
|
|
80961
|
+
const cachedInput = match[3].trim().toLowerCase();
|
|
80962
|
+
const outputMultiplier = Number.parseFloat(match[4]);
|
|
80963
|
+
if (modelName && !Number.isNaN(inputMultiplier) && !Number.isNaN(outputMultiplier)) {
|
|
80964
|
+
results.push({
|
|
80965
|
+
modelName,
|
|
80966
|
+
inputMultiplier,
|
|
80967
|
+
cachedInputMultiplier: cachedInput === "n/a" || cachedInput === "" ? null : Number.parseFloat(cachedInput) || null,
|
|
80968
|
+
outputMultiplier
|
|
80969
|
+
});
|
|
80970
|
+
}
|
|
80971
|
+
}
|
|
80972
|
+
return results;
|
|
80973
|
+
}
|
|
80974
|
+
function parsePremiumMultiplierTable(html) {
|
|
80975
|
+
const results = [];
|
|
80976
|
+
const tableRowPattern = /<tr[^>]*>\s*<td[^>]*>([^<]+)<\/td>\s*<td[^>]*>([^<]+)<\/td>\s*<\/tr>/gi;
|
|
80977
|
+
for (const match of html.matchAll(tableRowPattern)) {
|
|
80978
|
+
const modelName = cleanCellText(match[1]);
|
|
80979
|
+
const multiplier = Number.parseFloat(match[2]);
|
|
80980
|
+
if (modelName && !Number.isNaN(multiplier) && multiplier > 0) {
|
|
80981
|
+
results.push({ modelName, multiplier });
|
|
80982
|
+
}
|
|
80983
|
+
}
|
|
80984
|
+
return results;
|
|
80985
|
+
}
|
|
80986
|
+
function cleanCellText(text) {
|
|
80987
|
+
return text.replace(/<[^>]*>/g, "").replace(/&[^;]+;/g, " ").trim();
|
|
80988
|
+
}
|
|
80989
|
+
function parseCopilotPricingMarkdown(markdown) {
|
|
80990
|
+
const results = [];
|
|
80991
|
+
const seenModels = /* @__PURE__ */ new Set();
|
|
80992
|
+
const lines = markdown.split("\n");
|
|
80993
|
+
let columnIndices = null;
|
|
80994
|
+
for (const line of lines) {
|
|
80995
|
+
const trimmed = line.trim();
|
|
80996
|
+
if (!trimmed.startsWith("|")) continue;
|
|
80997
|
+
if (/\|\s*Model\s/i.test(trimmed)) {
|
|
80998
|
+
columnIndices = parseHeaderColumns(trimmed);
|
|
80999
|
+
continue;
|
|
81000
|
+
}
|
|
81001
|
+
if (/^[\s|:-]+$/.test(trimmed) || !columnIndices) continue;
|
|
81002
|
+
const entry = parseDataRow(trimmed, columnIndices);
|
|
81003
|
+
if (entry && !seenModels.has(entry.modelName.toLowerCase())) {
|
|
81004
|
+
seenModels.add(entry.modelName.toLowerCase());
|
|
81005
|
+
results.push(entry);
|
|
81006
|
+
}
|
|
81007
|
+
}
|
|
81008
|
+
return results;
|
|
81009
|
+
}
|
|
81010
|
+
function parseDataRow(line, columnIndices) {
|
|
81011
|
+
const cells = splitMarkdownRow(line);
|
|
81012
|
+
if (cells.length <= columnIndices.output) return null;
|
|
81013
|
+
const modelName = cells[columnIndices.model].trim();
|
|
81014
|
+
const inputPrice = parseDollarValue(cells[columnIndices.input]);
|
|
81015
|
+
const cachedPrice = columnIndices.cached >= 0 ? parseDollarValue(cells[columnIndices.cached]) : null;
|
|
81016
|
+
const outputPrice = parseDollarValue(cells[columnIndices.output]);
|
|
81017
|
+
if (!modelName || inputPrice === null || outputPrice === null) return null;
|
|
81018
|
+
return {
|
|
81019
|
+
modelName,
|
|
81020
|
+
inputMultiplier: inputPrice * PRICE_TO_MULTIPLIER,
|
|
81021
|
+
cachedInputMultiplier: cachedPrice !== null ? cachedPrice * PRICE_TO_MULTIPLIER : null,
|
|
81022
|
+
outputMultiplier: outputPrice * PRICE_TO_MULTIPLIER
|
|
81023
|
+
};
|
|
81024
|
+
}
|
|
81025
|
+
function parseHeaderColumns(headerLine) {
|
|
81026
|
+
const cells = splitMarkdownRow(headerLine).map((c) => c.trim().toLowerCase());
|
|
81027
|
+
const model = cells.findIndex((c) => c === "model" || c === "model name");
|
|
81028
|
+
const input = cells.findIndex(
|
|
81029
|
+
(c) => (c === "input" || c === "input multiplier") && !c.includes("cached")
|
|
81030
|
+
);
|
|
81031
|
+
const cached2 = cells.findIndex(
|
|
81032
|
+
(c) => c.includes("cached input") || c === "cached input multiplier"
|
|
81033
|
+
);
|
|
81034
|
+
const output = cells.findIndex(
|
|
81035
|
+
(c) => (c === "output" || c === "output multiplier") && !c.includes("cached")
|
|
81036
|
+
);
|
|
81037
|
+
if (model < 0 || input < 0 || output < 0) {
|
|
81038
|
+
return null;
|
|
81039
|
+
}
|
|
81040
|
+
return { model, input, cached: cached2 >= 0 ? cached2 : -1, output };
|
|
81041
|
+
}
|
|
81042
|
+
function splitMarkdownRow(line) {
|
|
81043
|
+
const parts = line.split("|");
|
|
81044
|
+
if (parts[0].trim() === "") parts.shift();
|
|
81045
|
+
if (parts[parts.length - 1]?.trim() === "") parts.pop();
|
|
81046
|
+
return parts;
|
|
81047
|
+
}
|
|
81048
|
+
function parseDollarValue(cell) {
|
|
81049
|
+
if (!cell) return null;
|
|
81050
|
+
const cleaned = cell.trim().replace(/[$,]/g, "");
|
|
81051
|
+
if (cleaned.toLowerCase() === "n/a" || cleaned === "" || cleaned === "-") {
|
|
81052
|
+
return null;
|
|
81053
|
+
}
|
|
81054
|
+
const value = Number.parseFloat(cleaned);
|
|
81055
|
+
return Number.isNaN(value) ? null : value;
|
|
81056
|
+
}
|
|
81057
|
+
|
|
81058
|
+
// packages/daemon/src/models/types.ts
|
|
81059
|
+
var TIER_RANGES = {
|
|
81060
|
+
trivial: { min: 0, max: 0.33 },
|
|
81061
|
+
fast: { min: 0.34, max: 1 },
|
|
81062
|
+
standard: { min: 1.1, max: 5 },
|
|
81063
|
+
premium: { min: 5.1, max: 15 },
|
|
81064
|
+
ultra: { min: 15.1, max: Number.POSITIVE_INFINITY }
|
|
81065
|
+
};
|
|
81066
|
+
function computeTierFromMultiplier(premiumMultiplier) {
|
|
81067
|
+
if (premiumMultiplier === null) {
|
|
81068
|
+
return "standard";
|
|
81069
|
+
}
|
|
81070
|
+
for (const [tier, range] of Object.entries(TIER_RANGES)) {
|
|
81071
|
+
if (premiumMultiplier >= range.min && premiumMultiplier <= range.max) {
|
|
81072
|
+
return tier;
|
|
81073
|
+
}
|
|
81074
|
+
}
|
|
81075
|
+
return "ultra";
|
|
81076
|
+
}
|
|
81077
|
+
var TOKEN_UNIT_PRICE = 1e-5;
|
|
81078
|
+
|
|
81079
|
+
// packages/daemon/src/models/registry.ts
|
|
81080
|
+
function stripVendorPrefix(id) {
|
|
81081
|
+
const slashIndex = id.indexOf("/");
|
|
81082
|
+
return slashIndex >= 0 ? id.slice(slashIndex + 1) : id;
|
|
81083
|
+
}
|
|
81084
|
+
function normalizeModelName(name) {
|
|
81085
|
+
return stripVendorPrefix(name).toLowerCase().replace(/^openai\s+/i, "").replace(/\s+/g, "-").replace(/[^a-z0-9.\-]/g, "").trim();
|
|
81086
|
+
}
|
|
81087
|
+
async function fetchCatalogIntoMap(modelMap, result, logger2) {
|
|
81088
|
+
try {
|
|
81089
|
+
const catalogModels = await fetchModelCatalog();
|
|
81090
|
+
result.catalogFetched = true;
|
|
81091
|
+
for (const m of catalogModels) {
|
|
81092
|
+
const key = normalizeModelName(m.id);
|
|
81093
|
+
const id = stripVendorPrefix(m.id);
|
|
81094
|
+
modelMap.set(key, { id, displayName: m.displayName, available: true });
|
|
81095
|
+
}
|
|
81096
|
+
} catch (error51) {
|
|
81097
|
+
const msg = error51 instanceof Error ? error51.message : String(error51);
|
|
81098
|
+
result.errors.push(`Catalog fetch failed: ${msg}`);
|
|
81099
|
+
logger2?.warn(`Model catalog fetch failed: ${msg}`);
|
|
81100
|
+
}
|
|
81101
|
+
}
|
|
81102
|
+
async function scrapeTokenPricingIntoMap(modelMap, result, logger2) {
|
|
81103
|
+
try {
|
|
81104
|
+
const tokenPricing = await scrapeTokenUnitPricing();
|
|
81105
|
+
result.tokenPricingScraped = true;
|
|
81106
|
+
for (const tp of tokenPricing) {
|
|
81107
|
+
const key = normalizeModelName(tp.modelName);
|
|
81108
|
+
const existing = modelMap.get(key) ?? findClosestKey(modelMap, key);
|
|
81109
|
+
if (existing) {
|
|
81110
|
+
existing.tokenInputMultiplier = tp.inputMultiplier;
|
|
81111
|
+
existing.tokenOutputMultiplier = tp.outputMultiplier;
|
|
81112
|
+
existing.cachedInputMultiplier = tp.cachedInputMultiplier;
|
|
81113
|
+
} else {
|
|
81114
|
+
modelMap.set(key, {
|
|
81115
|
+
id: key,
|
|
81116
|
+
displayName: tp.modelName,
|
|
81117
|
+
tokenInputMultiplier: tp.inputMultiplier,
|
|
81118
|
+
tokenOutputMultiplier: tp.outputMultiplier,
|
|
81119
|
+
cachedInputMultiplier: tp.cachedInputMultiplier,
|
|
81120
|
+
available: true
|
|
81121
|
+
});
|
|
81122
|
+
}
|
|
81123
|
+
}
|
|
81124
|
+
} catch (error51) {
|
|
81125
|
+
const msg = error51 instanceof Error ? error51.message : String(error51);
|
|
81126
|
+
result.errors.push(`Token pricing scrape failed: ${msg}`);
|
|
81127
|
+
logger2?.warn(`Token pricing scrape failed: ${msg}`);
|
|
81128
|
+
}
|
|
81129
|
+
}
|
|
81130
|
+
async function scrapePremiumPricingIntoMap(modelMap, result, logger2) {
|
|
81131
|
+
try {
|
|
81132
|
+
const premiumPricing = await scrapePremiumRequestPricing();
|
|
81133
|
+
result.premiumPricingScraped = true;
|
|
81134
|
+
for (const pp of premiumPricing) {
|
|
81135
|
+
const key = normalizeModelName(pp.modelName);
|
|
81136
|
+
const existing = modelMap.get(key) ?? findClosestKey(modelMap, key);
|
|
81137
|
+
if (existing) {
|
|
81138
|
+
existing.premiumMultiplier = pp.multiplier;
|
|
81139
|
+
} else {
|
|
81140
|
+
modelMap.set(key, {
|
|
81141
|
+
id: key,
|
|
81142
|
+
displayName: pp.modelName,
|
|
81143
|
+
premiumMultiplier: pp.multiplier,
|
|
81144
|
+
available: true
|
|
81145
|
+
});
|
|
81146
|
+
}
|
|
81147
|
+
}
|
|
81148
|
+
} catch (error51) {
|
|
81149
|
+
const msg = error51 instanceof Error ? error51.message : String(error51);
|
|
81150
|
+
result.errors.push(`Premium pricing scrape failed: ${msg}`);
|
|
81151
|
+
logger2?.warn(`Premium pricing scrape failed: ${msg}`);
|
|
81152
|
+
}
|
|
81153
|
+
}
|
|
81154
|
+
async function scrapeCopilotPricingIntoMap(modelMap, result, logger2) {
|
|
81155
|
+
try {
|
|
81156
|
+
const copilotPricing = await scrapeCopilotPricing();
|
|
81157
|
+
result.copilotPricingScraped = true;
|
|
81158
|
+
for (const cp of copilotPricing) {
|
|
81159
|
+
const key = normalizeModelName(cp.modelName);
|
|
81160
|
+
const existing = modelMap.get(key) ?? findClosestKey(modelMap, key);
|
|
81161
|
+
if (existing) {
|
|
81162
|
+
existing.tokenInputMultiplier = cp.inputMultiplier;
|
|
81163
|
+
existing.tokenOutputMultiplier = cp.outputMultiplier;
|
|
81164
|
+
if (cp.cachedInputMultiplier !== null) {
|
|
81165
|
+
existing.cachedInputMultiplier = cp.cachedInputMultiplier;
|
|
81166
|
+
}
|
|
81167
|
+
} else {
|
|
81168
|
+
modelMap.set(key, {
|
|
81169
|
+
id: key,
|
|
81170
|
+
displayName: cp.modelName,
|
|
81171
|
+
tokenInputMultiplier: cp.inputMultiplier,
|
|
81172
|
+
tokenOutputMultiplier: cp.outputMultiplier,
|
|
81173
|
+
cachedInputMultiplier: cp.cachedInputMultiplier,
|
|
81174
|
+
available: true
|
|
81175
|
+
});
|
|
81176
|
+
}
|
|
81177
|
+
}
|
|
81178
|
+
} catch (error51) {
|
|
81179
|
+
const msg = error51 instanceof Error ? error51.message : String(error51);
|
|
81180
|
+
result.errors.push(`Copilot pricing scrape failed: ${msg}`);
|
|
81181
|
+
logger2?.warn(`Copilot pricing scrape failed: ${msg}`);
|
|
81182
|
+
}
|
|
81183
|
+
}
|
|
81184
|
+
async function refreshModelPricing(logger2) {
|
|
81185
|
+
const result = {
|
|
81186
|
+
modelsUpdated: 0,
|
|
81187
|
+
catalogFetched: false,
|
|
81188
|
+
tokenPricingScraped: false,
|
|
81189
|
+
premiumPricingScraped: false,
|
|
81190
|
+
copilotPricingScraped: false,
|
|
81191
|
+
errors: []
|
|
81192
|
+
};
|
|
81193
|
+
const modelMap = /* @__PURE__ */ new Map();
|
|
81194
|
+
await fetchCatalogIntoMap(modelMap, result, logger2);
|
|
81195
|
+
await scrapeTokenPricingIntoMap(modelMap, result, logger2);
|
|
81196
|
+
await scrapeCopilotPricingIntoMap(modelMap, result, logger2);
|
|
81197
|
+
await scrapePremiumPricingIntoMap(modelMap, result, logger2);
|
|
81198
|
+
if (!result.catalogFetched && !result.tokenPricingScraped && !result.premiumPricingScraped && !result.copilotPricingScraped) {
|
|
81199
|
+
logger2?.warn("All pricing sources failed, no models available");
|
|
81200
|
+
return result;
|
|
81201
|
+
}
|
|
81202
|
+
const db = await getDatabase();
|
|
81203
|
+
const now = nowIso();
|
|
81204
|
+
await db.execute("DELETE FROM model_pricing WHERE id LIKE '%/%'");
|
|
81205
|
+
for (const model of modelMap.values()) {
|
|
81206
|
+
if (model.tokenInputMultiplier == null) {
|
|
81207
|
+
continue;
|
|
81208
|
+
}
|
|
81209
|
+
const tier = computeTierFromMultiplier(model.premiumMultiplier ?? null);
|
|
81210
|
+
await upsertModel(db, {
|
|
81211
|
+
id: model.id,
|
|
81212
|
+
displayName: model.displayName,
|
|
81213
|
+
premiumMultiplier: model.premiumMultiplier ?? null,
|
|
81214
|
+
tokenInputMultiplier: model.tokenInputMultiplier,
|
|
81215
|
+
tokenOutputMultiplier: model.tokenOutputMultiplier ?? null,
|
|
81216
|
+
cachedInputMultiplier: model.cachedInputMultiplier ?? null,
|
|
81217
|
+
tier,
|
|
81218
|
+
available: model.available ?? true,
|
|
81219
|
+
updatedAt: now
|
|
81220
|
+
});
|
|
81221
|
+
result.modelsUpdated++;
|
|
81222
|
+
}
|
|
81223
|
+
return result;
|
|
81224
|
+
}
|
|
81225
|
+
async function getModelsForTier(tier) {
|
|
81226
|
+
const db = await getDatabase();
|
|
81227
|
+
const result = await db.execute({
|
|
81228
|
+
sql: "SELECT * FROM model_pricing WHERE tier = ? AND available = 1 ORDER BY premium_multiplier ASC NULLS LAST",
|
|
81229
|
+
args: [tier]
|
|
81230
|
+
});
|
|
81231
|
+
return result.rows.map(rowToModelPricing);
|
|
81232
|
+
}
|
|
81233
|
+
async function getCheapestInTier(tier) {
|
|
81234
|
+
const models = await getModelsForTier(tier);
|
|
81235
|
+
return models[0] ?? null;
|
|
81236
|
+
}
|
|
81237
|
+
async function getModelPricing(modelId) {
|
|
81238
|
+
const db = await getDatabase();
|
|
81239
|
+
const result = await db.execute({
|
|
81240
|
+
sql: "SELECT * FROM model_pricing WHERE id = ?",
|
|
81241
|
+
args: [modelId]
|
|
81242
|
+
});
|
|
81243
|
+
if (result.rows.length > 0) {
|
|
81244
|
+
return rowToModelPricing(result.rows[0]);
|
|
81245
|
+
}
|
|
81246
|
+
const allModels = await db.execute(
|
|
81247
|
+
"SELECT * FROM model_pricing WHERE token_input_multiplier IS NOT NULL ORDER BY length(id) DESC"
|
|
81248
|
+
);
|
|
81249
|
+
for (const row of allModels.rows) {
|
|
81250
|
+
const storedId = asString(row.id);
|
|
81251
|
+
if (modelId.startsWith(storedId) || storedId.startsWith(modelId)) {
|
|
81252
|
+
return rowToModelPricing(row);
|
|
81253
|
+
}
|
|
81254
|
+
}
|
|
81255
|
+
return null;
|
|
81256
|
+
}
|
|
81257
|
+
async function getCheapestAvailableModel() {
|
|
81258
|
+
const tiers = ["trivial", "fast", "standard", "premium", "ultra"];
|
|
81259
|
+
for (const tier of tiers) {
|
|
81260
|
+
const model = await getCheapestInTier(tier);
|
|
81261
|
+
if (model) {
|
|
81262
|
+
return model;
|
|
81263
|
+
}
|
|
81264
|
+
}
|
|
81265
|
+
return null;
|
|
81266
|
+
}
|
|
81267
|
+
function calculateTokenUnitCost(inputTokens, outputTokens, inputMultiplier, outputMultiplier) {
|
|
81268
|
+
if (inputMultiplier === null || outputMultiplier === null) {
|
|
81269
|
+
return 0;
|
|
81270
|
+
}
|
|
81271
|
+
const tokenUnits = inputTokens * inputMultiplier + outputTokens * outputMultiplier;
|
|
81272
|
+
return tokenUnits * TOKEN_UNIT_PRICE;
|
|
81273
|
+
}
|
|
81274
|
+
function getNextTierUp(tier) {
|
|
81275
|
+
const order = ["trivial", "fast", "standard", "premium", "ultra"];
|
|
81276
|
+
const idx = order.indexOf(tier);
|
|
81277
|
+
if (idx < 0 || idx >= order.length - 1) {
|
|
81278
|
+
return null;
|
|
81279
|
+
}
|
|
81280
|
+
return order[idx + 1];
|
|
81281
|
+
}
|
|
81282
|
+
async function upsertModel(db, model) {
|
|
81283
|
+
await db.execute({
|
|
81284
|
+
sql: `INSERT INTO model_pricing (id, display_name, premium_multiplier, token_input_multiplier, token_output_multiplier, cached_input_multiplier, tier, available, updated_at)
|
|
81285
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
81286
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
81287
|
+
display_name = excluded.display_name,
|
|
81288
|
+
premium_multiplier = COALESCE(excluded.premium_multiplier, model_pricing.premium_multiplier),
|
|
81289
|
+
token_input_multiplier = COALESCE(excluded.token_input_multiplier, model_pricing.token_input_multiplier),
|
|
81290
|
+
token_output_multiplier = COALESCE(excluded.token_output_multiplier, model_pricing.token_output_multiplier),
|
|
81291
|
+
cached_input_multiplier = COALESCE(excluded.cached_input_multiplier, model_pricing.cached_input_multiplier),
|
|
81292
|
+
tier = excluded.tier,
|
|
81293
|
+
available = excluded.available,
|
|
81294
|
+
updated_at = excluded.updated_at`,
|
|
81295
|
+
args: [
|
|
81296
|
+
model.id,
|
|
81297
|
+
model.displayName,
|
|
81298
|
+
model.premiumMultiplier,
|
|
81299
|
+
model.tokenInputMultiplier,
|
|
81300
|
+
model.tokenOutputMultiplier,
|
|
81301
|
+
model.cachedInputMultiplier,
|
|
81302
|
+
model.tier,
|
|
81303
|
+
model.available ? 1 : 0,
|
|
81304
|
+
model.updatedAt
|
|
81305
|
+
]
|
|
81306
|
+
});
|
|
81307
|
+
}
|
|
81308
|
+
function rowToModelPricing(row) {
|
|
81309
|
+
return {
|
|
81310
|
+
id: stripVendorPrefix(asString(row.id)),
|
|
81311
|
+
displayName: asString(row.display_name),
|
|
81312
|
+
premiumMultiplier: asNullableNumber(row.premium_multiplier),
|
|
81313
|
+
tokenInputMultiplier: asNullableNumber(row.token_input_multiplier),
|
|
81314
|
+
tokenOutputMultiplier: asNullableNumber(row.token_output_multiplier),
|
|
81315
|
+
cachedInputMultiplier: asNullableNumber(row.cached_input_multiplier),
|
|
81316
|
+
tier: asString(row.tier),
|
|
81317
|
+
available: asNumber(row.available) === 1,
|
|
81318
|
+
updatedAt: asString(row.updated_at)
|
|
81319
|
+
};
|
|
81320
|
+
}
|
|
81321
|
+
function findClosestKey(map2, targetKey) {
|
|
81322
|
+
for (const [key, value] of map2) {
|
|
81323
|
+
if (key.includes(targetKey) || targetKey.includes(key)) {
|
|
81324
|
+
return value;
|
|
81325
|
+
}
|
|
81326
|
+
}
|
|
81327
|
+
return void 0;
|
|
81328
|
+
}
|
|
81380
81329
|
|
|
81381
81330
|
// packages/daemon/src/orchestrator/system-prompt.ts
|
|
81382
81331
|
function formatSquadRoster(squads) {
|
|
@@ -81710,9 +81659,6 @@ async function sendMessage(session, message2, onChunk) {
|
|
|
81710
81659
|
return operation;
|
|
81711
81660
|
}
|
|
81712
81661
|
|
|
81713
|
-
// packages/daemon/src/orchestrator/orchestrator.ts
|
|
81714
|
-
init_registry();
|
|
81715
|
-
|
|
81716
81662
|
// packages/daemon/src/skills/loader.ts
|
|
81717
81663
|
var import_gray_matter2 = __toESM(require_gray_matter(), 1);
|
|
81718
81664
|
init_paths();
|
|
@@ -82064,7 +82010,6 @@ var executeCodingToolCall = async (toolName, rawArgs) => {
|
|
|
82064
82010
|
// packages/daemon/src/orchestrator/tools/inbox.ts
|
|
82065
82011
|
init_dist();
|
|
82066
82012
|
init_zod();
|
|
82067
|
-
init_db();
|
|
82068
82013
|
var inboxReplySchema = external_exports.object({
|
|
82069
82014
|
itemId: external_exports.string().trim().min(1),
|
|
82070
82015
|
reply: external_exports.string().trim().min(1)
|
|
@@ -82336,42 +82281,39 @@ async function isSquadAvailable(squadId) {
|
|
|
82336
82281
|
}
|
|
82337
82282
|
|
|
82338
82283
|
// packages/daemon/src/execution/agent.ts
|
|
82339
|
-
init_registry();
|
|
82340
82284
|
import { exec as exec3 } from "node:child_process";
|
|
82341
82285
|
import { mkdir as mkdir9, readFile as readFile7, readdir as readdir5, stat as stat3, writeFile as writeFile6 } from "node:fs/promises";
|
|
82342
82286
|
import { dirname as dirname8, extname as extname3, isAbsolute, join as join11, relative as relative3, resolve as resolve4 } from "node:path";
|
|
82343
82287
|
import { promisify as promisify3 } from "node:util";
|
|
82344
82288
|
import {
|
|
82345
|
-
CopilotClient as
|
|
82346
|
-
approveAll as
|
|
82289
|
+
CopilotClient as CopilotClient2,
|
|
82290
|
+
approveAll as approveAll2,
|
|
82347
82291
|
defineTool
|
|
82348
82292
|
} from "@github/copilot-sdk";
|
|
82349
82293
|
|
|
82350
82294
|
// packages/daemon/src/squad/model-selector.ts
|
|
82351
|
-
|
|
82352
|
-
|
|
82353
|
-
|
|
82354
|
-
|
|
82355
|
-
|
|
82356
|
-
|
|
82357
|
-
|
|
82358
|
-
|
|
82359
|
-
|
|
82360
|
-
|
|
82361
|
-
|
|
82362
|
-
|
|
82363
|
-
|
|
82295
|
+
var TIER_KEYWORDS = {
|
|
82296
|
+
ultra: [/system[- ]wide/i, /redesign/i, /infrastructure/i, /cross[- ]cutting/i, /migration/i],
|
|
82297
|
+
premium: [/architect/i, /security/i, /performance/i, /complex refactor/i, /optimization/i],
|
|
82298
|
+
standard: [/implement/i, /feature/i, /multi[- ]file/i, /refactor/i, /integration/i],
|
|
82299
|
+
fast: [/fix/i, /bug/i, /update/i, /documentation/i, /single[- ]file/i, /small/i],
|
|
82300
|
+
trivial: [/typo/i, /rename/i, /comment/i, /config/i, /format/i]
|
|
82301
|
+
};
|
|
82302
|
+
function classifyTaskComplexity(taskDescription) {
|
|
82303
|
+
const tiers = ["ultra", "premium", "standard", "fast", "trivial"];
|
|
82304
|
+
for (const tier of tiers) {
|
|
82305
|
+
if (TIER_KEYWORDS[tier].some((pattern) => pattern.test(taskDescription))) {
|
|
82306
|
+
return tier;
|
|
82307
|
+
}
|
|
82308
|
+
}
|
|
82309
|
+
return "standard";
|
|
82310
|
+
}
|
|
82364
82311
|
async function selectModelForTask(taskDescription) {
|
|
82365
82312
|
const classifierModel = await getCheapestAvailableModel();
|
|
82366
82313
|
if (!classifierModel) {
|
|
82367
82314
|
throw new Error("No models available in pricing database");
|
|
82368
82315
|
}
|
|
82369
|
-
|
|
82370
|
-
try {
|
|
82371
|
-
tier = await classifyTaskComplexity(taskDescription, classifierModel.id);
|
|
82372
|
-
} catch {
|
|
82373
|
-
return classifierModel.id;
|
|
82374
|
-
}
|
|
82316
|
+
const tier = classifyTaskComplexity(taskDescription);
|
|
82375
82317
|
const selectedModel = await getCheapestInTier(tier);
|
|
82376
82318
|
if (selectedModel) {
|
|
82377
82319
|
return selectedModel.id;
|
|
@@ -82385,30 +82327,6 @@ async function selectModelForTask(taskDescription) {
|
|
|
82385
82327
|
}
|
|
82386
82328
|
return classifierModel.id;
|
|
82387
82329
|
}
|
|
82388
|
-
async function classifyTaskComplexity(taskDescription, modelId) {
|
|
82389
|
-
let client2 = null;
|
|
82390
|
-
try {
|
|
82391
|
-
client2 = new CopilotClient2();
|
|
82392
|
-
await client2.start();
|
|
82393
|
-
const session = await client2.createSession({
|
|
82394
|
-
model: modelId,
|
|
82395
|
-
onPermissionRequest: approveAll2,
|
|
82396
|
-
systemMessage: { content: CLASSIFICATION_PROMPT }
|
|
82397
|
-
});
|
|
82398
|
-
try {
|
|
82399
|
-
const response = await session.sendAndWait({ prompt: `Task: ${taskDescription}` }, 15e3);
|
|
82400
|
-
const raw = (response.text ?? "").trim().toLowerCase();
|
|
82401
|
-
const tier = VALID_TIERS.find((t) => raw.includes(t));
|
|
82402
|
-
return tier ?? "standard";
|
|
82403
|
-
} finally {
|
|
82404
|
-
await session.disconnect().catch(() => void 0);
|
|
82405
|
-
}
|
|
82406
|
-
} finally {
|
|
82407
|
-
if (client2) {
|
|
82408
|
-
await client2.stop().catch(() => void 0);
|
|
82409
|
-
}
|
|
82410
|
-
}
|
|
82411
|
-
}
|
|
82412
82330
|
|
|
82413
82331
|
// packages/daemon/src/execution/history.ts
|
|
82414
82332
|
var DEFAULT_CONTEXT_LIMIT = 5;
|
|
@@ -82439,6 +82357,7 @@ var execAsync3 = promisify3(exec3);
|
|
|
82439
82357
|
var MAX_FILE_SIZE = 2e5;
|
|
82440
82358
|
var MAX_LIST_RESULTS = 200;
|
|
82441
82359
|
var MAX_SEARCH_RESULTS = 100;
|
|
82360
|
+
var SESSION_CREATE_TIMEOUT_MS = 3e4;
|
|
82442
82361
|
function createEmptyUsage() {
|
|
82443
82362
|
return {
|
|
82444
82363
|
inputTokens: 0,
|
|
@@ -82695,15 +82614,15 @@ async function executeAgentTask(member, task, worktreePath, options2) {
|
|
|
82695
82614
|
const mcpServerNote = options2?.mcpServers?.length ? `Available MCP server labels: ${options2.mcpServers.join(", ")}.` : "No additional MCP servers were configured for this run.";
|
|
82696
82615
|
let client2 = null;
|
|
82697
82616
|
try {
|
|
82698
|
-
client2 = new
|
|
82617
|
+
client2 = new CopilotClient2({ workingDirectory: worktreePath });
|
|
82699
82618
|
await client2.start();
|
|
82700
82619
|
const model = member.model ? stripVendorPrefix(member.model) : await selectModelForTask(task.description);
|
|
82701
|
-
const
|
|
82620
|
+
const sessionPromise = client2.createSession({
|
|
82702
82621
|
model,
|
|
82703
82622
|
workingDirectory: worktreePath,
|
|
82704
82623
|
tools,
|
|
82705
82624
|
availableTools: ["custom:*"],
|
|
82706
|
-
onPermissionRequest:
|
|
82625
|
+
onPermissionRequest: approveAll2,
|
|
82707
82626
|
systemMessage: {
|
|
82708
82627
|
content: `${member.systemPrompt}
|
|
82709
82628
|
|
|
@@ -82713,6 +82632,15 @@ ${historyContext}
|
|
|
82713
82632
|
${mcpServerNote}${options2?.instancePromptSuffix ?? ""}`
|
|
82714
82633
|
}
|
|
82715
82634
|
});
|
|
82635
|
+
const session = await Promise.race([
|
|
82636
|
+
sessionPromise,
|
|
82637
|
+
new Promise(
|
|
82638
|
+
(_, reject) => setTimeout(
|
|
82639
|
+
() => reject(new Error(`Session creation timed out after ${SESSION_CREATE_TIMEOUT_MS}ms`)),
|
|
82640
|
+
SESSION_CREATE_TIMEOUT_MS
|
|
82641
|
+
)
|
|
82642
|
+
)
|
|
82643
|
+
]);
|
|
82716
82644
|
session.on("assistant.usage", (event) => {
|
|
82717
82645
|
usageEvents.push(event.data);
|
|
82718
82646
|
mergeUsage(usage, event.data);
|
|
@@ -82784,7 +82712,7 @@ import { exec as exec4 } from "node:child_process";
|
|
|
82784
82712
|
import { access, readFile as readFile8 } from "node:fs/promises";
|
|
82785
82713
|
import { join as join12 } from "node:path";
|
|
82786
82714
|
import { promisify as promisify4 } from "node:util";
|
|
82787
|
-
import { CopilotClient as
|
|
82715
|
+
import { CopilotClient as CopilotClient3, approveAll as approveAll3 } from "@github/copilot-sdk";
|
|
82788
82716
|
|
|
82789
82717
|
// packages/daemon/src/squad/roles.ts
|
|
82790
82718
|
var ROLE_GUIDELINES = [
|
|
@@ -82927,13 +82855,13 @@ Return strict JSON in this shape:
|
|
|
82927
82855
|
}`;
|
|
82928
82856
|
let client2 = null;
|
|
82929
82857
|
try {
|
|
82930
|
-
client2 = new
|
|
82858
|
+
client2 = new CopilotClient3({ workingDirectory: repoPath });
|
|
82931
82859
|
await client2.start();
|
|
82932
82860
|
const model = await selectModelForTask(`Create implementation plan: ${objective.description}`);
|
|
82933
82861
|
const session = await client2.createSession({
|
|
82934
82862
|
model,
|
|
82935
82863
|
workingDirectory: repoPath,
|
|
82936
|
-
onPermissionRequest:
|
|
82864
|
+
onPermissionRequest: approveAll3,
|
|
82937
82865
|
systemMessage: {
|
|
82938
82866
|
content: `${TEAM_LEAD_PROMPT}
|
|
82939
82867
|
|
|
@@ -83036,8 +82964,7 @@ async function createPullRequest(options2) {
|
|
|
83036
82964
|
init_dist();
|
|
83037
82965
|
import { exec as exec6 } from "node:child_process";
|
|
83038
82966
|
import { promisify as promisify6 } from "node:util";
|
|
83039
|
-
import { CopilotClient as
|
|
83040
|
-
init_registry();
|
|
82967
|
+
import { CopilotClient as CopilotClient4, approveAll as approveAll4 } from "@github/copilot-sdk";
|
|
83041
82968
|
var execAsync6 = promisify6(exec6);
|
|
83042
82969
|
var GIT_DIFF_MAX_BUFFER = 10 * 1024 * 1024;
|
|
83043
82970
|
function extractJsonObject2(content) {
|
|
@@ -83077,13 +83004,13 @@ Return strict JSON:
|
|
|
83077
83004
|
}`;
|
|
83078
83005
|
let client2 = null;
|
|
83079
83006
|
try {
|
|
83080
|
-
client2 = new
|
|
83007
|
+
client2 = new CopilotClient4({ workingDirectory: worktreePath });
|
|
83081
83008
|
await client2.start();
|
|
83082
83009
|
const model = qaMember.model ? stripVendorPrefix(qaMember.model) : await selectModelForTask(`QA review: ${objective.description}`);
|
|
83083
83010
|
const session = await client2.createSession({
|
|
83084
83011
|
model,
|
|
83085
83012
|
workingDirectory: worktreePath,
|
|
83086
|
-
onPermissionRequest:
|
|
83013
|
+
onPermissionRequest: approveAll4,
|
|
83087
83014
|
systemMessage: {
|
|
83088
83015
|
content: QA_PROMPT
|
|
83089
83016
|
}
|
|
@@ -83153,8 +83080,7 @@ async function handleQARejection(objectiveId, feedback) {
|
|
|
83153
83080
|
}
|
|
83154
83081
|
|
|
83155
83082
|
// packages/daemon/src/execution/review.ts
|
|
83156
|
-
|
|
83157
|
-
import { CopilotClient as CopilotClient6, approveAll as approveAll6 } from "@github/copilot-sdk";
|
|
83083
|
+
import { CopilotClient as CopilotClient5, approveAll as approveAll5 } from "@github/copilot-sdk";
|
|
83158
83084
|
function extractJsonObject3(content) {
|
|
83159
83085
|
const fenced = content.match(/```(?:json)?\s*([\s\S]*?)```/i);
|
|
83160
83086
|
if (fenced?.[1]) {
|
|
@@ -83199,12 +83125,12 @@ Return strict JSON:
|
|
|
83199
83125
|
}`;
|
|
83200
83126
|
let client2 = null;
|
|
83201
83127
|
try {
|
|
83202
|
-
client2 = new
|
|
83128
|
+
client2 = new CopilotClient5();
|
|
83203
83129
|
await client2.start();
|
|
83204
83130
|
const model = teamLead.model ? stripVendorPrefix(teamLead.model) : await selectModelForTask(`Code review: ${objective.description}`);
|
|
83205
83131
|
const session = await client2.createSession({
|
|
83206
83132
|
model,
|
|
83207
|
-
onPermissionRequest:
|
|
83133
|
+
onPermissionRequest: approveAll5,
|
|
83208
83134
|
systemMessage: {
|
|
83209
83135
|
content: `${TEAM_LEAD_PROMPT}
|
|
83210
83136
|
|
|
@@ -83349,60 +83275,49 @@ async function executePendingTasks(objective, members, worktreePath, mcpServers,
|
|
|
83349
83275
|
if (pendingTasks.length === 0) {
|
|
83350
83276
|
return getTasksForObjective(objective.id);
|
|
83351
83277
|
}
|
|
83352
|
-
const
|
|
83353
|
-
|
|
83354
|
-
|
|
83355
|
-
|
|
83356
|
-
const failedTask = await markTaskFailed(
|
|
83357
|
-
task.id,
|
|
83358
|
-
"No squad member matched the task assignee."
|
|
83359
|
-
);
|
|
83360
|
-
eventBus.emit(EVENT_NAMES.TASK_FAILED, {
|
|
83361
|
-
task: failedTask,
|
|
83362
|
-
agentName: "unassigned",
|
|
83363
|
-
reason: failedTask.result ?? "No assignee"
|
|
83364
|
-
});
|
|
83365
|
-
throw new Error(`Task ${task.id} has no matching assignee`);
|
|
83366
|
-
}
|
|
83367
|
-
const inProgressTask = await updateTaskStatus(
|
|
83278
|
+
for (const task of pendingTasks) {
|
|
83279
|
+
const member = members.find((candidate) => candidate.id === task.assigneeId);
|
|
83280
|
+
if (!member) {
|
|
83281
|
+
const failedTask = await markTaskFailed(
|
|
83368
83282
|
task.id,
|
|
83369
|
-
"
|
|
83370
|
-
task.result ?? void 0
|
|
83283
|
+
"No squad member matched the task assignee."
|
|
83371
83284
|
);
|
|
83372
|
-
|
|
83373
|
-
|
|
83374
|
-
|
|
83375
|
-
|
|
83376
|
-
agentId: member.id,
|
|
83377
|
-
taskId: task.id
|
|
83378
|
-
});
|
|
83379
|
-
const execution = await executeAgentTask(member, task, worktreePath, {
|
|
83380
|
-
mcpServers,
|
|
83381
|
-
instancePromptSuffix
|
|
83285
|
+
eventBus.emit(EVENT_NAMES.TASK_FAILED, {
|
|
83286
|
+
task: failedTask,
|
|
83287
|
+
agentName: "unassigned",
|
|
83288
|
+
reason: failedTask.result ?? "No assignee"
|
|
83382
83289
|
});
|
|
83383
|
-
|
|
83384
|
-
|
|
83385
|
-
|
|
83386
|
-
|
|
83387
|
-
|
|
83388
|
-
|
|
83389
|
-
|
|
83390
|
-
|
|
83391
|
-
|
|
83392
|
-
|
|
83393
|
-
|
|
83394
|
-
|
|
83395
|
-
|
|
83396
|
-
|
|
83397
|
-
|
|
83398
|
-
|
|
83290
|
+
throw new Error(`Task ${task.id} has no matching assignee`);
|
|
83291
|
+
}
|
|
83292
|
+
const inProgressTask = await updateTaskStatus(task.id, "in_progress", task.result ?? void 0);
|
|
83293
|
+
const startedTask = inProgressTask ?? task;
|
|
83294
|
+
eventBus.emit(EVENT_NAMES.TASK_STARTED, { task: startedTask, agentName: member.name });
|
|
83295
|
+
eventBus.emit(EVENT_NAMES.AGENT_EXECUTING, {
|
|
83296
|
+
squadId: objective.squadId,
|
|
83297
|
+
agentId: member.id,
|
|
83298
|
+
taskId: task.id
|
|
83299
|
+
});
|
|
83300
|
+
const execution = await executeAgentTask(member, task, worktreePath, {
|
|
83301
|
+
mcpServers,
|
|
83302
|
+
instancePromptSuffix
|
|
83303
|
+
});
|
|
83304
|
+
if (!execution.success) {
|
|
83305
|
+
const failedTask = await markTaskFailed(task.id, execution.result);
|
|
83306
|
+
eventBus.emit(EVENT_NAMES.TASK_FAILED, {
|
|
83307
|
+
task: failedTask,
|
|
83308
|
+
agentName: member.name,
|
|
83309
|
+
reason: execution.result
|
|
83399
83310
|
});
|
|
83400
|
-
|
|
83401
|
-
}
|
|
83402
|
-
|
|
83403
|
-
|
|
83404
|
-
|
|
83405
|
-
|
|
83311
|
+
throw new Error(execution.result);
|
|
83312
|
+
}
|
|
83313
|
+
const completedTask = await markTaskComplete(task.id, execution.result);
|
|
83314
|
+
await extractLearnings(member.id, member.squadId, execution.result);
|
|
83315
|
+
eventBus.emit(EVENT_NAMES.TASK_COMPLETED, { task: completedTask, agentName: member.name });
|
|
83316
|
+
eventBus.emit(EVENT_NAMES.AGENT_COMPLETED, {
|
|
83317
|
+
squadId: objective.squadId,
|
|
83318
|
+
agentId: member.id,
|
|
83319
|
+
taskId: task.id
|
|
83320
|
+
});
|
|
83406
83321
|
}
|
|
83407
83322
|
return getTasksForObjective(objective.id);
|
|
83408
83323
|
}
|
|
@@ -84595,7 +84510,6 @@ function createOrchestrator(config2, eventBus2) {
|
|
|
84595
84510
|
// packages/daemon/src/scheduler/engine.ts
|
|
84596
84511
|
init_dist();
|
|
84597
84512
|
var import_cron_parser2 = __toESM(require_dist(), 1);
|
|
84598
|
-
init_db();
|
|
84599
84513
|
var Scheduler = class {
|
|
84600
84514
|
orchestrator;
|
|
84601
84515
|
eventBus;
|
|
@@ -84683,9 +84597,6 @@ function createScheduler(orchestrator2, eventBus2) {
|
|
|
84683
84597
|
return new Scheduler(orchestrator2, eventBus2);
|
|
84684
84598
|
}
|
|
84685
84599
|
|
|
84686
|
-
// packages/daemon/src/index.ts
|
|
84687
|
-
init_db();
|
|
84688
|
-
|
|
84689
84600
|
// packages/daemon/src/telegram/bot.ts
|
|
84690
84601
|
var import_grammy = __toESM(require_mod2(), 1);
|
|
84691
84602
|
var TelegramBot = class {
|