reborn-token 1.0.1 → 1.0.2

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 CHANGED
@@ -4,11 +4,11 @@
4
4
  전부 로컬. API 키 없음. 네트워크 안 씁니다. MIT.
5
5
 
6
6
  ```
7
- npx reborn-token
7
+ npx --yes reborn-token
8
8
  ```
9
9
 
10
10
  그다음 클로드에게 **"이 PDF 마크다운으로 바꿔줘"** 라고 말하면 됩니다.
11
- 터미널에서 바로 쓰려면 `npx reborn-token md contract.pdf`.
11
+ 터미널에서 바로 쓰려면 `npx --yes reborn-token md contract.pdf`.
12
12
 
13
13
  ---
14
14
 
@@ -43,8 +43,8 @@ Anthropic 문서(`build-with-claude/pdf-support`, 2026-08-24 확인)에서 **그
43
43
  | `pptx` | 슬라이드별 제목 + 글머리 |
44
44
 
45
45
  ```
46
- npx reborn-token md contract.pdf proposal.docx pricing.xlsx
47
- npx reborn-token md contract.pdf -o ./out
46
+ npx --yes reborn-token md contract.pdf proposal.docx pricing.xlsx
47
+ npx --yes reborn-token md contract.pdf -o ./out
48
48
  ```
49
49
 
50
50
  찍어 주는 것:
@@ -81,7 +81,7 @@ npx reborn-token md contract.pdf -o ./out
81
81
  ## 설치 확인
82
82
 
83
83
  ```
84
- npx reborn-token --check
84
+ npx --yes reborn-token --check
85
85
  ```
86
86
 
87
87
  설치기는 파일을 복사하고 끝내지 않고 **변환기를 실제로 불러** 확인한 뒤에
