sayren 0.15.0 → 0.16.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/index.mjs +206 -559
- package/package.json +4 -4
- package/dist/boilerplate/.claude/skills/sayren/SKILL.md +0 -18
- package/dist/boilerplate/.mcp.json +0 -8
- package/dist/boilerplate/CLAUDE.md +0 -26
- package/dist/boilerplate/README.md +0 -12
- package/dist/boilerplate/_gitignore +0 -8
- package/dist/boilerplate/biome.json +0 -45
- package/dist/boilerplate/messages/en.json +0 -9
- package/dist/boilerplate/messages/ko.json +0 -9
- package/dist/boilerplate/package.json +0 -46
- package/dist/boilerplate/public/_headers +0 -5
- package/dist/boilerplate/public/favicon.svg +0 -1
- package/dist/boilerplate/src/hooks/use-catalog.ts +0 -28
- package/dist/boilerplate/src/i18n/index.ts +0 -99
- package/dist/boilerplate/src/i18n/locale.server.ts +0 -10
- package/dist/boilerplate/src/lib/analytics.ts +0 -60
- package/dist/boilerplate/src/lib/api.server.ts +0 -27
- package/dist/boilerplate/src/lib/api.ts +0 -7
- package/dist/boilerplate/src/lib/config.server.ts +0 -23
- package/dist/boilerplate/src/lib/config.test.ts +0 -16
- package/dist/boilerplate/src/lib/config.ts +0 -19
- package/dist/boilerplate/src/lib/cookies.server.ts +0 -35
- package/dist/boilerplate/src/lib/format.ts +0 -19
- package/dist/boilerplate/src/lib/queries.ts +0 -61
- package/dist/boilerplate/src/routeTree.gen.ts +0 -69
- package/dist/boilerplate/src/router.tsx +0 -44
- package/dist/boilerplate/src/routes/__root.tsx +0 -119
- package/dist/boilerplate/src/routes/index.tsx +0 -52
- package/dist/boilerplate/src/start.ts +0 -20
- package/dist/boilerplate/src/styles.css +0 -29
- package/dist/boilerplate/src/theme.css +0 -38
- package/dist/boilerplate/tsconfig.json +0 -16
- package/dist/boilerplate/vite.config.ts +0 -12
- package/dist/boilerplate/vitest.config.ts +0 -5
package/dist/index.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import { APP_DEPLOY_KEY_PATTERN, APP_README_MAX_BYTES, APP_SECRET_PATTERNS, APP_
|
|
|
6
6
|
import { chmodSync, closeSync, existsSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
7
7
|
import { createServer } from "node:http";
|
|
8
8
|
import { dirname, extname, join, relative, resolve, sep } from "node:path";
|
|
9
|
-
import {
|
|
9
|
+
import { pathToFileURL } from "node:url";
|
|
10
10
|
import { gzipSync } from "node:zlib";
|
|
11
11
|
import { createHash, randomBytes } from "node:crypto";
|
|
12
12
|
|
|
@@ -1082,7 +1082,7 @@ const mcp_report_next_reverify_remote = ((inputs = {}, options = {}) => {
|
|
|
1082
1082
|
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
1083
1083
|
/** @typedef {{ files: NonNullable<unknown> }} Mcp_Report_Template_Hint_LocalInputs */
|
|
1084
1084
|
const ko_mcp_report_template_hint_local = (i) => {
|
|
1085
|
-
return `손대지 않아야 하는 파일을 고친 결과일 수 있다 —
|
|
1085
|
+
return `손대지 않아야 하는 파일을 고친 결과일 수 있다 — ${i?.files}을(를) 규칙의 \`example\`이나 git 기록과 대조해 되돌린다.`;
|
|
1086
1086
|
};
|
|
1087
1087
|
/**
|
|
1088
1088
|
|
|
@@ -1100,7 +1100,7 @@ const mcp_report_template_hint_local = ((inputs, options = {}) => {
|
|
|
1100
1100
|
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
1101
1101
|
/** @typedef {{ files: NonNullable<unknown> }} Mcp_Report_Template_Hint_RemoteInputs */
|
|
1102
1102
|
const ko_mcp_report_template_hint_remote = (i) => {
|
|
1103
|
-
return `손대지 않아야 하는 파일을 고친 결과일 수 있다 — ${i?.files}을(를) \`read_file\`로 읽어
|
|
1103
|
+
return `손대지 않아야 하는 파일을 고친 결과일 수 있다 — ${i?.files}을(를) \`read_file\`로 읽어 규칙의 \`example\`과 대조하고 되돌린다.`;
|
|
1104
1104
|
};
|
|
1105
1105
|
/**
|
|
1106
1106
|
|
|
@@ -1985,7 +1985,7 @@ const mcp_rule_local_import_exists_example = ((inputs = {}, options = {}) => {
|
|
|
1985
1985
|
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
1986
1986
|
/** @typedef {{}} Mcp_Rule_Local_Import_Exists_FixInputs */
|
|
1987
1987
|
const ko_mcp_rule_local_import_exists_fix = () => {
|
|
1988
|
-
return `빠진 파일을
|
|
1988
|
+
return `빠진 파일을 같은 경로에 다시 만든다(git 기록에 있으면 되살린다). 호스팅 사이트는 \`write_files\`(\`expectedHash: null\`)나 \`sayren deploy\`로 올린다. 쓰지 않는 import면 지운다. 화면 문구 카탈로그는 \`messages/ko.json\`이다`;
|
|
1989
1989
|
};
|
|
1990
1990
|
/**
|
|
1991
1991
|
|
|
@@ -2751,42 +2751,6 @@ const mcp_rule_tenant_header_why = ((inputs = {}, options = {}) => {
|
|
|
2751
2751
|
return ko_mcp_rule_tenant_header_why(inputs);
|
|
2752
2752
|
});
|
|
2753
2753
|
|
|
2754
|
-
//#endregion
|
|
2755
|
-
//#region ../mcp/src/paraglide/messages/mcp_template_catalog_version_missing.js
|
|
2756
|
-
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
2757
|
-
/** @typedef {{ name: NonNullable<unknown> }} Mcp_Template_Catalog_Version_MissingInputs */
|
|
2758
|
-
const ko_mcp_template_catalog_version_missing = (i) => {
|
|
2759
|
-
return `catalog에 ${i?.name} 버전이 없습니다`;
|
|
2760
|
-
};
|
|
2761
|
-
/**
|
|
2762
|
-
|
|
2763
|
-
* @param {Mcp_Template_Catalog_Version_MissingInputs} inputs
|
|
2764
|
-
* @param {{ locale?: "ko" }} options
|
|
2765
|
-
* @returns {LocalizedString}
|
|
2766
|
-
*/
|
|
2767
|
-
const mcp_template_catalog_version_missing = ((inputs, options = {}) => {
|
|
2768
|
-
experimentalStaticLocale$1 ?? options.locale ?? getLocale$1();
|
|
2769
|
-
return ko_mcp_template_catalog_version_missing(inputs);
|
|
2770
|
-
});
|
|
2771
|
-
|
|
2772
|
-
//#endregion
|
|
2773
|
-
//#region ../mcp/src/paraglide/messages/mcp_template_published_version_unknown.js
|
|
2774
|
-
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
2775
|
-
/** @typedef {{ name: NonNullable<unknown> }} Mcp_Template_Published_Version_UnknownInputs */
|
|
2776
|
-
const ko_mcp_template_published_version_unknown = (i) => {
|
|
2777
|
-
return `${i?.name}의 배포 버전을 모르겠습니다`;
|
|
2778
|
-
};
|
|
2779
|
-
/**
|
|
2780
|
-
|
|
2781
|
-
* @param {Mcp_Template_Published_Version_UnknownInputs} inputs
|
|
2782
|
-
* @param {{ locale?: "ko" }} options
|
|
2783
|
-
* @returns {LocalizedString}
|
|
2784
|
-
*/
|
|
2785
|
-
const mcp_template_published_version_unknown = ((inputs, options = {}) => {
|
|
2786
|
-
experimentalStaticLocale$1 ?? options.locale ?? getLocale$1();
|
|
2787
|
-
return ko_mcp_template_published_version_unknown(inputs);
|
|
2788
|
-
});
|
|
2789
|
-
|
|
2790
2754
|
//#endregion
|
|
2791
2755
|
//#region ../mcp/src/paraglide/messages/mcp_verify_analytics_ids.js
|
|
2792
2756
|
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
@@ -3519,7 +3483,7 @@ function lazyMessages(table) {
|
|
|
3519
3483
|
/**
|
|
3520
3484
|
* 셀러 프로젝트의 `.mcp.json`(Claude Code 형식) — 원격 MCP(`mcp.sayren.io`)에 붙는 `sayren` 항목을 만들고 읽는다.
|
|
3521
3485
|
*
|
|
3522
|
-
* `npx sayren pull`·`login`(packages/cli)
|
|
3486
|
+
* `npx sayren pull`·`link`·`login`(packages/cli)이 같은 함수로 쓴다. 파일 입출력은 부르는 쪽이 하고 여기는 문자열만
|
|
3523
3487
|
* 다룬다 — 게이트웨이(Worker)가 헤더 이름을 이 파일에서 가져가므로 Node 전용 API를 쓰지 않는다.
|
|
3524
3488
|
*
|
|
3525
3489
|
* - **토큰을 쓰지 않는다(#71)** — 항목은 주소와 `X-Store-Id`뿐이고 MCP 클라이언트가 게이트웨이의 401 + `resource_metadata`를 보고
|
|
@@ -3609,7 +3573,7 @@ function sayrenStoreIdOf(text) {
|
|
|
3609
3573
|
//#endregion
|
|
3610
3574
|
//#region ../mcp/src/mcp-json-file.ts
|
|
3611
3575
|
/**
|
|
3612
|
-
* `.mcp.json` 파일 쓰기(Node) — `sayren` CLI(packages/cli)
|
|
3576
|
+
* `.mcp.json` 파일 쓰기(Node) — `sayren` CLI(packages/cli)가 쓴다. 형식은 `mcp-json.ts`(Node 없음)다.
|
|
3613
3577
|
* 항목에 토큰을 쓰지 않는다(#71 R1). 심볼릭 링크는 따라가지 않는다(폴더 밖 파일을 덮지 않게).
|
|
3614
3578
|
*/
|
|
3615
3579
|
function git(dir, args) {
|
|
@@ -5511,24 +5475,6 @@ const cli_checks_lock_drift = ((inputs, options = {}) => {
|
|
|
5511
5475
|
return ko_cli_checks_lock_drift(inputs);
|
|
5512
5476
|
});
|
|
5513
5477
|
|
|
5514
|
-
//#endregion
|
|
5515
|
-
//#region src/paraglide/messages/cli_checks_lock_missing.js
|
|
5516
|
-
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
5517
|
-
/** @typedef {{}} Cli_Checks_Lock_MissingInputs */
|
|
5518
|
-
const ko_cli_checks_lock_missing = () => {
|
|
5519
|
-
return `pnpm-lock.yaml이 없습니다. 호스팅 빌드의 설치가 실패할 수 있습니다`;
|
|
5520
|
-
};
|
|
5521
|
-
/**
|
|
5522
|
-
|
|
5523
|
-
* @param {Cli_Checks_Lock_MissingInputs} inputs
|
|
5524
|
-
* @param {{ locale?: "ko" }} options
|
|
5525
|
-
* @returns {LocalizedString}
|
|
5526
|
-
*/
|
|
5527
|
-
const cli_checks_lock_missing = ((inputs = {}, options = {}) => {
|
|
5528
|
-
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
5529
|
-
return ko_cli_checks_lock_missing(inputs);
|
|
5530
|
-
});
|
|
5531
|
-
|
|
5532
5478
|
//#endregion
|
|
5533
5479
|
//#region src/paraglide/messages/cli_checks_summary.js
|
|
5534
5480
|
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
@@ -5586,14 +5532,14 @@ const cli_create_dir_not_empty = ((inputs, options = {}) => {
|
|
|
5586
5532
|
//#endregion
|
|
5587
5533
|
//#region src/paraglide/messages/cli_create_done.js
|
|
5588
5534
|
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
5589
|
-
/** @typedef {{ dir: NonNullable<unknown>, count: NonNullable<unknown> }} Cli_Create_DoneInputs */
|
|
5535
|
+
/** @typedef {{ dir: NonNullable<unknown>, count: NonNullable<unknown>, install: NonNullable<unknown>, dev: NonNullable<unknown> }} Cli_Create_DoneInputs */
|
|
5590
5536
|
const ko_cli_create_done = (i) => {
|
|
5591
5537
|
return `시작 코드를 만들었습니다 — ${i?.dir} (파일 ${i?.count}개)
|
|
5592
5538
|
다음:
|
|
5593
5539
|
cd ${i?.dir}
|
|
5594
|
-
|
|
5540
|
+
${i?.install}
|
|
5595
5541
|
npx sayren link # 상점에 연결하고 .env에 상점 값을 씁니다
|
|
5596
|
-
|
|
5542
|
+
${i?.dev}`;
|
|
5597
5543
|
};
|
|
5598
5544
|
/**
|
|
5599
5545
|
|
|
@@ -5609,13 +5555,13 @@ const cli_create_done = ((inputs, options = {}) => {
|
|
|
5609
5555
|
//#endregion
|
|
5610
5556
|
//#region src/paraglide/messages/cli_create_done_store_code.js
|
|
5611
5557
|
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
5612
|
-
/** @typedef {{ dir: NonNullable<unknown>, count: NonNullable<unknown>, storeCode: NonNullable<unknown> }} Cli_Create_Done_Store_CodeInputs */
|
|
5558
|
+
/** @typedef {{ dir: NonNullable<unknown>, count: NonNullable<unknown>, storeCode: NonNullable<unknown>, install: NonNullable<unknown>, dev: NonNullable<unknown> }} Cli_Create_Done_Store_CodeInputs */
|
|
5613
5559
|
const ko_cli_create_done_store_code = (i) => {
|
|
5614
5560
|
return `시작 코드를 만들었습니다 — ${i?.dir} (파일 ${i?.count}개, .env에 상점 ${i?.storeCode} 연결 값)
|
|
5615
5561
|
다음:
|
|
5616
5562
|
cd ${i?.dir}
|
|
5617
|
-
|
|
5618
|
-
|
|
5563
|
+
${i?.install}
|
|
5564
|
+
${i?.dev}
|
|
5619
5565
|
npx sayren deploy # 처음이면 상점 사이트에 연결한 뒤 배포합니다`;
|
|
5620
5566
|
};
|
|
5621
5567
|
/**
|
|
@@ -5647,6 +5593,42 @@ const cli_create_name_invalid = ((inputs, options = {}) => {
|
|
|
5647
5593
|
return ko_cli_create_name_invalid(inputs);
|
|
5648
5594
|
});
|
|
5649
5595
|
|
|
5596
|
+
//#endregion
|
|
5597
|
+
//#region src/paraglide/messages/cli_create_starter_no_release.js
|
|
5598
|
+
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
5599
|
+
/** @typedef {{ status: NonNullable<unknown> }} Cli_Create_Starter_No_ReleaseInputs */
|
|
5600
|
+
const ko_cli_create_starter_no_release = (i) => {
|
|
5601
|
+
return `시작 코드의 최신 릴리스를 찾지 못했습니다(GitHub avarcorp/sayren-starter, HTTP ${i?.status}). 잠시 뒤 다시 시도하십시오`;
|
|
5602
|
+
};
|
|
5603
|
+
/**
|
|
5604
|
+
|
|
5605
|
+
* @param {Cli_Create_Starter_No_ReleaseInputs} inputs
|
|
5606
|
+
* @param {{ locale?: "ko" }} options
|
|
5607
|
+
* @returns {LocalizedString}
|
|
5608
|
+
*/
|
|
5609
|
+
const cli_create_starter_no_release = ((inputs, options = {}) => {
|
|
5610
|
+
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
5611
|
+
return ko_cli_create_starter_no_release(inputs);
|
|
5612
|
+
});
|
|
5613
|
+
|
|
5614
|
+
//#endregion
|
|
5615
|
+
//#region src/paraglide/messages/cli_create_starter_unreachable.js
|
|
5616
|
+
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
5617
|
+
/** @typedef {{}} Cli_Create_Starter_UnreachableInputs */
|
|
5618
|
+
const ko_cli_create_starter_unreachable = () => {
|
|
5619
|
+
return `시작 코드의 최신 버전을 확인하지 못했습니다. 시작 코드는 GitHub(avarcorp/sayren-starter)에서 받으므로 네트워크 연결을 확인하십시오`;
|
|
5620
|
+
};
|
|
5621
|
+
/**
|
|
5622
|
+
|
|
5623
|
+
* @param {Cli_Create_Starter_UnreachableInputs} inputs
|
|
5624
|
+
* @param {{ locale?: "ko" }} options
|
|
5625
|
+
* @returns {LocalizedString}
|
|
5626
|
+
*/
|
|
5627
|
+
const cli_create_starter_unreachable = ((inputs = {}, options = {}) => {
|
|
5628
|
+
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
5629
|
+
return ko_cli_create_starter_unreachable(inputs);
|
|
5630
|
+
});
|
|
5631
|
+
|
|
5650
5632
|
//#endregion
|
|
5651
5633
|
//#region src/paraglide/messages/cli_create_store_code_invalid.js
|
|
5652
5634
|
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
@@ -6029,9 +6011,9 @@ const cli_deploy_build_local_failed = ((inputs, options = {}) => {
|
|
|
6029
6011
|
//#endregion
|
|
6030
6012
|
//#region src/paraglide/messages/cli_deploy_build_local_no_deps.js
|
|
6031
6013
|
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
6032
|
-
/** @typedef {{}} Cli_Deploy_Build_Local_No_DepsInputs */
|
|
6033
|
-
const ko_cli_deploy_build_local_no_deps = () => {
|
|
6034
|
-
return `의존성이 설치되지 않아(node_modules 없음) 로컬 빌드를 건너뜁니다.
|
|
6014
|
+
/** @typedef {{ install: NonNullable<unknown> }} Cli_Deploy_Build_Local_No_DepsInputs */
|
|
6015
|
+
const ko_cli_deploy_build_local_no_deps = (i) => {
|
|
6016
|
+
return `의존성이 설치되지 않아(node_modules 없음) 로컬 빌드를 건너뜁니다. ${i?.install} 뒤 배포하면 올리기 전에 빌드를 확인합니다`;
|
|
6035
6017
|
};
|
|
6036
6018
|
/**
|
|
6037
6019
|
|
|
@@ -6039,7 +6021,7 @@ const ko_cli_deploy_build_local_no_deps = () => {
|
|
|
6039
6021
|
* @param {{ locale?: "ko" }} options
|
|
6040
6022
|
* @returns {LocalizedString}
|
|
6041
6023
|
*/
|
|
6042
|
-
const cli_deploy_build_local_no_deps = ((inputs
|
|
6024
|
+
const cli_deploy_build_local_no_deps = ((inputs, options = {}) => {
|
|
6043
6025
|
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
6044
6026
|
return ko_cli_deploy_build_local_no_deps(inputs);
|
|
6045
6027
|
});
|
|
@@ -6874,274 +6856,21 @@ const cli_flag_value_required = ((inputs, options = {}) => {
|
|
|
6874
6856
|
});
|
|
6875
6857
|
|
|
6876
6858
|
//#endregion
|
|
6877
|
-
//#region src/paraglide/messages/
|
|
6878
|
-
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
6879
|
-
/** @typedef {{}} Cli_Init_ConfirmInputs */
|
|
6880
|
-
const ko_cli_init_confirm = () => {
|
|
6881
|
-
return `사이트를 만드시겠습니까?`;
|
|
6882
|
-
};
|
|
6883
|
-
/**
|
|
6884
|
-
|
|
6885
|
-
* @param {Cli_Init_ConfirmInputs} inputs
|
|
6886
|
-
* @param {{ locale?: "ko" }} options
|
|
6887
|
-
* @returns {LocalizedString}
|
|
6888
|
-
*/
|
|
6889
|
-
const cli_init_confirm = ((inputs = {}, options = {}) => {
|
|
6890
|
-
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
6891
|
-
return ko_cli_init_confirm(inputs);
|
|
6892
|
-
});
|
|
6893
|
-
|
|
6894
|
-
//#endregion
|
|
6895
|
-
//#region src/paraglide/messages/cli_init_created.js
|
|
6859
|
+
//#region src/paraglide/messages/cli_init_retired.js
|
|
6896
6860
|
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
6897
|
-
/** @typedef {{
|
|
6898
|
-
const
|
|
6899
|
-
return
|
|
6861
|
+
/** @typedef {{}} Cli_Init_RetiredInputs */
|
|
6862
|
+
const ko_cli_init_retired = () => {
|
|
6863
|
+
return `npx sayren init은 더는 사이트를 만들지 않습니다. npx sayren create <이름>으로 시작 코드를 만든 뒤 그 폴더에서 npx sayren link로 사이트를 만들고 연결하십시오`;
|
|
6900
6864
|
};
|
|
6901
6865
|
/**
|
|
6902
6866
|
|
|
6903
|
-
* @param {
|
|
6867
|
+
* @param {Cli_Init_RetiredInputs} inputs
|
|
6904
6868
|
* @param {{ locale?: "ko" }} options
|
|
6905
6869
|
* @returns {LocalizedString}
|
|
6906
6870
|
*/
|
|
6907
|
-
const
|
|
6871
|
+
const cli_init_retired = ((inputs = {}, options = {}) => {
|
|
6908
6872
|
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
6909
|
-
return
|
|
6910
|
-
});
|
|
6911
|
-
|
|
6912
|
-
//#endregion
|
|
6913
|
-
//#region src/paraglide/messages/cli_init_dir_not_empty.js
|
|
6914
|
-
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
6915
|
-
/** @typedef {{ dir: NonNullable<unknown> }} Cli_Init_Dir_Not_EmptyInputs */
|
|
6916
|
-
const ko_cli_init_dir_not_empty = (i) => {
|
|
6917
|
-
return `폴더가 비어 있지 않습니다: ${i?.dir}. 빈 폴더나 새 폴더 이름을 주십시오`;
|
|
6918
|
-
};
|
|
6919
|
-
/**
|
|
6920
|
-
|
|
6921
|
-
* @param {Cli_Init_Dir_Not_EmptyInputs} inputs
|
|
6922
|
-
* @param {{ locale?: "ko" }} options
|
|
6923
|
-
* @returns {LocalizedString}
|
|
6924
|
-
*/
|
|
6925
|
-
const cli_init_dir_not_empty = ((inputs, options = {}) => {
|
|
6926
|
-
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
6927
|
-
return ko_cli_init_dir_not_empty(inputs);
|
|
6928
|
-
});
|
|
6929
|
-
|
|
6930
|
-
//#endregion
|
|
6931
|
-
//#region src/paraglide/messages/cli_init_inside_pulled.js
|
|
6932
|
-
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
6933
|
-
/** @typedef {{}} Cli_Init_Inside_PulledInputs */
|
|
6934
|
-
const ko_cli_init_inside_pulled = () => {
|
|
6935
|
-
return `지금 폴더는 이미 받은 사이트 폴더입니다. 새 사이트는 다른 폴더에서 npx sayren init <폴더>로 만들고, 이 사이트를 다시 받으려면 npx sayren pull --force를 쓰십시오`;
|
|
6936
|
-
};
|
|
6937
|
-
/**
|
|
6938
|
-
|
|
6939
|
-
* @param {Cli_Init_Inside_PulledInputs} inputs
|
|
6940
|
-
* @param {{ locale?: "ko" }} options
|
|
6941
|
-
* @returns {LocalizedString}
|
|
6942
|
-
*/
|
|
6943
|
-
const cli_init_inside_pulled = ((inputs = {}, options = {}) => {
|
|
6944
|
-
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
6945
|
-
return ko_cli_init_inside_pulled(inputs);
|
|
6946
|
-
});
|
|
6947
|
-
|
|
6948
|
-
//#endregion
|
|
6949
|
-
//#region src/paraglide/messages/cli_init_no_templates.js
|
|
6950
|
-
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
6951
|
-
/** @typedef {{}} Cli_Init_No_TemplatesInputs */
|
|
6952
|
-
const ko_cli_init_no_templates = () => {
|
|
6953
|
-
return `쓸 수 있는 템플릿이 없습니다`;
|
|
6954
|
-
};
|
|
6955
|
-
/**
|
|
6956
|
-
|
|
6957
|
-
* @param {Cli_Init_No_TemplatesInputs} inputs
|
|
6958
|
-
* @param {{ locale?: "ko" }} options
|
|
6959
|
-
* @returns {LocalizedString}
|
|
6960
|
-
*/
|
|
6961
|
-
const cli_init_no_templates = ((inputs = {}, options = {}) => {
|
|
6962
|
-
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
6963
|
-
return ko_cli_init_no_templates(inputs);
|
|
6964
|
-
});
|
|
6965
|
-
|
|
6966
|
-
//#endregion
|
|
6967
|
-
//#region src/paraglide/messages/cli_init_pull_failed.js
|
|
6968
|
-
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
6969
|
-
/** @typedef {{ storeId: NonNullable<unknown> }} Cli_Init_Pull_FailedInputs */
|
|
6970
|
-
const ko_cli_init_pull_failed = (i) => {
|
|
6971
|
-
return `사이트는 만들었지만 소스를 받지 못했습니다. 다시 만들지 말고 npx sayren pull --project ${i?.storeId}로 받으십시오`;
|
|
6972
|
-
};
|
|
6973
|
-
/**
|
|
6974
|
-
|
|
6975
|
-
* @param {Cli_Init_Pull_FailedInputs} inputs
|
|
6976
|
-
* @param {{ locale?: "ko" }} options
|
|
6977
|
-
* @returns {LocalizedString}
|
|
6978
|
-
*/
|
|
6979
|
-
const cli_init_pull_failed = ((inputs, options = {}) => {
|
|
6980
|
-
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
6981
|
-
return ko_cli_init_pull_failed(inputs);
|
|
6982
|
-
});
|
|
6983
|
-
|
|
6984
|
-
//#endregion
|
|
6985
|
-
//#region src/paraglide/messages/cli_init_site_exists.js
|
|
6986
|
-
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
6987
|
-
/** @typedef {{ storeId: NonNullable<unknown> }} Cli_Init_Site_ExistsInputs */
|
|
6988
|
-
const ko_cli_init_site_exists = (i) => {
|
|
6989
|
-
return `이 상점에는 이미 호스팅 사이트가 있어 새로 만들지 않았습니다. npx sayren pull --project ${i?.storeId}로 소스를 받으십시오`;
|
|
6990
|
-
};
|
|
6991
|
-
/**
|
|
6992
|
-
|
|
6993
|
-
* @param {Cli_Init_Site_ExistsInputs} inputs
|
|
6994
|
-
* @param {{ locale?: "ko" }} options
|
|
6995
|
-
* @returns {LocalizedString}
|
|
6996
|
-
*/
|
|
6997
|
-
const cli_init_site_exists = ((inputs, options = {}) => {
|
|
6998
|
-
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
6999
|
-
return ko_cli_init_site_exists(inputs);
|
|
7000
|
-
});
|
|
7001
|
-
|
|
7002
|
-
//#endregion
|
|
7003
|
-
//#region src/paraglide/messages/cli_init_site_url.js
|
|
7004
|
-
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
7005
|
-
/** @typedef {{ url: NonNullable<unknown> }} Cli_Init_Site_UrlInputs */
|
|
7006
|
-
const ko_cli_init_site_url = (i) => {
|
|
7007
|
-
return `지금 사이트: ${i?.url}`;
|
|
7008
|
-
};
|
|
7009
|
-
/**
|
|
7010
|
-
|
|
7011
|
-
* @param {Cli_Init_Site_UrlInputs} inputs
|
|
7012
|
-
* @param {{ locale?: "ko" }} options
|
|
7013
|
-
* @returns {LocalizedString}
|
|
7014
|
-
*/
|
|
7015
|
-
const cli_init_site_url = ((inputs, options = {}) => {
|
|
7016
|
-
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
7017
|
-
return ko_cli_init_site_url(inputs);
|
|
7018
|
-
});
|
|
7019
|
-
|
|
7020
|
-
//#endregion
|
|
7021
|
-
//#region src/paraglide/messages/cli_init_slug_taken.js
|
|
7022
|
-
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
7023
|
-
/** @typedef {{}} Cli_Init_Slug_TakenInputs */
|
|
7024
|
-
const ko_cli_init_slug_taken = () => {
|
|
7025
|
-
return `상점 코드와 같은 주소를 다른 사이트가 쓰고 있어 만들지 못했습니다. 상점 플랫폼 › 스토어프론트에서 다른 주소로 만든 뒤 npx sayren pull로 받으십시오`;
|
|
7026
|
-
};
|
|
7027
|
-
/**
|
|
7028
|
-
|
|
7029
|
-
* @param {Cli_Init_Slug_TakenInputs} inputs
|
|
7030
|
-
* @param {{ locale?: "ko" }} options
|
|
7031
|
-
* @returns {LocalizedString}
|
|
7032
|
-
*/
|
|
7033
|
-
const cli_init_slug_taken = ((inputs = {}, options = {}) => {
|
|
7034
|
-
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
7035
|
-
return ko_cli_init_slug_taken(inputs);
|
|
7036
|
-
});
|
|
7037
|
-
|
|
7038
|
-
//#endregion
|
|
7039
|
-
//#region src/paraglide/messages/cli_init_summary.js
|
|
7040
|
-
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
7041
|
-
/** @typedef {{ storeId: NonNullable<unknown>, name: NonNullable<unknown>, templateId: NonNullable<unknown>, version: NonNullable<unknown> }} Cli_Init_SummaryInputs */
|
|
7042
|
-
const ko_cli_init_summary = (i) => {
|
|
7043
|
-
return `상점 ${i?.storeId}에 템플릿 ${i?.name}(${i?.templateId} v${i?.version})로 호스팅 사이트를 만듭니다. 주소는 상점 코드이고 오픈 준비 중으로 시작합니다. 만들기는 상점당 30일에 3번까지입니다`;
|
|
7044
|
-
};
|
|
7045
|
-
/**
|
|
7046
|
-
|
|
7047
|
-
* @param {Cli_Init_SummaryInputs} inputs
|
|
7048
|
-
* @param {{ locale?: "ko" }} options
|
|
7049
|
-
* @returns {LocalizedString}
|
|
7050
|
-
*/
|
|
7051
|
-
const cli_init_summary = ((inputs, options = {}) => {
|
|
7052
|
-
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
7053
|
-
return ko_cli_init_summary(inputs);
|
|
7054
|
-
});
|
|
7055
|
-
|
|
7056
|
-
//#endregion
|
|
7057
|
-
//#region src/paraglide/messages/cli_init_template_option.js
|
|
7058
|
-
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
7059
|
-
/** @typedef {{ templateId: NonNullable<unknown>, name: NonNullable<unknown>, version: NonNullable<unknown>, description: NonNullable<unknown> }} Cli_Init_Template_OptionInputs */
|
|
7060
|
-
const ko_cli_init_template_option = (i) => {
|
|
7061
|
-
return `${i?.templateId} — ${i?.name} v${i?.version}: ${i?.description}`;
|
|
7062
|
-
};
|
|
7063
|
-
/**
|
|
7064
|
-
|
|
7065
|
-
* @param {Cli_Init_Template_OptionInputs} inputs
|
|
7066
|
-
* @param {{ locale?: "ko" }} options
|
|
7067
|
-
* @returns {LocalizedString}
|
|
7068
|
-
*/
|
|
7069
|
-
const cli_init_template_option = ((inputs, options = {}) => {
|
|
7070
|
-
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
7071
|
-
return ko_cli_init_template_option(inputs);
|
|
7072
|
-
});
|
|
7073
|
-
|
|
7074
|
-
//#endregion
|
|
7075
|
-
//#region src/paraglide/messages/cli_init_template_prompt.js
|
|
7076
|
-
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
7077
|
-
/** @typedef {{}} Cli_Init_Template_PromptInputs */
|
|
7078
|
-
const ko_cli_init_template_prompt = () => {
|
|
7079
|
-
return `템플릿을 고르십시오:`;
|
|
7080
|
-
};
|
|
7081
|
-
/**
|
|
7082
|
-
|
|
7083
|
-
* @param {Cli_Init_Template_PromptInputs} inputs
|
|
7084
|
-
* @param {{ locale?: "ko" }} options
|
|
7085
|
-
* @returns {LocalizedString}
|
|
7086
|
-
*/
|
|
7087
|
-
const cli_init_template_prompt = ((inputs = {}, options = {}) => {
|
|
7088
|
-
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
7089
|
-
return ko_cli_init_template_prompt(inputs);
|
|
7090
|
-
});
|
|
7091
|
-
|
|
7092
|
-
//#endregion
|
|
7093
|
-
//#region src/paraglide/messages/cli_init_template_required.js
|
|
7094
|
-
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
7095
|
-
/** @typedef {{ list: NonNullable<unknown> }} Cli_Init_Template_RequiredInputs */
|
|
7096
|
-
const ko_cli_init_template_required = (i) => {
|
|
7097
|
-
return `템플릿을 고르지 않았습니다. --template <id>로 주십시오(비대화형은 필수입니다):
|
|
7098
|
-
${i?.list}`;
|
|
7099
|
-
};
|
|
7100
|
-
/**
|
|
7101
|
-
|
|
7102
|
-
* @param {Cli_Init_Template_RequiredInputs} inputs
|
|
7103
|
-
* @param {{ locale?: "ko" }} options
|
|
7104
|
-
* @returns {LocalizedString}
|
|
7105
|
-
*/
|
|
7106
|
-
const cli_init_template_required = ((inputs, options = {}) => {
|
|
7107
|
-
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
7108
|
-
return ko_cli_init_template_required(inputs);
|
|
7109
|
-
});
|
|
7110
|
-
|
|
7111
|
-
//#endregion
|
|
7112
|
-
//#region src/paraglide/messages/cli_init_template_unknown.js
|
|
7113
|
-
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
7114
|
-
/** @typedef {{ templateId: NonNullable<unknown>, ids: NonNullable<unknown> }} Cli_Init_Template_UnknownInputs */
|
|
7115
|
-
const ko_cli_init_template_unknown = (i) => {
|
|
7116
|
-
return `템플릿을 찾지 못했습니다: ${i?.templateId}. 쓸 수 있는 템플릿: ${i?.ids}`;
|
|
7117
|
-
};
|
|
7118
|
-
/**
|
|
7119
|
-
|
|
7120
|
-
* @param {Cli_Init_Template_UnknownInputs} inputs
|
|
7121
|
-
* @param {{ locale?: "ko" }} options
|
|
7122
|
-
* @returns {LocalizedString}
|
|
7123
|
-
*/
|
|
7124
|
-
const cli_init_template_unknown = ((inputs, options = {}) => {
|
|
7125
|
-
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
7126
|
-
return ko_cli_init_template_unknown(inputs);
|
|
7127
|
-
});
|
|
7128
|
-
|
|
7129
|
-
//#endregion
|
|
7130
|
-
//#region src/paraglide/messages/cli_init_yes_required.js
|
|
7131
|
-
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
7132
|
-
/** @typedef {{}} Cli_Init_Yes_RequiredInputs */
|
|
7133
|
-
const ko_cli_init_yes_required = () => {
|
|
7134
|
-
return `사이트 만들기를 확인할 수 없는 환경입니다. --yes를 함께 주십시오`;
|
|
7135
|
-
};
|
|
7136
|
-
/**
|
|
7137
|
-
|
|
7138
|
-
* @param {Cli_Init_Yes_RequiredInputs} inputs
|
|
7139
|
-
* @param {{ locale?: "ko" }} options
|
|
7140
|
-
* @returns {LocalizedString}
|
|
7141
|
-
*/
|
|
7142
|
-
const cli_init_yes_required = ((inputs = {}, options = {}) => {
|
|
7143
|
-
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
7144
|
-
return ko_cli_init_yes_required(inputs);
|
|
6873
|
+
return ko_cli_init_retired(inputs);
|
|
7145
6874
|
});
|
|
7146
6875
|
|
|
7147
6876
|
//#endregion
|
|
@@ -7327,11 +7056,11 @@ const cli_link_gitignore = ((inputs, options = {}) => {
|
|
|
7327
7056
|
//#endregion
|
|
7328
7057
|
//#region src/paraglide/messages/cli_link_next_steps.js
|
|
7329
7058
|
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
7330
|
-
/** @typedef {{}} Cli_Link_Next_StepsInputs */
|
|
7331
|
-
const ko_cli_link_next_steps = () => {
|
|
7059
|
+
/** @typedef {{ install: NonNullable<unknown>, dev: NonNullable<unknown> }} Cli_Link_Next_StepsInputs */
|
|
7060
|
+
const ko_cli_link_next_steps = (i) => {
|
|
7332
7061
|
return `다음:
|
|
7333
|
-
|
|
7334
|
-
|
|
7062
|
+
${i?.install} # 의존성의 설치 스크립트를 돌리지 않습니다
|
|
7063
|
+
${i?.dev} # http://localhost:4010 — 운영 상점 데이터로 동작합니다
|
|
7335
7064
|
npx sayren deploy # 빌드 → 버전 → 발행`;
|
|
7336
7065
|
};
|
|
7337
7066
|
/**
|
|
@@ -7340,7 +7069,7 @@ const ko_cli_link_next_steps = () => {
|
|
|
7340
7069
|
* @param {{ locale?: "ko" }} options
|
|
7341
7070
|
* @returns {LocalizedString}
|
|
7342
7071
|
*/
|
|
7343
|
-
const cli_link_next_steps = ((inputs
|
|
7072
|
+
const cli_link_next_steps = ((inputs, options = {}) => {
|
|
7344
7073
|
experimentalStaticLocale ?? options.locale ?? getLocale();
|
|
7345
7074
|
return ko_cli_link_next_steps(inputs);
|
|
7346
7075
|
});
|
|
@@ -8266,13 +7995,13 @@ const cli_pull_mcp_written = ((inputs, options = {}) => {
|
|
|
8266
7995
|
//#endregion
|
|
8267
7996
|
//#region src/paraglide/messages/cli_pull_next_steps.js
|
|
8268
7997
|
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
8269
|
-
/** @typedef {{ dir: NonNullable<unknown> }} Cli_Pull_Next_StepsInputs */
|
|
7998
|
+
/** @typedef {{ dir: NonNullable<unknown>, install: NonNullable<unknown>, dev: NonNullable<unknown> }} Cli_Pull_Next_StepsInputs */
|
|
8270
7999
|
const ko_cli_pull_next_steps = (i) => {
|
|
8271
8000
|
return `
|
|
8272
8001
|
다음:
|
|
8273
8002
|
cd ${i?.dir}
|
|
8274
|
-
|
|
8275
|
-
|
|
8003
|
+
${i?.install} # 의존성의 설치 스크립트를 돌리지 않습니다
|
|
8004
|
+
${i?.dev} # http://localhost:4010 — 운영 상점 데이터로 동작합니다
|
|
8276
8005
|
npx sayren deploy # 빌드 → 버전 → 발행`;
|
|
8277
8006
|
};
|
|
8278
8007
|
/**
|
|
@@ -8291,7 +8020,7 @@ const cli_pull_next_steps = ((inputs, options = {}) => {
|
|
|
8291
8020
|
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
8292
8021
|
/** @typedef {{}} Cli_Pull_No_SiteInputs */
|
|
8293
8022
|
const ko_cli_pull_no_site = () => {
|
|
8294
|
-
return `이 상점에는 호스팅 사이트가 없습니다. npx sayren
|
|
8023
|
+
return `이 상점에는 호스팅 사이트가 없습니다. npx sayren link로 만들거나 상점 플랫폼 › 스토어프론트에서 만든 뒤 다시 받으십시오`;
|
|
8295
8024
|
};
|
|
8296
8025
|
/**
|
|
8297
8026
|
|
|
@@ -8397,9 +8126,9 @@ const cli_pull_store_mismatch = ((inputs, options = {}) => {
|
|
|
8397
8126
|
//#endregion
|
|
8398
8127
|
//#region src/paraglide/messages/cli_pull_watched_changed.js
|
|
8399
8128
|
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
8400
|
-
/** @typedef {{ path: NonNullable<unknown> }} Cli_Pull_Watched_ChangedInputs */
|
|
8129
|
+
/** @typedef {{ path: NonNullable<unknown>, install: NonNullable<unknown> }} Cli_Pull_Watched_ChangedInputs */
|
|
8401
8130
|
const ko_cli_pull_watched_changed = (i) => {
|
|
8402
|
-
return `알림: 원격의 ${i?.path}가 이 폴더와 다릅니다. 설치 전에 내용을 확인하십시오(
|
|
8131
|
+
return `알림: 원격의 ${i?.path}가 이 폴더와 다릅니다. 설치 전에 내용을 확인하십시오(${i?.install} 권장)`;
|
|
8403
8132
|
};
|
|
8404
8133
|
/**
|
|
8405
8134
|
|
|
@@ -9373,7 +9102,6 @@ const ko_cli_usage = (i) => {
|
|
|
9373
9102
|
npx sayren create <이름> [--template <템플릿>] # 시작 코드를 새 폴더에 만듭니다(파일만, 로그인 없음)
|
|
9374
9103
|
npx sayren link [폴더] [--store <storeId>] # 폴더를 상점 사이트에 연결합니다(없으면 사이트를 만듭니다)
|
|
9375
9104
|
npx sayren env pull # 연결된 상점 값을 .env에 씁니다
|
|
9376
|
-
npx sayren init [폴더] [--template <id>] [--store <storeId>] [--yes]
|
|
9377
9105
|
npx sayren pull --project <storeId> [폴더] [--force [--yes]]
|
|
9378
9106
|
npx sayren deploy [--no-publish] [--skip-build] [--message <메모>] [--force [--yes]]
|
|
9379
9107
|
npx sayren status
|
|
@@ -9388,7 +9116,6 @@ const ko_cli_usage = (i) => {
|
|
|
9388
9116
|
create 시작 코드(상점 이름·상품 목록 홈, SDK·문구·분석·에이전트 안내)를 <이름> 폴더에 만듭니다. 상점을 묻지 않고 호스팅 사이트도 만들지 않습니다
|
|
9389
9117
|
link 상점을 고르고(--store → 토큰 범위 → 선택) 사이트가 없으면 만든 뒤 .sayren/project.json·.env·.mcp.json을 씁니다
|
|
9390
9118
|
env env pull: 연결된 상점의 SAYREN_STORE_CODE·SAYREN_API_URL을 .env에 씁니다
|
|
9391
|
-
init 템플릿을 골라 호스팅 사이트를 만들고 pull과 같은 폴더(기본: 상점 코드)로 받습니다. 사이트가 이미 있으면 만들지 않습니다
|
|
9392
9119
|
pull 호스팅 중인 사이트의 작업 트리를 폴더(기본: 상점 코드)로 받고 .mcp.json·.env·.sayren/project.json을 씁니다
|
|
9393
9120
|
deploy 로컬 검사 → 로컬 빌드 → 작업 트리 올리기 → 빌드 → 발행. 연결이 없으면 link부터 하고 다음 버전으로 교체합니다. 원격이 마지막 받기·올리기 이후 바뀌었으면 덮어쓰지 않습니다
|
|
9394
9121
|
status 사이트·발행 버전·최근 빌드·편집 환경
|
|
@@ -9404,12 +9131,11 @@ const ko_cli_usage = (i) => {
|
|
|
9404
9131
|
옵션:
|
|
9405
9132
|
--project <storeId> pull: 받을 상점(--store와 같습니다)
|
|
9406
9133
|
--template <템플릿> create: github:owner/repo[/경로][#ref](공개 GitHub 저장소) 또는 템플릿 id. 없으면 CLI에 든 시작 코드
|
|
9407
|
-
init: 호스팅 템플릿 id(비대화형은 필수)
|
|
9408
9134
|
--store-code <코드> create: 이 상점 코드로 .env를 씁니다(없으면 link·env pull이 씁니다)
|
|
9409
|
-
--dir <폴더> 작업 폴더(기본: 지금 폴더, pull
|
|
9135
|
+
--dir <폴더> 작업 폴더(기본: 지금 폴더, pull은 상점 코드)
|
|
9410
9136
|
--force pull: 같은 사이트를 받은 폴더에 원격을 다시 받습니다(지울·덮을 파일을 보여 주고 묻습니다)
|
|
9411
9137
|
deploy: 원격 변경·열린 편집 환경을 무시하고 덮어씁니다(확인을 묻습니다)
|
|
9412
|
-
--yes --force
|
|
9138
|
+
--yes --force의 확인을 묻지 않습니다(비대화형)
|
|
9413
9139
|
--no-publish deploy: 버전까지만 만들고 발행하지 않습니다
|
|
9414
9140
|
--skip-build deploy: 올리기 전 로컬 빌드(npm run build)를 건너뜁니다
|
|
9415
9141
|
--message <메모> deploy: 버전 메모
|
|
@@ -10344,7 +10070,7 @@ async function selectStore(auth, client, io, candidates, folderStore = null) {
|
|
|
10344
10070
|
|
|
10345
10071
|
//#endregion
|
|
10346
10072
|
//#region package.json
|
|
10347
|
-
var version = "0.
|
|
10073
|
+
var version = "0.16.0";
|
|
10348
10074
|
|
|
10349
10075
|
//#endregion
|
|
10350
10076
|
//#region src/client.ts
|
|
@@ -12222,7 +11948,7 @@ function isNeverUpload(path) {
|
|
|
12222
11948
|
return segments.some((segment) => segment.startsWith(".env") || segment === ".sayren" || segment === ".dev.vars" || segment.startsWith(".dev.vars.")) || name === ".mcp.json" || name === ".sayrenrc" || name === ".npmrc";
|
|
12223
11949
|
}
|
|
12224
11950
|
/** 걸어 들어가지 않는 폴더 — 설치물·산출물·캐시·VCS(경로 규칙이 어차피 막는다. 크기 때문에 읽지도 않는다) */
|
|
12225
|
-
const SKIP_DIRS
|
|
11951
|
+
const SKIP_DIRS = new Set([
|
|
12226
11952
|
"node_modules",
|
|
12227
11953
|
"dist",
|
|
12228
11954
|
".output",
|
|
@@ -12243,7 +11969,7 @@ function collectTree(root) {
|
|
|
12243
11969
|
const full = join(dir, entry.name);
|
|
12244
11970
|
const rel = normalizeStorefrontPath(relative(root, full).split(sep).join("/"));
|
|
12245
11971
|
if (entry.isDirectory()) {
|
|
12246
|
-
if (SKIP_DIRS
|
|
11972
|
+
if (SKIP_DIRS.has(entry.name)) continue;
|
|
12247
11973
|
walk(full);
|
|
12248
11974
|
continue;
|
|
12249
11975
|
}
|
|
@@ -12379,7 +12105,7 @@ function runLocalChecks(tree) {
|
|
|
12379
12105
|
if (packageJson && lock) {
|
|
12380
12106
|
const drift = lockDrift(packageJson, lock);
|
|
12381
12107
|
if (drift.length) warnings.push(cli_checks_lock_drift({ names: drift.slice(0, 5).join(", ") }));
|
|
12382
|
-
}
|
|
12108
|
+
}
|
|
12383
12109
|
return {
|
|
12384
12110
|
report: report$1,
|
|
12385
12111
|
blockingRules,
|
|
@@ -12454,7 +12180,8 @@ function lockImporterSpecifiers(lock) {
|
|
|
12454
12180
|
//#region src/guide-skill.ts
|
|
12455
12181
|
/**
|
|
12456
12182
|
* 받은 폴더의 에이전트 안내 스킬(2026-10-16 사용자 결정) — 셀러의 Claude Code가 기능·화면을 고치기 전에 sayren 중앙 스킬을 `npx sayren skill`로 읽게 한다(스킬은 이 하나만 설치한다).
|
|
12457
|
-
*
|
|
12183
|
+
* 이 파일이 원천이다 — `create`는 받은 트리에 늘 이 내용을 쓰고(시작 코드 저장소에는 두지 않는다), `pull`·`init`은 없을 때만 넣는다(`withGuideSkill`).
|
|
12184
|
+
* sayren.io 디스커버리(`apps/website/app/lib/agent-skills.ts`)가 같은 내용을 내준다(`agent-skills.test.ts`가 고정한다).
|
|
12458
12185
|
*/
|
|
12459
12186
|
const GUIDE_SKILL_PATH = ".claude/skills/sayren/SKILL.md";
|
|
12460
12187
|
const GUIDE_SKILL = "---\nname: sayren\ndescription: Load before adding, implementing or changing any feature or page of this sayren storefront. Lists the current sayren skills and loads the ones the task needs.\n---\n\n# sayren skills\n\nThe sayren skills are maintained centrally and change without updating this project.\nDo not rely on memory or earlier copies. Load them at the start of each task.\n\n1. List the skills (name and when to use each):\n `npx -y sayren@latest skill list`\n2. Read every skill that matches the task, in full, and follow it:\n `npx -y sayren@latest skill <name>`\n\nIf the sayren MCP server is connected, the tools `list_skills` and `get_skill` return the same content.\n\nFollow the project's `CLAUDE.md` first. The skills add the sayren-specific details.\n";
|
|
@@ -12517,6 +12244,60 @@ function tailOf(output, lines = OUTPUT_TAIL_LINES) {
|
|
|
12517
12244
|
return output.trimEnd().split(/\r?\n/).slice(-lines).join("\n");
|
|
12518
12245
|
}
|
|
12519
12246
|
|
|
12247
|
+
//#endregion
|
|
12248
|
+
//#region src/package-manager.ts
|
|
12249
|
+
const KNOWN = [
|
|
12250
|
+
"npm",
|
|
12251
|
+
"pnpm",
|
|
12252
|
+
"yarn",
|
|
12253
|
+
"bun"
|
|
12254
|
+
];
|
|
12255
|
+
const LOCKFILES = [
|
|
12256
|
+
["pnpm-lock.yaml", "pnpm"],
|
|
12257
|
+
["yarn.lock", "yarn"],
|
|
12258
|
+
["bun.lock", "bun"],
|
|
12259
|
+
["bun.lockb", "bun"],
|
|
12260
|
+
["package-lock.json", "npm"]
|
|
12261
|
+
];
|
|
12262
|
+
/** `has(path)`는 그 파일이 있는지, `read(path)`는 텍스트(없으면 null)다 — 받은 트리(Map)와 디스크 폴더가 같은 판정을 쓴다 */
|
|
12263
|
+
function packageManagerOf(source) {
|
|
12264
|
+
const pkg = source.read("package.json");
|
|
12265
|
+
if (pkg) try {
|
|
12266
|
+
const field = JSON.parse(pkg).packageManager;
|
|
12267
|
+
const name = typeof field === "string" ? field.split("@")[0]?.trim() : void 0;
|
|
12268
|
+
if (name && KNOWN.includes(name)) return name;
|
|
12269
|
+
} catch {}
|
|
12270
|
+
for (const [file, manager] of LOCKFILES) if (source.has(file)) return manager;
|
|
12271
|
+
return "npm";
|
|
12272
|
+
}
|
|
12273
|
+
/** 받은 트리(경로 → 내용) */
|
|
12274
|
+
function packageManagerOfFiles(files) {
|
|
12275
|
+
return packageManagerOf({
|
|
12276
|
+
has: (path) => files.has(path),
|
|
12277
|
+
read: (path) => {
|
|
12278
|
+
const bytes = files.get(path);
|
|
12279
|
+
return bytes ? new TextDecoder().decode(bytes) : null;
|
|
12280
|
+
}
|
|
12281
|
+
});
|
|
12282
|
+
}
|
|
12283
|
+
/** 디스크 폴더 */
|
|
12284
|
+
function packageManagerOfDir(dir) {
|
|
12285
|
+
return packageManagerOf({
|
|
12286
|
+
has: (path) => existsSync(join(dir, path)),
|
|
12287
|
+
read: (path) => {
|
|
12288
|
+
try {
|
|
12289
|
+
return readFileSync(join(dir, path), "utf8");
|
|
12290
|
+
} catch {
|
|
12291
|
+
return null;
|
|
12292
|
+
}
|
|
12293
|
+
}
|
|
12294
|
+
});
|
|
12295
|
+
}
|
|
12296
|
+
/** 설치 스크립트를 돌리지 않는 설치 명령 */
|
|
12297
|
+
const installCommand = (manager) => `${manager} install --ignore-scripts`;
|
|
12298
|
+
/** 개발 서버 명령 — npm·bun은 `run`이 있어야 스크립트를 부른다 */
|
|
12299
|
+
const devCommand = (manager) => manager === "npm" || manager === "bun" ? `${manager} run dev` : `${manager} dev`;
|
|
12300
|
+
|
|
12520
12301
|
//#endregion
|
|
12521
12302
|
//#region src/commands.ts
|
|
12522
12303
|
/** 종료 코드 — 0 성공 · 1 실패 · 3 발행이 승인 대기(에이전트 토큰) */
|
|
@@ -12638,12 +12419,16 @@ async function receiveSource(client, auth, source, flags, io, migratedDir) {
|
|
|
12638
12419
|
if (sha256Hex(tgz) !== source.archive.sha256) throw new CliError(cli_pull_archive_corrupt());
|
|
12639
12420
|
const files = await unpackArchive(tgz);
|
|
12640
12421
|
withGuideSkill(files);
|
|
12422
|
+
const manager = packageManagerOfFiles(files);
|
|
12641
12423
|
const collisions = caseCollisions(files.keys());
|
|
12642
12424
|
if (collisions.length > 0) throw new CliError(cli_pull_case_collisions({ groups: collisions.map((group) => group.join(" · ")).join(", ") }));
|
|
12643
12425
|
const diff = diffLocal(target, files);
|
|
12644
12426
|
if (existing.length > 0) {
|
|
12645
12427
|
const watched = diff.overwrite.filter((path) => path === "package.json" || path === "vite.config.ts");
|
|
12646
|
-
for (const path of watched) io.out(cli_pull_watched_changed({
|
|
12428
|
+
for (const path of watched) io.out(cli_pull_watched_changed({
|
|
12429
|
+
path,
|
|
12430
|
+
install: installCommand(manager)
|
|
12431
|
+
}));
|
|
12647
12432
|
if (diff.remove.length + diff.overwrite.length > 0) {
|
|
12648
12433
|
io.out(cli_pull_replace_summary({
|
|
12649
12434
|
remove: diff.remove.length,
|
|
@@ -12706,81 +12491,19 @@ async function receiveSource(client, auth, source, flags, io, migratedDir) {
|
|
|
12706
12491
|
siteId: source.siteId
|
|
12707
12492
|
}));
|
|
12708
12493
|
if (source.editSessionOpen) io.out(cli_pull_edit_session_open());
|
|
12709
|
-
io.out(cli_pull_next_steps({
|
|
12494
|
+
io.out(cli_pull_next_steps({
|
|
12495
|
+
dir: pulledDir,
|
|
12496
|
+
install: installCommand(manager),
|
|
12497
|
+
dev: devCommand(manager)
|
|
12498
|
+
}));
|
|
12710
12499
|
return 0;
|
|
12711
12500
|
}
|
|
12712
12501
|
/**
|
|
12713
|
-
* `sayren init
|
|
12714
|
-
*
|
|
12715
|
-
* 토큰은 `storefront:rw`가 있어야 한다(로그인 토큰 `CLI_LOGIN_SCOPE`에 있다). 에이전트 토큰이어도 만들기는 승인 대상이 아니다
|
|
12716
|
-
* (쓰기 정책 표에 없다 — 오픈 준비 중으로 시작해 구매자 화면을 바꾸지 않는다).
|
|
12502
|
+
* `sayren init`(#101)은 템플릿을 골라 호스팅 사이트를 만들던 명령이다. 템플릿 사이트를 만들지 않으므로(#315 2차, 공개 API 템플릿 삭제)
|
|
12503
|
+
* 사이트를 만들지 않고 시작 경로(`create` → `link`)를 안내하고 끝낸다
|
|
12717
12504
|
*/
|
|
12718
|
-
|
|
12719
|
-
|
|
12720
|
-
if (target && existsSync(target) && readdirSync(target).length > 0) throw new CliError(cli_init_dir_not_empty({ dir: relativeOf(io, target) }));
|
|
12721
|
-
if (!target && isPulledDir(io.cwd)) throw new CliError(cli_init_inside_pulled());
|
|
12722
|
-
const authDir = target && existsSync(target) ? target : io.cwd;
|
|
12723
|
-
const { auth, client } = await apiFor(flags, authDir, null, io);
|
|
12724
|
-
const storeId = auth.storeId ?? "<storeId>";
|
|
12725
|
-
const hosting = await client.storefront.get();
|
|
12726
|
-
if (hosting.site) {
|
|
12727
|
-
io.out(cli_init_site_url({ url: hosting.site.url }));
|
|
12728
|
-
throw new CliError(cli_init_site_exists({ storeId }));
|
|
12729
|
-
}
|
|
12730
|
-
if (!hosting.editingEnabled) throw new CliError(cli_pull_editing_disabled());
|
|
12731
|
-
const template = await pickTemplate(await client.storefront.listTemplates(), flags.template, io);
|
|
12732
|
-
io.out(cli_init_summary({
|
|
12733
|
-
name: template.name,
|
|
12734
|
-
templateId: template.templateId,
|
|
12735
|
-
version: template.version,
|
|
12736
|
-
storeId
|
|
12737
|
-
}));
|
|
12738
|
-
if (!flags.yes) {
|
|
12739
|
-
if (!io.confirm) throw new CliError(cli_init_yes_required());
|
|
12740
|
-
if (!await io.confirm(cli_init_confirm())) {
|
|
12741
|
-
io.out(cli_cancelled());
|
|
12742
|
-
return 1;
|
|
12743
|
-
}
|
|
12744
|
-
}
|
|
12745
|
-
let site;
|
|
12746
|
-
try {
|
|
12747
|
-
site = await client.storefront.create({ templateId: template.templateId });
|
|
12748
|
-
} catch (error) {
|
|
12749
|
-
const code = codeOf(error);
|
|
12750
|
-
if (code === "STOREFRONT_SITE_EXISTS") throw new CliError(cli_init_site_exists({ storeId }));
|
|
12751
|
-
if (code === "STOREFRONT_SLUG_TAKEN") throw new CliError(cli_init_slug_taken());
|
|
12752
|
-
throw error;
|
|
12753
|
-
}
|
|
12754
|
-
io.out(cli_init_created({ url: site.url }));
|
|
12755
|
-
try {
|
|
12756
|
-
return await receiveSource(client, auth, await client.storefront.getSource(), { dir: flags.dir }, io, authDir);
|
|
12757
|
-
} catch (error) {
|
|
12758
|
-
io.err(cli_init_pull_failed({ storeId }));
|
|
12759
|
-
throw error;
|
|
12760
|
-
}
|
|
12761
|
-
}
|
|
12762
|
-
/** `--template`이 있으면 그 템플릿, 없으면 대화형 선택. 비대화형이면 `--template`이 있어야 한다 */
|
|
12763
|
-
async function pickTemplate(templates, wanted, io) {
|
|
12764
|
-
if (templates.length === 0) throw new CliError(cli_init_no_templates());
|
|
12765
|
-
const ids = templates.map((t) => t.templateId).join(", ");
|
|
12766
|
-
if (wanted) {
|
|
12767
|
-
const found = templates.find((t) => t.templateId === wanted);
|
|
12768
|
-
if (!found) throw new CliError(cli_init_template_unknown({
|
|
12769
|
-
templateId: wanted,
|
|
12770
|
-
ids
|
|
12771
|
-
}));
|
|
12772
|
-
return found;
|
|
12773
|
-
}
|
|
12774
|
-
const labels = templates.map((t) => cli_init_template_option({
|
|
12775
|
-
templateId: t.templateId,
|
|
12776
|
-
name: t.name,
|
|
12777
|
-
version: t.version,
|
|
12778
|
-
description: t.description
|
|
12779
|
-
}));
|
|
12780
|
-
const picked = io.select ? await io.select(cli_init_template_prompt(), labels) : null;
|
|
12781
|
-
const index = picked ? labels.indexOf(picked) : -1;
|
|
12782
|
-
if (index < 0) throw new CliError(cli_init_template_required({ list: labels.map((label) => ` ${label}`).join("\n") }));
|
|
12783
|
-
return templates[index];
|
|
12505
|
+
function init() {
|
|
12506
|
+
throw new CliError(cli_init_retired());
|
|
12784
12507
|
}
|
|
12785
12508
|
/**
|
|
12786
12509
|
* `sayren link [폴더]`(#315 C6) — 폴더를 상점의 호스팅 사이트에 연결한다. 상점은 `--store` → 토큰 범위 → 대화형 선택이고, 사이트가 없으면
|
|
@@ -12792,7 +12515,11 @@ async function link(flags, io) {
|
|
|
12792
12515
|
if (!existsSync(dir)) throw new CliError(cli_link_dir_missing({ dir: relativeOf(io, dir) }));
|
|
12793
12516
|
migrateLegacy(dir, io.out);
|
|
12794
12517
|
await linkDir(flags, dir, io);
|
|
12795
|
-
|
|
12518
|
+
const manager = packageManagerOfDir(dir);
|
|
12519
|
+
io.out(cli_link_next_steps({
|
|
12520
|
+
install: installCommand(manager),
|
|
12521
|
+
dev: devCommand(manager)
|
|
12522
|
+
}));
|
|
12796
12523
|
return 0;
|
|
12797
12524
|
}
|
|
12798
12525
|
/** link 본체 — `deploy`도 연결이 없으면 이것부터 부른다 */
|
|
@@ -13041,7 +12768,7 @@ async function localBuild(dir, skip, io) {
|
|
|
13041
12768
|
return;
|
|
13042
12769
|
}
|
|
13043
12770
|
if (plan.kind === "no-deps") {
|
|
13044
|
-
io.out(cli_deploy_build_local_no_deps());
|
|
12771
|
+
io.out(cli_deploy_build_local_no_deps({ install: installCommand(packageManagerOfDir(dir)) }));
|
|
13045
12772
|
return;
|
|
13046
12773
|
}
|
|
13047
12774
|
io.out(cli_deploy_build_local_running());
|
|
@@ -13390,9 +13117,10 @@ var StarterTransformError = class extends Error {
|
|
|
13390
13117
|
this.code = code;
|
|
13391
13118
|
}
|
|
13392
13119
|
};
|
|
13393
|
-
/** 새 프로젝트로 옮기지 않는 루트 경로인가 — 로컬 env·CLI 연결
|
|
13120
|
+
/** 새 프로젝트로 옮기지 않는 루트 경로인가 — 로컬 env·CLI 연결 정보·원본 저장소의 CI */
|
|
13394
13121
|
function isStarterLocalOnly(path) {
|
|
13395
13122
|
if (path === ".sayren" || path.startsWith(".sayren/")) return true;
|
|
13123
|
+
if (path === ".github" || path.startsWith(".github/")) return true;
|
|
13396
13124
|
if (path.includes("/")) return false;
|
|
13397
13125
|
return (path === ".env" || path.startsWith(".env.")) && path !== ".env.example";
|
|
13398
13126
|
}
|
|
@@ -13431,140 +13159,45 @@ function withPackageName(bytes, name, fields = {}) {
|
|
|
13431
13159
|
return new TextEncoder().encode(`${JSON.stringify(next, null, 2)}\n`);
|
|
13432
13160
|
}
|
|
13433
13161
|
|
|
13434
|
-
//#endregion
|
|
13435
|
-
//#region ../mcp/src/template-package.ts
|
|
13436
|
-
/** package.json의 기준 템플릿 표식 필드 — 원천은 이 함수다(api `template-marker.ts`가 같은 모양을 읽는다) */
|
|
13437
|
-
function withTemplateMarker(pkg, marker) {
|
|
13438
|
-
const current = pkg.sayren;
|
|
13439
|
-
pkg.sayren = {
|
|
13440
|
-
...current && typeof current === "object" && !Array.isArray(current) ? current : {},
|
|
13441
|
-
template: marker.id,
|
|
13442
|
-
templateVersion: marker.version
|
|
13443
|
-
};
|
|
13444
|
-
return pkg;
|
|
13445
|
-
}
|
|
13446
|
-
const DEP_FIELDS = [
|
|
13447
|
-
"dependencies",
|
|
13448
|
-
"devDependencies",
|
|
13449
|
-
"peerDependencies"
|
|
13450
|
-
];
|
|
13451
|
-
function renderTemplatePackageJson(raw, meta, options = {}) {
|
|
13452
|
-
const pkg = JSON.parse(raw);
|
|
13453
|
-
for (const field of DEP_FIELDS) {
|
|
13454
|
-
const deps = pkg[field];
|
|
13455
|
-
if (!deps) continue;
|
|
13456
|
-
for (const [name, spec] of Object.entries(deps)) deps[name] = resolveSpec(name, spec, meta);
|
|
13457
|
-
}
|
|
13458
|
-
if (options.name) pkg.name = options.name;
|
|
13459
|
-
const marker = options.template ?? meta.template;
|
|
13460
|
-
if (marker) withTemplateMarker(pkg, marker);
|
|
13461
|
-
return `${JSON.stringify(pkg, null, 2)}\n`;
|
|
13462
|
-
}
|
|
13463
|
-
function resolveSpec(name, spec, meta) {
|
|
13464
|
-
if (spec === "catalog:" || spec === "catalog:default") {
|
|
13465
|
-
const version$1 = meta.catalog[name];
|
|
13466
|
-
if (!version$1) throw new Error(mcp_template_catalog_version_missing({ name }));
|
|
13467
|
-
return version$1;
|
|
13468
|
-
}
|
|
13469
|
-
if (spec.startsWith("workspace:")) return workspaceRange(name, spec.slice(10), meta);
|
|
13470
|
-
return spec;
|
|
13471
|
-
}
|
|
13472
|
-
/**
|
|
13473
|
-
* `workspace:` 뒤 표기 → 셀러 프로젝트의 범위(#232). 템플릿은 SDK를 범위(`workspace:^0.35.0`)로 적고 `workspace:`만 뗀다 —
|
|
13474
|
-
* SDK patch가 올라도 풀어 쓴 package.json·첫 작업 트리가 그대로라 템플릿 버전을 올리지 않는다. 범위가 아닌 `*`·`^`·`~`만
|
|
13475
|
-
* 지금 워크스페이스 버전으로 푼다(`*`는 `^{버전}`)
|
|
13476
|
-
*/
|
|
13477
|
-
function workspaceRange(name, rest, meta) {
|
|
13478
|
-
if (rest !== "*" && rest !== "^" && rest !== "~" && rest !== "") return rest;
|
|
13479
|
-
const version$1 = meta.versions[name];
|
|
13480
|
-
if (!version$1) throw new Error(mcp_template_published_version_unknown({ name }));
|
|
13481
|
-
return `${rest === "~" ? "~" : "^"}${version$1}`;
|
|
13482
|
-
}
|
|
13483
|
-
/** pnpm-workspace.yaml의 최상위 `catalog:` 블록만 읽는다(` key: value`, 따옴표 허용) */
|
|
13484
|
-
function parseCatalog(yaml) {
|
|
13485
|
-
const out = {};
|
|
13486
|
-
let inCatalog = false;
|
|
13487
|
-
for (const line of yaml.split("\n")) {
|
|
13488
|
-
if (/^catalog:\s*$/.test(line)) {
|
|
13489
|
-
inCatalog = true;
|
|
13490
|
-
continue;
|
|
13491
|
-
}
|
|
13492
|
-
if (!inCatalog) continue;
|
|
13493
|
-
if (/^\S/.test(line)) break;
|
|
13494
|
-
const match = line.match(/^\s+["']?([^"':]+)["']?\s*:\s*["']?([^"'#\s]+)["']?/);
|
|
13495
|
-
if (match?.[1] && match[2]) out[match[1].trim()] = match[2];
|
|
13496
|
-
}
|
|
13497
|
-
return out;
|
|
13498
|
-
}
|
|
13499
|
-
function readWorkspaceVersions(packagesDir) {
|
|
13500
|
-
const out = {};
|
|
13501
|
-
for (const entry of readdirSync(packagesDir, { withFileTypes: true })) {
|
|
13502
|
-
if (!entry.isDirectory()) continue;
|
|
13503
|
-
const file = join(packagesDir, entry.name, "package.json");
|
|
13504
|
-
if (!existsSync(file)) continue;
|
|
13505
|
-
const pkg = JSON.parse(readFileSync(file, "utf8"));
|
|
13506
|
-
if (pkg.name && pkg.version) out[pkg.name] = pkg.version;
|
|
13507
|
-
}
|
|
13508
|
-
return out;
|
|
13509
|
-
}
|
|
13510
|
-
|
|
13511
13162
|
//#endregion
|
|
13512
13163
|
//#region src/create-command.ts
|
|
13513
13164
|
/**
|
|
13514
13165
|
* `npx sayren create <이름> [--template <템플릿>]`(#271, #315 C7) — 시작 코드를 새 폴더에 쓴다. 파일만 만들고 상점을 묻지 않는다.
|
|
13515
13166
|
* 상점 연결은 `sayren link`(사이트·`.sayren/project.json`)와 `sayren env pull`(`.env`)이 한다. `--store-code`를 주면 그 값으로 `.env`만 쓴다.
|
|
13516
13167
|
*
|
|
13517
|
-
* 템플릿: 없으면
|
|
13518
|
-
*
|
|
13168
|
+
* 템플릿: 없으면 시작 코드 공개 저장소(`avarcorp/sayren-starter`)의 최신 릴리스 태그, `github:owner/repo[/경로][#ref]`는 그 저장소다.
|
|
13169
|
+
* 둘 다 codeload tarball로 받는다(CLI에 시작 코드를 묶지 않는다 — 네트워크가 필요하다). 그 밖의 `<id>`는 sayren 레지스트리 자리다
|
|
13170
|
+
* (마켓 전까지 늘 「템플릿을 찾을 수 없습니다」).
|
|
13171
|
+
*
|
|
13172
|
+
* 받은 소스는 변환 함수 하나(`starter-transform.ts`, 서버와 공유)를 지난다. 변환(`package.json` `name`·`private`, `_gitignore` → `.gitignore`,
|
|
13173
|
+
* 로컬 전용 파일 빼기)은 **고정 계약이다**: 이미 설치된 옛 CLI도 늘 최신 시작 코드를 받으므로 시작 코드 저장소는 이 변환만 믿고 쓰고,
|
|
13174
|
+
* CLI는 변환을 바꾸거나 새 전제를 더하지 않는다. 안내 스킬(`.claude/skills/sayren/SKILL.md`)은 시작 코드 저장소에 두지 않고 CLI가 써 넣는다.
|
|
13519
13175
|
*/
|
|
13520
|
-
/**
|
|
13521
|
-
|
|
13522
|
-
|
|
13523
|
-
|
|
13524
|
-
|
|
13525
|
-
if (!found) throw new Error(`boilerplate not found: ${candidates.join(", ")}`);
|
|
13526
|
-
return found;
|
|
13527
|
-
}
|
|
13528
|
-
/** 싣지 않는 것 — 설치물·산출물. 점 파일은 에이전트 안내(`.claude/`·`.mcp.json`)와 `.gitignore`만(scripts/starter-bundle.mjs와 같다) */
|
|
13529
|
-
const SKIP_DIRS = new Set([
|
|
13530
|
-
"node_modules",
|
|
13531
|
-
"dist",
|
|
13532
|
-
".output",
|
|
13533
|
-
".tanstack",
|
|
13534
|
-
".nitro",
|
|
13535
|
-
".wrangler"
|
|
13536
|
-
]);
|
|
13537
|
-
const DOT_KEPT = new Set([
|
|
13538
|
-
".claude",
|
|
13539
|
-
".mcp.json",
|
|
13540
|
-
".gitignore"
|
|
13541
|
-
]);
|
|
13176
|
+
/** 기본 시작 코드 — 공개 저장소. 릴리스(태그 v*)는 그 저장소 Actions의 검사를 통과해야 생긴다 */
|
|
13177
|
+
const STARTER_REPO = {
|
|
13178
|
+
owner: "avarcorp",
|
|
13179
|
+
repo: "sayren-starter"
|
|
13180
|
+
};
|
|
13542
13181
|
/**
|
|
13543
|
-
*
|
|
13544
|
-
*
|
|
13182
|
+
* 기본 시작 코드의 최신 릴리스 태그 — `releases/latest`가 302로 가리키는 `/releases/tag/{태그}`에서 읽는다(GitHub API rate limit을 쓰지 않는다).
|
|
13183
|
+
* 릴리스가 없으면 GitHub은 `/releases`로 보내거나 404다
|
|
13545
13184
|
*/
|
|
13546
|
-
function
|
|
13547
|
-
const
|
|
13548
|
-
|
|
13549
|
-
|
|
13550
|
-
|
|
13551
|
-
|
|
13552
|
-
|
|
13553
|
-
|
|
13554
|
-
|
|
13555
|
-
|
|
13556
|
-
};
|
|
13557
|
-
walk(root);
|
|
13558
|
-
const repo = join(root, "..", "..", "..");
|
|
13559
|
-
const pkg = files.get("package.json");
|
|
13560
|
-
if (pkg && existsSync(join(repo, "pnpm-workspace.yaml"))) {
|
|
13561
|
-
const meta = {
|
|
13562
|
-
catalog: parseCatalog(readFileSync(join(repo, "pnpm-workspace.yaml"), "utf8")),
|
|
13563
|
-
versions: readWorkspaceVersions(join(repo, "packages"))
|
|
13564
|
-
};
|
|
13565
|
-
files.set("package.json", Buffer.from(renderTemplatePackageJson(Buffer.from(pkg).toString("utf8"), meta)));
|
|
13185
|
+
async function latestStarterTag(io) {
|
|
13186
|
+
const url = `https://github.com/${STARTER_REPO.owner}/${STARTER_REPO.repo}/releases/latest`;
|
|
13187
|
+
let res;
|
|
13188
|
+
try {
|
|
13189
|
+
res = await io.fetch(url, {
|
|
13190
|
+
method: "HEAD",
|
|
13191
|
+
redirect: "manual"
|
|
13192
|
+
});
|
|
13193
|
+
} catch {
|
|
13194
|
+
throw new CliError(cli_create_starter_unreachable());
|
|
13566
13195
|
}
|
|
13567
|
-
|
|
13196
|
+
const location = res.status >= 300 && res.status < 400 ? res.headers.get("location") : null;
|
|
13197
|
+
const tag = location ? /\/releases\/tag\/([^/?#]+)$/.exec(new URL(location, url).pathname)?.[1] : void 0;
|
|
13198
|
+
const decoded = tag ? decodeURIComponent(tag) : "";
|
|
13199
|
+
if (!GIT_REF.test(decoded) || decoded.includes("..")) throw new CliError(cli_create_starter_no_release({ status: String(res.status) }));
|
|
13200
|
+
return decoded;
|
|
13568
13201
|
}
|
|
13569
13202
|
const GITHUB_OWNER = /^[A-Za-z0-9](?:[A-Za-z0-9-]{0,38})$/;
|
|
13570
13203
|
const GITHUB_REPO = /^[A-Za-z0-9._-]{1,100}$/;
|
|
@@ -13573,7 +13206,7 @@ const GIT_REF = /^[A-Za-z0-9._/+-]{1,255}$/;
|
|
|
13573
13206
|
/** `--template` 값 → 받을 곳. 형식이 틀리면 api·네트워크를 부르기 전에 멈춘다 */
|
|
13574
13207
|
function parseTemplateSpec(value) {
|
|
13575
13208
|
const raw = value?.trim();
|
|
13576
|
-
if (!raw) return { kind: "
|
|
13209
|
+
if (!raw) return { kind: "starter" };
|
|
13577
13210
|
if (!raw.startsWith("github:")) return {
|
|
13578
13211
|
kind: "registry",
|
|
13579
13212
|
id: raw
|
|
@@ -13645,7 +13278,17 @@ async function create(flags, io) {
|
|
|
13645
13278
|
if (storeCode !== void 0 && !STORE_CODE_PATTERN.test(storeCode)) throw new CliError(cli_create_store_code_invalid({ storeCode }));
|
|
13646
13279
|
const spec = parseTemplateSpec(flags.template);
|
|
13647
13280
|
if (spec.kind === "registry") throw new CliError(cli_create_template_not_found({ template: spec.id }));
|
|
13648
|
-
|
|
13281
|
+
let source;
|
|
13282
|
+
if (spec.kind === "github") source = await githubTemplateFiles(spec, flags.template?.trim() ?? "", io);
|
|
13283
|
+
else {
|
|
13284
|
+
const ref = await latestStarterTag(io);
|
|
13285
|
+
source = await githubTemplateFiles({
|
|
13286
|
+
kind: "github",
|
|
13287
|
+
...STARTER_REPO,
|
|
13288
|
+
path: "",
|
|
13289
|
+
ref
|
|
13290
|
+
}, `github:${STARTER_REPO.owner}/${STARTER_REPO.repo}#${ref}`, io);
|
|
13291
|
+
}
|
|
13649
13292
|
let files;
|
|
13650
13293
|
try {
|
|
13651
13294
|
files = transformStarterFiles(source, { name });
|
|
@@ -13653,7 +13296,13 @@ async function create(flags, io) {
|
|
|
13653
13296
|
if (error instanceof StarterTransformError) throw new CliError(cli_create_template_no_package_json({ reason: error.message }));
|
|
13654
13297
|
throw error;
|
|
13655
13298
|
}
|
|
13299
|
+
files.set(GUIDE_SKILL_PATH, new TextEncoder().encode(GUIDE_SKILL));
|
|
13656
13300
|
writeTree(target, files);
|
|
13301
|
+
const manager = packageManagerOfFiles(files);
|
|
13302
|
+
const steps = {
|
|
13303
|
+
install: installCommand(manager),
|
|
13304
|
+
dev: devCommand(manager)
|
|
13305
|
+
};
|
|
13657
13306
|
if (storeCode) {
|
|
13658
13307
|
const { apiOrigin } = resolveApiOrigin(flags, target, null, io.env);
|
|
13659
13308
|
updateEnvFile(target, {
|
|
@@ -13663,11 +13312,13 @@ async function create(flags, io) {
|
|
|
13663
13312
|
io.out(cli_create_done_store_code({
|
|
13664
13313
|
dir: name,
|
|
13665
13314
|
count: files.size,
|
|
13666
|
-
storeCode
|
|
13315
|
+
storeCode,
|
|
13316
|
+
...steps
|
|
13667
13317
|
}));
|
|
13668
13318
|
} else io.out(cli_create_done({
|
|
13669
13319
|
dir: name,
|
|
13670
|
-
count: files.size
|
|
13320
|
+
count: files.size,
|
|
13321
|
+
...steps
|
|
13671
13322
|
}));
|
|
13672
13323
|
return 0;
|
|
13673
13324
|
}
|
|
@@ -13826,11 +13477,7 @@ async function main(argv, io) {
|
|
|
13826
13477
|
...common,
|
|
13827
13478
|
dir: str(parsed.flags.dir) ?? parsed.positional[1]
|
|
13828
13479
|
}, io);
|
|
13829
|
-
case "init": return init(
|
|
13830
|
-
...common,
|
|
13831
|
-
template: str(parsed.flags.template),
|
|
13832
|
-
yes: parsed.flags.yes === true
|
|
13833
|
-
}, io);
|
|
13480
|
+
case "init": return init();
|
|
13834
13481
|
case "pull": return pull({
|
|
13835
13482
|
...common,
|
|
13836
13483
|
project: str(parsed.flags.project),
|