pleumrouter 0.5.47 → 0.5.49
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/completion.mjs +3 -2
- package/src/install.mjs +3 -0
- package/src/interactive.mjs +18 -5
- package/src/locales/es.mjs +3 -0
- package/src/locales/ja.mjs +3 -0
- package/src/locales/ko.mjs +3 -0
- package/src/locales/zh.mjs +3 -0
- package/src/wire.mjs +7 -1
- package/src/workspace.mjs +30 -15
package/package.json
CHANGED
package/src/completion.mjs
CHANGED
|
@@ -49,13 +49,14 @@ _pleum() {
|
|
|
49
49
|
_pleum "$@"`;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
export function completion(shell) {
|
|
52
|
+
export function completion(shell, platform = process.platform) {
|
|
53
53
|
if (shell === "bash") return void console.log(bash());
|
|
54
54
|
if (shell === "zsh") return void console.log(zsh());
|
|
55
55
|
console.error(
|
|
56
56
|
t("Usage: pleum completion <zsh|bash>") + "\n" +
|
|
57
57
|
` zsh: eval "$(pleum completion zsh)" (${t("or add to ~/.zshrc")})\n` +
|
|
58
|
-
` bash: eval "$(pleum completion bash)" (${t("or add to ~/.bashrc")})
|
|
58
|
+
` bash: eval "$(pleum completion bash)" (${t("or add to ~/.bashrc")})` +
|
|
59
|
+
(platform === "win32" ? `\n${t("PowerShell and cmd completion are not supported; use Git Bash or WSL.")}` : ""),
|
|
59
60
|
);
|
|
60
61
|
process.exit(1);
|
|
61
62
|
}
|
package/src/install.mjs
CHANGED
|
@@ -82,9 +82,12 @@ function runCurlPipe(pipe, spawnImpl, resolve) {
|
|
|
82
82
|
export async function runInstallCommand(install, {
|
|
83
83
|
spawnImpl = spawn,
|
|
84
84
|
resolve = resolveLaunchCommand,
|
|
85
|
+
platform = process.platform,
|
|
85
86
|
} = {}) {
|
|
86
87
|
const parsed = parseInstallCommand(install);
|
|
87
88
|
if (parsed.manual) return { manual: true, reason: parsed.reason, code: null };
|
|
89
|
+
// Windows엔 sh/bash가 없다 — curl|sh는 시도하지 않고 수동 안내로 넘긴다.
|
|
90
|
+
if (parsed.pipe && platform === "win32") return { manual: true, reason: "windows-pipe", code: null };
|
|
88
91
|
if (parsed.pipe) {
|
|
89
92
|
return { manual: false, code: await runCurlPipe(parsed.pipe, spawnImpl, resolve) };
|
|
90
93
|
}
|
package/src/interactive.mjs
CHANGED
|
@@ -102,6 +102,7 @@ export function rowsFor(s, width = terminalWidth()) {
|
|
|
102
102
|
// 화살표 이동 · 타이핑 필터 · Enter 선택 · Esc/Ctrl+C 취소(null).
|
|
103
103
|
// 비TTY면 즉시 null — 호출자가 기존 번호 피커 등으로 폴백한다.
|
|
104
104
|
// process.exit는 절대 호출하지 않는다(취소 처리는 호출자 몫).
|
|
105
|
+
// `{ header: true }` 항목은 묶음 제목 — 커서가 건너뛰고 선택되지 않으며 필터 중엔 숨긴다.
|
|
105
106
|
export async function select(items, {
|
|
106
107
|
message = t("Select"),
|
|
107
108
|
formatItem = String,
|
|
@@ -118,6 +119,16 @@ export async function select(items, {
|
|
|
118
119
|
let cursor = Math.max(0, Math.min(initialCursor, Math.max(0, (items?.length ?? 1) - 1)));
|
|
119
120
|
let windowStart = 0;
|
|
120
121
|
let lastRows = 0;
|
|
122
|
+
const isHeader = (it) => it?.header === true;
|
|
123
|
+
const poolOf = () => {
|
|
124
|
+
const pool = matches(items, query);
|
|
125
|
+
return query ? pool.filter((it) => !isHeader(it)) : pool;
|
|
126
|
+
};
|
|
127
|
+
// from에서 dir 방향 첫 비제목 위치. 없으면 fallback(현재 위치 유지).
|
|
128
|
+
const seek = (pool, from, dir, fallback) => {
|
|
129
|
+
for (let i = from; i >= 0 && i < pool.length; i += dir) if (!isHeader(pool[i])) return i;
|
|
130
|
+
return fallback;
|
|
131
|
+
};
|
|
121
132
|
|
|
122
133
|
const erase = () => {
|
|
123
134
|
if (!lastRows) return;
|
|
@@ -126,8 +137,9 @@ export async function select(items, {
|
|
|
126
137
|
};
|
|
127
138
|
|
|
128
139
|
const render = () => {
|
|
129
|
-
const pool =
|
|
140
|
+
const pool = poolOf();
|
|
130
141
|
if (cursor >= pool.length) cursor = Math.max(0, pool.length - 1);
|
|
142
|
+
if (isHeader(pool[cursor])) cursor = seek(pool, cursor, 1, seek(pool, cursor, -1, cursor));
|
|
131
143
|
if (cursor < windowStart) {
|
|
132
144
|
windowStart = cursor;
|
|
133
145
|
} else if (cursor >= windowStart + limit) {
|
|
@@ -146,6 +158,7 @@ export async function select(items, {
|
|
|
146
158
|
rawLines.push(
|
|
147
159
|
...shown.map((it, idx) => {
|
|
148
160
|
const itemIndex = windowStart + idx;
|
|
161
|
+
if (isHeader(it)) return ` ${style.gray(formatItem(it))}`;
|
|
149
162
|
return itemIndex === cursor
|
|
150
163
|
? `${style.plum("❯")} ${style.bold(formatItem(it))}`
|
|
151
164
|
: ` ${style.dim(formatItem(it))}`;
|
|
@@ -180,15 +193,15 @@ export async function select(items, {
|
|
|
180
193
|
for (const key of feed(chunk)) {
|
|
181
194
|
if (key.type === "ctrlc" || key.type === "escape") return finish(null);
|
|
182
195
|
if (key.type === "enter") {
|
|
183
|
-
const pool =
|
|
196
|
+
const pool = poolOf();
|
|
184
197
|
const safeCursor = Math.max(0, Math.min(cursor, pool.length - 1));
|
|
198
|
+
if (isHeader(pool[safeCursor])) continue;
|
|
185
199
|
return finish(pool[safeCursor] ?? null);
|
|
186
200
|
}
|
|
187
201
|
if (key.type === "up") {
|
|
188
|
-
cursor =
|
|
202
|
+
cursor = seek(poolOf(), cursor - 1, -1, cursor);
|
|
189
203
|
} else if (key.type === "down") {
|
|
190
|
-
|
|
191
|
-
cursor = Math.min(Math.max(0, pool.length - 1), cursor + 1);
|
|
204
|
+
cursor = seek(poolOf(), cursor + 1, 1, cursor);
|
|
192
205
|
} else if (key.type === "backspace") {
|
|
193
206
|
query = query.slice(0, -1);
|
|
194
207
|
cursor = 0;
|
package/src/locales/es.mjs
CHANGED
|
@@ -193,6 +193,8 @@ export const ES = {
|
|
|
193
193
|
"Update CLI": "Actualizar la CLI",
|
|
194
194
|
"Usage": "Uso",
|
|
195
195
|
"Usage: pleum completion <zsh|bash>": "Uso: pleum completion <zsh|bash>",
|
|
196
|
+
"{tool}: wire needs a zsh/bash shell and is not supported on Windows. Use `pleum launch {tool}` instead.": "{tool}: wire necesita un shell zsh/bash y no es compatible con Windows. Usa `pleum launch {tool}` en su lugar.",
|
|
197
|
+
"PowerShell and cmd completion are not supported; use Git Bash or WSL.": "El autocompletado para PowerShell y cmd no es compatible; usa Git Bash o WSL.",
|
|
196
198
|
"Usage: pleum launch <tool> [--model id] [-- tool args]\n": "Uso: pleum launch <tool> [--model id] [-- tool args]\n",
|
|
197
199
|
"Usage: pleum models <model-id> --info": "Uso: pleum models <model-id> --info",
|
|
198
200
|
"Usage: pleum run <model> [\"prompt\"]\nModel list: pleum models": "Uso: pleum run <model> [\"prompt\"]\nLista de modelos: pleum models",
|
|
@@ -258,6 +260,7 @@ export const ES = {
|
|
|
258
260
|
"Team": "Equipo",
|
|
259
261
|
"Personal": "Personal",
|
|
260
262
|
"Personal Credit": "Crédito personal",
|
|
263
|
+
"Invited workspaces": "Espacios de trabajo invitados",
|
|
261
264
|
"Credit workspace": "Espacio de crédito",
|
|
262
265
|
"Credit Balance:": "Saldo de crédito:",
|
|
263
266
|
"credits": "créditos",
|
package/src/locales/ja.mjs
CHANGED
|
@@ -191,6 +191,8 @@ export const JA = {
|
|
|
191
191
|
"Update CLI": "CLIを更新",
|
|
192
192
|
"Usage": "使用状況",
|
|
193
193
|
"Usage: pleum completion <zsh|bash>": "使い方: pleum completion <zsh|bash>",
|
|
194
|
+
"{tool}: wire needs a zsh/bash shell and is not supported on Windows. Use `pleum launch {tool}` instead.": "{tool}: wire は zsh/bash シェルが必要なため Windows では使えません。代わりに `pleum launch {tool}` を使ってください。",
|
|
195
|
+
"PowerShell and cmd completion are not supported; use Git Bash or WSL.": "PowerShell・cmd の補完には対応していません。Git Bash か WSL を使ってください。",
|
|
194
196
|
"Usage: pleum launch <tool> [--model id] [-- tool args]\n": "使い方: pleum launch <tool> [--model id] [-- tool args]\n",
|
|
195
197
|
"Usage: pleum models <model-id> --info": "使い方: pleum models <model-id> --info",
|
|
196
198
|
"Usage: pleum run <model> [\"prompt\"]\nModel list: pleum models": "使い方: pleum run <model> [\"prompt\"]\nモデル一覧: pleum models",
|
|
@@ -258,6 +260,7 @@ export const JA = {
|
|
|
258
260
|
"Team": "チーム",
|
|
259
261
|
"Personal": "個人",
|
|
260
262
|
"Personal Credit": "個人クレジット",
|
|
263
|
+
"Invited workspaces": "招待されたワークスペース",
|
|
261
264
|
"Credit workspace": "クレジットワークスペース",
|
|
262
265
|
"Credit Balance:": "クレジット残高:",
|
|
263
266
|
"credits": "クレジット",
|
package/src/locales/ko.mjs
CHANGED
|
@@ -65,6 +65,8 @@ export const KO = {
|
|
|
65
65
|
|
|
66
66
|
// completion.mjs
|
|
67
67
|
"Usage: pleum completion <zsh|bash>": "사용법: pleum completion <zsh|bash>",
|
|
68
|
+
"{tool}: wire needs a zsh/bash shell and is not supported on Windows. Use `pleum launch {tool}` instead.": "{tool}: wire는 zsh/bash 셸이 필요해 Windows에서 지원하지 않습니다. 대신 `pleum launch {tool}`을 사용하세요.",
|
|
69
|
+
"PowerShell and cmd completion are not supported; use Git Bash or WSL.": "PowerShell·cmd 자동완성은 지원하지 않습니다. Git Bash나 WSL을 사용하세요.",
|
|
68
70
|
"or add to ~/.zshrc": "또는 ~/.zshrc에 추가",
|
|
69
71
|
"or add to ~/.bashrc": "또는 ~/.bashrc에 추가",
|
|
70
72
|
"or add _pleum to fpath": "또는 fpath에 _pleum로 추가",
|
|
@@ -317,6 +319,7 @@ export const KO = {
|
|
|
317
319
|
"Team": "팀",
|
|
318
320
|
"Personal": "개인",
|
|
319
321
|
"Personal Credit": "개인 크레딧",
|
|
322
|
+
"Invited workspaces": "초대받은 워크스페이스",
|
|
320
323
|
"Credit workspace": "크레딧 워크스페이스",
|
|
321
324
|
"Credit Balance:": "크레딧 잔액:",
|
|
322
325
|
"credits": "크레딧",
|
package/src/locales/zh.mjs
CHANGED
|
@@ -193,6 +193,8 @@ export const ZH = {
|
|
|
193
193
|
"Update CLI": "更新 CLI",
|
|
194
194
|
"Usage": "用量",
|
|
195
195
|
"Usage: pleum completion <zsh|bash>": "用法:pleum completion <zsh|bash>",
|
|
196
|
+
"{tool}: wire needs a zsh/bash shell and is not supported on Windows. Use `pleum launch {tool}` instead.": "{tool}:wire 需要 zsh/bash shell,不支持 Windows。请改用 `pleum launch {tool}`。",
|
|
197
|
+
"PowerShell and cmd completion are not supported; use Git Bash or WSL.": "不支持 PowerShell 和 cmd 自动补全,请使用 Git Bash 或 WSL。",
|
|
196
198
|
"Usage: pleum launch <tool> [--model id] [-- tool args]\n": "用法:pleum launch <tool> [--model id] [-- tool args]\n",
|
|
197
199
|
"Usage: pleum models <model-id> --info": "用法:pleum models <model-id> --info",
|
|
198
200
|
"Usage: pleum run <model> [\"prompt\"]\nModel list: pleum models": "用法:pleum run <model> [\"prompt\"]\n模型列表:pleum models",
|
|
@@ -258,6 +260,7 @@ export const ZH = {
|
|
|
258
260
|
"Team": "团队",
|
|
259
261
|
"Personal": "个人",
|
|
260
262
|
"Personal Credit": "个人额度",
|
|
263
|
+
"Invited workspaces": "受邀的工作区",
|
|
261
264
|
"Credit workspace": "额度工作区",
|
|
262
265
|
"Credit Balance:": "额度余额:",
|
|
263
266
|
"credits": "额度",
|
package/src/wire.mjs
CHANGED
|
@@ -895,7 +895,13 @@ function originalValues(tool, paths, state, text) {
|
|
|
895
895
|
return fromText ?? pickPrevious(tool, readText(paths[`${tool}Bak`])) ?? {};
|
|
896
896
|
}
|
|
897
897
|
|
|
898
|
-
|
|
898
|
+
// 셸 rc 래퍼 없이 설정 파일만으로 배선되는 도구. 나머지는 zsh/bash rc가 필요해 Windows에서 효과가 없다.
|
|
899
|
+
const FILE_WIRED_TOOLS = new Set(["claude", "codex", "opencode", "aider", "crush", "pi"]);
|
|
900
|
+
|
|
901
|
+
export function applyToolWiring(tool, paths, { key, model, models = [], billingOnly = false, activeContext, platform = process.platform } = {}) {
|
|
902
|
+
if (platform === "win32" && !FILE_WIRED_TOOLS.has(tool)) {
|
|
903
|
+
throw new Error(t("{tool}: wire needs a zsh/bash shell and is not supported on Windows. Use `pleum launch {tool}` instead.", { tool }));
|
|
904
|
+
}
|
|
899
905
|
const state = readWiredState(paths);
|
|
900
906
|
const mode = billingOnly ? "billing" : (models.length > 0 ? "list" : (model ? "custom" : "billing"));
|
|
901
907
|
let previous; // claude·agy가 덮어쓰는 사용자 원래 값 — unwire가 복원한다
|
package/src/workspace.mjs
CHANGED
|
@@ -56,15 +56,24 @@ export function workspaceLabel(context) {
|
|
|
56
56
|
return t("Personal");
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
// 서버가 소유 공간(role=owner)을 먼저 보낸다. 소유=개인 크레딧 아래, 나머지=초대받은 공간 묶음.
|
|
60
|
+
export function splitCandidates(candidates = []) {
|
|
61
|
+
return {
|
|
62
|
+
owned: candidates.filter((c) => c.role === "owner"),
|
|
63
|
+
invited: candidates.filter((c) => c.role !== "owner"),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
59
67
|
export function formatWorkspaceList(context, candidates = []) {
|
|
60
68
|
const activeId = context?.type === "workspace" ? String(context.workspace_id) : null;
|
|
61
|
-
const
|
|
62
|
-
|
|
69
|
+
const { owned, invited } = splitCandidates(candidates);
|
|
70
|
+
const line = (candidate) => {
|
|
63
71
|
const mark = String(candidate.workspace_id) === activeId ? style.bold(style.plum("▸ ")) : " ";
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
72
|
+
return `${mark}${candidate.workspace_id} ${sanitizeTerminalText(candidate.name)} (${sanitizeTerminalText(candidate.role)})`;
|
|
73
|
+
};
|
|
74
|
+
const lines = [`${t("Credit workspace")}: ${workspaceLabel(context)}`];
|
|
75
|
+
if (owned.length) lines.push(`${t("Personal Credit")}:`, ...owned.map(line));
|
|
76
|
+
if (invited.length) lines.push(`${t("Invited workspaces")}:`, ...invited.map(line));
|
|
68
77
|
return lines.join("\n");
|
|
69
78
|
}
|
|
70
79
|
|
|
@@ -118,6 +127,15 @@ export async function selectAndBindWorkspace({
|
|
|
118
127
|
const active = data?.active_context ?? getActiveContext();
|
|
119
128
|
const activeId = active?.type === "workspace" ? String(active.workspace_id) : null;
|
|
120
129
|
|
|
130
|
+
const { owned, invited } = splitCandidates(candidates);
|
|
131
|
+
const option = (c, title) => ({
|
|
132
|
+
id: String(c.workspace_id),
|
|
133
|
+
type: "workspace",
|
|
134
|
+
workspace_id: c.workspace_id,
|
|
135
|
+
name: c.name,
|
|
136
|
+
title,
|
|
137
|
+
label: `${activeId === String(c.workspace_id) ? "✓ " : " "} └ ${title}`,
|
|
138
|
+
});
|
|
121
139
|
const options = [
|
|
122
140
|
{
|
|
123
141
|
id: "personal",
|
|
@@ -125,20 +143,17 @@ export async function selectAndBindWorkspace({
|
|
|
125
143
|
title: t("Personal Credit"),
|
|
126
144
|
label: `${activeId ? " " : "✓ "}${t("Personal Credit")}`,
|
|
127
145
|
},
|
|
128
|
-
...
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
title: `${sanitizeTerminalText(c.name)} (${sanitizeTerminalText(c.role)})`,
|
|
134
|
-
label: `${activeId === String(c.workspace_id) ? "✓ " : " "}${sanitizeTerminalText(c.name)} (${sanitizeTerminalText(c.role)})`,
|
|
135
|
-
})),
|
|
146
|
+
...owned.map((c) => option(c, sanitizeTerminalText(c.name))),
|
|
147
|
+
...(invited.length
|
|
148
|
+
? [{ id: "header:invited", header: true, label: ` ${t("Invited workspaces")}` }]
|
|
149
|
+
: []),
|
|
150
|
+
...invited.map((c) => option(c, `${sanitizeTerminalText(c.name)} (${sanitizeTerminalText(c.role)})`)),
|
|
136
151
|
];
|
|
137
152
|
|
|
138
153
|
const picked = await selectFn(options, {
|
|
139
154
|
message: t("Select billing workspace for this agent"),
|
|
140
155
|
formatItem: (x) => x.label,
|
|
141
|
-
limit:
|
|
156
|
+
limit: 12,
|
|
142
157
|
});
|
|
143
158
|
|
|
144
159
|
if (!picked) return active;
|