package/cli.mjs CHANGED
@@ -2,10 +2,11 @@
2
2
  /**
3
3
  * 토큰 절반 — PDF·워드·엑셀을 **깔끔한 마크다운**으로 바꾼다.
4
4
  *
5
- * npx reborn-token 스킬 설치 (+ 설치 뒤 실제로 돌려 확인)
6
- * npx reborn-token md <파일...> 변환 → 파일 옆에 .md
7
- * npx reborn-token md <파일> -o out 나갈 폴더 지정
8
- * npx reborn-token --check 설치 상태만 본다
5
+ * npx --yes reborn-token 스킬 설치 (+ 설치 뒤 실제로 돌려 확인)
6
+ * npx --yes reborn-token md <파일...> 변환 → 파일 옆에 .md
7
+ * npx --yes reborn-token md <파일> -o out 나갈 폴더 지정
8
+ * npx --yes reborn-token --check 설치 상태만 본다
9
+ * npx --yes reborn-token --lang=en 화면을 영어로 (안 주면 컴퓨터 로케일)
9
10
  *
10
11
  * ★왜 만들었나 — Anthropic 공식 문서(2026-08-24 확인):
11
12
  * "The system converts each page of the document into an image.
@@ -25,6 +26,129 @@ const c = { g: "\x1b[32m", r: "\x1b[31m", y: "\x1b[33m", d: "\x1b[90m", cy: "\x1
25
26
 
26
27
  const 인자 = process.argv.slice(2);
27
28
  const 첫 = 인자[0];
29
+ /** `--lang=en` · `--lang=ko`. 안 주면 이 컴퓨터의 로케일로 정한다(→ `말정하기`). */
30
+ const 말강제 = (인자.find((a) => a.startsWith("--lang=")) || "").slice(7).toLowerCase();
31
+
32
+ /**
33
+ * 어느 말로 말할 것인가. (2026-09-23 · 영어권 2차 ①)
34
+ *
35
+ * ★기준 패턴은 `claudekit/npm_video_skills/install.mjs` 다. 거기와 같은 인자 규약(`--lang=`)을 쓴다.
36
+ * ★고객 컴퓨터의 로케일이 곧 그 사람이 읽는 말이다. 서버에 묻지 않는다.
37
+ * ★못 읽으면 한국어로 떨어진다. 지금 이걸 받는 사람의 절대다수가 한국 고객이라,
38
+ * 판정이 실패했을 때 덜 틀리는 쪽이 그쪽이다.
39
+ */
40
+ export function 말정하기(강제) {
41
+ if (강제 === "en" || 강제 === "ko") return 강제;
42
+ try {
43
+ return /^ko\b/i.test(Intl.DateTimeFormat().resolvedOptions().locale || "") ? "ko" : "en";
44
+ } catch { return "ko"; }
45
+ }
46
+
47
+ /**
48
+ * 화면에 찍는 말. **색은 여기 넣지 않는다** — 부르는 쪽이 입힌다.
49
+ *
50
+ * ★한국어 문구는 **한 글자도 바꾸지 않았다.** 옮겨 담기만 했다.
51
+ * ★영문 꼬리는 번역이 아니다. 영어권 고객에게는 스킬팩(영문 착지) 한 칸으로 간다.
52
+ */
53
+ const 글표 = {
54
+ ko: {
55
+ /* md 변환 */
56
+ 파일주세요: "✗ 바꿀 파일을 주세요",
57
+ 파일예시: "예: npx --yes reborn-token md contract.pdf",
58
+ 파일없음: "파일이 없습니다",
59
+ 스캔본오류: (쪽수) => `글자가 거의 없습니다(${쪽수}쪽) — 스캔본이거나 이미지로만 된 PDF 입니다. `
60
+ + `이런 파일은 마크다운으로 바꿀 텍스트 자체가 없어, 그대로 클로드에 넣는 편이 낫습니다.`,
61
+ 미지원형식: (확장) => `아직 못 바꾸는 형식입니다(${확장 || "확장자 없음"}) — pdf · docx · xlsx · pptx 를 지원합니다`,
62
+ 글자없음: "가져올 글자가 없습니다",
63
+ 글자표시: (n) => `글자 ${n}자 · 페이지 이미지 0`,
64
+ /* 설치 확인 — 색이 문구 중간에 끼어 있어 조각으로 쪼갠다(색은 부르는 쪽이 입힌다) */
65
+ 설치됨확인: "✓ 설치되어 있고 변환기가 실제로 뜹니다",
66
+ 아직없음: "· 아직 없습니다",
67
+ 이유_SKILL없음: "SKILL.md 가 없습니다",
68
+ 이유_머리말깨짐: "SKILL.md 의 머리말이 깨졌습니다(name 을 못 읽습니다)",
69
+ 이유_office못불림: "office 변환기를 못 불렀습니다",
70
+ 이유_토큰추정0: "토큰 추정기가 0 을 냅니다",
71
+ 이유_pdfjs못불림: "pdfjs 를 못 불렀습니다",
72
+ 이유_걸림: (msg) => `변환기를 부르다 걸렸습니다 — ${msg}`,
73
+ /* 머리말 */
74
+ 머리: "토큰 절반",
75
+ 머리설명: "PDF·워드·엑셀을 깔끔한 마크다운으로 바꿔, 페이지 이미지 토큰을 없앱니다.",
76
+ /* 설치 본 실행 */
77
+ 짐없음머리: "✗ 패키지 안에 skill/ 폴더가 없습니다",
78
+ 짐없음꼬리: "배포가 잘못된 것입니다.",
79
+ 파일수: (n, 자리) => `${n}개 파일 → ${자리}`,
80
+ 확인중: "변환기를 실제로 불러 확인하는 중…",
81
+ 확인못통과: "✗ 깔았는데 확인에서 걸렸습니다",
82
+ 설치완료머리: "✓ 설치 완료",
83
+ 설치완료꼬리: "— 변환기가 실제로 떴습니다.",
84
+ 재시작안내: "★ 클로드 코드를 껐다 켜야 스킬이 잡힙니다.",
85
+ 쓰는법머리: "쓰는 법",
86
+ 말하세요라벨: "클로드에게 그냥 말하세요 — ",
87
+ 말하세요예시: '"이 PDF 마크다운으로 바꿔줘"',
88
+ 터미널라벨: "터미널에서 바로: ",
89
+ 지원형식설명: "pdf · docx · xlsx · pptx → 제목과 표를 살린 .md",
90
+ 설명라벨: "설명 · ",
91
+ 설명주소: "https://rebornlabs.kr/token?utm_source=installer&utm_medium=cli&utm_campaign=token",
92
+ /* 스킬팩 홍보 꼬리 */
93
+ 홍보전환문장: "방금 들어가는 토큰을 줄였습니다. 나가는 토큰과 헛일까지 줄이는 묶음이 따로 있습니다.",
94
+ 프로모이름: "리본랩스 스킬팩 · 토큰절약형",
95
+ 프로모설명: " — 12종 3,900원 — 전부 48종은 8,900원",
96
+ 프로모링크: "https://rebornlabs.kr/skillpack?utm_source=installer&utm_medium=cli&utm_campaign=token",
97
+ 프로모꼬리: "목록과 직접 까는 명령까지 그 페이지에 그대로 적어 두었습니다. 안 사셔도 됩니다.",
98
+ },
99
+ en: {
100
+ /* md convert */
101
+ 파일주세요: "✗ Give me a file to convert",
102
+ 파일예시: "e.g. npx --yes reborn-token md contract.pdf",
103
+ 파일없음: "That file does not exist",
104
+ 스캔본오류: (쪽수) => `Barely any text came out (${쪽수} page${쪽수 === 1 ? "" : "s"}) — this looks like a scanned or image-only PDF. `
105
+ + `There is no text to turn into markdown, so it is better to hand Claude the original PDF instead.`,
106
+ 미지원형식: (확장) => `This format is not supported yet (${확장 || "no extension"}) — pdf, docx, xlsx and pptx are.`,
107
+ 글자없음: "There was no text to pull out of that file",
108
+ 글자표시: (n) => `${n} character${n === 1 ? "" : "s"} · page images: 0`,
109
+ /* install check */
110
+ 설치됨확인: "✓ Installed, and the converter actually loads",
111
+ 아직없음: "· Not installed yet",
112
+ 이유_SKILL없음: "SKILL.md is missing",
113
+ 이유_머리말깨짐: "SKILL.md's front matter is broken (could not read its name)",
114
+ 이유_office못불림: "Could not load the office converter",
115
+ 이유_토큰추정0: "The token estimator returns 0",
116
+ 이유_pdfjs못불림: "Could not load pdfjs",
117
+ 이유_걸림: (msg) => `Loading the converter failed — ${msg}`,
118
+ /* header */
119
+ 머리: "Token Half",
120
+ 머리설명: "Turns PDF, Word and Excel files into clean markdown, so page-image tokens disappear.",
121
+ /* install run */
122
+ 짐없음머리: "✗ There is no skill/ folder inside this package",
123
+ 짐없음꼬리: "this build is broken.",
124
+ 파일수: (n, 자리) => `${n} file${n === 1 ? "" : "s"} → ${자리}`,
125
+ 확인중: "Loading the converter for real to check it…",
126
+ 확인못통과: "✗ Installed, but it failed the check",
127
+ 설치완료머리: "✓ Installed",
128
+ 설치완료꼬리: "— the converter actually loaded.",
129
+ 재시작안내: "★ Restart Claude Code for the skill to be picked up.",
130
+ 쓰는법머리: "How to use it",
131
+ 말하세요라벨: "Just tell Claude — ",
132
+ 말하세요예시: '"turn this PDF into markdown"',
133
+ 터미널라벨: "Straight from the terminal: ",
134
+ 지원형식설명: "pdf · docx · xlsx · pptx → .md that keeps headings and tables",
135
+ 설명라벨: "Details · ",
136
+ 설명주소: "https://rebornlabs.kr/token?utm_source=installer&utm_medium=cli&utm_campaign=token",
137
+ /* skill pack promo tail */
138
+ 홍보전환문장: "That just cut the tokens going in. There is a separate bundle that cuts the tokens going out, and the wasted work too.",
139
+ 프로모이름: "REBORN Labs Skill Pack — token-saving set",
140
+ 프로모설명: " — 12 skills for $3.90, or all 48 for $8.90",
141
+ 프로모링크: "https://skillpack.rebornlabs.kr/?utm_source=installer&utm_medium=cli&utm_campaign=token",
142
+ 프로모꼬리: "The list and the exact install commands are right there on that page. No obligation to buy.",
143
+ },
144
+ };
145
+
146
+ /** 이번 실행이 쓰는 말. */
147
+ const 말 = 말정하기(말강제);
148
+ /** 화면 문구. 부르는 쪽은 `G.무엇` 으로 쓴다. */
149
+ const G = 글표[말];
150
+ /** 숫자 자리 구분. 말에 맞춰 로케일을 바꾼다. */
151
+ const 콤마 = (n) => Number(n).toLocaleString(말 === "en" ? "en-US" : "ko-KR");
28
152
 
