pleumrouter 0.5.22 → 0.5.24
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/README.md +5 -5
- package/package.json +1 -1
- package/src/completion.mjs +2 -2
- package/src/launch.mjs +48 -13
- package/src/locales/es.mjs +16 -0
- package/src/locales/ja.mjs +16 -0
- package/src/locales/ko.mjs +16 -0
- package/src/locales/zh.mjs +17 -1
- package/src/menu.mjs +9 -0
- package/src/recipes.mjs +195 -23
- package/src/wire.mjs +7 -1
package/README.md
CHANGED
|
@@ -74,11 +74,11 @@ SSH/CI에서는 `pleum login --device`를 쓰세요.
|
|
|
74
74
|
|
|
75
75
|
## 자동 실행 지원 도구
|
|
76
76
|
|
|
77
|
-
`claude` · `
|
|
78
|
-
env
|
|
79
|
-
|
|
77
|
+
`claude` · `codex` · `aider` · `goose` · `openhands` · `opencode` · `omp` · `hermes` · `qwen` · `copilot` · `gemini` · `agy` · `pi` · `crush` —
|
|
78
|
+
env 또는 격리 홈(`CODEX_HOME` / `PI_CODING_AGENT_DIR` / `CRUSH_GLOBAL_CONFIG`)만 세팅하고 바로 실행한다.
|
|
79
|
+
별칭: `antigravity`→`agy`, `picode`→`pi`, `ohmypi`→`omp`.
|
|
80
80
|
|
|
81
|
-
`
|
|
81
|
+
`agy`만 사용자 `~/.gemini/antigravity-cli/settings.json`에 `modelProvider=gemini`를 병합한다(제품이 이 파일 없이 키를 무시함). Kiro는 공식 BYOK가 없어 지원하지 않는다.
|
|
82
82
|
|
|
83
83
|
## 환경변수
|
|
84
84
|
|
|
@@ -97,7 +97,7 @@ npm link # 로컬에서 pleum 명령 노출
|
|
|
97
97
|
|
|
98
98
|
1. `npm version patch` (또는 minor/major)로 `package.json` bump 후 커밋.
|
|
99
99
|
2. `git tag cli-v$(node -p "require('./package.json').version")` → `git push origin HEAD --tags`.
|
|
100
|
-
3. 워크플로가 `secrets.NPM_TOKEN`으로 `npm publish
|
|
100
|
+
3. 워크플로가 `secrets.NPM_TOKEN`으로 `npm publish` 실행. (private GitHub repo라 `--provenance` 불가)
|
|
101
101
|
|
|
102
102
|
태그 규칙: `cli-v{semver}` (예: `cli-v0.5.15`).
|
|
103
103
|
|
package/package.json
CHANGED
package/src/completion.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// Shell 자동완성 스크립트 출력. 명령·도구는 정적, 모델명은 `pleum models`에서 동적으로 채운다.
|
|
2
2
|
// 설치: pleum completion zsh >> ~/.zshrc · pleum completion bash >> ~/.bashrc
|
|
3
3
|
import { t } from "./i18n.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { launchToolNames } from "./recipes.mjs";
|
|
5
5
|
|
|
6
6
|
const COMMANDS = "login logout lang launch wire unwire run models top balance usage health version upgrade completion help";
|
|
7
|
-
const TOOLS =
|
|
7
|
+
const TOOLS = launchToolNames().join(" ");
|
|
8
8
|
|
|
9
9
|
function bash() {
|
|
10
10
|
return `# pleum bash completion — eval "$(pleum completion bash)" (${t("or add to ~/.bashrc")})
|
package/src/launch.mjs
CHANGED
|
@@ -3,7 +3,16 @@ import { mkdirSync, writeFileSync, existsSync, readFileSync } from "node:fs";
|
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { join, delimiter, dirname, resolve } from "node:path";
|
|
5
5
|
import { requireAuth } from "./config.mjs";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
RECIPES,
|
|
8
|
+
MANUAL,
|
|
9
|
+
LAUNCH_ALIASES,
|
|
10
|
+
resolveLaunchTool,
|
|
11
|
+
codexToml,
|
|
12
|
+
piModelsJson,
|
|
13
|
+
crushJson,
|
|
14
|
+
mergeAgySettings,
|
|
15
|
+
} from "./recipes.mjs";
|
|
7
16
|
import { t } from "./i18n.mjs";
|
|
8
17
|
import { sanitizeTerminalText } from "./ansi.mjs";
|
|
9
18
|
|
|
@@ -72,28 +81,35 @@ export function launchHelp() {
|
|
|
72
81
|
const ok = onPath(r.bin) ? t("✓ installed") : `${t("✗ not installed —")} ${r.install}`;
|
|
73
82
|
console.log(` ${name.padEnd(11)} ${r.label.padEnd(13)} ${ok}`);
|
|
74
83
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const
|
|
78
|
-
|
|
84
|
+
if (Object.keys(MANUAL).length) {
|
|
85
|
+
console.log(`\n${t("Manual setup (needs a provider definition file):")}`);
|
|
86
|
+
for (const [name, m] of Object.entries(MANUAL)) {
|
|
87
|
+
const ok = onPath(m.bin) ? t("✓ installed") : `${t("✗ not installed —")} ${m.install}`;
|
|
88
|
+
console.log(` ${name.padEnd(11)} ${m.label.padEnd(13)} ${ok}`);
|
|
89
|
+
}
|
|
79
90
|
}
|
|
91
|
+
const aliases = Object.entries(LAUNCH_ALIASES).map(([from, to]) => `${from} → ${to}`).join(", ");
|
|
92
|
+
console.log(`\n${t("Aliases: {list}", { list: aliases })}`);
|
|
80
93
|
console.log(`\n${t("Example: pleum launch claude --model claude-sonnet-5")}`);
|
|
81
94
|
}
|
|
82
95
|
|
|
83
96
|
// exit:false면 process.exit 대신 자식 종료 코드를 반환 — 런처 메뉴의 실행 후 복귀용.
|
|
84
97
|
export async function launch(tool, model, passthrough, { exit = true } = {}) {
|
|
85
98
|
const key = await requireAuth();
|
|
86
|
-
const
|
|
99
|
+
const resolved = resolveLaunchTool(tool);
|
|
100
|
+
const r = RECIPES[resolved];
|
|
87
101
|
|
|
88
102
|
if (!r) {
|
|
89
|
-
if (MANUAL[
|
|
90
|
-
printManual(
|
|
103
|
+
if (MANUAL[resolved]) {
|
|
104
|
+
printManual(resolved, key);
|
|
91
105
|
return;
|
|
92
106
|
}
|
|
107
|
+
const aliases = Object.entries(LAUNCH_ALIASES).map(([from, to]) => `${from} → ${to}`).join(", ");
|
|
93
108
|
console.error(
|
|
94
109
|
t("Unsupported tool: {tool}", { tool }) +
|
|
95
110
|
`\n ${t("Auto-run:")} ${Object.keys(RECIPES).join(", ")}` +
|
|
96
|
-
`\n ${t("Manual setup:")} ${Object.keys(MANUAL).join(", ")}
|
|
111
|
+
(Object.keys(MANUAL).length ? `\n ${t("Manual setup:")} ${Object.keys(MANUAL).join(", ")}` : "") +
|
|
112
|
+
`\n ${t("Aliases: {list}", { list: aliases })}`,
|
|
97
113
|
);
|
|
98
114
|
process.exit(1);
|
|
99
115
|
}
|
|
@@ -102,11 +118,15 @@ export async function launch(tool, model, passthrough, { exit = true } = {}) {
|
|
|
102
118
|
|
|
103
119
|
// Codex는 격리 CODEX_HOME에 config.toml을 써서 사용자 ~/.codex를 보존한다.
|
|
104
120
|
if (r.type === "codex-home") {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
env.
|
|
121
|
+
env.CODEX_HOME = writeIsolatedHome("codex-home", "config.toml", codexToml(model));
|
|
122
|
+
}
|
|
123
|
+
if (r.type === "pi-home") {
|
|
124
|
+
env.PI_CODING_AGENT_DIR = writeIsolatedHome("pi-home", "models.json", piModelsJson(model));
|
|
109
125
|
}
|
|
126
|
+
if (r.type === "crush-home") {
|
|
127
|
+
env.CRUSH_GLOBAL_CONFIG = writeIsolatedHome("crush-home", "crush.json", crushJson(model));
|
|
128
|
+
}
|
|
129
|
+
if (r.type === "agy-settings") ensureAgySettings();
|
|
110
130
|
|
|
111
131
|
const args = [...r.args(model), ...passthrough];
|
|
112
132
|
if (r.note) console.log(`ℹ ${t(r.note)}`);
|
|
@@ -144,6 +164,21 @@ export async function launch(tool, model, passthrough, { exit = true } = {}) {
|
|
|
144
164
|
});
|
|
145
165
|
}
|
|
146
166
|
|
|
167
|
+
function writeIsolatedHome(name, filename, contents) {
|
|
168
|
+
const home = join(homedir(), ".pleum", name);
|
|
169
|
+
mkdirSync(home, { recursive: true, mode: 0o700 });
|
|
170
|
+
writeFileSync(join(home, filename), contents, { mode: 0o600 });
|
|
171
|
+
return home;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function ensureAgySettings() {
|
|
175
|
+
const dir = join(homedir(), ".gemini", "antigravity-cli");
|
|
176
|
+
const path = join(dir, "settings.json");
|
|
177
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
178
|
+
const existing = existsSync(path) ? readFileSync(path, "utf8") : "";
|
|
179
|
+
writeFileSync(path, `${JSON.stringify(mergeAgySettings(existing), null, 2)}\n`, { mode: 0o600 });
|
|
180
|
+
}
|
|
181
|
+
|
|
147
182
|
function printManual(tool, key) {
|
|
148
183
|
const m = MANUAL[tool];
|
|
149
184
|
console.log(`${t("{label} needs a provider definition in a file, so this only shows setup — it won't auto-run.", { label: m.label })}\n`);
|
package/src/locales/es.mjs
CHANGED
|
@@ -20,6 +20,15 @@ export const ES = {
|
|
|
20
20
|
"Nous Research's general-purpose agent": "Agente de propósito general de Nous Research",
|
|
21
21
|
"Alibaba's terminal coding agent": "Agente de codificación de terminal de Alibaba",
|
|
22
22
|
"GitHub's terminal coding agent": "Agente de codificación de terminal de GitHub",
|
|
23
|
+
"Google's Gemini CLI": "CLI de Gemini de Google",
|
|
24
|
+
"Google Antigravity CLI (agy)": "CLI de Google Antigravity (agy)",
|
|
25
|
+
"Pi coding agent (picode is a Pi package)": "Agente Pi (picode es un paquete de Pi)",
|
|
26
|
+
"Charmbracelet terminal coding agent": "Agente de terminal Charmbracelet",
|
|
27
|
+
"MiniMax's autonomous coding agent": "Agente de codificación autónomo de MiniMax",
|
|
28
|
+
"Xiaomi's terminal coding agent with persistent memory": "Agente de codificación de terminal de Xiaomi con memoria persistente",
|
|
29
|
+
"Autonomous personal AI coding agent": "Agente personal autónomo de codificación por IA",
|
|
30
|
+
"Terminal AI coding engine for complex tasks": "Motor de codificación de IA en terminal para tareas complejas",
|
|
31
|
+
"Local code execution & pair programmer": "Ejecución de código local y programador en pareja",
|
|
23
32
|
"Available: {list}": "Disponibles: {list}",
|
|
24
33
|
"Balance": "Saldo",
|
|
25
34
|
"Balance is below the auto-charge threshold ({threshold} ₩).": "El saldo está por debajo del umbral de recarga automática ({threshold} ₩).",
|
|
@@ -62,6 +71,13 @@ export const ES = {
|
|
|
62
71
|
"Necesita GitHub Copilot CLI 2026-04 o posterior para el enrutamiento de proveedores BYOK.",
|
|
63
72
|
"Gemini CLI speaks Google's native generateContent format — set the model after launch with `/model google/<id>`.":
|
|
64
73
|
"Gemini CLI usa el formato nativo generateContent de Google — establece el modelo tras el inicio con `/model google/<id>`.",
|
|
74
|
+
"Writes modelProvider=gemini into ~/.gemini/antigravity-cli/settings.json. GEMINI_API_KEY alone is ignored. Gemini-family models only.":
|
|
75
|
+
"Escribe modelProvider=gemini en ~/.gemini/antigravity-cli/settings.json. GEMINI_API_KEY sola se ignora. Solo familia Gemini.",
|
|
76
|
+
"Uses an isolated ~/.pleum/pi-home (PI_CODING_AGENT_DIR). Your ~/.pi is untouched.":
|
|
77
|
+
"Usa un ~/.pleum/pi-home aislado (PI_CODING_AGENT_DIR). No toca ~/.pi.",
|
|
78
|
+
"Uses an isolated ~/.pleum/crush-home (CRUSH_GLOBAL_CONFIG). Your crush.json is untouched.":
|
|
79
|
+
"Usa un ~/.pleum/crush-home aislado (CRUSH_GLOBAL_CONFIG). No toca crush.json.",
|
|
80
|
+
"Aliases: {list}": "Alias: {list}",
|
|
65
81
|
"Gateway": "Gateway",
|
|
66
82
|
"Gateway connection failed: {error}": "Error de conexión al gateway: {error}",
|
|
67
83
|
"Gateway connectivity · login status": "Conectividad del gateway · estado de la sesión",
|
package/src/locales/ja.mjs
CHANGED
|
@@ -20,6 +20,15 @@ export const JA = {
|
|
|
20
20
|
"Nous Research's general-purpose agent": "Nous Research の汎用エージェント",
|
|
21
21
|
"Alibaba's terminal coding agent": "Alibaba のターミナルコーディングエージェント",
|
|
22
22
|
"GitHub's terminal coding agent": "GitHub のターミナルコーディングエージェント",
|
|
23
|
+
"Google's Gemini CLI": "Google Gemini CLI",
|
|
24
|
+
"Google Antigravity CLI (agy)": "Google Antigravity CLI (agy)",
|
|
25
|
+
"Pi coding agent (picode is a Pi package)": "Pi コーディングエージェント (picode は Pi パッケージ)",
|
|
26
|
+
"Charmbracelet terminal coding agent": "Charmbracelet ターミナルコーディングエージェント",
|
|
27
|
+
"MiniMax's autonomous coding agent": "MiniMax の自律型コーディングエージェント",
|
|
28
|
+
"Xiaomi's terminal coding agent with persistent memory": "永続メモリを搭載した Xiaomi のターミナルコーディングエージェント",
|
|
29
|
+
"Autonomous personal AI coding agent": "個人向け自律型 AI コーディングエージェント",
|
|
30
|
+
"Terminal AI coding engine for complex tasks": "複雑なタスク向けターミナル AI コーディングエンジン",
|
|
31
|
+
"Local code execution & pair programmer": "ローカルコード実行&ペアプログラマー",
|
|
23
32
|
"Available: {list}": "利用可能: {list}",
|
|
24
33
|
"Balance": "残高",
|
|
25
34
|
"Balance is below the auto-charge threshold ({threshold} ₩).": "残高が自動チャージのしきい値 ({threshold} ₩) を下回っています。",
|
|
@@ -63,6 +72,13 @@ export const JA = {
|
|
|
63
72
|
"BYOK プロバイダールーティングに対応した 2026-04 以降の GitHub Copilot CLI が必要です。",
|
|
64
73
|
"Gemini CLI speaks Google's native generateContent format — set the model after launch with `/model google/<id>`.":
|
|
65
74
|
"Gemini CLI は Google のネイティブ generateContent 形式を使用します — 起動後に `/model google/<id>` でモデルを設定してください。",
|
|
75
|
+
"Writes modelProvider=gemini into ~/.gemini/antigravity-cli/settings.json. GEMINI_API_KEY alone is ignored. Gemini-family models only.":
|
|
76
|
+
"~/.gemini/antigravity-cli/settings.json に modelProvider=gemini を書き込みます。GEMINI_API_KEY だけでは無視されます。Gemini 系のみです。",
|
|
77
|
+
"Uses an isolated ~/.pleum/pi-home (PI_CODING_AGENT_DIR). Your ~/.pi is untouched.":
|
|
78
|
+
"隔離した ~/.pleum/pi-home (PI_CODING_AGENT_DIR) だけを使います。~/.pi は触れません。",
|
|
79
|
+
"Uses an isolated ~/.pleum/crush-home (CRUSH_GLOBAL_CONFIG). Your crush.json is untouched.":
|
|
80
|
+
"隔離した ~/.pleum/crush-home (CRUSH_GLOBAL_CONFIG) だけを使います。crush.json は触れません。",
|
|
81
|
+
"Aliases: {list}": "エイリアス: {list}",
|
|
66
82
|
"Gateway": "ゲートウェイ",
|
|
67
83
|
"Gateway connection failed: {error}": "ゲートウェイ接続に失敗しました: {error}",
|
|
68
84
|
"Gateway connectivity · login status": "ゲートウェイ接続 · ログイン状態",
|
package/src/locales/ko.mjs
CHANGED
|
@@ -52,6 +52,13 @@ export const KO = {
|
|
|
52
52
|
"BYOK provider 라우팅을 지원하는 2026-04 이후 버전의 GitHub Copilot CLI가 필요합니다.",
|
|
53
53
|
"Gemini CLI speaks Google's native generateContent format — set the model after launch with `/model google/<id>`.":
|
|
54
54
|
"Gemini CLI는 Google의 네이티브 generateContent 포맷을 사용합니다 — 실행 후 `/model google/<id>`로 모델을 설정하세요.",
|
|
55
|
+
"Writes modelProvider=gemini into ~/.gemini/antigravity-cli/settings.json. GEMINI_API_KEY alone is ignored. Gemini-family models only.":
|
|
56
|
+
"~/.gemini/antigravity-cli/settings.json 에 modelProvider=gemini 를 씁니다. GEMINI_API_KEY만 있으면 무시됩니다. Gemini 계열만 됩니다.",
|
|
57
|
+
"Uses an isolated ~/.pleum/pi-home (PI_CODING_AGENT_DIR). Your ~/.pi is untouched.":
|
|
58
|
+
"격리된 ~/.pleum/pi-home (PI_CODING_AGENT_DIR)만 씁니다. ~/.pi는 건드리지 않습니다.",
|
|
59
|
+
"Uses an isolated ~/.pleum/crush-home (CRUSH_GLOBAL_CONFIG). Your crush.json is untouched.":
|
|
60
|
+
"격리된 ~/.pleum/crush-home (CRUSH_GLOBAL_CONFIG)만 씁니다. crush.json은 건드리지 않습니다.",
|
|
61
|
+
"Aliases: {list}": "별칭: {list}",
|
|
55
62
|
|
|
56
63
|
// completion.mjs
|
|
57
64
|
"Usage: pleum completion <zsh|bash>": "사용법: pleum completion <zsh|bash>",
|
|
@@ -146,6 +153,15 @@ export const KO = {
|
|
|
146
153
|
"Nous Research's general-purpose agent": "Nous Research의 범용 에이전트",
|
|
147
154
|
"Alibaba's terminal coding agent": "Alibaba의 터미널 코딩 에이전트",
|
|
148
155
|
"GitHub's terminal coding agent": "GitHub의 터미널 코딩 에이전트",
|
|
156
|
+
"Google's Gemini CLI": "Google Gemini CLI",
|
|
157
|
+
"Google Antigravity CLI (agy)": "Google Antigravity CLI (agy)",
|
|
158
|
+
"Pi coding agent (picode is a Pi package)": "Pi 코딩 에이전트 (picode는 Pi 패키지)",
|
|
159
|
+
"Charmbracelet terminal coding agent": "Charmbracelet 터미널 코딩 에이전트",
|
|
160
|
+
"MiniMax's autonomous coding agent": "MiniMax의 자율 코딩 에이전트",
|
|
161
|
+
"Xiaomi's terminal coding agent with persistent memory": "영구 메모리를 탑재한 Xiaomi의 터미널 코딩 에이전트",
|
|
162
|
+
"Autonomous personal AI coding agent": "개인용 자율 AI 코딩 에이전트",
|
|
163
|
+
"Terminal AI coding engine for complex tasks": "복잡한 작업을 위한 터미널 AI 코딩 엔진",
|
|
164
|
+
"Local code execution & pair programmer": "로컬 코드 실행 및 페어 프로그래머",
|
|
149
165
|
"Log in": "로그인",
|
|
150
166
|
"Log in via browser and save the API key": "브라우저로 로그인하고 API 키를 저장합니다",
|
|
151
167
|
"Chat with a model": "모델과 채팅",
|
package/src/locales/zh.mjs
CHANGED
|
@@ -20,6 +20,15 @@ export const ZH = {
|
|
|
20
20
|
"Nous Research's general-purpose agent": "Nous Research 的通用代理",
|
|
21
21
|
"Alibaba's terminal coding agent": "阿里巴巴的终端编程代理",
|
|
22
22
|
"GitHub's terminal coding agent": "GitHub 的终端编程代理",
|
|
23
|
+
"Google's Gemini CLI": "Google Gemini CLI",
|
|
24
|
+
"Google Antigravity CLI (agy)": "Google Antigravity CLI (agy)",
|
|
25
|
+
"Pi coding agent (picode is a Pi package)": "Pi 编程代理(picode 是 Pi 包)",
|
|
26
|
+
"Charmbracelet terminal coding agent": "Charmbracelet 终端编程代理",
|
|
27
|
+
"MiniMax's autonomous coding agent": "MiniMax 自主编程代理",
|
|
28
|
+
"Xiaomi's terminal coding agent with persistent memory": "带持久记忆的 Xiaomi 终端编程代理",
|
|
29
|
+
"Autonomous personal AI coding agent": "个人自主 AI 编程代理",
|
|
30
|
+
"Terminal AI coding engine for complex tasks": "用于复杂任务的终端 AI 编程引擎",
|
|
31
|
+
"Local code execution & pair programmer": "本地代码执行与结对编程器",
|
|
23
32
|
"Available: {list}": "可用:{list}",
|
|
24
33
|
"Balance": "余额",
|
|
25
34
|
"Balance is below the auto-charge threshold ({threshold} ₩).": "余额低于自动充值阈值({threshold} ₩)。",
|
|
@@ -61,7 +70,14 @@ export const ZH = {
|
|
|
61
70
|
"Needs GitHub Copilot CLI 2026-04 or later for BYOK provider routing support.":
|
|
62
71
|
"需要 2026-04 或更新版本的 GitHub Copilot CLI 才支持 BYOK provider 路由。",
|
|
63
72
|
"Gemini CLI speaks Google's native generateContent format — set the model after launch with `/model google/<id>`.":
|
|
64
|
-
"Gemini CLI
|
|
73
|
+
"Gemini CLI 使用 Google 原生 generateContent 格式 — 启动后用 `/model google/<id>` 设置模型。",
|
|
74
|
+
"Writes modelProvider=gemini into ~/.gemini/antigravity-cli/settings.json. GEMINI_API_KEY alone is ignored. Gemini-family models only.":
|
|
75
|
+
"会把 modelProvider=gemini 写入 ~/.gemini/antigravity-cli/settings.json。只设 GEMINI_API_KEY 会被忽略。仅 Gemini 系列。",
|
|
76
|
+
"Uses an isolated ~/.pleum/pi-home (PI_CODING_AGENT_DIR). Your ~/.pi is untouched.":
|
|
77
|
+
"只用隔离的 ~/.pleum/pi-home(PI_CODING_AGENT_DIR),不改 ~/.pi。",
|
|
78
|
+
"Uses an isolated ~/.pleum/crush-home (CRUSH_GLOBAL_CONFIG). Your crush.json is untouched.":
|
|
79
|
+
"只用隔离的 ~/.pleum/crush-home(CRUSH_GLOBAL_CONFIG),不改 crush.json。",
|
|
80
|
+
"Aliases: {list}": "别名:{list}",
|
|
65
81
|
"Gateway": "网关",
|
|
66
82
|
"Gateway connection failed: {error}": "网关连接失败:{error}",
|
|
67
83
|
"Gateway connectivity · login status": "网关连通性 · 登录状态",
|
package/src/menu.mjs
CHANGED
|
@@ -40,6 +40,15 @@ const AGENT_DESC = {
|
|
|
40
40
|
hermes: "Nous Research's general-purpose agent",
|
|
41
41
|
qwen: "Alibaba's terminal coding agent",
|
|
42
42
|
copilot: "GitHub's terminal coding agent",
|
|
43
|
+
gemini: "Google's Gemini CLI",
|
|
44
|
+
agy: "Google Antigravity CLI (agy)",
|
|
45
|
+
pi: "Pi coding agent (picode is a Pi package)",
|
|
46
|
+
crush: "Charmbracelet terminal coding agent",
|
|
47
|
+
minimax: "MiniMax's autonomous coding agent",
|
|
48
|
+
mimo: "Xiaomi's terminal coding agent with persistent memory",
|
|
49
|
+
openclaw: "Autonomous personal AI coding agent",
|
|
50
|
+
plandex: "Terminal AI coding engine for complex tasks",
|
|
51
|
+
interpreter: "Local code execution & pair programmer",
|
|
43
52
|
};
|
|
44
53
|
|
|
45
54
|
const autoInstallable = (r) => !/^https?:/.test(r.install); // URL이면 수동 설치 안내만
|
package/src/recipes.mjs
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { ROOT, V1 } from "./config.mjs";
|
|
2
2
|
|
|
3
|
-
// 도구별 설정의 진실 원천. 출처: frontend .../docs/cookbook/{codex,claude-code,...} + 에이전트별 공식
|
|
4
|
-
// type "env"
|
|
5
|
-
// type "codex-home"
|
|
3
|
+
// 도구별 설정의 진실 원천. 출처: frontend .../docs/cookbook/{codex,claude-code,...} + 에이전트별 공식 문서.
|
|
4
|
+
// type "env" → 환경변수만 세팅하고 바로 실행.
|
|
5
|
+
// type "codex-home" → 격리 CODEX_HOME에 config.toml (사용자 ~/.codex 보존).
|
|
6
|
+
// type "pi-home" → 격리 PI_CODING_AGENT_DIR에 models.json (사용자 ~/.pi 보존).
|
|
7
|
+
// type "crush-home" → 격리 CRUSH_GLOBAL_CONFIG 디렉터리에 crush.json (사용자 crush.json 보존).
|
|
8
|
+
// type "agy-settings" → ~/.gemini/antigravity-cli/settings.json 에 modelProvider=gemini 병합.
|
|
9
|
+
// Antigravity는 이 파일이 없으면 GEMINI_API_KEY를 무시한다. 격리 홈 env가 없다.
|
|
6
10
|
// note 필드는 t() 키(영어 원문)만 담는다 — 여기서 t()를 호출하면 모듈 로드 시점에 번역이
|
|
7
11
|
// 고정돼 같은 프로세스 안에서 언어를 바꿔도(Settings) 안내문이 갱신되지 않는다.
|
|
8
12
|
// 실제 번역은 소비 지점(launch.mjs)에서 매번 t()를 호출해 얻는다.
|
|
9
13
|
//
|
|
10
|
-
// 커스텀
|
|
11
|
-
//
|
|
12
|
-
//
|
|
14
|
+
// 커스텀 엔드포인트가 없어 PleumRouter로 라우팅할 수 없으면 등록하지 않는다:
|
|
15
|
+
// Cursor CLI · Amp · Factory Droid · Kiro(공식 BYOK 없음, aws/kiro#9367) ·
|
|
16
|
+
// Cline CLI(cline auth가 사용자 cred를 디스크에 고정).
|
|
13
17
|
export const RECIPES = {
|
|
14
18
|
claude: {
|
|
15
19
|
label: "Claude Code",
|
|
@@ -27,6 +31,8 @@ export const RECIPES = {
|
|
|
27
31
|
ANTHROPIC_BASE_URL: ROOT,
|
|
28
32
|
ANTHROPIC_API_KEY: key,
|
|
29
33
|
ANTHROPIC_AUTH_TOKEN: key,
|
|
34
|
+
// /model 이 GET {ANTHROPIC_BASE_URL}/v1/models 를 치게 한다. 기본값은 꺼져 있다.
|
|
35
|
+
CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY: "1",
|
|
30
36
|
}),
|
|
31
37
|
args: (m) => (m ? ["--model", `anthropic/${m}`] : []),
|
|
32
38
|
},
|
|
@@ -185,8 +191,151 @@ export const RECIPES = {
|
|
|
185
191
|
}),
|
|
186
192
|
args: (m) => (m ? ["--model", `google/${m}`] : []),
|
|
187
193
|
},
|
|
194
|
+
agy: {
|
|
195
|
+
label: "Antigravity CLI",
|
|
196
|
+
bin: "agy",
|
|
197
|
+
type: "agy-settings",
|
|
198
|
+
install: "https://antigravity.google/cli/install.sh",
|
|
199
|
+
note: "Writes modelProvider=gemini into ~/.gemini/antigravity-cli/settings.json. GEMINI_API_KEY alone is ignored. Gemini-family models only.",
|
|
200
|
+
attribution: {
|
|
201
|
+
title: "Antigravity CLI",
|
|
202
|
+
referer: "https://www.antigravity.google/docs/cli/install",
|
|
203
|
+
},
|
|
204
|
+
env: (key) => ({
|
|
205
|
+
GOOGLE_GEMINI_BASE_URL: ROOT,
|
|
206
|
+
GEMINI_API_KEY: key,
|
|
207
|
+
GOOGLE_API_KEY: key,
|
|
208
|
+
}),
|
|
209
|
+
args: (m) => (m ? ["--model", `google/${m}`] : []),
|
|
210
|
+
},
|
|
211
|
+
pi: {
|
|
212
|
+
label: "Pi",
|
|
213
|
+
bin: "pi",
|
|
214
|
+
type: "pi-home",
|
|
215
|
+
install: "npm i -g @mariozechner/pi-coding-agent",
|
|
216
|
+
note: "Uses an isolated ~/.pleum/pi-home (PI_CODING_AGENT_DIR). Your ~/.pi is untouched.",
|
|
217
|
+
attribution: {
|
|
218
|
+
title: "Pi",
|
|
219
|
+
referer: "https://pi.dev",
|
|
220
|
+
},
|
|
221
|
+
env: (key) => ({ PLEUM_API_KEY: key }),
|
|
222
|
+
args: (m) => ["--model", m || "gpt-5.4-mini"],
|
|
223
|
+
},
|
|
224
|
+
crush: {
|
|
225
|
+
label: "Crush",
|
|
226
|
+
bin: "crush",
|
|
227
|
+
type: "crush-home",
|
|
228
|
+
install: "npm install -g @charmland/crush",
|
|
229
|
+
note: "Uses an isolated ~/.pleum/crush-home (CRUSH_GLOBAL_CONFIG). Your crush.json is untouched.",
|
|
230
|
+
attribution: {
|
|
231
|
+
title: "Crush",
|
|
232
|
+
referer: "https://github.com/charmbracelet/crush",
|
|
233
|
+
},
|
|
234
|
+
env: (key) => ({ PLEUM_API_KEY: key }),
|
|
235
|
+
args: () => [],
|
|
236
|
+
},
|
|
237
|
+
minimax: {
|
|
238
|
+
label: "MiniMax Code",
|
|
239
|
+
bin: "mcode",
|
|
240
|
+
type: "env",
|
|
241
|
+
install: "npm install -g @minimax-ai/code@latest",
|
|
242
|
+
attribution: {
|
|
243
|
+
title: "MiniMax Code",
|
|
244
|
+
referer: "https://github.com/MiniMax-AI/minimax-code",
|
|
245
|
+
},
|
|
246
|
+
env: (key, model) => ({
|
|
247
|
+
OPENAI_BASE_URL: V1,
|
|
248
|
+
OPENAI_API_KEY: key,
|
|
249
|
+
...(model ? { OPENAI_MODEL: model } : {}),
|
|
250
|
+
}),
|
|
251
|
+
args: (m) => (m ? ["--model", m] : []),
|
|
252
|
+
},
|
|
253
|
+
mimo: {
|
|
254
|
+
label: "MiMo Code",
|
|
255
|
+
bin: "mimo",
|
|
256
|
+
type: "env",
|
|
257
|
+
install: "npm install -g @mimo-ai/cli",
|
|
258
|
+
attribution: {
|
|
259
|
+
title: "MiMo Code",
|
|
260
|
+
referer: "https://github.com/XiaomiMiMo/MiMo-Code",
|
|
261
|
+
},
|
|
262
|
+
env: (key, model) => ({
|
|
263
|
+
OPENAI_BASE_URL: V1,
|
|
264
|
+
OPENAI_API_KEY: key,
|
|
265
|
+
...(model ? { OPENAI_MODEL: model } : {}),
|
|
266
|
+
}),
|
|
267
|
+
args: (m) => (m ? ["--model", m] : []),
|
|
268
|
+
},
|
|
269
|
+
openclaw: {
|
|
270
|
+
label: "OpenClaw",
|
|
271
|
+
bin: "openclaw",
|
|
272
|
+
type: "env",
|
|
273
|
+
install: "npm install -g openclaw@latest",
|
|
274
|
+
attribution: {
|
|
275
|
+
title: "OpenClaw",
|
|
276
|
+
referer: "https://github.com/openclaw/openclaw",
|
|
277
|
+
},
|
|
278
|
+
env: (key, model) => ({
|
|
279
|
+
OPENAI_BASE_URL: V1,
|
|
280
|
+
OPENAI_API_KEY: key,
|
|
281
|
+
...(model ? { OPENAI_MODEL: model } : {}),
|
|
282
|
+
}),
|
|
283
|
+
args: (m) => (m ? ["--model", m] : []),
|
|
284
|
+
},
|
|
285
|
+
plandex: {
|
|
286
|
+
label: "Plandex",
|
|
287
|
+
bin: "plandex",
|
|
288
|
+
type: "env",
|
|
289
|
+
install: "curl -sL https://plandex.ai/install.sh | bash",
|
|
290
|
+
attribution: {
|
|
291
|
+
title: "Plandex",
|
|
292
|
+
referer: "https://github.com/plandex-ai/plandex",
|
|
293
|
+
},
|
|
294
|
+
env: (key) => ({
|
|
295
|
+
OPENAI_API_BASE: V1,
|
|
296
|
+
OPENAI_API_KEY: key,
|
|
297
|
+
}),
|
|
298
|
+
args: () => [],
|
|
299
|
+
},
|
|
300
|
+
interpreter: {
|
|
301
|
+
label: "Open Interpreter",
|
|
302
|
+
bin: "interpreter",
|
|
303
|
+
type: "env",
|
|
304
|
+
install: "pip install open-interpreter",
|
|
305
|
+
attribution: {
|
|
306
|
+
title: "Open Interpreter",
|
|
307
|
+
referer: "https://github.com/OpenInterpreter/open-interpreter",
|
|
308
|
+
},
|
|
309
|
+
env: (key) => ({
|
|
310
|
+
OPENAI_API_BASE: V1,
|
|
311
|
+
OPENAI_API_KEY: key,
|
|
312
|
+
}),
|
|
313
|
+
args: (m) => (m ? ["--model", `openai/${m}`] : []),
|
|
314
|
+
},
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
export const LAUNCH_ALIASES = {
|
|
318
|
+
antigravity: "agy",
|
|
319
|
+
picode: "pi",
|
|
320
|
+
ohmypi: "omp",
|
|
321
|
+
"oh-my-pi": "omp",
|
|
322
|
+
qwencode: "qwen",
|
|
323
|
+
"qwen-code": "qwen",
|
|
324
|
+
"minimax-code": "minimax",
|
|
325
|
+
mcode: "minimax",
|
|
326
|
+
mimocode: "mimo",
|
|
327
|
+
"mimo-code": "mimo",
|
|
328
|
+
"open-interpreter": "interpreter",
|
|
188
329
|
};
|
|
189
330
|
|
|
331
|
+
export function resolveLaunchTool(name) {
|
|
332
|
+
return LAUNCH_ALIASES[name] ?? name;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
export function launchToolNames() {
|
|
336
|
+
return [...Object.keys(RECIPES), ...Object.keys(MANUAL), ...Object.keys(LAUNCH_ALIASES)];
|
|
337
|
+
}
|
|
338
|
+
|
|
190
339
|
// Codex는 Chat Completions가 제거돼 Responses API(wire_api="responses")만 지원.
|
|
191
340
|
// 사용자의 ~/.codex/config.toml을 건드리지 않도록 격리 CODEX_HOME에 이 파일을 쓴다.
|
|
192
341
|
// TOML basic string encoder. 모델명과 base_url은 CLI/env에서 오므로, 따옴표·개행이
|
|
@@ -222,22 +371,45 @@ supports_websockets = false
|
|
|
222
371
|
`;
|
|
223
372
|
}
|
|
224
373
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
file: "crush.json",
|
|
232
|
-
snippet: () => `{
|
|
233
|
-
"providers": {
|
|
234
|
-
"pleum": {
|
|
235
|
-
"type": "openai-compat",
|
|
236
|
-
"base_url": "${V1}",
|
|
237
|
-
"api_key": "$PLEUM_API_KEY",
|
|
238
|
-
"models": [{ "id": "gpt-5.4-mini", "name": "gpt-5.4-mini" }]
|
|
374
|
+
export function mergeAgySettings(existingJson) {
|
|
375
|
+
let obj = {};
|
|
376
|
+
if (existingJson && String(existingJson).trim()) {
|
|
377
|
+
obj = JSON.parse(existingJson);
|
|
378
|
+
if (obj === null || typeof obj !== "object" || Array.isArray(obj)) {
|
|
379
|
+
throw new Error("agy settings.json must be a JSON object");
|
|
239
380
|
}
|
|
240
381
|
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
|
|
382
|
+
return { ...obj, modelProvider: "gemini" };
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
export function piModelsJson(model) {
|
|
386
|
+
const m = model || "gpt-5.4-mini";
|
|
387
|
+
return `${JSON.stringify({
|
|
388
|
+
providers: {
|
|
389
|
+
pleum: {
|
|
390
|
+
baseUrl: V1,
|
|
391
|
+
api: "openai-completions",
|
|
392
|
+
apiKey: "$PLEUM_API_KEY",
|
|
393
|
+
models: [{ id: m }],
|
|
394
|
+
},
|
|
395
|
+
},
|
|
396
|
+
}, null, 2)}\n`;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
export function crushJson(model) {
|
|
400
|
+
const m = model || "gpt-5.4-mini";
|
|
401
|
+
return `${JSON.stringify({
|
|
402
|
+
providers: {
|
|
403
|
+
pleum: {
|
|
404
|
+
type: "openai-compat",
|
|
405
|
+
base_url: V1,
|
|
406
|
+
api_key: "$PLEUM_API_KEY",
|
|
407
|
+
models: [{ id: m, name: m }],
|
|
408
|
+
},
|
|
409
|
+
},
|
|
410
|
+
}, null, 2)}\n`;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// provider 정의가 파일에 있어야 자동 실행이 안 되는 도구. crush는 격리 CRUSH_GLOBAL_CONFIG로
|
|
414
|
+
// RECIPES로 올렸으니 지금은 비어 있다 — 스니펫-only 도구가 다시 생기면 여기 넣는다.
|
|
415
|
+
export const MANUAL = {};
|
package/src/wire.mjs
CHANGED
|
@@ -10,7 +10,12 @@ export const WIRE_KEY_NAME = "pleum-desktop";
|
|
|
10
10
|
export const WIRE_MARKER_START = "# pleum-wire-start";
|
|
11
11
|
export const WIRE_MARKER_END = "# pleum-wire-end";
|
|
12
12
|
|
|
13
|
-
const CLAUDE_ENV_KEYS = [
|
|
13
|
+
const CLAUDE_ENV_KEYS = [
|
|
14
|
+
"ANTHROPIC_BASE_URL",
|
|
15
|
+
"ANTHROPIC_AUTH_TOKEN",
|
|
16
|
+
"ANTHROPIC_API_KEY",
|
|
17
|
+
"CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY",
|
|
18
|
+
];
|
|
14
19
|
|
|
15
20
|
export function wirePaths(home = homedir()) {
|
|
16
21
|
const claude = join(home, ".claude", "settings.json");
|
|
@@ -81,6 +86,7 @@ export function wireClaudeSettings(existingJson, { root, key }) {
|
|
|
81
86
|
ANTHROPIC_BASE_URL: root,
|
|
82
87
|
ANTHROPIC_AUTH_TOKEN: key,
|
|
83
88
|
ANTHROPIC_API_KEY: key,
|
|
89
|
+
CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY: "1",
|
|
84
90
|
};
|
|
85
91
|
return `${JSON.stringify(obj, null, 2)}\n`;
|
|
86
92
|
}
|