connectbase-client 6.0.1 → 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.
package/dist/cli.js CHANGED
@@ -41,7 +41,8 @@ __export(cli_exports, {
41
41
  normalizeRelativePath: () => normalizeRelativePath,
42
42
  parseArgs: () => parseArgs,
43
43
  registerEndpointBinding: () => registerEndpointBinding,
44
- sha256Hex: () => sha256Hex
44
+ sha256Hex: () => sha256Hex,
45
+ storageAdminHeaders: () => storageAdminHeaders
45
46
  });
46
47
  module.exports = __toCommonJS(cli_exports);
47
48
  var crypto = __toESM(require("crypto"));
@@ -146,18 +147,7 @@ function handleTunnelError(msg, appId, localPort) {
146
147
  }
147
148
 
148
149
  // src/cli.ts
149
- function getPackageVersion() {
150
- try {
151
- const pkgPath = path2.join(__dirname, "..", "package.json");
152
- if (fs2.existsSync(pkgPath)) {
153
- const pkg = JSON.parse(fs2.readFileSync(pkgPath, "utf-8"));
154
- return pkg.version || "0.0.0";
155
- }
156
- } catch {
157
- }
158
- return "3.25.1";
159
- }
160
- var VERSION = getPackageVersion();
150
+ var VERSION = "6.3.0" ? "6.3.0" : getPackageVersion();
161
151
  var DEFAULT_BASE_URL = "https://api.connectbase.world";
162
152
  var colors = {
163
153
  reset: "\x1B[0m",
@@ -295,6 +285,41 @@ function normalizeRelativePath(relativePath) {
295
285
  if (!p.startsWith("/")) p = `/${p}`;
296
286
  return p;
297
287
  }
288
+ function storageAdminHeaders(config) {
289
+ const headers = {
290
+ "X-Public-Key": config.publicKey
291
+ };
292
+ if (config.secretKey) {
293
+ headers["X-User-Secret-Key"] = config.secretKey;
294
+ headers.Authorization = `Bearer ${config.secretKey}`;
295
+ return headers;
296
+ }
297
+ warn("Secret Key(cb_sk_)\uAC00 \uC124\uC815\uB3FC \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.");
298
+ log(
299
+ " Public Key \uB294 \uBE0C\uB77C\uC6B0\uC800 \uBC88\uB4E4\uC5D0 \uACF5\uAC1C\uB418\uB294 \uAC12\uC774\uB77C \uBC30\uD3EC/\uC2B9\uACA9\uC758 \uC790\uACA9\uC99D\uBA85\uC774 \uB420 \uC218 \uC5C6\uC5B4,"
300
+ );
301
+ log(" \uACE7 \uC11C\uBC84\uAC00 Secret Key \uB97C \uC694\uAD6C\uD569\uB2C8\uB2E4. \uC9C0\uAE08 \uC124\uC815\uD574 \uB450\uC138\uC694.");
302
+ log(
303
+ ` ${colors.cyan}npx connectbase-client init${colors.reset} \uC774 \uBC1C\uAE09\uD574 .connectbaserc \uC5D0 \uC800\uC7A5\uD569\uB2C8\uB2E4.`
304
+ );
305
+ log(
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.`
307
+ );
308
+ log(" CI \uC5D0\uC11C\uB294 \uC800\uC7A5\uC18C \uC2DC\uD06C\uB9BF\uC5D0 \uB123\uC73C\uC138\uC694 \u2014 \uC800\uC7A5\uC18C\uC5D0 \uCEE4\uBC0B\uD558\uBA74 \uC548 \uB429\uB2C8\uB2E4.");
309
+ return headers;
310
+ }
311
+ function reportDeployAuthError(status, data) {
312
+ if (status !== 401) return false;
313
+ const detail = data?.error;
314
+ if (detail?.code !== "SECRET_KEY_REQUIRED") return false;
315
+ error(detail.message || "\uC774 \uC694\uCCAD\uC5D0\uB294 Secret Key \uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.");
316
+ if (detail.suggestion) {
317
+ log("");
318
+ log(` ${detail.suggestion}`);
319
+ }
320
+ log("");
321
+ return true;
322
+ }
298
323
  function loadConfig() {
299
324
  const config = {
300
325
  publicKey: process.env.CONNECTBASE_PUBLIC_KEY,
@@ -631,10 +656,10 @@ async function deploy(directory, config, isDev = false, deployOpts = {}) {
631
656
  const pkg = JSON.parse(fs2.readFileSync(pkgPath, "utf-8"));
632
657
  if (pkg.scripts?.build) {
633
658
  warn(
634
- `\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}`
635
660
  );
636
661
  warn(
637
- `\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}`
638
663
  );
639
664
  }
640
665
  } catch {
@@ -666,11 +691,11 @@ async function deploy(directory, config, isDev = false, deployOpts = {}) {
666
691
  const envLabel = isDev ? "QA" : "Prod";
667
692
  if (isDev) {
668
693
  warn(
669
- `${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.`
670
695
  );
671
696
  }
672
697
  const baseStorageUrl = `${config.baseUrl}/v1/public/storages/webs/${config.storageId}`;
673
- const headers = { "X-Public-Key": config.publicKey };
698
+ const headers = storageAdminHeaders(config);
674
699
  const timeoutMs = computeDeployTimeout(totalSize, deployOpts.timeoutMs);
675
700
  log(
676
701
  `${colors.dim}\uD0C0\uC784\uC544\uC6C3: ${Math.round(timeoutMs / 1e3)}\uCD08${colors.reset}`
@@ -882,7 +907,7 @@ ${colors.cyan}Production: ${dep.production_url}${colors.reset}`
882
907
  log(`
883
908
  ${colors.yellow}QA URL: ${dep.qa_url}${colors.reset}`);
884
909
  log(
885
- `${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}
886
911
  `
887
912
  );
888
913
  }
@@ -897,13 +922,15 @@ ${colors.cyan}URL: ${data.url}${colors.reset}
897
922
  } else {
898
923
  const data = response.data;
899
924
  const errorMsg = typeof data === "object" && data !== null ? data.message || data.error || JSON.stringify(data) : typeof data === "string" ? data : `HTTP ${response.status}`;
900
- error(`\uBC30\uD3EC \uC2E4\uD328: ${errorMsg}`);
925
+ if (!reportDeployAuthError(response.status, response.data)) {
926
+ error(`\uBC30\uD3EC \uC2E4\uD328: ${errorMsg}`);
927
+ }
901
928
  process.exit(1);
902
929
  }
