heyio 4.2.4 → 4.2.7
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/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.2.
|
|
82
|
+
APP_VERSION = "4.2.7";
|
|
83
83
|
API_PORT = 7777;
|
|
84
84
|
API_HOST = "0.0.0.0";
|
|
85
85
|
DEFAULT_MODEL = "gpt-4o";
|
|
@@ -77130,6 +77130,11 @@ var MIGRATIONS = [
|
|
|
77130
77130
|
agent_name = (SELECT sm.name FROM squad_members sm WHERE sm.id = token_usage.agent_id)
|
|
77131
77131
|
WHERE squad_id IS NOT NULL OR agent_id IS NOT NULL`
|
|
77132
77132
|
]
|
|
77133
|
+
},
|
|
77134
|
+
{
|
|
77135
|
+
version: 5,
|
|
77136
|
+
name: "add-squad-soft-delete",
|
|
77137
|
+
statements: ["ALTER TABLE squads ADD COLUMN deleted_at TEXT"]
|
|
77133
77138
|
}
|
|
77134
77139
|
];
|
|
77135
77140
|
var client = null;
|
|
@@ -77277,7 +77282,8 @@ async function createSquad(data, db) {
|
|
|
77277
77282
|
status: data.status ?? "active",
|
|
77278
77283
|
config: data.config,
|
|
77279
77284
|
createdAt: timestamp,
|
|
77280
|
-
updatedAt: timestamp
|
|
77285
|
+
updatedAt: timestamp,
|
|
77286
|
+
deletedAt: null
|
|
77281
77287
|
};
|
|
77282
77288
|
await database.execute({
|
|
77283
77289
|
sql: `INSERT INTO squads (id, name, repo_url, repo_owner, repo_name, status, config, created_at, updated_at)
|
|
@@ -77299,7 +77305,7 @@ async function createSquad(data, db) {
|
|
|
77299
77305
|
async function getSquad(id, db) {
|
|
77300
77306
|
const database = db ?? await getDatabase();
|
|
77301
77307
|
const squadResult = await database.execute({
|
|
77302
|
-
sql: "SELECT * FROM squads WHERE id = ? LIMIT 1",
|
|
77308
|
+
sql: "SELECT * FROM squads WHERE id = ? AND deleted_at IS NULL LIMIT 1",
|
|
77303
77309
|
args: [id]
|
|
77304
77310
|
});
|
|
77305
77311
|
const row = squadResult.rows[0];
|
|
@@ -77315,7 +77321,7 @@ async function getSquad(id, db) {
|
|
|
77315
77321
|
async function getSquadByName(name, db) {
|
|
77316
77322
|
const database = db ?? await getDatabase();
|
|
77317
77323
|
const result = await database.execute({
|
|
77318
|
-
sql: "SELECT * FROM squads WHERE name = ? LIMIT 1",
|
|
77324
|
+
sql: "SELECT * FROM squads WHERE name = ? AND deleted_at IS NULL LIMIT 1",
|
|
77319
77325
|
args: [name]
|
|
77320
77326
|
});
|
|
77321
77327
|
const row = result.rows[0];
|
|
@@ -77328,7 +77334,9 @@ async function getSquadByName(name, db) {
|
|
|
77328
77334
|
}
|
|
77329
77335
|
async function listSquads(db) {
|
|
77330
77336
|
const database = db ?? await getDatabase();
|
|
77331
|
-
const result = await database.execute(
|
|
77337
|
+
const result = await database.execute(
|
|
77338
|
+
"SELECT * FROM squads WHERE deleted_at IS NULL ORDER BY created_at DESC, id DESC"
|
|
77339
|
+
);
|
|
77332
77340
|
return result.rows.map((row) => mapSquad(row));
|
|
77333
77341
|
}
|
|
77334
77342
|
async function updateSquad(id, data, db) {
|
|
@@ -77347,7 +77355,8 @@ async function updateSquad(id, data, db) {
|
|
|
77347
77355
|
status: data.status ?? existing.status,
|
|
77348
77356
|
config: data.config ?? existing.config,
|
|
77349
77357
|
createdAt: existing.createdAt,
|
|
77350
|
-
updatedAt
|
|
77358
|
+
updatedAt,
|
|
77359
|
+
deletedAt: existing.deletedAt
|
|
77351
77360
|
};
|
|
77352
77361
|
await database.execute({
|
|
77353
77362
|
sql: `UPDATE squads
|
|
@@ -77368,16 +77377,34 @@ async function updateSquad(id, data, db) {
|
|
|
77368
77377
|
}
|
|
77369
77378
|
async function deleteSquad(id, db) {
|
|
77370
77379
|
const database = db ?? await getDatabase();
|
|
77380
|
+
const now = nowIso();
|
|
77371
77381
|
const result = await database.execute({
|
|
77372
|
-
sql: "
|
|
77373
|
-
args: [id]
|
|
77382
|
+
sql: "UPDATE squads SET status = 'deleted', deleted_at = ?, updated_at = ? WHERE id = ? AND deleted_at IS NULL",
|
|
77383
|
+
args: [now, now, id]
|
|
77374
77384
|
});
|
|
77375
77385
|
return result.rowsAffected > 0;
|
|
77376
77386
|
}
|
|
77387
|
+
async function restoreSquad(id, db) {
|
|
77388
|
+
const database = db ?? await getDatabase();
|
|
77389
|
+
const now = nowIso();
|
|
77390
|
+
const result = await database.execute({
|
|
77391
|
+
sql: "UPDATE squads SET status = 'active', deleted_at = NULL, updated_at = ? WHERE id = ? AND deleted_at IS NOT NULL",
|
|
77392
|
+
args: [now, id]
|
|
77393
|
+
});
|
|
77394
|
+
if (result.rowsAffected === 0) return null;
|
|
77395
|
+
return getSquadRow(id, database);
|
|
77396
|
+
}
|
|
77397
|
+
async function listDeletedSquads(db) {
|
|
77398
|
+
const database = db ?? await getDatabase();
|
|
77399
|
+
const result = await database.execute(
|
|
77400
|
+
"SELECT * FROM squads WHERE deleted_at IS NOT NULL ORDER BY deleted_at DESC, id DESC"
|
|
77401
|
+
);
|
|
77402
|
+
return result.rows.map((row) => mapSquad(row));
|
|
77403
|
+
}
|
|
77377
77404
|
async function getSquadByRepo(repoOwner, repoName, db) {
|
|
77378
77405
|
const database = db ?? await getDatabase();
|
|
77379
77406
|
const result = await database.execute({
|
|
77380
|
-
sql: "SELECT * FROM squads WHERE repo_owner = ? AND repo_name = ? LIMIT 1",
|
|
77407
|
+
sql: "SELECT * FROM squads WHERE repo_owner = ? AND repo_name = ? AND deleted_at IS NULL LIMIT 1",
|
|
77381
77408
|
args: [repoOwner, repoName]
|
|
77382
77409
|
});
|
|
77383
77410
|
const row = result.rows[0];
|
|
@@ -77481,7 +77508,8 @@ function mapSquad(row) {
|
|
|
77481
77508
|
status: asString(row.status),
|
|
77482
77509
|
config: parseJson(asString(row.config)),
|
|
77483
77510
|
createdAt: asString(row.created_at),
|
|
77484
|
-
updatedAt: asString(row.updated_at)
|
|
77511
|
+
updatedAt: asString(row.updated_at),
|
|
77512
|
+
deletedAt: asNullableString(row.deleted_at)
|
|
77485
77513
|
};
|
|
77486
77514
|
}
|
|
77487
77515
|
function mapMember(row) {
|
|
@@ -79724,6 +79752,39 @@ router7.delete("/api/squads/:id", async (req, res) => {
|
|
|
79724
79752
|
});
|
|
79725
79753
|
}
|
|
79726
79754
|
});
|
|
79755
|
+
router7.get("/api/squads/deleted", async (_req, res) => {
|
|
79756
|
+
try {
|
|
79757
|
+
const squads = await listDeletedSquads();
|
|
79758
|
+
res.status(200).json({ squads });
|
|
79759
|
+
} catch (error51) {
|
|
79760
|
+
res.status(500).json({
|
|
79761
|
+
error: "Failed to list deleted squads",
|
|
79762
|
+
details: error51 instanceof Error ? error51.message : "Unknown error"
|
|
79763
|
+
});
|
|
79764
|
+
}
|
|
79765
|
+
});
|
|
79766
|
+
router7.post("/api/squads/:id/restore", async (req, res) => {
|
|
79767
|
+
try {
|
|
79768
|
+
const restored = await restoreSquad(req.params.id);
|
|
79769
|
+
if (!restored) {
|
|
79770
|
+
res.status(404).json({ error: "Squad not found or not deleted" });
|
|
79771
|
+
return;
|
|
79772
|
+
}
|
|
79773
|
+
await logActivity({
|
|
79774
|
+
squadId: restored.id,
|
|
79775
|
+
event: EVENT_NAMES.SQUAD_UPDATED,
|
|
79776
|
+
description: `Restored squad ${restored.name}`,
|
|
79777
|
+
metadata: { repoUrl: restored.repoUrl }
|
|
79778
|
+
});
|
|
79779
|
+
eventBus.emit(EVENT_NAMES.SQUAD_UPDATED, { squad: restored });
|
|
79780
|
+
res.status(200).json({ squad: restored });
|
|
79781
|
+
} catch (error51) {
|
|
79782
|
+
res.status(500).json({
|
|
79783
|
+
error: "Failed to restore squad",
|
|
79784
|
+
details: error51 instanceof Error ? error51.message : "Unknown error"
|
|
79785
|
+
});
|
|
79786
|
+
}
|
|
79787
|
+
});
|
|
79727
79788
|
router7.get("/api/squads/:id/members", async (req, res) => {
|
|
79728
79789
|
try {
|
|
79729
79790
|
const squad = await resolveSquad(req.params.id);
|
|
@@ -80828,10 +80889,16 @@ async function fetchModelCatalog() {
|
|
|
80828
80889
|
// packages/daemon/src/models/pricing-scraper.ts
|
|
80829
80890
|
var TOKEN_UNIT_COSTS_URL = "https://docs.github.com/en/billing/reference/costs-for-github-models";
|
|
80830
80891
|
var PREMIUM_MULTIPLIERS_URL = "https://docs.github.com/en/copilot/reference/copilot-billing/request-based-billing-legacy/model-multipliers-for-annual-plans";
|
|
80892
|
+
var COPILOT_PRICING_URL = "https://docs.github.com/api/article/body?pathname=/en/copilot/reference/copilot-billing/models-and-pricing";
|
|
80893
|
+
var PRICE_TO_MULTIPLIER = 0.1;
|
|
80831
80894
|
async function scrapeTokenUnitPricing() {
|
|
80832
80895
|
const html = await fetchPage(TOKEN_UNIT_COSTS_URL);
|
|
80833
80896
|
return parseTokenUnitTable(html);
|
|
80834
80897
|
}
|
|
80898
|
+
async function scrapeCopilotPricing() {
|
|
80899
|
+
const markdown = await fetchMarkdown(COPILOT_PRICING_URL);
|
|
80900
|
+
return parseCopilotPricingMarkdown(markdown);
|
|
80901
|
+
}
|
|
80835
80902
|
async function scrapePremiumRequestPricing() {
|
|
80836
80903
|
const html = await fetchPage(PREMIUM_MULTIPLIERS_URL);
|
|
80837
80904
|
return parsePremiumMultiplierTable(html);
|
|
@@ -80849,6 +80916,19 @@ async function fetchPage(url2) {
|
|
|
80849
80916
|
}
|
|
80850
80917
|
return response.text();
|
|
80851
80918
|
}
|
|
80919
|
+
async function fetchMarkdown(url2) {
|
|
80920
|
+
const response = await fetch(url2, {
|
|
80921
|
+
headers: {
|
|
80922
|
+
Accept: "text/markdown, text/plain, */*",
|
|
80923
|
+
"User-Agent": "IO-Daemon/4.0 (pricing-refresh)"
|
|
80924
|
+
},
|
|
80925
|
+
redirect: "follow"
|
|
80926
|
+
});
|
|
80927
|
+
if (!response.ok) {
|
|
80928
|
+
throw new Error(`Failed to fetch ${url2}: ${response.status} ${response.statusText}`);
|
|
80929
|
+
}
|
|
80930
|
+
return response.text();
|
|
80931
|
+
}
|
|
80852
80932
|
function parseTokenUnitTable(html) {
|
|
80853
80933
|
const results = [];
|
|
80854
80934
|
const tableRowPattern = /<tr[^>]*>\s*<td[^>]*>([^<]+)<\/td>\s*<td[^>]*>([^<]+)<\/td>\s*<td[^>]*>([^<]*)<\/td>\s*<td[^>]*>([^<]+)<\/td>/gi;
|
|
@@ -80883,140 +80963,74 @@ function parsePremiumMultiplierTable(html) {
|
|
|
80883
80963
|
function cleanCellText(text) {
|
|
80884
80964
|
return text.replace(/<[^>]*>/g, "").replace(/&[^;]+;/g, " ").trim();
|
|
80885
80965
|
}
|
|
80886
|
-
|
|
80887
|
-
|
|
80888
|
-
|
|
80889
|
-
|
|
80890
|
-
|
|
80891
|
-
|
|
80892
|
-
|
|
80893
|
-
|
|
80894
|
-
|
|
80895
|
-
|
|
80896
|
-
|
|
80897
|
-
|
|
80898
|
-
|
|
80899
|
-
|
|
80900
|
-
|
|
80901
|
-
|
|
80902
|
-
|
|
80903
|
-
|
|
80904
|
-
tokenOutputMultiplier: 1,
|
|
80905
|
-
cachedInputMultiplier: 0.125,
|
|
80906
|
-
tier: "trivial",
|
|
80907
|
-
available: true
|
|
80908
|
-
},
|
|
80909
|
-
{
|
|
80910
|
-
id: "gpt-5-mini",
|
|
80911
|
-
displayName: "GPT-5 mini",
|
|
80912
|
-
premiumMultiplier: 0.33,
|
|
80913
|
-
tokenInputMultiplier: null,
|
|
80914
|
-
tokenOutputMultiplier: null,
|
|
80915
|
-
cachedInputMultiplier: null,
|
|
80916
|
-
tier: "trivial",
|
|
80917
|
-
available: true
|
|
80918
|
-
},
|
|
80919
|
-
{
|
|
80920
|
-
id: "claude-sonnet-4",
|
|
80921
|
-
displayName: "Claude Sonnet 4",
|
|
80922
|
-
premiumMultiplier: 6,
|
|
80923
|
-
tokenInputMultiplier: 0.6,
|
|
80924
|
-
tokenOutputMultiplier: 2.4,
|
|
80925
|
-
cachedInputMultiplier: null,
|
|
80926
|
-
tier: "premium",
|
|
80927
|
-
available: true
|
|
80928
|
-
},
|
|
80929
|
-
{
|
|
80930
|
-
id: "claude-haiku-4.5",
|
|
80931
|
-
displayName: "Claude Haiku 4.5",
|
|
80932
|
-
premiumMultiplier: 0.33,
|
|
80933
|
-
tokenInputMultiplier: null,
|
|
80934
|
-
tokenOutputMultiplier: null,
|
|
80935
|
-
cachedInputMultiplier: null,
|
|
80936
|
-
tier: "trivial",
|
|
80937
|
-
available: true
|
|
80938
|
-
},
|
|
80939
|
-
{
|
|
80940
|
-
id: "gemini-2.5-pro",
|
|
80941
|
-
displayName: "Gemini 2.5 Pro",
|
|
80942
|
-
premiumMultiplier: 1,
|
|
80943
|
-
tokenInputMultiplier: null,
|
|
80944
|
-
tokenOutputMultiplier: null,
|
|
80945
|
-
cachedInputMultiplier: null,
|
|
80946
|
-
tier: "fast",
|
|
80947
|
-
available: true
|
|
80948
|
-
},
|
|
80949
|
-
{
|
|
80950
|
-
id: "gpt-5.1",
|
|
80951
|
-
displayName: "GPT-5.1",
|
|
80952
|
-
premiumMultiplier: 3,
|
|
80953
|
-
tokenInputMultiplier: null,
|
|
80954
|
-
tokenOutputMultiplier: null,
|
|
80955
|
-
cachedInputMultiplier: null,
|
|
80956
|
-
tier: "standard",
|
|
80957
|
-
available: true
|
|
80958
|
-
},
|
|
80959
|
-
{
|
|
80960
|
-
id: "gpt-5.2",
|
|
80961
|
-
displayName: "GPT-5.2",
|
|
80962
|
-
premiumMultiplier: 3,
|
|
80963
|
-
tokenInputMultiplier: null,
|
|
80964
|
-
tokenOutputMultiplier: null,
|
|
80965
|
-
cachedInputMultiplier: null,
|
|
80966
|
-
tier: "standard",
|
|
80967
|
-
available: true
|
|
80968
|
-
},
|
|
80969
|
-
{
|
|
80970
|
-
id: "gpt-5.4",
|
|
80971
|
-
displayName: "GPT-5.4",
|
|
80972
|
-
premiumMultiplier: 6,
|
|
80973
|
-
tokenInputMultiplier: null,
|
|
80974
|
-
tokenOutputMultiplier: null,
|
|
80975
|
-
cachedInputMultiplier: null,
|
|
80976
|
-
tier: "premium",
|
|
80977
|
-
available: true
|
|
80978
|
-
},
|
|
80979
|
-
{
|
|
80980
|
-
id: "claude-opus-4.5",
|
|
80981
|
-
displayName: "Claude Opus 4.5",
|
|
80982
|
-
premiumMultiplier: 15,
|
|
80983
|
-
tokenInputMultiplier: null,
|
|
80984
|
-
tokenOutputMultiplier: null,
|
|
80985
|
-
cachedInputMultiplier: null,
|
|
80986
|
-
tier: "premium",
|
|
80987
|
-
available: true
|
|
80988
|
-
},
|
|
80989
|
-
{
|
|
80990
|
-
id: "claude-opus-4.6",
|
|
80991
|
-
displayName: "Claude Opus 4.6",
|
|
80992
|
-
premiumMultiplier: 27,
|
|
80993
|
-
tokenInputMultiplier: null,
|
|
80994
|
-
tokenOutputMultiplier: null,
|
|
80995
|
-
cachedInputMultiplier: null,
|
|
80996
|
-
tier: "ultra",
|
|
80997
|
-
available: true
|
|
80998
|
-
},
|
|
80999
|
-
{
|
|
81000
|
-
id: "claude-opus-4.7",
|
|
81001
|
-
displayName: "Claude Opus 4.7",
|
|
81002
|
-
premiumMultiplier: 27,
|
|
81003
|
-
tokenInputMultiplier: null,
|
|
81004
|
-
tokenOutputMultiplier: null,
|
|
81005
|
-
cachedInputMultiplier: null,
|
|
81006
|
-
tier: "ultra",
|
|
81007
|
-
available: true
|
|
81008
|
-
},
|
|
81009
|
-
{
|
|
81010
|
-
id: "gpt-5.5",
|
|
81011
|
-
displayName: "GPT-5.5",
|
|
81012
|
-
premiumMultiplier: 57,
|
|
81013
|
-
tokenInputMultiplier: null,
|
|
81014
|
-
tokenOutputMultiplier: null,
|
|
81015
|
-
cachedInputMultiplier: null,
|
|
81016
|
-
tier: "ultra",
|
|
81017
|
-
available: true
|
|
80966
|
+
function parseCopilotPricingMarkdown(markdown) {
|
|
80967
|
+
const results = [];
|
|
80968
|
+
const seenModels = /* @__PURE__ */ new Set();
|
|
80969
|
+
const lines = markdown.split("\n");
|
|
80970
|
+
let columnIndices = null;
|
|
80971
|
+
for (const line of lines) {
|
|
80972
|
+
const trimmed = line.trim();
|
|
80973
|
+
if (!trimmed.startsWith("|")) continue;
|
|
80974
|
+
if (/\|\s*Model\s/i.test(trimmed)) {
|
|
80975
|
+
columnIndices = parseHeaderColumns(trimmed);
|
|
80976
|
+
continue;
|
|
80977
|
+
}
|
|
80978
|
+
if (/^[\s|:-]+$/.test(trimmed) || !columnIndices) continue;
|
|
80979
|
+
const entry = parseDataRow(trimmed, columnIndices);
|
|
80980
|
+
if (entry && !seenModels.has(entry.modelName.toLowerCase())) {
|
|
80981
|
+
seenModels.add(entry.modelName.toLowerCase());
|
|
80982
|
+
results.push(entry);
|
|
80983
|
+
}
|
|
81018
80984
|
}
|
|
81019
|
-
|
|
80985
|
+
return results;
|
|
80986
|
+
}
|
|
80987
|
+
function parseDataRow(line, columnIndices) {
|
|
80988
|
+
const cells = splitMarkdownRow(line);
|
|
80989
|
+
if (cells.length <= columnIndices.output) return null;
|
|
80990
|
+
const modelName = cells[columnIndices.model].trim();
|
|
80991
|
+
const inputPrice = parseDollarValue(cells[columnIndices.input]);
|
|
80992
|
+
const cachedPrice = columnIndices.cached >= 0 ? parseDollarValue(cells[columnIndices.cached]) : null;
|
|
80993
|
+
const outputPrice = parseDollarValue(cells[columnIndices.output]);
|
|
80994
|
+
if (!modelName || inputPrice === null || outputPrice === null) return null;
|
|
80995
|
+
return {
|
|
80996
|
+
modelName,
|
|
80997
|
+
inputMultiplier: inputPrice * PRICE_TO_MULTIPLIER,
|
|
80998
|
+
cachedInputMultiplier: cachedPrice !== null ? cachedPrice * PRICE_TO_MULTIPLIER : null,
|
|
80999
|
+
outputMultiplier: outputPrice * PRICE_TO_MULTIPLIER
|
|
81000
|
+
};
|
|
81001
|
+
}
|
|
81002
|
+
function parseHeaderColumns(headerLine) {
|
|
81003
|
+
const cells = splitMarkdownRow(headerLine).map((c) => c.trim().toLowerCase());
|
|
81004
|
+
const model = cells.findIndex((c) => c === "model" || c === "model name");
|
|
81005
|
+
const input = cells.findIndex(
|
|
81006
|
+
(c) => (c === "input" || c === "input multiplier") && !c.includes("cached")
|
|
81007
|
+
);
|
|
81008
|
+
const cached2 = cells.findIndex(
|
|
81009
|
+
(c) => c.includes("cached input") || c === "cached input multiplier"
|
|
81010
|
+
);
|
|
81011
|
+
const output = cells.findIndex(
|
|
81012
|
+
(c) => (c === "output" || c === "output multiplier") && !c.includes("cached")
|
|
81013
|
+
);
|
|
81014
|
+
if (model < 0 || input < 0 || output < 0) {
|
|
81015
|
+
return null;
|
|
81016
|
+
}
|
|
81017
|
+
return { model, input, cached: cached2 >= 0 ? cached2 : -1, output };
|
|
81018
|
+
}
|
|
81019
|
+
function splitMarkdownRow(line) {
|
|
81020
|
+
const parts = line.split("|");
|
|
81021
|
+
if (parts[0].trim() === "") parts.shift();
|
|
81022
|
+
if (parts[parts.length - 1]?.trim() === "") parts.pop();
|
|
81023
|
+
return parts;
|
|
81024
|
+
}
|
|
81025
|
+
function parseDollarValue(cell) {
|
|
81026
|
+
if (!cell) return null;
|
|
81027
|
+
const cleaned = cell.trim().replace(/[$,]/g, "");
|
|
81028
|
+
if (cleaned.toLowerCase() === "n/a" || cleaned === "" || cleaned === "-") {
|
|
81029
|
+
return null;
|
|
81030
|
+
}
|
|
81031
|
+
const value = Number.parseFloat(cleaned);
|
|
81032
|
+
return Number.isNaN(value) ? null : value;
|
|
81033
|
+
}
|
|
81020
81034
|
|
|
81021
81035
|
// packages/daemon/src/models/types.ts
|
|
81022
81036
|
var TIER_RANGES = {
|
|
@@ -81109,22 +81123,52 @@ async function scrapePremiumPricingIntoMap(modelMap, result, logger2) {
|
|
|
81109
81123
|
logger2?.warn(`Premium pricing scrape failed: ${msg}`);
|
|
81110
81124
|
}
|
|
81111
81125
|
}
|
|
81126
|
+
async function scrapeCopilotPricingIntoMap(modelMap, result, logger2) {
|
|
81127
|
+
try {
|
|
81128
|
+
const copilotPricing = await scrapeCopilotPricing();
|
|
81129
|
+
result.copilotPricingScraped = true;
|
|
81130
|
+
for (const cp of copilotPricing) {
|
|
81131
|
+
const key = normalizeModelName(cp.modelName);
|
|
81132
|
+
const existing = modelMap.get(key) ?? findClosestKey(modelMap, key);
|
|
81133
|
+
if (existing) {
|
|
81134
|
+
existing.tokenInputMultiplier = cp.inputMultiplier;
|
|
81135
|
+
existing.tokenOutputMultiplier = cp.outputMultiplier;
|
|
81136
|
+
if (cp.cachedInputMultiplier !== null) {
|
|
81137
|
+
existing.cachedInputMultiplier = cp.cachedInputMultiplier;
|
|
81138
|
+
}
|
|
81139
|
+
} else {
|
|
81140
|
+
modelMap.set(key, {
|
|
81141
|
+
id: key,
|
|
81142
|
+
displayName: cp.modelName,
|
|
81143
|
+
tokenInputMultiplier: cp.inputMultiplier,
|
|
81144
|
+
tokenOutputMultiplier: cp.outputMultiplier,
|
|
81145
|
+
cachedInputMultiplier: cp.cachedInputMultiplier,
|
|
81146
|
+
available: true
|
|
81147
|
+
});
|
|
81148
|
+
}
|
|
81149
|
+
}
|
|
81150
|
+
} catch (error51) {
|
|
81151
|
+
const msg = error51 instanceof Error ? error51.message : String(error51);
|
|
81152
|
+
result.errors.push(`Copilot pricing scrape failed: ${msg}`);
|
|
81153
|
+
logger2?.warn(`Copilot pricing scrape failed: ${msg}`);
|
|
81154
|
+
}
|
|
81155
|
+
}
|
|
81112
81156
|
async function refreshModelPricing(logger2) {
|
|
81113
81157
|
const result = {
|
|
81114
81158
|
modelsUpdated: 0,
|
|
81115
81159
|
catalogFetched: false,
|
|
81116
81160
|
tokenPricingScraped: false,
|
|
81117
81161
|
premiumPricingScraped: false,
|
|
81162
|
+
copilotPricingScraped: false,
|
|
81118
81163
|
errors: []
|
|
81119
81164
|
};
|
|
81120
81165
|
const modelMap = /* @__PURE__ */ new Map();
|
|
81121
81166
|
await fetchCatalogIntoMap(modelMap, result, logger2);
|
|
81122
81167
|
await scrapeTokenPricingIntoMap(modelMap, result, logger2);
|
|
81168
|
+
await scrapeCopilotPricingIntoMap(modelMap, result, logger2);
|
|
81123
81169
|
await scrapePremiumPricingIntoMap(modelMap, result, logger2);
|
|
81124
|
-
if (!result.catalogFetched && !result.tokenPricingScraped && !result.premiumPricingScraped) {
|
|
81125
|
-
logger2?.warn("All pricing sources failed,
|
|
81126
|
-
await seedFromFallback();
|
|
81127
|
-
result.modelsUpdated = SEED_MODELS.length;
|
|
81170
|
+
if (!result.catalogFetched && !result.tokenPricingScraped && !result.premiumPricingScraped && !result.copilotPricingScraped) {
|
|
81171
|
+
logger2?.warn("All pricing sources failed, no models available");
|
|
81128
81172
|
return result;
|
|
81129
81173
|
}
|
|
81130
81174
|
const db = await getDatabase();
|
|
@@ -81146,13 +81190,6 @@ async function refreshModelPricing(logger2) {
|
|
|
81146
81190
|
}
|
|
81147
81191
|
return result;
|
|
81148
81192
|
}
|
|
81149
|
-
async function seedFromFallback() {
|
|
81150
|
-
const db = await getDatabase();
|
|
81151
|
-
const now = nowIso();
|
|
81152
|
-
for (const model of SEED_MODELS) {
|
|
81153
|
-
await upsertModel(db, { ...model, updatedAt: now });
|
|
81154
|
-
}
|
|
81155
|
-
}
|
|
81156
81193
|
async function getModelPricing(modelId) {
|
|
81157
81194
|
const db = await getDatabase();
|
|
81158
81195
|
const result = await db.execute({
|
|
@@ -83374,7 +83411,9 @@ var addSquadMemberSchema = external_exports.object({
|
|
|
83374
83411
|
squadId: external_exports.string().trim().min(1),
|
|
83375
83412
|
role: external_exports.string().trim().min(1).describe("Slug-style role identifier (e.g. 'senior-frontend-engineer', 'team-lead')"),
|
|
83376
83413
|
name: external_exports.string().trim().min(1).describe("Display name for the member (e.g. 'Senior Frontend Engineer')"),
|
|
83377
|
-
systemPrompt: external_exports.string().min(1).describe(
|
|
83414
|
+
systemPrompt: external_exports.string().min(1).describe(
|
|
83415
|
+
"The system prompt defining this member's expertise, responsibilities, and behavior."
|
|
83416
|
+
),
|
|
83378
83417
|
model: external_exports.string().optional().describe("Model override for this member. Uses squad default if not provided.")
|
|
83379
83418
|
});
|
|
83380
83419
|
var removeSquadMemberSchema = external_exports.object({
|
|
@@ -83446,10 +83485,22 @@ var squadToolDefinitions = [
|
|
|
83446
83485
|
},
|
|
83447
83486
|
{
|
|
83448
83487
|
name: "fire_squad",
|
|
83449
|
-
description: "
|
|
83488
|
+
description: "Soft-delete a squad. The squad can be restored later with restore_squad.",
|
|
83450
83489
|
parameters: squadIdSchema,
|
|
83451
83490
|
skipPermission: true
|
|
83452
83491
|
},
|
|
83492
|
+
{
|
|
83493
|
+
name: "restore_squad",
|
|
83494
|
+
description: "Restore a previously deleted squad and all its members.",
|
|
83495
|
+
parameters: squadIdSchema,
|
|
83496
|
+
skipPermission: true
|
|
83497
|
+
},
|
|
83498
|
+
{
|
|
83499
|
+
name: "list_deleted_squads",
|
|
83500
|
+
description: "List all soft-deleted squads that can be restored.",
|
|
83501
|
+
parameters: external_exports.object({}),
|
|
83502
|
+
skipPermission: true
|
|
83503
|
+
},
|
|
83453
83504
|
{
|
|
83454
83505
|
name: "list_squads",
|
|
83455
83506
|
description: "List all squads and their status.",
|
|
@@ -83649,7 +83700,7 @@ async function processQueue2(squadId) {
|
|
|
83649
83700
|
const next = await getNextQueued(squadId);
|
|
83650
83701
|
if (next) {
|
|
83651
83702
|
const freshSquad = await getSquad(squadId);
|
|
83652
|
-
if (freshSquad) {
|
|
83703
|
+
if (freshSquad && next.objectiveId) {
|
|
83653
83704
|
void startAndExecuteInstance(next.id, freshSquad, next.objectiveId);
|
|
83654
83705
|
}
|
|
83655
83706
|
}
|
|
@@ -83784,13 +83835,28 @@ async function handleFireSquad(rawArgs) {
|
|
|
83784
83835
|
if (activeObjectives.length > 0) {
|
|
83785
83836
|
const updated = await updateSquad(squadId, { status: "inactive" });
|
|
83786
83837
|
return {
|
|
83787
|
-
message: `Squad ${squadId} was deactivated because it still has active objectives.`,
|
|
83838
|
+
message: `Squad ${squadId} was deactivated because it still has active objectives. Use fire_squad again after objectives complete to delete it.`,
|
|
83788
83839
|
squad: updated,
|
|
83789
83840
|
activeObjectives
|
|
83790
83841
|
};
|
|
83791
83842
|
}
|
|
83792
83843
|
await deleteSquad(squadId);
|
|
83793
|
-
return {
|
|
83844
|
+
return {
|
|
83845
|
+
message: `Squad "${squad.name}" has been deleted. It can be restored with restore_squad if needed.`,
|
|
83846
|
+
squadId
|
|
83847
|
+
};
|
|
83848
|
+
}
|
|
83849
|
+
async function handleRestoreSquad(rawArgs) {
|
|
83850
|
+
const { squadId } = squadIdSchema.parse(rawArgs);
|
|
83851
|
+
const restored = await restoreSquad(squadId);
|
|
83852
|
+
if (!restored) {
|
|
83853
|
+
throw new Error(`Squad ${squadId} was not found or is not deleted.`);
|
|
83854
|
+
}
|
|
83855
|
+
eventBus.emit(EVENT_NAMES.SQUAD_UPDATED, { squad: restored });
|
|
83856
|
+
return {
|
|
83857
|
+
message: `Squad "${restored.name}" has been restored.`,
|
|
83858
|
+
squad: restored
|
|
83859
|
+
};
|
|
83794
83860
|
}
|
|
83795
83861
|
async function handleDelegateToSquad(rawArgs) {
|
|
83796
83862
|
const { squadId, objective } = delegateToSquadSchema.parse(rawArgs);
|
|
@@ -83840,7 +83906,7 @@ async function handleUpdateSquadMember(rawArgs) {
|
|
|
83840
83906
|
member: updated
|
|
83841
83907
|
};
|
|
83842
83908
|
}
|
|
83843
|
-
function createSquadToolExecutor(
|
|
83909
|
+
function createSquadToolExecutor(_config) {
|
|
83844
83910
|
return async (toolName, rawArgs) => {
|
|
83845
83911
|
switch (toolName) {
|
|
83846
83912
|
case "create_squad":
|
|
@@ -83855,11 +83921,26 @@ function createSquadToolExecutor(config2) {
|
|
|
83855
83921
|
return handleAnalyzeRepo(rawArgs);
|
|
83856
83922
|
case "fire_squad":
|
|
83857
83923
|
return handleFireSquad(rawArgs);
|
|
83924
|
+
case "restore_squad":
|
|
83925
|
+
return handleRestoreSquad(rawArgs);
|
|
83926
|
+
case "list_deleted_squads": {
|
|
83927
|
+
const deletedSquads = await listDeletedSquads();
|
|
83928
|
+
if (deletedSquads.length === 0) {
|
|
83929
|
+
return { message: "No deleted squads.", squads: [] };
|
|
83930
|
+
}
|
|
83931
|
+
const list = deletedSquads.map((s) => `${s.id}: ${s.name} (${s.repoOwner}/${s.repoName}) [deleted ${s.deletedAt}]`).join("\n");
|
|
83932
|
+
return { message: list, squads: deletedSquads };
|
|
83933
|
+
}
|
|
83858
83934
|
case "list_squads": {
|
|
83859
83935
|
const squads = await listSquads();
|
|
83936
|
+
const deletedCount = (await listDeletedSquads()).length;
|
|
83937
|
+
const suffix = deletedCount > 0 ? `
|
|
83938
|
+
|
|
83939
|
+
${deletedCount} deleted squad(s) available for restore (use list_deleted_squads to view).` : "";
|
|
83860
83940
|
return {
|
|
83861
|
-
message: formatSquadList(squads),
|
|
83862
|
-
squads
|
|
83941
|
+
message: formatSquadList(squads) + suffix,
|
|
83942
|
+
squads,
|
|
83943
|
+
deletedCount
|
|
83863
83944
|
};
|
|
83864
83945
|
}
|
|
83865
83946
|
case "get_squad_status": {
|
|
@@ -84606,8 +84687,7 @@ async function main() {
|
|
|
84606
84687
|
logger2.info("Database initialized");
|
|
84607
84688
|
const pricingResult = await refreshModelPricing(logger2);
|
|
84608
84689
|
if (pricingResult.modelsUpdated === 0) {
|
|
84609
|
-
logger2.warn("Model pricing refresh returned 0 models
|
|
84610
|
-
await seedFromFallback();
|
|
84690
|
+
logger2.warn("Model pricing refresh returned 0 models");
|
|
84611
84691
|
}
|
|
84612
84692
|
logger2.info({ modelsUpdated: pricingResult.modelsUpdated }, "Model pricing initialized");
|
|
84613
84693
|
await scanSkills();
|