claude-pro-minmax 1.2.0 → 1.3.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/README.ko.md +113 -18
- package/README.md +113 -18
- package/install.sh +23 -1
- package/lib/cli.js +132 -8
- package/lib/rtk.js +179 -0
- package/package.json +1 -1
- package/scripts/hooks/README.ko.md +10 -0
- package/scripts/hooks/README.md +10 -1
package/README.ko.md
CHANGED
|
@@ -15,13 +15,15 @@
|
|
|
15
15
|
CPMM은 모델 라우팅, 출력 제어, 로컬 안전장치로 리셋 전까지 더 많은 검증된 작업을 완료하도록 돕습니다.
|
|
16
16
|
|
|
17
17
|
> **설치 완료했다면 여기서 시작하세요: [사용자 가이드](docs/USER-MANUAL.ko.md)**
|
|
18
|
+
>
|
|
19
|
+
> **New in v1.3.0:** Bash-heavy 출력 축약을 위한 RTK 선택 통합.
|
|
18
20
|
|
|
19
21
|
---
|
|
20
22
|
|
|
21
23
|
> [!TIP]
|
|
22
24
|
> **🚀 3초 요약: 왜 이걸 써야 하나요?**
|
|
23
25
|
> 1. **배치 실행:** `/do`로 구현-검증을 한 흐름에서 처리하고, 필요할 때만 `/do-sonnet`/`/do-opus`로 승격합니다.
|
|
24
|
-
> 2. **출력 비용 제어:** 응답
|
|
26
|
+
> 2. **출력 비용 제어:** 응답 예산, CLI 필터링, 그리고 optional RTK로 Bash-heavy 출력량을 줄입니다.
|
|
25
27
|
> 3. **로컬 안전장치:** 로컬 Hook + 원자적 롤백으로 실패 시 빠르게 복구합니다.
|
|
26
28
|
|
|
27
29
|
---
|
|
@@ -50,13 +52,61 @@ cpmm setup
|
|
|
50
52
|
cpmm doctor
|
|
51
53
|
```
|
|
52
54
|
|
|
55
|
+
> **v1.3.0 참고:** `cpmm setup`은 지원 환경에서 RTK 설치를 시도합니다. RTK 활성화는 여전히 opt-in입니다.
|
|
56
|
+
|
|
53
57
|
의존성 정책:
|
|
54
58
|
- `required`: `jq`, `mgrep`, `tmux`
|
|
59
|
+
- `optional` (자동 설치 시도): `rtk`
|
|
55
60
|
- `optional` (확인만): `claude` (사전 설치 가정)
|
|
56
|
-
- 자동 설치
|
|
61
|
+
- 도구별 자동 설치 경로:
|
|
62
|
+
- `mgrep`: `npm`
|
|
63
|
+
- `rtk`: `brew` 또는 upstream `curl` installer
|
|
64
|
+
- `jq`, `tmux`: `brew` (macOS) 또는 Linux 패키지 매니저 `apt-get`, `dnf`, `pacman`, `apk`
|
|
57
65
|
- macOS에서 Homebrew가 없으면 설치 명령을 안내합니다
|
|
58
66
|
|
|
59
|
-
### 4.
|
|
67
|
+
### 4. 커스텀 & 업데이트 정책
|
|
68
|
+
|
|
69
|
+
- `cpmm setup`은 누락된 의존성을 설치한 뒤, CPMM 설정(설정 파일 복사, 언어 선택, Perplexity 설정)까지 진행합니다.
|
|
70
|
+
- `cpmm doctor`는 수정 없이 의존성 상태와 RTK hook 상태를 확인합니다.
|
|
71
|
+
- 재실행 시 CPMM 관리 파일은 최신 버전으로 교체되고, 사용자 데이터는 보존됩니다.
|
|
72
|
+
|
|
73
|
+
```text
|
|
74
|
+
~/.claude/* ← Global Baseline (CPMM 관리)
|
|
75
|
+
├── agents/ 🔄 업데이트 시 교체됨
|
|
76
|
+
├── commands/ 🔄 업데이트 시 교체됨
|
|
77
|
+
├── contexts/ 🔄 업데이트 시 교체됨
|
|
78
|
+
├── scripts/ 🔄 업데이트 시 교체됨
|
|
79
|
+
├── skills/cli-wrappers/ 🔄 업데이트 시 교체됨
|
|
80
|
+
├── rules/*.md 🔄 업데이트 시 교체됨
|
|
81
|
+
├── settings.json 🔄 업데이트 시 교체됨
|
|
82
|
+
├── settings.local.json ✋ 사용자 소유 — 보존됨
|
|
83
|
+
├── skills/learned/ ✋ 사용자 소유 — 보존됨
|
|
84
|
+
├── sessions/ ✋ 사용자 소유 — 보존됨
|
|
85
|
+
├── plans/ ✋ 사용자 소유 — 보존됨
|
|
86
|
+
├── projects/ ✋ 사용자 소유 — 보존됨
|
|
87
|
+
└── rules/language.md ✋ 사용자 소유 — 보존됨
|
|
88
|
+
|
|
89
|
+
<project>/.claude/* ← Project-Specific (사용자/팀 커스텀)
|
|
90
|
+
├── CLAUDE.md 프로젝트별 지침
|
|
91
|
+
├── commands/ 프로젝트 전용 슬래시 명령어
|
|
92
|
+
├── skills/ 프로젝트 전용 스킬
|
|
93
|
+
├── rules/ 프로젝트 전용 규칙
|
|
94
|
+
└── settings.json 프로젝트 전용 권한/훅/MCP 비활성화
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
> **핵심 규칙 2가지:**
|
|
98
|
+
> 1. 글로벌 커스텀은 일반적으로 `settings.local.json`에 둡니다. `settings.json`은 CPMM 관리 대상이라 업데이트 시 덮어쓰기되므로, RTK 같은 third-party hook을 여기에 넣었다면 업데이트 후 다시 확인해야 합니다.
|
|
99
|
+
> 2. 커스텀 명령어/규칙은 프로젝트 `.claude/`에 — 글로벌 `commands/`는 CPMM이 관리합니다.
|
|
100
|
+
|
|
101
|
+
프로젝트 초기화 팁:
|
|
102
|
+
- `claude` 실행 전에 `project-templates/`를 참고해 프로젝트를 초기화하세요. (설치기는 `project-templates`를 `~/.claude`로 복사하지 않습니다.)
|
|
103
|
+
|
|
104
|
+
### 5. 고급 (선택)
|
|
105
|
+
<details>
|
|
106
|
+
<summary>Perplexity, 언어, 수동 설치 보기</summary>
|
|
107
|
+
|
|
108
|
+
**Perplexity/언어 설정 (필수 아님):**
|
|
109
|
+
- Perplexity는 `/dplan`의 웹 리서치에 사용됩니다. 설정하지 않아도 `/dplan`은 Sequential Thinking + Context7으로 동작하며, 나머지 모든 기능은 Perplexity와 무관합니다.
|
|
60
110
|
- 최초 인터랙티브 설치 시 `cpmm setup`이 출력 언어와 Perplexity API 키를 묻습니다.
|
|
61
111
|
- 영어(기본): 파일이 필요 없습니다. `~/.claude/rules/language.md`가 있으면 삭제하세요.
|
|
62
112
|
- 비영어: `~/.claude/rules/language.md`를 만들어 원하는 언어를 지정하세요.
|
|
@@ -72,11 +122,7 @@ cpmm doctor
|
|
|
72
122
|
}
|
|
73
123
|
```
|
|
74
124
|
|
|
75
|
-
|
|
76
|
-
<details>
|
|
77
|
-
<summary>수동 의존성 설치와 소스 설치 보기</summary>
|
|
78
|
-
|
|
79
|
-
수동 의존성 설치:
|
|
125
|
+
**수동 의존성 설치:**
|
|
80
126
|
```bash
|
|
81
127
|
# jq
|
|
82
128
|
brew install jq # macOS
|
|
@@ -97,7 +143,7 @@ sudo pacman -S --noconfirm tmux # Arch
|
|
|
97
143
|
sudo apk add tmux # Alpine
|
|
98
144
|
```
|
|
99
145
|
|
|
100
|
-
|
|
146
|
+
**소스에서 수동 설치:**
|
|
101
147
|
```bash
|
|
102
148
|
git clone https://github.com/move-hoon/claude-pro-minmax.git
|
|
103
149
|
cd claude-pro-minmax
|
|
@@ -106,20 +152,53 @@ node bin/cpmm.js setup
|
|
|
106
152
|
# bash install.sh
|
|
107
153
|
```
|
|
108
154
|
|
|
109
|
-
|
|
110
|
-
- `cpmm setup`은 누락된 의존성을 설치한 뒤, CPMM 설정(설정 파일 복사, 언어 선택, Perplexity 설정)까지 진행합니다.
|
|
111
|
-
- `cpmm doctor`는 수정 없이 의존성 상태만 확인합니다.
|
|
112
|
-
- 재실행 시 CPMM 관리 파일만 갱신하고, `language.md`, `settings.local.json`, `skills/learned/`, `sessions/` 등 사용자 파일은 보존합니다.
|
|
155
|
+
</details>
|
|
113
156
|
|
|
114
|
-
|
|
115
|
-
- `claude` 실행 전에 `project-templates/`를 참고해 프로젝트를 초기화하세요. (설치기는 `project-templates`를 `~/.claude`로 복사하지 않습니다.)
|
|
157
|
+
### 6. Bash 출력 최적화 (RTK)
|
|
116
158
|
|
|
117
|
-
|
|
159
|
+
RTK는 CPMM이 지원하는 **선택적 출력 최적화 계층**입니다. `cpmm setup`은 RTK 바이너리 설치를 시도하지만, RTK hook은 기본 활성화하지 않습니다.
|
|
160
|
+
|
|
161
|
+
권장 opt-in 절차:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
rtk init -g --hook-only
|
|
165
|
+
cpmm doctor
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
권장 `PreToolUse` 순서 (`~/.claude/settings.json`):
|
|
169
|
+
- 먼저 CPMM safety hook: `~/.claude/scripts/hooks/critical-action-check.sh` with `timeout: 5`
|
|
170
|
+
- 그 다음 RTK rewrite hook: `~/.claude/hooks/rtk-rewrite.sh` with `timeout: 10`
|
|
171
|
+
|
|
172
|
+
업데이트 참고:
|
|
173
|
+
- `cpmm setup`은 업데이트 시 `~/.claude/settings.json`을 다시 씁니다.
|
|
174
|
+
- RTK를 opt-in으로 사용 중이면 CPMM 업데이트 후 hook 순서와 timeout을 다시 확인하고, `cpmm doctor`를 다시 실행하세요.
|
|
175
|
+
|
|
176
|
+
권장 검증:
|
|
177
|
+
- `/hooks`에서 CPMM hook과 RTK hook이 모두 로드되는지 확인
|
|
178
|
+
- 위험 명령이 여전히 CPMM에서 먼저 차단되는지 확인
|
|
179
|
+
- `cpmm doctor` 실행
|
|
180
|
+
- 실제 Bash-heavy 세션 후 `rtk gain --quota --tier pro` 확인
|
|
181
|
+
|
|
182
|
+
롤백:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
rtk init -g --uninstall
|
|
186
|
+
```
|
|
118
187
|
|
|
119
188
|
---
|
|
120
189
|
|
|
121
190
|
## 🚀 빠른 시작 (Quick Start)
|
|
122
191
|
|
|
192
|
+
### ⚡ 첫 60초 (FTUE)
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
claude
|
|
196
|
+
> /plan 이 저장소를 분석하고 작은 개선 1개에 대한 3단계 실행 계획을 제안해줘.
|
|
197
|
+
> /do 1단계만 최소 변경으로 안전하게 구현해줘.
|
|
198
|
+
> /review .
|
|
199
|
+
> /session-save ftue-first-pass
|
|
200
|
+
```
|
|
201
|
+
|
|
123
202
|
### 🤖 에이전트 워크플로우
|
|
124
203
|
|
|
125
204
|
CPMM은 계층적 모델 라우팅을 제공합니다: `/plan`은 @planner (Sonnet 4.6) → @builder (Haiku 4.5) 체인으로 복잡한 작업을 처리하고, `/do`는 현재 세션 모델에서 직접 실행하여 속도를 높입니다.
|
|
@@ -413,7 +492,7 @@ A: 네, 하지만 이러한 최적화가 필요하지 않을 수 있습니다. M
|
|
|
413
492
|
<details>
|
|
414
493
|
<summary><strong>Q: 기존 Claude Code 설정과 충돌하나요?</strong></summary>
|
|
415
494
|
|
|
416
|
-
A: 최초 `cpmm setup` 시 기존 `~/.claude`를 `~/.claude.pre-cpmm`으로 백업합니다. 재실행 시 CPMM 관리
|
|
495
|
+
A: 최초 `cpmm setup` 시 기존 `~/.claude`를 `~/.claude.pre-cpmm`으로 백업합니다. 재실행 시 CPMM 관리 경로는 재생성되고, 사용자 소유 경로(언어 설정, 로컬 설정, 학습 패턴, 세션)는 보존됩니다. 정확한 경계는 설치 섹션의 2-Layer 구조를 참고하세요.
|
|
417
496
|
</details>
|
|
418
497
|
|
|
419
498
|
<details>
|
|
@@ -431,7 +510,22 @@ A: API 가격(컴퓨팅 비용 반영)을 보면 Opus 4.6 ($5/MTok input)은 Son
|
|
|
431
510
|
<details>
|
|
432
511
|
<summary><strong>Q: /do 실행 중 실패하면 어떻게 되나요?</strong></summary>
|
|
433
512
|
|
|
434
|
-
A: CPMM은
|
|
513
|
+
A: CPMM은 `scripts/snapshot.sh`를 통한 **best-effort 원자적 롤백**을 사용합니다.
|
|
514
|
+
|
|
515
|
+
- `/do` 실행 전 `snapshot.sh push`로 라벨된 stash 스냅샷을 시도합니다.
|
|
516
|
+
- 실패 시 `snapshot.sh pop`이 복구를 시도하며, 아래 상태 중 하나를 반환합니다:
|
|
517
|
+
|
|
518
|
+
| 상태 | 의미 |
|
|
519
|
+
| --- | --- |
|
|
520
|
+
| `RESTORED` | CPMM 라벨 stash를 정상 pop하여 복구 완료 |
|
|
521
|
+
| `RESTORE_FAILED` | `git stash pop` 실패 (예: 충돌) |
|
|
522
|
+
| `CHECKOUT_CLEAN` | CPMM stash가 없어 fallback `git checkout .` 성공 |
|
|
523
|
+
| `CLEAN_FAILED` | fallback 정리도 실패 |
|
|
524
|
+
|
|
525
|
+
롤백 후에도 완전히 깨끗하지 않다면:
|
|
526
|
+
1. `git status` 확인
|
|
527
|
+
2. `git stash list` 확인
|
|
528
|
+
3. 충돌 해결/새 untracked 파일 수동 정리 후 재시도
|
|
435
529
|
|
|
436
530
|
- 비용: 0 (git stash는 로컬 작업)
|
|
437
531
|
- 제한: 기존(tracked) 파일만 추적. 새로 생성된 파일은 수동 제거 필요.
|
|
@@ -442,6 +536,7 @@ A: CPMM은 **원자적 롤백**을 사용합니다. `/do` 실행 전 `git stash
|
|
|
442
536
|
## 참고 링크
|
|
443
537
|
|
|
444
538
|
- 핵심전략 근거 실험 아카이브: [핵심전략 실험 아카이브](docs/CORE_STRATEGY_EXPERIMENT_ARCHIVE.ko.md)
|
|
539
|
+
- 방향성 비교를 위한 외부 역분석 사례: [claude-limits](https://she-llac.com/claude-limits) (Claude 플랜 usage/credits 동작을 설명하려는 비공식 분석)
|
|
445
540
|
- 공식 문서:
|
|
446
541
|
- [Anthropic Pricing](https://docs.anthropic.com/en/docs/about-claude/pricing)
|
|
447
542
|
- [Usage Limit Best Practices](https://support.claude.com/en/articles/9797557-usage-limit-best-practices)
|
package/README.md
CHANGED
|
@@ -15,13 +15,15 @@
|
|
|
15
15
|
CPMM helps Pro users complete more verified tasks before reset through model routing, output control, and local safety rails.
|
|
16
16
|
|
|
17
17
|
> **Already installed? Start here: [User Guide](docs/USER-MANUAL.md)**
|
|
18
|
+
>
|
|
19
|
+
> **New in v1.3.0:** Optional RTK integration for Bash-heavy output reduction.
|
|
18
20
|
|
|
19
21
|
---
|
|
20
22
|
|
|
21
23
|
> [!TIP]
|
|
22
24
|
> **🚀 3-Second Summary: Why use this?**
|
|
23
25
|
> 1. **Batch Execution:** Use `/do` to keep implementation and verification in one flow, and escalate to `/do-sonnet`/`/do-opus` only when needed.
|
|
24
|
-
> 2. **Output Cost Control:** Use response budgets
|
|
26
|
+
> 2. **Output Cost Control:** Use response budgets, CLI filtering, and optional RTK for Bash-heavy output reduction.
|
|
25
27
|
> 3. **Local Safety Rails:** Local hooks and atomic rollback help you recover quickly on failure.
|
|
26
28
|
|
|
27
29
|
---
|
|
@@ -50,13 +52,61 @@ cpmm setup
|
|
|
50
52
|
cpmm doctor
|
|
51
53
|
```
|
|
52
54
|
|
|
55
|
+
> **v1.3.0 note:** `cpmm setup` now attempts RTK installation when supported. RTK activation remains opt-in.
|
|
56
|
+
|
|
53
57
|
Dependency policy:
|
|
54
58
|
- `required`: `jq`, `mgrep`, `tmux`
|
|
59
|
+
- `optional` (auto-install attempt): `rtk`
|
|
55
60
|
- `optional` (check only): `claude` (assumed pre-installed)
|
|
56
|
-
- auto-install
|
|
61
|
+
- auto-install paths by tool:
|
|
62
|
+
- `mgrep`: `npm`
|
|
63
|
+
- `rtk`: `brew` or upstream `curl` installer
|
|
64
|
+
- `jq`, `tmux`: `brew` (macOS) or Linux package managers `apt-get`, `dnf`, `pacman`, `apk`
|
|
57
65
|
- on macOS without Homebrew, setup prints the Homebrew install command
|
|
58
66
|
|
|
59
|
-
### 4.
|
|
67
|
+
### 4. Customization & Update Policy
|
|
68
|
+
|
|
69
|
+
- `cpmm setup` installs missing dependencies, then configures CPMM (copies config files, language selection, Perplexity setup).
|
|
70
|
+
- `cpmm doctor` checks dependency status and RTK hook health without modifying anything.
|
|
71
|
+
- Re-running `cpmm setup` replaces CPMM-managed files with the latest version while preserving user data.
|
|
72
|
+
|
|
73
|
+
```text
|
|
74
|
+
~/.claude/* ← Global Baseline (CPMM-managed)
|
|
75
|
+
├── agents/ 🔄 Replaced on update
|
|
76
|
+
├── commands/ 🔄 Replaced on update
|
|
77
|
+
├── contexts/ 🔄 Replaced on update
|
|
78
|
+
├── scripts/ 🔄 Replaced on update
|
|
79
|
+
├── skills/cli-wrappers/ 🔄 Replaced on update
|
|
80
|
+
├── rules/*.md 🔄 Replaced on update
|
|
81
|
+
├── settings.json 🔄 Replaced on update
|
|
82
|
+
├── settings.local.json ✋ User-owned — preserved
|
|
83
|
+
├── skills/learned/ ✋ User-owned — preserved
|
|
84
|
+
├── sessions/ ✋ User-owned — preserved
|
|
85
|
+
├── plans/ ✋ User-owned — preserved
|
|
86
|
+
├── projects/ ✋ User-owned — preserved
|
|
87
|
+
└── rules/language.md ✋ User-owned — preserved
|
|
88
|
+
|
|
89
|
+
<project>/.claude/* ← Project-Specific (user/team customization)
|
|
90
|
+
├── CLAUDE.md Project-specific instructions
|
|
91
|
+
├── commands/ Project-specific slash commands
|
|
92
|
+
├── skills/ Project-specific skills
|
|
93
|
+
├── rules/ Project-specific rules
|
|
94
|
+
└── settings.json Project-specific permissions/hooks/MCP disable
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
> **Two key rules:**
|
|
98
|
+
> 1. Global customization generally goes in `settings.local.json`. `settings.json` is CPMM-managed and overwritten on update; if you opt into RTK or other third-party hooks there, re-check them after updates.
|
|
99
|
+
> 2. Custom commands/rules go in project `.claude/` — global `commands/` is managed by CPMM.
|
|
100
|
+
|
|
101
|
+
Project initialization tip:
|
|
102
|
+
- Before running `claude`, initialize your project with templates in `project-templates/` (not copied into `~/.claude`).
|
|
103
|
+
|
|
104
|
+
### 5. Advanced (Optional)
|
|
105
|
+
<details>
|
|
106
|
+
<summary>Perplexity, language, manual install</summary>
|
|
107
|
+
|
|
108
|
+
**Perplexity/Language setup (not required):**
|
|
109
|
+
- Perplexity is used for web research in `/dplan`. Without it, `/dplan` still works via Sequential Thinking + Context7. All other features are unrelated to Perplexity.
|
|
60
110
|
- On fresh interactive installs, `cpmm setup` asks for output language and Perplexity API key.
|
|
61
111
|
- English (default): no file needed; remove `~/.claude/rules/language.md` if it exists.
|
|
62
112
|
- Non-English: create `~/.claude/rules/language.md` with your preferred language.
|
|
@@ -72,11 +122,7 @@ Dependency policy:
|
|
|
72
122
|
}
|
|
73
123
|
```
|
|
74
124
|
|
|
75
|
-
|
|
76
|
-
<details>
|
|
77
|
-
<summary>Show manual dependency setup and source install</summary>
|
|
78
|
-
|
|
79
|
-
Manual dependency setup:
|
|
125
|
+
**Manual dependency setup:**
|
|
80
126
|
```bash
|
|
81
127
|
# jq
|
|
82
128
|
brew install jq # macOS
|
|
@@ -97,7 +143,7 @@ sudo pacman -S --noconfirm tmux # Arch
|
|
|
97
143
|
sudo apk add tmux # Alpine
|
|
98
144
|
```
|
|
99
145
|
|
|
100
|
-
Manual install from source
|
|
146
|
+
**Manual install from source:**
|
|
101
147
|
```bash
|
|
102
148
|
git clone https://github.com/move-hoon/claude-pro-minmax.git
|
|
103
149
|
cd claude-pro-minmax
|
|
@@ -106,20 +152,53 @@ node bin/cpmm.js setup
|
|
|
106
152
|
# bash install.sh
|
|
107
153
|
```
|
|
108
154
|
|
|
109
|
-
|
|
110
|
-
- `cpmm setup` installs missing dependencies, then configures CPMM (copies config files, language selection, Perplexity setup).
|
|
111
|
-
- `cpmm doctor` checks dependency status without modifying anything.
|
|
112
|
-
- Re-running `cpmm setup` updates CPMM-managed files in place and preserves user-owned files like `language.md`, `settings.local.json`, `skills/learned/`, and `sessions/`.
|
|
155
|
+
</details>
|
|
113
156
|
|
|
114
|
-
|
|
115
|
-
- Before running `claude`, initialize your project with templates in `project-templates/` (not copied into `~/.claude`).
|
|
157
|
+
### 6. Bash Output Optimization (RTK)
|
|
116
158
|
|
|
117
|
-
|
|
159
|
+
CPMM supports RTK as an **optional output-optimization layer** for Bash-heavy workflows. `cpmm setup` attempts to install the RTK binary, but CPMM does **not** enable the RTK hook by default.
|
|
160
|
+
|
|
161
|
+
Recommended opt-in flow:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
rtk init -g --hook-only
|
|
165
|
+
cpmm doctor
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Recommended `PreToolUse` order in `~/.claude/settings.json`:
|
|
169
|
+
- CPMM safety hook first: `~/.claude/scripts/hooks/critical-action-check.sh` with `timeout: 5`
|
|
170
|
+
- RTK rewrite hook second: `~/.claude/hooks/rtk-rewrite.sh` with `timeout: 10`
|
|
171
|
+
|
|
172
|
+
Update note:
|
|
173
|
+
- `cpmm setup` rewrites `~/.claude/settings.json` on update.
|
|
174
|
+
- If you opt into RTK, re-check hook order and timeout after each CPMM update, then run `cpmm doctor`.
|
|
175
|
+
|
|
176
|
+
Recommended verification:
|
|
177
|
+
- Run `/hooks` and confirm both CPMM and RTK hooks are loaded
|
|
178
|
+
- Confirm dangerous commands are still blocked by CPMM
|
|
179
|
+
- Run `cpmm doctor`
|
|
180
|
+
- After real Bash-heavy sessions, inspect `rtk gain --quota --tier pro`
|
|
181
|
+
|
|
182
|
+
Rollback:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
rtk init -g --uninstall
|
|
186
|
+
```
|
|
118
187
|
|
|
119
188
|
---
|
|
120
189
|
|
|
121
190
|
## 🚀 Quick Start
|
|
122
191
|
|
|
192
|
+
### ⚡ First 60 Seconds (FTUE)
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
claude
|
|
196
|
+
> /plan Analyze this repository and propose a 3-step implementation plan for one small improvement.
|
|
197
|
+
> /do Implement step 1 only, with minimal and safe changes.
|
|
198
|
+
> /review .
|
|
199
|
+
> /session-save ftue-first-pass
|
|
200
|
+
```
|
|
201
|
+
|
|
123
202
|
### 🤖 Agent Workflow
|
|
124
203
|
|
|
125
204
|
CPMM provides layered model routing: `/plan` chains @planner (Sonnet 4.6) → @builder (Haiku 4.5) for complex tasks, while `/do` executes directly in the current session model for speed.
|
|
@@ -413,7 +492,7 @@ This configuration is specifically designed for the Pro Plan's 5-hour rolling re
|
|
|
413
492
|
<details>
|
|
414
493
|
<summary><strong>Q: Does it conflict with existing Claude Code settings?</strong></summary>
|
|
415
494
|
|
|
416
|
-
A: On first `cpmm setup`, CPMM backs up your existing `~/.claude` to `~/.claude.pre-cpmm`. Re-running `cpmm setup`
|
|
495
|
+
A: On first `cpmm setup`, CPMM backs up your existing `~/.claude` to `~/.claude.pre-cpmm`. Re-running `cpmm setup` recreates CPMM-managed paths and preserves user-owned paths (language settings, local config, learned patterns, sessions). See the 2-Layer structure in the install section for exact boundaries.
|
|
417
496
|
</details>
|
|
418
497
|
|
|
419
498
|
<details>
|
|
@@ -431,7 +510,22 @@ A: API pricing (reflecting compute cost), Opus 4.6 ($5/MTok input) is much more
|
|
|
431
510
|
<details>
|
|
432
511
|
<summary><strong>Q: What happens when /do fails mid-execution?</strong></summary>
|
|
433
512
|
|
|
434
|
-
A: CPMM uses **
|
|
513
|
+
A: CPMM uses **best-effort atomic rollback** via `scripts/snapshot.sh`.
|
|
514
|
+
|
|
515
|
+
- Before `/do`, `snapshot.sh push` attempts a labeled stash snapshot.
|
|
516
|
+
- On failure, `snapshot.sh pop` attempts restore and returns one of these statuses:
|
|
517
|
+
|
|
518
|
+
| Status | Meaning |
|
|
519
|
+
| --- | --- |
|
|
520
|
+
| `RESTORED` | Labeled CPMM stash was popped successfully. |
|
|
521
|
+
| `RESTORE_FAILED` | `git stash pop` failed (for example: conflicts). |
|
|
522
|
+
| `CHECKOUT_CLEAN` | No CPMM stash found; fallback `git checkout .` succeeded. |
|
|
523
|
+
| `CLEAN_FAILED` | Fallback cleanup also failed. |
|
|
524
|
+
|
|
525
|
+
If rollback did not fully restore clean state:
|
|
526
|
+
1. Run `git status`.
|
|
527
|
+
2. Run `git stash list`.
|
|
528
|
+
3. Resolve conflicts / remove new untracked files manually, then retry.
|
|
435
529
|
|
|
436
530
|
- Cost: Zero (git stash is a local operation)
|
|
437
531
|
- Limitation: Only tracks existing (tracked) files. Newly created files require manual removal.
|
|
@@ -442,6 +536,7 @@ A: CPMM uses **Atomic Rollback**. Before `/do` executes, `git stash push` saves
|
|
|
442
536
|
## References
|
|
443
537
|
|
|
444
538
|
- Archived experiment evidence for core strategy: [Core Strategy Experiment Archive](docs/CORE_STRATEGY_EXPERIMENT_ARCHIVE.md)
|
|
539
|
+
- Independent reverse-engineering case study for direction-checking: [claude-limits](https://she-llac.com/claude-limits) (unofficial analysis of Claude plan usage/credits behavior)
|
|
445
540
|
- Official pricing and usage docs:
|
|
446
541
|
- [Anthropic Pricing](https://docs.anthropic.com/en/docs/about-claude/pricing)
|
|
447
542
|
- [Usage Limit Best Practices](https://support.claude.com/en/articles/9797557-usage-limit-best-practices)
|
package/install.sh
CHANGED
|
@@ -47,6 +47,11 @@ else
|
|
|
47
47
|
fi
|
|
48
48
|
|
|
49
49
|
# Backup existing ~/.claude (Fresh Install Only)
|
|
50
|
+
HAS_EXISTING_RTK_HOOK=false
|
|
51
|
+
if [ -f "$HOME/.claude/settings.json" ] && grep -q "rtk-rewrite.sh" "$HOME/.claude/settings.json" 2>/dev/null; then
|
|
52
|
+
HAS_EXISTING_RTK_HOOK=true
|
|
53
|
+
fi
|
|
54
|
+
|
|
50
55
|
if [ "$IS_UPDATE" = false ] && [ -d "$HOME/.claude" ]; then
|
|
51
56
|
if [ -d "$HOME/.claude.pre-cpmm" ]; then
|
|
52
57
|
echo "⚠️ ~/.claude.pre-cpmm already exists, skipping backup."
|
|
@@ -283,9 +288,26 @@ echo " > /dplan Analyze complex architecture"
|
|
|
283
288
|
echo " > /do Implement the login page"
|
|
284
289
|
echo ""
|
|
285
290
|
echo "Dependency Check:"
|
|
286
|
-
echo " cpmm setup # install missing deps (jq, mgrep, tmux)"
|
|
291
|
+
echo " cpmm setup # install missing deps (jq, mgrep, tmux) + attempt optional RTK install"
|
|
287
292
|
echo " cpmm doctor # check status only"
|
|
288
293
|
echo ""
|
|
294
|
+
if command -v rtk >/dev/null 2>&1; then
|
|
295
|
+
echo "RTK (Optional Integration):"
|
|
296
|
+
echo " Installed: rtk"
|
|
297
|
+
echo " Enable hook: rtk init -g --hook-only"
|
|
298
|
+
echo " Recommended Bash hook order in ~/.claude/settings.json:"
|
|
299
|
+
echo " 1) ~/.claude/scripts/hooks/critical-action-check.sh (timeout: 5)"
|
|
300
|
+
echo " 2) ~/.claude/hooks/rtk-rewrite.sh (timeout: 10)"
|
|
301
|
+
echo " Rollback: rtk init -g --uninstall"
|
|
302
|
+
echo ""
|
|
303
|
+
fi
|
|
304
|
+
if [ "$HAS_EXISTING_RTK_HOOK" = true ]; then
|
|
305
|
+
echo "RTK Update Note:"
|
|
306
|
+
echo " An RTK hook was detected before this CPMM update."
|
|
307
|
+
echo " Because CPMM reinstalled ~/.claude/settings.json, re-check RTK hook order and timeout."
|
|
308
|
+
echo " Run: cpmm doctor"
|
|
309
|
+
echo ""
|
|
310
|
+
fi
|
|
289
311
|
echo "Language:"
|
|
290
312
|
echo " To change language: edit ~/.claude/rules/language.md"
|
|
291
313
|
echo " To use English: rm ~/.claude/rules/language.md"
|
package/lib/cli.js
CHANGED
|
@@ -4,14 +4,22 @@ const { execSync, spawnSync } = require("node:child_process");
|
|
|
4
4
|
const path = require("node:path");
|
|
5
5
|
const fs = require("node:fs");
|
|
6
6
|
const pkg = require("../package.json");
|
|
7
|
+
const {
|
|
8
|
+
RTK_DOCS_URL,
|
|
9
|
+
attemptRtkInstall,
|
|
10
|
+
getRtkManualInstallHints,
|
|
11
|
+
inspectRtkStatus,
|
|
12
|
+
} = require("./rtk");
|
|
7
13
|
|
|
8
14
|
const DEPS = [
|
|
9
15
|
{
|
|
10
16
|
key: "claude",
|
|
11
17
|
command: "claude",
|
|
12
18
|
required: false,
|
|
19
|
+
prerequisite: true,
|
|
13
20
|
installKind: "skip",
|
|
14
|
-
description: "Claude Code CLI
|
|
21
|
+
description: "Claude Code CLI",
|
|
22
|
+
installHint: "curl -fsSL https://claude.ai/install.sh | bash",
|
|
15
23
|
},
|
|
16
24
|
{
|
|
17
25
|
key: "jq",
|
|
@@ -40,6 +48,11 @@ const DEPS = [
|
|
|
40
48
|
},
|
|
41
49
|
];
|
|
42
50
|
|
|
51
|
+
function colorize(text, colorCode) {
|
|
52
|
+
if (!process.stdout.isTTY || process.env.NO_COLOR) return text;
|
|
53
|
+
return `\x1b[${colorCode}m${text}\x1b[0m`;
|
|
54
|
+
}
|
|
55
|
+
|
|
43
56
|
function commandExists(cmd) {
|
|
44
57
|
try {
|
|
45
58
|
execSync(`command -v ${cmd}`, { stdio: "ignore" });
|
|
@@ -119,15 +132,120 @@ function checkDeps() {
|
|
|
119
132
|
}
|
|
120
133
|
|
|
121
134
|
function printStatus(results) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
135
|
+
const prereqs = results.filter((r) => r.prerequisite);
|
|
136
|
+
const deps = results.filter((r) => !r.prerequisite);
|
|
137
|
+
|
|
138
|
+
if (prereqs.length > 0) {
|
|
139
|
+
console.log("\nPrerequisite:");
|
|
140
|
+
for (const r of prereqs) {
|
|
141
|
+
if (r.installed) {
|
|
142
|
+
console.log(` ${colorize("✓", "32")} ${r.key.padEnd(8)} ${r.description}`);
|
|
143
|
+
} else {
|
|
144
|
+
console.log(` ${colorize("⚠", "33")} ${r.key.padEnd(8)} ${r.description} — ${colorize("not found", "33")}`);
|
|
145
|
+
if (r.installHint) {
|
|
146
|
+
console.log(` Install: ${r.installHint}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
console.log("\nDependencies:");
|
|
153
|
+
for (const r of deps) {
|
|
154
|
+
const icon = r.installed
|
|
155
|
+
? colorize("✓", "32")
|
|
156
|
+
: (r.required ? colorize("✗", "31") : colorize("○", "33"));
|
|
125
157
|
const tag = r.required ? "[required]" : "[optional]";
|
|
126
158
|
console.log(` ${icon} ${r.key.padEnd(8)} ${tag} ${r.description}`);
|
|
127
159
|
}
|
|
128
160
|
console.log("");
|
|
129
161
|
}
|
|
130
162
|
|
|
163
|
+
function printRtkSetupResult(result) {
|
|
164
|
+
if (!result) return;
|
|
165
|
+
|
|
166
|
+
console.log("RTK Integration:");
|
|
167
|
+
switch (result.outcome) {
|
|
168
|
+
case "already_installed":
|
|
169
|
+
console.log(` ${colorize("✓", "32")} rtk [optional] already installed`);
|
|
170
|
+
break;
|
|
171
|
+
case "installed":
|
|
172
|
+
console.log(` ${colorize("✓", "32")} rtk [optional] installed (${result.method})`);
|
|
173
|
+
break;
|
|
174
|
+
default:
|
|
175
|
+
console.log(` ${colorize("⚠", "33")} rtk [optional] ${result.message}`);
|
|
176
|
+
for (const line of getRtkManualInstallHints()) {
|
|
177
|
+
console.log(` ${line}`);
|
|
178
|
+
}
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
console.log(" Optional activation:");
|
|
183
|
+
console.log(" 1) rtk init -g --hook-only");
|
|
184
|
+
console.log(" 2) Add ~/.claude/hooks/rtk-rewrite.sh after CPMM critical-action-check.sh");
|
|
185
|
+
console.log(" 3) Set RTK hook timeout to 10");
|
|
186
|
+
console.log(" 4) Re-run: cpmm doctor");
|
|
187
|
+
console.log("");
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function printRtkDoctorStatus(status) {
|
|
191
|
+
console.log("\nRTK Integration:");
|
|
192
|
+
console.log(
|
|
193
|
+
` ${status.binaryInstalled ? colorize("✓", "32") : colorize("○", "33")} rtk binary ${
|
|
194
|
+
status.binaryInstalled ? "installed" : "not installed (optional)"
|
|
195
|
+
}`,
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
if (status.failReason === "missing_settings_json") {
|
|
199
|
+
console.log(` ${colorize("✗", "31")} settings.json missing (~/.claude/settings.json)`);
|
|
200
|
+
console.log(" Fix: re-run cpmm setup");
|
|
201
|
+
console.log("");
|
|
202
|
+
return { failed: true };
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (status.failReason === "invalid_settings_json") {
|
|
206
|
+
console.log(` ${colorize("✗", "31")} settings.json invalid JSON`);
|
|
207
|
+
console.log(" Fix: repair ~/.claude/settings.json, then re-run cpmm doctor");
|
|
208
|
+
console.log("");
|
|
209
|
+
return { failed: true };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (!status.cpmmHookFound) {
|
|
213
|
+
console.log(` ${colorize("✗", "31")} CPMM hook critical-action-check.sh missing`);
|
|
214
|
+
console.log(" Fix: re-run cpmm setup");
|
|
215
|
+
console.log("");
|
|
216
|
+
return { failed: true };
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
console.log(` ${colorize("✓", "32")} CPMM hook critical-action-check.sh detected`);
|
|
220
|
+
|
|
221
|
+
if (!status.hookEnabled) {
|
|
222
|
+
console.log(` ${colorize("○", "33")} RTK hook not enabled (opt-in)`);
|
|
223
|
+
console.log(` Enable: rtk init -g --hook-only`);
|
|
224
|
+
console.log(` Docs: ${RTK_DOCS_URL}`);
|
|
225
|
+
console.log("");
|
|
226
|
+
return { failed: false };
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (status.orderOk) {
|
|
230
|
+
console.log(` ${colorize("✓", "32")} Hook order CPMM safety hook precedes RTK hook`);
|
|
231
|
+
} else {
|
|
232
|
+
console.log(` ${colorize("✗", "31")} Hook order RTK hook precedes CPMM safety hook`);
|
|
233
|
+
console.log(" Fix order in ~/.claude/settings.json:");
|
|
234
|
+
console.log(" 1) ~/.claude/scripts/hooks/critical-action-check.sh (timeout: 5)");
|
|
235
|
+
console.log(" 2) ~/.claude/hooks/rtk-rewrite.sh (timeout: 10)");
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (status.timeoutOk) {
|
|
239
|
+
console.log(` ${colorize("✓", "32")} RTK timeout 10`);
|
|
240
|
+
} else {
|
|
241
|
+
const rendered = status.timeoutValue == null ? "missing" : String(status.timeoutValue);
|
|
242
|
+
console.log(` ${colorize("⚠", "33")} RTK timeout ${rendered} (recommended: 10)`);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
console.log("");
|
|
246
|
+
return { failed: !status.orderOk };
|
|
247
|
+
}
|
|
248
|
+
|
|
131
249
|
function runSetup() {
|
|
132
250
|
console.log(`CPMM v${pkg.version} - Setup`);
|
|
133
251
|
|
|
@@ -159,6 +277,9 @@ function runSetup() {
|
|
|
159
277
|
printStatus(results);
|
|
160
278
|
}
|
|
161
279
|
|
|
280
|
+
const rtkResult = attemptRtkInstall();
|
|
281
|
+
printRtkSetupResult(rtkResult);
|
|
282
|
+
|
|
162
283
|
// Run install.sh for config files, language, and Perplexity setup
|
|
163
284
|
if (!runInstallScript()) {
|
|
164
285
|
return 1;
|
|
@@ -191,13 +312,16 @@ function runDoctor() {
|
|
|
191
312
|
const results = checkDeps();
|
|
192
313
|
printStatus(results);
|
|
193
314
|
|
|
315
|
+
const rtkStatus = inspectRtkStatus(path.join(process.env.HOME || process.env.USERPROFILE || "", ".claude", "settings.json"));
|
|
316
|
+
const rtkDoctor = printRtkDoctorStatus(rtkStatus);
|
|
317
|
+
|
|
194
318
|
const missing = results.filter((r) => r.required && !r.installed);
|
|
195
|
-
if (missing.length > 0) {
|
|
319
|
+
if (missing.length > 0 || rtkDoctor.failed) {
|
|
196
320
|
console.log(`Fix: cpmm setup`);
|
|
197
321
|
return 1;
|
|
198
322
|
}
|
|
199
323
|
|
|
200
|
-
console.log("All checks passed.");
|
|
324
|
+
console.log(colorize("All required checks passed.", "32"));
|
|
201
325
|
return 0;
|
|
202
326
|
}
|
|
203
327
|
|
|
@@ -205,8 +329,8 @@ function printHelp() {
|
|
|
205
329
|
console.log(`CPMM v${pkg.version}
|
|
206
330
|
|
|
207
331
|
Usage:
|
|
208
|
-
cpmm setup Install deps + configure CPMM (language, Perplexity)
|
|
209
|
-
cpmm doctor Check dependency status
|
|
332
|
+
cpmm setup Install deps + configure CPMM (language, Perplexity, optional RTK)
|
|
333
|
+
cpmm doctor Check dependency and RTK hook status
|
|
210
334
|
cpmm --help Show this help
|
|
211
335
|
cpmm --version Show version
|
|
212
336
|
`);
|
package/lib/rtk.js
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const fs = require("node:fs");
|
|
4
|
+
const os = require("node:os");
|
|
5
|
+
const path = require("node:path");
|
|
6
|
+
const { execSync, spawnSync } = require("node:child_process");
|
|
7
|
+
|
|
8
|
+
const RTK_INSTALL_URL = "https://raw.githubusercontent.com/rtk-ai/rtk/refs/heads/master/install.sh";
|
|
9
|
+
const RTK_DOCS_URL = "https://github.com/rtk-ai/rtk/blob/main/docs/INSTALL.md";
|
|
10
|
+
const CPMM_HOOK_NAME = "critical-action-check.sh";
|
|
11
|
+
const RTK_HOOK_NAME = "rtk-rewrite.sh";
|
|
12
|
+
|
|
13
|
+
function commandExists(cmd) {
|
|
14
|
+
try {
|
|
15
|
+
execSync(`command -v ${cmd}`, { stdio: "ignore" });
|
|
16
|
+
return true;
|
|
17
|
+
} catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function runCommand(bin, args, label) {
|
|
23
|
+
const rendered = [bin, ...args].join(" ");
|
|
24
|
+
console.log(` $ ${rendered}`);
|
|
25
|
+
const result = spawnSync(bin, args, { stdio: "inherit", env: { ...process.env } });
|
|
26
|
+
if (result.status !== 0) {
|
|
27
|
+
console.error(` FAIL: ${label} (exit ${result.status})`);
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function getRtkManualInstallHints() {
|
|
34
|
+
return [
|
|
35
|
+
"RTK is optional. CPMM setup will continue without it.",
|
|
36
|
+
"Install RTK manually with one of these upstream-supported methods:",
|
|
37
|
+
" - brew install rtk",
|
|
38
|
+
` - curl -fsSL ${RTK_INSTALL_URL} | sh`,
|
|
39
|
+
` - Docs: ${RTK_DOCS_URL}`,
|
|
40
|
+
];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function attemptRtkInstall() {
|
|
44
|
+
if (commandExists("rtk")) {
|
|
45
|
+
return {
|
|
46
|
+
ok: true,
|
|
47
|
+
outcome: "already_installed",
|
|
48
|
+
method: "existing",
|
|
49
|
+
message: "RTK already installed.",
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (commandExists("brew")) {
|
|
54
|
+
const ok = runCommand("brew", ["install", "rtk"], "rtk (brew)");
|
|
55
|
+
if (ok) {
|
|
56
|
+
return {
|
|
57
|
+
ok: true,
|
|
58
|
+
outcome: "installed",
|
|
59
|
+
method: "brew",
|
|
60
|
+
message: "RTK installed via Homebrew.",
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (commandExists("curl")) {
|
|
66
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "cpmm-rtk-"));
|
|
67
|
+
const scriptPath = path.join(tempDir, "install.sh");
|
|
68
|
+
try {
|
|
69
|
+
const downloaded = runCommand("curl", ["-fsSL", RTK_INSTALL_URL, "-o", scriptPath], "rtk installer download");
|
|
70
|
+
const installed = downloaded ? runCommand("sh", [scriptPath], "rtk installer") : false;
|
|
71
|
+
return {
|
|
72
|
+
ok: installed,
|
|
73
|
+
outcome: installed ? "installed" : "manual_action_required",
|
|
74
|
+
method: "curl",
|
|
75
|
+
message: installed ? "RTK installed via upstream installer." : "RTK upstream installer failed.",
|
|
76
|
+
};
|
|
77
|
+
} finally {
|
|
78
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
ok: false,
|
|
84
|
+
outcome: "manual_action_required",
|
|
85
|
+
method: "manual",
|
|
86
|
+
message: "No supported automatic RTK installer found.",
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function matcherIncludesBash(matcher) {
|
|
91
|
+
return String(matcher || "")
|
|
92
|
+
.split("|")
|
|
93
|
+
.map((token) => token.trim())
|
|
94
|
+
.includes("Bash");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function flattenBashHooks(settings) {
|
|
98
|
+
const entries = Array.isArray(settings?.hooks?.PreToolUse) ? settings.hooks.PreToolUse : [];
|
|
99
|
+
const flattened = [];
|
|
100
|
+
|
|
101
|
+
entries.forEach((entry, entryIndex) => {
|
|
102
|
+
if (!matcherIncludesBash(entry?.matcher)) return;
|
|
103
|
+
const hooks = Array.isArray(entry?.hooks) ? entry.hooks : [];
|
|
104
|
+
hooks.forEach((hook, hookIndex) => {
|
|
105
|
+
flattened.push({
|
|
106
|
+
entryIndex,
|
|
107
|
+
hookIndex,
|
|
108
|
+
command: String(hook?.command || ""),
|
|
109
|
+
timeout: hook?.timeout,
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
return flattened;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function inspectRtkStatus(settingsPath) {
|
|
118
|
+
const result = {
|
|
119
|
+
binaryInstalled: commandExists("rtk"),
|
|
120
|
+
settingsPath,
|
|
121
|
+
cpmmHookFound: false,
|
|
122
|
+
hookEnabled: false,
|
|
123
|
+
orderOk: null,
|
|
124
|
+
timeoutValue: null,
|
|
125
|
+
timeoutOk: null,
|
|
126
|
+
failReason: null,
|
|
127
|
+
warnings: [],
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
if (!fs.existsSync(settingsPath)) {
|
|
131
|
+
result.failReason = "missing_settings_json";
|
|
132
|
+
return result;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let parsed;
|
|
136
|
+
try {
|
|
137
|
+
parsed = JSON.parse(fs.readFileSync(settingsPath, "utf8"));
|
|
138
|
+
} catch {
|
|
139
|
+
result.failReason = "invalid_settings_json";
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const hooks = flattenBashHooks(parsed);
|
|
144
|
+
const cpmmIndex = hooks.findIndex((hook) => hook.command.includes(CPMM_HOOK_NAME));
|
|
145
|
+
if (cpmmIndex === -1) {
|
|
146
|
+
result.failReason = "missing_cpmm_hook";
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
result.cpmmHookFound = true;
|
|
151
|
+
|
|
152
|
+
const rtkIndex = hooks.findIndex((hook) => hook.command.includes(RTK_HOOK_NAME));
|
|
153
|
+
if (rtkIndex === -1) {
|
|
154
|
+
return result;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
result.hookEnabled = true;
|
|
158
|
+
result.orderOk = cpmmIndex < rtkIndex;
|
|
159
|
+
if (!result.orderOk) {
|
|
160
|
+
result.failReason = "rtk_precedes_cpmm";
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const rtkHook = hooks[rtkIndex];
|
|
164
|
+
result.timeoutValue = typeof rtkHook.timeout === "number" ? rtkHook.timeout : null;
|
|
165
|
+
result.timeoutOk = result.timeoutValue === 10;
|
|
166
|
+
if (!result.timeoutOk) {
|
|
167
|
+
result.warnings.push("rtk_timeout_not_10");
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return result;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
module.exports = {
|
|
174
|
+
RTK_DOCS_URL,
|
|
175
|
+
RTK_INSTALL_URL,
|
|
176
|
+
attemptRtkInstall,
|
|
177
|
+
getRtkManualInstallHints,
|
|
178
|
+
inspectRtkStatus,
|
|
179
|
+
};
|
package/package.json
CHANGED
|
@@ -77,6 +77,16 @@ flowchart TB
|
|
|
77
77
|
|
|
78
78
|
**비용 설명:** 모든 Hook은 머신에서 로컬로 실행되어 API 호출이 없습니다. Hook이 Claude에게 메시지를 표시할 때만(예: 명령 차단, 컴팩션 제안) 해당 메시지가 입력 토큰을 소비하며, 이러한 메시지는 의도적으로 간결합니다.
|
|
79
79
|
|
|
80
|
+
## RTK 순서
|
|
81
|
+
|
|
82
|
+
RTK를 opt-in으로 사용할 때는 CPMM의 Bash safety hook를 먼저 두고, RTK rewrite hook를 그 뒤에 둡니다.
|
|
83
|
+
|
|
84
|
+
권장 순서 (`~/.claude/settings.json`):
|
|
85
|
+
- `~/.claude/scripts/hooks/critical-action-check.sh` with `timeout: 5`
|
|
86
|
+
- `~/.claude/hooks/rtk-rewrite.sh` with `timeout: 10`
|
|
87
|
+
|
|
88
|
+
이 순서를 유지해야 CPMM의 위험 명령 차단이 RTK rewrite보다 먼저 실행됩니다.
|
|
89
|
+
|
|
80
90
|
## 종료 코드
|
|
81
91
|
|
|
82
92
|
| 코드 | 동작 |
|
package/scripts/hooks/README.md
CHANGED
|
@@ -77,6 +77,16 @@ flowchart TB
|
|
|
77
77
|
|
|
78
78
|
**Cost Explanation:** All hooks run locally on your machine without API calls. Only when a hook displays a message to Claude (e.g., blocking a command, suggesting compaction) does that message consume input tokens—and these messages are intentionally brief.
|
|
79
79
|
|
|
80
|
+
## RTK Ordering
|
|
81
|
+
|
|
82
|
+
If you opt into RTK, keep CPMM's Bash safety hook first and RTK's rewrite hook second.
|
|
83
|
+
|
|
84
|
+
Recommended order in `~/.claude/settings.json`:
|
|
85
|
+
- `~/.claude/scripts/hooks/critical-action-check.sh` with `timeout: 5`
|
|
86
|
+
- `~/.claude/hooks/rtk-rewrite.sh` with `timeout: 10`
|
|
87
|
+
|
|
88
|
+
This preserves CPMM's critical-action block before RTK rewrites the Bash command.
|
|
89
|
+
|
|
80
90
|
## Exit Codes
|
|
81
91
|
|
|
82
92
|
| Code | Behavior |
|
|
@@ -115,4 +125,3 @@ Output to **stderr** is shown to Claude when blocking (exit 2). Note: stdout JSO
|
|
|
115
125
|
2. Make executable: `chmod +x script.sh`
|
|
116
126
|
3. Add to `settings.json` or agent frontmatter
|
|
117
127
|
4. Test with various inputs
|
|
118
|
-
|