@zalkera/cli 0.28.1 → 0.29.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.
Files changed (3) hide show
  1. package/README.md +3 -3
  2. package/dist/main.js +84 -54
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -103,9 +103,9 @@ zalkera logout
103
103
  `y`/`버립니다` 를 그대로 이어 붙인다 — 크레딧이 안 걸렸으니 다시 묻지 않는다.
104
104
  - 다만 확인하시는 사이 사이트 쪽 편집이 달라졌으면 **아무것도 안 버리고** 멈춘다.
105
105
  보여 드린 것과 버리는 것이 갈리면 안 되기 때문이다.
106
- - ⚠ **되돌리기는 원장을 되감지 않는다.** 되돌릴 대상이 마지막 버전이 아니면 사이트는 그 내용으로
107
- **새 버전을 세워** 켠다 — 그래서 「5판으로 되돌렸습니다」 뒤에 켜진 번호가 10일 수 있다. 그때
108
- 그 사실을 함께 말한다.
106
+ - ⚠ **되돌리기는 버전 목록을 되감지 않는다.** 되돌릴 대상이 마지막 버전이 아니면 사이트는 그
107
+ 내용으로 **새 버전을 세워** 켠다 — 그래서 「버전 5로 되돌렸습니다」 뒤에 켜진 번호가 10일 수
108
+ 있다. 그때 그 사실을 함께 말한다.
109
109
  - ⚠ **편집이 걸려 있으면 되돌리기가 막힌다.** 사이트가 그것을 거절한다 — 먼저 `zalkera publish`
110
110
  로 새 버전을 만들거나 `zalkera discard` 로 버려야 한다.
111
111
  - 그 편집이 **옛 버전 위**에 있으면(그 사이 라이브가 옮겨진 경우) `publish` 쪽도 막힌다.
package/dist/main.js CHANGED
@@ -25,7 +25,7 @@ function plainNotice(text, limit = 300) {
25
25
  return "";
26
26
  const cap = Math.min(limit, MAX_CAP);
27
27
  const head = text.length > cap * 4 ? text.slice(0, cap * 4) : text;
28
- const stripped = head.replace(/[\u0000-\u001f\u007f-\u009f\u200b-\u200f\u202a-\u202e\u2066-\u2069\u2028\u2029]+/g, " ");
28
+ const stripped = head.replace(new RegExp("[\\u0000-\\u001f\\u007f-\\u009f\\u2028\\u2029]|\\p{Cf}", "gu"), " ");
29
29
  const tidy = defang(stripped).replace(/\s+/g, " ").trim();
30
30
  return tidy.length > cap ? `${tidy.slice(0, cap)}\u2026` : tidy;
31
31
  }
@@ -1131,7 +1131,7 @@ async function ensureEnvIgnored(dir) {
1131
1131
  return "created";
1132
1132
  }
1133
1133
  const content = await readFile2(path, "utf8");
1134
- const ignored = content.split("\n").map((line) => line.trim()).some((line) => line === ".env.local" || line === ".env*" || line === ".env*.local");
1134
+ const ignored = content.split("\n").map((line) => line.trim()).some((line) => line === ".env.local" || line === ".env*" || line === ".env.*" || line === ".env*.local");
1135
1135
  if (ignored)
1136
1136
  return "already";
1137
1137
  const suffix = content.endsWith("\n") || content.length === 0 ? "" : "\n";