903
930
  }
904
931
  async function promote(config, deploymentId) {
905
932
  const baseStorageUrl = `${config.baseUrl}/v1/public/storages/webs/${config.storageId}`;
906
- const headers = { "X-Public-Key": config.publicKey };
933
+ const headers = storageAdminHeaders(config);
907
934
  info(
908
935
  deploymentId ? `release ${deploymentId} \uB97C production \uC73C\uB85C \uC2B9\uACA9\uD569\uB2C8\uB2E4...` : "\uCD5C\uC2E0 \uBC30\uD3EC\uB97C production \uC73C\uB85C \uC2B9\uACA9\uD569\uB2C8\uB2E4..."
909
936
  );
@@ -925,7 +952,9 @@ async function promote(config, deploymentId) {
925
952
  if (res.status < 200 || res.status >= 300) {
926
953
  const data2 = res.data;
927
954
  const msg = typeof data2 === "object" && data2 !== null ? data2.error || data2.message || JSON.stringify(data2) : `HTTP ${res.status}`;
928
- error(`promote \uC2E4\uD328: ${msg}`);
955
+ if (!reportDeployAuthError(res.status, res.data)) {
956
+ error(`promote \uC2E4\uD328: ${msg}`);
957
+ }
929
958
  process.exit(1);
930
959
  }
931
960
  const data = res.data;
@@ -938,7 +967,7 @@ ${colors.cyan}Production: ${data.production_url}${colors.reset}
938
967
  }
939
968
  async function listReleases(config) {
940
969
  const baseStorageUrl = `${config.baseUrl}/v1/public/storages/webs/${config.storageId}`;
941
- const headers = { "X-Public-Key": config.publicKey };
970
+ const headers = storageAdminHeaders(config);
942
971
  const res = await makeRequest(
943
972
  `${baseStorageUrl}/deployments`,
944
973
  "GET",
@@ -947,7 +976,9 @@ async function listReleases(config) {
947
976
  if (res.status < 200 || res.status >= 300) {
948
977
  const data2 = res.data;
949
978
  const msg = typeof data2 === "object" && data2 !== null ? data2.error || data2.message || JSON.stringify(data2) : `HTTP ${res.status}`;
950
- error(`\uBC30\uD3EC \uC774\uB825 \uC870\uD68C \uC2E4\uD328: ${msg}`);
979
+ if (!reportDeployAuthError(res.status, res.data)) {
980
+ error(`\uBC30\uD3EC \uC774\uB825 \uC870\uD68C \uC2E4\uD328: ${msg}`);
981
+ }
951
982
  process.exit(1);
952
983
  }
953
984
  const data = res.data;
@@ -977,7 +1008,7 @@ ${colors.cyan}\uBC30\uD3EC \uC774\uB825${colors.reset} (promote_mode: ${data.pro
977
1008
  if (data.qa_url)
978
1009
  log(`${colors.yellow}QA: ${data.qa_url}${colors.reset}`);
979
1010
  log(
980
- `${colors.dim}\uB864\uBC31: npx connectbase promote <deployment_id>${colors.reset}
1011
+ `${colors.dim}\uB864\uBC31: npx connectbase-client promote <deployment_id>${colors.reset}
981
1012
  `
982
1013
  );
983
1014
  }
@@ -1044,7 +1075,9 @@ function getProjectRoot() {
1044
1075
  const gitRoot = getGitRoot();
1045
1076
  return gitRoot || process.cwd();
1046
1077
  }
1047
- var CONSOLE_URL = DEFAULT_BASE_URL.replace("api.", "");
1078
+ function consoleUrlFor(baseUrl) {
1079
+ return baseUrl.replace("api.", "");
1080
+ }
1048
1081
  function openBrowser(url) {
1049
1082
  const { exec } = require("child_process");
1050
1083
  const platform2 = process.platform;
@@ -1059,10 +1092,10 @@ function openBrowser(url) {
1059
1092
  exec(command, () => {
1060
1093
  });
1061
1094
  }
1062
- async function browserAuthFlow() {
1095
+ async function browserAuthFlow(baseUrl = DEFAULT_BASE_URL) {
1063
1096
  info("\uBE0C\uB77C\uC6B0\uC800 \uC778\uC99D \uC138\uC158\uC744 \uC2DC\uC791\uD569\uB2C8\uB2E4...");
1064
1097
  const startRes = await makeRequest(
1065
- `${DEFAULT_BASE_URL}/v1/public/cli-auth/start`,
1098
+ `${baseUrl}/v1/public/cli-auth/start`,
1066
1099
  "POST",
1067
1100
  {}
1068
1101
  );
@@ -1073,7 +1106,7 @@ async function browserAuthFlow() {
1073
1106
  process.exit(1);
1074
1107
  }
1075
1108
  const { session_id } = startRes.data;
1076
- const authUrl = `${CONSOLE_URL}/auth/cli-auth?session=${session_id}`;
1109
+ const authUrl = `${consoleUrlFor(baseUrl)}/auth/cli-auth?session=${session_id}`;
1077
1110
  log(`
1078
1111
  ${colors.cyan}\uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uB85C\uADF8\uC778\uD558\uC138\uC694:${colors.reset}`);
1079
1112
  log(`${colors.dim}${authUrl}${colors.reset}
@@ -1093,7 +1126,7 @@ ${colors.cyan}\uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uB85C\uADF8\uC778\uD558\uC13
1093
1126
  await new Promise((resolve2) => setTimeout(resolve2, pollInterval));
1094
1127
  try {
1095
1128
  const pollRes = await makeRequest(
1096
- `${DEFAULT_BASE_URL}/v1/public/cli-auth/poll/${session_id}`,
1129
+ `${baseUrl}/v1/public/cli-auth/poll/${session_id}`,
1097
1130
  "GET",
1098
1131
  {}
1099
1132
  );
@@ -1140,10 +1173,73 @@ ${colors.cyan}\uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uB85C\uADF8\uC778\uD558\uC13
1140
1173
  error("\uC778\uC99D \uC2DC\uAC04\uC774 \uCD08\uACFC\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694.");
1141
1174
  process.exit(1);
1142
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
+ }
1143
1238
  async function init(config = {}, opts = {}) {
1144
1239
  log(`
1145
1240
  ${colors.cyan}Connect Base \uD504\uB85C\uC81D\uD2B8 \uCD08\uAE30\uD654${colors.reset}
1146
1241
  `);
1242
+ const baseUrl = config.baseUrl || DEFAULT_BASE_URL;
1147
1243
  const cwd = process.cwd();
1148
1244
  const projectRoot = getProjectRoot();
1149
1245
  if (cwd !== projectRoot) {
@@ -1157,7 +1253,7 @@ ${colors.cyan}Connect Base \uD504\uB85C\uC81D\uD2B8 \uCD08\uAE30\uD654${colors.r
1157
1253
  if (!process.stdin.isTTY && !nonInteractive) {
1158
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");
1159
1255
  log(
1160
- `${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}`
1161
1257
  );
1162
1258
  log(
1163
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}`
@@ -1179,10 +1275,14 @@ ${colors.cyan}Connect Base \uD504\uB85C\uC81D\uD2B8 \uCD08\uAE30\uD654${colors.r
1179
1275
  process.exit(1);
1180
1276
  }
1181
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
+ );
1182
1281
  const overwrite = await prompt(
1183
- `${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): `
1184
1283
  );
1185
- if (overwrite.toLowerCase() !== "y") {
1284
+ const answer = overwrite.toLowerCase();
1285
+ if (answer === "n" || answer === "no") {
1186
1286
  info("\uCD08\uAE30\uD654\uAC00 \uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4");
1187
1287
  return;
1188
1288
  }
@@ -1196,57 +1296,14 @@ ${colors.cyan}Connect Base \uD504\uB85C\uC81D\uD2B8 \uCD08\uAE30\uD654${colors.r
1196
1296
  );
1197
1297
  process.exit(1);
1198
1298
  }
1199
- 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)");
1200
1300
  } else if (nonInteractive) {
1201
1301
  error(
1202
1302
  "Secret Key\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4: --secret-key cb_sk_... \uB610\uB294 CONNECTBASE_SECRET_KEY \uD658\uACBD\uBCC0\uC218"
1203
1303
  );
1204
1304
  process.exit(1);
1205
1305
  } else {
1206
- log(`
1207
- ${colors.dim}\uC778\uC99D \uBC29\uC2DD\uC744 \uC120\uD0DD\uD558\uC138\uC694:${colors.reset}`);
1208
- log(` ${colors.cyan}1${colors.reset}) Secret Key \uC9C1\uC811 \uC785\uB825 (cb_sk_...)`);
1209
- log(` ${colors.cyan}2${colors.reset}) \uBE0C\uB77C\uC6B0\uC800 \uB85C\uADF8\uC778\uC73C\uB85C \uC790\uB3D9 \uBC1C\uAE09
1210
- `);
1211
- const authChoice = await prompt(
1212
- `${colors.blue}?${colors.reset} \uC120\uD0DD (1/2): `
1213
- );
1214
- if (authChoice === "2") {
1215
- try {
1216
- secretKey = await browserAuthFlow();
1217
- } catch (err) {
1218
- error(`\uB124\uD2B8\uC6CC\uD06C \uC624\uB958: ${err instanceof Error ? err.message : err}`);
1219
- info(
1220
- "\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"
1221
- );
1222
- process.exit(1);
1223
- }
1224
- } else {
1225
- log(
1226
- `${colors.dim}Secret Key (cb_sk_): \uCF58\uC194 > \uD504\uB85C\uD544 > \uC2DC\uD06C\uB9BF \uD0A4 \uD0ED\uC5D0\uC11C \uBC1C\uAE09${colors.reset}
1227
- `
1228
- );
1229
- secretKey = await promptSecret(
1230
- `${colors.blue}?${colors.reset} Secret Key: `
1231
- );
1232
- if (!secretKey) {
1233
- error("Secret Key\uB294 \uD544\uC218\uC785\uB2C8\uB2E4");
1234
- process.exit(1);
1235
- }
1236
- if (secretKey.startsWith("cb_pk_")) {
1237
- error("Public Key\uAC00 \uC544\uB2CC Secret Key(cb_sk_)\uB97C \uC785\uB825\uD558\uC138\uC694");
1238
- info(
1239
- "Secret Key\uB294 \uCF58\uC194 > \uD504\uB85C\uD544 > \uC2DC\uD06C\uB9BF \uD0A4 \uD0ED\uC5D0\uC11C \uC0DD\uC131\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4"
1240
- );
1241
- process.exit(1);
1242
- }
1243
- if (!secretKey.startsWith("cb_sk_")) {
1244
- error(
1245
- "\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"
1246
- );
1247
- process.exit(1);
1248
- }
1249
- }
1306
+ secretKey = await promptForSecretKey(baseUrl);
1250
1307
  }
1251
1308
  let appId = "";
1252
1309
  let publicKey = "";
@@ -1262,7 +1319,7 @@ ${colors.dim}\uC778\uC99D \uBC29\uC2DD\uC744 \uC120\uD0DD\uD558\uC138\uC694:${co
1262
1319
  const issuePublicKey = async (targetAppId) => {
1263
1320
  info("Public Key \uC0DD\uC131 \uC911...");
1264
1321
  const newKeyRes = await makeRequest(
1265
- `${DEFAULT_BASE_URL}/v1/public/cli/apps/${targetAppId}/public-keys`,
1322
+ `${baseUrl}/v1/public/cli/apps/${targetAppId}/public-keys`,
1266
1323
  "POST",
1267
1324
  { "X-Public-Key": secretKey },
1268
1325
  JSON.stringify({})
@@ -1277,14 +1334,26 @@ ${colors.dim}\uC778\uC99D \uBC29\uC2DD\uC744 \uC120\uD0DD\uD558\uC138\uC694:${co
1277
1334
  };
1278
1335
  try {
1279
1336
  info("\uC571 \uBAA9\uB85D \uC870\uD68C \uC911...");
1280
- const appsRes = await makeRequest(
1281
- `${DEFAULT_BASE_URL}/v1/public/cli/apps`,
1282
- "GET",
1283
- { "X-Public-Key": secretKey }
1284
- );
1337
+ let appsRes = await fetchAppsWithSecretKey(baseUrl, secretKey);
1285
1338
  if (appsRes.status === 401) {
1286
- error("Secret Key\uAC00 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uCF58\uC194\uC5D0\uC11C \uD0A4\uB97C \uD655\uC778\uD558\uC138\uC694");
1287
- 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");
1288
1357
  }
1289
1358
  if (appsRes.status !== 200) {
1290
1359
  throw new Error(`HTTP ${appsRes.status}`);
@@ -1334,7 +1403,7 @@ ${colors.blue}?${colors.reset} \uC120\uD0DD (\uBC88\uD638): `
1334
1403
  ) || projectName;
1335
1404
  info("\uC571 \uC0DD\uC131 \uC911...");
1336
1405
  const createRes = await makeRequest(
1337
- `${DEFAULT_BASE_URL}/v1/public/cli/apps`,
1406
+ `${baseUrl}/v1/public/cli/apps`,
1338
1407
  "POST",
1339
1408
  { "X-Public-Key": secretKey },
1340
1409
  JSON.stringify({ name: appName })
@@ -1389,9 +1458,13 @@ ${colors.blue}?${colors.reset} \uC120\uD0DD (\uBC88\uD638): `
1389
1458
  try {
1390
1459
  info("\uC6F9 \uC2A4\uD1A0\uB9AC\uC9C0 \uC870\uD68C \uC911...");
1391
1460
  const listRes = await makeRequest(
1392
- `${DEFAULT_BASE_URL}/v1/public/storages/webs`,
1461
+ `${baseUrl}/v1/public/storages/webs`,
1393
1462
  "GET",
1394
- { "X-Public-Key": publicKeyForSdk }
1463
+ {
1464
+ "X-Public-Key": publicKeyForSdk,
1465
+ "X-User-Secret-Key": secretKey,
1466
+ Authorization: `Bearer ${secretKey}`
1467
+ }
1395
1468
  );
1396
1469
  if (listRes.status === 200) {
1397
1470
  const listData = listRes.data;
@@ -1427,9 +1500,13 @@ ${colors.blue}?${colors.reset} \uC120\uD0DD (\uBC88\uD638): `
1427
1500
  ) || projectName;
1428
1501
  info("\uC6F9 \uC2A4\uD1A0\uB9AC\uC9C0 \uC0DD\uC131 \uC911...");
1429
1502
  const createRes = await makeRequest(
1430
- `${DEFAULT_BASE_URL}/v1/public/storages/webs`,
1503
+ `${baseUrl}/v1/public/storages/webs`,
1431
1504
  "POST",
1432
- { "X-Public-Key": publicKeyForSdk },
1505
+ {
1506
+ "X-Public-Key": publicKeyForSdk,
1507
+ "X-User-Secret-Key": secretKey,
1508
+ Authorization: `Bearer ${secretKey}`
1509
+ },
1433
1510
  JSON.stringify({ name })
1434
1511
  );
1435
1512
  if (createRes.status !== 200) {
@@ -1479,12 +1556,17 @@ ${colors.blue}?${colors.reset} \uC120\uD0DD (\uBC88\uD638): `
1479
1556
  `);
1480
1557
  success(".connectbaserc \uC0DD\uC131 \uC644\uB8CC");
1481
1558
  addToGitignore(".connectbaserc");
1482
- addDeployScript(deployDir);
1483
- await setupClaudeCode(secretKey, projectRoot);
1559
+ const { needsInstall } = addDeployScript(deployDir);
1560
+ await setupClaudeCode(secretKey, projectRoot, baseUrl);
1484
1561
  log(`
1485
1562
  ${colors.green}\uCD08\uAE30\uD654 \uC644\uB8CC!${colors.reset}
1486
1563
  `);
1487
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
+ }
1488
1570
  log(` ${colors.cyan}npm run deploy${colors.reset}`);
1489
1571
  log(`
1490
1572
  ${colors.dim}Claude Code\uC5D0\uC11C MCP\uAC00 \uC790\uB3D9 \uC5F0\uACB0\uB429\uB2C8\uB2E4${colors.reset}
@@ -1539,31 +1621,46 @@ function addDeployScript(deployDir) {
1539
1621
  const pkgPath = path2.join(process.cwd(), "package.json");
1540
1622
  if (!fs2.existsSync(pkgPath)) {
1541
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");
1542
- return;
1624
+ return { needsInstall: false };
1543
1625
  }
1544
1626
  try {
1545
1627
  const pkg = JSON.parse(fs2.readFileSync(pkgPath, "utf-8"));
1546
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
+ }
1547
1636
  if (pkg.scripts.deploy) {
1548
1637
  info(
1549
1638
  `package.json\uC5D0 \uC774\uBBF8 deploy \uC2A4\uD06C\uB9BD\uD2B8\uAC00 \uC788\uC2B5\uB2C8\uB2E4: "${pkg.scripts.deploy}"`
1550
1639
  );
1551
- 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");
1552
1644
  }
1553
- const deployCmd = `connectbase deploy ${deployDir}`;
1554
- pkg.scripts.deploy = pkg.scripts.build ? `${pkg.scripts.build} && ${deployCmd}` : deployCmd;
1555
1645
  fs2.writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}
1556
1646
  `);
1557
- 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 };
1558
1653
  } catch {
1559
1654
  warn("package.json \uC218\uC815\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4");
1655
+ return { needsInstall: false };
1560
1656
  }
1561
1657
  }
1562
1658
  function getGitRoot() {
1563
1659
  try {
1564
1660
  const { execSync } = require("child_process");
1565
1661
  return execSync("git rev-parse --show-toplevel", {
1566
- encoding: "utf-8"
1662
+ encoding: "utf-8",
1663
+ stdio: ["ignore", "pipe", "ignore"]
1567
1664
  }).trim();
1568
1665
  } catch {
1569
1666
  return null;
@@ -1665,6 +1762,7 @@ var LEGACY_DOC_FILES = [
1665
1762
  ];
1666
1763
  async function downloadDocs(baseDir, opts = {}) {
1667
1764
  const quiet = opts.quiet === true;
1765
+ const baseUrl = opts.baseUrl || DEFAULT_BASE_URL;
1668
1766
  if (!baseDir) {
1669
1767
  baseDir = getProjectRoot();
1670
1768
  }
@@ -1686,7 +1784,7 @@ async function downloadDocs(baseDir, opts = {}) {
1686
1784
  if (!quiet) info("SDK \uAC1C\uBC1C \uAC00\uC774\uB4DC \uB2E4\uC6B4\uB85C\uB4DC \uC911...");
1687
1785
  try {
1688
1786
  const res = await makeRequest(
1689
- `${DEFAULT_BASE_URL}/v1/storages/webs/claude-md?template=rules&format=sections`,
1787
+ `${baseUrl}/v1/storages/webs/claude-md?template=rules&format=sections`,
1690
1788
  "GET",
1691
1789
  {}
1692
1790
  );
@@ -1719,7 +1817,7 @@ async function downloadDocs(baseDir, opts = {}) {
1719
1817
  }
1720
1818
  return "unchanged";
1721
1819
  }
1722
- 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 -->
1723
1821
 
1724
1822
  `;
1725
1823
  for (const section of sections) {
@@ -1799,7 +1897,7 @@ function updateRootClaudeMd(claudeMdPath, quiet = false) {
1799
1897
 
1800
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
1801
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
1802
- 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)
1803
1901
  ${endMarker}`;
1804
1902
  if (fs2.existsSync(claudeMdPath)) {
1805
1903
  let content = fs2.readFileSync(claudeMdPath, "utf-8");
@@ -1835,7 +1933,7 @@ function createSubPackageClaudeMd(subClaudeMdPath, gitRoot, quiet = false) {
1835
1933
 
1836
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
1837
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
1838
- 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
1839
1937
  ${endMarker}`;
1840
1938
  if (fs2.existsSync(subClaudeMdPath)) {
1841
1939
  let content = fs2.readFileSync(subClaudeMdPath, "utf-8");
@@ -1863,7 +1961,7 @@ ${subBlock}
1863
1961
  }
1864
1962
  if (!quiet) success(`\uC11C\uBE0C \uD328\uD0A4\uC9C0 CLAUDE.md \uC0DD\uC131 \uC644\uB8CC: ${subClaudeMdPath}`);
1865
1963
  }
1866
- async function setupMcp(secretKey) {
1964
+ async function setupMcp(secretKey, baseUrl = DEFAULT_BASE_URL) {
1867
1965
  const gitRoot = getGitRoot();
1868
1966
  const root = gitRoot || process.cwd();
1869
1967
  const monorepo = detectMonorepo(root);
@@ -1874,51 +1972,31 @@ async function setupMcp(secretKey) {
1874
1972
  }
1875
1973
  }
1876
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
+ }
1877
1984
  if (!secretKey) {
1878
1985
  if (!process.stdin.isTTY) {
1879
- 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)");
1880
1987
  log(`${colors.dim}\uB2E4\uC74C \uC911 \uD558\uB098\uB85C \uD0A4\uB97C \uC804\uB2EC\uD558\uC138\uC694:${colors.reset}`);
1881
1988
  log(
1882
- ` ${colors.cyan}npx connectbase mcp --secret-key cb_sk_...${colors.reset}`
1989
+ ` ${colors.cyan}npx connectbase-client mcp --secret-key cb_sk_...${colors.reset}`
1883
1990
  );
1884
1991
  log(
1885
- ` ${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}`
1886
1993
  );
1887
1994
  process.exit(1);
1888
1995
  }
1889
- log(`
1890
- ${colors.dim}\uC778\uC99D \uBC29\uC2DD\uC744 \uC120\uD0DD\uD558\uC138\uC694:${colors.reset}`);
1891
- log(` ${colors.cyan}1${colors.reset}) Secret Key \uC9C1\uC811 \uC785\uB825 (cb_sk_...)`);
1892
- log(` ${colors.cyan}2${colors.reset}) \uBE0C\uB77C\uC6B0\uC800 \uB85C\uADF8\uC778\uC73C\uB85C \uC790\uB3D9 \uBC1C\uAE09
1893
- `);
1894
- const authChoice = await prompt(
1895
- `${colors.blue}?${colors.reset} \uC120\uD0DD (1/2): `
1896
- );
1897
- if (authChoice === "2") {
1898
- try {
1899
- secretKey = await browserAuthFlow();
1900
- const skRcPath = path2.join(process.cwd(), ".connectbaserc");
1901
- let rcData = {};
1902
- if (fs2.existsSync(skRcPath)) {
1903
- try {
1904
- rcData = JSON.parse(fs2.readFileSync(skRcPath, "utf-8"));
1905
- } catch {
1906
- }
1907
- }
1908
- rcData.secretKey = secretKey;
1909
- fs2.writeFileSync(skRcPath, `${JSON.stringify(rcData, null, 2)}
1910
- `);
1911
- addToGitignore(".connectbaserc", root);
1912
- success("Secret Key \uBC1C\uAE09 \uBC0F \uC800\uC7A5 \uC644\uB8CC");
1913
- } catch (err) {
1914
- error(`\uC778\uC99D \uC2E4\uD328: ${err instanceof Error ? err.message : err}`);
1915
- process.exit(1);
1916
- }
1917
- } else {
1918
- secretKey = await promptSecret(
1919
- `${colors.blue}?${colors.reset} Secret Key: `
1920
- );
1921
- }
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");
1922
2000
  }
1923
2001
  const mcpEntry = {
1924
2002
  type: "http",
@@ -1957,10 +2035,10 @@ ${colors.dim}\uC778\uC99D \uBC29\uC2DD\uC744 \uC120\uD0DD\uD558\uC138\uC694:${co
1957
2035
  ${colors.dim}Claude Code\uC5D0\uC11C ConnectBase MCP \uB3C4\uAD6C\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.${colors.reset}`
1958
2036
  );
1959
2037
  }
1960
- async function setupClaudeCode(secretKey, projectRoot) {
2038
+ async function setupClaudeCode(secretKey, projectRoot, baseUrl = DEFAULT_BASE_URL) {
1961
2039
  const root = projectRoot || getProjectRoot();
1962
- await downloadDocs(root);
1963
- await setupMcp(secretKey);
2040
+ await downloadDocs(root, { baseUrl });
2041
+ await setupMcp(secretKey, baseUrl);
1964
2042
  }
1965
2043
  async function fetchLatestVersion(packageName) {
1966
2044
  try {
@@ -2068,7 +2146,7 @@ ${colors.cyan}ConnectBase Update${colors.reset}
2068
2146
  if (!opts.skipDocs) {
2069
2147
  log("");
2070
2148
  info("SDK \uBB38\uC11C \uC5C5\uB370\uC774\uD2B8 \uC911...");
2071
- await downloadDocs(projectRoot);
2149
+ await downloadDocs(projectRoot, { baseUrl: config.baseUrl });
2072
2150
  }
2073
2151
  if (!opts.skipMcp) {
2074
2152
  log("");
@@ -2153,15 +2231,15 @@ function setupMonorepoRoot(projectRoot, monorepo) {
2153
2231
  if (!pkg.scripts) pkg.scripts = {};
2154
2232
  let changed = false;
2155
2233
  if (!pkg.scripts["cb:update"]) {
2156
- pkg.scripts["cb:update"] = "npx connectbase update";
2234
+ pkg.scripts["cb:update"] = "npx connectbase-client update";
2157
2235
  changed = true;
2158
2236
  }
2159
2237
  if (!pkg.scripts["cb:docs"]) {
2160
- pkg.scripts["cb:docs"] = "npx connectbase docs";
2238
+ pkg.scripts["cb:docs"] = "npx connectbase-client docs";
2161
2239
  changed = true;
2162
2240
  }
2163
2241
  if (!pkg.scripts["cb:mcp"]) {
2164
- pkg.scripts["cb:mcp"] = "npx connectbase mcp";
2242
+ pkg.scripts["cb:mcp"] = "npx connectbase-client mcp";
2165
2243
  changed = true;
2166
2244
  }
2167
2245
  if (changed) {
@@ -3353,7 +3431,7 @@ function showHelp() {
3353
3431
  ${colors.cyan}connectbase${colors.reset} - Connect Base SDK & CLI
3354
3432
 
3355
3433
  ${colors.yellow}\uC0AC\uC6A9\uBC95:${colors.reset}
3356
- npx connectbase <command> [options]
3434
+ npx connectbase-client <command> [options]
3357
3435
 
3358
3436
  ${colors.yellow}\uBA85\uB839\uC5B4:${colors.reset}
3359
3437
  init \uD504\uB85C\uC81D\uD2B8 \uCD08\uAE30\uD654 (\uC571 \uC0DD\uC131, MCP \uC124\uC815, SDK \uBB38\uC11C \uB2E4\uC6B4\uB85C\uB4DC)
@@ -3401,40 +3479,40 @@ ${colors.yellow}\uC635\uC158:${colors.reset}
3401
3479
 
3402
3480
  ${colors.yellow}\uBE60\uB978 \uC2DC\uC791:${colors.reset}
3403
3481
  ${colors.dim}# 1. \uCD08\uAE30\uD654 (\uCD5C\uCD08 1\uD68C)${colors.reset}
3404
- npx connectbase init
3482
+ npx connectbase-client init
3405
3483
 
3406
3484
  ${colors.dim}# 1-1. \uBE44\uB300\uD654\uD615 \uCD08\uAE30\uD654 (CI/AI \uC5D0\uC774\uC804\uD2B8)${colors.reset}
3407
- npx connectbase init --yes --secret-key cb_sk_...
3485
+ npx connectbase-client init --yes --secret-key cb_sk_...
3408
3486
 
3409
3487
  ${colors.dim}# 2. SDK \uC804\uCCB4 \uC5C5\uB370\uC774\uD2B8 (\uBC84\uC804 \uCCB4\uD06C + \uBB38\uC11C + MCP)${colors.reset}
3410
- npx connectbase update
3488
+ npx connectbase-client update
3411
3489
 
3412
3490
  ${colors.dim}# 2-1. \uBAA8\uB178\uB808\uD3EC \uB8E8\uD2B8\uC5D0 \uD3B8\uC758 \uC2A4\uD06C\uB9BD\uD2B8 \uC124\uCE58${colors.reset}
3413
- npx connectbase update --setup-root
3491
+ npx connectbase-client update --setup-root
3414
3492
 
3415
3493
  ${colors.dim}# 3. SDK \uBB38\uC11C\uB9CC \uC5C5\uB370\uC774\uD2B8${colors.reset}
3416
- npx connectbase docs
3494
+ npx connectbase-client docs
3417
3495
 
3418
3496
  ${colors.dim}# 4. MCP \uC11C\uBC84 \uC124\uC815${colors.reset}
3419
- npx connectbase mcp
3497
+ npx connectbase-client mcp
3420
3498
 
3421
3499
  ${colors.dim}# 4. Prod \uBC30\uD3EC${colors.reset}
3422
3500
  npm run deploy
3423
3501
 
3424
3502
  ${colors.dim}# 4-1. QA \uC6CC\uD06C\uD50C\uB85C\uC6B0 (\uC2E0\uADDC \uC2A4\uD1A0\uB9AC\uC9C0 \uAE30\uBCF8 promote_mode=manual)${colors.reset}
3425
- npx connectbase deploy ./dist ${colors.dim}# QA \uD658\uACBD\uC5D0\uB9CC \uBC30\uD3EC${colors.reset}
3426
- npx connectbase releases ${colors.dim}# \uBC30\uD3EC \uC774\uB825 \uD655\uC778${colors.reset}
3427
- 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}
3428
3506
 
3429
3507
  ${colors.dim}# 5. \uD130\uB110 (\uAE30\uBCF8)${colors.reset}
3430
- npx connectbase tunnel 3000
3508
+ npx connectbase-client tunnel 3000
3431
3509
 
3432
3510
  ${colors.dim}# 6. \uD130\uB110 (GPU \uC11C\uBC84 \uB4F1 \uAE34 \uC751\uB2F5 \uC2DC)${colors.reset}
3433
- npx connectbase tunnel 7860 --timeout 300 --max-body 50
3511
+ npx connectbase-client tunnel 7860 --timeout 300 --max-body 50
3434
3512
 
3435
3513
  ${colors.yellow}\uD658\uACBD\uBCC0\uC218:${colors.reset}
3436
3514
  CONNECTBASE_PUBLIC_KEY Public Key (cb_pk_*)
3437
- CONNECTBASE_SECRET_KEY Secret Key (cb_sk_*, \uD130\uB110\uC6A9)
3515
+ CONNECTBASE_SECRET_KEY Secret Key (cb_sk_*) \u2014 \uBC30\uD3EC/\uC2B9\uACA9/\uD130\uB110\uC5D0 \uD544\uC218
3438
3516
  CONNECTBASE_PUBLIC_KEY (deprecated) \uB808\uAC70\uC2DC \u2014 publicKey \uB610\uB294 secretKey \uB85C \uC0AC\uC6A9
3439
3517
  CONNECTBASE_STORAGE_ID \uC2A4\uD1A0\uB9AC\uC9C0 ID
3440
3518
  CONNECTBASE_BASE_URL \uC11C\uBC84 URL
@@ -3544,20 +3622,20 @@ async function main() {
3544
3622
  setupRoot: parsed.options.setupRoot === "true"
3545
3623
  });
3546
3624
  } else if (parsed.command === "docs") {
3547
- await downloadDocs();
3625
+ await downloadDocs(void 0, { baseUrl: config.baseUrl });
3548
3626
  } else if (parsed.command === "mcp") {
3549
- await setupMcp(config.secretKey);
3627
+ await setupMcp(config.secretKey, config.baseUrl);
3550
3628
  } else if (parsed.command === "deploy") {
3551
3629
  const directory = parsed.args[0] || fileConfig.deployDir || ".";
3552
3630
  if (!config.publicKey) {
3553
3631
  error(
3554
- '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'
3555
3633
  );
3556
3634
  process.exit(1);
3557
3635
  }
3558
3636
  if (!config.storageId) {
3559
3637
  error(
3560
- '\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'
3561
3639
  );
3562
3640
  process.exit(1);
3563
3641
  }
@@ -3578,7 +3656,10 @@ async function main() {
3578
3656
  if (fs2.existsSync(
3579
3657
  path2.join(docsRoot, ".claude", "docs", DOCS_MANIFEST_FILE)
3580
3658
  )) {
3581
- const refreshed = await downloadDocs(docsRoot, { quiet: true });
3659
+ const refreshed = await downloadDocs(docsRoot, {
3660
+ quiet: true,
3661
+ baseUrl: config.baseUrl
3662
+ });
3582
3663
  if (refreshed === "updated") {
3583
3664
  info("SDK \uBB38\uC11C\uAC00 \uC0C8 \uBC84\uC804\uC73C\uB85C \uAC31\uC2E0\uB418\uC5C8\uC2B5\uB2C8\uB2E4 (.claude/docs/)");
3584
3665
  }
@@ -3589,13 +3670,13 @@ async function main() {
3589
3670
  } else if (parsed.command === "promote" || parsed.command === "releases") {
3590
3671
  if (!config.publicKey) {
3591
3672
  error(
3592
- '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'
3593
3674
  );
3594
3675
  process.exit(1);
3595
3676
  }
3596
3677
  if (!config.storageId) {
3597
3678
  error(
3598
- '\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'
3599
3680
  );
3600
3681
  process.exit(1);
3601
3682
  }
@@ -3607,7 +3688,7 @@ async function main() {
3607
3688
  } else if (parsed.command === "tunnel") {
3608
3689
  const portStr = parsed.args[0];
3609
3690
  if (!portStr) {
3610
- 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");
3611
3692
  process.exit(1);
3612
3693
  }
3613
3694
  const port = parseInt(portStr, 10);
@@ -3672,5 +3753,6 @@ main().catch((err) => {
3672
3753
  normalizeRelativePath,
3673
3754
  parseArgs,
3674
3755
  registerEndpointBinding,
3675
- sha256Hex
3756
+ sha256Hex,
3757
+ storageAdminHeaders
3676
3758
  });