@triflux/remote 10.50.1 → 10.51.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/cto/brief.mjs +0 -12
- package/cto/collect.mjs +16 -247
- package/cto/current.schema.json +4 -20
- package/cto/events.mjs +13 -294
- package/cto/hygiene.mjs +26 -346
- package/cto/lake-root.mjs +114 -16
- package/cto/status.mjs +33 -128
- package/hub/index.mjs +0 -8
- package/hub/store-adapter.mjs +1 -1
- package/hub/team/agent-map.json +0 -1
- package/hub/team/ansi.mjs +1 -35
- package/hub/team/backend.mjs +9 -145
- package/hub/team/cli/commands/attach.mjs +1 -17
- package/hub/team/cli/commands/control.mjs +12 -38
- package/hub/team/cli/commands/debug.mjs +1 -37
- package/hub/team/cli/commands/focus.mjs +5 -31
- package/hub/team/cli/commands/interrupt.mjs +6 -25
- package/hub/team/cli/commands/kill.mjs +1 -30
- package/hub/team/cli/commands/list.mjs +0 -16
- package/hub/team/cli/commands/send.mjs +6 -26
- package/hub/team/cli/commands/start/index.mjs +41 -133
- package/hub/team/cli/commands/start/parse-args.mjs +15 -40
- package/hub/team/cli/commands/start/start-headless.mjs +138 -105
- package/hub/team/cli/commands/start/start-mux.mjs +0 -3
- package/hub/team/cli/commands/status.mjs +2 -57
- package/hub/team/cli/commands/stop.mjs +14 -19
- package/hub/team/cli/help.mjs +4 -5
- package/hub/team/cli/manifest.mjs +5 -1
- package/hub/team/cli/render.mjs +0 -12
- package/hub/team/cli/services/hub-client.mjs +2 -88
- package/hub/team/cli/services/runtime-mode.mjs +27 -98
- package/hub/team/handoff.mjs +3 -34
- package/hub/team/headless.mjs +14 -755
- package/hub/team/orchestrator.mjs +4 -30
- package/hub/team/pane.mjs +6 -28
- package/hub/team/psmux.mjs +16 -403
- package/hub/team/remote-session.mjs +1 -2
- package/hub/team/session.mjs +8 -119
- package/hub/team/swarm-intent.mjs +0 -198
- package/hub/team/terminal-opener.mjs +11 -35
- package/hub/team/tui-core.mjs +1 -1
- package/hub/team/tui-viewer.mjs +2 -2
- package/hub/team/tui.mjs +8 -269
- package/hub/team/wt-manager.mjs +2 -2
- package/hub/workers/factory.mjs +4 -37
- package/hub/workers/lib/jsonrpc-ws-uds.mjs +0 -2
- package/package.json +1 -1
- package/scripts/lib/agent-route-policy.mjs +162 -14
- package/scripts/lib/claudemd-scanner.mjs +2 -199
- package/scripts/lib/cli-claude.mjs +0 -2
- package/scripts/lib/context.mjs +3 -19
- package/scripts/lib/env-probe.mjs +5 -64
- package/scripts/lib/gemini-profiles.mjs +2 -69
- package/scripts/lib/legacy-mcp-cleanup.mjs +14 -3
- package/scripts/lib/machine-profile.mjs +3 -17
- package/scripts/lib/mcp-filter.mjs +109 -53
- package/scripts/lib/mcp-health.mjs +2 -2
- package/scripts/lib/mcp-server-catalog.mjs +2 -2
- package/scripts/lib/psmux-info.mjs +25 -104
- package/scripts/lib/skill-template.mjs +0 -271
- package/cto/hygiene-actions.mjs +0 -355
- package/cto/hygiene-notify.mjs +0 -170
- package/hub/team/build-worker-prompt.mjs +0 -92
- package/hub/team/check-mcp-hub.mjs +0 -49
- package/hub/team/claude-native-bridge.mjs +0 -987
- package/hub/team/cli/commands/start/start-in-process.mjs +0 -50
- package/hub/team/cli/commands/start/start-wt.mjs +0 -86
- package/hub/team/cli/services/native-control.mjs +0 -145
- package/hub/team/codex-review.mjs +0 -520
- package/hub/team/conductor-mesh-bridge.mjs +0 -122
- package/hub/team/conductor.mjs +0 -1529
- package/hub/team/consensus-meta.mjs +0 -176
- package/hub/team/cto-pull.mjs +0 -31
- package/hub/team/daemon-pty-tmux-bridge.mjs +0 -146
- package/hub/team/dashboard.mjs +0 -322
- package/hub/team/event-log.mjs +0 -84
- package/hub/team/execution-mode.mjs +0 -324
- package/hub/team/extract-completion-payload.mjs +0 -110
- package/hub/team/headless-bridge-session.mjs +0 -17
- package/hub/team/health-probe.mjs +0 -435
- package/hub/team/interactive-native-launcher.mjs +0 -119
- package/hub/team/interactive-native-worker.mjs +0 -80
- package/hub/team/interactive-tui-transport.mjs +0 -479
- package/hub/team/launcher-template.mjs +0 -144
- package/hub/team/mcp-selector.mjs +0 -145
- package/hub/team/native-supervisor.mjs +0 -460
- package/hub/team/native.mjs +0 -727
- package/hub/team/recovery-store.mjs +0 -149
- package/hub/team/remote-probe.mjs +0 -292
- package/hub/team/remote-watcher.mjs +0 -506
- package/hub/team/runtime-strategy.mjs +0 -200
- package/hub/team/schemas/worker-completion.json +0 -39
- package/hub/team/sentinel-capture.mjs +0 -127
- package/hub/team/swarm-cli.mjs +0 -390
- package/hub/team/swarm-hypervisor.mjs +0 -2206
- package/hub/team/swarm-locks.mjs +0 -335
- package/hub/team/swarm-planner.mjs +0 -371
- package/hub/team/swarm-preflight.mjs +0 -366
- package/hub/team/swarm-reconciler.mjs +0 -242
- package/hub/team/tui-remote-adapter.mjs +0 -377
- package/hub/team/worker-completion-validator.mjs +0 -79
- package/hub/team/worktree-lifecycle.mjs +0 -639
- package/hub/team/wt-templates.json +0 -43
- package/hub/workers/antigravity-route-worker.mjs +0 -179
- package/hub/workers/gemini-worker.mjs +0 -217
- package/scripts/lib/agent-json.mjs +0 -27
- package/scripts/lib/async.mjs +0 -174
- package/scripts/lib/cli-agy.mjs +0 -85
- package/scripts/lib/cli-codex.mjs +0 -62
- package/scripts/lib/cli-gemini.mjs +0 -37
- package/scripts/lib/dynamic-route-cli.mjs +0 -107
- package/scripts/lib/env.mjs +0 -14
- package/scripts/lib/hub.mjs +0 -48
- package/scripts/lib/pid.mjs +0 -63
- package/scripts/lib/quota.mjs +0 -47
- package/scripts/lib/skill-state.mjs +0 -220
- package/scripts/lib/team.mjs +0 -75
- package/scripts/lib/timeout.mjs +0 -66
- package/scripts/lib/tmp.mjs +0 -26
- package/scripts/lib/toml.mjs +0 -132
|
@@ -30,36 +30,10 @@ const DEFAULT_GEMINI_PROFILES = {
|
|
|
30
30
|
},
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
// 1회 마이그레이션 테이블: 옛 ID 형식 모델값 → agy display name.
|
|
34
|
-
// null = 카탈로그에서 빠진 모델(2.5 계열, 3 Flash) → 해당 프로필 제거 대상.
|
|
35
|
-
const LEGACY_MODEL_MIGRATION = {
|
|
36
|
-
"gemini-3.1-pro-preview": "Gemini 3.1 Pro (High)",
|
|
37
|
-
"gemini-3-flash-preview": null,
|
|
38
|
-
"Gemini 3 Flash": null,
|
|
39
|
-
"gemini-2.5-pro": null,
|
|
40
|
-
"gemini-2.5-flash": null,
|
|
41
|
-
"gemini-2.5-flash-lite": null,
|
|
42
|
-
};
|
|
43
|
-
// 과거 setup 이 자동 생성했던 프로필 이름. 정책상 더 쓰지 않으므로 제거한다.
|
|
44
|
-
// 사용자가 직접 이름 붙인 프로필은 건드리지 않는다.
|
|
45
|
-
const LEGACY_PROFILE_NAMES = [
|
|
46
|
-
"pro25",
|
|
47
|
-
"flash25",
|
|
48
|
-
"lite25",
|
|
49
|
-
"flash3",
|
|
50
|
-
"pro31",
|
|
51
|
-
"pro31_low",
|
|
52
|
-
"flash35",
|
|
53
|
-
"flash35_high",
|
|
54
|
-
"flash35_low",
|
|
55
|
-
];
|
|
56
|
-
// 과거 setup 이 자동 생성한 기본 model 값. 사용자가 고른 값이 아니므로 새 기본으로 올린다.
|
|
57
|
-
const LEGACY_DEFAULT_MODELS = new Set(["Gemini 3.5 Flash (Medium)"]);
|
|
58
|
-
|
|
59
33
|
// ── 용도별 effort (SSOT) ──
|
|
60
34
|
// 한 세대(3.8 Flash)만 쓰고 역할에 따라 effort 를 나눈다. 키는 tfx 에이전트/역할 이름
|
|
61
35
|
// (agent-map.json 의 에이전트, tfx multi --assign 의 role). bash(tfx-route.sh)와
|
|
62
|
-
//
|
|
36
|
+
// 실행 모드(execution-mode)가 이 표를 읽는다.
|
|
63
37
|
// High : 판단이 결과를 좌우하는 역할 (검토, 설계, 디버깅, 분석)
|
|
64
38
|
// Medium : 생성/작성/실행 (기본값)
|
|
65
39
|
// Low : 분류, 요약, 추출, 번역처럼 짧고 기계적인 작업
|
|
@@ -182,40 +156,6 @@ function ensureGeminiProfiles({
|
|
|
182
156
|
)
|
|
183
157
|
cfg.profiles = {};
|
|
184
158
|
|
|
185
|
-
// ── 1회 마이그레이션: deprecated 2.5 프로필 prune + 옛 ID 형식 → display name ──
|
|
186
|
-
// merge-only 로직만으로는 기존 사용자 파일에 남은 stale 프로필/옛 모델 ID 가
|
|
187
|
-
// 정리되지 않으므로, 신규 default 를 채우기 전에 마이그레이션을 먼저 적용한다.
|
|
188
|
-
let migrated = false;
|
|
189
|
-
for (const legacy of LEGACY_PROFILE_NAMES) {
|
|
190
|
-
if (cfg.profiles[legacy]) {
|
|
191
|
-
delete cfg.profiles[legacy];
|
|
192
|
-
migrated = true;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
for (const [pname, pval] of Object.entries(cfg.profiles)) {
|
|
196
|
-
const mid = typeof pval === "string" ? pval : pval?.model;
|
|
197
|
-
if (mid && Object.hasOwn(LEGACY_MODEL_MIGRATION, mid)) {
|
|
198
|
-
const repl = LEGACY_MODEL_MIGRATION[mid];
|
|
199
|
-
if (repl === null) {
|
|
200
|
-
delete cfg.profiles[pname];
|
|
201
|
-
} else if (typeof pval === "string") {
|
|
202
|
-
cfg.profiles[pname] = repl;
|
|
203
|
-
} else {
|
|
204
|
-
cfg.profiles[pname].model = repl;
|
|
205
|
-
}
|
|
206
|
-
migrated = true;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
if (
|
|
210
|
-
typeof cfg.model === "string" &&
|
|
211
|
-
(Object.hasOwn(LEGACY_MODEL_MIGRATION, cfg.model) ||
|
|
212
|
-
LEGACY_DEFAULT_MODELS.has(cfg.model))
|
|
213
|
-
) {
|
|
214
|
-
// 옛 ID 형식/이전 세대 자동 생성 기본값은 새 기본(DEFAULT)으로 정규화한다.
|
|
215
|
-
cfg.model = DEFAULT_GEMINI_PROFILES.model;
|
|
216
|
-
migrated = true;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
159
|
let added = 0;
|
|
220
160
|
for (const [name, value] of Object.entries(
|
|
221
161
|
DEFAULT_GEMINI_PROFILES.profiles,
|
|
@@ -227,12 +167,7 @@ function ensureGeminiProfiles({
|
|
|
227
167
|
}
|
|
228
168
|
if (!cfg.model) cfg.model = DEFAULT_GEMINI_PROFILES.model;
|
|
229
169
|
|
|
230
|
-
if (added > 0
|
|
231
|
-
if (migrated) {
|
|
232
|
-
try {
|
|
233
|
-
copyFileSync(profilesPath, profilesPath + `.bak.${Date.now()}`);
|
|
234
|
-
} catch {}
|
|
235
|
-
}
|
|
170
|
+
if (added > 0) {
|
|
236
171
|
writeFileSync(profilesPath, JSON.stringify(cfg, null, 2) + "\n", {
|
|
237
172
|
encoding: "utf8",
|
|
238
173
|
mode: 0o600,
|
|
@@ -260,8 +195,6 @@ function ensureGeminiProfiles({
|
|
|
260
195
|
export {
|
|
261
196
|
DEFAULT_GEMINI_PROFILES,
|
|
262
197
|
ensureGeminiProfiles,
|
|
263
|
-
GEMINI_DEFAULT_PURPOSE_PROFILE,
|
|
264
|
-
GEMINI_PROFILE_BY_PURPOSE,
|
|
265
198
|
resolveGeminiModel,
|
|
266
199
|
resolveGeminiProfileForPurpose,
|
|
267
200
|
};
|
|
@@ -143,7 +143,14 @@ function envWarning(server, home, env, warnings) {
|
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
function patchJson(
|
|
146
|
+
function patchJson(
|
|
147
|
+
original,
|
|
148
|
+
file,
|
|
149
|
+
home,
|
|
150
|
+
env,
|
|
151
|
+
warnings,
|
|
152
|
+
{ withEnv = true } = {},
|
|
153
|
+
) {
|
|
147
154
|
const data = JSON.parse(original);
|
|
148
155
|
if (!data || typeof data !== "object" || Array.isArray(data))
|
|
149
156
|
throw new Error(`${file}: JSON 객체가 아닙니다`);
|
|
@@ -190,7 +197,7 @@ function patchJson(original, file, home, env, warnings) {
|
|
|
190
197
|
...kept,
|
|
191
198
|
command: server.command,
|
|
192
199
|
args: server.args,
|
|
193
|
-
...(server.envVars.length
|
|
200
|
+
...(withEnv && server.envVars.length
|
|
194
201
|
? {
|
|
195
202
|
env: {
|
|
196
203
|
...kept.env,
|
|
@@ -710,6 +717,8 @@ export function cleanupLegacyMcp({
|
|
|
710
717
|
[join(repoRoot, ".mcp.json"), "json"],
|
|
711
718
|
[join(home, ".codex/config.toml"), "toml"],
|
|
712
719
|
[join(home, ".gemini/settings.json"), "json"],
|
|
720
|
+
// agy 는 \${VAR} 참조를 풀지 않으므로 env 없이 바꾸고 셸 환경을 물려받게 한다.
|
|
721
|
+
[join(home, ".gemini/config/mcp_config.json"), "agy"],
|
|
713
722
|
];
|
|
714
723
|
const plans = [];
|
|
715
724
|
let blocked = false;
|
|
@@ -721,7 +730,9 @@ export function cleanupLegacyMcp({
|
|
|
721
730
|
const plan =
|
|
722
731
|
kind === "toml"
|
|
723
732
|
? patchToml(original, file, home, env, result.warnings)
|
|
724
|
-
: patchJson(original, file, home, env, result.warnings
|
|
733
|
+
: patchJson(original, file, home, env, result.warnings, {
|
|
734
|
+
withEnv: kind !== "agy",
|
|
735
|
+
});
|
|
725
736
|
if (plan.blocked) blocked = true;
|
|
726
737
|
if (plan.count) plans.push({ file, target, original, ...plan });
|
|
727
738
|
} catch {
|
|
@@ -14,7 +14,7 @@ import { readFileSync } from "node:fs";
|
|
|
14
14
|
import { homedir } from "node:os";
|
|
15
15
|
import { join, resolve } from "node:path";
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
const MACHINE_PROFILE_FILENAME = "machine-profile.env";
|
|
18
18
|
|
|
19
19
|
export const MACHINE_PROFILE_KEYS = Object.freeze([
|
|
20
20
|
"TFX_MACHINE_PROFILE_VERSION",
|
|
@@ -28,9 +28,9 @@ export const MACHINE_PROFILE_KEYS = Object.freeze([
|
|
|
28
28
|
"TFX_STALL_KILL",
|
|
29
29
|
]);
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
const MACHINE_PROFILE_KEY_SET = new Set(MACHINE_PROFILE_KEYS);
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
const MACHINE_PROFILE_VALUE_RE = /^[A-Za-z0-9_.-]+$/u;
|
|
34
34
|
|
|
35
35
|
// CLI 이름과 disable 키의 대응. 이 두 개가 TFX_DISABLE_* SSOT 의 전부다.
|
|
36
36
|
const CLI_DISABLE_KEYS = Object.freeze({
|
|
@@ -248,20 +248,6 @@ export function normalizeCliName(cli) {
|
|
|
248
248
|
return CLI_ALIASES[key] || null;
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
-
/**
|
|
252
|
-
* 세션 문맥 주입용 한 줄. 형식은 고정이며 소비자가 파싱하지 않고 그대로 보여준다.
|
|
253
|
-
*
|
|
254
|
-
* @param {ReturnType<typeof resolveCliPolicy>} policy
|
|
255
|
-
* @returns {string}
|
|
256
|
-
*/
|
|
257
|
-
export function formatCliPolicyLine(policy) {
|
|
258
|
-
const codex = policy?.codexDisabled ? "off" : "on";
|
|
259
|
-
const antigravity = policy?.antigravityDisabled ? "off" : "on";
|
|
260
|
-
const codexSource = policy?.source?.codex || "default";
|
|
261
|
-
const antigravitySource = policy?.source?.antigravity || "default";
|
|
262
|
-
return `cli-policy: codex=${codex} antigravity=${antigravity} (SSOT: TFX_DISABLE_*; codex<-${codexSource}, antigravity<-${antigravitySource})`;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
251
|
/**
|
|
266
252
|
* 차단된 CLI 실행 요청에 쓸 오류를 만든다. throw 는 호출자가 한다. 정책상 허용된
|
|
267
253
|
* CLI 이거나 모르는 이름이면 null 을 준다.
|
|
@@ -15,10 +15,6 @@ import {
|
|
|
15
15
|
uniqueStrings,
|
|
16
16
|
} from "./mcp-server-catalog.mjs";
|
|
17
17
|
|
|
18
|
-
export const KNOWN_MCP_SERVERS = Object.freeze(
|
|
19
|
-
Object.keys(MCP_SERVER_TOOL_CATALOG),
|
|
20
|
-
);
|
|
21
|
-
|
|
22
18
|
const SEARCH_INTENT_PATTERNS = Object.freeze([
|
|
23
19
|
/\b(search|web|browse|look ?up|find|latest|recent|news|current|today|release(?: note)?s?|changelog|announcement|pricing|status|verify|fact[- ]?check)\b/i,
|
|
24
20
|
/(검색|웹|브라우즈|찾아|조회|최신|최근|뉴스|현재|오늘|릴리즈|배포|변경사항|공지|가격|상태|검증)/u,
|
|
@@ -145,7 +141,7 @@ const PROFILE_DEFINITIONS = Object.freeze({
|
|
|
145
141
|
* 파이프라인 단계별 MCP 서버/도구 제한 (post-filter).
|
|
146
142
|
* role-based 프로필 위에 추가 적용. 빈 배열 = 전체 차단, 미정의 = 제한 없음.
|
|
147
143
|
*/
|
|
148
|
-
|
|
144
|
+
const PHASE_OVERRIDES = Object.freeze({
|
|
149
145
|
plan: Object.freeze({
|
|
150
146
|
description: "계획 단계: 읽기 전용 탐색만 허용",
|
|
151
147
|
allowedServers: Object.freeze(["context7"]),
|
|
@@ -166,7 +162,7 @@ export const PHASE_OVERRIDES = Object.freeze({
|
|
|
166
162
|
}),
|
|
167
163
|
});
|
|
168
164
|
|
|
169
|
-
|
|
165
|
+
const LEGACY_PROFILE_ALIASES = Object.freeze({
|
|
170
166
|
implement: "executor",
|
|
171
167
|
analyze: "analyze",
|
|
172
168
|
review: "reviewer",
|
|
@@ -257,30 +253,51 @@ function loadInventory(inventoryFile = "") {
|
|
|
257
253
|
}
|
|
258
254
|
}
|
|
259
255
|
|
|
256
|
+
function availableServersFromInventory(inventory, cliType) {
|
|
257
|
+
const servers = inventory?.[cliType]?.servers || [];
|
|
258
|
+
return uniqueStrings(
|
|
259
|
+
servers
|
|
260
|
+
.filter((server) => ["enabled", "configured"].includes(server.status))
|
|
261
|
+
.map((server) => server.name),
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function codexServersFromConfig(configFile) {
|
|
266
|
+
if (!configFile) return [];
|
|
267
|
+
try {
|
|
268
|
+
return uniqueStrings(
|
|
269
|
+
readFileSync(configFile, "utf8")
|
|
270
|
+
.split(/\r?\n/)
|
|
271
|
+
.map((line) => /^\[mcp_servers\.([^\].]+)\]$/.exec(line)?.[1])
|
|
272
|
+
.filter(Boolean),
|
|
273
|
+
).sort();
|
|
274
|
+
} catch {
|
|
275
|
+
return [];
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
260
279
|
function buildInventoryIndex(inventory = null) {
|
|
261
280
|
const index = new Map();
|
|
262
281
|
if (!inventory || typeof inventory !== "object") return index;
|
|
263
282
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
tool_count
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
domain_tags:
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
});
|
|
283
|
-
}
|
|
283
|
+
const servers = Array.isArray(inventory.codex?.servers)
|
|
284
|
+
? inventory.codex.servers
|
|
285
|
+
: [];
|
|
286
|
+
for (const server of servers) {
|
|
287
|
+
if (!server || typeof server.name !== "string" || !server.name.trim())
|
|
288
|
+
continue;
|
|
289
|
+
const name = server.name.trim();
|
|
290
|
+
const previous = index.get(name) || {};
|
|
291
|
+
index.set(name, {
|
|
292
|
+
...previous,
|
|
293
|
+
tool_count: Number.isFinite(server.tool_count)
|
|
294
|
+
? Math.max(previous.tool_count ?? 0, Math.trunc(server.tool_count))
|
|
295
|
+
: previous.tool_count,
|
|
296
|
+
domain_tags: uniqueStrings([
|
|
297
|
+
...(Array.isArray(previous.domain_tags) ? previous.domain_tags : []),
|
|
298
|
+
...(Array.isArray(server.domain_tags) ? server.domain_tags : []),
|
|
299
|
+
]),
|
|
300
|
+
});
|
|
284
301
|
}
|
|
285
302
|
|
|
286
303
|
return index;
|
|
@@ -498,7 +515,7 @@ export function resolveMcpProfile(agentType = "", requestedProfile = "auto") {
|
|
|
498
515
|
return normalized === "auto" ? resolveAutoProfile(agentType) : normalized;
|
|
499
516
|
}
|
|
500
517
|
|
|
501
|
-
|
|
518
|
+
function parseAvailableServers(rawAvailableServers = "") {
|
|
502
519
|
if (Array.isArray(rawAvailableServers))
|
|
503
520
|
return uniqueStrings(rawAvailableServers);
|
|
504
521
|
if (typeof rawAvailableServers !== "string" || !rawAvailableServers.trim())
|
|
@@ -554,15 +571,21 @@ function applyManifestFilter(servers) {
|
|
|
554
571
|
return servers.filter((s) => enabled.has(s));
|
|
555
572
|
}
|
|
556
573
|
|
|
557
|
-
|
|
574
|
+
function resolveAllowedServers(options = {}) {
|
|
558
575
|
const resolvedProfile = resolveMcpProfile(
|
|
559
576
|
options.agentType,
|
|
560
577
|
options.requestedProfile,
|
|
561
578
|
);
|
|
562
579
|
const profile = getProfileDefinition(resolvedProfile);
|
|
563
580
|
const availableServers = parseAvailableServers(options.availableServers);
|
|
564
|
-
const inventory =
|
|
565
|
-
|
|
581
|
+
const inventory =
|
|
582
|
+
options.inventory !== undefined
|
|
583
|
+
? options.inventory
|
|
584
|
+
: loadInventory(options.inventoryFile);
|
|
585
|
+
const inventoryIndex =
|
|
586
|
+
options.inventoryIndex instanceof Map
|
|
587
|
+
? options.inventoryIndex
|
|
588
|
+
: buildInventoryIndex(inventory);
|
|
566
589
|
const baseServers = availableServers.length
|
|
567
590
|
? profile.allowedServers.filter((server) =>
|
|
568
591
|
availableServers.includes(server),
|
|
@@ -585,8 +608,14 @@ export function buildPromptHint(options = {}) {
|
|
|
585
608
|
);
|
|
586
609
|
if (resolvedProfile === "none") return "";
|
|
587
610
|
|
|
588
|
-
const inventory =
|
|
589
|
-
|
|
611
|
+
const inventory =
|
|
612
|
+
options.inventory !== undefined
|
|
613
|
+
? options.inventory
|
|
614
|
+
: loadInventory(options.inventoryFile);
|
|
615
|
+
const inventoryIndex =
|
|
616
|
+
options.inventoryIndex instanceof Map
|
|
617
|
+
? options.inventoryIndex
|
|
618
|
+
: buildInventoryIndex(inventory);
|
|
590
619
|
const allowedServers = resolveAllowedServers({
|
|
591
620
|
...options,
|
|
592
621
|
inventory,
|
|
@@ -636,16 +665,7 @@ export function buildPromptHint(options = {}) {
|
|
|
636
665
|
.join(" ");
|
|
637
666
|
}
|
|
638
667
|
|
|
639
|
-
export function getGeminiAllowedServers(options = {}) {
|
|
640
|
-
return resolveAllowedServers(options);
|
|
641
|
-
}
|
|
642
|
-
|
|
643
668
|
export function getCodexMcpConfig(options = {}) {
|
|
644
|
-
const allowedServers = new Set(resolveAllowedServers(options));
|
|
645
|
-
const resolvedProfile = resolveMcpProfile(
|
|
646
|
-
options.agentType,
|
|
647
|
-
options.requestedProfile,
|
|
648
|
-
);
|
|
649
669
|
// Codex에 실제 등록된 서버만 대상으로 config override 생성.
|
|
650
670
|
// 미등록 서버에 enabled=false를 보내면 "invalid transport" 에러 발생.
|
|
651
671
|
const registeredServers = parseAvailableServers(options.availableServers);
|
|
@@ -654,6 +674,11 @@ export function getCodexMcpConfig(options = {}) {
|
|
|
654
674
|
if (registeredServers.length === 0) {
|
|
655
675
|
return { mcp_servers: {} };
|
|
656
676
|
}
|
|
677
|
+
const allowedServers = new Set(resolveAllowedServers(options));
|
|
678
|
+
const resolvedProfile = resolveMcpProfile(
|
|
679
|
+
options.agentType,
|
|
680
|
+
options.requestedProfile,
|
|
681
|
+
);
|
|
657
682
|
const targetServers = registeredServers;
|
|
658
683
|
|
|
659
684
|
if (resolvedProfile === "none") {
|
|
@@ -712,9 +737,27 @@ export function getCodexConfigOverrides(options = {}) {
|
|
|
712
737
|
}
|
|
713
738
|
|
|
714
739
|
export function buildMcpPolicy(options = {}) {
|
|
715
|
-
const inventory =
|
|
740
|
+
const inventory =
|
|
741
|
+
options.inventory !== undefined
|
|
742
|
+
? options.inventory
|
|
743
|
+
: loadInventory(options.inventoryFile);
|
|
716
744
|
const inventoryIndex = buildInventoryIndex(inventory);
|
|
717
|
-
|
|
745
|
+
let availableServers = options.availableServers;
|
|
746
|
+
if (availableServers === undefined) {
|
|
747
|
+
availableServers = availableServersFromInventory(
|
|
748
|
+
inventory,
|
|
749
|
+
options.cliType,
|
|
750
|
+
);
|
|
751
|
+
if (availableServers.length === 0 && options.cliType === "codex") {
|
|
752
|
+
availableServers = codexServersFromConfig(options.codexConfig);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
const resolvedOptions = {
|
|
756
|
+
...options,
|
|
757
|
+
availableServers,
|
|
758
|
+
inventory,
|
|
759
|
+
inventoryIndex,
|
|
760
|
+
};
|
|
718
761
|
const resolvedProfile = resolveMcpProfile(
|
|
719
762
|
options.agentType,
|
|
720
763
|
options.requestedProfile,
|
|
@@ -730,6 +773,12 @@ export function buildMcpPolicy(options = {}) {
|
|
|
730
773
|
allowedServers = allowedServers.filter((s) => !blocked.has(s));
|
|
731
774
|
}
|
|
732
775
|
|
|
776
|
+
// 플러그인 서버는 transport 설정이 없어 CLI override를 받으면 부팅이 실패한다.
|
|
777
|
+
const codexOptions = {
|
|
778
|
+
...resolvedOptions,
|
|
779
|
+
availableServers: codexServersFromConfig(options.codexConfig),
|
|
780
|
+
};
|
|
781
|
+
|
|
733
782
|
return {
|
|
734
783
|
requestedProfile:
|
|
735
784
|
typeof options.requestedProfile === "string" && options.requestedProfile
|
|
@@ -739,9 +788,8 @@ export function buildMcpPolicy(options = {}) {
|
|
|
739
788
|
resolvedPhase: phase || null,
|
|
740
789
|
allowedServers,
|
|
741
790
|
hint,
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
codexConfigOverrides: getCodexConfigOverrides(resolvedOptions),
|
|
791
|
+
codexConfig: getCodexMcpConfig(codexOptions),
|
|
792
|
+
codexConfigOverrides: getCodexConfigOverrides(codexOptions),
|
|
745
793
|
};
|
|
746
794
|
}
|
|
747
795
|
|
|
@@ -753,25 +801,25 @@ function shellArray(name, values) {
|
|
|
753
801
|
return `${name}=(${values.map((value) => shellEscape(value)).join(" ")})`;
|
|
754
802
|
}
|
|
755
803
|
|
|
756
|
-
|
|
804
|
+
function toDelimited(policy) {
|
|
757
805
|
const RS = "\x1e";
|
|
758
806
|
return [
|
|
759
807
|
policy.requestedProfile,
|
|
760
808
|
policy.resolvedProfile,
|
|
761
809
|
policy.hint,
|
|
762
|
-
policy.
|
|
763
|
-
policy.codexConfigOverrides.flatMap((o) => ["-c", o]).join("
|
|
810
|
+
policy.allowedServers.join(","),
|
|
811
|
+
policy.codexConfigOverrides.flatMap((o) => ["-c", o]).join("\x1f"),
|
|
764
812
|
JSON.stringify(policy.codexConfig),
|
|
765
813
|
policy.resolvedPhase || "",
|
|
766
814
|
].join(RS);
|
|
767
815
|
}
|
|
768
816
|
|
|
769
|
-
|
|
817
|
+
function toShellExports(policy) {
|
|
770
818
|
const lines = [
|
|
771
819
|
`MCP_PROFILE_REQUESTED=${shellEscape(policy.requestedProfile)}`,
|
|
772
820
|
`MCP_RESOLVED_PROFILE=${shellEscape(policy.resolvedProfile)}`,
|
|
773
821
|
`MCP_HINT=${shellEscape(policy.hint)}`,
|
|
774
|
-
shellArray("
|
|
822
|
+
shellArray("ALLOWED_MCP_SERVERS", policy.allowedServers),
|
|
775
823
|
shellArray(
|
|
776
824
|
"CODEX_CONFIG_FLAGS",
|
|
777
825
|
policy.codexConfigOverrides.flatMap((override) => ["-c", override]),
|
|
@@ -789,8 +837,10 @@ function parseCliArgs(argv) {
|
|
|
789
837
|
command: "json",
|
|
790
838
|
agentType: "",
|
|
791
839
|
requestedProfile: "auto",
|
|
792
|
-
availableServers:
|
|
840
|
+
availableServers: undefined,
|
|
793
841
|
inventoryFile: "",
|
|
842
|
+
cliType: "",
|
|
843
|
+
codexConfig: "",
|
|
794
844
|
searchTool: "",
|
|
795
845
|
taskText: "",
|
|
796
846
|
workerIndex: undefined,
|
|
@@ -821,6 +871,12 @@ function parseCliArgs(argv) {
|
|
|
821
871
|
case "--available":
|
|
822
872
|
args.availableServers = parseAvailableServers(next());
|
|
823
873
|
break;
|
|
874
|
+
case "--cli-type":
|
|
875
|
+
args.cliType = next();
|
|
876
|
+
break;
|
|
877
|
+
case "--codex-config":
|
|
878
|
+
args.codexConfig = next();
|
|
879
|
+
break;
|
|
824
880
|
case "--inventory-file":
|
|
825
881
|
args.inventoryFile = next();
|
|
826
882
|
break;
|
|
@@ -844,7 +900,7 @@ function parseCliArgs(argv) {
|
|
|
844
900
|
return args;
|
|
845
901
|
}
|
|
846
902
|
|
|
847
|
-
|
|
903
|
+
async function runCli(argv = process.argv.slice(2)) {
|
|
848
904
|
let args;
|
|
849
905
|
try {
|
|
850
906
|
args = parseCliArgs(argv);
|
|
@@ -224,7 +224,7 @@ export function parseMcpServersFromToml(content = "") {
|
|
|
224
224
|
return servers;
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
|
|
227
|
+
function readMcpServers(configPath = DEFAULT_CONFIG_PATH) {
|
|
228
228
|
if (!existsSync(configPath)) return {};
|
|
229
229
|
try {
|
|
230
230
|
const content = readFileSync(configPath, "utf8");
|
|
@@ -754,7 +754,7 @@ function renderOutput(results, source, format) {
|
|
|
754
754
|
return JSON.stringify({ source, healthy, dead, results }, null, 2);
|
|
755
755
|
}
|
|
756
756
|
|
|
757
|
-
|
|
757
|
+
async function runCli(argv = process.argv.slice(2)) {
|
|
758
758
|
let args;
|
|
759
759
|
try {
|
|
760
760
|
args = parseCliArgs(argv);
|
|
@@ -296,7 +296,7 @@ export function uniqueStrings(values = []) {
|
|
|
296
296
|
];
|
|
297
297
|
}
|
|
298
298
|
|
|
299
|
-
|
|
299
|
+
function inferDomainTagsFromText(text = "") {
|
|
300
300
|
if (typeof text !== "string" || !text.trim()) return [];
|
|
301
301
|
const normalized = text.toLocaleLowerCase();
|
|
302
302
|
const matched = [];
|
|
@@ -314,7 +314,7 @@ export function inferDomainTagsFromText(text = "") {
|
|
|
314
314
|
return uniqueStrings(matched);
|
|
315
315
|
}
|
|
316
316
|
|
|
317
|
-
|
|
317
|
+
function getDefaultServerMetadata(serverName = "") {
|
|
318
318
|
const toolCount = MCP_SERVER_TOOL_CATALOG[serverName]?.length || 0;
|
|
319
319
|
const domainTags = uniqueStrings([
|
|
320
320
|
...(MCP_SERVER_DOMAIN_TAGS[serverName] || []),
|