connectbase-client 6.2.0 → 6.3.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.
Files changed (4) hide show
  1. package/CHANGELOG.md +87 -5
  2. package/README.md +24 -19
  3. package/dist/cli.js +189 -158
  4. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,88 @@
3
3
  본 SDK 의 모든 주요 변경사항을 [Keep a Changelog](https://keepachangelog.com/ko/1.1.0/) 형식으로 기록합니다.
4
4
  버전은 [Semantic Versioning](https://semver.org/lang/ko/) 을 따릅니다.
5
5
 
6
+ ## [6.3.0] - 2026-09-07
7
+
8
+ ### Fixed — Secret Key 가 만료되면 `init` 을 다시 돌릴 수 없던 문제
9
+
10
+ `init` 은 `.connectbaserc` 에 저장된 Secret Key 를 그대로 집어 씁니다. 그 키가 만료되거나
11
+ 취소되면 앱 목록 조회가 401 을 받고 **그대로 종료**했는데, 다시 실행해도 같은 죽은 키를
12
+ 다시 집어 오므로 같은 자리에서 또 죽었습니다. `.connectbaserc` 를 손으로 지우는 것 말고는
13
+ 빠져나올 길이 없었습니다.
14
+
15
+ 이제 401 을 받으면 **그 자리에서 재인증**합니다 (브라우저 로그인 또는 직접 입력). 새 키는
16
+ 즉시 `.connectbaserc` 에 저장되고 `.mcp.json` 에도 반영되므로, 파일을 지우는 절차가
17
+ 사라졌습니다. 비대화형(`--yes`)에서는 프롬프트 대신 새 키를 넘기라고 명확히 안내합니다.
18
+
19
+ `connectbase mcp` 도 같습니다 — 넘겨받은 키가 살아 있는지 **먼저 확인**한 뒤 `.mcp.json`
20
+ 에 씁니다. 종전에는 만료된 키를 그대로 적고 "설정 완료" 라고 말해서, 실패가 Claude Code 의
21
+ 401 로만 드러났습니다. (네트워크 오류로는 막지 않습니다 — 오프라인에서도 설정은 써집니다.)
22
+
23
+ 재초기화 확인 프롬프트의 기본값도 "계속" 으로 바꿨습니다. 같은 앱을 고르면 Public Key 를
24
+ 재사용하므로 재실행은 안전한 동작입니다.
25
+
26
+ ### Fixed — `npm run deploy` 가 `command not found` 로 죽던 문제
27
+
28
+ `init` 이 `package.json` 에 deploy 스크립트만 넣고 CLI 를 의존성으로 선언하지 않아서,
29
+ SDK 가 설치되지 않은 프로젝트에서 마지막 안내대로 `npm run deploy` 를 치면
30
+ `connectbase: command not found` 가 났습니다. 이제 `devDependencies` 에
31
+ `connectbase-client` 를 함께 선언하고, 설치가 필요하면 마지막 안내에 `npm install` 을
32
+ 포함합니다. (`npx --yes` 를 스크립트에 박는 우회는 쓰지 않았습니다 — 빌드마다
33
+ 레지스트리에서 최신본을 끌어오면 재현 가능한 빌드가 아닙니다.)
34
+
35
+ 빌드 스크립트가 있으면 deploy 스크립트는 이제 build 명령을 **복사하지 않고**
36
+ `npm run build && connectbase deploy <dir>` 로 위임합니다. 복사본은 build 가 바뀌어도
37
+ 갱신되지 않아 조용히 낡습니다.
38
+
39
+ ### Fixed — `--base-url` / `CONNECTBASE_BASE_URL` 이 `init` 에서 무시되던 문제
40
+
41
+ `init` 과 브라우저 로그인, SDK 문서 다운로드, MCP 설정이 상수를 직접 참조해, 로컬이나
42
+ 스테이징 스택을 지정해도 프로덕션 API 로 갔습니다. 브라우저 로그인 URL 도 같은 환경을
43
+ 가리키도록 API URL 에서 파생시킵니다.
44
+
45
+ ### Fixed — CLI 버전을 빌드 시점에 주입
46
+
47
+ 종전에는 런타임에 `package.json` 을 찾아 읽고, 실패하면 하드코딩된 옛 버전(`3.25.1`)으로
48
+ 폴백했습니다. 그 폴백은 조용히 낡았고, 단순히 `--version` 이 틀리는 데서 끝나지 않았습니다 —
49
+ `init` 이 사용자의 `package.json` 에 적는 의존성 범위에까지 그 값이 들어갑니다.
50
+
51
+ ### Fixed — git 저장소가 아닌 폴더에서 `fatal:` 오류가 출력되던 문제
52
+
53
+ `init` 이 프로젝트 루트를 찾을 때 쓰는 `git rev-parse` 의 stderr 가 그대로 새어 나와,
54
+ 정상 경로인데도 화면에 `fatal: … 깃 저장소가 아닙니다` 가 세 번 찍혔습니다.
55
+
56
+ ### Changed — 문서의 `npx` 예제가 패키지 이름을 쓰도록 통일
57
+
58
+ `connectbase` 는 이 패키지가 설치하는 **bin 이름**이지 npm 패키지 이름이 아닙니다. npx 는
59
+ 로컬 `node_modules/.bin` 을 먼저 보고, 없으면 그 이름의 **패키지**를 레지스트리에서 받으려
60
+ 합니다. 그래서 `npx connectbase init` 은 이 패키지가 이미 설치된 프로젝트에서만 동작하고,
61
+ 아무것도 없는 새 폴더 — 즉 `init` 을 처음 실행하는 바로 그 상황 — 에서는 npm 404 가 났습니다.
62
+
63
+ ```
64
+ $ npx connectbase init
65
+ npm error 404 Not Found - GET https://registry.npmjs.org/connectbase
66
+ ```
67
+
68
+ 전역 설치(`npm i -g connectbase-client`)로 PATH 에 `connectbase` 가 있어도 마찬가지입니다.
69
+ npx 는 PATH 를 보지 않습니다.
70
+
71
+ 규칙을 하나로 정리했습니다:
72
+
73
+ | 형태 | 이름 | 왜 |
74
+ |---|---|---|
75
+ | `npx …` | `connectbase-client` | npx 인자는 **패키지** 이름이다. 설치 여부와 무관하게 항상 동작 |
76
+ | 전역 설치 후 / `npm run` 스크립트 / `node_modules/.bin` | `connectbase` | 짧은 bin 이름. 0.16.1 에서 정한 용도 그대로 |
77
+
78
+ ```bash
79
+ npx connectbase-client init # 설치 전 — 패키지 이름
80
+ npm install # init 이 devDependencies 에 넣어 둔 것을 설치
81
+ npm run deploy # 내부적으로 `connectbase deploy ./dist` — 짧은 이름 그대로
82
+ ```
83
+
84
+ `connectbase` 를 실제 패키지로도 발행하려 했으나, npm 이 2013 년의 `connect-base` 와
85
+ 이름이 유사하다는 이유로 거절했습니다 (`@connectbase` 스코프도 타인이 사용 중). 이름을
86
+ 확보하면 `npx connectbase` 도 함께 동작하게 할 예정입니다.
87
+
6
88
  ## [6.2.0] - 2026-09-06
7
89
 
8
90
  ### Added — 웹 스토리지 관리 API 에 Secret Key 전송
@@ -23,7 +105,7 @@ production 승격이 가능했습니다 — 공개된 사이트에서 키를 뽑
23
105
 
24
106
  **이 버전은 아무것도 깨뜨리지 않습니다.** Secret Key 가 없으면 경고만 하고 그대로 진행합니다.
25
107
  CLI 가 서버보다 먼저 조이면, 우리가 생성해 드리는 GitHub Actions 워크플로처럼 버전을 고정하지
26
- 않는(`npx --yes connectbase deploy`) 환경이 서버 변경 전에 깨지기 때문입니다.
108
+ 않는(`npx --yes connectbase-client deploy`) 환경이 서버 변경 전에 깨지기 때문입니다.
27
109
 
28
110
  **지금 해두실 것.** CI 를 쓰신다면 저장소 시크릿에 `CONNECTBASE_SECRET_KEY` 를 추가하고
29
111
  워크플로 env 에 넣으세요. 워크플로 파일에 값을 직접 적으면 저장소에 커밋됩니다.
@@ -554,7 +636,7 @@ await ctx.cbAdmin.appMembers.remove(ctx.appId, memberId)
554
636
  ```bash
555
637
  # 이제 dist 에 두기만 하면 함께 올라간다
556
638
  echo "/blog /blog.html 200" > dist/_redirects
557
- npx connectbase deploy ./dist
639
+ npx connectbase-client deploy ./dist
558
640
  ```
559
641
 
560
642
  - `_redirects`, `_headers` 만 이름 완전일치로 허용한다. `Dockerfile`·`Makefile`·`LICENSE`
@@ -1152,7 +1234,7 @@ AI 에이전트(Claude Code 등)가 `init` 을 직접 실행할 수 있도록
1152
1234
  자동 정리(레거시 fullstack 파일 포함), `deploy` 성공 후 변경이 있을 때만 조용히 자동 갱신
1153
1235
  (`--skip-docs` 로 생략 가능).
1154
1236
  - **CLAUDE.md @import**: 참조 블록이 `@.claude/docs/project-rules.md` import 로 규칙을 매
1155
- 세션 자동 로드. MCP 미연결 시 `npx connectbase mcp` 안내 지시 포함. `mcp` 명령도 비대화형
1237
+ 세션 자동 로드. MCP 미연결 시 `npx connectbase-client mcp` 안내 지시 포함. `mcp` 명령도 비대화형
1156
1238
  지원(`--secret-key`/env/.connectbaserc 자동 사용).
1157
1239
 
1158
1240
  ### Changed / Security
@@ -2793,7 +2875,7 @@ ComfyUI × 웹스토리지 같은 e2e 통합 패턴 (작업 제출 → 폴링
2793
2875
 
2794
2876
  ### Fixed
2795
2877
 
2796
- - `npx connectbase docs` 가 인증 없이 곧장 문서를 받도록 수정. 백엔드 `/v1/storages/webs/claude-md`
2878
+ - `npx connectbase-client docs` 가 인증 없이 곧장 문서를 받도록 수정. 백엔드 `/v1/storages/webs/claude-md`
2797
2879
  는 public 라우트인데 CLI 가 불필요하게 브라우저 인증 → 앱 선택 → Public Key 발급을 강제하던
2798
2880
  흐름을 제거. 캐시된 publicKey 가 있으면 문서에 박아주고, 없으면 백엔드가 placeholder
2799
2881
  (`YOUR_PUBLIC_KEY_HERE`) 로 대체해 그대로 다운로드.
@@ -3225,7 +3307,7 @@ sisun 팀(`019d85c7-...`) 의 운영 피드백 3건이 시작점이며, 백엔
3225
3307
 
3226
3308
  ## [1.4.2] - 2026-04-18
3227
3309
 
3228
- `npx connectbase docs` 명령이 init/deploy/tunnel 과 달리 brower auth 흐름을 거치지 않아, Public Key 가 없는 사용자가 키 발급 경로를 모른 채 prompt 만 보던 UX 문제 해결.
3310
+ `npx connectbase-client docs` 명령이 init/deploy/tunnel 과 달리 brower auth 흐름을 거치지 않아, Public Key 가 없는 사용자가 키 발급 경로를 모른 채 prompt 만 보던 UX 문제 해결.
3229
3311
 
3230
3312
  ### Fixed
3231
3313
 
package/README.md CHANGED
@@ -27,7 +27,7 @@ Connect Base provides **two types** of Keys. Use the right key for your use case
27
27
  |---------|----------|---------|
28
28
  | Frontend SDK (`new ConnectBase()`) | **Public Key** (`cb_pk_`) | Web/app: DB queries, auth, file uploads |
29
29
  | `.env` file (`VITE_CONNECTBASE_PUBLIC_KEY`) | **Public Key** (`cb_pk_`) | React, Vue, etc. |
30
- | CLI deploy (`.connectbaserc`) | **Public Key + Secret Key** (`cb_pk_` + `cb_sk_`) | `npx connectbase deploy` |
30
+ | CLI deploy (`.connectbaserc`) | **Public Key + Secret Key** (`cb_pk_` + `cb_sk_`) | `npx connectbase-client deploy` |
31
31
  | MCP server (AI tools) | **Secret Key** (`cb_sk_`) | Claude, Cursor, Windsurf |
32
32
  | Server-side admin tasks | **Secret Key** (`cb_sk_`) | Backend full data access |
33
33
 
@@ -131,22 +131,27 @@ try {
131
131
 
132
132
  Deploy your web application to Connect Base Web Storage with a single command.
133
133
 
134
- > 🔐 **Deploy commands require a Secret Key (`cb_sk_*`).** The web storage deploy, promote,
135
- > create and list routes require `Authorization: Bearer cb_sk_*` on top of `X-Public-Key`,
136
- > because a Public Key is a public identifier that ships in your browser bundle and cannot
137
- > prove deploy permission. The CLI reads `secretKey` from `.connectbaserc` or the
138
- > `CONNECTBASE_SECRET_KEY` environment variable and sends it automatically **just update to
139
- > the latest version** (`npm i -g connectbase-client@latest`). Older CLIs fail with
140
- > **401 `SECRET_KEY_REQUIRED`**.
134
+ > **After `npx`, always use the package name `connectbase-client`.** This package installs two
135
+ > bins — `connectbase` and `connectbase-client` but `connectbase` is a *bin* name, not a
136
+ > package name. npx checks the local `node_modules/.bin` first and otherwise fetches a
137
+ > **package** by that name, so `npx connectbase init` only works in a project that already has
138
+ > this package installed; in an empty folder it fails with npm 404. A global install does not
139
+ > help npx does not look at `PATH`.
141
140
  >
142
- > **Never commit a Secret Key.** `init` adds `.connectbaserc` to `.gitignore`; in CI, inject it
143
- > from a repository secret instead.
141
+ > Use the short `connectbase` **after** installing: globally, inside `npm run` scripts, or via
142
+ > `node_modules/.bin`.
143
+ >
144
+ > ```bash
145
+ > npx connectbase-client init # nothing installed yet — package name
146
+ > npm install # installs what init added to devDependencies
147
+ > npm run deploy # runs `connectbase deploy ./dist` — short name is fine here
148
+ > ```
144
149
 
145
150
  ### Quick Start
146
151
 
147
152
  ```bash
148
153
  # 1. Initialize (one-time setup)
149
- npx connectbase init
154
+ npx connectbase-client init
150
155
 
151
156
  # 2. Deploy
152
157
  npm run deploy
@@ -173,14 +178,14 @@ The `init` command will:
173
178
  If you prefer not to use `init`, you can pass options directly:
174
179
 
175
180
  ```bash
176
- npx connectbase deploy ./dist -s <storage-id> -k <public-key> --secret-key <secret-key>
181
+ npx connectbase-client deploy ./dist -s <storage-id> -k <public-key> --secret-key <secret-key>
177
182
  ```
178
183
 
179
184
  The Secret Key can also come from `CONNECTBASE_SECRET_KEY` — preferred in CI, so it never
180
185
  appears in shell history or CI logs:
181
186
 
182
187
  ```bash
183
- CONNECTBASE_SECRET_KEY=cb_sk_... npx connectbase deploy ./dist -s <storage-id> -k <public-key>
188
+ CONNECTBASE_SECRET_KEY=cb_sk_... npx connectbase-client deploy ./dist -s <storage-id> -k <public-key>
184
189
  ```
185
190
 
186
191
  ### Options
@@ -204,14 +209,14 @@ Expose a local server to the internet through a secure WebSocket tunnel. Useful
204
209
 
205
210
  ```bash
206
211
  # Expose local port 8084 to the internet
207
- npx connectbase tunnel 8084 -k <public-key>
212
+ npx connectbase-client tunnel 8084 -k <public-key>
208
213
 
209
214
  # With environment variable
210
215
  export CONNECTBASE_PUBLIC_KEY=your-public-key
211
- npx connectbase tunnel 8084
216
+ npx connectbase-client tunnel 8084
212
217
 
213
218
  # For GPU servers or long-running tasks (e.g., image generation)
214
- npx connectbase tunnel 7860 --timeout 300 --max-body 50
219
+ npx connectbase-client tunnel 7860 --timeout 300 --max-body 50
215
220
  ```
216
221
 
217
222
  The tunnel creates a public URL like `https://tunnel.connectbase.world/<tunnel-id>/` that proxies all HTTP requests to your local service.
@@ -241,7 +246,7 @@ on the server, so your SDK only needs the Public Key.
241
246
 
242
247
  ```bash
243
248
  # Start ComfyUI on port 8188, expose it as endpoint label "comfyui-main"
244
- npx connectbase tunnel 8188 --label comfyui-main --description "ComfyUI on my desktop"
249
+ npx connectbase-client tunnel 8188 --label comfyui-main --description "ComfyUI on my desktop"
245
250
  ```
246
251
 
247
252
  Authentication uses your User Secret Key (`cb_sk_*`); the CLI calls the dual-auth
@@ -272,14 +277,14 @@ The `init` command creates `.connectbaserc` automatically. You can also create i
272
277
  export CONNECTBASE_PUBLIC_KEY=cb_pk_your-public-key
273
278
  export CONNECTBASE_SECRET_KEY=cb_sk_your-secret-key # required by deploy / promote
274
279
  export CONNECTBASE_STORAGE_ID=your-storage-id
275
- npx connectbase deploy ./dist
280
+ npx connectbase-client deploy ./dist
276
281
  ```
277
282
 
278
283
  In CI, read the Secret Key from a repository secret:
279
284
 
280
285
  ```yaml
281
286
  # GitHub Actions
282
- - run: npx connectbase deploy ./dist
287
+ - run: npx connectbase-client deploy ./dist
283
288
  env:
284
289
  CONNECTBASE_PUBLIC_KEY: ${{ vars.CONNECTBASE_PUBLIC_KEY }}
285
290
  CONNECTBASE_SECRET_KEY: ${{ secrets.CONNECTBASE_SECRET_KEY }}
package/dist/cli.js CHANGED
@@ -147,18 +147,7 @@ function handleTunnelError(msg, appId, localPort) {
147
147
  }
148
148
 
149
149
  // src/cli.ts
150
- function getPackageVersion() {
151
- try {
152
- const pkgPath = path2.join(__dirname, "..", "package.json");
153
- if (fs2.existsSync(pkgPath)) {
154
- const pkg = JSON.parse(fs2.readFileSync(pkgPath, "utf-8"));
155
- return pkg.version || "0.0.0";
156
- }
157
- } catch {
158
- }
159
- return "3.25.1";
160
- }
161
- var VERSION = getPackageVersion();
150
+ var VERSION = "6.3.0" ? "6.3.0" : getPackageVersion();
162
151
  var DEFAULT_BASE_URL = "https://api.connectbase.world";
163
152
  var colors = {
164
153
  reset: "\x1B[0m",
@@ -311,7 +300,7 @@ function storageAdminHeaders(config) {
311
300
  );
312
301
  log(" \uACE7 \uC11C\uBC84\uAC00 Secret Key \uB97C \uC694\uAD6C\uD569\uB2C8\uB2E4. \uC9C0\uAE08 \uC124\uC815\uD574 \uB450\uC138\uC694.");
313
302
  log(
314
- ` ${colors.cyan}npx connectbase init${colors.reset} \uC774 \uBC1C\uAE09\uD574 .connectbaserc \uC5D0 \uC800\uC7A5\uD569\uB2C8\uB2E4.`
303
+ ` ${colors.cyan}npx connectbase-client init${colors.reset} \uC774 \uBC1C\uAE09\uD574 .connectbaserc \uC5D0 \uC800\uC7A5\uD569\uB2C8\uB2E4.`
315
304
  );
316
305
  log(
317
306
  ` \uC774\uBBF8 \uD0A4\uAC00 \uC788\uB2E4\uBA74 ${colors.cyan}CONNECTBASE_SECRET_KEY${colors.reset} \uD658\uACBD\uBCC0\uC218\uB85C \uC9C0\uC815\uD558\uC138\uC694.`
@@ -667,10 +656,10 @@ async function deploy(directory, config, isDev = false, deployOpts = {}) {
667
656
  const pkg = JSON.parse(fs2.readFileSync(pkgPath, "utf-8"));
668
657
  if (pkg.scripts?.build) {
669
658
  warn(
670
- `\uBC30\uD3EC \uC804 \uBE4C\uB4DC\uB97C \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694: ${colors.cyan}npm run build && npx connectbase deploy${colors.reset}`
659
+ `\uBC30\uD3EC \uC804 \uBE4C\uB4DC\uB97C \uBA3C\uC800 \uC2E4\uD589\uD558\uC138\uC694: ${colors.cyan}npm run build && npx connectbase-client deploy${colors.reset}`
671
660
  );
672
661
  warn(
673
- `\uB610\uB294 package.json\uC5D0 deploy \uC2A4\uD06C\uB9BD\uD2B8\uB97C \uB4F1\uB85D\uD558\uC138\uC694: ${colors.cyan}npx connectbase init${colors.reset}`
662
+ `\uB610\uB294 package.json\uC5D0 deploy \uC2A4\uD06C\uB9BD\uD2B8\uB97C \uB4F1\uB85D\uD558\uC138\uC694: ${colors.cyan}npx connectbase-client init${colors.reset}`
674
663
  );
675
664
  }
676
665
  } catch {
@@ -702,7 +691,7 @@ async function deploy(directory, config, isDev = false, deployOpts = {}) {
702
691
  const envLabel = isDev ? "QA" : "Prod";
703
692
  if (isDev) {
704
693
  warn(
705
- `${colors.yellow}--dev \uB294 deprecated${colors.reset} \uC785\uB2C8\uB2E4 \u2014 QA \uCC44\uB110\uB85C \uBC30\uD3EC\uD569\uB2C8\uB2E4(production \uBBF8\uBC18\uC601). \uC774\uD6C4 ${colors.cyan}npx connectbase promote${colors.reset} \uB85C production \uC5D0 \uBC18\uC601\uD558\uC138\uC694. promote_mode=manual \uC774\uBA74 \uC77C\uBC18 ${colors.cyan}deploy${colors.reset} \uB3C4 \uB3D9\uC77C\uD558\uAC8C QA \uB85C \uBC30\uD3EC\uB429\uB2C8\uB2E4.`
694
+ `${colors.yellow}--dev \uB294 deprecated${colors.reset} \uC785\uB2C8\uB2E4 \u2014 QA \uCC44\uB110\uB85C \uBC30\uD3EC\uD569\uB2C8\uB2E4(production \uBBF8\uBC18\uC601). \uC774\uD6C4 ${colors.cyan}npx connectbase-client promote${colors.reset} \uB85C production \uC5D0 \uBC18\uC601\uD558\uC138\uC694. promote_mode=manual \uC774\uBA74 \uC77C\uBC18 ${colors.cyan}deploy${colors.reset} \uB3C4 \uB3D9\uC77C\uD558\uAC8C QA \uB85C \uBC30\uD3EC\uB429\uB2C8\uB2E4.`
706
695
  );
707
696
  }
708
697
  const baseStorageUrl = `${config.baseUrl}/v1/public/storages/webs/${config.storageId}`;
@@ -918,7 +907,7 @@ ${colors.cyan}Production: ${dep.production_url}${colors.reset}`
918
907
  log(`
919
908
  ${colors.yellow}QA URL: ${dep.qa_url}${colors.reset}`);
920
909
  log(
921
- `${colors.dim}\uAC80\uC99D \uD6C4 \uBC18\uC601: ${colors.cyan}npx connectbase promote${colors.reset}
910
+ `${colors.dim}\uAC80\uC99D \uD6C4 \uBC18\uC601: ${colors.cyan}npx connectbase-client promote${colors.reset}
922
911
  `
923
912
  );
924
913
  }
@@ -1019,7 +1008,7 @@ ${colors.cyan}\uBC30\uD3EC \uC774\uB825${colors.reset} (promote_mode: ${data.pro
1019
1008
  if (data.qa_url)
1020
1009
  log(`${colors.yellow}QA: ${data.qa_url}${colors.reset}`);
1021
1010
  log(
1022
- `${colors.dim}\uB864\uBC31: npx connectbase promote <deployment_id>${colors.reset}
1011
+ `${colors.dim}\uB864\uBC31: npx connectbase-client promote <deployment_id>${colors.reset}
1023
1012
  `
1024
1013
  );
1025
1014
  }
@@ -1086,7 +1075,9 @@ function getProjectRoot() {
1086
1075
  const gitRoot = getGitRoot();
1087
1076
  return gitRoot || process.cwd();
1088
1077
  }
1089
- var CONSOLE_URL = DEFAULT_BASE_URL.replace("api.", "");
1078
+ function consoleUrlFor(baseUrl) {
1079
+ return baseUrl.replace("api.", "");
1080
+ }
1090
1081
  function openBrowser(url) {
1091
1082
  const { exec } = require("child_process");
1092
1083
  const platform2 = process.platform;
@@ -1101,10 +1092,10 @@ function openBrowser(url) {
1101
1092
  exec(command, () => {
1102
1093
  });
1103
1094
  }
1104
- async function browserAuthFlow() {
1095
+ async function browserAuthFlow(baseUrl = DEFAULT_BASE_URL) {
1105
1096
  info("\uBE0C\uB77C\uC6B0\uC800 \uC778\uC99D \uC138\uC158\uC744 \uC2DC\uC791\uD569\uB2C8\uB2E4...");
1106
1097
  const startRes = await makeRequest(
1107
- `${DEFAULT_BASE_URL}/v1/public/cli-auth/start`,
1098
+ `${baseUrl}/v1/public/cli-auth/start`,
1108
1099
  "POST",
1109
1100
  {}
1110
1101
  );
@@ -1115,7 +1106,7 @@ async function browserAuthFlow() {
1115
1106
  process.exit(1);
1116
1107
  }
1117
1108
  const { session_id } = startRes.data;
1118
- const authUrl = `${CONSOLE_URL}/auth/cli-auth?session=${session_id}`;
1109
+ const authUrl = `${consoleUrlFor(baseUrl)}/auth/cli-auth?session=${session_id}`;
1119
1110
  log(`
1120
1111
  ${colors.cyan}\uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uB85C\uADF8\uC778\uD558\uC138\uC694:${colors.reset}`);
1121
1112
  log(`${colors.dim}${authUrl}${colors.reset}
@@ -1135,7 +1126,7 @@ ${colors.cyan}\uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uB85C\uADF8\uC778\uD558\uC13
1135
1126
  await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
1136
1127
  try {
1137
1128
  const pollRes = await makeRequest(
1138
- `${DEFAULT_BASE_URL}/v1/public/cli-auth/poll/${session_id}`,
1129
+ `${baseUrl}/v1/public/cli-auth/poll/${session_id}`,
1139
1130
  "GET",
1140
1131
  {}
1141
1132
  );
@@ -1182,10 +1173,73 @@ ${colors.cyan}\uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uB85C\uADF8\uC778\uD558\uC13
1182
1173
  error("\uC778\uC99D \uC2DC\uAC04\uC774 \uCD08\uACFC\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694.");
1183
1174
  process.exit(1);
1184
1175
  }
1176
+ async function promptForSecretKey(baseUrl = DEFAULT_BASE_URL) {
1177
+ log(`
1178
+ ${colors.dim}\uC778\uC99D \uBC29\uC2DD\uC744 \uC120\uD0DD\uD558\uC138\uC694:${colors.reset}`);
1179
+ log(` ${colors.cyan}1${colors.reset}) Secret Key \uC9C1\uC811 \uC785\uB825 (cb_sk_...)`);
1180
+ log(` ${colors.cyan}2${colors.reset}) \uBE0C\uB77C\uC6B0\uC800 \uB85C\uADF8\uC778\uC73C\uB85C \uC790\uB3D9 \uBC1C\uAE09
1181
+ `);
1182
+ const authChoice = await prompt(
1183
+ `${colors.blue}?${colors.reset} \uC120\uD0DD (1/2): `
1184
+ );
1185
+ if (authChoice === "2") {
1186
+ try {
1187
+ return await browserAuthFlow(baseUrl);
1188
+ } catch (err) {
1189
+ error(`\uB124\uD2B8\uC6CC\uD06C \uC624\uB958: ${err instanceof Error ? err.message : err}`);
1190
+ info(
1191
+ "\uC778\uD130\uB137 \uC5F0\uACB0\uC744 \uD655\uC778\uD558\uAC70\uB098, Secret Key \uC9C1\uC811 \uC785\uB825(\uC635\uC158 1)\uC744 \uC2DC\uB3C4\uD558\uC138\uC694"
1192
+ );
1193
+ process.exit(1);
1194
+ }
1195
+ }
1196
+ log(
1197
+ `${colors.dim}Secret Key (cb_sk_): \uCF58\uC194 > \uD504\uB85C\uD544 > \uC2DC\uD06C\uB9BF \uD0A4 \uD0ED\uC5D0\uC11C \uBC1C\uAE09${colors.reset}
1198
+ `
1199
+ );
1200
+ const entered = await promptSecret(
1201
+ `${colors.blue}?${colors.reset} Secret Key: `
1202
+ );
1203
+ if (!entered) {
1204
+ error("Secret Key\uB294 \uD544\uC218\uC785\uB2C8\uB2E4");
1205
+ process.exit(1);
1206
+ }
1207
+ if (entered.startsWith("cb_pk_")) {
1208
+ error("Public Key\uAC00 \uC544\uB2CC Secret Key(cb_sk_)\uB97C \uC785\uB825\uD558\uC138\uC694");
1209
+ info("Secret Key\uB294 \uCF58\uC194 > \uD504\uB85C\uD544 > \uC2DC\uD06C\uB9BF \uD0A4 \uD0ED\uC5D0\uC11C \uC0DD\uC131\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4");
1210
+ process.exit(1);
1211
+ }
1212
+ if (!entered.startsWith("cb_sk_")) {
1213
+ error(
1214
+ "\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uD0A4 \uD615\uC2DD\uC785\uB2C8\uB2E4. cb_sk_\uB85C \uC2DC\uC791\uD558\uB294 Secret Key\uB97C \uC785\uB825\uD558\uC138\uC694"
1215
+ );
1216
+ process.exit(1);
1217
+ }
1218
+ return entered;
1219
+ }
1220
+ function saveSecretKeyToRc(secretKey, dir = process.cwd()) {
1221
+ const rcPath = path2.join(dir, ".connectbaserc");
1222
+ let rcData = {};
1223
+ if (fs2.existsSync(rcPath)) {
1224
+ try {
1225
+ rcData = JSON.parse(fs2.readFileSync(rcPath, "utf-8"));
1226
+ } catch {
1227
+ }
1228
+ }
1229
+ rcData.secretKey = secretKey;
1230
+ fs2.writeFileSync(rcPath, `${JSON.stringify(rcData, null, 2)}
1231
+ `);
1232
+ }
1233
+ async function fetchAppsWithSecretKey(baseUrl, secretKey) {
1234
+ return makeRequest(`${baseUrl}/v1/public/cli/apps`, "GET", {
1235
+ "X-Public-Key": secretKey
1236
+ });
1237
+ }
1185
1238
  async function init(config = {}, opts = {}) {
1186
1239
  log(`
1187
1240
  ${colors.cyan}Connect Base \uD504\uB85C\uC81D\uD2B8 \uCD08\uAE30\uD654${colors.reset}
1188
1241
  `);
1242
+ const baseUrl = config.baseUrl || DEFAULT_BASE_URL;
1189
1243
  const cwd = process.cwd();
1190
1244
  const projectRoot = getProjectRoot();
1191
1245
  if (cwd !== projectRoot) {
@@ -1199,7 +1253,7 @@ ${colors.cyan}Connect Base \uD504\uB85C\uC81D\uD2B8 \uCD08\uAE30\uD654${colors.r
1199
1253
  if (!process.stdin.isTTY && !nonInteractive) {
1200
1254
  error("\uBE44\uB300\uD654\uD615 \uD658\uACBD\uC785\uB2C8\uB2E4. --yes \uD50C\uB798\uADF8\uC640 \uD568\uAED8 \uD544\uC694\uD55C \uAC12\uC744 \uC9C0\uC815\uD558\uC138\uC694");
1201
1255
  log(
1202
- `${colors.dim}\uC608: npx connectbase init --yes --secret-key cb_sk_... [--app <\uC571ID>] [--storage <\uC2A4\uD1A0\uB9AC\uC9C0ID>] [--deploy-dir ./dist]${colors.reset}`
1256
+ `${colors.dim}\uC608: npx connectbase-client init --yes --secret-key cb_sk_... [--app <\uC571ID>] [--storage <\uC2A4\uD1A0\uB9AC\uC9C0ID>] [--deploy-dir ./dist]${colors.reset}`
1203
1257
  );
1204
1258
  log(
1205
1259
  `${colors.dim}Secret Key\uB294 CONNECTBASE_SECRET_KEY \uD658\uACBD\uBCC0\uC218\uB85C\uB3C4 \uC804\uB2EC\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4${colors.reset}`
@@ -1221,10 +1275,14 @@ ${colors.cyan}Connect Base \uD504\uB85C\uC81D\uD2B8 \uCD08\uAE30\uD654${colors.r
1221
1275
  process.exit(1);
1222
1276
  }
1223
1277
  } else {
1278
+ info(
1279
+ ".connectbaserc\uAC00 \uC774\uBBF8 \uC788\uC2B5\uB2C8\uB2E4 \u2014 \uAE30\uC874 \uC571/\uD0A4 \uC124\uC815\uC744 \uC7AC\uC0AC\uC6A9\uD574 \uB2E4\uC2DC \uAD6C\uC131\uD569\uB2C8\uB2E4"
1280
+ );
1224
1281
  const overwrite = await prompt(
1225
- `${colors.yellow}\u26A0${colors.reset} .connectbaserc\uAC00 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4. \uB36E\uC5B4\uC4F0\uC2DC\uACA0\uC2B5\uB2C8\uAE4C? (y/N): `
1282
+ `${colors.blue}?${colors.reset} \uACC4\uC18D\uD560\uAE4C\uC694? (Y/n): `
1226
1283
  );
1227
- if (overwrite.toLowerCase() !== "y") {
1284
+ const answer = overwrite.toLowerCase();
1285
+ if (answer === "n" || answer === "no") {
1228
1286
  info("\uCD08\uAE30\uD654\uAC00 \uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4");
1229
1287
  return;
1230
1288
  }
@@ -1238,57 +1296,14 @@ ${colors.cyan}Connect Base \uD504\uB85C\uC81D\uD2B8 \uCD08\uAE30\uD654${colors.r
1238
1296
  );
1239
1297
  process.exit(1);
1240
1298
  }
1241
- info("Secret Key \uD655\uC778\uB428 (\uD50C\uB798\uADF8/\uD658\uACBD\uBCC0\uC218/.connectbaserc)");
1299
+ info("\uC800\uC7A5\uB41C Secret Key \uC0AC\uC6A9 (\uD50C\uB798\uADF8/\uD658\uACBD\uBCC0\uC218/.connectbaserc)");
1242
1300
  } else if (nonInteractive) {
1243
1301
  error(
1244
1302
  "Secret Key\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4: --secret-key cb_sk_... \uB610\uB294 CONNECTBASE_SECRET_KEY \uD658\uACBD\uBCC0\uC218"
1245
1303
  );
1246
1304
  process.exit(1);
1247
1305
  } else {
1248
- log(`
1249
- ${colors.dim}\uC778\uC99D \uBC29\uC2DD\uC744 \uC120\uD0DD\uD558\uC138\uC694:${colors.reset}`);
1250
- log(` ${colors.cyan}1${colors.reset}) Secret Key \uC9C1\uC811 \uC785\uB825 (cb_sk_...)`);
1251
- log(` ${colors.cyan}2${colors.reset}) \uBE0C\uB77C\uC6B0\uC800 \uB85C\uADF8\uC778\uC73C\uB85C \uC790\uB3D9 \uBC1C\uAE09
1252
- `);
1253
- const authChoice = await prompt(
1254
- `${colors.blue}?${colors.reset} \uC120\uD0DD (1/2): `
1255
- );
1256
- if (authChoice === "2") {
1257
- try {
1258
- secretKey = await browserAuthFlow();
1259
- } catch (err) {
1260
- error(`\uB124\uD2B8\uC6CC\uD06C \uC624\uB958: ${err instanceof Error ? err.message : err}`);
1261
- info(
1262
- "\uC778\uD130\uB137 \uC5F0\uACB0\uC744 \uD655\uC778\uD558\uAC70\uB098, Secret Key \uC9C1\uC811 \uC785\uB825(\uC635\uC158 1)\uC744 \uC2DC\uB3C4\uD558\uC138\uC694"
1263
- );
1264
- process.exit(1);
1265
- }
1266
- } else {
1267
- log(
1268
- `${colors.dim}Secret Key (cb_sk_): \uCF58\uC194 > \uD504\uB85C\uD544 > \uC2DC\uD06C\uB9BF \uD0A4 \uD0ED\uC5D0\uC11C \uBC1C\uAE09${colors.reset}
1269
- `
1270
- );
1271
- secretKey = await promptSecret(
1272
- `${colors.blue}?${colors.reset} Secret Key: `
1273
- );
1274
- if (!secretKey) {
1275
- error("Secret Key\uB294 \uD544\uC218\uC785\uB2C8\uB2E4");
1276
- process.exit(1);
1277
- }
1278
- if (secretKey.startsWith("cb_pk_")) {
1279
- error("Public Key\uAC00 \uC544\uB2CC Secret Key(cb_sk_)\uB97C \uC785\uB825\uD558\uC138\uC694");
1280
- info(
1281
- "Secret Key\uB294 \uCF58\uC194 > \uD504\uB85C\uD544 > \uC2DC\uD06C\uB9BF \uD0A4 \uD0ED\uC5D0\uC11C \uC0DD\uC131\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4"
1282
- );
1283
- process.exit(1);
1284
- }
1285
- if (!secretKey.startsWith("cb_sk_")) {
1286
- error(
1287
- "\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uD0A4 \uD615\uC2DD\uC785\uB2C8\uB2E4. cb_sk_\uB85C \uC2DC\uC791\uD558\uB294 Secret Key\uB97C \uC785\uB825\uD558\uC138\uC694"
1288
- );
1289
- process.exit(1);
1290
- }
1291
- }
1306
+ secretKey = await promptForSecretKey(baseUrl);
1292
1307
  }
1293
1308
  let appId = "";
1294
1309
  let publicKey = "";
@@ -1304,7 +1319,7 @@ ${colors.dim}\uC778\uC99D \uBC29\uC2DD\uC744 \uC120\uD0DD\uD558\uC138\uC694:${co
1304
1319
  const issuePublicKey = async (targetAppId) => {
1305
1320
  info("Public Key \uC0DD\uC131 \uC911...");
1306
1321
  const newKeyRes = await makeRequest(
1307
- `${DEFAULT_BASE_URL}/v1/public/cli/apps/${targetAppId}/public-keys`,
1322
+ `${baseUrl}/v1/public/cli/apps/${targetAppId}/public-keys`,
1308
1323
  "POST",
1309
1324
  { "X-Public-Key": secretKey },
1310
1325
  JSON.stringify({})
@@ -1319,14 +1334,26 @@ ${colors.dim}\uC778\uC99D \uBC29\uC2DD\uC744 \uC120\uD0DD\uD558\uC138\uC694:${co
1319
1334
  };
1320
1335
  try {
1321
1336
  info("\uC571 \uBAA9\uB85D \uC870\uD68C \uC911...");
1322
- const appsRes = await makeRequest(
1323
- `${DEFAULT_BASE_URL}/v1/public/cli/apps`,
1324
- "GET",
1325
- { "X-Public-Key": secretKey }
1326
- );
1337
+ let appsRes = await fetchAppsWithSecretKey(baseUrl, secretKey);
1327
1338
  if (appsRes.status === 401) {
1328
- error("Secret Key\uAC00 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uCF58\uC194\uC5D0\uC11C \uD0A4\uB97C \uD655\uC778\uD558\uC138\uC694");
1329
- process.exit(1);
1339
+ warn("\uC800\uC7A5\uB41C Secret Key\uAC00 \uB354 \uC774\uC0C1 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 (\uB9CC\uB8CC \uB610\uB294 \uCDE8\uC18C)");
1340
+ if (nonInteractive) {
1341
+ error(
1342
+ "\uC0C8 Secret Key\uB97C --secret-key cb_sk_... \uB610\uB294 CONNECTBASE_SECRET_KEY \uB85C \uC804\uB2EC\uD558\uC138\uC694"
1343
+ );
1344
+ process.exit(1);
1345
+ }
1346
+ info("\uC0C8 Secret Key\uB85C \uB2E4\uC2DC \uC778\uC99D\uD569\uB2C8\uB2E4");
1347
+ secretKey = await promptForSecretKey(baseUrl);
1348
+ appsRes = await fetchAppsWithSecretKey(baseUrl, secretKey);
1349
+ if (appsRes.status === 401) {
1350
+ error(
1351
+ "\uC0C8\uB85C \uBC1B\uC740 Secret Key\uB3C4 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uCF58\uC194 > \uD504\uB85C\uD544 > \uC2DC\uD06C\uB9BF \uD0A4 \uD0ED\uC5D0\uC11C \uD0A4 \uC0C1\uD0DC\uB97C \uD655\uC778\uD558\uC138\uC694"
1352
+ );
1353
+ process.exit(1);
1354
+ }
1355
+ saveSecretKeyToRc(secretKey, cwd);
1356
+ success("\uC0C8 Secret Key\uB97C .connectbaserc\uC5D0 \uC800\uC7A5\uD588\uC2B5\uB2C8\uB2E4");
1330
1357
  }
1331
1358
  if (appsRes.status !== 200) {
1332
1359
  throw new Error(`HTTP ${appsRes.status}`);
@@ -1376,7 +1403,7 @@ ${colors.blue}?${colors.reset} \uC120\uD0DD (\uBC88\uD638): `
1376
1403
  ) || projectName;
1377
1404
  info("\uC571 \uC0DD\uC131 \uC911...");
1378
1405
  const createRes = await makeRequest(
1379
- `${DEFAULT_BASE_URL}/v1/public/cli/apps`,
1406
+ `${baseUrl}/v1/public/cli/apps`,
1380
1407
  "POST",
1381
1408
  { "X-Public-Key": secretKey },
1382
1409
  JSON.stringify({ name: appName })
@@ -1431,7 +1458,7 @@ ${colors.blue}?${colors.reset} \uC120\uD0DD (\uBC88\uD638): `
1431
1458
  try {
1432
1459
  info("\uC6F9 \uC2A4\uD1A0\uB9AC\uC9C0 \uC870\uD68C \uC911...");
1433
1460
  const listRes = await makeRequest(
1434
- `${DEFAULT_BASE_URL}/v1/public/storages/webs`,
1461
+ `${baseUrl}/v1/public/storages/webs`,
1435
1462
  "GET",
1436
1463
  {
1437
1464
  "X-Public-Key": publicKeyForSdk,
@@ -1473,7 +1500,7 @@ ${colors.blue}?${colors.reset} \uC120\uD0DD (\uBC88\uD638): `
1473
1500
  ) || projectName;
1474
1501
  info("\uC6F9 \uC2A4\uD1A0\uB9AC\uC9C0 \uC0DD\uC131 \uC911...");
1475
1502
  const createRes = await makeRequest(
1476
- `${DEFAULT_BASE_URL}/v1/public/storages/webs`,
1503
+ `${baseUrl}/v1/public/storages/webs`,
1477
1504
  "POST",
1478
1505
  {
1479
1506
  "X-Public-Key": publicKeyForSdk,
@@ -1529,12 +1556,17 @@ ${colors.blue}?${colors.reset} \uC120\uD0DD (\uBC88\uD638): `
1529
1556
  `);
1530
1557
  success(".connectbaserc \uC0DD\uC131 \uC644\uB8CC");
1531
1558
  addToGitignore(".connectbaserc");
1532
- addDeployScript(deployDir);
1533
- await setupClaudeCode(secretKey, projectRoot);
1559
+ const { needsInstall } = addDeployScript(deployDir);
1560
+ await setupClaudeCode(secretKey, projectRoot, baseUrl);
1534
1561
  log(`
1535
1562
  ${colors.green}\uCD08\uAE30\uD654 \uC644\uB8CC!${colors.reset}
1536
1563
  `);
1537
1564
  log(`${colors.dim}\uBC30\uD3EC\uD558\uB824\uBA74:${colors.reset}`);
1565
+ if (needsInstall) {
1566
+ log(
1567
+ ` ${colors.cyan}npm install${colors.reset} ${colors.dim}# connectbase-client (CLI \uD3EC\uD568) \uC124\uCE58${colors.reset}`
1568
+ );
1569
+ }
1538
1570
  log(` ${colors.cyan}npm run deploy${colors.reset}`);
1539
1571
  log(`
1540
1572
  ${colors.dim}Claude Code\uC5D0\uC11C MCP\uAC00 \uC790\uB3D9 \uC5F0\uACB0\uB429\uB2C8\uB2E4${colors.reset}
@@ -1589,31 +1621,46 @@ function addDeployScript(deployDir) {
1589
1621
  const pkgPath = path2.join(process.cwd(), "package.json");
1590
1622
  if (!fs2.existsSync(pkgPath)) {
1591
1623
  warn("package.json\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC5B4 deploy \uC2A4\uD06C\uB9BD\uD2B8\uB97C \uCD94\uAC00\uD558\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4");
1592
- return;
1624
+ return { needsInstall: false };
1593
1625
  }
1594
1626
  try {
1595
1627
  const pkg = JSON.parse(fs2.readFileSync(pkgPath, "utf-8"));
1596
1628
  if (!pkg.scripts) pkg.scripts = {};
1629
+ const declared = (name) => Boolean(pkg.dependencies?.[name] || pkg.devDependencies?.[name]);
1630
+ let needsInstall = false;
1631
+ if (!declared("connectbase-client")) {
1632
+ if (!pkg.devDependencies) pkg.devDependencies = {};
1633
+ pkg.devDependencies["connectbase-client"] = VERSION === "0.0.0" ? "latest" : `^${VERSION}`;
1634
+ needsInstall = true;
1635
+ }
1597
1636
  if (pkg.scripts.deploy) {
1598
1637
  info(
1599
1638
  `package.json\uC5D0 \uC774\uBBF8 deploy \uC2A4\uD06C\uB9BD\uD2B8\uAC00 \uC788\uC2B5\uB2C8\uB2E4: "${pkg.scripts.deploy}"`
1600
1639
  );
1601
- return;
1640
+ } else {
1641
+ const deployCmd = `connectbase deploy ${deployDir}`;
1642
+ pkg.scripts.deploy = pkg.scripts.build ? `npm run build && ${deployCmd}` : deployCmd;
1643
+ success("package.json\uC5D0 deploy \uC2A4\uD06C\uB9BD\uD2B8 \uCD94\uAC00 \uC644\uB8CC");
1602
1644
  }
1603
- const deployCmd = `connectbase deploy ${deployDir}`;
1604
- pkg.scripts.deploy = pkg.scripts.build ? `${pkg.scripts.build} && ${deployCmd}` : deployCmd;
1605
1645
  fs2.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}
1606
1646
  `);
1607
- success(`package.json\uC5D0 deploy \uC2A4\uD06C\uB9BD\uD2B8 \uCD94\uAC00 \uC644\uB8CC`);
1647
+ if (needsInstall) {
1648
+ success(
1649
+ `package.json devDependencies\uC5D0 connectbase-client@${pkg.devDependencies["connectbase-client"]} \uCD94\uAC00 \uC644\uB8CC`
1650
+ );
1651
+ }
1652
+ return { needsInstall };
1608
1653
  } catch {
1609
1654
  warn("package.json \uC218\uC815\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4");
1655
+ return { needsInstall: false };
1610
1656
  }
1611
1657
  }
1612
1658
  function getGitRoot() {
1613
1659
  try {
1614
1660
  const { execSync } = require("child_process");
1615
1661
  return execSync("git rev-parse --show-toplevel", {
1616
- encoding: "utf-8"
1662
+ encoding: "utf-8",
1663
+ stdio: ["ignore", "pipe", "ignore"]
1617
1664
  }).trim();
1618
1665
  } catch {
1619
1666
  return null;
@@ -1715,6 +1762,7 @@ var LEGACY_DOC_FILES = [
1715
1762
  ];
1716
1763
  async function downloadDocs(baseDir, opts = {}) {
1717
1764
  const quiet = opts.quiet === true;
1765
+ const baseUrl = opts.baseUrl || DEFAULT_BASE_URL;
1718
1766
  if (!baseDir) {
1719
1767
  baseDir = getProjectRoot();
1720
1768
  }
@@ -1736,7 +1784,7 @@ async function downloadDocs(baseDir, opts = {}) {
1736
1784
  if (!quiet) info("SDK \uAC1C\uBC1C \uAC00\uC774\uB4DC \uB2E4\uC6B4\uB85C\uB4DC \uC911...");
1737
1785
  try {
1738
1786
  const res = await makeRequest(
1739
- `${DEFAULT_BASE_URL}/v1/storages/webs/claude-md?template=rules&format=sections`,
1787
+ `${baseUrl}/v1/storages/webs/claude-md?template=rules&format=sections`,
1740
1788
  "GET",
1741
1789
  {}
1742
1790
  );
@@ -1769,7 +1817,7 @@ async function downloadDocs(baseDir, opts = {}) {
1769
1817
  }
1770
1818
  return "unchanged";
1771
1819
  }
1772
- const stamp = `<!-- generated by connectbase-cli v${VERSION} (${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}) \u2014 \uC790\uB3D9 \uC0DD\uC131 \uD30C\uC77C\uC785\uB2C8\uB2E4. \uC9C1\uC811 \uC218\uC815\uD558\uC9C0 \uB9D0\uACE0 'npx connectbase update'\uB85C \uAC31\uC2E0\uD558\uC138\uC694 -->
1820
+ const stamp = `<!-- generated by connectbase-cli v${VERSION} (${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}) \u2014 \uC790\uB3D9 \uC0DD\uC131 \uD30C\uC77C\uC785\uB2C8\uB2E4. \uC9C1\uC811 \uC218\uC815\uD558\uC9C0 \uB9D0\uACE0 'npx connectbase-client update'\uB85C \uAC31\uC2E0\uD558\uC138\uC694 -->
1773
1821
 
1774
1822
  `;
1775
1823
  for (const section of sections) {
@@ -1849,7 +1897,7 @@ function updateRootClaudeMd(claudeMdPath, quiet = false) {
1849
1897
 
1850
1898
  1. \uC704\uC5D0 import\uB41C project-rules.md\uC758 \uAE30\uB2A5 \uB9E4\uD551\uD45C\xB7\uBCF4\uC548 \uADDC\uCE59\uC744 \uB530\uB974\uC138\uC694
1851
1899
  2. \uCF54\uB4DC\uB97C \uC791\uC131\uD558\uAE30 \uC804 \`search_sdk_docs("\uD0A4\uC6CC\uB4DC")\`\uB85C SDK \uAD6C\uD604 \uBC29\uBC95\uC744 \uAC80\uC0C9\uD558\uACE0, \uAC80\uC0C9 \uACB0\uACFC\uC758 \uCF54\uB4DC \uD328\uD134\uC744 \uADF8\uB300\uB85C \uB530\uB974\uC138\uC694
1852
- 3. \`search_sdk_docs\` \uB3C4\uAD6C\uAC00 \uBCF4\uC774\uC9C0 \uC54A\uC73C\uBA74 MCP\uAC00 \uC5F0\uACB0\uB418\uC9C0 \uC54A\uC740 \uC0C1\uD0DC\uC785\uB2C8\uB2E4 \u2014 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \`npx connectbase mcp\` \uC2E4\uD589\uC744 \uC548\uB0B4\uD558\uC138\uC694 (Secret Key \uD544\uC694)
1900
+ 3. \`search_sdk_docs\` \uB3C4\uAD6C\uAC00 \uBCF4\uC774\uC9C0 \uC54A\uC73C\uBA74 MCP\uAC00 \uC5F0\uACB0\uB418\uC9C0 \uC54A\uC740 \uC0C1\uD0DC\uC785\uB2C8\uB2E4 \u2014 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \`npx connectbase-client mcp\` \uC2E4\uD589\uC744 \uC548\uB0B4\uD558\uC138\uC694 (Secret Key \uD544\uC694)
1853
1901
  ${endMarker}`;
1854
1902
  if (fs2.existsSync(claudeMdPath)) {
1855
1903
  let content = fs2.readFileSync(claudeMdPath, "utf-8");
@@ -1885,7 +1933,7 @@ function createSubPackageClaudeMd(subClaudeMdPath, gitRoot, quiet = false) {
1885
1933
 
1886
1934
  1. \uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8\uC758 \`${relPath}/.claude/docs/project-rules.md\`\uC758 \uAE30\uB2A5 \uB9E4\uD551\uD45C\xB7\uBCF4\uC548 \uADDC\uCE59\uC744 \uB530\uB974\uC138\uC694
1887
1935
  2. \uCF54\uB4DC\uB97C \uC791\uC131\uD558\uAE30 \uC804 \`search_sdk_docs("\uD0A4\uC6CC\uB4DC")\`\uB85C SDK \uAD6C\uD604 \uBC29\uBC95\uC744 \uAC80\uC0C9\uD558\uC138\uC694
1888
- 3. \`search_sdk_docs\` \uB3C4\uAD6C\uAC00 \uBCF4\uC774\uC9C0 \uC54A\uC73C\uBA74 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \`npx connectbase mcp\` \uC2E4\uD589\uC744 \uC548\uB0B4\uD558\uC138\uC694
1936
+ 3. \`search_sdk_docs\` \uB3C4\uAD6C\uAC00 \uBCF4\uC774\uC9C0 \uC54A\uC73C\uBA74 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \`npx connectbase-client mcp\` \uC2E4\uD589\uC744 \uC548\uB0B4\uD558\uC138\uC694
1889
1937
  ${endMarker}`;
1890
1938
  if (fs2.existsSync(subClaudeMdPath)) {
1891
1939
  let content = fs2.readFileSync(subClaudeMdPath, "utf-8");
@@ -1913,7 +1961,7 @@ ${subBlock}
1913
1961
  }
1914
1962
  if (!quiet) success(`\uC11C\uBE0C \uD328\uD0A4\uC9C0 CLAUDE.md \uC0DD\uC131 \uC644\uB8CC: ${subClaudeMdPath}`);
1915
1963
  }
1916
- async function setupMcp(secretKey) {
1964
+ async function setupMcp(secretKey, baseUrl = DEFAULT_BASE_URL) {
1917
1965
  const gitRoot = getGitRoot();
1918
1966
  const root = gitRoot || process.cwd();
1919
1967
  const monorepo = detectMonorepo(root);
@@ -1924,51 +1972,31 @@ async function setupMcp(secretKey) {
1924
1972
  }
1925
1973
  }
1926
1974
  const mcpConfigPath = path2.join(root, ".mcp.json");
1975
+ if (secretKey) {
1976
+ const check = await fetchAppsWithSecretKey(baseUrl, secretKey).catch(
1977
+ () => null
1978
+ );
1979
+ if (check?.status === 401) {
1980
+ warn("\uC800\uC7A5\uB41C Secret Key\uAC00 \uB354 \uC774\uC0C1 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 (\uB9CC\uB8CC \uB610\uB294 \uCDE8\uC18C)");
1981
+ secretKey = "";
1982
+ }
1983
+ }
1927
1984
  if (!secretKey) {
1928
1985
  if (!process.stdin.isTTY) {
1929
- error("Secret Key\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4 (\uBE44\uB300\uD654\uD615 \uD658\uACBD)");
1986
+ error("\uC720\uD6A8\uD55C Secret Key\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4 (\uBE44\uB300\uD654\uD615 \uD658\uACBD)");
1930
1987
  log(`${colors.dim}\uB2E4\uC74C \uC911 \uD558\uB098\uB85C \uD0A4\uB97C \uC804\uB2EC\uD558\uC138\uC694:${colors.reset}`);
1931
1988
  log(
1932
- ` ${colors.cyan}npx connectbase mcp --secret-key cb_sk_...${colors.reset}`
1989
+ ` ${colors.cyan}npx connectbase-client mcp --secret-key cb_sk_...${colors.reset}`
1933
1990
  );
1934
1991
  log(
1935
- ` ${colors.cyan}CONNECTBASE_SECRET_KEY=cb_sk_... npx connectbase mcp${colors.reset}`
1992
+ ` ${colors.cyan}CONNECTBASE_SECRET_KEY=cb_sk_... npx connectbase-client mcp${colors.reset}`
1936
1993
  );
1937
1994
  process.exit(1);
1938
1995
  }
1939
- log(`
1940
- ${colors.dim}\uC778\uC99D \uBC29\uC2DD\uC744 \uC120\uD0DD\uD558\uC138\uC694:${colors.reset}`);
1941
- log(` ${colors.cyan}1${colors.reset}) Secret Key \uC9C1\uC811 \uC785\uB825 (cb_sk_...)`);
1942
- log(` ${colors.cyan}2${colors.reset}) \uBE0C\uB77C\uC6B0\uC800 \uB85C\uADF8\uC778\uC73C\uB85C \uC790\uB3D9 \uBC1C\uAE09
1943
- `);
1944
- const authChoice = await prompt(
1945
- `${colors.blue}?${colors.reset} \uC120\uD0DD (1/2): `
1946
- );
1947
- if (authChoice === "2") {
1948
- try {
1949
- secretKey = await browserAuthFlow();
1950
- const skRcPath = path2.join(process.cwd(), ".connectbaserc");
1951
- let rcData = {};
1952
- if (fs2.existsSync(skRcPath)) {
1953
- try {
1954
- rcData = JSON.parse(fs2.readFileSync(skRcPath, "utf-8"));
1955
- } catch {
1956
- }
1957
- }
1958
- rcData.secretKey = secretKey;
1959
- fs2.writeFileSync(skRcPath, `${JSON.stringify(rcData, null, 2)}
1960
- `);
1961
- addToGitignore(".connectbaserc", root);
1962
- success("Secret Key \uBC1C\uAE09 \uBC0F \uC800\uC7A5 \uC644\uB8CC");
1963
- } catch (err) {
1964
- error(`\uC778\uC99D \uC2E4\uD328: ${err instanceof Error ? err.message : err}`);
1965
- process.exit(1);
1966
- }
1967
- } else {
1968
- secretKey = await promptSecret(
1969
- `${colors.blue}?${colors.reset} Secret Key: `
1970
- );
1971
- }
1996
+ secretKey = await promptForSecretKey(baseUrl);
1997
+ saveSecretKeyToRc(secretKey);
1998
+ addToGitignore(".connectbaserc", root);
1999
+ success("Secret Key\uB97C .connectbaserc\uC5D0 \uC800\uC7A5\uD588\uC2B5\uB2C8\uB2E4");
1972
2000
  }
1973
2001
  const mcpEntry = {
1974
2002
  type: "http",
@@ -2007,10 +2035,10 @@ ${colors.dim}\uC778\uC99D \uBC29\uC2DD\uC744 \uC120\uD0DD\uD558\uC138\uC694:${co
2007
2035
  ${colors.dim}Claude Code\uC5D0\uC11C ConnectBase MCP \uB3C4\uAD6C\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.${colors.reset}`
2008
2036
  );
2009
2037
  }
2010
- async function setupClaudeCode(secretKey, projectRoot) {
2038
+ async function setupClaudeCode(secretKey, projectRoot, baseUrl = DEFAULT_BASE_URL) {
2011
2039
  const root = projectRoot || getProjectRoot();
2012
- await downloadDocs(root);
2013
- await setupMcp(secretKey);
2040
+ await downloadDocs(root, { baseUrl });
2041
+ await setupMcp(secretKey, baseUrl);
2014
2042
  }
2015
2043
  async function fetchLatestVersion(packageName) {
2016
2044
  try {
@@ -2118,7 +2146,7 @@ ${colors.cyan}ConnectBase Update${colors.reset}
2118
2146
  if (!opts.skipDocs) {
2119
2147
  log("");
2120
2148
  info("SDK \uBB38\uC11C \uC5C5\uB370\uC774\uD2B8 \uC911...");
2121
- await downloadDocs(projectRoot);
2149
+ await downloadDocs(projectRoot, { baseUrl: config.baseUrl });
2122
2150
  }
2123
2151
  if (!opts.skipMcp) {
2124
2152
  log("");
@@ -2203,15 +2231,15 @@ function setupMonorepoRoot(projectRoot, monorepo) {
2203
2231
  if (!pkg.scripts) pkg.scripts = {};
2204
2232
  let changed = false;
2205
2233
  if (!pkg.scripts["cb:update"]) {
2206
- pkg.scripts["cb:update"] = "npx connectbase update";
2234
+ pkg.scripts["cb:update"] = "npx connectbase-client update";
2207
2235
  changed = true;
2208
2236
  }
2209
2237
  if (!pkg.scripts["cb:docs"]) {
2210
- pkg.scripts["cb:docs"] = "npx connectbase docs";
2238
+ pkg.scripts["cb:docs"] = "npx connectbase-client docs";
2211
2239
  changed = true;
2212
2240
  }
2213
2241
  if (!pkg.scripts["cb:mcp"]) {
2214
- pkg.scripts["cb:mcp"] = "npx connectbase mcp";
2242
+ pkg.scripts["cb:mcp"] = "npx connectbase-client mcp";
2215
2243
  changed = true;
2216
2244
  }
2217
2245
  if (changed) {
@@ -3403,7 +3431,7 @@ function showHelp() {
3403
3431
  ${colors.cyan}connectbase${colors.reset} - Connect Base SDK & CLI
3404
3432
 
3405
3433
  ${colors.yellow}\uC0AC\uC6A9\uBC95:${colors.reset}
3406
- npx connectbase <command> [options]
3434
+ npx connectbase-client <command> [options]
3407
3435
 
3408
3436
  ${colors.yellow}\uBA85\uB839\uC5B4:${colors.reset}
3409
3437
  init \uD504\uB85C\uC81D\uD2B8 \uCD08\uAE30\uD654 (\uC571 \uC0DD\uC131, MCP \uC124\uC815, SDK \uBB38\uC11C \uB2E4\uC6B4\uB85C\uB4DC)
@@ -3451,36 +3479,36 @@ ${colors.yellow}\uC635\uC158:${colors.reset}
3451
3479
 
3452
3480
  ${colors.yellow}\uBE60\uB978 \uC2DC\uC791:${colors.reset}
3453
3481
  ${colors.dim}# 1. \uCD08\uAE30\uD654 (\uCD5C\uCD08 1\uD68C)${colors.reset}
3454
- npx connectbase init
3482
+ npx connectbase-client init
3455
3483
 
3456
3484
  ${colors.dim}# 1-1. \uBE44\uB300\uD654\uD615 \uCD08\uAE30\uD654 (CI/AI \uC5D0\uC774\uC804\uD2B8)${colors.reset}
3457
- npx connectbase init --yes --secret-key cb_sk_...
3485
+ npx connectbase-client init --yes --secret-key cb_sk_...
3458
3486
 
3459
3487
  ${colors.dim}# 2. SDK \uC804\uCCB4 \uC5C5\uB370\uC774\uD2B8 (\uBC84\uC804 \uCCB4\uD06C + \uBB38\uC11C + MCP)${colors.reset}
3460
- npx connectbase update
3488
+ npx connectbase-client update
3461
3489
 
3462
3490
  ${colors.dim}# 2-1. \uBAA8\uB178\uB808\uD3EC \uB8E8\uD2B8\uC5D0 \uD3B8\uC758 \uC2A4\uD06C\uB9BD\uD2B8 \uC124\uCE58${colors.reset}
3463
- npx connectbase update --setup-root
3491
+ npx connectbase-client update --setup-root
3464
3492
 
3465
3493
  ${colors.dim}# 3. SDK \uBB38\uC11C\uB9CC \uC5C5\uB370\uC774\uD2B8${colors.reset}
3466
- npx connectbase docs
3494
+ npx connectbase-client docs
3467
3495
 
3468
3496
  ${colors.dim}# 4. MCP \uC11C\uBC84 \uC124\uC815${colors.reset}
3469
- npx connectbase mcp
3497
+ npx connectbase-client mcp
3470
3498
 
3471
3499
  ${colors.dim}# 4. Prod \uBC30\uD3EC${colors.reset}
3472
3500
  npm run deploy
3473
3501
 
3474
3502
  ${colors.dim}# 4-1. QA \uC6CC\uD06C\uD50C\uB85C\uC6B0 (\uC2E0\uADDC \uC2A4\uD1A0\uB9AC\uC9C0 \uAE30\uBCF8 promote_mode=manual)${colors.reset}
3475
- npx connectbase deploy ./dist ${colors.dim}# QA \uD658\uACBD\uC5D0\uB9CC \uBC30\uD3EC${colors.reset}
3476
- npx connectbase releases ${colors.dim}# \uBC30\uD3EC \uC774\uB825 \uD655\uC778${colors.reset}
3477
- npx connectbase promote ${colors.dim}# QA \uAC80\uC99D \uD6C4 production \uBC18\uC601${colors.reset}
3503
+ npx connectbase-client deploy ./dist ${colors.dim}# QA \uD658\uACBD\uC5D0\uB9CC \uBC30\uD3EC${colors.reset}
3504
+ npx connectbase-client releases ${colors.dim}# \uBC30\uD3EC \uC774\uB825 \uD655\uC778${colors.reset}
3505
+ npx connectbase-client promote ${colors.dim}# QA \uAC80\uC99D \uD6C4 production \uBC18\uC601${colors.reset}
3478
3506
 
3479
3507
  ${colors.dim}# 5. \uD130\uB110 (\uAE30\uBCF8)${colors.reset}
3480
- npx connectbase tunnel 3000
3508
+ npx connectbase-client tunnel 3000
3481
3509
 
3482
3510
  ${colors.dim}# 6. \uD130\uB110 (GPU \uC11C\uBC84 \uB4F1 \uAE34 \uC751\uB2F5 \uC2DC)${colors.reset}
3483
- npx connectbase tunnel 7860 --timeout 300 --max-body 50
3511
+ npx connectbase-client tunnel 7860 --timeout 300 --max-body 50
3484
3512
 
3485
3513
  ${colors.yellow}\uD658\uACBD\uBCC0\uC218:${colors.reset}
3486
3514
  CONNECTBASE_PUBLIC_KEY Public Key (cb_pk_*)
@@ -3594,20 +3622,20 @@ async function main() {
3594
3622
  setupRoot: parsed.options.setupRoot === "true"
3595
3623
  });
3596
3624
  } else if (parsed.command === "docs") {
3597
- await downloadDocs();
3625
+ await downloadDocs(void 0, { baseUrl: config.baseUrl });
3598
3626
  } else if (parsed.command === "mcp") {
3599
- await setupMcp(config.secretKey);
3627
+ await setupMcp(config.secretKey, config.baseUrl);
3600
3628
  } else if (parsed.command === "deploy") {
3601
3629
  const directory = parsed.args[0] || fileConfig.deployDir || ".";
3602
3630
  if (!config.publicKey) {
3603
3631
  error(
3604
- 'Public Key\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. "npx connectbase init"\uC73C\uB85C \uC124\uC815\uD558\uAC70\uB098 -k \uC635\uC158\uC744 \uC0AC\uC6A9\uD558\uC138\uC694'
3632
+ 'Public Key\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. "npx connectbase-client init"\uC73C\uB85C \uC124\uC815\uD558\uAC70\uB098 -k \uC635\uC158\uC744 \uC0AC\uC6A9\uD558\uC138\uC694'
3605
3633
  );
3606
3634
  process.exit(1);
3607
3635
  }
3608
3636
  if (!config.storageId) {
3609
3637
  error(
3610
- '\uC2A4\uD1A0\uB9AC\uC9C0 ID\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. "npx connectbase init"\uC73C\uB85C \uC124\uC815\uD558\uAC70\uB098 -s \uC635\uC158\uC744 \uC0AC\uC6A9\uD558\uC138\uC694'
3638
+ '\uC2A4\uD1A0\uB9AC\uC9C0 ID\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. "npx connectbase-client init"\uC73C\uB85C \uC124\uC815\uD558\uAC70\uB098 -s \uC635\uC158\uC744 \uC0AC\uC6A9\uD558\uC138\uC694'
3611
3639
  );
3612
3640
  process.exit(1);
3613
3641
  }
@@ -3628,7 +3656,10 @@ async function main() {
3628
3656
  if (fs2.existsSync(
3629
3657
  path2.join(docsRoot, ".claude", "docs", DOCS_MANIFEST_FILE)
3630
3658
  )) {
3631
- const refreshed = await downloadDocs(docsRoot, { quiet: true });
3659
+ const refreshed = await downloadDocs(docsRoot, {
3660
+ quiet: true,
3661
+ baseUrl: config.baseUrl
3662
+ });
3632
3663
  if (refreshed === "updated") {
3633
3664
  info("SDK \uBB38\uC11C\uAC00 \uC0C8 \uBC84\uC804\uC73C\uB85C \uAC31\uC2E0\uB418\uC5C8\uC2B5\uB2C8\uB2E4 (.claude/docs/)");
3634
3665
  }
@@ -3639,13 +3670,13 @@ async function main() {
3639
3670
  } else if (parsed.command === "promote" || parsed.command === "releases") {
3640
3671
  if (!config.publicKey) {
3641
3672
  error(
3642
- 'Public Key\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. "npx connectbase init"\uC73C\uB85C \uC124\uC815\uD558\uAC70\uB098 -k \uC635\uC158\uC744 \uC0AC\uC6A9\uD558\uC138\uC694'
3673
+ 'Public Key\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. "npx connectbase-client init"\uC73C\uB85C \uC124\uC815\uD558\uAC70\uB098 -k \uC635\uC158\uC744 \uC0AC\uC6A9\uD558\uC138\uC694'
3643
3674
  );
3644
3675
  process.exit(1);
3645
3676
  }
3646
3677
  if (!config.storageId) {
3647
3678
  error(
3648
- '\uC2A4\uD1A0\uB9AC\uC9C0 ID\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. "npx connectbase init"\uC73C\uB85C \uC124\uC815\uD558\uAC70\uB098 -s \uC635\uC158\uC744 \uC0AC\uC6A9\uD558\uC138\uC694'
3679
+ '\uC2A4\uD1A0\uB9AC\uC9C0 ID\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. "npx connectbase-client init"\uC73C\uB85C \uC124\uC815\uD558\uAC70\uB098 -s \uC635\uC158\uC744 \uC0AC\uC6A9\uD558\uC138\uC694'
3649
3680
  );
3650
3681
  process.exit(1);
3651
3682
  }
@@ -3657,7 +3688,7 @@ async function main() {
3657
3688
  } else if (parsed.command === "tunnel") {
3658
3689
  const portStr = parsed.args[0];
3659
3690
  if (!portStr) {
3660
- error("\uD3EC\uD2B8 \uBC88\uD638\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. \uC608: npx connectbase tunnel 8084");
3691
+ error("\uD3EC\uD2B8 \uBC88\uD638\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4. \uC608: npx connectbase-client tunnel 8084");
3661
3692
  process.exit(1);
3662
3693
  }
3663
3694
  const port = parseInt(portStr, 10);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "connectbase-client",
3
- "version": "6.2.0",
3
+ "version": "6.3.0",
4
4
  "description": "Connect Base JavaScript/TypeScript SDK for browser and Node.js",
5
5
  "repository": {
6
6
  "type": "git",