@su-record/vibe 3.2.31 → 3.2.33
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/plugin.json +22 -0
- package/.codex-plugin/plugin.json +1 -1
- package/CLAUDE.md +35 -1
- package/README.en.md +54 -0
- package/README.md +45 -14
- package/dist/cli/commands/plugin.d.ts.map +1 -1
- package/dist/cli/commands/plugin.js +77 -3
- package/dist/cli/commands/plugin.js.map +1 -1
- package/dist/cli/postinstall/claude-agents.d.ts +10 -0
- package/dist/cli/postinstall/claude-agents.d.ts.map +1 -1
- package/dist/cli/postinstall/claude-agents.js +20 -2
- package/dist/cli/postinstall/claude-agents.js.map +1 -1
- package/hooks/claude-plugin-hooks.json +123 -0
- package/hooks/plugin-hooks.json +13 -13
- package/hooks/scripts/plugin-hook-entry.js +57 -0
- package/package.json +7 -2
- package/vibe/rules/principles/dual-harness-doctrine.md +16 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vibe",
|
|
3
|
+
"displayName": "Vibe",
|
|
4
|
+
"version": "3.2.33",
|
|
5
|
+
"description": "Verification harness for AI coding agents — \"done\" is decided by deterministic gates (test exit codes, run-ledger, regression memory), not the model self-report.",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "su-record",
|
|
8
|
+
"url": "https://github.com/su-record"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/su-record/vibe",
|
|
11
|
+
"repository": "https://github.com/su-record/vibe",
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"keywords": [
|
|
14
|
+
"verification",
|
|
15
|
+
"spec",
|
|
16
|
+
"testing",
|
|
17
|
+
"code-review",
|
|
18
|
+
"loop",
|
|
19
|
+
"harness"
|
|
20
|
+
],
|
|
21
|
+
"hooks": "./hooks/claude-plugin-hooks.json"
|
|
22
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibe",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.33",
|
|
4
4
|
"description": "Verification harness for AI coding agents — \"done\" is decided by deterministic gates (test exit codes, run-ledger, regression memory), not the model self-report.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "su-record",
|
package/CLAUDE.md
CHANGED
|
@@ -53,6 +53,19 @@ Loop semantics SSOT: `vibe/rules/loop-contract.md` (ANCHOR→ACT→JUDGE→RECOR
|
|
|
53
53
|
- ESM only (`"type": "module"`) — imports need `.js` extension
|
|
54
54
|
- Build before test: `npm run build && npx vitest run`
|
|
55
55
|
|
|
56
|
+
### Release Gates (전부 exit 0 이어야 배포)
|
|
57
|
+
| 명령 | 막는 것 |
|
|
58
|
+
|---|---|
|
|
59
|
+
| `npm run build && npx vitest run` | 타입·동작 회귀 |
|
|
60
|
+
| `npm run gen:skill-docs:check` | SKILL-CATALOG.md 드리프트 |
|
|
61
|
+
| `npm run validate:counts` | README/package.json 개수 주장과 실제 불일치 |
|
|
62
|
+
| `npm run validate:skill-invocation` | 스킬 invocation 선언 오류 |
|
|
63
|
+
| `npm run sync:agent-models:check` | 에이전트 모델 섹션 드리프트 |
|
|
64
|
+
| `npm run gen:plugin-hooks:check` | 훅 정의 세 벌의 드리프트 |
|
|
65
|
+
| `npm run validate:plugin-tree` | 배포 트리와 소스 불일치 |
|
|
66
|
+
|
|
67
|
+
마지막 둘은 CI(`test.yml`)에서도 돈다. **배포 순서는 PR 병합 먼저, 태그는 그다음** — 태그를 먼저 밀면 보호 브랜치에 막혀 병합이 실패해도 CI 가 이미 npm 에 게시한다(실측 v3.2.19).
|
|
68
|
+
|
|
56
69
|
### Config Locations
|
|
57
70
|
| Path | Purpose |
|
|
58
71
|
|---|---|
|
|
@@ -61,6 +74,11 @@ Loop semantics SSOT: `vibe/rules/loop-contract.md` (ANCHOR→ACT→JUDGE→RECOR
|
|
|
61
74
|
| `.claude/settings.local.json` | Claude Code hooks (auto-generated, don't commit) |
|
|
62
75
|
| `.codex/hooks.json` | Codex native hooks (auto-generated, don't commit) |
|
|
63
76
|
| `~/.codex/config.toml` | Codex `notify` (turn-complete lifecycle hook, auto-installed) |
|
|
77
|
+
| `.claude-plugin/plugin.json` | Claude Code 플러그인 매니페스트 (버전은 package.json 이 SSOT) |
|
|
78
|
+
| `.claude-plugin/marketplace.json` | Claude Code 마켓플레이스 — `source: ./plugins/vibe` |
|
|
79
|
+
| `.codex-plugin/plugin.json` | Codex/ChatGPT 플러그인 매니페스트 |
|
|
80
|
+
| `.agents/plugins/marketplace.json` | Codex 마켓플레이스 — 같은 배포 트리를 가리킨다 |
|
|
81
|
+
| `plugins/vibe/` | **커밋되는** 배포 트리 (`npm run build:plugin`) — 아래 배포 3경로 참조 |
|
|
64
82
|
|
|
65
83
|
> ⚠️ 훅은 **프로젝트 로컬** 아티팩트다 — `vibe upgrade` 는 전역 자산만 갱신하므로 upgrade 만 쓰면 훅이 설치되지 않는다. `vibe upgrade` 가 현재 프로젝트의 누락 훅을 복구하고, `vibe status` 가 하네스별 설치 여부를 보고한다.
|
|
66
84
|
|
|
@@ -82,12 +100,28 @@ Legacy: 기존 `.claude/vibe/` 는 런타임에 자동 인식되며 `vibe init`/
|
|
|
82
100
|
### Dual-Harness Doctrine
|
|
83
101
|
하네스 차이는 경로가 아니라 **인지 방식**(CC=추론 / Codex=직역)에 있다. 원칙: **암묵적 동작에 의존하지 않는다 — 추론은 `/vibe` 디스패처가 앞단에서, skill 본문은 전부 명시적으로.** ("명시성 공통분모 + 추론 앞단"). Hook은 의도별 매핑: 라이프사이클(turn 완료) → Codex `config.toml notify`, 나머지(SessionStart·UserPromptSubmit·Pre/PostToolUse·Pre/PostCompact) → Codex 네이티브 hook(`.codex/hooks.json` + `codex-hook-adapter.js`). **`PostCompact` 는 압축 직후 `loop-ledger.js anchor` 로 재고정한다** — ANCHOR 가 컨텍스트 소실에 대비하는 장치인데 정작 압축 시점에 자동 실행이 없었다. AGENTS.md soft-hook 은 폐기하지 않고 **훅 미설치 환경의 2차 방어선**으로 유지(직역이라 신뢰성↑). 전문: `vibe/rules/principles/dual-harness-doctrine.md`.
|
|
84
102
|
|
|
103
|
+
### 배포 3경로 (npm · Claude Code 플러그인 · Codex 플러그인)
|
|
104
|
+
같은 자산을 세 경로로 내보낸다. **경로가 늘어난 만큼 정의도 갈라진다** — 갈라지면 한쪽 하네스에서만 게이트가 죽고, 그건 조용히 일어난다. 그래서 SSOT 를 하나로 묶고 생성·검증한다.
|
|
105
|
+
|
|
106
|
+
| 경로 | 설치 | 훅 정의 | 경로 변수 |
|
|
107
|
+
|---|---|---|---|
|
|
108
|
+
| npm | `npm i -g @su-record/vibe` | `hooks/hooks.json` (**SSOT**) | `{{VIBE_PATH}}` — postinstall 이 치환 |
|
|
109
|
+
| Claude Code | `claude plugin marketplace add su-record/vibe` | `hooks/claude-plugin-hooks.json` (생성물) | `${CLAUDE_PLUGIN_ROOT}` |
|
|
110
|
+
| Codex/ChatGPT | `vibe plugin install` → `codex plugin add vibe@vibe` | `hooks/plugin-hooks.json` (생성물) | `${PLUGIN_ROOT}` |
|
|
111
|
+
|
|
112
|
+
- **생성**: `npm run gen:plugin-hooks` — `--check` 가 CI 게이트. 손으로 고치지 않는다
|
|
113
|
+
- **이중 실행 가드**: 플러그인 훅은 `plugin-hook-entry.js` 를 거친다. 프로젝트에 **vibe 훅**이 있으면 플러그인 쪽이 물러난다 — 없으면 게이트가 2회, Stop auto-commit 도 2회 돈다. 판정은 "훅 키가 있다" 가 아니라 "vibe 훅이 있다" (사용자 자작 훅만 있는 프로젝트에서 침묵하면 설치한 의미가 없다). 실행은 spawn 이 아니라 in-process `import` — 위 훅 실행 모델 규약을 플러그인 경로에서도 지킨다
|
|
114
|
+
- **배포 트리를 커밋하는 이유**: Claude Code 마켓플레이스는 저장소를 **클론**해서 읽는다. `dist/` 는 gitignore 대상이고 `agents/*.md` 의 frontmatter 는 postinstall 이 만든다 — 저장소를 그대로 가리키면 기능이 빠진 플러그인이 된다(실측: 에이전트 11개 중 7개만, description 없이 로드). `plugins/vibe/` 를 커밋하고 드리프트는 `npm run validate:plugin-tree` 가 막는다. `.gitignore` 의 `dist/` 가 이 트리까지 삼키므로 `!/plugins/vibe/dist/` 예외가 필수다
|
|
115
|
+
|
|
85
116
|
### Gotchas
|
|
86
117
|
- `better-sqlite3` WAL mode — synchronous API
|
|
87
118
|
- `crypto.timingSafeEqual` requires same-length buffers — check length first
|
|
88
119
|
- **Stack → asset SSOT**: `GLOBAL_SKILLS_*`, `STACK_TO_SKILLS`, `CAPABILITY_SKILLS` in `src/cli/postinstall/constants.ts`
|
|
89
120
|
- **Hook dispatch order**: `prompt-dispatcher.js` → `llm-orchestrate.js` (매직 키워드 배너 훅 없음 — deprecated 별칭은 "Deprecated aliases" 표가 SSOT, 모델이 직접 해석)
|
|
90
121
|
- **Hook 실행 모델**: per-event process spawn 유지 — **daemon/IPC 지양** (무상태·크래시 격리·인프라 제로가 ~20ms VM 기동 절감보다 우선). 훅 레이턴시 최적화는 dispatcher in-process 평탄화(자식 spawn → `import` 실행)로만 접근한다
|
|
122
|
+
- **npm 12 `allowScripts`**: install 스크립트가 **기본 차단**된다. 설치는 ✅ 인데 vibe postinstall 도 `better-sqlite3` 네이티브 바인딩도 안 만들어진다 — 둘 다 자기복구(`runInstalledPostinstall`, `repairNativeDeps`)로 덮고 `vibe status` 가 보고한다. 근본 처방은 사용자 레벨 승인 하나뿐이다: `npm config set allow-scripts=@su-record/vibe,better-sqlite3 --location=user`. `npm install-scripts approve` 는 설치본 package.json 에 쓰므로 다음 설치에 지워진다(실측)
|
|
123
|
+
- **에이전트 frontmatter 는 따옴표 필수**: description 에 `: ` 가 들어가면 YAML 평문 스칼라가 매핑으로 해석돼 **frontmatter 전체가 버려진다** — 에러 없이. 실측으로 설치본 11개 중 4개가 그 상태였다 (`convertAgentToClaude` 의 `yamlString`)
|
|
124
|
+
- **Claude Code 는 `agents/*.md` 평면만 스캔**한다 — 하위 디렉토리 에이전트는 경고 없이 사라진다. 배포 트리는 평면화해서 굽는다
|
|
91
125
|
|
|
92
126
|
## Workflow
|
|
93
127
|
|
|
@@ -141,7 +175,7 @@ Public skills use the `vibe.*` namespace and are classified as **entry** / **sta
|
|
|
141
175
|
|
|
142
176
|
## Git
|
|
143
177
|
|
|
144
|
-
**Include**: `.vibe/{plans,specs,features,todos,research,regressions,contracts,recipes,anti-patterns,loops,config.json,constitution.md}`, `CLAUDE.md`
|
|
178
|
+
**Include**: `.vibe/{plans,specs,features,todos,research,regressions,contracts,recipes,anti-patterns,loops,config.json,constitution.md}`, `CLAUDE.md`, `plugins/vibe/` (배포 트리 — 생성물이지만 커밋한다, 위 "배포 3경로" 참조)
|
|
145
179
|
**Vibe-global (not project-local)**: `~/.vibe/test-reports/` — `/vibe.test` artifacts live with the vibe install, not with the project
|
|
146
180
|
**Exclude**: `~/.claude/{rules,commands,agents,skills}/`, `.claude/settings.local.json`, `.codex/hooks.json`, `.vibe/{memories,checkpoints,metrics,gates}/`
|
|
147
181
|
|
package/README.en.md
CHANGED
|
@@ -81,6 +81,52 @@ codex
|
|
|
81
81
|
/vibe "add user authentication"
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
+
> **On npm 12** — npm 12 blocks install scripts by default (`allowScripts`). Installation succeeds but the
|
|
85
|
+
> `better-sqlite3` native binding is never built, so memory/RAG die on every hook. `vibe upgrade` repairs it
|
|
86
|
+
> automatically; to prevent it at the source, approve once:
|
|
87
|
+
>
|
|
88
|
+
> ```bash
|
|
89
|
+
> npm config set allow-scripts=@su-record/vibe,better-sqlite3 --location=user
|
|
90
|
+
> ```
|
|
91
|
+
>
|
|
92
|
+
> Check with the `Native bindings` row in `vibe status`.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Install as a plugin (experimental)
|
|
97
|
+
|
|
98
|
+
An alternative to the npm install. The same distribution tree (`plugins/vibe`) ships to Claude Code, Codex, and ChatGPT.
|
|
99
|
+
|
|
100
|
+
**Claude Code — straight from the repo** (no npm needed)
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
claude plugin marketplace add su-record/vibe
|
|
104
|
+
claude plugin install vibe@vibe
|
|
105
|
+
claude plugin details vibe # Skills 52 · Agents 11 · Hooks 6
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**If you already installed via npm**
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
vibe plugin install # assemble the tree + register both marketplaces
|
|
112
|
+
vibe plugin status
|
|
113
|
+
|
|
114
|
+
claude plugin marketplace add ~/.vibe/plugin
|
|
115
|
+
claude plugin install vibe@vibe
|
|
116
|
+
|
|
117
|
+
codex plugin marketplace add ~
|
|
118
|
+
codex plugin add vibe@vibe
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
> **Double execution is prevented automatically.** If the npm install's project hooks are already present,
|
|
122
|
+
> the plugin hooks stand down (`plugin-hook-entry.js`). Otherwise every gate would run twice — and so would
|
|
123
|
+
> the auto-commit on Stop.
|
|
124
|
+
>
|
|
125
|
+
> **`plugins/vibe/` is a committed build artifact.** The Claude Code marketplace clones the repository, but
|
|
126
|
+
> `dist/` is gitignored and the frontmatter in `agents/*.md` is generated by postinstall — pointing at the
|
|
127
|
+
> repository itself yields a plugin with pieces missing (measured: only 7 of 11 agents loaded, and those
|
|
128
|
+
> without descriptions). CI's `validate:plugin-tree` blocks drift.
|
|
129
|
+
|
|
84
130
|
---
|
|
85
131
|
|
|
86
132
|
## Harness Engineering
|
|
@@ -237,6 +283,14 @@ Start with `/vibe` and it routes the rest. Below is the list for when you want t
|
|
|
237
283
|
| `/vibe.verify` | Verify implementation against SPEC Done criteria — result recorded in the run ledger |
|
|
238
284
|
| `/vibe.continue` | Session restore — pick up after `save_memory` → `/new` at 85%+ context |
|
|
239
285
|
|
|
286
|
+
**CLI**
|
|
287
|
+
|
|
288
|
+
| Command | Purpose |
|
|
289
|
+
|---------|---------|
|
|
290
|
+
| `vibe status` | Harness state — hooks per harness, native bindings, LLM auth |
|
|
291
|
+
| `vibe upgrade` | Upgrade + self-repair (global assets, project hooks, native bindings) |
|
|
292
|
+
| `vibe plugin install` | Assemble the plugin tree and register the marketplaces |
|
|
293
|
+
|
|
240
294
|
**Verification & quality**
|
|
241
295
|
|
|
242
296
|
| Command | Purpose |
|
package/README.md
CHANGED
|
@@ -197,39 +197,62 @@ codex
|
|
|
197
197
|
|
|
198
198
|
## 플러그인으로 설치 (실험적)
|
|
199
199
|
|
|
200
|
-
npm 전역
|
|
200
|
+
npm 전역 설치의 **대안** 경로다. Claude Code · Codex · ChatGPT 세 곳에 같은 배포 트리(`plugins/vibe`)가 올라간다.
|
|
201
201
|
|
|
202
|
-
**
|
|
202
|
+
**Claude Code — 저장소에서 바로** (npm 설치 불필요)
|
|
203
203
|
|
|
204
204
|
```bash
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
205
|
+
claude plugin marketplace add su-record/vibe
|
|
206
|
+
claude plugin install vibe@vibe
|
|
207
|
+
claude plugin details vibe # Skills 52 · Agents 11 · Hooks 6
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
**npm 으로 이미 설치한 경우**
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
vibe plugin install # 배포 트리 조립 + 마켓플레이스 두 벌 등록
|
|
214
|
+
vibe plugin status # 조립·등록 상태 확인
|
|
215
|
+
|
|
216
|
+
claude plugin marketplace add ~/.vibe/plugin
|
|
217
|
+
claude plugin install vibe@vibe
|
|
218
|
+
|
|
219
|
+
codex plugin marketplace add ~
|
|
220
|
+
codex plugin add vibe@vibe
|
|
210
221
|
```
|
|
211
222
|
|
|
212
223
|
**저장소를 클론한 경우** (개발·검증용)
|
|
213
224
|
|
|
214
225
|
```bash
|
|
215
|
-
npm run build:plugin
|
|
226
|
+
npm run build:plugin # plugins/vibe/ 로 조립 (package.json files 기준)
|
|
227
|
+
claude plugin validate plugins/vibe
|
|
216
228
|
codex plugin marketplace add .
|
|
217
229
|
codex plugin add vibe@vibe-local
|
|
218
230
|
```
|
|
219
231
|
|
|
232
|
+
> **훅 이중 실행은 자동으로 막힌다.** npm 설치본의 프로젝트 훅이 이미 있으면 플러그인 훅은
|
|
233
|
+
> 스스로 물러난다 (`plugin-hook-entry.js`). 그러지 않으면 같은 게이트가 2회 돌고
|
|
234
|
+
> Stop 의 auto-commit 도 2회 돈다.
|
|
235
|
+
>
|
|
236
|
+
> **`plugins/vibe/` 는 커밋되는 생성물이다.** Claude Code 마켓플레이스는 저장소를 클론해 읽는데
|
|
237
|
+
> `dist/` 는 gitignore 대상이고 `agents/*.md` 의 frontmatter 는 postinstall 이 만든다 —
|
|
238
|
+
> 즉 저장소를 그대로 가리키면 기능이 빠진 플러그인이 된다 (실측: 에이전트 11개 중 7개만,
|
|
239
|
+
> 그나마 description 없이 로드). 드리프트는 CI 의 `validate:plugin-tree` 가 막는다.
|
|
240
|
+
|
|
220
241
|
ChatGPT 데스크톱 앱에서는 앱을 **재시작**한 뒤 Plugins Directory 에서 "Vibe (local)" → `vibe` 를 설치한다.
|
|
221
242
|
|
|
222
243
|
> 마켓플레이스 파일만 만들어두면 잡히지 않는다 — `marketplace add` 로 **등록**해야 한다.
|
|
223
244
|
> `source.path` 는 저장소 루트가 아니라 빌드 산출물(`./plugins/vibe`)을 가리킨다.
|
|
224
245
|
> 루트를 가리키면 워킹트리가 통째로 캐시에 복사된다 (실측 655MB, 그중 620MB 가 `node_modules`).
|
|
225
246
|
|
|
226
|
-
| 번들 |
|
|
227
|
-
|
|
228
|
-
| skills (52) | ✅ | ✅ |
|
|
229
|
-
|
|
|
247
|
+
| 번들 | Claude Code | Codex CLI | ChatGPT 앱 |
|
|
248
|
+
|---|---|---|---|
|
|
249
|
+
| skills (52) | ✅ | ✅ | ✅ |
|
|
250
|
+
| agents (11) | ✅ | — | — |
|
|
251
|
+
| hooks (6 이벤트) | ✅ | ✅ (trust 승인 후) | **미확인** — 훅 문서가 Codex 아래에만 있다 |
|
|
230
252
|
|
|
231
|
-
> ⚠️ 훅은 설치·활성화만으로 신뢰되지 않는다 — Codex 가 정의를 검토·승인할 때까지 건너뛴다.
|
|
232
|
-
> `vibe init
|
|
253
|
+
> ⚠️ Codex 에서 훅은 설치·활성화만으로 신뢰되지 않는다 — Codex 가 정의를 검토·승인할 때까지 건너뛴다.
|
|
254
|
+
> `vibe init` 이 만드는 프로젝트 로컬 설정과 `vibe upgrade` 의 자기복구는 플러그인이 대체하지 못한다 —
|
|
255
|
+
> 그 둘이 필요하면 npm 설치를 함께 쓴다.
|
|
233
256
|
|
|
234
257
|
---
|
|
235
258
|
|
|
@@ -257,6 +280,14 @@ ChatGPT 데스크톱 앱에서는 앱을 **재시작**한 뒤 Plugins Directory
|
|
|
257
280
|
| `/vibe.verify` | 구현이 SPEC Done 기준에 맞는지 검증 — 결과는 run-ledger 에 기록 |
|
|
258
281
|
| `/vibe.continue` | 세션 복원 — 85%+ 컨텍스트에서 `save_memory` → `/new` 후 이어서 |
|
|
259
282
|
|
|
283
|
+
**CLI**
|
|
284
|
+
|
|
285
|
+
| 명령 | 용도 |
|
|
286
|
+
|---|---|
|
|
287
|
+
| `vibe status` | 하네스 상태 — 하네스별 훅, 네이티브 바인딩, LLM 인증 |
|
|
288
|
+
| `vibe upgrade` | 업그레이드 + 자기복구 (전역 자산 · 프로젝트 훅 · 네이티브 바인딩) |
|
|
289
|
+
| `vibe plugin install` | 플러그인 배포 트리 조립 + 마켓플레이스 등록 |
|
|
290
|
+
|
|
260
291
|
**검증 · 품질**
|
|
261
292
|
|
|
262
293
|
| 명령어 | 용도 |
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/plugin.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/plugin.ts"],"names":[],"mappings":"AAqKA,oCAAoC;AACpC,wBAAgB,aAAa,IAAI,IAAI,CA4CpC;AAGD,gCAAgC;AAChC,wBAAgB,YAAY,IAAI,IAAI,CAyBnC"}
|
|
@@ -14,9 +14,10 @@ import os from 'os';
|
|
|
14
14
|
import path from 'path';
|
|
15
15
|
import { log } from '../utils.js';
|
|
16
16
|
import { getCoreConfigDir } from '../setup/GlobalInstaller.js';
|
|
17
|
+
import { convertAgentToClaude } from '../postinstall/claude-agents.js';
|
|
17
18
|
/** 조립 대상 — package.json `files` 와 같은 목록을 쓴다 (배포 내용의 SSOT) */
|
|
18
19
|
const PLUGIN_ENTRIES = [
|
|
19
|
-
'.codex-plugin', 'dist', 'vibe', 'languages', 'agents', 'skills', 'hooks',
|
|
20
|
+
'.codex-plugin', '.claude-plugin', 'dist', 'vibe', 'languages', 'agents', 'skills', 'hooks',
|
|
20
21
|
'CLAUDE.md', 'README.md', 'LICENSE',
|
|
21
22
|
];
|
|
22
23
|
/** 조립본에 넣지 않는다 — 테스트와 의존성은 플러그인 런타임에 불필요하다 */
|
|
@@ -24,6 +25,10 @@ const SKIP = new Set(['node_modules', '__tests__']);
|
|
|
24
25
|
function pluginTreeDir() {
|
|
25
26
|
return path.join(getCoreConfigDir(), 'plugin', 'vibe');
|
|
26
27
|
}
|
|
28
|
+
/** Claude Code 마켓플레이스 — 플러그인 트리의 **부모**에 둔다 (source 가 `./vibe`) */
|
|
29
|
+
function claudeMarketplacePath() {
|
|
30
|
+
return path.join(pluginTreeDir(), '..', '.claude-plugin', 'marketplace.json');
|
|
31
|
+
}
|
|
27
32
|
function marketplacePath() {
|
|
28
33
|
return path.join(marketplaceRoot(), '.agents', 'plugins', 'marketplace.json');
|
|
29
34
|
}
|
|
@@ -85,6 +90,67 @@ function writeMarketplace(pluginDir) {
|
|
|
85
90
|
fs.writeFileSync(file, JSON.stringify(doc, null, 2) + '\n');
|
|
86
91
|
return file;
|
|
87
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Claude Code 마켓플레이스를 쓴다 — 스키마가 Codex 쪽과 다르다.
|
|
95
|
+
*
|
|
96
|
+
* `owner` 는 문자열이 아니라 객체여야 하고(`claude plugin validate` 가 거부한다),
|
|
97
|
+
* `source` 는 마켓플레이스 루트 기준 상대 경로 문자열이다.
|
|
98
|
+
*/
|
|
99
|
+
function writeClaudeMarketplace(pluginDir) {
|
|
100
|
+
const file = claudeMarketplacePath();
|
|
101
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
102
|
+
fs.writeFileSync(file, JSON.stringify({
|
|
103
|
+
$schema: 'https://anthropic.com/claude-code/marketplace.schema.json',
|
|
104
|
+
name: 'vibe',
|
|
105
|
+
description: 'Verification harness for AI coding agents — deterministic gates decide "done".',
|
|
106
|
+
owner: { name: 'su-record', url: 'https://github.com/su-record' },
|
|
107
|
+
plugins: [{
|
|
108
|
+
name: 'vibe',
|
|
109
|
+
displayName: 'Vibe',
|
|
110
|
+
description: 'Natural-language requirement to a SPEC you approve once, then an'
|
|
111
|
+
+ ' ANCHOR→ACT→JUDGE→RECORD loop until deterministic gates pass.',
|
|
112
|
+
author: { name: 'su-record' },
|
|
113
|
+
category: 'productivity',
|
|
114
|
+
homepage: 'https://github.com/su-record/vibe',
|
|
115
|
+
source: `./${path.basename(pluginDir)}`,
|
|
116
|
+
}],
|
|
117
|
+
}, null, 2) + '\n');
|
|
118
|
+
return file;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* 에이전트에 frontmatter 를 굽고 평면으로 다시 쓴다.
|
|
122
|
+
*
|
|
123
|
+
* 저장소·npm tarball 의 `agents/*.md` 에는 frontmatter 가 없다 — postinstall 이
|
|
124
|
+
* 설치 시점에 만든다. 플러그인은 그 단계를 거치지 않으므로 여기서 굽지 않으면
|
|
125
|
+
* description·model·tools 없이 로드된다. 평면화는 Claude Code 가 `agents/*.md` 만
|
|
126
|
+
* 스캔하기 때문이다(실측: 하위 디렉토리의 4개가 경고 없이 사라졌다).
|
|
127
|
+
*/
|
|
128
|
+
function bakeAgents(dir) {
|
|
129
|
+
if (!fs.existsSync(dir))
|
|
130
|
+
return;
|
|
131
|
+
const agents = [];
|
|
132
|
+
const walk = (current, rel) => {
|
|
133
|
+
for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
|
|
134
|
+
if (entry.isDirectory()) {
|
|
135
|
+
if (rel === '' && entry.name === 'teams')
|
|
136
|
+
continue;
|
|
137
|
+
walk(path.join(current, entry.name), rel ? `${rel}/${entry.name}` : entry.name);
|
|
138
|
+
}
|
|
139
|
+
else if (entry.name.endsWith('.md')) {
|
|
140
|
+
agents.push({
|
|
141
|
+
name: entry.name,
|
|
142
|
+
content: fs.readFileSync(path.join(current, entry.name), 'utf-8'),
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
walk(dir, '');
|
|
148
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
149
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
150
|
+
for (const { name, content } of agents) {
|
|
151
|
+
fs.writeFileSync(path.join(dir, name), convertAgentToClaude(content, name), 'utf-8');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
88
154
|
/** 플러그인 트리를 조립하고 개인 마켓플레이스에 등록한다 */
|
|
89
155
|
export function pluginInstall() {
|
|
90
156
|
const root = packageRoot();
|
|
@@ -105,19 +171,27 @@ export function pluginInstall() {
|
|
|
105
171
|
process.exitCode = 1;
|
|
106
172
|
return;
|
|
107
173
|
}
|
|
174
|
+
bakeAgents(path.join(out, 'agents'));
|
|
108
175
|
const file = writeMarketplace(out);
|
|
176
|
+
const claudeFile = writeClaudeMarketplace(out);
|
|
109
177
|
log(`
|
|
110
178
|
✅ vibe 플러그인 준비 완료
|
|
111
179
|
|
|
112
|
-
플러그인
|
|
180
|
+
플러그인 ${out}
|
|
113
181
|
마켓플레이스 ${file}
|
|
114
|
-
|
|
182
|
+
${claudeFile}
|
|
183
|
+
포함 ${copied.join(', ')}
|
|
115
184
|
|
|
116
185
|
다음 단계:
|
|
186
|
+
Claude Code claude plugin marketplace add ${path.dirname(path.dirname(claudeFile))}
|
|
187
|
+
claude plugin install vibe@vibe
|
|
117
188
|
Codex codex plugin marketplace add ${marketplaceRoot()}
|
|
118
189
|
codex plugin add vibe@vibe
|
|
119
190
|
(훅은 설치만으로 신뢰되지 않습니다 — Codex 가 정의를 검토·승인해야 실행됩니다)
|
|
120
191
|
ChatGPT 앱 앱을 재시작한 뒤 Plugins Directory 에서 Vibe 설치
|
|
192
|
+
|
|
193
|
+
⚠️ npm 설치본의 프로젝트 훅이 이미 있으면 플러그인 훅은 스스로 물러납니다
|
|
194
|
+
(같은 게이트가 두 번 도는 것을 막습니다).
|
|
121
195
|
`);
|
|
122
196
|
}
|
|
123
197
|
/** 조립 상태와 마켓플레이스 등록 여부를 보고한다 */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../src/cli/commands/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../src/cli/commands/plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,16 @@
|
|
|
4
4
|
* VIBE 에이전트 마크다운 파일을 Claude Code 네이티브 서브에이전트 형식
|
|
5
5
|
* (YAML frontmatter 포함)으로 변환하여 ~/.claude/agents/에 설치
|
|
6
6
|
*/
|
|
7
|
+
/**
|
|
8
|
+
* VIBE 에이전트를 Claude Code 네이티브 서브에이전트 형식으로 변환
|
|
9
|
+
*
|
|
10
|
+
* export 인 이유: 플러그인 배포 트리(`scripts/build-plugin.ts`)도 같은 변환을 써야
|
|
11
|
+
* 한다. 저장소의 `agents/*.md` 에는 frontmatter 가 없고 — 설치 시점에 여기서
|
|
12
|
+
* 생성된다 — 플러그인은 postinstall 을 거치지 않으므로 빌드 때 미리 굽지 않으면
|
|
13
|
+
* description·model·tools 없이 로드된다(실측: `claude plugin validate` 경고 11건).
|
|
14
|
+
* 변환 로직을 두 벌로 만들면 그 순간부터 갈라진다.
|
|
15
|
+
*/
|
|
16
|
+
export declare function convertAgentToClaude(content: string, filename: string): string;
|
|
7
17
|
export interface InstallClaudeAgentsOptions {
|
|
8
18
|
/** 최상위 디렉토리명 기준 제외 목록 (예: 조건부 그룹 'ui'/'figma'/'event') */
|
|
9
19
|
skipDirs?: ReadonlyArray<string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-agents.d.ts","sourceRoot":"","sources":["../../../src/cli/postinstall/claude-agents.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"claude-agents.d.ts","sourceRoot":"","sources":["../../../src/cli/postinstall/claude-agents.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAqDH;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CA4D9E;AAED,MAAM,WAAW,0BAA0B;IACzC,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACjC,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAClC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,YAAY,EAAE,MAAM,EACpB,eAAe,EAAE,MAAM,EACvB,OAAO,GAAE,0BAA+B,GACvC,IAAI,CAiEN"}
|
|
@@ -31,10 +31,28 @@ function generateDescription(name, title, roleLines) {
|
|
|
31
31
|
};
|
|
32
32
|
return descriptions[name] || `${title}. ${roleDesc}. Use proactively when relevant.`;
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* YAML 스칼라로 안전하게 감싼다.
|
|
36
|
+
*
|
|
37
|
+
* WHY: description 에 `: ` 가 들어가면 — `caller passes focus: correctness` 처럼
|
|
38
|
+
* 자연스럽게 생긴다 — 평문 스칼라가 매핑으로 해석돼 frontmatter 전체가 파싱에
|
|
39
|
+
* 실패한다. 그러면 name·model·tools·permissionMode 까지 **통째로 조용히 버려지고**
|
|
40
|
+
* 에이전트는 메타데이터 없이 로드된다. 실측: 설치본 11개 중 4개가 이 상태였고
|
|
41
|
+
* (`code-reviewer`·`e2e-tester`·`event-ops`·`security-reviewer`) 아무 경고도 없었다.
|
|
42
|
+
*/
|
|
43
|
+
function yamlString(value) {
|
|
44
|
+
return `"${value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
|
|
45
|
+
}
|
|
34
46
|
/**
|
|
35
47
|
* VIBE 에이전트를 Claude Code 네이티브 서브에이전트 형식으로 변환
|
|
48
|
+
*
|
|
49
|
+
* export 인 이유: 플러그인 배포 트리(`scripts/build-plugin.ts`)도 같은 변환을 써야
|
|
50
|
+
* 한다. 저장소의 `agents/*.md` 에는 frontmatter 가 없고 — 설치 시점에 여기서
|
|
51
|
+
* 생성된다 — 플러그인은 postinstall 을 거치지 않으므로 빌드 때 미리 굽지 않으면
|
|
52
|
+
* description·model·tools 없이 로드된다(실측: `claude plugin validate` 경고 11건).
|
|
53
|
+
* 변환 로직을 두 벌로 만들면 그 순간부터 갈라진다.
|
|
36
54
|
*/
|
|
37
|
-
function convertAgentToClaude(content, filename) {
|
|
55
|
+
export function convertAgentToClaude(content, filename) {
|
|
38
56
|
const normalizedContent = content.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
39
57
|
const name = path.basename(filename, '.md');
|
|
40
58
|
// 미등록 에이전트는 세션 모델을 상속한다 — 매핑 누락이 조용한 다운그레이드가
|
|
@@ -66,7 +84,7 @@ function convertAgentToClaude(content, filename) {
|
|
|
66
84
|
// YAML frontmatter 조립
|
|
67
85
|
let frontmatter = '---\n';
|
|
68
86
|
frontmatter += `name: ${name}\n`;
|
|
69
|
-
frontmatter += `description: ${description}\n`;
|
|
87
|
+
frontmatter += `description: ${yamlString(description)}\n`;
|
|
70
88
|
frontmatter += `model: ${model}\n`;
|
|
71
89
|
frontmatter += `tools: ${tools.join(', ')}\n`;
|
|
72
90
|
frontmatter += `permissionMode: ${permissionMode}\n`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-agents.js","sourceRoot":"","sources":["../../../src/cli/postinstall/claude-agents.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,0BAA0B,EAC1B,4BAA4B,EAC5B,6BAA6B,EAC7B,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AAExB;;GAEG;AACH,SAAS,mBAAmB,CAAC,IAAY,EAAE,KAAa,EAAE,SAAmB;IAC3E,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEtC,MAAM,YAAY,GAA2B;QAC3C,WAAW,EAAE,8CAA8C,QAAQ,kGAAkG;QACrK,aAAa,EAAE,mCAAmC,QAAQ,+DAA+D;QACzH,QAAQ,EAAE,gGAAgG,QAAQ,oFAAoF;QACtM,YAAY,EAAE,2CAA2C,QAAQ,+EAA+E;QAChJ,sBAAsB,EAAE,mCAAmC,QAAQ,mDAAmD;QACtH,iEAAiE;QACjE,eAAe,EAAE,8JAA8J,QAAQ,yEAAyE;QAChQ,mBAAmB,EAAE,yCAAyC,QAAQ,kKAAkK;QACxO,gCAAgC;QAChC,iBAAiB,EAAE,4GAA4G,QAAQ,gBAAgB;QACvJ,mBAAmB,EAAE,4BAA4B,QAAQ,+DAA+D;QACxH,mCAAmC;QACnC,eAAe,EAAE,uDAAuD,QAAQ,6CAA6C;QAC7H,WAAW,EAAE,wDAAwD,QAAQ,yCAAyC;KACvH,CAAC;IAEF,OAAO,YAAY,CAAC,IAAI,CAAC,IAAI,GAAG,KAAK,KAAK,QAAQ,kCAAkC,CAAC;AACvF,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"claude-agents.js","sourceRoot":"","sources":["../../../src/cli/postinstall/claude-agents.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAC9D,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,0BAA0B,EAC1B,4BAA4B,EAC5B,6BAA6B,EAC7B,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AAExB;;GAEG;AACH,SAAS,mBAAmB,CAAC,IAAY,EAAE,KAAa,EAAE,SAAmB;IAC3E,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEtC,MAAM,YAAY,GAA2B;QAC3C,WAAW,EAAE,8CAA8C,QAAQ,kGAAkG;QACrK,aAAa,EAAE,mCAAmC,QAAQ,+DAA+D;QACzH,QAAQ,EAAE,gGAAgG,QAAQ,oFAAoF;QACtM,YAAY,EAAE,2CAA2C,QAAQ,+EAA+E;QAChJ,sBAAsB,EAAE,mCAAmC,QAAQ,mDAAmD;QACtH,iEAAiE;QACjE,eAAe,EAAE,8JAA8J,QAAQ,yEAAyE;QAChQ,mBAAmB,EAAE,yCAAyC,QAAQ,kKAAkK;QACxO,gCAAgC;QAChC,iBAAiB,EAAE,4GAA4G,QAAQ,gBAAgB;QACvJ,mBAAmB,EAAE,4BAA4B,QAAQ,+DAA+D;QACxH,mCAAmC;QACnC,eAAe,EAAE,uDAAuD,QAAQ,6CAA6C;QAC7H,WAAW,EAAE,wDAAwD,QAAQ,yCAAyC;KACvH,CAAC;IAEF,OAAO,YAAY,CAAC,IAAI,CAAC,IAAI,GAAG,KAAK,KAAK,QAAQ,kCAAkC,CAAC;AACvF,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC;AAClE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAe,EAAE,QAAgB;IACpE,MAAM,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAE9E,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC5C,6CAA6C;IAC7C,uCAAuC;IACvC,MAAM,KAAK,GAAG,oBAAoB,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC;IAEtD,QAAQ;IACR,MAAM,YAAY,GAAG,0BAA0B,CAAC,IAAI,CAAC,IAAI,WAAW,CAAC;IACrE,MAAM,KAAK,GAAG,kBAAkB,CAAC,YAAY,CAAC,IAAI,kBAAkB,CAAC,WAAW,CAAC,CAAC;IAElF,QAAQ;IACR,MAAM,cAAc,GAAG,4BAA4B,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC;IAEvE,aAAa;IACb,MAAM,eAAe,GAAG,6BAA6B,CAAC,IAAI,CAAC,CAAC;IAE5D,WAAW;IACX,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;IAEzC,QAAQ;IACR,MAAM,UAAU,GAAG,iBAAiB,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACxD,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAEvD,aAAa;IACb,MAAM,SAAS,GAAG,iBAAiB,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;IAC7E,MAAM,SAAS,GAAG,SAAS;QACzB,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;aACT,KAAK,CAAC,IAAI,CAAC;aACX,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;aAC9C,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;aACpD,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;QAChB,CAAC,CAAC,EAAE,CAAC;IAEP,iBAAiB;IACjB,MAAM,WAAW,GAAG,mBAAmB,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IAEhE,sBAAsB;IACtB,IAAI,WAAW,GAAG,OAAO,CAAC;IAC1B,WAAW,IAAI,SAAS,IAAI,IAAI,CAAC;IACjC,WAAW,IAAI,gBAAgB,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC;IAC3D,WAAW,IAAI,UAAU,KAAK,IAAI,CAAC;IACnC,WAAW,IAAI,UAAU,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IAC9C,WAAW,IAAI,mBAAmB,cAAc,IAAI,CAAC;IAErD,IAAI,eAAe,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClD,WAAW,IAAI,oBAAoB,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IACpE,CAAC;IAED,IAAI,MAAM,EAAE,CAAC;QACX,WAAW,IAAI,WAAW,MAAM,IAAI,CAAC;IACvC,CAAC;IAED,WAAW,IAAI,OAAO,CAAC;IAEvB,+BAA+B;IAC/B,MAAM,WAAW,GAAG,iBAAiB,CAAC,OAAO,CAAC,uBAAuB,EAAE,EAAE,CAAC,CAAC;IAE3E,OAAO,GAAG,WAAW,KAAK,WAAW,EAAE,CAAC;AAC1C,CAAC;AASD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mBAAmB,CACjC,YAAoB,EACpB,eAAuB,EACvB,UAAsC,EAAE;IAExC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACjC,OAAO,CAAC,GAAG,CAAC,qCAAqC,YAAY,EAAE,CAAC,CAAC;QACjE,OAAO;IACT,CAAC;IAED,yBAAyB;IACzB,iDAAiD;IACjD,oCAAoC;IACpC,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC;YACjD,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;gBAAE,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;SAAM,IAAI,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QAC1C,kBAAkB,CAAC,eAAe,CAAC,CAAC;IACtC,CAAC;IACD,SAAS,CAAC,eAAe,CAAC,CAAC;IAE3B,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,SAAS,gBAAgB,CAAC,MAAc,EAAE,OAAe,EAAE,OAAe;QACxE,SAAS,CAAC,OAAO,CAAC,CAAC;QACnB,MAAM,OAAO,GAAG,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAEhE,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YAC9C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YAChD,MAAM,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;YAEnE,qCAAqC;YACrC,IAAI,KAAK,CAAC,WAAW,EAAE,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;gBACpE,MAAM,SAAS,GAAG,EAAE,CAAC,WAAW,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAyB,CAAC;qBAClF,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;gBACjF,YAAY,GAAG,SAAS,CAAC;gBACzB,SAAS;YACX,CAAC;YAED,uCAAuC;YACvC,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;gBACnB,IAAI,KAAK,CAAC,WAAW,EAAE,IAAI,OAAO,CAAC,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;oBAAE,SAAS;gBAC5E,IAAI,OAAO,CAAC,QAAQ,IAAI,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBAAE,SAAS;YACrG,CAAC;YAED,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,gBAAgB,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAChD,CAAC;iBAAM,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBACtC,KAAK,EAAE,CAAC;gBACR,IAAI,CAAC;oBACH,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;oBAClD,MAAM,aAAa,GAAG,oBAAoB,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;oBAChE,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,aAAa,EAAE,OAAO,CAAC,CAAC;oBACnD,SAAS,EAAE,CAAC;gBACd,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,OAAO,CAAC,IAAI,CAAC,2BAA2B,KAAK,CAAC,IAAI,KAAM,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;gBACnF,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,gBAAgB,CAAC,YAAY,EAAE,eAAe,EAAE,EAAE,CAAC,CAAC;IACpD,MAAM,QAAQ,GAAG,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,YAAY,6BAA6B,CAAC,CAAC,CAAC,EAAE,CAAC;IACzF,OAAO,CAAC,GAAG,CAAC,wBAAwB,SAAS,IAAI,KAAK,aAAa,QAAQ,EAAE,CAAC,CAAC;AACjF,CAAC"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "Claude Code 플러그인용 훅 정의. hooks/hooks.json 에서 생성된다 (scripts/gen-plugin-hooks.ts) — 손으로 고치지 말 것. Claude Code 가 주입하는 ${CLAUDE_PLUGIN_ROOT} 를 쓰며, plugin-hook-entry.js 를 거쳐 npm 설치본과의 이중 실행을 막는다.",
|
|
3
|
+
"hooks": {
|
|
4
|
+
"SessionStart": [
|
|
5
|
+
{
|
|
6
|
+
"matcher": "startup|resume|clear",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/plugin-hook-entry.js session-start.js"
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"PreToolUse": [
|
|
16
|
+
{
|
|
17
|
+
"matcher": "Bash",
|
|
18
|
+
"hooks": [
|
|
19
|
+
{
|
|
20
|
+
"type": "command",
|
|
21
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/plugin-hook-entry.js pre-tool-dispatcher.js Bash"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"matcher": "Edit",
|
|
27
|
+
"hooks": [
|
|
28
|
+
{
|
|
29
|
+
"type": "command",
|
|
30
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/plugin-hook-entry.js pre-tool-dispatcher.js Edit"
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"matcher": "Write",
|
|
36
|
+
"hooks": [
|
|
37
|
+
{
|
|
38
|
+
"type": "command",
|
|
39
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/plugin-hook-entry.js pre-tool-dispatcher.js Write"
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"matcher": "mcp__github__create_pull_request",
|
|
45
|
+
"hooks": [
|
|
46
|
+
{
|
|
47
|
+
"type": "command",
|
|
48
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/plugin-hook-entry.js pr-test-gate.js"
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
"PostToolUse": [
|
|
54
|
+
{
|
|
55
|
+
"matcher": "Write|Edit",
|
|
56
|
+
"hooks": [
|
|
57
|
+
{
|
|
58
|
+
"type": "command",
|
|
59
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/plugin-hook-entry.js post-edit-dispatcher.js"
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"matcher": "Edit|Write|Bash|Task|SlashCommand|NotebookEdit",
|
|
65
|
+
"hooks": [
|
|
66
|
+
{
|
|
67
|
+
"type": "command",
|
|
68
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/plugin-hook-entry.js step-counter.js"
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
"UserPromptSubmit": [
|
|
74
|
+
{
|
|
75
|
+
"hooks": [
|
|
76
|
+
{
|
|
77
|
+
"type": "command",
|
|
78
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/plugin-hook-entry.js prompt-dispatcher.js"
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
],
|
|
83
|
+
"Notification": [
|
|
84
|
+
{
|
|
85
|
+
"matcher": "context_window_80",
|
|
86
|
+
"hooks": [
|
|
87
|
+
{
|
|
88
|
+
"type": "command",
|
|
89
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/plugin-hook-entry.js context-save.js medium"
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"matcher": "context_window_90",
|
|
95
|
+
"hooks": [
|
|
96
|
+
{
|
|
97
|
+
"type": "command",
|
|
98
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/plugin-hook-entry.js context-save.js high"
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"matcher": "context_window_95",
|
|
104
|
+
"hooks": [
|
|
105
|
+
{
|
|
106
|
+
"type": "command",
|
|
107
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/plugin-hook-entry.js context-save.js critical"
|
|
108
|
+
}
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
],
|
|
112
|
+
"Stop": [
|
|
113
|
+
{
|
|
114
|
+
"hooks": [
|
|
115
|
+
{
|
|
116
|
+
"type": "command",
|
|
117
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/scripts/plugin-hook-entry.js stop-dispatcher.js"
|
|
118
|
+
}
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
}
|
package/hooks/plugin-hooks.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_comment": "
|
|
2
|
+
"_comment": "Codex 플러그인용 훅 정의. hooks/hooks.json 에서 생성된다 (scripts/gen-plugin-hooks.ts) — 손으로 고치지 말 것. npm 경로는 postinstall 이 {{VIBE_PATH}} 를 치환하지만 플러그인은 치환 단계가 없어 런타임 변수 ${PLUGIN_ROOT} 를 쓴다. 커맨드가 plugin-hook-entry.js 를 거치는 이유는 npm 설치본과 겹칠 때 같은 훅이 두 번 도는 것을 막기 위해서다.",
|
|
3
3
|
"hooks": {
|
|
4
4
|
"SessionStart": [
|
|
5
5
|
{
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"hooks": [
|
|
8
8
|
{
|
|
9
9
|
"type": "command",
|
|
10
|
-
"command": "node ${PLUGIN_ROOT}/hooks/scripts/session-start.js"
|
|
10
|
+
"command": "node ${PLUGIN_ROOT}/hooks/scripts/plugin-hook-entry.js session-start.js"
|
|
11
11
|
}
|
|
12
12
|
]
|
|
13
13
|
}
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"hooks": [
|
|
19
19
|
{
|
|
20
20
|
"type": "command",
|
|
21
|
-
"command": "node ${PLUGIN_ROOT}/hooks/scripts/pre-tool-dispatcher.js Bash"
|
|
21
|
+
"command": "node ${PLUGIN_ROOT}/hooks/scripts/plugin-hook-entry.js pre-tool-dispatcher.js Bash"
|
|
22
22
|
}
|
|
23
23
|
]
|
|
24
24
|
},
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"hooks": [
|
|
28
28
|
{
|
|
29
29
|
"type": "command",
|
|
30
|
-
"command": "node ${PLUGIN_ROOT}/hooks/scripts/pre-tool-dispatcher.js Edit"
|
|
30
|
+
"command": "node ${PLUGIN_ROOT}/hooks/scripts/plugin-hook-entry.js pre-tool-dispatcher.js Edit"
|
|
31
31
|
}
|
|
32
32
|
]
|
|
33
33
|
},
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"hooks": [
|
|
37
37
|
{
|
|
38
38
|
"type": "command",
|
|
39
|
-
"command": "node ${PLUGIN_ROOT}/hooks/scripts/pre-tool-dispatcher.js Write"
|
|
39
|
+
"command": "node ${PLUGIN_ROOT}/hooks/scripts/plugin-hook-entry.js pre-tool-dispatcher.js Write"
|
|
40
40
|
}
|
|
41
41
|
]
|
|
42
42
|
},
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"hooks": [
|
|
46
46
|
{
|
|
47
47
|
"type": "command",
|
|
48
|
-
"command": "node ${PLUGIN_ROOT}/hooks/scripts/pr-test-gate.js"
|
|
48
|
+
"command": "node ${PLUGIN_ROOT}/hooks/scripts/plugin-hook-entry.js pr-test-gate.js"
|
|
49
49
|
}
|
|
50
50
|
]
|
|
51
51
|
}
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"hooks": [
|
|
57
57
|
{
|
|
58
58
|
"type": "command",
|
|
59
|
-
"command": "node ${PLUGIN_ROOT}/hooks/scripts/post-edit-dispatcher.js"
|
|
59
|
+
"command": "node ${PLUGIN_ROOT}/hooks/scripts/plugin-hook-entry.js post-edit-dispatcher.js"
|
|
60
60
|
}
|
|
61
61
|
]
|
|
62
62
|
},
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"hooks": [
|
|
66
66
|
{
|
|
67
67
|
"type": "command",
|
|
68
|
-
"command": "node ${PLUGIN_ROOT}/hooks/scripts/step-counter.js"
|
|
68
|
+
"command": "node ${PLUGIN_ROOT}/hooks/scripts/plugin-hook-entry.js step-counter.js"
|
|
69
69
|
}
|
|
70
70
|
]
|
|
71
71
|
}
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"hooks": [
|
|
76
76
|
{
|
|
77
77
|
"type": "command",
|
|
78
|
-
"command": "node ${PLUGIN_ROOT}/hooks/scripts/prompt-dispatcher.js"
|
|
78
|
+
"command": "node ${PLUGIN_ROOT}/hooks/scripts/plugin-hook-entry.js prompt-dispatcher.js"
|
|
79
79
|
}
|
|
80
80
|
]
|
|
81
81
|
}
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"hooks": [
|
|
87
87
|
{
|
|
88
88
|
"type": "command",
|
|
89
|
-
"command": "node ${PLUGIN_ROOT}/hooks/scripts/context-save.js medium"
|
|
89
|
+
"command": "node ${PLUGIN_ROOT}/hooks/scripts/plugin-hook-entry.js context-save.js medium"
|
|
90
90
|
}
|
|
91
91
|
]
|
|
92
92
|
},
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
"hooks": [
|
|
96
96
|
{
|
|
97
97
|
"type": "command",
|
|
98
|
-
"command": "node ${PLUGIN_ROOT}/hooks/scripts/context-save.js high"
|
|
98
|
+
"command": "node ${PLUGIN_ROOT}/hooks/scripts/plugin-hook-entry.js context-save.js high"
|
|
99
99
|
}
|
|
100
100
|
]
|
|
101
101
|
},
|
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
"hooks": [
|
|
105
105
|
{
|
|
106
106
|
"type": "command",
|
|
107
|
-
"command": "node ${PLUGIN_ROOT}/hooks/scripts/context-save.js critical"
|
|
107
|
+
"command": "node ${PLUGIN_ROOT}/hooks/scripts/plugin-hook-entry.js context-save.js critical"
|
|
108
108
|
}
|
|
109
109
|
]
|
|
110
110
|
}
|
|
@@ -114,7 +114,7 @@
|
|
|
114
114
|
"hooks": [
|
|
115
115
|
{
|
|
116
116
|
"type": "command",
|
|
117
|
-
"command": "node ${PLUGIN_ROOT}/hooks/scripts/stop-dispatcher.js"
|
|
117
|
+
"command": "node ${PLUGIN_ROOT}/hooks/scripts/plugin-hook-entry.js stop-dispatcher.js"
|
|
118
118
|
}
|
|
119
119
|
]
|
|
120
120
|
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 플러그인 훅의 단일 진입점 — 이중 실행을 막는다.
|
|
3
|
+
*
|
|
4
|
+
* 실측한 사건: vibe 를 npm 으로 설치하면 프로젝트에 `.claude/settings.local.json`
|
|
5
|
+
* 훅 6개가 설치된다. 여기에 플러그인까지 설치하면 **같은 6개 이벤트가 두 벌** 등록돼
|
|
6
|
+
* 모든 게이트가 2회 돌고, Stop 의 auto-commit·devlog 도 2회 돈다. 게이트가 두 번
|
|
7
|
+
* 도는 건 느린 정도지만 커밋이 두 번 나는 건 되돌릴 일이 생긴다.
|
|
8
|
+
*
|
|
9
|
+
* 그래서 플러그인 훅은 전부 이 진입점을 거친다. 프로젝트에 vibe 훅이 이미 있으면
|
|
10
|
+
* **플러그인 쪽이 물러난다** — 프로젝트 설정이 사용자가 명시적으로 설치한 것이고,
|
|
11
|
+
* 경로도 그쪽이 정확하기 때문이다(플러그인 트리에는 node_modules 가 없다).
|
|
12
|
+
*
|
|
13
|
+
* 실행은 spawn 이 아니라 in-process `import` 다 — 훅 레이턴시 규약(CLAUDE.md
|
|
14
|
+
* "dispatcher in-process 평탄화")을 플러그인 경로에서도 깨지 않는다.
|
|
15
|
+
*/
|
|
16
|
+
import fs from 'fs';
|
|
17
|
+
import path from 'path';
|
|
18
|
+
import { pathToFileURL } from 'url';
|
|
19
|
+
|
|
20
|
+
/** 프로젝트에 vibe 훅이 이미 설치돼 있는가 — 있으면 플러그인은 실행하지 않는다 */
|
|
21
|
+
export function projectHooksInstalled(projectDir) {
|
|
22
|
+
const settings = path.join(projectDir, '.claude', 'settings.local.json');
|
|
23
|
+
try {
|
|
24
|
+
const parsed = JSON.parse(fs.readFileSync(settings, 'utf-8'));
|
|
25
|
+
const hooks = parsed?.hooks;
|
|
26
|
+
if (!hooks || typeof hooks !== 'object') return false;
|
|
27
|
+
// vibe 훅인지까지 확인한다 — 사용자가 자기 훅만 넣어둔 경우에는 물러날 이유가 없다
|
|
28
|
+
return JSON.stringify(hooks).includes('hooks/scripts/');
|
|
29
|
+
} catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function main() {
|
|
35
|
+
const [, , script, ...rest] = process.argv;
|
|
36
|
+
if (!script) {
|
|
37
|
+
process.stderr.write('plugin-hook-entry: 실행할 스크립트가 지정되지 않았다\n');
|
|
38
|
+
process.exit(0); // 훅은 사용자 작업을 막지 않는다
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (projectHooksInstalled(process.cwd())) process.exit(0);
|
|
42
|
+
|
|
43
|
+
const target = path.resolve(import.meta.dirname, script);
|
|
44
|
+
if (!fs.existsSync(target)) {
|
|
45
|
+
process.stderr.write(`plugin-hook-entry: 스크립트를 찾지 못했다 — ${target}\n`);
|
|
46
|
+
process.exit(0);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// 대상 스크립트가 자기 argv 를 그대로 읽도록 맞춘다 (pre-tool-dispatcher.js Bash 등)
|
|
50
|
+
process.argv = [process.argv[0], target, ...rest];
|
|
51
|
+
await import(pathToFileURL(target).href);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// 테스트에서 import 할 때는 실행하지 않는다
|
|
55
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === path.resolve(import.meta.filename)) {
|
|
56
|
+
await main();
|
|
57
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@su-record/vibe",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.33",
|
|
4
4
|
"description": "AI Coding Framework for Claude Code — 7+ agents, 52 skills, multi-LLM orchestration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/cli/index.js",
|
|
@@ -37,7 +37,10 @@
|
|
|
37
37
|
"release": "bash scripts/release.sh",
|
|
38
38
|
"sync:plugin-version": "npx tsx scripts/sync-plugin-version.ts",
|
|
39
39
|
"version": "npx tsx scripts/sync-plugin-version.ts && git add .codex-plugin/plugin.json",
|
|
40
|
-
"build:plugin": "npx tsx scripts/build-plugin.ts"
|
|
40
|
+
"build:plugin": "npx tsx scripts/build-plugin.ts",
|
|
41
|
+
"gen:plugin-hooks": "npx tsx scripts/gen-plugin-hooks.ts",
|
|
42
|
+
"gen:plugin-hooks:check": "npx tsx scripts/gen-plugin-hooks.ts --check",
|
|
43
|
+
"validate:plugin-tree": "npx tsx scripts/build-plugin.ts && git diff --exit-code --stat HEAD -- plugins/"
|
|
41
44
|
},
|
|
42
45
|
"keywords": [
|
|
43
46
|
"ai",
|
|
@@ -97,6 +100,8 @@
|
|
|
97
100
|
"vitest": "^4.1.10"
|
|
98
101
|
},
|
|
99
102
|
"files": [
|
|
103
|
+
".claude-plugin/",
|
|
104
|
+
"!.claude-plugin/marketplace.json",
|
|
100
105
|
".codex-plugin/",
|
|
101
106
|
"dist/",
|
|
102
107
|
"vibe/",
|
|
@@ -56,3 +56,19 @@ Codex는 네이티브 hook을 지원한다(`codex features list` → `hooks: sta
|
|
|
56
56
|
**핵심 통찰: Codex의 직역 성향이 AGENTS.md "soft hook"을 신뢰성 있게 만든다.** CC는 soft 지시를 가끔 무시해 hard hook이 필요하지만, Codex는 적힌 대로 실행한다. 따라서 AGENTS.md 운영 규칙은 네이티브 hook이 생긴 뒤에도 **폐기하지 않고 2차 방어선으로 유지한다** — hook이 설치되지 않은 환경(전역 설치만 한 경우, 다른 클론)에서도 가드가 남는다.
|
|
57
57
|
|
|
58
58
|
> ⚠️ **훅은 "설치돼 있다"고 가정하지 않는다.** 훅은 프로젝트 로컬 아티팩트라 `vibe upgrade` 만으로는 설치되지 않는다(전역 자산만 갱신). `vibe status` 가 하네스별 훅 설치 여부를 보고하고, `vibe upgrade` 는 현재 프로젝트의 누락 훅을 복구한다. 결정론적 가드의 생사는 **관측 가능해야** 한다 — 조용히 죽은 가드는 없는 가드보다 나쁘다.
|
|
59
|
+
|
|
60
|
+
## 훅 정의가 세 벌이 됐다 (배포 경로별)
|
|
61
|
+
|
|
62
|
+
배포 경로가 npm · Claude Code 플러그인 · Codex 플러그인 셋으로 늘면서 훅 정의도 셋이 됐다. 경로 변수가 다르기 때문이다 — 그리고 **정의가 갈라지면 한쪽 하네스에서만 게이트가 죽고, 그건 조용히 일어난다.** 이 문서가 반복해서 말하는 실패 모드다.
|
|
63
|
+
|
|
64
|
+
| 파일 | 경로 | 변수 | 생성 |
|
|
65
|
+
|---|---|---|---|
|
|
66
|
+
| `hooks/hooks.json` | npm | `{{VIBE_PATH}}` — postinstall 이 치환 | **SSOT** (손으로 고치는 유일한 파일) |
|
|
67
|
+
| `hooks/claude-plugin-hooks.json` | Claude Code 플러그인 | `${CLAUDE_PLUGIN_ROOT}` | `gen-plugin-hooks.ts` |
|
|
68
|
+
| `hooks/plugin-hooks.json` | Codex 플러그인 | `${PLUGIN_ROOT}` | `gen-plugin-hooks.ts` |
|
|
69
|
+
|
|
70
|
+
- 드리프트는 `npm run gen:plugin-hooks:check` 가 CI 에서 막는다. 손으로 맞추는 선택지는 두지 않는다
|
|
71
|
+
- **이중 실행 가드**: npm 설치본과 플러그인이 겹치면 같은 6개 이벤트가 두 벌 등록돼 게이트가 2회, Stop 의 auto-commit 도 2회 돈다. 플러그인 훅은 `plugin-hook-entry.js` 를 거쳐, 프로젝트에 **vibe 훅**이 있으면 물러난다. 판정 기준이 "훅 키가 있다" 가 아니라 "vibe 훅이 있다" 인 이유는 사용자 자작 훅만 있는 프로젝트에서까지 침묵하면 설치한 의미가 없기 때문이다
|
|
72
|
+
- 실행은 자식 spawn 이 아니라 in-process `import` 다 — 훅 실행 모델 규약을 플러그인 경로에서도 지킨다
|
|
73
|
+
|
|
74
|
+
> 하네스가 늘어날 때 늘려야 하는 것은 **정의가 아니라 생성기**다. 정의를 늘리면 그 수만큼 갈라질 자리가 생긴다.
|