@@ -1363,8 +1363,12 @@ async function createSink(targetDir, options) {
1363
1363
  if (options.rejectVendored === true)
1364
1364
  assertNotVendored(segments, name);
1365
1365
  if (entry.type === "5") {
1366
- if (options.decide)
1367
- return;
1366
+ if (options.decide) {
1367
+ if (options.emptyDirs !== true)
1368
+ return;
1369
+ if (options.decide(`${segments.join("/")}/`) === "skip")
1370
+ return;
1371
+ }
1368
1372
  await descend(root, segments, verified);
1369
1373
  return;
1370
1374
  }
@@ -1940,7 +1944,39 @@ function serializeSyncLedger(ledger) {
1940
1944
  }
1941
1945
 
1942
1946
  // ../core/dist/localMark.js
1947
+ import { join as join10 } from "node:path";
1948
+
1949
+ // ../core/dist/gitExclude.js
1950
+ import { chmod as chmod3, lstat as lstat3, readFile as readFile5 } from "node:fs/promises";
1943
1951
  import { join as join9 } from "node:path";
1952
+ async function excludeFromGit(root, path) {
1953
+ try {
1954
+ const info = await lstat3(join9(root, ".git")).catch(() => null);
1955
+ if (!info || !info.isDirectory())
1956
+ return "no-git";
1957
+ const dir = await ensureOwnDir(root, ".git", "info");
1958
+ const file = join9(dir, "exclude");
1959
+ const leaf = await lstat3(file).catch((error) => {
1960
+ if (error?.code === "ENOENT")
1961
+ return null;
1962
+ throw error;
1963
+ });
1964
+ if (leaf !== null && !leaf.isFile())
1965
+ return "failed";
1966
+ const current = leaf === null ? "" : await readFile5(file, "utf8");
1967
+ if (current.split(/\r?\n/).some((line) => line.trim() === path))
1968
+ return "already";
1969
+ const prefix = current === "" || current.endsWith("\n") ? "" : "\n";
1970
+ const mode = leaf === null ? 420 : leaf.mode & 511;
1971
+ await writeOwnFile(file, `${current}${prefix}${path}
1972
+ `, mode);
1973
+ if (leaf !== null)
1974
+ await chmod3(file, mode);
1975
+ return "written";
1976
+ } catch {
1977
+ return "failed";
1978
+ }
1979
+ }
1944
1980
 
1945
1981
  // ../core/dist/sourceVersion.js
1946
1982
  var VERSION_DIGEST_PATTERN = /^[0-9a-f]{64}$/;
@@ -2027,11 +2063,12 @@ async function writeSourceMarkTo(root, mark) {
2027
2063
  async function writeMarkText(root, text) {
2028
2064
  try {
2029
2065
  await ensureOwnDir(root, ".zalkera");
2030
- await writeOwnFile(join9(root, SOURCE_MARK_PATH), text);
2031
- return { ok: true, text: "" };
2066
+ await writeOwnFile(join10(root, SOURCE_MARK_PATH), text);
2032
2067
  } catch (error) {
2033
2068
  return { ok: false, reason: error instanceof Error ? error.message : String(error) };
2034
2069
  }
2070
+ await excludeFromGit(root, SOURCE_MARK_PATH);
2071
+ return { ok: true, text: "" };
2035
2072
  }
2036
2073
 
2037
2074
  // ../core/dist/provenance.js
@@ -2039,7 +2076,7 @@ var PROVENANCE_PATH = ".zalkera/provenance.json";
2039
2076
 
2040
2077
  // ../core/dist/zip.js
2041
2078
  init_errors();
2042
- import { join as join10, relative as relative3, sep as sep3 } from "node:path";
2079
+ import { join as join11, relative as relative3, sep as sep3 } from "node:path";
2043
2080
  import { deflateRaw } from "node:zlib";
2044
2081
  import { promisify } from "node:util";
2045
2082
  var deflate = promisify(deflateRaw);
@@ -2184,8 +2221,9 @@ var SECRET_NAMES = /* @__PURE__ */ new Set([
2184
2221
  var SECRET_SUFFIXES = [".pem", ".key", ".p12", ".pfx", ".p8"];
2185
2222
  var EXCLUDED_PATHS = /* @__PURE__ */ new Set([".zalkera/source.json", SYNC_LEDGER_PATH, PROVENANCE_PATH]);
2186
2223
  var EXCLUDED_PREFIXES = [".zalkera/saved/"];
2224
+ var OWN_TMP = /\.zalkera-[0-9a-f]{12}\.tmp$/;
2187
2225
  function isExcludedPath(path) {
2188
- return EXCLUDED_PATHS.has(path) || EXCLUDED_PREFIXES.some((prefix) => path.startsWith(prefix));
2226
+ return EXCLUDED_PATHS.has(path) || EXCLUDED_PREFIXES.some((prefix) => path.startsWith(prefix)) || OWN_TMP.test(path);
2189
2227
  }
2190
2228
  function isExcludedEntry(entryPath) {
2191
2229
  const path = entryPath.split(sep3).join("/").toLowerCase();
@@ -2268,8 +2306,8 @@ var SERVER_NORMALIZATION_SETS = {
2268
2306
  init_errors();
2269
2307
  import { createReadStream as createReadStream2 } from "node:fs";
2270
2308
  import { createHash as createHash5 } from "node:crypto";
2271
- import { lstat as lstat3, readdir as readdir3 } from "node:fs/promises";
2272
- import { join as join11, sep as sep4 } from "node:path";
2309
+ import { lstat as lstat4, readdir as readdir3 } from "node:fs/promises";
2310
+ import { join as join12, sep as sep4 } from "node:path";
2273
2311
  async function hashWorkdir(root, options = {}) {
2274
2312
  const manifest = {};
2275
2313
  const cap = Math.min(options.maxEntries ?? MAX_ENTRIES, MAX_ENTRIES);
@@ -2287,7 +2325,7 @@ async function hashWorkdir(root, options = {}) {
2287
2325
  if (item.isSymbolicLink())
2288
2326
  continue;
2289
2327
  if (item.isDirectory()) {
2290
- await walk(join11(dir, item.name), relative5);
2328
+ await walk(join12(dir, item.name), relative5);
2291
2329
  continue;
2292
2330
  }
2293
2331
  if (!item.isFile())
@@ -2296,7 +2334,7 @@ async function hashWorkdir(root, options = {}) {
2296
2334
  if (seen > cap) {
2297
2335
  throw new DevtoolsError("LOCAL_TOO_LARGE", `\uC774 \uD3F4\uB354\uC758 \uD30C\uC77C\uC774 \uB108\uBB34 \uB9CE\uC2B5\uB2C8\uB2E4(${cap}\uAC1C \uCD08\uACFC).`, "\uC0AC\uC774\uD2B8 \uD3F4\uB354\uAC00 \uC544\uB2CC \uACF3\uC744 \uAC00\uB9AC\uD0A4\uACE0 \uC788\uC9C0 \uC54A\uC740\uC9C0 \uD655\uC778\uD574 \uC8FC\uC138\uC694.");
2298
2336
  }
2299
- manifest[relative5] = { sha256: await hashFile(join11(dir, item.name)) };
2337
+ manifest[relative5] = { sha256: await hashFile(join12(dir, item.name)) };
2300
2338
  }
2301
2339
  }
2302
2340
  await walk(root, "");
@@ -2318,8 +2356,8 @@ async function resolveExisting(root, path) {
2318
2356
  return null;
2319
2357
  let current = root;
2320
2358
  for (const part of segments) {
2321
- const next = join11(current, part);
2322
- const info = await lstat3(next).catch(() => null);
2359
+ const next = join12(current, part);
2360
+ const info = await lstat4(next).catch(() => null);
2323
2361
  if (!info || info.isSymbolicLink())
2324
2362
  return null;
2325
2363
  current = next;
@@ -2496,10 +2534,13 @@ var DEFAULT_TIMEOUT_MS2 = 10 * 60 * 1e3;
2496
2534
  // ../core/dist/tenantScope.js
2497
2535
  init_notice();
2498
2536
 
2537
+ // ../core/dist/git.js
2538
+ init_notice();
2539
+
2499
2540
  // ../core/dist/npmChoice.js
2500
2541
  import { execFileSync } from "node:child_process";
2501
2542
  import { existsSync as existsSync7, realpathSync } from "node:fs";
2502
- import { delimiter as delimiter2, isAbsolute as isAbsolute2, join as join12, normalize as normalize3, sep as sep5 } from "node:path";
2543
+ import { delimiter as delimiter2, isAbsolute as isAbsolute2, join as join13, normalize as normalize3, sep as sep5 } from "node:path";
2503
2544
  var MIN_SYSTEM_NPM_MAJOR = 9;
2504
2545
  function majorOf(version2) {
2505
2546
  const m = /^(\d+)\./.exec((version2 ?? "").trim());
@@ -2562,7 +2603,7 @@ function npmArgvOf(choice, nodePath) {
2562
2603
  return null;
2563
2604
  }
2564
2605
  }
2565
- var PATH_OPS = { join: join12, isAbsolute: isAbsolute2, normalize: normalize3, sep: sep5 };
2606
+ var PATH_OPS = { join: join13, isAbsolute: isAbsolute2, normalize: normalize3, sep: sep5 };
2566
2607
  function probeSystemNpm(nodePath, excludeUnder = [], env = process.env) {
2567
2608
  const entries = (env.PATH ?? "").split(delimiter2);
2568
2609
  for (const step of systemNpmSearchSteps(entries, PATH_OPS, excludeUnder)) {
@@ -2641,12 +2682,12 @@ var UPGRADE_NOTICE_INTERVAL_MS = 24 * 60 * 60 * 1e3;
2641
2682
 
2642
2683
  // ../core/dist/tokenPath.js
2643
2684
  import { homedir as homedir2 } from "node:os";
2644
- import { isAbsolute as isAbsolute3, join as join13, resolve as resolve5, sep as sep6 } from "node:path";
2685
+ import { isAbsolute as isAbsolute3, join as join14, resolve as resolve5, sep as sep6 } from "node:path";
2645
2686
  function tokenPath(env = process.env, home = homedir2()) {
2646
- const fallback = join13(home, ".config");
2687
+ const fallback = join14(home, ".config");
2647
2688
  const base = env.XDG_CONFIG_HOME;
2648
2689
  const inside = base !== void 0 && isAbsolute3(base) && (resolve5(base) === resolve5(home) || resolve5(base).startsWith(resolve5(home) + sep6));
2649
- return join13(inside ? resolve5(base) : fallback, "zalkera", "auth.json");
2690
+ return join14(inside ? resolve5(base) : fallback, "zalkera", "auth.json");
2650
2691
  }
2651
2692
 
2652
2693
  // ../core/dist/index.js
@@ -2766,9 +2807,9 @@ function trimPaths(paths, cap = PATH_LIST_CAP, all = false) {
2766
2807
  }
2767
2808
 
2768
2809
  // ../core/dist/pull.js
2769
- import { lstat as lstat4, mkdir as mkdir5, readFile as readFile5, realpath as realpath2, rename as rename2, rmdir, stat as stat3, unlink, writeFile as writeFile7 } from "node:fs/promises";
2810
+ import { lstat as lstat5, mkdir as mkdir5, readFile as readFile6, realpath as realpath2, rename as rename2, rmdir, unlink } from "node:fs/promises";
2770
2811
  init_errors();
2771
- import { basename as basename2, dirname as dirname2, join as join14, relative as relative4, resolve as resolve6, sep as sep7 } from "node:path";
2812
+ import { basename as basename2, dirname as dirname2, join as join15, relative as relative4, resolve as resolve6, sep as sep7 } from "node:path";
2772
2813
  var SAVED_SUFFIX = ".zalkera-saved";
2773
2814
  async function pullSiteSource(options) {
2774
2815
  const report = options.onProgress ?? (() => {
@@ -2867,11 +2908,11 @@ async function requireNoLinkedTargets(root, paths) {
2867
2908
  const segments = path.split("/").filter((s) => s !== "");
2868
2909
  let current = root;
2869
2910
  for (const part of segments) {
2870
- current = join14(current, part);
2911
+ current = join15(current, part);
2871
2912
  if (checked.has(current))
2872
2913
  continue;
2873
2914
  checked.add(current);
2874
- const info = await lstat4(current).catch(() => null);
2915
+ const info = await lstat5(current).catch(() => null);
2875
2916
  if (!info?.isSymbolicLink())
2876
2917
  continue;
2877
2918
  throw new DevtoolsError("PULL_WOULD_OVERWRITE", `\uC774 \uD3F4\uB354\uC758 ${relative4(root, current).split(sep7).join("/")} \uAC00 \uB2E4\uB978 \uACF3\uC744 \uAC00\uB9AC\uD0A4\uB294 \uBC14\uB85C\uAC00\uAE30\uC785\uB2C8\uB2E4. \uC544\uBB34\uAC83\uB3C4 \uBC1B\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.`, "\uADF8 \uBC14\uB85C\uAC00\uAE30\uB97C \uC9C0\uC6B0\uACE0 \uB2E4\uC2DC \uC2E4\uD589\uD574 \uC8FC\uC138\uC694. \uADF8\uB300\uB85C \uB450\uBA74 \uC774 \uD3F4\uB354 \uBC16\uC758 \uAC83\uC744 \uB36E\uC5B4\uC4F0\uAC8C \uB429\uB2C8\uB2E4.");
@@ -2890,13 +2931,13 @@ function withoutExcluded(declared) {
2890
2931
  return { incoming, dropped: dropped.sort() };
2891
2932
  }
2892
2933
  async function readLedger(root) {
2893
- const text = await readFile5(join14(root, SYNC_LEDGER_PATH), "utf8").catch(() => null);
2934
+ const text = await readFile6(join15(root, SYNC_LEDGER_PATH), "utf8").catch(() => null);
2894
2935
  return text === null ? null : parseSyncLedger(text);
2895
2936
  }
2896
2937
  async function writeLedger(root, ledger) {
2897
2938
  try {
2898
2939
  const dir = await ensureOwnDir(root, ...SYNC_LEDGER_PATH.split("/").slice(0, -1));
2899
- await writeOwnFile(join14(dir, basename2(SYNC_LEDGER_PATH)), serializeSyncLedger(ledger));
2940
+ await writeOwnFile(join15(dir, basename2(SYNC_LEDGER_PATH)), serializeSyncLedger(ledger));
2900
2941
  } catch {
2901
2942
  return false;
2902
2943
  }
@@ -2905,18 +2946,7 @@ async function writeLedger(root, ledger) {
2905
2946
  return true;
2906
2947
  }
2907
2948
  async function ignoreLedger(root) {
2908
- const info = join14(root, ".git", "info");
2909
- const exists = await stat3(join14(root, ".git")).then((s) => s.isDirectory()).catch(() => false);
2910
- if (!exists)
2911
- return;
2912
- const path = join14(info, "exclude");
2913
- const current = await readFile5(path, "utf8").catch(() => "");
2914
- if (current.split(/\r?\n/).some((line) => line.trim() === SYNC_LEDGER_PATH))
2915
- return;
2916
- await mkdir5(info, { recursive: true });
2917
- const prefix = current === "" || current.endsWith("\n") ? "" : "\n";
2918
- await writeFile7(path, `${current}${prefix}${SYNC_LEDGER_PATH}
2919
- `);
2949
+ await excludeFromGit(root, SYNC_LEDGER_PATH);
2920
2950
  }
2921
2951
  async function currentGeneration(api) {
2922
2952
  return await api.draftFiles().then((state) => state.generation ?? null).catch(() => null);
@@ -2946,13 +2976,13 @@ async function applyDeletes(root, paths) {
2946
2976
  async function setAside(root, plan) {
2947
2977
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
2948
2978
  const real = await realpath2(root).catch(() => root);
2949
- const saved = join14(dirname2(real), `${basename2(real)}${SAVED_SUFFIX}`, stamp);
2979
+ const saved = join15(dirname2(real), `${basename2(real)}${SAVED_SUFFIX}`, stamp);
2950
2980
  const moved = [];
2951
2981
  for (const conflict of plan.conflicts) {
2952
2982
  const from = await resolveExisting(root, conflict.path);
2953
2983
  if (!from)
2954
2984
  continue;
2955
- const to = join14(saved, conflict.path);
2985
+ const to = join15(saved, conflict.path);
2956
2986
  await mkdir5(dirname2(to), { recursive: true });
2957
2987
  await rename2(from, to);
2958
2988
  moved.push(conflict.path);
@@ -2974,13 +3004,13 @@ ${list}`,
2974
3004
 
2975
3005
  // ../core/dist/baseline.js
2976
3006
  init_errors();
2977
- import { readFile as readFile6 } from "node:fs/promises";
2978
- import { join as join15, resolve as resolve7 } from "node:path";
3007
+ import { readFile as readFile7 } from "node:fs/promises";
3008
+ import { join as join16, resolve as resolve7 } from "node:path";
2979
3009
  async function rebuildBaseline(options) {
2980
3010
  const report = options.onProgress ?? (() => {
2981
3011
  });
2982
3012
  const root = resolve7(options.folder);
2983
- const previousText = await readFile6(join15(root, SYNC_LEDGER_PATH), "utf8").catch(() => null);
3013
+ const previousText = await readFile7(join16(root, SYNC_LEDGER_PATH), "utf8").catch(() => null);
2984
3014
  const previous = previousText === null ? null : parseSyncLedger(previousText);
2985
3015
  report("\uD310\uC758 \uD30C\uC77C \uBAA9\uB85D\uC744 \uB2E4\uC2DC \uC77D\uB294 \uC911\uC785\uB2C8\uB2E4\u2026");
2986
3016
  const tar = await fetchVerifiedSourceTar({
@@ -3080,8 +3110,8 @@ function ledgerCorrection(ledger, draft) {
3080
3110
  // ../core/dist/push.js
3081
3111
  init_errors();
3082
3112
  init_notice();
3083
- import { readFile as readFile7, stat as stat4 } from "node:fs/promises";
3084
- import { basename as basename3, join as join16, resolve as resolve8 } from "node:path";
3113
+ import { readFile as readFile8, stat as stat3 } from "node:fs/promises";
3114
+ import { basename as basename3, join as join17, resolve as resolve8 } from "node:path";
3085
3115
 
3086
3116
  // ../core/dist/pushPlan.js
3087
3117
  function effectiveSha(base, draft, path) {
@@ -3358,13 +3388,13 @@ async function bodyOf(root, edits) {
3358
3388
  body.push({ path: edit.path, remove: true, ...edit.baseSha256 === null ? {} : { baseSha256: edit.baseSha256 } });
3359
3389
  continue;
3360
3390
  }
3361
- const size = (await stat4(join16(root, edit.path))).size;
3391
+ const size = (await stat3(join17(root, edit.path))).size;
3362
3392
  if (size > MAX_PUSH_FILE_BYTES) {
3363
3393
  throw new DevtoolsError("PUSH_TOO_LARGE", `\uD30C\uC77C \uD558\uB098\uAC00 \uB108\uBB34 \uD07D\uB2C8\uB2E4: ${edit.path} (${Math.round(size / 1024)}KB \xB7 \uC0C1\uD55C ${MAX_PUSH_FILE_BYTES / 1024}KB).`, "\uB3D9\uC601\uC0C1\xB7\uC6D0\uBCF8 \uC774\uBBF8\uC9C0\xB7\uBE4C\uB4DC \uC0B0\uCD9C\uBB3C\uC774 \uC18C\uC2A4 \uD3F4\uB354\uC5D0 \uB4E4\uC5B4 \uC788\uC9C0 \uC54A\uC740\uC9C0 \uD655\uC778\uD574 \uC8FC\uC138\uC694.");
3364
3394
  }
3365
3395
  if (total + size > MAX_PUSH_BYTES)
3366
3396
  throw tooLarge();
3367
- const raw = await readFile7(join16(root, edit.path));
3397
+ const raw = await readFile8(join17(root, edit.path));
3368
3398
  const breach = templateBreach(basename3(edit.path), raw);
3369
3399
  if (breach !== null) {
3370
3400
  throw new DevtoolsError("PUSH_SECRET_TEMPLATE", `${edit.path} \uC5D0 \uC2E4\uC81C \uAC12\uC774 \uB4E4\uC5B4 \uC788\uC5B4 \uC62C\uB9AC\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4(${breach}).`, "`.env.example` \uAC19\uC740 \uC11C\uC2DD \uD30C\uC77C\uC740 \uAC12\uC744 \uBE44\uC6CC \uB450\uC5B4\uC57C \uC62C\uB77C\uAC11\uB2C8\uB2E4. \uC2E4\uC81C \uAC12\uC740 \uCF58\uC194\uC758 \uD658\uACBD\uBCC0\uC218 \uD654\uBA74\uC5D0\uC11C \uAD00\uB9AC\uD574 \uC8FC\uC138\uC694.");
@@ -3631,12 +3661,12 @@ function flagValue(flags, name) {
3631
3661
 
3632
3662
  // src/context.ts
3633
3663
  import { readFileSync } from "node:fs";
3634
- import { readFile as readFile9 } from "node:fs/promises";
3664
+ import { readFile as readFile10 } from "node:fs/promises";
3635
3665
  import { fileURLToPath } from "node:url";
3636
- import { join as join18, resolve as resolve11 } from "node:path";
3666
+ import { join as join19, resolve as resolve11 } from "node:path";
3637
3667
 
3638
3668
  // src/tokenStore.ts
3639
- import { chmod as chmod3, readFile as readFile8, rm as rm6 } from "node:fs/promises";
3669
+ import { chmod as chmod4, readFile as readFile9, rm as rm6 } from "node:fs/promises";
3640
3670
  import { basename as basename4, dirname as dirname3 } from "node:path";
3641
3671
  var FileTokenStore = class {
3642
3672
  // ⚠ 매개변수 프로퍼티(`constructor(private path)`)를 안 쓴다 — Node 의 타입 제거 실행기가
@@ -3646,7 +3676,7 @@ var FileTokenStore = class {
3646
3676
  this.path = path;
3647
3677
  }
3648
3678
  async read() {
3649
- const text = await readFile8(this.path, "utf8").catch(() => null);
3679
+ const text = await readFile9(this.path, "utf8").catch(() => null);
3650
3680
  if (text === null) return null;
3651
3681
  try {
3652
3682
  const raw = JSON.parse(text);
@@ -3667,10 +3697,10 @@ var FileTokenStore = class {
3667
3697
  }
3668
3698
  async write(tokens) {
3669
3699
  const dir = await ensureOwnDir(dirname3(dirname3(this.path)), basename4(dirname3(this.path)));
3670
- await chmod3(dir, 448).catch(() => {
3700
+ await chmod4(dir, 448).catch(() => {
3671
3701
  });
3672
3702
  await writeOwnFile(this.path, JSON.stringify(tokens), 384);
3673
- await chmod3(this.path, 384);
3703
+ await chmod4(this.path, 384);
3674
3704
  }
3675
3705
  async clear() {
3676
3706
  await rm6(this.path, { force: true });
@@ -3693,9 +3723,9 @@ function serverUrlOf(env = process.env) {
3693
3723
  }
3694
3724
  async function tenantOf(folder, explicit) {
3695
3725
  if (explicit) return TENANT_CODE.test(explicit) ? explicit : null;
3696
- const mark = parseSourceMark(await readFile9(join18(folder, SOURCE_MARK_PATH), "utf8").catch(() => null));
3726
+ const mark = parseSourceMark(await readFile10(join19(folder, SOURCE_MARK_PATH), "utf8").catch(() => null));
3697
3727
  if (mark) return mark.tenant;
3698
- const text = await readFile9(join18(folder, SYNC_LEDGER_PATH), "utf8").catch(() => null);
3728
+ const text = await readFile10(join19(folder, SYNC_LEDGER_PATH), "utf8").catch(() => null);
3699
3729
  return text === null ? null : parseSyncLedger(text)?.tenant ?? null;
3700
3730
  }
3701
3731
  async function openAuth(options = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zalkera/cli",
3
- "version": "0.28.1",
3
+ "version": "0.29.1",
4
4
  "description": "잘커라 사이트 소스를 터미널에서 받고·올리고·발행합니다. 편집기 없이, 스크립트에서도.",
5
5
  "license": "MIT",
6
6
  "type": "module",