pleumrouter 0.2.0 → 0.2.2

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/LICENSE ADDED
@@ -0,0 +1,133 @@
1
+ PolyForm Noncommercial License 1.0.0
2
+
3
+ <https://polyformproject.org/licenses/noncommercial/1.0.0>
4
+
5
+ Acceptance
6
+
7
+ In order to get any license under these terms, you must agree
8
+ to them as both strict obligations and conditions to all
9
+ your licenses.
10
+
11
+ Copyright License
12
+
13
+ The licensor grants you a copyright license for the
14
+ software to do everything you might do with the software
15
+ that would otherwise infringe the licensor's copyright
16
+ in it for any permitted purpose. However, you may only
17
+ distribute the software according to Distribution License
18
+ and make changes or new works based on the software
19
+ according to Changes and New Works License.
20
+
21
+ Distribution License
22
+
23
+ The licensor grants you an additional copyright license
24
+ to distribute copies of the software. Your license to
25
+ distribute covers distributing the software with changes
26
+ and new works permitted by Changes and New Works License.
27
+
28
+ Notices
29
+
30
+ You must ensure that anyone who gets a copy of any part of
31
+ the software from you also gets a copy of these terms or the
32
+ URL for them above, as well as copies of any plain-text lines
33
+ beginning with Required Notice: that the licensor provided
34
+ with the software. For example:
35
+
36
+ Required Notice: Copyright 2026 Lee Wonyoung (https://github.com/gachon-star-want/PleumRouter)
37
+
38
+ Changes and New Works License
39
+
40
+ The licensor grants you an additional copyright license to
41
+ make changes and new works based on the software for any
42
+ permitted purpose.
43
+
44
+ Patent License
45
+
46
+ The licensor grants you a patent license for the software
47
+ that covers patent claims the licensor can license, or will
48
+ be able to license, that you would infringe by using the
49
+ software.
50
+
51
+ Noncommercial Purposes
52
+
53
+ Any noncommercial purpose is a permitted purpose.
54
+
55
+ Personal Uses
56
+
57
+ Personal use for research, experiment, and testing for
58
+ the benefit of public knowledge, personal study, private
59
+ entertainment, hobby projects, amateur pursuits, or
60
+ religious observance, without any anticipated commercial
61
+ application, is use for a permitted purpose.
62
+
63
+ Noncommercial Organizations
64
+
65
+ Use by any charitable organization, educational institution,
66
+ public research organization, public safety or health
67
+ organization, environmental protection organization,
68
+ or government institution is use for a permitted purpose
69
+ regardless of the source of funding or obligations resulting
70
+ from the funding.
71
+
72
+ Fair Use
73
+
74
+ You may have "fair use" rights for the software under the
75
+ law. These terms do not limit them.
76
+
77
+ No Other Rights
78
+
79
+ These terms do not allow you to sublicense or transfer any of
80
+ your licenses to anyone else, or prevent the licensor from
81
+ granting licenses to anyone else. These terms do not imply
82
+ any other licenses.
83
+
84
+ Patent Defense
85
+
86
+ If you make any written claim that the software infringes or
87
+ contributes to infringement of any patent, your patent license
88
+ for the software granted under these terms ends immediately. If
89
+ your employer makes such a claim, your patent license ends
90
+ immediately for work on behalf of your employer.
91
+
92
+ Violations
93
+
94
+ The first time you are notified in writing that you have
95
+ violated any of these terms, or done anything with the software
96
+ not covered by your licenses, your licenses can nonetheless
97
+ continue if you come into compliance within 32 days after
98
+ receiving notice. Otherwise, all your licenses end permanently.
99
+
100
+ No Liability
101
+
102
+ As far as the law allows, the software comes as is, without
103
+ any warranty or condition, and the licensor will not be liable
104
+ to you for any damages arising out of these terms or the use
105
+ or nature of the software, under any kind of legal claim.
106
+
107
+ Definitions
108
+
109
+ The licensor is the individual or entity offering these
110
+ terms, and the software is the software the licensor makes
111
+ available under these terms.
112
+
113
+ You refers to the individual or entity agreeing to these
114
+ terms.
115
+
116
+ Your company is any legal entity, sole proprietorship,
117
+ or other kind of organization that you work for, plus all
118
+ organizations that have control over, are under the control of,
119
+ or are under common control with that organization. Control
120
+ means ownership of substantially all the assets of an entity,
121
+ or the power to direct its management and legal affairs.
122
+
123
+ Your licenses are all the licenses granted to you for the
124
+ software under these terms.
125
+
126
+ Use means anything you do with the software requiring one
127
+ of your licenses.
128
+
129
+ Trademark
130
+
131
+ The PolyForm Noncommercial License 1.0.0 does not grant
132
+ any rights to use the licensor's trademarks, trade names,
133
+ or logos.
package/README.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  PleumRouter 공식 터미널 CLI. 쓰던 코딩 에이전트를 한 줄로 PleumRouter에 붙여 실행한다.
4
4
 
5
+ ## 설치
6
+
7
+ Node.js 18 이상 필요(순수 Node CLI라 별도 바이너리 없음).
8
+
9
+ ```bash
10
+ curl -fsSL https://router.pleum.ai/install | sh # 원라이너(npm 전역 설치를 감쌈)
11
+ npm install -g pleumrouter # npm
12
+ bun install -g pleumrouter # bun
13
+ ```
14
+
15
+ 설치 없이 `npx pleumrouter <명령>` 으로 바로 실행할 수도 있다.
16
+
17
+ ## 빠른 시작
18
+
5
19
  ```bash
6
20
  npx pleumrouter login # 브라우저 로그인 + 키 자동 저장
7
21
  npx pleumrouter launch claude --model claude-sonnet-4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pleumrouter",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Official PleumRouter terminal CLI — launch any coding agent against PleumRouter.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -12,12 +12,13 @@
12
12
  "files": [
13
13
  "bin",
14
14
  "src",
15
- "README.md"
15
+ "README.md",
16
+ "LICENSE"
16
17
  ],
17
18
  "scripts": {
18
19
  "test": "node --test"
19
20
  },
20
- "license": "MIT",
21
+ "license": "PolyForm-Noncommercial-1.0.0",
21
22
  "publishConfig": {
22
23
  "access": "public"
23
24
  },
package/src/config.mjs CHANGED
@@ -3,7 +3,9 @@ import { join } from "node:path";
3
3
  import { readFileSync, writeFileSync, mkdirSync, rmSync } from "node:fs";
4
4
 
5
5
  // 공개 게이트웨이 루트. 셀프호스트/스테이징은 PLEUM_BASE_URL로 덮어쓴다.
6
- export const ROOT = (process.env.PLEUM_BASE_URL ?? "https://router.pleum.ai").replace(/\/+$/, "");
6
+ export const ROOT = (process.env.PLEUM_BASE_URL ?? "https://router.pleum.ai")
7
+ .replace(/\/+$/, "")
8
+ .replace(/\/v1$/, ""); // 사용자가 실수로 /v1까지 붙여도 V1이 /v1/v1 이중 경로가 되지 않게 정리(L12)
7
9
  // OpenAI 호환 엔드포인트는 /v1. (Claude Code만 루트를 쓴다 — recipes 참고)
8
10
  export const V1 = `${ROOT}/v1`;
9
11
 
package/src/launch.mjs CHANGED
@@ -50,7 +50,7 @@ export async function launch(tool, model, passthrough) {
50
50
  // Codex는 격리 CODEX_HOME에 config.toml을 써서 사용자 ~/.codex를 보존한다.
51
51
  if (r.type === "codex-home") {
52
52
  const home = join(homedir(), ".pleum", "codex-home");
53
- mkdirSync(home, { recursive: true });
53
+ mkdirSync(home, { recursive: true, mode: 0o700 }); // 사용자 데이터 디렉토리 권한 제한(L11)
54
54
  writeFileSync(join(home, "config.toml"), codexToml(model), { mode: 0o600 });
55
55
  env.CODEX_HOME = home;
56
56
  }
package/src/run.mjs CHANGED
@@ -52,6 +52,11 @@ export async function run(rest) {
52
52
  const key = requireKey();
53
53
 
54
54
  if (!model && !oneShot) {
55
+ if (!process.stdin.isTTY) {
56
+ // 비대화형(non-TTY) stdin이면 인터랙티브 모델 선택이 멈춰버리므로 명확히 안내하고 종료(L10).
57
+ console.error('모델을 지정하세요: pleum run <model> ["프롬프트"] (비대화형 stdin에선 모델 선택 불가)');
58
+ process.exit(1);
59
+ }
55
60
  model = await pickModel(); // 인터랙티브 모델 선택
56
61
  if (!model) process.exit(1);
57
62
  }
@@ -62,7 +67,13 @@ export async function run(rest) {
62
67
 
63
68
  if (oneShot) {
64
69
  const prompt = [inlinePrompt, piped].filter(Boolean).join("\n\n");
65
- const messages = [{ role: "user", content: buildContent(prompt) }];
70
+ const content = buildContent(prompt);
71
+ if (Array.isArray(content)) {
72
+ const n = content.filter((p) => p.type === "image_url").length;
73
+ // 프롬프트 내 로컬 이미지 경로를 자동 첨부·업로드하므로 조용히 올리지 않고 명시 고지한다(M8).
74
+ console.error(`ℹ 프롬프트의 로컬 이미지 ${n}개를 첨부해 업로드합니다.`);
75
+ }
76
+ const messages = [{ role: "user", content }];
66
77
  try {
67
78
  await streamChat(key, model, messages, { verbose, quiet: true });
68
79
  } catch (e) {