codexmu 0.1.0
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 +21 -0
- package/README.ko.md +233 -0
- package/README.md +233 -0
- package/bin/codexmu.mjs +24 -0
- package/docs/terminal-preview.png +0 -0
- package/package.json +40 -0
- package/vendor/darwin-arm64/codexmu +0 -0
- package/vendor/darwin-x64/codexmu +0 -0
- package/vendor/linux-arm64/codexmu +0 -0
- package/vendor/linux-x64/codexmu +0 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 codexmu contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.ko.md
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# codexmu
|
|
2
|
+
|
|
3
|
+
[English](README.md) | **한국어**
|
|
4
|
+
|
|
5
|
+
Codex의 여러 ChatGPT 계정을 저장하고, 사용 한도에 도달하면 사용 가능한 계정으로 자동 전환하는 Rust 프로그램입니다.
|
|
6
|
+
|
|
7
|
+
**`codex-auth`, `codext`, Zig가 필요하지 않습니다.** 인증 파일 관리, OAuth 갱신, 사용량 조회, 전환 판단을 Rust에서 직접 처리합니다. 로그인과 터미널·데스크톱 연결에는 **공식 Codex** 실행 파일을 사용합니다. npm 설치는 Node.js를 실행 진입점으로 사용하며, Cargo 설치는 Node.js도 필요하지 않습니다.
|
|
8
|
+
|
|
9
|
+
## 설치
|
|
10
|
+
|
|
11
|
+
### npm
|
|
12
|
+
|
|
13
|
+
Node.js **24 이상**과 공식 Codex가 필요합니다. npm 패키지는 macOS / Linux의 ARM64·x64 실행 파일을 포함하며, 설치 시 Rust 빌드나 별도 바이너리 다운로드를 하지 않습니다.
|
|
14
|
+
|
|
15
|
+
공개 npm 배포 후에는 다음 명령으로 설치합니다. **현재 저장소에 배포 구성을 추가한 상태이며, 공개 레지스트리 게시 여부는 별도로 확인해야 합니다.**
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npm install -g codexmu
|
|
19
|
+
codexmu
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
로컬에서 만든 패키지는 바로 설치할 수 있습니다. 로컬 빌드는 현재 플랫폼용 실행 파일만 포함합니다.
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
# 저장소에서 실행; 이 빌드 단계에는 Rust 필요
|
|
26
|
+
npm run build
|
|
27
|
+
mkdir -p dist
|
|
28
|
+
npm pack --pack-destination dist
|
|
29
|
+
npm install -g ./dist/codexmu-0.1.0.tgz
|
|
30
|
+
codexmu --version
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
기존 Cargo 설치가 있다면 `command -v codexmu`로 PATH에서 어떤 설치가 선택되는지 확인하세요.
|
|
34
|
+
|
|
35
|
+
### Cargo
|
|
36
|
+
|
|
37
|
+
Rust 1.89 이상과 공식 Codex가 필요합니다. 터미널 모드는 macOS / Linux, 데스크톱 앱 실행은 macOS에서 지원합니다. 공식 Codex는 `--remote unix://...`를 지원해야 하며, 기존 검증 버전은 CLI 0.153.4입니다.
|
|
38
|
+
|
|
39
|
+
소스를 내려받은 프로젝트 디렉터리에서 실행하세요.
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
cargo install --path . --locked
|
|
43
|
+
codexmu --help
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Cargo가 PATH에 없다면 먼저 `source "$HOME/.cargo/env"`를 실행하세요. 설치 없이 `cargo build --release` 후 `./target/release/codexmu`를 실행해도 됩니다.
|
|
47
|
+
|
|
48
|
+
## 계정 등록과 실행
|
|
49
|
+
|
|
50
|
+
**계정은 2개, 3개 이상 등록할 수 있으며 프로그램에 개수 제한은 없습니다.** 현재 Codex에 로그인된 계정을 저장하고, 추가 계정마다 다른 이름으로 로그인하세요.
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
codexmu add personal
|
|
54
|
+
codexmu login work --device-auth
|
|
55
|
+
codexmu login extra --device-auth
|
|
56
|
+
codexmu switch personal
|
|
57
|
+
codexmu list --live
|
|
58
|
+
codexmu
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
등록된 모든 계정이 자동 전환 후보가 됩니다. 예를 들어 `personal`과 `work`가 차례로 한도에 걸리면 사용 가능한 `extra`로 전환해 같은 대화를 이어갑니다. 전환 순서는 등록 순서가 아니라 남은 사용량에 따라 결정합니다.
|
|
62
|
+
|
|
63
|
+
`login`은 임시 `CODEX_HOME`에서 공식 `codex login`을 실행합니다. 로그인 취소·실패 시 기존 활성 계정은 그대로 유지됩니다. 브라우저 로그인을 쓰려면 `--device-auth`를 생략하세요. 키체인에만 저장되어 `auth.json`이 없다면 `add` 대신 `login`을 사용하세요.
|
|
64
|
+
|
|
65
|
+
이미 저장한 **표준 Codex auth.json**도 가져올 수 있습니다.
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
codexmu add work --auth-file /path/to/work-auth.json
|
|
69
|
+
codexmu remove unused
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
같은 계정의 중복 등록, 이름 덮어쓰기, 활성 계정 삭제는 거부합니다. 계정 이름은 영문·숫자·`-`·`_`로 1~64자입니다. API 키 계정은 자동 과금 전환을 하지 않도록 지원 대상에서 제외했습니다.
|
|
73
|
+
|
|
74
|
+
## Codex 터미널 — macOS / Linux
|
|
75
|
+
|
|
76
|
+
계정을 등록한 뒤 **`codexmu`만 실행하면 공식 Codex 터미널 화면으로 바로 들어갑니다.** 한도 오류가 발생하면 다른 등록 계정으로 전환하고 같은 대화에서 작업을 자동으로 이어갑니다.
|
|
77
|
+
|
|
78
|
+
`codext`의 미리보기처럼 입력창 바로 위에 색상 상태 헤더를 표시합니다.
|
|
79
|
+
|
|
80
|
+

