connectbase-client 3.42.0 → 3.44.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/CHANGELOG.md +44 -0
- package/dist/cli.js +415 -176
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,50 @@
|
|
|
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
|
+
## [3.44.0] - 2026-07-03
|
|
7
|
+
|
|
8
|
+
### Added — CLI 비대화형 init + SDK 문서 수명주기 정비
|
|
9
|
+
|
|
10
|
+
AI 에이전트(Claude Code 등)가 `init` 을 직접 실행할 수 있도록 비대화형 모드를 추가하고,
|
|
11
|
+
`.claude/docs/` 문서의 신선도/정리 체계를 도입했다.
|
|
12
|
+
|
|
13
|
+
- **비대화형 init**: `connectbase init --yes --secret-key cb_sk_...` — 프롬프트 없이 진행.
|
|
14
|
+
비TTY 환경에서 `--yes` 없이 실행하면 hang 대신 필요한 플래그를 안내하고 즉시 종료.
|
|
15
|
+
`--app <앱ID>`/`--storage <스토리지ID>`/`--deploy-dir <dir>` 로 명시 지정, `--yes` 는
|
|
16
|
+
프로젝트 이름과 같은 앱/스토리지가 있으면 재사용(반복 실행에 멱등). Secret Key 는
|
|
17
|
+
`CONNECTBASE_SECRET_KEY` 환경변수로도 전달 가능.
|
|
18
|
+
- **Public Key 스프롤 방지**: `.connectbaserc` 에 `appId` 를 저장하고, 같은 앱을 다시 init
|
|
19
|
+
하면 기존 Public Key 를 재사용 (이전에는 실행마다 새 키 발급).
|
|
20
|
+
- **문서 생성 스탬프 + 매니페스트**: `.claude/docs/` 파일에 생성 CLI 버전/날짜 스탬프를 넣고
|
|
21
|
+
`.connectbase-manifest.json` 으로 추적 — 콘텐츠 해시로 신선도 비교, 서버에서 사라진 문서
|
|
22
|
+
자동 정리(레거시 fullstack 파일 포함), `deploy` 성공 후 변경이 있을 때만 조용히 자동 갱신
|
|
23
|
+
(`--skip-docs` 로 생략 가능).
|
|
24
|
+
- **CLAUDE.md @import**: 참조 블록이 `@.claude/docs/project-rules.md` import 로 규칙을 매
|
|
25
|
+
세션 자동 로드. MCP 미연결 시 `npx connectbase mcp` 안내 지시 포함. `mcp` 명령도 비대화형
|
|
26
|
+
지원(`--secret-key`/env/.connectbaserc 자동 사용).
|
|
27
|
+
|
|
28
|
+
### Changed / Security
|
|
29
|
+
|
|
30
|
+
- **키를 쿼리스트링에 싣지 않음**: 문서 다운로드가 `public_key` 쿼리 파라미터를 더 이상
|
|
31
|
+
전송하지 않는다 (서버 측 키 치환은 플레이스홀더 불일치로 오래전부터 무동작 — 액세스 로그에
|
|
32
|
+
키가 남는 위험만 있었음). `update` 의 secretKey fallback 도 제거.
|
|
33
|
+
- 모든 CLI 요청에 `User-Agent: connectbase-cli/<version>` 명시.
|
|
34
|
+
- `detectBuildDir`: Next.js 는 `output: 'export'` 미설정 시 경고 안내.
|
|
35
|
+
- 버전 비교가 prerelease(`-beta.1`) 형식에서 NaN 이 되던 문제 수정.
|
|
36
|
+
- `.gitignore` 항목 추가가 부분 문자열 오탐으로 건너뛰던 문제 수정 (라인 단위 정확 매칭).
|
|
37
|
+
|
|
38
|
+
## [3.43.0] - 2026-07-02
|
|
39
|
+
|
|
40
|
+
### Added — `--dev` 배포도 대용량 바이너리 지원
|
|
41
|
+
|
|
42
|
+
dev 배포(`connectbase deploy --dev`)는 DB 를 거치지 않고 파일을 dev Object Storage 경로에 직접
|
|
43
|
+
올리므로 6 MiB(TiDB 엔트리) 한도가 애초에 없다. 3.41.0~3.42.0 은 dev 에서도 fail-fast 로 대용량을
|
|
44
|
+
막았는데(과도한 제한), 이를 풀고 prod 와 동일하게 처리한다.
|
|
45
|
+
|
|
46
|
+
- 대용량 **바이너리**는 presign(`dev:true`)으로 dev 서빙 경로(`{id}/dev{path}`)에 직접 업로드하고 바디에서 제외(효율).
|
|
47
|
+
- 대응 core-server 가 없으면(구버전) 오프로드 없이 전량 base64 바디로 전송 — dev 는 DB 한도가 없어 안전.
|
|
48
|
+
- dev 는 이제 대용량 파일에 대해 fail-fast 하지 않는다.
|
|
49
|
+
|
|
6
50
|
## [3.42.0] - 2026-07-02
|
|
7
51
|
|
|
8
52
|
### Added — 웹 배포 대용량 바이너리 Object Storage 직접 업로드 (플랫폼 이슈 019f221b)
|
package/dist/cli.js
CHANGED
|
@@ -349,8 +349,8 @@ function validateFileSizes(files) {
|
|
|
349
349
|
warn("\uC62C\uB9AC\uACE0 URL \uB85C \uCC38\uC870\uD558\uC138\uC694. \uD30C\uC77C \uC2A4\uD1A0\uB9AC\uC9C0\uB294 \uD30C\uC77C\uB2F9 \uACE0\uC815 \uC0C1\uD55C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
350
350
|
process.exit(1);
|
|
351
351
|
}
|
|
352
|
-
async function requestDeployPresign(baseStorageUrl, headers, files, timeoutMs) {
|
|
353
|
-
const body = JSON.stringify({ files });
|
|
352
|
+
async function requestDeployPresign(baseStorageUrl, headers, files, timeoutMs, dev = false) {
|
|
353
|
+
const body = JSON.stringify(dev ? { files, dev: true } : { files });
|
|
354
354
|
const res = await makeRequest(`${baseStorageUrl}/deploy/presign`, "POST", headers, body, { timeoutMs });
|
|
355
355
|
if (res.status === 404) return null;
|
|
356
356
|
if (res.status < 200 || res.status >= 300) {
|
|
@@ -466,6 +466,50 @@ async function offloadLargeBinaries(baseStorageUrl, headers, diff, _envLabel, ti
|
|
|
466
466
|
f.content = "";
|
|
467
467
|
}
|
|
468
468
|
}
|
|
469
|
+
async function offloadDevLargeBinaries(baseStorageUrl, headers, files, timeoutMs) {
|
|
470
|
+
const large = files.filter((f) => f.isBinary && Buffer.byteLength(f.content, "utf8") > WEB_FILE_MAX_STORED_BYTES);
|
|
471
|
+
if (large.length === 0) return files;
|
|
472
|
+
const presignFiles = large.map((f) => ({
|
|
473
|
+
path: f.path,
|
|
474
|
+
size: Buffer.from(f.content, "base64").length,
|
|
475
|
+
mime_type: guessMimeType(f.path)
|
|
476
|
+
}));
|
|
477
|
+
let presigned;
|
|
478
|
+
try {
|
|
479
|
+
presigned = await requestDeployPresign(baseStorageUrl, headers, presignFiles, timeoutMs, true);
|
|
480
|
+
} catch (err) {
|
|
481
|
+
error(`dev \uB300\uC6A9\uB7C9 \uD30C\uC77C \uC5C5\uB85C\uB4DC \uC900\uBE44 \uC2E4\uD328: ${err instanceof Error ? err.message : err}`);
|
|
482
|
+
process.exit(1);
|
|
483
|
+
}
|
|
484
|
+
if (presigned === null) {
|
|
485
|
+
info("\uC11C\uBC84\uAC00 \uB300\uC6A9\uB7C9 \uC9C1\uC811 \uC5C5\uB85C\uB4DC\uB97C \uBBF8\uC9C0\uC6D0 \u2014 dev \uB294 \uC804\uB7C9 \uC5C5\uB85C\uB4DC\uB85C \uC9C4\uD589\uD569\uB2C8\uB2E4.");
|
|
486
|
+
return files;
|
|
487
|
+
}
|
|
488
|
+
if (!presigned.every((p) => p.object_key.includes("/dev/"))) {
|
|
489
|
+
info("\uC11C\uBC84\uAC00 dev \uC9C1\uC811 \uC5C5\uB85C\uB4DC\uB97C \uBBF8\uC9C0\uC6D0(\uC751\uB2F5 \uD0A4\uAC00 dev \uACBD\uB85C \uC544\uB2D8) \u2014 dev \uB294 \uC804\uB7C9 \uC5C5\uB85C\uB4DC\uB85C \uC9C4\uD589\uD569\uB2C8\uB2E4.");
|
|
490
|
+
return files;
|
|
491
|
+
}
|
|
492
|
+
const urlByPath = new Map(presigned.map((p) => [p.path, p.upload_url]));
|
|
493
|
+
info(`\uB300\uC6A9\uB7C9 \uBC14\uC774\uB108\uB9AC ${large.length}\uAC1C\uB97C dev Object Storage \uB85C \uC9C1\uC811 \uC5C5\uB85C\uB4DC\uD569\uB2C8\uB2E4...`);
|
|
494
|
+
const offloaded = /* @__PURE__ */ new Set();
|
|
495
|
+
for (const f of large) {
|
|
496
|
+
const uploadUrl = urlByPath.get(f.path);
|
|
497
|
+
if (!uploadUrl) {
|
|
498
|
+
error(`presign \uC751\uB2F5\uC5D0 \uC5C5\uB85C\uB4DC URL \uC774 \uC5C6\uC2B5\uB2C8\uB2E4: ${f.path}`);
|
|
499
|
+
process.exit(1);
|
|
500
|
+
}
|
|
501
|
+
const bytes = Buffer.from(f.content, "base64");
|
|
502
|
+
try {
|
|
503
|
+
await putToPresignedUrl(uploadUrl, bytes, guessMimeType(f.path), timeoutMs);
|
|
504
|
+
} catch (err) {
|
|
505
|
+
error(`dev \uC5C5\uB85C\uB4DC \uC2E4\uD328 (${f.path}): ${err instanceof Error ? err.message : err}`);
|
|
506
|
+
process.exit(1);
|
|
507
|
+
}
|
|
508
|
+
success(`\uC9C1\uC811 \uC5C5\uB85C\uB4DC(dev): ${f.path} (${formatSize(bytes.length)})`);
|
|
509
|
+
offloaded.add(f.path);
|
|
510
|
+
}
|
|
511
|
+
return files.filter((f) => !offloaded.has(f.path));
|
|
512
|
+
}
|
|
469
513
|
var DEFAULT_REQUEST_TIMEOUT_MS = 6e4;
|
|
470
514
|
async function makeRequest(url, method, headers, body, reqOpts = {}) {
|
|
471
515
|
return new Promise((resolve2, reject) => {
|
|
@@ -481,6 +525,8 @@ async function makeRequest(url, method, headers, body, reqOpts = {}) {
|
|
|
481
525
|
family: 4,
|
|
482
526
|
autoSelectFamily: false,
|
|
483
527
|
headers: {
|
|
528
|
+
// 명시적 UA: 관측성 + WAF 봇 휴리스틱(비브라우저 UA 차단 규칙)과의 충돌 방지
|
|
529
|
+
"User-Agent": `connectbase-cli/${VERSION}`,
|
|
484
530
|
...headers,
|
|
485
531
|
"Content-Type": "application/json",
|
|
486
532
|
...bodyBuffer ? { "Content-Length": bodyBuffer.length } : {}
|
|
@@ -572,8 +618,8 @@ async function deploy(directory, config, isDev = false, deployOpts = {}) {
|
|
|
572
618
|
const timeoutMs = computeDeployTimeout(totalSize, deployOpts.timeoutMs);
|
|
573
619
|
log(`${colors.dim}\uD0C0\uC784\uC544\uC6C3: ${Math.round(timeoutMs / 1e3)}\uCD08${colors.reset}`);
|
|
574
620
|
if (isDev) {
|
|
575
|
-
|
|
576
|
-
await fullDeploy(baseStorageUrl, headers,
|
|
621
|
+
const toSend = await offloadDevLargeBinaries(baseStorageUrl, headers, files, timeoutMs);
|
|
622
|
+
await fullDeploy(baseStorageUrl, headers, toSend, envLabel, "deploy/dev", timeoutMs);
|
|
577
623
|
return;
|
|
578
624
|
}
|
|
579
625
|
try {
|
|
@@ -861,7 +907,7 @@ ${colors.cyan}\uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uB85C\uADF8\uC778\uD558\uC13
|
|
|
861
907
|
error("\uC778\uC99D \uC2DC\uAC04\uC774 \uCD08\uACFC\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694.");
|
|
862
908
|
process.exit(1);
|
|
863
909
|
}
|
|
864
|
-
async function init() {
|
|
910
|
+
async function init(config = {}, opts = {}) {
|
|
865
911
|
log(`
|
|
866
912
|
${colors.cyan}Connect Base \uD504\uB85C\uC81D\uD2B8 \uCD08\uAE30\uD654${colors.reset}
|
|
867
913
|
`);
|
|
@@ -872,49 +918,104 @@ ${colors.cyan}Connect Base \uD504\uB85C\uC81D\uD2B8 \uCD08\uAE30\uD654${colors.r
|
|
|
872
918
|
info(`MCP/\uBB38\uC11C\uB294 \uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8\uC5D0, \uBC30\uD3EC \uC124\uC815\uC740 \uD604\uC7AC \uB514\uB809\uD1A0\uB9AC\uC5D0 \uC0DD\uC131\uB429\uB2C8\uB2E4
|
|
873
919
|
`);
|
|
874
920
|
}
|
|
921
|
+
const nonInteractive = opts.yes === true;
|
|
922
|
+
if (!process.stdin.isTTY && !nonInteractive) {
|
|
923
|
+
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");
|
|
924
|
+
log(`${colors.dim}\uC608: npx connectbase init --yes --secret-key cb_sk_... [--app <\uC571ID>] [--storage <\uC2A4\uD1A0\uB9AC\uC9C0ID>] [--deploy-dir ./dist]${colors.reset}`);
|
|
925
|
+
log(`${colors.dim}Secret Key\uB294 CONNECTBASE_SECRET_KEY \uD658\uACBD\uBCC0\uC218\uB85C\uB3C4 \uC804\uB2EC\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4${colors.reset}`);
|
|
926
|
+
process.exit(1);
|
|
927
|
+
}
|
|
875
928
|
const rcPath = path2.join(cwd, ".connectbaserc");
|
|
929
|
+
let existingRc = {};
|
|
876
930
|
if (fs2.existsSync(rcPath)) {
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
931
|
+
try {
|
|
932
|
+
existingRc = JSON.parse(fs2.readFileSync(rcPath, "utf-8"));
|
|
933
|
+
} catch {
|
|
934
|
+
}
|
|
935
|
+
if (nonInteractive) {
|
|
936
|
+
if (!opts.force) {
|
|
937
|
+
error(".connectbaserc\uAC00 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4. \uB36E\uC5B4\uC4F0\uB824\uBA74 --force\uB97C \uD568\uAED8 \uC0AC\uC6A9\uD558\uC138\uC694");
|
|
938
|
+
process.exit(1);
|
|
939
|
+
}
|
|
940
|
+
} else {
|
|
941
|
+
const overwrite = await prompt(`${colors.yellow}\u26A0${colors.reset} .connectbaserc\uAC00 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4. \uB36E\uC5B4\uC4F0\uC2DC\uACA0\uC2B5\uB2C8\uAE4C? (y/N): `);
|
|
942
|
+
if (overwrite.toLowerCase() !== "y") {
|
|
943
|
+
info("\uCD08\uAE30\uD654\uAC00 \uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4");
|
|
944
|
+
return;
|
|
945
|
+
}
|
|
881
946
|
}
|
|
882
947
|
}
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
`);
|
|
888
|
-
const authChoice = await prompt(`${colors.blue}?${colors.reset} \uC120\uD0DD (1/2): `);
|
|
889
|
-
let secretKey = "";
|
|
890
|
-
if (authChoice === "2") {
|
|
891
|
-
try {
|
|
892
|
-
secretKey = await browserAuthFlow();
|
|
893
|
-
} catch (err) {
|
|
894
|
-
error(`\uB124\uD2B8\uC6CC\uD06C \uC624\uB958: ${err instanceof Error ? err.message : err}`);
|
|
895
|
-
info("\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");
|
|
948
|
+
let secretKey = config.secretKey || "";
|
|
949
|
+
if (secretKey) {
|
|
950
|
+
if (!secretKey.startsWith("cb_sk_")) {
|
|
951
|
+
error("\uC720\uD6A8\uD558\uC9C0 \uC54A\uC740 \uD0A4 \uD615\uC2DD\uC785\uB2C8\uB2E4. cb_sk_\uB85C \uC2DC\uC791\uD558\uB294 Secret Key\uB97C \uC9C0\uC815\uD558\uC138\uC694");
|
|
896
952
|
process.exit(1);
|
|
897
953
|
}
|
|
954
|
+
info("Secret Key \uD655\uC778\uB428 (\uD50C\uB798\uADF8/\uD658\uACBD\uBCC0\uC218/.connectbaserc)");
|
|
955
|
+
} else if (nonInteractive) {
|
|
956
|
+
error("Secret Key\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4: --secret-key cb_sk_... \uB610\uB294 CONNECTBASE_SECRET_KEY \uD658\uACBD\uBCC0\uC218");
|
|
957
|
+
process.exit(1);
|
|
898
958
|
} else {
|
|
899
|
-
log(
|
|
959
|
+
log(`
|
|
960
|
+
${colors.dim}\uC778\uC99D \uBC29\uC2DD\uC744 \uC120\uD0DD\uD558\uC138\uC694:${colors.reset}`);
|
|
961
|
+
log(` ${colors.cyan}1${colors.reset}) Secret Key \uC9C1\uC811 \uC785\uB825 (cb_sk_...)`);
|
|
962
|
+
log(` ${colors.cyan}2${colors.reset}) \uBE0C\uB77C\uC6B0\uC800 \uB85C\uADF8\uC778\uC73C\uB85C \uC790\uB3D9 \uBC1C\uAE09
|
|
900
963
|
`);
|
|
901
|
-
|
|
902
|
-
if (
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
964
|
+
const authChoice = await prompt(`${colors.blue}?${colors.reset} \uC120\uD0DD (1/2): `);
|
|
965
|
+
if (authChoice === "2") {
|
|
966
|
+
try {
|
|
967
|
+
secretKey = await browserAuthFlow();
|
|
968
|
+
} catch (err) {
|
|
969
|
+
error(`\uB124\uD2B8\uC6CC\uD06C \uC624\uB958: ${err instanceof Error ? err.message : err}`);
|
|
970
|
+
info("\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");
|
|
971
|
+
process.exit(1);
|
|
972
|
+
}
|
|
973
|
+
} else {
|
|
974
|
+
log(`${colors.dim}Secret Key (cb_sk_): \uCF58\uC194 > \uD504\uB85C\uD544 > \uC2DC\uD06C\uB9BF \uD0A4 \uD0ED\uC5D0\uC11C \uBC1C\uAE09${colors.reset}
|
|
975
|
+
`);
|
|
976
|
+
secretKey = await promptSecret(`${colors.blue}?${colors.reset} Secret Key: `);
|
|
977
|
+
if (!secretKey) {
|
|
978
|
+
error("Secret Key\uB294 \uD544\uC218\uC785\uB2C8\uB2E4");
|
|
979
|
+
process.exit(1);
|
|
980
|
+
}
|
|
981
|
+
if (secretKey.startsWith("cb_pk_")) {
|
|
982
|
+
error("Public Key\uAC00 \uC544\uB2CC Secret Key(cb_sk_)\uB97C \uC785\uB825\uD558\uC138\uC694");
|
|
983
|
+
info("Secret Key\uB294 \uCF58\uC194 > \uD504\uB85C\uD544 > \uC2DC\uD06C\uB9BF \uD0A4 \uD0ED\uC5D0\uC11C \uC0DD\uC131\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4");
|
|
984
|
+
process.exit(1);
|
|
985
|
+
}
|
|
986
|
+
if (!secretKey.startsWith("cb_sk_")) {
|
|
987
|
+
error("\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");
|
|
988
|
+
process.exit(1);
|
|
989
|
+
}
|
|
914
990
|
}
|
|
915
991
|
}
|
|
916
992
|
let appId = "";
|
|
917
993
|
let publicKey = "";
|
|
994
|
+
const projectName = path2.basename(cwd);
|
|
995
|
+
const reuseKeyIfSameApp = (selectedAppId) => {
|
|
996
|
+
if (existingRc.appId === selectedAppId && existingRc.publicKey?.startsWith("cb_pk_")) {
|
|
997
|
+
publicKey = existingRc.publicKey;
|
|
998
|
+
success("\uAE30\uC874 Public Key \uC7AC\uC0AC\uC6A9 (.connectbaserc)");
|
|
999
|
+
return true;
|
|
1000
|
+
}
|
|
1001
|
+
return false;
|
|
1002
|
+
};
|
|
1003
|
+
const issuePublicKey = async (targetAppId) => {
|
|
1004
|
+
info("Public Key \uC0DD\uC131 \uC911...");
|
|
1005
|
+
const newKeyRes = await makeRequest(
|
|
1006
|
+
`${DEFAULT_BASE_URL}/v1/public/cli/apps/${targetAppId}/public-keys`,
|
|
1007
|
+
"POST",
|
|
1008
|
+
{ "X-Public-Key": secretKey },
|
|
1009
|
+
JSON.stringify({})
|
|
1010
|
+
);
|
|
1011
|
+
if (newKeyRes.status === 201) {
|
|
1012
|
+
const keyData = newKeyRes.data;
|
|
1013
|
+
publicKey = keyData.key;
|
|
1014
|
+
success("Public Key \uBC1C\uAE09 \uC644\uB8CC");
|
|
1015
|
+
} else {
|
|
1016
|
+
warn("Public Key \uC790\uB3D9 \uC0DD\uC131 \uC2E4\uD328. \uC218\uB3D9\uC73C\uB85C \uC0DD\uC131\uD558\uC138\uC694");
|
|
1017
|
+
}
|
|
1018
|
+
};
|
|
918
1019
|
try {
|
|
919
1020
|
info("\uC571 \uBAA9\uB85D \uC870\uD68C \uC911...");
|
|
920
1021
|
const appsRes = await makeRequest(
|
|
@@ -931,7 +1032,23 @@ ${colors.dim}\uC778\uC99D \uBC29\uC2DD\uC744 \uC120\uD0DD\uD558\uC138\uC694:${co
|
|
|
931
1032
|
}
|
|
932
1033
|
const appsData = appsRes.data;
|
|
933
1034
|
const apps = appsData.apps || [];
|
|
934
|
-
if (
|
|
1035
|
+
if (opts.appId) {
|
|
1036
|
+
const found = apps.find((a) => a.id === opts.appId);
|
|
1037
|
+
if (!found) {
|
|
1038
|
+
error(`\uC9C0\uC815\uD55C \uC571\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${opts.appId}`);
|
|
1039
|
+
process.exit(1);
|
|
1040
|
+
}
|
|
1041
|
+
appId = found.id;
|
|
1042
|
+
success(`\uC120\uD0DD\uB428: ${found.name}`);
|
|
1043
|
+
if (!reuseKeyIfSameApp(appId)) await issuePublicKey(appId);
|
|
1044
|
+
} else if (nonInteractive) {
|
|
1045
|
+
const found = apps.find((a) => a.name === projectName);
|
|
1046
|
+
if (found) {
|
|
1047
|
+
appId = found.id;
|
|
1048
|
+
success(`\uAE30\uC874 \uC571 \uC7AC\uC0AC\uC6A9: ${found.name}`);
|
|
1049
|
+
if (!reuseKeyIfSameApp(appId)) await issuePublicKey(appId);
|
|
1050
|
+
}
|
|
1051
|
+
} else if (apps.length > 0) {
|
|
935
1052
|
log(`
|
|
936
1053
|
${colors.dim}\uB0B4 \uC571 \uBAA9\uB85D:${colors.reset}`);
|
|
937
1054
|
apps.forEach((a, i) => {
|
|
@@ -945,25 +1062,11 @@ ${colors.blue}?${colors.reset} \uC120\uD0DD (\uBC88\uD638): `);
|
|
|
945
1062
|
if (num > 0 && num <= apps.length) {
|
|
946
1063
|
appId = apps[num - 1].id;
|
|
947
1064
|
success(`\uC120\uD0DD\uB428: ${apps[num - 1].name}`);
|
|
948
|
-
|
|
949
|
-
const newKeyRes = await makeRequest(
|
|
950
|
-
`${DEFAULT_BASE_URL}/v1/public/cli/apps/${appId}/public-keys`,
|
|
951
|
-
"POST",
|
|
952
|
-
{ "X-Public-Key": secretKey },
|
|
953
|
-
JSON.stringify({})
|
|
954
|
-
);
|
|
955
|
-
if (newKeyRes.status === 201) {
|
|
956
|
-
const keyData = newKeyRes.data;
|
|
957
|
-
publicKey = keyData.key;
|
|
958
|
-
success("Public Key \uBC1C\uAE09 \uC644\uB8CC");
|
|
959
|
-
} else {
|
|
960
|
-
warn("Public Key \uC790\uB3D9 \uC0DD\uC131 \uC2E4\uD328. \uC218\uB3D9\uC73C\uB85C \uC0DD\uC131\uD558\uC138\uC694");
|
|
961
|
-
}
|
|
1065
|
+
if (!reuseKeyIfSameApp(appId)) await issuePublicKey(appId);
|
|
962
1066
|
}
|
|
963
1067
|
}
|
|
964
1068
|
if (!appId) {
|
|
965
|
-
const
|
|
966
|
-
const appName = await prompt(`${colors.blue}?${colors.reset} \uC571 \uC774\uB984 (${projectName}): `) || projectName;
|
|
1069
|
+
const appName = nonInteractive ? projectName : await prompt(`${colors.blue}?${colors.reset} \uC571 \uC774\uB984 (${projectName}): `) || projectName;
|
|
967
1070
|
info("\uC571 \uC0DD\uC131 \uC911...");
|
|
968
1071
|
const createRes = await makeRequest(
|
|
969
1072
|
`${DEFAULT_BASE_URL}/v1/public/cli/apps`,
|
|
@@ -990,6 +1093,10 @@ ${colors.blue}?${colors.reset} \uC120\uD0DD (\uBC88\uD638): `);
|
|
|
990
1093
|
}
|
|
991
1094
|
} catch (err) {
|
|
992
1095
|
error(`\uB124\uD2B8\uC6CC\uD06C \uC624\uB958: ${err instanceof Error ? err.message : err}`);
|
|
1096
|
+
if (nonInteractive) {
|
|
1097
|
+
info("\uB124\uD2B8\uC6CC\uD06C \uBCF5\uAD6C \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uAC70\uB098, \uCF58\uC194\uC5D0\uC11C \uBC1C\uAE09\uD55C \uAC12\uC73C\uB85C .connectbaserc\uB97C \uC9C1\uC811 \uC791\uC131\uD558\uC138\uC694");
|
|
1098
|
+
process.exit(1);
|
|
1099
|
+
}
|
|
993
1100
|
log(`${colors.dim}\uC218\uB3D9\uC73C\uB85C \uC785\uB825\uD558\uC138\uC694${colors.reset}`);
|
|
994
1101
|
appId = await prompt(`${colors.blue}?${colors.reset} App ID: `);
|
|
995
1102
|
publicKey = await prompt(`${colors.blue}?${colors.reset} Public Key (cb_pk_): `);
|
|
@@ -1004,77 +1111,92 @@ ${colors.blue}?${colors.reset} \uC120\uD0DD (\uBC88\uD638): `);
|
|
|
1004
1111
|
}
|
|
1005
1112
|
const publicKeyForSdk = publicKey;
|
|
1006
1113
|
let storageId = "";
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1114
|
+
if (opts.storageId) {
|
|
1115
|
+
storageId = opts.storageId;
|
|
1116
|
+
success(`\uC6F9 \uC2A4\uD1A0\uB9AC\uC9C0 \uC9C0\uC815\uB428: ${storageId}`);
|
|
1117
|
+
} else {
|
|
1118
|
+
try {
|
|
1119
|
+
info("\uC6F9 \uC2A4\uD1A0\uB9AC\uC9C0 \uC870\uD68C \uC911...");
|
|
1120
|
+
const listRes = await makeRequest(
|
|
1121
|
+
`${DEFAULT_BASE_URL}/v1/public/storages/webs`,
|
|
1122
|
+
"GET",
|
|
1123
|
+
{ "X-Public-Key": publicKeyForSdk }
|
|
1124
|
+
);
|
|
1125
|
+
if (listRes.status === 200) {
|
|
1126
|
+
const listData = listRes.data;
|
|
1127
|
+
const storages = listData.storages || [];
|
|
1128
|
+
if (nonInteractive) {
|
|
1129
|
+
const found = storages.find((s) => s.name === projectName);
|
|
1130
|
+
if (found) {
|
|
1131
|
+
storageId = found.id;
|
|
1132
|
+
success(`\uAE30\uC874 \uC6F9 \uC2A4\uD1A0\uB9AC\uC9C0 \uC7AC\uC0AC\uC6A9: ${found.name}`);
|
|
1133
|
+
}
|
|
1134
|
+
} else if (storages.length > 0) {
|
|
1135
|
+
log(`
|
|
1019
1136
|
${colors.dim}\uAE30\uC874 \uC6F9 \uC2A4\uD1A0\uB9AC\uC9C0:${colors.reset}`);
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1137
|
+
storages.forEach((s, i) => {
|
|
1138
|
+
log(` ${colors.cyan}${i + 1}${colors.reset}) ${s.name} (${colors.dim}${s.id}${colors.reset})`);
|
|
1139
|
+
});
|
|
1140
|
+
log(` ${colors.cyan}0${colors.reset}) \uC0C8\uB85C \uC0DD\uC131`);
|
|
1141
|
+
const choice = await prompt(`
|
|
1025
1142
|
${colors.blue}?${colors.reset} \uC120\uD0DD (\uBC88\uD638): `);
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1143
|
+
const num = parseInt(choice, 10);
|
|
1144
|
+
if (num > 0 && num <= storages.length) {
|
|
1145
|
+
storageId = storages[num - 1].id;
|
|
1146
|
+
success(`\uC120\uD0DD\uB428: ${storages[num - 1].name}`);
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
if (!storageId) {
|
|
1150
|
+
const name = nonInteractive ? projectName : await prompt(`${colors.blue}?${colors.reset} \uC2A4\uD1A0\uB9AC\uC9C0 \uC774\uB984 (${projectName}): `) || projectName;
|
|
1151
|
+
info("\uC6F9 \uC2A4\uD1A0\uB9AC\uC9C0 \uC0DD\uC131 \uC911...");
|
|
1152
|
+
const createRes = await makeRequest(
|
|
1153
|
+
`${DEFAULT_BASE_URL}/v1/public/storages/webs`,
|
|
1154
|
+
"POST",
|
|
1155
|
+
{ "X-Public-Key": publicKeyForSdk },
|
|
1156
|
+
JSON.stringify({ name })
|
|
1157
|
+
);
|
|
1158
|
+
if (createRes.status !== 200) {
|
|
1159
|
+
const data = createRes.data;
|
|
1160
|
+
error(`\uC0DD\uC131 \uC2E4\uD328: ${data?.error || data?.message || `HTTP ${createRes.status}`}`);
|
|
1161
|
+
process.exit(1);
|
|
1162
|
+
}
|
|
1163
|
+
const createData = createRes.data;
|
|
1164
|
+
storageId = createData.storage_web_id;
|
|
1165
|
+
success(`\uC6F9 \uC2A4\uD1A0\uB9AC\uC9C0 \uC0DD\uC131 \uC644\uB8CC: ${createData.name}`);
|
|
1030
1166
|
}
|
|
1167
|
+
} else {
|
|
1168
|
+
throw new Error(`HTTP ${listRes.status}`);
|
|
1169
|
+
}
|
|
1170
|
+
} catch (err) {
|
|
1171
|
+
error(`\uB124\uD2B8\uC6CC\uD06C \uC624\uB958: ${err instanceof Error ? err.message : err}`);
|
|
1172
|
+
if (nonInteractive) {
|
|
1173
|
+
info("\uB124\uD2B8\uC6CC\uD06C \uBCF5\uAD6C \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uAC70\uB098, --storage <\uC2A4\uD1A0\uB9AC\uC9C0ID>\uC640 \uD568\uAED8 \uC2E4\uD589\uD558\uC138\uC694");
|
|
1174
|
+
process.exit(1);
|
|
1031
1175
|
}
|
|
1176
|
+
log(`${colors.dim}\uC218\uB3D9\uC73C\uB85C Storage ID\uB97C \uC785\uB825\uD558\uC138\uC694${colors.reset}`);
|
|
1177
|
+
storageId = await prompt(`${colors.blue}?${colors.reset} Storage ID: `);
|
|
1032
1178
|
if (!storageId) {
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
info("\uC6F9 \uC2A4\uD1A0\uB9AC\uC9C0 \uC0DD\uC131 \uC911...");
|
|
1036
|
-
const createRes = await makeRequest(
|
|
1037
|
-
`${DEFAULT_BASE_URL}/v1/public/storages/webs`,
|
|
1038
|
-
"POST",
|
|
1039
|
-
{ "X-Public-Key": publicKeyForSdk },
|
|
1040
|
-
JSON.stringify({ name })
|
|
1041
|
-
);
|
|
1042
|
-
if (createRes.status !== 200) {
|
|
1043
|
-
const data = createRes.data;
|
|
1044
|
-
error(`\uC0DD\uC131 \uC2E4\uD328: ${data?.error || data?.message || `HTTP ${createRes.status}`}`);
|
|
1045
|
-
process.exit(1);
|
|
1046
|
-
}
|
|
1047
|
-
const createData = createRes.data;
|
|
1048
|
-
storageId = createData.storage_web_id;
|
|
1049
|
-
success(`\uC6F9 \uC2A4\uD1A0\uB9AC\uC9C0 \uC0DD\uC131 \uC644\uB8CC: ${createData.name}`);
|
|
1179
|
+
error("Storage ID\uB294 \uD544\uC218\uC785\uB2C8\uB2E4");
|
|
1180
|
+
process.exit(1);
|
|
1050
1181
|
}
|
|
1051
|
-
} else {
|
|
1052
|
-
throw new Error(`HTTP ${listRes.status}`);
|
|
1053
|
-
}
|
|
1054
|
-
} catch (err) {
|
|
1055
|
-
error(`\uB124\uD2B8\uC6CC\uD06C \uC624\uB958: ${err instanceof Error ? err.message : err}`);
|
|
1056
|
-
log(`${colors.dim}\uC218\uB3D9\uC73C\uB85C Storage ID\uB97C \uC785\uB825\uD558\uC138\uC694${colors.reset}`);
|
|
1057
|
-
storageId = await prompt(`${colors.blue}?${colors.reset} Storage ID: `);
|
|
1058
|
-
if (!storageId) {
|
|
1059
|
-
error("Storage ID\uB294 \uD544\uC218\uC785\uB2C8\uB2E4");
|
|
1060
|
-
process.exit(1);
|
|
1061
1182
|
}
|
|
1062
1183
|
}
|
|
1063
|
-
const defaultDir = detectBuildDir();
|
|
1064
|
-
const deployDir = await prompt(`${colors.blue}?${colors.reset} \uBC30\uD3EC \uB514\uB809\uD1A0\uB9AC (${defaultDir}): `) || defaultDir;
|
|
1065
|
-
const
|
|
1184
|
+
const defaultDir = opts.deployDir || detectBuildDir();
|
|
1185
|
+
const deployDir = nonInteractive ? defaultDir : await prompt(`${colors.blue}?${colors.reset} \uBC30\uD3EC \uB514\uB809\uD1A0\uB9AC (${defaultDir}): `) || defaultDir;
|
|
1186
|
+
const rcData = {
|
|
1187
|
+
appId,
|
|
1066
1188
|
publicKey: publicKey || "",
|
|
1067
1189
|
storageId,
|
|
1068
1190
|
deployDir
|
|
1069
1191
|
};
|
|
1070
1192
|
if (secretKey) {
|
|
1071
|
-
|
|
1193
|
+
rcData.secretKey = secretKey;
|
|
1072
1194
|
}
|
|
1073
|
-
fs2.writeFileSync(rcPath, JSON.stringify(
|
|
1195
|
+
fs2.writeFileSync(rcPath, JSON.stringify(rcData, null, 2) + "\n");
|
|
1074
1196
|
success(".connectbaserc \uC0DD\uC131 \uC644\uB8CC");
|
|
1075
1197
|
addToGitignore(".connectbaserc");
|
|
1076
1198
|
addDeployScript(deployDir);
|
|
1077
|
-
await setupClaudeCode(
|
|
1199
|
+
await setupClaudeCode(secretKey, projectRoot);
|
|
1078
1200
|
log(`
|
|
1079
1201
|
${colors.green}\uCD08\uAE30\uD654 \uC644\uB8CC!${colors.reset}
|
|
1080
1202
|
`);
|
|
@@ -1088,9 +1210,20 @@ function detectBuildDir() {
|
|
|
1088
1210
|
if (fs2.existsSync(path2.join(process.cwd(), "dist"))) return "./dist";
|
|
1089
1211
|
if (fs2.existsSync(path2.join(process.cwd(), "build"))) return "./build";
|
|
1090
1212
|
if (fs2.existsSync(path2.join(process.cwd(), "out"))) return "./out";
|
|
1091
|
-
|
|
1213
|
+
const nextConfig = ["next.config.js", "next.config.mjs", "next.config.ts"].map((f) => path2.join(process.cwd(), f)).find((f) => fs2.existsSync(f));
|
|
1214
|
+
if (nextConfig || fs2.existsSync(path2.join(process.cwd(), ".next"))) {
|
|
1215
|
+
if (nextConfig) {
|
|
1216
|
+
try {
|
|
1217
|
+
const src = fs2.readFileSync(nextConfig, "utf-8");
|
|
1218
|
+
if (!/output\s*:\s*['"]export['"]/.test(src)) {
|
|
1219
|
+
warn(`Next.js \uAC10\uC9C0: \uC815\uC801 \uBC30\uD3EC\uD558\uB824\uBA74 ${path2.basename(nextConfig)}\uC5D0 output: 'export' \uC124\uC815\uC774 \uD544\uC694\uD569\uB2C8\uB2E4`);
|
|
1220
|
+
}
|
|
1221
|
+
} catch {
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
return "./out";
|
|
1225
|
+
}
|
|
1092
1226
|
if (fs2.existsSync(path2.join(process.cwd(), "vite.config.ts")) || fs2.existsSync(path2.join(process.cwd(), "vite.config.js"))) return "./dist";
|
|
1093
|
-
if (fs2.existsSync(path2.join(process.cwd(), "next.config.js")) || fs2.existsSync(path2.join(process.cwd(), "next.config.mjs"))) return "./out";
|
|
1094
1227
|
return "./dist";
|
|
1095
1228
|
}
|
|
1096
1229
|
function addToGitignore(entry, basePath) {
|
|
@@ -1098,7 +1231,8 @@ function addToGitignore(entry, basePath) {
|
|
|
1098
1231
|
const gitignorePath = path2.join(dir, ".gitignore");
|
|
1099
1232
|
if (fs2.existsSync(gitignorePath)) {
|
|
1100
1233
|
const content = fs2.readFileSync(gitignorePath, "utf-8");
|
|
1101
|
-
|
|
1234
|
+
const lines = content.split(/\r?\n/).map((l) => l.trim());
|
|
1235
|
+
if (!lines.includes(entry)) {
|
|
1102
1236
|
fs2.appendFileSync(gitignorePath, `
|
|
1103
1237
|
# Connect Base
|
|
1104
1238
|
${entry}
|
|
@@ -1179,13 +1313,66 @@ function detectMonorepo(gitRoot) {
|
|
|
1179
1313
|
}
|
|
1180
1314
|
return result;
|
|
1181
1315
|
}
|
|
1182
|
-
|
|
1316
|
+
var DOCS_MANIFEST_FILE = ".connectbase-manifest.json";
|
|
1317
|
+
function readDocsManifest(docsDir) {
|
|
1318
|
+
try {
|
|
1319
|
+
const parsed = JSON.parse(fs2.readFileSync(path2.join(docsDir, DOCS_MANIFEST_FILE), "utf-8"));
|
|
1320
|
+
if (parsed && Array.isArray(parsed.files)) return parsed;
|
|
1321
|
+
} catch {
|
|
1322
|
+
}
|
|
1323
|
+
return null;
|
|
1324
|
+
}
|
|
1325
|
+
var LEGACY_DOC_FILES = [
|
|
1326
|
+
"intro.md",
|
|
1327
|
+
"mcp-workflow.md",
|
|
1328
|
+
"sdk-basic.md",
|
|
1329
|
+
"sdk-database.md",
|
|
1330
|
+
"sdk-storage.md",
|
|
1331
|
+
"sdk-realtime.md",
|
|
1332
|
+
"sdk-auth.md",
|
|
1333
|
+
"sdk-payment.md",
|
|
1334
|
+
"example.md",
|
|
1335
|
+
"mcp-config.md",
|
|
1336
|
+
"mcp-tools.md",
|
|
1337
|
+
"resources.md",
|
|
1338
|
+
"sdk-game.md",
|
|
1339
|
+
"sdk-push.md",
|
|
1340
|
+
"sdk-video.md",
|
|
1341
|
+
"sdk-ads.md",
|
|
1342
|
+
"sdk-ai.md",
|
|
1343
|
+
"sdk-error-tracker.md",
|
|
1344
|
+
"sdk-webrtc.md",
|
|
1345
|
+
"sdk-subscription.md",
|
|
1346
|
+
"sdk-functions.md",
|
|
1347
|
+
"sdk-webhooks.md",
|
|
1348
|
+
"deploy-guide.md",
|
|
1349
|
+
"app-packaging.md",
|
|
1350
|
+
"best-practices.md",
|
|
1351
|
+
"code-analysis.md",
|
|
1352
|
+
"sdk-queue.md",
|
|
1353
|
+
"sdk-knowledge.md",
|
|
1354
|
+
"sdk-workflow.md",
|
|
1355
|
+
"sdk-tunnel.md",
|
|
1356
|
+
"sdk-native.md",
|
|
1357
|
+
"sdk-analytics.md",
|
|
1358
|
+
"sdk-domain.md",
|
|
1359
|
+
"sdk-public-key.md",
|
|
1360
|
+
"sdk-invoice.md",
|
|
1361
|
+
"web-performance.md",
|
|
1362
|
+
"sdk-analytics-advanced.md",
|
|
1363
|
+
"sdk-endpoint.md",
|
|
1364
|
+
"sdk-web-search.md",
|
|
1365
|
+
"sdk-oauth-provider.md",
|
|
1366
|
+
"sdk-oauth-integration.md"
|
|
1367
|
+
];
|
|
1368
|
+
async function downloadDocs(baseDir, opts = {}) {
|
|
1369
|
+
const quiet = opts.quiet === true;
|
|
1183
1370
|
if (!baseDir) {
|
|
1184
1371
|
baseDir = getProjectRoot();
|
|
1185
1372
|
}
|
|
1186
1373
|
const gitRoot = getGitRoot() || baseDir;
|
|
1187
1374
|
const monorepo = detectMonorepo(gitRoot);
|
|
1188
|
-
if (monorepo.type !== "none") {
|
|
1375
|
+
if (!quiet && monorepo.type !== "none") {
|
|
1189
1376
|
info(`\uBAA8\uB178\uB808\uD3EC \uAC10\uC9C0: ${monorepo.type} (\uB8E8\uD2B8: ${gitRoot})`);
|
|
1190
1377
|
if (monorepo.isSubPackage) {
|
|
1191
1378
|
info(`\uD604\uC7AC \uC11C\uBE0C \uD328\uD0A4\uC9C0: ${monorepo.subPackageName || path2.basename(process.cwd())}`);
|
|
@@ -1196,14 +1383,10 @@ async function downloadDocs(publicKey, templates, baseDir) {
|
|
|
1196
1383
|
if (!fs2.existsSync(docsDir)) {
|
|
1197
1384
|
fs2.mkdirSync(docsDir, { recursive: true });
|
|
1198
1385
|
}
|
|
1199
|
-
if (!
|
|
1200
|
-
templates = ["rules"];
|
|
1201
|
-
}
|
|
1202
|
-
info("SDK \uAC1C\uBC1C \uAC00\uC774\uB4DC \uB2E4\uC6B4\uB85C\uB4DC \uC911...");
|
|
1386
|
+
if (!quiet) info("SDK \uAC1C\uBC1C \uAC00\uC774\uB4DC \uB2E4\uC6B4\uB85C\uB4DC \uC911...");
|
|
1203
1387
|
try {
|
|
1204
|
-
const templateParam = templates.join(",");
|
|
1205
1388
|
const res = await makeRequest(
|
|
1206
|
-
`${DEFAULT_BASE_URL}/v1/storages/webs/claude-md?template
|
|
1389
|
+
`${DEFAULT_BASE_URL}/v1/storages/webs/claude-md?template=rules&format=sections`,
|
|
1207
1390
|
"GET",
|
|
1208
1391
|
{}
|
|
1209
1392
|
);
|
|
@@ -1212,18 +1395,59 @@ async function downloadDocs(publicKey, templates, baseDir) {
|
|
|
1212
1395
|
}
|
|
1213
1396
|
const data = typeof res.data === "string" ? JSON.parse(res.data) : res.data;
|
|
1214
1397
|
const sections = data.sections || [];
|
|
1398
|
+
const hasher = crypto.createHash("sha256");
|
|
1399
|
+
const newFiles = [];
|
|
1215
1400
|
for (const section of sections) {
|
|
1216
|
-
const
|
|
1217
|
-
|
|
1401
|
+
const safeName = path2.basename(section.filename);
|
|
1402
|
+
newFiles.push(safeName);
|
|
1403
|
+
hasher.update(safeName).update("\0").update(section.content).update("\0");
|
|
1404
|
+
}
|
|
1405
|
+
const contentHash = hasher.digest("hex");
|
|
1406
|
+
const prevManifest = readDocsManifest(docsDir);
|
|
1407
|
+
const allPresent = newFiles.every((f) => fs2.existsSync(path2.join(docsDir, f)));
|
|
1408
|
+
if (prevManifest && prevManifest.contentHash === contentHash && allPresent) {
|
|
1409
|
+
if (!quiet) success("SDK \uBB38\uC11C\uAC00 \uC774\uBBF8 \uCD5C\uC2E0\uC785\uB2C8\uB2E4");
|
|
1410
|
+
updateRootClaudeMd(rootClaudeMd, quiet);
|
|
1411
|
+
if (monorepo.isSubPackage) {
|
|
1412
|
+
createSubPackageClaudeMd(path2.join(process.cwd(), "CLAUDE.md"), gitRoot, quiet);
|
|
1413
|
+
}
|
|
1414
|
+
return "unchanged";
|
|
1218
1415
|
}
|
|
1219
|
-
|
|
1220
|
-
|
|
1416
|
+
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 -->
|
|
1417
|
+
|
|
1418
|
+
`;
|
|
1419
|
+
for (const section of sections) {
|
|
1420
|
+
const safeName = path2.basename(section.filename);
|
|
1421
|
+
fs2.writeFileSync(path2.join(docsDir, safeName), stamp + section.content);
|
|
1422
|
+
}
|
|
1423
|
+
const staleCandidates = prevManifest ? prevManifest.files.map((f) => path2.basename(f)) : LEGACY_DOC_FILES;
|
|
1424
|
+
for (const old of staleCandidates) {
|
|
1425
|
+
if (newFiles.includes(old)) continue;
|
|
1426
|
+
const oldPath = path2.join(docsDir, old);
|
|
1427
|
+
if (fs2.existsSync(oldPath)) {
|
|
1428
|
+
try {
|
|
1429
|
+
fs2.unlinkSync(oldPath);
|
|
1430
|
+
if (!quiet) info(`\uC2A4\uD14C\uC77C \uBB38\uC11C \uC0AD\uC81C: ${old}`);
|
|
1431
|
+
} catch {
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
const manifest = {
|
|
1436
|
+
cliVersion: VERSION,
|
|
1437
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1438
|
+
contentHash,
|
|
1439
|
+
files: newFiles
|
|
1440
|
+
};
|
|
1441
|
+
fs2.writeFileSync(path2.join(docsDir, DOCS_MANIFEST_FILE), JSON.stringify(manifest, null, 2) + "\n");
|
|
1442
|
+
if (!quiet) success(`${gitRoot}/.claude/docs/ \uC5D0 ${sections.length}\uAC1C \uBB38\uC11C \uC800\uC7A5 \uC644\uB8CC`);
|
|
1443
|
+
updateRootClaudeMd(rootClaudeMd, quiet);
|
|
1221
1444
|
if (monorepo.isSubPackage) {
|
|
1222
|
-
|
|
1223
|
-
createSubPackageClaudeMd(subClaudeMd, gitRoot);
|
|
1445
|
+
createSubPackageClaudeMd(path2.join(process.cwd(), "CLAUDE.md"), gitRoot, quiet);
|
|
1224
1446
|
}
|
|
1225
|
-
log(`${colors.dim}\u203B SDK \uBB38\uC11C\uB294 MCP search_sdk_docs\uB85C \uAC80\uC0C9\uD558\uC138\uC694${colors.reset}`);
|
|
1447
|
+
if (!quiet) log(`${colors.dim}\u203B SDK \uBB38\uC11C\uB294 MCP search_sdk_docs\uB85C \uAC80\uC0C9\uD558\uC138\uC694${colors.reset}`);
|
|
1448
|
+
return "updated";
|
|
1226
1449
|
} catch {
|
|
1450
|
+
if (quiet) return "failed";
|
|
1227
1451
|
warn("SDK \uAC00\uC774\uB4DC \uB2E4\uC6B4\uB85C\uB4DC \uC2E4\uD328, \uAE30\uBCF8 \uBB38\uC11C\uB97C \uC0DD\uC131\uD569\uB2C8\uB2E4");
|
|
1228
1452
|
const fallbackContent = `# ConnectBase \uD504\uB85C\uC81D\uD2B8
|
|
1229
1453
|
|
|
@@ -1238,9 +1462,10 @@ async function downloadDocs(publicKey, templates, baseDir) {
|
|
|
1238
1462
|
createSubPackageClaudeMd(subClaudeMd, gitRoot);
|
|
1239
1463
|
}
|
|
1240
1464
|
success(`.claude/docs/ \uC0DD\uC131 \uC644\uB8CC (\uAE30\uBCF8)`);
|
|
1465
|
+
return "failed";
|
|
1241
1466
|
}
|
|
1242
1467
|
}
|
|
1243
|
-
function updateRootClaudeMd(claudeMdPath) {
|
|
1468
|
+
function updateRootClaudeMd(claudeMdPath, quiet = false) {
|
|
1244
1469
|
const startMarker = "<!-- CONNECTBASE_START -->";
|
|
1245
1470
|
const endMarker = "<!-- CONNECTBASE_END -->";
|
|
1246
1471
|
const sdkBlock = `${startMarker}
|
|
@@ -1248,11 +1473,13 @@ function updateRootClaudeMd(claudeMdPath) {
|
|
|
1248
1473
|
|
|
1249
1474
|
\uC774 \uD504\uB85C\uC81D\uD2B8\uB294 **ConnectBase**\uB97C \uBC31\uC5D4\uB4DC\uB85C \uC0AC\uC6A9\uD569\uB2C8\uB2E4.
|
|
1250
1475
|
|
|
1251
|
-
|
|
1476
|
+
@.claude/docs/project-rules.md
|
|
1252
1477
|
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1478
|
+
### AI \uD544\uC218 \uC6CC\uD06C\uD50C\uB85C\uC6B0
|
|
1479
|
+
|
|
1480
|
+
1. \uC704\uC5D0 import\uB41C project-rules.md\uC758 \uAE30\uB2A5 \uB9E4\uD551\uD45C\xB7\uBCF4\uC548 \uADDC\uCE59\uC744 \uB530\uB974\uC138\uC694
|
|
1481
|
+
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
|
|
1482
|
+
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)
|
|
1256
1483
|
${endMarker}`;
|
|
1257
1484
|
if (fs2.existsSync(claudeMdPath)) {
|
|
1258
1485
|
let content = fs2.readFileSync(claudeMdPath, "utf-8");
|
|
@@ -1264,16 +1491,16 @@ ${endMarker}`;
|
|
|
1264
1491
|
content = sdkBlock + "\n\n" + content.trimStart();
|
|
1265
1492
|
}
|
|
1266
1493
|
fs2.writeFileSync(claudeMdPath, content);
|
|
1267
|
-
info("CLAUDE.md\uC5D0 ConnectBase \uCC38\uC870 \uC5C5\uB370\uC774\uD2B8 \uC644\uB8CC");
|
|
1494
|
+
if (!quiet) info("CLAUDE.md\uC5D0 ConnectBase \uCC38\uC870 \uC5C5\uB370\uC774\uD2B8 \uC644\uB8CC");
|
|
1268
1495
|
} else {
|
|
1269
1496
|
fs2.writeFileSync(claudeMdPath, `# \uD504\uB85C\uC81D\uD2B8
|
|
1270
1497
|
|
|
1271
1498
|
${sdkBlock}
|
|
1272
1499
|
`);
|
|
1273
|
-
success("CLAUDE.md \uC0DD\uC131 \uC644\uB8CC");
|
|
1500
|
+
if (!quiet) success("CLAUDE.md \uC0DD\uC131 \uC644\uB8CC");
|
|
1274
1501
|
}
|
|
1275
1502
|
}
|
|
1276
|
-
function createSubPackageClaudeMd(subClaudeMdPath, gitRoot) {
|
|
1503
|
+
function createSubPackageClaudeMd(subClaudeMdPath, gitRoot, quiet = false) {
|
|
1277
1504
|
const startMarker = "<!-- CONNECTBASE_SUB_START -->";
|
|
1278
1505
|
const endMarker = "<!-- CONNECTBASE_SUB_END -->";
|
|
1279
1506
|
const relPath = path2.relative(path2.dirname(subClaudeMdPath), gitRoot);
|
|
@@ -1284,9 +1511,9 @@ function createSubPackageClaudeMd(subClaudeMdPath, gitRoot) {
|
|
|
1284
1511
|
|
|
1285
1512
|
### AI \uD544\uB3C5
|
|
1286
1513
|
|
|
1287
|
-
1. \uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8\uC758 \`${relPath}/.claude/docs/project-rules.md\`\
|
|
1288
|
-
2. \`search_sdk_docs("\uD0A4\uC6CC\uB4DC")\`\uB85C SDK \uAD6C\uD604 \uBC29\uBC95\uC744 \uAC80\uC0C9\uD558\uC138\uC694
|
|
1289
|
-
3. \
|
|
1514
|
+
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
|
|
1515
|
+
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
|
|
1516
|
+
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
|
|
1290
1517
|
${endMarker}`;
|
|
1291
1518
|
if (fs2.existsSync(subClaudeMdPath)) {
|
|
1292
1519
|
let content = fs2.readFileSync(subClaudeMdPath, "utf-8");
|
|
@@ -1306,7 +1533,7 @@ ${endMarker}`;
|
|
|
1306
1533
|
${subBlock}
|
|
1307
1534
|
`);
|
|
1308
1535
|
}
|
|
1309
|
-
success(`\uC11C\uBE0C \uD328\uD0A4\uC9C0 CLAUDE.md \uC0DD\uC131 \uC644\uB8CC: ${subClaudeMdPath}`);
|
|
1536
|
+
if (!quiet) success(`\uC11C\uBE0C \uD328\uD0A4\uC9C0 CLAUDE.md \uC0DD\uC131 \uC644\uB8CC: ${subClaudeMdPath}`);
|
|
1310
1537
|
}
|
|
1311
1538
|
async function setupMcp(secretKey) {
|
|
1312
1539
|
const gitRoot = getGitRoot();
|
|
@@ -1320,6 +1547,13 @@ async function setupMcp(secretKey) {
|
|
|
1320
1547
|
}
|
|
1321
1548
|
const mcpConfigPath = path2.join(root, ".mcp.json");
|
|
1322
1549
|
if (!secretKey) {
|
|
1550
|
+
if (!process.stdin.isTTY) {
|
|
1551
|
+
error("Secret Key\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4 (\uBE44\uB300\uD654\uD615 \uD658\uACBD)");
|
|
1552
|
+
log(`${colors.dim}\uB2E4\uC74C \uC911 \uD558\uB098\uB85C \uD0A4\uB97C \uC804\uB2EC\uD558\uC138\uC694:${colors.reset}`);
|
|
1553
|
+
log(` ${colors.cyan}npx connectbase mcp --secret-key cb_sk_...${colors.reset}`);
|
|
1554
|
+
log(` ${colors.cyan}CONNECTBASE_SECRET_KEY=cb_sk_... npx connectbase mcp${colors.reset}`);
|
|
1555
|
+
process.exit(1);
|
|
1556
|
+
}
|
|
1323
1557
|
log(`
|
|
1324
1558
|
${colors.dim}\uC778\uC99D \uBC29\uC2DD\uC744 \uC120\uD0DD\uD558\uC138\uC694:${colors.reset}`);
|
|
1325
1559
|
log(` ${colors.cyan}1${colors.reset}) Secret Key \uC9C1\uC811 \uC785\uB825 (cb_sk_...)`);
|
|
@@ -1383,9 +1617,9 @@ ${colors.dim}\uC778\uC99D \uBC29\uC2DD\uC744 \uC120\uD0DD\uD558\uC138\uC694:${co
|
|
|
1383
1617
|
log(`
|
|
1384
1618
|
${colors.dim}Claude Code\uC5D0\uC11C ConnectBase MCP \uB3C4\uAD6C\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.${colors.reset}`);
|
|
1385
1619
|
}
|
|
1386
|
-
async function setupClaudeCode(
|
|
1620
|
+
async function setupClaudeCode(secretKey, projectRoot) {
|
|
1387
1621
|
const root = projectRoot || getProjectRoot();
|
|
1388
|
-
await downloadDocs(
|
|
1622
|
+
await downloadDocs(root);
|
|
1389
1623
|
await setupMcp(secretKey);
|
|
1390
1624
|
}
|
|
1391
1625
|
async function fetchLatestVersion(packageName) {
|
|
@@ -1404,13 +1638,18 @@ async function fetchLatestVersion(packageName) {
|
|
|
1404
1638
|
return null;
|
|
1405
1639
|
}
|
|
1406
1640
|
function compareVersions(a, b) {
|
|
1407
|
-
const
|
|
1408
|
-
const
|
|
1641
|
+
const [aMain, aPre] = a.split("-", 2);
|
|
1642
|
+
const [bMain, bPre] = b.split("-", 2);
|
|
1643
|
+
const pa = aMain.split(".").map(Number);
|
|
1644
|
+
const pb = bMain.split(".").map(Number);
|
|
1409
1645
|
for (let i = 0; i < 3; i++) {
|
|
1410
1646
|
const diff = (pa[i] || 0) - (pb[i] || 0);
|
|
1411
1647
|
if (diff !== 0) return diff > 0 ? 1 : -1;
|
|
1412
1648
|
}
|
|
1413
|
-
return 0;
|
|
1649
|
+
if (aPre === bPre) return 0;
|
|
1650
|
+
if (!aPre) return 1;
|
|
1651
|
+
if (!bPre) return -1;
|
|
1652
|
+
return aPre < bPre ? -1 : aPre > bPre ? 1 : 0;
|
|
1414
1653
|
}
|
|
1415
1654
|
function findSubPackagesWithConfig(gitRoot) {
|
|
1416
1655
|
const results = [];
|
|
@@ -1482,36 +1721,7 @@ ${colors.cyan}ConnectBase Update${colors.reset}
|
|
|
1482
1721
|
if (!opts.skipDocs) {
|
|
1483
1722
|
log("");
|
|
1484
1723
|
info("SDK \uBB38\uC11C \uC5C5\uB370\uC774\uD2B8 \uC911...");
|
|
1485
|
-
|
|
1486
|
-
if (!docsKey) {
|
|
1487
|
-
const rootRcPath = path2.join(projectRoot, ".connectbaserc");
|
|
1488
|
-
if (fs2.existsSync(rootRcPath)) {
|
|
1489
|
-
try {
|
|
1490
|
-
const rc = JSON.parse(fs2.readFileSync(rootRcPath, "utf-8"));
|
|
1491
|
-
docsKey = rc.publicKey || rc.secretKey;
|
|
1492
|
-
} catch {
|
|
1493
|
-
}
|
|
1494
|
-
}
|
|
1495
|
-
}
|
|
1496
|
-
if (!docsKey && monorepo.type !== "none") {
|
|
1497
|
-
const subPackages = findSubPackagesWithConfig(projectRoot);
|
|
1498
|
-
for (const sp of subPackages) {
|
|
1499
|
-
try {
|
|
1500
|
-
const rc = JSON.parse(fs2.readFileSync(path2.join(sp, ".connectbaserc"), "utf-8"));
|
|
1501
|
-
if (rc.publicKey || rc.secretKey) {
|
|
1502
|
-
docsKey = rc.publicKey || rc.secretKey;
|
|
1503
|
-
break;
|
|
1504
|
-
}
|
|
1505
|
-
} catch {
|
|
1506
|
-
}
|
|
1507
|
-
}
|
|
1508
|
-
}
|
|
1509
|
-
if (docsKey) {
|
|
1510
|
-
await downloadDocs(docsKey, void 0, projectRoot);
|
|
1511
|
-
} else {
|
|
1512
|
-
warn("Public Key\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC5B4 \uBB38\uC11C \uC5C5\uB370\uC774\uD2B8\uB97C \uAC74\uB108\uB701\uB2C8\uB2E4");
|
|
1513
|
-
info(".connectbaserc \uD30C\uC77C\uC774\uB098 --public-key \uC635\uC158\uC73C\uB85C \uD0A4\uB97C \uC9C0\uC815\uD558\uC138\uC694");
|
|
1514
|
-
}
|
|
1724
|
+
await downloadDocs(projectRoot);
|
|
1515
1725
|
}
|
|
1516
1726
|
if (!opts.skipMcp) {
|
|
1517
1727
|
log("");
|
|
@@ -2598,8 +2808,12 @@ ${colors.yellow}\uC635\uC158:${colors.reset}
|
|
|
2598
2808
|
--label <name> Endpoint binding \uC790\uB3D9 \uB4F1\uB85D (tunnel \uC804\uC6A9) \u2014 SDK \uC758 cb.endpoint.call(label) \uD638\uCD9C \uAC00\uB2A5
|
|
2599
2809
|
--description <text> Endpoint binding \uC124\uBA85 (--label \uB3D9\uBC18 \uC2DC\uB9CC)
|
|
2600
2810
|
-d, --dev Dev \uD658\uACBD\uC5D0 \uBC30\uD3EC (deploy \uC804\uC6A9)
|
|
2811
|
+
-y, --yes \uBE44\uB300\uD654\uD615 \uCD08\uAE30\uD654 \u2014 \uD504\uB86C\uD504\uD2B8 \uC5C6\uC774 \uAE30\uBCF8\uAC12/\uD50C\uB798\uADF8\uB85C \uC9C4\uD589 (init \uC804\uC6A9, CI/AI \uC5D0\uC774\uC804\uD2B8\uC6A9)
|
|
2812
|
+
-a, --app <id> \uAE30\uC874 \uC571 ID \uC9C0\uC815 (init \uC804\uC6A9)
|
|
2813
|
+
--secret-key <key> Secret Key (cb_sk_) \uC9C0\uC815 (init/mcp)
|
|
2814
|
+
--deploy-dir <dir> \uBC30\uD3EC \uB514\uB809\uD1A0\uB9AC \uC9C0\uC815 (init \uC804\uC6A9, \uAE30\uBCF8: \uC790\uB3D9 \uAC10\uC9C0)
|
|
2601
2815
|
--check \uBC84\uC804\uB9CC \uD655\uC778 (update \uC804\uC6A9)
|
|
2602
|
-
--skip-docs \uBB38\uC11C \uC5C5\uB370\uC774\uD2B8 \uAC74\uB108\uB6F0\uAE30 (update
|
|
2816
|
+
--skip-docs \uBB38\uC11C \uC5C5\uB370\uC774\uD2B8 \uAC74\uB108\uB6F0\uAE30 (update/deploy)
|
|
2603
2817
|
--skip-mcp MCP \uC5C5\uB370\uC774\uD2B8 \uAC74\uB108\uB6F0\uAE30 (update \uC804\uC6A9)
|
|
2604
2818
|
--setup-root \uBAA8\uB178\uB808\uD3EC \uB8E8\uD2B8\uC5D0 \uD3B8\uC758 \uC2A4\uD06C\uB9BD\uD2B8 \uCD94\uAC00 (update \uC804\uC6A9)
|
|
2605
2819
|
(docs, mcp, update\uB294 \uBAA8\uB178\uB808\uD3EC\uB97C \uC790\uB3D9 \uAC10\uC9C0\uD558\uC5EC \uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8\uC5D0 \uC0DD\uC131)
|
|
@@ -2610,6 +2824,9 @@ ${colors.yellow}\uBE60\uB978 \uC2DC\uC791:${colors.reset}
|
|
|
2610
2824
|
${colors.dim}# 1. \uCD08\uAE30\uD654 (\uCD5C\uCD08 1\uD68C)${colors.reset}
|
|
2611
2825
|
npx connectbase init
|
|
2612
2826
|
|
|
2827
|
+
${colors.dim}# 1-1. \uBE44\uB300\uD654\uD615 \uCD08\uAE30\uD654 (CI/AI \uC5D0\uC774\uC804\uD2B8)${colors.reset}
|
|
2828
|
+
npx connectbase init --yes --secret-key cb_sk_...
|
|
2829
|
+
|
|
2613
2830
|
${colors.dim}# 2. SDK \uC804\uCCB4 \uC5C5\uB370\uC774\uD2B8 (\uBC84\uC804 \uCCB4\uD06C + \uBB38\uC11C + MCP)${colors.reset}
|
|
2614
2831
|
npx connectbase update
|
|
2615
2832
|
|
|
@@ -2680,6 +2897,10 @@ function parseArgs(args) {
|
|
|
2680
2897
|
result.options.appId = args[++i];
|
|
2681
2898
|
} else if (arg === "--force") {
|
|
2682
2899
|
result.options.force = "true";
|
|
2900
|
+
} else if (arg === "-y" || arg === "--yes") {
|
|
2901
|
+
result.options.yes = "true";
|
|
2902
|
+
} else if (arg === "--deploy-dir") {
|
|
2903
|
+
result.options.deployDir = args[++i];
|
|
2683
2904
|
} else if (arg === "--public") {
|
|
2684
2905
|
result.options.public = "true";
|
|
2685
2906
|
} else if (arg === "--show-token") {
|
|
@@ -2727,7 +2948,13 @@ async function main() {
|
|
|
2727
2948
|
baseUrl: parsed.options.baseUrl || fileConfig.baseUrl || DEFAULT_BASE_URL
|
|
2728
2949
|
};
|
|
2729
2950
|
if (parsed.command === "init") {
|
|
2730
|
-
await init(
|
|
2951
|
+
await init(config, {
|
|
2952
|
+
yes: parsed.options.yes === "true",
|
|
2953
|
+
force: parsed.options.force === "true",
|
|
2954
|
+
appId: parsed.options.appId,
|
|
2955
|
+
storageId: parsed.options.storageId,
|
|
2956
|
+
deployDir: parsed.options.deployDir
|
|
2957
|
+
});
|
|
2731
2958
|
} else if (parsed.command === "update") {
|
|
2732
2959
|
await update(config, {
|
|
2733
2960
|
checkOnly: parsed.options.check === "true",
|
|
@@ -2736,9 +2963,9 @@ async function main() {
|
|
|
2736
2963
|
setupRoot: parsed.options.setupRoot === "true"
|
|
2737
2964
|
});
|
|
2738
2965
|
} else if (parsed.command === "docs") {
|
|
2739
|
-
await downloadDocs(
|
|
2966
|
+
await downloadDocs();
|
|
2740
2967
|
} else if (parsed.command === "mcp") {
|
|
2741
|
-
await setupMcp();
|
|
2968
|
+
await setupMcp(config.secretKey);
|
|
2742
2969
|
} else if (parsed.command === "deploy") {
|
|
2743
2970
|
const directory = parsed.args[0] || fileConfig.deployDir || ".";
|
|
2744
2971
|
if (!config.publicKey) {
|
|
@@ -2757,6 +2984,18 @@ async function main() {
|
|
|
2757
2984
|
else warn(`--timeout \uAC12\uC774 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC544 \uBB34\uC2DC\uB429\uB2C8\uB2E4: ${parsed.options.timeout}`);
|
|
2758
2985
|
}
|
|
2759
2986
|
await deploy(directory, config, isDev, deployOpts);
|
|
2987
|
+
if (parsed.options.skipDocs !== "true") {
|
|
2988
|
+
try {
|
|
2989
|
+
const docsRoot = getGitRoot() || getProjectRoot();
|
|
2990
|
+
if (fs2.existsSync(path2.join(docsRoot, ".claude", "docs", DOCS_MANIFEST_FILE))) {
|
|
2991
|
+
const refreshed = await downloadDocs(docsRoot, { quiet: true });
|
|
2992
|
+
if (refreshed === "updated") {
|
|
2993
|
+
info("SDK \uBB38\uC11C\uAC00 \uC0C8 \uBC84\uC804\uC73C\uB85C \uAC31\uC2E0\uB418\uC5C8\uC2B5\uB2C8\uB2E4 (.claude/docs/)");
|
|
2994
|
+
}
|
|
2995
|
+
}
|
|
2996
|
+
} catch {
|
|
2997
|
+
}
|
|
2998
|
+
}
|
|
2760
2999
|
} else if (parsed.command === "tunnel") {
|
|
2761
3000
|
const portStr = parsed.args[0];
|
|
2762
3001
|
if (!portStr) {
|