@triflux/remote 10.86.1 → 10.88.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/hub/team/cli/commands/debug.mjs +11 -4
- package/hub/team/handoff.mjs +100 -0
- package/hub/team/headless.mjs +49 -10
- package/hub/team/lead-launch.mjs +186 -0
- package/hub/team/native-peer.mjs +97 -3
- package/hub/team/orchestrator.mjs +80 -0
- package/hub/team/pane.mjs +99 -0
- package/hub/team/results-index.mjs +35 -0
- package/hub/team/retry-state-machine.mjs +97 -9
- package/hub/team/uds-orchestrator.mjs +30 -8
- package/package.json +1 -1
- package/scripts/lib/agent-route-policy.mjs +39 -28
- package/scripts/lib/codex-profile-config.mjs +40 -59
- package/scripts/lib/doctor-env-checks.mjs +377 -0
- package/scripts/lib/gemini-profiles.mjs +2 -5
- package/scripts/lib/mcp-filter.mjs +86 -3
- package/scripts/lib/model-effort.mjs +134 -0
- package/scripts/lib/model-family-resolver.mjs +73 -8
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AGY_FAMILY_PROFILES,
|
|
3
|
+
CODEX_FAMILY_PROFILES,
|
|
4
|
+
readCodexModelCatalog,
|
|
5
|
+
resolveModelFamilies,
|
|
6
|
+
} from "./model-family-resolver.mjs";
|
|
7
|
+
|
|
8
|
+
export const EFFORT_ORDER = Object.freeze([
|
|
9
|
+
"none",
|
|
10
|
+
"low",
|
|
11
|
+
"medium",
|
|
12
|
+
"high",
|
|
13
|
+
"xhigh",
|
|
14
|
+
"max",
|
|
15
|
+
"ultra",
|
|
16
|
+
]);
|
|
17
|
+
|
|
18
|
+
const LEGACY_CANONICAL_PROFILE_ALIASES = Object.freeze({
|
|
19
|
+
gpt56_sol_xhigh: "astra_xhigh",
|
|
20
|
+
gpt56_sol_max: "astra_max",
|
|
21
|
+
gpt56_sol_ultra: "astra_ultra",
|
|
22
|
+
gpt56_terra_high: "sol_high",
|
|
23
|
+
gpt56_terra_med: "sol_med",
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export function normalizeCodexProfileName(profileName) {
|
|
27
|
+
const normalized = String(profileName ?? "").trim();
|
|
28
|
+
if (Object.hasOwn(LEGACY_CANONICAL_PROFILE_ALIASES, normalized))
|
|
29
|
+
return LEGACY_CANONICAL_PROFILE_ALIASES[normalized];
|
|
30
|
+
const familyName = normalized.replace(/^gpt\d+_(sol|astra|luna)_/, "$1_");
|
|
31
|
+
return Object.hasOwn(CODEX_FAMILY_PROFILES, familyName)
|
|
32
|
+
? familyName
|
|
33
|
+
: normalized;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function normalizeGeminiProfileName(name) {
|
|
37
|
+
const raw = String(name ?? "").trim();
|
|
38
|
+
// 옛 Flash 이름은 effort와 상관없이 Argon Low로 보낸다.
|
|
39
|
+
return raw.replace(/^flash\d*(?:_(?:low|high))?$/, "argon_low");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function modelEffortFromProfile(cli, profile, effort) {
|
|
43
|
+
if (effort !== undefined) {
|
|
44
|
+
const definitions =
|
|
45
|
+
cli === "codex"
|
|
46
|
+
? CODEX_FAMILY_PROFILES
|
|
47
|
+
: cli === "antigravity" || cli === "agy"
|
|
48
|
+
? AGY_FAMILY_PROFILES
|
|
49
|
+
: {};
|
|
50
|
+
return EFFORT_ORDER.includes(effort) &&
|
|
51
|
+
Object.values(definitions).some(({ family }) => family === profile)
|
|
52
|
+
? { family: profile, effort }
|
|
53
|
+
: null;
|
|
54
|
+
}
|
|
55
|
+
let definition;
|
|
56
|
+
if (cli === "codex") {
|
|
57
|
+
const normalized = normalizeCodexProfileName(profile);
|
|
58
|
+
const name =
|
|
59
|
+
normalized === "max" || normalized === "ultra"
|
|
60
|
+
? `astra_${normalized}`
|
|
61
|
+
: normalized;
|
|
62
|
+
if (Object.hasOwn(CODEX_FAMILY_PROFILES, name))
|
|
63
|
+
definition = CODEX_FAMILY_PROFILES[name];
|
|
64
|
+
} else if (cli === "antigravity" || cli === "agy") {
|
|
65
|
+
const name = normalizeGeminiProfileName(profile);
|
|
66
|
+
if (Object.hasOwn(AGY_FAMILY_PROFILES, name))
|
|
67
|
+
definition = AGY_FAMILY_PROFILES[name];
|
|
68
|
+
}
|
|
69
|
+
return definition
|
|
70
|
+
? { family: definition.family, effort: definition.effort }
|
|
71
|
+
: null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function profileFromModelEffort(cli, { family, effort }) {
|
|
75
|
+
const profiles =
|
|
76
|
+
cli === "codex"
|
|
77
|
+
? CODEX_FAMILY_PROFILES
|
|
78
|
+
: cli === "antigravity" || cli === "agy"
|
|
79
|
+
? AGY_FAMILY_PROFILES
|
|
80
|
+
: {};
|
|
81
|
+
return (
|
|
82
|
+
Object.entries(profiles).find(
|
|
83
|
+
([, value]) => value.family === family && value.effort === effort,
|
|
84
|
+
)?.[0] || null
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function resolveCodexModelEffort({ family, effort }, opts = {}) {
|
|
89
|
+
const { families } = resolveModelFamilies("codex", {
|
|
90
|
+
...opts,
|
|
91
|
+
allowCommand: false,
|
|
92
|
+
persist: false,
|
|
93
|
+
});
|
|
94
|
+
if (!Object.hasOwn(families, family) || !EFFORT_ORDER.includes(effort)) {
|
|
95
|
+
throw new Error(`알 수 없는 Codex 가족 또는 effort: ${family}/${effort}`);
|
|
96
|
+
}
|
|
97
|
+
const model = families[family].model;
|
|
98
|
+
const supported = readCodexModelCatalog(opts)?.models?.find(
|
|
99
|
+
(entry) => entry?.slug === model,
|
|
100
|
+
)?.supported_reasoning_levels;
|
|
101
|
+
if (!Array.isArray(supported)) return { family, model, effort };
|
|
102
|
+
const levels = supported.map((level) => level?.effort ?? level);
|
|
103
|
+
const selected = EFFORT_ORDER.slice(0, EFFORT_ORDER.indexOf(effort) + 1)
|
|
104
|
+
.filter((level) => levels.includes(level))
|
|
105
|
+
.at(-1);
|
|
106
|
+
if (!selected) {
|
|
107
|
+
const error = new Error(
|
|
108
|
+
`${model}: ${effort} 이하의 지원 effort가 없습니다`,
|
|
109
|
+
);
|
|
110
|
+
error.code = "unsupported-effort";
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
113
|
+
return { family, model, effort: selected };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function resolveAgyModelEffort({ family, effort }, opts = {}) {
|
|
117
|
+
const { families } = resolveModelFamilies("agy", opts);
|
|
118
|
+
if (!Object.hasOwn(families, family) || !EFFORT_ORDER.includes(effort)) {
|
|
119
|
+
throw new Error(`알 수 없는 agy 가족 또는 effort: ${family}/${effort}`);
|
|
120
|
+
}
|
|
121
|
+
const { model, supportedEfforts } = families[family];
|
|
122
|
+
if (!supportedEfforts) return { family, model, effort };
|
|
123
|
+
const selected = EFFORT_ORDER.slice(0, EFFORT_ORDER.indexOf(effort) + 1)
|
|
124
|
+
.filter((level) => supportedEfforts.includes(level))
|
|
125
|
+
.at(-1);
|
|
126
|
+
if (!selected) {
|
|
127
|
+
const error = new Error(
|
|
128
|
+
`${model}: ${effort} 이하의 지원 effort가 없습니다`,
|
|
129
|
+
);
|
|
130
|
+
error.code = "unsupported-effort";
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
return { family, model, effort: selected };
|
|
134
|
+
}
|
|
@@ -39,7 +39,8 @@ export const AGY_FAMILY_PROFILES = Object.freeze({
|
|
|
39
39
|
});
|
|
40
40
|
const DAY_MS = 86_400_000;
|
|
41
41
|
const CODEX_SLUG = /^gpt-(\d+(?:\.\d+)*)-(sol|astra|terra|luna)$/;
|
|
42
|
-
const AGY_SLUG =
|
|
42
|
+
const AGY_SLUG =
|
|
43
|
+
/^gemini-(\d+(?:\.\d+)*)-(argon)-(none|low|medium|high|xhigh|max|ultra)$/;
|
|
43
44
|
|
|
44
45
|
function compareVersions(a, b) {
|
|
45
46
|
const left = a.split(".").map(Number);
|
|
@@ -59,10 +60,11 @@ export function selectCodexModel(models, family, effort) {
|
|
|
59
60
|
return (
|
|
60
61
|
match?.[2] === family &&
|
|
61
62
|
item.visibility === "list" &&
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
(effort === undefined ||
|
|
64
|
+
(Array.isArray(item.supported_reasoning_levels) &&
|
|
65
|
+
item.supported_reasoning_levels.some(
|
|
66
|
+
(level) => (level?.effort ?? level) === effort,
|
|
67
|
+
)))
|
|
66
68
|
);
|
|
67
69
|
})
|
|
68
70
|
.sort((a, b) =>
|
|
@@ -89,7 +91,7 @@ export function selectAgyModel(models, family, effort) {
|
|
|
89
91
|
const match = AGY_SLUG.exec(item?.slug);
|
|
90
92
|
return (
|
|
91
93
|
match?.[2] === family &&
|
|
92
|
-
match?.[3] === effort &&
|
|
94
|
+
(effort === undefined || match?.[3] === effort) &&
|
|
93
95
|
typeof item.model === "string"
|
|
94
96
|
);
|
|
95
97
|
})
|
|
@@ -203,7 +205,7 @@ export function resolveModelFamilies(provider, opts = {}) {
|
|
|
203
205
|
if (provider === "codex") {
|
|
204
206
|
const cachePath = join(paths.codexHome, "models_cache.json");
|
|
205
207
|
sourceSignature = signature(cachePath);
|
|
206
|
-
if (sourceSignature !== previous.sourceSignature)
|
|
208
|
+
if (sourceSignature !== previous.sourceSignature || !previous.families)
|
|
207
209
|
catalog = readCodexModelCatalog(opts);
|
|
208
210
|
if (
|
|
209
211
|
sourceSignature.endsWith(":missing") &&
|
|
@@ -266,6 +268,8 @@ export function resolveModelFamilies(provider, opts = {}) {
|
|
|
266
268
|
}
|
|
267
269
|
const profiles = {};
|
|
268
270
|
const selectedProfiles = {};
|
|
271
|
+
const families = {};
|
|
272
|
+
const selectedFamilies = {};
|
|
269
273
|
const pins = readJson(paths.pinsPath) || {};
|
|
270
274
|
for (const [name, definition] of Object.entries(definitions)) {
|
|
271
275
|
const saved = previous.profiles?.[name];
|
|
@@ -329,13 +333,74 @@ export function resolveModelFamilies(provider, opts = {}) {
|
|
|
329
333
|
fetched_at: null,
|
|
330
334
|
};
|
|
331
335
|
}
|
|
336
|
+
if (provider === "codex" && !Object.hasOwn(families, definition.family)) {
|
|
337
|
+
const latest = selectCodexModel(catalog?.models, definition.family);
|
|
338
|
+
const lastFamily =
|
|
339
|
+
previous.families?.[definition.family] || profiles[name];
|
|
340
|
+
families[definition.family] =
|
|
341
|
+
latest &&
|
|
342
|
+
(!lastFamily.fetched_at ||
|
|
343
|
+
!catalog.fetched_at ||
|
|
344
|
+
Date.parse(catalog.fetched_at) >= Date.parse(lastFamily.fetched_at))
|
|
345
|
+
? { model: latest.slug, fetched_at: catalog.fetched_at || fetchedAt }
|
|
346
|
+
: { model: lastFamily.model, fetched_at: lastFamily.fetched_at };
|
|
347
|
+
selectedFamilies[definition.family] =
|
|
348
|
+
typeof pin === "string" &&
|
|
349
|
+
CODEX_SLUG.exec(pin)?.[2] === definition.family
|
|
350
|
+
? { model: pin, source: paths.pinsPath, fetched_at: null }
|
|
351
|
+
: { ...families[definition.family] };
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
if (provider === "agy") {
|
|
355
|
+
const latest = selectAgyModel(catalog?.models, "argon");
|
|
356
|
+
// 옛 기록에는 가족 ID가 없으므로 마지막 성공 프로필의 표시 이름에서 복원한다.
|
|
357
|
+
const savedModels = [
|
|
358
|
+
...Object.values(AGY_FAMILY_PROFILES),
|
|
359
|
+
...Object.values(profiles),
|
|
360
|
+
].flatMap((profile) => {
|
|
361
|
+
const match = /^Gemini (\d+(?:\.\d+)*) Argon \(/i.exec(profile.model);
|
|
362
|
+
return match
|
|
363
|
+
? [{ ...profile, slug: `gemini-${match[1]}-argon-${profile.effort}` }]
|
|
364
|
+
: [];
|
|
365
|
+
});
|
|
366
|
+
const saved = selectAgyModel(savedModels, "argon");
|
|
367
|
+
const last = previous.families?.argon || {
|
|
368
|
+
model: saved.slug.replace(/-[^-]+$/, ""),
|
|
369
|
+
fetched_at: saved.fetched_at,
|
|
370
|
+
};
|
|
371
|
+
families.argon =
|
|
372
|
+
latest &&
|
|
373
|
+
(!last.fetched_at ||
|
|
374
|
+
!catalog.fetched_at ||
|
|
375
|
+
Date.parse(catalog.fetched_at) >= Date.parse(last.fetched_at))
|
|
376
|
+
? {
|
|
377
|
+
model: latest.slug.replace(/-[^-]+$/, ""),
|
|
378
|
+
fetched_at: catalog.fetched_at || fetchedAt,
|
|
379
|
+
}
|
|
380
|
+
: last;
|
|
381
|
+
const pin = pins.argon;
|
|
382
|
+
selectedFamilies.argon =
|
|
383
|
+
typeof pin === "string" && AGY_SLUG.test(`${pin}-low`)
|
|
384
|
+
? { model: pin, source: paths.pinsPath, fetched_at: null }
|
|
385
|
+
: { ...families.argon };
|
|
386
|
+
const supported = catalog?.models
|
|
387
|
+
?.filter((item) =>
|
|
388
|
+
item.slug.startsWith(`${selectedFamilies.argon.model}-`),
|
|
389
|
+
)
|
|
390
|
+
.map((item) => AGY_SLUG.exec(item.slug)?.[3])
|
|
391
|
+
.filter(Boolean);
|
|
392
|
+
if (supported?.length) selectedFamilies.argon.supportedEfforts = supported;
|
|
332
393
|
}
|
|
333
394
|
const record = {
|
|
334
395
|
sourceSignature,
|
|
335
396
|
checked_at: checkedAt || null,
|
|
336
397
|
profiles,
|
|
337
398
|
selectedProfiles,
|
|
399
|
+
families,
|
|
338
400
|
};
|
|
339
401
|
if (opts.persist !== false) saveJson(recordPath, record);
|
|
340
|
-
return {
|
|
402
|
+
return {
|
|
403
|
+
profiles: selectedProfiles,
|
|
404
|
+
families: selectedFamilies,
|
|
405
|
+
};
|
|
341
406
|
}
|