@bstage-sdk/cli 0.6.1 → 0.8.1

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.js CHANGED
@@ -166,6 +166,14 @@ var PortalClient = class {
166
166
  { buildId, expectedLiveBuildId }
167
167
  );
168
168
  }
169
+ /**
170
+ * `POST .../placements` — 배치를 만든다(CLI 토큰은 deploy 등급 필요). 응답은 래퍼 없이
171
+ * 배치 하나(201). 포털이 최신 SUCCEEDED 빌드의 산출물에서 kind·경로를 검증·파생하므로
172
+ * `path`는 기본 경로를 바꿀 때만 보낸다. 비멱등 POST라 네트워크 재시도하지 않는다.
173
+ */
174
+ createPlacement(org, space, input) {
175
+ return this.json("POST", `${this.stage(org, space)}/placements`, input);
176
+ }
169
177
  async setPlacementEnabled(org, space, placementId, enabled) {
170
178
  const r = await this.json(
171
179
  "PATCH",
@@ -1938,12 +1946,12 @@ function formatSize(bytes) {
1938
1946
  }
1939
1947
 
1940
1948
  // src/commands/deploy.ts
1941
- import pc10 from "picocolors";
1949
+ import pc11 from "picocolors";
1942
1950
 
1943
1951
  // src/portal/applyPlacements.ts
1944
1952
  import pc8 from "picocolors";
1945
- function publishHint(placement) {
1946
- return placement.enabled === false ? "\uAC8C\uC2DC \uAEBC\uC9D0 \u2014 bstage publish \uB85C \uAC8C\uC2DC\uD574\uC57C \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uBCF4\uC785\uB2C8\uB2E4." : void 0;
1953
+ function publishHint(placement2) {
1954
+ return placement2.enabled === false ? "\uAC8C\uC2DC \uAEBC\uC9D0 \u2014 bstage publish \uB85C \uAC8C\uC2DC\uD574\uC57C \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uBCF4\uC785\uB2C8\uB2E4." : void 0;
1947
1955
  }
1948
1956
  async function applyPlacements(ctx, plan) {
1949
1957
  const { organizationId: org, spaceId: space } = ctx.link;
@@ -2028,6 +2036,9 @@ function assertCanConfirm(deps) {
2028
2036
  );
2029
2037
  }
2030
2038
 
2039
+ // src/portal/buildFlow.ts
2040
+ import pc10 from "picocolors";
2041
+
2031
2042
  // src/portal/git.ts
2032
2043
  import { execFile } from "child_process";
2033
2044
  import { promisify } from "util";
@@ -2083,6 +2094,117 @@ function assertDeployable(state, defaultBranch) {
2083
2094
  }
2084
2095
  }
2085
2096
 
2097
+ // src/portal/waitBuild.ts
2098
+ import pc9 from "picocolors";
2099
+
2100
+ // src/portal/types.ts
2101
+ var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
2102
+ "SUCCEEDED",
2103
+ "FAILED",
2104
+ "TIMED_OUT",
2105
+ "CANCELED"
2106
+ ]);
2107
+ function placementLabel(p5) {
2108
+ return p5.kind === "SLOT" ? p5.slotId ?? p5.artifact ?? p5.id : p5.path ?? p5.artifact ?? p5.id;
2109
+ }
2110
+
2111
+ // src/portal/waitBuild.ts
2112
+ var DEFAULT_INTERVAL = 3e3;
2113
+ var DEFAULT_TIMEOUT = 20 * 60 * 1e3;
2114
+ async function waitForBuild(client, org, space, buildId, o = {}) {
2115
+ const interval = o.intervalMs ?? DEFAULT_INTERVAL;
2116
+ const timeout = o.timeoutMs ?? DEFAULT_TIMEOUT;
2117
+ const sleep = o.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
2118
+ const started = Date.now();
2119
+ let seen = 0;
2120
+ let logFailing = false;
2121
+ const flushLog = async () => {
2122
+ if (!o.onLog) return;
2123
+ let log3;
2124
+ try {
2125
+ log3 = await client.getBuildLog(org, space, buildId);
2126
+ } catch {
2127
+ if (!logFailing) {
2128
+ console.error(pc9.dim("[bstage] \uB85C\uADF8 \uC870\uD68C \uC2E4\uD328, \uB2E4\uC74C \uD3F4\uB9C1\uC5D0\uC11C \uC7AC\uC2DC\uB3C4\uD569\uB2C8\uB2E4."));
2129
+ logFailing = true;
2130
+ }
2131
+ return;
2132
+ }
2133
+ logFailing = false;
2134
+ if (log3.length < seen) {
2135
+ o.onLog("\n[bstage] \uB85C\uADF8\uAC00 \uC7AC\uC2DC\uC791\uB41C \uAC83\uC73C\uB85C \uBCF4\uC785\uB2C8\uB2E4 \u2014 \uCC98\uC74C\uBD80\uD130 \uB2E4\uC2DC \uCD9C\uB825\uD569\uB2C8\uB2E4.\n");
2136
+ seen = 0;
2137
+ }
2138
+ if (log3.length > seen) {
2139
+ o.onLog(log3.slice(seen));
2140
+ seen = log3.length;
2141
+ }
2142
+ };
2143
+ for (; ; ) {
2144
+ const build = await client.getBuild(org, space, buildId);
2145
+ await flushLog();
2146
+ if (TERMINAL_STATUSES.has(build.status)) return build;
2147
+ if (Date.now() - started > timeout) {
2148
+ fail(
2149
+ ExitCode.FAILURE,
2150
+ `\uBE4C\uB4DC ${buildId} \uAC00 ${Math.round(timeout / 6e4)}\uBD84 \uC548\uC5D0 \uB05D\uB098\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uD3EC\uD138\uC5D0\uC11C \uC0C1\uD0DC\uB97C \uD655\uC778\uD558\uC138\uC694.`
2151
+ );
2152
+ }
2153
+ await sleep(interval);
2154
+ }
2155
+ }
2156
+
2157
+ // src/portal/buildFlow.ts
2158
+ async function repoDefaultBranch(ctx) {
2159
+ const repos = await ctx.client.listRepos(ctx.link.organizationId, ctx.link.spaceId);
2160
+ const repo = repos.find((r) => r.id === ctx.link.repoId);
2161
+ if (!repo) {
2162
+ fail(
2163
+ ExitCode.PRECONDITION,
2164
+ `\uC5F0\uACB0\uB41C \uB808\uD3EC ${ctx.link.repoId} \uB97C \uD3EC\uD138\uC5D0\uC11C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. bstage link \uB97C \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.`
2165
+ );
2166
+ }
2167
+ return repo.defaultBranch;
2168
+ }
2169
+ async function precheckGit(deps, defaultBranch) {
2170
+ const exec = deps.exec ?? gitExec(deps.cwd ?? process.cwd());
2171
+ let state;
2172
+ try {
2173
+ state = await readGitState(exec);
2174
+ } catch (err) {
2175
+ fail(
2176
+ ExitCode.PRECONDITION,
2177
+ `git \uC0C1\uD0DC\uB97C \uD655\uC778\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${err instanceof Error ? err.message : String(err)}. git\uC774 \uC124\uCE58\uB3FC \uC788\uACE0 \uC774 \uB514\uB809\uD130\uB9AC\uAC00 git \uC800\uC7A5\uC18C\uC778\uC9C0 \uD655\uC778\uD558\uAC70\uB098 --skip-git-check \uB85C \uAC74\uB108\uB6F0\uC138\uC694.`
2178
+ );
2179
+ }
2180
+ assertDeployable(state, defaultBranch);
2181
+ }
2182
+ async function createAndAnnounceBuild(ctx, json) {
2183
+ const created = await ctx.client.createBuild(
2184
+ ctx.link.organizationId,
2185
+ ctx.link.spaceId,
2186
+ ctx.link.repoId
2187
+ );
2188
+ if (!json) {
2189
+ console.error(pc10.dim(`[bstage] \uBE4C\uB4DC ${created.id} \uC2DC\uC791 (${shortSha(created.commitSha)})`));
2190
+ }
2191
+ return created;
2192
+ }
2193
+ async function waitForCompletedBuild(ctx, deps, build, json) {
2194
+ const { organizationId: org, spaceId: space } = ctx.link;
2195
+ const done = await waitForBuild(ctx.client, org, space, build.id, {
2196
+ sleep: deps.sleep,
2197
+ onLog: json ? void 0 : (delta) => process.stderr.write(pc10.dim(delta))
2198
+ });
2199
+ if (done.status !== "SUCCEEDED") {
2200
+ fail(
2201
+ ExitCode.FAILURE,
2202
+ `\uBE4C\uB4DC ${done.id} \uC2E4\uD328: ${done.status}${done.failureReason ? ` (${done.failureReason})` : ""}. bstage logs ${done.id} \uB85C \uB85C\uADF8\uB97C \uD655\uC778\uD558\uC138\uC694.`
2203
+ );
2204
+ }
2205
+ return done;
2206
+ }
2207
+
2086
2208
  // src/portal/config.ts
2087
2209
  import { mkdir as mkdir2, readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
2088
2210
  import { dirname as dirname5, join as join7 } from "path";
@@ -2397,17 +2519,6 @@ async function resolveContext(opts = {}) {
2397
2519
  };
2398
2520
  }
2399
2521
 
2400
- // src/portal/types.ts
2401
- var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
2402
- "SUCCEEDED",
2403
- "FAILED",
2404
- "TIMED_OUT",
2405
- "CANCELED"
2406
- ]);
2407
- function placementLabel(p5) {
2408
- return p5.kind === "SLOT" ? p5.slotId ?? p5.artifact ?? p5.id : p5.path ?? p5.artifact ?? p5.id;
2409
- }
2410
-
2411
2522
  // src/portal/selectPlacements.ts
2412
2523
  function selectPlacements(all, repoId, filter) {
2413
2524
  const mine = all.filter((p5) => p5.stageRepoId === repoId);
@@ -2426,7 +2537,7 @@ function applyPlan(placements, buildId) {
2426
2537
  function requireTargets(all, repoId, filter, buildIdHint) {
2427
2538
  const mine = selectPlacements(all, repoId, filter);
2428
2539
  if (mine.length > 0) return mine;
2429
- const base = filter ? `\uBC30\uCE58 '${filter}' \uC744(\uB97C) \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. bstage list \uB85C \uD655\uC778\uD558\uC138\uC694.` : "\uC774 \uB808\uD3EC\uC5D0 \uC5F0\uACB0\uB41C \uBC30\uCE58\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. \uD3EC\uD138 > \uC2A4\uD14C\uC774\uC9C0 > \uD398\uC774\uC9C0\uC5D0\uC11C \uBC30\uCE58\uB97C \uBA3C\uC800 \uB9CC\uB4DC\uC138\uC694.";
2540
+ const base = filter ? `\uBC30\uCE58 '${filter}' \uC744(\uB97C) \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. bstage list \uB85C \uD655\uC778\uD558\uC138\uC694.` : "\uC774 \uB808\uD3EC\uC5D0 \uC5F0\uACB0\uB41C \uBC30\uCE58\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. bstage placement create --template <\uC0B0\uCD9C\uBB3C \uC774\uB984> [--path /\uACBD\uB85C] \uB85C \uD398\uC774\uC9C0 \uBC30\uCE58\uB97C \uBA3C\uC800 \uB9CC\uB4DC\uC138\uC694(\uC131\uACF5\uD55C \uBE4C\uB4DC\uAC00 \uC5C6\uC73C\uBA74 \uBE4C\uB4DC\uBD80\uD130 \uD569\uB2C8\uB2E4). \uC704\uC82F(\uC2AC\uB86F) \uBC30\uCE58\uB294 \uD3EC\uD138 \uD654\uBA74\uC5D0\uC11C \uB9CC\uB4ED\uB2C8\uB2E4.";
2430
2541
  const hint = buildIdHint ? ` \uBE4C\uB4DC ${buildIdHint} \uB294 \uB0A8\uC544 \uC788\uC73C\uB2C8 \uBC30\uCE58\uB97C \uD655\uC778\uD55C \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD574 \uC801\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.` : "";
2431
2542
  return fail(ExitCode.PRECONDITION, base + hint);
2432
2543
  }
@@ -2439,53 +2550,6 @@ async function fetchTargets(ctx, filter, buildIdHint) {
2439
2550
  return requireTargets(all, ctx.link.repoId, filter, buildIdHint);
2440
2551
  }
2441
2552
 
2442
- // src/portal/waitBuild.ts
2443
- import pc9 from "picocolors";
2444
- var DEFAULT_INTERVAL = 3e3;
2445
- var DEFAULT_TIMEOUT = 20 * 60 * 1e3;
2446
- async function waitForBuild(client, org, space, buildId, o = {}) {
2447
- const interval = o.intervalMs ?? DEFAULT_INTERVAL;
2448
- const timeout = o.timeoutMs ?? DEFAULT_TIMEOUT;
2449
- const sleep = o.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
2450
- const started = Date.now();
2451
- let seen = 0;
2452
- let logFailing = false;
2453
- const flushLog = async () => {
2454
- if (!o.onLog) return;
2455
- let log3;
2456
- try {
2457
- log3 = await client.getBuildLog(org, space, buildId);
2458
- } catch {
2459
- if (!logFailing) {
2460
- console.error(pc9.dim("[bstage] \uB85C\uADF8 \uC870\uD68C \uC2E4\uD328, \uB2E4\uC74C \uD3F4\uB9C1\uC5D0\uC11C \uC7AC\uC2DC\uB3C4\uD569\uB2C8\uB2E4."));
2461
- logFailing = true;
2462
- }
2463
- return;
2464
- }
2465
- logFailing = false;
2466
- if (log3.length < seen) {
2467
- o.onLog("\n[bstage] \uB85C\uADF8\uAC00 \uC7AC\uC2DC\uC791\uB41C \uAC83\uC73C\uB85C \uBCF4\uC785\uB2C8\uB2E4 \u2014 \uCC98\uC74C\uBD80\uD130 \uB2E4\uC2DC \uCD9C\uB825\uD569\uB2C8\uB2E4.\n");
2468
- seen = 0;
2469
- }
2470
- if (log3.length > seen) {
2471
- o.onLog(log3.slice(seen));
2472
- seen = log3.length;
2473
- }
2474
- };
2475
- for (; ; ) {
2476
- const build = await client.getBuild(org, space, buildId);
2477
- await flushLog();
2478
- if (TERMINAL_STATUSES.has(build.status)) return build;
2479
- if (Date.now() - started > timeout) {
2480
- fail(
2481
- ExitCode.FAILURE,
2482
- `\uBE4C\uB4DC ${buildId} \uAC00 ${Math.round(timeout / 6e4)}\uBD84 \uC548\uC5D0 \uB05D\uB098\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uD3EC\uD138\uC5D0\uC11C \uC0C1\uD0DC\uB97C \uD655\uC778\uD558\uC138\uC694.`
2483
- );
2484
- }
2485
- await sleep(interval);
2486
- }
2487
- }
2488
-
2489
2553
  // src/commands/deploy.ts
2490
2554
  function assertNoSlotPlacement(targets) {
2491
2555
  const slots = targets.filter((p5) => p5.kind === "SLOT");
@@ -2497,41 +2561,6 @@ function assertNoSlotPlacement(targets) {
2497
2561
  )}. --placement \uB85C \uD398\uC774\uC9C0 \uBC30\uCE58\uB9CC \uACE0\uB974\uAC70\uB098, \uD3EC\uD138\uC5D0\uC11C \uC774 \uB808\uD3EC\uC758 \uC704\uC82F \uBC30\uCE58\uB97C \uC815\uB9AC\uD558\uC138\uC694.`
2498
2562
  );
2499
2563
  }
2500
- async function repoDefaultBranch(ctx) {
2501
- const repos = await ctx.client.listRepos(ctx.link.organizationId, ctx.link.spaceId);
2502
- const repo = repos.find((r) => r.id === ctx.link.repoId);
2503
- if (!repo) {
2504
- fail(
2505
- ExitCode.PRECONDITION,
2506
- `\uC5F0\uACB0\uB41C \uB808\uD3EC ${ctx.link.repoId} \uB97C \uD3EC\uD138\uC5D0\uC11C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. bstage link \uB97C \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694.`
2507
- );
2508
- }
2509
- return repo.defaultBranch;
2510
- }
2511
- async function precheckGit(deps, defaultBranch) {
2512
- const exec = deps.exec ?? gitExec(deps.cwd ?? process.cwd());
2513
- let state;
2514
- try {
2515
- state = await readGitState(exec);
2516
- } catch (err) {
2517
- fail(
2518
- ExitCode.PRECONDITION,
2519
- `git \uC0C1\uD0DC\uB97C \uD655\uC778\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${err instanceof Error ? err.message : String(err)}. git\uC774 \uC124\uCE58\uB3FC \uC788\uACE0 \uC774 \uB514\uB809\uD130\uB9AC\uAC00 git \uC800\uC7A5\uC18C\uC778\uC9C0 \uD655\uC778\uD558\uAC70\uB098 --skip-git-check \uB85C \uAC74\uB108\uB6F0\uC138\uC694.`
2520
- );
2521
- }
2522
- assertDeployable(state, defaultBranch);
2523
- }
2524
- async function createAndAnnounceBuild(ctx, options) {
2525
- const created = await ctx.client.createBuild(
2526
- ctx.link.organizationId,
2527
- ctx.link.spaceId,
2528
- ctx.link.repoId
2529
- );
2530
- if (!options.json) {
2531
- console.error(pc10.dim(`[bstage] \uBE4C\uB4DC ${created.id} \uC2DC\uC791 (${shortSha(created.commitSha)})`));
2532
- }
2533
- return created;
2534
- }
2535
2564
  function reportNoWait(build, options, out) {
2536
2565
  if (options.json) {
2537
2566
  printJson(jsonSummary([], { build }));
@@ -2541,20 +2570,6 @@ function reportNoWait(build, options, out) {
2541
2570
  `\uBE4C\uB4DC ${build.id} \uB97C \uC2DC\uC791\uD588\uC2B5\uB2C8\uB2E4. bstage logs ${build.id} --follow \uB85C \uC9C4\uD589 \uC0C1\uD669\uC744 \uD655\uC778\uD558\uC138\uC694.`
2542
2571
  );
2543
2572
  }
2544
- async function waitForCompletedBuild(ctx, deps, build, json) {
2545
- const { organizationId: org, spaceId: space } = ctx.link;
2546
- const done = await waitForBuild(ctx.client, org, space, build.id, {
2547
- sleep: deps.sleep,
2548
- onLog: json ? void 0 : (delta) => process.stderr.write(pc10.dim(delta))
2549
- });
2550
- if (done.status !== "SUCCEEDED") {
2551
- fail(
2552
- ExitCode.FAILURE,
2553
- `\uBE4C\uB4DC ${done.id} \uC2E4\uD328: ${done.status}${done.failureReason ? ` (${done.failureReason})` : ""}. bstage logs ${done.id} \uB85C \uB85C\uADF8\uB97C \uD655\uC778\uD558\uC138\uC694.`
2554
- );
2555
- }
2556
- return done;
2557
- }
2558
2573
  function renderPlanTable(plan, build) {
2559
2574
  const header2 = `\uBE4C\uB4DC ${build.id} (\uCEE4\uBC0B ${shortSha(build.commitSha)})`;
2560
2575
  const rows = table([
@@ -2596,19 +2611,19 @@ async function deployCommand(options, deps = {}) {
2596
2611
  }
2597
2612
  if (!options.json && kind === "liquid") {
2598
2613
  out(
2599
- pc10.dim(
2614
+ pc11.dim(
2600
2615
  "[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
2616
  )
2602
2617
  );
2603
2618
  }
2604
2619
  if (!options.json && kind === "mixed") {
2605
2620
  out(
2606
- pc10.dim(
2621
+ pc11.dim(
2607
2622
  `[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
2623
  )
2609
2624
  );
2610
2625
  }