|
|
81
|
+
|
|
82
|
+
위 이미지는 로컬 가짜 계정으로 검증한 실제 PTY 출력을 터미널 에뮬레이터에서 재생한 모습입니다.
|
|
83
|
+
|
|
84
|
+
```text
|
|
85
|
+
codexmu │ gpt-5.1 medium │ …/codexmu │ main +2 │ 5h 85% · 0h42m │ user@example.com (plus)
|
|
86
|
+
|
|
87
|
+
› 프로젝트를 설명해 줘
|
|
88
|
+
Context 100% left · Fast off · 5h 85% · weekly 58% · 0.153.4
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
표시되는 값은 현재 세션의 모델·추론 강도·작업 경로, Git 브랜치와 변경 수, 실제 조회한 남은 사용량, 활성 계정의 이메일·플랜입니다. 헤더의 시간은 한도 초기화까지 남은 시간입니다. 계정 전환이 서버에서 승인되면 헤더도 새 계정으로 바뀌고 전환 알림을 잠시 표시합니다. 조회되지 않은 한도는 `—`로 표시하며, 좁은 창에서는 경로·Git 표시를 줄입니다. 배경·글꼴은 사용하는 터미널 설정을 따릅니다.
|
|
92
|
+
|
|
93
|
+
```sh
|
|
94
|
+
codexmu
|
|
95
|
+
codexmu "이 프로젝트를 설명해 줘"
|
|
96
|
+
codexmu run -- --model gpt-5.1
|
|
97
|
+
codexmu run -- resume --last
|
|
98
|
+
|
|
99
|
+
# 상태 헤더 없이 원래 공식 Codex 화면 사용
|
|
100
|
+
codexmu --plain
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**같은 `CODEX_HOME`에서 여러 `codexmu` 창을 동시에 실행할 수 있습니다.** 각 터미널에서 `codexmu`를 실행하면 됩니다. 계정 목록과 기본 활성 계정은 공유하고, 대화·승인·실행 중인 인증은 각 창의 공식 Codex 서버가 관리합니다. 다른 창에서 계정이 바뀌면 각 창은 실행 중인 턴이 끝난 뒤 사용량 확인 시 새 계정을 적용합니다. 한도 오류가 난 창은 바로 전환을 시도합니다.
|
|
104
|
+
|
|
105
|
+
계정 저장소 접근·사용량 조회·OAuth 갱신은 저장소 잠금으로 직렬화합니다. 여러 창이 같은 토큰을 갱신하려고 하면 먼저 갱신된 토큰을 재사용하며, 다른 계정으로 작업 중인 창의 인증을 덮어쓰지 않습니다. 잠금은 세션 전체를 점유하지 않습니다.
|
|
106
|
+
|
|
107
|
+
새 홈에서 공식 Codex의 SQLite 초기화가 충돌하지 않도록 서버 시작부터 초기화 응답까지는 별도 시작 잠금으로 순서를 맞춥니다. 초기화 응답을 받으면 즉시 해제하여 여러 세션이 함께 작업할 수 있습니다.
|
|
108
|
+
|
|
109
|
+
공식 Codex의 `--remote unix://...` 기능을 이용합니다. 이 기능을 지원하는 Codex가 필요하며 CLI 0.153.4에서 검증했습니다. 임시 전용 Unix 소켓으로 기존 터미널 UI와 인증 전환 브리지를 연결하고, PTY 화면에 상태 헤더를 합성합니다. 종료 시 소켓을 제거하고 터미널 설정을 복구합니다. TCP 포트를 열지 않습니다. 긴 대화는 공식 Codex의 `Ctrl+T` 화면에서 확인할 수 있습니다. 터미널 고유의 키보드·스크롤 동작이 필요하면 `--plain`을 사용하세요.
|
|
110
|
+
|
|
111
|
+
Codex 옵션은 `run --` 뒤에 전달하면 관리 명령·옵션과 혼동하지 않습니다. `--remote` 연결 주소는 codexmu가 관리합니다. 자동 재개를 끄려면 `codexmu --no-resume`을 실행하세요.
|
|
112
|
+
|
|
113
|
+
## Codex 데스크톱 앱 — macOS
|
|
114
|
+
|
|
115
|
+
**실행 중인 Codex 앱을 종료한 다음** 실행하세요.
|
|
116
|
+
|
|
117
|
+
```sh
|
|
118
|
+
codexmu app
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
공식 CLI 경로를 지정하려면:
|
|
122
|
+
|
|
123
|
+
```sh
|
|
124
|
+
codexmu --codex-bin /absolute/path/to/codex app
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
`app`은 macOS `open --env`로 `CODEX_CLI_PATH`를 이 바이너리로 설정합니다. 앱이 시작한 `codexmu`는 공식 `codex app-server`와 앱 사이에서 JSON-RPC를 전달합니다. 앱 설치 파일이나 전역 설정을 수정하지 않습니다. 이미 실행 중인 앱에는 환경변수가 적용되지 않으므로 실행을 거부하고 종료 후 재실행을 안내합니다.
|
|
128
|
+
|
|
129
|
+
터미널과 데스크톱은 같은 전환 동작을 사용합니다.
|
|
130
|
+
|
|
131
|
+
- 기본 60초마다 **턴이 실행 중이지 않을 때** 사용량을 조회합니다.
|
|
132
|
+
- `usageLimitExceeded`로 턴이 끝나면 다음 주기를 기다리지 않고 다른 계정을 찾습니다.
|
|
133
|
+
- 사용 가능한 계정 중 응답에 포함된 사용량 창의 최대 사용률이 가장 낮은 계정을 선택합니다.
|
|
134
|
+
- 새 인증은 `account/login/start`로 실행 중인 공식 app-server에 전달합니다. 파일만 교체하고 끝내지 않습니다.
|
|
135
|
+
- 기본적으로 같은 스레드에 계속 진행하라는 새 턴을 보냅니다. 원래 프롬프트나 실행한 도구 호출을 재전송하지 않습니다.
|
|
136
|
+
- 다른 턴이 실행 중이면 전환을 미룹니다. 전환 중 들어온 새 턴은 잠시 대기하고, 승인 응답은 계속 전달합니다. 취소된 대기 턴은 실행하지 않습니다.
|
|
137
|
+
|
|
138
|
+
자동 재개 없이 계정만 전환하려면:
|
|
139
|
+
|
|
140
|
+
```sh
|
|
141
|
+
codexmu --no-resume app
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
같은 실패의 자동 복구는 계정별 한 번으로 제한합니다. 전체 계정이 소진되면 재시도 루프를 만들지 않고 사용량 감시를 계속합니다. 이후 계정이 복구되면 다시 계속 진행하라고 입력할 수 있습니다. 일반 네트워크 오류, 서버 과부하, 모델 출력에 포함된 “limit” 문자열만으로 계정을 바꾸지 않습니다.
|
|
145
|
+
|
|
146
|
+
## 독립 감시와 다른 클라이언트 연결
|
|
147
|
+
|
|
148
|
+
```sh
|
|
149
|
+
# 한 번 판단하기 / 전환 계획만 확인하기
|
|
150
|
+
codexmu watch --once
|
|
151
|
+
codexmu watch --once --dry-run
|
|
152
|
+
|
|
153
|
+
# 주기적으로 auth.json 전환하기
|
|
154
|
+
codexmu --interval 30 watch
|
|
155
|
+
|
|
156
|
+
# JSON-RPC stdio 클라이언트에서 실행할 서버
|
|
157
|
+
codexmu app-server
|
|
158
|
+
codexmu app-server -- --stdio
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
`watch`는 파일을 관리하는 모드입니다. **별도로 실행한 일반 `codex`의 메모리상 인증을 강제로 바꾸지는 않습니다.** 실행 중에 자동 전환하려면 `codexmu`, `codexmu app` 또는 `codexmu app-server` 연결을 사용하세요.
|
|
162
|
+
|
|
163
|
+
`app-server` 명령은 stdio 연결만 지원하며 `--listen`을 받지 않습니다. 기본 터미널 모드에서는 세션별 전용 Unix 소켓을 내부적으로 사용합니다. 터미널과 브리지는 여러 개 실행할 수 있으며 독립 `watch` 프로세스만 홈별 하나로 제한합니다. 연결 중 UI 내 로그인·로그아웃 대신 `codexmu login/add/switch`를 사용합니다.
|
|
164
|
+
|
|
165
|
+
`codexmu`를 실행할 때는 별도의 `codexmu watch`가 필요하지 않습니다. 중복 `watch`를 실행하면 점유 프로세스의 PID를 오류에 표시합니다. 프로세스 종료 시 운영체제가 잠금을 해제하므로 잠금 파일을 삭제할 필요는 없습니다.
|
|
166
|
+
|
|
167
|
+
## 저장 위치와 설정
|
|
168
|
+
|
|
169
|
+
```text
|
|
170
|
+
$CODEX_HOME/auth.json 활성 Codex 인증
|
|
171
|
+
$CODEX_HOME/codexmu/accounts/<name>.json 계정별 인증·일시 제외 시각
|
|
172
|
+
$CODEX_HOME/codexmu/previous-auth.json 직전 활성 인증 백업
|
|
173
|
+
$CODEX_HOME/codexmu/pending-refresh.json 중단된 OAuth 갱신 복구용 임시 기록
|
|
174
|
+
$CODEX_HOME/codexmu/terminal-<PID>.log 세션별 공식 서버 진단 로그
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
`CODEX_HOME` 기본값은 `~/.codex`입니다. 별도 계정 저장 공간이 필요하면 `--codex-home /path`를 사용하세요. 로그인 토큰은 로컬 JSON에 저장하며 암호화하지 않습니다. Unix에서는 관리 디렉터리를 `0700`, 인증 파일을 `0600`으로 생성하고 원자적으로 교체합니다. `list`에는 토큰을 출력하지 않습니다. 갱신은 잠금과 복구 기록으로 보호하고, 외부 Codex가 갱신한 활성 토큰도 전환 전에 보존합니다.
|
|
178
|
+
|
|
179
|
+
| 설정 | 환경변수 | 기본값 |
|
|
180
|
+
| --- | --- | --- |
|
|
181
|
+
| `--codex-home` | `CODEX_HOME` | `~/.codex` |
|
|
182
|
+
| `--codex-bin` | `CODEXMU_CODEX_BIN` | `codex` |
|
|
183
|
+
| `--interval` | `CODEXMU_INTERVAL` | 60초, 최소 5초 |
|
|
184
|
+
| `--no-resume` | `CODEXMU_NO_RESUME` | false |
|
|
185
|
+
|
|
186
|
+
사용량 요청 실패·유효한 사용량 창이 없는 응답·이미 지난 리셋 시각을 여유 계정의 증거로 사용하지 않습니다. 한도에 도달한 계정은 최소 60초 동안 후보에서 제외됩니다. `--dry-run`은 계정 전환을 하지 않지만 정상 인증 유지에 필요한 OAuth 갱신은 할 수 있습니다.
|
|
187
|
+
|
|
188
|
+
## 검증
|
|
189
|
+
|
|
190
|
+
```sh
|
|
191
|
+
npm test
|
|
192
|
+
cargo fmt --check
|
|
193
|
+
cargo clippy --all-targets -- -D warnings
|
|
194
|
+
cargo test
|
|
195
|
+
cargo build
|
|
196
|
+
python3 tests/check.py
|
|
197
|
+
|
|
198
|
+
# 공식 Codex에 실제 인증 변경 RPC까지 검증 (테스트용 가짜 토큰 사용)
|
|
199
|
+
python3 tests/check.py --native "$(command -v codex)"
|
|
200
|
+
|
|
201
|
+
# 실제 공식 Codex 터미널: 입력 → A 한도 → B 응답 → /quit → 터미널 복구
|
|
202
|
+
python3 tests/terminal.py --codex-bin "$(command -v codex)" --resize
|
|
203
|
+
python3 tests/terminal.py --codex-bin "$(command -v codex)" --plain
|
|
204
|
+
python3 tests/terminal.py --codex-bin "$(command -v codex)" --sessions 3 --resize
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
테스트는 임시 홈과 로컬 HTTP 서버를 사용합니다. 개인 인증 파일을 읽거나 실제 한도를 소진하지 않습니다. HTTP 오류·401 갱신·전체 소진·중복 계정·원자적 저장·갱신 복구·RPC ID 충돌·한도 후 같은 스레드 재개·승인 전달·일반 오류·종료 동작을 검사합니다. `--native`는 공식 Codex가 HTTP 429를 받은 뒤 **같은 스레드의 후속 모델 요청에 B 계정의 토큰을 사용하고 정상 완료하는 것**과 `account/read`의 계정 변경을 확인합니다.
|
|
208
|
+
|
|
209
|
+
기존 검증 환경은 macOS ARM64 / 공식 Codex CLI 0.153.4이며 빌드·프로토콜·실제 터미널 PTY 테스트를 포함합니다. 데스크톱 GUI의 전체 실행과 실제 계정의 한도 소진은 검증 범위에 포함되지 않습니다. `chatgptAuthTokens`는 실험적 프로토콜이고 사용량 엔드포인트도 공개 안정 API가 아니므로, Codex 변경 시 호환성 확인이 필요합니다.
|
|
210
|
+
|
|
211
|
+
## 기여
|
|
212
|
+
|
|
213
|
+
코드 구조, 인증·동시 실행 시 지켜야 할 조건, 변경별 검증 방법은 [AGENTS.md](AGENTS.md)를 참고하세요. 동작이나 명령을 변경하면 영문·한글 README를 함께 갱신하세요.
|
|
214
|
+
|
|
215
|
+
## npm 배포
|
|
216
|
+
|
|
217
|
+
`package.json`과 `Cargo.toml`의 버전을 함께 변경하세요. GitHub 저장소에 코드를 올린 뒤 Actions의 **npm release → Run workflow**를 실행하면 네 플랫폼의 바이너리를 빌드·검증하고 `npm-package` 아티팩트에 설치 가능한 `.tgz`를 만듭니다. Linux는 musl 타깃으로 빌드합니다.
|
|
218
|
+
|
|
219
|
+
공개 게시하려면 해당 npm 패키지에 게시 권한이 있는 토큰을 저장소의 Actions secret **`NPM_TOKEN`**에 등록하고, 워크플로의 **publish**를 선택하세요. 패키지 이름을 바꾸려면 `package.json`의 `name`을 변경하면 됩니다. 워크플로는 네 플랫폼의 빌드와 검증이 모두 성공한 뒤 패키지를 게시합니다.
|
|
220
|
+
|
|
221
|
+
로컬 `npm publish`도 네 플랫폼 실행 파일이 모두 있는지 먼저 확인합니다. `npm pack`은 현재 플랫폼만으로 허용하므로 로컬 설치 테스트에 사용할 수 있습니다. 이 로컬 전용 `.tgz`를 공개 게시하지 마세요. 의존 npm 패키지와 설치 스크립트는 없습니다.
|
|
222
|
+
|
|
223
|
+
## 참고한 프로젝트
|
|
224
|
+
|
|
225
|
+
- [Loongphy/codex-auth](https://github.com/Loongphy/codex-auth/tree/0fde29598c2e02e28e0e8bcc33a4bb8d45d7b23a): 인증 파일 구조와 사용량 조회 방식 참고.
|
|
226
|
+
- [Loongphy/codext](https://github.com/Loongphy/codext/tree/50990b9913fd8f66456d9838dbeee572c6f10fc1): 안전한 턴 경계에서 인증 변경과 한도 오류 후 재개 방식 참고.
|
|
227
|
+
- [공식 Codex App Server 문서](https://developers.openai.com/codex/app-server): JSON-RPC 초기화·턴·계정 프로토콜 참고.
|
|
228
|
+
|
|
229
|
+
두 프로젝트의 바이너리·소스·패키지를 다운로드하거나 호출하는 런타임 코드는 없습니다.
|
|
230
|
+
|
|
231
|
+
## 라이선스
|
|
232
|
+
|
|
233
|
+
[MIT](LICENSE)
|
package/README.md
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# codexmu
|
|
2
|
+
|
|
3
|
+
**English** | [한국어](README.ko.md)
|
|
4
|
+
|
|
5
|
+
A Rust program that stores multiple ChatGPT accounts for Codex and automatically switches to an available account when the current one reaches its usage limit.
|
|
6
|
+
|
|
7
|
+
**No `codex-auth`, `codext`, or Zig is required.** codexmu handles auth files, OAuth refresh, usage queries, and account selection in Rust. It uses the **official Codex executable** for login and terminal / desktop integration. npm installations use Node.js as the entry point; Cargo installations do not require Node.js.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
### npm
|
|
12
|
+
|
|
13
|
+
Requires **Node.js 24 or later** and official Codex. The release package bundles macOS / Linux binaries for ARM64 and x64, without a Rust build or separate binary download during installation.
|
|
14
|
+
|
|
15
|
+
After publication to npm, install with the following commands. **This repository contains the release configuration; public registry publication must be checked separately.**
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npm install -g codexmu
|
|
19
|
+
codexmu
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
You can install a locally built package immediately. Local builds include only the current platform's executable:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
# Run from the repository; this build step requires Rust
|
|
26
|
+
npm run build
|
|
27
|
+
mkdir -p dist
|
|
28
|
+
npm pack --pack-destination dist
|
|
29
|
+
npm install -g ./dist/codexmu-0.1.0.tgz
|
|
30
|
+
codexmu --version
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
If you already installed through Cargo, use `command -v codexmu` to check which installation your PATH selects.
|
|
34
|
+
|
|
35
|
+
### Cargo
|
|
36
|
+
|
|
37
|
+
Requires Rust 1.89 or later and official Codex. Terminal mode supports macOS / Linux; desktop app launching supports macOS. Codex must support `--remote unix://...`; the previously tested CLI version is 0.153.4.
|
|
38
|
+
|
|
39
|
+
Run from the project directory after downloading the source:
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
cargo install --path . --locked
|
|
43
|
+
codexmu --help
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
If Cargo is not on your PATH, run `source "$HOME/.cargo/env"` first. You can also run `cargo build --release` and use `./target/release/codexmu` without installing it.
|
|
47
|
+
|
|
48
|
+
## Register accounts and start
|
|
49
|
+
|
|
50
|
+
**You can register two, three, or more accounts; codexmu imposes no account-count limit.** Save the account currently signed in to Codex, then log in to additional accounts under different names:
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
codexmu add personal
|
|
54
|
+
codexmu login work --device-auth
|
|
55
|
+
codexmu login extra --device-auth
|
|
56
|
+
codexmu switch personal
|
|
57
|
+
codexmu list --live
|
|
58
|
+
codexmu
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
All registered accounts are candidates for automatic switching. For example, if `personal` and then `work` reach their limits, codexmu can switch to an available `extra` account and continue the same conversation. Selection depends on remaining usage, not registration order.
|
|
62
|
+
|
|
63
|
+
`login` runs official `codex login` in a temporary `CODEX_HOME`. Cancelling or failing login preserves the existing active account. Omit `--device-auth` for browser login. If your credentials exist only in the keychain and there is no `auth.json`, use `login` instead of `add`.
|
|
64
|
+
|
|
65
|
+
You can also import an existing **standard Codex auth.json**:
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
codexmu add work --auth-file /path/to/work-auth.json
|
|
69
|
+
codexmu remove unused
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Duplicate accounts, overwriting an existing name, and deleting the active account are rejected. Names must contain 1–64 ASCII letters, digits, hyphens, or underscores. API key accounts are excluded to avoid automatically switching to usage-based billing.
|
|
73
|
+
|
|
74
|
+
## Codex terminal — macOS / Linux
|
|
75
|
+
|
|
76
|
+
After registering accounts, **run `codexmu` to open the official Codex terminal UI.** When a usage-limit error occurs, it switches to another registered account and automatically continues work in the same conversation.
|
|
77
|
+
|
|
78
|
+
A colored status header appears just above the input area, inspired by the `codext` preview:
|
|
79
|
+
|
|
80
|
+

|
|
81
|
+
|
|
82
|
+
The image replays actual PTY output from a local fake-account test in a terminal emulator.
|
|
83
|
+
|
|
84
|
+
```text
|
|
85
|
+
codexmu │ gpt-5.1 medium │ …/codexmu │ main +2 │ 5h 85% · 0h42m │ user@example.com (plus)
|
|
86
|
+
|
|
87
|
+
› Explain this project
|
|
88
|
+
Context 100% left · Fast off · 5h 85% · weekly 58% · 0.153.4
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The header shows the session model, reasoning effort, working directory, Git branch and change count, queried remaining usage, and active account email and plan. The time is the countdown to the usage reset. Once the server acknowledges an account switch, the header updates and briefly shows a notification. Unavailable quota data appears as `—`; narrow windows shorten or hide path and Git details. Your terminal controls the background and font.
|
|
92
|
+
|
|
93
|
+
```sh
|
|
94
|
+
codexmu
|
|
95
|
+
codexmu "Explain this project"
|
|
96
|
+
codexmu run -- --model gpt-5.1
|
|
97
|
+
codexmu run -- resume --last
|
|
98
|
+
|
|
99
|
+
# Use the original official Codex layout without the status header
|
|
100
|
+
codexmu --plain
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**Multiple `codexmu` windows can run simultaneously with the same `CODEX_HOME`.** Run `codexmu` in each terminal. They share the account list and default active account; each window's official Codex server manages its own conversations, approvals, and live authentication. When another window switches accounts, each window applies the new account during a usage check after its current turn finishes. A window receiving a usage-limit error attempts a switch immediately.
|
|
104
|
+
|
|
105
|
+
Account-store access, usage queries, and OAuth refresh are serialized by a store lock. Concurrent refreshes reuse tokens already refreshed by another window and do not overwrite the authentication of a window working with a different account. The lock is not held for the entire session.
|
|
106
|
+
|
|
107
|
+
A separate startup lock serializes server startup through the initialization response to avoid official Codex SQLite initialization conflicts in a fresh home. It releases immediately after initialization so sessions can work concurrently.
|
|
108
|
+
|
|
109
|
+
codexmu uses official Codex's `--remote unix://...` feature, verified with CLI 0.153.4. A private temporary Unix socket connects the native terminal UI to the authentication bridge, and the status header is composed over the PTY display. On exit, codexmu removes the socket and restores terminal settings. It opens no TCP port. Use official Codex's `Ctrl+T` view for long conversations, or `--plain` when you need the native terminal keyboard and scrolling behavior.
|
|
110
|
+
|
|
111
|
+
Pass Codex options after `run --` to avoid confusion with management commands and options. codexmu manages the `--remote` address. Use `codexmu --no-resume` to disable automatic continuation.
|
|
112
|
+
|
|
113
|
+
## Codex desktop app — macOS
|
|
114
|
+
|
|
115
|
+
**Quit the running Codex app first**, then run:
|
|
116
|
+
|
|
117
|
+
```sh
|
|
118
|
+
codexmu app
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
To specify the official CLI path:
|
|
122
|
+
|
|
123
|
+
```sh
|
|
124
|
+
codexmu --codex-bin /absolute/path/to/codex app
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
`app` uses macOS `open --env` to set `CODEX_CLI_PATH` to this binary. The app-launched `codexmu` forwards JSON-RPC between the app and official `codex app-server`. It does not modify the app installation or global configuration. An already-running app cannot receive these environment variables, so codexmu refuses to launch until you quit it.
|
|
128
|
+
|
|
129
|
+
Terminal and desktop modes share the same switching behavior:
|
|
130
|
+
|
|
131
|
+
- Query usage every 60 seconds by default, **only when no turn is running**.
|
|
132
|
+
- Look for another account immediately when a turn ends with `usageLimitExceeded`.
|
|
133
|
+
- Among available accounts, select the one with the lowest maximum usage across the usage windows present in the response.
|
|
134
|
+
- Send new credentials to the running official app-server through `account/login/start`, rather than only replacing a file.
|
|
135
|
+
- By default, send a new continuation turn in the same thread. Do not replay the original prompt or executed tool calls.
|
|
136
|
+
- Defer switching while another turn is running. Queue new turns during a switch while continuing to forward approval responses. Do not execute cancelled queued turns.
|
|
137
|
+
|
|
138
|
+
To switch accounts without automatic continuation:
|
|
139
|
+
|
|
140
|
+
```sh
|
|
141
|
+
codexmu --no-resume app
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Automatic recovery from the same failure is limited to one attempt per account. If all accounts are exhausted, codexmu keeps monitoring usage without entering a retry loop. After an account recovers, you can ask it to continue. Ordinary network errors, server overload, and the word “limit” in model output do not trigger account switching.
|
|
145
|
+
|
|
146
|
+
## Standalone monitoring and other clients
|
|
147
|
+
|
|
148
|
+
```sh
|
|
149
|
+
# Evaluate once / preview the switching decision
|
|
150
|
+
codexmu watch --once
|
|
151
|
+
codexmu watch --once --dry-run
|
|
152
|
+
|
|
153
|
+
# Periodically switch auth.json
|
|
154
|
+
codexmu --interval 30 watch
|
|
155
|
+
|
|
156
|
+
# Server command for a JSON-RPC stdio client
|
|
157
|
+
codexmu app-server
|
|
158
|
+
codexmu app-server -- --stdio
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
`watch` manages files. **It cannot force a separately launched ordinary `codex` process to reload its in-memory authentication.** For live switching, use `codexmu`, `codexmu app`, or a `codexmu app-server` connection.
|
|
162
|
+
|
|
163
|
+
The `app-server` command supports stdio only and rejects `--listen`. Default terminal mode internally uses a private Unix socket for each session. Multiple terminals and bridges can run together; only standalone `watch` is limited to one process per home. Use `codexmu login/add/switch` instead of logging in or out through the connected UI.
|
|
164
|
+
|
|
165
|
+
You do not need a separate `codexmu watch` when running `codexmu`. A duplicate `watch` reports the owning process's PID. The OS releases the lock when the process exits; there is no need to delete lock files.
|
|
166
|
+
|
|
167
|
+
## Storage and configuration
|
|
168
|
+
|
|
169
|
+
```text
|
|
170
|
+
$CODEX_HOME/auth.json Active Codex authentication
|
|
171
|
+
$CODEX_HOME/codexmu/accounts/<name>.json Account credentials and temporary exclusion time
|
|
172
|
+
$CODEX_HOME/codexmu/previous-auth.json Previous active authentication backup
|
|
173
|
+
$CODEX_HOME/codexmu/pending-refresh.json Interrupted OAuth refresh recovery journal
|
|
174
|
+
$CODEX_HOME/codexmu/terminal-<PID>.log Per-session official server diagnostics
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
`CODEX_HOME` defaults to `~/.codex`. Use `--codex-home /path` for a separate account store. Login tokens are stored in local JSON without encryption. On Unix, managed directories are created with mode `0700` and authentication files with `0600`; files are replaced atomically. `list` does not print tokens. Locks and a recovery journal protect refreshes, and active tokens refreshed by an external Codex process are preserved before switching.
|
|
178
|
+
|
|
179
|
+
| Option | Environment variable | Default |
|
|
180
|
+
| --- | --- | --- |
|
|
181
|
+
| `--codex-home` | `CODEX_HOME` | `~/.codex` |
|
|
182
|
+
| `--codex-bin` | `CODEXMU_CODEX_BIN` | `codex` |
|
|
183
|
+
| `--interval` | `CODEXMU_INTERVAL` | 60 seconds; minimum 5 |
|
|
184
|
+
| `--no-resume` | `CODEXMU_NO_RESUME` | false |
|
|
185
|
+
|
|
186
|
+
Failed usage requests, responses without a valid usage window, and past reset timestamps are not treated as evidence of available quota. Accounts that reach their limits are excluded from selection for at least 60 seconds. `--dry-run` does not switch accounts, but may refresh OAuth tokens to keep credentials valid.
|
|
187
|
+
|
|
188
|
+
## Validation
|
|
189
|
+
|
|
190
|
+
```sh
|
|
191
|
+
npm test
|
|
192
|
+
cargo fmt --check
|
|
193
|
+
cargo clippy --all-targets -- -D warnings
|
|
194
|
+
cargo test
|
|
195
|
+
cargo build
|
|
196
|
+
python3 tests/check.py
|
|
197
|
+
|
|
198
|
+
# Verify real authentication-switch RPCs with official Codex (fake test tokens)
|
|
199
|
+
python3 tests/check.py --native "$(command -v codex)"
|
|
200
|
+
|
|
201
|
+
# Official Codex terminal: input → A hits limit → B responds → /quit → terminal restored
|
|
202
|
+
python3 tests/terminal.py --codex-bin "$(command -v codex)" --resize
|
|
203
|
+
python3 tests/terminal.py --codex-bin "$(command -v codex)" --plain
|
|
204
|
+
python3 tests/terminal.py --codex-bin "$(command -v codex)" --sessions 3 --resize
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Tests use temporary homes and a local HTTP server. They do not read personal credentials or consume real quota. Coverage includes HTTP errors, refresh after 401, full exhaustion, duplicate accounts, atomic saves, refresh recovery, RPC ID collisions, same-thread continuation after limits, approval forwarding, ordinary errors, and shutdown. `--native` verifies that after official Codex receives HTTP 429, **a subsequent model request in the same thread uses account B's token and completes successfully**, as well as checking the account change through `account/read`.
|
|
208
|
+
|
|
209
|
+
The previously documented validation environment is macOS ARM64 / official Codex CLI 0.153.4, covering builds, protocol checks, and real terminal PTY tests. Full desktop GUI operation and real-account quota exhaustion are outside that validation scope. `chatgptAuthTokens` is experimental, and the usage endpoint is not a public stable API; compatibility needs checking when Codex changes.
|
|
210
|
+
|
|
211
|
+
## Contributing
|
|
212
|
+
|
|
213
|
+
See [AGENTS.md](AGENTS.md) for the code layout, authentication and concurrency invariants, and checks appropriate to each change. Update both English and Korean READMEs when behavior or commands change.
|
|
214
|
+
|
|
215
|
+
## npm releases
|
|
216
|
+
|
|
217
|
+
Update the versions in `package.json` and `Cargo.toml` together. After pushing the code to GitHub, select **npm release → Run workflow** in Actions to build and check all four platforms and create an installable `.tgz` in the `npm-package` artifact. Linux builds use musl targets.
|
|
218
|
+
|
|
219
|
+
To publish publicly, add a token with permission to publish the npm package as the repository's **`NPM_TOKEN`** Actions secret and select **publish** in the workflow. Change `name` in `package.json` to rename the package. The workflow publishes only after builds and checks succeed for all four platforms.
|
|
220
|
+
|
|
221
|
+
Local `npm publish` also checks that executables for all four platforms are present. `npm pack` permits a current-platform-only package for local installation tests; do not publish that local-only `.tgz` publicly. There are no npm dependencies or installation scripts.
|
|
222
|
+
|
|
223
|
+
## References
|
|
224
|
+
|
|
225
|
+
- [Loongphy/codex-auth](https://github.com/Loongphy/codex-auth/tree/0fde29598c2e02e28e0e8bcc33a4bb8d45d7b23a): reference for auth-file structure and usage queries.
|
|
226
|
+
- [Loongphy/codext](https://github.com/Loongphy/codext/tree/50990b9913fd8f66456d9838dbeee572c6f10fc1): reference for authentication changes at safe turn boundaries and continuation after usage-limit errors.
|
|
227
|
+
- [Official Codex App Server documentation](https://developers.openai.com/codex/app-server): reference for JSON-RPC initialization, turn, and account protocols.
|
|
228
|
+
|
|
229
|
+
No runtime code downloads or invokes the binaries, source, or packages of the two reference projects.
|
|
230
|
+
|
|
231
|
+
## License
|
|
232
|
+
|
|
233
|
+
[MIT](LICENSE)
|
package/bin/codexmu.mjs
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { accessSync, constants } from 'node:fs';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
|
|
5
|
+
try {
|
|
6
|
+
if (Number(process.versions.node.split('.')[0]) < 24 || !process.execve) {
|
|
7
|
+
throw new Error('Node.js 24 or newer is required');
|
|
8
|
+
}
|
|
9
|
+
const platform = `${process.platform}-${process.arch}`;
|
|
10
|
+
if (!['darwin-arm64', 'darwin-x64', 'linux-arm64', 'linux-x64'].includes(platform)) {
|
|
11
|
+
throw new Error(`unsupported platform: ${platform} (macOS/Linux, ARM64/x64 required)`);
|
|
12
|
+
}
|
|
13
|
+
const binary = fileURLToPath(new URL(`../vendor/${platform}/codexmu`, import.meta.url));
|
|
14
|
+
try {
|
|
15
|
+
accessSync(binary, constants.X_OK);
|
|
16
|
+
} catch {
|
|
17
|
+
throw new Error(`missing executable for ${platform}; reinstall a package built for this platform`);
|
|
18
|
+
}
|
|
19
|
+
// Replace Node so the native CLI owns its PID, terminal, and signals.
|
|
20
|
+
process.execve(binary, [binary, ...process.argv.slice(2)], process.env);
|
|
21
|
+
} catch (error) {
|
|
22
|
+
console.error(`codexmu: ${error.message}`);
|
|
23
|
+
process.exitCode = 1;
|
|
24
|
+
}
|
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "codexmu",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Multi-account manager and automatic account switching for Codex",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"codexmu": "bin/codexmu.mjs"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"bin/",
|
|
12
|
+
"vendor/",
|
|
13
|
+
"docs/terminal-preview.png"
|
|
14
|
+
],
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=24"
|
|
17
|
+
},
|
|
18
|
+
"os": [
|
|
19
|
+
"darwin",
|
|
20
|
+
"linux"
|
|
21
|
+
],
|
|
22
|
+
"cpu": [
|
|
23
|
+
"arm64",
|
|
24
|
+
"x64"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "cargo build --release --locked && node scripts/package.mjs stage",
|
|
28
|
+
"test": "node tests/npm.mjs",
|
|
29
|
+
"prepack": "node scripts/package.mjs check",
|
|
30
|
+
"prepublishOnly": "node scripts/package.mjs check-all"
|
|
31
|
+
},
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public",
|
|
34
|
+
"registry": "https://registry.npmjs.org/"
|
|
35
|
+
},
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/deepnmr/codexmu.git"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|