@kaydash9999/banker-plugins 0.18.0 → 0.19.1
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 +103 -0
- package/README.md +18 -7
- package/bin/lib/telemetry-config.mjs +25 -0
- package/codex/manifest.json +1 -0
- package/codex/transform-matrix.md +1 -0
- package/hooks/graceful-pause.mjs +4 -2
- package/hooks/obsidize-hook.mjs +61 -32
- package/hooks/progress-plan.mjs +14 -8
- package/hooks/progress.mjs +187 -48
- package/hooks/register.mjs +15 -7
- package/hooks/telemetry-count-skill.mjs +4 -6
- package/hooks/telemetry-count.mjs +4 -6
- package/hooks/update-checkin.mjs +46 -43
- package/hooks/update-fetch.mjs +8 -7
- package/package.json +1 -1
- package/skills/anti-drm/SKILL.md +46 -15
- package/skills/anti-drm/scripts/anti-drm.mjs +213 -61
- package/skills/anti-drm/scripts/instruction-toggle.mjs +280 -44
- package/skills/lineage/SKILL.md +4 -1
- package/skills/lineage/lineage.py +196 -73
- package/skills/omc-patch/SKILL.md +37 -11
- package/skills/omc-patch/scripts/omc-patch.mjs +635 -103
- package/skills/theme-selection/SKILL.md +165 -0
- package/skills/theme-selection/assets/LICENSE +21 -0
- package/skills/theme-selection/assets/NOTICE.md +30 -0
- package/skills/theme-selection/assets/palettes.json +81 -0
- package/skills/theme-selection/references/contrast.md +138 -0
- package/skills/theme-selection/references/integrate.md +161 -0
- package/skills/theme-selection/scripts/themes.mjs +1067 -0
- package/skills/tone-compact/SKILL.md +14 -5
- package/skills/tone-compact/scripts/instruction-toggle.mjs +280 -44
- package/skills/tone-compact/scripts/tone-compact.mjs +4 -4
- package/skills/update-banker/SKILL.md +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "banker",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.1",
|
|
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,108 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.19.1] - 2026-10-16
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
- 유지보수자용: lineage 의 `parse_turns` 를 동작 그대로 기록 판정, 내용 조각, 항목 하나 처리로 나눴다(함수 규칙 50줄, 복잡도 10). 특성 시험 6개가 동작을 고정한다.
|
|
7
|
+
- 유지보수자용: lineage 시험(`TestRangeFiltersE2E`)이 만든 임시 폴더를 지운다. 예전에는 한 번 돌릴 때마다 임시 폴더에 6개씩 남았다.
|
|
8
|
+
- 유지보수자용: lineage 시험이 실제 `~/.cache/lineage` 에 요약 캐시를 남기지 않는다(모듈을 시작할 때 캐시를 임시 폴더로 돌림). 요약 캐시의 0600 권한을 시험이 고정한다.
|
|
9
|
+
- 유지보수자용: gen-skill-changes, obsidize 훅, 업데이트 확인 훅에서 나눈 main 을 특성 시험으로 고정한다. smoke 와 시험의 npm 오프라인 설정은 철자만 다른 같은 변수에 지지 않는다(Windows 는 변수 이름의 대소문자를 가리지 않아 대문자 변수 하나로도 졌다). smoke 의 파이썬 단계도 임시 HOME 에서 돈다. `bin/banker.test.mjs` 는 상속한 `BANKER_NO_TELEMETRY`, `BANKER_NO_UPDATE_CHECK`, `BANKER_TELEMETRY_ENDPOINT` 를 지운다.
|
|
10
|
+
- `omc-patch`: 적용할 항목과 이 도구로 지울 수 없는 옛 URL 칸이 함께 있으면 결과 줄은 `적용되지 않은 항목이 있습니다.` 이고, 그 칸은 결과 줄 아래 `참고:` 두 줄로 알린다. 예전에는 막힘 줄이 결과가 되어 스킬이 훅 패치까지 하지 않았다. 막힘 결과 줄과 참고 줄은 `옛 URL 칸이 이 도구로 지울 수 없는 곳에 있습니다.` 로 바꿨다(하드 링크처럼 이 이름에서는 지우고 다른 이름에만 남는 때도 맞게). 시도 전 판단은 `지울 수 없음`, 시도해 실패한 것은 `지우지 못함` 으로 문구를 나눴다.
|
|
11
|
+
- `omc-patch` SKILL: 지울 수 없는 옛 기록은 2단계 승인 질문에서 지울지 남길지 함께 묻는다. 남기면 그 줄 하나만 예상된 실패로 보고 검증까지 간다. 기록 설명을 도구 동작에 맞췄다(링크 너머에 그 칸이 없으면 알리지 않음, 되돌리기는 링크가 아닌 기록이면 JSON 이 아니거나 읽지 못해도 그냥 지움).
|
|
12
|
+
- 유지보수자용: omc-patch 시험이 특수 파일인 고정 기록(FIFO, 링크 고리, 끊어진 링크, 폴더, 소켓), origin 복구 실패 뒤의 기록 삭제, FIFO 기록의 되돌리기를 덮는다.
|
|
13
|
+
- `anti-drm` SKILL: 설정 파일이 올바르지 않을 때의 절차를 `on` 표와 문제 해결 표에서 하나로 맞췄다. 다시 정할지 묻고, 그 파일은 새 파일로 바뀌며(그 자리가 폴더나 특수 파일이거나, 64KiB 보다 크거나, 읽을 수 없는 파일이면 바꾸지 않고 거부. 링크와 하드 링크는 그 이름만 바뀌고 `.bak` 에 남지 않음) anti-drm 형식이 아니면 `anti-drm.json.bak` 에 한 번 남는다. 에이전트는 그 파일을 직접 지우거나 옮기지 않는다.
|
|
14
|
+
- `tone-compact`, `anti-drm` SKILL: 문제 해결 표에서 파일을 보일 때는 `ls -l` 로 종류와 링크 대상 경로를 먼저 보이고, 링크가 아닌 일반 파일만 내용을 연다. 링크일 수 있는 행(쓰는 사이에 생긴 이름, 같은 이름의 다른 규칙 파일)에도 적었다. 심어 둔 링크가 가리키는 파일(키 등)이 세션에 오르지 않게 한다.
|
|
15
|
+
- `tone-compact`, `anti-drm` SKILL: `.bak` 파일은 내용을 열지 않고 경로만 알린다. 링크가 가리키던 파일(키 등)의 사본일 수 있다.
|
|
16
|
+
- 유지보수자용: anti-drm 시험이 비차단 표준 입력의 `EAGAIN` 재시도를 덮는다.
|
|
17
|
+
- 유지보수자용: tone-compact 의 링크 고리 시험과 소켓 시험을 나눴다. 소켓을 만들 수 없는 곳(경로가 100바이트 이상, listen 실패)에서는 소켓 시험이 통과가 아니라 건너뜀으로 보인다.
|
|
18
|
+
- 유지보수자용: /progress 시험이 도구 호출, 계획 읽기, 턴 끝과 시작, 할 일 목록 뒤의 다시 그리기 요청, 답 없이 끝나는 알림 턴, 진행 중 항목 둘을 덮고, 작업 도구 읽기를 무작위로 겹친 모형(시드 고정)과 대조한다. 시험의 엔진 대역을 함수 규칙(50줄) 안으로 나눴다.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
- `lineage` 3.0.6: 다른 런타임이나 손으로 만든 전사에서 자료형이 틀린 줄(숫자인 type, 문자열인 message, 목록인 도구 이름, 글이 아닌 text 항목), 객체가 아닌 줄, 너무 깊게 중첩된 줄, 파서가 읽지 못하는 긴 숫자가 든 줄은 경고 뒤 건너뛴다. 글이 아닌 timestamp 는 없는 것으로 읽고, 이름이 null 인 도구는 `?` 로 센다. 예전에는 줄 하나 때문에 내보내기 전체가 트레이스백으로 멈췄다. 경고 줄은 전사에서 온 이름을 이스케이프해 제어 글자로 줄을 꾸미지 못한다. 너무 깊게 중첩된 검토 묶음과 표본은 메시지와 함께 거부한다.
|
|
22
|
+
- `lineage` 3.0.6: 요약 캐시와 결정 캐시는 64KiB 이하의 일반 파일만 읽고 링크를 따르지 않는다(Windows 는 열기 전 확인만 한다). 입력 id 열쇠를 쓰는 임시 이름에 놓인 링크도 따라가지 않는다. 캐시 자리의 FIFO 에서 멈추거나, 링크가 가리키는 다른 파일의 내용을 요약으로 싣거나 그 파일을 덮어쓰던 것을 막는다. 요약 쓰기는 결정 캐시처럼 새 임시 파일과 교체로 한다.
|
|
23
|
+
- `lineage` 3.0.6: 검토 모델이 폭 없는 글자만으로 쓴 요약은 규칙 요약으로 바꾼다. 예전에는 페이지의 요약 줄이 빈 줄로 보였다.
|
|
24
|
+
- `lineage` 3.0.6: 글자 방향을 바꾸는 제어 문자 9자(U+202A~202E, U+2066~2069)를 페이지(날짜 범위 포함)에 `[U+202E]` 같은 보이는 표지로 넣는다. 예전에는 그대로 들어가 화면의 글자 순서가 실제와 달라 보일 수 있었다(예: `gpj.exe` 가 `exe.jpg` 로 보임).
|
|
25
|
+
- `lineage` 3.0.6: Windows 에서도 페이지와 캐시를 LF 줄 끝으로 쓴다. 예전에는 같은 전사에서 Windows 만 CRLF 로 써 바이트가 달랐다.
|
|
26
|
+
- 업데이트 확인 훅: 응답 본문은 256KiB 까지만 받고, 요청 하나는 30초 안에 끝낸다(시험용 값으로도 늘지 않는다). 예전에는 조금씩 계속 보내는 서버에서 훅이 끝나지 않아 세션을 시작할 때마다 하나씩 쌓였고, 큰 응답을 모두 메모리에 받았다.
|
|
27
|
+
- 업데이트 확인 훅: 체크인에 싣는 스킬 이름을 사용 기록을 쓰는 훅과 같은 규칙(`banker:<이름>`, 이름은 64자까지)으로 거른다. 사용 기록에 다른 꼴의 줄이 섞여도 보내지 않는다.
|
|
28
|
+
- obsidize 훅: 로그 줄의 제어 글자를 공백으로 접고 사유를 500자에서 자른다. 로그 자리가 링크면 쓰지 않고(저장소가 실어 올 수 있음. `O_NOFOLLOW` 가 없는 Windows 는 열기 전에 본다), FIFO 여도 멈추지 않는다. 새로 만드는 로그 파일은 이 계정만 읽고 쓴다(0600).
|
|
29
|
+
- `omc-patch`: 문법 오류로 되돌리는 쓰기까지 실패하면 스택 트레이스 대신 `롤백도 실패` 와 백업 위치를 알리고 실패로 센다. 도구가 처리하지 못한 오류는 경로를 정화한 한 줄과 종료 1 로 끝난다.
|
|
30
|
+
- `omc-patch`: 읽을 수 없는 훅(권한, 폴더, FIFO)은 `읽지 못함` 으로 이름을 대고 실패로 센다. 예전에는 FIFO 로 가는 링크에서 멈췄고 나머지는 스택 트레이스였다. 쓸 권한이 없는 훅과 FIFO 같은 특수 파일을 가리키는 훅은 새 파일로 바꿔 쓰지 않는다(`쓰지 않음`, `되돌리지 않음`, `--check` 가 미리 알림). Windows 는 전부터 거부했고 POSIX 가 말없이 바꾸던 것을 맞췄다. hooks.json 이 폴더나 FIFO 이거나 읽을 수 없으면 `--check` 는 `hooks.json 을 읽지 못함`, 적용은 `hooks.json 을 건드리지 않음` 으로 이름을 대고 센다(예전에는 FIFO 에서 멈추고 폴더는 스택 트레이스였다).
|
|
31
|
+
- `omc-patch`: 같은 폴더에서 둘이 동시에 돌아도 거짓 `변환 실패` 와 `되돌리지 않음` 을 내지 않는다. 다른 실행이 백업을 먼저 가져간 경우는 되돌린 것으로 보고, 복구는 됐는데 백업만 못 지우면 그렇게 알린다.
|
|
32
|
+
- `omc-patch`: 파일을 쓸 때 임시 파일을 디스크까지 내린 뒤 rename 한다(상류 OMC 와 같은 꼴).
|
|
33
|
+
- `omc-patch`: 고정 해제에 실패하면 원래 URL 을 호스트까지만 낸다(사용자 정보, 경로, 쿼리, 조각에는 비밀이 들 수 있음. 호스트 모양이 아니면 그것도 내지 않음). `--check` 의 미고정 줄과 git 오류 줄의 쿼리 값은 이름과 상관없이 가린다. git 이 오류 문구 없이 끝나면 명령 줄(URL 전체가 듦) 대신 어떻게 끝났는지만 낸다. 판이 여럿일 때 hooks.json 의 `[!]` 줄에 판 이름을 붙이고, 비활성 판의 읽기 실패는 결과 줄 밑에 참고로 알린다. 손 복구 안내는 링크 대상이 이 도구 계열로 패치된 파일일 때만 덮어쓰라고 한다. 백업 없음 안내는 임시 tar 파일을 거친다(Windows 의 tar 는 파이프를 받지 않음). installed_plugins.json 을 읽지 못하면 `읽지 못함` 이라 하고 파일 글을 내지 않는다.
|
|
34
|
+
- `omc-patch`: 인자 없는 apply 는 대상 판이 캐시에 있어도 활성이 아니면 전환한다. 예전에는 첫 전환이 실패한 PC 에서 다시 돌리면 판을 못 바꾸고도 성공으로 보였다.
|
|
35
|
+
- `omc-patch` SKILL: 5단계의 고정 확인 명령은 origin 이 `omc-pinned://` 로 시작하는지만 보고 `pinned` 나 `not-pinned` 를 낸다. 예전 명령은 쿼리의 토큰을 그대로 보였다.
|
|
36
|
+
- `omc-patch`: 고정 기록(`PINNED`)이 링크면 첫 고정, 되돌린 뒤 다시 적용, 옛 URL 칸 지우기 모두 링크를 따라가 쓰지 않는다. 확인한 뒤 링크로 바뀐 자리도 같다. 예전에는 첫 고정과 다시 적용이 링크가 가리키는 파일을 덮었다.
|
|
37
|
+
- `omc-patch`: 옛 URL 칸이 든 기록에 하드 링크로 이어진 다른 이름이 있으면 적용(첫 고정이 새 기록으로 덮을 때 포함)과 되돌리기는 `이 이름에서만 지움` 으로 알리고 실패로 센다. `--check` 는 `이 이름에서만 지울 수 있음` 으로 미리 알린다(origin 이 아직 고정되지 않은 PC 에서는 적용이 처음 알린다). 다른 이름을 찾을 inode(Windows 는 파일 ID) 번호도 낸다. 예전에는 이 이름만 지우고 성공으로 끝나 다른 이름에 URL 이 남았다.
|
|
38
|
+
- `omc-patch`: git 이 마켓플레이스 설정을 읽지 못하면(git 없음, 다른 계정 저장소라 거부, 깨진 설정) `origin 을 읽지 못함` 으로 알리고 실패로 센다. `--check` 의 결과 줄은 `마켓플레이스 origin 을 확인하지 못했습니다.` 다. 예전에는 `origin remote 없음 — 이미 fetch 불가` 로 성공했고, 되돌리기는 고정이 그대로인데 `되돌리기 완료` 라고 했다.
|
|
39
|
+
- `omc-patch`: 되돌리기는 마켓플레이스가 없거나, git 저장소가 아니거나, origin 이 없어도 고정 기록을 지운다. 마켓플레이스가 없는 PC 에서도 옛 기록의 URL 칸을 점검하고 지운다.
|
|
40
|
+
- `omc-patch`: 옛 URL 칸은 JSON 최상위 칸으로 판정한다. 값 안에 그 글자가 든 기록이나 이스케이프로 쓴 키를 잘못 보지 않는다.
|
|
41
|
+
- `omc-patch`: 설정 파일(`installed_plugins.json`, `settings.json`), `--root` 폴더의 이름표, `--scan` 에 준 파일, 고정 기록도 일반 파일만 읽는다. 예전에는 그 자리가 FIFO 면 `--check` 까지 멈췄다. 고정 기록과 손 복구 안내가 들여다보는 링크 대상은 확인과 읽기 사이에 FIFO 로 바뀌어도 멈추지 않는다.
|
|
42
|
+
- `omc-patch`: `--check` 는 기록이 든 폴더에 쓸 수 없으면 `(적용하면 지움)` 대신 `지울 수 없음 (쓰지 못함: ...)` 으로 알린다.
|
|
43
|
+
- `tone-compact`, `anti-drm`: Codex 에 새 AGENTS.md 를 만들 때 그 사이에 같은 이름이 생기면 따라가 쓰지 않고 거부한다(종료 1). 심어 둔 링크도 거부한다. 단 Windows 는 아무것도 가리키지 않는 링크를 따라가 그 대상 파일을 만든다(`wx` 의 Windows 동작, 링크를 심으려면 관리자 권한이나 개발자 모드가 필요). 예전에는 링크가 가리키는 파일에 썼다.
|
|
44
|
+
- `tone-compact`, `anti-drm`: 샌드박스가 권한 확인은 통과시키고 쓰기를 막으면 `예기치 못한 오류`(종료 2) 대신 `쓸 권한이 없어 그대로 두었습니다`(종료 1)로 끝난다. 메시지는 시스템이 거부한 자리(백업 파일 등)를 댄다. Windows 에서 백업 자리에 폴더가 있을 때의 EPERM 도 이 거부로 끝난다. 파일 둘을 바꾸던 중에 거부되면 첫 파일은 이미 바뀌었을 수 있고, 메시지 끝의 `앞서 바꾼 파일:` 줄이 그 파일을 댄다(같은 이름이 생겨 거부할 때도 같다).
|
|
45
|
+
- `tone-compact`, `anti-drm`: AGENTS.override.md 에 이 스킬 블록만 있고 AGENTS.md 가 끊어진 링크면 status 가 `on` 이 블록을 옮기지 못한다고 알린다. 예전에는 `on` 으로 옮긴다고 했지만 `on` 은 거부했다.
|
|
46
|
+
- `tone-compact`, `anti-drm`: 규칙 파일 자리가 링크(끊어진 링크, 옛 사본으로 가는 링크)였으면 `on` 이 일반 파일로 바꾼 뒤 결과에 알린다. 링크가 가리키던 곳은 건드리지 않는다. 예전에는 말없이 바꿨다.
|
|
47
|
+
- `anti-drm`: 설정을 저장하는 `config` 와 설정 값을 준 `on` 도 설정 파일 자리가 링크나 하드 링크였으면 알리고, anti-drm 이 쓰지 않은 원래 파일을 `.bak` 에 남겼는지, 먼저 남긴 파일이나 일반 파일이 아닌 것(링크, 폴더)이 그 자리에 있어 남기지 않았는지 알린다. 알림은 `.bak` 에 쓸지 정한 그 확인에서 나온다.
|
|
48
|
+
- `anti-drm`: 설정을 저장할 때 설정 파일 자리가 링크나 하드 링크(이름이 둘 이상인 일반 파일)면 가리키던 파일을 읽거나 `anti-drm.json.bak` 에 복사하지 않는다. 그 이름만 새 파일로 바뀌고 가리키던 파일은 그대로 남는다. 64KiB 를 넘거나 읽을 수 없는 파일을 가리키는 링크와 하드 링크도 이제 거부하지 않고 그 이름만 바꾼다. 저장 전에 기존 파일을 열 때 Linux 와 macOS 는 링크를 따르지 않고(`O_NOFOLLOW`), 이 플래그가 없는 Windows 는 연 뒤 그 이름이 연 파일인지 파일 ID 로 다시 본다. 그 사이에 다른 파일로 바뀌었으면 `확인하는 사이에 바뀐 자리라 설정을 저장하지 않았습니다` 로 거부한다. 예전에는 링크가 가리키는 작은 파일(키 등)의 사본이 `~/.config/banker/` 에 일반 파일로 남아, 일반 파일만 내용을 여는 SKILL 규칙에 걸리지 않았다. 0.19.0 까지 남은 사본은 지우지 않으니, 설정 파일 자리에 링크를 둔 적이 있으면 `anti-drm.json.bak` 을 확인한 뒤 지운다.
|
|
49
|
+
- `tone-compact`, `anti-drm`: 남은 잠금을 정리하다 네트워크 공유가 `ESTALE` 을 내면 이미 사라진 잠금으로 본다. 예전에는 종료 2 로 멈췄다.
|
|
50
|
+
- `/progress`: `/clear` 를 하면 패널이 바로 빈 목록을 그린다. 예전에는 다음 프롬프트까지 옛 단계가 남아 보였다.
|
|
51
|
+
- `/progress`: 계획을 건드린 뒤 검토 문서(약한 계획)를 건드리면, 두 읽기가 거꾸로 끝나도 계획이 그대로다. 세션이 읽기만 한 단계 없는 계획은 체크박스가 있는 검토 문서를 대신한다.
|
|
52
|
+
- `/progress`: 작업 도구 읽기(TaskGet, TaskList)가 겹쳐 돌아도 나중에 시작한 읽기가 이긴다. 작업이 없다는 TaskGet 과 작업을 뺀 TaskList(판에 없던 작업 포함)도 그렇다. 예전에는 늦게 끝난 옛 읽기가 지워진 작업을 되살릴 수 있었다.
|
|
53
|
+
|
|
54
|
+
## [0.19.0] - 2026-10-15
|
|
55
|
+
|
|
56
|
+
npm 에는 0.18.1 을 게시하지 않았다. npm 에서는 이 판이 0.18.0 다음이며, 아래 [0.18.1] 의 변경도 함께 담는다.
|
|
57
|
+
|
|
58
|
+
### Added
|
|
59
|
+
- `theme-selection`: 프로젝트에 테마 74종을 라이트와 다크 한 쌍씩(148 조합) CSS 사용자 지정 속성으로 입힌다. 대비 보정을 거친 값을 내고, 테마 고르개(마크업과 스크립트 둘)와 대비 감사(`check`)도 낸다. 프로젝트의 DESIGN.md 를 읽어 테마로 더하거나 같은 이름의 번들 테마를 덮는다. Node 만 쓰고 인터넷을 쓰지 않는다.
|
|
60
|
+
- `theme-selection`: 번들 팔레트는 VoltAgent/awesome-design-md(MIT)의 DESIGN.md 에서 색 값을 읽어 만들었다. 원본 라이선스와 출처 고지는 `assets/LICENSE`, `assets/NOTICE.md` 에 있다. 테마 이름의 상표는 각 소유자의 것이다.
|
|
61
|
+
|
|
62
|
+
### Changed
|
|
63
|
+
- README: 첫 부분을 □ 개조식으로 정리했다. Codex 설명은 실제 동작에 맞췄다. 스킬과 커맨드는 Codex CLI 에 모두 설치되고, 도구 의존성이 있는 스킬은 실행할 때 그 도구가 필요하다.
|
|
64
|
+
- 유지보수자용: smoke 시험이 스킬 63개와 `theme-selection` 의 Codex 설치본(스크립트, 팔레트, 고지 파일)을 보고, 설치본을 한 번 실행한다. CI 의 manifest 개수 단언을 63 으로 고쳤다. 0.18.0 부터 61 로 남아 있었다.
|
|
65
|
+
|
|
66
|
+
## [0.18.1] - 2026-10-15
|
|
67
|
+
|
|
68
|
+
### Fixed
|
|
69
|
+
- `omc-patch`: 모르는 인자를 받지 않는다. 예전에는 말없이 넘겨 `--dry-run` 을 줘도 실제로 적용했고, `--root=<폴더>` 꼴은 `--root` 가 무시돼 `--revert` 가 모든 판을 되돌리고 고정까지 풀었다. 이제 아는 인자 밖이면 아무것도 읽거나 쓰지 않고 사용법과 함께 종료 1 로 멈춘다. `--help` 는 사용법을 낸다.
|
|
70
|
+
- `omc-patch`: 출력 정화를 유니코드 속성 기준으로 넓혔다. 단어 결합자, 태그 문자(보이지 않는 ASCII), 빈 글자(U+3164 등), 점자 빈칸, ASCII 밖 공백을 `?` 로 바꾼다. `--root` 이름표 출력도 정화한다. 출력하는 경로(`--root` 폴더, 마켓플레이스, 캐시), 판 이름, 문법 오류 줄도 정화한다.
|
|
71
|
+
- `omc-patch`: 새 임시 파일과 rename 으로 쓴다. 하드 링크로 이어진 폴더 밖 파일이 바뀌지 않고, 백업은 이미 있으면 실패하는 복사로 만들어 확인과 복사 사이에 바뀌지 않는다. Windows 에서 잠시 거부된 rename 은 다시 한다. 쓰지 못한 파일(installed_plugins.json, PINNED 포함)은 이름을 대고 실패로 센다. 예전에는 예외로 멈췄다.
|
|
72
|
+
- `omc-patch`: origin 의 인증 정보를 출력에서 `***` 로 가린다(사용자 정보의 공백, 탭, 비밀번호 안의 `@`, 쿼리의 토큰 포함). PINNED 에 URL 을 남기지 않고 이 계정만 읽게 한다(0600). 옛 판이 남긴 PINNED 의 URL 칸은 `--check` 가 알리고(모두 적용된 상태로 보지 않음) 다음 적용 때 지운다. 지우지 못하면(기록이 링크, JSON 이 아님, 쓰기 실패, 읽지 못함) `[!]` 로 그 경로를 알리고 실패로 센다. 링크는 따라가 쓰지 않는다.
|
|
73
|
+
- `omc-patch`: origin 을 설정 값 그대로 읽는다. 전역 `insteadOf` 가 펼친 URL 이 고정되거나 되돌린 뒤 남지 않고, `-` 로 시작하는 origin 도 옵션으로 읽지 않는다.
|
|
74
|
+
- `omc-patch`: 실행 폴더를 정하지 않던 git, tar 호출을 홈 폴더에서 실행한다. Windows 에서 현재 폴더(프로젝트 폴더)의 `git.exe` 가 먼저 실행되지 않는다. 마켓플레이스 저장소를 다루는 git 은 그 폴더에서 실행한다.
|
|
75
|
+
- `omc-patch`: 고친 hooks.json 이 다시 읽어 JSON 이 아니면 원본으로 되돌리는데, 이 되돌림을 실패로 센다. 예전에는 `완료. 실패 0건.` 과 종료 0 이었다.
|
|
76
|
+
- `omc-patch`: 되돌리기가 PINNED 를 지우지 못하면(읽기 전용 폴더, 폴더인 PINNED) `[!]` 로 알리고 실패로 센다. origin 은 그대로 되돌린다. 예전에는 스택 트레이스로 멈춰 origin 이 고정된 채 남았다. 링크인 PINNED 너머에 옛 URL 칸이 있으면 링크를 두고 알리고 실패로 센다. 예전에는 링크만 지우고 `되돌리기 완료.` 로 끝났다.
|
|
77
|
+
- `omc-patch`: origin 을 바꾸지 못하면 git 의 원인 줄(`fatal:`, `error:`)과 함께 `[!]` 로 알리고 종료 1 이다. 예전에는 되돌리기가 성공이라고 했고, 고정은 기록만 남기고 예외로 멈췄다.
|
|
78
|
+
- `omc-patch`: 손 수정 판정이 실제 손 패치 모양(최상위의 `await Promise.race([import(`)만 본다.
|
|
79
|
+
- `tone-compact`, `anti-drm`: 지침 파일 자리(AGENTS.md, AGENTS.override.md, 규칙 파일)에 폴더, FIFO, 소켓, 링크 고리가 있으면 읽지 않는다. 예전에는 FIFO 에서 `status` 와 `off` 가 멈췄고, 폴더와 소켓, 링크 고리에서는 종료 2 로 끝났다. 이제 `on`, `off` 는 거부(종료 1)하고 `status` 는 그 사실과 그 파일의 경로를 보인다.
|
|
80
|
+
- `tone-compact`, `anti-drm`: UTF-8 이 아닌 파일이나 표시 짝이 맞지 않는 파일이 있으면 `status` 가 그 파일의 경로를 보인다. 예전에는 블록이 들어갈 파일을 보였다.
|
|
81
|
+
- `tone-compact`, `anti-drm`: AGENTS.override.md 가 AGENTS.md 의 링크나 하드 링크면 한 파일로 다룬다. 예전에는 `on` 을 할 때마다 블록이 들어갔다 빠졌다 했다. 같은 파일인지는 실제 경로나 inode 로 보고, inode 번호 0 은 믿지 않는다.
|
|
82
|
+
- `tone-compact`, `anti-drm`: AGENTS.md 가 끊어진 링크면 `on` 이 거부한다. 예전에는 링크를 따라 대상 자리에 파일을 만들었다.
|
|
83
|
+
- `tone-compact`, `anti-drm`: 두 스킬의 `on`, `off` 가 동시에 돌아도 블록이 사라지지 않는다. Codex 폴더의 잠금 파일(`.banker-agents.lock`)로 차례를 지키고, 1분 넘은 잠금은 넘어간다. 죽은 실행이 남긴 잠금을 두 실행이 같은 순간에 넘기는 드문 경우는 보장하지 못한다.
|
|
84
|
+
- `tone-compact`, `anti-drm`: 메시지의 경로에서 빈 글자(U+3164 등), 점자 빈칸, ASCII 밖 공백도 `?` 로 바꾼다.
|
|
85
|
+
- `anti-drm`: 설정 파일의 TSV 구분자도 대소문자를 가리지 않는다(`"Tab"`). 채운 규칙에 `{{` 가 남으면 오류로 멈춘다.
|
|
86
|
+
- `lineage` 3.0.5: 공백이나 보이지 않는 글자(BOM, 폭 없는 공백, 한글 채움 문자, 점자 빈칸, 제어 문자 등)만 든 요약 캐시는 읽지 못한 것으로 보고 다시 요약한다.
|
|
87
|
+
- `scripts/gen-skill-changes.js`(유지보수자용): npm 묶음에 들어가지 않는 파일(시험, `__pycache__`, `.omc`)만 바뀐 스킬은 바뀐 스킬로 세지 않는다.
|
|
88
|
+
- `/progress`: 늦게 끝난 TaskList, TaskGet 이 그 결과에만 있는 작업을 버리지 않는다. 겹친 조회와 상태 갱신은 나중에 시작한 것이 남고, 삭제보다 먼저 시작한 조회나 갱신은 지운 작업을 되살리지 않는다.
|
|
89
|
+
- `/progress`: 알림 턴이 대답 없이 끝나면(중단, 거절, 오류) 단계 아래에 그 사실을 보인다.
|
|
90
|
+
- `/progress`: Claude Code 2.1.289 아래 판에서는 즉시 실행 없이 일반 명령으로 등록한다.
|
|
91
|
+
- `/progress`, `/graceful-pause`: 하위 에이전트, 포크, 팀원의 턴 시작을 단계나 주 턴으로 보지 않는다. Claude Code 2.1.300 은 그 턴에도 `turn.start` 를 보내, 예전에는 포크의 지시문이 단계로 생겨 다음 요청 전까지 진행 중으로 남았고 `/graceful-pause` 는 포크를 멈출 턴으로 잘못 기억했다.
|
|
92
|
+
- `/progress`: 진행 중인 단계가 바뀌거나 패널을 다시 열면 패널 창을 그 행으로 옮긴다. 예전에는 긴 목록에서 진행 단계가 창 밖에 남았다.
|
|
93
|
+
|
|
94
|
+
### Changed
|
|
95
|
+
- `anti-drm`: 설정 값을 표준 입력(`--stdin`, 줄마다 `deny=`, `alt=`, `tsv=`)으로 받는다. 스킬은 따옴표 친 heredoc 으로 넘겨 사용자가 고른 값이 셸을 거치지 않고, 넘기기 전에 heredoc 줄마다 꼴을 확인한다. 입력은 64KiB 를 넘는 순간 읽기를 멈추고, 설정 줄이 없으면 `on` 과 `config` 모두 거부하며, 값 앞뒤 공백은 지운다. `--deny`, `--alt`, `--tsv` 도 그대로 받는다.
|
|
96
|
+
- `tone-compact`, `anti-drm`: 문제 해결 표가 사용자 파일을 치우거나 지우라고 하지 않는다. 무엇인지 보이고 물은 뒤 다시 실행한다.
|
|
97
|
+
- `tone-compact`, `anti-drm`: Codex `off` 결과에 지우기 전 파일(`<파일>.<스킬>.bak`)을 알린다. 다른 banker 블록 때문에 Codex 가 AGENTS.md 를 읽지 않으면 `on` 의 첫 문장이 그렇다고 말한다.
|
|
98
|
+
- `update-banker`: Claude Code 가 캐시의 옛 판을 지우는 규칙을 확인된 사실로 적었다(`.orphaned_at` 뒤 14일, 그 판을 쓰는 세션 없음, 링크 판 제외).
|
|
99
|
+
- `omc-patch`: `--check` 가 쓸 수 없는 훅과 hooks.json 을 미리 알린다. JSON 이 아닌 hooks.json 은 `읽지 못함` 으로 알리고 모두 적용됐다고 하지 않는다. 폴더 밖 링크 때문에 되돌리지 못한 파일은 손 복구 방법을 안내한다.
|
|
100
|
+
- `omc-patch`: 파일을 새 임시 파일과 rename 으로 바꾸므로, 폴더는 쓸 수 없고 파일만 쓸 수 있는 곳에서는 `쓰지 못함: EACCES` 로 알리고 실패로 센다. 예전에는 파일 자리에 그대로 썼다.
|
|
101
|
+
- `omc-patch`: 지울 git 변수에 이 PC 의 `git rev-parse --local-env-vars` 결과를 더한다. 업데이트 경로의 fetch 는 환경 변수로 준 git 설정 가운데 프록시와 TLS 신뢰 설정(`http.proxy`, `http.sslCAInfo`, `http.sslVerify`, `http.proxyAuthMethod`)만 쓴다. `url.*.insteadOf`, `core.hooksPath` 같은 나머지는 예전처럼 지운다.
|
|
102
|
+
- smoke 시험: banker 작업 파일 검사가 대소문자를 가리지 않고 `skills/`, `commands/` 의 모든 글 파일을 본다.
|
|
103
|
+
- `/progress`: 위치와 상관없이 `prd.json` 과 `ultragoal/goals.json` 을 PRD 나 목표 모양일 때 계획으로 본다. 검토 문서 이름(`-critic`, `-review` 등)의 파일은 다른 계획이 없을 때만 계획으로 보인다.
|
|
104
|
+
- 유지보수자용: npm pack 대조 시험과 smoke 시험의 npm 이 레지스트리에 접속하지 않는다. smoke 의 DRM 이름 검사가 긴 줄에서도 선형 시간이다. `scripts/gen-skill-changes.js`, `hooks/obsidize-hook.mjs`, `hooks/update-checkin.mjs` 의 main 을 함수 규칙(복잡도 10) 안으로 나눴다(동작 그대로).
|
|
105
|
+
|
|
3
106
|
## [0.18.0] - 2026-10-14
|
|
4
107
|
|
|
5
108
|
### Added
|
package/README.md
CHANGED
|
@@ -8,11 +8,18 @@
|
|
|
8
8
|
|
|
9
9
|
[빠른 시작](#빠른-시작) · [워크플로 예시](#워크플로-사용-예시) · [구성](#구성) · [설치 상세](#설치-상세-npm--codex) · [설정 변경 지점](#설정-변경-지점-claude-code--codex) · [요구사항](#요구사항) · [업데이트 / 제거](#업데이트--제거) · [업데이트 확인](#업데이트-확인-및-사용량-카운팅) · [라이선스 / 서드파티](#라이선스--서드파티)
|
|
10
10
|
|
|
11
|
-
banker는
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
□ banker는 다음을 포함하는 Claude Code 및 Codex CLI 플러그인입니다.
|
|
12
|
+
- QA·보안 감사·문서·아키텍처·위키·미디어 작업과 의존성·개발환경(OS별) 설치를 아우르는 **스킬 63개 + 커맨드 2개**(총 65개 구성요소)
|
|
13
|
+
- Claude Code 즉시 명령 `/graceful-pause`, `/progress`
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
□ 설치하면 스킬과 커맨드가 `/banker:<이름>` 네임스페이스로 노출됩니다.
|
|
16
|
+
|
|
17
|
+
□ 이 저장소 자체가 Claude Code 마켓플레이스(`.claude-plugin/marketplace.json`)이자,\
|
|
18
|
+
플러그인(`.claude-plugin/plugin.json`, name `banker`)이며,\
|
|
19
|
+
스킬과 커맨드는 Codex CLI에도 모두 구성됩니다.\
|
|
20
|
+
도구 의존성이 있는 스킬은 실행할 때 그 도구가 필요합니다.
|
|
21
|
+
|
|
22
|
+
> npm 패키지(`@kaydash9999/banker-plugins`)와 GitHub 저장소(`smallOpenSource/banker_plugins`)는 같은 메인테이너가 관리
|
|
16
23
|
|
|
17
24
|
## 빠른 시작
|
|
18
25
|
|
|
@@ -102,6 +109,7 @@ Claude Code 2.1.296 은 Claude 5 모델(Opus 5.5 등)에 작업 목록 도구(Ta
|
|
|
102
109
|
| `make-notion-guide` | API 호출 가이드를 노션 양식 문서로 작성 |
|
|
103
110
|
| `pdf-vision-extract` | 비주얼 PDF를 고해상도 PNG로 변환(비전 입력) |
|
|
104
111
|
| `nothing-design` | Nothing 스타일 UI 디자인 적용 |
|
|
112
|
+
| `theme-selection` | 테마 74종을 라이트와 다크 CSS 변수로 입힘(대비 보정 포함). 테마 고르개와 대비 감사도 냄 |
|
|
105
113
|
| `rfp-author` | 외주 제안요청서(RFP) 저작 (범용 프레임워크) |
|
|
106
114
|
| `humanizer` | AI 글 흔적 제거(자연스러운 문체로 윤문) |
|
|
107
115
|
| `lineage` | 세션 대화를 카카오톡 스타일 단일 HTML로 export. 세션 모델이 턴마다 1줄 요약을 쓰고 남길 턴을 고름(`--rulebase` 는 규칙만), 마크다운 렌더, 다중 세션 병합 |
|
|
@@ -197,7 +205,7 @@ banker uninstall # 제거
|
|
|
197
205
|
|
|
198
206
|
- `--scope project` 로 프로젝트 로컬(`./.codex`)에 설치하고, `--dry-run` 으로 미리 볼 수 있습니다.
|
|
199
207
|
- non-root 전용입니다(전역 sudo 설치 시 root 소유 파일을 방지). postinstall이 없으므로 `banker setup` 을 직접 실행합니다.
|
|
200
|
-
- Codex에는 스킬
|
|
208
|
+
- Codex에는 스킬 63개가 `~/.codex/skills/banker-<name>/` 에, 커맨드 2개가 `~/.codex/prompts/banker-<name>.md` 에 설치됩니다(`codex/manifest.json`). \
|
|
201
209
|
디렉터리명과 일치하도록 프론트매터 `name:` 이 `banker-<name>` 으로 재작성되어 Codex가 `banker-<name>` 으로 인식합니다.
|
|
202
210
|
- OMC/Claude 에 결합됐던 오케스트레이터·설치·유틸 표면(all-in-one·ultra-chain·ultra-init·front-qa·setup·setup-omc·setup-omc-hud·setup-stitch·omc-reference·compact-copy)은 본문이 **런타임 인식**이라 Codex에서도 동작합니다.
|
|
203
211
|
- `payload-mon` 은 Codex에서 실행해도 같은 머신의 Claude Code HUD 래퍼만 켜고 끕니다. \
|
|
@@ -352,14 +360,17 @@ Codex CLI는 샌드박스가 네트워크를 차단하므로 알림·카운팅
|
|
|
352
360
|
|
|
353
361
|
banker 자체는 **MIT** ([LICENSE](LICENSE)). Owner: [smallOpenSource](https://github.com/smallOpenSource).
|
|
354
362
|
|
|
355
|
-
**번들된
|
|
363
|
+
**번들된 코드와 데이터 (이 패키지가 재배포)**
|
|
356
364
|
- `skills/humanizer`: [blader/humanizer](https://github.com/blader/humanizer) 기반, **MIT License**(© 2025 Siqi Chen).\
|
|
357
365
|
원본 라이선스 고지는 `skills/humanizer/LICENSE` 에 포함.\
|
|
358
366
|
패턴 목록은 Wikipedia [*Signs of AI writing*](https://en.wikipedia.org/wiki/Wikipedia:Signs_of_AI_writing)(WikiProject AI Cleanup, **CC BY-SA**)에 기반합니다.
|
|
359
367
|
- `skills/3d-intro-build/references`: [oso95/scroll-world](https://github.com/oso95/scroll-world) 의 스크럽 엔진(`scrub-engine.js`·`index-template.html`)을 그대로 벤더링, **MIT License**(© 2026 cyw).\
|
|
360
368
|
원본 라이선스 고지는 `skills/3d-intro-build/references/LICENSE` 와 `NOTICE.md` 에 포함.
|
|
369
|
+
- `skills/theme-selection/assets`: 번들 팔레트(`palettes.json`)는 [VoltAgent/awesome-design-md](https://github.com/VoltAgent/awesome-design-md) 의 DESIGN.md 에서 색 값을 읽어 만든 것, **MIT License**(© 2026 VoltAgent).\
|
|
370
|
+
원본 라이선스 고지는 `skills/theme-selection/assets/LICENSE` 와 `NOTICE.md` 에 포함.\
|
|
371
|
+
테마 이름의 상표는 각 소유자에게 있으며, banker 는 그 회사들과 관계가 없습니다.
|
|
361
372
|
|
|
362
|
-
코드로 포함(재배포)하는 서드파티는 `humanizer` 와 `scroll-world`(`3d-intro-build`)
|
|
373
|
+
코드로 포함(재배포)하는 서드파티는 `humanizer` 와 `scroll-world`(`3d-intro-build`) 둘이고, 데이터로 포함하는 것은 `awesome-design-md`(`theme-selection`) 하나입니다.\
|
|
363
374
|
아래는 스킬이 **런타임에 의존하거나 연동**하는 외부 요소로, banker 가 재배포하지 않으며 각 라이선스·상표는 소유자에게 있습니다.
|
|
364
375
|
|
|
365
376
|
**의존 라이브러리·도구 (사용 시 별도 설치, 라이선스는 각 프로젝트 소유)**
|
|
@@ -48,6 +48,31 @@ export const NPM_LATEST_URL = 'https://registry.npmjs.org/@kaydash9999/banker-pl
|
|
|
48
48
|
// 테스트는 BANKER_SKILL_CHANGES_URL 로 loopback mock 을 주입해 실제 네트워크를 때리지 않는다.
|
|
49
49
|
export const SKILL_CHANGES_URL = 'https://raw.githubusercontent.com/smallOpenSource/banker_plugins/main/skill-changes.json';
|
|
50
50
|
|
|
51
|
+
// usage-log 와 체크인 본문에 실리는 스킬/커맨드 이름 꼴. 쓰는 훅 둘과 보내는 훅이 같은 규칙을 쓴다.
|
|
52
|
+
// 이름은 64자까지다(가장 긴 실제 이름은 24자). 모델이 지어낸 긴 이름이 기록과 체크인에 실리지 않게 한다.
|
|
53
|
+
export const SKILL_NAME_RE = /^banker:[a-z0-9_-]{1,64}$/i;
|
|
54
|
+
|
|
55
|
+
// 갱신 확인 요청 하나의 전체 마감(ms). 시험이 줄일 수 있게 BANKER_NET_DEADLINE_MS 를 받되 줄이기만 한다: 30초보다
|
|
56
|
+
// 길면 30초다. setTimeout 이 1ms 로 바꿔 버리는 값(0 이하, 숫자 아님)도 버리고 30초를 쓴다. 문서에 적지 않는 시험용 장치다.
|
|
57
|
+
export function netDeadlineMs(env = process.env) {
|
|
58
|
+
const v = Number(env.BANKER_NET_DEADLINE_MS);
|
|
59
|
+
return Number.isFinite(v) && v > 0 ? Math.min(v, 30_000) : 30_000;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 네트워크 응답 본문을 maxBytes 까지만 모아 done(문자열)로 넘긴다. 한도를 넘으면 연결을 끊고 done(null),
|
|
63
|
+
// 응답 스트림 오류도 done(null). 낯선 서버가 끝없이 보내도 메모리가 한도 밖으로 늘지 않게 한다.
|
|
64
|
+
export function collectBody(res, maxBytes, done) {
|
|
65
|
+
const chunks = [];
|
|
66
|
+
let size = 0;
|
|
67
|
+
res.on('data', (c) => {
|
|
68
|
+
size += c.length;
|
|
69
|
+
if (size > maxBytes) { res.destroy(); done(null); return; }
|
|
70
|
+
chunks.push(c);
|
|
71
|
+
});
|
|
72
|
+
res.on('end', () => done(Buffer.concat(chunks).toString('utf8')));
|
|
73
|
+
res.on('error', () => done(null));
|
|
74
|
+
}
|
|
75
|
+
|
|
51
76
|
// config.json 을 읽어 객체로 반환. 파일 없음·malformed JSON·권한 오류 등 어떤 예외에도 던지지 않고 {} 반환.
|
|
52
77
|
export function readConfig() {
|
|
53
78
|
try {
|
package/codex/manifest.json
CHANGED
|
@@ -71,6 +71,7 @@
|
|
|
71
71
|
{ "name": "trouble-shooting", "type": "skill", "target": "both", "reason": "investigates a problem and reports symptom, problem, cause, fix and action plan in one table, one row per problem; --no-plan stops at the fix; report only, never fixes", "supportingFiles": [] },
|
|
72
72
|
{ "name": "ultra-chain", "type": "skill", "target": "both", "reason": "orchestrates nine stages in order: deep-research, ultra-interview, ralplan --deliberate followed by a ralph-qa plan quorum of 3+ reviewers (ralplan has two reviewers and no way to add more), a mock the user approves, ralph --critic=critic (Codex: OMX ralph plus a critic loop, since OMX ralph has no --critic), tests on the registered OS boxes fed to a ralph-qa quorum, visual review (machine diff against the mock, screenshots, an independent verdict), a process report rendered from its own ledger, and local sharing; Claude=OMC 5, Codex=OMX; body runtime-aware; pure Node helpers, no deps", "supportingFiles": ["references/chain-ledger.mjs", "references/chain-report.mjs", "references/capture.mjs", "references/serve.mjs", "references/preview-lib.mjs"], "caveat": "uses the sibling banker skills deep-research, ultra-interview, ralph-qa and remains (boxes.mjs); box runs need ssh, scp and git with key-only logins in ~/.config/banker/test-boxes.json; screenshots need Playwright with Chromium; serve.mjs and preview-lib.mjs are byte-identical copies of 3d-intro-build's (scripts/sync-adapter.js); never pushes, opens a PR or posts outside without an explicit request" },
|
|
73
73
|
{ "name": "anti-drm", "type": "skill", "target": "both", "reason": "turns on or off rules that steer the agent away from the file extensions a network-separated PC's DRM encrypts (default .txt .pdf .ppt .pptx .doc .docx .hwp .hwpx .xls .xlsx .csv) toward replacements (.md .html .tsv); asks the extensions on first use and keeps them in ~/.config/banker/anti-drm.json; pure Node, no deps", "supportingFiles": ["scripts/anti-drm.mjs", "scripts/instruction-toggle.mjs"], "caveat": "the same places as tone-compact (shared module instruction-toggle.mjs): Claude Code gets <config>/rules/banker-anti-drm.md; Codex gets one marked block wrapped in USER:OMX:POLICY at the end of AGENTS.md, or AGENTS.override.md when it has content of its own. The settings are shared by both runtimes; on and off act on one runtime, while config and on with settings refresh every runtime that holds the rules. It never decrypts or converts files DRM already protects; it only picks the extensions of files the agent newly creates. The organization's security rules come first" },
|
|
74
|
+
{ "name": "theme-selection", "type": "skill", "target": "both", "reason": "applies 74 themes to a project as CSS custom properties, light and dark (148 combinations), with contrast correction; also emits a theme picker (markup and two scripts) and a contrast audit (check), and reads the project's DESIGN.md as more themes; pure Node, no deps, no network", "supportingFiles": ["scripts/themes.mjs", "assets/palettes.json", "assets/LICENSE", "assets/NOTICE.md", "references/integrate.md", "references/contrast.md"], "caveat": "the bundled palettes derive from VoltAgent/awesome-design-md (MIT; LICENSE and NOTICE.md in assets/); theme names only point at the sites the designs reference, and the trademarks belong to their owners; --out overwrites the file it names (refused when that file itself is a symbolic link), so the skill asks first when that file exists" },
|
|
74
75
|
|
|
75
76
|
{ "name": "front-qa", "type": "command", "target": "both", "reason": "ralplan->ralph frontend-QA pipeline; Claude=OMC, Codex=OMX", "supportingFiles": [] },
|
|
76
77
|
{ "name": "setup", "type": "command", "target": "both", "reason": "installer orchestrator; Claude AskUserQuestion multi-select, Codex prompt-based selection", "supportingFiles": [] }
|
|
@@ -47,6 +47,7 @@ The generator (`banker setup --codex`) applies the rules below for `target: both
|
|
|
47
47
|
- `omc-patch` — acts on the Claude Code OMC plugin cache (`~/.claude/plugins/`) even when run from Codex; Codex's own OMX is untouched. The skill always passes `--no-update` (a plain apply would switch the active OMC to the tool's hard-coded `TARGET_VERSION`). `--revert --root` restores only the active plugin folder when an older kit left the timeout helper inside a block, and `scripts/probe-pm.mjs` runs OMC's project-memory hook in a temp scratch project with its own home and state folder.
|
|
48
48
|
- `remains` — the same procedure in both runtimes; box runs go through `scripts/boxes.mjs` (Codex: `~/.codex/skills/banker-remains/scripts/boxes.mjs`), which needs `ssh`, `scp` and `git` on the machine and key-only logins to the boxes in `~/.config/banker/test-boxes.json`. It reads and runs tests only: no fix, no commit, no push.
|
|
49
49
|
- `ultra-chain` — the same nine stages in both runtimes. Claude=OMC 5 (`ralplan --deliberate`, `ralph --critic=critic`); Codex=OMX (`$ralplan --deliberate`, then `$ralph` with the skill's own critic loop through `spawn_agent`, because OMX `ralph` has no `--critic`). Both add a `ralph-qa` plan quorum after ralplan (two reviewers, no option to add more), run OS tests through the sibling `remains/scripts/boxes.mjs` (Codex: `banker-remains`), judge screenshots with a fresh agent (OMX 0.20.2's `visual-verdict` is a deprecated stub), and render the process report from the skill's own ledger (`lineage` reads Claude Code sessions only). Box runs need `ssh`, `scp` and `git`; screenshots need Playwright with Chromium; under Codex's `workspace-write` sandbox the ssh calls and the review seats' home writes may ask for approval.
|
|
50
|
+
- `theme-selection` — the same procedure in both runtimes; the engine is `scripts/themes.mjs` (Codex: `~/.codex/skills/banker-theme-selection/scripts/themes.mjs`), which reads `assets/palettes.json` beside it. Pure Node with no network; it writes only the file `--out` names (refused when that file itself is a symbolic link), and the skill asks before it overwrites one that exists.
|
|
50
51
|
- `/graceful-pause` (not a manifest surface) — a Claude Code function-hooks command (`hooks/register.mjs`, 2.1.289+) registered `immediate`, so it runs mid-turn; it appends one hidden user row the running turn reads at its next model request. Codex has no equivalent (no function hooks), and the earlier `graceful_pause` skill was removed because a typed skill waits until the turn ends.
|
|
51
52
|
|
|
52
53
|
신규 스킬(0.7.0)도 `both`·런타임 인식:
|
package/hooks/graceful-pause.mjs
CHANGED
|
@@ -124,8 +124,9 @@ const fresh = () => ({ main: null, step: -1, pending: null, background: 0, queue
|
|
|
124
124
|
const listed = (v) => (Array.isArray(v) ? v.length : 0);
|
|
125
125
|
const backgroundCount = (e) => listed(e.background_tasks) + listed(e.session_crons);
|
|
126
126
|
|
|
127
|
-
// The main turn in flight and its latest model request; subagent
|
|
128
|
-
//
|
|
127
|
+
// The main turn in flight and its latest model request; a subagent's, a fork's or a teammate's loop starts
|
|
128
|
+
// and ends with an agentId (Claude Code 2.1.300 raises turn.start for them too) and is not the main turn.
|
|
129
|
+
// `queued`: a report prompt not started yet. One per loaded module.
|
|
129
130
|
const state = fresh();
|
|
130
131
|
|
|
131
132
|
// The command and the events only this feature hooks. register.mjs hooks the events every banker
|
|
@@ -167,6 +168,7 @@ export function pauseReset() {
|
|
|
167
168
|
}
|
|
168
169
|
|
|
169
170
|
export function pauseTurnStarted(e) {
|
|
171
|
+
if (e.agentId) return;
|
|
170
172
|
Object.assign(state, { main: e.turnId, step: -1, queued: false });
|
|
171
173
|
}
|
|
172
174
|
|
package/hooks/obsidize-hook.mjs
CHANGED
|
@@ -17,16 +17,22 @@
|
|
|
17
17
|
* - Exits 0 on every path. A hook cannot block or alter a tool result and must not try.
|
|
18
18
|
* - Every error appends exactly one line to <wikiDir>/.obsidizer-hook.log. Exit 0 hides
|
|
19
19
|
* stderr too, so that log is the only channel by which a permanently broken hook is
|
|
20
|
-
* discoverable rather than silently doing nothing forever.
|
|
20
|
+
* discoverable rather than silently doing nothing forever. Only a regular file there is
|
|
21
|
+
* written: a link (a cloned repository can carry one) or a pipe gets no line.
|
|
21
22
|
*/
|
|
22
23
|
import { spawnSync } from 'node:child_process';
|
|
23
|
-
import {
|
|
24
|
+
import { closeSync, constants, existsSync, fstatSync, lstatSync, openSync, readdirSync, statSync, writeSync } from 'node:fs';
|
|
24
25
|
import { basename, dirname, join, resolve } from 'node:path';
|
|
25
26
|
import { fileURLToPath } from 'node:url';
|
|
26
27
|
|
|
27
28
|
const CANONICALIZER = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'skills', 'obsidizer', 'obsidize.mjs');
|
|
28
29
|
const FLAG = '.obsidizer';
|
|
29
30
|
const LOG = '.obsidizer-hook.log';
|
|
31
|
+
const LOG_REASON_MAX = 500;
|
|
32
|
+
// Append, never through a link, and never wait for a pipe's reader. Windows has neither flag: there the log place is
|
|
33
|
+
// looked at first and a link is left alone (one swapped in after that look is still followed there).
|
|
34
|
+
const NO_FOLLOW = constants.O_NOFOLLOW ?? 0;
|
|
35
|
+
const LOG_FLAGS = constants.O_WRONLY | constants.O_APPEND | constants.O_CREAT | NO_FOLLOW | (constants.O_NONBLOCK ?? 0);
|
|
30
36
|
// OMC owns these three. index.md is rewritten on every ingest, so it is always the freshest
|
|
31
37
|
// file in the vault — the scan fallback below would target it first without this guard.
|
|
32
38
|
const RESERVED = new Set(['index.md', 'log.md', 'environment.md']);
|
|
@@ -46,14 +52,27 @@ function readStdin() {
|
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
function log(wikiDir, tool, reason) {
|
|
49
|
-
|
|
55
|
+
// One line of plain text: whitespace and control characters (ESC among them) fold to a space, and a long reason is cut.
|
|
56
|
+
const text = String(reason).replace(/[\s\x00-\x1f\x7f-\x9f]+/g, ' ').trim();
|
|
57
|
+
const line = `${new Date().toISOString()}\t${tool}\t${text.length > LOG_REASON_MAX ? `${text.slice(0, LOG_REASON_MAX)}...` : text}\n`;
|
|
58
|
+
const at = join(wikiDir, LOG);
|
|
50
59
|
try {
|
|
51
|
-
|
|
60
|
+
if (!NO_FOLLOW && isLink(at)) return;
|
|
61
|
+
const fd = openSync(at, LOG_FLAGS, 0o600);
|
|
62
|
+
try {
|
|
63
|
+
if (fstatSync(fd).isFile()) writeSync(fd, line);
|
|
64
|
+
} finally {
|
|
65
|
+
closeSync(fd);
|
|
66
|
+
}
|
|
52
67
|
} catch {
|
|
53
68
|
// The log is best-effort; the failure path must never throw.
|
|
54
69
|
}
|
|
55
70
|
}
|
|
56
71
|
|
|
72
|
+
function isLink(path) {
|
|
73
|
+
try { return lstatSync(path).isSymbolicLink(); } catch { return false; }
|
|
74
|
+
}
|
|
75
|
+
|
|
57
76
|
function isDir(path) {
|
|
58
77
|
try { return statSync(path).isDirectory(); } catch { return false; }
|
|
59
78
|
}
|
|
@@ -103,43 +122,53 @@ function resolvePages(wikiDir, toolResponse) {
|
|
|
103
122
|
.filter((path) => existsSync(path));
|
|
104
123
|
}
|
|
105
124
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
let stdinError = null;
|
|
125
|
+
// The hook payload, or the error that kept it from being read.
|
|
126
|
+
async function readPayload() {
|
|
109
127
|
try {
|
|
110
|
-
payload
|
|
128
|
+
return { payload: JSON.parse(await readStdin()), error: null };
|
|
111
129
|
} catch (err) {
|
|
112
|
-
|
|
130
|
+
return { payload: null, error: err };
|
|
113
131
|
}
|
|
132
|
+
}
|
|
114
133
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
134
|
+
// Why a canonicalizer run failed, or null when it ran and reported JSON.
|
|
135
|
+
function runFailure(run) {
|
|
136
|
+
if (run.error) return `canonicalizer did not run: ${run.error.message}`;
|
|
137
|
+
if (run.status !== 0) return `canonicalizer exited ${run.status}: ${run.stderr || run.stdout}`;
|
|
138
|
+
try {
|
|
139
|
+
JSON.parse(run.stdout);
|
|
140
|
+
return null;
|
|
141
|
+
} catch {
|
|
142
|
+
return 'canonicalizer report was not json';
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Canonicalizes one page; a failure appends its one log line.
|
|
147
|
+
function canonicalize(wikiDir, tool, page) {
|
|
148
|
+
const run = spawnSync(process.execPath, [CANONICALIZER, page, '--profile=omc', '--json'], {
|
|
149
|
+
encoding: 'utf8',
|
|
150
|
+
timeout: CANONICALIZE_TIMEOUT_MS,
|
|
151
|
+
windowsHide: true,
|
|
152
|
+
});
|
|
153
|
+
const why = runFailure(run);
|
|
154
|
+
if (why) log(wikiDir, tool, `${basename(page)}: ${why}`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// A write can be redirected with workingDirectory; fall back to the session cwd.
|
|
158
|
+
function writeRoot(payload) {
|
|
159
|
+
return payload?.tool_input?.workingDirectory || payload?.cwd || process.cwd();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async function main() {
|
|
163
|
+
const { payload, error } = await readPayload();
|
|
164
|
+
const wikiDir = findArmedWikiDir(writeRoot(payload));
|
|
118
165
|
if (!wikiDir) return; // Not armed: change nothing, log nothing.
|
|
119
166
|
|
|
120
167
|
const tool = payload?.tool_name ?? 'unknown';
|
|
121
168
|
try {
|
|
122
|
-
if (
|
|
169
|
+
if (error) return log(wikiDir, tool, `unreadable hook payload: ${error.message}`);
|
|
123
170
|
if (!existsSync(CANONICALIZER)) return log(wikiDir, tool, `canonicalizer missing at ${CANONICALIZER}`);
|
|
124
|
-
|
|
125
|
-
for (const page of resolvePages(wikiDir, payload.tool_response)) {
|
|
126
|
-
const run = spawnSync(process.execPath, [CANONICALIZER, page, '--profile=omc', '--json'], {
|
|
127
|
-
encoding: 'utf8',
|
|
128
|
-
timeout: CANONICALIZE_TIMEOUT_MS,
|
|
129
|
-
windowsHide: true,
|
|
130
|
-
});
|
|
131
|
-
if (run.error) {
|
|
132
|
-
log(wikiDir, tool, `${basename(page)}: canonicalizer did not run: ${run.error.message}`);
|
|
133
|
-
} else if (run.status !== 0) {
|
|
134
|
-
log(wikiDir, tool, `${basename(page)}: canonicalizer exited ${run.status}: ${run.stderr || run.stdout}`);
|
|
135
|
-
} else {
|
|
136
|
-
try {
|
|
137
|
-
JSON.parse(run.stdout);
|
|
138
|
-
} catch {
|
|
139
|
-
log(wikiDir, tool, `${basename(page)}: canonicalizer report was not json`);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
171
|
+
for (const page of resolvePages(wikiDir, payload.tool_response)) canonicalize(wikiDir, tool, page);
|
|
143
172
|
} catch (err) {
|
|
144
173
|
log(wikiDir, tool, `unexpected: ${err.message}`);
|
|
145
174
|
}
|
package/hooks/progress-plan.mjs
CHANGED
|
@@ -183,18 +183,24 @@ const PLAN_PATHS = [
|
|
|
183
183
|
/\/\.omc\/plans\/[^/]+\.md$/,
|
|
184
184
|
/\/docs\/superpowers\/plans\/[^/]+\.md$/,
|
|
185
185
|
/\/\.claude\/plans\/[^/]+\.md$/,
|
|
186
|
-
|
|
187
|
-
|
|
186
|
+
// A ralph PRD and ultragoal's goals wherever they sit: OMC_STATE_DIR moves OMC's state out of .omc (a mod cannot
|
|
187
|
+
// read that variable), and a project may keep its PRD at the top. Only a file that parses as one becomes the plan.
|
|
188
|
+
/\/prd\.json$/,
|
|
189
|
+
/\/ultragoal\/goals\.json$/,
|
|
188
190
|
];
|
|
189
191
|
// Plan folders keep a plan's review rounds beside it (ralplan's `<plan>-critic-r2.md`,
|
|
190
|
-
// `architect-review-r1.md`) and OMC's open questions: a name that ends so is
|
|
191
|
-
|
|
192
|
+
// `architect-review-r1.md`) and OMC's open questions: a name that ends so is a weak plan, the plan only while the
|
|
193
|
+
// pane has no other.
|
|
194
|
+
const WEAK_NAMES = [/(?:^|[-_])(?:critic|architect|review|verdict|feedback)(?:-r\d+)?\.md$/i, /^open-questions\.md$/i];
|
|
192
195
|
|
|
193
|
-
|
|
196
|
+
/** What a path is to the pane: 'plan', 'weak' (a review round or open questions beside a plan), or null. */
|
|
197
|
+
export function planKind(path) {
|
|
194
198
|
const p = String(path ?? '').replaceAll('\\', '/');
|
|
195
|
-
|
|
196
|
-
return
|
|
197
|
-
}
|
|
199
|
+
if (!PLAN_PATHS.some((re) => re.test(p))) return null;
|
|
200
|
+
return WEAK_NAMES.some((re) => re.test(p.split('/').at(-1))) ? 'weak' : 'plan';
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export const isPlanPath = (path) => planKind(path) === 'plan';
|
|
198
204
|
|
|
199
205
|
// ── a plan file ──────────────────────────────────────────────────────────────
|
|
200
206
|
|