2611
- const created = await createAndAnnounceBuild(ctx, options);
2626
+ const created = await createAndAnnounceBuild(ctx, options.json);
2612
2627
  if (options.noWait) {
2613
2628
  reportNoWait(created, options, out);
2614
2629
  return;
@@ -2624,7 +2639,7 @@ async function deployCommand(options, deps = {}) {
2624
2639
  // src/commands/dev.ts
2625
2640
  import { createServer as createViteServer, searchForWorkspaceRoot } from "vite";
2626
2641
  import react from "@vitejs/plugin-react";
2627
- import pc11 from "picocolors";
2642
+ import pc12 from "picocolors";
2628
2643
 
2629
2644
  // src/liquid/server.ts
2630
2645
  import { existsSync as existsSync5, realpathSync as realpathSync2, statSync, watch } from "fs";
@@ -3117,7 +3132,7 @@ async function devCommand(options) {
3117
3132
  const report2 = detectProjectKind(root);
3118
3133
  const decision = resolveDevMode(report2.kind, options.kind);
3119
3134
  const ignored = ignoredLiquidNotice(report2.ignoredLiquid);
3120
- if (ignored !== null) console.log(`[bstage] ${pc11.yellow("\uACBD\uACE0")}: ${ignored}
3135
+ if (ignored !== null) console.log(`[bstage] ${pc12.yellow("\uACBD\uACE0")}: ${ignored}
3121
3136
  `);
3122
3137
  if (decision.hint !== void 0) console.log(`[bstage] ${decision.hint}
3123
3138
  `);
@@ -3127,7 +3142,7 @@ async function devCommand(options) {
3127
3142
 
3128
3143
  // src/commands/init.ts
3129
3144
  import * as p3 from "@clack/prompts";
3130
- import pc13 from "picocolors";
3145
+ import pc14 from "picocolors";
3131
3146
  import { existsSync as existsSync6 } from "fs";
3132
3147
  import { execSync } from "child_process";
3133
3148
  import { resolve as resolve3 } from "path";
@@ -3284,7 +3299,7 @@ API \uD0A4(APP-ID/APP KEY)\uB294 \`.env\`\uC5D0\uC11C \uC124\uC815\uD569\uB2C8\u
3284
3299
 
3285
3300
  \uD3EC\uD138\uC740 **\uC6D0\uACA9 \uC800\uC7A5\uC18C \uAE30\uBCF8 \uBE0C\uB79C\uCE58\uC5D0 push\uB41C \uCEE4\uBC0B**\uC744 \uBE4C\uB4DC\uD569\uB2C8\uB2E4. \uB85C\uCEEC \uBE4C\uB4DC \uC0B0\uCD9C\uBB3C\uC744 \uC62C\uB9AC\uB294 \uAC83\uC774 \uC544\uB2C8\uBBC0\uB85C push\uD558\uC9C0 \uC54A\uC740 \uBCC0\uACBD\uC740 \uBC18\uC601\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.
3286
3301
 
3287
- 1. \uCC98\uC74C \uD55C \uBC88(\uD3EC\uD138 \uD654\uBA74\uC5D0\uC11C\uB9CC \uAC00\uB2A5): \uC2A4\uD14C\uC774\uC9C0\uC5D0 \uC774 \uB808\uD3EC\uB97C \uC5F0\uACB0 \u2192 \uCCAB \uBE4C\uB4DC \u2192 \uD398\uC774\uC9C0(\uBC30\uCE58) \uB9CC\uB4E4\uAE30 \u2192 \uAC8C\uC2DC\uD558\uAE30.
3302
+ 1. \uCC98\uC74C \uD55C \uBC88: \uD3EC\uD138 \uD654\uBA74\uC5D0\uC11C \uC2A4\uD14C\uC774\uC9C0\uC5D0 \uC774 \uB808\uD3EC\uB97C \uC5F0\uACB0 \u2192 \uD130\uBBF8\uB110\uC5D0\uC11C \`npx bstage placement create --template <\uD398\uC774\uC9C0 \uC774\uB984> --path /<\uACBD\uB85C>\`(\uBE4C\uB4DC\uAC00 \uC5C6\uC73C\uBA74 \uBE4C\uB4DC\uBD80\uD130) \u2192 \`npx bstage deploy\`.
3288
3303
  2. \uC774\uD6C4: \uACE0\uCE5C \uB4A4 \uCEE4\uBC0B\xB7push \u2192 \`npx bstage deploy\`. \uB418\uB3CC\uB9AC\uAE30\uB294 \`npx bstage rollback\`, \uAE09\uD788 \uB0B4\uB9B4 \uB54C\uB294 \`npx bstage publish off\`.
3289
3304
 
3290
3305
  \uD130\uBBF8\uB110\uC740 \`npx bstage login\`(\uBE0C\uB77C\uC6B0\uC800 \uC2B9\uC778) \u2192 \`npx bstage link\`(\uC870\uC9C1\xB7\uC2A4\uD14C\uC774\uC9C0\xB7\uB808\uD3EC \uC5F0\uACB0) \uC21C\uC11C\uB85C \uD55C \uBC88 \uC900\uBE44\uD569\uB2C8\uB2E4. \uC808\uCC28\uC640 \uC2E4\uD328 \uB300\uC751\uC740 \`.claude/skills/bstage-deploy/SKILL.md\`\uC5D0 \uC788\uC2B5\uB2C8\uB2E4.
@@ -4003,17 +4018,17 @@ function buildFiles2(input) {
4003
4018
 
4004
4019
  // src/commands/init/prompts.ts
4005
4020
  import * as p2 from "@clack/prompts";
4006
- import pc12 from "picocolors";
4021
+ import pc13 from "picocolors";
4007
4022
  var PHASES = ["dev", "qa", "real", "sandbox"];
4008
4023
  var TARGETS = ["user", "admin"];
4009
4024
  var KINDS = ["sdk", "liquid"];
4010
4025
  function fail2(message) {
4011
4026
  p2.log.error(message);
4012
- p2.outro(pc12.red("\uC911\uB2E8\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
4027
+ p2.outro(pc13.red("\uC911\uB2E8\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
4013
4028
  process.exit(1);
4014
4029
  }
4015
4030
  function cancelled() {
4016
- p2.outro(pc12.red("\uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
4031
+ p2.outro(pc13.red("\uCDE8\uC18C\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
4017
4032
  process.exit(0);
4018
4033
  }
4019
4034
  var ELEMENT_NAME_RE2 = /^[a-z][a-z0-9-]*-[a-z0-9-]*$/;
@@ -4067,12 +4082,12 @@ function answersFromOptions(options) {
4067
4082
  if (!options.space) fail2("--yes \uBAA8\uB4DC\uC5D0\uC11C\uB294 --space\uAC00 \uD544\uC218\uC785\uB2C8\uB2E4.");
4068
4083
  if (!SPACE_RE.test(options.space)) {
4069
4084
  fail2(
4070
- `${pc12.red("--space")} \uAC12\uC740 \uC601\uBB38\uC790\uB85C \uC2DC\uC791\uD574\uC57C \uD558\uBA70, \uC601\uBB38, \uC22B\uC790, \uD558\uC774\uD508\uB9CC \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.`
4085
+ `${pc13.red("--space")} \uAC12\uC740 \uC601\uBB38\uC790\uB85C \uC2DC\uC791\uD574\uC57C \uD558\uBA70, \uC601\uBB38, \uC22B\uC790, \uD558\uC774\uD508\uB9CC \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.`
4071
4086
  );
4072
4087
  }
4073
4088
  const templateName = kind === "liquid" ? options.template ?? LIQUID_DEFAULT_TEMPLATE : resolveTemplateName(options.space, options.template);
4074
4089
  const nameError = validateTemplateName(kind)(templateName);
4075
- if (nameError) fail2(`${pc12.red("--template")} \uAC12\uC774 \uADDC\uCE59\uC5D0 \uB9DE\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: ${nameError}`);
4090
+ if (nameError) fail2(`${pc13.red("--template")} \uAC12\uC774 \uADDC\uCE59\uC5D0 \uB9DE\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: ${nameError}`);
4076
4091
  const phaseOpt = options.phase ?? "sandbox";
4077
4092
  if (!PHASES.includes(phaseOpt)) {
4078
4093
  fail2(`--phase \uAC12\uC740 ${PHASES.join(" | ")} \uC911 \uD558\uB098\uC5EC\uC57C \uD569\uB2C8\uB2E4.`);
@@ -4129,7 +4144,7 @@ async function answersFromPrompts(options) {
4129
4144
  });
4130
4145
  if (p2.isCancel(phase)) cancelled();
4131
4146
  const templateName = await p2.text({
4132
- message: kind === "liquid" ? `\uCCAB \uBC88\uC9F8 \uD15C\uD50C\uB9BF \uC774\uB984\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694. ${pc12.dim(`(${LIQUID_NAME_HINT})`)}` : `\uCCAB \uBC88\uC9F8 \uD15C\uD50C\uB9BF \uC774\uB984\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694. ${pc12.dim(`(\uC608: ${space}-hello \u2014 \uD558\uC774\uD508 \uD544\uC218)`)}`,
4147
+ message: kind === "liquid" ? `\uCCAB \uBC88\uC9F8 \uD15C\uD50C\uB9BF \uC774\uB984\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694. ${pc13.dim(`(${LIQUID_NAME_HINT})`)}` : `\uCCAB \uBC88\uC9F8 \uD15C\uD50C\uB9BF \uC774\uB984\uC744 \uC785\uB825\uD574 \uC8FC\uC138\uC694. ${pc13.dim(`(\uC608: ${space}-hello \u2014 \uD558\uC774\uD508 \uD544\uC218)`)}`,
4133
4148
  placeholder: kind === "liquid" ? LIQUID_DEFAULT_TEMPLATE : resolveTemplateName(space, void 0),
4134
4149
  validate: validateTemplateName(kind)
4135
4150
  });
@@ -4155,7 +4170,7 @@ async function promptCredentials(space) {
4155
4170
  });
4156
4171
  if (p2.isCancel(configureAuth)) cancelled();
4157
4172
  if (!configureAuth) return empty;
4158
- p2.log.info(pc12.dim("API \uC778\uC99D \uC124\uC815 (\uC120\uD0DD)"));
4173
+ p2.log.info(pc13.dim("API \uC778\uC99D \uC124\uC815 (\uC120\uD0DD)"));
4159
4174
  const appId = await p2.text({
4160
4175
  message: "\uD30C\uD2B8\uB108 \uCF58\uC194\uC5D0\uC11C \uBC1C\uAE09\uBC1B\uC740 APP-ID\uB97C \uC785\uB825\uD574 \uC8FC\uC138\uC694."
4161
4176
  }) ?? "";
@@ -4174,16 +4189,16 @@ async function collectInitAnswers(options) {
4174
4189
  // src/commands/init.ts
4175
4190
  var DEV_PORT = 5173;
4176
4191
  async function initCommand(options) {
4177
- p3.intro(`${pc13.cyan(pc13.bold("bstage init"))} ${pc13.dim("\u2014 b.stage Template Project Setup")}`);
4192
+ p3.intro(`${pc14.cyan(pc14.bold("bstage init"))} ${pc14.dim("\u2014 b.stage Template Project Setup")}`);
4178
4193
  const answers = await collectInitAnswers(options);
4179
4194
  const { kind, space, packageManager, phase, target } = answers;
4180
4195
  const projectName = `${space}-custom-templates-${phase}`;
4181
4196
  const projectDir = resolve3(process.cwd(), projectName);
4182
4197
  if (existsSync6(projectDir)) {
4183
4198
  p3.log.error(
4184
- `${pc13.red(projectDir)} \uB514\uB809\uD1A0\uB9AC\uAC00 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4. \uD574\uB2F9 \uB514\uB809\uD1A0\uB9AC\uB97C \uC815\uB9AC\uD55C \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD574 \uC8FC\uC138\uC694.`
4199
+ `${pc14.red(projectDir)} \uB514\uB809\uD1A0\uB9AC\uAC00 \uC774\uBBF8 \uC874\uC7AC\uD569\uB2C8\uB2E4. \uD574\uB2F9 \uB514\uB809\uD1A0\uB9AC\uB97C \uC815\uB9AC\uD55C \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD574 \uC8FC\uC138\uC694.`
4185
4200
  );
4186
- p3.outro(pc13.red("\uC911\uB2E8\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
4201
+ p3.outro(pc14.red("\uC911\uB2E8\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
4187
4202
  process.exit(1);
4188
4203
  }
4189
4204
  const s = p3.spinner();
@@ -4192,9 +4207,9 @@ async function initCommand(options) {
4192
4207
  try {
4193
4208
  writeScaffold(projectDir, scaffold);
4194
4209
  } catch (err) {
4195
- s.stop(pc13.red("\uD504\uB85C\uC81D\uD2B8 \uD30C\uC77C \uC0DD\uC131 \uC2E4\uD328"));
4210
+ s.stop(pc14.red("\uD504\uB85C\uC81D\uD2B8 \uD30C\uC77C \uC0DD\uC131 \uC2E4\uD328"));
4196
4211
  p3.log.error(err instanceof Error ? err.message : String(err));
4197
- p3.outro(pc13.red("\uC911\uB2E8\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
4212
+ p3.outro(pc14.red("\uC911\uB2E8\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
4198
4213
  process.exit(1);
4199
4214
  }
4200
4215
  s.stop("\uD504\uB85C\uC81D\uD2B8 \uD30C\uC77C \uC0DD\uC131 \uC644\uB8CC");
@@ -4208,7 +4223,7 @@ async function initCommand(options) {
4208
4223
  });
4209
4224
  s.stop("Git \uCD08\uAE30\uD654 \uC644\uB8CC");
4210
4225
  } catch {
4211
- s.stop(pc13.yellow("Git \uCD08\uAE30\uD654 \uAC74\uB108\uB700 (git\uC774 \uC124\uCE58\uB418\uC9C0 \uC54A\uC558\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4)"));
4226
+ s.stop(pc14.yellow("Git \uCD08\uAE30\uD654 \uAC74\uB108\uB700 (git\uC774 \uC124\uCE58\uB418\uC9C0 \uC54A\uC558\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4)"));
4212
4227
  }
4213
4228
  s.start(`\uC758\uC874\uC131 \uC124\uCE58 \uC911... (${packageManager} install)`);
4214
4229
  try {
@@ -4216,26 +4231,26 @@ async function initCommand(options) {
4216
4231
  execSync(installCmd, { cwd: projectDir, stdio: "ignore", env: { ...process.env } });
4217
4232
  s.stop("\uC758\uC874\uC131 \uC124\uCE58 \uC644\uB8CC");
4218
4233
  } catch {
4219
- s.stop(pc13.yellow("\uC758\uC874\uC131 \uC124\uCE58 \uC2E4\uD328 \u2014 \uC9C1\uC811 \uC124\uCE58\uD574 \uC8FC\uC138\uC694"));
4234
+ s.stop(pc14.yellow("\uC758\uC874\uC131 \uC124\uCE58 \uC2E4\uD328 \u2014 \uC9C1\uC811 \uC124\uCE58\uD574 \uC8FC\uC138\uC694"));
4220
4235
  }
4221
4236
  const runCmd = packageManager === "pnpm" ? "pnpm dev" : "npm run dev";
4222
4237
  if (kind === "liquid") {
4223
- p3.outro(`${pc13.green("liquid \uD15C\uD50C\uB9BF \uD504\uB85C\uC81D\uD2B8\uAC00 \uC0DD\uC131\uB418\uC5C8\uC2B5\uB2C8\uB2E4!")}
4238
+ p3.outro(`${pc14.green("liquid \uD15C\uD50C\uB9BF \uD504\uB85C\uC81D\uD2B8\uAC00 \uC0DD\uC131\uB418\uC5C8\uC2B5\uB2C8\uB2E4!")}
4224
4239
 
4225
4240
  \uB2E4\uC74C \uB2E8\uACC4:
4226
- ${pc13.cyan(`cd ${projectName}`)}
4227
- ${pc13.cyan(runCmd)}
4228
- ${pc13.dim(`# \uBE0C\uB77C\uC6B0\uC800: http://localhost:${DEV_PORT} \u2014 \uD15C\uD50C\uB9BF \uBAA9\uB85D`)}
4229
- ${pc13.dim("# \uBC30\uD3EC \uC804\uC5D0 \uD3EC\uD138\uC5D0\uC11C \uB808\uD3EC \uC5F0\uACB0\xB7\uD398\uC774\uC9C0 \uC0DD\uC131\uC774 \uD544\uC694\uD569\uB2C8\uB2E4 \u2014 bstage-onboarding \uC2A4\uD0AC \uCC38\uC870")}`);
4241
+ ${pc14.cyan(`cd ${projectName}`)}
4242
+ ${pc14.cyan(runCmd)}
4243
+ ${pc14.dim(`# \uBE0C\uB77C\uC6B0\uC800: http://localhost:${DEV_PORT} \u2014 \uD15C\uD50C\uB9BF \uBAA9\uB85D`)}
4244
+ ${pc14.dim("# \uBC30\uD3EC \uC804\uC5D0 \uD3EC\uD138\uC5D0\uC11C \uB808\uD3EC \uC5F0\uACB0\xB7\uD398\uC774\uC9C0 \uC0DD\uC131\uC774 \uD544\uC694\uD569\uB2C8\uB2E4 \u2014 bstage-onboarding \uC2A4\uD0AC \uCC38\uC870")}`);
4230
4245
  return;
4231
4246
  }
4232
4247
  const label = target === "admin" ? "\uC5B4\uB4DC\uBBFC \uD15C\uD50C\uB9BF \uD504\uB85C\uC81D\uD2B8" : "\uD504\uB85C\uC81D\uD2B8";
4233
- p3.outro(`${pc13.green(`${label}\uAC00 \uC0DD\uC131\uB418\uC5C8\uC2B5\uB2C8\uB2E4!`)}
4248
+ p3.outro(`${pc14.green(`${label}\uAC00 \uC0DD\uC131\uB418\uC5C8\uC2B5\uB2C8\uB2E4!`)}
4234
4249
 
4235
4250
  \uB2E4\uC74C \uB2E8\uACC4:
4236
- ${pc13.cyan(`cd ${projectName}`)}
4237
- ${pc13.cyan(runCmd)}
4238
- ${pc13.dim(`# \uBE0C\uB77C\uC6B0\uC800: http://localhost:${DEV_PORT}`)}`);
4251
+ ${pc14.cyan(`cd ${projectName}`)}
4252
+ ${pc14.cyan(runCmd)}
4253
+ ${pc14.dim(`# \uBE0C\uB77C\uC6B0\uC800: http://localhost:${DEV_PORT}`)}`);
4239
4254
  }
4240
4255
  async function buildScaffold(answers, projectName, s) {
4241
4256
  const { kind, space, templateName, target, phase, packageManager, appId, appKey, tenantId } = answers;
@@ -4278,12 +4293,12 @@ async function buildScaffold(answers, projectName, s) {
4278
4293
  });
4279
4294
  }
4280
4295
  function failVersionLookup(s, err, label = "SDK") {
4281
- s.stop(pc13.red(`${label} \uCD5C\uC2E0 \uBC84\uC804 \uC870\uD68C \uC2E4\uD328`));
4296
+ s.stop(pc14.red(`${label} \uCD5C\uC2E0 \uBC84\uC804 \uC870\uD68C \uC2E4\uD328`));
4282
4297
  p3.log.error(
4283
4298
  (err instanceof Error ? err.message : String(err)) + `
4284
- ${pc13.dim("\uB124\uD2B8\uC6CC\uD06C \uC5F0\uACB0\uACFC registry.npmjs.org \uC811\uADFC\uC774 \uAC00\uB2A5\uD55C\uC9C0 \uD655\uC778\uD574 \uC8FC\uC138\uC694.")}`
4299
+ ${pc14.dim("\uB124\uD2B8\uC6CC\uD06C \uC5F0\uACB0\uACFC registry.npmjs.org \uC811\uADFC\uC774 \uAC00\uB2A5\uD55C\uC9C0 \uD655\uC778\uD574 \uC8FC\uC138\uC694.")}`
4285
4300
  );
4286
- p3.outro(pc13.red("\uC911\uB2E8\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
4301
+ p3.outro(pc14.red("\uC911\uB2E8\uB418\uC5C8\uC2B5\uB2C8\uB2E4."));
4287
4302
  process.exit(1);
4288
4303
  }
4289
4304
  async function fetchLatestVersion(packageName) {
@@ -4304,7 +4319,7 @@ async function fetchLatestVersion(packageName) {
4304
4319
  // src/commands/i18n.ts
4305
4320
  import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync3 } from "fs";
4306
4321
  import { dirname as dirname8, join as join11, resolve as resolve4 } from "path";
4307
- import pc14 from "picocolors";
4322
+ import pc15 from "picocolors";
4308
4323
  function latestKey(phase, tier, target) {
4309
4324
  const segments = tier === DEFAULT_TRANSLATION_TIER ? [TRANSLATION_CDN_BASE_KEY, phase, target] : [TRANSLATION_CDN_BASE_KEY, phase, target, tier];
4310
4325
  return [...segments, "latest.json"].join("/");
@@ -4351,18 +4366,18 @@ async function i18nPullCommand(options) {
4351
4366
  const tier = options.tier || DEFAULT_TRANSLATION_TIER;
4352
4367
  const target = options.target || "user";
4353
4368
  const latestUrl = `${TRANSLATION_CDN_ORIGIN}/${latestKey(options.phase, tier, target)}?date=${cacheStamp(/* @__PURE__ */ new Date())}`;
4354
- console.log(pc14.cyan(`[bstage] \uBC88\uC5ED pull: ${options.phase}/${target} (tier=${tier})`));
4369
+ console.log(pc15.cyan(`[bstage] \uBC88\uC5ED pull: ${options.phase}/${target} (tier=${tier})`));
4355
4370
  let latest;
4356
4371
  try {
4357
4372
  latest = await fetchJson(latestUrl);
4358
4373
  } catch (err) {
4359
4374
  const msg = err instanceof Error ? err.message : String(err);
4360
- console.error(pc14.red(`[bstage] latest.json \uC870\uD68C \uC2E4\uD328: ${msg}
4375
+ console.error(pc15.red(`[bstage] latest.json \uC870\uD68C \uC2E4\uD328: ${msg}
4361
4376
  ${latestUrl}`));
4362
4377
  process.exit(1);
4363
4378
  }
4364
4379
  const versionBase = `${TRANSLATION_CDN_ORIGIN}/${latest.cdnPath.replace(TRANSLATION_CDN_BUCKET_PREFIX, "")}`;
4365
- console.log(pc14.dim(` version: ${latest.version}`));
4380
+ console.log(pc15.dim(` version: ${latest.version}`));
4366
4381
  const cacheDir = join11(root, ".bstage", "i18n", target);
4367
4382
  mkdirSync4(cacheDir, { recursive: true });
4368
4383
  let refDict = null;
@@ -4373,32 +4388,32 @@ async function i18nPullCommand(options) {
4373
4388
  writeFileSync3(join11(cacheDir, `${locale}.json`), JSON.stringify(dict, null, 2));
4374
4389
  fetched.push(locale);
4375
4390
  if (locale === options.ref) refDict = dict;
4376
- console.log(pc14.green(` \u2713 ${locale} (${Object.keys(dict).length})`));
4391
+ console.log(pc15.green(` \u2713 ${locale} (${Object.keys(dict).length})`));
4377
4392
  } catch (err) {
4378
4393
  const msg = err instanceof Error ? err.message : String(err);
4379
- console.warn(pc14.yellow(` - ${locale}: ${msg} \u2014 \uAC74\uB108\uB700`));
4394
+ console.warn(pc15.yellow(` - ${locale}: ${msg} \u2014 \uAC74\uB108\uB700`));
4380
4395
  }
4381
4396
  }
4382
4397
  if (fetched.length === 0) {
4383
- console.error(pc14.red("[bstage] \uBC1B\uC740 \uBC88\uC5ED\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."));
4398
+ console.error(pc15.red("[bstage] \uBC1B\uC740 \uBC88\uC5ED\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."));
4384
4399
  process.exit(1);
4385
4400
  }
4386
4401
  if (!refDict) {
4387
4402
  console.warn(
4388
- pc14.yellow(`[bstage] ref \uB85C\uCF00\uC77C(${options.ref}) \uC0AC\uC804\uC774 \uC5C6\uC5B4 \uD0C0\uC785 \uC0DD\uC131\uC744 \uAC74\uB108\uB701\uB2C8\uB2E4.`)
4403
+ pc15.yellow(`[bstage] ref \uB85C\uCF00\uC77C(${options.ref}) \uC0AC\uC804\uC774 \uC5C6\uC5B4 \uD0C0\uC785 \uC0DD\uC131\uC744 \uAC74\uB108\uB701\uB2C8\uB2E4.`)
4389
4404
  );
4390
4405
  return;
4391
4406
  }
4392
4407
  const outPath = resolve4(root, options.out);
4393
4408
  mkdirSync4(dirname8(outPath), { recursive: true });
4394
4409
  writeFileSync3(outPath, generateTypeModule(refDict, { version: latest.version, ref: options.ref }));
4395
- console.log(pc14.green(`[bstage] \uD0C0\uC785 \uC0DD\uC131: ${options.out} (${Object.keys(refDict).length} \uD0A4)`));
4410
+ console.log(pc15.green(`[bstage] \uD0C0\uC785 \uC0DD\uC131: ${options.out} (${Object.keys(refDict).length} \uD0A4)`));
4396
4411
  console.log(
4397
- pc14.dim(
4412
+ pc15.dim(
4398
4413
  ` \uCE90\uC2DC: .bstage/i18n/${target}/*.json \u2014 \uD0C0\uC785 \uC0DD\uC131 \uC785\uB825 + \uC6D0\uBB38 \uAC80\uC0C9\uC6A9(\uB7F0\uD0C0\uC784\uC740 CDN\uC5D0\uC11C \uC9C1\uC811 \uBC1B\uB294\uB2E4)`
4399
4414
  )
4400
4415
  );
4401
- console.log(pc14.dim(" \uC0DD\uC131 \uD30C\uC77C\uC744 \uD55C \uBC88 import\uD558\uBA74 useBstageTranslations().t() \uD0A4\uAC00 \uC881\uD600\uC9D1\uB2C8\uB2E4."));
4416
+ console.log(pc15.dim(" \uC0DD\uC131 \uD30C\uC77C\uC744 \uD55C \uBC88 import\uD558\uBA74 useBstageTranslations().t() \uD0A4\uAC00 \uC881\uD600\uC9D1\uB2C8\uB2E4."));
4402
4417
  }
4403
4418
 
4404
4419
  // src/commands/doctor/report.ts
@@ -4802,18 +4817,18 @@ async function fetchLatestVersion2(packageName) {
4802
4817
  }
4803
4818
 
4804
4819
  // src/commands/doctor/render.ts
4805
- import pc15 from "picocolors";
4820
+ import pc16 from "picocolors";
4806
4821
  function printVersions(r) {
4807
- console.log(pc15.bold("\u{1F4E6} SDK \uBC84\uC804"));
4822
+ console.log(pc16.bold("\u{1F4E6} SDK \uBC84\uC804"));
4808
4823
  if (!r.latestChecked) {
4809
- console.log(pc15.dim(" \uB808\uC9C0\uC2A4\uD2B8\uB9AC \uC870\uD68C\uB97C \uAC74\uB108\uB6F0\uC5B4 \uC124\uCE58 \uBC84\uC804\uB9CC \uD45C\uC2DC\uD569\uB2C8\uB2E4."));
4824
+ console.log(pc16.dim(" \uB808\uC9C0\uC2A4\uD2B8\uB9AC \uC870\uD68C\uB97C \uAC74\uB108\uB6F0\uC5B4 \uC124\uCE58 \uBC84\uC804\uB9CC \uD45C\uC2DC\uD569\uB2C8\uB2E4."));
4810
4825
  }
4811
4826
  const nameWidth = Math.max(12, ...r.versions.map((v) => v.pkg.replace("@bstage-sdk/", "").length));
4812
4827
  for (const v of r.versions) {
4813
4828
  const name = v.pkg.replace("@bstage-sdk/", "").padEnd(nameWidth);
4814
4829
  const inst = v.installed ?? "?";
4815
4830
  if (v.latest && v.installed) {
4816
- const arrow = v.outdated ? pc15.yellow(`\u2192 ${v.latest} (\uB4A4\uCC98\uC9D0)`) : pc15.green("(\uCD5C\uC2E0)");
4831
+ const arrow = v.outdated ? pc16.yellow(`\u2192 ${v.latest} (\uB4A4\uCC98\uC9D0)`) : pc16.green("(\uCD5C\uC2E0)");
4817
4832
  console.log(` ${name} ${inst.padEnd(8)} ${arrow}`);
4818
4833
  } else {
4819
4834
  console.log(` ${name} ${inst}`);
@@ -4822,89 +4837,89 @@ function printVersions(r) {
4822
4837
  console.log("");
4823
4838
  }
4824
4839
  function printFiles(r) {
4825
- console.log(pc15.bold("\u{1F4C1} init \uAE30\uBCF8 \uD30C\uC77C (\uCC38\uACE0)"));
4840
+ console.log(pc16.bold("\u{1F4C1} init \uAE30\uBCF8 \uD30C\uC77C (\uCC38\uACE0)"));
4826
4841
  const absent = r.files.filter((f) => !f.present);
4827
4842
  if (absent.length === 0) {
4828
- console.log(pc15.green(" \u2713 init \uAE30\uBCF8 \uAD6C\uC131\uACFC \uB3D9\uC77C"));
4843
+ console.log(pc16.green(" \u2713 init \uAE30\uBCF8 \uAD6C\uC131\uACFC \uB3D9\uC77C"));
4829
4844
  } else {
4830
- console.log(pc15.dim(" init \uAE30\uBCF8\uAC12\uACFC\uC758 \uCC28\uC774\uC77C \uBFD0 \u2014 \uD504\uB85C\uC81D\uD2B8\uAC00 \uB2E4\uB974\uAC8C \uCC98\uB9AC \uC911\uC774\uBA74 \uBB34\uC2DC\uD558\uC138\uC694."));
4845
+ console.log(pc16.dim(" init \uAE30\uBCF8\uAC12\uACFC\uC758 \uCC28\uC774\uC77C \uBFD0 \u2014 \uD504\uB85C\uC81D\uD2B8\uAC00 \uB2E4\uB974\uAC8C \uCC98\uB9AC \uC911\uC774\uBA74 \uBB34\uC2DC\uD558\uC138\uC694."));
4831
4846
  for (const f of r.files) {
4832
- if (f.present) console.log(` ${pc15.green("\u2713")} ${f.path}`);
4833
- else console.log(` ${pc15.dim("\xB7")} ${f.path.padEnd(20)} ${pc15.dim(`\uC5C6\uC74C (${f.note})`)}`);
4847
+ if (f.present) console.log(` ${pc16.green("\u2713")} ${f.path}`);
4848
+ else console.log(` ${pc16.dim("\xB7")} ${f.path.padEnd(20)} ${pc16.dim(`\uC5C6\uC74C (${f.note})`)}`);
4834
4849
  }
4835
4850
  }
4836
4851
  console.log("");
4837
4852
  }
4838
4853
  function printLayout(r) {
4839
- console.log(pc15.bold("\u{1F5C2} \uD15C\uD50C\uB9BF \uB514\uB809\uD1A0\uB9AC"));
4854
+ console.log(pc16.bold("\u{1F5C2} \uD15C\uD50C\uB9BF \uB514\uB809\uD1A0\uB9AC"));
4840
4855
  if (r.layout.legacyPresent) {
4841
- console.log(` ${pc15.yellow("\u2192")} ${pc15.yellow("src/templates/ \uAC00 \uB0A8\uC544 \uC788\uC2B5\uB2C8\uB2E4 (\uC61B \uAD6C\uC870)")}`);
4842
- console.log(pc15.dim(" \uBE4C\uB4DC \uC0B0\uCD9C\uBB3C \uACBD\uB85C\uAC00 \uD3F4\uB354 \uAD6C\uC870\uB97C \uB530\uB77C\uAC00\uB3C4\uB85D \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4."));
4843
- console.log(pc15.dim(" \uD398\uC774\uC9C0 \u2192 src/pages/{\uACBD\uB85C}/ \xB7 \uC704\uC82F \u2192 src/slots/{\uC544\uBB34\uC774\uB984}/"));
4856
+ console.log(` ${pc16.yellow("\u2192")} ${pc16.yellow("src/templates/ \uAC00 \uB0A8\uC544 \uC788\uC2B5\uB2C8\uB2E4 (\uC61B \uAD6C\uC870)")}`);
4857
+ console.log(pc16.dim(" \uBE4C\uB4DC \uC0B0\uCD9C\uBB3C \uACBD\uB85C\uAC00 \uD3F4\uB354 \uAD6C\uC870\uB97C \uB530\uB77C\uAC00\uB3C4\uB85D \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4."));
4858
+ console.log(pc16.dim(" \uD398\uC774\uC9C0 \u2192 src/pages/{\uACBD\uB85C}/ \xB7 \uC704\uC82F \u2192 src/slots/{\uC544\uBB34\uC774\uB984}/"));
4844
4859
  if (r.layout.legacyTemplates.length > 0) {
4845
- console.log(pc15.dim(` \uC62E\uACA8\uC57C \uD560 \uD15C\uD50C\uB9BF: ${r.layout.legacyTemplates.join(", ")}`));
4860
+ console.log(pc16.dim(` \uC62E\uACA8\uC57C \uD560 \uD15C\uD50C\uB9BF: ${r.layout.legacyTemplates.join(", ")}`));
4846
4861
  }
4847
- console.log(pc15.dim(' \uBCC0\uD658: \uC5D0\uC774\uC804\uD2B8\uC5D0\uAC8C "bstage \uB9C8\uC774\uADF8\uB808\uC774\uC158" \uC694\uCCAD'));
4862
+ console.log(pc16.dim(' \uBCC0\uD658: \uC5D0\uC774\uC804\uD2B8\uC5D0\uAC8C "bstage \uB9C8\uC774\uADF8\uB808\uC774\uC158" \uC694\uCCAD'));
4848
4863
  } else if (!r.layout.pagesPresent && !r.layout.slotsPresent) {
4849
- console.log(` ${pc15.dim("\xB7")} src/pages/ \xB7 src/slots/ \uB458 \uB2E4 \uC5C6\uC74C`);
4864
+ console.log(` ${pc16.dim("\xB7")} src/pages/ \xB7 src/slots/ \uB458 \uB2E4 \uC5C6\uC74C`);
4850
4865
  } else {
4851
- console.log(pc15.green(" \u2713 src/pages/ \xB7 src/slots/ \uAD6C\uC870"));
4866
+ console.log(pc16.green(" \u2713 src/pages/ \xB7 src/slots/ \uAD6C\uC870"));
4852
4867
  }
4853
4868
  console.log("");
4854
4869
  }
4855
4870
  function printPnpmWorkspace(r) {
4856
4871
  if (!r.pnpmWorkspace.relevant) return;
4857
- console.log(pc15.bold("\u{1F4E6} pnpm workspace \uC124\uC815"));
4872
+ console.log(pc16.bold("\u{1F4E6} pnpm workspace \uC124\uC815"));
4858
4873
  if (r.pnpmWorkspace.allowBuildsDeclared) {
4859
- console.log(pc15.green(" \u2713 pnpm-workspace.yaml\uC5D0 allowBuilds \uC120\uC5B8\uB428"));
4874
+ console.log(pc16.green(" \u2713 pnpm-workspace.yaml\uC5D0 allowBuilds \uC120\uC5B8\uB428"));
4860
4875
  } else {
4861
- console.log(` ${pc15.yellow("\u2192")} ${pc15.yellow("pnpm-workspace.yaml\uC5D0 allowBuilds \uC5C6\uC74C")}`);
4876
+ console.log(` ${pc16.yellow("\u2192")} ${pc16.yellow("pnpm-workspace.yaml\uC5D0 allowBuilds \uC5C6\uC74C")}`);
4862
4877
  console.log(
4863
- pc15.dim(" pnpm\uC740 \uC758\uC874\uC131 build script\uB97C \uAE30\uBCF8 \uCC28\uB2E8\uD558\uACE0, pnpm 11\uC740 \uADF8\uAC83\uC744 \uC5D0\uB7EC\uB85C \uB0B8\uB2E4")
4878
+ pc16.dim(" pnpm\uC740 \uC758\uC874\uC131 build script\uB97C \uAE30\uBCF8 \uCC28\uB2E8\uD558\uACE0, pnpm 11\uC740 \uADF8\uAC83\uC744 \uC5D0\uB7EC\uB85C \uB0B8\uB2E4")
4864
4879
  );
4865
4880
  console.log(
4866
- pc15.dim(" \u2192 `pnpm install`\uC774 ERR_PNPM_IGNORED_BUILDS\uB85C \uC2E4\uD328\uD558\uACE0 `pnpm dev`\uB3C4 \uC8FD\uB294\uB2E4")
4881
+ pc16.dim(" \u2192 `pnpm install`\uC774 ERR_PNPM_IGNORED_BUILDS\uB85C \uC2E4\uD328\uD558\uACE0 `pnpm dev`\uB3C4 \uC8FD\uB294\uB2E4")
4867
4882
  );
4868
- console.log(pc15.dim(" \uCD94\uAC00: pnpm-workspace.yaml\uC5D0 `allowBuilds:` + `esbuild: true`"));
4869
- console.log(pc15.dim(" \uB610\uB294 `pnpm approve-builds`\uB85C \uB300\uD654\uC2DD \uC120\uD0DD"));
4883
+ console.log(pc16.dim(" \uCD94\uAC00: pnpm-workspace.yaml\uC5D0 `allowBuilds:` + `esbuild: true`"));
4884
+ console.log(pc16.dim(" \uB610\uB294 `pnpm approve-builds`\uB85C \uB300\uD654\uC2DD \uC120\uD0DD"));
4870
4885
  }
4871
4886
  if (r.pnpmWorkspace.filePresent && !r.pnpmWorkspace.packagesDeclared) {
4872
- console.log(` ${pc15.yellow("\u2192")} ${pc15.yellow("pnpm-workspace.yaml\uC5D0 packages \uC5C6\uC74C")}`);
4873
- console.log(pc15.dim(" pnpm 9\uB294 \uC774 \uD30C\uC77C\uC774 \uC788\uC73C\uBA74 workspace \uB8E8\uD2B8\uB85C \uBCF4\uACE0 packages\uB97C \uC694\uAD6C\uD55C\uB2E4"));
4874
- console.log(pc15.dim(" \u2192 pnpm 9\uC5D0\uC11C `ERROR packages field missing or empty`\uB85C \uC8FD\uB294\uB2E4"));
4875
- console.log(pc15.dim(" \uCD94\uAC00: pnpm-workspace.yaml \uB9E8 \uC704\uC5D0 `packages:` + `- '.'`"));
4887
+ console.log(` ${pc16.yellow("\u2192")} ${pc16.yellow("pnpm-workspace.yaml\uC5D0 packages \uC5C6\uC74C")}`);
4888
+ console.log(pc16.dim(" pnpm 9\uB294 \uC774 \uD30C\uC77C\uC774 \uC788\uC73C\uBA74 workspace \uB8E8\uD2B8\uB85C \uBCF4\uACE0 packages\uB97C \uC694\uAD6C\uD55C\uB2E4"));
4889
+ console.log(pc16.dim(" \u2192 pnpm 9\uC5D0\uC11C `ERROR packages field missing or empty`\uB85C \uC8FD\uB294\uB2E4"));
4890
+ console.log(pc16.dim(" \uCD94\uAC00: pnpm-workspace.yaml \uB9E8 \uC704\uC5D0 `packages:` + `- '.'`"));
4876
4891
  } else if (r.pnpmWorkspace.packagesDeclared) {
4877
- console.log(pc15.green(" \u2713 pnpm-workspace.yaml\uC5D0 packages \uC120\uC5B8\uB428"));
4892
+ console.log(pc16.green(" \u2713 pnpm-workspace.yaml\uC5D0 packages \uC120\uC5B8\uB428"));
4878
4893
  }
4879
4894
  console.log("");
4880
4895
  }
4881
4896
  function printScriptRow(sc) {
4882
4897
  if (sc.actual === null) {
4883
- console.log(` ${pc15.yellow("\u2192")} ${sc.name} ${pc15.yellow("\uC5C6\uC74C")}`);
4898
+ console.log(` ${pc16.yellow("\u2192")} ${sc.name} ${pc16.yellow("\uC5C6\uC74C")}`);
4884
4899
  } else {
4885
4900
  console.log(
4886
- ` ${pc15.yellow("\u2192")} ${sc.name} ${pc15.yellow("\uB2E4\uB984")} ${pc15.dim(`\u2014 \uD604\uC7AC \`${sc.actual}\``)}`
4901
+ ` ${pc16.yellow("\u2192")} ${sc.name} ${pc16.yellow("\uB2E4\uB984")} ${pc16.dim(`\u2014 \uD604\uC7AC \`${sc.actual}\``)}`
4887
4902
  );
4888
4903
  if (sc.actual.includes("--noEmit") && !sc.actual.includes("-p ")) {
4889
4904
  console.log(
4890
- pc15.dim(
4905
+ pc16.dim(
4891
4906
  " \uC8FC\uC758: solution-style tsconfig\uC5D0\uC11C `tsc --noEmit`\uC740 \uC544\uBB34 \uD30C\uC77C\uB3C4 \uAC80\uC0AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4."
4892
4907
  )
4893
4908
  );
4894
4909
  }
4895
4910
  }
4896
- console.log(pc15.dim(` ${sc.why}`));
4897
- console.log(pc15.dim(` \uAD8C\uC7A5: "${sc.name}": "${sc.expected}"`));
4911
+ console.log(pc16.dim(` ${sc.why}`));
4912
+ console.log(pc16.dim(` \uAD8C\uC7A5: "${sc.name}": "${sc.expected}"`));
4898
4913
  }
4899
4914
  function printScripts(r) {
4900
- console.log(pc15.bold("\u{1F6E0} package.json \uC2A4\uD06C\uB9BD\uD2B8"));
4915
+ console.log(pc16.bold("\u{1F6E0} package.json \uC2A4\uD06C\uB9BD\uD2B8"));
4901
4916
  const scriptIssues = r.scripts.filter((sc) => sc.actual !== sc.expected);
4902
4917
  if (scriptIssues.length === 0) {
4903
- console.log(pc15.green(" \u2713 init \uAE30\uBCF8 \uAD6C\uC131\uACFC \uB3D9\uC77C"));
4918
+ console.log(pc16.green(" \u2713 init \uAE30\uBCF8 \uAD6C\uC131\uACFC \uB3D9\uC77C"));
4904
4919
  } else {
4905
4920
  for (const sc of r.scripts) {
4906
4921
  if (sc.actual === sc.expected) {
4907
- console.log(` ${pc15.green("\u2713")} ${sc.name}`);
4922
+ console.log(` ${pc16.green("\u2713")} ${sc.name}`);
4908
4923
  continue;
4909
4924
  }
4910
4925
  printScriptRow(sc);
@@ -4914,76 +4929,76 @@ function printScripts(r) {
4914
4929
  }
4915
4930
  function printLiquid(r) {
4916
4931
  if (r.liquid === null) return;
4917
- console.log(pc15.bold("\u{1F4A7} liquid \uAC80\uC99D"));
4932
+ console.log(pc16.bold("\u{1F4A7} liquid \uAC80\uC99D"));
4918
4933
  const errors = r.liquid.issues.filter((i) => i.level === "error");
4919
4934
  const warns = r.liquid.issues.filter((i) => i.level === "warn");
4920
4935
  if (errors.length === 0 && warns.length === 0) {
4921
- console.log(pc15.green(" \u2713 \uADDC\uC57D\xB7\uBB38\uBC95 \uC774\uC0C1 \uC5C6\uC74C"));
4936
+ console.log(pc16.green(" \u2713 \uADDC\uC57D\xB7\uBB38\uBC95 \uC774\uC0C1 \uC5C6\uC74C"));
4922
4937
  }
4923
- for (const i of errors) console.log(` ${pc15.red("\u2717")} ${i.path} ${pc15.red(i.message)}`);
4924
- for (const i of warns) console.log(` ${pc15.yellow("\u26A0")} ${i.path} ${pc15.dim(i.message)}`);
4938
+ for (const i of errors) console.log(` ${pc16.red("\u2717")} ${i.path} ${pc16.red(i.message)}`);
4939
+ for (const i of warns) console.log(` ${pc16.yellow("\u26A0")} ${i.path} ${pc16.dim(i.message)}`);
4925
4940
  if (errors.length > 0) {
4926
4941
  console.log(
4927
- pc15.dim(" \uACE0\uCE5C \uB4A4 `bstage build`\uB85C \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694 \u2014 \uD3EC\uD138 \uBE4C\uB4DC\uB3C4 \uAC19\uC740 \uAC80\uC0AC\uB97C \uD569\uB2C8\uB2E4.")
4942
+ pc16.dim(" \uACE0\uCE5C \uB4A4 `bstage build`\uB85C \uB2E4\uC2DC \uD655\uC778\uD558\uC138\uC694 \u2014 \uD3EC\uD138 \uBE4C\uB4DC\uB3C4 \uAC19\uC740 \uAC80\uC0AC\uB97C \uD569\uB2C8\uB2E4.")
4928
4943
  );
4929
4944
  }
4930
4945
  console.log("");
4931
4946
  }
4932
4947
  function printRecommendedDeps(r) {
4933
4948
  if (r.recommendedDeps.length === 0) return;
4934
- console.log(pc15.bold("\u{1F9F1} \uAD8C\uC7A5 \uC758\uC874\uC131"));
4949
+ console.log(pc16.bold("\u{1F9F1} \uAD8C\uC7A5 \uC758\uC874\uC131"));
4935
4950
  if (r.recommendedDeps.every((d) => d.declared)) {
4936
- console.log(pc15.green(" \u2713 \uBAA8\uB450 \uC120\uC5B8\uB428"));
4951
+ console.log(pc16.green(" \u2713 \uBAA8\uB450 \uC120\uC5B8\uB428"));
4937
4952
  } else {
4938
4953
  for (const d of r.recommendedDeps) {
4939
4954
  if (d.declared) {
4940
- console.log(` ${pc15.green("\u2713")} ${d.pkg}`);
4955
+ console.log(` ${pc16.green("\u2713")} ${d.pkg}`);
4941
4956
  continue;
4942
4957
  }
4943
- console.log(` ${pc15.yellow("\u2192")} ${d.pkg} ${pc15.yellow("\uBBF8\uC120\uC5B8")} ${pc15.dim(`\u2014 ${d.note}`)}`);
4944
- console.log(pc15.dim(` ${d.why}`));
4945
- console.log(pc15.dim(` \uCD94\uAC00: npm i ${d.pkg} (\uD504\uB85C\uC81D\uD2B8 \uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800\uB85C)`));
4958
+ console.log(` ${pc16.yellow("\u2192")} ${d.pkg} ${pc16.yellow("\uBBF8\uC120\uC5B8")} ${pc16.dim(`\u2014 ${d.note}`)}`);
4959
+ console.log(pc16.dim(` ${d.why}`));
4960
+ console.log(pc16.dim(` \uCD94\uAC00: npm i ${d.pkg} (\uD504\uB85C\uC81D\uD2B8 \uD328\uD0A4\uC9C0 \uB9E4\uB2C8\uC800\uB85C)`));
4946
4961
  }
4947
4962
  }
4948
4963
  console.log("");
4949
4964
  }
4950
4965
  function printMigrations(r) {
4951
- console.log(pc15.bold("\u{1F4D6} \uC801\uC6A9 \uAC00\uB2A5\uD55C \uB9C8\uC774\uADF8\uB808\uC774\uC158"));
4966
+ console.log(pc16.bold("\u{1F4D6} \uC801\uC6A9 \uAC00\uB2A5\uD55C \uB9C8\uC774\uADF8\uB808\uC774\uC158"));
4952
4967
  if (r.migrations.length === 0) {
4953
- console.log(pc15.dim(" \uD574\uB2F9 \uD56D\uBAA9 \uC5C6\uC74C."));
4968
+ console.log(pc16.dim(" \uD574\uB2F9 \uD56D\uBAA9 \uC5C6\uC74C."));
4954
4969
  } else {
4955
4970
  for (const m of r.migrations) {
4956
- console.log(` ${pc15.cyan(`\u2192 ${m.label}`)}`);
4971
+ console.log(` ${pc16.cyan(`\u2192 ${m.label}`)}`);
4957
4972
  for (const item of m.items) console.log(` \u2022 ${item}`);
4958
4973
  }
4959
4974
  }
4960
4975
  console.log("");
4961
4976
  }
4962
4977
  function printAgentsMd(r) {
4963
- console.log(pc15.bold("\u{1F4DD} AGENTS.md"));
4978
+ console.log(pc16.bold("\u{1F4DD} AGENTS.md"));
4964
4979
  switch (r.agentsMd.status) {
4965
4980
  case "ok":
4966
- console.log(pc15.green(" \u2713 \uAD00\uB9AC \uC601\uC5ED \uCD5C\uC2E0"));
4981
+ console.log(pc16.green(" \u2713 \uAD00\uB9AC \uC601\uC5ED \uCD5C\uC2E0"));
4967
4982
  break;
4968
4983
  case "missing":
4969
- console.log(pc15.dim(" \xB7 \uD30C\uC77C \uC5C6\uC74C \u2014 bstage \uD504\uB85C\uC81D\uD2B8\uB77C\uBA74 init/\uB9C8\uC774\uADF8\uB808\uC774\uC158\uC73C\uB85C \uC0DD\uC131\uD558\uC138\uC694."));
4984
+ console.log(pc16.dim(" \xB7 \uD30C\uC77C \uC5C6\uC74C \u2014 bstage \uD504\uB85C\uC81D\uD2B8\uB77C\uBA74 init/\uB9C8\uC774\uADF8\uB808\uC774\uC158\uC73C\uB85C \uC0DD\uC131\uD558\uC138\uC694."));
4970
4985
  break;
4971
4986
  case "stale":
4972
4987
  if (r.agentsMd.downgrade) {
4973
4988
  console.log(
4974
- pc15.yellow(" ! \uAD00\uB9AC \uC601\uC5ED\uC774 \uC774 CLI\uBCF4\uB2E4 \uC0C8 \uBC84\uC804") + pc15.dim(
4989
+ pc16.yellow(" ! \uAD00\uB9AC \uC601\uC5ED\uC774 \uC774 CLI\uBCF4\uB2E4 \uC0C8 \uBC84\uC804") + pc16.dim(
4975
4990
  " \u2014 \uC774 CLI\uAC00 \uC624\uB798\uB3FC \uAC31\uC2E0\uD558\uBA74 \uC61B \uBCF8\uBB38\uC73C\uB85C \uB418\uB3CC\uC544\uAC11\uB2C8\uB2E4(\uD558\uD5A5). \uCD5C\uC2E0 CLI(npx @bstage-sdk/cli@latest)\uB85C \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694."
4976
4991
  )
4977
4992
  );
4978
4993
  break;
4979
4994
  }
4980
4995
  console.log(
4981
- pc15.yellow(" \u2192 \uAD00\uB9AC \uC601\uC5ED\uC774 \uC624\uB798\uB428") + pc15.dim(" \u2014 `bstage ai update`\uB85C \uAC31\uC2E0(\uC790\uC720 \uC601\uC5ED\uC740 \uBCF4\uC874).")
4996
+ pc16.yellow(" \u2192 \uAD00\uB9AC \uC601\uC5ED\uC774 \uC624\uB798\uB428") + pc16.dim(" \u2014 `bstage ai update`\uB85C \uAC31\uC2E0(\uC790\uC720 \uC601\uC5ED\uC740 \uBCF4\uC874).")
4982
4997
  );
4983
4998
  break;
4984
4999
  case "legacy":
4985
5000
  console.log(
4986
- pc15.yellow(" \u2192 \uB808\uAC70\uC2DC \uD3EC\uB9F7(\uAD00\uB9AC \uC601\uC5ED \uB9C8\uCEE4 \uC5C6\uC74C)") + pc15.dim(
5001
+ pc16.yellow(" \u2192 \uB808\uAC70\uC2DC \uD3EC\uB9F7(\uAD00\uB9AC \uC601\uC5ED \uB9C8\uCEE4 \uC5C6\uC74C)") + pc16.dim(
4987
5002
  " \u2014 `bstage ai install`\uB85C \uC2A4\uD0AC\uC744 \uBA3C\uC800 \uC124\uCE58\uD55C \uB4A4, `bstage-migrate` \uC2A4\uD0AC\uB85C reconcile(SDK \uC601\uC5ED \uAD50\uCCB4 + \uC0AC\uC6A9\uC790 \uB0B4\uC6A9 \uBCF4\uC874)."
4988
5003
  )
4989
5004
  );
@@ -4992,29 +5007,29 @@ function printAgentsMd(r) {
4992
5007
  console.log("");
4993
5008
  }
4994
5009
  function printSkills(r) {
4995
- console.log(pc15.bold("\u{1F9E9} \uC5D0\uC774\uC804\uD2B8 \uC2A4\uD0AC (.claude/skills/)"));
5010
+ console.log(pc16.bold("\u{1F9E9} \uC5D0\uC774\uC804\uD2B8 \uC2A4\uD0AC (.claude/skills/)"));
4996
5011
  const skillsNeedWork = r.skills.filter((s) => s.status !== "ok");
4997
5012
  if (r.skillsSkipped) {
4998
5013
  console.log(
4999
- pc15.yellow(" ! sdk\uC640 liquid\uAC00 \uC11E\uC5EC \uC788\uC5B4 \uC2A4\uD0AC \uAC80\uC0AC\uB97C \uAC74\uB108\uB701\uB2C8\uB2E4 \u2014 \uD558\uB098\uB9CC \uB0A8\uACA8 \uC8FC\uC138\uC694.")
5014
+ pc16.yellow(" ! sdk\uC640 liquid\uAC00 \uC11E\uC5EC \uC788\uC5B4 \uC2A4\uD0AC \uAC80\uC0AC\uB97C \uAC74\uB108\uB701\uB2C8\uB2E4 \u2014 \uD558\uB098\uB9CC \uB0A8\uACA8 \uC8FC\uC138\uC694.")
5000
5015
  );
5001
5016
  } else if (skillsNeedWork.length === 0) {
5002
- console.log(pc15.green(" \u2713 \uBAA8\uB4E0 \uC2A4\uD0AC \uCD5C\uC2E0"));
5017
+ console.log(pc16.green(" \u2713 \uBAA8\uB4E0 \uC2A4\uD0AC \uCD5C\uC2E0"));
5003
5018
  } else {
5004
5019
  for (const s of r.skills) {
5005
- if (s.status === "ok") console.log(` ${pc15.green("\u2713")} ${s.name}`);
5020
+ if (s.status === "ok") console.log(` ${pc16.green("\u2713")} ${s.name}`);
5006
5021
  else if (s.status === "missing")
5007
- console.log(` ${pc15.yellow("\u2192")} ${s.name.padEnd(16)} ${pc15.yellow("\uBBF8\uC124\uCE58")}`);
5022
+ console.log(` ${pc16.yellow("\u2192")} ${s.name.padEnd(16)} ${pc16.yellow("\uBBF8\uC124\uCE58")}`);
5008
5023
  else if (s.status === "newer")
5009
5024
  console.log(
5010
- ` ${pc15.yellow("!")} ${s.name.padEnd(16)} ${pc15.yellow("\uC774 CLI\uBCF4\uB2E4 \uC0C8 \uBC84\uC804")}` + pc15.dim(
5025
+ ` ${pc16.yellow("!")} ${s.name.padEnd(16)} ${pc16.yellow("\uC774 CLI\uBCF4\uB2E4 \uC0C8 \uBC84\uC804")}` + pc16.dim(
5011
5026
  " \u2014 \uC774 CLI\uAC00 \uC624\uB798\uB3FC \uC61B \uBCF8\uBB38\uC73C\uB85C \uB418\uB3CC\uB9BD\uB2C8\uB2E4(\uD558\uD5A5). \uCD5C\uC2E0 CLI(npx @bstage-sdk/cli@latest)\uB85C \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694."
5012
5027
  )
5013
5028
  );
5014
- else console.log(` ${pc15.yellow("\u2192")} ${s.name.padEnd(16)} ${pc15.yellow("\uAD6C\uBC84\uC804/\uC218\uC815\uB428")}`);
5029
+ else console.log(` ${pc16.yellow("\u2192")} ${s.name.padEnd(16)} ${pc16.yellow("\uAD6C\uBC84\uC804/\uC218\uC815\uB428")}`);
5015
5030
  }
5016
5031
  console.log(
5017
- pc15.dim(
5032
+ pc16.dim(
5018
5033
  " \uC544\uB798\uC5D0\uC11C \uC790\uB3D9 \uB3D9\uAE30\uD654\uD569\uB2C8\uB2E4 \u2014 bstage-* \uC2A4\uD0AC\uB9CC \uB36E\uC5B4\uC4F0\uBA70, \uADF8 \uC678 \uC0AC\uC6A9\uC790 \uC2A4\uD0AC\uC740 \uAC74\uB4DC\uB9AC\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4."
5019
5034
  )
5020
5035
  );
@@ -5027,33 +5042,33 @@ function printNextSteps(r) {
5027
5042
  const hasWork = r.versions.some((v) => v.outdated) || r.migrations.length > 0 || agentsNeedsWork || liquidBroken;
5028
5043
  if (liquidBroken) {
5029
5044
  console.log(
5030
- pc15.yellow("\uC704 liquid \uAC80\uC99D \uC624\uB958\uB97C \uBA3C\uC800 \uACE0\uCE58\uC138\uC694 \u2014 \uADF8\uB300\uB85C push\uD558\uBA74 \uD3EC\uD138 \uBE4C\uB4DC\uAC00 \uB9C9\uD799\uB2C8\uB2E4.")
5045
+ pc16.yellow("\uC704 liquid \uAC80\uC99D \uC624\uB958\uB97C \uBA3C\uC800 \uACE0\uCE58\uC138\uC694 \u2014 \uADF8\uB300\uB85C push\uD558\uBA74 \uD3EC\uD138 \uBE4C\uB4DC\uAC00 \uB9C9\uD799\uB2C8\uB2E4.")
5031
5046
  );
5032
5047
  }
5033
5048
  if (hasWork) {
5034
5049
  console.log(
5035
- pc15.dim(
5050
+ pc16.dim(
5036
5051
  "\uB2E4\uC74C \uB2E8\uACC4: \uB9C8\uC774\uADF8\uB808\uC774\uC158 \uC2A4\uD0AC\uC744 \uC2E4\uD589\uD574 \uC704 \uD56D\uBAA9\uC744 \uD504\uB85C\uC81D\uD2B8\uC5D0 \uB9DE\uCDB0 \uC801\uC6A9\uD558\uC138\uC694.\n \uC0C1\uC138 \uAC00\uC774\uB4DC: SDK \uBB38\uC11C\uC758 MIGRATION.md (\uC704 \uD56D\uBAA9\uBCC4 \uC801\uC6A9 \uC808\uCC28)"
5037
5052
  )
5038
5053
  );
5039
5054
  } else {
5040
- console.log(pc15.green("\u2713 \uCD5C\uC2E0 \uC0C1\uD0DC\uC785\uB2C8\uB2E4. \uB9C8\uC774\uADF8\uB808\uC774\uC158\uC774 \uD544\uC694 \uC5C6\uC2B5\uB2C8\uB2E4."));
5055
+ console.log(pc16.green("\u2713 \uCD5C\uC2E0 \uC0C1\uD0DC\uC785\uB2C8\uB2E4. \uB9C8\uC774\uADF8\uB808\uC774\uC158\uC774 \uD544\uC694 \uC5C6\uC2B5\uB2C8\uB2E4."));
5041
5056
  if (r.files.some((f) => !f.present)) {
5042
- console.log(pc15.dim(" (\uC704 init \uAE30\uBCF8 \uD30C\uC77C \uCC28\uC774\uB294 \uC120\uD0DD \uC0AC\uD56D\uC785\uB2C8\uB2E4.)"));
5057
+ console.log(pc16.dim(" (\uC704 init \uAE30\uBCF8 \uD30C\uC77C \uCC28\uC774\uB294 \uC120\uD0DD \uC0AC\uD56D\uC785\uB2C8\uB2E4.)"));
5043
5058
  }
5044
5059
  if (r.recommendedDeps.some((d) => !d.declared)) {
5045
- console.log(pc15.dim(" (\uC704 \uAD8C\uC7A5 \uC758\uC874\uC131\uC740 \uBC84\uC804\uACFC \uBB34\uAD00\uD569\uB2C8\uB2E4 \u2014 \uC4F8 \uAC70\uBA74 \uB530\uB85C \uCD94\uAC00\uD558\uC138\uC694.)"));
5060
+ console.log(pc16.dim(" (\uC704 \uAD8C\uC7A5 \uC758\uC874\uC131\uC740 \uBC84\uC804\uACFC \uBB34\uAD00\uD569\uB2C8\uB2E4 \u2014 \uC4F8 \uAC70\uBA74 \uB530\uB85C \uCD94\uAC00\uD558\uC138\uC694.)"));
5046
5061
  }
5047
5062
  }
5048
5063
  console.log("");
5049
5064
  }
5050
5065
  function printReport(r) {
5051
5066
  console.log("");
5052
- console.log(`${pc15.cyan(pc15.bold("bstage doctor"))} ${pc15.dim(`\u2014 ${r.project ?? "(\uC774\uB984 \uC5C6\uC74C)"}`)}`);
5067
+ console.log(`${pc16.cyan(pc16.bold("bstage doctor"))} ${pc16.dim(`\u2014 ${r.project ?? "(\uC774\uB984 \uC5C6\uC74C)"}`)}`);
5053
5068
  console.log("");
5054
5069
  if (!r.isBstageProject) {
5055
- console.log(pc15.yellow("\uC774 \uB514\uB809\uD1A0\uB9AC\uB294 bstage \uD15C\uD50C\uB9BF \uD504\uB85C\uC81D\uD2B8\uAC00 \uC544\uB2CC \uAC83 \uAC19\uC2B5\uB2C8\uB2E4."));
5056
- console.log(pc15.dim(" package.json\uC5D0 @bstage-sdk/* \uC758\uC874\uC131\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."));
5070
+ console.log(pc16.yellow("\uC774 \uB514\uB809\uD1A0\uB9AC\uB294 bstage \uD15C\uD50C\uB9BF \uD504\uB85C\uC81D\uD2B8\uAC00 \uC544\uB2CC \uAC83 \uAC19\uC2B5\uB2C8\uB2E4."));
5071
+ console.log(pc16.dim(" package.json\uC5D0 @bstage-sdk/* \uC758\uC874\uC131\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."));
5057
5072
  return;
5058
5073
  }
5059
5074
  printVersions(r);
@@ -5083,7 +5098,7 @@ async function doctorCommand(options) {
5083
5098
 
5084
5099
  // src/commands/link.ts
5085
5100
  import * as p4 from "@clack/prompts";
5086
- import pc16 from "picocolors";
5101
+ import pc17 from "picocolors";
5087
5102
  var clackSelect = async (message, items) => {
5088
5103
  const options = items.map((i) => ({
5089
5104
  value: i.value,
@@ -5195,15 +5210,15 @@ function printLinked(link, repoLabel, repoFromOrigin, json) {
5195
5210
  return;
5196
5211
  }
5197
5212
  if (repoFromOrigin) {
5198
- console.log(pc16.dim(` git origin(${repoLabel})\uACFC \uC77C\uCE58\uD558\uB294 \uB808\uD3EC\uB97C \uAE30\uBCF8\uAC12\uC73C\uB85C \uC120\uD0DD\uD588\uC2B5\uB2C8\uB2E4.`));
5213
+ console.log(pc17.dim(` git origin(${repoLabel})\uACFC \uC77C\uCE58\uD558\uB294 \uB808\uD3EC\uB97C \uAE30\uBCF8\uAC12\uC73C\uB85C \uC120\uD0DD\uD588\uC2B5\uB2C8\uB2E4.`));
5199
5214
  }
5200
5215
  console.log(
5201
- pc16.green(
5216
+ pc17.green(
5202
5217
  `\u2713 \uC5F0\uACB0\uD588\uC2B5\uB2C8\uB2E4: ${link.organizationId} / ${link.spaceId} / ${repoLabel} [${link.surface}]`
5203
5218
  )
5204
5219
  );
5205
5220
  console.log(
5206
- pc16.dim(
5221
+ pc17.dim(
5207
5222
  " .bstage/project.json \uC5D0 \uC800\uC7A5 (gitignore \uB300\uC0C1). CI\uC5D0\uC11C\uB294 BSTAGE_ORG\xB7BSTAGE_SPACE\xB7BSTAGE_REPO\xB7BSTAGE_SURFACE\xB7BSTAGE_PORTAL_URL \uD658\uACBD\uBCC0\uC218\uB97C \uC4F0\uC138\uC694."
5208
5223
  )
5209
5224
  );
@@ -5258,7 +5273,7 @@ async function linkCommand(options, deps = {}) {
5258
5273
  }
5259
5274
 
5260
5275
  // src/commands/list.ts
5261
- import pc17 from "picocolors";
5276
+ import pc18 from "picocolors";
5262
5277
 
5263
5278
  // src/portal/buildRepo.ts
5264
5279
  function buildMatchesRepo(b, repo) {
@@ -5290,11 +5305,11 @@ function artifactKinds(build) {
5290
5305
  function renderList(placements, builds, repo) {
5291
5306
  const mine = placements.filter((p5) => p5.stageRepoId === repo.id);
5292
5307
  const lines = [];
5293
- lines.push(pc17.bold("\uBC30\uCE58"));
5308
+ lines.push(pc18.bold("\uBC30\uCE58"));
5294
5309
  if (mine.length === 0) {
5295
5310
  lines.push(
5296
- pc17.yellow(
5297
- " \uC774 \uB808\uD3EC\uC5D0 \uC5F0\uACB0\uB41C \uBC30\uCE58\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. \uD3EC\uD138 > \uC2A4\uD14C\uC774\uC9C0 > \uD398\uC774\uC9C0\uC5D0\uC11C \uBC30\uCE58\uB97C \uBA3C\uC800 \uB9CC\uB4DC\uC138\uC694."
5311
+ pc18.yellow(
5312
+ " \uC774 \uB808\uD3EC\uC5D0 \uC5F0\uACB0\uB41C \uBC30\uCE58\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. bstage placement create \uB85C \uD398\uC774\uC9C0 \uBC30\uCE58\uB97C \uBA3C\uC800 \uB9CC\uB4DC\uC138\uC694."
5298
5313
  )
5299
5314
  );
5300
5315
  } else {
@@ -5312,10 +5327,10 @@ function renderList(placements, builds, repo) {
5312
5327
  );
5313
5328
  }
5314
5329
  lines.push("");
5315
- lines.push(pc17.bold("\uCD5C\uADFC \uBE4C\uB4DC"));
5330
+ lines.push(pc18.bold("\uCD5C\uADFC \uBE4C\uB4DC"));
5316
5331
  const recent = builds.filter((b) => buildMatchesRepo(b, repo));
5317
5332
  lines.push(
5318
- recent.length === 0 ? pc17.dim(" \uBE4C\uB4DC \uC774\uB825\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.") : table([
5333
+ recent.length === 0 ? pc18.dim(" \uBE4C\uB4DC \uC774\uB825\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.") : table([
5319
5334
  ["\uBE4C\uB4DC", "\uC0C1\uD0DC", "\uC885\uB958", "\uCEE4\uBC0B", "\uC694\uCCAD \uC2DC\uAC01"],
5320
5335
  ...recent.map((b) => [
5321
5336
  b.id,
@@ -5329,8 +5344,8 @@ function renderList(placements, builds, repo) {
5329
5344
  if (mine.length === 0) {
5330
5345
  lines.push("");
5331
5346
  lines.push(
5332
- pc17.yellow(
5333
- "\uC774 \uB808\uD3EC\uC5D0 \uBC30\uCE58\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. \uD3EC\uD138 \uD654\uBA74\uC5D0\uC11C \uD398\uC774\uC9C0(\uBC30\uCE58)\uB97C \uBA3C\uC800 \uB9CC\uB4E4\uC5B4 \uC8FC\uC138\uC694 \u2014 \uC2A4\uD14C\uC774\uC9C0 > \uD398\uC774\uC9C0 > \uC0C8 \uD398\uC774\uC9C0. (bstage-deploy \uC2A4\uD0AC \uCC38\uC870)"
5347
+ pc18.yellow(
5348
+ "\uC774 \uB808\uD3EC\uC5D0 \uBC30\uCE58\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. \uB2E4\uC74C: bstage placement create --template <\uC0B0\uCD9C\uBB3C \uC774\uB984> [--path /\uACBD\uB85C] \u2192 bstage deploy. \uC704\uC82F(\uC2AC\uB86F) \uBC30\uCE58\uB294 \uD3EC\uD138 \uD654\uBA74(\uC2A4\uD14C\uC774\uC9C0 > \uD398\uC774\uC9C0 > \uC0C8 \uD398\uC774\uC9C0)\uC5D0\uC11C \uB9CC\uB4ED\uB2C8\uB2E4. (bstage-deploy \uC2A4\uD0AC \uCC38\uC870)"
5334
5349
  )
5335
5350
  );
5336
5351
  }
@@ -5355,12 +5370,12 @@ async function listCommand(options, deps = {}) {
5355
5370
  printJson({ link, placements: mine, builds: myBuilds });
5356
5371
  return;
5357
5372
  }
5358
- out(pc17.dim(`${link.organizationId} / ${link.spaceId} [${link.surface}]`));
5373
+ out(pc18.dim(`${link.organizationId} / ${link.spaceId} [${link.surface}]`));
5359
5374
  out(renderList(placements, builds, repo));
5360
5375
  }
5361
5376
 
5362
5377
  // src/commands/logs.ts
5363
- import pc18 from "picocolors";
5378
+ import pc19 from "picocolors";
5364
5379
  function statusLine(build) {
5365
5380
  return `[bstage] \uBE4C\uB4DC ${build.id} \xB7 ${build.status}${build.failureReason ? ` \xB7 ${build.failureReason}` : ""}`;
5366
5381
  }
@@ -5374,7 +5389,7 @@ async function latestBuildId(ctx) {
5374
5389
  return latest.id;
5375
5390
  }
5376
5391
  function logSink(json) {
5377
- return json ? (delta) => void process.stderr.write(pc18.dim(delta)) : (delta) => void process.stdout.write(delta);
5392
+ return json ? (delta) => void process.stderr.write(pc19.dim(delta)) : (delta) => void process.stdout.write(delta);
5378
5393
  }
5379
5394
  async function logsCommand(buildId, options, deps = {}) {
5380
5395
  const out = deps.out ?? ((s) => void process.stdout.write(s));
@@ -5398,18 +5413,250 @@ async function report(client, org, space, id, build, options, out, following) {
5398
5413
  return;
5399
5414
  }
5400
5415
  if (following) {
5401
- console.error(pc18.dim(`
5416
+ console.error(pc19.dim(`
5402
5417
  ${statusLine(build)}`));
5403
5418
  return;
5404
5419
  }
5405
5420
  const log3 = await client.getBuildLog(org, space, id);
5406
5421
  out(log3.endsWith("\n") ? log3 : log3 + "\n");
5407
- console.error(pc18.dim(statusLine(build)));
5422
+ console.error(pc19.dim(statusLine(build)));
5423
+ }
5424
+
5425
+ // src/commands/placement.ts
5426
+ import pc20 from "picocolors";
5427
+
5428
+ // src/portal/pagePlacement.ts
5429
+ function normalizePagePath(raw) {
5430
+ const bad = (why) => fail(ExitCode.PRECONDITION, `--path \uAC12\uC774 \uC62C\uBC14\uB974\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4 (${raw}): ${why}`);
5431
+ if (!raw.startsWith("/")) bad('"/"\uB85C \uC2DC\uC791\uD574\uC57C \uD569\uB2C8\uB2E4');
5432
+ if ([" ", " ", "\n", "\r", "\\"].some((c) => raw.includes(c))) {
5433
+ bad("\uACF5\uBC31\uC774\uB098 \uBC31\uC2AC\uB798\uC2DC\uB97C \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
5434
+ }
5435
+ if ([":", "[", "]"].some((c) => raw.includes(c))) bad("\uB3D9\uC801 \uC138\uADF8\uBA3C\uD2B8(:, [, ])\uB97C \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
5436
+ if (raw === "/") return "/";
5437
+ const trimmed = trimTrailingSlashes(raw);
5438
+ if (trimmed === "") bad("\uBE48 \uC138\uADF8\uBA3C\uD2B8\uB97C \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
5439
+ for (const seg of trimmed.split("/").slice(1)) {
5440
+ if (seg === "") bad("\uBE48 \uC138\uADF8\uBA3C\uD2B8\uB97C \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4");
5441
+ if (seg === "." || seg === "..") bad('"."\xB7".." \uC138\uADF8\uBA3C\uD2B8\uB97C \uC4F8 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4');
5442
+ }
5443
+ return trimmed;
5444
+ }
5445
+ function trimTrailingSlashes(s) {
5446
+ let end = s.length;
5447
+ while (end > 0 && s[end - 1] === "/") end--;
5448
+ return s.slice(0, end);
5449
+ }
5450
+ function isSlotArtifact(a) {
5451
+ return a.name.includes("--");
5452
+ }
5453
+ function pageArtifacts(build, surface) {
5454
+ const prefix = surface.toLowerCase() + "/";
5455
+ return (build.artifacts ?? []).filter((a) => {
5456
+ if (isSlotArtifact(a)) return false;
5457
+ return a.kind !== "liquid" || a.name.startsWith(prefix);
5458
+ });
5459
+ }
5460
+ function displayName(a) {
5461
+ return a.kind === "liquid" ? a.name.slice(a.name.indexOf("/") + 1) : a.name;
5462
+ }
5463
+ function pageArtifactNames(build, surface) {
5464
+ return pageArtifacts(build, surface).map(displayName);
5465
+ }
5466
+ function resolvePageArtifact(build, template, surface) {
5467
+ const candidates = pageArtifacts(build, surface);
5468
+ return candidates.find((a) => a.name === template) ?? candidates.find((a) => a.kind === "liquid" && displayName(a) === template);
5469
+ }
5470
+ function derivedPagePath(a) {
5471
+ return "/" + displayName(a);
5472
+ }
5473
+ function findPathOwner(placements, path) {
5474
+ return placements.find((p5) => p5.kind === "PAGE" && p5.path !== void 0 && samePath(p5.path, path));
5475
+ }
5476
+ function samePath(a, b) {
5477
+ const norm = (s) => s === "/" ? s : trimTrailingSlashes(s) || "/";
5478
+ return norm(a) === norm(b);
5479
+ }
5480
+
5481
+ // src/commands/placement.ts
5482
+ var RECENT_BUILDS = 20;
5483
+ function latestSucceeded(builds, repo) {
5484
+ return builds.filter((b) => b.status === "SUCCEEDED" && buildMatchesRepo(b, repo)).sort((a, b) => a.requestedAt < b.requestedAt ? 1 : -1)[0];
5485
+ }
5486
+ function buildReason(latest, options) {
5487
+ if (options.build) return "--build \uC9C0\uC815 \u2014 push\uB41C \uAE30\uBCF8 \uBE0C\uB79C\uCE58 HEAD\uB85C \uC0C8\uB85C \uBE4C\uB4DC\uD569\uB2C8\uB2E4.";
5488
+ if (!latest)
5489
+ return "\uC774 \uB808\uD3EC\uC758 \uC131\uACF5\uD55C \uBE4C\uB4DC\uAC00 \uC5C6\uC5B4 \uBA3C\uC800 \uBE4C\uB4DC\uD569\uB2C8\uB2E4(\uD3EC\uD138\uC740 \uB808\uD3EC \uC5F0\uACB0\uB9CC\uC73C\uB85C \uBE4C\uB4DC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4).";
5490
+ return `\uCD5C\uC2E0 \uC131\uACF5 \uBE4C\uB4DC ${latest.id} \uC5D0 '${options.template}' \uD398\uC774\uC9C0\uAC00 \uC5C6\uC5B4 push\uB41C HEAD\uB85C \uB2E4\uC2DC \uBE4C\uB4DC\uD569\uB2C8\uB2E4.`;
5491
+ }
5492
+ async function ensureBuildWithArtifact(ctx, repo, template, options, deps) {
5493
+ const { organizationId: org, spaceId: space, surface } = ctx.link;
5494
+ const latest = options.build ? void 0 : latestSucceeded(await ctx.client.listBuilds(org, space, RECENT_BUILDS), repo);
5495
+ const found = latest && resolvePageArtifact(latest, template, surface);
5496
+ if (latest && found) return { build: latest, artifact: found };
5497
+ if (!options.json) console.error(pc20.dim(`[bstage] ${buildReason(latest, options)}`));
5498
+ if (!options.skipGitCheck) await precheckGit(deps, repo.defaultBranch);
5499
+ const created = await createAndAnnounceBuild(ctx, options.json);
5500
+ const done = await waitForCompletedBuild(ctx, deps, created, options.json);
5501
+ const artifact = resolvePageArtifact(done, template, surface);
5502
+ if (!artifact) {
5503
+ const names = pageArtifactNames(done, surface);
5504
+ fail(
5505
+ ExitCode.PRECONDITION,
5506
+ `\uBE4C\uB4DC ${done.id} \uC758 \uC0B0\uCD9C\uBB3C\uC5D0 '${template}' \uD398\uC774\uC9C0\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. --template \uC5D0 \uC4F8 \uC218 \uC788\uB294 \uAC12: ${names.length > 0 ? names.join(", ") : "(\uC5C6\uC74C)"}. sdk\uB294 src/pages/{\uC774\uB984}/template.tsx, liquid\uB294 public/{user|admin}/{\uC774\uB984}/ \uC744 \uCEE4\uBC0B\xB7push\uD588\uB294\uC9C0 \uD655\uC778\uD558\uC138\uC694.`
5507
+ );
5508
+ }
5509
+ return { build: done, artifact };
5510
+ }
5511
+ function nextCommand(path) {
5512
+ return `bstage deploy --placement ${path}`;
5513
+ }
5514
+ function reportExisting(owner, resolved, repoId, options, out) {
5515
+ const label = placementLabel(owner);
5516
+ if (owner.stageRepoId === repoId && owner.artifact === resolved.artifact.name) {
5517
+ if (options.json) {
5518
+ printJson(
5519
+ jsonSummary([{ id: owner.id, label, status: "unchanged" }], {
5520
+ placement: owner,
5521
+ build: { id: resolved.build.id, commitSha: resolved.build.commitSha },
5522
+ next: nextCommand(label)
5523
+ })
5524
+ );
5525
+ return;
5526
+ }
5527
+ out(
5528
+ `${pc20.green("\u2713")} ${label} \uC5D0 \uC774 \uB808\uD3EC\uC758 '${resolved.artifact.name}' \uBC30\uCE58\uAC00 \uC774\uBBF8 \uC788\uC2B5\uB2C8\uB2E4 (${owner.id}).`
5529
+ );
5530
+ out(pc20.dim(` \uB2E4\uC74C: ${nextCommand(label)}`));
5531
+ return;
5532
+ }
5533
+ const who = `\uBC30\uCE58 ${owner.id}, \uC0B0\uCD9C\uBB3C ${owner.artifact ?? "-"}${owner.stageRepoId === repoId ? "" : ", \uB2E4\uB978 \uB808\uD3EC"}`;
5534
+ if (options.json) {
5535
+ printJson(
5536
+ jsonSummary([{ id: owner.id, label, status: "conflict", message: who }], {
5537
+ placement: owner
5538
+ })
5539
+ );
5540
+ }
5541
+ fail(
5542
+ ExitCode.CONFLICT,
5543
+ `\uACBD\uB85C ${label} \uC5D0\uB294 \uC774\uBBF8 \uB2E4\uB978 \uBC30\uCE58\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${who}). \uB2E4\uB978 --path \uB97C \uC4F0\uAC70\uB098 \uD3EC\uD138\uC5D0\uC11C \uAE30\uC874 \uBC30\uCE58\uB97C \uC815\uB9AC\uD558\uC138\uC694.`
5544
+ );
5545
+ }
5546
+ function assertPathNotTakenEarly(placements, earlyPath, template, ctx, options) {
5547
+ const owner = findPathOwner(placements, earlyPath);
5548
+ if (!owner) return;
5549
+ const sameArtifact = owner.artifact === template || owner.artifact === `${ctx.link.surface.toLowerCase()}/${template}`;
5550
+ if (owner.stageRepoId === ctx.link.repoId && (owner.artifact === void 0 || sameArtifact)) {
5551
+ return;
5552
+ }
5553
+ const label = placementLabel(owner);
5554
+ const who = `\uBC30\uCE58 ${owner.id}, \uC0B0\uCD9C\uBB3C ${owner.artifact ?? "-"}${owner.stageRepoId === ctx.link.repoId ? "" : ", \uB2E4\uB978 \uB808\uD3EC"}`;
5555
+ if (options.json) {
5556
+ printJson(
5557
+ jsonSummary([{ id: owner.id, label, status: "conflict", message: who }], {
5558
+ placement: owner
5559
+ })
5560
+ );
5561
+ }
5562
+ fail(
5563
+ ExitCode.CONFLICT,
5564
+ `\uACBD\uB85C ${label} \uC5D0\uB294 \uC774\uBBF8 \uB2E4\uB978 \uBC30\uCE58\uAC00 \uC788\uC2B5\uB2C8\uB2E4 (${who}). \uB2E4\uB978 --path \uB97C \uC4F0\uAC70\uB098 \uD3EC\uD138\uC5D0\uC11C \uAE30\uC874 \uBC30\uCE58\uB97C \uC815\uB9AC\uD558\uC138\uC694.`
5565
+ );
5566
+ }
5567
+ function explainCreateError(err, label, options) {
5568
+ if (!(err instanceof PortalError)) throw err;
5569
+ if (options.json) {
5570
+ const status = err.status === 409 ? "conflict" : "failed";
5571
+ printJson(jsonSummary([{ id: "", label, status, message: err.message }]));
5572
+ }
5573
+ if (err.status === 409) {
5574
+ fail(
5575
+ ExitCode.CONFLICT,
5576
+ `\uAC19\uC740 \uB300\uC0C1\uC758 \uBC30\uCE58\uAC00 \uC774\uBBF8 \uC788\uC2B5\uB2C8\uB2E4: ${err.message}. bstage list \uB85C \uD655\uC778\uD558\uC138\uC694.`
5577
+ );
5578
+ }
5579
+ if (err.status === 403) {
5580
+ fail(
5581
+ ExitCode.AUTH,
5582
+ `\uBC30\uCE58\uB97C \uB9CC\uB4E4 \uAD8C\uD55C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4: ${err.message}. \uBC30\uCE58 \uC0DD\uC131\uC5D0\uB294 deploy \uB4F1\uAE09 CLI \uD1A0\uD070\uACFC \uC2A4\uD14C\uC774\uC9C0 \uAD00\uB9AC\uC790 \uC774\uC0C1 \uAD8C\uD55C\uC774 \uD544\uC694\uD569\uB2C8\uB2E4 \u2014 bstage login \uC73C\uB85C deploy \uB4F1\uAE09 \uD1A0\uD070\uC744 \uBC1B\uC73C\uC138\uC694. \uD3EC\uD138\uC774 CLI \uBC30\uCE58 \uC0DD\uC131\uC744 \uC544\uC9C1 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uBC84\uC804\uC774\uBA74 \uD3EC\uD138 \uD654\uBA74(\uC2A4\uD14C\uC774\uC9C0 > \uD398\uC774\uC9C0 > \uC0C8 \uD398\uC774\uC9C0)\uC5D0\uC11C \uB9CC\uB4DC\uC138\uC694.`
5583
+ );
5584
+ }
5585
+ if (err.status === 400) {
5586
+ const hint = err.message.includes("\uBE4C\uB4DC") ? " --build \uB85C \uB2E4\uC2DC \uBE4C\uB4DC\uD55C \uB4A4 \uC2E4\uD589\uD558\uC138\uC694." : "";
5587
+ fail(ExitCode.PRECONDITION, `\uBC30\uCE58\uB97C \uB9CC\uB4E4 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${err.message}.${hint}`);
5588
+ }
5589
+ throw err;
5590
+ }
5591
+ function reportCreated(created, resolved, options, out) {
5592
+ const label = placementLabel(created);
5593
+ if (options.json) {
5594
+ printJson(
5595
+ jsonSummary([{ id: created.id, label, status: "changed" }], {
5596
+ placement: created,
5597
+ build: { id: resolved.build.id, commitSha: resolved.build.commitSha },
5598
+ next: nextCommand(label)
5599
+ })
5600
+ );
5601
+ return;
5602
+ }
5603
+ out(
5604
+ `${pc20.green("\u2713")} \uBC30\uCE58\uB97C \uB9CC\uB4E4\uC5C8\uC2B5\uB2C8\uB2E4: ${label} \u2190 ${resolved.artifact.name} (${created.id}, \uBE4C\uB4DC ${resolved.build.id} \xB7 ${shortSha(resolved.build.commitSha)})`
5605
+ );
5606
+ out(pc20.dim(` \uC544\uC9C1 \uB77C\uC774\uBE0C\uAC00 \uC544\uB2D9\uB2C8\uB2E4. \uB2E4\uC74C: ${nextCommand(label)}`));
5607
+ }
5608
+ async function placementCreateCommand(options, deps = {}) {
5609
+ if (options.json && !options.yes) {
5610
+ fail(ExitCode.PRECONDITION, "--json \uC740 --yes \uC640 \uD568\uAED8 \uC4F0\uC138\uC694.");
5611
+ }
5612
+ const template = options.template?.trim();
5613
+ if (!template) {
5614
+ fail(
5615
+ ExitCode.PRECONDITION,
5616
+ "--template <\uC0B0\uCD9C\uBB3C \uC774\uB984> \uC774 \uD544\uC694\uD569\uB2C8\uB2E4 (sdk: src/pages/{\uC774\uB984}, liquid: public/{user|admin}/{\uC774\uB984})."
5617
+ );
5618
+ }
5619
+ const path = options.path !== void 0 ? normalizePagePath(options.path) : void 0;
5620
+ if (!options.yes) assertCanConfirm(deps);
5621
+ const out = deps.out ?? console.log;
5622
+ const ctx = await resolveContext({ cwd: deps.cwd, env: deps.env, fetch: deps.fetch });
5623
+ const { organizationId: org, spaceId: space, surface, repoId } = ctx.link;
5624
+ const repo = await resolveLinkedRepo(ctx);
5625
+ const before = await ctx.client.listPlacements(org, space, surface);
5626
+ assertPathNotTakenEarly(before, path ?? "/" + template, template, ctx, options);
5627
+ const resolved = await ensureBuildWithArtifact(ctx, repo, template, options, deps);
5628
+ const targetPath = path ?? derivedPagePath(resolved.artifact);
5629
+ const placements = await ctx.client.listPlacements(org, space, surface);
5630
+ const owner = findPathOwner(placements, targetPath);
5631
+ if (owner) {
5632
+ reportExisting(owner, resolved, repoId, options, out);
5633
+ return;
5634
+ }
5635
+ if (!options.yes) {
5636
+ const ok = await askConfirm(
5637
+ deps,
5638
+ `${org} / ${space} [${surface}] \uC758 ${targetPath} \uC5D0 '${resolved.artifact.name}' \uD398\uC774\uC9C0 \uBC30\uCE58\uB97C \uB9CC\uB4ED\uB2C8\uB2E4. \uC9C4\uD589\uD560\uAE4C\uC694?`
5639
+ );
5640
+ if (!ok) fail(ExitCode.PRECONDITION, "\uCDE8\uC18C\uD588\uC2B5\uB2C8\uB2E4.");
5641
+ }
5642
+ let created;
5643
+ try {
5644
+ created = await ctx.client.createPlacement(org, space, {
5645
+ kind: "PAGE",
5646
+ surface,
5647
+ repoId,
5648
+ artifact: resolved.artifact.name,
5649
+ ...path !== void 0 ? { path } : {}
5650
+ });
5651
+ } catch (err) {
5652
+ explainCreateError(err, targetPath, options);
5653
+ }
5654
+ reportCreated(created, resolved, options, out);
5408
5655
  }
5409
5656
 
5410
5657
  // src/commands/login.ts
5411
5658
  import { hostname as osHostname } from "os";
5412
- import pc19 from "picocolors";
5659
+ import pc21 from "picocolors";
5413
5660
 
5414
5661
  // src/portal/openBrowser.ts
5415
5662
  import { execFile as execFile2 } from "child_process";
@@ -5477,7 +5724,7 @@ async function loginWithToken(portalUrl, token, options, deps, env2) {
5477
5724
  return;
5478
5725
  }
5479
5726
  console.log(
5480
- pc19.green(`\u2713 ${portalUrl} \uC5D0 ${me.user.email} \uB85C \uB85C\uADF8\uC778\uD588\uC2B5\uB2C8\uB2E4 (\uC870\uC9C1 ${organizationId}).`)
5727
+ pc21.green(`\u2713 ${portalUrl} \uC5D0 ${me.user.email} \uB85C \uB85C\uADF8\uC778\uD588\uC2B5\uB2C8\uB2E4 (\uC870\uC9C1 ${organizationId}).`)
5481
5728
  );
5482
5729
  }
5483
5730
  function nextIntervalOnSlowDown(interval, retryAfterSec) {
@@ -5488,11 +5735,11 @@ function printDeviceCodePrompt(userCode, verificationUriComplete, expiresIn) {
5488
5735
  console.log("");
5489
5736
  console.log(` \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uC544\uB798 \uCF54\uB4DC\uB97C \uD655\uC778\uD558\uACE0 \uC2B9\uC778\uD558\uC138\uC694.`);
5490
5737
  console.log("");
5491
- console.log(` \uCF54\uB4DC ${pc19.bold(userCode)}`);
5492
- console.log(` \uC8FC\uC18C ${pc19.underline(verificationUriComplete)}`);
5738
+ console.log(` \uCF54\uB4DC ${pc21.bold(userCode)}`);
5739
+ console.log(` \uC8FC\uC18C ${pc21.underline(verificationUriComplete)}`);
5493
5740
  console.log("");
5494
5741
  console.log(
5495
- pc19.dim(
5742
+ pc21.dim(
5496
5743
  ` \uD130\uBBF8\uB110\uC758 \uCF54\uB4DC\uC640 \uBE0C\uB77C\uC6B0\uC800\uC758 \uCF54\uB4DC\uAC00 \uAC19\uC740\uC9C0 \uAF2D \uD655\uC778\uD558\uC138\uC694. ${Math.round(expiresIn / 60)}\uBD84 \uC548\uC5D0 \uC2B9\uC778\uB418\uC9C0 \uC54A\uC73C\uBA74 \uB9CC\uB8CC\uB429\uB2C8\uB2E4.`
5497
5744
  )
5498
5745
  );
@@ -5533,7 +5780,7 @@ async function openVerificationUri(portalUrl, verificationUriComplete, options,
5533
5780
  if (!sameOrigin(portalUrl, verificationUriComplete)) {
5534
5781
  if (!options.json) {
5535
5782
  console.log(
5536
- pc19.yellow(
5783
+ pc21.yellow(
5537
5784
  " \uC2B9\uC778 \uC8FC\uC18C\uAC00 \uD3EC\uD138\uACFC \uB2E4\uB978 \uC0AC\uC774\uD2B8\uC785\uB2C8\uB2E4. \uBE0C\uB77C\uC6B0\uC800\uB97C \uC5F4\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4 \u2014 \uC8FC\uC18C\uB97C \uD655\uC778\uD55C \uB4A4 \uC9C1\uC811 \uC5F4\uC5B4 \uC8FC\uC138\uC694."
5538
5785
  )
5539
5786
  );
@@ -5542,7 +5789,7 @@ async function openVerificationUri(portalUrl, verificationUriComplete, options,
5542
5789
  }
5543
5790
  const opened = await (deps.openBrowser ?? openBrowser)(verificationUriComplete);
5544
5791
  if (!opened && !options.json) {
5545
- console.log(pc19.dim(" \uBE0C\uB77C\uC6B0\uC800\uB97C \uC790\uB3D9\uC73C\uB85C \uC5F4\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uC704 \uC8FC\uC18C\uB97C \uC9C1\uC811 \uC5F4\uC5B4 \uC8FC\uC138\uC694."));
5792
+ console.log(pc21.dim(" \uBE0C\uB77C\uC6B0\uC800\uB97C \uC790\uB3D9\uC73C\uB85C \uC5F4\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uC704 \uC8FC\uC18C\uB97C \uC9C1\uC811 \uC5F4\uC5B4 \uC8FC\uC138\uC694."));
5546
5793
  }
5547
5794
  }
5548
5795
  function sameOrigin(a, b) {
@@ -5607,13 +5854,13 @@ function reportIssued(portalUrl, issued, organizationId, json) {
5607
5854
  });
5608
5855
  return;
5609
5856
  }
5610
- console.log(pc19.green(`\u2713 ${portalUrl} \uC5D0 \uB85C\uADF8\uC778\uD588\uC2B5\uB2C8\uB2E4.`));
5857
+ console.log(pc21.green(`\u2713 ${portalUrl} \uC5D0 \uB85C\uADF8\uC778\uD588\uC2B5\uB2C8\uB2E4.`));
5611
5858
  console.log(
5612
- pc19.dim(
5859
+ pc21.dim(
5613
5860
  ` \uC870\uC9C1 ${orgLabel(organizationId ?? UNKNOWN_ORG)} \xB7 \uD1A0\uD070 ${issued.prefix}\u2026 \xB7 \uB4F1\uAE09 ${issued.permission} \xB7 ${scopeLabel(issued.allSpaces, issued.spaceIds)} \xB7 \uB9CC\uB8CC ${issued.expiresAt.slice(0, 10)}`
5614
5861
  )
5615
5862
  );
5616
- console.log(pc19.dim(" \uB2E4\uC74C: \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC\uC5D0\uC11C bstage link"));
5863
+ console.log(pc21.dim(" \uB2E4\uC74C: \uD504\uB85C\uC81D\uD2B8 \uB514\uB809\uD130\uB9AC\uC5D0\uC11C bstage link"));
5617
5864
  }
5618
5865
  async function loginCommand(options, deps = {}) {
5619
5866
  const env2 = deps.env ?? process.env;
@@ -5630,7 +5877,7 @@ async function loginCommand(options, deps = {}) {
5630
5877
  }
5631
5878
 
5632
5879
  // src/commands/logout.ts
5633
- import pc20 from "picocolors";
5880
+ import pc22 from "picocolors";
5634
5881
  async function logoutCommand(options, deps = {}) {
5635
5882
  const cwd = deps.cwd ?? process.cwd();
5636
5883
  const env2 = deps.env ?? process.env;
@@ -5644,16 +5891,16 @@ async function logoutCommand(options, deps = {}) {
5644
5891
  const removed = await deleteCredential(portalUrl, options.org, env2);
5645
5892
  if (removed.length === 0) {
5646
5893
  const scope = options.org ? `\uC870\uC9C1 ${options.org} \uC758 ` : "";
5647
- console.log(pc20.yellow(`${portalUrl} \uC5D0 \uC800\uC7A5\uB41C ${scope}\uC790\uACA9\uC99D\uBA85\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.`));
5894
+ console.log(pc22.yellow(`${portalUrl} \uC5D0 \uC800\uC7A5\uB41C ${scope}\uC790\uACA9\uC99D\uBA85\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.`));
5648
5895
  } else {
5649
5896
  const orgs = removed.map(orgLabel).join(", ");
5650
- console.log(pc20.green(`\u2713 ${portalUrl} \uC790\uACA9\uC99D\uBA85\uC744 \uC0AD\uC81C\uD588\uC2B5\uB2C8\uB2E4 \u2014 \uC870\uC9C1 ${orgs}`));
5897
+ console.log(pc22.green(`\u2713 ${portalUrl} \uC790\uACA9\uC99D\uBA85\uC744 \uC0AD\uC81C\uD588\uC2B5\uB2C8\uB2E4 \u2014 \uC870\uC9C1 ${orgs}`));
5651
5898
  }
5652
- console.log(pc20.dim(" \uD3EC\uD138 \uD654\uBA74\uC5D0\uC11C \uD1A0\uD070 \uC790\uCCB4\uB97C \uD3D0\uAE30\uD558\uBA74 \uB2E4\uB978 \uAE30\uAE30\uC5D0\uC11C\uB3C4 \uBB34\uD6A8\uAC00 \uB429\uB2C8\uB2E4."));
5899
+ console.log(pc22.dim(" \uD3EC\uD138 \uD654\uBA74\uC5D0\uC11C \uD1A0\uD070 \uC790\uCCB4\uB97C \uD3D0\uAE30\uD558\uBA74 \uB2E4\uB978 \uAE30\uAE30\uC5D0\uC11C\uB3C4 \uBB34\uD6A8\uAC00 \uB429\uB2C8\uB2E4."));
5653
5900
  }
5654
5901
 
5655
5902
  // src/commands/publish.ts
5656
- import pc21 from "picocolors";
5903
+ import pc23 from "picocolors";
5657
5904
  function parseOnOff(v) {
5658
5905
  const s = v.toLowerCase();
5659
5906
  if (s === "on") return true;
@@ -5692,13 +5939,13 @@ async function togglePlacement(ctx, p5, enabled) {
5692
5939
  }
5693
5940
  function printResults2(results, enabled, out) {
5694
5941
  for (const r of results) {
5695
- const mark = r.status === "failed" ? pc21.red("\u2717") : r.status === "conflict" ? pc21.yellow("!") : pc21.green("\u2713");
5942
+ const mark = r.status === "failed" ? pc23.red("\u2717") : r.status === "conflict" ? pc23.yellow("!") : pc23.green("\u2713");
5696
5943
  const stateLabel = r.status === "unchanged" ? "\uBCC0\uACBD \uC5C6\uC74C" : `\uAC8C\uC2DC ${r.enabled ? "on" : "off"}`;
5697
- const suffix = r.message && r.status !== "unchanged" ? pc21.dim(` ${r.message}`) : "";
5944
+ const suffix = r.message && r.status !== "unchanged" ? pc23.dim(` ${r.message}`) : "";
5698
5945
  out(`${mark} ${r.label} ${stateLabel}${suffix}`);
5699
5946
  }
5700
5947
  if (!enabled) {
5701
- out(pc21.dim(" \uB77C\uC774\uBE0C \uBC84\uC804 \uD3EC\uC778\uD130\uB294 \uC720\uC9C0\uB429\uB2C8\uB2E4 \u2014 \uB2E4\uC2DC \uCF1C\uBA74 \uAC19\uC740 \uBE4C\uB4DC\uAC00 \uC989\uC2DC \uC11C\uBE59\uB429\uB2C8\uB2E4."));
5948
+ out(pc23.dim(" \uB77C\uC774\uBE0C \uBC84\uC804 \uD3EC\uC778\uD130\uB294 \uC720\uC9C0\uB429\uB2C8\uB2E4 \u2014 \uB2E4\uC2DC \uCF1C\uBA74 \uAC19\uC740 \uBE4C\uB4DC\uAC00 \uC989\uC2DC \uC11C\uBE59\uB429\uB2C8\uB2E4."));
5702
5949
  }
5703
5950
  }
5704
5951
  function reportOutcome2(results, options, enabled, out) {
@@ -5738,7 +5985,7 @@ async function publishCommand(state, options, deps = {}) {
5738
5985
  }
5739
5986
 
5740
5987
  // src/commands/rollback.ts
5741
- import pc22 from "picocolors";
5988
+ import pc24 from "picocolors";
5742
5989
  function pickRollbackTarget(builds, repo, currentLive) {
5743
5990
  const ok = builds.filter((b) => buildMatchesRepo(b, repo) && b.status === "SUCCEEDED").sort((a, b) => a.requestedAt < b.requestedAt ? 1 : -1);
5744
5991
  if (!currentLive) return ok[0] ?? null;
@@ -5823,16 +6070,16 @@ async function rollbackCommand(buildId, options, deps = {}) {
5823
6070
  reportOutcome(results, options, out);
5824
6071
  if (!options.json) {
5825
6072
  out(
5826
- pc22.dim(" \uB418\uB3CC\uB9B0 \uB4A4\uC5D0\uB3C4 \uCD5C\uC2E0 \uBE4C\uB4DC\uB294 \uB0A8\uC544 \uC788\uC2B5\uB2C8\uB2E4 \u2014 bstage deploy \uB85C \uB2E4\uC2DC \uC62C\uB9B4 \uC218 \uC788\uC2B5\uB2C8\uB2E4.")
6073
+ pc24.dim(" \uB418\uB3CC\uB9B0 \uB4A4\uC5D0\uB3C4 \uCD5C\uC2E0 \uBE4C\uB4DC\uB294 \uB0A8\uC544 \uC788\uC2B5\uB2C8\uB2E4 \u2014 bstage deploy \uB85C \uB2E4\uC2DC \uC62C\uB9B4 \uC218 \uC788\uC2B5\uB2C8\uB2E4.")
5827
6074
  );
5828
6075
  }
5829
6076
  }
5830
6077
 
5831
6078
  // src/commands/skills.ts
5832
- import pc23 from "picocolors";
6079
+ import pc25 from "picocolors";
5833
6080
  async function skillsInstallCommand(options) {
5834
6081
  console.warn(
5835
- pc23.yellow(
6082
+ pc25.yellow(
5836
6083
  "bstage skills install\uC740 bstage ai install\uB85C \uBC14\uB00C\uC5C8\uC2B5\uB2C8\uB2E4. \uB2E4\uC74C \uB9B4\uB9AC\uC988\uC5D0\uC11C \uC81C\uAC70\uB429\uB2C8\uB2E4."
5837
6084
  )
5838
6085
  );
@@ -5842,7 +6089,7 @@ async function skillsInstallCommand(options) {
5842
6089
  // src/commands/docs.ts
5843
6090
  import { existsSync as existsSync8, readdirSync as readdirSync3 } from "fs";
5844
6091
  import { join as join16 } from "path";
5845
- import pc24 from "picocolors";
6092
+ import pc26 from "picocolors";
5846
6093
  var DOC_ORDER = [
5847
6094
  ["GETTING_STARTED.md", "\uBE60\uB978 \uC2DC\uC791 \uAC00\uC774\uB4DC"],
5848
6095
  ["API_REFERENCE.md", "createTemplate, hooks, BstageClient, PlatformBridge API"],
@@ -5862,10 +6109,10 @@ var CORE_DOCS_SEGMENTS = ["node_modules", "@bstage-sdk", "core", "docs"];
5862
6109
  async function docsCommand() {
5863
6110
  const docsDir = join16(process.cwd(), ...CORE_DOCS_SEGMENTS);
5864
6111
  if (!existsSync8(docsDir)) {
5865
- console.log(pc24.yellow("SDK \uBB38\uC11C\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."));
5866
- console.log(pc24.dim(" @bstage-sdk/core\uAC00 \uC124\uCE58\uB418\uC5B4 \uC788\uB294\uC9C0 \uD655\uC778\uD558\uC138\uC694 (npm install \uD6C4 \uC7AC\uC2DC\uB3C4)."));
6112
+ console.log(pc26.yellow("SDK \uBB38\uC11C\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4."));
6113
+ console.log(pc26.dim(" @bstage-sdk/core\uAC00 \uC124\uCE58\uB418\uC5B4 \uC788\uB294\uC9C0 \uD655\uC778\uD558\uC138\uC694 (npm install \uD6C4 \uC7AC\uC2DC\uB3C4)."));
5867
6114
  console.log(
5868
- pc24.dim(
6115
+ pc26.dim(
5869
6116
  " SDK \uC758\uC874\uC774 \uC5C6\uB294 \uB808\uD3EC\uC5D0\uB294 \uC774 \uACBD\uB85C\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 liquid \uADDC\uC57D\xB7\uB370\uC774\uD130\uB294 bstage-liquid \uC2A4\uD0AC\uC744 \uBCF4\uC138\uC694."
5870
6117
  )
5871
6118
  );
@@ -5877,24 +6124,24 @@ async function docsCommand() {
5877
6124
  const known = new Set(DOC_ORDER.map(([f]) => f));
5878
6125
  const extras = [...present].filter((f) => !known.has(f)).sort();
5879
6126
  console.log("");
5880
- console.log(pc24.bold("bstage SDK \uBB38\uC11C"));
5881
- console.log(pc24.dim(` ${docsDir}`));
6127
+ console.log(pc26.bold("bstage SDK \uBB38\uC11C"));
6128
+ console.log(pc26.dim(` ${docsDir}`));
5882
6129
  console.log("");
5883
6130
  for (const [file3, desc] of ordered) {
5884
- console.log(` ${pc24.cyan(file3.padEnd(22))} ${pc24.dim(desc)}`);
6131
+ console.log(` ${pc26.cyan(file3.padEnd(22))} ${pc26.dim(desc)}`);
5885
6132
  }
5886
6133
  for (const file3 of extras) {
5887
- console.log(` ${pc24.cyan(file3.padEnd(22))}`);
6134
+ console.log(` ${pc26.cyan(file3.padEnd(22))}`);
5888
6135
  }
5889
6136
  console.log("");
5890
6137
  console.log(
5891
- pc24.dim("\uD30C\uC77C\uC744 \uC5F4\uC5B4 \uC0C1\uC138 \uB0B4\uC6A9\uC744 \uD655\uC778\uD558\uC138\uC694. \uCEE4\uB9E8\uB4DC \uB3C4\uC6C0\uB9D0\uC740 `bstage <command> --help`.")
6138
+ pc26.dim("\uD30C\uC77C\uC744 \uC5F4\uC5B4 \uC0C1\uC138 \uB0B4\uC6A9\uC744 \uD655\uC778\uD558\uC138\uC694. \uCEE4\uB9E8\uB4DC \uB3C4\uC6C0\uB9D0\uC740 `bstage <command> --help`.")
5892
6139
  );
5893
6140
  console.log("");
5894
6141
  }
5895
6142
 
5896
6143
  // src/commands/whoami.ts
5897
- import pc25 from "picocolors";
6144
+ import pc27 from "picocolors";
5898
6145
  function jsonEntry(c, active) {
5899
6146
  return {
5900
6147
  organizationId: c.organizationId,
@@ -5908,21 +6155,21 @@ function jsonEntry(c, active) {
5908
6155
  }
5909
6156
  function printCredentials(stored, activeOrg) {
5910
6157
  if (stored.length === 0) return;
5911
- console.log(pc25.dim("\uC800\uC7A5\uB41C \uD1A0\uD070"));
6158
+ console.log(pc27.dim("\uC800\uC7A5\uB41C \uD1A0\uD070"));
5912
6159
  const rows = stored.map((c) => [
5913
6160
  ` \uC870\uC9C1 ${orgLabel(c.organizationId)}`,
5914
6161
  `\uB4F1\uAE09 ${c.permission ?? "-"}`,
5915
6162
  scopeLabel(c.allSpaces, c.spaceIds),
5916
6163
  `\uB9CC\uB8CC ${c.expiresAt ? c.expiresAt.slice(0, 10) : "-"}`,
5917
- c.organizationId === activeOrg ? pc25.dim("(\uC0AC\uC6A9 \uC911)") : ""
6164
+ c.organizationId === activeOrg ? pc27.dim("(\uC0AC\uC6A9 \uC911)") : ""
5918
6165
  ]);
5919
6166
  console.log(table(rows));
5920
6167
  }
5921
6168
  function printMe(me, portalUrl) {
5922
- console.log(`${pc25.bold(me.user.email)} ${pc25.dim(portalUrl)}`);
6169
+ console.log(`${pc27.bold(me.user.email)} ${pc27.dim(portalUrl)}`);
5923
6170
  for (const m of me.memberships) {
5924
6171
  const stages = Object.entries(m.stageRoles ?? {}).map(([s, r]) => `${s}:${r}`).join(", ");
5925
- console.log(` \uC870\uC9C1 ${m.organizationId} ${m.organizationRole ?? ""} ${pc25.dim(stages)}`);
6172
+ console.log(` \uC870\uC9C1 ${m.organizationId} ${m.organizationRole ?? ""} ${pc27.dim(stages)}`);
5926
6173
  }
5927
6174
  }
5928
6175
  async function whoamiCommand(options, deps = {}) {
@@ -5978,10 +6225,10 @@ function reportStoredOnly(portalUrl, stored, json) {
5978
6225
  });
5979
6226
  return;
5980
6227
  }
5981
- console.log(pc25.dim(portalUrl));
6228
+ console.log(pc27.dim(portalUrl));
5982
6229
  printCredentials(stored);
5983
6230
  console.log(
5984
- pc25.yellow(" \uC5EC\uB7EC \uC870\uC9C1\uC758 \uD1A0\uD070\uC774 \uC788\uC2B5\uB2C8\uB2E4 \u2014 --org <id> \uB85C \uC870\uC9C1\uC744 \uC9C0\uC815\uD558\uBA74 \uACC4\uC815 \uC815\uBCF4\uB3C4 \uBD05\uB2C8\uB2E4.")
6231
+ pc27.yellow(" \uC5EC\uB7EC \uC870\uC9C1\uC758 \uD1A0\uD070\uC774 \uC788\uC2B5\uB2C8\uB2E4 \u2014 --org <id> \uB85C \uC870\uC9C1\uC744 \uC9C0\uC815\uD558\uBA74 \uACC4\uC815 \uC815\uBCF4\uB3C4 \uBD05\uB2C8\uB2E4.")
5985
6232
  );
5986
6233
  }
5987
6234
 
@@ -6038,6 +6285,13 @@ program.command("logout").description("\uC800\uC7A5\uB41C \uD3EC\uD138 \uC790\uA
6038
6285
  program.command("link").description("\uC774 \uB514\uB809\uD130\uB9AC\uB97C \uD3EC\uD138 \uC870\uC9C1\xB7\uC2A4\uD14C\uC774\uC9C0\xB7\uB808\uD3EC\uC5D0 \uC5F0\uACB0 (.bstage/project.json)").option("--phase <phase>", "\uD3EC\uD138 \uD658\uACBD (\uC0DD\uB7B5 \uC2DC .env\uC758 VITE_BSTAGE_PHASE \u2192 sandbox)").option("--portal <url>", "\uD3EC\uD138 \uC8FC\uC18C \uC9C1\uC811 \uC9C0\uC815 (\uD5C8\uC6A9 \uBAA9\uB85D \uBC16 \uD3EC\uD138\uC740 \uC774 \uC635\uC158\uC73C\uB85C)").option("--org <id>", "\uC870\uC9C1 ID").option("--space <id>", "\uC2A4\uD14C\uC774\uC9C0(\uC2A4\uD398\uC774\uC2A4) ID").option("--repo <id|owner/repo>", "\uC5F0\uACB0 \uB808\uD3EC").option("-y, --yes", "\uD504\uB86C\uD504\uD2B8 \uC5C6\uC774 (\uD6C4\uBCF4\uAC00 \uC720\uC77C\uD558\uAC70\uB098 \uC635\uC158\uC73C\uB85C \uC9C0\uC815\uB3FC\uC57C \uD568)").option("--json", "\uAD6C\uC870\uD654 \uCD9C\uB825 (--yes \uC640 \uD568\uAED8)").action((o) => runCommand(() => linkCommand(o)));
6039
6286
  program.command("list").alias("ls").description("\uC774 \uB808\uD3EC\uC758 \uBC30\uCE58(\uB77C\uC774\uBE0C \uBC84\uC804\xB7\uAC8C\uC2DC \uC0C1\uD0DC)\uC640 \uCD5C\uADFC \uBE4C\uB4DC").option("--builds <n>", "\uD45C\uC2DC\uD560 \uBE4C\uB4DC \uC218", "5").option("--json", "\uAD6C\uC870\uD654 \uCD9C\uB825").action((o) => runCommand(() => listCommand(o)));
6040
6287
  program.command("deploy").description("push\uB41C \uCEE4\uBC0B\uC744 \uD3EC\uD138\uC5D0\uC11C \uBE4C\uB4DC\uD558\uACE0 \uC774 \uB808\uD3EC\uC758 \uBC30\uCE58\uC5D0 \uB77C\uC774\uBE0C \uC801\uC6A9").option("-y, --yes", "\uD655\uC778 \uC5C6\uC774 \uC801\uC6A9").option("--placement <id|path|slotId>", "\uD2B9\uC815 \uBC30\uCE58\uB9CC").option("--skip-git-check", "\uB354\uD2F0 \uD2B8\uB9AC\xB7\uBE0C\uB79C\uCE58\xB7push \uC810\uAC80 \uC0DD\uB7B5").option("--no-wait", "\uBE4C\uB4DC\uB9CC \uC2DC\uC791\uD558\uACE0 \uC885\uB8CC").option("--json", "\uAD6C\uC870\uD654 \uCD9C\uB825 (--yes \uC640 \uD568\uAED8)").action((o) => runCommand(() => deployCommand({ ...o, noWait: o.wait === false })));
6288
+ var placement = program.command("placement").description("\uC774 \uB808\uD3EC\uC758 \uD398\uC774\uC9C0 \uBC30\uCE58 \uAD00\uB9AC (\uC0DD\uC131 \u2014 \uC0AD\uC81C\xB7\uC704\uC82F \uBC30\uCE58\uB294 \uD3EC\uD138 \uD654\uBA74 \uC804\uC6A9)");
6289
+ placement.command("create").description(
6290
+ "\uBE4C\uB4DC \uC0B0\uCD9C\uBB3C \uD558\uB098\uB97C \uD398\uC774\uC9C0(PAGE) \uBC30\uCE58\uB85C \uB9CC\uB4E0\uB2E4 \u2014 \uC131\uACF5 \uBE4C\uB4DC\uC5D0 \uC0B0\uCD9C\uBB3C\uC774 \uC5C6\uC73C\uBA74 \uBE4C\uB4DC\uBD80\uD130 (deploy \uB4F1\uAE09 \uD1A0\uD070)"
6291
+ ).option(
6292
+ "--template <name>",
6293
+ "(\uD544\uC218) \uC0B0\uCD9C\uBB3C \uC774\uB984 (sdk: src/pages/{\uC774\uB984}, liquid: public/{user|admin}/{\uC774\uB984})"
6294
+ ).option("--path <path>", "\uD398\uC774\uC9C0 \uACBD\uB85C (\uC0DD\uB7B5 \uC2DC /{\uC0B0\uCD9C\uBB3C \uC774\uB984})").option("--build", "\uC131\uACF5 \uBE4C\uB4DC\uAC00 \uC788\uC5B4\uB3C4 push\uB41C \uAE30\uBCF8 \uBE0C\uB79C\uCE58 HEAD\uB85C \uC0C8\uB85C \uBE4C\uB4DC").option("--skip-git-check", "\uBE4C\uB4DC\uD560 \uB54C \uB354\uD2F0 \uD2B8\uB9AC\xB7\uBE0C\uB79C\uCE58\xB7push \uC810\uAC80 \uC0DD\uB7B5").option("-y, --yes", "\uD655\uC778 \uC5C6\uC774").option("--json", "\uAD6C\uC870\uD654 \uCD9C\uB825 (--yes \uC640 \uD568\uAED8)").action((o) => runCommand(() => placementCreateCommand(o)));
6041
6295
  program.command("rollback [buildId]").description("\uC774\uC804 \uC131\uACF5 \uBE4C\uB4DC(\uB610\uB294 \uC9C0\uC815\uD55C \uBE4C\uB4DC)\uB97C \uB77C\uC774\uBE0C\uB85C \uC7AC\uC801\uC6A9").option("-y, --yes", "\uD655\uC778 \uC5C6\uC774 \uC801\uC6A9").option("--placement <id|path|slotId>", "\uD2B9\uC815 \uBC30\uCE58\uB9CC").option("--json", "\uAD6C\uC870\uD654 \uCD9C\uB825 (--yes \uC640 \uD568\uAED8)").action((id, o) => runCommand(() => rollbackCommand(id, o)));
6042
6296
  program.command("publish <on|off>").description("\uBC30\uCE58 \uAC8C\uC2DC \uCF1C\uAE30/\uB044\uAE30 (\uB77C\uC774\uBE0C \uBC84\uC804\uC740 \uC720\uC9C0)").option("--placement <id|path|slotId>", "\uD2B9\uC815 \uBC30\uCE58\uB9CC").option("-y, --yes", "\uD655\uC778 \uC5C6\uC774").option("--json", "\uAD6C\uC870\uD654 \uCD9C\uB825 (--yes \uC640 \uD568\uAED8)").action((state, o) => runCommand(() => publishCommand(state, o)));
6043
6297
  program.command("logs [buildId]").description("\uBE4C\uB4DC \uB85C\uADF8 (\uC0DD\uB7B5 \uC2DC \uCD5C\uADFC \uBE4C\uB4DC)").option("-f, --follow", "\uC9C4\uD589 \uC911\uC774\uBA74 \uB05D\uB0A0 \uB54C\uAE4C\uC9C0 \uC774\uC5B4\uC11C \uCD9C\uB825").option("--json", "\uAD6C\uC870\uD654 \uCD9C\uB825").action((id, o) => runCommand(() => logsCommand(id, o)));
@@ -6056,6 +6310,8 @@ program.addHelpText(
6056
6310
  $ bstage login \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uC2B9\uC778\uD574 \uB85C\uADF8\uC778 (CI: --token \uB610\uB294 BSTAGE_TOKEN)
6057
6311
  $ bstage link \uB514\uB809\uD130\uB9AC\uB97C \uD3EC\uD138 \uC870\uC9C1\xB7\uC2A4\uD14C\uC774\uC9C0\xB7\uB808\uD3EC\uC5D0 \uC5F0\uACB0
6058
6312
  $ bstage list \uC774 \uB808\uD3EC\uC758 \uBC30\uCE58\xB7\uCD5C\uADFC \uBE4C\uB4DC \uD655\uC778
6313
+ $ bstage placement create --template todos --path /todos
6314
+ \uD398\uC774\uC9C0 \uBC30\uCE58 \uB9CC\uB4E4\uAE30 (\uBE4C\uB4DC\uAC00 \uC5C6\uC73C\uBA74 \uBE4C\uB4DC\uBD80\uD130)
6059
6315
  $ bstage deploy push\uB41C \uCEE4\uBC0B\uC744 \uBE4C\uB4DC\uD574 \uC774 \uB808\uD3EC\uC758 \uBC30\uCE58\uC5D0 \uB77C\uC774\uBE0C \uC801\uC6A9
6060
6316
  $ bstage rollback \uC774\uC804 \uC131\uACF5 \uBE4C\uB4DC\uB85C \uB77C\uC774\uBE0C\uB97C \uB418\uB3CC\uB9BC
6061
6317
  $ bstage publish off \uAC8C\uC2DC \uB044\uAE30 (\uB77C\uC774\uBE0C \uBC84\uC804 \uC720\uC9C0)