@kaydash9999/banker-plugins 0.21.0 → 0.22.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +28 -0
- package/PRIVACY.md +7 -3
- package/README.md +41 -4
- package/bin/banker.js +38 -12
- package/bin/lib/codex-hooks.mjs +7 -2
- package/bin/lib/codex-routes.mjs +112 -0
- package/bin/lib/command-skill.cjs +19 -0
- package/bin/lib/telemetry-config.mjs +2 -1
- package/codex/command-skills/front-qa/SKILL.md +56 -0
- package/codex/command-skills/setup/SKILL.md +87 -0
- package/codex/hooks.json +29 -0
- package/codex/skills/graceful-pause/SKILL.md +2 -2
- package/commands/setup.md +2 -2
- package/hooks/telemetry-count-codex.mjs +112 -25
- package/hooks/update-notify.mjs +82 -11
- package/package.json +1 -1
- package/skills/3d-intro-build/references/verify-intro.mjs +15 -1
- package/skills/anti-drm/SKILL.md +1 -1
- package/skills/anti-drm/scripts/instruction-toggle.mjs +57 -4
- package/skills/arch-diagram/build_pptx_template.py +47 -28
- package/skills/audit-web-page/SKILL.md +1 -1
- package/skills/audit-web-page/harness.py +0 -1
- package/skills/lineage/lineage.py +1435 -533
- package/skills/motion-graphic-make/SKILL.md +1 -1
- package/skills/obsidizer/SKILL.md +20 -5
- package/skills/payload-mon/SKILL.md +1 -1
- package/skills/play-qa/SKILL.md +1 -1
- package/skills/ralph-qa/SKILL.md +1 -1
- package/skills/remains/SKILL.md +1 -1
- package/skills/rfp-author/scripts/md2docx.py +63 -34
- package/skills/setup-bypass-permissions/SKILL.md +2 -2
- package/skills/setup-bypass-permissions/scripts/fallback/bypass-permissions.py +66 -15
- package/skills/smart-compact/SKILL.md +1 -1
- package/skills/smart-compact/scripts/codex-gate.mjs +2 -1
- package/skills/theme-selection/SKILL.md +1 -1
- package/skills/tone-compact/SKILL.md +1 -1
- package/skills/tone-compact/scripts/instruction-toggle.mjs +57 -4
- package/skills/ultra-chain/SKILL.md +2 -2
- package/skills/ultra-ui-qa/SKILL.md +1 -1
- package/skills/update-banker/SKILL.md +31 -6
- package/skills/vertical-pptx/SKILL.md +1 -1
- package/skills/vertical-pptx/build_a4p.js +20 -2
- package/skills/vertical-pptx/build_a4p.py +560 -359
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "banker",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"description": "Claude Code plugin: QA/audit/docs/architecture skills + commands, a /banker:setup installer for OS dependencies (playwright, etc.), and wiki compaction.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "smallOpenSource",
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.22.0] - 2026-10-29
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- Codex 의 plugin 명령으로도 설치할 수 있다: `codex plugin marketplace add smallOpenSource/banker_plugins` 뒤 `codex plugin add banker@banker-plugins`. 스킬은 `$banker:<이름>` 으로 부른다. npm 길(`banker setup --codex`, `$banker-<이름>`)과 같은 구성요소가 들어간다.
|
|
7
|
+
- Codex 플러그인 매니페스트 `.codex-plugin/plugin.json`: 스킬 폴더 셋(`skills/`, Codex 전용 `codex/skills/`, 명령을 스킬로 바꾼 `codex/command-skills/`), 훅 파일 `codex/hooks.json`, `commands: []`(Codex 0.160 이 Claude 명령을 `source-command-*` 스킬로 바꾸지 않게).
|
|
8
|
+
- 훅: 업데이트 알림(`SessionStart`)과 사용량 카운팅(`Stop`). `/hooks` 에서 신뢰한 뒤에 돈다. obsidizer 훅은 `obsidizer --enable` 할 때만 사용자 범위에 따로 설치한다.
|
|
9
|
+
- 두 길을 함께 두면 스킬이 두 이름으로 겹친다. 세션 시작 알림, `banker setup --codex`, `banker doctor` 가 알리고, 지우지는 않는다(프로젝트 범위 npm 설치도 본다).
|
|
10
|
+
- 스킬 본문의 Codex 경로 안내가 두 길을 모두 적는다.
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
- Codex 플러그인 훅이 샌드박스 밖에서 돌리는 node 를 고르는 규칙: PATH 의 node 를 실제 경로로 풀어, 임시 폴더나 작업 폴더 안이면 돌리지 않고 이유를 알린다(작업 폴더가 홈 자체면 작업 폴더 규칙은 쓰지 않음). 플러그인 폴더에서 돈다. npm 길 훅도 홈 폴더에서 연 세션의 nvm node 를 받는다.
|
|
14
|
+
- multicall shim(Volta, mise, snap)과 Windows 의 `node.cmd` shim 은 그 shim 에 실제 node 를 물어 그 node 로 돈다.
|
|
15
|
+
- node 를 찾은 뒤에는 PATH 에서 임시 폴더와 작업 폴더 아래 항목을 빼, `realpath`, `readlink` 와 shim 이 부르는 프로그램을 프로젝트의 `.venv/bin`, `node_modules/.bin` 같은 곳에서 가져오지 않는다. Windows 는 경로를 비교할 때 링크, junction, subst 드라이브를 풀고 8.3 짧은 이름도 긴 경로로 비교하며, node 를 찾을 때부터 네트워크 드라이브와 UNC PATH 항목은 읽지 않는다(Windows PowerShell 5.1 과 pwsh 7 에서 시험).
|
|
16
|
+
- macOS 데스크톱에서 연 Codex 처럼 PATH 에 node 가 없으면 Homebrew(`/opt/homebrew/bin`)와 공식 설치(`/usr/local/bin`) 위치를 본다. realpath 와 `readlink -f` 가 없는 macOS 12.3 미만도 링크를 따라가 판단한다.
|
|
17
|
+
- Codex 플러그인 훅 명령 앞에 훅이 실행하는 파일의 해시(`banker-hooks-rev`)가 붙는다. 훅 코드가 바뀐 판은 Codex 가 `/hooks` 에서 신뢰를 다시 묻고, 신뢰하기 전에는 돌지 않는다(0.144.5, 0.160.1 실측).
|
|
18
|
+
- 두 길의 훅이 같은 세션에서 함께 돌아도 세션 시작 알림과 사용 횟수는 한 번이다(세션 id 폴더 `codex-sessions/`, 턴 키 잠금. PRIVACY.md). 30초 넘게 지나 같은 세션을 이어 열면(resume) 알림을 다시 확인한다.
|
|
19
|
+
- 사용 기록과 체크인의 스킬 이름은 소문자만 받는다.
|
|
20
|
+
- `vertical-pptx` python 빌더가 node 빌더와 같은 글꼴 체인과 대조로 글꼴을 고른다. Windows 에 `NotoSansKR-VF.ttf` 만 있을 때 없는 이름 `Noto Sans CJK KR` 을 적던 것, ASCII 글자 없는 이름(예: 나눔고딕)을 아무 파일로 찾던 것, Windows junction 글꼴 폴더로 들어가던 것을 고친다. node 빌더는 `--font constructor` 에서 멈추지 않는다.
|
|
21
|
+
- `tone-compact`, `anti-drm` 의 Codex 지침 쓰기가 Windows 에서 끊어진 링크를 따라가 그 너머에 파일을 만들던 것을 고친다(잠금, 새 `AGENTS.md`, 임시 파일).
|
|
22
|
+
- `obsidizer --enable` 의 Codex 훅 설치 절차는 설치 길과 관계없이 실제 node 와 `banker.js` 의 절대경로를 확인한 뒤 샌드박스 밖 실행을 요청한다.
|
|
23
|
+
- `3d-intro-build` 의 측정(`verify-intro`)이 Chromium 의 일시적 `Unable to capture screenshot` 에서 멈추지 않고 세 번까지 다시 찍는다.
|
|
24
|
+
- README 의 Codex CLI 설치 안내가 플러그인 마켓플레이스 길(`codex plugin marketplace add smallOpenSource/banker_plugins` 뒤 `codex plugin add banker@banker-plugins`)을 권장으로 적는다.
|
|
25
|
+
|
|
26
|
+
### Notes
|
|
27
|
+
- main 에 push 한 커밋은 다음 Codex 세션에서 플러그인 사용자에게 바로 간다(Codex 가 세션 시작 때 git 마켓플레이스를 올림). RELEASING.md 9번에 적었다.
|
|
28
|
+
- 유지보수자용: Windows 에서 늘 건너뛰던 링크 시험 29건이 링크를 만들 수 있는 계정이면 돈다(`scripts/test-fixtures/can-symlink.mjs`). 파이썬 파일은 `ruff format` 을 따르고 `ruff.toml` 의 대상 판은 3.7 이다(3.6 에서도 파싱).
|
|
29
|
+
- 실측: 실제 Codex 0.144.5(Linux), 0.160.1(Linux, macOS, Windows), 0.165.0(macOS, Rocky Linux 8). vertical-pptx 결과는 Windows 에서 LibreOffice 26.8 로 렌더해 Noto Sans KR 과 맑은 고딕이 대체 글꼴 없이 그려짐을 확인했다. PowerPoint 로는 렌더하지 않았다.
|
|
30
|
+
|
|
3
31
|
## [0.21.0] - 2026-10-28
|
|
4
32
|
|
|
5
33
|
### Added
|
package/PRIVACY.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
하나는 새 버전이 나왔을 때 알려주는 **업데이트 알림**이고, 다른 하나는 유지보수자가 사용량을 파악하기 위한 **익명 사용량 카운팅**입니다.\
|
|
9
9
|
두 기능 모두 기본값은 켜짐(default-on)이며, 따로 끌 수 있습니다.\
|
|
10
10
|
다만 사용량 체크인은 업데이트 확인과 함께 보내므로, 업데이트 알림을 끄면(`BANKER_NO_UPDATE_CHECK`) 체크인 전송도 멈춥니다. 그때 카운팅 기록은 이 기기에만 쌓이다가 5,000줄에서 멈춥니다.\
|
|
11
|
-
Claude Code 와 Codex CLI 모두에서 동작합니다. Codex 에서는 `banker setup --codex` 가 Codex 훅으로
|
|
11
|
+
Claude Code 와 Codex CLI 모두에서 동작합니다. Codex 에서는 `banker setup --codex` 가 Codex 훅으로 설치하거나, Codex 플러그인(`codex plugin add banker@banker-plugins`)이 훅을 함께 가져옵니다. 수집 범위는 아래 "Codex CLI" 절에 있습니다.
|
|
12
12
|
|
|
13
13
|
## 현재 상태
|
|
14
14
|
|
|
@@ -90,19 +90,23 @@ opt-out 하더라도 훅의 등록 자체는 남고, 각 스크립트 내부의
|
|
|
90
90
|
훅 스크립트는 `~/.codex/hooks-custom/banker/` 사본에서 돌고, Codex 를 다시 열 때 뜨는 Hooks need review 창이나 `/hooks` 에서 사용자가 신뢰해야 돌기 시작합니다.\
|
|
91
91
|
`banker uninstall --codex` 가 둘 다 지우고, `banker hooks disable update` 나 `banker hooks disable count` 로 하나씩 끌 수 있습니다.
|
|
92
92
|
|
|
93
|
+
Codex 플러그인으로 설치하면 같은 두 훅이 플러그인의 `codex/hooks.json` 에서 오고, 설치된 플러그인 폴더(`~/.codex/plugins/cache/banker-plugins/banker/<판>/`)에서 돕니다.\
|
|
94
|
+
역시 `/hooks` 에서 신뢰해야 돌고, 신뢰하지 않거나 `/hooks` 에서 끄면 돌지 않습니다. `codex plugin remove banker@banker-plugins` 가 이 두 훅을 함께 지웁니다. `obsidizer --enable` 로 따로 설치한 obsidizer 훅은 사용자 범위에 있어 남습니다(README 의 제거 절).
|
|
95
|
+
|
|
93
96
|
- `SessionStart`: 세션 시작 시 1회, Claude Code 와 같은 캐시로 업데이트 알림을 확인합니다. 알림은 TUI 에 경고 줄로 보입니다.
|
|
94
97
|
- `Stop`: 턴이 끝날 때 1회, 이번 턴에 쓴 banker 스킬 이름을 셉니다. 도구 호출마다 돌지 않습니다.
|
|
95
98
|
|
|
96
99
|
Codex 카운팅이 읽는 것과 남기는 것은 다음과 같습니다.
|
|
97
100
|
|
|
98
|
-
- 읽는 것: 훅 입력이 알려 주는 이 세션의 Codex 기록 파일(rollout)에서 이번 턴 부분만. 그중 도구 호출 기록과, `$banker-<이름>` 으로 부른 스킬을 Codex 가 넣은 머리 줄의 `skills/banker-<이름>/SKILL.md` 경로만 봅니다. 이 Codex 에 설치된 banker 스킬 이름만 셉니다.
|
|
101
|
+
- 읽는 것: 훅 입력이 알려 주는 이 세션의 Codex 기록 파일(rollout)에서 이번 턴 부분만. 그중 도구 호출 기록과, `$banker-<이름>`(플러그인은 `$banker:<이름>`)으로 부른 스킬을 Codex 가 넣은 머리 줄의 `skills/banker-<이름>/SKILL.md`(플러그인은 `plugins/cache/<마켓플레이스>/banker/<판>/.../<이름>/SKILL.md`) 경로만 봅니다. 이 Codex 에 설치된 banker 스킬 이름만 셉니다.
|
|
99
102
|
- 보지 않는 것: 사용자가 입력한 글, 모델의 답, 도구 결과, 스킬 본문.
|
|
100
103
|
- 로컬에 남기는 것: Claude Code 와 같은 `usage-log`, `used-skills.json` 의 스킬 이름과 시간대, 같은 턴을 두 번 세지 않게 하는 최근 턴 키(`codex-count-turns`, Codex 세션 ID 와 턴 ID, 최근 100개).
|
|
104
|
+
- 로컬에 남기는 것(추가): 세션 시작 알림을 낸 Codex 세션 ID 를 이름으로 한 빈 폴더(`codex-sessions/`, 이틀 뒤 지움). npm 설치와 플러그인 설치의 훅이 함께 돌 때 같은 세션에 두 번 알리지 않는 데만 쓰고 전송하지 않습니다.
|
|
101
105
|
- 로컬에 남기는 것(추가): 이 훅이 기록 형식을 읽지 못한 Codex 버전(`codex-shape-miss.json`, 버전과 알림 여부만). 다음 세션 시작 때 경고를 한 번 보이는 데만 쓰고 전송하지 않습니다.
|
|
102
106
|
- 전송하는 것: Claude Code 와 같은 체크인 `{version, os, counts}` 입니다. 세션 ID 와 턴 ID 는 전송하지 않습니다.
|
|
103
107
|
|
|
104
108
|
Codex 훅은 Codex 샌드박스 밖에서 돌므로, 샌드박스가 네트워크를 막아도 업데이트 조회와 체크인은 Claude Code 와 같이 나갑니다.\
|
|
105
|
-
끄는 방법(`BANKER_NO_TELEMETRY`, `BANKER_NO_UPDATE_CHECK`, `banker telemetry off`)도 같습니다.
|
|
109
|
+
끄는 방법(`BANKER_NO_TELEMETRY`, `BANKER_NO_UPDATE_CHECK`, `banker telemetry off`)도 같습니다. 플러그인만 설치해 `banker` 명령이 없으면 두 환경 변수를 쓰거나 `/hooks` 에서 banker 훅을 끕니다.
|
|
106
110
|
|
|
107
111
|
## 전송 안전
|
|
108
112
|
|
package/README.md
CHANGED
|
@@ -37,21 +37,38 @@ Claude Code 세션 안에서 입력합니다.
|
|
|
37
37
|
|
|
38
38
|
스킬과 커맨드를 `/banker:audit-security` 처럼 `/banker:` 로 호출합니다.
|
|
39
39
|
|
|
40
|
-
**Codex CLI:**
|
|
40
|
+
**Codex CLI:** 두 방법 중 하나를 고릅니다.
|
|
41
|
+
|
|
42
|
+
1) Codex 플러그인 마켓플레이스로 설치 (권장, npm 불필요)
|
|
43
|
+
|
|
44
|
+
터미널 셸에서 입력합니다. 첫 줄은 이 GitHub 저장소를 Codex 의 플러그인 마켓플레이스 `banker-plugins` 로 등록하고, 둘째 줄은 그 마켓플레이스에서 banker 플러그인을 설치합니다.
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
codex plugin marketplace add smallOpenSource/banker_plugins
|
|
48
|
+
codex plugin add banker@banker-plugins
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
스킬을 `$banker:audit-security` 처럼 `$banker:<name>` 으로 호출합니다.\
|
|
52
|
+
훅(업데이트 알림, 사용량 카운팅)은 Codex 를 다시 열 때 뜨는 Hooks need review 창이나 `/hooks` 에서 신뢰해야 돕니다.\
|
|
53
|
+
Codex 는 세션을 시작할 때 마켓플레이스를 스스로 올려 새 판을 받습니다. 바로 올리려면 `codex plugin marketplace upgrade banker-plugins` 를 실행합니다.
|
|
54
|
+
|
|
55
|
+
2) npm 전역 설치 후 `banker setup`
|
|
41
56
|
|
|
42
57
|
```bash
|
|
43
58
|
npm i -g @kaydash9999/banker-plugins
|
|
44
59
|
banker setup --codex
|
|
45
60
|
```
|
|
46
61
|
|
|
47
|
-
스킬을
|
|
62
|
+
스킬을 `$banker-audit-security` 처럼 `$banker-<name>` 으로 호출합니다.
|
|
63
|
+
|
|
64
|
+
두 방법을 함께 쓰지 않습니다. 함께 두면 스킬과 훅이 두 벌이 되고, banker 가 세션 시작과 `banker doctor` 에서 알립니다.
|
|
48
65
|
|
|
49
66
|
playwright(브라우저 QA)나 oh-my-claudecode(OMC/OMX)처럼 별도 의존성이 필요한 스킬은 실행 전에 설치부터 안내합니다(Claude Code는 `/banker:setup`).
|
|
50
67
|
|
|
51
68
|
## 워크플로 사용 예시
|
|
52
69
|
|
|
53
70
|
무엇부터 써야 할지 막막할 때, 상황별로 골라 쓰는 대표 워크플로입니다.\
|
|
54
|
-
Claude Code는 `/banker:<이름>`, Codex는
|
|
71
|
+
Claude Code는 `/banker:<이름>`, Codex는 `$banker-<이름>`(플러그인 설치면 `$banker:<이름>`)으로 호출합니다.
|
|
55
72
|
|
|
56
73
|
| 워크플로 | 언제 쓰나 | 하는 일 |
|
|
57
74
|
|---|---|---|
|
|
@@ -194,7 +211,7 @@ USER_RESOURCES 가이드의 공통 요소를 OS별·런타임별(Claude Code/Cod
|
|
|
194
211
|
## 설치 상세 (npm · Codex)
|
|
195
212
|
|
|
196
213
|
마켓플레이스 대신 npm으로 전역 설치할 수 있고, Codex CLI에도 스킬을 설치할 수 있습니다.\
|
|
197
|
-
Codex
|
|
214
|
+
Codex CLI 에는 두 길이 있습니다. Codex 플러그인 마켓플레이스 길(`codex plugin marketplace add` 뒤 `codex plugin add`, npm 불필요, 아래 목록의 Codex 플러그인 항목)과 npm 길(`banker setup --codex`, npm 전역 설치가 먼저)입니다. 둘 중 하나만 씁니다.
|
|
198
215
|
|
|
199
216
|
```bash
|
|
200
217
|
npm i -g @kaydash9999/banker-plugins
|
|
@@ -213,6 +230,14 @@ banker uninstall # 제거
|
|
|
213
230
|
Codex 를 업데이트한 뒤에는 `banker doctor` 로 형식을 점검합니다. 읽지 못하면 lineage 는 빈 페이지 대신 오류로 멈추고, progress 는 경고 줄을 보이며, 카운팅은 다음 세션 시작 때 경고를 한 번 보입니다. \
|
|
214
231
|
Codex 0.144 이상에는 사용자 프롬프트가 없으므로 커맨드 2개는 스킬로도 설치되어 `$banker-front-qa`, `$banker-setup` 으로 부릅니다. \
|
|
215
232
|
디렉터리명과 일치하도록 프론트매터 `name:` 이 `banker-<name>` 으로 재작성되어 Codex가 `banker-<name>` 으로 인식합니다.
|
|
233
|
+
- Codex 플러그인 설치(`codex plugin add banker@banker-plugins`)는 저장소를 `~/.codex/plugins/cache/banker-plugins/banker/<판>/` 에 두고 `.codex-plugin/plugin.json` 을 읽습니다. \
|
|
234
|
+
스킬 64개, Codex 전용 스킬 2개, 커맨드 2개(스킬로)가 `$banker:<name>` 으로 보이고, 업데이트 알림과 사용량 카운팅 훅은 `codex/hooks.json` 에서 옵니다. \
|
|
235
|
+
Codex 는 세션을 시작할 때 마켓플레이스를 스스로 올려 새 판을 설치합니다. 훅 명령 앞에는 훅이 실행하는 파일의 해시가 붙어 있어, 훅 코드가 바뀐 판에서는 `/hooks` 가 다시 신뢰를 묻고 신뢰하기 전에는 훅이 돌지 않습니다. 훅 코드가 그대로인 판은 신뢰도 그대로입니다. 스킬 파일은 신뢰 확인 없이 새 판으로 바뀝니다. \
|
|
236
|
+
obsidizer 훅은 npm 설치와 같이 `obsidizer --enable` 할 때만 사용자 범위에 설치됩니다(셸 호출마다 node 를 띄우므로). \
|
|
237
|
+
훅은 Codex 샌드박스 밖에서 돌므로, PATH 의 node 가 임시 폴더나 작업 폴더 안에 있으면(샌드박스가 바꿀 수 있는 곳) 아무것도 돌리지 않고 그 이유를 세션 시작 알림으로 보입니다. 작업 폴더가 홈 폴더 자체이면 홈 아래의 node(nvm 등)는 그대로 씁니다. \
|
|
238
|
+
node 를 찾은 뒤에는 PATH 에서 임시 폴더와 작업 폴더 아래 항목을 빼므로, 프로젝트의 `.venv/bin` 이나 `node_modules/.bin` 에 있는 프로그램은 훅에서 돌지 않습니다(작업 폴더가 홈 폴더 자체이면 홈 아래 항목은 남깁니다). Windows 는 네트워크 드라이브와 UNC 경로의 PATH 항목을 읽지 않습니다. macOS 데스크톱에서 연 Codex 처럼 PATH 에 node 가 없으면 Homebrew(`/opt/homebrew/bin`)와 공식 설치(`/usr/local/bin`)의 node 를 씁니다. \
|
|
239
|
+
Volta, mise, snap 처럼 이름을 보고 동작하는 node 와 Windows 의 `node.cmd` shim(mise)은 그 도구가 고른 node 를 씁니다. 훅은 플러그인 폴더에서 돌므로 asdf, nodenv 는 전역 버전(`asdf set -u nodejs <판>`, asdf 0.16 미만은 `asdf global nodejs <판>`, `nodenv global <판>`)이 있어야 합니다. \
|
|
240
|
+
이 설치에는 `banker` 명령이 없습니다. `banker doctor`, `banker telemetry` 가 필요하면 npm 으로도 설치하되 `banker setup`(인자 없음)과 `banker setup --codex` 는 돌리지 않습니다(Codex 에 npm 길이 함께 설치됨). Claude Code 에 넣으려면 `banker setup --claude` 만 씁니다.
|
|
216
241
|
- OMC/Claude 에 결합됐던 오케스트레이터·설치·유틸 표면(all-in-one·ultra-chain·ultra-init·front-qa·setup·setup-omc·setup-omc-hud·setup-stitch·omc-reference·compact-copy)은 본문이 **런타임 인식**이라 Codex에서도 동작합니다.
|
|
217
242
|
- `payload-mon` 은 Codex에서 실행해도 같은 머신의 Claude Code HUD 래퍼만 켜고 끕니다. \
|
|
218
243
|
32MB 요청 한도는 Claude Code 의 것이라 Codex 자신의 요청 크기는 재지 않습니다.
|
|
@@ -304,6 +329,17 @@ banker uninstall # 제거
|
|
|
304
329
|
|
|
305
330
|
Codex는 재설치할 때마다 기존 `banker-*` 를 먼저 정리하므로 옛 버전이 중복으로 남지 않습니다.
|
|
306
331
|
|
|
332
|
+
**Codex 플러그인:**
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
codex plugin marketplace upgrade banker-plugins # 최신화 (Codex 가 세션 시작 때도 스스로 올림, 다시 열면 적용)
|
|
336
|
+
codex plugin remove banker@banker-plugins # 제거
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
> Codex 플러그인 설치에서 `obsidizer --enable` 을 했다면, 제거 전에 obsidizer 의 Codex 절차대로 `hooks disable obsidize` 를 실행하세요.\
|
|
340
|
+
> 이 훅은 사용자 범위(`~/.codex/hooks.json`, `~/.codex/hooks-custom/banker/`)에 따로 있어서 `codex plugin remove` 로 지워지지 않고, 셸 호출마다 node 를 계속 띄웁니다.\
|
|
341
|
+
> 이미 지웠다면 `~/.codex/hooks.json` 에서 명령에 `hooks-custom/banker/hooks/obsidize-hook.mjs` 가 든 묶음을 지우고 `~/.codex/hooks-custom/banker/` 폴더를 지우면 됩니다.
|
|
342
|
+
|
|
307
343
|
> `payload-mon` 을 켰다면 제거 전에 `/banker:payload-mon off`(Codex는 `banker-payload-mon` 에 `off`)를 실행하세요.\
|
|
308
344
|
> 표시 블록과 모듈 사본은 플러그인 밖(`~/.claude/hud/`)에 있어서, 플러그인을 지워도 남아 계속 표시됩니다.\
|
|
309
345
|
> 이미 지웠다면 HUD를 재설치하거나, `omc-hud-custom.mjs` 에서 `// >>> payload-mon >>>` 부터 `// <<< payload-mon <<<` 까지 지우면 됩니다.
|
|
@@ -376,6 +412,7 @@ npm i -g ./kaydash9999-banker-plugins-<판>.tgz # 옮긴 뒤
|
|
|
376
412
|
banker setup
|
|
377
413
|
```
|
|
378
414
|
|
|
415
|
+
- Codex 플러그인 설치(`codex plugin add`)는 GitHub 에서 저장소를 받으므로 네트워크가 필요합니다. 오프라인에서는 위의 npm 묶음으로 `banker setup --codex` 를 씁니다.
|
|
379
416
|
- 세션 시작 훅의 업데이트 조회와 체크인은 따로 돌아 세션을 기다리게 하지 않습니다. 실패하면 24시간 동안 다시 시도하지 않고, 아예 시도하지 않게 하려면 `BANKER_NO_UPDATE_CHECK=1` 을 둡니다.
|
|
380
417
|
- 훅은 `HTTPS_PROXY`, `HTTP_PROXY` 를 따르지 않습니다(Node 가 `NODE_USE_ENV_PROXY=1` 일 때만 따름). 프록시를 거쳐야만 밖에 닿는 망에서는 훅의 확인이 실패로 기록됩니다(`banker telemetry status` 의 "마지막 시도").
|
|
381
418
|
- 네트워크가 필요한 스킬과 네트워크 없이 끝나는 모습
|
package/bin/banker.js
CHANGED
|
@@ -12,6 +12,7 @@ const os = require('os');
|
|
|
12
12
|
const path = require('path');
|
|
13
13
|
const cp = require('child_process');
|
|
14
14
|
const { pathToFileURL } = require('url');
|
|
15
|
+
const { commandSkillText } = require('./lib/command-skill.cjs');
|
|
15
16
|
|
|
16
17
|
const PKG_ROOT = path.resolve(__dirname, '..');
|
|
17
18
|
const MANIFEST = path.join(PKG_ROOT, 'codex', 'manifest.json');
|
|
@@ -162,17 +163,11 @@ function setCodexSkillName(skillMd, newName, dryRun) {
|
|
|
162
163
|
fs.writeFileSync(skillMd, src.slice(0, fm.index) + `---\n${block}\n---` + src.slice(fm.index + fm[0].length));
|
|
163
164
|
}
|
|
164
165
|
|
|
165
|
-
// A command as a Codex skill
|
|
166
|
-
// no $ARGUMENTS substitution, so a note says where the arguments come from.
|
|
166
|
+
// A command as a Codex skill (bin/lib/command-skill.cjs, shared with the Codex plugin's codex/command-skills/).
|
|
167
167
|
function writeCommandSkill(src, destDir, name, dryRun) {
|
|
168
168
|
if (dryRun) { log(` [dry-run] write command skill ${path.relative(PKG_ROOT, src)} -> ${destDir}`); return; }
|
|
169
|
-
const text = fs.readFileSync(src, 'utf8');
|
|
170
|
-
const fm = text.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
|
|
171
|
-
const desc = fm && fm[1].match(/^description:\s*(.*)$/m);
|
|
172
|
-
const body = fm ? text.slice(fm[0].length) : text;
|
|
173
|
-
const note = '> Codex: 이 명령은 스킬로 설치됐다. 본문의 `$ARGUMENTS`, `$1` 은 사용자가 `$' + name + '` 뒤에 쓴 글이다.\n\n';
|
|
174
169
|
fs.mkdirSync(destDir, { recursive: true });
|
|
175
|
-
fs.writeFileSync(path.join(destDir, 'SKILL.md'),
|
|
170
|
+
fs.writeFileSync(path.join(destDir, 'SKILL.md'), commandSkillText(fs.readFileSync(src, 'utf8'), name, `$${name}`));
|
|
176
171
|
}
|
|
177
172
|
|
|
178
173
|
/* ---------- Claude Code target ---------- */
|
|
@@ -278,7 +273,28 @@ function doctorCodexShape(base) {
|
|
|
278
273
|
else if (!r.toolCall) log(' (no tool calls: fine for a session that used no tools)');
|
|
279
274
|
}
|
|
280
275
|
|
|
281
|
-
|
|
276
|
+
// bin/lib/codex-routes.mjs is ESM: the two ways banker gets into Codex (this npm install, and the Codex plugin).
|
|
277
|
+
async function loadCodexRoutes() {
|
|
278
|
+
return import(pathToFileURL(path.join(__dirname, 'lib', 'codex-routes.mjs')).href);
|
|
279
|
+
}
|
|
280
|
+
// Codex plugin installs of banker in <base> as 'banker@<marketplace> (<versions in the plugin cache>)'.
|
|
281
|
+
async function codexPluginInstalls(base) {
|
|
282
|
+
const r = await loadCodexRoutes();
|
|
283
|
+
return r.pluginRoutes(base).map((id) => {
|
|
284
|
+
let vers = [];
|
|
285
|
+
try { vers = fs.readdirSync(path.join(base, 'plugins', 'cache', id.slice(id.indexOf('@') + 1), PLUGIN_NAME)); } catch {}
|
|
286
|
+
return `${id}${vers.length ? ` (${vers.join(', ')})` : ''}`;
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
// Beside the Codex plugin, this npm install shows every skill twice and runs every hook twice. Say so; remove nothing.
|
|
290
|
+
async function warnCodexPlugin(base) {
|
|
291
|
+
const ids = await codexPluginInstalls(base);
|
|
292
|
+
if (!ids.length) return;
|
|
293
|
+
warn(` ⚠ banker is also installed as a Codex plugin here: ${ids.join(', ')}. Skills show twice ($banker-<name> and $banker:<name>) and the hooks run twice.`);
|
|
294
|
+
warn(` Keep one: codex plugin remove ${ids[0].split(' ')[0]}, or banker uninstall --codex.`);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
async function doctor() {
|
|
282
298
|
log(`banker v${version()} (pkg: ${PKG_ROOT})`);
|
|
283
299
|
log(`plugin.json version: ${(() => { try { return require(PLUGIN_JSON).version; } catch { return '?'; } })()}`);
|
|
284
300
|
log('Claude Code:');
|
|
@@ -299,7 +315,12 @@ function doctor() {
|
|
|
299
315
|
log(` ⚠ dir/name mismatch (Codex will NOT list these) — reinstall with this version:`);
|
|
300
316
|
for (const x of mismatched) log(` ${x.d}/ has name: ${x.name}`);
|
|
301
317
|
}
|
|
302
|
-
|
|
318
|
+
const plugins = await codexPluginInstalls(base);
|
|
319
|
+
log(` Codex plugin (codex plugin add): ${plugins.length ? plugins.join(', ') : 'not installed'}`);
|
|
320
|
+
// A project-scope npm install (banker setup --codex --scope project) in this folder doubles the skills here too.
|
|
321
|
+
const projectNpm = (await loadCodexRoutes()).projectNpmRoot(process.cwd());
|
|
322
|
+
if (plugins.length && (installed.length || projectNpm)) log(` ⚠ banker is installed both ways${projectNpm && !installed.length ? ` (npm in ${path.join(projectNpm, '.codex')})` : ''}: skills show twice ($banker-<name> and $banker:<name>). Keep one: banker uninstall --codex, or codex plugin remove ${plugins[0].split(' ')[0]}`);
|
|
323
|
+
if (have('codex') && installed.length === 0 && !plugins.length) log(' ⚠ codex found but 0 banker skills installed — run: banker setup --codex, or codex plugin add banker@banker-plugins');
|
|
303
324
|
const m = readManifest();
|
|
304
325
|
const nSkills = eligible(m).filter(s => s.type === 'skill').length;
|
|
305
326
|
log(` manifest: ${eligible(m).length} codex-eligible surfaces (${nSkills} skills) of ${m.surfaces.length}.`);
|
|
@@ -543,6 +564,8 @@ Notes:
|
|
|
543
564
|
- --claude registers the marketplace + installs banker@banker-plugins (skills as /banker:*).
|
|
544
565
|
- --codex copies codex-eligible skills -> ~/.codex/skills/banker-* and commands -> ~/.codex/prompts/banker-*.md
|
|
545
566
|
($CODEX_HOME instead of ~/.codex when it is set).
|
|
567
|
+
- Codex can also take banker as a plugin (codex plugin marketplace add smallOpenSource/banker_plugins, then
|
|
568
|
+
codex plugin add banker@banker-plugins; skills as $banker:<name>). Keep one of the two ways in.
|
|
546
569
|
- telemetry on|off toggles anonymous usage counting opt-out (default-on; config only); status prints counting + update-check state. See PRIVACY.md.
|
|
547
570
|
- Never runs as root. --dry-run prints planned actions without writing.`;
|
|
548
571
|
|
|
@@ -550,14 +573,17 @@ async function main() {
|
|
|
550
573
|
const a = parseArgs(process.argv.slice(2));
|
|
551
574
|
if (a.version) { log(version()); return; }
|
|
552
575
|
if (a.help || a.cmd === 'help' || !a.cmd) { log(HELP); return; }
|
|
553
|
-
if (a.cmd === 'doctor') { doctor(); return; }
|
|
576
|
+
if (a.cmd === 'doctor') { await doctor(); return; }
|
|
554
577
|
if (a.cmd === 'telemetry') { await telemetryCmd(a.sub); return; }
|
|
555
578
|
if (a.cmd === 'hooks') { assertNotRoot(); await hooksCmd(a.sub, a.hookIds); return; }
|
|
556
579
|
assertNotRoot();
|
|
557
580
|
if (a.cmd === 'setup') {
|
|
558
581
|
log(`banker setup${a.dryRun ? ' (dry-run)' : ''}: claude=${a.claude} codex=${a.codex}`);
|
|
559
582
|
if (a.claude) setupClaude(a.dryRun);
|
|
560
|
-
if (a.codex && setupCodex(a.dryRun, a.scope))
|
|
583
|
+
if (a.codex && setupCodex(a.dryRun, a.scope)) {
|
|
584
|
+
await setupCodexHooks(a.dryRun, a.scope);
|
|
585
|
+
if (a.scope === 'user') await warnCodexPlugin(codexBase('user'));
|
|
586
|
+
}
|
|
561
587
|
// Best-effort first-run prompts (interactive TTY only). A prompt failure must never fail setup.
|
|
562
588
|
try { await maybeFirstRunPrompts(a); } catch { /* non-fatal */ }
|
|
563
589
|
log('done.');
|
package/bin/lib/codex-hooks.mjs
CHANGED
|
@@ -25,6 +25,7 @@ export const HOOKS = {
|
|
|
25
25
|
export const PAYLOAD = [
|
|
26
26
|
'.claude-plugin/plugin.json',
|
|
27
27
|
'bin/lib/telemetry-config.mjs',
|
|
28
|
+
'bin/lib/codex-routes.mjs',
|
|
28
29
|
'hooks/update-notify.mjs',
|
|
29
30
|
'hooks/update-fetch.mjs',
|
|
30
31
|
'hooks/update-checkin.mjs',
|
|
@@ -77,7 +78,7 @@ export function formatCommand(node, script, args, win = process.platform === 'wi
|
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
// 임시 폴더의 node 는 거부한다. Codex 안에서 돌 때는 작업 폴더 안의 node 도(샌드박스 안 세션이 고칠 수 있다).
|
|
80
|
-
export function safeNode(node, { win = process.platform === 'win32', cwd = process.cwd(), codex = Boolean(process.env.CODEX_THREAD_ID) } = {}) {
|
|
81
|
+
export function safeNode(node, { win = process.platform === 'win32', cwd = process.cwd(), codex = Boolean(process.env.CODEX_THREAD_ID), home = os.homedir() } = {}) {
|
|
81
82
|
const P = win ? path.win32 : path.posix;
|
|
82
83
|
const under = (f, dir) => {
|
|
83
84
|
const r = P.relative(dir, f);
|
|
@@ -85,7 +86,11 @@ export function safeNode(node, { win = process.platform === 'win32', cwd = proce
|
|
|
85
86
|
};
|
|
86
87
|
// A link elsewhere is judged where it leads too, so a link in a safe place cannot pin a node from the temp folder.
|
|
87
88
|
const places = [node, real(node)];
|
|
88
|
-
|
|
89
|
+
// A session in the home folder is no workspace to judge by (as homeInWorkspace): nvm keeps node under ~/.nvm. Only an
|
|
90
|
+
// absolute home names one (HOME=. would make every folder the home); path.relative compares as the OS does (case on Windows).
|
|
91
|
+
const isHome = P.isAbsolute(home) && P.relative(real(home), real(cwd)) === '';
|
|
92
|
+
const inWork = codex && !isHome;
|
|
93
|
+
return !places.some((f) => under(f, os.tmpdir()) || (inWork && under(f, cwd)));
|
|
89
94
|
}
|
|
90
95
|
|
|
91
96
|
function real(file) {
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* banker 가 Codex 에 들어가는 두 길.
|
|
3
|
+
* - npm: `banker setup --codex` 가 <CODEX_HOME>/skills/banker-<이름>/ 에 복사한다. 스킬은 $banker-<이름>.
|
|
4
|
+
* - 플러그인: `codex plugin add banker@<마켓플레이스>` 가 <CODEX_HOME>/plugins/cache/<마켓플레이스>/banker/<판>/ 에
|
|
5
|
+
* 저장소를 두고 config.toml 에 [plugins."banker@<마켓플레이스>"] 를 적는다. 스킬은 $banker:<이름>.
|
|
6
|
+
* 둘을 함께 두면 스킬과 훅이 두 벌이 된다. 지우지는 않고 알리기만 한다(update-notify, banker setup --codex, doctor).
|
|
7
|
+
* 훅(update-notify, telemetry-count-codex)과 bin/banker.js 가 함께 쓰므로 npm 길의 훅 사본(codex-hooks.mjs 의
|
|
8
|
+
* PAYLOAD)에도 들어간다.
|
|
9
|
+
*/
|
|
10
|
+
import fs from 'node:fs';
|
|
11
|
+
import os from 'node:os';
|
|
12
|
+
import path from 'node:path';
|
|
13
|
+
|
|
14
|
+
export const PLUGIN = 'banker';
|
|
15
|
+
export const DEFAULT_MARKETPLACE = 'banker-plugins';
|
|
16
|
+
const NAME_RE = /^[A-Za-z0-9._-]{1,80}$/;
|
|
17
|
+
|
|
18
|
+
const MAX_CONFIG = 4 << 20;
|
|
19
|
+
// 4 MB 까지의 일반 파일만 읽는다(FIFO 를 기다리지 않음, 훅의 5초 안에 끝남). 없거나 읽지 못하면 ''.
|
|
20
|
+
function readRegular(file) {
|
|
21
|
+
let fd;
|
|
22
|
+
try {
|
|
23
|
+
fd = fs.openSync(file, fs.constants.O_RDONLY | (fs.constants.O_NONBLOCK ?? 0));
|
|
24
|
+
const st = fs.fstatSync(fd);
|
|
25
|
+
return st.isFile() && st.size <= MAX_CONFIG ? fs.readFileSync(fd, 'utf8') : '';
|
|
26
|
+
} catch {
|
|
27
|
+
return '';
|
|
28
|
+
} finally {
|
|
29
|
+
if (fd !== undefined) try { fs.closeSync(fd); } catch { /* best-effort */ }
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// 플러그인 훅의 PLUGIN_ROOT(<홈>/plugins/cache/<마켓플레이스>/banker/<판>)에서 { home, marketplace }. 그 모양이 아니면 null.
|
|
34
|
+
export function pluginRootInfo(root) {
|
|
35
|
+
if (!root || !path.isAbsolute(root)) return null;
|
|
36
|
+
const ver = path.resolve(root);
|
|
37
|
+
const plugin = path.dirname(ver);
|
|
38
|
+
const mkt = path.dirname(plugin);
|
|
39
|
+
const cache = path.dirname(mkt);
|
|
40
|
+
const plugins = path.dirname(cache);
|
|
41
|
+
if (path.basename(plugin) !== PLUGIN || path.basename(cache) !== 'cache' || path.basename(plugins) !== 'plugins') return null;
|
|
42
|
+
const marketplace = path.basename(mkt);
|
|
43
|
+
return NAME_RE.test(marketplace) && NAME_RE.test(path.basename(ver)) ? { home: path.dirname(plugins), marketplace } : null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 이 세션의 Codex 홈: rollout 이 <홈>/sessions/YYYY/MM/DD/ 에 있으면 그 홈(상대 경로 CODEX_HOME 도 Codex 가 푼 그대로),
|
|
47
|
+
// 아니면 플러그인 훅의 PLUGIN_ROOT 가 든 홈, 아니면 CODEX_HOME, 그것도 없으면 ~/.codex.
|
|
48
|
+
export function codexHomeOf(transcript, env = process.env) {
|
|
49
|
+
const t = String(transcript ?? '');
|
|
50
|
+
const sessions = path.dirname(path.dirname(path.dirname(path.dirname(t))));
|
|
51
|
+
if (t && path.isAbsolute(t) && path.basename(sessions) === 'sessions') return path.dirname(sessions);
|
|
52
|
+
const info = pluginRootInfo(env.PLUGIN_ROOT);
|
|
53
|
+
if (info) return info.home;
|
|
54
|
+
return env.CODEX_HOME || path.join(os.homedir(), '.codex');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// npm 길로 설치된 banker 스킬이 있는지(<홈>/skills/banker-*/SKILL.md).
|
|
58
|
+
export function npmRoute(home) {
|
|
59
|
+
try {
|
|
60
|
+
return fs.readdirSync(path.join(home, 'skills')).some((d) => d.startsWith('banker-') && fs.existsSync(path.join(home, 'skills', d, 'SKILL.md')));
|
|
61
|
+
} catch {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 켜져 있는 banker 플러그인의 id(banker@<마켓플레이스>) 목록. config.toml 의 [plugins."banker@..."] 표 중
|
|
67
|
+
// enabled = false 가 아닌 것.
|
|
68
|
+
export function pluginRoutes(home) {
|
|
69
|
+
const lines = readRegular(path.join(home, 'config.toml')).split(/\r?\n/);
|
|
70
|
+
const out = [];
|
|
71
|
+
for (let i = 0; i < lines.length; i++) {
|
|
72
|
+
const m = /^\s*\[\s*plugins\s*\.\s*["']banker@([A-Za-z0-9._-]{1,80})["']\s*\]\s*(?:#.*)?$/.exec(lines[i]);
|
|
73
|
+
if (!m) continue;
|
|
74
|
+
let enabled = true;
|
|
75
|
+
for (let j = i + 1; j < lines.length && !/^\s*\[/.test(lines[j]); j++) {
|
|
76
|
+
if (/^\s*enabled\s*=\s*false\s*(?:#.*)?$/.test(lines[j])) enabled = false;
|
|
77
|
+
}
|
|
78
|
+
if (enabled) out.push(`${PLUGIN}@${m[1]}`);
|
|
79
|
+
}
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 프로젝트 범위 npm 설치(`banker setup --codex --scope project` 의 <폴더>/.codex/skills/banker-*)가 있는 폴더. cwd 에서
|
|
84
|
+
// 저장소 최상위(.git 이 있는 폴더)까지 올라가며 찾는다(저장소 밖이면 cwd 만). 없으면 ''.
|
|
85
|
+
export function projectNpmRoot(cwd) {
|
|
86
|
+
if (!cwd || !path.isAbsolute(cwd)) return '';
|
|
87
|
+
let dir = path.resolve(cwd);
|
|
88
|
+
const top = (() => {
|
|
89
|
+
for (let d = dir, i = 0; i < 64; i++) {
|
|
90
|
+
if (fs.existsSync(path.join(d, '.git'))) return d;
|
|
91
|
+
const up = path.dirname(d);
|
|
92
|
+
if (up === d) return '';
|
|
93
|
+
d = up;
|
|
94
|
+
}
|
|
95
|
+
return '';
|
|
96
|
+
})();
|
|
97
|
+
for (let i = 0; i < 64; i++) {
|
|
98
|
+
if (npmRoute(path.join(dir, '.codex'))) return dir;
|
|
99
|
+
if (!top || dir === top) return '';
|
|
100
|
+
dir = path.dirname(dir);
|
|
101
|
+
}
|
|
102
|
+
return '';
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// 두 길이 함께 있으면 알림 글, 아니면 ''. npm 길은 사용자 범위(<홈>/skills)와, cwd 가 있으면 프로젝트 범위도 본다.
|
|
106
|
+
export function dualInstallNote(home, cwd = '') {
|
|
107
|
+
const plugins = pluginRoutes(home);
|
|
108
|
+
if (!plugins.length || !(npmRoute(home) || projectNpmRoot(cwd))) return '';
|
|
109
|
+
return `banker 가 Codex 에 두 번 설치됨: npm 의 banker setup --codex 와 Codex 플러그인 ${plugins.join(', ')}. `
|
|
110
|
+
+ '스킬이 $banker-<이름> 과 $banker:<이름> 으로 겹칩니다. 하나만 두십시오: '
|
|
111
|
+
+ `npm 쪽을 빼려면 banker uninstall --codex, 플러그인을 빼려면 codex plugin remove ${plugins[0]}`;
|
|
112
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/*
|
|
3
|
+
* A command (commands/<name>.md) as a Codex skill. Codex 0.144+ has no custom prompts, so each command is also a skill.
|
|
4
|
+
* Two installs use it:
|
|
5
|
+
* - npm (banker setup --codex): writes <CODEX_HOME>/skills/banker-<name>/SKILL.md, invoked as $banker-<name>.
|
|
6
|
+
* - Codex plugin (codex plugin add banker@banker-plugins): scripts/sync-codex-plugin.js writes
|
|
7
|
+
* codex/command-skills/<name>/SKILL.md in the repo, invoked as $banker:<name>.
|
|
8
|
+
* The command's description becomes the skill's. Codex skills get no $ARGUMENTS substitution, so a note says where the
|
|
9
|
+
* arguments come from.
|
|
10
|
+
*/
|
|
11
|
+
function commandSkillText(text, name, invoke) {
|
|
12
|
+
const fm = text.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?/);
|
|
13
|
+
const desc = fm && fm[1].match(/^description:\s*(.*)$/m);
|
|
14
|
+
const body = fm ? text.slice(fm[0].length) : text;
|
|
15
|
+
const note = '> Codex: 이 명령은 스킬로 설치됐다. 본문의 `$ARGUMENTS`, `$1` 은 사용자가 `' + invoke + '` 뒤에 쓴 글이다.\n\n';
|
|
16
|
+
return `---\nname: ${name}\ndescription: ${desc ? desc[1] : '""'}\n---\n\n${note}${body}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
module.exports = { commandSkillText };
|
|
@@ -62,7 +62,8 @@ export const SKILL_CHANGES_URL = 'https://raw.githubusercontent.com/smallOpenSou
|
|
|
62
62
|
|
|
63
63
|
// usage-log 와 체크인 본문에 실리는 스킬/커맨드 이름 꼴. 쓰는 훅 둘과 보내는 훅이 같은 규칙을 쓴다.
|
|
64
64
|
// 이름은 64자까지다(가장 긴 실제 이름은 24자). 모델이 지어낸 긴 이름이 기록과 체크인에 실리지 않게 한다.
|
|
65
|
-
|
|
65
|
+
// 스킬 폴더 이름은 모두 소문자라 대문자는 받지 않는다(`banker:FRONT-QA` 가 다른 이름으로 세어지지 않게).
|
|
66
|
+
export const SKILL_NAME_RE = /^banker:[a-z0-9_-]{1,64}$/;
|
|
66
67
|
|
|
67
68
|
// 갱신 확인 요청 하나의 전체 마감(ms). 시험이 줄일 수 있게 BANKER_NET_DEADLINE_MS 를 받되 줄이기만 한다: 30초보다
|
|
68
69
|
// 길면 30초다. setTimeout 이 1ms 로 바꿔 버리는 값(0 이하, 숫자 아님)도 버리고 30초를 쓴다. 문서에 적지 않는 시험용 장치다.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: front-qa
|
|
3
|
+
description: "스펙 파일(기본 `docs/note.md`)을 바탕으로 프론트엔드를 구현하고, 레퍼런스 구현과 같은지 엄격하게 QA 하는 워크플로(`ralplan`, `ralph`, `/loop`)."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> Codex: 이 명령은 스킬로 설치됐다. 본문의 `$ARGUMENTS`, `$1` 은 사용자가 `$banker:front-qa` 뒤에 쓴 글이다.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# /front-qa — 스펙 기반 프론트엔드 구현 + 엄격 QA
|
|
10
|
+
|
|
11
|
+
`$1`(없으면 `docs/note.md`. 그 파일이 없고 `docs/note.txt` 가 있으면 그 파일)의 요구사항을 React 프론트엔드(`$FRONTEND_DIR`, 예: `apps/web`)에 구현하고,
|
|
12
|
+
**레퍼런스 구현(reference implementation — 예: 이전 Streamlit/타 빌드)과 엄격 비교 + 스펙 지시 정확 준수**를 검증한다. 모든 항목 해결까지 진행.
|
|
13
|
+
|
|
14
|
+
## 0. 전제조건: OMC (없으면 설치부터)
|
|
15
|
+
|
|
16
|
+
이 커맨드는 `/ralplan`·`/ralph` 등 oh-my-claudecode(OMC)에 의존한다. **진행 전 먼저 확인**하고, 없거나 낡았으면 **설치·갱신부터 안내**한다:
|
|
17
|
+
- 확인(Claude Code): `/oh-my-claudecode:*` 사용 가능 여부 + `omc` CLI 가 `ralph verify` 를 갖췄는지. OMC 5 의 `ralph` 는 첫 반복에 `omc ralph verify` 를 실행하고 없으면 멈춘다. 플러그인보다 낡은 4.x CLI 는 이 명령이 없는데도 `--help` 를 주면 전체 도움말을 찍고 종료 코드 0 을 내므로 **출력 문구로 판정**한다(`--help` 없이 부르면 Claude 실행으로 넘어가니 반드시 붙인다). Codex 는 `omx --version` 으로 OMX 를 확인한다:
|
|
18
|
+
```bash
|
|
19
|
+
omc ralph verify --help 2>&1 | grep -q 'Usage: omc ralph verify' && echo "omc ok" || echo "omc CLI 없음 또는 낡음"
|
|
20
|
+
```
|
|
21
|
+
- 실패하면 `/banker:setup` → oh-my-claudecode(또는 `setup-omc` 스킬 / `npm install -g oh-my-claude-sisyphus@latest`)로 먼저 구성한 뒤 이어서 진행. 점검을 통과하기 전에는 절차 1을 시작하지 않는다.
|
|
22
|
+
- **런타임 매핑:** 아래 절차의 `/ralplan`·`/ralph`는 Claude Code에선 OMC 스킬, **Codex에선 oh-my-codex(OMX)의 동명 스킬**이다(Codex는 OMC 대신 OMX 전제). 각 런타임에서 사용 가능한 형태로 호출한다.
|
|
23
|
+
|
|
24
|
+
## 절차 (CLAUDE.md: 계획 없는 즉시실행 금지)
|
|
25
|
+
|
|
26
|
+
1. **스펙 정독**: 대상 파일을 읽어 요구사항을 항목화. 코드베이스 정찰(병렬 explore/general-purpose 에이전트로
|
|
27
|
+
각 항목의 현재 React 상태 ↔ 레퍼런스 구현 갭을 file:line 증거로 매핑).
|
|
28
|
+
2. **`/ralplan --deliberate`**: Planner(정찰 종합)→Architect→Critic consensus(ITERATE 폐루프). Principles/Drivers/
|
|
29
|
+
Options(기각 사유)/pre-mortem/확장 테스트계획(unit·integration·e2e선택·observability)/ADR. 항목을 충돌-안전 순서의
|
|
30
|
+
스테이지로 분해(파일 경합 시 순차, 독립 시 병렬 가능). 계획을 `.omc/plans/`에 저장.
|
|
31
|
+
3. **`/ralph --critic=critic`**: 새 feature 브랜치(현 HEAD off). 스테이지별:
|
|
32
|
+
- executor(opus) 위임 구현 + 테스트 작성/수정.
|
|
33
|
+
- 🔴 **orchestrator fresh 재검증**(executor 완료보고 신뢰 금지 — 과거 오보고 사례): typecheck + 관련/전체 vitest.
|
|
34
|
+
- critic(opus) APPROVE까지 ITERATE.
|
|
35
|
+
- 로컬 커밋 + `scripts/parity-gate.sh:TEST_FLOOR` 실측 상향(같은 커밋). dead-code 제거 시 floor 하향도 정당(문서화).
|
|
36
|
+
- 위험 스테이지(env·deps·build·CSS토큰·스키마)는 **전체 parity-gate** 실행.
|
|
37
|
+
4. **홀리스틱 리뷰(Step7)**: critic(opus)이 **스펙 N항목 逐条 충족 + 레퍼런스 parity + 교차충돌 0 + 불변 보존**을 검증(충족표).
|
|
38
|
+
5. **필수 deslop(Step7.5)**: `ai-slop-cleaner` 변경 파일 범위. dead-code/중복/과추상/장황주석만(맥락 주석 보존). 무변경이면 무변경.
|
|
39
|
+
6. **regression(Step7.6)** + `/oh-my-claudecode:cancel`.
|
|
40
|
+
|
|
41
|
+
## 루프/중단 (사용자 directive)
|
|
42
|
+
- **/loop**: 모든 문제 해결까지 진행. credit/llm/token 비용 비고려.
|
|
43
|
+
- **중단 조건**: 컨텍스트 85% 도달 OR 작업 완료 → 작업·loop 중단(체크포인트: prd.json·progress.txt·메모리).
|
|
44
|
+
|
|
45
|
+
## 🔴 불변 제약
|
|
46
|
+
- 보안모델: 비밀 서버사이드 주입·VITE_ 비밀 금지·`client.ts` onResponse 인터셉터 금지(openapi-fetch body 1회 소비)·
|
|
47
|
+
`.env`는 gitignore 유지(dist 실토큰 0).
|
|
48
|
+
- FSD 단방향(app→pages→widgets→features→entities→shared)·feature↔feature import 0.
|
|
49
|
+
- No-mock/하드코딩 금지·env 기반. **백엔드 무수정**(프론트 전용; server/auth BFF는 프론트 코드라 가능).
|
|
50
|
+
- 비배포 로컬도구(배포·엔드포인트 RBAC 서버강제 = 비목표). push/머지 = **사용자 통제**(원격 origin은 사용자 설정).
|
|
51
|
+
- 답변·문서 한글(기술 토큰 영문).
|
|
52
|
+
|
|
53
|
+
## 완료 보고
|
|
54
|
+
- 스펙 항목별 결과를 **표**(항목/상태/근거 file:line)로 간결히.
|
|
55
|
+
- 테스트 수 변화(기준 floor→최종)·각 스테이지 critic 판정·게이트 결과.
|
|
56
|
+
- 미충족/수용-범위한정/후속분리 항목 정직 명시.
|