pleumrouter 0.5.32 → 0.5.33
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 +1 -1
- package/src/interactive.mjs +13 -6
- package/src/locales/es.mjs +3 -8
- package/src/locales/ja.mjs +3 -8
- package/src/locales/ko.mjs +3 -8
- package/src/locales/zh.mjs +3 -8
- package/src/menu.mjs +19 -55
package/package.json
CHANGED
package/src/interactive.mjs
CHANGED
|
@@ -92,6 +92,13 @@ export function keyFeeder() {
|
|
|
92
92
|
};
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
// 문자열의 터미널 줄 수 계산 — 개행 문자(\n)가 있어도 줄 단위로 쪼개어 실제 출력 행 수를 정확히 합산
|
|
96
|
+
export function rowsFor(s, width = terminalWidth()) {
|
|
97
|
+
return String(s)
|
|
98
|
+
.split("\n")
|
|
99
|
+
.reduce((sum, line) => sum + Math.max(1, Math.ceil(displayWidth(line) / Math.max(width, 1))), 0);
|
|
100
|
+
}
|
|
101
|
+
|
|
95
102
|
// 화살표 이동 · 타이핑 필터 · Enter 선택 · Esc/Ctrl+C 취소(null).
|
|
96
103
|
// 비TTY면 즉시 null — 호출자가 기존 번호 피커 등으로 폴백한다.
|
|
97
104
|
// process.exit는 절대 호출하지 않는다(취소 처리는 호출자 몫).
|
|
@@ -112,7 +119,6 @@ export async function select(items, {
|
|
|
112
119
|
let windowStart = 0;
|
|
113
120
|
let lastRows = 0;
|
|
114
121
|
|
|
115
|
-
const rowsFor = (s) => Math.max(1, Math.ceil(displayWidth(s) / Math.max(terminalWidth(), 1)));
|
|
116
122
|
const erase = () => {
|
|
117
123
|
if (!lastRows) return;
|
|
118
124
|
output.write("\r" + (lastRows > 1 ? `\x1b[${lastRows - 1}A` : "") + "\x1b[0J");
|
|
@@ -130,14 +136,14 @@ export async function select(items, {
|
|
|
130
136
|
windowStart = Math.max(0, Math.min(windowStart, Math.max(0, pool.length - limit)));
|
|
131
137
|
|
|
132
138
|
const shown = pool.slice(windowStart, windowStart + limit);
|
|
133
|
-
const
|
|
139
|
+
const rawLines = [
|
|
134
140
|
`${style.plum("?")} ${style.bold(message)} ${style.dim(t("type to filter · ↑↓ move · Enter select · Esc cancel"))}`,
|
|
135
141
|
`${style.gray("›")} ${query}`,
|
|
136
142
|
];
|
|
137
143
|
if (windowStart > 0) {
|
|
138
|
-
|
|
144
|
+
rawLines.push(style.dim(` ${t("↑ {n} more above", { n: windowStart })}`));
|
|
139
145
|
}
|
|
140
|
-
|
|
146
|
+
rawLines.push(
|
|
141
147
|
...shown.map((it, idx) => {
|
|
142
148
|
const itemIndex = windowStart + idx;
|
|
143
149
|
return itemIndex === cursor
|
|
@@ -147,10 +153,11 @@ export async function select(items, {
|
|
|
147
153
|
);
|
|
148
154
|
const remainingBelow = pool.length - (windowStart + shown.length);
|
|
149
155
|
if (remainingBelow > 0) {
|
|
150
|
-
|
|
156
|
+
rawLines.push(style.dim(` ${t("… {n} more — type to narrow down", { n: remainingBelow })}`));
|
|
151
157
|
}
|
|
152
|
-
if (!pool.length)
|
|
158
|
+
if (!pool.length) rawLines.push(style.dim(` ${t("No matches")}`));
|
|
153
159
|
erase();
|
|
160
|
+
const lines = rawLines.flatMap((l) => String(l).split("\n"));
|
|
154
161
|
const frame = lines.join("\n");
|
|
155
162
|
output.write(frame);
|
|
156
163
|
lastRows = lines.reduce((n, l) => n + rowsFor(l), 0);
|
package/src/locales/es.mjs
CHANGED
|
@@ -308,14 +308,9 @@ export const ES = {
|
|
|
308
308
|
"Update completed! Please run `pleum` again.": "¡Actualización completada! Ejecute `pleum` de nuevo.",
|
|
309
309
|
|
|
310
310
|
// Claude Code Tier Mapping
|
|
311
|
-
"
|
|
312
|
-
"
|
|
313
|
-
"
|
|
314
|
-
"Choose specific models for Sonnet (main), Opus (thinker), and Haiku (subagent)": "Elegir modelos específicos para Sonnet (principal), Opus (pensamiento) y Haiku (subagente)",
|
|
315
|
-
"Select model tier mapping": "Seleccionar asignación de niveles de modelo",
|
|
316
|
-
"Main model (Sonnet tier)": "Modelo principal (nivel Sonnet)",
|
|
317
|
-
"Thinker model (Opus tier)": "Modelo de razonamiento (nivel Opus)",
|
|
318
|
-
"Subagent model (Haiku tier)": "Modelo de subagente (nivel Haiku)",
|
|
311
|
+
"Sonnet model": "Modelo Sonnet",
|
|
312
|
+
"Opus model": "Modelo Opus",
|
|
313
|
+
"Haiku model": "Modelo Haiku",
|
|
319
314
|
|
|
320
315
|
// Codex & agy Effort
|
|
321
316
|
"Select reasoning effort": "Seleccionar esfuerzo de razonamiento",
|
package/src/locales/ja.mjs
CHANGED
|
@@ -308,14 +308,9 @@ export const JA = {
|
|
|
308
308
|
"Update completed! Please run `pleum` again.": "アップデート完了!`pleum` を再起動してください。",
|
|
309
309
|
|
|
310
310
|
// Claude Code Tier Mapping
|
|
311
|
-
"
|
|
312
|
-
"
|
|
313
|
-
"
|
|
314
|
-
"Choose specific models for Sonnet (main), Opus (thinker), and Haiku (subagent)": "Sonnet(メイン)、Opus(思考)、Haiku(サブエージェント)のモデルを個別に選択",
|
|
315
|
-
"Select model tier mapping": "モデルティアのマッピングを選択",
|
|
316
|
-
"Main model (Sonnet tier)": "メインモデル (Sonnet ティア)",
|
|
317
|
-
"Thinker model (Opus tier)": "思考モデル (Opus ティア)",
|
|
318
|
-
"Subagent model (Haiku tier)": "サブエージェントモデル (Haiku ティア)",
|
|
311
|
+
"Sonnet model": "Sonnet モデル",
|
|
312
|
+
"Opus model": "Opus モデル",
|
|
313
|
+
"Haiku model": "Haiku モデル",
|
|
319
314
|
|
|
320
315
|
// Codex & agy Effort
|
|
321
316
|
"Select reasoning effort": "推論強度 (effort) の選択",
|
package/src/locales/ko.mjs
CHANGED
|
@@ -371,14 +371,9 @@ export const KO = {
|
|
|
371
371
|
"Update completed! Please run `pleum` again.": "업데이트 완료! `pleum`을 다시 실행하세요.",
|
|
372
372
|
|
|
373
373
|
// Claude Code Tier Mapping
|
|
374
|
-
"
|
|
375
|
-
"
|
|
376
|
-
"
|
|
377
|
-
"Choose specific models for Sonnet (main), Opus (thinker), and Haiku (subagent)": "Sonnet(메인), Opus(추론), Haiku(서브에이전트)에 사용할 모델을 직접 선택합니다",
|
|
378
|
-
"Select model tier mapping": "모델 티어 매핑 선택",
|
|
379
|
-
"Main model (Sonnet tier)": "메인 모델 (Sonnet 티어)",
|
|
380
|
-
"Thinker model (Opus tier)": "심층 추론 모델 (Opus 티어)",
|
|
381
|
-
"Subagent model (Haiku tier)": "서브에이전트 모델 (Haiku 티어)",
|
|
374
|
+
"Sonnet model": "Sonnet 모델",
|
|
375
|
+
"Opus model": "Opus 모델",
|
|
376
|
+
"Haiku model": "Haiku 모델",
|
|
382
377
|
|
|
383
378
|
// Codex & agy Effort
|
|
384
379
|
"Select reasoning effort": "추론 강도(effort) 선택",
|
package/src/locales/zh.mjs
CHANGED
|
@@ -308,14 +308,9 @@ export const ZH = {
|
|
|
308
308
|
"Update completed! Please run `pleum` again.": "更新完成!请重新运行 `pleum`。",
|
|
309
309
|
|
|
310
310
|
// Claude Code Tier Mapping
|
|
311
|
-
"
|
|
312
|
-
"
|
|
313
|
-
"
|
|
314
|
-
"Choose specific models for Sonnet (main), Opus (thinker), and Haiku (subagent)": "为 Sonnet (主模型)、Opus (深度思考) 和 Haiku (子代理) 分别指定模型",
|
|
315
|
-
"Select model tier mapping": "选择模型层级映射",
|
|
316
|
-
"Main model (Sonnet tier)": "主模型 (Sonnet 层级)",
|
|
317
|
-
"Thinker model (Opus tier)": "深度思考模型 (Opus 层级)",
|
|
318
|
-
"Subagent model (Haiku tier)": "子代理模型 (Haiku 层级)",
|
|
311
|
+
"Sonnet model": "Sonnet 模型",
|
|
312
|
+
"Opus model": "Opus 模型",
|
|
313
|
+
"Haiku model": "Haiku 模型",
|
|
319
314
|
|
|
320
315
|
// Codex & agy Effort
|
|
321
316
|
"Select reasoning effort": "选择推理强度 (effort)",
|
package/src/menu.mjs
CHANGED
|
@@ -203,75 +203,35 @@ export async function pickModelFor(item, defaultModel) {
|
|
|
203
203
|
|
|
204
204
|
export async function pickClaudeCodeTiers(agentItem) {
|
|
205
205
|
const cfg = readConfig() ?? {};
|
|
206
|
-
const savedTiers = cfg.claude_tiers;
|
|
206
|
+
const savedTiers = cfg.claude_tiers || {};
|
|
207
207
|
const defaultTiers = {
|
|
208
208
|
sonnet: "claude-sonnet-5",
|
|
209
209
|
opus: "claude-opus-5-5",
|
|
210
210
|
haiku: DEFAULT_MODEL,
|
|
211
211
|
};
|
|
212
|
+
const baseTiers = {
|
|
213
|
+
sonnet: savedTiers.sonnet || defaultTiers.sonnet,
|
|
214
|
+
opus: savedTiers.opus || defaultTiers.opus,
|
|
215
|
+
haiku: savedTiers.haiku || defaultTiers.haiku,
|
|
216
|
+
};
|
|
212
217
|
|
|
213
|
-
|
|
214
|
-
{
|
|
215
|
-
id: "preset:recommended",
|
|
216
|
-
title: `⚡ ${t("Recommended Preset")}`,
|
|
217
|
-
desc: `Main: ${defaultTiers.sonnet} · Thinker: ${defaultTiers.opus} · Subagent: ${defaultTiers.haiku}`,
|
|
218
|
-
tiers: defaultTiers,
|
|
219
|
-
},
|
|
220
|
-
];
|
|
221
|
-
|
|
222
|
-
if (
|
|
223
|
-
savedTiers &&
|
|
224
|
-
(savedTiers.sonnet !== defaultTiers.sonnet ||
|
|
225
|
-
savedTiers.opus !== defaultTiers.opus ||
|
|
226
|
-
savedTiers.haiku !== defaultTiers.haiku)
|
|
227
|
-
) {
|
|
228
|
-
options.push({
|
|
229
|
-
id: "preset:previous",
|
|
230
|
-
title: `↻ ${t("Use Previous Configuration")}`,
|
|
231
|
-
desc: `Main: ${savedTiers.sonnet} · Thinker: ${savedTiers.opus} · Subagent: ${savedTiers.haiku}`,
|
|
232
|
-
tiers: savedTiers,
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
options.push({
|
|
237
|
-
id: "preset:custom",
|
|
238
|
-
title: `⚙️ ${t("Configure Tiers Manually")}`,
|
|
239
|
-
desc: t("Choose specific models for Sonnet (main), Opus (thinker), and Haiku (subagent)"),
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
const picked = await select(options, {
|
|
243
|
-
message: `${agentItem.title} — ${t("Select model tier mapping")}`,
|
|
244
|
-
formatItem: (x) => `${x.title}\n ${style.dim(x.desc)}`,
|
|
245
|
-
limit: 5,
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
if (!picked) return null;
|
|
249
|
-
|
|
250
|
-
if (picked.tiers) {
|
|
251
|
-
cfg.claude_tiers = picked.tiers;
|
|
252
|
-
writeConfig(cfg);
|
|
253
|
-
return picked.tiers;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const baseTiers = savedTiers || defaultTiers;
|
|
257
|
-
|
|
258
|
-
// Step 1: Sonnet (Main)
|
|
218
|
+
// 1/3단계: Sonnet 모델 지정 (10개 핵심 추천 + 200+ 전체 검색 + 프로바이더 라우팅)
|
|
259
219
|
const sonnet = await pickModelFor(
|
|
260
|
-
{ title: `${agentItem.title} — ${t("
|
|
220
|
+
{ title: `${agentItem.title} (1/3) — ${t("Sonnet model")}` },
|
|
261
221
|
baseTiers.sonnet,
|
|
262
222
|
);
|
|
263
223
|
if (!sonnet) return null;
|
|
264
224
|
|
|
265
|
-
//
|
|
225
|
+
// 2/3단계: Opus 모델 지정 (10개 핵심 추천 + 200+ 전체 검색 + 프로바이더 라우팅)
|
|
266
226
|
const opus = await pickModelFor(
|
|
267
|
-
{ title: `${agentItem.title} — ${t("
|
|
227
|
+
{ title: `${agentItem.title} (2/3) — ${t("Opus model")}` },
|
|
268
228
|
baseTiers.opus,
|
|
269
229
|
);
|
|
270
230
|
if (!opus) return null;
|
|
271
231
|
|
|
272
|
-
//
|
|
232
|
+
// 3/3단계: Haiku 모델 지정 (10개 핵심 추천 + 200+ 전체 검색 + 프로바이더 라우팅)
|
|
273
233
|
const haiku = await pickModelFor(
|
|
274
|
-
{ title: `${agentItem.title} — ${t("
|
|
234
|
+
{ title: `${agentItem.title} (3/3) — ${t("Haiku model")}` },
|
|
275
235
|
baseTiers.haiku,
|
|
276
236
|
);
|
|
277
237
|
if (!haiku) return null;
|
|
@@ -359,7 +319,10 @@ export async function runList(items, { header, footer, initialCursor = 0 } = {})
|
|
|
359
319
|
let windowStart = 0;
|
|
360
320
|
let lastRows = 0;
|
|
361
321
|
|
|
362
|
-
const rowsFor = (s) =>
|
|
322
|
+
const rowsFor = (s) =>
|
|
323
|
+
String(s)
|
|
324
|
+
.split("\n")
|
|
325
|
+
.reduce((sum, line) => sum + Math.max(1, Math.ceil(displayWidth(line) / Math.max(terminalWidth(), 1))), 0);
|
|
363
326
|
const erase = () => {
|
|
364
327
|
if (!lastRows) return;
|
|
365
328
|
output.write("\r" + (lastRows > 1 ? `\x1b[${lastRows - 1}A` : "") + "\x1b[0J");
|
|
@@ -411,8 +374,9 @@ export async function runList(items, { header, footer, initialCursor = 0 } = {})
|
|
|
411
374
|
lines.push(style.dim(footer));
|
|
412
375
|
|
|
413
376
|
erase();
|
|
414
|
-
|
|
415
|
-
|
|
377
|
+
const frameLines = lines.flatMap((l) => String(l).split("\n"));
|
|
378
|
+
output.write(frameLines.join("\n"));
|
|
379
|
+
lastRows = frameLines.reduce((n, l) => n + rowsFor(l), 0);
|
|
416
380
|
};
|
|
417
381
|
|
|
418
382
|
const move = (dir) => {
|