sns-auto-builder 1.0.5 → 1.0.7

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.
@@ -28,6 +28,13 @@ function workspaceDir() {
28
28
  }
29
29
 
30
30
  // 매 실행 때 최신으로 덮어쓰는 것 = 도구 자체.
31
+ // 빌더 전용 CDP 포트. 9222 는 크롬 디버깅의 관례 포트라 사용자 본인의 크롬,
32
+ // chrome-devtools MCP, 다른 자동화 도구가 이미 쓰고 있기 쉽다. 겹치면 한쪽이
33
+ // ::1 을, 다른 쪽이 127.0.0.1 을 잡아서 **엉뚱한 브라우저에 붙는다** — 조용히
34
+ // 사용자 개인 크롬을 조종하게 되므로 관례 포트를 피한다.
35
+ // scripts/chatgpt-image-gen.js 가 같은 기본값과 같은 환경변수를 쓴다.
36
+ const CDP_PORT = process.env.SNS_BUILDER_CDP_PORT || '19222';
37
+
31
38
  const TOOL_FILES = ['server.mjs', 'index.html', 'CLAUDE.md'];
32
39
  const TOOL_DIRS = ['scripts', '.claude', 'templates', 'knowledge'];
33
40
 
@@ -131,8 +138,13 @@ if (argv.includes('--login')) {
131
138
  console.log(` 로그인만 하고 창은 그대로 두거나 닫으면 됩니다.\n`);
132
139
  // 포트를 반드시 붙인다. Chrome 은 user-data-dir 당 인스턴스 하나만 띄우므로,
133
140
  // 포트 없이 뜬 창이 남으면 빌더가 그 프로필로 포트를 못 연다.
141
+ //
142
+ // 9222 가 아니라 CDP_PORT 인 이유: 9222 는 크롬 디버깅의 관례 포트라 사용자
143
+ // 본인의 크롬이나 다른 도구가 이미 쓰고 있는 경우가 있다. 실제로 한쪽이
144
+ // ::1:9222 를, 다른 한쪽이 127.0.0.1:9222 를 잡아서, 빌더가 사용자 개인
145
+ // 크롬에 붙을 뻔했다. chatgpt-image-gen.js 와 같은 값을 써야 한다.
134
146
  spawn(exe, [
135
- '--remote-debugging-port=9222',
147
+ `--remote-debugging-port=${CDP_PORT}`,
136
148
  `--user-data-dir=${profile}`,
137
149
  '--no-first-run', '--no-default-browser-check',
138
150
  'https://chatgpt.com',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sns-auto-builder",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "인스타 카드뉴스 자동 제작 빌더. Claude Code + ChatGPT 웹을 그대로 써서 API 키 없이 돌아갑니다.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -38,7 +38,14 @@ function checkBat(name, buf) {
38
38
  }
39
39
  }
40
40
 
41
- const files = readdirSync(DIST).filter((f) => f !== OUT).sort();
41
+ // 확장자 화이트리스트. dist 안에서 claude 한 번 실행했더니 .claude/.omc 가
42
+ // 생겨서 zip 빌드가 깨진 적이 있다. 팀원에게 갈 것만 명시적으로 고른다.
43
+ const files = readdirSync(DIST, { withFileTypes: true })
44
+ .filter((e) => e.isFile() && e.name !== OUT && /\.(bat|txt)$/.test(e.name))
45
+ .map((e) => e.name)
46
+ .sort();
47
+
48
+ if (files.length !== 4) throw new Error(`4개여야 하는데 ${files.length}개: ${files.join(', ')}`);
42
49
  const locals = [];
43
50
  const central = [];
44
51
  let offset = 0;
@@ -24,7 +24,7 @@
24
24
  * 브라우저:
25
25
  * 기본 — .chrome-profile 로 Chrome 을 직접 띄운다. 그 프로필로 이미 Chrome 이
26
26
  * 떠 있으면(예: chrome-devtools MCP) 프로필이 잠겨 실패한다. 그때는
27
- * --browser-url http://127.0.0.1:9222 로 떠 있는 Chrome 에 붙어라.
27
+ * --browser-url http://127.0.0.1:19222 로 떠 있는 Chrome 에 붙어라.
28
28
  */
29
29
  import { readFileSync, writeFileSync, mkdirSync, existsSync, statSync } from 'node:fs';
30
30
  import { join, resolve, dirname } from 'node:path';
@@ -35,7 +35,12 @@ const REPO_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
35
35
  const BASE_W = 1080, BASE_H = 1350, SCALE = 2; // openai-image-gen.js / html-carousel-gen.js 와 동일
36
36
  const CHATGPT = 'https://chatgpt.com/';
37
37
  const PROFILE = join(REPO_ROOT, '.chrome-profile');
38
- const DEBUG_URL = 'http://127.0.0.1:9222'; // .mcp.json MCP Chrome 열어두는 포트
38
+ // 빌더 전용 CDP 포트. bin/sns-auto-builder.mjs CDP_PORT 같은 값이어야 한다.
39
+ // 9222(크롬 디버깅 관례 포트)를 쓰다가, 사용자 본인 크롬이 127.0.0.1:9222 를 잡고
40
+ // 빌더 크롬은 ::1:9222 만 잡은 적이 있다. 그 상태에서 여기가 127.0.0.1 로 붙으면
41
+ // **사용자 개인 크롬을 조종하게 된다.** 관례 포트를 피하는 이유다.
42
+ const CDP_PORT = process.env.SNS_BUILDER_CDP_PORT || '19222';
43
+ const DEBUG_URL = `http://127.0.0.1:${CDP_PORT}`;
39
44
 
40
45
  // 이미지 안에 한글이 들어가므로 정확도 가드를 붙인다 (openai-image-gen.js 의 KOREAN 과 같은 역할).
41
46
  const KOREAN = '한글은 오타 없이 정확히 그대로 렌더링할 것. 지정하지 않은 문구는 넣지 말 것.';
@@ -156,13 +161,22 @@ async function waitForComposer(page) {
156
161
  // 조용히 틀리느니 시끄럽게 멈추는 게 낫다.
157
162
  async function attachRef(page, refPaths) {
158
163
  const want = refPaths.length;
159
- // 파일 입력이 여러 개다. 컴포저(form) 안에 있는 것이 첨부용이다.
164
+ // 화면에 input[type=file] 개쯤 있다. **accept 고른다.**
165
+ //
166
+ // 예전에는 "form 안에 있는 것"을 골랐는데, ChatGPT 가 이미지 업로드 input 을
167
+ // form 밖으로 옮기면서 form 안에는 accept 없는 다른 input 만 남았다. 거기에
168
+ // 파일을 넣으면 아무 일도 안 일어나고, 썸네일을 2분 기다리다 실패한다
169
+ // (증상: "크롬은 떴는데 프롬프트를 입력하지 않는다").
160
170
  const pickInput = async () => {
161
- const handles = await page.$$('input[type="file"]');
162
- for (const h of handles) {
163
- if (await h.evaluate((el) => !!el.closest('form'))) return h;
171
+ for (const sel of [
172
+ 'input[type="file"][data-testid="upload-photos-input"]', // 현재 ChatGPT
173
+ 'input[type="file"][accept*="image"]', // testid 바뀌어도 살아남는 조건
174
+ 'input[type="file"]',
175
+ ]) {
176
+ const h = await page.$(sel);
177
+ if (h) return h;
164
178
  }
165
- return handles[0] || null;
179
+ return null;
166
180
  };
167
181
 
168
182
  for (let attempt = 1; attempt <= 2; attempt++) {