reborn-plugin5 1.0.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/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # reborn-plugin5
2
+
3
+ 바이브 코딩에 붙이는 플러그인 **5종을 붙이기 전에 이 컴퓨터를 재 주는 안내 스킬**입니다.
4
+
5
+ ```bash
6
+ npx --yes reborn-plugin5 --check # 깔지 않고 이 컴퓨터를 잽니다
7
+ npx --yes reborn-plugin5 # 안내 스킬을 깝니다
8
+ ```
9
+
10
+ > `--yes` 를 빼지 마세요. 없으면 클로드 코드 안에서 설치 확인 프롬프트를 기다리다 조용히 멈춥니다.
11
+
12
+ ## 무엇을 재나
13
+
14
+ | | 잽니다 |
15
+ |---|---|
16
+ | Node.js | 18 이상인가 |
17
+ | Docker | 깔렸나가 아니라 **지금 응답하나** — Strix 첫 실행이 여기서 멈춥니다 |
18
+ | LLM API 키 | 환경에 있나 (**값은 읽지 않습니다. 있는지만 봅니다**) |
19
+ | Claude Code | 있나 (커서·코덱스에서도 됩니다) |
20
+ | 이미 붙은 것 | 다섯 중 무엇이 이 컴퓨터에 이미 있나 |
21
+
22
+ ## 다섯
23
+
24
+ | | 도구 | 무엇을 하나 | 준비물 |
25
+ |---|---|---|---|
26
+ | 1 | [Playwright CLI](https://github.com/microsoft/playwright-cli) | AI 가 브라우저를 열어 눌러 보고 스크린샷을 찍는다 | Node 18+ |
27
+ | 2 | [Supabase MCP](https://github.com/supabase-community/supabase-mcp) | SQL 없이 데이터베이스를 짓고 관리한다 | 계정 · project_ref · **읽기전용** |
28
+ | 3 | [Strix](https://github.com/usestrix/strix) | 내 앱을 실제로 공격해 보안 구멍을 찾는다 | **Docker** · LLM 키 · **허락** |
29
+ | 4 | [SkillUI](https://github.com/amaancoderx/npxskillui) | 사이트의 디자인 시스템을 스킬 파일로 뜯어 온다 | Node 18+ |
30
+ | 5 | [Context7](https://github.com/upstash/context7) | 라이브러리 최신 문서를 어시스턴트에 물려준다 | Node 18+ |
31
+
32
+ 버전·라이선스·별 수는 **2026-09-03 에 npm 레지스트리·PyPI·GitHub API 를 직접 호출해 읽은 값**입니다.
33
+ 전부 Apache-2.0 또는 MIT 이고 지역 제한 조항은 없습니다.
34
+
35
+ ## 영상이 말하지 않은 것
36
+
37
+ - **Strix 는 도커가 떠 있어야 합니다.** 첫 실행이 샌드박스 이미지를 받습니다 — 안 떠 있으면 거기서 멈춥니다.
38
+ - **Strix 는 LLM 키가 따로 듭니다.** 도구는 공짜지만 도구가 부르는 모델은 아닙니다.
39
+ - **Supabase 는 `read_only=true` 를 켜세요.** 안 켜면 지우고 바꾸는 도구까지 열립니다.
40
+ - **Playwright 는 CLI 판과 MCP 판이 다릅니다.** 코딩 에이전트에는 CLI+스킬이 문맥을 훨씬 덜 먹습니다.
41
+ - **Context7 은 키 없이도 되지만 요청 제한이 있습니다.** `npx --yes ctx7 setup` 한 번이 무료 키를 만들어 줍니다.
42
+
43
+ ## ⚠️ Strix 는 허락받은 대상에만
44
+
45
+ Strix 는 겨눈 대상을 **실제로 공격합니다.** 저장소가 「Authorized use only」 를 명시합니다 —
46
+ 내가 소유했거나 문서로 허락받은 시스템이 아니면 돌리지 마세요. 대부분의 나라에서 위법입니다.
47
+
48
+ ## 자기시험
49
+
50
+ ```bash
51
+ npm test # node cli.mjs --self-test · 네트워크 안 씁니다
52
+ ```
53
+
54
+ ## 상표
55
+
56
+ Playwright 는 Microsoft, Supabase MCP 는 Supabase, Strix 는 usestrix,
57
+ SkillUI 는 amaancoderx, Context7 은 Upstash 의 것입니다.
58
+ 리본랩스는 만든 곳들과 아무 관계가 없고, 이 패키지는 **깔기 전에 이 컴퓨터를 재 주는 안내 스킬**입니다.
59
+
60
+ ## 같은 방식으로 골라 담은 48종
61
+
62
+ 리본랩스 스킬팩 — https://rebornlabs.kr/skillpack?utm_source=installer&utm_medium=cli&utm_campaign=plugin5
63
+
64
+ 목록과 직접 까는 명령까지 그 페이지에 그대로 적어 두었습니다. 안 사셔도 됩니다.
65
+
66
+ MIT · REBORN LABS
package/cli.mjs ADDED
@@ -0,0 +1,369 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * vibe-plugins-guide 설치기 — **영상이 말한 플러그인 다섯을 붙이기 전에 이 컴퓨터를 잰다.**
4
+ *
5
+ * npx --yes reborn-plugin5 안내 스킬을 깐다 (이게 전부다)
6
+ * npx --yes reborn-plugin5 --check ★깔지 않고 **이 컴퓨터를 잰다**
7
+ * npx --yes reborn-plugin5 --dry-run 무엇을 할지 보여주기만 한다
8
+ * npx --yes reborn-plugin5 --local 홈(~/.claude/skills)이 아니라 현재 폴더에 깐다
9
+ * npx --yes reborn-plugin5 --self-test 자기시험 (네트워크 안 씀)
10
+ *
11
+ * ★★왜 우리가 대신 안 깔고 **안내 스킬**을 까나
12
+ * 다섯 줄은 이미 공개돼 있다. 우리가 그 줄을 대신 실행해 준다고 아껴지는 게 없다.
13
+ * 실제로 막히는 자리는 **다섯이 서로 다른 준비물을 요구한다**는 데 있다:
14
+ * ① Strix 는 **도커가 떠 있어야** 첫 실행에서 샌드박스 이미지를 받는다. 안 떠 있으면 거기서 멈춘다
15
+ * ② Strix 는 **LLM API 키**가 따로 든다 — 도구는 공짜지만 도구가 부르는 모델은 아니다
16
+ * ③ Supabase 는 **읽기전용을 안 켜면** 지우고 바꾸는 도구까지 열린다
17
+ * ④ Playwright 는 **CLI 판과 MCP 판이 다르다** — 코딩 에이전트에는 CLI+스킬이 문맥을 훨씬 덜 먹는다
18
+ * ⑤ Context7 은 키 없이도 붙지만 **요청 제한**이 걸린다
19
+ * 참고본은 다섯이 무엇을 해 주는지까지 말한다. 그건 맞다. **준비물이 남는다.**
20
+ *
21
+ * ★★--check 가 이 설치기의 존재 이유다
22
+ * 말로 「되실 겁니다」 하지 않는다. 실행 파일을 실제로 찾고, 도커에 실제로 말을 걸고,
23
+ * 설정 파일을 실제로 읽는다. 못 보면 「모른다」고 한다 — 「된다」고 하지 않는다.
24
+ *
25
+ * ★★깔았다고 「됐다」고 하지 않는다.
26
+ * 복사는 조용히 실패한다(권한·경로·한글 홈디렉터리). 쓴 뒤 **다시 읽어 본다**
27
+ * [[kit-update-selfcheck]].
28
+ */
29
+ import { execFileSync } from "node:child_process";
30
+ import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync } from "node:fs";
31
+ import { homedir, platform } from "node:os";
32
+ import { dirname, join } from "node:path";
33
+ import { fileURLToPath } from "node:url";
34
+ import { 링크, TAIL, 마지막 } from "./tail.mjs";
35
+
36
+ const HOME = homedir();
37
+ const 여기 = dirname(fileURLToPath(import.meta.url));
38
+ const 인자 = process.argv.slice(2);
39
+ const 확인만 = 인자.includes("--check");
40
+ const 미리보기 = 인자.includes("--dry-run");
41
+ const 여기에 = 인자.includes("--local");
42
+ const 자기시험모드 = 인자.includes("--self-test");
43
+
44
+ const c = { g: "\x1b[32m", r: "\x1b[31m", y: "\x1b[33m", d: "\x1b[90m", cy: "\x1b[36m", b: "\x1b[1m", 0: "\x1b[0m" };
45
+ const 굵게 = (t) => String(t).replace(/\*\*(.+?)\*\*/g, `${c[0]}${c.b}$1${c[0]}${c.d}`);
46
+
47
+ const 퍼널 = "plugin5";
48
+ const 스킬이름 = "vibe-plugins-guide";
49
+ const 원본 = join(여기, "skill");
50
+ const 대상뿌리 = 여기에 ? join(process.cwd(), ".claude", "skills") : join(HOME, ".claude", "skills");
51
+ const 대상 = join(대상뿌리, 스킬이름);
52
+
53
+ /* ══ 원장 ═══════════════════════════════════════════════════════ */
54
+
55
+ function 원장읽기() {
56
+ const p = join(원본, "plugin5.json");
57
+ if (!existsSync(p)) return { 됨: false, 이유: `원장이 없다 — ${p}` };
58
+ try { return { 됨: true, d: JSON.parse(readFileSync(p, "utf8")) }; }
59
+ catch (e) { return { 됨: false, 이유: `원장을 못 읽는다 — ${e.message}` }; }
60
+ }
61
+
62
+ /** ★조건 없이 단정하는 말. 홍보문에 섞이면 잡는다. [[kmong-no-unbounded-guarantee]] */
63
+ const 금칙 = [/완전\s*무료/, /무제한/, /평생/, /100\s*%\s*보장/, /누구나\s*바로/, /무조건/,
64
+ /설정\s*없이/, /깔면\s*끝/, /전혀\s*없/, /절대\s*안/];
65
+
66
+ /** ★「그 말을 하지 마라」고 적어 둔 문장까지 잡으면 원장을 못 쓴다. */
67
+ const 금칙면제 = /(하지\s*않는다|말하지\s*마라|쓰지\s*않는다|아니다|틀리다|금칙|안\s*된다|하지\s*마라|말하지\s*않는다|은\s*아니다|되지\s*않는다|겨누지\s*마라|돌리지\s*마라)/;
68
+
69
+ /** ★낫표 안은 **인용**이다 [[forbidden-word-checker-blocks-its-own-quotes]] */
70
+ const 인용벗기기 = (s) => String(s).replace(/「[^」]*」/g, "○");
71
+
72
+ function 금칙검사(텍스트, 어디) {
73
+ const 문제 = [];
74
+ for (const 원줄 of String(텍스트).split(/\n|(?<=[.。])\s+/)) {
75
+ const 줄 = 인용벗기기(원줄);
76
+ if (금칙면제.test(줄)) continue;
77
+ for (const re of 금칙) if (re.test(줄)) 문제.push(`${어디}에 조건 없는 단정: ${re.source}`);
78
+ }
79
+ return 문제;
80
+ }
81
+
82
+ function 원장검사(d) {
83
+ const 문제 = [];
84
+ const 있나 = (v) => v !== undefined && v !== null && v !== "";
85
+
86
+ if (!있나(d?.확인일)) 문제.push("확인일이 없다 — 언제 잰 값인지 모르면 사실은 못 쓴다");
87
+ if (!있나(d?.확인방법)) 문제.push("확인방법이 없다 — 어디서 읽었는지 없는 말은 지어낸 것과 구분이 안 된다");
88
+
89
+ const P = Array.isArray(d?.플러그인) ? d.플러그인 : [];
90
+ if (P.length !== 5) 문제.push(`플러그인이 ${P.length}개다 — 이 회차 소재는 다섯이다`);
91
+ for (const p of P) {
92
+ const 어디 = `플러그인 ${p?.키 || "?"}`;
93
+ for (const k of ["이름", "한줄", "패키지", "버전", "라이선스", "저장소", "설치", "★함정", "★근거"]) {
94
+ if (!있나(p?.[k])) 문제.push(`${어디}: ${k} 이 없다`);
95
+ }
96
+ if (있나(p?.저장소) && !/^https:\/\//.test(String(p.저장소))) 문제.push(`${어디}: 저장소가 https 주소가 아니다`);
97
+ if (있나(p?.설치) && /^npx\s+(?!--yes)/.test(String(p.설치)))
98
+ 문제.push(`${어디}: npx 안내에 --yes 가 없다 — 클로드 코드 안에서 무음으로 멈춘다 [[npx-installer-needs-yes-flag]]`);
99
+ 문제.push(...금칙검사(`${p?.한줄}\n${p?.["★함정"]}`, 어디));
100
+ }
101
+
102
+ /* ★설치 명령이 원장에 없으면 릴스·착지·DM 이 저마다 손으로 적게 된다. */
103
+ const 명령 = d?.설치?.["★명령"];
104
+ if (!있나(명령)) 문제.push("설치.★명령 이 없다 — 이 문자열 하나를 릴스·착지·DM 이 같이 읽는다");
105
+ else if (!/^npx\s+--yes\s+reborn-plugin5$/.test(String(명령)))
106
+ 문제.push(`설치.★명령 이 「npx --yes reborn-plugin5」 가 아니다 — 지금 값: ${명령}`);
107
+
108
+ /* ★Strix 는 법 조항을 반드시 들고 다녀야 한다. 빼면 남의 사이트에 겨누게 된다. */
109
+ const strix = P.find((p) => p?.키 === "strix");
110
+ if (strix && !있나(strix["★법"])) 문제.push("strix 에 ★법(허락받은 대상만) 칸이 없다 — 이건 빼면 안 되는 문장이다");
111
+
112
+ /* ★공짜의 범위를 말하지 않으면 「전부 0원」으로 읽힌다. */
113
+ if (!Array.isArray(d?.["★공짜의범위"]?.["★따로_드는것"]) || d["★공짜의범위"]["★따로_드는것"].length < 3)
114
+ 문제.push("★공짜의범위.★따로_드는것 이 3줄 미만이다 — 값이 드는 자리를 안 말하면 공짜로 읽힌다");
115
+
116
+ 문제.push(...금칙검사(JSON.stringify(d?.["★영상이_말하지_않은_것"] || {}), "★영상이_말하지_않은_것"));
117
+ return 문제;
118
+ }
119
+
120
+ /* ══ 이 컴퓨터를 잰다 ═══════════════════════════════════════════ */
121
+
122
+ function 실행파일있나(cmd) {
123
+ const 찾기 = platform() === "win32" ? "where" : "which";
124
+ try { execFileSync(찾기, [cmd], { stdio: "pipe", timeout: 4000 }); return true; }
125
+ catch { return false; }
126
+ }
127
+
128
+ function 명령해보기(cmd, args, ms = 6000) {
129
+ try { return String(execFileSync(cmd, args, { stdio: "pipe", timeout: ms })).trim(); }
130
+ catch { return null; }
131
+ }
132
+
133
+ function 노드판() {
134
+ const m = /^v(\d+)/.exec(process.version);
135
+ return m ? Number(m[1]) : 0;
136
+ }
137
+
138
+ /** ★★도커는 「깔렸나」가 아니라 **「지금 응답하나」**를 본다.
139
+ * 깔려 있어도 데스크톱이 안 떠 있으면 Strix 첫 실행이 이미지를 못 받고 멈춘다. */
140
+ function 도커상태() {
141
+ if (!실행파일있나("docker")) return { 있나: false, 뜸: false, 판: null };
142
+ const v = 명령해보기("docker", ["version", "--format", "{{.Server.Version}}"], 8000);
143
+ return { 있나: true, 뜸: !!v, 판: v || null };
144
+ }
145
+
146
+ /** LLM 키가 환경에 있나 — 값은 절대 읽지 않고 **있는지만** 본다. */
147
+ function LLM키() {
148
+ const 후보 = ["ANTHROPIC_API_KEY", "OPENAI_API_KEY", "GEMINI_API_KEY", "GOOGLE_API_KEY"];
149
+ return 후보.filter((k) => String(process.env[k] || "").length > 8);
150
+ }
151
+
152
+ function 이미깔렸나() {
153
+ const 자리 = [];
154
+ for (const 뿌리 of [join(HOME, ".claude", "skills"), join(process.cwd(), ".claude", "skills")]) {
155
+ const p = join(뿌리, 스킬이름);
156
+ if (existsSync(p) && statSync(p).isDirectory()) 자리.push({ 어디: p, 개수: readdirSync(p).length });
157
+ }
158
+ return 자리;
159
+ }
160
+
161
+ /** 다섯 중 어느 것이 이 컴퓨터에 이미 있나 — 실행 파일과 설정 파일을 실제로 본다. */
162
+ function 붙은것() {
163
+ const 결과 = {};
164
+ 결과.playwright = 실행파일있나("playwright-cli");
165
+ 결과.skillui = null; /* npx 로만 쓰는 것이라 「깔림」이라는 상태가 없다 */
166
+ 결과.context7 = 실행파일있나("ctx7");
167
+ /* MCP 등록은 클로드 코드 설정 파일에서 이름으로 본다. 없으면 「모른다」다. */
168
+ const 설정후보 = [join(HOME, ".claude.json"), join(HOME, ".claude", "settings.json")];
169
+ let 본문 = null;
170
+ for (const p of 설정후보) if (existsSync(p)) { try { 본문 = readFileSync(p, "utf8"); break; } catch { /* 못 읽으면 모른다 */ } }
171
+ 결과.supabaseMCP = 본문 == null ? null : /mcp\.supabase\.com|mcp-server-supabase/.test(본문);
172
+ 결과.strix = 실행파일있나("strix");
173
+ return 결과;
174
+ }
175
+
176
+ function 환경재기() {
177
+ return {
178
+ 노드: 노드판(),
179
+ 도커: 도커상태(),
180
+ LLM키: LLM키(),
181
+ 클로드코드: 실행파일있나("claude"),
182
+ git: 실행파일있나("git"),
183
+ 붙은것: 붙은것(),
184
+ 이미: 이미깔렸나(),
185
+ };
186
+ }
187
+
188
+ /** ★어느 것이 지금 바로 되는지 **잰 값으로** 가른다. 「아마 될 겁니다」를 하지 않는다. */
189
+ function 준비표(E, D) {
190
+ const 줄 = [];
191
+ for (const p of D.플러그인) {
192
+ let 상태 = "됨", 왜 = "";
193
+ if (E.노드 < 18) { 상태 = "막힘"; 왜 = `노드 ${E.노드} — 18 이상이 필요합니다`; }
194
+ if (p.키 === "strix") {
195
+ if (!E.도커.있나) { 상태 = "막힘"; 왜 = "도커가 없습니다 — 첫 실행이 샌드박스 이미지를 받습니다"; }
196
+ else if (!E.도커.뜸) { 상태 = "막힘"; 왜 = "도커가 깔려 있지만 지금 응답하지 않습니다 — 데스크톱을 켜 주세요"; }
197
+ else if (!E.LLM키.length) { 상태 = "준비"; 왜 = "LLM API 키가 환경에 안 보입니다 — 값이 따로 듭니다"; }
198
+ }
199
+ if (p.키 === "supabase") {
200
+ 상태 = "준비";
201
+ 왜 = E.붙은것.supabaseMCP === true ? "이미 붙어 있습니다 — 읽기전용인지 한 번 보세요"
202
+ : "계정과 project_ref 가 먼저입니다. 붙일 때 읽기전용을 켜세요";
203
+ }
204
+ if (p.키 === "playwright" && E.붙은것.playwright) { 상태 = "있음"; 왜 = "playwright-cli 가 이미 있습니다"; }
205
+ if (p.키 === "context7" && E.붙은것.context7) { 상태 = "있음"; 왜 = "ctx7 이 이미 있습니다"; }
206
+ if (p.키 === "strix" && E.붙은것.strix && 상태 === "됨") { 상태 = "있음"; 왜 = "strix 가 이미 있습니다"; }
207
+ 줄.push({ p, 상태, 왜 });
208
+ }
209
+ return 줄;
210
+ }
211
+
212
+ /* ══ 보고 ═══════════════════════════════════════════════════════ */
213
+
214
+ function 환경보고(E, D) {
215
+ const 표시 = { 됨: `${c.g}지금 바로${c[0]}`, 있음: `${c.g}이미 있음${c[0]}`, 준비: `${c.y}준비 먼저${c[0]}`, 막힘: `${c.r}지금은 막힘${c[0]}` };
216
+ console.log(`\n${c.b}이 컴퓨터를 재 봤습니다${c[0]} ${c.d}(${D.확인일} 기준 원장)${c[0]}\n`);
217
+ console.log(` Node.js ${E.노드 >= 18 ? c.g + process.version + c[0] : c.r + process.version + " — 18 이상이 필요합니다" + c[0]}`);
218
+ console.log(` Docker ${E.도커.뜸 ? `${c.g}응답함${c[0]} ${c.d}(${E.도커.판})${c[0]}` : E.도커.있나 ? `${c.y}깔려 있지만 응답 없음${c[0]}` : `${c.d}없음${c[0]}`}`);
219
+ console.log(` LLM API 키 ${E.LLM키.length ? `${c.g}${E.LLM키.join(", ")}${c[0]}` : `${c.d}환경에 안 보임${c[0]}`}`);
220
+ console.log(` Claude Code ${E.클로드코드 ? `${c.g}있음${c[0]}` : `${c.d}없음 — 커서·코덱스에서도 됩니다${c[0]}`}`);
221
+
222
+ console.log(`\n${c.b}다섯 중 지금 어디까지 되나${c[0]}\n`);
223
+ for (const { p, 상태, 왜 } of 준비표(E, D)) {
224
+ console.log(` ${c.b}${p.번호}. ${p.이름}${c[0]} ${표시[상태]}`);
225
+ if (왜) console.log(` ${c.d}${왜}${c[0]}`);
226
+ console.log(` ${c.cy}${p.설치}${c[0]}`);
227
+ if (p.이어서) console.log(` ${c.cy}${p.이어서}${c[0]}`);
228
+ console.log(` ${c.d}${굵게(p["★함정"])}${c[0]}`);
229
+ console.log();
230
+ }
231
+
232
+ console.log(`${c.b}영상이 말하지 않은 것${c[0]}`);
233
+ for (const [k, v] of Object.entries(D["★영상이_말하지_않은_것"])) {
234
+ if (k.startsWith("_") || k === "판정") continue; /* 판정은 아래에 굵게 따로 세운다 */
235
+ console.log(` ${c.d}${k} ${굵게(String(v))}${c[0]}`);
236
+ }
237
+ console.log(`\n ${c.b}판정${c[0]} ${c.d}${굵게(D["★영상이_말하지_않은_것"].판정)}${c[0]}`);
238
+
239
+ console.log(`\n${c.b}값이 드는 자리${c[0]}`);
240
+ for (const r of D["★공짜의범위"]["★따로_드는것"]) console.log(` ${c.d}· ${r.무엇} — ${r.값} (${r.근거})${c[0]}`);
241
+ console.log(`\n${c.d}${D["★상표"].고지}${c[0]}\n`);
242
+ }
243
+
244
+ /** 「끝난 뒤 한 칸」 — ★아무것도 못 깔았으면 안 띄운다. */
245
+ function 꼬리(깔았나) {
246
+ if (!깔았나) return;
247
+ const t = TAIL[퍼널];
248
+ console.log();
249
+ for (const 줄 of t.이음) console.log(`${c.d}${굵게(줄)}${c[0]}`);
250
+ console.log(`\n ${c.b}${t.제목}${c[0]} ${c.d}— ${t.한줄}${c[0]}`);
251
+ console.log(` ${c.cy}${링크(퍼널)}${c[0]}`);
252
+ console.log(`${c.d}${마지막}${c[0]}\n`);
253
+ }
254
+
255
+ /* ══ 심기 ═══════════════════════════════════════════════════════ */
256
+
257
+ function 심기() {
258
+ mkdirSync(대상뿌리, { recursive: true });
259
+ cpSync(원본, 대상, { recursive: true });
260
+
261
+ /* ★★쓴 뒤 다시 읽어 본다 — 복사는 조용히 실패한다 [[kit-update-selfcheck]] */
262
+ const 있어야할것 = ["SKILL.md", "plugin5.json"];
263
+ for (const f of 있어야할것) {
264
+ const p = join(대상, f);
265
+ if (!existsSync(p)) throw new Error(`심었는데 ${f} 이 없다 — ${p}`);
266
+ if (readFileSync(p, "utf8").length < 200) throw new Error(`${f} 이 너무 짧다 — 복사가 끊긴 것 같다`);
267
+ }
268
+ const 원장 = JSON.parse(readFileSync(join(대상, "plugin5.json"), "utf8"));
269
+ if (!Array.isArray(원장.플러그인) || 원장.플러그인.length !== 5)
270
+ throw new Error("심은 원장의 플러그인이 다섯이 아니다 — 복사가 깨졌다");
271
+ return 대상;
272
+ }
273
+
274
+ /* ══ 자기시험 — ★양방향으로 본다 [[verifier-must-be-tested-both-ways]] ══ */
275
+
276
+ function 자기시험() {
277
+ const 나쁨 = [];
278
+ const r = 원장읽기();
279
+ if (!r.됨) { console.log(`${c.r}✗ ${r.이유}${c[0]}`); process.exit(1); }
280
+ const D = r.d;
281
+
282
+ /* 오탐 — 멀쩡한 원장을 막으면 안 된다 */
283
+ const 문제 = 원장검사(D);
284
+ if (문제.length) 나쁨.push(...문제.map((m) => `오탐 또는 진짜 문제: ${m}`));
285
+
286
+ /* 미탐 ① 지역 제한 확인이 빠지면 잡아야 한다 */
287
+ {
288
+ const 흉내 = JSON.parse(JSON.stringify(D));
289
+ 흉내.플러그인[2]["★법"] = "";
290
+ if (!원장검사(흉내).some((m) => m.includes("★법"))) 나쁨.push("미탐: strix 의 법 조항을 지워도 통과한다");
291
+ }
292
+ /* 미탐 ② npx 에 --yes 가 빠지면 잡아야 한다 */
293
+ {
294
+ const 흉내 = JSON.parse(JSON.stringify(D));
295
+ 흉내.플러그인[3].설치 = "npx skillui --url https://example.com";
296
+ if (!원장검사(흉내).some((m) => m.includes("--yes"))) 나쁨.push("미탐: npx 에서 --yes 를 빼도 통과한다");
297
+ }
298
+ /* 미탐 ③ 조건 없는 단정이 섞이면 잡아야 한다 */
299
+ {
300
+ const 흉내 = JSON.parse(JSON.stringify(D));
301
+ 흉내.플러그인[0].한줄 = "누구나 바로 됩니다. 설정 없이 깔면 끝입니다.";
302
+ if (!원장검사(흉내).some((m) => m.includes("단정"))) 나쁨.push("미탐: 조건 없는 단정이 섞여도 통과한다");
303
+ }
304
+ /* 미탐 ④ 다섯이 아니면 잡아야 한다 */
305
+ {
306
+ const 흉내 = JSON.parse(JSON.stringify(D));
307
+ 흉내.플러그인.pop();
308
+ if (!원장검사(흉내).some((m) => m.includes("다섯"))) 나쁨.push("미탐: 넷만 있어도 통과한다");
309
+ }
310
+ /* 심는 자리에 SKILL.md 가 실제로 있나 (네트워크 안 씀) */
311
+ if (!existsSync(join(원본, "SKILL.md"))) 나쁨.push("skill/SKILL.md 가 패키지에 없다 — 깔아도 빈 폴더가 된다");
312
+ /* 꼬리 문안이 있나 */
313
+ if (!TAIL[퍼널]) 나쁨.push(`tail.mjs 에 「${퍼널}」 문안이 없다`);
314
+
315
+ if (나쁨.length) { for (const m of 나쁨) console.log(`${c.r}✗${c[0]} ${m}`); process.exit(1); }
316
+ console.log(`${c.g}✓${c[0]} 자기시험 통과 — 원장 ${D.플러그인.length}종 · 확인일 ${D.확인일} · 검사기 미탐 시험 4종`);
317
+ }
318
+
319
+ /* ══ 본체 ═══════════════════════════════════════════════════════ */
320
+
321
+ function 본체() {
322
+ if (자기시험모드) return 자기시험();
323
+
324
+ const r = 원장읽기();
325
+ if (!r.됨) { console.log(`${c.r}✗ ${r.이유}${c[0]}`); process.exit(1); }
326
+ const D = r.d;
327
+ const 문제 = 원장검사(D);
328
+ if (문제.length) {
329
+ console.log(`${c.r}✗ 원장이 규격에 안 맞습니다 — 화면에 잘못된 사실이 나갈 수 있어 멈춥니다${c[0]}`);
330
+ for (const m of 문제) console.log(` ${c.d}· ${m}${c[0]}`);
331
+ process.exit(1);
332
+ }
333
+
334
+ const E = 환경재기();
335
+ 환경보고(E, D);
336
+
337
+ if (확인만) {
338
+ console.log(`${c.d}재기만 했습니다 — 아무것도 깔지 않았습니다. 안내 스킬을 깔려면 ${c.cy}npx --yes reborn-plugin5${c.d} 를 그냥 실행하세요.${c[0]}\n`);
339
+ return;
340
+ }
341
+
342
+ if (E.이미.length) {
343
+ for (const 자리 of E.이미) console.log(`${c.g}✓${c[0]} ${자리.어디} 에 ${c.b}이미 있습니다${c[0]} ${c.d}(파일 ${자리.개수}개) — 또 깔지 마세요${c[0]}`);
344
+ console.log(`${c.d}다시 깔려면 그 폴더를 지우고 실행하세요.${c[0]}\n`);
345
+ return;
346
+ }
347
+
348
+ if (미리보기) {
349
+ console.log(`${c.d}깔 자리: ${대상}${c[0]}`);
350
+ console.log(`${c.d}넣을 것: ${readdirSync(원본).join(", ")}${c[0]}`);
351
+ console.log(`${c.d}미리보기라 아무것도 쓰지 않았습니다.${c[0]}\n`);
352
+ return;
353
+ }
354
+
355
+ let 깔았나 = false;
356
+ try {
357
+ const p = 심기();
358
+ console.log(`${c.g}✓${c[0]} 안내 스킬을 깔았습니다 — ${c.b}${p}${c[0]}`);
359
+ console.log(`${c.d}클로드 코드를 다시 시작하면 「${스킬이름}」 이 잡힙니다. 다섯 중 무엇부터 붙일지 물어보세요.${c[0]}`);
360
+ 깔았나 = true;
361
+ } catch (e) {
362
+ console.log(`${c.r}✗ 못 깔았습니다 — ${e.message}${c[0]}`);
363
+ console.log(`${c.d}위의 다섯 줄은 그대로 쓰실 수 있습니다. 안내 스킬 없이도 됩니다.${c[0]}`);
364
+ process.exitCode = 1;
365
+ }
366
+ 꼬리(깔았나);
367
+ }
368
+
369
+ 본체();
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "reborn-plugin5",
3
+ "version": "1.0.0",
4
+ "description": "영상에서 소개한 바이브 코딩 플러그인 5종(Playwright CLI · Supabase MCP · Strix · SkillUI · Context7)을 붙이기 전에 이 컴퓨터를 먼저 재 주는 안내 스킬입니다. 다섯 줄은 공개돼 있지만 준비물이 서로 다릅니다 — Strix 는 도커가 떠 있어야 하고 LLM 키가 따로 들며, Supabase 는 읽기전용을 켜야 지우는 도구가 안 열리고, Playwright 는 CLI 판과 MCP 판이 다릅니다. 도커·노드·에이전트를 실제로 재서 지금 바로 되는 것과 준비가 먼저인 것을 갈라 줍니다.",
5
+ "keywords": [
6
+ "claude",
7
+ "claude-code",
8
+ "mcp",
9
+ "playwright",
10
+ "supabase",
11
+ "strix",
12
+ "skillui",
13
+ "context7",
14
+ "vibe-coding",
15
+ "cursor",
16
+ "korean"
17
+ ],
18
+ "homepage": "https://rebornlabs.kr/plugin5?utm_source=installer&utm_medium=cli&utm_campaign=plugin5",
19
+ "bugs": {
20
+ "url": "https://mobility.rebornlabs.kr/cs"
21
+ },
22
+ "license": "MIT",
23
+ "author": "REBORN LABS",
24
+ "type": "module",
25
+ "bin": {
26
+ "reborn-plugin5": "cli.mjs"
27
+ },
28
+ "files": [
29
+ "cli.mjs",
30
+ "tail.mjs",
31
+ "skill/",
32
+ "README.md",
33
+ "안내스킬.md"
34
+ ],
35
+ "engines": {
36
+ "node": ">=18"
37
+ },
38
+ "scripts": {
39
+ "test": "node cli.mjs --self-test",
40
+ "check": "node cli.mjs --check"
41
+ },
42
+ "publishConfig": {
43
+ "access": "public"
44
+ }
45
+ }
package/skill/SKILL.md ADDED
@@ -0,0 +1,109 @@
1
+ ---
2
+ name: vibe-plugins-guide
3
+ description: 바이브 코딩에 붙이는 플러그인 5종(Playwright CLI · Supabase MCP · Strix · SkillUI · Context7)을 붙이기 전에 이 컴퓨터를 재고, 다섯 중 지금 바로 되는 것과 준비가 먼저인 것을 갈라 준다. "플러그인 뭐 깔지", "브라우저 자동으로 열어서 확인", "SQL 없이 DB", "내 앱 보안 점검", "이 사이트 디자인 뜯어와", "최신 문서 물려줘", "MCP 뭐 붙이지", "Strix 가 안 돌아", "도커가 필요하다는데", "Supabase MCP 읽기전용" 같은 이야기가 나올 때 쓴다.
4
+ ---
5
+
6
+ # 바이브 코딩 플러그인 5종 — 붙이기 전에 재는 안내
7
+
8
+ 원장은 `plugin5.json` 이다. **여기 없는 숫자·이름은 말하지 않는다.**
9
+ 확인일이 지났으면 다시 재고 원장을 먼저 고친다.
10
+
11
+ ## 0. 먼저 이걸 말한다
12
+
13
+ 다섯은 **서로 다른 준비물**을 요구한다. 「다섯 개 다 깔면 된다」가 아니다.
14
+
15
+ | | 도구 | 지금 바로 되나 |
16
+ |---|---|---|
17
+ | 1 | Playwright CLI | ✅ 노드 18 이상이면 한 줄 |
18
+ | 2 | Supabase MCP | ⚠️ 계정·project_ref 먼저 · **읽기전용을 켜라** |
19
+ | 3 | Strix | ⚠️ **도커가 떠 있어야** 하고 **LLM 키가 따로 든다** |
20
+ | 4 | SkillUI | ✅ 한 줄 · 키 자체가 없다 |
21
+ | 5 | Context7 | ✅ 한 줄 · 키 없이도 되나 요청 제한이 있다 |
22
+
23
+ ## 1. 이 컴퓨터를 잰다
24
+
25
+ ```
26
+ npx --yes reborn-plugin5 --check
27
+ ```
28
+
29
+ 도커가 **지금 응답하는지**, 노드 판이 되는지, LLM 키가 환경에 있는지,
30
+ 클로드 코드가 있는지, 다섯 중 무엇이 이미 붙어 있는지를 실제로 본다.
31
+ **「아마 될 겁니다」 라고 말하지 않는다.** 못 보면 「모른다」고 한다.
32
+
33
+ ## 2. 하나씩 붙인다 — 한꺼번에 붙이지 마라
34
+
35
+ MCP 를 여러 개 붙이면 **도구 스키마가 매 호출 문맥에 실린다.**
36
+ 지금 하는 일에 쓰는 것부터 하나씩 붙이는 편이 낫다.
37
+
38
+ ### 1. Playwright CLI — 화면을 눌러 보고 스크린샷을 찍는다
39
+
40
+ ```
41
+ npm install -g @playwright/cli@latest
42
+ playwright-cli install --skills
43
+ ```
44
+
45
+ ★**CLI 와 MCP 는 다른 물건이다.** 저장소 README 가 코딩 에이전트에는 CLI+스킬이 맞다고
46
+ 적어 둔다 — MCP 는 접근성 트리와 도구 스키마가 문맥에 실려 토큰을 많이 쓴다.
47
+ 둘을 같이 붙이면 같은 일을 두 벌로 들고 있게 된다.
48
+
49
+ ### 2. Supabase MCP — SQL 없이 데이터베이스를 짓는다
50
+
51
+ ```
52
+ claude mcp add --transport http supabase "https://mcp.supabase.com/mcp?read_only=true&features=database,docs"
53
+ ```
54
+
55
+ ★**`read_only=true` 를 빼지 마라.** 빼면 지우고 바꾸는 도구까지 같이 열린다.
56
+ 운영 프로젝트가 아니라 개발 프로젝트의 `project_ref` 로 먼저 붙여 본다.
57
+
58
+ ### 3. Strix — 내 앱을 실제로 공격해 본다
59
+
60
+ ```
61
+ curl -sSL https://strix.ai/install | bash
62
+ npx --yes skills add usestrix/strix
63
+ ```
64
+
65
+ ★**도커가 떠 있어야 한다.** 첫 실행이 샌드박스 이미지를 받는다 —
66
+ 안 떠 있으면 거기서 멈추고 「설치가 안 된다」로 보인다.
67
+ ★**LLM API 키가 따로 든다.** 도구는 공짜지만 도구가 부르는 모델은 아니다.
68
+ ★★**허락받은 대상에만 돌린다.** 저장소 README 가 「Authorized use only」 를 명시한다 —
69
+ 내가 소유했거나 문서로 허락받은 것이 아니면 겨누지 마라. 대부분의 나라에서 위법이다.
70
+
71
+ ### 4. SkillUI — 사이트의 결을 재 온다
72
+
73
+ ```
74
+ npx --yes skillui --url https://example.com
75
+ ```
76
+
77
+ ★**AI 를 쓰지 않는다.** 정적 분석이라 키가 없고 값도 안 든다.
78
+ 뽑아 오는 것은 **치수**(색·글꼴·간격·모서리)지 남의 사진·로고·본문이 아니다.
79
+
80
+ ### 5. Context7 — 최신 문서를 물려준다
81
+
82
+ ```
83
+ npx --yes ctx7 setup --claude
84
+ ```
85
+
86
+ ★키 없이도 붙지만 **요청 제한**이 걸린다. 이 명령이 브라우저 로그인으로 무료 키를
87
+ 만들어 붙여 준다. CLI+스킬 모드와 MCP 모드 중 고를 수 있다.
88
+
89
+ ## 3. 안 되는 것처럼 보일 때
90
+
91
+ | 증상 | 대개 이것이다 |
92
+ |---|---|
93
+ | Strix 첫 실행이 멈춘다 | 도커 데스크톱이 안 떠 있다. `docker version` 이 답하는지 본다 |
94
+ | 깔았는데 아무 일도 안 일어난다 | 에이전트를 다시 시작하지 않았거나, 그 일에 해당하는 스킬이 없다 |
95
+ | Supabase 가 테이블을 못 만든다 | 읽기전용으로 붙였다 — 의도한 것이면 그대로 두는 편이 안전하다 |
96
+ | Context7 이 한창 쓰다 느려진다 | 키 없이 쓰고 있어 요청 제한에 걸렸다 |
97
+ | 엉뚱한 패키지가 깔렸다 | 이름이 흔하다. 저장소 주소로 확인하고 깐다 |
98
+
99
+ ## 4. 값
100
+
101
+ 다섯 전부 오픈소스다 — Apache-2.0 셋, MIT 둘. 지역 제한 조항은 없다.
102
+ 다만 **Strix 가 부르는 LLM** 은 별도 과금이고, Supabase 프로젝트와 Context7 키는
103
+ 무료 등급이 있다. **도구가 공짜라고 쓰는 값이 0원은 아니다.**
104
+
105
+ ## 5. 상표
106
+
107
+ Playwright 는 Microsoft, Supabase MCP 는 Supabase, Strix 는 usestrix,
108
+ SkillUI 는 amaancoderx, Context7 은 Upstash 의 것이다.
109
+ 리본랩스는 만든 곳들과 아무 관계가 없다.
@@ -0,0 +1,142 @@
1
+ {
2
+ "_doc": "바이브 코딩 플러그인 5종 사실 원장 — 릴스·착지·DM·설치기가 전부 이 파일 하나를 본다. 지어낸 숫자·지어낸 이름이 화면에 뜨지 않게 하는 것이 목적이다. 고칠 일이 생기면 여기부터 고친다.",
3
+ "확인일": "2026-09-03",
4
+ "확인방법": "npm 레지스트리(registry.npmjs.org)와 PyPI, GitHub API 를 직접 호출해 버전·라이선스·별을 재고, 각 저장소의 README 를 받아 요구사항·설치 명령을 그대로 읽었다. 사람이 기억으로 적은 값은 하나도 없다.",
5
+
6
+ "참고본": {
7
+ "계정": "@nick_saraev",
8
+ "파일": "문제해결/릴스/KakaoTalk_20260825_225636176.mp4",
9
+ "길이": 49.519,
10
+ "말한것": "커서나 클로드 코드로 바이브 코딩 중이라면 꼭 챙겨야 할 플러그인 5가지",
11
+ "★참고본이_안한말": "다섯 중 셋은 그냥 깔리지 않는다 — Strix 는 도커와 LLM 키가 있어야 돌고, Supabase 는 읽기전용을 안 켜면 지우는 도구까지 열리고, Context7 은 키 없이도 되지만 요청 제한이 걸린다. 참고본은 무엇을 해 주는지만 말한다."
12
+ },
13
+
14
+ "플러그인": [
15
+ {
16
+ "번호": 1,
17
+ "키": "playwright",
18
+ "이름": "Playwright CLI",
19
+ "한줄": "AI 가 직접 브라우저를 열어 방금 만든 화면을 눌러 보고 스크린샷을 찍는다. 사람이 보기 전에 깨진 화면과 콘솔 오류를 잡는다.",
20
+ "패키지": "@playwright/cli",
21
+ "버전": "0.1.19",
22
+ "라이선스": "Apache-2.0",
23
+ "저장소": "https://github.com/microsoft/playwright-cli",
24
+ "별": 13040,
25
+ "만든곳": "Microsoft",
26
+ "설치": "npm install -g @playwright/cli@latest",
27
+ "이어서": "playwright-cli install --skills",
28
+ "요구": ["Node.js 18 이상", "클로드 코드·코파일럿 같은 코딩 에이전트"],
29
+ "★함정": "★CLI 와 MCP 는 다른 물건이다. 참고본이 말한 것은 CLI 쪽이고, 저장소 README 도 코딩 에이전트에는 CLI+스킬이 맞다고 적어 둔다 — MCP 는 도구 스키마와 접근성 트리가 매 호출 문맥에 실려 토큰을 많이 쓴다. 둘을 같이 붙이면 같은 일을 두 벌로 들고 있게 된다.",
30
+ "★근거": "microsoft/playwright-cli README 의 「Playwright CLI vs Playwright MCP」 절과 Requirements 절"
31
+ },
32
+ {
33
+ "번호": 2,
34
+ "키": "supabase",
35
+ "이름": "Supabase MCP",
36
+ "한줄": "SQL 을 직접 쓰지 않아도 앱이 쓸 데이터베이스를 짓고 관리한다. 테이블·마이그레이션·로그를 에이전트가 다룬다.",
37
+ "패키지": "@supabase/mcp-server-supabase",
38
+ "버전": "0.11.0",
39
+ "라이선스": "Apache-2.0",
40
+ "저장소": "https://github.com/supabase-community/supabase-mcp",
41
+ "만든곳": "Supabase",
42
+ "설치": "claude mcp add --transport http supabase \"https://mcp.supabase.com/mcp?read_only=true&features=database,docs\"",
43
+ "요구": ["Supabase 계정과 프로젝트", "project_ref (프로젝트 설정에서 확인)"],
44
+ "★함정": "★읽기전용을 안 켜면 지우고 바꾸는 도구까지 같이 열린다. 공식 서버 주소가 `read_only=true` 를 파라미터로 받는다 — 붙일 때 켜 두고, 운영 프로젝트가 아니라 개발 프로젝트의 project_ref 를 먼저 쓰는 편이 안전하다.",
45
+ "★근거": "supabase-community/supabase-mcp README 의 서버 URL 예시(`?project_ref=<project-ref>&read_only=true&features=database,docs`)와 readOnly 옵션 설명"
46
+ },
47
+ {
48
+ "번호": 3,
49
+ "키": "strix",
50
+ "이름": "Strix",
51
+ "한줄": "진짜 침투 테스터처럼 내가 만든 앱을 실제로 공격해 본다. 놓친 보안 구멍을 찾아내고 고치는 곳까지 짚어 준다.",
52
+ "패키지": "strix-agent (PyPI)",
53
+ "버전": "1.6.1",
54
+ "라이선스": "Apache-2.0",
55
+ "저장소": "https://github.com/usestrix/strix",
56
+ "별": 60195,
57
+ "설치": "curl -sSL https://strix.ai/install | bash",
58
+ "이어서": "npx --yes skills add usestrix/strix",
59
+ "요구": ["Docker 가 떠 있어야 한다", "LLM API 키 (OpenAI·앤트로픽·구글 중 하나)"],
60
+ "★함정": "★★이 셋 중 유일하게 그냥 깔리지 않는다. 첫 실행이 샌드박스 도커 이미지를 받는데, 도커가 안 떠 있으면 거기서 멈춘다. 그리고 LLM 키는 별도 과금이다 — 도구는 공짜지만 도구가 부르는 모델은 아니다.",
61
+ "★법": "★★저장소 README 가 「Authorized use only」 를 명시한다 — 내가 소유했거나 문서로 허락받은 대상에만 돌려야 하고, 허락 없는 테스트는 대부분의 나라에서 위법이다. 남의 사이트에 겨누지 마라.",
62
+ "★근거": "usestrix/strix README 의 Prerequisites(도커·LLM 키)와 맨 아래 Authorized use only 경고"
63
+ },
64
+ {
65
+ "번호": 4,
66
+ "키": "skillui",
67
+ "이름": "SkillUI",
68
+ "한줄": "마음에 드는 사이트를 가리키면 색·글꼴·간격·모서리 같은 디자인 시스템을 통째로 뜯어 스킬 파일 한 장으로 만들어 준다.",
69
+ "패키지": "skillui",
70
+ "버전": "1.3.4",
71
+ "라이선스": "MIT",
72
+ "저장소": "https://github.com/amaancoderx/npxskillui",
73
+ "설치": "npx --yes skillui --url https://example.com",
74
+ "요구": ["Node.js 18 이상"],
75
+ "★함정": "★AI 를 쓰지 않는다 — 정적 분석이라 API 키가 필요 없고 값도 안 든다. 대신 뽑아 오는 것은 치수(색·글꼴·간격)지 남의 사진·로고·본문이 아니다. 화면을 베끼는 도구가 아니라 결을 재 오는 도구다.",
76
+ "★근거": "skillui npm README — 「Pure static analysis. No AI. No API keys.」"
77
+ },
78
+ {
79
+ "번호": 5,
80
+ "키": "context7",
81
+ "이름": "Context7",
82
+ "한줄": "라이브러리와 도구의 최신 문서를 코딩 어시스턴트에 그대로 물려준다. 옛 버전 기준으로 코드를 쓰는 일이 줄어든다.",
83
+ "패키지": "@upstash/context7-mcp",
84
+ "버전": "4.0.4",
85
+ "라이선스": "MIT",
86
+ "저장소": "https://github.com/upstash/context7",
87
+ "만든곳": "Upstash",
88
+ "설치": "npx --yes ctx7 setup --claude",
89
+ "요구": ["Node.js 18 이상"],
90
+ "★함정": "★키 없이도 쓸 수 있지만 요청 제한이 걸린다. `npx --yes ctx7 setup` 이 브라우저 로그인으로 무료 키를 만들어 붙여 준다 — 그 한 번을 건너뛰면 한창 쓰다가 조용히 느려진다. CLI+스킬 모드와 MCP 모드 중 고를 수 있고, 클로드 코드에는 `--claude` 를 준다.",
91
+ "★근거": "upstash/context7 README — 「API Key Recommended: Get a free API key … for higher rate limits」 와 `npx ctx7 setup` 절"
92
+ }
93
+ ],
94
+
95
+ "설치": {
96
+ "★명령": "npx --yes reborn-plugin5",
97
+ "★왜원장에두나": "릴스 자막·터미널 목업·착지 페이지·DM 이 전부 이 문자열 하나를 읽어 간다. 손으로 옮겨 적으면 어느 한 곳이 조용히 어긋나고, 그 자리가 고객 터미널에서 멈추는 자리가 된다.",
98
+ "재보기": "npx --yes reborn-plugin5 --check",
99
+ "★npx는yes": "안내문에 쓰는 명령에는 --yes 가 들어 있다. 없으면 클로드 코드 안에서 설치 확인 프롬프트를 기다리다 무음으로 멈춘다 [[npx-installer-needs-yes-flag]]",
100
+ "★우리가_까는것": "우리는 다섯 도구를 대신 깔지 않는다. 다섯 줄은 이미 공개돼 있고 우리가 대신 쳐 준다고 아껴지는 게 없다. 우리가 까는 것은 **안내 스킬 한 장**이다 — 이 컴퓨터에 도커가 떠 있는지, 노드 판이 맞는지, 클로드 코드가 어디 있는지를 실제로 재서 다섯 중 지금 바로 되는 것과 준비가 필요한 것을 갈라 준다."
101
+ },
102
+
103
+ "★공짜의범위": {
104
+ "도구": "다섯 전부 오픈소스다 — Apache-2.0 셋(Playwright CLI·Supabase MCP·Strix), MIT 둘(SkillUI·Context7). 받아서 쓰고 고치고 재배포해도 되며 저작권 표시만 남기면 된다.",
105
+ "지역": "Apache-2.0 과 MIT 에는 지역 제한 조항이 없다. 한국에서 쓰는 데 걸리는 조항을 보지 못했다 [[copied-reel-claims-need-license-territory-check]]",
106
+ "★따로_드는것": [
107
+ { "무엇": "Strix 가 부르는 LLM", "값": "별도 과금", "근거": "README 가 OpenAI·앤트로픽·구글 중 하나의 API 키를 요구한다" },
108
+ { "무엇": "Supabase 프로젝트", "값": "무료 등급 있음", "근거": "계정과 project_ref 가 있어야 붙는다" },
109
+ { "무엇": "Context7 키", "값": "무료 등급 있음", "근거": "키 없이도 되지만 요청 제한이 걸린다" }
110
+ ],
111
+ "★쓰는_모델값": "★도구가 공짜라고 쓰는 값이 0원은 아니다. 이 도구들을 읽고 일하는 것은 클로드 코드·커서 같은 에이전트이고, 그쪽 요금은 별개다. Strix 는 그 위에 자기 몫의 LLM 호출을 더 얹는다.",
112
+ "비교표": [
113
+ { "무엇": "Playwright CLI", "값": "0원", "근거": "Apache-2.0" },
114
+ { "무엇": "Supabase MCP", "값": "0원", "근거": "Apache-2.0 · 프로젝트는 무료 등급" },
115
+ { "무엇": "Strix", "값": "0원 (+LLM 값)", "근거": "Apache-2.0 · LLM 키 별도" },
116
+ { "무엇": "SkillUI", "값": "0원", "근거": "MIT · 키 자체가 없다" },
117
+ { "무엇": "Context7", "값": "0원", "근거": "MIT · 키 없이도 되고 무료 키로 제한이 풀린다" }
118
+ ]
119
+ },
120
+
121
+ "★영상이_말하지_않은_것": {
122
+ "_왜": "★★이 회차에서 우리가 참고본에 더하는 자리다. 참고본은 다섯이 무엇을 해 주는지까지만 말한다. 실제로 막히는 자리는 그 뒤에 있다.",
123
+ "①도커": "★★Strix 는 첫 실행에서 샌드박스 도커 이미지를 받는다. 도커 데스크톱이 안 떠 있으면 거기서 멈추고, 「설치가 안 된다」로 보인다. --check 가 도커가 실제로 응답하는지 본다.",
124
+ "②읽기전용": "★Supabase MCP 를 읽기전용 없이 붙이면 지우고 바꾸는 도구까지 열린다. 우리가 안내하는 주소에는 read_only=true 가 박혀 있다.",
125
+ "③CLI냐MCP냐": "★Playwright 는 CLI 판과 MCP 판이 따로 있다. 코딩 에이전트에는 CLI+스킬이 문맥을 훨씬 덜 먹는다 — 저장소 README 가 그렇게 적어 둔다. 둘을 같이 붙이면 같은 일을 두 벌로 든다.",
126
+ "④요청제한": "★Context7 은 키 없이도 붙지만 요청 제한이 있다. `npx --yes ctx7 setup` 한 번이 무료 키를 만들어 준다.",
127
+ "⑤허락": "★★Strix 는 겨눈 대상을 실제로 공격한다. 내 것이 아니면 돌리지 마라 — README 가 「Authorized use only」 를 명시한다.",
128
+ "판정": "다섯 중 셋(Playwright CLI · SkillUI · Context7)은 정말로 한 줄이면 된다. Supabase 는 계정과 project_ref 가, Strix 는 도커와 LLM 키가 먼저다. --check 가 이 컴퓨터에서 어느 쪽인지 갈라 준다."
129
+ },
130
+
131
+ "★상표": {
132
+ "고지": "Playwright 는 Microsoft, Supabase MCP 는 Supabase, Strix 는 usestrix, SkillUI 는 amaancoderx, Context7 은 Upstash 의 것입니다. 리본랩스는 만든 곳들과 아무 관계가 없고, 이 설치기는 깔기 전에 이 컴퓨터를 재 주는 안내 스킬입니다.",
133
+ "GitHub": "별 수는 GitHub 공개 API 에서 2026-09-03 에 읽은 값입니다.",
134
+ "npm": "버전과 라이선스는 npm 레지스트리와 PyPI 에서 2026-09-03 에 읽은 값입니다."
135
+ },
136
+
137
+ "★함정": {
138
+ "★다섯을_한꺼번에_붙이지_마라": "MCP 를 여러 개 붙이면 도구 스키마가 매 호출 문맥에 실린다. 지금 하는 일에 쓰는 것부터 하나씩 붙이는 편이 낫다.",
139
+ "★깔았다고_켜지지는_않는다": "스킬은 하는 일에 맞을 때 켜진다. 「깔았는데 아무 일도 안 일어난다」는 대개 그 일에 해당하는 스킬이 없거나, 에이전트를 다시 시작하지 않은 것이다.",
140
+ "★같은_이름의_다른_패키지": "npm 의 `skillui` 는 amaancoderx 가 만든 것이고, `skills` 는 vercel-labs 의 스킬 CLI 다. 이름이 흔해서 다른 걸 깔기 쉽다 — 저장소 주소로 확인하고 깐다."
141
+ }
142
+ }
package/tail.mjs ADDED
@@ -0,0 +1,24 @@
1
+ /**
2
+ * 「끝난 뒤 한 칸」 문안 — 정본은 `skillpack/tail_copy.mjs` 다.
3
+ * 사본이 여기 있는 이유는 하나뿐이다: npm 패키지는 폴더 밖을 import 할 수 없다.
4
+ * 고칠 일이 생기면 정본을 먼저 고치고 여기로 옮긴다. 반대로 하지 마라.
5
+ *
6
+ * 규율: ① 끝난 뒤 딱 한 칸 · ② 못 깔았으면 안 띄운다 · ③ 파일을 안 남긴다
7
+ * ④ 고지 블록 금지 · ⑤ 첫 줄은 방금 한 일에서 이어져야 한다
8
+ * ★클로드킷·자비스 풀스택은 여기서 말하지 않는다 — 스킬팩 구매 이후다(2026-08-24 전략).
9
+ */
10
+ export const 랜딩 = "https://rebornlabs.kr/skillpack";
11
+ export const 링크 = (퍼널) => `${랜딩}?utm_source=installer&utm_medium=cli&utm_campaign=${퍼널}`;
12
+
13
+ export const TAIL = {
14
+ plugin5: {
15
+ 이음: [
16
+ "방금 한 일은 **붙이기 전에 이 컴퓨터를 잰 것**입니다 — 도커가 떠 있는지, 노드 판이 되는지, 다섯 중 지금 바로 되는 것은 무엇인지.",
17
+ "소개 영상은 다섯이 무엇을 해 주는지까지 말합니다. 막히는 자리는 늘 **그 다음**입니다.",
18
+ ],
19
+ 제목: "리본랩스 스킬팩",
20
+ 한줄: "같은 방식으로 골라 담은 48종을 한 줄로. 8,900원",
21
+ },
22
+ };
23
+
24
+ export const 마지막 = "목록과 직접 까는 명령까지 그 페이지에 그대로 적어 두었습니다. 안 사셔도 됩니다.";
@@ -0,0 +1,58 @@
1
+ # 안내스킬 — `vibe-plugins-guide`
2
+
3
+ 이 패키지가 `~/.claude/skills/vibe-plugins-guide/` 에 심는 것.
4
+
5
+ | 파일 | 무엇 |
6
+ |---|---|
7
+ | `SKILL.md` | 클로드가 읽는 안내. **답하는 순서**가 여기 있다 |
8
+ | `plugin5.json` | **원장.** 모든 사실의 주인. 여기 없는 숫자·명령은 말하지 않는다 |
9
+
10
+ ★심는 것은 이 폴더 하나뿐이다. **공유 안내스킬에는 손대지 않는다** —
11
+ 같은 파일을 여러 설치기가 덮는 사고를 애초에 안 만든다.
12
+
13
+ ## 왜 원장을 따로 두나
14
+
15
+ 사실을 `SKILL.md` 본문에 적으면 두 곳이 서로 다른 말을 하기 시작한다.
16
+ 설치 명령·버전·라이선스·별 수·확인일은 **한 곳에서만** 나온다. [[one-metric-one-owner]]
17
+
18
+ ★특히 **설치 명령 문자열**이 그렇다. 릴스 자막·터미널 목업·착지 페이지·DM 이
19
+ 전부 원장의 `설치.★명령` 과 각 도구의 `설치` 를 읽어 간다.
20
+ 손으로 옮겨 적으면 어느 한 곳이 조용히 어긋나고, 그 자리가 고객 터미널에서 멈추는 자리가 된다.
21
+
22
+ 원장에는 **확인일과 확인방법**이 반드시 있다. 없으면 설치기가 막는다.
23
+
24
+ ## ★이 킷의 존재 이유는 `★영상이_말하지_않은_것` 이다
25
+
26
+ 참고본은 다섯이 **무엇을 해 주는지**까지만 말한다. 그건 맞다.
27
+ **준비물이 남는다:**
28
+
29
+ - ① **Strix 는 도커가 떠 있어야** 첫 실행에서 샌드박스 이미지를 받는다.
30
+ 안 떠 있으면 거기서 멈추고 「설치가 안 된다」로 보인다
31
+ - ② **Strix 는 LLM API 키가 따로 든다** — 도구는 공짜지만 도구가 부르는 모델은 아니다
32
+ - ③ **Supabase 는 읽기전용을 안 켜면** 지우고 바꾸는 도구까지 열린다
33
+ - ④ **Playwright 는 CLI 판과 MCP 판이 다르다** — 코딩 에이전트에는 CLI+스킬이 문맥을 덜 먹는다
34
+ - ⑤ **Context7 은 키 없이도 붙지만 요청 제한**이 걸린다
35
+
36
+ 원장에서 이 칸을 지우면 설치기가 **깔지 않고 멈춘다.**
37
+ 그게 없으면 우리는 참고본과 똑같은 말만 하는 패키지가 되기 때문이다.
38
+
39
+ ## ★법 조항은 빼면 안 된다
40
+
41
+ Strix 는 겨눈 대상을 **실제로 공격한다.** 저장소 README 가
42
+ 「Authorized use only」 를 명시한다 — 내 것이 아니면 돌리면 안 되고, 대부분의 나라에서 위법이다.
43
+ 원장의 `플러그인[strix].★법` 이 비면 설치기가 막는다. 이건 편의 문구가 아니라 안전 장치다.
44
+
45
+ ## ★숫자는 잰 값만 쓴다
46
+
47
+ 버전·라이선스·별 수는 2026-09-03 에 npm 레지스트리·PyPI·GitHub API 를 직접 호출해 읽은 값이다.
48
+ 기억으로 적은 값은 하나도 없다. 확인일이 지났으면 다시 재고 원장을 먼저 고친다.
49
+
50
+ ## 자기시험
51
+
52
+ ```
53
+ node cli.mjs --self-test
54
+ ```
55
+
56
+ ★**양방향으로 본다** — 멀쩡한 원장을 막지 않는지(오탐), 그리고
57
+ 법 조항을 지우거나 `--yes` 를 빼거나 조건 없는 단정을 섞거나 다섯이 넷이 되면
58
+ 실제로 잡는지(미탐 4종)를 같이 시험한다. [[verifier-must-be-tested-both-ways]]