sayren 0.9.0 → 0.10.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 +39 -114
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -2261,84 +2261,6 @@ const mcp_rule_payment_browser_launch_why = ((inputs = {}, options = {}) => {
|
|
|
2261
2261
|
return ko_mcp_rule_payment_browser_launch_why(inputs);
|
|
2262
2262
|
});
|
|
2263
2263
|
|
|
2264
|
-
//#endregion
|
|
2265
|
-
//#region ../mcp/src/paraglide/messages/mcp_rule_payment_popup_prepare_example.js
|
|
2266
|
-
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
2267
|
-
/** @typedef {{}} Mcp_Rule_Payment_Popup_Prepare_ExampleInputs */
|
|
2268
|
-
const ko_mcp_rule_payment_popup_prepare_example = () => {
|
|
2269
|
-
return `const paymentWindow = payments.prepareWindow(); // 클릭 시점에 먼저 연다
|
|
2270
|
-
const { start, error } = await startPayment({ data });
|
|
2271
|
-
if (!start) {
|
|
2272
|
-
paymentWindow.close();
|
|
2273
|
-
return;
|
|
2274
|
-
}
|
|
2275
|
-
await payments.open(parsed, { window: paymentWindow });`;
|
|
2276
|
-
};
|
|
2277
|
-
/**
|
|
2278
|
-
|
|
2279
|
-
* @param {Mcp_Rule_Payment_Popup_Prepare_ExampleInputs} inputs
|
|
2280
|
-
* @param {{ locale?: "ko" }} options
|
|
2281
|
-
* @returns {LocalizedString}
|
|
2282
|
-
*/
|
|
2283
|
-
const mcp_rule_payment_popup_prepare_example = ((inputs = {}, options = {}) => {
|
|
2284
|
-
experimentalStaticLocale$1 ?? options.locale ?? getLocale$1();
|
|
2285
|
-
return ko_mcp_rule_payment_popup_prepare_example(inputs);
|
|
2286
|
-
});
|
|
2287
|
-
|
|
2288
|
-
//#endregion
|
|
2289
|
-
//#region ../mcp/src/paraglide/messages/mcp_rule_payment_popup_prepare_fix.js
|
|
2290
|
-
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
2291
|
-
/** @typedef {{}} Mcp_Rule_Payment_Popup_Prepare_FixInputs */
|
|
2292
|
-
const ko_mcp_rule_payment_popup_prepare_fix = () => {
|
|
2293
|
-
return `클릭 핸들러 첫 줄에서 \`payments.prepareWindow()\`로 빈 창을 열고, 서버 함수가 끝나면 그 핸들을 \`payments.open(start, { window })\`에 넘긴다. 결제 시작이 실패하면 \`window.close()\`로 닫는다`;
|
|
2294
|
-
};
|
|
2295
|
-
/**
|
|
2296
|
-
|
|
2297
|
-
* @param {Mcp_Rule_Payment_Popup_Prepare_FixInputs} inputs
|
|
2298
|
-
* @param {{ locale?: "ko" }} options
|
|
2299
|
-
* @returns {LocalizedString}
|
|
2300
|
-
*/
|
|
2301
|
-
const mcp_rule_payment_popup_prepare_fix = ((inputs = {}, options = {}) => {
|
|
2302
|
-
experimentalStaticLocale$1 ?? options.locale ?? getLocale$1();
|
|
2303
|
-
return ko_mcp_rule_payment_popup_prepare_fix(inputs);
|
|
2304
|
-
});
|
|
2305
|
-
|
|
2306
|
-
//#endregion
|
|
2307
|
-
//#region ../mcp/src/paraglide/messages/mcp_rule_payment_popup_prepare_title.js
|
|
2308
|
-
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
2309
|
-
/** @typedef {{}} Mcp_Rule_Payment_Popup_Prepare_TitleInputs */
|
|
2310
|
-
const ko_mcp_rule_payment_popup_prepare_title = () => {
|
|
2311
|
-
return `결제 시작이 서버 함수를 거치면 클릭 시점에 \`payments.prepareWindow()\`로 창을 먼저 연다`;
|
|
2312
|
-
};
|
|
2313
|
-
/**
|
|
2314
|
-
|
|
2315
|
-
* @param {Mcp_Rule_Payment_Popup_Prepare_TitleInputs} inputs
|
|
2316
|
-
* @param {{ locale?: "ko" }} options
|
|
2317
|
-
* @returns {LocalizedString}
|
|
2318
|
-
*/
|
|
2319
|
-
const mcp_rule_payment_popup_prepare_title = ((inputs = {}, options = {}) => {
|
|
2320
|
-
experimentalStaticLocale$1 ?? options.locale ?? getLocale$1();
|
|
2321
|
-
return ko_mcp_rule_payment_popup_prepare_title(inputs);
|
|
2322
|
-
});
|
|
2323
|
-
|
|
2324
|
-
//#endregion
|
|
2325
|
-
//#region ../mcp/src/paraglide/messages/mcp_rule_payment_popup_prepare_why.js
|
|
2326
|
-
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
2327
|
-
/** @typedef {{}} Mcp_Rule_Payment_Popup_Prepare_WhyInputs */
|
|
2328
|
-
const ko_mcp_rule_payment_popup_prepare_why = () => {
|
|
2329
|
-
return `팝업은 사용자 클릭에서 동기로 열어야 차단되지 않는다. 서버 응답을 기다린 뒤 열면 브라우저가 막아 결제가 시작되지 않는다`;
|
|
2330
|
-
};
|
|
2331
|
-
/**
|
|
2332
|
-
|
|
2333
|
-
* @param {Mcp_Rule_Payment_Popup_Prepare_WhyInputs} inputs
|
|
2334
|
-
* @param {{ locale?: "ko" }} options
|
|
2335
|
-
* @returns {LocalizedString}
|
|
2336
|
-
*/
|
|
2337
|
-
const mcp_rule_payment_popup_prepare_why = ((inputs = {}, options = {}) => {
|
|
2338
|
-
experimentalStaticLocale$1 ?? options.locale ?? getLocale$1();
|
|
2339
|
-
return ko_mcp_rule_payment_popup_prepare_why(inputs);
|
|
2340
|
-
});
|
|
2341
|
-
|
|
2342
2264
|
//#endregion
|
|
2343
2265
|
//#region ../mcp/src/paraglide/messages/mcp_rule_payment_processing_status_example.js
|
|
2344
2266
|
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
@@ -3297,24 +3219,6 @@ const mcp_verify_payment_browser_launch_server_file = ((inputs = {}, options = {
|
|
|
3297
3219
|
return ko_mcp_verify_payment_browser_launch_server_file(inputs);
|
|
3298
3220
|
});
|
|
3299
3221
|
|
|
3300
|
-
//#endregion
|
|
3301
|
-
//#region ../mcp/src/paraglide/messages/mcp_verify_payment_popup_prepare.js
|
|
3302
|
-
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
3303
|
-
/** @typedef {{}} Mcp_Verify_Payment_Popup_PrepareInputs */
|
|
3304
|
-
const ko_mcp_verify_payment_popup_prepare = () => {
|
|
3305
|
-
return `받아 둔 결제 시작 값으로 결제창을 열지만 클릭 시점에 \`payments.prepareWindow()\`로 창을 먼저 여는 코드가 없다`;
|
|
3306
|
-
};
|
|
3307
|
-
/**
|
|
3308
|
-
|
|
3309
|
-
* @param {Mcp_Verify_Payment_Popup_PrepareInputs} inputs
|
|
3310
|
-
* @param {{ locale?: "ko" }} options
|
|
3311
|
-
* @returns {LocalizedString}
|
|
3312
|
-
*/
|
|
3313
|
-
const mcp_verify_payment_popup_prepare = ((inputs = {}, options = {}) => {
|
|
3314
|
-
experimentalStaticLocale$1 ?? options.locale ?? getLocale$1();
|
|
3315
|
-
return ko_mcp_verify_payment_popup_prepare(inputs);
|
|
3316
|
-
});
|
|
3317
|
-
|
|
3318
3222
|
//#endregion
|
|
3319
3223
|
//#region ../mcp/src/paraglide/messages/mcp_verify_payment_processing_status.js
|
|
3320
3224
|
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
@@ -9784,7 +9688,7 @@ async function selectStore(auth, client, io, candidates, folderStore = null) {
|
|
|
9784
9688
|
|
|
9785
9689
|
//#endregion
|
|
9786
9690
|
//#region package.json
|
|
9787
|
-
var version = "0.
|
|
9691
|
+
var version = "0.10.0";
|
|
9788
9692
|
|
|
9789
9693
|
//#endregion
|
|
9790
9694
|
//#region src/client.ts
|
|
@@ -10870,21 +10774,12 @@ const RULES = [
|
|
|
10870
10774
|
doc: "/guides/checkout-flow",
|
|
10871
10775
|
templateFile: "src/lib/payments.ts"
|
|
10872
10776
|
}),
|
|
10873
|
-
defineRule({
|
|
10874
|
-
id: "payment-popup-prepare",
|
|
10875
|
-
title: mcp_rule_payment_popup_prepare_title,
|
|
10876
|
-
why: mcp_rule_payment_popup_prepare_why,
|
|
10877
|
-
fix: mcp_rule_payment_popup_prepare_fix,
|
|
10878
|
-
example: mcp_rule_payment_popup_prepare_example,
|
|
10879
|
-
doc: "/guides/checkout-flow",
|
|
10880
|
-
templateFile: "src/routes/checkout.index.tsx"
|
|
10881
|
-
}),
|
|
10882
10777
|
defineRule({
|
|
10883
10778
|
id: "payment-return-route",
|
|
10884
10779
|
title: mcp_rule_payment_return_route_title,
|
|
10885
10780
|
why: mcp_rule_payment_return_route_why,
|
|
10886
10781
|
fix: mcp_rule_payment_return_route_fix,
|
|
10887
|
-
example: "useEffect(() => {\n void payments.result(
|
|
10782
|
+
example: "useEffect(() => {\n void payments.result().then((result) => {\n if (result.status === \"COMPLETED\") navigate({ to: \"/checkout/complete\", search: { orderId: result.orderId } });\n });\n}, []);",
|
|
10888
10783
|
doc: "/guides/checkout-flow",
|
|
10889
10784
|
templateFile: "src/routes/checkout.return.tsx"
|
|
10890
10785
|
}),
|
|
@@ -11128,7 +11023,6 @@ function verifySources(files, options = {}) {
|
|
|
11128
11023
|
}
|
|
11129
11024
|
if (has("startPayment(") && !has("@sayren/storefront-sdk/payments")) inProject("payment-browser-launch", mcp_verify_payment_browser_launch_missing());
|
|
11130
11025
|
const opensPayment = matches(/\bpayments\.open\(|\.open\(\s*(start|paymentStart)\b/);
|
|
11131
|
-
if (opensPayment && !has("prepareWindow(")) inFile("payment-popup-prepare", opensPayment, mcp_verify_payment_popup_prepare(), /\bpayments\.open\(|\.open\(\s*(start|paymentStart)\b/);
|
|
11132
11026
|
if (opensPayment && !/amounts/.test(opensPayment.content)) inFile("payment-amounts-final", opensPayment, mcp_verify_payment_amounts_final(), /\bpayments\.open\(/);
|
|
11133
11027
|
const fixedReturnUrl = matches(/returnUrl\s*[:=]\s*["'`]https?:\/\//);
|
|
11134
11028
|
if (fixedReturnUrl) inFile("checkout-origin", fixedReturnUrl, mcp_verify_checkout_origin(), /returnUrl\s*[:=]\s*["'`]https?:\/\//);
|
|
@@ -11476,8 +11370,18 @@ const WRITABLE_ROOT_FILES = new Set([
|
|
|
11476
11370
|
"biome.json",
|
|
11477
11371
|
".gitignore"
|
|
11478
11372
|
]);
|
|
11479
|
-
/**
|
|
11480
|
-
|
|
11373
|
+
/**
|
|
11374
|
+
* 읽기만 되는 루트 파일 — 의존성은 전용 경로로만 바꾼다(레지스트리 프록시와 잠금 파일을 함께 맞춘다).
|
|
11375
|
+
* `CLAUDE.md`·`.mcp.json`은 템플릿이 싣는 에이전트 안내·MCP 연결 설정이다(2026-10-14, blank 템플릿) — 편집 도구는 바꾸지 않는다
|
|
11376
|
+
*/
|
|
11377
|
+
const READONLY_ROOT_FILES = new Set([
|
|
11378
|
+
"package.json",
|
|
11379
|
+
"pnpm-lock.yaml",
|
|
11380
|
+
"CLAUDE.md",
|
|
11381
|
+
".mcp.json"
|
|
11382
|
+
]);
|
|
11383
|
+
/** 읽기만 되는 폴더 — 템플릿이 싣는 Claude 스킬(`.claude/skills/…`, 2026-10-14). 셀러 로컬 Claude Code와 AI 상점 도우미가 같은 기준을 읽는다 */
|
|
11384
|
+
const READONLY_DIRS = new Set([".claude"]);
|
|
11481
11385
|
/**
|
|
11482
11386
|
* 쓸 수 있는 폴더 — 코드(`src`), 정적 파일(`public`), 화면 문구 카탈로그(`messages`, 템플릿 `src/i18n`이 `messages/ko.json`을 import한다, #73).
|
|
11483
11387
|
* 템플릿이 import하는 파일이 이 밖에 있으면 첫 작업 트리(source.tgz)를 풀 때 빠져 빌드·검사가 깨진다(#78)
|
|
@@ -11490,6 +11394,7 @@ const WRITABLE_DIRS = new Set([
|
|
|
11490
11394
|
/** 작업 트리 루트에 둘 수 있는 이름(폴더·파일) — 컨테이너 스냅샷이 이 이름만 묶는다(`container-tree.ts`) */
|
|
11491
11395
|
const TRACKED_ROOT_NAMES = [
|
|
11492
11396
|
...WRITABLE_DIRS,
|
|
11397
|
+
...READONLY_DIRS,
|
|
11493
11398
|
...WRITABLE_ROOT_FILES,
|
|
11494
11399
|
...READONLY_ROOT_FILES
|
|
11495
11400
|
];
|
|
@@ -11519,9 +11424,10 @@ function accessOf(path) {
|
|
|
11519
11424
|
if (READONLY_ROOT_FILES.has(first)) return "read";
|
|
11520
11425
|
return null;
|
|
11521
11426
|
}
|
|
11522
|
-
|
|
11523
|
-
if (
|
|
11524
|
-
|
|
11427
|
+
const readonlyDir = READONLY_DIRS.has(first);
|
|
11428
|
+
if (!readonlyDir && !WRITABLE_DIRS.has(first)) return null;
|
|
11429
|
+
if (segments.slice(1).some((s) => s.startsWith("."))) return null;
|
|
11430
|
+
return readonlyDir ? "read" : "write";
|
|
11525
11431
|
}
|
|
11526
11432
|
|
|
11527
11433
|
//#endregion
|
|
@@ -11870,6 +11776,24 @@ function lockImporterSpecifiers(lock) {
|
|
|
11870
11776
|
return out;
|
|
11871
11777
|
}
|
|
11872
11778
|
|
|
11779
|
+
//#endregion
|
|
11780
|
+
//#region src/guide-skill.ts
|
|
11781
|
+
/**
|
|
11782
|
+
* 받은 폴더의 에이전트 안내 스킬(2026-10-16 사용자 결정) — 셀러의 Claude Code가 sayren 중앙 스킬을 HTTP로 읽게 한다.
|
|
11783
|
+
* 빈 템플릿이 싣는 `templates/storefront-blank/.claude/skills/sayren/SKILL.md`와 같은 내용이다(`guide-skill.test.ts`가 고정한다).
|
|
11784
|
+
*/
|
|
11785
|
+
const GUIDE_SKILL_PATH = ".claude/skills/sayren/SKILL.md";
|
|
11786
|
+
const GUIDE_SKILL = "---\nname: sayren\ndescription: Use for any work on this sayren storefront — pages, product display, cart, checkout, payments, buyer login, account pages, analytics, design and code quality. Loads the current sayren skills over HTTP.\n---\n\n# sayren skills (central)\n\nThe sayren skills are maintained centrally and change without updating this project. Read them over HTTP at the start of a task instead of relying on memory.\n\n1. List the skills: `GET https://api.sayren.io/v1/public/agent-skills`\n The response is `{ \"data\": [{ \"name\", \"description\", \"version\", \"updatedAt\" }] }`.\n2. Read the skills that match the task: `GET https://api.sayren.io/v1/public/agent-skills/{name}`\n The response is `{ \"data\": { \"name\", \"description\", \"body\", \"version\", \"updatedAt\" } }`; `body` is the guide (markdown).\n\nStart points:\n- Any code change: `code-quality`, `sayren-storefront-rules`, `sdk-client`, `template-stack`\n- Product pages: `sayren-product-display`, `sdk-catalog`\n- Cart, checkout, payment: `sdk-cart`, `sdk-checkout`, `sdk-payments`\n- Buyer login and account pages: `sdk-buyer-auth`, `sdk-account`\n- Visual design: `design-quality`\n\nFollow the project's `CLAUDE.md` first; the skills add the sayren-specific details.\n";
|
|
11787
|
+
/**
|
|
11788
|
+
* 받은 트리에 안내 스킬이 없으면 넣는다 — 템플릿이 싣거나 셀러가 올린 내용이 우선이다. 트리에 넣으므로 다시 받을 때 지울 파일로 잡히지 않고
|
|
11789
|
+
* `deploy`가 원격 작업 트리에도 올린다(AI 상점 도우미가 같은 안내를 읽는다). 넣었으면 true
|
|
11790
|
+
*/
|
|
11791
|
+
function withGuideSkill(files) {
|
|
11792
|
+
if (files.has(GUIDE_SKILL_PATH)) return false;
|
|
11793
|
+
files.set(GUIDE_SKILL_PATH, new TextEncoder().encode(GUIDE_SKILL));
|
|
11794
|
+
return true;
|
|
11795
|
+
}
|
|
11796
|
+
|
|
11873
11797
|
//#endregion
|
|
11874
11798
|
//#region src/local-build.ts
|
|
11875
11799
|
/** 실패할 때 보여 주는 빌드 출력 줄 수 */
|
|
@@ -11978,7 +11902,7 @@ async function pull(flags, io) {
|
|
|
11978
11902
|
return receiveSource(client, auth, source, flags, io, authDir);
|
|
11979
11903
|
}
|
|
11980
11904
|
/**
|
|
11981
|
-
* 받은 작업
|
|
11905
|
+
* 받은 작업 트리(+ 에이전트 안내 스킬 `withGuideSkill`)를 폴더에 쓰고 받은 폴더 파일(`.sayren/state.json`·`.env`·`.mcp.json`·`.gitignore`)을 맞춘다. `pull`과 `init`(#101)이 같이 쓴다.
|
|
11982
11906
|
* 대상은 `--dir` → 받은 폴더 안이면 그 폴더 → 상점 코드다. 비어 있지 않은 폴더는 `--force`일 때 같은 사이트를 받은 폴더만 다시 받는다.
|
|
11983
11907
|
*/
|
|
11984
11908
|
async function receiveSource(client, auth, source, flags, io, migratedDir) {
|
|
@@ -12039,6 +11963,7 @@ async function receiveSource(client, auth, source, flags, io, migratedDir) {
|
|
|
12039
11963
|
const tgz = new Uint8Array(Buffer.concat(chunks));
|
|
12040
11964
|
if (sha256Hex(tgz) !== source.archive.sha256) throw new CliError(cli_pull_archive_corrupt());
|
|
12041
11965
|
const files = await unpackArchive(tgz);
|
|
11966
|
+
withGuideSkill(files);
|
|
12042
11967
|
const collisions = caseCollisions(files.keys());
|
|
12043
11968
|
if (collisions.length > 0) throw new CliError(cli_pull_case_collisions({ groups: collisions.map((group) => group.join(" · ")).join(", ") }));
|
|
12044
11969
|
const diff = diffLocal(target, files);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sayren",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"imports": {
|
|
6
6
|
"#paraglide/*": "./src/paraglide/*"
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"esbuild": "^0.28.2",
|
|
20
|
-
"@sayren/store-sdk": "^0.
|
|
20
|
+
"@sayren/store-sdk": "^0.33.0"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@biomejs/biome": "^2.5.14",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"tsx": "^4.20.3",
|
|
29
29
|
"typescript": "^6.0.3",
|
|
30
30
|
"vitest": "^5.0.1",
|
|
31
|
-
"@sayren/mcp": "0.
|
|
31
|
+
"@sayren/mcp": "0.26.0"
|
|
32
32
|
},
|
|
33
33
|
"publishConfig": {
|
|
34
34
|
"access": "public"
|