@kaydash9999/banker-plugins 0.23.3 → 0.24.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.
Files changed (78) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +56 -0
  4. package/README.md +14 -6
  5. package/codex/manifest.json +6 -2
  6. package/codex/skills/teamwork/scripts/teamwork.mjs +3 -3
  7. package/codex/transform-matrix.md +6 -2
  8. package/package.json +1 -1
  9. package/skills/build-testbox/SKILL.md +213 -0
  10. package/skills/build-testbox/scripts/args.mjs +156 -0
  11. package/skills/build-testbox/scripts/browser-cell.mjs +181 -0
  12. package/skills/build-testbox/scripts/browsers.mjs +164 -0
  13. package/skills/build-testbox/scripts/containers.mjs +237 -0
  14. package/skills/build-testbox/scripts/detect.mjs +166 -0
  15. package/skills/build-testbox/scripts/proc.mjs +91 -0
  16. package/skills/build-testbox/scripts/report.mjs +109 -0
  17. package/skills/build-testbox/scripts/setup.mjs +144 -0
  18. package/skills/build-testbox/scripts/testbox.mjs +148 -0
  19. package/skills/git-init/SKILL.md +152 -0
  20. package/skills/git-init/scripts/git-init.mjs +440 -0
  21. package/skills/git-init/scripts/marker-block.mjs +321 -0
  22. package/skills/git-init/scripts/payload-scan.mjs +186 -0
  23. package/skills/init-dir/SKILL.md +172 -0
  24. package/skills/init-dir/scripts/init-dir.mjs +308 -0
  25. package/skills/init-dir/scripts/marker-block.mjs +321 -0
  26. package/skills/init-dir/scripts/templates.mjs +100 -0
  27. package/skills/init-dir/templates/KB/README.md +15 -0
  28. package/skills/init-dir/templates/docs/README.md +14 -0
  29. package/skills/init-dir/templates/logs/README.md +14 -0
  30. package/skills/init-dir/templates/logs/gitignore +3 -0
  31. package/skills/init-dir/templates/mockup/README.md +7 -0
  32. package/skills/init-dir/templates/scripts/README.md +39 -0
  33. package/skills/init-dir/templates/scripts/lib/service.mjs +596 -0
  34. package/skills/init-dir/templates/scripts/restart.cmd +13 -0
  35. package/skills/init-dir/templates/scripts/restart.sh +10 -0
  36. package/skills/init-dir/templates/scripts/service.conf +5 -0
  37. package/skills/init-dir/templates/scripts/start.cmd +13 -0
  38. package/skills/init-dir/templates/scripts/start.sh +10 -0
  39. package/skills/init-dir/templates/scripts/status.cmd +13 -0
  40. package/skills/init-dir/templates/scripts/status.sh +10 -0
  41. package/skills/init-dir/templates/scripts/stop.cmd +13 -0
  42. package/skills/init-dir/templates/scripts/stop.sh +10 -0
  43. package/skills/init-dir/templates/tests/README.md +15 -0
  44. package/skills/init-dir/templates/tests/run.cmd +13 -0
  45. package/skills/init-dir/templates/tests/run.mjs +160 -0
  46. package/skills/init-dir/templates/tests/run.sh +10 -0
  47. package/skills/init-dir/templates/tests/tests.conf +7 -0
  48. package/skills/init-dir/templates/work/README.md +8 -0
  49. package/skills/progress-mon/README.md +11 -8
  50. package/skills/progress-mon/SKILL.md +53 -16
  51. package/skills/progress-mon/assets/fixture/README.md +1 -1
  52. package/skills/progress-mon/assets/fixture/adr.json +35 -0
  53. package/skills/progress-mon/assets/fixture/arch.json +1 -1
  54. package/skills/progress-mon/assets/fixture/flow.json +2 -2
  55. package/skills/progress-mon/assets/fixture/variants/arch-auto/arch.json +1 -1
  56. package/skills/progress-mon/assets/fixture/variants/legacy-init/rules.json +6 -0
  57. package/skills/progress-mon/assets/fixture/variants/legacy-init/state.json +5 -0
  58. package/skills/progress-mon/references/adr.md +184 -0
  59. package/skills/progress-mon/references/authoring.md +13 -5
  60. package/skills/progress-mon/scripts/pm-adr-view.mjs +101 -0
  61. package/skills/progress-mon/scripts/pm-adr.mjs +515 -0
  62. package/skills/progress-mon/scripts/pm-check.mjs +59 -22
  63. package/skills/progress-mon/scripts/pm-data.mjs +1 -1
  64. package/skills/progress-mon/scripts/pm-html.mjs +1 -0
  65. package/skills/progress-mon/scripts/pm-memory.mjs +113 -28
  66. package/skills/progress-mon/scripts/pm-render.mjs +6 -4
  67. package/skills/progress-mon/scripts/pm-server.mjs +2 -1
  68. package/skills/progress-mon/scripts/pm-sources.mjs +10 -0
  69. package/skills/progress-mon/scripts/progress-mon.mjs +3 -2
  70. package/skills/tune-tmux/SKILL.md +235 -0
  71. package/skills/tune-tmux/scripts/app-notes.mjs +38 -0
  72. package/skills/tune-tmux/scripts/marker-block.mjs +321 -0
  73. package/skills/tune-tmux/scripts/psmux-caps.json +71 -0
  74. package/skills/tune-tmux/scripts/tmux-config.mjs +251 -0
  75. package/skills/tune-tmux/scripts/tune-tmux.mjs +284 -0
  76. package/skills/ultra-chain/SKILL.md +52 -22
  77. package/skills/ultra-chain/references/chain-ledger.mjs +93 -11
  78. package/skills/ultra-chain/references/chain-report.mjs +13 -2
@@ -6,7 +6,7 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "Claude Code skills + commands — QA, audit, docs, architecture, dependency setup, and wiki; the banker plugin marketplace.",
9
- "version": "0.23.3"
9
+ "version": "0.24.1"
10
10
  },