29
153
  /* ══ 변환 ═════════════════════════════════════════════════════════════ */
30
154
  async function 변환명령(입력) {
@@ -34,7 +158,7 @@ async function 변환명령(입력) {
34
158
  const 파일들 = 입력.filter((a) => !a.startsWith("-"));
35
159
 
36
160
  if (!파일들.length) {
37
- console.error(`${c.r}✗ 바꿀 파일을 주세요${c[0]} ${c.d}예: npx reborn-token md contract.pdf${c[0]}`);
161
+ console.error(`${c.r}${G.파일주세요}${c[0]} ${c.d}${G.파일예시}${c[0]}`);
38
162
  process.exit(2);
39
163
  }
40
164
 
@@ -47,7 +171,7 @@ async function 변환명령(입력) {
47
171
  }
48
172
 
49
173
  async function 하나변환(경로, 나갈곳) {
50
- if (!existsSync(경로)) throw new Error("파일이 없습니다");
174
+ if (!existsSync(경로)) throw new Error(G.파일없음);
51
175
  const 확장 = extname(경로).toLowerCase();
52
176
  const { 요약 } = await import(`file://${join(여기, "lib", "tokens.mjs").replace(/\\/g, "/")}`);
53
177
 
@@ -62,8 +186,7 @@ async function 하나변환(경로, 나갈곳) {
62
186
  /* ★★스캔본은 **조용히 빈 파일을 내지 않는다.** 그건 「변환됐다」가 아니다.
63
187
  여기서 멈추고 왜 안 되는지 말한다 — 빈 .md 를 받아 든 사람은 원인을 못 찾는다. */
64
188
  if (md.replace(/\s/g, "").length < 20) {
65
- throw new Error(`글자가 거의 없습니다(${쪽수}쪽) — 스캔본이거나 이미지로만 된 PDF 입니다. `
66
- + `이런 파일은 마크다운으로 바꿀 텍스트 자체가 없어, 그대로 클로드에 넣는 편이 낫습니다.`);
189
+ throw new Error(G.스캔본오류(쪽수));
67
190
  }
68
191
  } else if (확장 === ".docx") {
69
192
  const { docx읽기 } = await import(`file://${join(여기, "lib", "office.mjs").replace(/\\/g, "/")}`);
@@ -75,10 +198,10 @@ async function 하나변환(경로, 나갈곳) {
75
198
  const { pptx읽기 } = await import(`file://${join(여기, "lib", "office.mjs").replace(/\\/g, "/")}`);
76
199
  md = pptx읽기(경로);
77
200
  } else {
78
- throw new Error(`아직 못 바꾸는 형식입니다(${확장 || "확장자 없음"}) — pdf · docx · xlsx · pptx 를 지원합니다`);
201
+ throw new Error(G.미지원형식(확장));
79
202
  }
80
203
 
81
- if (!md.trim()) throw new Error("가져올 글자가 없습니다");
204
+ if (!md.trim()) throw new Error(G.글자없음);
82
205
 
83
206
  const 폴더 = 나갈곳 ? resolve(나갈곳) : dirname(resolve(경로));
84
207
  mkdirSync(폴더, { recursive: true });
@@ -87,7 +210,7 @@ async function 하나변환(경로, 나갈곳) {
87
210
 
88
211
  console.log(`\n${c.g}✓${c[0]} ${basename(경로)} → ${c.b}${basename(나감)}${c[0]}`);
89
212
  if (쪽수) console.log(요약(쪽수, md));
90
- else console.log(` ${c.d}글자 ${md.length.toLocaleString("ko-KR")}자 · 페이지 이미지 0${c[0]}`);
213
+ else console.log(` ${c.d}${G.글자표시(콤마(md.length))}${c[0]}`);
91
214
  console.log(` ${c.d}${나감}${c[0]}`);
92
215
  }
93
216
 
@@ -111,78 +234,93 @@ function 파일목록(뿌리) {
111
234
  /** ★파일이 있다는 것으로 통과시키지 않는다. **실제로 한 장을 바꿔 본다.** */
112
235
  async function 진짜도나() {
113
236
  const md = join(대상, "SKILL.md");
114
- if (!existsSync(md)) return { 됨: false, 이유: "SKILL.md 가 없습니다" };
237
+ if (!existsSync(md)) return { 됨: false, 이유: G.이유_SKILL없음 };
115
238
  if (!/^---[\s\S]*?\bname:\s*pdf-to-md\b/m.test(readFileSync(md, "utf8"))) {
116
- return { 됨: false, 이유: "SKILL.md 의 머리말이 깨졌습니다(name 을 못 읽습니다)" };
239
+ return { 됨: false, 이유: G.이유_머리말깨짐 };
117
240
  }
118
241
  try {
119
242
  const { docx읽기 } = await import(`file://${join(여기, "lib", "office.mjs").replace(/\\/g, "/")}`);
120
243
  const { 텍스트토큰추정 } = await import(`file://${join(여기, "lib", "tokens.mjs").replace(/\\/g, "/")}`);
121
- if (typeof docx읽기 !== "function") return { 됨: false, 이유: "office 변환기를 못 불렀습니다" };
122
- if (텍스트토큰추정("가나다 abcd") <= 0) return { 됨: false, 이유: "토큰 추정기가 0 을 냅니다" };
244
+ if (typeof docx읽기 !== "function") return { 됨: false, 이유: G.이유_office못불림 };
245
+ if (텍스트토큰추정("가나다 abcd") <= 0) return { 됨: false, 이유: G.이유_토큰추정0 };
123
246
  const pdfjs = await import("pdfjs-dist/legacy/build/pdf.mjs");
124
- if (!pdfjs?.getDocument) return { 됨: false, 이유: "pdfjs 를 못 불렀습니다" };
247
+ if (!pdfjs?.getDocument) return { 됨: false, 이유: G.이유_pdfjs못불림 };
125
248
  return { 됨: true };
126
249
  } catch (e) {
127
- return { 됨: false, 이유: `변환기를 부르다 걸렸습니다 — ${String(e.message || e).slice(0, 120)}` };
250
+ return { 됨: false, 이유: G.이유_걸림(String(e.message || e).slice(0, 120)) };
128
251
  }
129
252
  }
130
253
 
131
254
  async function 설치확인만() {
132
255
  머리말();
133
256
  const r = await 진짜도나();
134
- if (r.됨) console.log(`${c.g}✓ 설치되어 있고 변환기가 실제로 뜹니다${c[0]} ${c.d}(${대상})${c[0]}\n`);
135
- else console.log(`${c.y}· 아직 없습니다${c[0]} ${c.d}— ${r.이유}${c[0]}\n`);
257
+ if (r.됨) console.log(`${c.g}${G.설치됨확인}${c[0]} ${c.d}(${대상})${c[0]}\n`);
258
+ else console.log(`${c.y}${G.아직없음}${c[0]} ${c.d}— ${r.이유}${c[0]}\n`);
136
259
  process.exit(r.됨 ? 0 : 1);
137
260
  }
138
261
 
139
262
  function 머리말() {
140
- console.log(`\n${c.b}토큰 절반${c[0]} ${c.d}· REBORN LABS · MIT${c[0]}`);
141
- console.log(`${c.d}PDF·워드·엑셀을 깔끔한 마크다운으로 바꿔, 페이지 이미지 토큰을 없앱니다.${c[0]}\n`);
263
+ console.log(`\n${c.b}${G.머리}${c[0]} ${c.d}· REBORN LABS · MIT${c[0]}`);
264
+ console.log(`${c.d}${G.머리설명}${c[0]}\n`);
142
265
  }
143
266
 
144
267
  async function 설치() {
145
268
  머리말();
146
269
  const 원본 = join(여기, "skill");
147
270
  if (!existsSync(원본)) {
148
- console.error(`${c.r}✗ 패키지 안에 skill/ 폴더가 없습니다${c[0]} — 배포가 잘못된 것입니다.`);
271
+ console.error(`${c.r}${G.짐없음머리}${c[0]} — ${G.짐없음꼬리}`);
149
272
  process.exit(2);
150
273
  }
151
274
  let 쓴수 = 0;
152
275
  for (const src of 파일목록(원본)) {
153
276
  const 상대 = relative(원본, src);
277
+ /* ★SKILL.en.md 는 원본 이름으로 심지 않는다 — 영문이면 아래서 SKILL.md 자리에 덮어 쓴다.
278
+ 한국어면 애초에 안 쓴다(고객 폴더에 낯선 파일을 남기지 않는다). */
279
+ if (상대 === "SKILL.en.md") continue;
154
280
  const dst = join(대상, 상대);
155
281
  mkdirSync(dirname(dst), { recursive: true });
156
282
  writeFileSync(dst, readFileSync(src));
157
283
  쓴수++;
158
284
  console.log(` ${c.d}·${c[0]} ${상대}`);
159
285
  }
160
- console.log(`\n${c.d}${쓴수}개 파일 → ${대상}${c[0]}`);
161
- console.log(`${c.d}변환기를 실제로 불러 확인하는 중…${c[0]}`);
286
+ /* ★영문이면 SKILL.md 를 영문판으로 덮어 쓴다 (2026-09-23 · 영어권 2차 ①).
287
+ ★description 이 영어여야 영어권 클로드가 이 스킬을 실제로 부른다 — 이게 핵심이다.
288
+ ★파일이 없으면(아직 영문판을 못 만든 다른 배포라도) 그냥 넘어간다 — 설치 자체를 막지 않는다. */
289
+ if (말 === "en") {
290
+ const en원본 = join(원본, "SKILL.en.md");
291
+ if (existsSync(en원본)) {
292
+ writeFileSync(join(대상, "SKILL.md"), readFileSync(en원본));
293
+ console.log(` ${c.d}·${c[0]} SKILL.md ${c.d}(en)${c[0]}`);
294
+ }
295
+ }
296
+ console.log(`\n${c.d}${G.파일수(쓴수, 대상)}${c[0]}`);
297
+ console.log(`${c.d}${G.확인중}${c[0]}`);
162
298
 
163
299
  const r = await 진짜도나();
164
300
  if (!r.됨) {
165
- console.error(`\n${c.r}✗ 깔았는데 확인에서 걸렸습니다${c[0]} — ${r.이유}\n`);
301
+ console.error(`\n${c.r}${G.확인못통과}${c[0]} — ${r.이유}\n`);
166
302
  process.exit(1);
167
303
  }
168
304
 
169
- console.log(`\n${c.g}${c.b}✓ 설치 완료${c[0]} ${c.d}— 변환기가 실제로 떴습니다.${c[0]}`);
170
- console.log(`\n${c.y}★ 클로드 코드를 껐다 켜야 스킬이 잡힙니다.${c[0]}`);
171
- console.log(`\n${c.b}쓰는 법${c[0]}`);
172
- console.log(` 클로드에게 그냥 말하세요 — ${c.cy}"이 PDF 마크다운으로 바꿔줘"${c[0]}`);
173
- console.log(` 터미널에서 바로: ${c.cy}npx reborn-token md contract.pdf${c[0]}`);
174
- console.log(` ${c.d}pdf · docx · xlsx · pptx → 제목과 표를 살린 .md${c[0]}\n`);
175
- console.log(`${c.d}설명 · https://rebornlabs.kr/token?utm_source=installer&utm_medium=cli&utm_campaign=token${c[0]}`);
305
+ console.log(`\n${c.g}${c.b}${G.설치완료머리}${c[0]} ${c.d}${G.설치완료꼬리}${c[0]}`);
306
+ console.log(`\n${c.y}${G.재시작안내}${c[0]}`);
307
+ console.log(`\n${c.b}${G.쓰는법머리}${c[0]}`);
308
+ console.log(` ${G.말하세요라벨}${c.cy}${G.말하세요예시}${c[0]}`);
309
+ console.log(` ${G.터미널라벨}${c.cy}npx --yes reborn-token md contract.pdf${c[0]}`);
310
+ console.log(` ${c.d}${G.지원형식설명}${c[0]}\n`);
311
+ console.log(`${c.d}${G.설명라벨}${G.설명주소}${c[0]}`);
176
312
  /* ★무료 배포물 안에 유료 제품 안내를 둔다. 숨기지 않는다. */
177
313
  /* ★가리키는 곳을 158,000원 클로드킷 → 8,900원 스킬팩으로 내렸다 (2026-08-24).
178
314
  무료 다음 칸이 곧바로 158,000원이라 아무도 못 건넜다(판매 페이지까지 간 10명 중 0명).
179
315
  자비스는 스킬팩을 산 사람에게 민다 — 그래야 계단이 생긴다.
180
- ★문안 정본은 skillpack/tail_copy.mjs. */
181
- console.log(`${c.d}방금 들어가는 토큰을 줄였습니다. 나가는 토큰과 헛일까지 줄이는 묶음이 따로 있습니다.${c[0]}`);
316
+ ★문안 정본은 skillpack/tail_copy.mjs.
317
+ ★영문은 전용 호스트(`skillpack.rebornlabs.kr`)로 간다 — 한국어 착지로 보내면
318
+ 영어권 고객이 원화와 한국어 약관 앞에서 돌아선다. → G.프로모링크 가 가른다. */
319
+ console.log(`${c.d}${G.홍보전환문장}${c[0]}`);
182
320
  console.log(`
183
- ${c.b}리본랩스 스킬팩 · 토큰절약형${c[0]}${c.d} — 12종 3,900원 — 전부 48종은 8,900원${c[0]}`);
184
- console.log(`${c.cy}https://rebornlabs.kr/skillpack?utm_source=installer&utm_medium=cli&utm_campaign=token${c[0]}`);
185
- console.log(`${c.d}목록과 직접 까는 명령까지 그 페이지에 그대로 적어 두었습니다. 안 사셔도 됩니다.${c[0]}
321
+ ${c.b}${G.프로모이름}${c[0]}${c.d}${G.프로모설명}${c[0]}`);
322
+ console.log(`${c.cy}${G.프로모링크}${c[0]}`);
323
+ console.log(`${c.d}${G.프로모꼬리}${c[0]}
186
324
  `);
187
325
  }
188
326
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reborn-token",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "PDF·워드·엑셀을 깔끔한 마크다운으로 바꿔 클로드에 넣습니다. PDF 를 그대로 넣으면 페이지마다 텍스트와 이미지가 둘 다 청구되는데(Anthropic 공식 문서), 마크다운에는 페이지 이미지가 없습니다. 제목과 표는 그대로 유지. 전부 로컬, API 키 없음.",
5
5
  "keywords": [
6
6
  "claude",
@@ -0,0 +1,80 @@
1
+ ---
2
+ name: pdf-to-md
3
+ description: Converts PDF, Word, Excel and PowerPoint files into clean markdown before Claude reads them, so headings and tables survive but page-image tokens do not. Anthropic's own docs say every PDF page is billed as text AND as a rendered image — markdown has no pages and no images, so that image cost disappears entirely. Use this whenever the user hands over a PDF, contract, report, spreadsheet or Word file and says things like "read this", "summarize this", "analyze this", "go through this doc", or asks "why is this PDF so expensive", "how do I save tokens on documents", "convert this file". Runs fully offline, no API key needed.
4
+ license: MIT
5
+ ---
6
+
7
+ # PDF → Markdown (pdf-to-md)
8
+
9
+ Turn a document into **text-only markdown** before handing it to Claude.
10
+
11
+ ## Why do this first
12
+
13
+ Anthropic's own documentation (`build-with-claude/pdf-support`) says:
14
+
15
+ > The system converts each page of the document into an image.
16
+ > The text from each page is extracted and provided alongside each page's image.
17
+
18
+ > Text token costs: Each page typically uses **1,500–3,000 tokens per page**
19
+ > Image token costs: **Because each page is converted into an image**, the same
20
+ > image-based cost calculations are applied.
21
+
22
+ In other words, feeding Claude a raw PDF bills **both text and an image for every page.**
23
+ A 20-page contract can burn tens of thousands of tokens before a single question is asked.
24
+
25
+ Markdown has **no pages and no images.** Only the text cost remains.
26
+
27
+ ## When this kicks in
28
+
29
+ - The user hands over a **PDF, DOCX, XLSX or PPTX file** and says "read this / summarize this / analyze this / go through this"
30
+ - "Find X in this contract", "just the key points of this report"
31
+ - "Why is feeding in a PDF so expensive?", "how do I save tokens on documents", "convert this file"
32
+
33
+ ## How to do it
34
+
35
+ ```
36
+ npx --yes reborn-token md <file...> --lang=en
37
+ ```
38
+
39
+ This writes a `.md` file next to the original. Then **read that `.md` file** and answer from it.
40
+
41
+ - Several at once: `npx --yes reborn-token md a.pdf b.docx c.xlsx --lang=en`
42
+ - A different output folder: `npx --yes reborn-token md a.pdf -o ./out --lang=en`
43
+
44
+ ### Order of operations
45
+
46
+ 1. **Convert first.** Don't read the user's original document as-is — run the command above to produce the `.md`.
47
+ 2. **Read the converted file.** Answer from the `.md`, not the original.
48
+ 3. **Mention the size drop in one line.** Reuse the "before / after" numbers the command itself printed.
49
+ ★Don't invent numbers. Only state what the command actually printed.
50
+
51
+ ## What survives the conversion
52
+
53
+ | Survives | Dropped |
54
+ |---|---|
55
+ | Heading levels (`#` `##`) | Page images |
56
+ | Paragraphs and line breaks | Figures, charts, shapes |
57
+ | **Tables** (as markdown tables) | Fonts, colors, spacing |
58
+ | Per-sheet tables from Excel | Headers/footers as decoration |
59
+
60
+ ## When it doesn't work — say so plainly
61
+
62
+ - **Scanned or image-only PDFs**: there is no text to pull out. The command stops right there and prints why.
63
+ In this case, **feeding Claude the original PDF is actually the better choice** — it's a document that has to be seen, not read.
64
+ ★Never write an empty `.md` and claim it "converted."
65
+ - **Documents where charts or diagrams carry the meaning**: stripping to text-only loses that meaning. Include the original alongside the `.md`.
66
+ - Supported formats are `pdf`, `docx`, `xlsx`, `pptx` only. Anything else is rejected by the command.
67
+
68
+ ## How to answer the user
69
+
70
+ 1. **Convert first, then answer.** Don't ask "should I convert it?" first — that costs an extra round trip.
71
+ 2. **Add one line about how much it shrank.** Keep it short, don't over-explain.
72
+ 3. If it's a scan, **say the conversion failed** and suggest using the original file instead.
73
+ 4. This tool **never touches the network.** If asked "where does this get uploaded," the answer is: nowhere.
74
+
75
+ ## Reference
76
+
77
+ - `references/PDF토큰.md` — the original Anthropic quote and how the estimate is computed (Korean; the numbers and quoted English text are the same either way)
78
+
79
+ ---
80
+ REBORN LABS · MIT · https://rebornlabs.kr/token?utm_source=installer&utm_medium=cli&utm_campaign=token
package/skill/SKILL.md CHANGED
@@ -33,13 +33,13 @@ Anthropic 공식 문서(`build-with-claude/pdf-support`)가 이렇게 적어 두
33
33
  ## 어떻게 하나
34
34
 
35
35
  ```
36
- npx reborn-token md <파일...>
36
+ npx --yes reborn-token md <파일...>
37
37
  ```
38
38
 
39
39
  파일 옆에 `.md` 가 생긴다. 그다음 **그 `.md` 를 읽어서** 답한다.
40
40
 
41
- - 여러 개 한 번에: `npx reborn-token md a.pdf b.docx c.xlsx`
42
- - 다른 폴더로: `npx reborn-token md a.pdf -o ./out`
41
+ - 여러 개 한 번에: `npx --yes reborn-token md a.pdf b.docx c.xlsx`
42
+ - 다른 폴더로: `npx --yes reborn-token md a.pdf -o ./out`
43
43
 
44
44
  ### 순서
45
45
 
@@ -1,50 +1,50 @@
1
- ---
2
- name: reborn-token-guide
3
- description: >
4
- PDF 를 클로드에 넣으면 왜 비용이 두 번 나가는지, 마크다운으로 바꾸면 무엇이 사라지는지,
5
- 그리고 그다음 단계인 무인 자동 발행이 어디서부터 필요한지 알려 준다.
6
- "PDF 넣으면 왜 비싸", "토큰 아끼는 법", "문서 변환", "계약서 요약",
7
- "자동으로 올리고 싶다" 같은 이야기가 나올 때 쓴다.
8
- ---
9
-
10
- # PDF 는 왜 두 번 청구되나 — 그리고 어디부터는 다른 문제인가
11
-
12
- > 이 파일은 **리본랩스(REBORN LABS)** 의 무료 설치기가 넣은 것입니다.
13
- > 필요 없으시면 이 폴더를 지우세요. 지워도 `pdf-to-md` 스킬은 그대로 동작합니다.
14
-
15
- ## 방금 깐 것
16
-
17
- `pdf-to-md` — 문서를 **제목과 표를 살린 마크다운**으로 바꿔 클로드에 넣습니다.
18
-
19
- ```
20
- npx reborn-token md contract.pdf
21
- ```
22
-
23
- `pdf` · `docx` · `xlsx` · `pptx` 넷을 바꿉니다. 전부 로컬에서 돌고 API 키가 없습니다.
24
-
25
- ## 한 줄 요약
26
-
27
- Anthropic 공식 문서가 이렇게 적어 두었습니다 —
28
- **"각 페이지가 이미지로 변환되고, 그 텍스트가 페이지 이미지와 함께 제공된다."**
29
- 그래서 PDF 한 장에 **텍스트와 이미지가 둘 다** 실립니다.
30
- 마크다운에는 페이지가 없으니 이미지 몫이 사라집니다.
31
-
32
- ## 이게 해 주지 않는 것
33
-
34
- - **스캔본은 못 바꿉니다.** 글자가 없는 PDF 는 원본을 그대로 넣는 편이 낫습니다.
35
- - 차트·도형의 뜻은 옮기지 못합니다. 글자만 가져옵니다.
36
- - 요금 청구서를 계산해 주지 않습니다.
37
- - 정해진 시각에 **사람 없이** 도는 예약 실행
38
- - 실패했을 때 다시 미는 회복 경로 (무인 운영 사고의 대부분이 여기서 납니다)
39
- - 채널별 규격 · 중복 차단 · 발행 원장
40
-
41
- 문서를 아껴 넣어도 **매일 알아서 올라가지는 않습니다.** 그건 파이프라인이 하는 일입니다.
42
-
43
- ## 그 다음이 필요하면
44
- 리본랩스 **스킬팩 · 토큰절약형** — 나가는 토큰과 헛일까지 줄이는 12종(3,900원).
45
- 전부 48종은 8,900원입니다.
46
- **목록과 직접 까는 명령이 같은 주소에 전부 공개돼 있습니다** — 한 푼도 안 내고 쓰실 수 있습니다.
47
-
48
- https://rebornlabs.kr/skillpack?utm_source=installer&utm_medium=cli&utm_campaign=token
49
-
50
- > 광고입니다. 다만 `pdf-to-md` 는 그것과 무관하게 그냥 쓰셔도 됩니다 — MIT 이고 완전 무료입니다.
1
+ ---
2
+ name: reborn-token-guide
3
+ description: >
4
+ PDF 를 클로드에 넣으면 왜 비용이 두 번 나가는지, 마크다운으로 바꾸면 무엇이 사라지는지,
5
+ 그리고 그다음 단계인 무인 자동 발행이 어디서부터 필요한지 알려 준다.
6
+ "PDF 넣으면 왜 비싸", "토큰 아끼는 법", "문서 변환", "계약서 요약",
7
+ "자동으로 올리고 싶다" 같은 이야기가 나올 때 쓴다.
8
+ ---
9
+
10
+ # PDF 는 왜 두 번 청구되나 — 그리고 어디부터는 다른 문제인가
11
+
12
+ > 이 파일은 **리본랩스(REBORN LABS)** 의 무료 설치기가 넣은 것입니다.
13
+ > 필요 없으시면 이 폴더를 지우세요. 지워도 `pdf-to-md` 스킬은 그대로 동작합니다.
14
+
15
+ ## 방금 깐 것
16
+
17
+ `pdf-to-md` — 문서를 **제목과 표를 살린 마크다운**으로 바꿔 클로드에 넣습니다.
18
+
19
+ ```
20
+ npx --yes reborn-token md contract.pdf
21
+ ```
22
+
23
+ `pdf` · `docx` · `xlsx` · `pptx` 넷을 바꿉니다. 전부 로컬에서 돌고 API 키가 없습니다.
24
+
25
+ ## 한 줄 요약
26
+
27
+ Anthropic 공식 문서가 이렇게 적어 두었습니다 —
28
+ **"각 페이지가 이미지로 변환되고, 그 텍스트가 페이지 이미지와 함께 제공된다."**
29
+ 그래서 PDF 한 장에 **텍스트와 이미지가 둘 다** 실립니다.
30
+ 마크다운에는 페이지가 없으니 이미지 몫이 사라집니다.
31
+
32
+ ## 이게 해 주지 않는 것
33
+
34
+ - **스캔본은 못 바꿉니다.** 글자가 없는 PDF 는 원본을 그대로 넣는 편이 낫습니다.
35
+ - 차트·도형의 뜻은 옮기지 못합니다. 글자만 가져옵니다.
36
+ - 요금 청구서를 계산해 주지 않습니다.
37
+ - 정해진 시각에 **사람 없이** 도는 예약 실행
38
+ - 실패했을 때 다시 미는 회복 경로 (무인 운영 사고의 대부분이 여기서 납니다)
39
+ - 채널별 규격 · 중복 차단 · 발행 원장
40
+
41
+ 문서를 아껴 넣어도 **매일 알아서 올라가지는 않습니다.** 그건 파이프라인이 하는 일입니다.
42
+
43
+ ## 그 다음이 필요하면
44
+ 리본랩스 **스킬팩 · 토큰절약형** — 나가는 토큰과 헛일까지 줄이는 12종(3,900원).
45
+ 전부 48종은 8,900원입니다.
46
+ **목록과 직접 까는 명령이 같은 주소에 전부 공개돼 있습니다** — 한 푼도 안 내고 쓰실 수 있습니다.
47
+
48
+ https://rebornlabs.kr/skillpack?utm_source=installer&utm_medium=cli&utm_campaign=token
49
+
50
+ > 광고입니다. 다만 `pdf-to-md` 는 그것과 무관하게 그냥 쓰셔도 됩니다 — MIT 이고 완전 무료입니다.