triflux 10.38.0 → 10.39.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "triflux",
3
- "version": "10.38.0",
3
+ "version": "10.39.0",
4
4
  "description": "CLI-first multi-model orchestrator for Claude Code — route tasks to Codex, Antigravity, and Claude",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,23 +8,49 @@ import {
8
8
  import { homedir } from "node:os";
9
9
  import { join } from "node:path";
10
10
 
11
+ // 모델명 SSOT. 값은 agy 1.0.x `agy models` 가 출력하는 display name 형식이다
12
+ // (`--model` 인자가 이 문자열을 받는다). 옛 `gemini-*-preview` ID 형식이 아님.
11
13
  const DEFAULT_GEMINI_PROFILES = {
12
- model: "gemini-3.1-pro-preview",
14
+ model: "Gemini 3.5 Flash (Medium)",
13
15
  profiles: {
16
+ flash35_low: {
17
+ model: "Gemini 3.5 Flash (Low)",
18
+ hint: "3.5 Flash (Low) — 경량·저비용",
19
+ },
20
+ flash35: {
21
+ model: "Gemini 3.5 Flash (Medium)",
22
+ hint: "3.5 Flash (Medium) — 기본, 비용·속도 균형",
23
+ },
24
+ flash35_high: {
25
+ model: "Gemini 3.5 Flash (High)",
26
+ hint: "3.5 Flash (High) — 코드/추론 강화",
27
+ },
28
+ pro31_low: {
29
+ model: "Gemini 3.1 Pro (Low)",
30
+ hint: "3.1 Pro (Low) — 플래그십 경량",
31
+ },
14
32
  pro31: {
15
- model: "gemini-3.1-pro-preview",
16
- hint: "3.1 Pro — 플래그십 (1M ctx, 멀티모달)",
33
+ model: "Gemini 3.1 Pro (High)",
34
+ hint: "3.1 Pro (High) — 플래그십 최고 ( 컨텍스트/복잡 추론)",
17
35
  },
18
36
  flash3: {
19
- model: "gemini-3-flash-preview",
20
- hint: "3.0 Flash — 빠른 응답, 비용 효율",
37
+ model: "Gemini 3 Flash",
38
+ hint: "3.0 Flash — 레거시 호환",
21
39
  },
22
- pro25: { model: "gemini-2.5-pro", hint: "2.5 Pro — 안정 (추론 강화)" },
23
- flash25: { model: "gemini-2.5-flash", hint: "2.5 Flash — 경량 범용" },
24
- lite25: { model: "gemini-2.5-flash-lite", hint: "2.5 Flash Lite — 최경량" },
25
40
  },
26
41
  };
27
42
 
43
+ // 1회 마이그레이션 테이블: 옛 ID 형식 모델값 → agy display name.
44
+ // null = deprecated(2.5 계열) → 해당 프로필 제거 대상.
45
+ const LEGACY_MODEL_MIGRATION = {
46
+ "gemini-3.1-pro-preview": "Gemini 3.1 Pro (High)",
47
+ "gemini-3-flash-preview": "Gemini 3 Flash",
48
+ "gemini-2.5-pro": null,
49
+ "gemini-2.5-flash": null,
50
+ "gemini-2.5-flash-lite": null,
51
+ };
52
+ const LEGACY_PROFILE_NAMES = ["pro25", "flash25", "lite25"];
53
+
28
54
  const DEFAULT_PROFILE_COUNT = Object.keys(
29
55
  DEFAULT_GEMINI_PROFILES.profiles,
30
56
  ).length;
@@ -80,6 +106,39 @@ function ensureGeminiProfiles({
80
106
  )
81
107
  cfg.profiles = {};
82
108
 
109
+ // ── 1회 마이그레이션: deprecated 2.5 프로필 prune + 옛 ID 형식 → display name ──
110
+ // merge-only 로직만으로는 기존 사용자 파일에 남은 stale 프로필/옛 모델 ID 가
111
+ // 정리되지 않으므로, 신규 default 를 채우기 전에 마이그레이션을 먼저 적용한다.
112
+ let migrated = false;
113
+ for (const legacy of LEGACY_PROFILE_NAMES) {
114
+ if (cfg.profiles[legacy]) {
115
+ delete cfg.profiles[legacy];
116
+ migrated = true;
117
+ }
118
+ }
119
+ for (const [pname, pval] of Object.entries(cfg.profiles)) {
120
+ const mid = typeof pval === "string" ? pval : pval?.model;
121
+ if (mid && Object.hasOwn(LEGACY_MODEL_MIGRATION, mid)) {
122
+ const repl = LEGACY_MODEL_MIGRATION[mid];
123
+ if (repl === null) {
124
+ delete cfg.profiles[pname];
125
+ } else if (typeof pval === "string") {
126
+ cfg.profiles[pname] = repl;
127
+ } else {
128
+ cfg.profiles[pname].model = repl;
129
+ }
130
+ migrated = true;
131
+ }
132
+ }
133
+ if (
134
+ typeof cfg.model === "string" &&
135
+ Object.hasOwn(LEGACY_MODEL_MIGRATION, cfg.model)
136
+ ) {
137
+ // 옛 ID 형식 기본값은 구버전 자동 생성값이므로 새 기본(DEFAULT)으로 정규화한다.
138
+ cfg.model = DEFAULT_GEMINI_PROFILES.model;
139
+ migrated = true;
140
+ }
141
+
83
142
  let added = 0;
84
143
  for (const [name, value] of Object.entries(
85
144
  DEFAULT_GEMINI_PROFILES.profiles,
@@ -91,7 +150,12 @@ function ensureGeminiProfiles({
91
150
  }
92
151
  if (!cfg.model) cfg.model = DEFAULT_GEMINI_PROFILES.model;
93
152
 
94
- if (added > 0) {
153
+ if (added > 0 || migrated) {
154
+ if (migrated) {
155
+ try {
156
+ copyFileSync(profilesPath, profilesPath + `.bak.${Date.now()}`);
157
+ } catch {}
158
+ }
95
159
  writeFileSync(profilesPath, JSON.stringify(cfg, null, 2) + "\n", {
96
160
  encoding: "utf8",
97
161
  mode: 0o600,
@@ -1121,11 +1121,12 @@ resolve_gemini_profile() {
1121
1121
  const primaryRaw = process.argv[2] || '{}';
1122
1122
  const settingsRaw = process.argv[3] || '{}';
1123
1123
  const defaults = {
1124
- pro31: 'gemini-3.1-pro-preview',
1125
- flash3: 'gemini-3-flash-preview',
1126
- pro25: 'gemini-2.5-pro',
1127
- flash25: 'gemini-2.5-flash',
1128
- lite25: 'gemini-2.5-flash-lite'
1124
+ flash35_low: 'Gemini 3.5 Flash (Low)',
1125
+ flash35: 'Gemini 3.5 Flash (Medium)',
1126
+ flash35_high: 'Gemini 3.5 Flash (High)',
1127
+ pro31_low: 'Gemini 3.1 Pro (Low)',
1128
+ pro31: 'Gemini 3.1 Pro (High)',
1129
+ flash3: 'Gemini 3 Flash'
1129
1130
  };
1130
1131
 
1131
1132
  if (typeof name === 'string' && name.startsWith('gemini-')) {
@@ -1193,9 +1194,9 @@ resolve_gemini_profile() {
1193
1194
  }
1194
1195
  }
1195
1196
 
1196
- process.stdout.write(defaults[name] || defaults[process.env.TFX_GEMINI_DEFAULT_PROFILE] || defaults.pro25);
1197
+ process.stdout.write(defaults[name] || defaults[process.env.TFX_GEMINI_DEFAULT_PROFILE] || defaults.flash35);
1197
1198
  " "$profile" "$_GEMINI_PROFILE_CACHE" "$settings_cache" 2>/dev/null)
1198
- echo "${result:-gemini-2.5-pro}"
1199
+ echo "${result:-Gemini 3.5 Flash (Medium)}"
1199
1200
  }
1200
1201
 
1201
1202
  # ── 라우팅 테이블 ──
@@ -1289,13 +1290,28 @@ route_agent() {
1289
1290
  CLI_EFFORT="gpt55_xhigh"; DEFAULT_TIMEOUT=3600; RUN_MODE="bg"; OPUS_OVERSIGHT="false" ;;
1290
1291
 
1291
1292
  # ─── Antigravity CLI 레인 (Gemini CLI 후속) ───
1292
- # 모델 선택 옵션 부재 (top-level), Antigravity settings.json 으로 endemic.
1293
+ # effort 차등: agent GEMINI_PROFILE 설정하면 run_antigravity_exec()
1294
+ # resolve_gemini_profile 로 해석해 `--model "<display name>"`을 agy_args 에
1295
+ # 주입한다. 우선순위는 TFX_GEMINI_PROFILE(env) > GEMINI_PROFILE(agent) > flash35.
1296
+ # CLI_ARGS 는 read -a 로 word-split 되므로 공백 포함 모델명을 여기 넣지 않는다.
1293
1297
  # #310: upstream callers are normalized through agent-map.json, but this
1294
1298
  # direct route entrypoint intentionally keeps agy as a compatibility alias.
1295
- designer|writer|gemini|antigravity|agy)
1299
+ designer)
1300
+ # 디자인 = 시각/UX 추론 → 3.5 Flash (High)
1301
+ CLI_ARGS="--print --dangerously-skip-permissions"
1302
+ GEMINI_PROFILE="flash35_high"
1303
+ CLI_EFFORT="agy_v1"; DEFAULT_TIMEOUT=900; RUN_MODE="bg"; OPUS_OVERSIGHT="false" ;;
1304
+ writer)
1305
+ # 문서 작성 = 균형 → 3.5 Flash (Medium)
1306
+ CLI_ARGS="--print --dangerously-skip-permissions"
1307
+ GEMINI_PROFILE="flash35"
1308
+ CLI_EFFORT="agy_v1"; DEFAULT_TIMEOUT=900; RUN_MODE="bg"; OPUS_OVERSIGHT="false" ;;
1309
+ gemini|antigravity|agy)
1310
+ # 직접 호출 alias — 기본 flash35. TFX_GEMINI_PROFILE 로 override 가능.
1296
1311
  # agy --print + --dangerously-skip-permissions 조합은 positional prompt에서
1297
1312
  # timeout이 재현되므로 wrapper 호출은 stdin pipe로 고정한다.
1298
1313
  CLI_ARGS="--print --dangerously-skip-permissions"
1314
+ GEMINI_PROFILE="flash35"
1299
1315
  CLI_EFFORT="agy_v1"; DEFAULT_TIMEOUT=900; RUN_MODE="bg"; OPUS_OVERSIGHT="false" ;;
1300
1316
 
1301
1317
  # ─── 탐색 (Claude-native: Glob/Grep/Read 직접 접근) ───
@@ -1488,6 +1504,12 @@ apply_cli_mode() {
1488
1504
  CLI_TYPE="antigravity"
1489
1505
  CLI_CMD="agy"
1490
1506
  CLI_ARGS="--print --dangerously-skip-permissions"
1507
+ # 주 라우팅(route_agent)과 동일하게 designer 만 effort 상향. 나머지는
1508
+ # run_antigravity_exec 폴백(flash35) 또는 TFX_GEMINI_PROFILE override.
1509
+ case "$AGENT_TYPE" in
1510
+ designer) GEMINI_PROFILE="flash35_high" ;;
1511
+ *) GEMINI_PROFILE="flash35" ;;
1512
+ esac
1491
1513
  CLI_EFFORT="agy_v1"
1492
1514
  DEFAULT_TIMEOUT=900
1493
1515
  echo "[tfx-route] TFX_CLI_MODE=antigravity: $AGENT_TYPE → antigravity($CLI_EFFORT)로 리매핑" >&2
@@ -2180,6 +2202,18 @@ run_antigravity_exec() {
2180
2202
  local -a agy_args=()
2181
2203
  read -r -a agy_args <<< "$CLI_ARGS"
2182
2204
 
2205
+ # ── 프로필 기반 모델 주입 ──
2206
+ # display name 에 공백/괄호가 있으므로(예: "Gemini 3.5 Flash (Medium)") CLI_ARGS
2207
+ # 문자열이 아니라 agy_args 배열에 두 원소(--model, <display name>)로 append 해야
2208
+ # "${agy_args[@]}" expand 시 단일 인자로 보존된다. 모델 SSOT 는 프로필 설정이다.
2209
+ if [[ -z "${TFX_GEMINI_NO_MODEL:-}" ]]; then
2210
+ local _agy_model
2211
+ _agy_model="$(resolve_gemini_profile "${TFX_GEMINI_PROFILE:-${GEMINI_PROFILE:-flash35}}")"
2212
+ if [[ -n "$_agy_model" ]]; then
2213
+ agy_args+=("--model" "$_agy_model")
2214
+ fi
2215
+ fi
2216
+
2183
2217
  if ! agy_supports_headless "$CLI_CMD"; then
2184
2218
  echo "[tfx-route] Antigravity CLI headless flags unsupported or missing: $CLI_CMD" >"$STDERR_LOG"
2185
2219
  return 127