11
11
  "plugins": [
12
12
  {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "banker",
3
- "version": "0.23.3",
3
+ "version": "0.24.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,61 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.24.1] - 2026-11-02
4
+
5
+ ### Fixed
6
+ - `init-dir`(Windows): `AGENTS.md` 와 `CLAUDE.md` 가 둘 다 있을 때 가끔 `CLAUDE.md` 에 블록을 쓰지 않고도 종료 0 으로 끝나던 것을 고친다. 두 파일이 같은 파일인지 가릴 때 파일 번호(ino)를 Number 로 받았는데, NTFS 파일 ID 는 2^53 을 넘어 아래 자리가 잘리고 연달아 만든 두 파일이 같은 번호가 될 수 있었다(Windows 테스트박스 실측: 300쌍 중 3쌍 충돌). 이제 bigint 로 가리고, 번호가 0 인 파일 시스템은 파일 시스템이 쓰는 경로 표기로 가린다. 같은 표지 블록 모듈을 쓰는 `git-init`, `tune-tmux` 도 같은 판으로 맞췄다. 두 스킬은 파일 하나만 쓰므로 이 결함에 닿지 않았다.
7
+ - `init-dir` 틀의 `service.mjs`: 낡은 시작 잠금이 있을 때 `start` 를 여럿 동시에 실행하면 감독이 둘 뜰 수 있던 틈을 닫는다. 낡은 잠금은 이제 정리 잠금(`logs/<이름>.start.lock.break`)을 새 파일로 만든 `start` 하나만 지우고, 지우기 전에 다시 읽어 그 사이 다른 `start` 가 잡은 잠금은 지우지 않는다. Windows 에서 지우는 중인 잠금이 내는 EPERM, EACCES, EBUSY 는 바쁨으로 보고 기다리고, 잠금을 만들 수 없는 진짜 권한 오류는 바로 사유와 함께 종료 1 로 끝난다. 고친 틀은 새로 만드는 `scripts/` 폴더에 들어간다. `init-dir` 은 이미 있는 폴더의 내용을 건드리지 않으므로 이미 만든 프로젝트의 틀은 그대로다.
8
+ - `teamwork`(Codex 전용): `--file` 이 확인과 열기 사이에 바뀐 파일을 가릴 때도 파일 번호를 bigint 로 비교한다. Windows 에서 다른 파일로 바꿔치기된 것을 놓칠 수 있었다.
9
+
10
+ ### Changed
11
+ - `progress-mon`: ADR 화면이 `check` 결과와 같은지 알린다. 화면은 참조 파일을 열지 않아 적힌 참조로 세고, `check` 는 확인을 마친 참조로 세므로 "참조 없는 서술" 수가 다를 수 있었다. 이제 `check` 가 자료 폴더의 `adr-check.json` 에 집계와 그때 `adr.json` 의 sha256 을 남기고, 화면은 집계 배지 옆에 `check 와 같음`, `check 뒤 adr.json 이 바뀜`, `check 기준: <집계>`(다름), `check 기록 없음` 가운데 하나를 보인다. 기록을 쓰지 못하면 경고만 내고 검사 결과와 종료 코드는 그대로다.
12
+ - `progress-mon`: ADR 화면 렌더를 `scripts/pm-adr-view.mjs` 로 나눴다. 검사, 정리, 밀도, 집계는 `scripts/pm-adr.mjs` 에 남는다.
13
+
14
+ ### Notes
15
+ - Windows 에서 0.24.0 의 `init-dir apply` 를 쓴 프로젝트는 업데이트 뒤 `init-dir status` 로 확인한다. `CLAUDE.md` 나 `AGENTS.md` 가 `stale` 로 나오면 블록이 빠진 것이므로 `init-dir apply` 를 한 번 더 실행하면 채워진다. 이미 블록이 있는 파일은 바뀌지 않는다.
16
+ - 시험 정비: Windows 에서 위 결함 때문에 가끔 실패하던 `init-dir` 시험의 원인을 고쳤다. `3d-intro-build` 의 Sora 배포 확인 시험이 실제 현재 시각을 써 시험 자료의 퇴역일(2026-11-02)이 지나자 실패하던 것을 고정 시각으로 고쳤다(제품 동작은 바뀌지 않음). `progress-mon` 의 ADR 화면 e2e 는 테스트박스 도구 폴더의 Playwright(`BUILD_TESTBOX_PLAYWRIGHT_DIR`)를 먼저 써서 박스에서 건너뛰지 않는다.
17
+ - 훅 코드는 바뀌지 않아 Codex 플러그인 사용자에게 `/hooks` 신뢰를 다시 묻지 않는다.
18
+ - 실측: 테스트박스 3대에서 38ab876 을 시험했다(통과/실패/건너뜀). Rocky Linux 8 2807/0/34, macOS 2799/0/42, Windows 2492/0/344.
19
+
20
+ ## [0.24.0] - 2026-11-02
21
+
22
+ ### Added
23
+ - 새 스킬 `init-dir`: 프로젝트에 관리 폴더 7개(`logs`, `scripts`, `work`, `mockup`, `tests`, `docs`, `KB`)를 만들고, 폴더마다 목적을 지금 세션에 알리며 `AGENTS.md`, `CLAUDE.md` 중 있는 것에 표지 블록으로 적는다. 새로 만든 폴더에만 틀 파일(서비스 시작, 정지, 상태, 재시작 스크립트와 100MB 로그 로테이션, 시험 실행기, README)을 넣고, 이미 있는 폴더는 내용을 건드리지 않는다. 두 런타임에서 쓰고, 내려받지 않는다.
24
+ - `docs` 의 목적은 "문서를 관리하는 영역. evidence와 ADR도 포함하여 보관한다." 이고, 새 `docs/` 에 `evidence/`, `adr/` 하위 폴더를 만든다. 옛 판이 쓴 블록은 docs 줄만 멱등으로 바꾼다.
25
+ - 틀은 임시 폴더에 다 쓴 뒤 rename 으로 옮긴다. 강제 종료로 남은 임시 폴더는 `status` 가 보고한다.
26
+ - 틀의 `service.mjs` 는 PID 재사용으로 남의 프로세스를 끄지 않는다. Linux 는 `/proc/<pid>/cmdline` 을 먼저 읽고, 끝내 확인하지 못하면 PID 파일을 남기고 종료 1 로 끝난다. 동시에 `start` 해도 감독은 하나다. Windows 에서는 감독과 함께 죽은 셸이 남긴 자식도 찾아 끈다.
27
+ - 새 스킬 `git-init`: 저장소가 아닌 폴더에 첫 커밋을 만들어 worktree 같은 병렬 작업을 준비한다. 민감 정보를 빼는 `.gitignore` 를 쓰고, 추적할 파일을 이름과 내용으로 비밀값 스캔한 뒤 `git init`, `git add .`, `git commit -m init` 을 실행한다. 걸리면 `.git` 을 만들지 않고 위치(`파일:줄:종류`)만 보고하며, 사용자가 오탐으로 확인한 것만 `--accept` 로 넘긴다. 키 파일 이름은 넘길 수 없다. 두 런타임에서 쓰고, 네트워크를 쓰지 않는다.
28
+ - `.npmrc`, `.netrc` 같은 자격 증명 파일과 강제 종료로 남은 `init-dir` 임시 폴더를 자동으로 뺀다. 스캔하지 못한 파일 목록을 보인다.
29
+ - 새 스킬 `build-testbox`: 이 PC 의 자원으로 시험 환경을 꾸린다. Playwright Chromium, WebKit 의 데스크톱과 모바일 기기 에뮬레이션과 docker, podman 의 Rocky Linux 8, 9 컨테이너를 병렬로 돌려, 칸마다 pass, fail, unverified, unsupported 와 사유를 표와 `results.json` 으로 낸다. 두 런타임에서 쓴다.
30
+ - `run` 은 내려받지 않는다. 없는 이미지나 브라우저는 `unverified` 와 사유로 남는다. 받기는 `setup` 이 목록과 크기를 보인 뒤 `--yes` 로 다시 부를 때만 한다.
31
+ - Playwright 위치는 `--playwright-dir` 이나 `BUILD_TESTBOX_PLAYWRIGHT_DIR` 로 줄 수 있다. Rocky 8 처럼 WebKit 라이브러리가 없는 호스트는 `--browser-in-container` 로 Playwright 공식 이미지에서 돌린다.
32
+ - e2e 시험의 조용한 통과를 사유 있는 건너뜀으로 바꿨다.
33
+ - 새 스킬 `tune-tmux`: tmux, psmux 설정 파일에 표지 블록을 넣고 빼서, 마우스 드래그 복사(OS 클립보드, 도구가 없으면 OSC 52)와 일반 화면의 PageUp/PageDown 스크롤을 맞춘다. 전체 화면 앱(Claude Code, Codex)의 키와 마우스는 앱에 넘긴다. 첫 원본을 백업하고, `off` 는 블록만 빼며, `--reload` 로 떠 있는 서버에 반영한다. 두 런타임에서 쓰고, 네트워크를 쓰지 않는다.
34
+
35
+ ### Changed
36
+ - `ultra-chain`: `--agents=N`(기본 3)을 5단계 critic 좌석과 7단계 시각 판정자에도 쓴다. 전원 승인 합치기와 좌석 수는 기록 스크립트(`chain-ledger`)가 강제한다. ralph 자체 승인은 `ralph-reviewer` 로 기록하고, 좌석을 잃으면 `INCONCLUSIVE` 로 멈춘다. 5단계 판정을 기록하는 쪽은 `critic`, `ralph-reviewer` 둘뿐이고 결과값도 정해진 값만 받는다. `--agents` 를 주지 않으면 init 에 3 을 넘기지 않아 기본값으로 기록된다.
37
+ - `progress-mon`: ADR 탭을 더해 5탭이 된다.
38
+ - 자료는 두 층이다. 프로젝트 단위(검증, 흐름, 증거)와 결정 단위(최적화 로직, 확장 대응, 포기와 얻은 것)의 6항목을 확인 가능한 참조와 함께 보인다.
39
+ - `check` 가 스키마, 참조, 밀도, `docs/adr` 와의 갈라짐을 검사한다.
40
+ - "주장에는 증거" 규칙: 구현된 기능의 증명과 검증한 모듈의 evidence 에 확인을 마친 참조(FAIL, WARN 없음)가 없으면 FAIL 이다. 통과하려면 그 기능을 구현 못 함으로, 그 모듈을 미검증으로 옮겨야 한다. 결정의 서술 칸 gap 은 WARN 이다. 화면 배지와 `check` 마지막 줄에 근거 없음 칸, 미검증, 구현 못 함, 참조 없는 서술 수를 늘 보인다.
41
+ - 꼴이 틀린 `adr.json` 은 지우지 않고 `adr.json.rejected-<시각>` 으로 옮긴다.
42
+ - ADR 탭 전에 init 한 프로젝트는 다음 인자 없는 호출에서 확인 뒤 ADR 단계를 하고, 메모리의 옛 규칙 줄을 새 판으로 바꾼다(백업, UTF-8 아닌 파일 거부, 임시 파일 rename).
43
+
44
+ ### Fixed
45
+ - 저장소 `.gitignore` 의 `work/` 가 스킬 틀 폴더(`skills/init-dir/templates/work/`)까지 무시해 틀 파일이 커밋에서 빠지던 것을 고친다. 규칙을 루트 `/work/` 로 한정했다. 스모크가 배포 파일이 git 무시 규칙에 걸리지 않는지 단언한다.
46
+ - `progress-mon` 시험이 macOS 의 차례 포트 배정 때문에 다른 시험 서버가 잡은 `port+k` 를 자기 서버로 보고 실패하던 것을 고친다. 남은 서버 확인이 신원 경로의 PID 로 자기 서버만 판정한다.
47
+ - 부하에 흔들리던 시험의 대기를 폴링으로 바꿨다. `omc-patch` 의 git 도우미 연결 종료 대기는 3초에서 15초로 늘렸다(50ms 폴링, 끝나지 않는 도우미는 그대로 실패).
48
+
49
+ ### Notes
50
+ - 범위 축소와 한계
51
+ - psmux(3.3.8 실측)는 넣을 줄이 0줄이다. `on` 은 종료 0 과 `넣은 줄 0: psmux 기본값 유지. 미확인 2, 안 됨 3` 줄, 되는 것, 확인 못 한 것, 안 되는 것 목록을 낸다. 종료 0 은 원하는 동작이 다 된다는 뜻이 아니다.
52
+ - `build-testbox` 의 macOS 배포 시험은 Apple Silicon 호스트의 Tart VM 만 지원한다. 비 Apple 호스트는 라이선스 사유로 `unsupported` 다. 실제 Safari, iOS 시뮬레이터는 WebKit 에뮬레이션으로 대신한다.
53
+ - Codex Fullscreen(기본)의 기록 스크롤은 tmux 설정으로 고칠 수 없다. 공식 우회(`/tui` 의 Scrollback, `codex --no-alt-screen`, `tui.alternate_screen = "never"`)를 안내만 하고 Codex 설정은 바꾸지 않는다.
54
+ - ADR `check` 는 참조가 가리키는 파일과 위치가 있는지만 본다. 참조 내용이 주장을 뒷받침하는지는 판정하지 않는다.
55
+ - 훅 코드는 바뀌지 않아 Codex 플러그인 사용자에게 `/hooks` 신뢰를 다시 묻지 않는다.
56
+ - 실측: 테스트박스 3대에서 945d3e3 을 시험했다(통과/실패/건너뜀). Rocky Linux 8 2796/0/35, macOS 2788/0/43, Windows 2483/0/343.
57
+ - 실측: Rocky Linux 8 박스(podman 4.9.4)에서 `build-testbox run --browser-in-container` 로 Desktop Chrome, Pixel 7(Chromium), Desktop Safari, iPhone 15(WebKit)와 `os:rocky8`, `os:rocky9` 6칸이 모두 통과했고, 브라우저 칸과 컨테이너 칸이 병렬로 겹쳐 돈 것을 확인했다.
58
+
3
59
  ## [0.23.3] - 2026-10-31
4
60
 
5
61
  ### Fixed
package/README.md CHANGED
@@ -9,7 +9,7 @@
9
9
  [빠른 시작](#빠른-시작) · [워크플로 예시](#워크플로-사용-예시) · [구성](#구성) · [설치 상세](#설치-상세-npm--codex) · [설정 변경 지점](#설정-변경-지점-claude-code--codex) · [요구사항](#요구사항) · [업데이트 / 제거](#업데이트--제거) · [업데이트 확인](#업데이트-확인-및-사용량-카운팅) · [오프라인](#오프라인에서-쓰기) · [라이선스 / 서드파티](#라이선스--서드파티)
10
10
 
11
11
  □ banker는 다음을 포함하는 Claude Code 및 Codex CLI 플러그인입니다.
12
- - QA·보안 감사·문서·아키텍처·위키·미디어 작업과 의존성·개발환경(OS별) 설치를 아우르는 **스킬 66개 + 커맨드 2개**(총 68개 구성요소. Codex 는 Claude Code 전용 `ultraqa` 를 뺀 스킬 65개와 Codex 전용 스킬 3개)
12
+ - QA·보안 감사·문서·아키텍처·위키·미디어 작업과 의존성·개발환경(OS별) 설치를 아우르는 **스킬 70개 + 커맨드 2개**(총 72개 구성요소. Codex 는 Claude Code 전용 `ultraqa` 를 뺀 스킬 69개와 Codex 전용 스킬 3개)
13
13
  - Claude Code 즉시 명령 `/graceful-pause`, `/progress`
14
14
 
15
15
  □ 설치하면 스킬과 커맨드가 `/banker:<이름>` 네임스페이스로 노출됩니다.
@@ -117,6 +117,7 @@ Claude Code 2.1.296 은 Claude 5 모델(Opus 5.5 등)에 작업 목록 도구(Ta
117
117
  | `play-qa` | 웹 기반 동작 컨텐츠를 실제 브라우저에서 직접 플레이하는 QA |
118
118
  | `ultra-ui-qa` | UI를 기준(디자인 PDF/스펙)과 1:1 대조 QA |
119
119
  | `visual-ralph` | 레퍼런스(생성/정적/URL) 기준 프론트 UI를 Visual Verdict(≥90)로 측정 빌드 |
120
+ | `build-testbox` | 이 PC 의 자원으로 시험 환경을 꾸림. 127.0.0.1 서비스를 브라우저 행렬(Playwright Chromium, WebKit 의 데스크톱과 모바일 기기 에뮬레이션)로, 배포 명령을 컨테이너 OS(Rocky Linux 8, 9. docker 나 podman)로 병렬 실행하고 칸마다 통과, 실패, 미검증, 미지원과 사유를 남김. `run` 은 내려받지 않고, 받기는 확인 뒤 `setup --yes` 로만. macOS 는 Apple Silicon 호스트의 Tart VM 만 |
120
121
 
121
122
  ### 스킬: 문서 · 디자인 · 위키
122
123
 
@@ -169,8 +170,10 @@ Claude Code 2.1.296 은 Claude 5 모델(Opus 5.5 등)에 작업 목록 도구(Ta
169
170
  | `omc-patch` | OMC 자동 업데이트 뒤 사라진 훅 패치를 재적용하고 OMC 마켓플레이스 자동 업데이트를 고정(진단·확인·적용·검증·되돌리기). 옛 킷이 블록 안에 넣은 헬퍼(project-memory 꺼짐)를 찾아 고치고, project-memory 훅이 실제로 일하는지 임시 폴더에서 확인 |
170
171
  | `remains` | 남은 버그, 하자, 미검증 항목을 찾아 표로 보여 줌. 테스트박스(`~/.config/banker/test-boxes.json`)가 등록돼 있으면 각 OS 에서 시험을 돌려 확인(읽기와 시험만, 고치지 않음) |
171
172
  | `trouble-shooting` | 문제를 조사해 현상, 문제점, 원인, 해결방법, 조치계획을 표 하나로 간결히 보고(문제마다 한 행, `--no-plan` 은 해결방법까지, 고치지 않고 보고만) |
172
- | `ultra-chain` | 자료 조사, 모호성 제거, 검토자 3명 이상의 합의 계획, 목업 승인, 비판 검증 구현, 실제 OS 테스트박스 시험과 합의 검증, 시각 검토, 과정 시각화, 결과 공유를 한 명령으로 잇는 9단계 연쇄. 사람이 볼 곳은 인터뷰의 취향 질문과 목업 승인으로 줄임. 실행 기록과 단일 HTML 보고서를 남기고, push 나 외부 게시는 요청할 때만 |
173
- | `progress-mon` | 프로젝트 진척도를 4탭 웹 화면(진척도, 구현요건, workflow, 구성도)으로 로컬 서버(기본 127.0.0.1)에 띄움. `init` 이 코드를 읽어 탭 자료를 쓰고 프로젝트 메모리에 갱신 규칙 한 줄을 등록, `export` 는 서버 없는 단일 HTML. 세션 작업 목록 패널은 `/progress` |
173
+ | `ultra-chain` | 자료 조사, 모호성 제거, 검토자 3명 이상의 합의 계획, 목업 승인, 비판 검증 구현, 실제 OS 테스트박스 시험과 합의 검증, 시각 검토, 과정 시각화, 결과 공유를 한 명령으로 잇는 9단계 연쇄. 사람이 볼 곳은 인터뷰의 취향 질문과 목업 승인으로 줄임. `--agents`(기본 3)가 합의 계획, 비판 검증, 합의 검증의 검토자 수와 시각 판정자 수를 정하고 전원 승인일 때만 넘어감. 실행 기록과 단일 HTML 보고서를 남기고, push 나 외부 게시는 요청할 때만 |
174
+ | `progress-mon` | 프로젝트 진척도를 5탭 웹 화면(진척도, 구현요건, workflow, 구성도, ADR)으로 로컬 서버(기본 127.0.0.1)에 띄움. ADR 탭은 결정마다 최적화 로직, 확장 대응, 포기와 얻은 것과 프로젝트의 검증, 흐름, 증거를 `check` 가 확인한 참조와 함께 보임. `init` 이 코드를 읽어 탭 자료를 쓰고 프로젝트 메모리에 갱신 규칙 한 줄을 등록, `export` 는 서버 없는 단일 HTML. 세션 작업 목록 패널은 `/progress` |
175
+ | `init-dir` | 프로젝트에 관리 폴더 7개(logs, scripts, work, mockup, tests, docs, KB)를 만들고 폴더 목적을 지금 세션에 전달하며, `AGENTS.md` 와 `CLAUDE.md` 중 있는 것에 표지 블록으로 기록. 새로 만든 폴더에만 틀 파일(서비스 시작, 정지 스크립트와 로그 로테이션, 시험 실행기, README)을 넣고, 이미 있는 폴더는 목적만 전달 |
176
+ | `git-init` | 저장소가 아닌 폴더에 첫 커밋 `init` 을 만들어 worktree 같은 병렬 작업을 준비. 비밀값과 로컬 상태를 빼는 `.gitignore` 를 쓰고, 추적될 파일을 이름과 내용으로 스캔(위치와 종류만 보이고 값은 안 보임)한 뒤 `git init`, `git add .`, `git commit` 실행. 걸림이 있으면 `.git` 을 만들지 않음. `check` 는 계획만, 원격 연결과 push 는 안 함 |
174
177
 
175
178
  ### 스킬: 미디어 (모션 그래픽 · 3D 인트로)
176
179
 
@@ -191,6 +194,7 @@ USER_RESOURCES 가이드의 공통 요소를 OS별·런타임별(Claude Code/Cod
191
194
  | `setup-java` | JDK 21 + JAVA_HOME (Debian=Adoptium Temurin) |
192
195
  | `setup-lsp` | 언어별 LSP(vtsls·basedpyright·bash·jdtls·spring) + lsp-mcp 브리지 (node·python·java 의존) |
193
196
  | `setup-tmux` | tmux(Rocky8 3.6a 소스빌드) / psmux(Windows) |
197
+ | `tune-tmux` | 설치된 tmux, psmux 의 설정 파일에 표지 블록을 넣고 빼서 마우스 드래그 복사(OS 클립보드)와 PageUp/PageDown 스크롤을 맞춤. 전체 화면 앱(Claude Code, Codex)의 키와 마우스는 빼앗지 않고 앱별 동작을 `status` 로 안내. 첫 원본 백업, `off` 는 블록만 뺌, `--reload` 로 떠 있는 서버에 반영. psmux 는 넣는 줄 0(기본값으로 되는 것: 마우스, set-clipboard, 휠 copy-mode. 확인 못 한 것: 드래그한 글의 Windows 클립보드 전달, 전체 화면 앱 안 PageUp/PageDown. 안 되는 것: 앱 밖 PageUp 은 prefix 필요, PageDown 은 바닥에서 copy-mode 를 안 빠짐, `alternate_on` 이 늘 0 이라 앱 구분 불가). `on` 은 미확인, 안 됨 수를 보이고 옛 블록이 있으면 뺌 |
194
198
  | `setup-pwsh` | Windows PowerShell 7 환경(비-Windows no-op) |
195
199
  | `setup-mcp` | 공통 MCP 서버(context7·seq-thinking·filesystem·git·fetch) |
196
200
  | `setup-sandbox` | OS별 샌드박스(bubblewrap+userns / Seatbelt) + rust + git safe.directory |
@@ -227,14 +231,14 @@ banker uninstall # 제거
227
231
 
228
232
  - `--scope project` 로 프로젝트 로컬(`./.codex`)에 설치하고, `--dry-run` 으로 미리 볼 수 있습니다.
229
233
  - non-root 전용입니다(전역 sudo 설치 시 root 소유 파일을 방지). postinstall이 없으므로 `banker setup` 을 직접 실행합니다.
230
- - Codex에는 스킬 65개와 Codex 전용 스킬 3개(`graceful-pause`, `progress`, `teamwork`)가 `~/.codex/skills/banker-<name>/` 에, 커맨드 2개가 `~/.codex/prompts/banker-<name>.md` 에 설치됩니다(`codex/manifest.json`). \
234
+ - Codex에는 스킬 69개와 Codex 전용 스킬 3개(`graceful-pause`, `progress`, `teamwork`)가 `~/.codex/skills/banker-<name>/` 에, 커맨드 2개가 `~/.codex/prompts/banker-<name>.md` 에 설치됩니다(`codex/manifest.json`). \
231
235
  `CODEX_HOME` 을 설정했으면 `~/.codex` 대신 그 폴더에 설치합니다(Codex 가 읽는 곳). \
232
236
  `lineage`, `progress`, 사용량 카운팅은 Codex 의 대화 기록(rollout)을 읽습니다. Codex 는 이 형식을 공개 약속으로 내놓지 않아 업데이트로 바뀔 수 있습니다. \
233
237
  Codex 를 업데이트한 뒤에는 `banker doctor` 로 형식을 점검합니다. 읽지 못하면 lineage 는 빈 페이지 대신 오류로 멈추고, progress 는 경고 줄을 보이며, 카운팅은 다음 세션 시작 때 경고를 한 번 보입니다. \
234
238
  Codex 0.144 이상에는 사용자 프롬프트가 없으므로 커맨드 2개는 스킬로도 설치되어 `$banker-front-qa`, `$banker-setup` 으로 부릅니다. \
235
239
  디렉터리명과 일치하도록 프론트매터 `name:` 이 `banker-<name>` 으로 재작성되어 Codex가 `banker-<name>` 으로 인식합니다.
236
240
  - Codex 플러그인 설치(`codex plugin add banker@banker-plugins`)는 저장소를 `~/.codex/plugins/cache/banker-plugins/banker/<판>/` 에 두고 `.codex-plugin/plugin.json` 을 읽습니다. \
237
- 스킬 65개, Codex 전용 스킬 3개, 커맨드 2개(스킬로)가 `$banker:<name>` 으로 보이고, 업데이트 알림과 사용량 카운팅 훅은 `codex/hooks.json` 에서 옵니다. \
241
+ 스킬 69개, Codex 전용 스킬 3개, 커맨드 2개(스킬로)가 `$banker:<name>` 으로 보이고, 업데이트 알림과 사용량 카운팅 훅은 `codex/hooks.json` 에서 옵니다. \
238
242
  Codex 는 세션을 시작할 때 마켓플레이스를 스스로 올려 새 판을 설치합니다. 훅 명령 앞에는 훅이 실행하는 파일의 해시가 붙어 있어, 훅 코드가 바뀐 판에서는 `/hooks` 가 다시 신뢰를 묻고 신뢰하기 전에는 훅이 돌지 않습니다. 훅 코드가 그대로인 판은 신뢰도 그대로입니다. 스킬 파일은 신뢰 확인 없이 새 판으로 바뀝니다. \
239
243
  obsidizer 훅은 npm 설치와 같이 `obsidizer --enable` 할 때만 사용자 범위에 설치됩니다(셸 호출마다 node 를 띄우므로). \
240
244
  훅은 Codex 샌드박스 밖에서 돌므로, PATH 의 node 가 임시 폴더나 작업 폴더 안에 있으면(샌드박스가 바꿀 수 있는 곳) 아무것도 돌리지 않고 그 이유를 세션 시작 알림으로 보입니다. 작업 폴더가 홈 폴더 자체이면 홈 아래의 node(nvm 등)는 그대로 씁니다. 훅 스크립트, 플러그인 폴더, node 가 `config.toml` 의 `[sandbox_workspace_write] writable_roots` 아래(그 항목 맨 위 `.codex` 제외)면 훅은 다른 일을 하지 않고 그 이유를 한 줄로 알립니다. 이 검사는 훅 파일 안에서 하므로, 샌드박스가 이미 그 파일을 고친 뒤에는 막지 못합니다. writable_roots 에 Codex 홈이나 node 가 든 폴더를 넣지 마십시오. \
@@ -308,6 +312,7 @@ banker uninstall # 제거
308
312
  | `anti-drm` | `rules/banker-anti-drm.md` 생성 (`off` 로 삭제) + 설정 `~/.config/banker/anti-drm.json`(두 런타임 공용, `off` 뒤에도 남음, anti-drm 이 쓰지 않은 파일이 있었으면 `.bak`) | `AGENTS.md`(내용이 있는 `AGENTS.override.md` 우선) 끝에 `USER:OMX:POLICY` 로 감싼 블록 1개(`.anti-drm.bak` 백업·멱등, `off` 로 원복) |
309
313
  | `omc-patch` | 활성 OMC 버전의 `scripts/*.mjs` 와 `hooks/hooks.json` 수정(`.omcbak` 백업, `PostToolUse` 훅 제거) + OMC 마켓플레이스 `origin` 을 `omc-pinned://` 로 고정(기록 `~/.claude/omc-local-patches/PINNED`, `revert` 로 원복). 헬퍼 자리 결함은 활성 폴더만 되돌린 뒤 다시 패치. project-memory 확인은 임시 폴더에서만 하고 끝나면 지움 | — (Codex에서 실행해도 Claude Code 의 OMC 캐시만 다룸) |
310
314
  | `remains` | 설정 파일 미변경. `~/.config/banker/test-boxes.json` 은 읽기만 함(사용자가 만들거나, 사용자가 준 정보로 확인받고 만듦). 처음 접속하는 박스의 호스트 키가 `~/.ssh/known_hosts` 에 더해짐. 테스트박스에는 임시 폴더를 만들고 끝나면 지움(시간 초과나 중단 때는 시작한 프로세스를 먼저 끝냄, 못 지우면 결과에 표시) | 동일 |
315
+ | `tune-tmux` | tmux, psmux 설정 파일(`~/.tmux.conf` 등)에 `# banker:tune-tmux:start` 표지 블록 1개(바이트가 바뀔 때만 첫 원본을 `<파일>.tune-tmux.bak` 에 백업·멱등, `off` 로 블록만 뺌). `--reload` 는 떠 있는 서버에 반영 | 동일. 설정 파일이 작업 폴더 밖이라 `on`, `off`, `--reload` 는 승인 요청 |
311
316
  | `motion-graphic-setup` | 설정 파일 미패치 (Node/ffmpeg 확보 + `npx hyperframes` 설치만) | 동일 (`config.toml` 미변경) |
312
317
  | `3d-intro-setup` | `settings.json` 미패치 — 크레덴셜을 untracked env 파일에 기록(`.env.3d-intro.local` 또는 `~/.config/banker/3d-intro/env`) | 동일 (`config.toml` 미변경) |
313
318
  | `setup-bypass-permissions` | `permissions.defaultMode` = `bypassPermissions` (켜기 전 내용은 `settings.json.bypass-permissions.bak`, 되돌리기 기록은 `settings.json.bypass-permissions.json`, `off` 로 원복. 관리 정책, 설정 파일의 금지 키, root 계정이면 거부) | 대상 `codex` 면 `~/.codex/config.toml` 최상위의 `approval_policy` = `"never"`, `sandbox_mode` = `"danger-full-access"` (켜기 전 원본 `config.toml.bypass-permissions.bak`, 되돌리기 기록 `config.toml.bypass-permissions.json`, `off` 로 원복. 조직 정책이 막으면 거부). 대상 `claude` 면 Codex 에서 실행해도 Claude Code 설정을 바꿈 |
@@ -326,6 +331,8 @@ banker uninstall # 제거
326
331
  - `progress-mon`: Node 18 이상(npm 의존 없음). 커밋 기록을 보이려면 `git`. 서버는 기본 127.0.0.1 에만 바인드하고, `--host` 는 사설 IPv4 만 받습니다.
327
332
  - `remains`: 테스트박스를 쓰려면 이 머신에 `ssh`, `scp`, `git`, 박스에 `tar` 와 시험에 필요한 런타임(예: Node)이 있어야 하고, SSH 키로 암호 없이 접속돼야 합니다.
328
333
  - `ultra-chain`: 위 OMC(Codex 는 OMX), 웹 조사 수단, 시각 검토의 캡처에는 Node 용 playwright 패키지와 Chromium, OS 시험에는 `remains` 와 같은 테스트박스 조건.
334
+ - `build-testbox`: Node 18 이상. 브라우저 칸의 Playwright(전역 설치. 저장소 의존성 아님)와 컨테이너 칸의 docker 또는 podman 은 선택이며, 없으면 그 칸은 `unverified` 와 사유로 끝납니다. macOS 칸은 Apple Silicon 호스트의 Tart 만.
335
+ - `init-dir`: 만든 틀(서비스 시작, 정지 스크립트와 시험 실행기)은 대상 프로젝트에 Node 18 이상이 필요합니다.
329
336
  - `/graceful-pause`: Claude Code 2.1.289 이상(mod). 그보다 오래된 Claude Code 는 명령을 등록하지 않고 한 줄로 알립니다. Codex 는 스킬 `$banker-graceful-pause` 입니다(0.144.5 에서 확인).
330
337
  - `/progress`: mod 를 지원하는 Claude Code(2.1.286 과 2.1.296 에서 확인). 작업 중 즉시 실행은 2.1.289 이상에서 확인했습니다. mod 가 없는 Claude Code(2.1.250 에서 확인)에서는 "mod 를 지원하지않는 claude code 버전입니다" 만 보이고 모델은 호출되지 않습니다. Codex 는 스킬 `$banker-progress` 입니다(상시 패널이 아니라 부를 때마다 보임, tmux 칸은 선택).
331
338
  - `teamwork`(Codex 전용): Node 18 이상, Codex 0.149.0 이상(`codex queue`), Linux 와 macOS. Windows 는 `on` 이 까닭을 밝히고 끝납니다. Codex 0.160.1 Windows 에서 승인 규칙 판정(`codex execpolicy check`)이 PowerShell 로 부르는 래퍼에는 맞지 않아(래퍼를 바로 부르는 꼴만 맞음) 쓸 때마다 승인을 물어야 하기 때문입니다. \
@@ -448,8 +455,9 @@ banker setup
448
455
  - `deep-research`, `lfm`, 이를 부르는 `ultra-chain` 1단계, `ultra-interview` 와 `rfp-author` 의 조사: 웹 도구가 모두 실패하면 조사하지 못했다고 알립니다. `lfm` 은 모델이 아는 관행으로 표를 채우지 않고 "웹 조사 불가" 로 끝납니다.
449
456
  - `npx` 로 부르는 도구(`motion-graphic-make` 의 hyperframes 등): 전역 설치가 없으면 패키지를 받으려 해, 네트워크가 없으면 약 70초 뒤 실패합니다. 오프라인에서는 전역 설치한 실행 파일을 부릅니다.
450
457
  - 유료 API 를 부르는 `3d-intro-build`(요청마다 시간 제한), `ralph-qa` 의 외부 좌석(codex, gemini, opencode, 좌석마다 600초)
458
+ - `build-testbox`: `run` 은 내려받지 않고, 없는 이미지, 브라우저, 엔진의 칸은 `unverified` 와 setup 할 항목으로 끝납니다. `setup` 은 `--yes` 확인 뒤에만 받고, 원천에 닿지 못하면 받지 않고 "네트워크 필요" 로 끝납니다.
451
459
  - `vertical-pptx`, `pdf-vision-extract` 가 빠진 도구를 설치하라고 안내할 때, `nothing-design` 의 글꼴(Google Fonts. 받지 못하면 대체 글꼴로 보임)
452
- - 네트워크를 쓰지 않는 스킬(예: `lineage`, `setup-omc-hud`, `tone-compact`, `anti-drm`, `payload-mon`)은 네트워크 없이 그대로 씁니다.
460
+ - 네트워크를 쓰지 않는 스킬(예: `lineage`, `setup-omc-hud`, `tone-compact`, `anti-drm`, `payload-mon`, `init-dir`, `git-init`, `tune-tmux`)은 네트워크 없이 그대로 씁니다.
453
461
 
454
462
  ## 라이선스 / 서드파티
455
463
 
@@ -71,10 +71,14 @@
71
71
  { "name": "omc-patch", "type": "skill", "target": "both", "reason": "re-applies local OMC hook patches after an OMC auto-update and pins the OMC marketplace origin; finds a timeout helper an older kit left inside a block (hooks such as project-memory silently off) and fixes it by reverting the active folder and patching again; probes the project-memory hook in a scratch project; pure Node, no deps", "supportingFiles": ["scripts/omc-patch.mjs", "scripts/probe-pm.mjs"], "caveat": "acts on the Claude Code OMC plugin cache under ~/.claude even when run from Codex; under Codex's workspace-write sandbox --check and probe-pm run as they are, while apply and revert need approval to run outside it (not --add-dir ~/.claude); TARGET_VERSION 5.7.0 is hard-coded in the tool and only a plain apply uses it; the skill passes --no-update on every apply and check; --root touches one plugin folder only and never the marketplace pin" },
72
72
  { "name": "remains", "type": "skill", "target": "both", "reason": "finds remaining bugs, defects and unverified items and shows them in one table; runs the project's tests on registered SSH test boxes; pure Node, no deps", "supportingFiles": ["scripts/boxes.mjs"], "caveat": "box runs need ssh, scp and git on this machine and key-only SSH logins; boxes are registered in ~/.config/banker/test-boxes.json; read and test only, never fixes or pushes" },
73
73
  { "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": [] },
74
- { "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), local gates run by ralph-qa's gate-evidence runner (observed records against a baseline taken before the build) and tests on the registered OS boxes, fed to a ralph-qa quorum with --gates (the plan quorum declares no gates), 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" },
74
+ { "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, which has no --critic) followed in both runtimes by the skill's own critic seat loop, local gates run by ralph-qa's gate-evidence runner (observed records against a baseline taken before the build) and tests on the registered OS boxes, fed to a ralph-qa quorum with --gates (the plan quorum declares no gates), visual review (machine diff against the mock, screenshots, independent judges), --agents=N (default 3) reviewers for every independent verdict with the ledger enforcing the count and the all-approve rule, 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" },
75
75
  { "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" },
76
76
  { "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" },
77
- { "name": "progress-mon", "type": "skill", "target": "both", "reason": "project progress web screen with four tabs (progress, requirements, workflow, architecture) on a local server; init reads the code and writes the tab data, registers a one-line update rule in project memory; item, note, stage, story keep it current; pure Node, no deps", "supportingFiles": ["README.md","references/arch.md","references/authoring.md","references/config.md","references/flow.md","references/inventory.md","references/items.md","references/req-spec.md","references/reqs.md","scripts/index.js","scripts/pm-check.mjs","scripts/pm-config.mjs","scripts/pm-data.mjs","scripts/pm-html.mjs","scripts/pm-memory.mjs","scripts/pm-render.mjs","scripts/pm-server.mjs","scripts/pm-sources.mjs","scripts/progress-mon.mjs","assets/fixture/README.md","assets/fixture/config.json","assets/fixture/events.jsonl","assets/fixture/items.json","assets/fixture/commits.json","assets/fixture/req-spec.json","assets/fixture/reqs.json","assets/fixture/flow.json","assets/fixture/arch.json","assets/fixture/workflows/wf_ex1/journal.jsonl","assets/fixture/workflows/wf_ex1/agent-a01.jsonl","assets/fixture/workflows/wf_ex1/agent-a02.jsonl","assets/fixture/workflows/wf_ex1/agent-a03.jsonl","assets/fixture/workflows/wf_ex1/agent-a04.jsonl","assets/fixture/variants/arch-auto/arch.json","assets/fixture/variants/check-auto/arch.json","assets/fixture/variants/check-overlap/arch.json","assets/fixture/variants/history-manual/config.json","assets/fixture/variants/history-manual/items.json","assets/fixture/variants/workflow-wide/flow.json"], "caveat": "needs Node 18 or later (above the package engines floor); binds 127.0.0.1 only by default, --host takes a private IPv4 with a warning; data lives in .omc/progress-mon/ (Codex .omx/progress-mon/); on Codex start, stop, status and init each ask for sandbox_permissions require_escalated, and a long-lived screen runs from the user's terminal (serve) since closing the session may stop the server" },
77
+ { "name": "progress-mon", "type": "skill", "target": "both", "reason": "project progress web screen with five tabs (progress, requirements, workflow, architecture, ADR) on a local server; the ADR tab shows each decision with its optimization check, scaling argument and trade-offs, and the project's module verification, input-to-output flow and proof locations, every reference checked by check; init reads the code and writes the tab data, registers a one-line update rule in project memory (an older rule line is replaced in place with a backup); item, note, stage, story keep it current; pure Node, no deps", "supportingFiles": ["README.md","references/adr.md","references/arch.md","references/authoring.md","references/config.md","references/flow.md","references/inventory.md","references/items.md","references/req-spec.md","references/reqs.md","scripts/index.js","scripts/pm-adr.mjs","scripts/pm-adr-view.mjs","scripts/pm-check.mjs","scripts/pm-config.mjs","scripts/pm-data.mjs","scripts/pm-html.mjs","scripts/pm-memory.mjs","scripts/pm-render.mjs","scripts/pm-server.mjs","scripts/pm-sources.mjs","scripts/progress-mon.mjs","assets/fixture/README.md","assets/fixture/config.json","assets/fixture/events.jsonl","assets/fixture/items.json","assets/fixture/commits.json","assets/fixture/req-spec.json","assets/fixture/reqs.json","assets/fixture/flow.json","assets/fixture/arch.json","assets/fixture/adr.json","assets/fixture/workflows/wf_ex1/journal.jsonl","assets/fixture/workflows/wf_ex1/agent-a01.jsonl","assets/fixture/workflows/wf_ex1/agent-a02.jsonl","assets/fixture/workflows/wf_ex1/agent-a03.jsonl","assets/fixture/workflows/wf_ex1/agent-a04.jsonl","assets/fixture/variants/arch-auto/arch.json","assets/fixture/variants/check-auto/arch.json","assets/fixture/variants/check-overlap/arch.json","assets/fixture/variants/history-manual/config.json","assets/fixture/variants/history-manual/items.json","assets/fixture/variants/workflow-wide/flow.json","assets/fixture/variants/legacy-init/rules.json","assets/fixture/variants/legacy-init/state.json"], "caveat": "needs Node 18 or later (above the package engines floor); binds 127.0.0.1 only by default, --host takes a private IPv4 with a warning; data lives in .omc/progress-mon/ (Codex .omx/progress-mon/); on Codex start, stop, status and init each ask for sandbox_permissions require_escalated, and a long-lived screen runs from the user's terminal (serve) since closing the session may stop the server" },
78
+ { "name": "init-dir", "type": "skill", "target": "both", "reason": "creates seven project folders (logs, scripts, work, mockup, tests, docs, KB), tells the current session what each folder is for, and records it as one marked block in AGENTS.md and CLAUDE.md (whichever exist; AGENTS.md alone for Codex when neither does); only newly created folders get starter files (service start/stop/status/restart scripts with log rotation, a test runner, READMEs), existing folders keep their contents; pure Node, no deps", "supportingFiles": ["scripts/init-dir.mjs","scripts/marker-block.mjs","scripts/templates.mjs","templates/logs/README.md","templates/logs/gitignore","templates/scripts/start.sh","templates/scripts/stop.sh","templates/scripts/status.sh","templates/scripts/restart.sh","templates/scripts/start.cmd","templates/scripts/stop.cmd","templates/scripts/status.cmd","templates/scripts/restart.cmd","templates/scripts/service.conf","templates/scripts/lib/service.mjs","templates/scripts/README.md","templates/work/README.md","templates/mockup/README.md","templates/tests/run.sh","templates/tests/run.cmd","templates/tests/run.mjs","templates/tests/tests.conf","templates/tests/README.md","templates/docs/README.md","templates/KB/README.md"], "caveat": "the starter scripts need Node 18 or later in the target project (NODE names another one); it writes AGENTS.md and CLAUDE.md, changing only the bytes between its markers and keeping the first original as <file>.init-dir.bak; the AGENTS.md block sits inside its own USER:OMX:POLICY pair, AGENTS.override.md is never written (a warning when it has content of its own); a CLAUDE.md symbolic link is refused unless --follow-symlink; .cmd templates are stored with LF and written with CRLF; on Codex a --root outside the workspace, or a started service that must outlive the session, asks for sandbox_permissions require_escalated" },
79
+ { "name": "git-init", "type": "skill", "target": "both", "reason": "makes the first commit of a folder that is not a git repository yet, so worktrees and other parallel work can start from it: writes a .gitignore that keeps secrets and local state out, scans the files to track for secrets by name and content (payload-scan.mjs, file:line:kind only, never the value), then runs git init, git add . and git commit -m init; a hit stops it before any .git exists; pure Node, no deps, no network", "supportingFiles": ["scripts/git-init.mjs","scripts/marker-block.mjs","scripts/payload-scan.mjs"], "caveat": "needs git on PATH (before git 2.28 the first branch is set with git symbolic-ref) and a commit identity (user.name and user.email, or --local-identity, written to .git/config only); an existing .gitignore keeps its bytes and gets one marked block at its end, the first original kept in .gitignore.git-init.bak, which the block itself ignores; a .gitignore symbolic link is refused unless --follow-symlink; key file names cannot be accepted, a content hit only by its exact file:line:kind with --accept; commit hooks are not skipped; it never adds a remote or pushes; on Codex run asks for sandbox_permissions require_escalated, since the default sandbox may block writes to .git" },
80
+ { "name": "build-testbox", "type": "skill", "target": "both", "reason": "a test environment this machine builds from its own resources: a browser matrix (Playwright Chromium and WebKit, desktop and mobile device emulation) against a loopback URL and container OSes (Rocky Linux 8, 9; macOS only as a Tart VM on Apple Silicon) run in parallel, every requested cell kept as a pass, fail, unverified or unsupported row with a reason, results.json and summary.md; detect, run, setup; pure Node, no deps", "supportingFiles": ["scripts/testbox.mjs","scripts/args.mjs","scripts/detect.mjs","scripts/browsers.mjs","scripts/browser-cell.mjs","scripts/containers.mjs","scripts/setup.mjs","scripts/report.mjs","scripts/proc.mjs"], "caveat": "Playwright (a global install, or the project's with --playwright-from-project) and docker or podman are optional; a missing one leaves its cells unverified with the reason; run downloads nothing (a missing image or browser build is unverified, never pulled); setup only lists what it would fetch and its rough size, and fetches after the user confirms and it runs again with --yes (exit 4 and network needed when the sources are unreachable); macOS runs only as a Tart VM on an Apple Silicon host (other hosts are unsupported under the Apple SLA), and the skill never downloads or starts the VM; on Codex detect and run ask for sandbox_permissions require_escalated for the container engine and the headless browsers, the server under test on a 127.0.0.1 port is the user's own (approved where it is started), and setup --yes, or a container command that uses the network, asks for network access (--network host lifts that cell's isolation, and the user is told)" },
81
+ { "name": "tune-tmux", "type": "skill", "target": "both", "reason": "adds or removes one marked block in the tmux or psmux config file so mouse drag copies to the OS clipboard and PageUp/PageDown scroll inside tmux, without taking keys or the mouse from full-screen apps; status shows the chosen file, the lines and why any are left out, conflicts in other files tmux reads, and per-app behavior (Claude Code, Codex); first original kept, off removes only the block, --reload applies it to a running server; pure Node, no deps, no network", "supportingFiles": ["scripts/tune-tmux.mjs","scripts/tmux-config.mjs","scripts/app-notes.mjs","scripts/marker-block.mjs","scripts/psmux-caps.json"], "caveat": "needs tmux or psmux (install with setup-tmux; status alone works without them); it writes the user's config file outside the workspace (~/.tmux.conf or the XDG tmux.conf, ~/.psmux.conf for psmux), keeping the first original as <conf>.tune-tmux.bak, so on Codex on, off and --reload ask for sandbox_permissions require_escalated (no --add-dir); a config file that is a symbolic link is refused unless --follow-symlink; psmux gets a block of zero lines today (its defaults give mouse, set-clipboard and wheel copy-mode; drag to the Windows clipboard and PageUp/PageDown inside full-screen apps are unverified; outside apps PageUp needs the prefix, PageDown does not leave copy-mode at the bottom and #{alternate_on} is always 0), so on reports the unverified and broken counts with exit 0 and only takes out an old tune-tmux block left in that file; inside full-screen apps (Claude Code fullscreen, Codex Fullscreen) the app keeps PageUp/PageDown and the mouse, and tmux copy-mode cannot scroll Codex history, a limit tmux config cannot fix; it never changes Claude Code or Codex settings" },
78
82
 
79
83
  { "name": "front-qa", "type": "command", "target": "both", "reason": "ralplan->ralph frontend-QA pipeline; Claude=OMC, Codex=OMX", "supportingFiles": [] },
80
84
  { "name": "setup", "type": "command", "target": "both", "reason": "installer orchestrator; Claude AskUserQuestion multi-select, Codex prompt-based selection", "supportingFiles": [], "codexDescription": "구성요소와 의존성을 여러 개 골라 설치하는 오케스트레이터. 런타임(Node, Python, Java), LSP, tmux, MCP, 샌드박스, OMX, Playwright 등. 권한 확인 끄기는 따로 묻고 기본으로 고르지 않으며, 골라도 실행하지 않고 직접 입력할 명령만 안내." },
@@ -906,12 +906,12 @@ function sessionCwd() {
906
906
  function openedPath(fd) { try { return fs.readlinkSync(`/proc/self/fd/${fd}`); } catch { return ''; } }
907
907
 
908
908
  // 연 파일이 확인한 파일과 같은지: 마지막 이름은 O_NOFOLLOW 로 링크를 따라가지 않고(Windows 는 그 플래그가 없어 lstat 으로 링크가 아님을 봄),
909
- // 연 파일의 dev, ino 를 실제 경로의 lstat 과 비교한다. Linux 는 연 파일의 경로도 경계 안인지 다시 봐 그사이 바뀐 폴더를 거부한다
909
+ // 연 파일의 dev, ino 를 실제 경로의 lstat 과 비교한다(bigint: NTFS 파일 ID 는 2^53 을 넘어 Number 로는 다른 두 파일이 같아 보일 수 있음). Linux 는 연 파일의 경로도 경계 안인지 다시 봐 그사이 바뀐 폴더를 거부한다
910
910
  function readChecked(real, roots) {
911
- const before = fs.lstatSync(real);
911
+ const before = fs.lstatSync(real, { bigint: true });
912
912
  const fd = fs.openSync(real, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW || 0));
913
913
  try {
914
- const st = fs.fstatSync(fd);
914
+ const st = fs.fstatSync(fd, { bigint: true });
915
915
  const opened = openedPath(fd);
916
916
  const moved = !st.isFile() || !before.isFile() || st.dev !== before.dev || st.ino !== before.ino;
917
917
  if (moved || (opened && !roots.some((r) => under(opened, r)))) throw new Error(`확인한 뒤 바뀌었거나 일반 파일이 아님: ${real}`);
@@ -48,9 +48,13 @@ The generator (`banker setup --codex`) applies the rules below for `target: both
48
48
  - `anti-drm` — the same places as `tone-compact` through the same shared module (`instruction-toggle.mjs`, a byte-identical copy in each skill): `<config>/rules/banker-anti-drm.md` for Claude Code, one `USER:OMX:POLICY`-wrapped block in the instructions file Codex reads. The settings (`~/.config/banker/anti-drm.json`) 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.
49
49
  - `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. Under `workspace-write`, `--check` and `probe-pm.mjs` run as they are; apply and revert need approval to run outside the sandbox (not `--add-dir ~/.claude`).
50
50
  - `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.
51
- - `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.
51
+ - `ultra-chain` — the same nine stages in both runtimes. Claude=OMC 5 (`ralplan --deliberate`, `ralph --critic=critic`); Codex=OMX (`$ralplan --deliberate`, then `$ralph`, which has no `--critic`). After ralph both runtimes run the skill's own critic seat loop (`critic#1..N`; Claude `Agent` `Plan`, Codex `spawn_agent`; ralph's own approval is recorded as `ralph-reviewer` and is not the gate). `--agents=N` (default 3, raised to 3, over 17 refused, kept in `run.json` as `agents` and `agentsSource`) sets the stage 3 and 6 `ralph-qa` seats, the stage 5 critic seats and the stage 7 visual judges; the ledger enforces the count, the seat ids and the all-approve rule, and a seat that cannot be spawned stops the stage as `INCONCLUSIVE`. Both add a `ralph-qa` plan quorum of `--agents` reviewers after ralplan (whose Architect and Critic are two fixed reviewers with no option to add more and are not counted), run OS tests through the sibling `remains/scripts/boxes.mjs` (Codex: `banker-remains`), judge screenshots with `--agents` fresh judges whose lowest score must reach 90 (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.
52
52
  - `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.
53
- - `progress-mon` — the same procedure in both runtimes; the engine is `scripts/progress-mon.mjs` (Codex npm install: `~/.codex/skills/banker-progress-mon/scripts/progress-mon.mjs`; plugin install: `~/.codex/plugins/cache/<marketplace>/banker/<version>/skills/progress-mon/scripts/progress-mon.mjs`), every command with `--runtime claude|codex`. The data folder is `.omc/progress-mon/` for Claude Code and `.omx/progress-mon/` for Codex. Pure Node with no network; the server binds 127.0.0.1 by default (`--host` takes a private IPv4 only). On Codex `start`, `stop`, `status` and `init` each ask for `sandbox_permissions: "require_escalated"` (`init` writes the git exclude list), and since closing the session may stop the server, a long-lived screen runs from the user's terminal (`serve`). `init --memory agents-md` writes its rule to `AGENTS.override.md` when that file has content of its own, as Codex then reads it instead of `AGENTS.md`. Not the same as `/progress` (the session's own task panel).
53
+ - `progress-mon` — the same procedure in both runtimes; the engine is `scripts/progress-mon.mjs` (Codex npm install: `~/.codex/skills/banker-progress-mon/scripts/progress-mon.mjs`; plugin install: `~/.codex/plugins/cache/<marketplace>/banker/<version>/skills/progress-mon/scripts/progress-mon.mjs`), every command with `--runtime claude|codex`. The data folder is `.omc/progress-mon/` for Claude Code and `.omx/progress-mon/` for Codex. Pure Node with no network; the server binds 127.0.0.1 by default (`--host` takes a private IPv4 only). On Codex `start`, `stop`, `status` and `init` each ask for `sandbox_permissions: "require_escalated"` (`init` writes the git exclude list), and since closing the session may stop the server, a long-lived screen runs from the user's terminal (`serve`). `init --memory agents-md` writes its rule to `AGENTS.override.md` when that file has content of its own, as Codex then reads it instead of `AGENTS.md`. The fifth tab, ADR, reads `adr.json` only (the agent cites `docs/adr/` and `docs/evidence/` from it); a project set up before the ADR tab gets, on the next bare call and after one confirmation (Claude Code AskUserQuestion, Codex request_user_input), a rerun of `init` with the memory kind from `state.json` (auto-memory passes the folder of its `MEMORY.md` as `--memory-dir`) that replaces the old rule line in place with a `.progress-mon.bak` backup, then the ADR step. Not the same as `/progress` (the session's own task panel).
54
+ - `init-dir` — the same procedure in both runtimes; the engine is `scripts/init-dir.mjs` (Codex npm install: `~/.codex/skills/banker-init-dir/scripts/init-dir.mjs`; plugin install: `~/.codex/plugins/cache/<marketplace>/banker/<version>/skills/init-dir/scripts/init-dir.mjs`), run with `--runtime claude|codex`. It writes one marked block (`<!-- banker:init-dir:start -->` to `<!-- banker:init-dir:end -->`) into whichever of `AGENTS.md` and `CLAUDE.md` exist (Codex with neither: `AGENTS.md`), the `AGENTS.md` block inside its own `USER:OMX:POLICY` pair; `AGENTS.override.md` is never written, only warned about when it has content of its own. The block editor `scripts/marker-block.mjs` is the source of truth for its future copies (`scripts/sync-adapter.js`). Pure Node with no network. On Codex a `--root` outside the workspace, or starting a generated service that must outlive the session, asks for `sandbox_permissions: "require_escalated"`.
55
+ - `git-init` — the same procedure in both runtimes; the engine is `scripts/git-init.mjs` (Codex npm install: `~/.codex/skills/banker-git-init/scripts/git-init.mjs`; plugin install: `~/.codex/plugins/cache/<marketplace>/banker/<version>/skills/git-init/scripts/git-init.mjs`). `check` (the default) writes nothing; `run` writes the `.gitignore` block (`# banker:git-init:start` to `# banker:git-init:end`, through `scripts/marker-block.mjs`, a byte-identical copy of init-dir's), scans the files to track with `scripts/payload-scan.mjs` (a byte-identical copy of ralph-qa's; both kept by `scripts/sync-adapter.js`) and only then runs `git init`, `git add .` and `git commit -m "init"`. Needs `git`; no network, no remote, no push. On Codex `run` asks for `sandbox_permissions: "require_escalated"`, as the default sandbox may block writes to `.git`.
56
+ - `build-testbox` — the same procedure in both runtimes; the engine is `scripts/testbox.mjs` (Codex npm install: `~/.codex/skills/banker-build-testbox/scripts/testbox.mjs`; plugin install: `~/.codex/plugins/cache/<marketplace>/banker/<version>/skills/build-testbox/scripts/testbox.mjs`) with `detect`, `run` and `setup`; `scripts/browser-cell.mjs` is copied into the Playwright image and runs there alone for `--browser-in-container`. Playwright and docker or podman are optional: a missing one leaves its cells `unverified` with the reason. `run` downloads nothing; `setup` without `--yes` only lists what it would fetch, and the skill confirms with the user (Claude Code `AskUserQuestion`, Codex `request_user_input`) before running it again with `--yes`. macOS runs only as a Tart VM on an Apple Silicon host; other hosts get `unsupported(apple-sla)`. On Codex `detect` and `run` ask for `sandbox_permissions: "require_escalated"` (container engine, headless browsers, copies under the OS temp folder), `setup --yes` and container commands that use the network ask for network access, and the server under test is the user's own on a 127.0.0.1 port; a cell stopped by a permission error is `unverified(sandbox)`.
57
+ - `tune-tmux` — the same procedure in both runtimes; the engine is `scripts/tune-tmux.mjs` (Codex npm install: `~/.codex/skills/banker-tune-tmux/scripts/tune-tmux.mjs`; plugin install: `~/.codex/plugins/cache/<marketplace>/banker/<version>/skills/tune-tmux/scripts/tune-tmux.mjs`) with `status` (the default), `on` and `off`. It writes one marked block (`# banker:tune-tmux:start` to `# banker:tune-tmux:end`) through `scripts/marker-block.mjs`, a byte-identical copy of init-dir's kept by `scripts/sync-adapter.js`, into the user's tmux config (`~/.tmux.conf` or the XDG `tmux.conf`) or psmux config (`~/.psmux.conf` and the rest of psmux's order); psmux gets zero lines today, as `scripts/psmux-caps.json` verifies nothing beyond its defaults. The conditional `#{||:}` is probed on a private `tmux -L` server, never the user's. A symbolic-link config is refused unless `--follow-symlink`. No network. On Codex `on`, `off` and `--reload` ask for `sandbox_permissions: "require_escalated"`, as the config file and the tmux socket are outside the workspace; Claude Code and Codex settings are never changed, and Codex Fullscreen history cannot be scrolled by tmux copy-mode (only the user's `--no-alt-screen` or `tui.alternate_screen = "never"` changes that).
54
58
  - `/graceful-pause` — in Claude Code a function-hooks command (`hooks/register.mjs`, 2.1.289+, not a manifest surface) registered `immediate`, so it runs mid-turn; it appends one hidden user row the running turn reads at its next model request. In Codex the `codex-only` skill `graceful-pause` (`$banker-graceful-pause`): a message sent with Enter while a turn runs is held as "Messages to be submitted after next tool call" and put into the same turn when the running tool call ends, so the session stops after the current step (Codex 0.144.5: verified with `sleep 40` in a real TUI).
55
59
  - `/progress` — in Claude Code a mod panel (`hooks/progress.mjs`). In Codex the `codex-only` skill `progress` (`$banker-progress`, `codex/skills/progress/scripts/progress.mjs`): it reads this session's rollout, found by `CODEX_THREAD_ID` (the id at the end of the rollout file name), and prints the last plan file the session wrote or read (tool-call commands and `apply_patch` file heads; `.omx/plans/` counts like `.omc/plans/`) as a tree with the same engine (`progress-plan.mjs`, a byte-identical copy kept by `scripts/sync-adapter.js`), then the last `update_plan` steps (or the typed requests) with the recent tool calls under the step in progress. Not a live panel: `--pane` opens a tmux side pane that redraws every 2 s.
56
60
  - `teamwork` — `codex-only` (`$banker-teamwork`, plugin `$banker:teamwork`, `codex/skills/teamwork/scripts/teamwork.mjs`): peer work between the Codex sessions of one Codex home. `on` copies the engine to `$CODEX_HOME/teamwork/bin/` beside an sh wrapper, adds a `SessionStart` and a `UserPromptSubmit` hook last under each event (taking the same `hooks.json.lock` as `bin/lib/codex-hooks.mjs`, `timeout: 5`, fixed in place; the command ends with `--rev <hash of engine and wrapper>`, so a newer engine asks for trust once more) and writes `$CODEX_HOME/rules/teamwork.rules`, a `prefix_rule` that lets only the wrapper's `peers`, `role`, `send`, `reply`, `status` and `version` run outside the sandbox (`on`, `off`, `uninstall` ask for approval; a same-named file without the `# teamwork` first line is left alone). The wrapper and the hooks run outside the sandbox, so `node`, `codex`, `ps` and `sh` are recorded as absolute paths at `on` and nothing is looked up on PATH afterwards; programs, and a Codex home, under a temp folder, the session folder or its git top, or a `writable_roots` entry are refused (exit 6). Requests and results travel by `codex queue --thread <UUID>` (Codex 0.149.0 or later). Windows ends `on` with exit 6 and the reason: on Codex 0.160.1 for Windows, `codex execpolicy check` matches the rule only for the wrapper called directly, not for the PowerShell call form (`& '<wrapper>' send ...`), so every call would ask for approval. `banker uninstall --codex` removes it only when no other way of banker into that Codex home is left.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kaydash9999/banker-plugins",
3
- "version": "0.23.3",
3
+ "version": "0.24.1",
4
4
  "description": "banker — Claude Code + Codex CLI plugin (QA, audit, docs, architecture, wiki skills). Install via Claude Code marketplace, or `npm i -g @kaydash9999/banker-plugins` then `banker setup`.",
5
5
  "bin": {
6
6
  "banker": "bin/banker.js"
@@ -0,0 +1,213 @@
1
+ ---
2
+ name: build-testbox
3
+ description: "이 PC 가 스스로 구성하는 범용 시험 환경. 서비스 시험용 브라우저 행렬(Playwright Chromium 과 WebKit, 데스크톱과 모바일 기기 에뮬레이션)과 배포 시험용 컨테이너 OS(Rocky Linux 8, 9. macOS 는 Apple Silicon 의 Tart VM 만)를 병렬로 실행. run 은 내려받지 않고 못 돈 칸은 unverified 와 사유로 끝남. 받기는 확인 뒤 setup --yes 로만. 'build-testbox'/'테스트박스 구성'/'멀티 OS 브라우저 시험'/'컨테이너 OS 시험'/'사파리 크롬 모바일 시험' 시 사용."
4
+ ---
5
+
6
+ # build-testbox: 브라우저 행렬과 컨테이너 OS 를 병렬로 돌리는 시험 환경
7
+
8
+ 이 스킬을 쓰는 PC, 서버, 세션이 자기 자원으로 시험 환경을 꾸린다. 특정 테스트박스를 전제하지 않는다.
9
+ 스크립트는 순수 Node 18+ 이고 의존성이 없다. Playwright 는 이 저장소의 의존성이 아니라 설치된 것을 찾아 불러온다. 찾는 순서는 아래와 같고, 앞의 것이 있으면 뒤는 보지 않는다.
10
+
11
+ 1. `--playwright-dir <폴더>`: `node_modules/playwright` 를 담은 폴더
12
+ 2. 환경 변수 `BUILD_TESTBOX_PLAYWRIGHT_DIR`: 1 과 같은 뜻
13
+ 3. `--playwright-from-project` 일 때 작업 폴더의 프로젝트 설치(그 프로젝트 코드가 돎)
14
+ 4. 전역 npm root
15
+
16
+ 1 이나 2 로 준 폴더에 Playwright 가 없으면 3, 4 로 넘어가지 않고 그 폴더를 적어 "없음" 으로 보고한다.
17
+ 답변은 한글.
18
+
19
+ | 묶음 | 칸 | 엔진 |
20
+ |---|---|---|
21
+ | 브라우저(서비스 시험) | 기기 하나가 칸 하나. 기본 `Desktop Chrome`, `Pixel 7`(chromium), `Desktop Safari`, `iPhone 15`(webkit) | 호스트의 Playwright, 또는 `--browser-in-container` 로 Playwright 공식 이미지 |
22
+ | 컨테이너 OS(배포 시험) | OS 하나가 칸 하나. 기본 `rocky8`, `rocky9` | docker 또는 podman |
23
+ | macOS | `--os macos` | Apple Silicon Mac 의 Tart VM |
24
+
25
+ - 두 묶음은 같은 순간에 시작한다. 묶음 안에서도 칸마다 `--jobs` 개까지 동시에 돈다
26
+ - Safari 는 WebKit 에뮬레이션, 모바일은 Playwright 기기 에뮬레이션이다. 실제 Safari, iOS 시뮬레이터는 범위 밖이다
27
+
28
+ ## 언제 쓰나
29
+
30
+ - 로컬 서비스(127.0.0.1)를 Chrome 과 Safari 계열, PC 와 모바일 화면으로 한 번에 열어 보고 싶을 때
31
+ - 배포 스크립트나 설치 명령을 Rocky Linux 8, 9 컨테이너에서 같이 돌려 보고 싶을 때
32
+ - airgap 에서도 "무엇이 돌았고 무엇이 왜 못 돌았는지" 를 거짓 통과 없이 남기고 싶을 때
33
+
34
+ ## 쓰지 않을 때
35
+
36
+ - Playwright 자체의 설치와 OS 라이브러리, Xvfb 준비. setup-playwright 를 쓴다
37
+ - 등록된 SSH 테스트박스에서 저장소 시험을 돌릴 때. remains 를 쓴다
38
+ - 비 Apple 호스트에서 macOS 를 띄우려 할 때. 라이선스상 하지 않는다(아래 "macOS" 절)
39
+
40
+ ## setup-playwright 와 역할 나눔
41
+
42
+ | 일 | 맡는 스킬 |
43
+ |---|---|
44
+ | Playwright 패키지 설치, OS 라이브러리(dnf, apt), Xvfb, `PLAYWRIGHT_BROWSERS_PATH` | setup-playwright |
45
+ | 이미 있는 Playwright 로 브라우저 빌드 받기(`npx --no-install playwright install <이름>`) | build-testbox `setup` |
46
+ | 컨테이너 이미지 받기(Rocky, Playwright 공식 이미지) | build-testbox `setup` |
47
+ | 브라우저 행렬과 컨테이너 OS 실행, 판정, 결과 기록 | build-testbox `run` |
48
+
49
+ - Playwright 패키지가 없으면 브라우저 칸은 `unverified(needs-playwright)` 이고 안내는 setup-playwright 다
50
+
51
+ ## 자리 표시
52
+
53
+ | 자리 | 뜻 |
54
+ |---|---|
55
+ | `<S>` | 이 스킬 디렉터리 절대경로(아래 런타임 표) |
56
+ | `<out>` | 결과 폴더. 기본 `./.testbox/<UTC 시각>` |
57
+
58
+ - 명령은 `node "<S>/scripts/testbox.mjs" <detect|run|setup> [인자]` 꼴로 실행한다
59
+ - 셸 변수는 도구 호출 사이에 남지 않는다. 명령마다 실제 경로를 적는다
60
+
61
+ ## 런타임 표
62
+
63
+ | 항목 | Claude Code | Codex |
64
+ |---|---|---|
65
+ | 스킬 디렉터리 | 스킬 맨 위 "Base directory for this skill:" 경로 | Codex 스킬 목록이 보이는 이 SKILL.md 경로의 폴더. npm 설치는 `~/.codex/skills/banker-build-testbox/`, 플러그인 설치는 `~/.codex/plugins/cache/<마켓플레이스>/banker/<판>/skills/build-testbox/`. 절대경로로 씀 |
66
+ | `detect` | 바로 실행 | 엔진 소켓과 브라우저 실행 때문에 승인 요청(아래 승인 표) |
67
+ | `run` | 바로 실행 | 승인 요청 |
68
+ | `setup` 확인 | `AskUserQuestion` | `request_user_input` |
69
+ | `setup --yes` | 확인 뒤 실행 | 확인 뒤 네트워크 승인 요청 |
70
+
71
+ ## 하위 명령
72
+
73
+ | 명령 | 내용 |
74
+ |---|---|
75
+ | `detect [--json] [--engine ...] [--os ...] [--image <os>=<이미지>] [--playwright-from-project] [--playwright-dir <폴더>]` | 호스트 OS, 아키텍처, Apple Silicon 여부, Playwright 위치와 판, 브라우저별 실제 headless 실행 결과(chromium 은 headless shell 과 전체 chromium 을 따로), 엔진(docker 가 podman 에뮬레이션인지), 로컬 이미지 유무(`image inspect`), Tart 와 VM 목록. 내려받지 않음 |
76
+ | `run [옵션]` | 브라우저 묶음과 컨테이너 묶음을 병렬 실행. 내려받지 않음 |
77
+ | `setup [--images <os,...>] [--browsers <이름,...>] [--playwright-image] [--yes]` | `--yes` 가 없으면 받을 것과 대략 크기만 보이고 종료 0. 이름을 주지 않으면 로컬에 없는 기본 이미지와 빌드가 없는 브라우저가 대상 |
78
+
79
+ `run` 옵션
80
+
81
+ | 옵션 | 뜻 | 기본 |
82
+ |---|---|---|
83
+ | `--url <loopback URL\|파일>` | 브라우저 묶음 대상. 없으면 브라우저 묶음은 요청 안 됨 | 없음 |
84
+ | `--browsers chromium,webkit` | 브라우저 거름 | 둘 다 |
85
+ | `--devices "<이름>,..."` | Playwright 기기 이름. 기기의 `defaultBrowserType` 으로 돎 | 위 4개 |
86
+ | `--browser-in-container` | 브라우저 칸을 `mcr.microsoft.com/playwright:v<호스트 Playwright 판>-noble` 안에서 돌림. http, https URL 만 | 꺼짐 |
87
+ | `--os rocky8,rocky9,macos` | 컨테이너와 VM 대상. `none` 이면 컨테이너 묶음을 빼고, 다른 이름은 `--image` 와 함께 | `rocky8,rocky9` |
88
+ | `--image <os>=<이미지>` | 이미지 바꾸기. `playwright=<이미지>` 는 `--browser-in-container` 이미지 | rocky8 `docker.io/rockylinux/rockylinux:8`, rocky9 `:9` |
89
+ | `--cmd "<명령>"` | 컨테이너 안 `/src` 에서 `sh -c` 로 실행 | `cat /etc/os-release` |
90
+ | `--src <dir>` | 컨테이너로 넣을 소스 | 작업 폴더 |
91
+ | `--engine auto\|docker\|podman` | `auto` 는 실제 docker, podman, podman 에뮬레이션 docker 순 | `auto` |
92
+ | `--network bridge\|none\|host` | 컨테이너 네트워크 | 엔진 기본 |
93
+ | `--jobs N`, `--timeout <초>` | 묶음마다 동시 칸 수, 칸마다 시간 제한 | `min(4, CPU 수)`, 300 |
94
+ | `--out <dir>` | 결과 폴더 | `./.testbox/<시각>` |
95
+ | `--playwright-from-project` | 프로젝트 `node_modules` 의 Playwright(그 프로젝트 코드가 돎) | 꺼짐 |
96
+ | `--playwright-dir <폴더>` | 이 폴더의 `node_modules/playwright` 를 씀. `detect`, `setup` 에도 씀. 환경 변수 `BUILD_TESTBOX_PLAYWRIGHT_DIR` 보다 앞 | 없음 |
97
+ | `--allow-remote` | loopback 이 아닌 URL 도 엶 | 꺼짐 |
98
+ | `--tart-vm <이름>`, `--json` | Tart VM 이름(없으면 첫 로컬 VM), 결과 JSON 한 줄 출력 | 꺼짐 |
99
+
100
+ - 배포 시험 명령은 사용자가 준다. Rocky 기본 이미지에는 node, npm 이 없다
101
+ - 온라인 예: `--cmd "dnf -y install nodejs && node -v"`(bridge 네트워크와 저장소 미러 필요)
102
+ - 오프라인 예: `--cmd "cat /etc/os-release && rpm -q bash"`
103
+ - 컨테이너 칸: `image inspect`(받지 않음), `create`, 소스 사본을 `cp` 로 `/src` 에, `start -a`, 끝나면 `rm -f`. 바인드 마운트는 쓰지 않는다(SELinux 재라벨, Windows 경로 문제)
104
+ - 소스 사본: git 저장소면 추적 파일과 무시되지 않은 새 파일(작업 트리 내용), 아니면 `node_modules`, `.git`, `.testbox` 를 뺀 전부. 결과 폴더는 뺀다
105
+ - 이름은 `banker-testbox-<난수>-<os>`. 시간 초과, SIGINT, SIGTERM, SIGHUP 에서도 지운다
106
+ - 브라우저 칸: 브라우저 종류마다 한 번 띄우고 기기마다 새 컨텍스트. 응답 상태, 페이지 오류 수, 콘솔 오류 수, 제목, 스크린숏(`<out>/browser-<기기>.png`). 통과는 응답 2xx 나 3xx(파일 URL 은 응답 없음)이고 페이지 오류 0
107
+
108
+ ## 칸 상태와 사유
109
+
110
+ | 상태 | 사유 | 뜻과 안내 |
111
+ |---|---|---|
112
+ | `pass` | | 통과 |
113
+ | `fail` | `exit-<n>` | 컨테이너나 VM 안 명령이 0 이 아닌 값으로 끝남 |
114
+ | `fail` | `http-<n>` | 응답이 2xx, 3xx 가 아님 |
115
+ | `fail` | `page-error` | 페이지가 예외를 던짐, 또는 페이지를 열지 못함 |
116
+ | `unverified` | `needs-playwright` | Playwright 패키지 없음. setup-playwright |
117
+ | `unverified` | `needs-browser` | 브라우저 빌드 없음. `setup --browsers <이름>` |
118
+ | `unverified` | `needs-image` | 로컬 이미지 없음. `setup --images <os>` 또는 `setup --playwright-image` |
119
+ | `unverified` | `needs-engine` | docker, podman 없음이나 엔진에 연결 못 함 |
120
+ | `unverified` | `needs-network` | `setup` 의 원천에 닿지 못함 |
121
+ | `unverified` | `needs-tool` | 컨테이너 안 명령 종료 127(명령 없음). 이미지에 도구를 넣거나 `--cmd` 를 바꿈 |
122
+ | `unverified` | `needs-tart` | Apple Silicon Mac 에 Tart 없음 |
123
+ | `unverified` | `needs-vm` | Tart VM 없음이나 꺼짐(VM 이미지 약 25GB) |
124
+ | `unverified` | `tart-exec-unsupported` | `tart exec --help` 실패. Tart 를 올림 |
125
+ | `unverified` | `host-deps` | 브라우저 실행에 필요한 OS 라이브러리 없음(Rocky 8 의 WebKit 등). `--browser-in-container` |
126
+ | `unverified` | `launch-failed` | 그 밖의 실행 실패. 로그 확인 |
127
+ | `unverified` | `unknown-device` | 이 Playwright 판에 없는 기기 이름 |
128
+ | `unverified` | `timeout` | 시간 초과 |
129
+ | `unverified` | `sandbox` | 엔진이나 브라우저의 권한 오류(Codex 샌드박스, 소켓 권한). 승인 뒤 다시 |
130
+ | `unsupported` | `apple-sla` | 비 Apple 호스트의 macOS. 요구 축소 항목 |
131
+ | `unsupported` | `tart-needs-apple-silicon` | Intel Mac 이나 x86_64 macOS 가상 머신. Tart 는 Apple Silicon 전용 |
132
+
133
+ - `--url` 이 없으면 브라우저 칸은 만들지 않고 요약에 "브라우저 묶음 요청 안 됨" 한 줄을 쓴다(판정에 넣지 않음). `--os none` 도 같은 꼴
134
+ - Firefox 기기(`Desktop Firefox`)는 사용 오류다(범위 밖)
135
+
136
+ ## 종료 코드
137
+
138
+ | 명령 | 코드 |
139
+ |---|---|
140
+ | `run` | 0 요청한 모든 칸 `pass`, 1 `fail` 1칸 이상, 4 `fail` 없이 `unverified` 나 `unsupported` 1칸 이상, 2 사용 오류, 3 내부 오류나 결과 폴더 쓰기 실패, 129, 130, 143 SIGHUP, SIGINT, SIGTERM(만든 컨테이너를 지운 뒤) |
141
+ | `setup` | 0 받고 확인됨(또는 계획만 보임), 1 일부 실패, 4 실패 없이 닿지 못한 원천이 있음("네트워크 필요"), 2 사용 오류 |
142
+ | `detect` | 0, 사용 오류 2 |
143
+
144
+ - 요약 첫 줄: `pass <n>, fail <n>, unverified <n>, unsupported <n>`
145
+ - 결과: `<out>/results.json`(칸마다 상태, 사유, 시작과 끝 시각, 로그 경로, 컨테이너 칸은 네트워크 모드), `<out>/summary.md`. 화면에도 같은 표를 낸다
146
+
147
+ ## setup 확인 절차
148
+
149
+ 1. `node "<S>/scripts/testbox.mjs" setup [이름들]` 로 계획을 본다(아무것도 받지 않음)
150
+ 2. 계획(무엇을, 대략 크기)을 사용자에게 보이고 확인을 받는다. Claude Code `AskUserQuestion`, Codex `request_user_input`
151
+ 3. 확인을 받으면 같은 인자에 `--yes` 를 붙여 실행한다. Codex 는 네트워크 승인을 요청한다
152
+ 4. 출력의 `needs-network` 줄과 실패 줄을 그대로 보고한다
153
+
154
+ | 대상 | 대략 크기 |
155
+ |---|---|
156
+ | rocky8, rocky9 이미지 | 약 200MB, 약 180MB |
157
+ | chromium(headless shell 포함) | 약 280MB |
158
+ | webkit | 약 100MB |
159
+ | Playwright 공식 이미지(`--playwright-image`) | 약 2GB |
160
+
161
+ - `--yes` 는 받기 전에 원천마다 15초 안의 확인을 한다. 레지스트리는 `https://<호스트>/v2/`(docker.io 는 `registry-1.docker.io`, loopback 레지스트리는 http), 브라우저는 `PLAYWRIGHT_DOWNLOAD_HOST`(chromium 은 `PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST` 도) 또는 `https://cdn.playwright.dev`. 주소의 사용자 정보는 뗀다. HTTP 답이면 401, 404 도 닿은 것이다
162
+ - 닿지 못한 원천의 항목은 받지 않고 `needs-network` 로 남긴다. `CODEX_SANDBOX_NETWORK_DISABLED=1` 이면 "Codex 샌드박스가 네트워크를 막음" 으로 구분한다
163
+ - 받는 순서: 이미지(준 순서), 그다음 브라우저. 하나씩 받고, 받을 때마다 `image inspect` 나 실제 headless 실행으로 확인한다
164
+ - 브라우저 설치는 `npx --no-install playwright install <이름>` 을 홈 폴더에서 실행한다(`--playwright-dir` 이나 `BUILD_TESTBOX_PLAYWRIGHT_DIR` 이면 그 폴더, `--playwright-from-project` 면 작업 폴더)
165
+ - Playwright 패키지를 찾지 못하면 브라우저 항목은 받지 않고 `failed` 로 남기며(종료 1) 찾아본 곳을 적는다
166
+
167
+ ## macOS
168
+
169
+ - 비 Apple 호스트: `unsupported(apple-sla)`. Apple macOS 사용권 계약(SLA)은 이미 macOS 가 도는 Apple 하드웨어에서만 가상 사본(최대 2개)을 허용한다. 비 Apple 호스트용 macOS 컨테이너(dockur/macos 등)는 그 프로젝트 스스로 EULA 위반을 밝히므로 안내하지 않는다
170
+ - macOS 지만 Apple Silicon 이 아님: `unsupported(tart-needs-apple-silicon)`. `sysctl hw.model` 은 믿지 않는다. QEMU 위 OpenCore 가상 머신(x86_64)도 `MacPro7,1` 같은 값을 낸다(실측). Apple Silicon 판정은 `process.arch` 가 `arm64` 이거나 `sysctl -n hw.optional.arm64` 가 1(Rosetta 아래 Node)
171
+ - Apple Silicon Mac: Tart 없음 `needs-tart`, VM 없음이나 꺼짐 `needs-vm`, `tart exec --help` 실패 `tart-exec-unsupported`, 그 밖은 `tart exec <vm> -- sh -c "<cmd>"`
172
+ - VM 은 사용자가 `tart clone` 으로 받고(약 25GB) `tart run` 으로 켠다. 이 스킬은 VM 을 받거나 켜지 않는다
173
+ - macOS 칸에는 소스 사본을 넣지 않는다. 명령만 돈다
174
+ - 사용자 보고(요구 축소): macOS 는 Apple Silicon 호스트의 Tart VM 만 지원하고, 비 Apple 호스트는 라이선스 사유로 `unsupported`. 실제 Safari, iOS 시뮬레이터는 WebKit 에뮬레이션으로 대신한다
175
+
176
+ ## Codex 샌드박스 승인
177
+
178
+ | 동작 | 이유 | 요청 |
179
+ |---|---|---|
180
+ | 컨테이너 실행(`detect`, `run`) | 엔진 소켓, rootless podman 의 사용자 네임스페이스 | `sandbox_permissions: "require_escalated"` |
181
+ | 브라우저 실행(`detect`, `run`) | 브라우저 프로세스와 네임스페이스 | 같음 |
182
+ | 포트 | 시험 대상 서버는 사용자가 띄운 127.0.0.1 포트. 이 스킬은 포트를 열지 않음 | 서버 실행 쪽 승인 |
183
+ | 네트워크(`setup --yes`, `--network bridge` 의 명령) | 레지스트리, 브라우저 서버, 컨테이너 안 `dnf` | 같음 |
184
+ | 작업 폴더 밖 쓰기 | 소스 사본과 실행기 사본을 OS 임시 폴더에 만듦 | 같음 |
185
+ | `--network host` | 그 칸의 네트워크 격리가 풀림. `--browser-in-container` 는 Linux 에서 호스트 loopback 에 닿으려고 이것을 씀 | 같음, 사용자에게 알림 |
186
+
187
+ - Codex 는 명령 하나씩 승인을 요청한다. `&&` 로 묶지 않는다
188
+ - 권한 오류로 끝난 칸은 `unverified(sandbox)` 다. 승인 뒤 다시 실행한다
189
+
190
+ ## 오프라인 동작
191
+
192
+ - `run`, `detect` 는 내려받지 않는다. 없는 이미지, 브라우저, 엔진은 `unverified` 와 "무엇을 setup 하면 되는지" 로 끝난다
193
+ - `setup --yes` 는 원천마다 15초 안에 확인하고, 닿지 못하면 받지 않고 종료 4 와 "네트워크 필요" 로 끝난다
194
+
195
+ ## 함정
196
+
197
+ - Rocky 8, RHEL 8 은 Playwright 공식 지원 OS 가 아니다. WebKit 은 OS 라이브러리 부족으로 `host-deps` 가 되기 쉽다. `--browser-in-container`(공식 이미지 약 2GB, `setup --playwright-image`)로 돌린다
198
+ - `--browser-in-container` 는 호스트 Playwright 패키지와 그것이 의존하는 `playwright-core` 를 `cp` 로 넣는다. 공식 이미지 판은 호스트 Playwright 판과 같아야 한다. Linux 밖에서는 loopback URL 을 `host.containers.internal`(podman)이나 `host.docker.internal`(docker)로 바꿔 연다. 이 경로는 Linux 밖에서 실측하지 않았다
199
+ - `--network host` 는 칸의 네트워크 격리를 푼다. `results.json` 의 칸에 네트워크 모드가 남는다
200
+ - rootless podman 의 엔진 기본 네트워크는 `bridge` 가 아니라 `slirp4netns` 나 `pasta` 일 수 있다. `results.json` 에는 엔진이 실제로 쓴 모드를 적는다
201
+ - docker 명령이 podman 에뮬레이션이면 엔진 이름은 docker 여도 지우기는 `rm -f -t 0`(즉시 종료)를 쓴다
202
+ - Node 의 fetch 는 `HTTPS_PROXY` 를 따르지 않는다(Node 24 는 `NODE_USE_ENV_PROXY=1` 일 때만). 프록시만 열린 망에서 `setup` 의 확인이 실패하면 `needs-network` 로 보인다
203
+ - `run` 의 기본 결과 폴더 `./.testbox/` 는 작업 폴더 안에 생긴다. git 저장소면 `.gitignore` 에 넣는다
204
+
205
+ ## 출처
206
+
207
+ - Playwright 브라우저 위치와 `PLAYWRIGHT_BROWSERS_PATH`: https://playwright.dev/docs/browsers
208
+ - Playwright 기기 에뮬레이션과 `devices`: https://playwright.dev/docs/emulation
209
+ - Playwright 지원 OS: https://playwright.dev/docs/intro , Rocky 8 의 WebKit 라이브러리 부족 보고: https://github.com/microsoft/playwright/issues/11122
210
+ - Playwright 공식 이미지: https://playwright.dev/docs/docker
211
+ - Rocky Linux 이미지(`docker.io/rockylinux/rockylinux`): https://hub.docker.com/r/rockylinux/rockylinux
212
+ - Apple macOS 사용권 계약: https://www.apple.com/legal/sla/ , 비 Apple 호스트 macOS 컨테이너의 EULA 위반 명시: https://github.com/dockur/macos
213
+ - Tart 요구 조건(Apple Silicon, macOS 13 이상)과 라이선스: https://tart.run/quick-start/ , https://tart.run/licensing/