heyio 4.0.3 → 4.0.5
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 +807 -245
- package/dist/daemon/index.js +759 -237
- package/dist/web/assets/{index-Bkx7szi0.js → index-DNdaxCqk.js} +76 -76
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
package/dist/daemon/cli.js
CHANGED
|
@@ -75,18 +75,15 @@ var init_api = __esm({
|
|
|
75
75
|
});
|
|
76
76
|
|
|
77
77
|
// packages/shared/dist/constants.js
|
|
78
|
-
var APP_NAME, APP_VERSION, API_PORT, API_HOST, DEFAULT_MODEL,
|
|
78
|
+
var APP_NAME, APP_VERSION, API_PORT, API_HOST, DEFAULT_MODEL, SESSION_RESET_THRESHOLD, SCHEDULER_INTERVAL_MS, QA_MAX_REVISIONS, MANDATORY_ROLES, EVENT_NAMES;
|
|
79
79
|
var init_constants = __esm({
|
|
80
80
|
"packages/shared/dist/constants.js"() {
|
|
81
81
|
"use strict";
|
|
82
82
|
APP_NAME = "io";
|
|
83
|
-
APP_VERSION = "4.0.
|
|
83
|
+
APP_VERSION = "4.0.5";
|
|
84
84
|
API_PORT = 7777;
|
|
85
85
|
API_HOST = "0.0.0.0";
|
|
86
|
-
DEFAULT_MODEL = "gpt-
|
|
87
|
-
FAST_MODEL = "gpt-4.1-mini";
|
|
88
|
-
STANDARD_MODEL = "claude-sonnet-4.6";
|
|
89
|
-
PREMIUM_MODEL = "claude-sonnet-4.6";
|
|
86
|
+
DEFAULT_MODEL = "gpt-4o";
|
|
90
87
|
SESSION_RESET_THRESHOLD = 50;
|
|
91
88
|
SCHEDULER_INTERVAL_MS = 6e4;
|
|
92
89
|
QA_MAX_REVISIONS = 3;
|
|
@@ -2067,6 +2064,27 @@ var init_db = __esm({
|
|
|
2067
2064
|
"CREATE INDEX IF NOT EXISTS idx_activity_objective_id ON activity(objective_id)",
|
|
2068
2065
|
"CREATE INDEX IF NOT EXISTS idx_agent_history_agent_id_created_at ON agent_history(agent_id, created_at)"
|
|
2069
2066
|
]
|
|
2067
|
+
},
|
|
2068
|
+
{
|
|
2069
|
+
version: 2,
|
|
2070
|
+
name: "add-model-pricing-and-dual-costs",
|
|
2071
|
+
statements: [
|
|
2072
|
+
`CREATE TABLE IF NOT EXISTS model_pricing (
|
|
2073
|
+
id TEXT PRIMARY KEY,
|
|
2074
|
+
display_name TEXT NOT NULL,
|
|
2075
|
+
premium_multiplier REAL,
|
|
2076
|
+
token_input_multiplier REAL,
|
|
2077
|
+
token_output_multiplier REAL,
|
|
2078
|
+
cached_input_multiplier REAL,
|
|
2079
|
+
tier TEXT NOT NULL,
|
|
2080
|
+
available INTEGER NOT NULL DEFAULT 1,
|
|
2081
|
+
updated_at TEXT NOT NULL
|
|
2082
|
+
)`,
|
|
2083
|
+
"CREATE INDEX IF NOT EXISTS idx_model_pricing_tier ON model_pricing(tier)",
|
|
2084
|
+
"CREATE INDEX IF NOT EXISTS idx_model_pricing_available ON model_pricing(available)",
|
|
2085
|
+
"ALTER TABLE token_usage ADD COLUMN premium_request_cost REAL",
|
|
2086
|
+
"ALTER TABLE token_usage ADD COLUMN token_unit_cost REAL"
|
|
2087
|
+
]
|
|
2070
2088
|
}
|
|
2071
2089
|
];
|
|
2072
2090
|
client = null;
|
|
@@ -11817,8 +11835,8 @@ async function recordUsage(data, db) {
|
|
|
11817
11835
|
createdAt: data.createdAt ?? nowIso()
|
|
11818
11836
|
};
|
|
11819
11837
|
await database.execute({
|
|
11820
|
-
sql: `INSERT INTO token_usage (id, squad_id, agent_id, model, input_tokens, output_tokens, cost, created_at)
|
|
11821
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
11838
|
+
sql: `INSERT INTO token_usage (id, squad_id, agent_id, model, input_tokens, output_tokens, cost, premium_request_cost, token_unit_cost, created_at)
|
|
11839
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
11822
11840
|
args: [
|
|
11823
11841
|
usage.id,
|
|
11824
11842
|
usage.squadId,
|
|
@@ -11827,6 +11845,8 @@ async function recordUsage(data, db) {
|
|
|
11827
11845
|
usage.inputTokens,
|
|
11828
11846
|
usage.outputTokens,
|
|
11829
11847
|
usage.cost,
|
|
11848
|
+
data.premiumRequestCost ?? null,
|
|
11849
|
+
data.tokenUnitCost ?? null,
|
|
11830
11850
|
usage.createdAt
|
|
11831
11851
|
]
|
|
11832
11852
|
});
|
|
@@ -31154,7 +31174,7 @@ var require_view = __commonJS({
|
|
|
31154
31174
|
var dirname9 = path.dirname;
|
|
31155
31175
|
var basename6 = path.basename;
|
|
31156
31176
|
var extname4 = path.extname;
|
|
31157
|
-
var
|
|
31177
|
+
var join15 = path.join;
|
|
31158
31178
|
var resolve5 = path.resolve;
|
|
31159
31179
|
module2.exports = View;
|
|
31160
31180
|
function View(name, options2) {
|
|
@@ -31216,12 +31236,12 @@ var require_view = __commonJS({
|
|
|
31216
31236
|
};
|
|
31217
31237
|
View.prototype.resolve = function resolve6(dir, file2) {
|
|
31218
31238
|
var ext = this.ext;
|
|
31219
|
-
var path2 =
|
|
31239
|
+
var path2 = join15(dir, file2);
|
|
31220
31240
|
var stat4 = tryStat(path2);
|
|
31221
31241
|
if (stat4 && stat4.isFile()) {
|
|
31222
31242
|
return path2;
|
|
31223
31243
|
}
|
|
31224
|
-
path2 =
|
|
31244
|
+
path2 = join15(dir, basename6(file2, ext), "index" + ext);
|
|
31225
31245
|
stat4 = tryStat(path2);
|
|
31226
31246
|
if (stat4 && stat4.isFile()) {
|
|
31227
31247
|
return path2;
|
|
@@ -34926,7 +34946,7 @@ var require_send = __commonJS({
|
|
|
34926
34946
|
var Stream = __require("stream");
|
|
34927
34947
|
var util = __require("util");
|
|
34928
34948
|
var extname4 = path.extname;
|
|
34929
|
-
var
|
|
34949
|
+
var join15 = path.join;
|
|
34930
34950
|
var normalize = path.normalize;
|
|
34931
34951
|
var resolve5 = path.resolve;
|
|
34932
34952
|
var sep = path.sep;
|
|
@@ -35098,7 +35118,7 @@ var require_send = __commonJS({
|
|
|
35098
35118
|
return res;
|
|
35099
35119
|
}
|
|
35100
35120
|
parts = path2.split(sep);
|
|
35101
|
-
path2 = normalize(
|
|
35121
|
+
path2 = normalize(join15(root, path2));
|
|
35102
35122
|
} else {
|
|
35103
35123
|
if (UP_PATH_REGEXP.test(path2)) {
|
|
35104
35124
|
debug('malicious path "%s"', path2);
|
|
@@ -35231,7 +35251,7 @@ var require_send = __commonJS({
|
|
|
35231
35251
|
if (err) return self.onStatError(err);
|
|
35232
35252
|
return self.error(404);
|
|
35233
35253
|
}
|
|
35234
|
-
var p =
|
|
35254
|
+
var p = join15(path2, self._index[i]);
|
|
35235
35255
|
debug('stat "%s"', p);
|
|
35236
35256
|
fs.stat(p, function(err2, stat4) {
|
|
35237
35257
|
if (err2) return next(err2);
|
|
@@ -51543,6 +51563,9 @@ function readEnvOverrides() {
|
|
|
51543
51563
|
if (process.env.IO_SESSION_RESET_THRESHOLD !== void 0) {
|
|
51544
51564
|
overrides.sessionResetThreshold = process.env.IO_SESSION_RESET_THRESHOLD;
|
|
51545
51565
|
}
|
|
51566
|
+
if (process.env.IO_PRICING_REFRESH_HOURS !== void 0) {
|
|
51567
|
+
overrides.pricingRefreshHours = process.env.IO_PRICING_REFRESH_HOURS;
|
|
51568
|
+
}
|
|
51546
51569
|
return overrides;
|
|
51547
51570
|
}
|
|
51548
51571
|
function loadConfig() {
|
|
@@ -51569,7 +51592,8 @@ var init_config = __esm({
|
|
|
51569
51592
|
telegramUserId: external_exports.string().trim().min(1).nullable().default(null),
|
|
51570
51593
|
supabaseUrl: external_exports.string().trim().min(1).nullable().default(null),
|
|
51571
51594
|
supabaseAnonKey: external_exports.string().trim().min(1).nullable().default(null),
|
|
51572
|
-
sessionResetThreshold: external_exports.coerce.number().int().positive().default(SESSION_RESET_THRESHOLD)
|
|
51595
|
+
sessionResetThreshold: external_exports.coerce.number().int().positive().default(SESSION_RESET_THRESHOLD),
|
|
51596
|
+
pricingRefreshHours: external_exports.coerce.number().positive().default(24)
|
|
51573
51597
|
});
|
|
51574
51598
|
}
|
|
51575
51599
|
});
|
|
@@ -51650,7 +51674,8 @@ var init_settings = __esm({
|
|
|
51650
51674
|
"telegramUserId",
|
|
51651
51675
|
"supabaseUrl",
|
|
51652
51676
|
"supabaseAnonKey",
|
|
51653
|
-
"sessionResetThreshold"
|
|
51677
|
+
"sessionResetThreshold",
|
|
51678
|
+
"pricingRefreshHours"
|
|
51654
51679
|
];
|
|
51655
51680
|
router5.get("/api/settings", async (_req, res) => {
|
|
51656
51681
|
try {
|
|
@@ -51702,13 +51727,20 @@ async function installSkill(request) {
|
|
|
51702
51727
|
const directory = join3(SKILLS_DIR, directoryName);
|
|
51703
51728
|
const existing = installedSkills.find((skill2) => skill2.id === id);
|
|
51704
51729
|
let entryFile = existing?.entryFile ?? null;
|
|
51705
|
-
|
|
51706
|
-
|
|
51730
|
+
let resolvedUrl = request.url;
|
|
51731
|
+
if (source === "skillssh" && resolvedUrl) {
|
|
51732
|
+
const fetchResult = await fetch(resolvedUrl);
|
|
51733
|
+
if (!fetchResult.ok) {
|
|
51734
|
+
resolvedUrl = await resolveSkillsShUrl(request) ?? resolvedUrl;
|
|
51735
|
+
}
|
|
51736
|
+
}
|
|
51737
|
+
if (resolvedUrl) {
|
|
51738
|
+
const response = await fetch(resolvedUrl);
|
|
51707
51739
|
if (!response.ok) {
|
|
51708
|
-
throw new Error(`Failed to fetch skill from ${
|
|
51740
|
+
throw new Error(`Failed to fetch skill from ${resolvedUrl} (${response.status})`);
|
|
51709
51741
|
}
|
|
51710
51742
|
const body = await response.text();
|
|
51711
|
-
entryFile = chooseEntryFileName(
|
|
51743
|
+
entryFile = chooseEntryFileName(resolvedUrl, response.headers.get("content-type"));
|
|
51712
51744
|
await mkdir3(directory, { recursive: true });
|
|
51713
51745
|
await writeFile2(join3(directory, entryFile), body, "utf8");
|
|
51714
51746
|
} else {
|
|
@@ -51795,7 +51827,114 @@ function chooseEntryFileName(url2, contentType) {
|
|
|
51795
51827
|
function isMissingFileError2(error51) {
|
|
51796
51828
|
return !!error51 && typeof error51 === "object" && "code" in error51 && error51.code === "ENOENT";
|
|
51797
51829
|
}
|
|
51798
|
-
|
|
51830
|
+
async function resolveSkillsShUrl(request) {
|
|
51831
|
+
const slug = request.slug?.trim();
|
|
51832
|
+
if (!slug) return null;
|
|
51833
|
+
try {
|
|
51834
|
+
const searchResponse = await fetch(
|
|
51835
|
+
`https://skills.sh/api/search?q=${encodeURIComponent(slug)}&limit=10`,
|
|
51836
|
+
{ signal: AbortSignal.timeout(1e4) }
|
|
51837
|
+
);
|
|
51838
|
+
if (!searchResponse.ok) return null;
|
|
51839
|
+
const data = await searchResponse.json();
|
|
51840
|
+
const match = data.skills?.find(
|
|
51841
|
+
(s) => s.skillId === slug || s.name === slug || s.id.endsWith(`/${slug}`)
|
|
51842
|
+
);
|
|
51843
|
+
if (!match?.source) return null;
|
|
51844
|
+
const headers = {
|
|
51845
|
+
Accept: "application/vnd.github.v3+json",
|
|
51846
|
+
"User-Agent": "io-daemon"
|
|
51847
|
+
};
|
|
51848
|
+
if (process.env.GITHUB_TOKEN) {
|
|
51849
|
+
headers.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`;
|
|
51850
|
+
}
|
|
51851
|
+
const treeResponse = await fetch(
|
|
51852
|
+
`https://api.github.com/repos/${match.source}/git/trees/main?recursive=1`,
|
|
51853
|
+
{ headers, signal: AbortSignal.timeout(15e3) }
|
|
51854
|
+
);
|
|
51855
|
+
if (!treeResponse.ok) return null;
|
|
51856
|
+
const treeData = await treeResponse.json();
|
|
51857
|
+
const skillFile = treeData.tree?.find(
|
|
51858
|
+
(entry) => entry.type === "blob" && entry.path.endsWith(`/${match.skillId}/SKILL.md`)
|
|
51859
|
+
);
|
|
51860
|
+
if (!skillFile) return null;
|
|
51861
|
+
return `https://raw.githubusercontent.com/${match.source}/main/${skillFile.path}`;
|
|
51862
|
+
} catch {
|
|
51863
|
+
return null;
|
|
51864
|
+
}
|
|
51865
|
+
}
|
|
51866
|
+
async function discoverSkillsSh(query) {
|
|
51867
|
+
if (!query) return [];
|
|
51868
|
+
const endpoint = `https://skills.sh/api/search?q=${encodeURIComponent(query)}&limit=50`;
|
|
51869
|
+
const response = await fetch(endpoint, { signal: AbortSignal.timeout(1e4) });
|
|
51870
|
+
if (!response.ok) {
|
|
51871
|
+
throw new Error(`skills.sh returned ${response.status}`);
|
|
51872
|
+
}
|
|
51873
|
+
const data = await response.json();
|
|
51874
|
+
const installedSkills = await readInstalledSkills();
|
|
51875
|
+
const installedIds = new Set(installedSkills.map((s) => s.id));
|
|
51876
|
+
return (data.skills ?? []).map((entry) => {
|
|
51877
|
+
const skillUrl = entry.source ? `https://raw.githubusercontent.com/${entry.source}/main/skills/${entry.skillId}/SKILL.md` : "";
|
|
51878
|
+
return {
|
|
51879
|
+
name: entry.name || entry.skillId,
|
|
51880
|
+
title: entry.name || entry.skillId,
|
|
51881
|
+
description: `${entry.source ?? ""}`,
|
|
51882
|
+
url: skillUrl,
|
|
51883
|
+
source: "skillssh",
|
|
51884
|
+
installed: installedIds.has(`skillssh:${normalizeSlug(entry.skillId || entry.name)}`),
|
|
51885
|
+
registrySource: entry.source ?? void 0,
|
|
51886
|
+
skillId: entry.skillId ?? void 0,
|
|
51887
|
+
installs: entry.installs ?? 0
|
|
51888
|
+
};
|
|
51889
|
+
});
|
|
51890
|
+
}
|
|
51891
|
+
async function discoverAwesomeCopilot(query) {
|
|
51892
|
+
const now = Date.now();
|
|
51893
|
+
if (!awesomeCopilotCache || now - awesomeCopilotCache.fetchedAt > AWESOME_COPILOT_CACHE_TTL) {
|
|
51894
|
+
awesomeCopilotCache = { skills: await fetchAwesomeCopilotList(), fetchedAt: now };
|
|
51895
|
+
}
|
|
51896
|
+
const skills = awesomeCopilotCache.skills;
|
|
51897
|
+
if (!query) return skills;
|
|
51898
|
+
const needle = query.toLowerCase();
|
|
51899
|
+
return skills.filter(
|
|
51900
|
+
(s) => s.name.toLowerCase().includes(needle) || s.title.toLowerCase().includes(needle) || s.description.toLowerCase().includes(needle)
|
|
51901
|
+
);
|
|
51902
|
+
}
|
|
51903
|
+
async function fetchAwesomeCopilotList() {
|
|
51904
|
+
const treeUrl = "https://api.github.com/repos/github/awesome-copilot/git/trees/main?recursive=1";
|
|
51905
|
+
const headers = {
|
|
51906
|
+
Accept: "application/vnd.github.v3+json",
|
|
51907
|
+
"User-Agent": "io-daemon"
|
|
51908
|
+
};
|
|
51909
|
+
if (process.env.GITHUB_TOKEN) {
|
|
51910
|
+
headers.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`;
|
|
51911
|
+
}
|
|
51912
|
+
const response = await fetch(treeUrl, { headers, signal: AbortSignal.timeout(15e3) });
|
|
51913
|
+
if (!response.ok) {
|
|
51914
|
+
throw new Error(`GitHub API returned ${response.status}`);
|
|
51915
|
+
}
|
|
51916
|
+
const data = await response.json();
|
|
51917
|
+
const installedSkills = await readInstalledSkills();
|
|
51918
|
+
const installedIds = new Set(installedSkills.map((s) => s.id));
|
|
51919
|
+
const skillEntries = (data.tree ?? []).filter(
|
|
51920
|
+
(entry) => entry.type === "blob" && entry.path.startsWith("skills/") && entry.path.endsWith("/SKILL.md")
|
|
51921
|
+
);
|
|
51922
|
+
return skillEntries.map((entry) => {
|
|
51923
|
+
const parts = entry.path.split("/");
|
|
51924
|
+
const skillName = parts[1] ?? "unknown";
|
|
51925
|
+
const slug = normalizeSlug(skillName);
|
|
51926
|
+
const rawUrl = `https://raw.githubusercontent.com/github/awesome-copilot/main/${entry.path}`;
|
|
51927
|
+
return {
|
|
51928
|
+
name: skillName,
|
|
51929
|
+
title: skillName.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()),
|
|
51930
|
+
description: "From github/awesome-copilot",
|
|
51931
|
+
url: rawUrl,
|
|
51932
|
+
source: "awesome-copilot",
|
|
51933
|
+
installed: installedIds.has(`awesome-copilot:${slug}`)
|
|
51934
|
+
};
|
|
51935
|
+
});
|
|
51936
|
+
}
|
|
51937
|
+
var import_express6, router6, awesomeCopilotCache, AWESOME_COPILOT_CACHE_TTL;
|
|
51799
51938
|
var init_skills = __esm({
|
|
51800
51939
|
"packages/daemon/src/api/routes/skills.ts"() {
|
|
51801
51940
|
"use strict";
|
|
@@ -51815,11 +51954,16 @@ var init_skills = __esm({
|
|
|
51815
51954
|
router6.post("/api/skills/install", async (req, res) => {
|
|
51816
51955
|
try {
|
|
51817
51956
|
const body = req.body;
|
|
51818
|
-
if (!body?.url && !(body?.source && body?.slug)) {
|
|
51957
|
+
if (!body?.url && !(body?.source && (body?.slug || body?.skillId || body?.name))) {
|
|
51819
51958
|
res.status(400).json({ error: "Provide url or source+slug to install a skill" });
|
|
51820
51959
|
return;
|
|
51821
51960
|
}
|
|
51822
|
-
const
|
|
51961
|
+
const normalized = {
|
|
51962
|
+
url: body.url,
|
|
51963
|
+
source: body.source,
|
|
51964
|
+
slug: body.slug || body.skillId || body.name
|
|
51965
|
+
};
|
|
51966
|
+
const result = await installSkill(normalized);
|
|
51823
51967
|
res.status(result.created ? 201 : 200).json(result.skill);
|
|
51824
51968
|
} catch (error51) {
|
|
51825
51969
|
const statusCode = error51 instanceof Error && /Invalid skill|fetch/i.test(error51.message) ? 400 : 500;
|
|
@@ -51844,9 +51988,28 @@ var init_skills = __esm({
|
|
|
51844
51988
|
});
|
|
51845
51989
|
}
|
|
51846
51990
|
});
|
|
51847
|
-
router6.get("/api/skills/discover", async (
|
|
51848
|
-
|
|
51991
|
+
router6.get("/api/skills/discover", async (req, res) => {
|
|
51992
|
+
try {
|
|
51993
|
+
const source = typeof req.query.source === "string" ? req.query.source : "";
|
|
51994
|
+
const query = typeof req.query.q === "string" ? req.query.q.trim() : "";
|
|
51995
|
+
if (source === "skillssh") {
|
|
51996
|
+
const skills = await discoverSkillsSh(query);
|
|
51997
|
+
res.status(200).json(skills);
|
|
51998
|
+
} else if (source === "awesome-copilot") {
|
|
51999
|
+
const skills = await discoverAwesomeCopilot(query);
|
|
52000
|
+
res.status(200).json(skills);
|
|
52001
|
+
} else {
|
|
52002
|
+
res.status(400).json({ error: `Unknown source: ${source}` });
|
|
52003
|
+
}
|
|
52004
|
+
} catch (error51) {
|
|
52005
|
+
res.status(500).json({
|
|
52006
|
+
error: "Failed to discover skills",
|
|
52007
|
+
details: error51 instanceof Error ? error51.message : "Unknown error"
|
|
52008
|
+
});
|
|
52009
|
+
}
|
|
51849
52010
|
});
|
|
52011
|
+
awesomeCopilotCache = null;
|
|
52012
|
+
AWESOME_COPILOT_CACHE_TTL = 60 * 60 * 1e3;
|
|
51850
52013
|
}
|
|
51851
52014
|
});
|
|
51852
52015
|
|
|
@@ -59888,7 +60051,7 @@ var init_websocket = __esm({
|
|
|
59888
60051
|
// packages/daemon/src/api/server.ts
|
|
59889
60052
|
import { existsSync as existsSync2 } from "node:fs";
|
|
59890
60053
|
import { createServer } from "node:http";
|
|
59891
|
-
import { dirname as dirname4, resolve as resolve2 } from "node:path";
|
|
60054
|
+
import { dirname as dirname4, join as join5, resolve as resolve2 } from "node:path";
|
|
59892
60055
|
import { fileURLToPath } from "node:url";
|
|
59893
60056
|
function createApiServer(config2) {
|
|
59894
60057
|
const app = (0, import_express10.default)();
|
|
@@ -59926,6 +60089,9 @@ function createApiServer(config2) {
|
|
|
59926
60089
|
});
|
|
59927
60090
|
if (existsSync2(webDirectory)) {
|
|
59928
60091
|
app.use(import_express10.default.static(webDirectory));
|
|
60092
|
+
app.get("*", (_req, res) => {
|
|
60093
|
+
res.sendFile(join5(webDirectory, "index.html"));
|
|
60094
|
+
});
|
|
59929
60095
|
}
|
|
59930
60096
|
app.use((error51, _req, res, next) => {
|
|
59931
60097
|
if (res.headersSent) {
|
|
@@ -62008,7 +62174,7 @@ var require_thread_stream = __commonJS({
|
|
|
62008
62174
|
var { version: version2 } = require_package();
|
|
62009
62175
|
var { EventEmitter: EventEmitter2 } = __require("events");
|
|
62010
62176
|
var { Worker } = __require("worker_threads");
|
|
62011
|
-
var { join:
|
|
62177
|
+
var { join: join15 } = __require("path");
|
|
62012
62178
|
var { pathToFileURL: pathToFileURL2 } = __require("url");
|
|
62013
62179
|
var { wait } = require_wait();
|
|
62014
62180
|
var {
|
|
@@ -62051,7 +62217,7 @@ var require_thread_stream = __commonJS({
|
|
|
62051
62217
|
function createWorker(stream, opts) {
|
|
62052
62218
|
const { filename, workerData } = opts;
|
|
62053
62219
|
const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
|
|
62054
|
-
const toExecute = bundlerOverrides["thread-stream-worker"] ||
|
|
62220
|
+
const toExecute = bundlerOverrides["thread-stream-worker"] || join15(__dirname, "lib", "worker.js");
|
|
62055
62221
|
const worker = new Worker(toExecute, {
|
|
62056
62222
|
...opts.workerOpts,
|
|
62057
62223
|
trackUnmanagedFds: false,
|
|
@@ -62454,7 +62620,7 @@ var require_transport = __commonJS({
|
|
|
62454
62620
|
"use strict";
|
|
62455
62621
|
var { createRequire } = __require("module");
|
|
62456
62622
|
var getCallers = require_caller();
|
|
62457
|
-
var { join:
|
|
62623
|
+
var { join: join15, isAbsolute: isAbsolute2, sep } = __require("node:path");
|
|
62458
62624
|
var sleep = require_atomic_sleep();
|
|
62459
62625
|
var onExit = require_on_exit_leak_free();
|
|
62460
62626
|
var ThreadStream = require_thread_stream();
|
|
@@ -62517,7 +62683,7 @@ var require_transport = __commonJS({
|
|
|
62517
62683
|
throw new Error("only one of target or targets can be specified");
|
|
62518
62684
|
}
|
|
62519
62685
|
if (targets) {
|
|
62520
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
62686
|
+
target = bundlerOverrides["pino-worker"] || join15(__dirname, "worker.js");
|
|
62521
62687
|
options2.targets = targets.filter((dest) => dest.target).map((dest) => {
|
|
62522
62688
|
return {
|
|
62523
62689
|
...dest,
|
|
@@ -62535,7 +62701,7 @@ var require_transport = __commonJS({
|
|
|
62535
62701
|
});
|
|
62536
62702
|
});
|
|
62537
62703
|
} else if (pipeline) {
|
|
62538
|
-
target = bundlerOverrides["pino-worker"] ||
|
|
62704
|
+
target = bundlerOverrides["pino-worker"] || join15(__dirname, "worker.js");
|
|
62539
62705
|
options2.pipelines = [pipeline.map((dest) => {
|
|
62540
62706
|
return {
|
|
62541
62707
|
...dest,
|
|
@@ -62557,7 +62723,7 @@ var require_transport = __commonJS({
|
|
|
62557
62723
|
return origin;
|
|
62558
62724
|
}
|
|
62559
62725
|
if (origin === "pino/file") {
|
|
62560
|
-
return
|
|
62726
|
+
return join15(__dirname, "..", "file.js");
|
|
62561
62727
|
}
|
|
62562
62728
|
let fixTarget2;
|
|
62563
62729
|
for (const filePath of callers) {
|
|
@@ -63546,7 +63712,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
63546
63712
|
return circularValue;
|
|
63547
63713
|
}
|
|
63548
63714
|
let res = "";
|
|
63549
|
-
let
|
|
63715
|
+
let join15 = ",";
|
|
63550
63716
|
const originalIndentation = indentation;
|
|
63551
63717
|
if (Array.isArray(value)) {
|
|
63552
63718
|
if (value.length === 0) {
|
|
@@ -63560,7 +63726,7 @@ var require_safe_stable_stringify = __commonJS({
|
|
|
63560
63726
|
indentation += spacer;
|
|
63561
63727
|
res += `
|
|
63562
63728
|
${indentation}`;
|
|
63563
|
-
|
|
63729
|
+
join15 = `,
|
|
63564
63730
|
${indentation}`;
|
|
63565
63731
|
}
|
|
63566
63732
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -63568,13 +63734,13 @@ ${indentation}`;
|
|
|
63568
63734
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
63569
63735
|
const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
63570
63736
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
63571
|
-
res +=
|
|
63737
|
+
res += join15;
|
|
63572
63738
|
}
|
|
63573
63739
|
const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
|
|
63574
63740
|
res += tmp !== void 0 ? tmp : "null";
|
|
63575
63741
|
if (value.length - 1 > maximumBreadth) {
|
|
63576
63742
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
63577
|
-
res += `${
|
|
63743
|
+
res += `${join15}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
63578
63744
|
}
|
|
63579
63745
|
if (spacer !== "") {
|
|
63580
63746
|
res += `
|
|
@@ -63595,7 +63761,7 @@ ${originalIndentation}`;
|
|
|
63595
63761
|
let separator = "";
|
|
63596
63762
|
if (spacer !== "") {
|
|
63597
63763
|
indentation += spacer;
|
|
63598
|
-
|
|
63764
|
+
join15 = `,
|
|
63599
63765
|
${indentation}`;
|
|
63600
63766
|
whitespace = " ";
|
|
63601
63767
|
}
|
|
@@ -63609,13 +63775,13 @@ ${indentation}`;
|
|
|
63609
63775
|
const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
|
|
63610
63776
|
if (tmp !== void 0) {
|
|
63611
63777
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
63612
|
-
separator =
|
|
63778
|
+
separator = join15;
|
|
63613
63779
|
}
|
|
63614
63780
|
}
|
|
63615
63781
|
if (keyLength > maximumBreadth) {
|
|
63616
63782
|
const removedKeys = keyLength - maximumBreadth;
|
|
63617
63783
|
res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
|
|
63618
|
-
separator =
|
|
63784
|
+
separator = join15;
|
|
63619
63785
|
}
|
|
63620
63786
|
if (spacer !== "" && separator.length > 1) {
|
|
63621
63787
|
res = `
|
|
@@ -63656,7 +63822,7 @@ ${originalIndentation}`;
|
|
|
63656
63822
|
}
|
|
63657
63823
|
const originalIndentation = indentation;
|
|
63658
63824
|
let res = "";
|
|
63659
|
-
let
|
|
63825
|
+
let join15 = ",";
|
|
63660
63826
|
if (Array.isArray(value)) {
|
|
63661
63827
|
if (value.length === 0) {
|
|
63662
63828
|
return "[]";
|
|
@@ -63669,7 +63835,7 @@ ${originalIndentation}`;
|
|
|
63669
63835
|
indentation += spacer;
|
|
63670
63836
|
res += `
|
|
63671
63837
|
${indentation}`;
|
|
63672
|
-
|
|
63838
|
+
join15 = `,
|
|
63673
63839
|
${indentation}`;
|
|
63674
63840
|
}
|
|
63675
63841
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
@@ -63677,13 +63843,13 @@ ${indentation}`;
|
|
|
63677
63843
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
63678
63844
|
const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
63679
63845
|
res += tmp2 !== void 0 ? tmp2 : "null";
|
|
63680
|
-
res +=
|
|
63846
|
+
res += join15;
|
|
63681
63847
|
}
|
|
63682
63848
|
const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
|
|
63683
63849
|
res += tmp !== void 0 ? tmp : "null";
|
|
63684
63850
|
if (value.length - 1 > maximumBreadth) {
|
|
63685
63851
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
63686
|
-
res += `${
|
|
63852
|
+
res += `${join15}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
63687
63853
|
}
|
|
63688
63854
|
if (spacer !== "") {
|
|
63689
63855
|
res += `
|
|
@@ -63696,7 +63862,7 @@ ${originalIndentation}`;
|
|
|
63696
63862
|
let whitespace = "";
|
|
63697
63863
|
if (spacer !== "") {
|
|
63698
63864
|
indentation += spacer;
|
|
63699
|
-
|
|
63865
|
+
join15 = `,
|
|
63700
63866
|
${indentation}`;
|
|
63701
63867
|
whitespace = " ";
|
|
63702
63868
|
}
|
|
@@ -63705,7 +63871,7 @@ ${indentation}`;
|
|
|
63705
63871
|
const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
|
|
63706
63872
|
if (tmp !== void 0) {
|
|
63707
63873
|
res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
|
|
63708
|
-
separator =
|
|
63874
|
+
separator = join15;
|
|
63709
63875
|
}
|
|
63710
63876
|
}
|
|
63711
63877
|
if (spacer !== "" && separator.length > 1) {
|
|
@@ -63763,20 +63929,20 @@ ${originalIndentation}`;
|
|
|
63763
63929
|
indentation += spacer;
|
|
63764
63930
|
let res2 = `
|
|
63765
63931
|
${indentation}`;
|
|
63766
|
-
const
|
|
63932
|
+
const join16 = `,
|
|
63767
63933
|
${indentation}`;
|
|
63768
63934
|
const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
|
|
63769
63935
|
let i = 0;
|
|
63770
63936
|
for (; i < maximumValuesToStringify - 1; i++) {
|
|
63771
63937
|
const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
63772
63938
|
res2 += tmp2 !== void 0 ? tmp2 : "null";
|
|
63773
|
-
res2 +=
|
|
63939
|
+
res2 += join16;
|
|
63774
63940
|
}
|
|
63775
63941
|
const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
|
|
63776
63942
|
res2 += tmp !== void 0 ? tmp : "null";
|
|
63777
63943
|
if (value.length - 1 > maximumBreadth) {
|
|
63778
63944
|
const removedKeys = value.length - maximumBreadth - 1;
|
|
63779
|
-
res2 += `${
|
|
63945
|
+
res2 += `${join16}"... ${getItemCount(removedKeys)} not stringified"`;
|
|
63780
63946
|
}
|
|
63781
63947
|
res2 += `
|
|
63782
63948
|
${originalIndentation}`;
|
|
@@ -63792,16 +63958,16 @@ ${originalIndentation}`;
|
|
|
63792
63958
|
return '"[Object]"';
|
|
63793
63959
|
}
|
|
63794
63960
|
indentation += spacer;
|
|
63795
|
-
const
|
|
63961
|
+
const join15 = `,
|
|
63796
63962
|
${indentation}`;
|
|
63797
63963
|
let res = "";
|
|
63798
63964
|
let separator = "";
|
|
63799
63965
|
let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
|
|
63800
63966
|
if (isTypedArrayWithEntries(value)) {
|
|
63801
|
-
res += stringifyTypedArray(value,
|
|
63967
|
+
res += stringifyTypedArray(value, join15, maximumBreadth);
|
|
63802
63968
|
keys = keys.slice(value.length);
|
|
63803
63969
|
maximumPropertiesToStringify -= value.length;
|
|
63804
|
-
separator =
|
|
63970
|
+
separator = join15;
|
|
63805
63971
|
}
|
|
63806
63972
|
if (deterministic) {
|
|
63807
63973
|
keys = sort(keys, comparator);
|
|
@@ -63812,13 +63978,13 @@ ${indentation}`;
|
|
|
63812
63978
|
const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
|
|
63813
63979
|
if (tmp !== void 0) {
|
|
63814
63980
|
res += `${separator}${strEscape(key2)}: ${tmp}`;
|
|
63815
|
-
separator =
|
|
63981
|
+
separator = join15;
|
|
63816
63982
|
}
|
|
63817
63983
|
}
|
|
63818
63984
|
if (keyLength > maximumBreadth) {
|
|
63819
63985
|
const removedKeys = keyLength - maximumBreadth;
|
|
63820
63986
|
res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
|
|
63821
|
-
separator =
|
|
63987
|
+
separator = join15;
|
|
63822
63988
|
}
|
|
63823
63989
|
if (separator !== "") {
|
|
63824
63990
|
res = `
|
|
@@ -66848,7 +67014,7 @@ var require_pino_pretty = __commonJS({
|
|
|
66848
67014
|
});
|
|
66849
67015
|
|
|
66850
67016
|
// packages/daemon/src/logging/logger.ts
|
|
66851
|
-
import { join as
|
|
67017
|
+
import { join as join6 } from "node:path";
|
|
66852
67018
|
function shouldPrettyPrint(logLevel) {
|
|
66853
67019
|
return process.env.NODE_ENV !== "production" || process.env.LOG_LEVEL === "debug" || logLevel === "debug" || logLevel === "trace";
|
|
66854
67020
|
}
|
|
@@ -66895,11 +67061,498 @@ var init_logger = __esm({
|
|
|
66895
67061
|
init_paths();
|
|
66896
67062
|
import_pino = __toESM(require_pino(), 1);
|
|
66897
67063
|
import_pino_pretty = __toESM(require_pino_pretty(), 1);
|
|
66898
|
-
LOG_FILE_PATH =
|
|
67064
|
+
LOG_FILE_PATH = join6(LOGS_DIR, "io.log");
|
|
66899
67065
|
rootLogger = null;
|
|
66900
67066
|
}
|
|
66901
67067
|
});
|
|
66902
67068
|
|
|
67069
|
+
// packages/daemon/src/models/catalog.ts
|
|
67070
|
+
import { execFileSync } from "node:child_process";
|
|
67071
|
+
function resolveGitHubToken() {
|
|
67072
|
+
const envToken = process.env.GITHUB_TOKEN?.trim();
|
|
67073
|
+
if (envToken && envToken.length > 0) {
|
|
67074
|
+
return envToken;
|
|
67075
|
+
}
|
|
67076
|
+
try {
|
|
67077
|
+
const token = execFileSync("gh", ["auth", "token"], {
|
|
67078
|
+
encoding: "utf8",
|
|
67079
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
67080
|
+
}).trim();
|
|
67081
|
+
return token.length > 0 ? token : void 0;
|
|
67082
|
+
} catch {
|
|
67083
|
+
return void 0;
|
|
67084
|
+
}
|
|
67085
|
+
}
|
|
67086
|
+
async function fetchModelCatalog() {
|
|
67087
|
+
const token = resolveGitHubToken();
|
|
67088
|
+
if (!token) {
|
|
67089
|
+
throw new Error("No GitHub token available for model catalog fetch");
|
|
67090
|
+
}
|
|
67091
|
+
const response = await fetch(CATALOG_URL, {
|
|
67092
|
+
headers: {
|
|
67093
|
+
Accept: "application/json",
|
|
67094
|
+
Authorization: `Bearer ${token}`,
|
|
67095
|
+
"X-GitHub-Api-Version": "2024-12-01"
|
|
67096
|
+
}
|
|
67097
|
+
});
|
|
67098
|
+
if (!response.ok) {
|
|
67099
|
+
throw new Error(`Model catalog fetch failed: ${response.status} ${response.statusText}`);
|
|
67100
|
+
}
|
|
67101
|
+
const data = await response.json();
|
|
67102
|
+
if (!Array.isArray(data)) {
|
|
67103
|
+
throw new Error("Model catalog response is not an array");
|
|
67104
|
+
}
|
|
67105
|
+
const models = [];
|
|
67106
|
+
for (const entry of data) {
|
|
67107
|
+
const id = entry.id ?? entry.name;
|
|
67108
|
+
const displayName = entry.friendly_name ?? entry.name ?? id;
|
|
67109
|
+
if (id && typeof id === "string") {
|
|
67110
|
+
models.push({ id, displayName: displayName ?? id });
|
|
67111
|
+
}
|
|
67112
|
+
}
|
|
67113
|
+
return models;
|
|
67114
|
+
}
|
|
67115
|
+
var CATALOG_URL;
|
|
67116
|
+
var init_catalog = __esm({
|
|
67117
|
+
"packages/daemon/src/models/catalog.ts"() {
|
|
67118
|
+
"use strict";
|
|
67119
|
+
CATALOG_URL = "https://models.github.ai/catalog/models";
|
|
67120
|
+
}
|
|
67121
|
+
});
|
|
67122
|
+
|
|
67123
|
+
// packages/daemon/src/models/pricing-scraper.ts
|
|
67124
|
+
async function scrapeTokenUnitPricing() {
|
|
67125
|
+
const html = await fetchPage(TOKEN_UNIT_COSTS_URL);
|
|
67126
|
+
return parseTokenUnitTable(html);
|
|
67127
|
+
}
|
|
67128
|
+
async function scrapePremiumRequestPricing() {
|
|
67129
|
+
const html = await fetchPage(PREMIUM_MULTIPLIERS_URL);
|
|
67130
|
+
return parsePremiumMultiplierTable(html);
|
|
67131
|
+
}
|
|
67132
|
+
async function fetchPage(url2) {
|
|
67133
|
+
const response = await fetch(url2, {
|
|
67134
|
+
headers: {
|
|
67135
|
+
Accept: "text/html",
|
|
67136
|
+
"User-Agent": "IO-Daemon/4.0 (pricing-refresh)"
|
|
67137
|
+
},
|
|
67138
|
+
redirect: "follow"
|
|
67139
|
+
});
|
|
67140
|
+
if (!response.ok) {
|
|
67141
|
+
throw new Error(`Failed to fetch ${url2}: ${response.status} ${response.statusText}`);
|
|
67142
|
+
}
|
|
67143
|
+
return response.text();
|
|
67144
|
+
}
|
|
67145
|
+
function parseTokenUnitTable(html) {
|
|
67146
|
+
const results = [];
|
|
67147
|
+
const tableRowPattern = /<tr[^>]*>\s*<td[^>]*>([^<]+)<\/td>\s*<td[^>]*>([^<]+)<\/td>\s*<td[^>]*>([^<]*)<\/td>\s*<td[^>]*>([^<]+)<\/td>/gi;
|
|
67148
|
+
for (const match of html.matchAll(tableRowPattern)) {
|
|
67149
|
+
const modelName = cleanCellText(match[1]);
|
|
67150
|
+
const inputMultiplier = Number.parseFloat(match[2]);
|
|
67151
|
+
const cachedInput = match[3].trim().toLowerCase();
|
|
67152
|
+
const outputMultiplier = Number.parseFloat(match[4]);
|
|
67153
|
+
if (modelName && !Number.isNaN(inputMultiplier) && !Number.isNaN(outputMultiplier)) {
|
|
67154
|
+
results.push({
|
|
67155
|
+
modelName,
|
|
67156
|
+
inputMultiplier,
|
|
67157
|
+
cachedInputMultiplier: cachedInput === "n/a" || cachedInput === "" ? null : Number.parseFloat(cachedInput) || null,
|
|
67158
|
+
outputMultiplier
|
|
67159
|
+
});
|
|
67160
|
+
}
|
|
67161
|
+
}
|
|
67162
|
+
return results;
|
|
67163
|
+
}
|
|
67164
|
+
function parsePremiumMultiplierTable(html) {
|
|
67165
|
+
const results = [];
|
|
67166
|
+
const tableRowPattern = /<tr[^>]*>\s*<td[^>]*>([^<]+)<\/td>\s*<td[^>]*>([^<]+)<\/td>\s*<\/tr>/gi;
|
|
67167
|
+
for (const match of html.matchAll(tableRowPattern)) {
|
|
67168
|
+
const modelName = cleanCellText(match[1]);
|
|
67169
|
+
const multiplier = Number.parseFloat(match[2]);
|
|
67170
|
+
if (modelName && !Number.isNaN(multiplier) && multiplier > 0) {
|
|
67171
|
+
results.push({ modelName, multiplier });
|
|
67172
|
+
}
|
|
67173
|
+
}
|
|
67174
|
+
return results;
|
|
67175
|
+
}
|
|
67176
|
+
function cleanCellText(text) {
|
|
67177
|
+
return text.replace(/<[^>]*>/g, "").replace(/&[^;]+;/g, " ").trim();
|
|
67178
|
+
}
|
|
67179
|
+
var TOKEN_UNIT_COSTS_URL, PREMIUM_MULTIPLIERS_URL;
|
|
67180
|
+
var init_pricing_scraper = __esm({
|
|
67181
|
+
"packages/daemon/src/models/pricing-scraper.ts"() {
|
|
67182
|
+
"use strict";
|
|
67183
|
+
TOKEN_UNIT_COSTS_URL = "https://docs.github.com/en/billing/reference/costs-for-github-models";
|
|
67184
|
+
PREMIUM_MULTIPLIERS_URL = "https://docs.github.com/en/copilot/reference/copilot-billing/request-based-billing-legacy/model-multipliers-for-annual-plans";
|
|
67185
|
+
}
|
|
67186
|
+
});
|
|
67187
|
+
|
|
67188
|
+
// packages/daemon/src/models/seed.ts
|
|
67189
|
+
var SEED_MODELS;
|
|
67190
|
+
var init_seed = __esm({
|
|
67191
|
+
"packages/daemon/src/models/seed.ts"() {
|
|
67192
|
+
"use strict";
|
|
67193
|
+
SEED_MODELS = [
|
|
67194
|
+
{
|
|
67195
|
+
id: "gpt-4o-mini",
|
|
67196
|
+
displayName: "OpenAI GPT-4o mini",
|
|
67197
|
+
premiumMultiplier: 0.33,
|
|
67198
|
+
tokenInputMultiplier: 0.015,
|
|
67199
|
+
tokenOutputMultiplier: 0.06,
|
|
67200
|
+
cachedInputMultiplier: 75e-4,
|
|
67201
|
+
tier: "trivial",
|
|
67202
|
+
available: true
|
|
67203
|
+
},
|
|
67204
|
+
{
|
|
67205
|
+
id: "gpt-4o",
|
|
67206
|
+
displayName: "OpenAI GPT-4o",
|
|
67207
|
+
premiumMultiplier: 0.33,
|
|
67208
|
+
tokenInputMultiplier: 0.25,
|
|
67209
|
+
tokenOutputMultiplier: 1,
|
|
67210
|
+
cachedInputMultiplier: 0.125,
|
|
67211
|
+
tier: "trivial",
|
|
67212
|
+
available: true
|
|
67213
|
+
},
|
|
67214
|
+
{
|
|
67215
|
+
id: "gpt-5-mini",
|
|
67216
|
+
displayName: "GPT-5 mini",
|
|
67217
|
+
premiumMultiplier: 0.33,
|
|
67218
|
+
tokenInputMultiplier: null,
|
|
67219
|
+
tokenOutputMultiplier: null,
|
|
67220
|
+
cachedInputMultiplier: null,
|
|
67221
|
+
tier: "trivial",
|
|
67222
|
+
available: true
|
|
67223
|
+
},
|
|
67224
|
+
{
|
|
67225
|
+
id: "claude-sonnet-4",
|
|
67226
|
+
displayName: "Claude Sonnet 4",
|
|
67227
|
+
premiumMultiplier: 6,
|
|
67228
|
+
tokenInputMultiplier: 0.6,
|
|
67229
|
+
tokenOutputMultiplier: 2.4,
|
|
67230
|
+
cachedInputMultiplier: null,
|
|
67231
|
+
tier: "premium",
|
|
67232
|
+
available: true
|
|
67233
|
+
},
|
|
67234
|
+
{
|
|
67235
|
+
id: "claude-haiku-4.5",
|
|
67236
|
+
displayName: "Claude Haiku 4.5",
|
|
67237
|
+
premiumMultiplier: 0.33,
|
|
67238
|
+
tokenInputMultiplier: null,
|
|
67239
|
+
tokenOutputMultiplier: null,
|
|
67240
|
+
cachedInputMultiplier: null,
|
|
67241
|
+
tier: "trivial",
|
|
67242
|
+
available: true
|
|
67243
|
+
},
|
|
67244
|
+
{
|
|
67245
|
+
id: "gemini-2.5-pro",
|
|
67246
|
+
displayName: "Gemini 2.5 Pro",
|
|
67247
|
+
premiumMultiplier: 1,
|
|
67248
|
+
tokenInputMultiplier: null,
|
|
67249
|
+
tokenOutputMultiplier: null,
|
|
67250
|
+
cachedInputMultiplier: null,
|
|
67251
|
+
tier: "fast",
|
|
67252
|
+
available: true
|
|
67253
|
+
},
|
|
67254
|
+
{
|
|
67255
|
+
id: "gpt-5.1",
|
|
67256
|
+
displayName: "GPT-5.1",
|
|
67257
|
+
premiumMultiplier: 3,
|
|
67258
|
+
tokenInputMultiplier: null,
|
|
67259
|
+
tokenOutputMultiplier: null,
|
|
67260
|
+
cachedInputMultiplier: null,
|
|
67261
|
+
tier: "standard",
|
|
67262
|
+
available: true
|
|
67263
|
+
},
|
|
67264
|
+
{
|
|
67265
|
+
id: "gpt-5.2",
|
|
67266
|
+
displayName: "GPT-5.2",
|
|
67267
|
+
premiumMultiplier: 3,
|
|
67268
|
+
tokenInputMultiplier: null,
|
|
67269
|
+
tokenOutputMultiplier: null,
|
|
67270
|
+
cachedInputMultiplier: null,
|
|
67271
|
+
tier: "standard",
|
|
67272
|
+
available: true
|
|
67273
|
+
},
|
|
67274
|
+
{
|
|
67275
|
+
id: "gpt-5.4",
|
|
67276
|
+
displayName: "GPT-5.4",
|
|
67277
|
+
premiumMultiplier: 6,
|
|
67278
|
+
tokenInputMultiplier: null,
|
|
67279
|
+
tokenOutputMultiplier: null,
|
|
67280
|
+
cachedInputMultiplier: null,
|
|
67281
|
+
tier: "premium",
|
|
67282
|
+
available: true
|
|
67283
|
+
},
|
|
67284
|
+
{
|
|
67285
|
+
id: "claude-opus-4.5",
|
|
67286
|
+
displayName: "Claude Opus 4.5",
|
|
67287
|
+
premiumMultiplier: 15,
|
|
67288
|
+
tokenInputMultiplier: null,
|
|
67289
|
+
tokenOutputMultiplier: null,
|
|
67290
|
+
cachedInputMultiplier: null,
|
|
67291
|
+
tier: "premium",
|
|
67292
|
+
available: true
|
|
67293
|
+
},
|
|
67294
|
+
{
|
|
67295
|
+
id: "claude-opus-4.6",
|
|
67296
|
+
displayName: "Claude Opus 4.6",
|
|
67297
|
+
premiumMultiplier: 27,
|
|
67298
|
+
tokenInputMultiplier: null,
|
|
67299
|
+
tokenOutputMultiplier: null,
|
|
67300
|
+
cachedInputMultiplier: null,
|
|
67301
|
+
tier: "ultra",
|
|
67302
|
+
available: true
|
|
67303
|
+
},
|
|
67304
|
+
{
|
|
67305
|
+
id: "claude-opus-4.7",
|
|
67306
|
+
displayName: "Claude Opus 4.7",
|
|
67307
|
+
premiumMultiplier: 27,
|
|
67308
|
+
tokenInputMultiplier: null,
|
|
67309
|
+
tokenOutputMultiplier: null,
|
|
67310
|
+
cachedInputMultiplier: null,
|
|
67311
|
+
tier: "ultra",
|
|
67312
|
+
available: true
|
|
67313
|
+
},
|
|
67314
|
+
{
|
|
67315
|
+
id: "gpt-5.5",
|
|
67316
|
+
displayName: "GPT-5.5",
|
|
67317
|
+
premiumMultiplier: 57,
|
|
67318
|
+
tokenInputMultiplier: null,
|
|
67319
|
+
tokenOutputMultiplier: null,
|
|
67320
|
+
cachedInputMultiplier: null,
|
|
67321
|
+
tier: "ultra",
|
|
67322
|
+
available: true
|
|
67323
|
+
}
|
|
67324
|
+
];
|
|
67325
|
+
}
|
|
67326
|
+
});
|
|
67327
|
+
|
|
67328
|
+
// packages/daemon/src/models/types.ts
|
|
67329
|
+
function computeTierFromMultiplier(premiumMultiplier) {
|
|
67330
|
+
if (premiumMultiplier === null) {
|
|
67331
|
+
return "standard";
|
|
67332
|
+
}
|
|
67333
|
+
for (const [tier, range] of Object.entries(TIER_RANGES)) {
|
|
67334
|
+
if (premiumMultiplier >= range.min && premiumMultiplier <= range.max) {
|
|
67335
|
+
return tier;
|
|
67336
|
+
}
|
|
67337
|
+
}
|
|
67338
|
+
return "ultra";
|
|
67339
|
+
}
|
|
67340
|
+
var TIER_RANGES, TOKEN_UNIT_PRICE;
|
|
67341
|
+
var init_types = __esm({
|
|
67342
|
+
"packages/daemon/src/models/types.ts"() {
|
|
67343
|
+
"use strict";
|
|
67344
|
+
TIER_RANGES = {
|
|
67345
|
+
trivial: { min: 0, max: 0.33 },
|
|
67346
|
+
fast: { min: 0.34, max: 1 },
|
|
67347
|
+
standard: { min: 1.1, max: 5 },
|
|
67348
|
+
premium: { min: 5.1, max: 15 },
|
|
67349
|
+
ultra: { min: 15.1, max: Number.POSITIVE_INFINITY }
|
|
67350
|
+
};
|
|
67351
|
+
TOKEN_UNIT_PRICE = 1e-5;
|
|
67352
|
+
}
|
|
67353
|
+
});
|
|
67354
|
+
|
|
67355
|
+
// packages/daemon/src/models/registry.ts
|
|
67356
|
+
function normalizeModelName(name) {
|
|
67357
|
+
return name.toLowerCase().replace(/^openai\s+/i, "").replace(/\s+/g, "-").replace(/[^a-z0-9.\-]/g, "").trim();
|
|
67358
|
+
}
|
|
67359
|
+
async function fetchCatalogIntoMap(modelMap, result, logger) {
|
|
67360
|
+
try {
|
|
67361
|
+
const catalogModels = await fetchModelCatalog();
|
|
67362
|
+
result.catalogFetched = true;
|
|
67363
|
+
for (const m of catalogModels) {
|
|
67364
|
+
const key = normalizeModelName(m.id);
|
|
67365
|
+
modelMap.set(key, { id: m.id, displayName: m.displayName, available: true });
|
|
67366
|
+
}
|
|
67367
|
+
} catch (error51) {
|
|
67368
|
+
const msg = error51 instanceof Error ? error51.message : String(error51);
|
|
67369
|
+
result.errors.push(`Catalog fetch failed: ${msg}`);
|
|
67370
|
+
logger?.warn(`Model catalog fetch failed: ${msg}`);
|
|
67371
|
+
}
|
|
67372
|
+
}
|
|
67373
|
+
async function scrapeTokenPricingIntoMap(modelMap, result, logger) {
|
|
67374
|
+
try {
|
|
67375
|
+
const tokenPricing = await scrapeTokenUnitPricing();
|
|
67376
|
+
result.tokenPricingScraped = true;
|
|
67377
|
+
for (const tp of tokenPricing) {
|
|
67378
|
+
const key = normalizeModelName(tp.modelName);
|
|
67379
|
+
const existing = modelMap.get(key) ?? findClosestKey(modelMap, key);
|
|
67380
|
+
if (existing) {
|
|
67381
|
+
existing.tokenInputMultiplier = tp.inputMultiplier;
|
|
67382
|
+
existing.tokenOutputMultiplier = tp.outputMultiplier;
|
|
67383
|
+
existing.cachedInputMultiplier = tp.cachedInputMultiplier;
|
|
67384
|
+
} else {
|
|
67385
|
+
modelMap.set(key, {
|
|
67386
|
+
id: key,
|
|
67387
|
+
displayName: tp.modelName,
|
|
67388
|
+
tokenInputMultiplier: tp.inputMultiplier,
|
|
67389
|
+
tokenOutputMultiplier: tp.outputMultiplier,
|
|
67390
|
+
cachedInputMultiplier: tp.cachedInputMultiplier,
|
|
67391
|
+
available: true
|
|
67392
|
+
});
|
|
67393
|
+
}
|
|
67394
|
+
}
|
|
67395
|
+
} catch (error51) {
|
|
67396
|
+
const msg = error51 instanceof Error ? error51.message : String(error51);
|
|
67397
|
+
result.errors.push(`Token pricing scrape failed: ${msg}`);
|
|
67398
|
+
logger?.warn(`Token pricing scrape failed: ${msg}`);
|
|
67399
|
+
}
|
|
67400
|
+
}
|
|
67401
|
+
async function scrapePremiumPricingIntoMap(modelMap, result, logger) {
|
|
67402
|
+
try {
|
|
67403
|
+
const premiumPricing = await scrapePremiumRequestPricing();
|
|
67404
|
+
result.premiumPricingScraped = true;
|
|
67405
|
+
for (const pp of premiumPricing) {
|
|
67406
|
+
const key = normalizeModelName(pp.modelName);
|
|
67407
|
+
const existing = modelMap.get(key) ?? findClosestKey(modelMap, key);
|
|
67408
|
+
if (existing) {
|
|
67409
|
+
existing.premiumMultiplier = pp.multiplier;
|
|
67410
|
+
} else {
|
|
67411
|
+
modelMap.set(key, {
|
|
67412
|
+
id: key,
|
|
67413
|
+
displayName: pp.modelName,
|
|
67414
|
+
premiumMultiplier: pp.multiplier,
|
|
67415
|
+
available: true
|
|
67416
|
+
});
|
|
67417
|
+
}
|
|
67418
|
+
}
|
|
67419
|
+
} catch (error51) {
|
|
67420
|
+
const msg = error51 instanceof Error ? error51.message : String(error51);
|
|
67421
|
+
result.errors.push(`Premium pricing scrape failed: ${msg}`);
|
|
67422
|
+
logger?.warn(`Premium pricing scrape failed: ${msg}`);
|
|
67423
|
+
}
|
|
67424
|
+
}
|
|
67425
|
+
async function refreshModelPricing(logger) {
|
|
67426
|
+
const result = {
|
|
67427
|
+
modelsUpdated: 0,
|
|
67428
|
+
catalogFetched: false,
|
|
67429
|
+
tokenPricingScraped: false,
|
|
67430
|
+
premiumPricingScraped: false,
|
|
67431
|
+
errors: []
|
|
67432
|
+
};
|
|
67433
|
+
const modelMap = /* @__PURE__ */ new Map();
|
|
67434
|
+
await fetchCatalogIntoMap(modelMap, result, logger);
|
|
67435
|
+
await scrapeTokenPricingIntoMap(modelMap, result, logger);
|
|
67436
|
+
await scrapePremiumPricingIntoMap(modelMap, result, logger);
|
|
67437
|
+
if (!result.catalogFetched && !result.tokenPricingScraped && !result.premiumPricingScraped) {
|
|
67438
|
+
logger?.warn("All pricing sources failed, using seed data");
|
|
67439
|
+
await seedFromFallback();
|
|
67440
|
+
result.modelsUpdated = SEED_MODELS.length;
|
|
67441
|
+
return result;
|
|
67442
|
+
}
|
|
67443
|
+
const db = await getDatabase();
|
|
67444
|
+
const now = nowIso();
|
|
67445
|
+
for (const model of modelMap.values()) {
|
|
67446
|
+
const tier = computeTierFromMultiplier(model.premiumMultiplier ?? null);
|
|
67447
|
+
await upsertModel(db, {
|
|
67448
|
+
id: model.id,
|
|
67449
|
+
displayName: model.displayName,
|
|
67450
|
+
premiumMultiplier: model.premiumMultiplier ?? null,
|
|
67451
|
+
tokenInputMultiplier: model.tokenInputMultiplier ?? null,
|
|
67452
|
+
tokenOutputMultiplier: model.tokenOutputMultiplier ?? null,
|
|
67453
|
+
cachedInputMultiplier: model.cachedInputMultiplier ?? null,
|
|
67454
|
+
tier,
|
|
67455
|
+
available: model.available ?? true,
|
|
67456
|
+
updatedAt: now
|
|
67457
|
+
});
|
|
67458
|
+
result.modelsUpdated++;
|
|
67459
|
+
}
|
|
67460
|
+
return result;
|
|
67461
|
+
}
|
|
67462
|
+
async function seedFromFallback() {
|
|
67463
|
+
const db = await getDatabase();
|
|
67464
|
+
const now = nowIso();
|
|
67465
|
+
for (const model of SEED_MODELS) {
|
|
67466
|
+
await upsertModel(db, { ...model, updatedAt: now });
|
|
67467
|
+
}
|
|
67468
|
+
}
|
|
67469
|
+
async function getModelPricing(modelId) {
|
|
67470
|
+
const db = await getDatabase();
|
|
67471
|
+
const result = await db.execute({
|
|
67472
|
+
sql: "SELECT * FROM model_pricing WHERE id = ?",
|
|
67473
|
+
args: [modelId]
|
|
67474
|
+
});
|
|
67475
|
+
if (result.rows.length === 0) {
|
|
67476
|
+
return null;
|
|
67477
|
+
}
|
|
67478
|
+
return rowToModelPricing(result.rows[0]);
|
|
67479
|
+
}
|
|
67480
|
+
function calculateTokenUnitCost(inputTokens, outputTokens, inputMultiplier, outputMultiplier) {
|
|
67481
|
+
if (inputMultiplier === null || outputMultiplier === null) {
|
|
67482
|
+
return 0;
|
|
67483
|
+
}
|
|
67484
|
+
const tokenUnits = inputTokens * inputMultiplier + outputTokens * outputMultiplier;
|
|
67485
|
+
return tokenUnits * TOKEN_UNIT_PRICE;
|
|
67486
|
+
}
|
|
67487
|
+
async function upsertModel(db, model) {
|
|
67488
|
+
await db.execute({
|
|
67489
|
+
sql: `INSERT INTO model_pricing (id, display_name, premium_multiplier, token_input_multiplier, token_output_multiplier, cached_input_multiplier, tier, available, updated_at)
|
|
67490
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
67491
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
67492
|
+
display_name = excluded.display_name,
|
|
67493
|
+
premium_multiplier = COALESCE(excluded.premium_multiplier, model_pricing.premium_multiplier),
|
|
67494
|
+
token_input_multiplier = COALESCE(excluded.token_input_multiplier, model_pricing.token_input_multiplier),
|
|
67495
|
+
token_output_multiplier = COALESCE(excluded.token_output_multiplier, model_pricing.token_output_multiplier),
|
|
67496
|
+
cached_input_multiplier = COALESCE(excluded.cached_input_multiplier, model_pricing.cached_input_multiplier),
|
|
67497
|
+
tier = excluded.tier,
|
|
67498
|
+
available = excluded.available,
|
|
67499
|
+
updated_at = excluded.updated_at`,
|
|
67500
|
+
args: [
|
|
67501
|
+
model.id,
|
|
67502
|
+
model.displayName,
|
|
67503
|
+
model.premiumMultiplier,
|
|
67504
|
+
model.tokenInputMultiplier,
|
|
67505
|
+
model.tokenOutputMultiplier,
|
|
67506
|
+
model.cachedInputMultiplier,
|
|
67507
|
+
model.tier,
|
|
67508
|
+
model.available ? 1 : 0,
|
|
67509
|
+
model.updatedAt
|
|
67510
|
+
]
|
|
67511
|
+
});
|
|
67512
|
+
}
|
|
67513
|
+
function rowToModelPricing(row) {
|
|
67514
|
+
return {
|
|
67515
|
+
id: asString(row.id),
|
|
67516
|
+
displayName: asString(row.display_name),
|
|
67517
|
+
premiumMultiplier: asNullableNumber(row.premium_multiplier),
|
|
67518
|
+
tokenInputMultiplier: asNullableNumber(row.token_input_multiplier),
|
|
67519
|
+
tokenOutputMultiplier: asNullableNumber(row.token_output_multiplier),
|
|
67520
|
+
cachedInputMultiplier: asNullableNumber(row.cached_input_multiplier),
|
|
67521
|
+
tier: asString(row.tier),
|
|
67522
|
+
available: asNumber(row.available) === 1,
|
|
67523
|
+
updatedAt: asString(row.updated_at)
|
|
67524
|
+
};
|
|
67525
|
+
}
|
|
67526
|
+
function findClosestKey(map2, targetKey) {
|
|
67527
|
+
for (const [key, value] of map2) {
|
|
67528
|
+
if (key.includes(targetKey) || targetKey.includes(key)) {
|
|
67529
|
+
return value;
|
|
67530
|
+
}
|
|
67531
|
+
}
|
|
67532
|
+
return void 0;
|
|
67533
|
+
}
|
|
67534
|
+
var init_registry = __esm({
|
|
67535
|
+
"packages/daemon/src/models/registry.ts"() {
|
|
67536
|
+
"use strict";
|
|
67537
|
+
init_db();
|
|
67538
|
+
init_catalog();
|
|
67539
|
+
init_pricing_scraper();
|
|
67540
|
+
init_seed();
|
|
67541
|
+
init_types();
|
|
67542
|
+
}
|
|
67543
|
+
});
|
|
67544
|
+
|
|
67545
|
+
// packages/daemon/src/models/index.ts
|
|
67546
|
+
var init_models = __esm({
|
|
67547
|
+
"packages/daemon/src/models/index.ts"() {
|
|
67548
|
+
"use strict";
|
|
67549
|
+
init_catalog();
|
|
67550
|
+
init_registry();
|
|
67551
|
+
init_seed();
|
|
67552
|
+
init_types();
|
|
67553
|
+
}
|
|
67554
|
+
});
|
|
67555
|
+
|
|
66903
67556
|
// packages/daemon/src/orchestrator/system-prompt.ts
|
|
66904
67557
|
function formatSquadRoster(squads) {
|
|
66905
67558
|
if (squads.length === 0) {
|
|
@@ -67003,150 +67656,10 @@ var init_reset = __esm({
|
|
|
67003
67656
|
}
|
|
67004
67657
|
});
|
|
67005
67658
|
|
|
67006
|
-
// packages/daemon/src/copilot/router.ts
|
|
67007
|
-
function normalizeMessage(message2) {
|
|
67008
|
-
return message2.trim().toLowerCase();
|
|
67009
|
-
}
|
|
67010
|
-
function getWordCount(message2) {
|
|
67011
|
-
const normalized = message2.trim();
|
|
67012
|
-
if (normalized.length === 0) {
|
|
67013
|
-
return 0;
|
|
67014
|
-
}
|
|
67015
|
-
return normalized.split(/\s+/u).length;
|
|
67016
|
-
}
|
|
67017
|
-
function containsAny(message2, keywords) {
|
|
67018
|
-
return keywords.some((keyword) => message2.includes(keyword));
|
|
67019
|
-
}
|
|
67020
|
-
function startsWithSimpleQuestion(message2) {
|
|
67021
|
-
return SIMPLE_QUESTION_PREFIXES.some(
|
|
67022
|
-
(prefix) => message2 === prefix || message2.startsWith(`${prefix} `)
|
|
67023
|
-
);
|
|
67024
|
-
}
|
|
67025
|
-
function classifyMessage(message2) {
|
|
67026
|
-
const normalized = normalizeMessage(message2);
|
|
67027
|
-
const wordCount = getWordCount(normalized);
|
|
67028
|
-
if (normalized.length === 0) {
|
|
67029
|
-
return "fast";
|
|
67030
|
-
}
|
|
67031
|
-
if (containsAny(normalized, PREMIUM_KEYWORDS) || normalized.includes("```") || wordCount >= 80) {
|
|
67032
|
-
return "premium";
|
|
67033
|
-
}
|
|
67034
|
-
if (wordCount <= 20 && (containsAny(normalized, FAST_KEYWORDS) || startsWithSimpleQuestion(normalized) || /^(yes|no|sure|okay|ok|thanks)[!.?]*$/u.test(normalized))) {
|
|
67035
|
-
return "fast";
|
|
67036
|
-
}
|
|
67037
|
-
if (wordCount <= 8 && /^(what|when|where|who)\b/u.test(normalized)) {
|
|
67038
|
-
return "fast";
|
|
67039
|
-
}
|
|
67040
|
-
return "standard";
|
|
67041
|
-
}
|
|
67042
|
-
function getModelForTier(tier) {
|
|
67043
|
-
switch (tier) {
|
|
67044
|
-
case "fast":
|
|
67045
|
-
return FAST_MODEL;
|
|
67046
|
-
case "premium":
|
|
67047
|
-
return PREMIUM_MODEL;
|
|
67048
|
-
default:
|
|
67049
|
-
return STANDARD_MODEL;
|
|
67050
|
-
}
|
|
67051
|
-
}
|
|
67052
|
-
function routeMessage(message2) {
|
|
67053
|
-
const requestedTier = classifyMessage(message2);
|
|
67054
|
-
if (activeTier === null) {
|
|
67055
|
-
activeTier = requestedTier;
|
|
67056
|
-
messagesSinceLastSwitch = 0;
|
|
67057
|
-
return {
|
|
67058
|
-
requestedTier,
|
|
67059
|
-
effectiveTier: activeTier,
|
|
67060
|
-
model: getModelForTier(activeTier),
|
|
67061
|
-
switched: true,
|
|
67062
|
-
cooldownRemaining: MODEL_SWITCH_COOLDOWN_MESSAGES
|
|
67063
|
-
};
|
|
67064
|
-
}
|
|
67065
|
-
if (requestedTier !== activeTier && messagesSinceLastSwitch >= MODEL_SWITCH_COOLDOWN_MESSAGES) {
|
|
67066
|
-
activeTier = requestedTier;
|
|
67067
|
-
messagesSinceLastSwitch = 0;
|
|
67068
|
-
return {
|
|
67069
|
-
requestedTier,
|
|
67070
|
-
effectiveTier: activeTier,
|
|
67071
|
-
model: getModelForTier(activeTier),
|
|
67072
|
-
switched: true,
|
|
67073
|
-
cooldownRemaining: MODEL_SWITCH_COOLDOWN_MESSAGES
|
|
67074
|
-
};
|
|
67075
|
-
}
|
|
67076
|
-
messagesSinceLastSwitch += 1;
|
|
67077
|
-
return {
|
|
67078
|
-
requestedTier,
|
|
67079
|
-
effectiveTier: activeTier,
|
|
67080
|
-
model: getModelForTier(activeTier),
|
|
67081
|
-
switched: false,
|
|
67082
|
-
cooldownRemaining: Math.max(MODEL_SWITCH_COOLDOWN_MESSAGES - messagesSinceLastSwitch, 0)
|
|
67083
|
-
};
|
|
67084
|
-
}
|
|
67085
|
-
var FAST_KEYWORDS, PREMIUM_KEYWORDS, SIMPLE_QUESTION_PREFIXES, MODEL_SWITCH_COOLDOWN_MESSAGES, activeTier, messagesSinceLastSwitch;
|
|
67086
|
-
var init_router = __esm({
|
|
67087
|
-
"packages/daemon/src/copilot/router.ts"() {
|
|
67088
|
-
"use strict";
|
|
67089
|
-
init_dist();
|
|
67090
|
-
FAST_KEYWORDS = [
|
|
67091
|
-
"hi",
|
|
67092
|
-
"hello",
|
|
67093
|
-
"hey",
|
|
67094
|
-
"thanks",
|
|
67095
|
-
"thank you",
|
|
67096
|
-
"status",
|
|
67097
|
-
"list",
|
|
67098
|
-
"show",
|
|
67099
|
-
"ping",
|
|
67100
|
-
"uptime",
|
|
67101
|
-
"what time",
|
|
67102
|
-
"ok",
|
|
67103
|
-
"okay"
|
|
67104
|
-
];
|
|
67105
|
-
PREMIUM_KEYWORDS = [
|
|
67106
|
-
"architecture",
|
|
67107
|
-
"architect",
|
|
67108
|
-
"design",
|
|
67109
|
-
"tradeoff",
|
|
67110
|
-
"trade-off",
|
|
67111
|
-
"plan",
|
|
67112
|
-
"planning",
|
|
67113
|
-
"strategy",
|
|
67114
|
-
"roadmap",
|
|
67115
|
-
"migration",
|
|
67116
|
-
"refactor",
|
|
67117
|
-
"generate",
|
|
67118
|
-
"implement",
|
|
67119
|
-
"build",
|
|
67120
|
-
"codebase",
|
|
67121
|
-
"repository",
|
|
67122
|
-
"system prompt",
|
|
67123
|
-
"multi-step",
|
|
67124
|
-
"complex",
|
|
67125
|
-
"reason",
|
|
67126
|
-
"compare"
|
|
67127
|
-
];
|
|
67128
|
-
SIMPLE_QUESTION_PREFIXES = [
|
|
67129
|
-
"is",
|
|
67130
|
-
"are",
|
|
67131
|
-
"do",
|
|
67132
|
-
"does",
|
|
67133
|
-
"did",
|
|
67134
|
-
"can",
|
|
67135
|
-
"could",
|
|
67136
|
-
"should",
|
|
67137
|
-
"would",
|
|
67138
|
-
"will"
|
|
67139
|
-
];
|
|
67140
|
-
MODEL_SWITCH_COOLDOWN_MESSAGES = 3;
|
|
67141
|
-
activeTier = null;
|
|
67142
|
-
messagesSinceLastSwitch = MODEL_SWITCH_COOLDOWN_MESSAGES;
|
|
67143
|
-
}
|
|
67144
|
-
});
|
|
67145
|
-
|
|
67146
67659
|
// packages/daemon/src/copilot/client.ts
|
|
67147
|
-
import { execFileSync } from "node:child_process";
|
|
67660
|
+
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
67148
67661
|
import { mkdirSync as mkdirSync2 } from "node:fs";
|
|
67149
|
-
import { join as
|
|
67662
|
+
import { join as join7 } from "node:path";
|
|
67150
67663
|
import { CopilotClient } from "@github/copilot-sdk";
|
|
67151
67664
|
function readTokenFromEnvironment() {
|
|
67152
67665
|
const token = process.env.GITHUB_TOKEN?.trim();
|
|
@@ -67154,7 +67667,7 @@ function readTokenFromEnvironment() {
|
|
|
67154
67667
|
}
|
|
67155
67668
|
function readTokenFromGhCli() {
|
|
67156
67669
|
try {
|
|
67157
|
-
const token =
|
|
67670
|
+
const token = execFileSync2("gh", ["auth", "token"], {
|
|
67158
67671
|
encoding: "utf8",
|
|
67159
67672
|
stdio: ["ignore", "pipe", "pipe"]
|
|
67160
67673
|
}).trim();
|
|
@@ -67163,7 +67676,7 @@ function readTokenFromGhCli() {
|
|
|
67163
67676
|
return void 0;
|
|
67164
67677
|
}
|
|
67165
67678
|
}
|
|
67166
|
-
function
|
|
67679
|
+
function resolveGitHubToken2() {
|
|
67167
67680
|
return readTokenFromEnvironment() ?? readTokenFromGhCli();
|
|
67168
67681
|
}
|
|
67169
67682
|
function buildClientOptions(token) {
|
|
@@ -67199,7 +67712,7 @@ async function initCopilotClient() {
|
|
|
67199
67712
|
}
|
|
67200
67713
|
copilotClientInitPromise = (async () => {
|
|
67201
67714
|
try {
|
|
67202
|
-
const token =
|
|
67715
|
+
const token = resolveGitHubToken2();
|
|
67203
67716
|
if (token === void 0) {
|
|
67204
67717
|
throw new Error(
|
|
67205
67718
|
`Unable to find a GitHub token for Copilot SDK authentication. ${COPILOT_AUTH_ERROR_HINT}`
|
|
@@ -67232,7 +67745,7 @@ var init_client = __esm({
|
|
|
67232
67745
|
"use strict";
|
|
67233
67746
|
init_paths();
|
|
67234
67747
|
COPILOT_AUTH_ERROR_HINT = "Set GITHUB_TOKEN or authenticate with the GitHub CLI (`gh auth login`) so `gh auth token` returns a valid token.";
|
|
67235
|
-
COPILOT_BASE_DIRECTORY =
|
|
67748
|
+
COPILOT_BASE_DIRECTORY = join7(DATA_DIR, "copilot-sdk");
|
|
67236
67749
|
copilotClientSingleton = null;
|
|
67237
67750
|
copilotClientInitPromise = null;
|
|
67238
67751
|
}
|
|
@@ -67392,7 +67905,7 @@ var init_session = __esm({
|
|
|
67392
67905
|
|
|
67393
67906
|
// packages/daemon/src/skills/loader.ts
|
|
67394
67907
|
import { readFile as readFile4, readdir as readdir2 } from "node:fs/promises";
|
|
67395
|
-
import { basename as basename3, dirname as dirname5, join as
|
|
67908
|
+
import { basename as basename3, dirname as dirname5, join as join8 } from "node:path";
|
|
67396
67909
|
async function scanSkills() {
|
|
67397
67910
|
const skillFilePaths = await collectSkillFiles(SKILLS_DIR);
|
|
67398
67911
|
const skills = await Promise.all(skillFilePaths.map((filePath) => readSkillFromFile(filePath)));
|
|
@@ -67403,7 +67916,7 @@ async function collectSkillFiles(directory) {
|
|
|
67403
67916
|
const entries = await readdir2(directory, { withFileTypes: true });
|
|
67404
67917
|
const skillFiles = [];
|
|
67405
67918
|
for (const entry of entries) {
|
|
67406
|
-
const entryPath =
|
|
67919
|
+
const entryPath = join8(directory, entry.name);
|
|
67407
67920
|
if (entry.isDirectory()) {
|
|
67408
67921
|
skillFiles.push(...await collectSkillFiles(entryPath));
|
|
67409
67922
|
continue;
|
|
@@ -67447,7 +67960,7 @@ var init_loader = __esm({
|
|
|
67447
67960
|
|
|
67448
67961
|
// packages/daemon/src/skills/manager.ts
|
|
67449
67962
|
import { mkdir as mkdir5, readFile as readFile5, rm as rm3, writeFile as writeFile4 } from "node:fs/promises";
|
|
67450
|
-
import { basename as basename4, dirname as dirname6, join as
|
|
67963
|
+
import { basename as basename4, dirname as dirname6, join as join9 } from "node:path";
|
|
67451
67964
|
async function installSkill2(url2) {
|
|
67452
67965
|
const response = await fetch(url2);
|
|
67453
67966
|
if (!response.ok) {
|
|
@@ -67457,8 +67970,8 @@ async function installSkill2(url2) {
|
|
|
67457
67970
|
}
|
|
67458
67971
|
const skillMarkdown = await response.text();
|
|
67459
67972
|
const skillId = getSkillIdFromUrl(url2);
|
|
67460
|
-
const skillDirectory =
|
|
67461
|
-
const skillPath =
|
|
67973
|
+
const skillDirectory = join9(SKILLS_DIR, skillId);
|
|
67974
|
+
const skillPath = join9(skillDirectory, "SKILL.md");
|
|
67462
67975
|
const parsed = (0, import_gray_matter3.default)(skillMarkdown);
|
|
67463
67976
|
const installedSkill = {
|
|
67464
67977
|
id: skillId,
|
|
@@ -67472,7 +67985,7 @@ async function installSkill2(url2) {
|
|
|
67472
67985
|
return installedSkill;
|
|
67473
67986
|
}
|
|
67474
67987
|
async function removeSkill2(id) {
|
|
67475
|
-
await rm3(
|
|
67988
|
+
await rm3(join9(SKILLS_DIR, id), { recursive: true, force: true });
|
|
67476
67989
|
const lockFile = await readSkillsLock();
|
|
67477
67990
|
lockFile.skills = lockFile.skills.filter((skill) => skill.id !== id);
|
|
67478
67991
|
await writeSkillsLock2(lockFile);
|
|
@@ -68084,7 +68597,7 @@ var init_history = __esm({
|
|
|
68084
68597
|
// packages/daemon/src/execution/agent.ts
|
|
68085
68598
|
import { exec as exec2 } from "node:child_process";
|
|
68086
68599
|
import { mkdir as mkdir7, readFile as readFile7, readdir as readdir4, stat as stat3, writeFile as writeFile6 } from "node:fs/promises";
|
|
68087
|
-
import { dirname as dirname8, extname as extname3, isAbsolute, join as
|
|
68600
|
+
import { dirname as dirname8, extname as extname3, isAbsolute, join as join10, relative as relative3, resolve as resolve4 } from "node:path";
|
|
68088
68601
|
import { promisify as promisify2 } from "node:util";
|
|
68089
68602
|
import {
|
|
68090
68603
|
CopilotClient as CopilotClient2,
|
|
@@ -68115,13 +68628,24 @@ function mergeUsage(target, usage) {
|
|
|
68115
68628
|
}
|
|
68116
68629
|
async function persistUsage(member, usageEvents) {
|
|
68117
68630
|
for (const usage of usageEvents) {
|
|
68631
|
+
const model = usage.model;
|
|
68632
|
+
const pricing = await getModelPricing(model);
|
|
68633
|
+
const premiumRequestCost = pricing?.premiumMultiplier ?? 0;
|
|
68634
|
+
const tokenUnitCost = pricing ? calculateTokenUnitCost(
|
|
68635
|
+
usage.inputTokens ?? 0,
|
|
68636
|
+
usage.outputTokens ?? 0,
|
|
68637
|
+
pricing.tokenInputMultiplier,
|
|
68638
|
+
pricing.tokenOutputMultiplier
|
|
68639
|
+
) : 0;
|
|
68118
68640
|
await recordUsage({
|
|
68119
68641
|
squadId: member.squadId,
|
|
68120
68642
|
agentId: member.id,
|
|
68121
|
-
model
|
|
68643
|
+
model,
|
|
68122
68644
|
inputTokens: usage.inputTokens ?? 0,
|
|
68123
68645
|
outputTokens: usage.outputTokens ?? 0,
|
|
68124
|
-
cost:
|
|
68646
|
+
cost: 0,
|
|
68647
|
+
premiumRequestCost,
|
|
68648
|
+
tokenUnitCost
|
|
68125
68649
|
});
|
|
68126
68650
|
}
|
|
68127
68651
|
}
|
|
@@ -68139,7 +68663,7 @@ async function collectFiles(directory, recursive, output2) {
|
|
|
68139
68663
|
if (output2.length >= MAX_LIST_RESULTS) {
|
|
68140
68664
|
return;
|
|
68141
68665
|
}
|
|
68142
|
-
const fullPath =
|
|
68666
|
+
const fullPath = join10(directory, entry.name);
|
|
68143
68667
|
output2.push(fullPath);
|
|
68144
68668
|
if (recursive && entry.isDirectory()) {
|
|
68145
68669
|
await collectFiles(fullPath, recursive, output2);
|
|
@@ -68339,7 +68863,7 @@ async function executeAgentTask(member, task, worktreePath, options2) {
|
|
|
68339
68863
|
client2 = new CopilotClient2({ workingDirectory: worktreePath });
|
|
68340
68864
|
await client2.start();
|
|
68341
68865
|
const session = await client2.createSession({
|
|
68342
|
-
model: member.model ??
|
|
68866
|
+
model: member.model ?? DEFAULT_MODEL,
|
|
68343
68867
|
workingDirectory: worktreePath,
|
|
68344
68868
|
tools,
|
|
68345
68869
|
availableTools: ["custom:*"],
|
|
@@ -68396,6 +68920,7 @@ var init_agent = __esm({
|
|
|
68396
68920
|
"packages/daemon/src/execution/agent.ts"() {
|
|
68397
68921
|
"use strict";
|
|
68398
68922
|
init_dist();
|
|
68923
|
+
init_registry();
|
|
68399
68924
|
init_store2();
|
|
68400
68925
|
init_history();
|
|
68401
68926
|
execAsync2 = promisify2(exec2);
|
|
@@ -68495,7 +69020,7 @@ Return strict JSON in this shape:
|
|
|
68495
69020
|
// packages/daemon/src/execution/planning.ts
|
|
68496
69021
|
import { exec as exec3 } from "node:child_process";
|
|
68497
69022
|
import { access, readFile as readFile8 } from "node:fs/promises";
|
|
68498
|
-
import { join as
|
|
69023
|
+
import { join as join11 } from "node:path";
|
|
68499
69024
|
import { promisify as promisify3 } from "node:util";
|
|
68500
69025
|
import { CopilotClient as CopilotClient3, approveAll as approveAll3 } from "@github/copilot-sdk";
|
|
68501
69026
|
async function fileExists(path) {
|
|
@@ -68508,7 +69033,7 @@ async function fileExists(path) {
|
|
|
68508
69033
|
}
|
|
68509
69034
|
async function buildRepoContext(repoPath) {
|
|
68510
69035
|
for (const candidate of README_CANDIDATES) {
|
|
68511
|
-
const readmePath =
|
|
69036
|
+
const readmePath = join11(repoPath, candidate);
|
|
68512
69037
|
if (await fileExists(readmePath)) {
|
|
68513
69038
|
const content = await readFile8(readmePath, "utf8");
|
|
68514
69039
|
return content.slice(0, MAX_REPO_CONTEXT_LENGTH);
|
|
@@ -68594,7 +69119,7 @@ Return strict JSON in this shape:
|
|
|
68594
69119
|
client2 = new CopilotClient3({ workingDirectory: repoPath });
|
|
68595
69120
|
await client2.start();
|
|
68596
69121
|
const session = await client2.createSession({
|
|
68597
|
-
model:
|
|
69122
|
+
model: DEFAULT_MODEL,
|
|
68598
69123
|
workingDirectory: repoPath,
|
|
68599
69124
|
onPermissionRequest: approveAll3,
|
|
68600
69125
|
systemMessage: {
|
|
@@ -68642,7 +69167,7 @@ var init_planning = __esm({
|
|
|
68642
69167
|
// packages/daemon/src/execution/worktree.ts
|
|
68643
69168
|
import { exec as exec4 } from "node:child_process";
|
|
68644
69169
|
import { mkdir as mkdir8, rm as rm4 } from "node:fs/promises";
|
|
68645
|
-
import { join as
|
|
69170
|
+
import { join as join12 } from "node:path";
|
|
68646
69171
|
import { promisify as promisify4 } from "node:util";
|
|
68647
69172
|
function sanitizeBranchName(branchName) {
|
|
68648
69173
|
return branchName.replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
@@ -68659,7 +69184,7 @@ async function branchExists(repoPath, branchName) {
|
|
|
68659
69184
|
return output2.length > 0;
|
|
68660
69185
|
}
|
|
68661
69186
|
function getWorktreePath(repoPath, branchName) {
|
|
68662
|
-
return
|
|
69187
|
+
return join12(repoPath, ".worktrees", sanitizeBranchName(branchName));
|
|
68663
69188
|
}
|
|
68664
69189
|
async function listWorktrees(repoPath) {
|
|
68665
69190
|
const output2 = await runGit("git worktree list --porcelain", repoPath);
|
|
@@ -68709,7 +69234,7 @@ async function listWorktrees(repoPath) {
|
|
|
68709
69234
|
}
|
|
68710
69235
|
async function createWorktree(repoPath, branchName, baseBranch) {
|
|
68711
69236
|
const worktreePath = getWorktreePath(repoPath, branchName);
|
|
68712
|
-
await mkdir8(
|
|
69237
|
+
await mkdir8(join12(repoPath, ".worktrees"), { recursive: true });
|
|
68713
69238
|
const existing = (await listWorktrees(repoPath)).find(
|
|
68714
69239
|
(worktree) => worktree.path === worktreePath
|
|
68715
69240
|
);
|
|
@@ -68731,7 +69256,7 @@ async function createWorktree(repoPath, branchName, baseBranch) {
|
|
|
68731
69256
|
}
|
|
68732
69257
|
}
|
|
68733
69258
|
async function cleanupWorktree(worktreePath) {
|
|
68734
|
-
const parentRepoPath =
|
|
69259
|
+
const parentRepoPath = join12(worktreePath, "..", "..");
|
|
68735
69260
|
try {
|
|
68736
69261
|
await runGit(`git worktree remove ${JSON.stringify(worktreePath)}`, parentRepoPath);
|
|
68737
69262
|
} catch (error51) {
|
|
@@ -68770,7 +69295,7 @@ var init_worktree = __esm({
|
|
|
68770
69295
|
// packages/daemon/src/execution/pr.ts
|
|
68771
69296
|
import { exec as exec5 } from "node:child_process";
|
|
68772
69297
|
import { rm as rm5, writeFile as writeFile7 } from "node:fs/promises";
|
|
68773
|
-
import { join as
|
|
69298
|
+
import { join as join13 } from "node:path";
|
|
68774
69299
|
import { promisify as promisify5 } from "node:util";
|
|
68775
69300
|
async function runCommand(command, cwd) {
|
|
68776
69301
|
const { stdout } = await execAsync5(command, {
|
|
@@ -68784,7 +69309,7 @@ function extractUrl(output2) {
|
|
|
68784
69309
|
}
|
|
68785
69310
|
function buildBodyFilePath(repoPath, branchName) {
|
|
68786
69311
|
const safeBranchName = branchName.replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
68787
|
-
return
|
|
69312
|
+
return join13(repoPath, `.io-pr-body-${safeBranchName}.md`);
|
|
68788
69313
|
}
|
|
68789
69314
|
function buildPrBody(objective, plan, taskSummaries, qaOutcome) {
|
|
68790
69315
|
const tasks = taskSummaries.map((summary) => `- ${summary}`).join("\n") || "- No task summaries recorded.";
|
|
@@ -68885,7 +69410,7 @@ Return strict JSON:
|
|
|
68885
69410
|
client2 = new CopilotClient4({ workingDirectory: worktreePath });
|
|
68886
69411
|
await client2.start();
|
|
68887
69412
|
const session = await client2.createSession({
|
|
68888
|
-
model: qaMember.model ??
|
|
69413
|
+
model: qaMember.model ?? DEFAULT_MODEL,
|
|
68889
69414
|
workingDirectory: worktreePath,
|
|
68890
69415
|
onPermissionRequest: approveAll4,
|
|
68891
69416
|
systemMessage: {
|
|
@@ -69017,7 +69542,7 @@ Return strict JSON:
|
|
|
69017
69542
|
client2 = new CopilotClient5();
|
|
69018
69543
|
await client2.start();
|
|
69019
69544
|
const session = await client2.createSession({
|
|
69020
|
-
model: teamLead.model ??
|
|
69545
|
+
model: teamLead.model ?? DEFAULT_MODEL,
|
|
69021
69546
|
onPermissionRequest: approveAll5,
|
|
69022
69547
|
systemMessage: {
|
|
69023
69548
|
content: `${TEAM_LEAD_PROMPT}
|
|
@@ -69117,7 +69642,7 @@ var init_tasks = __esm({
|
|
|
69117
69642
|
// packages/daemon/src/execution/runner.ts
|
|
69118
69643
|
import { exec as exec7 } from "node:child_process";
|
|
69119
69644
|
import { access as access2 } from "node:fs/promises";
|
|
69120
|
-
import { basename as basename5, join as
|
|
69645
|
+
import { basename as basename5, join as join14 } from "node:path";
|
|
69121
69646
|
import { promisify as promisify7 } from "node:util";
|
|
69122
69647
|
async function pathExists(path) {
|
|
69123
69648
|
try {
|
|
@@ -69137,12 +69662,12 @@ async function runGit2(command, cwd) {
|
|
|
69137
69662
|
async function resolveRepoPath(repoUrl, repoName) {
|
|
69138
69663
|
const candidates = [
|
|
69139
69664
|
process.cwd(),
|
|
69140
|
-
|
|
69141
|
-
|
|
69142
|
-
|
|
69665
|
+
join14(process.cwd(), repoName),
|
|
69666
|
+
join14(process.cwd(), "repos", repoName),
|
|
69667
|
+
join14(process.cwd(), "..", repoName)
|
|
69143
69668
|
];
|
|
69144
69669
|
for (const candidate of candidates) {
|
|
69145
|
-
if (!await pathExists(
|
|
69670
|
+
if (!await pathExists(join14(candidate, ".git"))) {
|
|
69146
69671
|
continue;
|
|
69147
69672
|
}
|
|
69148
69673
|
const remoteUrl = await runGit2("git remote get-url origin", candidate).catch(() => "");
|
|
@@ -69507,12 +70032,9 @@ function buildMandatoryRoles() {
|
|
|
69507
70032
|
function modelForRole(role) {
|
|
69508
70033
|
const normalized = slugifyRole(role);
|
|
69509
70034
|
if (normalized === "team-lead") {
|
|
69510
|
-
return
|
|
70035
|
+
return DEFAULT_MODEL;
|
|
69511
70036
|
}
|
|
69512
|
-
|
|
69513
|
-
return STANDARD_MODEL;
|
|
69514
|
-
}
|
|
69515
|
-
return STANDARD_MODEL;
|
|
70037
|
+
return DEFAULT_MODEL;
|
|
69516
70038
|
}
|
|
69517
70039
|
function systemPromptForRole(role, repoContext) {
|
|
69518
70040
|
const normalized = slugifyRole(role);
|
|
@@ -69544,7 +70066,7 @@ ${ROLE_GENERATION_PROMPT}`;
|
|
|
69544
70066
|
client2 = new CopilotClient6();
|
|
69545
70067
|
await client2.start();
|
|
69546
70068
|
const session = await client2.createSession({
|
|
69547
|
-
model:
|
|
70069
|
+
model: DEFAULT_MODEL,
|
|
69548
70070
|
onPermissionRequest: approveAll6,
|
|
69549
70071
|
systemMessage: {
|
|
69550
70072
|
content: ROLE_GENERATION_PROMPT
|
|
@@ -69983,9 +70505,9 @@ var init_orchestrator = __esm({
|
|
|
69983
70505
|
"use strict";
|
|
69984
70506
|
init_dist();
|
|
69985
70507
|
init_reset();
|
|
69986
|
-
init_router();
|
|
69987
70508
|
init_session();
|
|
69988
70509
|
init_logger();
|
|
70510
|
+
init_registry();
|
|
69989
70511
|
init_skills2();
|
|
69990
70512
|
init_store2();
|
|
69991
70513
|
init_episodes();
|
|
@@ -70078,8 +70600,7 @@ var init_orchestrator = __esm({
|
|
|
70078
70600
|
skillsContext,
|
|
70079
70601
|
conversationSummary: [this.latestResetSummary, conversationSummary].filter(Boolean).join("\n\n")
|
|
70080
70602
|
});
|
|
70081
|
-
|
|
70082
|
-
await this.refreshSession(route.model, systemPrompt);
|
|
70603
|
+
await this.refreshSession(this.config.defaultModel, systemPrompt);
|
|
70083
70604
|
const sendResult = await sendMessage(
|
|
70084
70605
|
this.requireActiveSession(),
|
|
70085
70606
|
normalizedMessage,
|
|
@@ -70180,12 +70701,25 @@ var init_orchestrator = __esm({
|
|
|
70180
70701
|
}
|
|
70181
70702
|
async refreshSession(model, systemPrompt) {
|
|
70182
70703
|
await this.disconnectSession();
|
|
70183
|
-
|
|
70184
|
-
|
|
70185
|
-
|
|
70186
|
-
|
|
70187
|
-
|
|
70188
|
-
|
|
70704
|
+
try {
|
|
70705
|
+
this.activeSession = await createSession({
|
|
70706
|
+
model,
|
|
70707
|
+
systemPrompt,
|
|
70708
|
+
tools: createBoundOrchestratorTools(this.config)
|
|
70709
|
+
});
|
|
70710
|
+
this.activeModel = model;
|
|
70711
|
+
} catch (error51) {
|
|
70712
|
+
if (model !== DEFAULT_MODEL) {
|
|
70713
|
+
this.activeSession = await createSession({
|
|
70714
|
+
model: DEFAULT_MODEL,
|
|
70715
|
+
systemPrompt,
|
|
70716
|
+
tools: createBoundOrchestratorTools(this.config)
|
|
70717
|
+
});
|
|
70718
|
+
this.activeModel = DEFAULT_MODEL;
|
|
70719
|
+
} else {
|
|
70720
|
+
throw error51;
|
|
70721
|
+
}
|
|
70722
|
+
}
|
|
70189
70723
|
}
|
|
70190
70724
|
async disconnectSession() {
|
|
70191
70725
|
if (!this.activeSession) {
|
|
@@ -70207,11 +70741,22 @@ var init_orchestrator = __esm({
|
|
|
70207
70741
|
if (usage.inputTokens === 0 && usage.outputTokens === 0) {
|
|
70208
70742
|
return;
|
|
70209
70743
|
}
|
|
70744
|
+
const model = usage.model || this.activeModel || this.config.defaultModel;
|
|
70745
|
+
const pricing = await getModelPricing(model);
|
|
70746
|
+
const premiumRequestCost = pricing?.premiumMultiplier ?? 0;
|
|
70747
|
+
const tokenUnitCost = pricing ? calculateTokenUnitCost(
|
|
70748
|
+
usage.inputTokens,
|
|
70749
|
+
usage.outputTokens,
|
|
70750
|
+
pricing.tokenInputMultiplier,
|
|
70751
|
+
pricing.tokenOutputMultiplier
|
|
70752
|
+
) : 0;
|
|
70210
70753
|
await recordUsage({
|
|
70211
|
-
model
|
|
70754
|
+
model,
|
|
70212
70755
|
inputTokens: usage.inputTokens,
|
|
70213
70756
|
outputTokens: usage.outputTokens,
|
|
70214
|
-
cost: 0
|
|
70757
|
+
cost: 0,
|
|
70758
|
+
premiumRequestCost,
|
|
70759
|
+
tokenUnitCost
|
|
70215
70760
|
});
|
|
70216
70761
|
}
|
|
70217
70762
|
};
|
|
@@ -83818,6 +84363,7 @@ function registerShutdownHandlers(logger, onShutdown) {
|
|
|
83818
84363
|
}
|
|
83819
84364
|
async function main() {
|
|
83820
84365
|
let logger;
|
|
84366
|
+
let pricingRefreshTimer = null;
|
|
83821
84367
|
try {
|
|
83822
84368
|
ensureDataDirectories();
|
|
83823
84369
|
const config2 = loadConfig();
|
|
@@ -83825,6 +84371,12 @@ async function main() {
|
|
|
83825
84371
|
logger.info(`IO Daemon v${APP_VERSION} starting...`);
|
|
83826
84372
|
await initDatabase();
|
|
83827
84373
|
logger.info("Database initialized");
|
|
84374
|
+
const pricingResult = await refreshModelPricing(logger);
|
|
84375
|
+
if (pricingResult.modelsUpdated === 0) {
|
|
84376
|
+
logger.warn("Model pricing refresh returned 0 models, seeding with fallback");
|
|
84377
|
+
await seedFromFallback();
|
|
84378
|
+
}
|
|
84379
|
+
logger.info({ modelsUpdated: pricingResult.modelsUpdated }, "Model pricing initialized");
|
|
83828
84380
|
await scanSkills();
|
|
83829
84381
|
logger.info("Skills scanned");
|
|
83830
84382
|
const orchestrator2 = createOrchestrator(config2, eventBus);
|
|
@@ -83833,12 +84385,21 @@ async function main() {
|
|
|
83833
84385
|
const scheduler = createScheduler(orchestrator2, eventBus);
|
|
83834
84386
|
scheduler.start();
|
|
83835
84387
|
logger.info("Scheduler started");
|
|
84388
|
+
const refreshIntervalMs = config2.pricingRefreshHours * 60 * 60 * 1e3;
|
|
84389
|
+
pricingRefreshTimer = setInterval(() => {
|
|
84390
|
+
void refreshModelPricing(logger).catch((err) => {
|
|
84391
|
+
logger?.warn({ err }, "Periodic model pricing refresh failed");
|
|
84392
|
+
});
|
|
84393
|
+
}, refreshIntervalMs);
|
|
83836
84394
|
setChatOrchestrator(orchestrator2);
|
|
83837
84395
|
const apiServer = createApiServer(config2);
|
|
83838
84396
|
const telegramBot = createTelegramBot(config2, orchestrator2);
|
|
83839
84397
|
telegramBot?.start();
|
|
83840
84398
|
createTelegramNotifier(telegramBot, config2, eventBus);
|
|
83841
84399
|
registerShutdownHandlers(logger, async () => {
|
|
84400
|
+
if (pricingRefreshTimer) {
|
|
84401
|
+
clearInterval(pricingRefreshTimer);
|
|
84402
|
+
}
|
|
83842
84403
|
scheduler.stop();
|
|
83843
84404
|
telegramBot?.stop();
|
|
83844
84405
|
apiServer.server.close();
|
|
@@ -83863,6 +84424,7 @@ var init_index = __esm({
|
|
|
83863
84424
|
init_data_dir();
|
|
83864
84425
|
init_event_bus();
|
|
83865
84426
|
init_logger();
|
|
84427
|
+
init_models();
|
|
83866
84428
|
init_orchestrator2();
|
|
83867
84429
|
init_scheduler();
|
|
83868
84430
|
init_skills2();
|