@bstage-sdk/cli 0.5.0 → 0.6.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/MIGRATION.md +45 -0
- package/dist/index.js +171 -70
- package/package.json +4 -4
package/dist/MIGRATION.md
CHANGED
|
@@ -50,6 +50,51 @@
|
|
|
50
50
|
> **정렬**: 릴리즈 **시점 최신이 위**. 패키지가 독립 버전이라 헤더 숫자만으로는 시간순 정렬이 되지 않으므로 릴리즈 순서를 기준으로 한다.
|
|
51
51
|
|
|
52
52
|
---
|
|
53
|
+
|
|
54
|
+
## → cli 0.6.0
|
|
55
|
+
|
|
56
|
+
### sdk와 liquid 템플릿이 한 레포에 있어도 빌드·배포된다(혼합 레포) — `자동` · `선택`
|
|
57
|
+
|
|
58
|
+
**영향**
|
|
59
|
+
|
|
60
|
+
- **단일 종류(sdk만·liquid만) 레포가 할 일은 없다.** 명령·산출물이 그대로다.
|
|
61
|
+
- `mixed`(sdk 템플릿 + liquid 템플릿)로 판정돼 `bstage build`·`dev`·`deploy`가 종료 코드 2로 멈추던 레포는 이제 진행한다.
|
|
62
|
+
- 감지: `bstage build`가 "liquid 템플릿 N개 … 포털이 … 패키징합니다" 안내를 낸다. `bstage deploy`도 혼합 안내 한 줄을 낸다.
|
|
63
|
+
|
|
64
|
+
**변경 내용**
|
|
65
|
+
|
|
66
|
+
- **`bstage build`**: 혼합 레포에서 sdk 엔트리만 번들하고 liquid는 검증만 한다 — `dist/`에 liquid를 넣지 않는다(포털 빌더가 push된 커밋의 `public/{user|admin}/{이름}/`을 sdk 산출물과 함께 패키징한다). 검증은 번들보다 먼저 하고, 오류가 있으면 번들 없이 종료 코드 2다. `--json`은 `{ "kind": "mixed", "issues", "sdk": { "templates", "outputs" }, "liquid": { "templates" } }` 객체 하나를 stdout에 쓰고 진행 로그는 stderr로 보낸다.
|
|
67
|
+
- **예약 이름**: 혼합 레포에서 `src/pages/user/…`·`src/pages/admin/…` 페이지는 error다. 산출물이 `dist/{user|admin}/…`로 나가 liquid 자리와 겹치고, 같은 디렉터리에 `template.js`와 `template.liquid`가 함께 있으면 포털이 sdk로만 판정해 liquid가 조용히 사라진다. 포털 빌더도 같은 자리에서 막는다. 위젯(`src/slots`)은 해당 없다.
|
|
68
|
+
- **`bstage deploy`**: 혼합 레포를 막지 않는다. 위젯(SLOT) 배치 사전점검은 liquid 전용 레포에서만 하고, 혼합 레포의 항목별 판정(liquid 항목에 SLOT을 걸면 400)은 포털이 한다.
|
|
69
|
+
- **`bstage dev --kind <sdk|liquid>`**: 혼합 레포에서 어느 프리뷰를 띄울지 고른다. 기본은 sdk(Vite)이고 시작할 때 liquid 프리뷰 방법을 안내한다. 두 서버를 함께 띄우지 않는다. 단일 종류 레포에서 판정과 어긋난 값은 종료 코드 2다.
|
|
70
|
+
- **liquid 검증기**(`bstage build`·`bstage doctor`의 liquid 절)는 sdk와 섞인 것을 더 이상 error로 보고하지 않는다.
|
|
71
|
+
- **포털 빌더는 별도로 갱신된다.** 갱신 전 포털은 혼합 레포에서 liquid만 패키징하므로, CLI와 빌더가 모두 반영된 뒤 혼합 레포를 배포한다.
|
|
72
|
+
|
|
73
|
+
**적용**
|
|
74
|
+
|
|
75
|
+
1. (자동) 단일 종류 레포는 그대로 둔다 — 올리기만 하면 된다.
|
|
76
|
+
2. (판단) 혼합 레포를 만들 때: liquid는 `public/{user|admin}/{이름}/template.liquid`, sdk 페이지는 `src/pages/{이름}/template.tsx`(`user`·`admin` 제외), 위젯은 `src/slots/…`. `bstage build`가 겹치는 자리를 짚어 준다.
|
|
77
|
+
3. (자동) 혼합 레포의 liquid 프리뷰는 `bstage dev --kind liquid`.
|
|
78
|
+
|
|
79
|
+
### AGENTS.md 관리 영역 v14 · 혼합 레포 스킬 세트(`bstage ai install`·`doctor`) — `자동` · `선택`
|
|
80
|
+
|
|
81
|
+
**영향**
|
|
82
|
+
|
|
83
|
+
- `bstage init`으로 만든 모든 프로젝트. 관리 영역이 v14보다 낮으면 해당한다(본문 문구 변경 — liquid 본문의 "sdk와 섞지 않는다"가 공존 규칙으로 바뀌었다).
|
|
84
|
+
- `mixed`로 판정돼 `bstage ai install`·`update`가 종료 코드 2로 멈추고 `bstage doctor`가 스킬 검사를 건너뛰던 혼합 레포.
|
|
85
|
+
- 감지: `bstage ai doctor`가 `AGENTS.md`를 `stale`로 보고한다. 혼합 레포에서는 `bstage-template`·`bstage-liquid` 둘 다 검사 대상이 된다.
|
|
86
|
+
|
|
87
|
+
**변경 내용**
|
|
88
|
+
|
|
89
|
+
- `bstage ai install`·`update`·`doctor`가 혼합 레포를 지원한다 — 스킬은 sdk 세트와 liquid 세트의 **합집합**(5종)을 설치하고, `AGENTS.md` 관리 영역은 두 구조와 혼합 규칙(어느 방식으로 만들지 · sdk 페이지 `user`·`admin` 금지 · `bstage build`·`dev --kind` 동작)을 담은 **혼합 본문**이 된다. `mixed`는 판정으로만 나오며 `--kind`로 지정하는 값이 아니다 — 혼합 레포에 `--kind sdk|liquid`를 주면 판정과 어긋나 멈춘다.
|
|
90
|
+
- `bstage doctor`는 혼합 레포에서 스킬 검사를 건너뛰지 않고 두 세트를 모두 보며, liquid 검증 결과도 함께 낸다. `--json`의 `skillsSkipped`는 항상 `false`다(필드는 비파괴적으로 남긴다).
|
|
91
|
+
- `bstage-onboarding`·`bstage-liquid` 스킬과 `AGENTS.md`의 "한 레포에 한 방식만" 문구를 공존 규칙(예약 이름 · `dev --kind liquid`)으로 바꿨다.
|
|
92
|
+
|
|
93
|
+
**적용**
|
|
94
|
+
|
|
95
|
+
1. (자동) `npx @bstage-sdk/cli@latest ai update` — 스킬·`AGENTS.md` 관리 영역을 v14로 갱신한다. 혼합 레포에서는 없는 스킬도 만들어야 하므로 `ai install`을 쓴다.
|
|
96
|
+
2. (판단) 혼합 레포의 `AGENTS.md` 자유 영역에 "한 레포에 한 방식만" 류의 자체 규칙을 적어 두었다면 지운다 — 관리 영역과 어긋난다.
|
|
97
|
+
|
|
53
98
|
## → cli 0.5.0
|
|
54
99
|
|
|
55
100
|
### liquid 에셋은 포털 미디어에 올린다 — 레포 상대 경로는 배포 후 깨진다 — `판단` · `필수`
|
package/dist/index.js
CHANGED
|
@@ -662,6 +662,13 @@ function detectProjectKind(root) {
|
|
|
662
662
|
hasSdkDependency: sdkDependency
|
|
663
663
|
};
|
|
664
664
|
}
|
|
665
|
+
function collidingSdkPages(report2) {
|
|
666
|
+
if (report2.liquidTemplates.length === 0) return [];
|
|
667
|
+
return report2.sdkTemplates.filter((t) => {
|
|
668
|
+
const [root, first] = t.split("/");
|
|
669
|
+
return root === "pages" && first !== void 0 && LIQUID_SURFACES.has(first.toLowerCase());
|
|
670
|
+
});
|
|
671
|
+
}
|
|
665
672
|
|
|
666
673
|
// src/commands/ai/context.ts
|
|
667
674
|
var DEFAULT_SKILLS_DIR = ".claude/skills";
|
|
@@ -703,10 +710,13 @@ function resolveKind(root, requested) {
|
|
|
703
710
|
const wanted = parseKindOption(requested);
|
|
704
711
|
const detected = detectProjectKind(root).kind;
|
|
705
712
|
if (detected === "mixed") {
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
713
|
+
if (wanted) {
|
|
714
|
+
fail(
|
|
715
|
+
ExitCode.PRECONDITION,
|
|
716
|
+
`--kind ${wanted}\uB85C \uC9C0\uC815\uD588\uC9C0\uB9CC \uC774 \uB808\uD3EC\uB294 mixed(sdk + liquid \uD63C\uD569)\uB85C \uD310\uC815\uB429\uB2C8\uB2E4 \u2014 \uC635\uC158\uC744 \uBE7C\uACE0 \uC2E4\uD589\uD558\uC138\uC694(\uB450 \uC138\uD2B8\uB97C \uBAA8\uB450 \uC124\uCE58\uD569\uB2C8\uB2E4).`
|
|
717
|
+
);
|
|
718
|
+
}
|
|
719
|
+
return "mixed";
|
|
710
720
|
}
|
|
711
721
|
if (detected === "unknown") {
|
|
712
722
|
if (!wanted) {
|
|
@@ -1099,7 +1109,7 @@ async function aiDoctorCommand(o, deps = {}) {
|
|
|
1099
1109
|
}
|
|
1100
1110
|
|
|
1101
1111
|
// src/commands/build.ts
|
|
1102
|
-
import { resolve as resolve2, join as join6, relative as relative2 } from "path";
|
|
1112
|
+
import { resolve as resolve2, join as join6, relative as relative2, sep as sep3 } from "path";
|
|
1103
1113
|
import { readFile as readFile2, access, readdir, rename, mkdir, rm } from "fs/promises";
|
|
1104
1114
|
import { build as viteBuild, loadEnv } from "vite";
|
|
1105
1115
|
import pc7 from "picocolors";
|
|
@@ -1523,13 +1533,6 @@ function findMisnamedTemplates(root) {
|
|
|
1523
1533
|
function validateLiquid(root) {
|
|
1524
1534
|
const detected = detectProjectKind(root);
|
|
1525
1535
|
const issues = [];
|
|
1526
|
-
if (detected.kind === "mixed") {
|
|
1527
|
-
issues.push({
|
|
1528
|
-
level: "error",
|
|
1529
|
-
path: ".",
|
|
1530
|
-
message: "sdk \uD15C\uD50C\uB9BF(src/pages\xB7src/slots\uC758 template.tsx)\uACFC liquid \uD15C\uD50C\uB9BF\uC774 \uD55C \uB808\uD3EC\uC5D0 \uC11E\uC5EC \uC788\uC2B5\uB2C8\uB2E4 \u2014 \uD3EC\uD138 \uBE4C\uB354\uB294 \uB458\uC744 \uD568\uAED8 \uD328\uD0A4\uC9D5\uD558\uC9C0 \uBABB\uD569\uB2C8\uB2E4. \uD558\uB098\uB9CC \uB0A8\uACA8 \uC8FC\uC138\uC694."
|
|
1531
|
-
});
|
|
1532
|
-
}
|
|
1533
1536
|
if (detected.liquidTemplates.length === 0) {
|
|
1534
1537
|
issues.push({
|
|
1535
1538
|
level: "error",
|
|
@@ -1746,8 +1749,9 @@ ${pc7.red("Error")} ${label}: name "${elementName}"\uC744 ${elementNameOwner}\uA
|
|
|
1746
1749
|
const finalDir = outputName ? join6(cwd, DIST_DIR, outputName) : join6(cwd, DIST_DIR);
|
|
1747
1750
|
await mkdir(finalDir, { recursive: true });
|
|
1748
1751
|
await rename(join6(cwd, outDir, "template.js"), join6(finalDir, "template.js"));
|
|
1749
|
-
|
|
1750
|
-
|
|
1752
|
+
const output = relative2(cwd, finalDir).split(sep3).join("/");
|
|
1753
|
+
console.log(` ${output}/template.js (${formatSize(bundleSize)})`);
|
|
1754
|
+
return { usesClient, output };
|
|
1751
1755
|
}
|
|
1752
1756
|
function printCredentialReport(env2, referenced) {
|
|
1753
1757
|
const issues = checkCredentials(env2, referenced);
|
|
@@ -1813,19 +1817,101 @@ function printLiquidIssues(issues) {
|
|
|
1813
1817
|
console.log(pc7.green("\u2713 liquid \uAC80\uC99D \uD1B5\uACFC"));
|
|
1814
1818
|
}
|
|
1815
1819
|
}
|
|
1820
|
+
async function bundleAll(cwd, entries, bundleEntry) {
|
|
1821
|
+
await rm(join6(cwd, DIST_DIR), { recursive: true, force: true });
|
|
1822
|
+
const ctx = {
|
|
1823
|
+
cwd,
|
|
1824
|
+
takenOutputs: /* @__PURE__ */ new Map(),
|
|
1825
|
+
takenElementNames: /* @__PURE__ */ new Map()
|
|
1826
|
+
};
|
|
1827
|
+
console.log(
|
|
1828
|
+
`Found ${entries.length} template${entries.length > 1 ? "s" : ""}: ${entries.map(entryLabel).join(", ")}`
|
|
1829
|
+
);
|
|
1830
|
+
const results = [];
|
|
1831
|
+
for (const entry of entries) {
|
|
1832
|
+
results.push(await bundleEntry(ctx, entry));
|
|
1833
|
+
}
|
|
1834
|
+
await rm(join6(cwd, DIST_DIR, STAGING_DIR), { recursive: true, force: true });
|
|
1835
|
+
return results;
|
|
1836
|
+
}
|
|
1837
|
+
async function reportCredentials(cwd, results) {
|
|
1838
|
+
if (!results.some((r) => r.usesClient)) return;
|
|
1839
|
+
const referenced = collectReferencedVars(await readProjectSources(cwd));
|
|
1840
|
+
printCredentialReport(loadEnv("production", cwd, "VITE_"), referenced);
|
|
1841
|
+
}
|
|
1842
|
+
function collisionIssues(report2) {
|
|
1843
|
+
return collidingSdkPages(report2).map((t) => ({
|
|
1844
|
+
level: "error",
|
|
1845
|
+
path: `src/${t}`,
|
|
1846
|
+
message: `\uC0B0\uCD9C\uBB3C\uC774 ${DIST_DIR}/${t.slice("pages/".length)}/ \uB85C \uB098\uAC00 liquid \uD15C\uD50C\uB9BF \uC790\uB9AC(${DIST_DIR}/{user|admin}/{\uC774\uB984}/)\uC640 \uACB9\uCE69\uB2C8\uB2E4 \u2014 ${PAGES_ROOT}/ \uBC14\uB85C \uC544\uB798 \uD3F4\uB354 \uC774\uB984\uC5D0 user\xB7admin \uC744 \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uD3F4\uB354 \uC774\uB984\uC744 \uBC14\uAFD4 \uC8FC\uC138\uC694.`
|
|
1847
|
+
}));
|
|
1848
|
+
}
|
|
1849
|
+
async function withStdoutQuiet(fn) {
|
|
1850
|
+
const { log: log3, info } = console;
|
|
1851
|
+
console.log = (...args) => console.error(...args);
|
|
1852
|
+
console.info = (...args) => console.error(...args);
|
|
1853
|
+
try {
|
|
1854
|
+
return await fn();
|
|
1855
|
+
} finally {
|
|
1856
|
+
console.log = log3;
|
|
1857
|
+
console.info = info;
|
|
1858
|
+
}
|
|
1859
|
+
}
|
|
1860
|
+
async function buildMixed(cwd, options, report2, bundleEntry) {
|
|
1861
|
+
const issues = [...validateLiquid(cwd), ...collisionIssues(report2)];
|
|
1862
|
+
const hasError = issues.some((i) => i.level === "error");
|
|
1863
|
+
const liquid = { templates: report2.liquidTemplates };
|
|
1864
|
+
if (options.json) {
|
|
1865
|
+
if (hasError) {
|
|
1866
|
+
printJson({ kind: "mixed", issues, liquid });
|
|
1867
|
+
process.exitCode = ExitCode.PRECONDITION;
|
|
1868
|
+
return;
|
|
1869
|
+
}
|
|
1870
|
+
const entries2 = await discoverEntries(cwd);
|
|
1871
|
+
const results2 = await withStdoutQuiet(() => bundleAll(cwd, entries2, bundleEntry));
|
|
1872
|
+
printJson({
|
|
1873
|
+
kind: "mixed",
|
|
1874
|
+
issues,
|
|
1875
|
+
sdk: { templates: entries2.map(entryLabel), outputs: results2.map((r) => r.output) },
|
|
1876
|
+
liquid
|
|
1877
|
+
});
|
|
1878
|
+
return;
|
|
1879
|
+
}
|
|
1880
|
+
printLiquidIssues(issues);
|
|
1881
|
+
if (hasError) {
|
|
1882
|
+
console.error(
|
|
1883
|
+
`
|
|
1884
|
+
${pc7.red("\u2717")} \uAC80\uC99D \uC2E4\uD328 \u2014 \uC704 \uD56D\uBAA9\uC744 \uACE0\uCE5C \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694. \uC774\uB300\uB85C push\uD558\uBA74 \uD3EC\uD138 \uBE4C\uB4DC\uB3C4 \uAC19\uC740 \uC790\uB9AC\uC5D0\uC11C \uB9C9\uD799\uB2C8\uB2E4.`
|
|
1885
|
+
);
|
|
1886
|
+
process.exit(ExitCode.PRECONDITION);
|
|
1887
|
+
}
|
|
1888
|
+
const entries = await discoverEntries(cwd);
|
|
1889
|
+
const results = await bundleAll(cwd, entries, bundleEntry);
|
|
1890
|
+
console.log(`
|
|
1891
|
+
Build complete.`);
|
|
1892
|
+
console.log(
|
|
1893
|
+
`liquid \uD15C\uD50C\uB9BF ${report2.liquidTemplates.length}\uAC1C(${report2.liquidTemplates.join(", ")})\uB294 \uB85C\uCEEC \uC0B0\uCD9C\uBB3C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 \uD3EC\uD138\uC774 push\uB41C \uCEE4\uBC0B\uC758 public/{user|admin}/{name}/ \uC744 \uADF8\uB300\uB85C \uD328\uD0A4\uC9D5\uD569\uB2C8\uB2E4(data.json\xB7layout.json \uC81C\uC678)`
|
|
1894
|
+
);
|
|
1895
|
+
await reportCredentials(cwd, results);
|
|
1896
|
+
}
|
|
1816
1897
|
async function buildCommand(options = {}, deps = {}) {
|
|
1817
1898
|
const cwd = deps.cwd ?? process.cwd();
|
|
1899
|
+
const bundleEntry = deps.bundleEntry ?? buildEntry;
|
|
1818
1900
|
const report2 = detectProjectKind(cwd);
|
|
1819
1901
|
const kind = report2.kind;
|
|
1820
|
-
if (kind === "liquid"
|
|
1902
|
+
if (kind === "liquid") {
|
|
1821
1903
|
reportLiquid(cwd, options);
|
|
1822
1904
|
return;
|
|
1823
1905
|
}
|
|
1906
|
+
if (kind === "mixed") {
|
|
1907
|
+
await buildMixed(cwd, options, report2, bundleEntry);
|
|
1908
|
+
return;
|
|
1909
|
+
}
|
|
1824
1910
|
const entries = await discoverEntries(cwd);
|
|
1825
1911
|
if (entries.length === 0) {
|
|
1826
|
-
const
|
|
1827
|
-
if (
|
|
1828
|
-
console.error(`Error: ${
|
|
1912
|
+
const ignored2 = ignoredLiquidNotice(report2.ignoredLiquid);
|
|
1913
|
+
if (ignored2 !== null) {
|
|
1914
|
+
console.error(`Error: ${ignored2}`);
|
|
1829
1915
|
await printLegacyHint(cwd);
|
|
1830
1916
|
process.exit(ExitCode.PRECONDITION);
|
|
1831
1917
|
}
|
|
@@ -1835,26 +1921,13 @@ async function buildCommand(options = {}, deps = {}) {
|
|
|
1835
1921
|
await printLegacyHint(cwd);
|
|
1836
1922
|
process.exit(ExitCode.PRECONDITION);
|
|
1837
1923
|
}
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
takenElementNames: /* @__PURE__ */ new Map()
|
|
1843
|
-
};
|
|
1844
|
-
console.log(
|
|
1845
|
-
`Found ${entries.length} template${entries.length > 1 ? "s" : ""}: ${entries.map(entryLabel).join(", ")}`
|
|
1846
|
-
);
|
|
1847
|
-
const results = [];
|
|
1848
|
-
for (const entry of entries) {
|
|
1849
|
-
results.push(await buildEntry(ctx, entry));
|
|
1850
|
-
}
|
|
1851
|
-
await rm(join6(cwd, DIST_DIR, STAGING_DIR), { recursive: true, force: true });
|
|
1924
|
+
const ignored = ignoredLiquidNotice(report2.ignoredLiquid);
|
|
1925
|
+
if (ignored !== null) console.log(`${pc7.yellow("\u26A0")} ${ignored}
|
|
1926
|
+
`);
|
|
1927
|
+
const results = await bundleAll(cwd, entries, bundleEntry);
|
|
1852
1928
|
console.log(`
|
|
1853
1929
|
Build complete.`);
|
|
1854
|
-
|
|
1855
|
-
const referenced = collectReferencedVars(await readProjectSources(cwd));
|
|
1856
|
-
printCredentialReport(loadEnv("production", cwd, "VITE_"), referenced);
|
|
1857
|
-
}
|
|
1930
|
+
await reportCredentials(cwd, results);
|
|
1858
1931
|
}
|
|
1859
1932
|
function formatSize(bytes) {
|
|
1860
1933
|
if (bytes < 1024) return `${bytes} B`;
|
|
@@ -2511,13 +2584,8 @@ async function deployCommand(options, deps = {}) {
|
|
|
2511
2584
|
fail(ExitCode.PRECONDITION, "--json \uC740 --yes \uC640 \uD568\uAED8 \uC4F0\uC138\uC694.");
|
|
2512
2585
|
}
|
|
2513
2586
|
if (!options.yes) assertCanConfirm(deps);
|
|
2514
|
-
const
|
|
2515
|
-
|
|
2516
|
-
fail(
|
|
2517
|
-
ExitCode.PRECONDITION,
|
|
2518
|
-
"sdk \uD15C\uD50C\uB9BF\uACFC liquid \uD15C\uD50C\uB9BF\uC774 \uD55C \uB808\uD3EC\uC5D0 \uC11E\uC5EC \uC788\uC2B5\uB2C8\uB2E4 \u2014 \uD3EC\uD138 \uBE4C\uB354\uAC00 \uD328\uD0A4\uC9D5\uD558\uC9C0 \uBABB\uD569\uB2C8\uB2E4. bstage build \uB85C \uC5B4\uB290 \uD30C\uC77C\uC774 \uAC78\uB9AC\uB294\uC9C0 \uD655\uC778\uD55C \uB4A4 \uD558\uB098\uB9CC \uB0A8\uACA8 \uC8FC\uC138\uC694."
|
|
2519
|
-
);
|
|
2520
|
-
}
|
|
2587
|
+
const report2 = detectProjectKind(deps.cwd ?? process.cwd());
|
|
2588
|
+
const kind = report2.kind;
|
|
2521
2589
|
const out = deps.out ?? console.log;
|
|
2522
2590
|
const ctx = await resolveContext({ cwd: deps.cwd, env: deps.env, fetch: deps.fetch });
|
|
2523
2591
|
const defaultBranch = await repoDefaultBranch(ctx);
|
|
@@ -2525,13 +2593,20 @@ async function deployCommand(options, deps = {}) {
|
|
|
2525
2593
|
const targets = await fetchTargets(ctx, options.placement);
|
|
2526
2594
|
if (kind === "liquid") {
|
|
2527
2595
|
assertNoSlotPlacement(targets);
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
)
|
|
2534
|
-
|
|
2596
|
+
}
|
|
2597
|
+
if (!options.json && kind === "liquid") {
|
|
2598
|
+
out(
|
|
2599
|
+
pc10.dim(
|
|
2600
|
+
"[bstage] liquid \uB808\uD3EC \u2014 \uB85C\uCEEC \uBE4C\uB4DC \uC5C6\uC774 \uD3EC\uD138\uC774 push\uB41C \uCEE4\uBC0B\uC758 public/{user|admin}/ \uC744 \uADF8\uB300\uB85C \uD328\uD0A4\uC9D5\uD569\uB2C8\uB2E4."
|
|
2601
|
+
)
|
|
2602
|
+
);
|
|
2603
|
+
}
|
|
2604
|
+
if (!options.json && kind === "mixed") {
|
|
2605
|
+
out(
|
|
2606
|
+
pc10.dim(
|
|
2607
|
+
`[bstage] \uD63C\uD569 \uB808\uD3EC \u2014 sdk \uD15C\uD50C\uB9BF\uC740 \uD3EC\uD138\uC774 \uBE4C\uB4DC\uD558\uACE0, liquid \uD15C\uD50C\uB9BF ${report2.liquidTemplates.length}\uAC1C\uB294 push\uB41C \uCEE4\uBC0B\uC758 public/{user|admin}/ \uC744 \uADF8\uB300\uB85C \uD328\uD0A4\uC9D5\uD569\uB2C8\uB2E4.`
|
|
2608
|
+
)
|
|
2609
|
+
);
|
|
2535
2610
|
}
|
|
2536
2611
|
const created = await createAndAnnounceBuild(ctx, options);
|
|
2537
2612
|
if (options.noWait) {
|
|
@@ -2555,7 +2630,7 @@ import pc11 from "picocolors";
|
|
|
2555
2630
|
import { existsSync as existsSync5, realpathSync as realpathSync2, statSync, watch } from "fs";
|
|
2556
2631
|
import { readFile as readFile5 } from "fs/promises";
|
|
2557
2632
|
import { createServer } from "http";
|
|
2558
|
-
import { join as join9, relative as relative3, sep as
|
|
2633
|
+
import { join as join9, relative as relative3, sep as sep4 } from "path";
|
|
2559
2634
|
|
|
2560
2635
|
// src/liquid/routes.ts
|
|
2561
2636
|
var RELOAD_PATH = "/__bstage__/reload";
|
|
@@ -2788,7 +2863,7 @@ function isInside(publicDir, full) {
|
|
|
2788
2863
|
try {
|
|
2789
2864
|
const base = realpathSync2(publicDir);
|
|
2790
2865
|
const real = realpathSync2(full);
|
|
2791
|
-
return real === base || real.startsWith(base +
|
|
2866
|
+
return real === base || real.startsWith(base + sep4);
|
|
2792
2867
|
} catch {
|
|
2793
2868
|
return false;
|
|
2794
2869
|
}
|
|
@@ -2961,6 +3036,27 @@ async function startLiquidDevServer(options) {
|
|
|
2961
3036
|
}
|
|
2962
3037
|
|
|
2963
3038
|
// src/commands/dev.ts
|
|
3039
|
+
function resolveDevMode(kind, requested) {
|
|
3040
|
+
if (requested !== void 0 && requested !== "sdk" && requested !== "liquid") {
|
|
3041
|
+
fail(ExitCode.PRECONDITION, `--kind \uAC12\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: ${requested} (sdk \uB610\uB294 liquid)`);
|
|
3042
|
+
}
|
|
3043
|
+
const detected = kind === "liquid" ? "liquid" : "sdk";
|
|
3044
|
+
if (kind === "mixed") {
|
|
3045
|
+
if (requested === "liquid") return { mode: "liquid" };
|
|
3046
|
+
if (requested === "sdk") return { mode: "sdk" };
|
|
3047
|
+
return {
|
|
3048
|
+
mode: "sdk",
|
|
3049
|
+
hint: "sdk\uC640 liquid \uD15C\uD50C\uB9BF\uC774 \uD568\uAED8 \uC788\uB294 \uB808\uD3EC\uC785\uB2C8\uB2E4 \u2014 \uC9C0\uAE08\uC740 sdk(Vite) \uD504\uB9AC\uBDF0\uB97C \uB744\uC6C1\uB2C8\uB2E4. liquid \uD504\uB9AC\uBDF0\uB294 `bstage dev --kind liquid` \uB85C \uB530\uB85C \uB744\uC6B0\uC138\uC694."
|
|
3050
|
+
};
|
|
3051
|
+
}
|
|
3052
|
+
if (requested !== void 0 && requested !== detected) {
|
|
3053
|
+
fail(
|
|
3054
|
+
ExitCode.PRECONDITION,
|
|
3055
|
+
`--kind ${requested}\uB85C \uC9C0\uC815\uD588\uC9C0\uB9CC \uC774 \uB808\uD3EC\uB294 ${kind}\uB85C \uD310\uC815\uB429\uB2C8\uB2E4 \u2014 \uC635\uC158\uC744 \uBE7C\uACE0 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.`
|
|
3056
|
+
);
|
|
3057
|
+
}
|
|
3058
|
+
return { mode: detected };
|
|
3059
|
+
}
|
|
2964
3060
|
async function runLiquidPreview(root, port, phase) {
|
|
2965
3061
|
if (phase !== void 0) {
|
|
2966
3062
|
console.log("[bstage] liquid \uD504\uB9AC\uBDF0\uB294 phase\uB97C \uC4F0\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 \u2014 --phase \uB97C \uBB34\uC2DC\uD569\uB2C8\uB2E4.");
|
|
@@ -2977,7 +3073,6 @@ async function runLiquidPreview(root, port, phase) {
|
|
|
2977
3073
|
console.log(` admin \uBAA9\uB85D: ${base}/admin`);
|
|
2978
3074
|
console.log(" phase\uC640 \uC778\uC99D \uD504\uB85D\uC2DC\uB294 liquid \uD504\uB9AC\uBDF0\uC5D0 \uC5C6\uC2B5\uB2C8\uB2E4. \uAC12\uC740 data.json\uC5D0\uC11C \uC635\uB2C8\uB2E4.\n");
|
|
2979
3075
|
}
|
|
2980
|
-
var MIXED_MESSAGE = "liquid \uD15C\uD50C\uB9BF(public/{user|admin}/{\uC774\uB984}/template.liquid)\uACFC React \uD15C\uD50C\uB9BF(src/**/template.tsx)\uC774 \uD55C \uB808\uD3EC\uC5D0 \uC11E\uC5EC \uC788\uC2B5\uB2C8\uB2E4. \uD3EC\uD138 \uBE4C\uB354\uAC00 \uBE4C\uB4DC\uD558\uC9C0 \uBABB\uD558\uBBC0\uB85C \uD55C\uCABD\uC73C\uB85C \uC815\uB9AC\uD55C \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.";
|
|
2981
3076
|
async function runViteDevServer(root, port, phaseOption) {
|
|
2982
3077
|
let resolved;
|
|
2983
3078
|
try {
|
|
@@ -3020,12 +3115,13 @@ async function devCommand(options) {
|
|
|
3020
3115
|
const port = parseInt(options.port, 10);
|
|
3021
3116
|
const root = process.cwd();
|
|
3022
3117
|
const report2 = detectProjectKind(root);
|
|
3023
|
-
const
|
|
3118
|
+
const decision = resolveDevMode(report2.kind, options.kind);
|
|
3024
3119
|
const ignored = ignoredLiquidNotice(report2.ignoredLiquid);
|
|
3025
3120
|
if (ignored !== null) console.log(`[bstage] ${pc11.yellow("\uACBD\uACE0")}: ${ignored}
|
|
3026
3121
|
`);
|
|
3027
|
-
if (
|
|
3028
|
-
|
|
3122
|
+
if (decision.hint !== void 0) console.log(`[bstage] ${decision.hint}
|
|
3123
|
+
`);
|
|
3124
|
+
if (decision.mode === "liquid") return await runLiquidPreview(root, port, options.phase);
|
|
3029
3125
|
await runViteDevServer(root, port, options.phase);
|
|
3030
3126
|
}
|
|
3031
3127
|
|
|
@@ -4530,6 +4626,7 @@ import {
|
|
|
4530
4626
|
parseAgentsIdentity as parseAgentsIdentity2,
|
|
4531
4627
|
readSkillStamp as readSkillStamp2,
|
|
4532
4628
|
renderManagedBlock,
|
|
4629
|
+
sanitizeIdentity as sanitizeIdentity2,
|
|
4533
4630
|
skillsFor as skillsFor4
|
|
4534
4631
|
} from "@bstage-sdk/ai-toolkit";
|
|
4535
4632
|
async function autoSyncSkills(root, report2) {
|
|
@@ -4555,10 +4652,10 @@ async function diagnoseSkills(root, kind) {
|
|
|
4555
4652
|
);
|
|
4556
4653
|
}
|
|
4557
4654
|
function resolveSkillKind(detected) {
|
|
4558
|
-
if (detected === "mixed") return
|
|
4655
|
+
if (detected === "mixed") return "mixed";
|
|
4559
4656
|
return detected === "liquid" ? "liquid" : "sdk";
|
|
4560
4657
|
}
|
|
4561
|
-
async function diagnoseAgentsMd(root, pkgName) {
|
|
4658
|
+
async function diagnoseAgentsMd(root, pkgName, kind = "sdk") {
|
|
4562
4659
|
let content;
|
|
4563
4660
|
try {
|
|
4564
4661
|
content = await readFile8(join14(root, "AGENTS.md"), "utf-8");
|
|
@@ -4568,10 +4665,10 @@ async function diagnoseAgentsMd(root, pkgName) {
|
|
|
4568
4665
|
const status = agentsMdStatus(content);
|
|
4569
4666
|
if (status === "ok") return { status, managedBlock: null };
|
|
4570
4667
|
const parsed = parseAgentsIdentity2(content);
|
|
4571
|
-
const projectName = parsed.projectName ?? pkgName ?? "custom-templates";
|
|
4572
|
-
const space = parsed.space ?? projectName.split("-custom-templates-")[0] ?? projectName;
|
|
4668
|
+
const projectName = sanitizeIdentity2(parsed.projectName) ?? sanitizeIdentity2(pkgName) ?? "custom-templates";
|
|
4669
|
+
const space = sanitizeIdentity2(parsed.space) ?? projectName.split("-custom-templates-")[0] ?? projectName;
|
|
4573
4670
|
const target = resolveProjectTarget(root);
|
|
4574
|
-
return { status, managedBlock: renderManagedBlock({ space, projectName, target }) };
|
|
4671
|
+
return { status, managedBlock: renderManagedBlock({ space, projectName, target, kind }) };
|
|
4575
4672
|
}
|
|
4576
4673
|
|
|
4577
4674
|
// src/commands/doctor/report.ts
|
|
@@ -4646,7 +4743,8 @@ async function diagnose2(root) {
|
|
|
4646
4743
|
const deps = pkg.deps;
|
|
4647
4744
|
const kind = detectProjectKind(root).kind;
|
|
4648
4745
|
const isLiquid = kind === "liquid";
|
|
4649
|
-
const
|
|
4746
|
+
const hasLiquid = isLiquid || kind === "mixed";
|
|
4747
|
+
const isBstageProject = hasLiquid || SDK_PACKAGES2.some((p5) => p5 in deps);
|
|
4650
4748
|
const installed = await collectInstalledVersions(root, deps);
|
|
4651
4749
|
const { versions, latestChecked } = await diagnoseVersions(
|
|
4652
4750
|
deps,
|
|
@@ -4667,11 +4765,11 @@ async function diagnose2(root) {
|
|
|
4667
4765
|
scripts: diagnoseScripts(pkg.scripts, tables.scripts),
|
|
4668
4766
|
recommendedDeps: diagnoseRecommendedDeps(deps, tables.deps),
|
|
4669
4767
|
migrations: await readApplicableMigrations(migrationResolver(root, deps, installed)),
|
|
4670
|
-
agentsMd: await diagnoseAgentsMd(root, pkg.name),
|
|
4671
|
-
skills:
|
|
4672
|
-
skillsSkipped:
|
|
4768
|
+
agentsMd: await diagnoseAgentsMd(root, pkg.name, skillKind),
|
|
4769
|
+
skills: await diagnoseSkills(root, skillKind),
|
|
4770
|
+
skillsSkipped: false,
|
|
4673
4771
|
latestChecked,
|
|
4674
|
-
liquid:
|
|
4772
|
+
liquid: hasLiquid ? { issues: validateLiquid(root) } : null
|
|
4675
4773
|
};
|
|
4676
4774
|
}
|
|
4677
4775
|
async function readInstalledVersion(root, pkg) {
|
|
@@ -4943,8 +5041,8 @@ function printReport(r) {
|
|
|
4943
5041
|
}
|
|
4944
5042
|
printVersions(r);
|
|
4945
5043
|
printFiles(r);
|
|
4946
|
-
if (r.
|
|
4947
|
-
|
|
5044
|
+
if (r.kind !== "liquid") printLayout(r);
|
|
5045
|
+
if (r.liquid !== null) printLiquid(r);
|
|
4948
5046
|
printPnpmWorkspace(r);
|
|
4949
5047
|
printScripts(r);
|
|
4950
5048
|
printRecommendedDeps(r);
|
|
@@ -5882,8 +5980,8 @@ function readVersion() {
|
|
|
5882
5980
|
var program = new Command().name("bstage").description("b.stage \uC11C\uB4DC\uD30C\uD2F0 \uD15C\uD50C\uB9BF SDK CLI \u2014 \uD15C\uD50C\uB9BF \uAC1C\uBC1C\xB7\uBE4C\uB4DC\xB7\uB85C\uCEEC \uC11C\uBC84\xB7\uB9C8\uC774\uADF8\uB808\uC774\uC158").version(readVersion(), "-v, --version", "\uBC84\uC804 \uCD9C\uB825");
|
|
5883
5981
|
program.command("init").description("\uC0C8 bstage \uD15C\uD50C\uB9BF \uD504\uB85C\uC81D\uD2B8 \uC0DD\uC131").option("-y, --yes", "\uAE30\uBCF8\uAC12\uC73C\uB85C \uBE44\uC778\uD130\uB799\uD2F0\uBE0C \uC2E4\uD589").option("--space <space>", "Space \uC774\uB984").option("--target <target>", "\uC2A4\uCE90\uD3F4\uB4DC \uB300\uC0C1 (user, admin)", "user").option("--kind <kind>", "\uD504\uB85C\uC81D\uD2B8 \uC885\uB958 (sdk: React \uCEF4\uD3EC\uB10C\uD2B8, liquid: liquid \uD15C\uD50C\uB9BF)", "sdk").option("--template <template>", "\uCCAB \uBC88\uC9F8 \uD15C\uD50C\uB9BF \uC774\uB984 (\uAE30\uBCF8: sdk {space}-hello, liquid hello)").option("--phase <phase>", "\uBC30\uD3EC \uD658\uACBD (dev, qa, real, sandbox)", "sandbox").option("--pm <pm>", "\uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800 (npm, pnpm)", "npm").action(initCommand);
|
|
5884
5982
|
program.command("build").description(
|
|
5885
|
-
"\uD15C\uD50C\uB9BF\uC744 IIFE \uBC88\uB4E4\uB85C \uBE4C\uB4DC (\uD398\uC774\uC9C0\uB294 \uACBD\uB85C\uBCC4, \uC704\uC82F\uC740 \uC2AC\uB86F\uBCC4 \uB514\uB809\uD1A0\uB9AC) \u2014 liquid \uB808\uD3EC\uB294 \uAC80\uC99D\uB9CC"
|
|
5886
|
-
).option("--json", "\uAC80\uC99D \uACB0\uACFC\
|
|
5983
|
+
"\uD15C\uD50C\uB9BF\uC744 IIFE \uBC88\uB4E4\uB85C \uBE4C\uB4DC (\uD398\uC774\uC9C0\uB294 \uACBD\uB85C\uBCC4, \uC704\uC82F\uC740 \uC2AC\uB86F\uBCC4 \uB514\uB809\uD1A0\uB9AC) \u2014 liquid \uB808\uD3EC\uB294 \uAC80\uC99D\uB9CC, \uD63C\uD569 \uB808\uD3EC\uB294 sdk \uBC88\uB4E4 + liquid \uAC80\uC99D"
|
|
5984
|
+
).option("--json", "\uAC80\uC99D \uACB0\uACFC\xB7\uC0B0\uCD9C\uBB3C \uC694\uC57D\uC744 JSON\uC73C\uB85C \uCD9C\uB825 (liquid\xB7\uD63C\uD569 \uB808\uD3EC)").action((options) => buildCommand(options));
|
|
5887
5985
|
program.command("docs").description("\uC124\uCE58\uB41C SDK \uBB38\uC11C \uBAA9\uB85D\xB7\uACBD\uB85C \uCD9C\uB825").action(docsCommand);
|
|
5888
5986
|
program.command("doctor").description(
|
|
5889
5987
|
"SDK \uBC84\uC804\xB7\uBCF4\uC77C\uB7EC\uD50C\uB808\uC774\uD2B8 \uB4DC\uB9AC\uD504\uD2B8 \uC9C4\uB2E8 (\uC9C4\uB2E8 + SDK \uC18C\uC720 \uC2A4\uD0AC \uC790\uB3D9 \uB3D9\uAE30\uD654; package.json\xB7\uD6C5\uC740 \uAC74\uB4DC\uB9AC\uC9C0 \uC54A\uC74C)"
|
|
@@ -5891,6 +5989,9 @@ program.command("doctor").description(
|
|
|
5891
5989
|
program.command("dev").description("\uC778\uC99D \uD504\uB85D\uC2DC \uD3EC\uD568 \uB85C\uCEEC \uAC1C\uBC1C \uC11C\uBC84 (liquid \uB808\uD3EC\uB294 liquidjs \uD504\uB9AC\uBDF0)").option("-p, --port <port>", "Dev server port", "5173").option(
|
|
5892
5990
|
"--phase <phase>",
|
|
5893
5991
|
"Target phase (dev, qa, real, sandbox). \uC0DD\uB7B5 \uC2DC .env\uC758 VITE_BSTAGE_PHASE, \uADF8\uAC83\uB3C4 \uC5C6\uC73C\uBA74 sandbox"
|
|
5992
|
+
).option(
|
|
5993
|
+
"--kind <kind>",
|
|
5994
|
+
"\uD63C\uD569 \uB808\uD3EC(sdk + liquid)\uC5D0\uC11C \uB744\uC6B8 \uD504\uB9AC\uBDF0 (sdk: Vite \uAE30\uBCF8, liquid: liquidjs)"
|
|
5894
5995
|
).action((o) => runCommand(() => devCommand(o)));
|
|
5895
5996
|
var ai = program.command("ai").description("\uC5D0\uC774\uC804\uD2B8\uC6A9 \uC2A4\uD0AC\xB7AGENTS.md \uC124\uCE58\xB7\uB3D9\uAE30\uD654\xB7\uC9C4\uB2E8");
|
|
5896
5997
|
ai.command("install").description("\uC2A4\uD0AC(.claude/skills)\xB7AGENTS.md\xB7CLAUDE.md \uC124\uCE58 \uBC0F \uCD5C\uC2E0\uD654 + pre-commit \uC2DC\uD06C\uB9BF \uAC00\uB4DC").option("--dir <dir>", "\uC2A4\uD0AC \uB514\uB809\uD130\uB9AC", ".claude/skills").option("--kind <kind>", "\uD504\uB85C\uC81D\uD2B8 \uC885\uB958(sdk|liquid) \u2014 \uC790\uB3D9 \uD310\uC815\uC774 \uC548 \uB420 \uB54C").action((o) => runCommand(() => aiInstallCommand(o)));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bstage-sdk/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "bstage SDK CLI — build b.stage templates",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -32,14 +32,14 @@
|
|
|
32
32
|
"liquidjs": "^10.24.0",
|
|
33
33
|
"picocolors": "^1.1.1",
|
|
34
34
|
"vite": "^7.0.0",
|
|
35
|
-
"@bstage-sdk/ai-toolkit": "0.
|
|
36
|
-
"@bstage-sdk/core": "0.
|
|
35
|
+
"@bstage-sdk/ai-toolkit": "0.6.0",
|
|
36
|
+
"@bstage-sdk/core": "0.6.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@types/node": "^25.5.0",
|
|
40
40
|
"tsup": "^8.0.0",
|
|
41
41
|
"typescript": "^5.5.0",
|
|
42
|
-
"@bstage-sdk/design": "0.
|
|
42
|
+
"@bstage-sdk/design": "0.6.0"
|
|
43
43
|
},
|
|
44
44
|
"license": "MIT",
|
|
45
45
|
"scripts": {
|