reborn-erase 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 REBORN LABS
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # reborn-erase
2
+
3
+ **챗GPT Work 모드로 인터넷에 흩어진 내 정보를 지우기 — 시작하기 전에 볼 것 다섯.**
4
+ 클로드 코드에 안내 스킬(`erase-guide`)을 깔고, 삭제 요청 **원장**을 대신 들고 갑니다.
5
+
6
+ ```
7
+ npx --yes reborn-erase
8
+ ```
9
+
10
+ 깔고 나면 **클로드 코드를 껐다 켜야** 스킬이 잡힙니다. 그다음엔 그냥 말하세요 —
11
+ `인터넷에 흩어진 내 정보 지우고 싶어`
12
+
13
+ ---
14
+
15
+ ## 이게 뭔가
16
+
17
+ 프롬프트는 어디에나 굴러다닙니다. 없는 것은 **「그거 하다가 어디서 막히는가」** 입니다.
18
+
19
+ 1. **유료 플랜이어야 합니다** — Work 도 클라우드 브라우저도 Free·Go 에는 없습니다.
20
+ 게다가 순차 배포라 **돈을 냈는데도 토글이 안 뜰 수 있습니다.**
21
+ 2. **★예약이 조용히 멈춥니다** — 개인정보를 훑은 대화는 끝나면 지우고 싶어집니다.
22
+ 그런데 대화를 지우면 거기 붙은 주간 재확인 예약이 멈춥니다. **알림이 없습니다.**
23
+ 3. **지우러 갔다가 흔적이 남습니다** — 클라우드 브라우저는 자기 쿠키와 로그인 세션을
24
+ 만료까지 들고 있습니다.
25
+ 4. **막히면 뚫지 않습니다** — 봇 차단이 뜨면 멈춥니다. 내 브라우저에서 멀쩡한 사이트여도 그렇습니다.
26
+ 5. **가입만 해둔 곳은 한 줄도 안 나옵니다** — 공개된 페이지만 봅니다.
27
+ **표가 깨끗한 것과 노출이 없는 것은 다른 말입니다.**
28
+
29
+ 그리고 **삭제 요청 원장**을 만듭니다. 보낸 것과 처리된 것을 세는 곳이 없으면 둘이 같아 보입니다.
30
+
31
+ ## 명령
32
+
33
+ | | |
34
+ |---|---|
35
+ | `npx --yes reborn-erase` | 안내 스킬을 깝니다 |
36
+ | `npx --yes reborn-erase steps` | 3단계와 각 단계의 함정 (안 깔고) |
37
+ | `npx --yes reborn-erase facts` | 사실 원장 전체 |
38
+ | `npx --yes reborn-erase ledger` | `내정보삭제_원장.md` 를 지금 폴더에 만듭니다 |
39
+ | `npx --yes reborn-erase verify` | 인용한 도움말 주소가 지금 응답하는지 |
40
+ | `npx --yes reborn-erase --check` | 깔렸는지 + 원장이 규칙을 지키는지 |
41
+ | `npx --yes reborn-erase --self-test` | 자기시험 39건 (양방향) |
42
+
43
+ ## 하지 않는 말
44
+
45
+ - ❌ 「다 지워 드립니다」 — 요청을 **보내는** 절차입니다. 응답은 각 사이트가 정합니다
46
+ - ❌ 「무료로 됩니다」 — Work·클라우드 브라우저는 유료 전용입니다
47
+ - ❌ 「검색 결과에서도 바로 사라집니다」 — 원문이 지워져도 남습니다
48
+ - ❌ **남의 정보 찾기** — 본인 정보에만 씁니다
49
+
50
+ ## 출처와 경계
51
+
52
+ - 챗GPT · Work · 클라우드 브라우저 · 예약 작업은 **[OpenAI](https://openai.com) 의 기능**입니다.
53
+ 저희가 만든 것이 아니고 **제휴 관계도 없습니다.** 저희는 한국어 안내와 원장 관리를 대신합니다.
54
+ - 사실은 [OpenAI 도움말](https://help.openai.com) 3편(예약 작업 · ChatGPT Work 및 Codex ·
55
+ 클라우드 브라우저)을 **직접 열어** 확인했습니다. 확인일 **2026-09-09**.
56
+ - 절차의 원안은 미국 크리에이터 **사브리나 라모노프**가 2026년 6월에 공개한 4단계 프롬프트입니다.
57
+ **이 패키지의 프롬프트 규격과 문장은 리본랩스가 새로 썼습니다** — 원안이나 국내 정리본의
58
+ 글을 옮겨 담지 않았습니다.
59
+
60
+ 설명 · <https://rebornlabs.kr/erase>
61
+
62
+ MIT © REBORN LABS
package/cli.mjs ADDED
@@ -0,0 +1,590 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * 내 정보 지우기 — 시작하기 전에 볼 것. 스킬 설치기.
4
+ *
5
+ * npx --yes reborn-erase 클로드 코드에 안내 스킬을 깐다
6
+ * npx --yes reborn-erase steps 3단계와 각 단계의 함정을 찍는다 (안 깔고)
7
+ * npx --yes reborn-erase facts 원장 전체를 찍는다
8
+ * npx --yes reborn-erase ledger 내정보삭제_원장.md 를 여기에 만든다
9
+ * npx --yes reborn-erase verify 인용한 도움말 주소가 지금 응답하는지 (네트워크)
10
+ * npx --yes reborn-erase --check 깔렸는지 + 원장이 규칙을 지키는지
11
+ * npx --yes reborn-erase --self-test 자기시험 (네트워크 안 씀)
12
+ *
13
+ * ★★이 설치기가 주는 건 프롬프트가 아니라 **원장의 정직함**이다.
14
+ * 프롬프트는 어디에나 굴러다닌다. 없는 것은 「그거 하다가 어디서 막히는가」다.
15
+ *
16
+ * ① **유료 전용** — Work 도 클라우드 브라우저도 Free·Go 에는 없다. 게다가 순차 배포라
17
+ * **돈을 냈는데도 토글이 없을 수 있다.** 이걸 안 말하면 사람들은 결제부터 의심한다.
18
+ * ② **예약이 조용히 멈춘다** — 개인정보를 훑은 대화는 끝나고 지우고 싶어진다. 그런데
19
+ * 대화를 지우면 거기 붙은 주간 재확인 예약이 멈춘다. **알림이 없다.**
20
+ * 지우는 절차에서 가장 위험한 칸인데 어느 정리본도 말하지 않는다.
21
+ * ③ **흔적이 남는다** — 클라우드 브라우저는 자기 쿠키·로그인 세션을 만료까지 들고 있다.
22
+ * 지우러 갔다가 세션을 남기는 셈이다.
23
+ * ④ **가입만 해둔 곳은 안 나온다** — 공개된 페이지만 본다. 표가 깨끗한 것과
24
+ * 노출이 없는 것은 다른 말이다.
25
+ *
26
+ * ★★★남의 글을 옮겨 담지 않는다. 원안은 사브리나 라모노프(2026-06)이고 국내 정리본이
27
+ * 따로 있지만, 이 패키지의 프롬프트 규격과 문장은 **우리가 새로 썼다.** 원장의
28
+ * `★프롬프트.누가썼나` 가 그 사실을 들고 있고, 검사기가 그 칸을 본다.
29
+ *
30
+ * ★자기시험은 **양방향**이다. 좋은 원장을 통과시키는 것만으로는 아무것도 증명 못 한다.
31
+ * 일부러 조건을 지운 가짜 원장을 만들어 검사기가 **그걸 잡는지** 같이 본다
32
+ * [[verifier-must-be-tested-both-ways]].
33
+ */
34
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, readdirSync, statSync } from "node:fs";
35
+ import { homedir } from "node:os";
36
+ import { dirname, join, relative } from "node:path";
37
+ import { fileURLToPath } from "node:url";
38
+ import { 링크, TAIL, 마지막 } from "./tail.mjs";
39
+
40
+ const HOME = homedir();
41
+ const 여기 = dirname(fileURLToPath(import.meta.url));
42
+ const c = { g: "\x1b[32m", r: "\x1b[31m", y: "\x1b[33m", d: "\x1b[90m", cy: "\x1b[36m", b: "\x1b[1m", 0: "\x1b[0m" };
43
+ /** 원장 문자열은 **굵게** 를 쓴다. 터미널에서 별표가 글자로 나오면 손으로 쓴 티가 난다. */
44
+ const 굵게 = (t, 바탕 = c.d) => String(t).replace(/\*\*(.+?)\*\*/g, `${c[0]}${c.b}$1${c[0]}${바탕}`);
45
+
46
+ const 스킬이름 = "erase-guide";
47
+ const 퍼널 = "erase";
48
+ const 원본 = join(여기, "skill");
49
+ const 스킬뿌리 = join(HOME, ".claude", "skills");
50
+ const 대상 = join(스킬뿌리, 스킬이름);
51
+
52
+ /** ★원장 파일 이름. 스킬·CLI·문서가 같은 이름을 써야 사람이 안 헤맨다. */
53
+ const 원장파일 = "내정보삭제_원장.md";
54
+
55
+ /** ★상태값은 이 일곱뿐이다. 늘리면 「했다 치는」 칸이 생긴다. */
56
+ const 상태값 = ["미요청", "요청함", "응답없음", "추가서류요구", "거절", "삭제확인", "손으로해야함"];
57
+
58
+ /** ★플랜별 활성 예약 개수 — OpenAI 도움말 원문에서 그대로 온다. */
59
+ const 예약개수 = { "Free · Go": 3, Plus: 5, "Business · Edu": 10, "Pro · Enterprise": 15 };
60
+
61
+ /** ★조건 없이 단정하지 않는다. 「지우는 일」에서 단정은 곧 거짓이 된다. */
62
+ const 금칙 = [/완전\s*삭제/, /전부\s*지워/, /100\s*%/, /무료로\s*됩니다/, /반드시\s*지워집니다/];
63
+
64
+ function 머리말() {
65
+ console.log(`\n${c.b}내 정보 지우기 — 시작하기 전에 볼 것${c[0]} ${c.d}· 안내 스킬 · REBORN LABS${c[0]}`);
66
+ console.log(`${c.d}챗GPT · Work · 클라우드 브라우저 · 예약 작업은 OpenAI 의 기능입니다. 저희 것이 아닙니다.${c[0]}`);
67
+ console.log(`${c.d}어디서 막히고, 무엇이 소리 없이 멈추고, 무엇이 애초에 안 나오는지를 먼저 말합니다.${c[0]}\n`);
68
+ }
69
+
70
+ function 파일목록(뿌리) {
71
+ const 모음 = [];
72
+ for (const 이름 of readdirSync(뿌리)) {
73
+ const p = join(뿌리, 이름);
74
+ if (statSync(p).isDirectory()) 모음.push(...파일목록(p));
75
+ else 모음.push(p);
76
+ }
77
+ return 모음;
78
+ }
79
+
80
+ const 원장읽기 = (뿌리) => {
81
+ const f = join(뿌리, "erase.json");
82
+ if (!existsSync(f)) return null;
83
+ try { return JSON.parse(readFileSync(f, "utf8")); } catch { return null; }
84
+ };
85
+
86
+ /**
87
+ * ★원장 판정. 여기가 이 설치기의 심장이다.
88
+ * 깔렸는지가 아니라 **깔린 원장이 함정을 숨기지 않았는지**를 본다.
89
+ */
90
+ function 원장검사(d) {
91
+ if (!d) return { 됨: false, 이유: "erase.json 을 못 읽었습니다" };
92
+ if (!d.확인일) return { 됨: false, 이유: "확인일이 없습니다 — 언제 기준인지 모르면 못 믿습니다" };
93
+ if (!d.확인방법) return { 됨: false, 이유: "확인방법이 없습니다 — 어디서 잰 사실인지 모르면 못 믿습니다" };
94
+
95
+ /* ── ① 누가 만들었나 — 남의 기능을 우리 것처럼 말하지 않는다 ──── */
96
+ const P = d.제품;
97
+ if (!P) return { 됨: false, 이유: "제품 칸이 없습니다" };
98
+ if (!/OpenAI/.test(String(P.만든곳 || "")))
99
+ return { 됨: false, 이유: "만든곳이 OpenAI 라고 적혀 있지 않습니다 — Work·클라우드 브라우저는 남의 기능입니다" };
100
+ if (!/제휴 관계가 없/.test(String(P.이스킬은 || "")))
101
+ return { 됨: false, 이유: "제휴 관계가 없다는 사실이 없습니다" };
102
+ if (!P.무엇이아닌가)
103
+ return { 됨: false, 이유: "「무엇이 아닌가」가 없습니다 — 삭제 대행이 아니라 요청 절차라는 걸 안 밝히면 과장이 됩니다" };
104
+ if (!/라모노프/.test(String(P.원안 || "")))
105
+ return { 됨: false, 이유: "원안(사브리나 라모노프)이 적혀 있지 않습니다 — 남의 절차를 출처 없이 쓰지 않습니다" };
106
+
107
+ /* ── ② ★플랜 — 유료 전용. 이 킷이 존재하는 첫 번째 이유 ──────── */
108
+ const F = d["★플랜"];
109
+ if (!F) return { 됨: false, 이유: "플랜 칸이 통째로 없습니다 — 무료 계정에는 Work 토글이 아예 없습니다" };
110
+ if (!/paid plans/i.test(String(F.원문 || "")))
111
+ return { 됨: false, 이유: "도움말 원문(eligible paid plans)이 없습니다 — 번역만 남기면 나중에 못 다툽니다" };
112
+ if (!/Free\s*및\s*Go\s*플랜\s*제외|Free 및 Go/.test(String(F.클라우드브라우저원문 || "")))
113
+ return { 됨: false, 이유: "클라우드 브라우저가 Free·Go 제외라는 원문이 없습니다" };
114
+ if (!F["★유료여도_안_뜰_수_있다"])
115
+ return { 됨: false, 이유: "「유료여도 아직 안 뜰 수 있다」가 없습니다 — 순차 배포입니다. 이걸 빼면 결제를 의심하게 됩니다" };
116
+ if (!F["★사용량도_한도가_있다"])
117
+ return { 됨: false, 이유: "Work 사용량 한도가 없습니다 — 사이트 수십 곳을 한 번에 돌리면 중간에 걸립니다" };
118
+ if (!F.그래서어떻게 || !/1단계|표/.test(F.그래서어떻게))
119
+ return { 됨: false, 이유: "Work 가 없을 때의 우회(1단계는 일반 채팅에서 됨)가 없습니다 — 막기만 하면 아무도 안 씁니다" };
120
+ if (!F.출처) return { 됨: false, 이유: "플랜 이야기의 출처가 없습니다" };
121
+
122
+ /* ── ③ ★예약 — 이 절차에서 가장 위험한 칸 ────────────────────── */
123
+ const R = d["★예약"];
124
+ if (!R) return { 됨: false, 이유: "예약 칸이 없습니다 — 3단계가 통째로 이것입니다" };
125
+ if (!Array.isArray(R.플랜별) || R.플랜별.length !== Object.keys(예약개수).length)
126
+ return { 됨: false, 이유: "플랜별 예약 개수가 네 줄이 아닙니다" };
127
+ for (const [플랜, 개수] of Object.entries(예약개수)) {
128
+ const 줄 = R.플랜별.find((x) => x?.플랜 === 플랜);
129
+ if (!줄) return { 됨: false, 이유: `플랜별 예약 개수에 「${플랜}」 줄이 없습니다` };
130
+ if (줄.개수 !== 개수)
131
+ return { 됨: false, 이유: `「${플랜}」 예약 개수가 ${줄.개수} 로 적혀 있습니다 — 도움말 원문은 ${개수} 입니다` };
132
+ }
133
+ if (!/associated chat is deleted/i.test(String(R["★조용히_멈춘다"] || "")))
134
+ return { 됨: false, 이유: "「대화를 지우면 예약이 멈춘다」 원문이 없습니다 — 이 킷의 가장 중요한 칸입니다" };
135
+ if (!R["★이게_왜_이_소재에서_치명적인가"])
136
+ return { 됨: false, 이유: "예약이 멈추는 것이 왜 이 소재에서 치명적인지가 없습니다 — 사실만 적고 이유를 빼면 안 지킵니다" };
137
+ if (!R.그래서어떻게 || !/새 대화/.test(R.그래서어떻게))
138
+ return { 됨: false, 이유: "「예약은 새 대화에서 만든다」 처방이 없습니다" };
139
+ if (!R.출처) return { 됨: false, 이유: "예약 이야기의 출처가 없습니다" };
140
+
141
+ /* ── ④ ★브라우저 — 막히면 안 뚫는다 · 비밀번호는 대화창에 안 친다 ─ */
142
+ const B = d["★브라우저"];
143
+ if (!B) return { 됨: false, 이유: "브라우저 칸이 없습니다" };
144
+ if (!/restrict access from automated browser agents/i.test(String(B["★막히면_안_뚫는다"] || "")))
145
+ return { 됨: false, 이유: "봇 차단 원문이 없습니다 — 「뚫어 준다」로 읽히면 안 됩니다" };
146
+ if (!/Never paste passwords/i.test(String(B["★비밀번호는_대화창에_치지_않는다"] || "")))
147
+ return { 됨: false, 이유: "「비밀번호를 대화창에 치지 마라」 원문이 없습니다 — 개인정보 소재에서 이걸 빼면 안 됩니다" };
148
+ if (!B.그래서어떻게) return { 됨: false, 이유: "브라우저 칸에 「그래서 어떻게」가 없습니다" };
149
+ if (!B.출처) return { 됨: false, 이유: "브라우저 이야기의 출처가 없습니다" };
150
+
151
+ /* ── ⑤ ★남는것 — 지우러 갔다가 남기는 흔적 ───────────────────── */
152
+ const L = d["★남는것"];
153
+ if (!L) return { 됨: false, 이유: "「남는것」 칸이 없습니다 — 클라우드 브라우저에 로그인 세션이 남습니다" };
154
+ if (!/persist for future tasks/i.test(String(L.원문 || "")))
155
+ return { 됨: false, 이유: "세션이 만료까지 유지된다는 원문이 없습니다" };
156
+ if (!L.그래서어떻게 || !/브라우저 데이터/.test(L.그래서어떻게))
157
+ return { 됨: false, 이유: "「설정 > 클라우드 브라우저 > 브라우저 데이터에서 지운다」 처방이 없습니다" };
158
+
159
+ /* ── ⑥ ★못찾는것 — 표가 깨끗한 것과 노출이 없는 것은 다르다 ──── */
160
+ const N = d["★못찾는것"];
161
+ if (!N) return { 됨: false, 이유: "「못찾는것」 칸이 없습니다" };
162
+ if (!Array.isArray(N.목록) || N.목록.length < 3)
163
+ return { 됨: false, 이유: "못 찾는 자리가 3개 미만입니다" };
164
+ for (const x of N.목록)
165
+ if (!x?.어디 || !x?.왜 || !x?.대신)
166
+ return { 됨: false, 이유: "못 찾는 자리에 「왜」나 「대신 어떻게」가 빠진 항목이 있습니다" };
167
+ if (!N["★가장_큰_구멍"] || !/가입/.test(N["★가장_큰_구멍"]))
168
+ return { 됨: false, 이유: "「가장 큰 구멍은 가입 내역」이 없습니다 — 표가 비었다고 안심하게 두면 안 됩니다" };
169
+ const G = N.정부통로;
170
+ if (!G || !G.이름) return { 됨: false, 이유: "정부 통로(e프라이버시 클린서비스)가 없습니다" };
171
+ if (!G["★실측"] || !/응답하지 않/.test(G["★실측"]))
172
+ return { 됨: false, 이유: "정부 통로를 실제로 두드려 본 기록이 없습니다 — 안 열리는 링크를 세우면 그 줄 전체를 못 믿습니다" };
173
+
174
+ /* ── ⑦ ★원장 — 대화 프롬프트와 다른 유일한 칸 ────────────────── */
175
+ const D2 = d["★원장"];
176
+ if (!D2) return { 됨: false, 이유: "원장 칸이 없습니다 — 보낸 것과 처리된 것을 세는 곳이 이 스킬의 값입니다" };
177
+ if (!Array.isArray(D2.칸) || D2.칸.length < 6)
178
+ return { 됨: false, 이유: "원장 표의 칸이 6개 미만입니다" };
179
+ if (!Array.isArray(D2.상태값) || D2.상태값.length !== 상태값.length)
180
+ return { 됨: false, 이유: `상태값이 ${상태값.length}개가 아닙니다` };
181
+ for (const s of D2.상태값)
182
+ if (!상태값.includes(s))
183
+ return { 됨: false, 이유: `상태값에 없는 값이 있습니다 — "${s}"` };
184
+ if (!D2["★한계"] || !/삭제확인/.test(D2["★한계"]))
185
+ return { 됨: false, 이유: "「삭제확인은 눈으로 본 뒤에만」 이라는 한계가 없습니다 — 보낸 것을 지워진 것으로 세면 안 됩니다" };
186
+
187
+ /* ── ⑧ ★프롬프트 — 남의 글을 옮기지 않았다는 사실 ────────────── */
188
+ const Q = d["★프롬프트"];
189
+ if (!Q) return { 됨: false, 이유: "프롬프트 칸이 없습니다" };
190
+ if (!/리본랩스가 새로 썼/.test(String(Q.누가썼나 || "")))
191
+ return { 됨: false, 이유: "프롬프트를 우리가 새로 썼다는 사실이 없습니다 — 남의 글을 옮겨 담지 않습니다" };
192
+ if (!Array.isArray(Q.단계) || Q.단계.length !== 3)
193
+ return { 됨: false, 이유: "단계가 3개가 아닙니다" };
194
+ for (const s of Q.단계)
195
+ if (!s?.이름 || !s?.무엇을한다)
196
+ return { 됨: false, 이유: "단계에 이름이나 하는 일이 빠진 항목이 있습니다" };
197
+ if (!/아직 보내지 않/.test(String(Q.단계[0]?.무엇을한다 || "")))
198
+ return { 됨: false, 이유: "1단계가 「요청은 아직 안 보낸다」를 말하지 않습니다 — 찾자마자 보내면 되돌릴 수 없습니다" };
199
+
200
+ /* ── ⑨ 금칙어 — 지우는 일에서 단정은 곧 거짓이 된다 ──────────── */
201
+ const 홍보문 = [
202
+ P.무엇, P.무엇이아닌가, F.그래서어떻게, R.그래서어떻게, B.그래서어떻게, L.그래서어떻게, D2["★한계"],
203
+ ].join(" ");
204
+ for (const re of 금칙)
205
+ if (re.test(홍보문))
206
+ return { 됨: false, 이유: `설명에 「${re.source}」 에 걸리는 말이 있습니다 — 조건 없이 단정하지 않습니다` };
207
+
208
+ /* ── ⑩ 안 하는 말 — 무엇을 뺐느냐가 원장의 절반이다 ──────────── */
209
+ if (!Array.isArray(d.안하는말) || d.안하는말.length < 4)
210
+ return { 됨: false, 이유: "「안하는말」 이 4개 미만입니다 — 무엇을 안 말하는지가 원장의 절반입니다" };
211
+ for (const x of d.안하는말)
212
+ if (!x?.말 || !x?.이유) return { 됨: false, 이유: "「안하는말」 에 이유가 없는 항목이 있습니다" };
213
+ if (!d.안하는말.some((x) => /남의 정보|타인/.test(x.말 + x.이유)))
214
+ return { 됨: false, 이유: "「안하는말」 에 남의 정보 찾기 금지가 없습니다 — 이 킷의 가장 중요한 경계입니다" };
215
+
216
+ return { 됨: true, 예약: R.플랜별.length, 확인일: d.확인일 };
217
+ }
218
+
219
+ /** 깔린 스킬이 실제로 읽히는지 — 머리말까지 확인한다. */
220
+ function 진짜도나() {
221
+ const md = join(대상, "SKILL.md");
222
+ if (!existsSync(md)) return { 됨: false, 이유: "SKILL.md 가 없습니다" };
223
+ const 본문 = readFileSync(md, "utf8");
224
+ if (!new RegExp("^---[\\s\\S]*?\\bname:\\s*" + 스킬이름 + "\\b", "m").test(본문))
225
+ return { 됨: false, 이유: "SKILL.md 머리말이 깨졌습니다(name 을 못 읽습니다)" };
226
+ return 원장검사(원장읽기(대상));
227
+ }
228
+
229
+ const 원장고르기 = () => 원장읽기(existsSync(join(대상, "erase.json")) ? 대상 : 원본);
230
+ function 원장이나죽기() {
231
+ const d = 원장고르기();
232
+ const r = 원장검사(d);
233
+ if (!r.됨) { console.error(`${c.r}✗ 원장이 이상합니다${c[0]} — ${r.이유}`); process.exit(1); }
234
+ return d;
235
+ }
236
+
237
+ /* ── steps ──────────────────────────────────────────────────────── */
238
+ function 단계보기() {
239
+ const d = 원장이나죽기();
240
+ 머리말();
241
+ const Q = d["★프롬프트"], F = d["★플랜"], R = d["★예약"];
242
+
243
+ console.log(`${c.y}${c.b}★ 시작하기 전에 — 유료 플랜이어야 합니다${c[0]}`);
244
+ console.log(` ${c.d}${굵게(F.핵심)}${c[0]}`);
245
+ console.log(` ${c.d}${굵게(F["★유료여도_안_뜰_수_있다"])}${c[0]}`);
246
+ console.log(` ${c.g}${굵게(F.그래서어떻게, c.g)}${c[0]}\n`);
247
+
248
+ console.log(`${c.g}${c.b}✅ 세 단계입니다${c[0]}`);
249
+ for (const s of Q.단계) {
250
+ console.log(`\n ${c.b}${s.번호}단계 — ${s.이름}${c[0]} ${c.d}(${s.걸리는시간})${c[0]}`);
251
+ console.log(` ${c.d}${굵게(s.무엇을한다)}${c[0]}`);
252
+ for (const [k, v] of Object.entries(s)) {
253
+ if (!k.startsWith("★")) continue;
254
+ console.log(` ${c.y}★${c[0]} ${c.d}${굵게(v)}${c[0]}`);
255
+ }
256
+ }
257
+
258
+ console.log(`\n${c.r}${c.b}★ 3단계에서 사람들이 다 죽는 자리${c[0]}`);
259
+ console.log(` ${c.d}${굵게(R["★이게_왜_이_소재에서_치명적인가"])}${c[0]}`);
260
+ console.log(` ${c.g}${굵게(R.그래서어떻게, c.g)}${c[0]}`);
261
+ console.log(` ${c.d}활성 예약 개수 — ${R.플랜별.map((x) => `${x.플랜} ${x.개수}`).join(" · ")}${c[0]}\n`);
262
+
263
+ console.log(`${c.d}프롬프트 문장은 클로드가 여러분 상황에 맞게 그 자리에서 씁니다.${c[0]}`);
264
+ console.log(`${c.d}클로드에게 그냥 말하세요 — ${c[0]}${c.cy}"인터넷에 흩어진 내 정보 지우고 싶어"${c[0]}`);
265
+ console.log(`${c.d}확인일 ${d.확인일}. 플랜 구성·예약 개수는 밖에서 바뀝니다.${c[0]}\n`);
266
+ }
267
+
268
+ /* ── facts ──────────────────────────────────────────────────────── */
269
+ function 원장보기() {
270
+ const d = 원장이나죽기();
271
+ 머리말();
272
+ const P = d.제품;
273
+ console.log(`${c.b}${P.무엇}${c[0]}`);
274
+ console.log(`${c.y}아닌 것 — ${P.무엇이아닌가}${c[0]}`);
275
+ console.log(`${c.d}기능 제공 ${P.만든곳} · ${P.이스킬은}${c[0]}`);
276
+ console.log(`${c.d}원안 — ${P.원안.replace(/\*\*/g, "")}${c[0]}\n`);
277
+
278
+ const F = d["★플랜"];
279
+ console.log(`${c.b}플랜${c[0]} ${c.y}${굵게(F.핵심, c.y)}${c[0]}`);
280
+ console.log(` ${c.d}"${F.원문}"${c[0]}`);
281
+ console.log(` ${c.d}${굵게(F["★사용량도_한도가_있다"])}${c[0]}`);
282
+
283
+ const R = d["★예약"];
284
+ console.log(`\n${c.b}예약${c[0]}`);
285
+ for (const x of R.플랜별)
286
+ console.log(` ${c.d}${String(x.플랜).padEnd(18)}${c[0]}${c.cy}${x.개수}개${c[0]} ${c.d}${x.비고}${c[0]}`);
287
+ console.log(` ${c.r}${굵게(R["★조용히_멈춘다"], c.r)}${c[0]}`);
288
+
289
+ const B = d["★브라우저"], L = d["★남는것"];
290
+ console.log(`\n${c.b}클라우드 브라우저${c[0]}`);
291
+ console.log(` ${c.d}${굵게(B.핵심)}${c[0]}`);
292
+ console.log(` ${c.d}${굵게(B["★막히면_안_뚫는다"])}${c[0]}`);
293
+ console.log(` ${c.r}${굵게(L.핵심, c.r)}${c[0]}`);
294
+ console.log(` ${c.g}${굵게(L.그래서어떻게, c.g)}${c[0]}`);
295
+
296
+ const N = d["★못찾는것"];
297
+ console.log(`\n${c.b}못 찾는 자리${c[0]}`);
298
+ for (const x of N.목록) console.log(` ${c.d}${String(x.어디).padEnd(24)}${c[0]}${c.d}→ ${x.대신}${c[0]}`);
299
+ console.log(` ${c.y}${굵게(N["★가장_큰_구멍"], c.y)}${c[0]}`);
300
+ console.log(` ${c.d}${N.정부통로.이름} — ${N.정부통로.무엇}${c[0]}`);
301
+ console.log(` ${c.d}${굵게(N.정부통로["★실측"])}${c[0]}`);
302
+
303
+ const D2 = d["★원장"];
304
+ console.log(`\n${c.b}삭제 요청 원장${c[0]} ${c.d}(${원장파일})${c[0]}`);
305
+ console.log(` ${c.d}${D2.칸.join(" · ")}${c[0]}`);
306
+ console.log(` ${c.d}상태 — ${D2.상태값.join(" · ")}${c[0]}`);
307
+ console.log(` ${c.y}${굵게(D2["★한계"], c.y)}${c[0]}`);
308
+
309
+ console.log(`\n${c.b}이 스킬이 하지 않는 말${c[0]}`);
310
+ for (const x of d.안하는말) console.log(` ${c.r}✗${c[0]} ${x.말} ${c.d}— ${x.이유}${c[0]}`);
311
+ console.log(`\n${c.d}확인일 ${d.확인일} · ${d.확인방법}${c[0]}\n`);
312
+ }
313
+
314
+ /* ── ledger — 원장 파일을 여기에 만든다 ─────────────────────────── */
315
+ function 원장만들기() {
316
+ const d = 원장이나죽기();
317
+ 머리말();
318
+ const D2 = d["★원장"];
319
+ const 길 = join(process.cwd(), 원장파일);
320
+
321
+ if (existsSync(길)) {
322
+ console.log(`${c.y}· 이미 있습니다${c[0]} ${c.d}${길}${c[0]}`);
323
+ console.log(`${c.d} 덮어쓰지 않습니다 — 지금까지 보낸 요청 기록이 들어 있을 수 있습니다.${c[0]}\n`);
324
+ process.exit(0);
325
+ }
326
+
327
+ const 오늘 = new Date().toISOString().slice(0, 10);
328
+ const 본문 = [
329
+ `# 내 정보 삭제 요청 원장`,
330
+ ``,
331
+ `> ${오늘} 시작 · \`npx --yes reborn-erase ledger\` 로 만들었습니다.`,
332
+ `> ★**주민번호·계좌·비밀번호를 여기 적지 마세요.** 사이트와 상태만 적습니다 —`,
333
+ `> 지우려고 만든 파일이 새 노출 지점이 되면 안 됩니다.`,
334
+ ``,
335
+ `## 규칙`,
336
+ ``,
337
+ `- \`삭제확인\` 은 **직접 눈으로 본 뒤에만** 찍습니다. 요청을 보낸 것은 \`요청함\` 입니다.`,
338
+ `- 재확인할 때는 이 표를 **먼저 읽고** 무엇을 다시 보낼지 정합니다. 처음부터 다시 찾지 않습니다.`,
339
+ `- 막힌 곳·탈퇴가 필요한 곳은 \`손으로해야함\` 으로 남깁니다. 지운 척하지 않습니다.`,
340
+ ``,
341
+ `상태값: ${D2.상태값.map((s) => "`" + s + "`").join(" · ")}`,
342
+ ``,
343
+ `## 표`,
344
+ ``,
345
+ `| ${D2.칸.join(" | ")} |`,
346
+ `|${D2.칸.map(() => "---").join("|")}|`,
347
+ `| | | | | | | |`,
348
+ ``,
349
+ `## 기록`,
350
+ ``,
351
+ `- ${오늘} 원장 시작`,
352
+ ``,
353
+ ].join("\n");
354
+
355
+ writeFileSync(길, 본문, "utf8");
356
+ console.log(`${c.g}✓ 만들었습니다${c[0]} ${c.d}${길}${c[0]}`);
357
+ console.log(`${c.d} 칸 — ${D2.칸.join(" · ")}${c[0]}`);
358
+ console.log(`\n${c.d}클로드에게 그냥 말하세요 — ${c[0]}${c.cy}"내정보삭제_원장.md 채우게 1단계부터 시작하자"${c[0]}\n`);
359
+ }
360
+
361
+ /* ── verify (네트워크) ──────────────────────────────────────────── */
362
+ async function 확인명령() {
363
+ const d = 원장이나죽기();
364
+ 머리말();
365
+ console.log(`${c.d}인용한 도움말 주소가 지금 응답하는지 봅니다. 응답한다고 여러분 계정에서 된다는 뜻은 아닙니다.${c[0]}\n`);
366
+ const 볼곳 = [
367
+ ["Work 도움말", d["★플랜"].출처],
368
+ ["예약 도움말", d["★예약"].출처],
369
+ ["브라우저 도움말", d["★브라우저"].출처],
370
+ ];
371
+ /* ★403/429 를 「죽었다」로 세지 않는다. help.openai.com 은 살아 있고 **자동 접근만** 막는다
372
+ (2026-09-09 실측: 브라우저로는 열리고 fetch 로는 403). 이걸 빨간 ✗ 로 찍으면
373
+ 멀쩡한 원장을 못 믿게 만든다 — 이 킷이 말하는 「봇 차단」이 여기서 그대로 일어난다.
374
+ [[wrong-diagnosis-is-a-silent-failure]] */
375
+ const 봇차단 = new Set([401, 403, 405, 406, 429]);
376
+ let 끊김 = 0, 차단 = 0;
377
+ for (const [이름, 주소] of 볼곳) {
378
+ let 표, 말;
379
+ try {
380
+ const res = await fetch(주소, {
381
+ redirect: "follow",
382
+ signal: AbortSignal.timeout(20000),
383
+ headers: { "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0 Safari/537.36" },
384
+ });
385
+ if (res.ok) { 표 = `${c.g}✓${c[0]}`; 말 = String(res.status); }
386
+ else if (봇차단.has(res.status)) {
387
+ 표 = `${c.y}!${c[0]}`; 차단++;
388
+ 말 = `${res.status} — 살아 있지만 자동 접근을 막습니다. 브라우저로는 열립니다`;
389
+ } else { 표 = `${c.r}✗${c[0]}`; 말 = String(res.status); 끊김++; }
390
+ } catch (e) { 표 = `${c.r}✗${c[0]}`; 말 = String(e.message).slice(0, 40); 끊김++; }
391
+ console.log(` ${표} ${이름.padEnd(16)} ${c.d}${말}${c[0]}`);
392
+ }
393
+ if (끊김) console.log(`\n${c.r}${끊김}건이 응답하지 않습니다 — 원장을 다시 봐야 합니다.${c[0]}\n`);
394
+ else if (차단) console.log(`\n${c.g}전부 살아 있습니다.${c[0]} ${c.d}${차단}건은 자동 접근을 막습니다 — 주소를 브라우저에 붙여 넣어 보세요.${c[0]}\n`);
395
+ else console.log(`\n${c.g}전부 응답합니다.${c[0]}\n`);
396
+ process.exit(끊김 ? 1 : 0);
397
+ }
398
+
399
+ /* ── --check ────────────────────────────────────────────────────── */
400
+ function 확인만() {
401
+ 머리말();
402
+ const r = 진짜도나();
403
+ if (r.됨) {
404
+ console.log(`${c.g}✓ 설치되어 있고 원장이 규칙을 지킵니다${c[0]} ${c.d}(${대상})${c[0]}`);
405
+ console.log(`${c.d} 플랜별 예약 ${r.예약}줄 · 확인일 ${r.확인일}${c[0]}\n`);
406
+ } else console.log(`${c.y}· 아직 없습니다${c[0]} ${c.d}— ${r.이유}${c[0]}\n`);
407
+ process.exit(r.됨 ? 0 : 1);
408
+ }
409
+
410
+ /* ── 자기시험 (네트워크 안 씀) ─────────────────────────────────── */
411
+ function 자기시험() {
412
+ const 결과 = [];
413
+ const T = (n, ok) => 결과.push([n, !!ok]);
414
+ const 원 = 원장읽기(원본);
415
+ const 복 = () => JSON.parse(JSON.stringify(원));
416
+ const 스킬본문 = () => readFileSync(join(원본, "SKILL.md"), "utf8");
417
+
418
+ /* ── 통과해야 하는 쪽 ─────────────────────────────────────── */
419
+ T("패키지 안에 skill/ 이 있다", existsSync(원본));
420
+ T("원장을 읽는다", !!원);
421
+ T("지금 원장은 통과한다", 원장검사(원).됨);
422
+ T("SKILL.md 머리말의 name 이 맞다",
423
+ new RegExp("^---[\\s\\S]*?\\bname:\\s*" + 스킬이름 + "\\b", "m").test(스킬본문()));
424
+ T("SKILL.md 가 스킬팩을 가리키지 클로드킷을 가리키지 않는다",
425
+ !/클로드킷|자비스\s*풀스택/.test(스킬본문()));
426
+ T("tail 문안이 스킬팩 한 칸만 말한다",
427
+ !/클로드킷|자비스\s*풀스택|일감\s*진단/.test(JSON.stringify(TAIL) + 마지막));
428
+ T("SKILL.md 가 원안(라모노프)을 밝힌다", /라모노프/.test(스킬본문()));
429
+ T("SKILL.md 가 프롬프트를 우리가 새로 썼다고 밝힌다", /새로 썼/.test(스킬본문()));
430
+ T("SKILL.md 의 상태값이 원장의 상태값과 같다",
431
+ 상태값.every((s) => 스킬본문().includes(s)));
432
+ T("예약 개수 네 줄이 코드와 원장에서 같다",
433
+ Object.entries(예약개수).every(([p, n]) => 원["★예약"].플랜별.some((x) => x.플랜 === p && x.개수 === n)));
434
+
435
+ /* ── ★잡아야 하는 쪽 — 전건 통과하는 검사기는 검사기가 아니다 ── */
436
+ T("★★플랜 칸을 지우면 잡는다", (() => { const d = 복(); delete d["★플랜"]; return !원장검사(d).됨; })());
437
+ T("★★「유료여도 안 뜰 수 있다」를 지우면 잡는다", (() => {
438
+ const d = 복(); delete d["★플랜"]["★유료여도_안_뜰_수_있다"]; return !원장검사(d).됨;
439
+ })());
440
+ T("★★Work 없을 때의 우회를 지우면 잡는다", (() => {
441
+ const d = 복(); d["★플랜"].그래서어떻게 = "유료로 올리세요"; return !원장검사(d).됨;
442
+ })());
443
+ T("★★예약 칸을 지우면 잡는다", (() => { const d = 복(); delete d["★예약"]; return !원장검사(d).됨; })());
444
+ T("★★Plus 예약 개수를 10으로 부풀리면 잡는다", (() => {
445
+ const d = 복(); d["★예약"].플랜별.find((x) => x.플랜 === "Plus").개수 = 10; return !원장검사(d).됨;
446
+ })());
447
+ T("★★「대화를 지우면 멈춘다」 원문을 지우면 잡는다", (() => {
448
+ const d = 복(); d["★예약"]["★조용히_멈춘다"] = "가끔 멈출 수 있습니다"; return !원장검사(d).됨;
449
+ })());
450
+ T("★★「새 대화에서 예약을 만든다」 처방을 지우면 잡는다", (() => {
451
+ const d = 복(); d["★예약"].그래서어떻게 = "가끔 확인하세요"; return !원장검사(d).됨;
452
+ })());
453
+ T("★★봇 차단 원문을 지우면 잡는다", (() => {
454
+ const d = 복(); d["★브라우저"]["★막히면_안_뚫는다"] = "막히면 멈춥니다"; return !원장검사(d).됨;
455
+ })());
456
+ T("★★「비밀번호를 대화창에 치지 마라」를 지우면 잡는다", (() => {
457
+ const d = 복(); d["★브라우저"]["★비밀번호는_대화창에_치지_않는다"] = "조심하세요"; return !원장검사(d).됨;
458
+ })());
459
+ T("★★「남는것」 칸을 지우면 잡는다", (() => { const d = 복(); delete d["★남는것"]; return !원장검사(d).됨; })());
460
+ T("★★세션이 남는다는 원문을 지우면 잡는다", (() => {
461
+ const d = 복(); d["★남는것"].원문 = "세션이 유지됩니다"; return !원장검사(d).됨;
462
+ })());
463
+ T("★★브라우저 데이터 지우는 처방을 빼면 잡는다", (() => {
464
+ const d = 복(); d["★남는것"].그래서어떻게 = "끝나면 정리하세요"; return !원장검사(d).됨;
465
+ })());
466
+ T("★★「가장 큰 구멍은 가입 내역」을 지우면 잡는다", (() => {
467
+ const d = 복(); d["★못찾는것"]["★가장_큰_구멍"] = "표를 잘 보세요"; return !원장검사(d).됨;
468
+ })());
469
+ T("★★정부 통로를 두드려 본 기록을 지우면 잡는다", (() => {
470
+ const d = 복(); d["★못찾는것"].정부통로["★실측"] = "잘 됩니다"; return !원장검사(d).됨;
471
+ })());
472
+ T("★★원장 칸을 지우면 잡는다", (() => { const d = 복(); delete d["★원장"]; return !원장검사(d).됨; })());
473
+ T("★★상태값에 「완료」를 끼워 넣으면 잡는다", (() => {
474
+ const d = 복(); d["★원장"].상태값 = [...상태값.slice(0, 6), "완료"]; return !원장검사(d).됨;
475
+ })());
476
+ T("★★「삭제확인은 눈으로 본 뒤에만」 을 지우면 잡는다", (() => {
477
+ const d = 복(); d["★원장"]["★한계"] = "원장은 편리합니다"; return !원장검사(d).됨;
478
+ })());
479
+ T("★★1단계에서 「아직 안 보낸다」를 빼면 잡는다", (() => {
480
+ const d = 복(); d["★프롬프트"].단계[0].무엇을한다 = "찾아서 바로 삭제를 요청합니다"; return !원장검사(d).됨;
481
+ })());
482
+ T("★★「프롬프트를 우리가 새로 썼다」를 지우면 잡는다", (() => {
483
+ const d = 복(); d["★프롬프트"].누가썼나 = "정리본에서 가져왔습니다"; return !원장검사(d).됨;
484
+ })());
485
+ T("★★원안(라모노프)을 지우면 잡는다", (() => {
486
+ const d = 복(); d.제품.원안 = "저희가 처음 만든 절차입니다"; return !원장검사(d).됨;
487
+ })());
488
+ T("★★만든곳을 우리로 바꾸면 잡는다", (() => {
489
+ const d = 복(); d.제품.만든곳 = "REBORN LABS"; return !원장검사(d).됨;
490
+ })());
491
+ T("★★제휴 관계가 없다는 줄을 지우면 잡는다", (() => {
492
+ const d = 복(); d.제품.이스킬은 = "리본랩스의 공식 안내입니다"; return !원장검사(d).됨;
493
+ })());
494
+ T("★★설명에 「완전 삭제」를 넣으면 잡는다", (() => {
495
+ const d = 복(); d.제품.무엇 = "웹에 흩어진 내 정보를 완전 삭제합니다"; return !원장검사(d).됨;
496
+ })());
497
+ T("★★설명에 「무료로 됩니다」를 넣으면 잡는다", (() => {
498
+ const d = 복(); d["★플랜"].그래서어떻게 = "1단계 표는 무료로 됩니다"; return !원장검사(d).됨;
499
+ })());
500
+ T("★★「무엇이 아닌가」를 지우면 잡는다", (() => {
501
+ const d = 복(); delete d.제품.무엇이아닌가; return !원장검사(d).됨;
502
+ })());
503
+ T("★★「안하는말」 을 비우면 잡는다", (() => { const d = 복(); d.안하는말 = []; return !원장검사(d).됨; })());
504
+ T("★★「안하는말」 에서 타인 정보 금지를 빼면 잡는다", (() => {
505
+ const d = 복(); d.안하는말 = d.안하는말.filter((x) => !/남의 정보|타인/.test(x.말 + x.이유));
506
+ while (d.안하는말.length < 4) d.안하는말.push({ 말: "채움", 이유: "채움" });
507
+ return !원장검사(d).됨;
508
+ })());
509
+ T("★★확인일을 지우면 잡는다", (() => { const d = 복(); delete d.확인일; return !원장검사(d).됨; })());
510
+ T("★없는 원장은 통과하지 않는다", !원장검사(null).됨);
511
+
512
+ for (const [n, ok] of 결과) console.log(` ${ok ? c.g + "✓" : c.r + "✗"}${c[0]} ${n}`);
513
+ const 실패 = 결과.filter(([, ok]) => !ok).length;
514
+ console.log(실패 ? `\n${c.r}✗ 자기시험 ${실패}건 실패${c[0]}` : `\n${c.g}✓ 자기시험 ${결과.length}건 통과${c[0]}`);
515
+ return 실패 ? 1 : 0;
516
+ }
517
+
518
+ /* ── 설치 ───────────────────────────────────────────────────────── */
519
+ function 설치() {
520
+ 머리말();
521
+ if (!existsSync(원본)) {
522
+ console.error(`${c.r}✗ 패키지 안에 skill/ 폴더가 없습니다${c[0]} — 배포가 잘못된 것입니다.`);
523
+ process.exit(2);
524
+ }
525
+ let 쓴수 = 0;
526
+ for (const src of 파일목록(원본)) {
527
+ const 상대 = relative(원본, src);
528
+ const dst = join(대상, 상대);
529
+ mkdirSync(dirname(dst), { recursive: true });
530
+ writeFileSync(dst, readFileSync(src));
531
+ 쓴수++;
532
+ console.log(` ${c.d}·${c[0]} ${상대}`);
533
+ }
534
+ console.log(`\n${c.d}${쓴수}개 파일 → ${대상}${c[0]}`);
535
+ console.log(`${c.d}원장이 함정을 숨기지 않았는지 다시 확인하는 중…${c[0]}`);
536
+
537
+ const r = 진짜도나();
538
+ if (!r.됨) {
539
+ console.error(`\n${c.r}✗ 깔았는데 확인에서 걸렸습니다${c[0]} — ${r.이유}\n`);
540
+ process.exit(1);
541
+ }
542
+
543
+ const d = 원장읽기(대상);
544
+ const F = d["★플랜"], R = d["★예약"], L = d["★남는것"], N = d["★못찾는것"];
545
+ console.log(`\n${c.g}${c.b}✓ 설치 완료${c[0]} ${c.d}— 확인일 ${r.확인일}${c[0]}`);
546
+
547
+ console.log(`\n${c.y}${c.b}★ 시작하기 전에 — 유료 플랜이어야 합니다${c[0]}`);
548
+ console.log(` ${c.d}${굵게(F.핵심)}${c[0]}`);
549
+ console.log(` ${c.d}${굵게(F["★유료여도_안_뜰_수_있다"])}${c[0]}`);
550
+
551
+ console.log(`\n${c.r}${c.b}★ 가장 위험한 칸 — 대화를 지우면 예약이 멈춥니다${c[0]}`);
552
+ console.log(` ${c.d}${굵게(R["★이게_왜_이_소재에서_치명적인가"])}${c[0]}`);
553
+ console.log(` ${c.g}${굵게(R.그래서어떻게, c.g)}${c[0]}`);
554
+
555
+ console.log(`\n${c.y}${c.b}★ 끝나고 흔적을 지우세요${c[0]}`);
556
+ console.log(` ${c.d}${굵게(L.핵심)}${c[0]}`);
557
+ console.log(` ${c.d}${굵게(L.그래서어떻게)}${c[0]}`);
558
+
559
+ console.log(`\n${c.y}${c.b}★ 표가 깨끗해도 끝난 게 아닙니다${c[0]}`);
560
+ console.log(` ${c.d}${굵게(N["★가장_큰_구멍"])}${c[0]}`);
561
+
562
+ console.log(`\n${c.y}★ 클로드 코드를 껐다 켜야 스킬이 잡힙니다.${c[0]}`);
563
+ console.log(`\n${c.b}쓰는 법${c[0]}`);
564
+ console.log(` 클로드에게 그냥 말하세요 — ${c.cy}"인터넷에 흩어진 내 정보 지우고 싶어"${c[0]}`);
565
+ console.log(` 3단계와 함정: ${c.cy}npx --yes reborn-erase steps${c[0]}`);
566
+ console.log(` 삭제 요청 원장 만들기: ${c.cy}npx --yes reborn-erase ledger${c[0]}`);
567
+ console.log(` 사실 원장 전체: ${c.cy}npx --yes reborn-erase facts${c[0]}`);
568
+ console.log(` ${c.d}플랜 구성·예약 개수·기능 이름은 밖에서 바뀝니다. 확인일을 같이 적어 둔 이유입니다.${c[0]}\n`);
569
+ console.log(`${c.d}설명 · https://rebornlabs.kr/erase?utm_source=installer&utm_medium=cli&utm_campaign=${퍼널}${c[0]}`);
570
+
571
+ /* ★끝난 뒤 딱 한 칸. 못 깔았으면 여기까지 오지 않는다(위에서 exit 1).
572
+ ★가리키는 곳은 스킬팩(8,900원)이다. 클로드킷은 여기서 말하지 않는다 — 계단이 무너진다. */
573
+ const t = TAIL[퍼널];
574
+ console.log("");
575
+ for (const 줄 of t.이음) console.log(`${c.d}${줄.replace(/\*\*(.+?)\*\*/g, `${c[0]}${c.b}$1${c[0]}${c.d}`)}${c[0]}`);
576
+ console.log(`\n${c.b}${t.제목}${c[0]}${c.d} — ${t.한줄}${c[0]}`);
577
+ console.log(`${c.cy}${링크(퍼널)}${c[0]}`);
578
+ console.log(`${c.d}${마지막}${c[0]}\n`);
579
+ }
580
+
581
+ /* ══ 실행 ═══════════════════════════════════════════════════════ */
582
+ const 인자 = process.argv.slice(2);
583
+ const 첫 = 인자[0];
584
+ if (인자.includes("--self-test")) process.exit(자기시험());
585
+ else if (첫 === "steps" || 첫 === "단계") 단계보기();
586
+ else if (첫 === "facts" || 첫 === "원장") 원장보기();
587
+ else if (첫 === "ledger" || 첫 === "장부") 원장만들기();
588
+ else if (첫 === "verify" || 첫 === "확인") await 확인명령();
589
+ else if (인자.includes("--check")) 확인만();
590
+ else 설치();
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "reborn-erase",
3
+ "version": "1.0.0",
4
+ "description": "챗GPT Work 모드로 인터넷에 흩어진 내 정보를 찾아 삭제 요청하는 절차를 시작하기 전에 무엇이 막고 무엇이 조용히 멈추는지 알려 주는 클로드 코드 스킬. Work 가 유료 전용이라는 것, 대화를 지우면 주간 재확인 예약이 소리 없이 멈춘다는 것, 클라우드 브라우저에 로그인 세션이 남는다는 것, 가입만 해둔 곳은 한 줄도 안 나온다는 것을 먼저 말하고, 삭제 요청 원장을 대신 들고 간다.",
5
+ "keywords": [
6
+ "claude",
7
+ "claude-code",
8
+ "agent-skills",
9
+ "skill",
10
+ "chatgpt",
11
+ "chatgpt-work",
12
+ "privacy",
13
+ "data-removal",
14
+ "right-to-be-forgotten",
15
+ "opt-out",
16
+ "korean",
17
+ "개인정보"
18
+ ],
19
+ "homepage": "https://rebornlabs.kr/erase?utm_source=installer&utm_medium=cli&utm_campaign=erase",
20
+ "bugs": {
21
+ "url": "https://mobility.rebornlabs.kr/cs"
22
+ },
23
+ "license": "MIT",
24
+ "author": "REBORN LABS",
25
+ "type": "module",
26
+ "bin": {
27
+ "reborn-erase": "cli.mjs"
28
+ },
29
+ "files": [
30
+ "cli.mjs",
31
+ "tail.mjs",
32
+ "skill/",
33
+ "README.md",
34
+ "안내스킬.md"
35
+ ],
36
+ "engines": {
37
+ "node": ">=18"
38
+ },
39
+ "scripts": {
40
+ "test": "node cli.mjs --self-test",
41
+ "check": "node cli.mjs --check"
42
+ },
43
+ "publishConfig": {
44
+ "access": "public"
45
+ }
46
+ }
package/skill/SKILL.md ADDED
@@ -0,0 +1,172 @@
1
+ ---
2
+ name: erase-guide
3
+ description: >
4
+ 챗GPT Work 모드로 인터넷에 흩어진 내 정보를 찾아 삭제 요청하는 절차를 **시작하기 전에**
5
+ 무엇이 막고 무엇이 조용히 멈추는지 알려 주고, 삭제 요청 원장을 대신 들고 간다.
6
+ Work 모드가 유료 전용이라는 것, 예약이 대화를 지우면 멈춘다는 것, 클라우드 브라우저에
7
+ 로그인 세션이 남는다는 것, 가입만 해둔 곳은 한 줄도 안 나온다는 것을 먼저 말한다.
8
+ "내 정보 지우기", "개인정보 삭제 요청", "인터넷에 내 이름 검색하면 나온다", "구글에서 내 정보 지우기",
9
+ "디지털 장의사", "잊힐 권리", "챗GPT 워크 모드", "ChatGPT Work", "내 정보 노출 확인",
10
+ "회원 탈퇴 대행", "e프라이버시" 같은 이야기가 나올 때 쓴다.
11
+ ---
12
+
13
+ # 내 정보 지우기 — 시작하기 전에 볼 것 다섯
14
+
15
+ > 이 파일은 **리본랩스(REBORN LABS)** 의 무료 설치기(`npx --yes reborn-erase`)가 넣은 것입니다.
16
+ > 필요 없으시면 이 폴더를 지우세요.
17
+ >
18
+ > **챗GPT · Work 모드 · 클라우드 브라우저 · 예약 작업은 [OpenAI](https://openai.com) 의 기능입니다.
19
+ > 저희가 만든 것이 아니고, 저희와 제휴 관계도 없습니다.** 저희는 한국어 안내와 원장 관리를 대신합니다.
20
+ >
21
+ > 절차의 원안은 미국 크리에이터 **사브리나 라모노프**가 2026년 6월에 공개한 4단계 프롬프트입니다.
22
+ > **이 스킬의 프롬프트 문장은 리본랩스가 새로 썼습니다** — 원안이나 국내 정리본의 글을 옮기지 않았습니다.
23
+
24
+ 사실 원장은 같은 폴더의 `erase.json` 입니다. **거기 없는 숫자는 말하지 마세요.**
25
+
26
+ ---
27
+
28
+ ## 0. 사람이 물으면 이 순서로 답한다
29
+
30
+ 「인터넷에 내 정보가 떠 있는데 지울 수 있나」 류의 질문이 오면, **먼저 다섯 개를 말하고**
31
+ 그다음에 프롬프트를 준다. 순서를 바꾸면 하다가 막힌 자리에서 "안 되는구나"로 끝난다.
32
+
33
+ ### ① 유료 플랜이어야 합니다 — 그리고 유료여도 아직 안 뜰 수 있습니다
34
+
35
+ Work 는 유료 플랜 전용입니다(원문: *"Work is available on ChatGPT web and mobile for eligible
36
+ paid plans."*). 클라우드 브라우저도 **Free·Go 제외**입니다.
37
+
38
+ ★그런데 **돈을 냈는데 토글이 없는 경우가 실제로 있습니다.** 도움말이 아직 순차 배포 중이라고
39
+ 적어 두었습니다 — 고장이 아니라 순번입니다. 이걸 안 말해 주면 사람들이 결제부터 의심합니다.
40
+
41
+ **Work 가 없으면** 1단계(표 만들기)는 일반 채팅에서도 됩니다. 표까지만 받고 2단계는 손으로 하세요.
42
+
43
+ ### ② ★예약은 **대화를 지우면 멈춥니다** — 이게 이 절차에서 가장 위험한 칸입니다
44
+
45
+ 도움말 원문: *"A task may pause if it is inactive, requires additional action, or its associated
46
+ chat is deleted."*
47
+
48
+ 내 개인정보를 훑어 놓은 대화입니다. 다 끝나면 **그 대화부터 지우고 싶어집니다.**
49
+ 지우는 순간 매주 재확인 예약이 **소리 없이 멈춥니다. 알림은 오지 않습니다.**
50
+ 무시된 요청을 다시 보내는 사람이 사라지는데, 본인은 여전히 돌고 있다고 믿습니다.
51
+
52
+ → **재확인 예약은 개인정보가 안 들어간 새 대화에서 따로 만들게 하세요.**
53
+ → 한 달에 한 번 예약 화면(Scheduled)을 직접 열어 「일시중지」로 바뀌지 않았는지 눈으로 보게 하세요.
54
+
55
+ 활성 예약 개수도 제한입니다 — **Free·Go 3 · Plus 5 · Business·Edu 10 · Pro·Enterprise 15.**
56
+ 다른 예약이 이미 차 있으면 이 작업이 안 걸립니다.
57
+
58
+ ### ③ ★지우러 갔다가 **흔적이 남습니다**
59
+
60
+ 클라우드 브라우저는 내 브라우저가 아니라 **클라우드의 다른 컴퓨터**이고, 자기 쿠키와
61
+ 로그인 세션을 따로 들고 있습니다. 원문: *"The authentication will persist for future tasks
62
+ until it expires."*
63
+
64
+ 개인정보를 지우겠다고 여러 사이트에 로그인한 세션이 **만료될 때까지 그쪽에 남습니다.**
65
+
66
+ → 작업이 끝나면 **설정 > 클라우드 브라우저 > 브라우저 데이터**에서 사이트 데이터를 지우게 하세요.
67
+
68
+ ### ④ 막히면 뚫지 않습니다
69
+
70
+ *"A website may block ChatGPT from accessing the site or completing your task, even if the same
71
+ website works normally in your own browser."* 봇 차단이 뜨면 멈춥니다.
72
+ 그 사이트는 **표에 「손으로해야함」으로 남기고** 직접 들어가 요청문을 붙여넣습니다.
73
+
74
+ ★비밀번호·인증번호는 **대화창에 절대 치지 않습니다.** 로그인은 보안 로그인 양식으로만 합니다
75
+ (*"Never paste passwords, security codes, or payment details into the conversation."*).
76
+
77
+ ### ⑤ ★가장 큰 구멍은 「가입만 해둔 곳」입니다
78
+
79
+ 챗GPT 가 보는 것은 **웹에 공개된 페이지**뿐입니다. 로그인해야 보이는 곳, 검색 로봇을 막아 둔
80
+ 커뮤니티, 그리고 **가입만 하고 글은 안 쓴 곳**은 한 줄도 안 나옵니다.
81
+
82
+ **표가 깨끗하다고 안심하면 안 됩니다.** 가입 내역은 다른 통로로 따로 봐야 합니다:
83
+
84
+ - 이메일함에서 **「회원가입」** 검색
85
+ - 네이버·카카오·구글 계정의 **「연결된 서비스」** 목록
86
+ - **e프라이버시 클린서비스**(개인정보보호위원회·한국인터넷진흥원) — 본인인증 가입 내역 조회·탈퇴 대행
87
+ ★2026-09-09 실측으로 `eprivacy.go.kr` 이 **응답하지 않았습니다.** 그래서 링크를 세우지 않습니다.
88
+ 이름으로 검색해 들어가시고, 안 열리면 개인정보보호포털(`privacy.go.kr`)에서 찾으세요.
89
+
90
+ ---
91
+
92
+ ## 1. 그다음에 이 세 단계를 준다
93
+
94
+ 프롬프트는 **네가 그 자리에서 사용자 상황에 맞게 써 준다.** 아래는 각 단계가 반드시 담아야
95
+ 하는 것이고, 문장은 사람마다 다르게 나가도 된다.
96
+
97
+ ### 1단계 — 어디에 떠 있는지 표로 (1~15분) · 요청은 아직 안 보낸다
98
+
99
+ 담아야 하는 것:
100
+ - 아는 식별자만 채우게 한다(이름 · 아이디 · 이메일 · 지역 · 예전 직장 등). **모르는 칸은 비워 둔다.**
101
+ - 결과는 **표**로: 사이트 · 어떤 정보가 보이는가 · 페이지 주소 · **삭제 요청 통로** · 확실도
102
+ - 「확인 필요」 줄을 따로 표시하게 한다 — 이름만 넣었으면 이 줄이 많은 게 **정상**이다
103
+ - **이 단계에서는 아무것도 제출하지 않는다**고 못 박는다
104
+
105
+ ★**거절당하면**: 「특정인의 개인정보 추적에 이용될 수 있다」며 멈출 수 있다. 챗GPT 는 본인 확인을
106
+ 못 하기 때문이다. 그 자리에서 **목적을 밝히면** 진행된다 — 내 정보이고, 삭제 요청을 하려고
107
+ 노출 위치를 확인하는 중이라고.
108
+
109
+ ★단서를 하나만 더 주면 정확도가 확 오른다. 이름 하나면 남의 결과가 섞인다.
110
+
111
+ ### 2단계 — 요청문 쓰고 대신 제출 (사이트 수에 따라 30분~)
112
+
113
+ 담아야 하는 것:
114
+ - 사이트별 삭제 요청문(국내는 한국어, **해외는 영어** — 처리율이 다르다)
115
+ - 클라우드 브라우저로 문의 폼을 채우되 **최종 제출 전에 반드시 멈추고 물어본다**
116
+ - 로그인이 필요한 곳은 **보안 로그인 양식**으로만
117
+ - 막히거나 탈퇴가 필요한 곳은 **제출하지 말고 표에 「손으로해야함」으로 남긴다**
118
+
119
+ ★**5~10곳씩 끊어서** 돌리게 한다. Work 사용량은 Codex 와 같은 주머니라 한 번에 수십 곳을
120
+ 돌리면 중간에 한도에 걸린다.
121
+
122
+ ### 3단계 — 매주 재확인 예약 (1분)
123
+
124
+ 담아야 하는 것:
125
+ - 무시된 요청 재발송 · 새로 올라온 곳 표에 추가
126
+ - ★**개인정보가 안 들어간 새 대화에서 만든다**(②번 이유)
127
+ - 예약 개수 여유가 있는지 먼저 확인
128
+
129
+ ---
130
+
131
+ ## 2. ★원장을 네가 들고 간다 — 이게 대화 프롬프트와 다른 점이다
132
+
133
+ 삭제 요청은 **보낸 것**과 **처리된 것**이 다르다. 세는 곳이 없으면 둘이 같아 보인다.
134
+ 1단계 표는 대화 속에 있고, 3주쯤 지나면 본인도 어디까지 했는지 모른다.
135
+
136
+ **작업 폴더에 `내정보삭제_원장.md` 를 만들고 유지한다.**
137
+
138
+ | 사이트 | 찾은경로 | 요청일 | 통로 | 응답 | 재요청일 | 상태 |
139
+ |---|---|---|---|---|---|---|
140
+
141
+ 상태값은 이 일곱 개만 쓴다:
142
+ `미요청` · `요청함` · `응답없음` · `추가서류요구` · `거절` · `삭제확인` · `손으로해야함`
143
+
144
+ 규칙:
145
+ - **`삭제확인` 은 사람이 직접 눈으로 본 뒤에만 찍는다.** 요청을 보낸 것은 `요청함` 이다.
146
+ - 재확인할 때는 **표를 먼저 읽고** 무엇을 다시 보낼지 정한다. 처음부터 다시 찾지 않는다.
147
+ - ★원장에 **주민번호·계좌·비밀번호를 적지 않는다.** 사이트와 상태만 적는다.
148
+ 지우려고 만든 파일이 새 노출 지점이 되면 안 된다.
149
+
150
+ ---
151
+
152
+ ## 3. 하지 않는 말
153
+
154
+ - ❌ 「다 지워 드립니다」 — 요청을 보내는 절차다. 응답은 각 사이트가 정한다
155
+ - ❌ 「무료로 됩니다」 — Work·클라우드 브라우저는 유료 전용이다
156
+ - ❌ 「검색 결과에서도 바로 사라집니다」 — 원문이 지워져도 남는다. 구글·빙의 오래된 콘텐츠
157
+ 삭제 요청이 별도로 필요하다
158
+ - ❌ 「가입한 사이트를 전부 찾아 줍니다」 — 공개된 페이지만 본다
159
+ - ❌ **남의 정보 찾기** — 본인 정보에만 쓴다. 그래서 챗GPT 도 목적을 물어본다
160
+ - ❌ 「봇 차단도 뚫습니다」 — 막히면 멈춘다
161
+
162
+ ---
163
+
164
+ ## 4. 원장 다시 보기
165
+
166
+ ```
167
+ npx --yes reborn-erase facts 사실 원장 전체
168
+ npx --yes reborn-erase steps 3단계 요약과 각 단계의 함정
169
+ npx --yes reborn-erase ledger 내정보삭제_원장.md 를 여기에 만든다
170
+ ```
171
+
172
+ 확인일 **2026-09-09**. 플랜 구성·예약 개수·기능 이름은 밖에서 바뀝니다.
@@ -0,0 +1,121 @@
1
+ {
2
+ "확인일": "2026-09-09",
3
+ "확인방법": "OpenAI 도움말 3편(예약 작업 · ChatGPT Work 및 Codex · 클라우드 브라우저)을 브라우저로 직접 열어 원문 확인. 정부 사이트 두 곳은 HTTP 응답 코드를 실측.",
4
+
5
+ "제품": {
6
+ "무엇": "챗GPT **Work 모드**로 웹에 흩어진 내 정보를 찾아 삭제를 요청하고, 매주 다시 확인하게 만드는 절차입니다.",
7
+ "무엇이아닌가": "삭제 대행 서비스가 아닙니다. 요청을 **보내 주는 것**이지 **지워 주는 것**이 아닙니다. 응답 여부는 각 사이트가 정합니다.",
8
+ "만든곳": "OpenAI (Work · 클라우드 브라우저 · 예약 작업)",
9
+ "이스킬은": "리본랩스가 만든 한국어 안내입니다. 저희는 OpenAI 와 제휴 관계가 없고, 챗GPT 를 만들지도 재배포하지도 않습니다.",
10
+ "원안": "미국 크리에이터 사브리나 라모노프가 2026년 6월에 공개한 4단계 프롬프트가 원안입니다. 국내에는 이를 3단계로 줄인 정리본이 돌고 있습니다. **이 스킬의 프롬프트 문장은 리본랩스가 새로 썼습니다** — 남의 글을 옮겨 담지 않았습니다.",
11
+ "출처": "https://help.openai.com/en/articles/20001275-chatgpt-work-and-codex"
12
+ },
13
+
14
+ "★플랜": {
15
+ "핵심": "Work 모드는 **유료 플랜에서만** 열립니다. 무료·Go 계정에는 토글 자체가 없습니다.",
16
+ "원문": "Work is available on ChatGPT web and mobile for eligible paid plans.",
17
+ "클라우드브라우저원문": "클라우드 브라우저는 지원되는 지역의 유료 ChatGPT 플랜(Free 및 Go 플랜 제외)에서 ChatGPT Work에 사용할 수 있습니다.",
18
+ "★유료여도_안_뜰_수_있다": "도움말이 **아직 순차 배포 중**이라고 적어 두었습니다 — \"계정에 ChatGPT Work가 아직 표시되지 않는다면, 계정에 아직 접근 권한이 부여되지 않았을 수 있습니다.\" 돈을 냈는데 토글이 없으면 **고장이 아니라 순번**입니다.",
19
+ "★사용량도_한도가_있다": "Work 사용량은 Codex 와 같은 주머니에서 나갑니다(에이전트 사용량·크레딧). 사이트 수십 곳을 한 번에 돌리면 **중간에 한도에 걸릴 수 있습니다.**",
20
+ "그래서어떻게": "1단계(표 만들기)는 일반 채팅에서도 됩니다. Work 가 없으면 표까지만 받고, **2단계(폼 대신 제출)는 손으로** 합니다. 한 번에 다 하지 말고 사이트를 5~10곳씩 끊어서 돌리세요.",
21
+ "출처": "https://help.openai.com/en/articles/20001275-chatgpt-work-and-codex"
22
+ },
23
+
24
+ "★예약": {
25
+ "핵심": "3단계에서 만드는 주간 재확인 예약은 **개수 제한**이 있습니다.",
26
+ "원문": "Active task limits depend on the plan: 3 for Free and Go, 5 for Plus, 10 for Business and Edu, and 15 for Pro and Enterprise.",
27
+ "플랜별": [
28
+ { "플랜": "Free · Go", "개수": 3, "비고": "반복은 **하루 1회까지**. 시각은 오전/오후/밤 같은 **구간**으로만 잡힙니다" },
29
+ { "플랜": "Plus", "개수": 5, "비고": "정시 지정·시간 단위 반복이 여기서부터 됩니다" },
30
+ { "플랜": "Business · Edu", "개수": 10, "비고": "" },
31
+ { "플랜": "Pro · Enterprise", "개수": 15, "비고": "" }
32
+ ],
33
+ "★조용히_멈춘다": "도움말이 직접 적어 둡니다 — \"A task may pause if it is inactive, requires additional action, or its associated chat is deleted.\" **대화를 지우면 그 대화에 붙은 예약이 멈춥니다.**",
34
+ "★이게_왜_이_소재에서_치명적인가": "내 개인정보를 훑어 놓은 대화입니다. 다 끝나면 **그 대화부터 지우고 싶어집니다.** 그런데 지우는 순간 매주 재확인 예약이 **소리 없이 멈춥니다.** 아무 알림도 오지 않습니다. 무시된 삭제 요청을 다시 보내는 사람이 사라지는데, 본인은 여전히 돌고 있다고 믿습니다.",
35
+ "그래서어떻게": "재확인 예약은 **정보가 안 들어간 새 대화**에서 따로 만드세요. 원본 대화를 지우더라도 예약이 살아 있습니다. 그리고 한 달에 한 번 **예약 화면을 직접 열어** 「일시중지」로 바뀌어 있지 않은지 눈으로 보세요.",
36
+ "확인하는곳": "ChatGPT → 예약(Scheduled) · 또는 설정 > 알림 > 작업 관리",
37
+ "출처": "https://help.openai.com/en/articles/10291617-scheduled-tasks-in-chatgpt"
38
+ },
39
+
40
+ "★브라우저": {
41
+ "핵심": "클라우드 브라우저는 **클라우드의 다른 컴퓨터**에서 돕니다. 내 브라우저가 아닙니다.",
42
+ "원문": "클라우드 브라우저는 사용자의 기기에 설치된 브라우저와 별개입니다. 클라우드 브라우저는 자체적으로 쿠키, 브라우저 데이터 및 로그인 세션을 유지합니다.",
43
+ "멈추는순간": "입력 · 로그인 · 확인이 필요할 때만 멈춥니다. 그 외에는 대화를 닫거나 컴퓨터를 꺼도 계속 돕니다.",
44
+ "★막히면_안_뚫는다": "\"Some websites use security measures that restrict access from automated browser agents. A website may block ChatGPT from accessing the site or completing your task, even if the same website works normally in your own browser.\" — 봇 차단이 뜨면 **우회하지 않고 멈춥니다.** 내 브라우저에서 멀쩡한 사이트여도 그렇습니다.",
45
+ "★비밀번호는_대화창에_치지_않는다": "\"Never paste passwords, security codes, or payment details into the conversation. Use the secure sign-in flow for credentials.\" 로그인은 **보안 로그인 양식**으로만 합니다. 그 양식에 넣은 아이디·비밀번호는 모델에게 보이지 않습니다.",
46
+ "그래서어떻게": "막힌 사이트는 **표에 남겨 두고 직접 들어가** 요청문을 붙여넣으세요. 지우는 일에서 「못 한 곳」을 목록에 남기는 것이 「했다 치는 것」보다 낫습니다.",
47
+ "출처": "https://help.openai.com/en/articles/20001280-using-cloud-browser-in-chatgpt"
48
+ },
49
+
50
+ "★남는것": {
51
+ "핵심": "**지우러 갔다가 흔적을 남깁니다.** 클라우드 브라우저는 자기 쿠키와 로그인 세션을 따로 들고 있습니다.",
52
+ "원문": "After you sign in, ChatGPT can resume the task using your signed-in session. The authentication will persist for future tasks until it expires, so you do not need to sign in each time.",
53
+ "★왜_이_소재에서_문제인가": "개인정보를 지우겠다고 여러 사이트에 **로그인한 세션**이 클라우드 쪽에 그대로 남습니다. 만료될 때까지 유지됩니다. 원안 정리본들은 이 칸을 말하지 않습니다.",
54
+ "그래서어떻게": "작업이 끝나면 **설정 > 클라우드 브라우저 > 브라우저 데이터**에서 사이트 데이터를 지우세요. 지우면 그 사이트에서 로그아웃됩니다(그게 목적입니다).",
55
+ "출처": "https://help.openai.com/en/articles/20001280-using-cloud-browser-in-chatgpt"
56
+ },
57
+
58
+ "★못찾는것": {
59
+ "핵심": "챗GPT 가 보는 것은 **웹에 공개된 페이지**뿐입니다. 못 찾는 자리가 정해져 있습니다.",
60
+ "목록": [
61
+ { "어디": "로그인해야 보이는 곳", "왜": "공개 페이지가 아니라 검색으로 안 잡힙니다", "대신": "직접 로그인해 내 이름·아이디로 사이트 내 검색" },
62
+ { "어디": "검색 로봇을 막아 둔 국내 커뮤니티", "왜": "크롤러 접근이 차단돼 있어 대신 들여다보지 못합니다", "대신": "로그인한 상태에서 손으로 검색" },
63
+ { "어디": "가입만 해두고 글은 안 쓴 곳", "왜": "노출된 페이지가 없으니 **찾을 근거 자체가 없습니다**", "대신": "이메일함에서 「회원가입」 검색 · 네이버·카카오·구글 계정의 「연결된 서비스」 목록" }
64
+ ],
65
+ "★가장_큰_구멍": "가입 내역입니다. 표가 아무리 깨끗해도 **가입해 둔 곳은 한 줄도 안 나옵니다.** 표가 비었다고 안심하면 안 되는 이유입니다.",
66
+ "정부통로": {
67
+ "이름": "e프라이버시 클린서비스 (개인정보보호위원회·한국인터넷진흥원)",
68
+ "무엇": "본인인증으로 가입한 사이트 내역을 조회하고, 탈퇴가 어려운 곳은 탈퇴를 대신 신청해 줍니다",
69
+ "★실측": "2026-09-09 이 PC 에서 www.eprivacy.go.kr 이 **응답하지 않았습니다**(타임아웃). 같은 시각 www.privacy.go.kr 과 www.kisa.or.kr 은 200 이었습니다. 그래서 **주소를 링크로 세우지 않습니다** — 안 열리는 링크를 적어 두면 그 줄 전체를 못 믿게 됩니다.",
70
+ "그래서어떻게": "이름으로 검색해 들어가시고, 안 열리면 개인정보보호포털(www.privacy.go.kr)에서 찾으세요."
71
+ },
72
+ "출처": "OpenAI 도움말(클라우드 브라우저) + 2026-09-09 응답 코드 실측"
73
+ },
74
+
75
+ "★원장": {
76
+ "핵심": "삭제 요청은 **보낸 것**과 **처리된 것**이 다릅니다. 세는 곳이 없으면 둘이 같아 보입니다.",
77
+ "왜필요한가": "1단계 표는 대화 속에 있습니다. 2단계에서 요청을 보내고, 3단계 예약이 매주 돕니다. 그런데 **어느 사이트가 언제 어떤 통로로 요청됐고 무엇이 답했는지**는 아무 데도 안 남습니다. 3주쯤 지나면 본인도 모릅니다.",
78
+ "칸": ["사이트", "찾은경로", "요청일", "통로(폼·메일·탈퇴)", "응답", "재요청일", "상태"],
79
+ "상태값": ["미요청", "요청함", "응답없음", "추가서류요구", "거절", "삭제확인", "손으로해야함"],
80
+ "그래서어떻게": "이 스킬이 깔리면 클로드가 작업 폴더에 `내정보삭제_원장.md` 를 만들어 그 표를 직접 들고 갑니다. 매주 재확인 때 **표를 먼저 읽고** 무엇을 다시 보낼지 정합니다.",
81
+ "★한계": "원장은 **내가 보낸 것**을 셉니다. 사이트가 실제로 지웠는지는 그 사이트만 압니다. 「삭제확인」은 직접 눈으로 본 뒤에만 찍으세요."
82
+ },
83
+
84
+ "★프롬프트": {
85
+ "누가썼나": "리본랩스가 새로 썼습니다. 원안(라모노프)과 국내 정리본의 문장을 옮기지 않았습니다.",
86
+ "단계": [
87
+ {
88
+ "번호": 1,
89
+ "이름": "어디에 떠 있는지 표로",
90
+ "걸리는시간": "1~15분",
91
+ "무엇을한다": "노출된 페이지를 찾아 삭제 요청 통로까지 표 한 장으로 받습니다. **요청은 아직 보내지 않습니다.**",
92
+ "★거절당하면": "「특정인의 개인정보를 추적하는 데 이용될 수 있다」며 멈출 수 있습니다. 챗GPT 는 본인 확인을 못 하기 때문입니다. 그 자리에서 **목적을 밝히세요** — 내 정보이고, 삭제 요청을 하려고 노출 위치를 확인하는 중이라고.",
93
+ "★단서를_더_주면_정확해진다": "이름 하나로도 시작되지만 그러면 「확인 필요」 줄이 많아집니다. 아이디·이메일을 하나만 더 넣어도 남의 결과가 섞이는 게 크게 줄어듭니다."
94
+ },
95
+ {
96
+ "번호": 2,
97
+ "이름": "요청문 쓰고 대신 제출",
98
+ "걸리는시간": "사이트 수에 따라 30분~",
99
+ "무엇을한다": "사이트마다 삭제 요청문을 쓰고, 클라우드 브라우저가 문의 폼을 채웁니다. 로그인·최종 전송 앞에서는 멈추고 물어봅니다.",
100
+ "★해외사이트": "요청문은 **영어로** 씁니다. 처리율이 다릅니다.",
101
+ "★탈퇴가_필요한곳": "로그인이 필요한 커뮤니티·중고 거래는 삭제 요청 폼이 아니라 **탈퇴 절차**가 필요할 수 있습니다. 그건 표에 「손으로해야함」으로 남깁니다."
102
+ },
103
+ {
104
+ "번호": 3,
105
+ "이름": "매주 재확인 예약",
106
+ "걸리는시간": "1분",
107
+ "무엇을한다": "무시된 요청을 다시 보내고 새로 올라온 곳을 표에 추가하는 예약을 겁니다.",
108
+ "★새_대화에서_만든다": "개인정보가 들어간 원본 대화에서 만들지 마세요. 그 대화를 지우면 예약이 멈춥니다(★예약 칸)."
109
+ }
110
+ ]
111
+ },
112
+
113
+ "안하는말": [
114
+ { "말": "다 지워 드립니다 / 완전 삭제", "이유": "요청을 보내는 절차입니다. 응답 여부는 각 사이트가 정합니다. 서류를 요구하거나 아예 답을 안 하는 곳이 있습니다." },
115
+ { "말": "무료로 됩니다", "이유": "Work 모드와 클라우드 브라우저는 유료 플랜 전용입니다. 무료·Go 계정에는 없습니다." },
116
+ { "말": "검색 결과에서도 바로 사라집니다", "이유": "원문이 지워져도 검색 결과에 남을 수 있습니다. 구글·빙의 오래된 콘텐츠 삭제 요청이 별도로 필요합니다." },
117
+ { "말": "가입한 사이트를 전부 찾아 줍니다", "이유": "공개된 페이지만 봅니다. 가입만 해둔 곳은 한 줄도 안 나옵니다." },
118
+ { "말": "남의 정보도 찾아 드립니다", "이유": "본인 정보에만 씁니다. 타인 추적에 쓰지 마세요 — 그래서 챗GPT 도 목적을 물어봅니다." },
119
+ { "말": "봇 차단도 뚫습니다", "이유": "막히면 멈춥니다. 우회하지 않습니다." }
120
+ ]
121
+ }
package/tail.mjs ADDED
@@ -0,0 +1,31 @@
1
+ /**
2
+ * 「끝난 뒤 한 칸」 문안 — **정본은 `skillpack/tail_copy.mjs` 다.**
3
+ *
4
+ * 여기 사본이 있는 이유는 하나뿐이다: npm 패키지는 폴더 밖을 import 할 수 없다.
5
+ * 문구를 고칠 일이 생기면 **정본을 먼저 고치고** 이 파일에 옮긴다. 반대로 하지 마라.
6
+ *
7
+ * 규율(정본에서 그대로 온다):
8
+ * ① 끝난 뒤 딱 한 칸 · ② 못 깔았으면 안 띄운다 · ③ 파일을 남기지 않는다
9
+ * ④ 고지 블록 금지 — 대신 마지막 줄에서 목록과 직접 까는 법을 알려 준다
10
+ * ⑤ 첫 줄은 **방금 한 일에서 이어져야** 한다.
11
+ *
12
+ * ★가리키는 곳은 **스킬팩(8,900원)** 하나다. 클로드킷·자비스 풀스택은 여기서 말하지 않는다 —
13
+ * 0원 다음 칸이 곧바로 158,000원이면 둘 다 안 고른다(2026-08-19~24 실측).
14
+ */
15
+ export const 랜딩 = "https://rebornlabs.kr/skillpack";
16
+
17
+ export const 링크 = (퍼널) =>
18
+ `${랜딩}?utm_source=installer&utm_medium=cli&utm_campaign=${퍼널}`;
19
+
20
+ export const TAIL = {
21
+ erase: {
22
+ 이음: [
23
+ "방금 드린 건 **시작하기 전에 볼 눈**입니다 — 어디서 막히고, 무엇이 소리 없이 멈추고, 무엇이 애초에 안 나오는지.",
24
+ "이런 걸 절차마다 매번 확인하다 보면 다음 질문은 대개 **\"그래서 이 판단을 매번 누가 기억하지\"** 입니다.",
25
+ ],
26
+ 제목: "리본랩스 스킬팩",
27
+ 한줄: "같은 방식으로 골라 담은 48종을 한 줄로. 8,900원",
28
+ },
29
+ };
30
+
31
+ export const 마지막 = "목록과 직접 까는 명령까지 그 페이지에 그대로 적어 두었습니다. 안 사셔도 됩니다.";
@@ -0,0 +1,43 @@
1
+ ---
2
+ name: reborn-erase-guide
3
+ description: >
4
+ 챗GPT Work 모드로 인터넷에 흩어진 내 정보를 찾아 삭제 요청하기 전에 확인할 것 — Work 가
5
+ 유료 전용이라는 것(그리고 유료여도 순차 배포라 안 뜰 수 있다는 것), 대화를 지우면 주간
6
+ 재확인 예약이 소리 없이 멈춘다는 것, 클라우드 브라우저에 로그인 세션이 남는다는 것,
7
+ 가입만 해둔 곳은 한 줄도 안 나온다는 것. "내 정보 지우기", "개인정보 삭제 요청",
8
+ "잊힐 권리", "챗GPT 워크 모드", "구글에서 내 정보 지우기" 이야기가 나올 때 쓴다.
9
+ ---
10
+
11
+ # 내 정보 지우기 — 설치기가 남긴 안내
12
+
13
+ > **리본랩스(REBORN LABS)** 의 무료 설치기(`npx --yes reborn-erase`)가 넣은 파일입니다.
14
+ > 필요 없으시면 이 폴더를 지우세요. 지워도 `erase-guide` 스킬은 그대로 동작합니다.
15
+ >
16
+ > **챗GPT · Work · 클라우드 브라우저 · 예약 작업은 [OpenAI](https://openai.com) 의 기능입니다.
17
+ > 저희가 만든 것이 아니고, 저희와 제휴 관계도 없습니다.**
18
+ >
19
+ > 절차의 원안은 사브리나 라모노프(2026-06)의 4단계 프롬프트입니다.
20
+ > **이 스킬의 프롬프트 문장은 리본랩스가 새로 썼습니다.**
21
+
22
+ ## 깔린 것
23
+
24
+ - `erase-guide` — 사실 원장(`erase.json`)을 가진 안내 스킬
25
+
26
+ ## 다시 볼 명령
27
+
28
+ ```
29
+ npx --yes reborn-erase steps 3단계와 각 단계의 함정
30
+ npx --yes reborn-erase facts 사실 원장 전체
31
+ npx --yes reborn-erase ledger 내정보삭제_원장.md 를 여기에 만든다
32
+ ```
33
+
34
+ ## 한 줄로 기억할 것
35
+
36
+ **대화를 지우면 예약이 멈춥니다.** 개인정보를 훑어 놓은 대화라 끝나면 지우고 싶어지는데,
37
+ 지우는 순간 매주 재확인이 소리 없이 멎습니다. 알림은 오지 않습니다.
38
+ → 재확인 예약은 **정보가 안 들어간 새 대화**에서 따로 만드세요.
39
+
40
+ ## 경계
41
+
42
+ 본인 정보에만 씁니다. 타인 추적에 쓰지 마세요.
43
+ 비밀번호·인증번호는 **대화창에 치지 않습니다** — 로그인은 보안 로그인 양식으로만.