pleumrouter 0.5.14 → 0.5.16
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 +13 -1
- package/package.json +1 -1
- package/src/balance.mjs +1 -1
- package/src/config.mjs +8 -1
- package/src/login.mjs +2 -2
- package/src/models.mjs +1 -1
- package/src/run.mjs +1 -1
- package/src/usage.mjs +1 -1
package/README.md
CHANGED
|
@@ -80,7 +80,7 @@ env(또는 격리된 `CODEX_HOME`/임시 설정 문자열)만 세팅하고 바
|
|
|
80
80
|
|
|
81
81
|
## 환경변수
|
|
82
82
|
|
|
83
|
-
- `PLEUM_BASE_URL` — 게이트웨이 루트 덮어쓰기(기본 `https://router.pleum.ai`). 셀프호스트/스테이징용.
|
|
83
|
+
- `PLEUM_BASE_URL` — 게이트웨이 루트 덮어쓰기(API 호출용 기본 `https://apirouter.pleum.ai`, 브라우저 로그인 URL용 기본 `https://router.pleum.ai` 둘 다에 적용됨). 셀프호스트/스테이징용.
|
|
84
84
|
|
|
85
85
|
## 개발
|
|
86
86
|
|
|
@@ -88,3 +88,15 @@ env(또는 격리된 `CODEX_HOME`/임시 설정 문자열)만 세팅하고 바
|
|
|
88
88
|
npm test # node --test (의존성 0)
|
|
89
89
|
npm link # 로컬에서 pleum 명령 노출
|
|
90
90
|
```
|
|
91
|
+
|
|
92
|
+
## npm 게시 (운영)
|
|
93
|
+
|
|
94
|
+
정상 경로는 **태그 → GitHub Actions** (`.github/workflows/publish-cli.yml`).
|
|
95
|
+
|
|
96
|
+
1. `npm version patch` (또는 minor/major)로 `package.json` bump 후 커밋.
|
|
97
|
+
2. `git tag cli-v$(node -p "require('./package.json').version")` → `git push origin HEAD --tags`.
|
|
98
|
+
3. 워크플로가 `secrets.NPM_TOKEN`으로 `npm publish --provenance` 실행.
|
|
99
|
+
|
|
100
|
+
태그 규칙: `cli-v{semver}` (예: `cli-v0.5.15`).
|
|
101
|
+
|
|
102
|
+
로컬 `npm publish`는 GHA/SAS 불가 시 **비상만**. 토큰 유출 시 npm에서 즉시 Revoke.
|
package/package.json
CHANGED
package/src/balance.mjs
CHANGED
|
@@ -10,5 +10,5 @@ export async function balance() {
|
|
|
10
10
|
const data = await res.json();
|
|
11
11
|
const plm = data.balance_krw;
|
|
12
12
|
const usd = data.balance_usd != null ? ` / $${data.balance_usd.toFixed(4)}` : "";
|
|
13
|
-
console.log(`잔액:
|
|
13
|
+
console.log(`잔액: ${plm.toLocaleString("ko-KR")} 크레딧${usd}`);
|
|
14
14
|
}
|
package/src/config.mjs
CHANGED
|
@@ -6,11 +6,18 @@ import { t } from "./i18n.mjs";
|
|
|
6
6
|
// 공개 게이트웨이 루트(canonical API). /v1/* 를 Next.js Route Handler 가 프록시하는
|
|
7
7
|
// router.pleum.ai 와 달리, 이 도메인은 백엔드에 직접 붙는다 — /v1beta/* (Gemini native)
|
|
8
8
|
// 경로도 라우팅된다. 셀프호스트/스테이징은 PLEUM_BASE_URL로 덮어쓴다.
|
|
9
|
-
|
|
9
|
+
const overrideBase = process.env.PLEUM_BASE_URL;
|
|
10
|
+
export const ROOT = (overrideBase ?? "https://apirouter.pleum.ai")
|
|
10
11
|
.replace(/\/+$/, "")
|
|
11
12
|
.replace(/\/v1$/, ""); // 사용자가 실수로 /v1까지 붙여도 V1이 /v1/v1 이중 경로가 되지 않게 정리(L12)
|
|
12
13
|
// OpenAI 호환 엔드포인트는 /v1. (Claude Code만 루트를 쓴다 — recipes 참고)
|
|
13
14
|
export const V1 = `${ROOT}/v1`;
|
|
15
|
+
// 브라우저가 여는 /cli-auth 는 Next.js 프론트 도메인에만 존재한다 — API 도메인(ROOT)과 분리해야
|
|
16
|
+
// 한다(과거 ROOT를 공유해서 쓰다가 apirouter로 기본값이 바뀌며 로그인이 깨진 적 있음).
|
|
17
|
+
// 셀프호스트(PLEUM_BASE_URL 지정)는 같은 도메인이 프론트도 서빙한다고 가정해 ROOT를 재사용한다.
|
|
18
|
+
export const SITE_ROOT = (overrideBase ?? "https://router.pleum.ai")
|
|
19
|
+
.replace(/\/+$/, "")
|
|
20
|
+
.replace(/\/v1$/, "");
|
|
14
21
|
|
|
15
22
|
const DIR = join(homedir(), ".pleum");
|
|
16
23
|
const FILE = join(DIR, "config.json");
|
package/src/login.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createServer } from "node:http";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
|
-
import { ROOT, V1, readConfig, writeConfig, mergeLoginConfig } from "./config.mjs";
|
|
4
|
+
import { ROOT, SITE_ROOT, V1, readConfig, writeConfig, mergeLoginConfig } from "./config.mjs";
|
|
5
5
|
import { t } from "./i18n.mjs";
|
|
6
6
|
import { sanitizeTerminalText } from "./ansi.mjs";
|
|
7
7
|
|
|
@@ -92,7 +92,7 @@ export async function login() {
|
|
|
92
92
|
server.on("error", reject);
|
|
93
93
|
server.listen(0, "127.0.0.1", () => {
|
|
94
94
|
const { port } = server.address();
|
|
95
|
-
const authUrl = `${
|
|
95
|
+
const authUrl = `${SITE_ROOT}/cli-auth?port=${port}&state=${state}`;
|
|
96
96
|
console.log(`${t("Log in from your browser. If it doesn't open automatically, open this URL:")}\n ${sanitizeTerminalText(authUrl)}\n`);
|
|
97
97
|
openBrowser(authUrl);
|
|
98
98
|
});
|
package/src/models.mjs
CHANGED
|
@@ -45,7 +45,7 @@ export function fmtPrice(model) {
|
|
|
45
45
|
if (v == null) return "—";
|
|
46
46
|
const n = Number(v) * 1_000_000;
|
|
47
47
|
if (!Number.isFinite(n)) return "—";
|
|
48
|
-
return sym === "₩" ?
|
|
48
|
+
return sym === "₩" ? `${Math.round(n).toLocaleString("en-US")} 크레딧` : `$${n.toFixed(2)}`;
|
|
49
49
|
};
|
|
50
50
|
const kr = model.pricing_krw || {};
|
|
51
51
|
if (kr.prompt != null || kr.completion != null) return [per1m(kr.prompt, "₩"), per1m(kr.completion, "₩")];
|
package/src/run.mjs
CHANGED
|
@@ -165,7 +165,7 @@ export function buildContent(text, { attachments = [], lstat = lstatSync, read =
|
|
|
165
165
|
// 응답 후 한 줄 통계(순수 함수 — 테스트 대상). verbose일 때만 토큰/속도 표시.
|
|
166
166
|
export function formatStats({ cost, usage, ms, tokPerSec, verbose }) {
|
|
167
167
|
const bits = [];
|
|
168
|
-
if (cost != null && cost !== "") bits.push(
|
|
168
|
+
if (cost != null && cost !== "") bits.push(`${fmtCost(cost)} 크레딧`);
|
|
169
169
|
if (verbose && usage) {
|
|
170
170
|
bits.push(`↑${sanitizeTerminalText(usage.prompt_tokens ?? "?")} ↓${sanitizeTerminalText(usage.completion_tokens ?? "?")} tok`);
|
|
171
171
|
if (tokPerSec) bits.push(`${tokPerSec.toFixed(1)} tok/s`);
|
package/src/usage.mjs
CHANGED
|
@@ -19,7 +19,7 @@ export function parseUsageArgs(rest = []) {
|
|
|
19
19
|
return { by, days };
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
const fmtKrw = (n) =>
|
|
22
|
+
const fmtKrw = (n) => `${Math.round(n).toLocaleString("en-US")} 크레딧`;
|
|
23
23
|
|
|
24
24
|
// report 응답 → 표시 문자열(순수 함수 — fixture 테스트 대상).
|
|
25
25
|
export function renderUsage(data, styler = style) {
|