@kaydash9999/banker-plugins 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +30 -0
- package/README.md +23 -2
- package/codex/manifest.json +12 -0
- package/codex/transform-matrix.md +1 -0
- package/commands/setup.md +28 -16
- package/hooks/hooks.json +17 -0
- package/hooks/obsidize-hook.mjs +150 -0
- package/hooks/run.cjs +45 -0
- package/package.json +3 -1
- package/skills/harness-factory/SKILL.md +114 -0
- package/skills/obsidizer/SKILL.md +255 -0
- package/skills/obsidizer/obsidize.mjs +554 -0
- package/skills/setup-java/SKILL.md +113 -0
- package/skills/setup-lsp/SKILL.md +232 -0
- package/skills/setup-mcp/SKILL.md +156 -0
- package/skills/setup-node/SKILL.md +112 -0
- package/skills/setup-pwsh/SKILL.md +106 -0
- package/skills/setup-python/SKILL.md +121 -0
- package/skills/setup-sandbox/SKILL.md +202 -0
- package/skills/setup-tmux/SKILL.md +105 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "banker",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Claude Code plugin: QA/audit/docs/architecture skills + commands, a /banker:setup installer for OS dependencies (playwright, etc.), and wiki compaction.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "smallOpenSource",
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.6.0] - 2026-07-15
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- **신규 스킬 `obsidizer`** (`target: both`): AI가 생성한 마크다운 위키를 의미 보존한 채 Obsidian 지식그래프로 정규화·상호링크·백링크한다. in-place 정규화(별도 export 트리 없음)·절대 rename 금지·LLM 의미론적 편집 + 제로-입력 결정적 캐노니컬라이저(`obsidize.mjs`) 2계층 엔진·OMC 트리에서는 bare-form(`[[slug]]`)만 허용하는 위키링크(`extractWikiLinks`가 피이프/헤딩 형태를 통째로 슬러그화해 `links[]`를 깨뜨림)·generic vault 한정 `aliases`(OMC 트리는 READ 시점 silent strip + 유일한 소비처인 피이프 링크가 금지라 destructive 실패 모드로 거부). `--enable`/`--disable`은 banker 최초의 **플러그인 선언 hook**(`hooks/hooks.json`)으로 Claude에서만 구조적으로 동작(위키 쓰기 후 원자적 쓰기 + read-back CAS로 동시쓰기를 skip)하고 Codex(MCP tool hook 없음)에서는 정직한 no-op이다. **hook은 banker가 활성화되어 있으면 항상 등록**되어 위키 쓰기(`wiki_ingest`/`wiki_add`)마다 실행되므로, `--enable`을 켜지 않은 사용자도 쓰기당 약 30ms의 node 프로세스 기동 비용을 치른다(플래그 확인 자체가 그 프로세스 내부에서 일어나기 때문); `--enable` 이전에는 아무 파일도 쓰지 않는 순수 no-op이다.
|
|
7
|
+
- **Deferred to 0.7.0 (품질 이유, 효율 이유 아님):** Canvas-MOC sidecar 생성 · inline Dataview `::` 생성 · MOC 허브 페이지 생성. 셋 다 in-place durable 은 이미 코드로 검증됐지만(좌표 결정성·필드 날조 방지·링크 인플레 방지 기준이 아직 없어) **생성만** 보류한다 — 호환성은 v1에서 이미 무료로 확보돼 있다.
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
- Codex 설치 스킬 수 **41 → 42**(+커맨드 2 유지, claude-only=0). `codex/manifest.json`·`README.md`·`codex/transform-matrix.md`·`scripts/smoke-test.js`·`.github/workflows/harness-setup-ci.yml`을 동기화했다.
|
|
11
|
+
- `package.json` `files[]`에 `hooks`를 추가해 `hooks/hooks.json`·`hooks/obsidize-hook.mjs`·`hooks/run.cjs`가 npm 패키지에 포함되도록 했다(`npm pack --dry-run`으로 확인).
|
|
12
|
+
|
|
13
|
+
## [0.5.0] - 2026-07-15
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- **신규 스킬 9종** (전부 `target: both`, 런타임 인식 — Claude=OMC / Codex=OMX): 개발환경 "harness" 구성요소를 OS별·런타임별로 개별 설치/구성하는 스킬 계층. USER_RESOURCES의 과거버전 가이드(5-OS Claude Code + 6-OS Codex/Azure)에서 공통 유용요소를 추출하고 2026 현행 방식으로 현행화했다.
|
|
17
|
+
- `setup-node`: nvm + Node 22 (winget/nvm-windows) per-OS. npx 기반 MCP·CLI의 전제.
|
|
18
|
+
- `setup-python`: Python 3.11 + pipx + uv per-OS (dnf module/deadsnakes/winget/brew, PEP668). `docs-setup`가 이 런타임을 소비.
|
|
19
|
+
- `setup-java`: JDK 21 + JAVA_HOME per-OS (Debian은 Adoptium Temurin 전용). `setup-lsp`의 jdtls가 요구.
|
|
20
|
+
- `setup-lsp`: 언어별 LSP(vtsls·basedpyright·bash·jdtls·spring) + lsp-mcp 브리지. Claude=LSP MCP 도구, Codex=`config.toml [mcp_servers.lsp_bridge]`. `--lang` 선택.
|
|
21
|
+
- `setup-tmux`: tmux per-OS (Rocky8 `3.6a` 소스빌드·apt/brew·Windows psmux). OMC team·worktree / OMX `$team`·HUD 전제.
|
|
22
|
+
- `setup-pwsh`: Windows PowerShell 7 환경(`$PROFILE` UTF-8·Terminal·Git). Claude=`CLAUDE_CODE_GIT_BASH_PATH`, Codex=네이티브 셸. 비-Windows는 no-op 안내.
|
|
23
|
+
- `setup-mcp`: 공통 MCP 서버(context7·sequential-thinking·filesystem·git·fetch). Claude=`claude mcp add`, Codex=`config.toml [mcp_servers.*]` (timeout 300).
|
|
24
|
+
- `setup-sandbox`: OS별 샌드박스(bubblewrap+userns / AppContainer / Seatbelt) + rust/cargo + git `safe.directory`. Codex=`sandbox_mode`.
|
|
25
|
+
- `harness-factory`: revfactory/harness(팀 아키텍처 팩토리) 플러그인 설치+구성+사용안내. Claude=`harness@harness-marketplace`(+`CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` 를 settings.json에 영속), Codex=`SaehwanPark/meta-harness`. 설치를 넘어 모드/6패턴 선택·비용가드(~7× 토큰)·experimental 리스크 고지까지 담되, harness references는 이식하지 않고 설치된 플러그인 참조(Apache-2.0 연동/참조, banker 재배포 아님).
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
- Codex 설치 스킬 수 **32 → 41**(+커맨드 2 유지, claude-only=0). **2계층 아키텍처**: 얇은 setup-* 실행 유닛 + `banker:setup`/`harness-factory` 오케스트레이터가 조합·의존성 관리(setup-lsp→node/python/java, setup-mcp→node/python, docs-setup→python).
|
|
29
|
+
- `commands/setup.md` 오케스트레이터에 신규 9 스킬(계층·의존성)을 추가하고, `README.md`·`codex/transform-matrix.md`를 동기화했다. `scripts/smoke-test.js`에 `copies===41` + 신규 9 존재 회귀 단언을 추가했다.
|
|
30
|
+
- **서드파티 명시(연동/참조, 재배포 아님)**: revfactory/harness·SaehwanPark/meta-harness(Apache-2.0), jdtls(EPL), tmux(ISC), psmux, basedpyright·vtsls·bash-language-server·lsp-mcp 등 각 프로젝트 라이선스 소유.
|
|
31
|
+
- **per-OS CI**: `.github/workflows/`에 GitHub-hosted 러너(ubuntu/windows/macos + Rocky8 컨테이너) 기반 설치·동작 검증 워크플로를 추가했다(설치가 실제 실행되는 도구를 만드는지 "존재 vs 동작" 검증).
|
|
32
|
+
|
|
3
33
|
## [0.4.0] - 2026-07-15
|
|
4
34
|
|
|
5
35
|
### Added
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
[빠른 시작](#빠른-시작) · [구성](#구성) · [설치 상세](#설치-상세-npm--codex) · [요구사항](#요구사항) · [업데이트 / 제거](#업데이트--제거) · [라이선스 / 서드파티](#라이선스--서드파티)
|
|
9
9
|
|
|
10
|
-
banker는 QA, 보안 감사, 문서, 아키텍처, 위키 작업을 위한 스킬
|
|
10
|
+
banker는 QA, 보안 감사, 문서, 아키텍처, 위키 작업을 위한 스킬 42개와 의존성·개발환경(OS별) 설치 스킬을 묶은 Claude Code 플러그인입니다. 설치하면 스킬과 커맨드가 `/banker:<이름>` 네임스페이스로 노출됩니다. 이 저장소 자체가 Claude Code 마켓플레이스(`.claude-plugin/marketplace.json`)이자 플러그인(`.claude-plugin/plugin.json`, name `banker`)이며, 도구에 무관한 스킬은 Codex CLI에도 설치됩니다.
|
|
11
11
|
|
|
12
12
|
> npm 패키지(`@kaydash9999/banker-plugins`)와 GitHub 저장소(`smallOpenSource/banker_plugins`)는 같은 메인테이너가 관리합니다.
|
|
13
13
|
|
|
@@ -66,8 +66,11 @@ playwright(브라우저 QA)나 oh-my-claudecode(OMC/OMX)처럼 별도 의존성
|
|
|
66
66
|
| `lineage` | 세션 대화를 카카오톡 스타일 단일 HTML로 export |
|
|
67
67
|
| `append_wiki` | 프로젝트 위키 문서 추가/보강 |
|
|
68
68
|
| `compact-wiki` | 위키 중복 제거·supersede·병합 (무손실) |
|
|
69
|
+
| `obsidizer` | AI 위키를 의미보존 Obsidian 그래프로 정규화·상호링크·백링크 |
|
|
69
70
|
| `deep-init` | 코드베이스 전체에 계층형 AGENTS.md 문서 생성/갱신 |
|
|
70
71
|
|
|
72
|
+
> `obsidizer` 는 banker 최초의 플러그인 선언 hook(`hooks/hooks.json`)을 함께 설치합니다. banker가 활성화되어 있으면 이 hook은 **항상 등록**되어 위키 쓰기(`wiki_ingest`/`wiki_add`)마다 실행되고, `obsidizer --enable` 을 켜지 않은 사용자도 쓰기당 약 30ms의 node 프로세스 기동 비용을 치릅니다(플래그 확인 자체가 그 프로세스 안에서 일어나기 때문). `--enable` 전에는 아무것도 쓰지 않는 순수 no-op입니다.
|
|
73
|
+
|
|
71
74
|
### 스킬: 워크플로 · 유틸
|
|
72
75
|
|
|
73
76
|
| 스킬 | 설명 |
|
|
@@ -83,11 +86,27 @@ playwright(브라우저 QA)나 oh-my-claudecode(OMC/OMX)처럼 별도 의존성
|
|
|
83
86
|
| `smart-compact` | 컨텍스트 임계 초과 시 위키·resume 저장 게이트 자동 무장 |
|
|
84
87
|
| `deep-research` | 다중 소스 팬아웃 + 적대적 검증 인용 리서치 |
|
|
85
88
|
|
|
89
|
+
### 스킬: 개발환경 setup (OS별 · 런타임별)
|
|
90
|
+
|
|
91
|
+
USER_RESOURCES 가이드의 공통 요소를 OS별·런타임별(Claude Code/Codex)로 구성하는 얇은 실행 유닛. `/banker:setup` 오케스트레이터가 의존 순서(런타임 먼저)로 조합한다.
|
|
92
|
+
|
|
93
|
+
| 스킬 | 설명 |
|
|
94
|
+
|---|---|
|
|
95
|
+
| `setup-node` | nvm + Node 22 (winget/nvm-windows) |
|
|
96
|
+
| `setup-python` | Python 3.11 + pipx + uv (PEP668) |
|
|
97
|
+
| `setup-java` | JDK 21 + JAVA_HOME (Debian=Adoptium Temurin) |
|
|
98
|
+
| `setup-lsp` | 언어별 LSP(vtsls·basedpyright·bash·jdtls·spring) + lsp-mcp 브리지 (node·python·java 의존) |
|
|
99
|
+
| `setup-tmux` | tmux(Rocky8 3.6a 소스빌드) / psmux(Windows) |
|
|
100
|
+
| `setup-pwsh` | Windows PowerShell 7 환경(비-Windows no-op) |
|
|
101
|
+
| `setup-mcp` | 공통 MCP 서버(context7·seq-thinking·filesystem·git·fetch) |
|
|
102
|
+
| `setup-sandbox` | OS별 샌드박스(bubblewrap+userns / Seatbelt) + rust + git safe.directory |
|
|
103
|
+
|
|
86
104
|
### 스킬: 설치 (`/banker:setup` 가 호출)
|
|
87
105
|
|
|
88
106
|
| 스킬 | 설명 |
|
|
89
107
|
|---|---|
|
|
90
108
|
| `setup-omc` | oh-my-claudecode(OMC) 설치·갱신 (Codex는 OMX) |
|
|
109
|
+
| `harness-factory` | revfactory/harness 팀 아키텍처 팩토리 설치·구성·사용안내 (Codex=meta-harness) |
|
|
91
110
|
| `setup-playwright` | Playwright + headless 브라우저 (RHEL8/Rocky8·non-root·no-conda 폴백) |
|
|
92
111
|
| `setup-omc-hud` | omc_hud 상태표시줄 (OS별) |
|
|
93
112
|
| `setup-insane-search` | insane-search 플러그인 설치 (Claude·Codex) |
|
|
@@ -109,7 +128,7 @@ banker uninstall # 제거
|
|
|
109
128
|
|
|
110
129
|
- `--scope project` 로 프로젝트 로컬(`./.codex`)에 설치하고, `--dry-run` 으로 미리 볼 수 있습니다.
|
|
111
130
|
- non-root 전용입니다(전역 sudo 설치 시 root 소유 파일을 방지). postinstall이 없으므로 `banker setup` 을 직접 실행합니다.
|
|
112
|
-
- Codex에는 스킬
|
|
131
|
+
- Codex에는 스킬 42개가 `~/.codex/skills/banker-<name>/` 에, 커맨드 2개가 `~/.codex/prompts/banker-<name>.md` 에 설치됩니다(`codex/manifest.json`). 디렉터리명과 일치하도록 프론트매터 `name:` 이 `banker-<name>` 으로 재작성되어 Codex가 `banker-<name>` 으로 인식합니다.
|
|
113
132
|
- OMC/Claude 에 결합됐던 오케스트레이터·설치·유틸 표면(all-in-one·ultra-init·front-qa·setup·setup-omc·setup-omc-hud·setup-stitch·omc-reference·compact-copy)은 본문이 **런타임 인식**이라 Codex에서도 동작합니다 — Codex에선 OMC 대신 **oh-my-codex(OMX)** 의 동명 스킬(ralplan·ralph·ultraqa·hud 등)과 `codex mcp`·내장 `/copy` 를 사용합니다(Codex는 `omx setup` 전제).
|
|
114
133
|
- `~/.codex/AGENTS.md` 는 건드리지 않습니다(omx가 재생성하므로 `~/.codex/skills/` 자동 검색에 의존).
|
|
115
134
|
|
|
@@ -154,9 +173,11 @@ banker 자체는 **MIT** ([LICENSE](LICENSE)). Owner: [smallOpenSource](https://
|
|
|
154
173
|
- Python: python-pptx(MIT, `arch-diagram`), python-docx(MIT, `rfp-author`), Playwright(Apache-2.0, `audit-web-page`·`play-qa`·`ultra-ui-qa`), detect-secrets(Apache-2.0, `lineage` 시크릿 스캔).
|
|
155
174
|
- 브라우저·렌더링: Chromium(BSD-3-Clause), SwiftShader(Apache-2.0), Xvfb·X.Org(MIT). `setup-playwright` 및 브라우저 QA 스킬이 사용.
|
|
156
175
|
- 문서·다이어그램: PlantUML(GPL 계열·다중 라이선스, `arch-diagram`), Poppler(GPL, `pdftoppm`), ImageMagick(ImageMagick License, `pdf-vision-extract`).
|
|
176
|
+
- 개발환경·LSP: Node.js·nvm(MIT), uv(Apache-2.0/MIT), OpenJDK·Temurin(GPL+CE), jdtls(EPL-2.0), basedpyright(MIT)·vtsls·bash-language-server(MIT)·vscode-langservers-extracted, lsp-mcp([CesarPetrescu/lsp-mcp](https://github.com/CesarPetrescu/lsp-mcp)), tmux(ISC)·psmux, bubblewrap(LGPL-2.0), rustup. `setup-node`·`setup-python`·`setup-java`·`setup-lsp`·`setup-tmux`·`setup-sandbox` 가 설치.
|
|
157
177
|
|
|
158
178
|
**연동·참조 (외부 프레임워크·서비스·브랜드)**
|
|
159
179
|
- 프레임워크: oh-my-claudecode(OMC, **MIT**)·oh-my-codex(OMX, **MIT**), by [Yeachan-Heo](https://github.com/Yeachan-Heo). `all-in-one`·`ultra-init`·`/banker:front-qa`·`setup-omc` 가 사용.
|
|
160
180
|
- 플러그인: insane-search(**MIT**, © fivetaku, [fivetaku/gptaku_plugins](https://github.com/fivetaku/gptaku_plugins)). `setup-insane-search` 가 설치.
|
|
181
|
+
- 팀 아키텍처 팩토리: revfactory/harness(**Apache-2.0**, © Minho Hwang, [revfactory/harness](https://github.com/revfactory/harness))·Codex 포트 SaehwanPark/meta-harness(**Apache-2.0**). `harness-factory` 가 설치(banker 는 재배포하지 않고 설치·구성만 안내).
|
|
161
182
|
- 서비스·디자인(독점·상표): Notion(`make-notion-guide`), Google Stitch(`setup-stitch`), Nothing 디자인 언어(`nothing-design`).
|
|
162
183
|
- QA 대상 엔진(예시): Godot(MIT), Phaser(MIT) 등(`play-qa`).
|
package/codex/manifest.json
CHANGED
|
@@ -38,6 +38,18 @@
|
|
|
38
38
|
{ "name": "smart-compact", "type": "skill", "target": "both", "reason": "context-threshold compaction-hygiene gate (statusLine detect + hook bridge + assistant chain + TUI handoff); runtime-aware", "supportingFiles": [] },
|
|
39
39
|
{ "name": "visual-ralph", "type": "skill", "target": "both", "reason": "measured visual build loop (port of OMX visual-ralph); Claude ralph+visual-verdict+Stitch imagegen, Codex $ralph+$imagegen; runtime-aware", "supportingFiles": [] },
|
|
40
40
|
|
|
41
|
+
{ "name": "setup-node", "type": "skill", "target": "both", "reason": "installs nvm+Node22 (or winget/nvm-windows) per-OS; prerequisite for npx MCP servers + Codex/OMX tooling; runtime-agnostic installer", "supportingFiles": [] },
|
|
42
|
+
{ "name": "setup-python", "type": "skill", "target": "both", "reason": "installs Python 3.11 + pipx + uv per-OS (dnf module/deadsnakes/winget/brew, PEP668); runtime foundation; docs-setup consumes it", "supportingFiles": [] },
|
|
43
|
+
{ "name": "setup-java", "type": "skill", "target": "both", "reason": "installs JDK 21 + JAVA_HOME per-OS (dnf/apt-Adoptium/winget/brew); required by jdtls in setup-lsp", "supportingFiles": [] },
|
|
44
|
+
{ "name": "setup-lsp", "type": "skill", "target": "both", "reason": "installs per-language LSP servers (vtsls/basedpyright/bash/jdtls/spring) + lsp-mcp bridge; Claude=LSP MCP tools, Codex=config.toml [mcp_servers.lsp_bridge]; needs setup-node/python/java", "supportingFiles": [] },
|
|
45
|
+
{ "name": "setup-tmux", "type": "skill", "target": "both", "reason": "installs tmux per-OS (Rocky8 3.6a source-build, apt/brew, Windows psmux); OMC team/worktree + OMX $team/HUD require it", "supportingFiles": [] },
|
|
46
|
+
{ "name": "setup-pwsh", "type": "skill", "target": "both", "reason": "Windows PowerShell 7 env (Terminal/Git/$PROFILE UTF-8); Claude CLAUDE_CODE_GIT_BASH_PATH, Codex native shell; no-op off-Windows", "supportingFiles": [] },
|
|
47
|
+
{ "name": "setup-mcp", "type": "skill", "target": "both", "reason": "installs common standalone MCP servers (context7/seq-thinking/filesystem/git/fetch); Claude `claude mcp add`, Codex config.toml [mcp_servers.*]; needs setup-node/python", "supportingFiles": [] },
|
|
48
|
+
{ "name": "setup-sandbox", "type": "skill", "target": "both", "reason": "agent sandbox per-OS (bubblewrap+userns / AppContainer / Seatbelt) + rust/cargo + git safe.directory; Codex sandbox_mode", "supportingFiles": [] },
|
|
49
|
+
{ "name": "harness-factory", "type": "skill", "target": "both", "reason": "installs+configures+guides the revfactory/harness team-architecture factory plugin (Claude harness@harness-marketplace, Codex SaehwanPark/meta-harness); Apache-2.0 referenced not redistributed", "supportingFiles": [] },
|
|
50
|
+
|
|
51
|
+
{ "name": "obsidizer", "type": "skill", "target": "both", "reason": "AI-wiki -> Obsidian graph normalize/interlink; LLM semantic edits + zero-input deterministic canonicalizer, runtime-agnostic; in-place durable", "supportingFiles": ["obsidize.mjs"], "caveat": "OMC-managed trees: 9-field frontmatter envelope + reserved files + no-rename + bare [[slug]] links only (extractWikiLinks slugifies piped/heading forms -> broken-ref); aliases written in generic vaults only; Canvas sidecars and body-inline :: are durable in-place; uses wiki_lint read-only. --enable is Claude-only (Codex has no MCP tool hooks) and is an honest no-op on Codex." },
|
|
52
|
+
|
|
41
53
|
{ "name": "front-qa", "type": "command", "target": "both", "reason": "ralplan->ralph frontend-QA pipeline; Claude=OMC, Codex=OMX", "supportingFiles": [] },
|
|
42
54
|
{ "name": "setup", "type": "command", "target": "both", "reason": "installer orchestrator; Claude AskUserQuestion multi-select, Codex prompt-based selection", "supportingFiles": [] }
|
|
43
55
|
]
|
|
@@ -39,3 +39,4 @@ The generator (`banker setup --codex`) applies the rules below for `target: both
|
|
|
39
39
|
- `ralph-qa` — needs a *different* LLM provider auth (`omc ask codex` / OMX `$ask`); falls back to same-runtime `critic` if unavailable.
|
|
40
40
|
- `deep-research` — needs web search/fetch (Claude WebSearch/WebFetch or bundled workflow; Codex OMX autoresearch).
|
|
41
41
|
- `smart-compact` — Claude statusLine exposes context%; Codex signal unconfirmed → heuristic fallback; `/copy`·`/compact`·paste stay user-driven (TUI).
|
|
42
|
+
- `obsidizer` — OMC-managed trees respect the 9-field frontmatter whitelist + reserved files + no-rename + bare `[[slug]]` links only; `aliases` are written in generic vaults only; Canvas sidecars and body-inline `::` are durable in-place; no `wiki_*` write dependency, `wiki_lint` read-only for verification. `--enable` is Claude-only (plugin-declared PostToolUse hook); Codex has no MCP tool hooks → honest no-op.
|
package/commands/setup.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: "(banker) 구성요소·의존성을 multi-select로 골라 설치하는 오케스트레이터(
|
|
2
|
+
description: "(banker) 구성요소·의존성을 multi-select로 골라 설치하는 오케스트레이터(런타임 node·python·java, LSP, tmux, MCP, sandbox, OMC, harness-factory, playwright 등)."
|
|
3
3
|
argument-hint: "[설치할 컴포넌트명 — 비우면 multi-select 표시]"
|
|
4
4
|
---
|
|
5
5
|
|
|
@@ -11,22 +11,34 @@ banker 플러그인이 제공하는 설치 스킬들을 **multi-select**로 골
|
|
|
11
11
|
## 절차
|
|
12
12
|
|
|
13
13
|
1. **선택 받기**: `$ARGUMENTS` 에 컴포넌트명이 명시돼 있으면 그것만 실행(질문 생략).
|
|
14
|
-
비어 있으면
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
- **setup-
|
|
18
|
-
- **setup-
|
|
14
|
+
비어 있으면 아래를 `AskUserQuestion`(**multiSelect: true**)으로 제시한다(**Codex 런타임엔 AskUserQuestion 이 없으므로 목록을 제시하고 설치할 항목을 사용자에게 물어 받는다**). 항목은 **계층/의존 순서**로 묶여 있으니, 뒤 계층을 고르면 앞 계층 전제를 먼저 채운다:
|
|
15
|
+
|
|
16
|
+
**런타임 (기반 — 먼저)**
|
|
17
|
+
- **setup-node** — nvm + Node 22(winget/nvm-windows). npx 기반 MCP·CLI 전제.
|
|
18
|
+
- **setup-python** — Python 3.11 + pipx + uv(PEP668). `setup-lsp`·`setup-mcp`·`docs-setup` 전제.
|
|
19
|
+
- **setup-java** — JDK 21 + JAVA_HOME(Debian=Adoptium). `setup-lsp` 의 jdtls 요구.
|
|
20
|
+
|
|
21
|
+
**개발도구**
|
|
22
|
+
- **setup-lsp** — 언어별 LSP(vtsls·basedpyright·bash·jdtls·spring) + lsp-mcp 브리지. (의존: node·python·java)
|
|
23
|
+
- **setup-tmux** — tmux(Rocky8 3.6a 소스빌드)/psmux(Windows). OMC team·OMX `$team`/HUD 전제.
|
|
24
|
+
- **setup-pwsh** — Windows PowerShell 7 환경($PROFILE UTF-8·Terminal·Git). 비-Windows는 no-op.
|
|
25
|
+
- **setup-mcp** — 공통 MCP 서버(context7·seq-thinking·filesystem·git·fetch). (의존: node·python)
|
|
26
|
+
- **setup-sandbox** — OS별 샌드박스(bubblewrap+userns / AppContainer / Seatbelt) + rust + git safe.directory.
|
|
27
|
+
|
|
28
|
+
**프레임워크·플러그인**
|
|
29
|
+
- **setup-omc** — oh-my-claudecode(OMC) 설치/갱신(Codex는 OMX). `all-in-one`·`ultra-init`·`/banker:front-qa` 의존성.
|
|
30
|
+
- **harness-factory** — revfactory/harness(팀 아키텍처 팩토리) 설치+구성+안내(Codex=meta-harness).
|
|
31
|
+
- **setup-insane-search** — insane-search 플러그인(차단 사이트 우회, Claude/Codex 양쪽).
|
|
32
|
+
- **setup-omc-hud** — omc_hud 상태표시줄(OS별).
|
|
19
33
|
- **setup-stitch** — Stitch(디자인 생성) MCP 프록시 등록(RockyLinux8 proxy-script, API key 필요).
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
- setup-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
- setup-
|
|
27
|
-
-
|
|
28
|
-
- docs-setup → `Skill("banker:docs-setup")`
|
|
29
|
-
각 스킬이 OS를 감지해 알맞은 절차로 설치하고 끝에 검증한다. 한 항목이 실패해도 정직히 보고하고 다음 항목 진행.
|
|
34
|
+
|
|
35
|
+
**의존성 라이브러리**
|
|
36
|
+
- **setup-playwright** — Playwright + 브라우저 + Xvfb(RHEL8/Rocky8 폴백). (`ultra-ui-qa`·`audit-web-page`·`play-qa` 의존성)
|
|
37
|
+
- **docs-setup** — arch-diagram·pdf-vision-extract 의존성(python-pptx·pymupdf·plantuml). (의존: python)
|
|
38
|
+
|
|
39
|
+
2. **실행**: 선택된 각 항목을 호출한다(미선택은 건드리지 않음). Claude Code는 `Skill("banker:<name>")`, **Codex 런타임에선 설치된 `banker-<name>` 스킬을 적용**한다(예: `Skill("banker:setup-node")`).
|
|
40
|
+
- **의존 순서 강제**: 뒤 계층을 고르면 전제 스킬을 먼저 실행한다 — `setup-lsp` 전에 setup-node·setup-python·setup-java; `setup-mcp` 전에 setup-node·setup-python; `docs-setup` 전에 setup-python. 이미 설치돼 있으면 각 스킬이 감지해 skip(멱등).
|
|
41
|
+
- 각 스킬이 OS를 감지해 알맞은 절차로 설치하고 끝에 검증한다. 한 항목이 실패해도 정직히 보고하고 다음 항목 진행.
|
|
30
42
|
|
|
31
43
|
3. **마무리 보고(한글)**: 설치된 항목·검증 결과·**재시작/reload 필요 여부**.
|
|
32
44
|
- 플러그인 설치(insane-search)는 `/reload-plugins`(Claude) 또는 재시작 후 반영(Codex는 재시작).
|
package/hooks/hooks.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "banker obsidizer: canonicalize an OMC wiki page right after it is written, but only when the vault is armed via `obsidizer --enable`. Inert otherwise.",
|
|
3
|
+
"hooks": {
|
|
4
|
+
"PostToolUse": [
|
|
5
|
+
{
|
|
6
|
+
"matcher": "^mcp__.*wiki_(ingest|add)$",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"command": "node \"$CLAUDE_PLUGIN_ROOT\"/hooks/run.cjs \"$CLAUDE_PLUGIN_ROOT\"/hooks/obsidize-hook.mjs",
|
|
11
|
+
"timeout": 5
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/*
|
|
3
|
+
* banker obsidizer PostToolUse hook — thin gate + dispatcher.
|
|
4
|
+
*
|
|
5
|
+
* Fires after an OMC wiki write (the matcher lives in hooks.json) and canonicalizes only
|
|
6
|
+
* the page(s) that write touched, by delegating to skills/obsidizer/obsidize.mjs. There is
|
|
7
|
+
* exactly one canonicalizer: no frontmatter/link/tag logic belongs in this file, and the
|
|
8
|
+
* armed hook and a bare `obsidizer` run therefore apply a byte-identical ruleset.
|
|
9
|
+
*
|
|
10
|
+
* Invariants (each is enforced by a test in obsidize-hook.test.mjs):
|
|
11
|
+
* - Pure filesystem. It never calls back into an MCP tool — this hook fires ON wiki
|
|
12
|
+
* writes, so issuing one would re-enter and loop. No tool identifier appears below.
|
|
13
|
+
* - Armed by <wikiDir>/.obsidizer. Absent => exit 0 having changed nothing, logged nothing.
|
|
14
|
+
* - Atomicity and read-back CAS live inside the canonicalizer, so both entry points
|
|
15
|
+
* inherit them. This file must not defeat them: it never pre-processes a page and
|
|
16
|
+
* never writes one itself.
|
|
17
|
+
* - Exits 0 on every path. A hook cannot block or alter a tool result and must not try.
|
|
18
|
+
* - Every error appends exactly one line to <wikiDir>/.obsidizer-hook.log. Exit 0 hides
|
|
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.
|
|
21
|
+
*/
|
|
22
|
+
import { spawnSync } from 'node:child_process';
|
|
23
|
+
import { appendFileSync, existsSync, readdirSync, statSync } from 'node:fs';
|
|
24
|
+
import { basename, dirname, join, resolve } from 'node:path';
|
|
25
|
+
import { fileURLToPath } from 'node:url';
|
|
26
|
+
|
|
27
|
+
const CANONICALIZER = resolve(dirname(fileURLToPath(import.meta.url)), '..', 'skills', 'obsidizer', 'obsidize.mjs');
|
|
28
|
+
const FLAG = '.obsidizer';
|
|
29
|
+
const LOG = '.obsidizer-hook.log';
|
|
30
|
+
// OMC owns these three. index.md is rewritten on every ingest, so it is always the freshest
|
|
31
|
+
// file in the vault — the scan fallback below would target it first without this guard.
|
|
32
|
+
const RESERVED = new Set(['index.md', 'log.md', 'environment.md']);
|
|
33
|
+
// Scan fallback: how recently a page must have changed to count as "this write touched it".
|
|
34
|
+
const RECENT_MS = 10_000;
|
|
35
|
+
// Stay inside the `timeout: 5` declared in hooks.json.
|
|
36
|
+
const CANONICALIZE_TIMEOUT_MS = 4000;
|
|
37
|
+
|
|
38
|
+
function readStdin() {
|
|
39
|
+
return new Promise((resolvePromise, rejectPromise) => {
|
|
40
|
+
let data = '';
|
|
41
|
+
process.stdin.setEncoding('utf8');
|
|
42
|
+
process.stdin.on('data', (chunk) => { data += chunk; });
|
|
43
|
+
process.stdin.on('end', () => resolvePromise(data));
|
|
44
|
+
process.stdin.on('error', rejectPromise);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function log(wikiDir, tool, reason) {
|
|
49
|
+
const line = `${new Date().toISOString()}\t${tool}\t${String(reason).replace(/\s+/g, ' ').trim()}\n`;
|
|
50
|
+
try {
|
|
51
|
+
appendFileSync(join(wikiDir, LOG), line);
|
|
52
|
+
} catch {
|
|
53
|
+
// The log is best-effort; the failure path must never throw.
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function isDir(path) {
|
|
58
|
+
try { return statSync(path).isDirectory(); } catch { return false; }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function wikiDirCandidates(root) {
|
|
62
|
+
const dirs = [];
|
|
63
|
+
// OMC relocates state to <OMC_STATE_DIR>/<projectId>/wiki. projectId is an OMC internal
|
|
64
|
+
// we must not reimplement, so enumerate the candidates instead of deriving the name.
|
|
65
|
+
const stateDir = process.env.OMC_STATE_DIR;
|
|
66
|
+
if (stateDir) {
|
|
67
|
+
try {
|
|
68
|
+
for (const entry of readdirSync(stateDir)) dirs.push(join(stateDir, entry, 'wiki'));
|
|
69
|
+
} catch {
|
|
70
|
+
// Unreadable OMC_STATE_DIR — fall through to the default layout.
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (root) dirs.push(join(root, '.omc', 'wiki'));
|
|
74
|
+
return dirs;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// The flag both arms the hook and identifies which vault it may touch.
|
|
78
|
+
function findArmedWikiDir(root) {
|
|
79
|
+
return wikiDirCandidates(root).find((dir) => isDir(dir) && existsSync(join(dir, FLAG))) ?? null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function namesFromResponse(toolResponse) {
|
|
83
|
+
// The payload carries no file path; the tool's own response text names the slugs it wrote
|
|
84
|
+
// ("- Created: a.md" / "Path: .omc/wiki/a.md"). Stringify first — the response arrives as
|
|
85
|
+
// text or as a structured content array depending on how the server is wired.
|
|
86
|
+
const text = typeof toolResponse === 'string' ? toolResponse : JSON.stringify(toolResponse ?? '');
|
|
87
|
+
return [...new Set([...text.matchAll(/[\w.-]+\.md/g)].map((match) => match[0]))];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function namesFromScan(wikiDir) {
|
|
91
|
+
const cutoff = Date.now() - RECENT_MS;
|
|
92
|
+
return readdirSync(wikiDir).filter((file) => {
|
|
93
|
+
if (!file.endsWith('.md')) return false;
|
|
94
|
+
try { return statSync(join(wikiDir, file)).mtimeMs >= cutoff; } catch { return false; }
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function resolvePages(wikiDir, toolResponse) {
|
|
99
|
+
const names = namesFromResponse(toolResponse);
|
|
100
|
+
return (names.length > 0 ? names : namesFromScan(wikiDir))
|
|
101
|
+
.filter((name) => !RESERVED.has(name))
|
|
102
|
+
.map((name) => join(wikiDir, name))
|
|
103
|
+
.filter((path) => existsSync(path));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function main() {
|
|
107
|
+
let payload = null;
|
|
108
|
+
let stdinError = null;
|
|
109
|
+
try {
|
|
110
|
+
payload = JSON.parse(await readStdin());
|
|
111
|
+
} catch (err) {
|
|
112
|
+
stdinError = err;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// A write can be redirected with workingDirectory; fall back to the session cwd.
|
|
116
|
+
const root = payload?.tool_input?.workingDirectory || payload?.cwd || process.cwd();
|
|
117
|
+
const wikiDir = findArmedWikiDir(root);
|
|
118
|
+
if (!wikiDir) return; // Not armed: change nothing, log nothing.
|
|
119
|
+
|
|
120
|
+
const tool = payload?.tool_name ?? 'unknown';
|
|
121
|
+
try {
|
|
122
|
+
if (stdinError) return log(wikiDir, tool, `unreadable hook payload: ${stdinError.message}`);
|
|
123
|
+
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
|
+
}
|
|
143
|
+
} catch (err) {
|
|
144
|
+
log(wikiDir, tool, `unexpected: ${err.message}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
main()
|
|
149
|
+
.catch(() => {}) // An un-canonicalized page is not-yet-formatted; the next bare run repairs it.
|
|
150
|
+
.finally(() => process.exit(0));
|
package/hooks/run.cjs
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
/*
|
|
4
|
+
* banker cross-platform hook runner.
|
|
5
|
+
*
|
|
6
|
+
* Re-spawns the target hook script with process.execPath — the Node binary already
|
|
7
|
+
* running this file — instead of letting the hook's shell resolve `node` from PATH.
|
|
8
|
+
* nvm/fnm shims and Windows both fail that resolution; OMC hit it in hooks (#909,
|
|
9
|
+
* #899, #892, #869) and answers it with the same pattern.
|
|
10
|
+
*
|
|
11
|
+
* Never blocks a tool: exits 0 whenever it cannot run the target.
|
|
12
|
+
*
|
|
13
|
+
* Usage (hooks.json):
|
|
14
|
+
* node "$CLAUDE_PLUGIN_ROOT"/hooks/run.cjs "$CLAUDE_PLUGIN_ROOT"/hooks/<hook>.mjs [args...]
|
|
15
|
+
*/
|
|
16
|
+
const { spawnSync } = require('child_process');
|
|
17
|
+
const { existsSync, realpathSync } = require('fs');
|
|
18
|
+
|
|
19
|
+
const target = process.argv[2];
|
|
20
|
+
if (!target) process.exit(0);
|
|
21
|
+
|
|
22
|
+
function resolveTarget(scriptPath) {
|
|
23
|
+
if (existsSync(scriptPath)) return scriptPath;
|
|
24
|
+
try {
|
|
25
|
+
// A plugin update can leave CLAUDE_PLUGIN_ROOT pointing at a version dir that is now
|
|
26
|
+
// a symlink; realpath follows it.
|
|
27
|
+
const real = realpathSync(scriptPath);
|
|
28
|
+
if (existsSync(real)) return real;
|
|
29
|
+
} catch {
|
|
30
|
+
// realpathSync throws when the path is gone entirely — expected, fall through.
|
|
31
|
+
}
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const resolved = resolveTarget(target);
|
|
36
|
+
if (!resolved) process.exit(0);
|
|
37
|
+
|
|
38
|
+
// stdio: 'inherit' hands our stdin to the child — that is how the hook payload reaches it.
|
|
39
|
+
const result = spawnSync(process.execPath, [resolved, ...process.argv.slice(3)], {
|
|
40
|
+
stdio: 'inherit',
|
|
41
|
+
env: process.env,
|
|
42
|
+
windowsHide: true,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
process.exit(result.status ?? 0);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kaydash9999/banker-plugins",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
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"
|
|
@@ -16,7 +16,9 @@
|
|
|
16
16
|
"commands",
|
|
17
17
|
".claude-plugin",
|
|
18
18
|
"codex",
|
|
19
|
+
"hooks",
|
|
19
20
|
"bin",
|
|
21
|
+
"!**/*.test.mjs",
|
|
20
22
|
"LICENSE",
|
|
21
23
|
"README.md",
|
|
22
24
|
"CHANGELOG.md"
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: harness-factory
|
|
3
|
+
description: "(banker) revfactory/harness(팀 아키텍처 팩토리) 플러그인 설치·구성·사용안내. Claude=harness@harness-marketplace, Codex=meta-harness. 'harness-factory'/'하네스 팩토리'/'에이전트팀 생성' 또는 /banker:setup 시 사용."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# harness-factory: revfactory/harness 팀 아키텍처 팩토리 설치·구성
|
|
7
|
+
|
|
8
|
+
`harness`는 도메인을 한 줄로 받아 `.claude/agents/`+`.claude/skills/`(전문 에이전트팀 + 그 에이전트가 쓸
|
|
9
|
+
스킬)를 생성하는 **메타 스킬**이다. 이 플러그인의 본체는 설치물이 아니라 **방법론**이다. 따라서 이
|
|
10
|
+
스킬은 설치에서 그치지 않고 구성(experimental flag 영속화)과 사용 안내(모드·패턴·비용 가드)까지
|
|
11
|
+
책임진다. 이미 설치돼 있으면 갱신·재확인만 한다(멱등). 답변은 한글.
|
|
12
|
+
|
|
13
|
+
## 런타임 배선
|
|
14
|
+
- **Claude Code** = `revfactory/harness` 플러그인(마켓플레이스 설치, 네이티브 팀 프리미티브 사용).
|
|
15
|
+
- **Codex** = `SaehwanPark/meta-harness`(별개 레포·Python 인스톨러·파일 handoff). Codex엔 네이티브 팀
|
|
16
|
+
프리미티브가 없어 파일 기반 순차 handoff로 우회한다(banker의 OMX 패턴과 동일 원리).
|
|
17
|
+
|
|
18
|
+
## 0. 감지 (먼저, 추정 금지)
|
|
19
|
+
```bash
|
|
20
|
+
command -v claude >/dev/null && claude --version || echo "claude: 미설치"
|
|
21
|
+
ls -la .claude/agents .claude/skills 2>/dev/null # 기존 harness 산출물 흔적 감사
|
|
22
|
+
```
|
|
23
|
+
- **v2.1.178 경계 주의**: 그 이후 버전은 `TeamCreate`/`TeamDelete` 도구가 제거되고 팀이 세션 시작 시
|
|
24
|
+
자동 구성된다. harness SKILL.md·OMC 문서의 `TeamCreate` 호출 예시가 현행 CLI와 어긋날 수 있다.
|
|
25
|
+
버전을 확인하고 **불일치 가능성을 사용자에게 정직히 고지**한다(가짜 확신 금지).
|
|
26
|
+
- 기존 `.claude/agents/`·`.claude/skills/`·`CLAUDE.md`에 harness 흔적이 있으면 신규 생성이 아니라
|
|
27
|
+
확장·유지보수로 다룬다(harness 자신의 Phase 0 감사 원칙).
|
|
28
|
+
|
|
29
|
+
## 1. 설치
|
|
30
|
+
### Claude Code
|
|
31
|
+
세션 안(슬래시 커맨드):
|
|
32
|
+
```
|
|
33
|
+
/plugin marketplace add revfactory/harness
|
|
34
|
+
/plugin install harness@harness-marketplace
|
|
35
|
+
/reload-plugins
|
|
36
|
+
```
|
|
37
|
+
- **정답 슬러그는 `harness@harness-marketplace` 하나뿐이다.** 하드코딩한다. 저장소 문서가 3-way로
|
|
38
|
+
어긋나 있으니(KO/JA README=`harness-marketplace`[`harness@` 접두 누락], quickstart=`harness@harness`
|
|
39
|
+
[마켓플레이스 접미 오류]) 그대로 복붙하지 말 것.
|
|
40
|
+
- 설치 전 `claude plugin marketplace list`로 등록명을 재확인한다.
|
|
41
|
+
- 대안(마켓플레이스 없이 글로벌 스킬 직접 설치): `cp -r skills/harness ~/.claude/skills/harness`.
|
|
42
|
+
|
|
43
|
+
### Codex CLI
|
|
44
|
+
마켓플레이스 개념이 없고 Python 인스톨러를 쓴다:
|
|
45
|
+
```bash
|
|
46
|
+
git clone https://github.com/SaehwanPark/meta-harness
|
|
47
|
+
cd meta-harness
|
|
48
|
+
python3 scripts/install_harness.py --scope user --layout codex
|
|
49
|
+
# 프로젝트 범위: python3 scripts/install_harness.py --scope project --target <repo> --layout codex
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## 2. 구성 (핵심)
|
|
53
|
+
팀 프리미티브는 **experimental flag로 게이트**된다. 셸 세션이 아니라 `settings.json`에 영속화한다:
|
|
54
|
+
```json
|
|
55
|
+
{ "env": { "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1" } }
|
|
56
|
+
```
|
|
57
|
+
- 셸 `export`는 **그 셸에서 띄운 claude에만** 적용되어 재시작 후 유실된다. 반드시 `settings.json`
|
|
58
|
+
`env`에 기록해야 영속한다.
|
|
59
|
+
- 미설정 시 **에러 없이 조용히 단일 에이전트로 폴백**되어 Pipeline/Fan-out-in/Supervisor/Hierarchical
|
|
60
|
+
패턴이 소리 없이 깨진다(harness 관리자가 `docs/experimental-dependency.md`에 공식 인정). Claude Code
|
|
61
|
+
v2.x+ 필요.
|
|
62
|
+
|
|
63
|
+
## 3. 사용 안내 (요약; 심층은 설치된 플러그인 references/ 위임)
|
|
64
|
+
> harness 자신이 6종 references/(패턴 카탈로그·오케스트레이터 템플릿·팀 예시·skill writing/testing·QA)로
|
|
65
|
+
> Progressive Disclosure한다. 여기서는 요약만 담고, 깊이는 설치된 플러그인의 references/를 읽게 위임한다
|
|
66
|
+
> (상류 문서를 verbatim 복사하지 않는다).
|
|
67
|
+
|
|
68
|
+
**(a) 모드 결정트리** (team / subagent / hybrid):
|
|
69
|
+
- 2+ 에이전트 + 실시간 상호통신(교차검증·발견 공유)이 가치를 더하면 → **team**.
|
|
70
|
+
- 단일 작업·독립 병렬·결과만 반환이면 → **subagent**(경량·토큰효율).
|
|
71
|
+
- 공식 비용지침: **순차·동일 파일 편집·의존성 많은 작업은 subagent/단일세션이 유리**하다. harness의
|
|
72
|
+
"2+면 팀 기본"과 어긋날 수 있으니, 팀이 정말 필요한지 재확인하는 게이트를 둔다.
|
|
73
|
+
|
|
74
|
+
**(b) 6개 아키텍처 패턴**(1줄):
|
|
75
|
+
- **Pipeline** (순차 의존): n 출력이 n+1 입력.
|
|
76
|
+
- **Fan-out/Fan-in** (병렬+집계): 팀모드가 가장 자연스럽다.
|
|
77
|
+
- **Expert Pool** (라우팅 택1): 라우터가 입력 분류 후 전문가 하나 호출, subagent 적합.
|
|
78
|
+
- **Producer-Reviewer** (생성·검증): 재시도 캡 2-3(무한루프 방지).
|
|
79
|
+
- **Supervisor** (동적 분배): 중앙이 런타임 조건으로 워커 배정.
|
|
80
|
+
- **Hierarchical** (재귀 위임): 깊이 ≤ 2(3+는 지연·컨텍스트 손실).
|
|
81
|
+
|
|
82
|
+
**(c) 비용 가드**: 팀 실행은 단일세션 대비 **약 7× 토큰**(공식). 그러므로:
|
|
83
|
+
- 팀 규모 **3-5명**(집중된 3명 > 분산된 5명).
|
|
84
|
+
- 워커 모델은 **Sonnet** 기본.
|
|
85
|
+
- 작업 완료 즉시 종료. spawn 프롬프트는 간결하게.
|
|
86
|
+
|
|
87
|
+
## 4. 리스크 고지
|
|
88
|
+
harness는 실험적 팀 API에 의존한다. `docs/experimental-dependency.md`가 3시나리오를 자체 정의한다:
|
|
89
|
+
- **A** 플래그 제거(GA 승격) / **B** Managed Agents 서버사이드 실행으로 대체 / **C** 하위호환 없는
|
|
90
|
+
시그니처 변경.
|
|
91
|
+
- **C는 v2.1.178에서 사실상 현실화된 정황이다**(`TeamCreate`/`TeamDelete` 제거). 설치 시 "실험적 기능
|
|
92
|
+
의존"이라는 사실을 반드시 드러낸다.
|
|
93
|
+
- **부작용(read-only 아님)**: 실행 시 사용자 프로젝트에 파일을 직접 생성한다(`.claude/agents/`·
|
|
94
|
+
`.claude/skills/`·중간산출물 `_workspace/`). 기존 파일 충돌 처리·CLAUDE.md 포인터 등록을 안내한다.
|
|
95
|
+
|
|
96
|
+
## 검증 (보고 의무)
|
|
97
|
+
1. **산출물**: `ls -la .claude/agents .claude/skills` 로 에이전트/스킬 파일이 실제 생성됐는지.
|
|
98
|
+
2. **flag 영속**: `settings.json`에 `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`이 기록됐는지.
|
|
99
|
+
3. **팀 스폰**: 간단한 샘플 태스크로 **팀이 실제로 스폰되는지**(무증상 단일 에이전트 폴백이 아닌지).
|
|
100
|
+
4. **Codex**: meta-harness 산출물(스킬·`_workspace/` handoff)이 생성됐는지.
|
|
101
|
+
|
|
102
|
+
보고는 4필드로 한다: **감지(버전·기존흔적) · 설치(플러그인 or meta-harness) · 구성(flag 영속) ·
|
|
103
|
+
검증(산출물·팀스폰)**. 실패·불명확은 정직 보고(가짜 성공 금지).
|
|
104
|
+
|
|
105
|
+
## 함정
|
|
106
|
+
- **3-way 설치명령 버그**: 유일 정답은 `harness@harness-marketplace`. KO/JA README·quickstart는 틀림.
|
|
107
|
+
- **무증상 폴백**: flag 없으면 팀 패턴이 조용히 단일 에이전트로 저하(에러 안 남).
|
|
108
|
+
- **비용 7×**: 팀은 고토큰. 규모·모델·종료 가드 없이 돌리지 말 것.
|
|
109
|
+
- **버전 drift**: v2.1.178에서 `TeamCreate`/`TeamDelete` 제거. 상류 문서의 팀 호출 예시가 현행과 어긋남.
|
|
110
|
+
- **릴리스/태그 0건**: GitHub Releases·Tags 모두 없음. 버전 근거는 오직 `plugin.json`의 `1.2.0`.
|
|
111
|
+
- **라이선스 Apache-2.0**: 연동·참조이지 banker 재배포가 아니다. 상류 references/를 verbatim 복사하지
|
|
112
|
+
않고 설치된 플러그인 자체를 가리킨다.
|
|
113
|
+
|
|
114
|
+
ARGUMENTS: `[--scope user|project]` (Codex meta-harness 설치 범위; 기본 user)
|