reborn-v3code 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,89 @@
1
+ # reborn-v3code
2
+
3
+ 영상에서 소개한 **V3Code** 를 **받기 전에 먼저 재 주는** 안내 스킬입니다.
4
+
5
+ ```bash
6
+ npx --yes reborn-v3code
7
+ ```
8
+
9
+ ## 이게 무엇을 하나
10
+
11
+ `~/.claude/skills/v3code-guide/` 에 안내 스킬 하나를 심습니다. 그게 전부입니다.
12
+
13
+ **V3Code 자체는 저희가 깔지 않습니다.** 클로즈드소스 바이너리이고,
14
+ 남의 서명된 실행 파일을 저희 이름으로 밀어 넣는 건 할 수 있어도 하면 안 되는 일입니다.
15
+ 받는 결정은 쓰는 사람이 합니다.
16
+
17
+ ## 그럼 무엇을 파나
18
+
19
+ 실제로 막히는 자리는 설치가 아니라 **그 앞**입니다.
20
+
21
+ | 막히는 자리 | 이 패키지가 하는 일 |
22
+ |---|---|
23
+ | 「완전 무료」인 줄 알고 받았는데 API 키를 넣으래요 | **맨 앞에서** 무료의 범위를 말합니다 |
24
+ | 리눅스에서 받으러 갔더니 없어요 | 운영체제를 **먼저 재고** 거기서 멈춥니다 |
25
+ | MCP 로 붙인다는데 붙일 게 없어요 | `claude` · `cursor` · `code` 가 있는지 **실제로 찾습니다** |
26
+ | 붙이려는데 설정 파일이 어디죠 | `~/.claude.json` · `~/.cursor/mcp.json` 자리를 **찾아 줍니다** |
27
+
28
+ ```bash
29
+ npx --yes reborn-v3code --check # 깔지 않고 이 컴퓨터만 잽니다
30
+ ```
31
+
32
+ ## 무료의 범위
33
+
34
+ | | 값 | |
35
+ |---|---|---|
36
+ | 에디터 자체 | **0원** | 구독료가 없습니다 |
37
+ | AI 기능 | **내 API 키 값** | OpenAI·Anthropic 등에 제가 직접 결제합니다(BYOK) |
38
+ | 클라우드 인덱싱 | **유료 플랜** | 기본은 꺼져 있습니다 |
39
+ | 계정 | 무료 사용엔 불필요 | 결제할 때만 필요합니다 |
40
+
41
+ 공식 문구가 「Free — bring your own key」입니다.
42
+ **구독료가 없다는 뜻으로는 무료가 맞고, 돈이 하나도 안 든다는 뜻으로는 아닙니다.**
43
+
44
+ ## 영상과 공식 문서가 어긋나는 곳
45
+
46
+ 소개 영상을 보고 오셨다면 이 셋이 다르게 적혀 있습니다.
47
+ 영상이 틀렸다는 말이 아니라, 공식 페이지에 그렇게 적혀 있다는 뜻입니다.
48
+
49
+ | 영상 | 공식 |
50
+ |---|---|
51
+ | 메모리가 **여섯 층** | 공식 페이지엔 **세 층**(editor · workspace · chat). 여섯 개짜리 명칭 목록은 확인되지 않습니다 |
52
+ | 구조 도구 **열두 개** | **개수는 맞습니다.** 다만 12개가 각각 무엇인지는 공개돼 있지 않습니다 |
53
+ | 코드가 기기를 **절대 안 떠난다** | 기본값은 맞습니다. 다만 **모델을 부르면** 그 요청은 제가 고른 공급자로 나갑니다 |
54
+
55
+ 그리고 **오픈소스가 아닙니다.** VS Code 포크지만 제품 소스는 공개돼 있지 않습니다.
56
+ GitHub 에서 `v3code` 로 검색되는 저장소들은 무관한 동명 프로젝트입니다.
57
+
58
+ ## 이 컴퓨터를 재는 방식
59
+
60
+ 말로 「되실 겁니다」 하지 않습니다.
61
+
62
+ - 운영체제·아키텍처를 읽고 **다운로드 가능 여부**를 먼저 판정합니다
63
+ - API 키 환경변수 일곱 종을 **실제로 봅니다**
64
+ - `claude` · `cursor` · `code` · `codex` 를 `where`/`which` 로 **실제로 찾습니다**
65
+ - MCP 설정 파일이 **실제로 존재하는지** 열어 봅니다
66
+ - 못 찾으면 「모른다」고 합니다. **「된다」고 하지 않습니다**
67
+
68
+ ## 되돌리기
69
+
70
+ ```bash
71
+ rm -rf ~/.claude/skills/v3code-guide
72
+ ```
73
+
74
+ 심는 건 그 폴더 하나뿐입니다. 다른 곳은 건드리지 않습니다.
75
+
76
+ ## 자기시험
77
+
78
+ ```bash
79
+ npm test # = node cli.mjs --self-test (네트워크 안 씁니다)
80
+ ```
81
+
82
+ 원장에 확인일·확인방법·무료의 범위가 있는지, 라이선스가 클로즈드소스로 적혀 있는지,
83
+ 공개된 적 없는 12개 목록이 몰래 들어가 있지 않은지를 봅니다.
84
+ **검사기 자체도 양방향으로 시험합니다** — 멀쩡한 원장을 막지 않는지, 망가뜨린 원장을 통과시키지 않는지.
85
+
86
+ ---
87
+
88
+ MIT · REBORN LABS · 문의 https://mobility.rebornlabs.kr/cs
89
+ V3Code 는 K&D Labs 의 제품이며 저희와 아무 관계가 없습니다. 이 패키지는 안내 스킬입니다.
package/cli.mjs ADDED
@@ -0,0 +1,383 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * v3code-guide 설치기 — **영상이 말한 그 에디터를 받기 전에 재 준다.**
4
+ *
5
+ * npx --yes reborn-v3code 안내 스킬을 깐다 (이게 전부다)
6
+ * npx --yes reborn-v3code --check ★깔지 않고 **이 컴퓨터를 잰다**
7
+ * npx --yes reborn-v3code --dry-run 무엇을 할지 보여주기만 한다
8
+ * npx --yes reborn-v3code --local 홈(~/.claude/skills)이 아니라 현재 폴더에 깐다
9
+ * npx --yes reborn-v3code --self-test 자기시험 (네트워크 안 씀)
10
+ *
11
+ * ★★왜 에디터를 우리가 안 깔고 **안내 스킬**을 까나
12
+ * V3Code 는 **클로즈드소스 바이너리**다. 우리가 대신 내려받아 실행시키는 건
13
+ * 할 수 있어도 하면 안 되는 일이다 — 남의 서명된 바이너리를 우리 이름으로 밀어 넣는 꼴이다.
14
+ * 그리고 실제로 막히는 자리는 설치가 아니라 **그 앞**이다:
15
+ * ① 「완전 무료」인 줄 알고 받았는데 API 키를 넣으라고 한다 (BYOK)
16
+ * ② 리눅스면 다운로드 페이지에서 아예 안 내려간다
17
+ * ③ MCP 로 붙인다는데 붙일 에이전트가 이 컴퓨터에 없다
18
+ * 우리가 파는 건 바이너리가 아니라 **그 셋을 먼저 말해 주는 것**과 **실제로 재는 것**이다.
19
+ *
20
+ * ★★--check 가 이 설치기의 존재 이유다
21
+ * 말로 「되실 겁니다」 하지 않는다. 실행 파일을 실제로 찾고, 설정 파일을 실제로 연다.
22
+ * 못 찾으면 「모른다」고 한다 — 「된다」고 하지 않는다.
23
+ *
24
+ * ★★깔았다고 「됐다」고 하지 않는다.
25
+ * 복사는 조용히 실패한다(권한·경로·한글 홈디렉터리). 쓴 뒤 **다시 읽어 본다**
26
+ * [[kit-update-selfcheck]].
27
+ */
28
+ import { execFileSync } from "node:child_process";
29
+ import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync } from "node:fs";
30
+ import { homedir, platform, arch } from "node:os";
31
+ import { dirname, join } from "node:path";
32
+ import { fileURLToPath } from "node:url";
33
+ import { 링크, TAIL, 마지막 } from "./tail.mjs";
34
+
35
+ const HOME = homedir();
36
+ const 여기 = dirname(fileURLToPath(import.meta.url));
37
+ const 인자 = process.argv.slice(2);
38
+ const 확인만 = 인자.includes("--check");
39
+ const 미리보기 = 인자.includes("--dry-run");
40
+ const 여기에 = 인자.includes("--local");
41
+ const 자기시험모드 = 인자.includes("--self-test");
42
+
43
+ const c = { g: "\x1b[32m", r: "\x1b[31m", y: "\x1b[33m", d: "\x1b[90m", cy: "\x1b[36m", b: "\x1b[1m", 0: "\x1b[0m" };
44
+ const 굵게 = (t) => String(t).replace(/\*\*(.+?)\*\*/g, `${c[0]}${c.b}$1${c[0]}${c.d}`);
45
+
46
+ const 퍼널 = "v3code";
47
+ const 스킬이름 = "v3code-guide";
48
+ const 원본 = join(여기, "skill");
49
+ const 대상뿌리 = 여기에 ? join(process.cwd(), ".claude", "skills") : join(HOME, ".claude", "skills");
50
+ const 대상 = join(대상뿌리, 스킬이름);
51
+
52
+ /* ══ 원장 ═══════════════════════════════════════════════════════ */
53
+
54
+ function 원장읽기() {
55
+ const p = join(원본, "v3code.json");
56
+ if (!existsSync(p)) return { 됨: false, 이유: `원장이 없다 — ${p}` };
57
+ try { return { 됨: true, d: JSON.parse(readFileSync(p, "utf8")) }; }
58
+ catch (e) { return { 됨: false, 이유: `원장을 못 읽는다 — ${e.message}` }; }
59
+ }
60
+
61
+ /** ★조건 없이 단정하는 말. 홍보문에 섞이면 잡는다. [[kmong-no-unbounded-guarantee]]
62
+ * ★이 회차는 「오픈소스」도 금칙이다 — 클로즈드소스 제품이라 그 한 낱말이 사실을 뒤집는다. */
63
+ const 금칙 = [/완전\s*무료/, /무제한/, /평생/, /100\s*%\s*보장/, /누구나\s*바로/, /무조건/,
64
+ /오픈\s*소스/, /공짜로\s*다/];
65
+
66
+ /** ★금칙 검사에서 빼는 자리 — 「그 말을 하지 마라」고 적어 둔 문장까지 잡으면
67
+ * 검사기가 자기 규칙 문서를 막는다(회차 ㉔에서 실제로 밟았다). 부정문만 골라 뺀다. */
68
+ const 금칙면제 = /(하지\s*않는다|말하지\s*마라|쓰지\s*않는다|아니다|틀리다|금칙|안\s*된다|하지\s*마라|말하지\s*않는다)/;
69
+
70
+ /** ★낫표 안은 **인용**이다 — 우리가 하는 말이 아니라 남이 한 말을 옮긴 것이다.
71
+ * 이 킷의 본문 절반이 「참고본은 이렇게 말했다」이므로, 인용까지 잡으면
72
+ * 검사기가 자기 존재 이유를 막는다. 인용 부호가 없는 문장만 우리 주장으로 본다. */
73
+ const 인용벗기기 = (s) => String(s).replace(/「[^」]*」/g, "○");
74
+
75
+ function 금칙검사(텍스트, 어디) {
76
+ const 문제 = [];
77
+ for (const 원줄 of String(텍스트).split(/\n|(?<=[.。])\s+/)) {
78
+ const 줄 = 인용벗기기(원줄);
79
+ if (금칙면제.test(줄)) continue;
80
+ for (const re of 금칙) if (re.test(줄)) 문제.push(`${어디}에 조건 없는 단정: ${re.source}`);
81
+ }
82
+ return 문제;
83
+ }
84
+
85
+ function 원장검사(d) {
86
+ const 문제 = [];
87
+ const 있나 = (v) => v !== undefined && v !== null && v !== "";
88
+
89
+ if (!있나(d?.확인일)) 문제.push("확인일이 없다 — 언제 잰 값인지 모르면 사실은 못 쓴다");
90
+ if (!있나(d?.확인방법)) 문제.push("확인방법이 없다 — 어디서 읽었는지 없는 말은 지어낸 것과 구분이 안 된다");
91
+ if (!있나(d?.제품?.다운로드)) 문제.push("제품.다운로드 주소가 없다");
92
+
93
+ /* ★라이선스를 틀리면 이 패키지가 거짓말이 된다. 여기는 값까지 못 박는다. */
94
+ if (d?.라이선스?.구분 !== "클로즈드소스")
95
+ 문제.push("라이선스.구분 이 「클로즈드소스」가 아니다 — 이 제품은 소스가 공개돼 있지 않다");
96
+
97
+ /* ★리눅스 칸이 비면 리눅스 사용자가 받으러 갔다가 빈손으로 돌아온다. */
98
+ if (!있나(d?.플랫폼?.리눅스)) 문제.push("플랫폼.리눅스 칸이 비었다");
99
+
100
+ /* ★★이 킷의 존재 이유 — 「무료의 범위」가 비면 통과시키지 않는다.
101
+ 이게 없으면 우리는 참고본과 똑같은 말만 하는 패키지가 된다. */
102
+ const 범위 = d?.["★무료의범위"];
103
+ if (!범위) 문제.push("★무료의범위 칸이 없다 — 이 패키지가 존재할 이유가 사라진다");
104
+ else {
105
+ if (!/BYOK|내 키|내 것/.test(범위.모델 || ""))
106
+ 문제.push("★무료의범위.모델 이 BYOK(내 키)임을 말하지 않는다 — 그러면 범위를 안 나눈 것이다");
107
+ if (!/유료|별도/.test(범위.유료플랜 || ""))
108
+ 문제.push("★무료의범위.유료플랜 이 유료임을 말하지 않는다");
109
+ if (!Array.isArray(범위.비교표) || 범위.비교표.length < 3)
110
+ 문제.push("★무료의범위.비교표 가 3줄 미만이다");
111
+ }
112
+
113
+ /* ★★참고본과 공식이 어긋나는 자리 — 이게 있어야 우리가 더하는 한 줄이 생긴다. */
114
+ const 어긋 = d?.["★참고본과_공식이_어긋나는_곳"];
115
+ if (!어긋) 문제.push("★참고본과_공식이_어긋나는_곳 칸이 없다");
116
+ else {
117
+ for (const k of ["메모리층", "구조도구", "로컬", "무료"]) {
118
+ if (!어긋[k]?.판정) 문제.push(`★어긋나는곳.${k}.판정 이 비었다`);
119
+ }
120
+ /* 12개 목록을 원장이 들고 있으면 그게 곧 지어낸 목록이다. */
121
+ if (Array.isArray(어긋.구조도구?.목록))
122
+ 문제.push("★구조도구 목록이 원장에 들어 있다 — 공개된 적 없는 목록이다. 지어낸 것이다");
123
+ }
124
+
125
+ for (const m of 금칙검사(JSON.stringify(d), "원장")) 문제.push(m);
126
+ return 문제;
127
+ }
128
+
129
+ /* ══ 이 컴퓨터를 잰다 ══════════════════════════════════════════════
130
+ ★말로 판정하지 않는다. 실제로 찾는다. 못 찾으면 「모른다」고 한다. */
131
+
132
+ function 실행파일있나(cmd) {
133
+ const 찾기 = process.platform === "win32" ? "where" : "which";
134
+ try {
135
+ const out = execFileSync(찾기, [cmd], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], timeout: 6000 });
136
+ const 첫줄 = String(out).trim().split(/\r?\n/)[0];
137
+ return 첫줄 ? 첫줄.trim() : null;
138
+ } catch { return null; }
139
+ }
140
+
141
+ /** V3Code 가 이미 깔려 있는지. ★없다고 「못 깐다」는 뜻이 아니다 — 아직 안 깐 것뿐이다. */
142
+ function 이미깔렸나() {
143
+ const 후보 = process.platform === "win32"
144
+ ? [join(process.env.LOCALAPPDATA || "", "Programs", "V3Code"),
145
+ join(process.env.LOCALAPPDATA || "", "Programs", "v3code")]
146
+ : process.platform === "darwin"
147
+ ? ["/Applications/V3Code.app", join(HOME, "Applications", "V3Code.app")]
148
+ : [join(HOME, ".local", "share", "v3code")];
149
+ for (const p of 후보) if (p && existsSync(p)) return p;
150
+ return 실행파일있나("v3code");
151
+ }
152
+
153
+ function 환경재기() {
154
+ const R = {
155
+ os: platform(), arch: arch(),
156
+ 받을수있나: null, 리눅스막힘: false,
157
+ 키: [], 에이전트: [], mcp: [], 이미: null,
158
+ };
159
+
160
+ R.리눅스막힘 = R.os === "linux";
161
+ R.받을수있나 = R.os === "win32" || R.os === "darwin";
162
+
163
+ /* BYOK — 이게 이 제품의 진짜 관문이다 */
164
+ for (const k of ["ANTHROPIC_API_KEY", "OPENAI_API_KEY", "GOOGLE_API_KEY", "GEMINI_API_KEY",
165
+ "GROQ_API_KEY", "AZURE_OPENAI_API_KEY", "OPENROUTER_API_KEY"]) {
166
+ if (process.env[k]) R.키.push(k);
167
+ }
168
+
169
+ /* MCP 로 붙일 대상이 실제로 있나 */
170
+ for (const [cmd, 이름] of [["claude", "Claude Code"], ["cursor", "Cursor"], ["code", "VS Code"], ["codex", "Codex"]]) {
171
+ const p = 실행파일있나(cmd);
172
+ if (p) R.에이전트.push({ 이름, 경로: p });
173
+ }
174
+
175
+ /* 붙일 자리(설정 파일)를 미리 찾아 둔다 */
176
+ for (const [p, 이름] of [
177
+ [join(HOME, ".claude.json"), "Claude Code"],
178
+ [join(HOME, ".cursor", "mcp.json"), "Cursor"],
179
+ [join(process.cwd(), ".mcp.json"), "이 폴더(프로젝트 범위)"],
180
+ ]) {
181
+ if (existsSync(p)) R.mcp.push({ 이름, 경로: p });
182
+ }
183
+
184
+ R.이미 = 이미깔렸나();
185
+ return R;
186
+ }
187
+
188
+ function 환경보고(E, D) {
189
+ console.log(`\n${c.b}이 컴퓨터를 실제로 재 봤습니다${c[0]}`);
190
+ console.log(`${c.d}${"─".repeat(58)}${c[0]}`);
191
+
192
+ const os이름 = { win32: "윈도우", darwin: "맥", linux: "리눅스" }[E.os] || E.os;
193
+ if (E.리눅스막힘) {
194
+ console.log(`${c.r}✗${c[0]} ${os이름} (${E.arch}) — ${c.b}지금은 내려받을 수 없습니다${c[0]}`);
195
+ console.log(` ${c.d}${D.플랫폼.리눅스}${c[0]}`);
196
+ console.log(` ${c.y}★여기서 멈추는 게 낫습니다. 받으러 갔다가 빈손으로 오는 자리입니다.${c[0]}`);
197
+ } else if (E.받을수있나) {
198
+ console.log(`${c.g}✓${c[0]} ${os이름} (${E.arch}) — 내려받을 수 있습니다`);
199
+ console.log(` ${c.d}${E.os === "win32" ? D.플랫폼.윈도우 : D.플랫폼.맥}${c[0]}`);
200
+ } else {
201
+ console.log(`${c.y}…${c[0]} ${os이름} (${E.arch}) — 공식 다운로드 페이지에서 확인이 필요합니다`);
202
+ }
203
+
204
+ if (E.이미) console.log(`${c.g}✓${c[0]} 이미 깔려 있습니다 ${c.d}${E.이미}${c[0]}`);
205
+
206
+ console.log("");
207
+ if (E.키.length) {
208
+ console.log(`${c.g}✓${c[0]} API 키 ${E.키.join(", ")} ${c.d}— AI 기능을 돌릴 수 있습니다${c[0]}`);
209
+ } else {
210
+ console.log(`${c.y}…${c[0]} API 키를 못 찾았습니다`);
211
+ console.log(` ${c.d}${굵게("에디터는 **0원**이지만 AI 기능은 **내 키로** 돕니다(BYOK).")}${c[0]}`);
212
+ console.log(` ${c.d}키가 없으면 에디터는 깔리는데 ${굵게("**AI 기능이 안 돕니다**")}. 다른 이야기입니다.${c[0]}`);
213
+ }
214
+
215
+ console.log("");
216
+ if (E.에이전트.length) {
217
+ console.log(`${c.g}✓${c[0]} MCP 로 붙일 대상 ${E.에이전트.length}개 ${c.d}${E.에이전트.map((a) => a.이름).join(" · ")}${c[0]}`);
218
+ } else {
219
+ console.log(`${c.y}…${c[0]} Claude Code·Cursor 같은 에이전트를 못 찾았습니다`);
220
+ console.log(` ${c.d}MCP 연동은 ${굵게("**붙일 대상이 있어야**")} 의미가 있습니다.${c[0]}`);
221
+ }
222
+
223
+ if (E.mcp.length) {
224
+ console.log(`${c.g}✓${c[0]} MCP 설정 파일`);
225
+ for (const m of E.mcp) console.log(` ${c.d}${m.이름} → ${m.경로}${c[0]}`);
226
+ }
227
+
228
+ console.log("");
229
+ console.log(`${c.d}${굵게("무료의 범위 —")}${c[0]}`);
230
+ /* ★한글은 글자 하나가 두 칸이다 — padEnd 로 맞추면 표가 어긋난다 [[korean-text-never-use-ch-width]] */
231
+ const 표폭 = (s) => [...s].reduce((n, ch) => n + (/[ᄀ-ᇿ㄰-㆏가-힯一-鿿]/.test(ch) ? 2 : 1), 0);
232
+ const 채움 = (s, w) => s + " ".repeat(Math.max(1, w - 표폭(s)));
233
+ for (const [무엇, 값, 설명] of D["★무료의범위"].비교표) {
234
+ console.log(` ${c.d}${채움(무엇, 20)}${c[0]}${값} ${c.d}${설명}${c[0]}`);
235
+ }
236
+ console.log(`${c.d}${"─".repeat(58)}${c[0]}`);
237
+ }
238
+
239
+ /* ══ 심기 ═══════════════════════════════════════════════════════ */
240
+
241
+ function 심기() {
242
+ mkdirSync(대상, { recursive: true });
243
+ cpSync(원본, 대상, { recursive: true });
244
+ /* ★쓴 뒤 다시 읽는다 — 복사는 조용히 실패한다 [[kit-update-selfcheck]] */
245
+ const 문제 = [];
246
+ for (const f of readdirSync(원본)) {
247
+ const a = join(원본, f), b = join(대상, f);
248
+ if (!existsSync(b)) { 문제.push(`${f} 가 안 복사됐다`); continue; }
249
+ if (statSync(b).size !== statSync(a).size) 문제.push(`${f} 크기가 다르다 — 잘려 복사됐다`);
250
+ }
251
+ if (!문제.length) {
252
+ try { JSON.parse(readFileSync(join(대상, "v3code.json"), "utf8")); }
253
+ catch { 문제.push("깐 원장이 JSON 으로 안 읽힌다"); }
254
+ }
255
+ return 문제;
256
+ }
257
+
258
+ /* ══ 자기시험 — 네트워크 안 씀 ══════════════════════════════════ */
259
+
260
+ function 자기시험() {
261
+ const 나쁨 = [];
262
+ const L = 원장읽기();
263
+ if (!L.됨) { 나쁨.push(L.이유); return 나쁨; }
264
+ for (const m of 원장검사(L.d)) 나쁨.push(`원장: ${m}`);
265
+
266
+ if (!existsSync(join(원본, "SKILL.md"))) 나쁨.push("skill/SKILL.md 가 없다");
267
+ else {
268
+ const md = readFileSync(join(원본, "SKILL.md"), "utf8");
269
+ if (!/^---[\s\S]*?name:\s*v3code-guide/m.test(md))
270
+ 나쁨.push("SKILL.md 머리말의 name 이 v3code-guide 가 아니다 — 클로드가 못 찾는다");
271
+ if (!/description:/.test(md)) 나쁨.push("SKILL.md 에 description 이 없다 — 발동하지 않는다");
272
+ if (!/BYOK|내 키/.test(md))
273
+ 나쁨.push("SKILL.md 가 BYOK(모델은 내 키)를 말하지 않는다 — 이게 이 스킬의 첫 줄이다");
274
+ if (!/리눅스/.test(md))
275
+ 나쁨.push("SKILL.md 가 리눅스를 말하지 않는다 — 받으러 갔다가 빈손으로 오는 자리다");
276
+ if (!/클로즈드소스|공개돼 있지 않/.test(md))
277
+ 나쁨.push("SKILL.md 가 클로즈드소스임을 말하지 않는다");
278
+ for (const m of 금칙검사(md, "SKILL.md")) 나쁨.push(m);
279
+ }
280
+
281
+ /* ★검사기 자체를 양방향으로 본다 [[verifier-must-be-tested-both-ways]] */
282
+ const 좋은원장 = JSON.parse(JSON.stringify(L.d));
283
+ if (원장검사(좋은원장).length) 나쁨.push("자기시험 오탐: 멀쩡한 원장을 막는다");
284
+
285
+ const 나쁜1 = JSON.parse(JSON.stringify(L.d));
286
+ delete 나쁜1["★무료의범위"];
287
+ if (!원장검사(나쁜1).length) 나쁨.push("자기시험 미탐: 무료의범위가 빠져도 통과한다");
288
+
289
+ const 나쁜2 = JSON.parse(JSON.stringify(L.d));
290
+ 나쁜2.라이선스.구분 = "오픈소스";
291
+ if (!원장검사(나쁜2).length) 나쁨.push("자기시험 미탐: 라이선스를 오픈소스로 바꿔도 통과한다");
292
+
293
+ const 나쁜3 = JSON.parse(JSON.stringify(L.d));
294
+ 나쁜3["★참고본과_공식이_어긋나는_곳"].구조도구.목록 = ["a", "b", "c"];
295
+ if (!원장검사(나쁜3).length) 나쁨.push("자기시험 미탐: 12개 목록을 지어내도 통과한다");
296
+
297
+ const 나쁜4 = JSON.parse(JSON.stringify(L.d));
298
+ 나쁜4.플랫폼.리눅스 = "";
299
+ if (!원장검사(나쁜4).length) 나쁨.push("자기시험 미탐: 리눅스 칸이 비어도 통과한다");
300
+
301
+ return 나쁨;
302
+ }
303
+
304
+ /* ══ 끝난 뒤 한 칸 ═══════════════════════════════════════════════
305
+ 규율: ① 끝난 뒤 딱 한 칸 · ② 못 깔았으면 안 띄운다 · ③ 파일을 안 남긴다
306
+ ④ 고지 블록 금지 · ⑤ 첫 줄은 방금 한 일에서 이어져야 한다 */
307
+ function 꼬리() {
308
+ const T = TAIL[퍼널];
309
+ if (!T) return;
310
+ console.log("");
311
+ for (const l of T.이음) console.log(`${c.d}${굵게(l)}${c[0]}`);
312
+ console.log("");
313
+ console.log(` ${c.b}${T.제목}${c[0]} ${c.d}${T.한줄}${c[0]}`);
314
+ console.log(` ${c.cy}${링크(퍼널)}${c[0]}`);
315
+ console.log("");
316
+ console.log(`${c.d}${마지막}${c[0]}`);
317
+ }
318
+
319
+ /* ══ 본체 ═══════════════════════════════════════════════════════ */
320
+
321
+ if (자기시험모드) {
322
+ const 나쁨 = 자기시험();
323
+ if (나쁨.length) {
324
+ console.log(`${c.r}자기시험 실패${c[0]}`);
325
+ for (const m of 나쁨) console.log(" - " + m);
326
+ process.exit(1);
327
+ }
328
+ console.log(`${c.g}자기시험 통과${c[0]}`);
329
+ process.exit(0);
330
+ }
331
+
332
+ const L = 원장읽기();
333
+ if (!L.됨) { console.log(`${c.r}✗ ${L.이유}${c[0]}`); process.exit(1); }
334
+ const 원장문제 = 원장검사(L.d);
335
+ if (원장문제.length) {
336
+ console.log(`${c.r}✗ 원장이 성하지 않다 — 깔지 않는다${c[0]}`);
337
+ for (const m of 원장문제) console.log(" - " + m);
338
+ process.exit(1);
339
+ }
340
+ const D = L.d;
341
+
342
+ console.log("");
343
+ console.log(`${c.b}V3Code${c[0]} ${c.d}— ${D.제품.한줄} (${D.확인일} 확인)${c[0]}`);
344
+
345
+ /* ★★무엇이 무료인지를 **맨 앞에서** 말한다. 받고 나서 막히는 자리가 여기라서다. */
346
+ console.log("");
347
+ console.log(`${c.d}${굵게("**에디터는 0원**입니다 — 구독료가 없습니다.")}${c[0]}`);
348
+ console.log(`${c.d}${굵게("**모델은 내 키**입니다 — OpenAI·Anthropic 같은 데 제가 따로 결제합니다(BYOK).")}${c[0]}`);
349
+ console.log(`${c.d}클라우드 인덱싱 같은 부가 기능은 ${굵게("**별도 유료 플랜**")}입니다.${c[0]}`);
350
+ console.log(`${c.d}그리고 ${굵게("**오픈소스가 아닙니다**")} — VS Code 포크지만 소스는 공개돼 있지 않습니다.${c[0]}`);
351
+
352
+ const E = 환경재기();
353
+ 환경보고(E, D);
354
+
355
+ if (확인만) {
356
+ console.log(`${c.d}깔려면: npx --yes reborn-v3code${c[0]}\n`);
357
+ process.exit(0);
358
+ }
359
+
360
+ if (미리보기) {
361
+ console.log(`${c.d}할 일:${c[0]}`);
362
+ console.log(` ${스킬이름} → ${대상}`);
363
+ console.log(`${c.d}(--dry-run 이라 아무것도 안 했습니다)${c[0]}\n`);
364
+ process.exit(0);
365
+ }
366
+
367
+ const 문제 = 심기();
368
+ if (문제.length) {
369
+ console.log(`\n${c.r}✗ 심다가 막혔습니다${c[0]}`);
370
+ for (const m of 문제) console.log(" - " + m);
371
+ console.log(`${c.d}권한이나 경로 문제일 수 있습니다. --local 로 현재 폴더에 깔아 보세요.${c[0]}\n`);
372
+ process.exit(1);
373
+ }
374
+
375
+ console.log(`\n${c.g}✓${c[0]} ${c.b}${스킬이름}${c[0]} 을 깔았습니다`);
376
+ console.log(` ${c.d}${대상}${c[0]}`);
377
+ console.log("");
378
+ console.log(`${c.d}클로드 코드를 ${굵게("**다시 시작**")}하면 잡힙니다. 그 뒤 이렇게 물어 보세요:${c[0]}`);
379
+ console.log(` ${c.cy}"V3Code 받을까 하는데 내 환경에서 되나?"${c[0]}`);
380
+ console.log("");
381
+ console.log(`${c.d}지금 상태만 다시 재려면: ${c[0]}npx --yes reborn-v3code --check`);
382
+
383
+ 꼬리();
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "reborn-v3code",
3
+ "version": "1.0.0",
4
+ "description": "영상에서 소개한 V3Code(지속 메모리를 얹은 VS Code 포크 에디터)를 받기 전에 먼저 재 주는 안내 스킬입니다. 에디터는 0원이지만 AI 기능은 내 API 키로 돈다는 것(BYOK), 리눅스는 지금 안 내려간다는 것, MCP 로 붙일 에이전트가 이 컴퓨터에 있는지를 직접 재 줍니다.",
5
+ "keywords": [
6
+ "claude",
7
+ "claude-code",
8
+ "agent-skills",
9
+ "skill",
10
+ "v3code",
11
+ "mcp",
12
+ "code-editor",
13
+ "vscode",
14
+ "cursor",
15
+ "byok",
16
+ "korean"
17
+ ],
18
+ "homepage": "https://rebornlabs.kr/v3code?utm_source=installer&utm_medium=cli&utm_campaign=v3code",
19
+ "bugs": {
20
+ "url": "https://mobility.rebornlabs.kr/cs"
21
+ },
22
+ "license": "MIT",
23
+ "author": "REBORN LABS",
24
+ "type": "module",
25
+ "bin": {
26
+ "reborn-v3code": "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,93 @@
1
+ ---
2
+ name: v3code-guide
3
+ description: V3Code(지속 메모리를 얹은 VS Code 포크 에디터)를 내려받기 전에 무엇이 무료이고 무엇이 아닌지, 내 운영체제에서 받을 수 있는지, MCP 로 이미 쓰는 에이전트에 붙이려면 무엇이 필요한지 먼저 말해 준다. "V3Code", "v3code.dev", "AI 에디터 메모리", "코드베이스 기억하는 에디터", "커서 대신", "무료 AI 에디터", "MCP 로 코드 색인", "에디터가 옛 대화를 다 쏟는다" 같은 이야기가 나올 때 쓴다. ★가장 자주 하는 오해를 먼저 잡는다 — 「완전 무료」는 에디터 이야기이고 모델 값은 내 키다.
4
+ ---
5
+
6
+ # V3Code — 받기 전에 알아야 할 것
7
+
8
+ **정본 원장은 `v3code.json` 이다.** 이 문서가 말하는 사실은 전부 거기서 온다.
9
+ 원장에 없는 숫자·기능 이름을 말하지 마라. 확인한 날짜와 방법이 거기 적혀 있다.
10
+
11
+ ---
12
+
13
+ ## 0. 먼저 말할 것 — 순서를 지켜라
14
+
15
+ 사용자가 V3Code 를 물으면 **이 순서로** 답한다. 기능 자랑부터 하면 나중에 막힌다.
16
+
17
+ 1. **무엇이 무료인가** — 에디터는 0원이다. 구독료가 없다.
18
+ **다만 AI 기능은 내 API 키로 돈다**(BYOK). 공식 문구가 그렇게 적혀 있다.
19
+ 클라우드 인덱싱 같은 부가 기능은 별도 유료 플랜이다.
20
+ 2. **내 운영체제에서 받을 수 있나** — 윈도우·맥은 받는다.
21
+ **리눅스는 지금 다운로드 페이지에서 내려가지 않는다.**
22
+ 3. **오픈소스가 아니다** — VS Code 포크지만 제품 소스는 공개돼 있지 않다.
23
+ GitHub 에서 `v3code` 로 검색되는 저장소들은 **무관한 동명 프로젝트**다. 연결하지 마라.
24
+ 4. 그 다음에 기능을 말한다.
25
+
26
+ ---
27
+
28
+ ## 1. 자주 하는 오해 넷
29
+
30
+ | 들은 말 | 실제 |
31
+ |---|---|
32
+ | 「완전 무료」 | 구독료가 없다는 뜻으로는 맞다. **돈이 하나도 안 든다는 뜻으로는 틀리다** — 모델 값은 내가 낸다 |
33
+ | 「메모리가 여섯 층」 | 공식 페이지에 적힌 건 **세 층**(editor · workspace · chat)이다. 여섯 개짜리 명칭 목록은 공식 문구로 확인되지 않았다 |
34
+ | 「구조 도구 열두 개」 | **개수는 공식 문구가 맞다.** 다만 12개가 각각 무엇인지는 공개돼 있지 않다 — 목록을 지어내지 마라 |
35
+ | 「코드가 기기를 안 떠난다」 | 기본값은 맞다(텔레메트리·업로드 없음). **다만 모델을 부르는 순간 그 요청은 내가 고른 공급자로 나간다** |
36
+
37
+ ★사용자가 릴스나 영상을 보고 왔다면, 그 영상을 **틀렸다고 하지 마라.**
38
+ 「화면에 답이 떠 있는데 말하지 않았다」까지만 말하면 충분하다.
39
+
40
+ ---
41
+
42
+ ## 2. 이 컴퓨터를 재 준다
43
+
44
+ 말로 「되실 겁니다」 하지 않는다. 실제로 잰다.
45
+
46
+ ```
47
+ npx --yes reborn-v3code --check
48
+ ```
49
+
50
+ 재는 것 넷:
51
+
52
+ - **운영체제·아키텍처** — 리눅스면 지금은 받을 수 없다고 그 자리에서 말한다
53
+ - **API 키(BYOK)** — `ANTHROPIC_API_KEY` · `OPENAI_API_KEY` 등이 이 환경에 있는지
54
+ - **이미 쓰는 에이전트** — `claude` · `cursor` · `code` 실행 파일이 PATH 에 있는지.
55
+ MCP 로 붙일 대상이 실제로 있어야 그 기능이 의미가 있다
56
+ - **MCP 설정 파일 자리** — `~/.claude.json` · `~/.cursor/mcp.json` 이 어디 있는지 미리 찾아 둔다
57
+
58
+ ★키가 없으면 「못 쓴다」가 아니라 **「에디터는 깔리는데 AI 기능이 안 돈다」**고 말한다. 다른 말이다.
59
+
60
+ ---
61
+
62
+ ## 3. MCP 로 붙이는 이야기를 할 때
63
+
64
+ 공식 페이지는 Claude Code·Cursor 등에 붙는다고 말한다.
65
+ **그런데 설치 명령이나 설정 JSON 예시는 공개 페이지에서 찾지 못했다.**
66
+
67
+ → 그러면 예시를 **지어내지 마라.** 이렇게 말한다:
68
+
69
+ > 공식 페이지가 MCP 연동을 말하지만, 붙이는 명령은 앱 안 설정이나 공식 문서에서
70
+ > 확인해야 합니다. 제가 지어내면 안 되는 자리라 여기까지만 말씀드립니다.
71
+
72
+ ★그 대신 **붙일 자리**는 찾아 줄 수 있다 — `--check` 가 MCP 설정 파일 위치를 알려 준다.
73
+
74
+ ---
75
+
76
+ ## 4. 말하지 않는 것
77
+
78
+ - 「완전 무료」 · 「무제한」 · 「평생」 · 「누구나 바로」 — 조건 없는 단정은 쓰지 않는다
79
+ - 「오픈소스」 — 클로즈드소스다
80
+ - 여섯 층 메모리의 6개 이름을 **공식 명칭인 것처럼** 인용하는 것
81
+ - 12개 구조 도구의 **목록을 나열하는 것** (비공개다)
82
+ - 다른 에디터(Cursor·Copilot 등)가 나쁘다는 식의 비교 — 우리가 잰 적 없다
83
+ - 설치를 대신 눌러 주는 것. **바이너리를 내려받는 결정은 사용자가 한다**
84
+
85
+ ---
86
+
87
+ ## 5. 이 스킬이 하는 일과 안 하는 일
88
+
89
+ **한다**: 무엇이 무료인지 먼저 말한다 · 내 컴퓨터가 받을 수 있는지 잰다 ·
90
+ 참고본과 공식 문서가 어긋나는 자리를 그대로 보여 준다 · MCP 설정 파일 자리를 찾아 준다
91
+
92
+ **안 한다**: V3Code 를 대신 설치하지 않는다 · 성능을 평가하지 않는다(재 본 적 없다) ·
93
+ 다른 에디터와 우열을 말하지 않는다 · 공개되지 않은 기능 목록을 채워 넣지 않는다
@@ -0,0 +1,76 @@
1
+ {
2
+ "_doc": "V3Code 사실 원장 — 릴스·착지·DM·설치기가 **전부 이 파일 하나**를 본다. 지어낸 수치·지어낸 기능 이름이 화면에 오르는 것을 막는다.",
3
+ "확인일": "2026-09-02",
4
+ "확인방법": "공식 사이트(v3code.dev)·다운로드 페이지(app.v3code.dev/download)·약관(/terms)·개인정보처리방침(/privacy)을 직접 읽었다. 사이트가 JS 렌더링이라 렌더 프록시로 두 번 교차 확인했다. GitHub 에서 v3code 로 검색되는 저장소 둘은 **동명이인 프로젝트**임을 저장소 내용으로 확인해 배제했다.",
5
+
6
+ "제품": {
7
+ "이름": "V3Code",
8
+ "주소": "https://v3code.dev/",
9
+ "다운로드": "https://app.v3code.dev/download",
10
+ "한줄": "지속 메모리와 의미 색인을 얹은 VS Code 포크 에디터. 12개 구조 LSP 도구를 MCP 로 다른 에이전트에 연다.",
11
+ "회사": "K&D Labs",
12
+ "★정체": "독립 에디터가 아니라 **VS Code 포크**다. MCP 서버 단품이 아니다 — 에디터에 얹힌 기능이다."
13
+ },
14
+
15
+ "라이선스": {
16
+ "구분": "클로즈드소스",
17
+ "★주의": "VS Code 와 일부 오픈소스 부품 위에 얹었을 뿐 제품 소스는 공개돼 있지 않다. 약관에 「V3Code 의 인터페이스·테마·브랜딩·독자 코드는 회사 소유」라고 적혀 있다.",
18
+ "★하지마라": "「오픈소스」라고 말하지 않는다. GitHub 의 동명 저장소(H-Ekana/v3code · aGamingGod1234/v3code)는 **무관한 프로젝트**다 — 공식 저장소로 연결하지 마라."
19
+ },
20
+
21
+ "플랫폼": {
22
+ "윈도우": "x64 · 관리자 권한 불필요 · 자동 업데이트",
23
+ "맥": "Apple Silicon / Intel · 서명·공증됨",
24
+ "리눅스": "★현재 내려받을 수 없다(다운로드 페이지 기준)",
25
+ "설치방식": "바이너리 직접 내려받기. npm·brew 명령은 없다."
26
+ },
27
+
28
+ "★무료의범위": {
29
+ "_왜": "★★이 회차에서 우리가 참고본에 **더하는 한 줄**이다. 참고본은 「completely free」라고 말하고 화면에도 「Free to download / Free to run locally」를 띄운다. 틀린 말은 아니다 — 다만 무엇이 무료인지를 말하지 않았을 뿐이다.",
30
+ "에디터": "무료. 내려받는 데도 쓰는 데도 구독료가 없다.",
31
+ "모델": "★**BYOK — 내 키다.** 공식 문구가 「Free — bring your own key. Add your OpenAI, Anthropic, or any provider key」다. 즉 AI 기능을 쓰려면 내가 OpenAI·Anthropic 등에 따로 돈을 낸다.",
32
+ "유료플랜": "클라우드 인덱싱 등 부가 기능은 **별도 유료**다. Stripe 결제이고 계정(이메일)이 필요하다.",
33
+ "비교표": [
34
+ ["에디터 자체", "0원", "구독료 없음"],
35
+ ["AI 기능", "내 API 키 값", "OpenAI·Anthropic 등에 내가 직접 결제"],
36
+ ["클라우드 인덱싱", "유료 플랜", "기본은 꺼져 있다"],
37
+ ["계정", "무료 사용엔 불필요", "결제할 때만 필요"]
38
+ ]
39
+ },
40
+
41
+ "★참고본과_공식이_어긋나는_곳": {
42
+ "_왜": "★★참고본을 「거짓말」이라고 부르지 않는다. 우리가 확인한 범위에서 공식 문구와 다른 자리를 그대로 적어 둘 뿐이다.",
43
+ "메모리층": {
44
+ "참고본": "six memory layers — Semantic code index / Symbol graph / Verified fact injection / Compaction checkpoints / Indexed evidence retrieval / Raw local archive",
45
+ "공식": "3-layer (editor · workspace · chat)",
46
+ "판정": "★이 여섯 개 명칭은 공식 페이지에서 확인되지 않았다. 우리는 이 여섯을 **공식 명칭인 것처럼 인용하지 않는다.** 화면에 띄울 때는 「참고본이 띄운 목록」임이 드러나야 한다."
47
+ },
48
+ "구조도구": {
49
+ "참고본": "twelve structural tools built right in",
50
+ "공식": "12 structural LSP tools — 개수는 공식 문구다",
51
+ "판정": "★개수는 그대로 써도 된다. **다만 12개 목록은 비공개다** — 나열하면 그 자리에서 지어낸 것이 된다."
52
+ },
53
+ "로컬": {
54
+ "참고본": "Your code never leaves your device / No external database / No privacy risk",
55
+ "공식": "기본값으로 텔레메트리를 보내지 않고 코드베이스를 업로드하지 않는다. API 키는 로컬에서 AES-256-GCM 으로 암호화한다.",
56
+ "판정": "★기본값은 맞다. 다만 BYOK 구조상 **모델을 부르는 순간 그 요청은 내가 고른 공급자 서버로 나간다.** 그리고 유료 플랜의 클라우드 인덱싱을 켜면 달라진다."
57
+ },
58
+ "무료": {
59
+ "참고본": "completely free · all of it free",
60
+ "공식": "에디터는 무료 + BYOK. 유료 플랜 별도.",
61
+ "판정": "★절반만 사실이다. 구독료가 없다는 뜻으로는 맞고, 돈이 하나도 안 든다는 뜻으로는 틀리다."
62
+ }
63
+ },
64
+
65
+ "MCP": {
66
+ "붙는곳": ["Claude Code", "Cursor", "그 밖의 MCP 클라이언트"],
67
+ "★주의": "공식 페이지가 연동을 말하지만 **설치 명령·설정 JSON 예시는 공개 페이지에서 찾지 못했다.** 우리가 예시를 지어내지 않는다 — 스킬은 「어디를 봐야 하는지」까지만 말한다."
68
+ },
69
+
70
+ "★깔기전에_재는것": [
71
+ "리눅스면 지금은 못 받는다 — 이걸 먼저 말한다",
72
+ "AI 기능을 쓰려면 API 키가 있어야 한다. 지금 이 컴퓨터에 있는지 잰다",
73
+ "이미 쓰는 에디터·에이전트가 무엇인지 — MCP 로 붙일 대상이 실제로 있는지",
74
+ "MCP 설정 파일이 어디 있는지 — 붙일 자리를 미리 찾아 둔다"
75
+ ]
76
+ }
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
+ v3code: {
15
+ 이음: [
16
+ "방금 한 일은 **받기 전에 재 본 것**입니다 — 내 운영체제에서 받히는지, 모델 값은 어디서 나가는지, 붙일 에이전트가 있는지.",
17
+ "도구마다 이 세 가지가 다르고, 매번 이만큼 걸립니다. 소개 영상에는 안 나오니까요.",
18
+ ],
19
+ 제목: "리본랩스 스킬팩",
20
+ 한줄: "같은 방식으로 골라 담은 48종을 한 줄로. 8,900원",
21
+ },
22
+ };
23
+
24
+ export const 마지막 = "목록과 직접 까는 명령까지 그 페이지에 그대로 적어 두었습니다. 안 사셔도 됩니다.";
@@ -0,0 +1,67 @@
1
+ # 안내스킬 — `v3code-guide`
2
+
3
+ 이 패키지가 `~/.claude/skills/v3code-guide/` 에 심는 것.
4
+
5
+ | 파일 | 무엇 |
6
+ |---|---|
7
+ | `SKILL.md` | 클로드가 읽는 안내. **답하는 순서**가 여기 있다 |
8
+ | `v3code.json` | **원장.** 모든 사실의 주인. 여기 없는 기능 이름은 말하지 않는다 |
9
+
10
+ ★심는 것은 이 폴더 하나뿐이다. **공유 안내스킬에는 손대지 않는다** —
11
+ 같은 파일을 여러 설치기가 덮는 사고를 애초에 안 만든다.
12
+
13
+ ## 왜 원장을 따로 두나
14
+
15
+ 사실을 `SKILL.md` 본문에 적으면 두 곳이 서로 다른 말을 하기 시작한다.
16
+ 라이선스·플랫폼·무료의 범위는 **한 곳에서만** 나온다. [[one-metric-one-owner]]
17
+
18
+ 원장에는 **확인일과 확인방법**이 반드시 있다. 없으면 설치기가 막는다.
19
+
20
+ ## ★이 킷의 존재 이유는 `★무료의범위` 와 `★참고본과_공식이_어긋나는_곳` 둘이다
21
+
22
+ 참고본(그리고 대부분의 소개 영상)은 「completely free」라고 말한다. 틀린 말은 아니다 —
23
+ 구독료가 없는 건 사실이다. 다만 **무엇이 무료인지**를 말하지 않았을 뿐이다.
24
+
25
+ 원장이 그 범위를 네 줄로 나눠 들고 있고, 설치기가 **맨 앞에서** 그걸 말한다.
26
+ 이 칸이 비면 자기시험이 막는다. 그러면 우리는 참고본과 똑같은 말만 하는 패키지가 되기 때문이다.
27
+
28
+ ## ★숫자·이름을 지어내지 못하게 막는 자리
29
+
30
+ | 막는 것 | 어떻게 |
31
+ |---|---|
32
+ | 「오픈소스」라고 말하는 것 | 원장의 `라이선스.구분` 이 「클로즈드소스」가 아니면 자기시험이 실패한다 |
33
+ | 12개 구조 도구 **목록을 채워 넣는 것** | 원장에 `구조도구.목록` 배열이 있으면 그 자체를 실패로 본다 — 공개된 적 없는 목록이다 |
34
+ | 「완전 무료」·「무제한」·「평생」 | 금칙어 검사. 단 **「그 말을 하지 마라」고 적은 문장은 면제**한다(부정문 판별) |
35
+ | 리눅스 칸을 비워 두는 것 | 비면 실패. 받으러 갔다가 빈손으로 오는 자리다 |
36
+
37
+ ★금칙 면제 규칙은 회차 ㉔에서 실제로 밟은 사고를 막는 것이다 — 검사기가 자기 규칙 문서를
38
+ 금칙어로 잡아 스스로를 막았다. 검사기는 제대로 돈 것이었고 문서 쪽을 고쳤지만,
39
+ 「하지 않는다」로 끝나는 줄까지 잡는 건 오탐이라 이번엔 부정문을 골라 뺀다.
40
+
41
+ ## 검사기를 양방향으로 시험한다
42
+
43
+ `--self-test` 는 원장이 통과하는지만 보지 않는다. **일부러 망가뜨린 원장 넷**을 만들어
44
+ 그것들이 **막히는지**까지 본다 [[verifier-must-be-tested-both-ways]]:
45
+
46
+ 1. `★무료의범위` 를 지운 것
47
+ 2. 라이선스를 「오픈소스」로 바꾼 것
48
+ 3. 12개 목록을 지어 넣은 것
49
+ 4. 리눅스 칸을 비운 것
50
+
51
+ 전건 통과나 전건 실패는 검사기가 고장 났다는 신호다.
52
+
53
+ ## 스킬이 안 뜰 때
54
+
55
+ 깐 다음 **클로드 코드를 껐다 켜세요.** 그래도 안 뜨면 이름을 직접 부르시고,
56
+ 그래도 없으면 지금 상태를 재 봅니다 — `npx --yes reborn-v3code --check`
57
+
58
+ ---
59
+
60
+ 방금 한 일은 **받기 전에 재 본 것**입니다 — 내 운영체제에서 받히는지,
61
+ 모델 값은 어디서 나가는지, 붙일 에이전트가 있는지.
62
+ 도구마다 이 세 가지가 다르고 소개 영상에는 안 나옵니다.
63
+
64
+ **리본랩스 스킬팩** — 같은 방식으로 골라 담은 48종을 한 줄로. 8,900원
65
+ https://rebornlabs.kr/skillpack?utm_source=installer&utm_medium=cli&utm_campaign=v3code
66
+
67
+ 목록과 직접 까는 명령까지 그 페이지에 그대로 적어 두었습니다. 안 사셔도 됩니다.