mimi-seed 0.21.2 → 0.21.4

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.
@@ -14,13 +14,26 @@ import path3 from "path";
14
14
  import fs from "fs";
15
15
  import os from "os";
16
16
  import path from "path";
17
- var DEFAULT_LANG = "ko";
17
+ var DEFAULT_LANG = "en";
18
18
  function isLang(v) {
19
19
  return v === "ko" || v === "en";
20
20
  }
21
21
  function settingsPath(home = os.homedir()) {
22
22
  return path.join(home, ".mimi-seed", "settings.json");
23
23
  }
24
+ function systemLang(env = process.env) {
25
+ for (const key of ["LC_ALL", "LC_MESSAGES", "LANG"]) {
26
+ const value = env[key]?.trim();
27
+ if (!value) continue;
28
+ if (/^(?:C|POSIX)(?:[._@]|$)/i.test(value)) return DEFAULT_LANG;
29
+ return /^ko(?:[_.@-]|$)/i.test(value) ? "ko" : "en";
30
+ }
31
+ try {
32
+ return /^ko(?:-|$)/i.test(Intl.DateTimeFormat().resolvedOptions().locale) ? "ko" : "en";
33
+ } catch {
34
+ return DEFAULT_LANG;
35
+ }
36
+ }
24
37
  function resolveLang(home = os.homedir()) {
25
38
  const env = process.env.MIMI_SEED_LANG?.toLowerCase();
26
39
  if (isLang(env)) return env;
@@ -29,7 +42,7 @@ function resolveLang(home = os.homedir()) {
29
42
  if (isLang(saved)) return saved;
30
43
  } catch {
31
44
  }
32
- return DEFAULT_LANG;
45
+ return systemLang();
33
46
  }
34
47
 
35
48
  // ../core/src/project-manifest.ts
@@ -466,7 +479,10 @@ var CREDENTIALS = [
466
479
  docsAnchor: "google-ads",
467
480
  detect: (home) => {
468
481
  const cfg = readJson(home, "google-ads.json");
469
- return cfg?.customerId ? { present: true, detail: cfg.customerId } : { present: false };
482
+ const isId = (v) => typeof v === "string" && v.trim() !== "" || typeof v === "number" && Number.isSafeInteger(v) && v > 0;
483
+ const login = cfg?.loginCustomerId;
484
+ const loginOk = login === void 0 || login === null || login === "" || isId(login);
485
+ return typeof cfg?.developerToken === "string" && cfg.developerToken && isId(cfg.customerId) && loginOk ? { present: true, detail: String(cfg.customerId) } : { present: false };
470
486
  }
471
487
  },
472
488
  {
@@ -668,7 +684,7 @@ function planSetup(detected, opts = {}) {
668
684
  // src/mcp-bin.ts
669
685
  import { spawn, spawnSync } from "child_process";
670
686
  import { existsSync, readFileSync } from "fs";
671
- import path4 from "path";
687
+ import path5 from "path";
672
688
  import { fileURLToPath } from "url";
673
689
 
674
690
  // src/i18n.ts
@@ -793,7 +809,7 @@ var en = {
793
809
  checkWith: "Check with: mimi-seed doctor"
794
810
  },
795
811
  lang: {
796
- ask: " Choose a language [1] \uD55C\uAD6D\uC5B4 [2] English (Enter = \uD55C\uAD6D\uC5B4): ",
812
+ ask: " Choose a language [1] \uD55C\uAD6D\uC5B4 [2] English (Enter = English): ",
797
813
  saved: (l) => ` \u2705 Language: ${l === "ko" ? "\uD55C\uAD6D\uC5B4" : "English"} (change later: mimi-seed lang ko)`,
798
814
  usage: `mimi-seed lang \u2014 CLI output language
799
815
 
@@ -893,19 +909,42 @@ function t() {
893
909
  }
894
910
 
895
911
  // package.json
896
- var version = "0.21.2";
912
+ var version = "0.21.4";
913
+
914
+ // src/lib/windows-path.ts
915
+ import path4 from "path";
916
+ function absoluteWindowsPathDirs(env = process.env) {
917
+ const key = Object.keys(env).find((k) => k.toLowerCase() === "path");
918
+ const value = key ? env[key] ?? "" : "";
919
+ const dirs = [];
920
+ const flush = (entry) => {
921
+ const dir = entry.trim();
922
+ if (dir && path4.win32.isAbsolute(dir) && !/^[\\/](?![\\/])/.test(dir)) dirs.push(dir);
923
+ };
924
+ let current = "";
925
+ let quoted = false;
926
+ for (const c of value) {
927
+ if (c === '"') quoted = !quoted;
928
+ else if (c === ";" && !quoted) {
929
+ flush(current);
930
+ current = "";
931
+ } else current += c;
932
+ }
933
+ if (quoted) for (const entry of current.split(";")) flush(entry);
934
+ else flush(current);
935
+ return dirs;
936
+ }
897
937
 
898
938
  // src/mcp-bin.ts
899
939
  var MCP_PKG = "@yoonion/mimi-seed-mcp";
900
940
  function resolveOnPath(bin, honorForceNpx = true) {
901
941
  if (honorForceNpx && process.env.MIMI_SEED_FORCE_NPX) return null;
902
942
  if (process.platform === "win32") {
903
- const pathKey = Object.keys(process.env).find((key) => key.toLowerCase() === "path");
904
- const directories = (pathKey ? process.env[pathKey] ?? "" : "").split(path4.delimiter).filter(Boolean);
943
+ const directories = absoluteWindowsPathDirs();
905
944
  const names = bin.toLowerCase().endsWith(".cmd") ? [bin] : [`${bin}.cmd`, bin];
906
945
  for (const directory of directories) {
907
946
  for (const name of names) {
908
- const candidate = path4.join(directory.replace(/^"|"$/g, ""), name);
947
+ const candidate = path5.join(directory, name);
909
948
  if (existsSync(candidate)) return candidate;
910
949
  }
911
950
  }
@@ -921,13 +960,13 @@ function resolveWindowsShimTarget(shimPath, source) {
921
960
  const matches = [...source.matchAll(/["']([^"']+\.js)["']\s+%\*/gi)];
922
961
  const raw = matches.at(-1)?.[1];
923
962
  if (!raw) return null;
924
- return path4.win32.normalize(raw.replace(/%~?dp0%?/gi, `${path4.win32.dirname(shimPath)}${path4.win32.sep}`));
963
+ return path5.win32.normalize(raw.replace(/%~?dp0%?/gi, `${path5.win32.dirname(shimPath)}${path5.win32.sep}`));
925
964
  }
926
965
  function npxCliPath(shimPath) {
927
966
  const candidates = [
928
- shimPath ? path4.join(path4.dirname(shimPath), "node_modules", "npm", "bin", "npx-cli.js") : "",
929
- path4.join(path4.dirname(process.execPath), "node_modules", "npm", "bin", "npx-cli.js"),
930
- process.env.npm_execpath ? path4.join(path4.dirname(process.env.npm_execpath), "npx-cli.js") : ""
967
+ shimPath ? path5.join(path5.dirname(shimPath), "node_modules", "npm", "bin", "npx-cli.js") : "",
968
+ path5.join(path5.dirname(process.execPath), "node_modules", "npm", "bin", "npx-cli.js"),
969
+ process.env.npm_execpath ? path5.join(path5.dirname(process.env.npm_execpath), "npx-cli.js") : ""
931
970
  ];
932
971
  return candidates.find((candidate) => candidate && existsSync(candidate)) ?? null;
933
972
  }
@@ -997,12 +1036,12 @@ async function runMcpBin(bin, extraArgs = []) {
997
1036
  // src/jenkins-config.ts
998
1037
  import fs4 from "fs";
999
1038
  import os3 from "os";
1000
- import path6 from "path";
1039
+ import path7 from "path";
1001
1040
 
1002
1041
  // ../core/src/atomic-write.ts
1003
1042
  import { chmodSync, mkdirSync, renameSync, unlinkSync, writeFileSync } from "fs";
1004
1043
  import { randomUUID } from "crypto";
1005
- import path5 from "path";
1044
+ import path6 from "path";
1006
1045
  var CREDENTIAL_FILE_MODE = 384;
1007
1046
  var CREDENTIAL_DIR_MODE = 448;
1008
1047
  var RENAME_RETRY_DELAYS_MS = [10, 20, 40, 80, 160, 320, 370];
@@ -1025,7 +1064,7 @@ function renameWithRetry(from, to, deps = {}) {
1025
1064
  }
1026
1065
  }
1027
1066
  function writeFileAtomic(filePath, contents, options = {}) {
1028
- mkdirSync(path5.dirname(filePath), { recursive: true, ...options.dirMode !== void 0 && { mode: options.dirMode } });
1067
+ mkdirSync(path6.dirname(filePath), { recursive: true, ...options.dirMode !== void 0 && { mode: options.dirMode } });
1029
1068
  const tempPath = `${filePath}.${process.pid}.${randomUUID()}.tmp`;
1030
1069
  try {
1031
1070
  writeFileSync(tempPath, contents, {
@@ -1051,21 +1090,21 @@ function writeCredentialJson(filePath, value) {
1051
1090
  }
1052
1091
 
1053
1092
  // src/jenkins-config.ts
1054
- var CONFIG_DIR = path6.join(os3.homedir(), ".mimi-seed");
1055
- var JENKINS_PATH = path6.join(CONFIG_DIR, "jenkins.json");
1056
- var LEGACY_PATH = path6.join(CONFIG_DIR, "config.json");
1093
+ var CONFIG_DIR = path7.join(os3.homedir(), ".mimi-seed");
1094
+ var JENKINS_PATH = path7.join(CONFIG_DIR, "jenkins.json");
1095
+ var LEGACY_PATH = path7.join(CONFIG_DIR, "config.json");
1057
1096
  function loadJenkinsConfig(home = os3.homedir()) {
1058
1097
  try {
1059
- const p = path6.join(home, ".mimi-seed", "jenkins.json");
1098
+ const p = path7.join(home, ".mimi-seed", "jenkins.json");
1060
1099
  return JSON.parse(fs4.readFileSync(p, "utf-8"));
1061
1100
  } catch {
1062
1101
  return null;
1063
1102
  }
1064
1103
  }
1065
1104
  function migrateLegacyJenkins(home = os3.homedir()) {
1066
- const dir = path6.join(home, ".mimi-seed");
1067
- const jenkinsPath = path6.join(dir, "jenkins.json");
1068
- const legacyPath = path6.join(dir, "config.json");
1105
+ const dir = path7.join(home, ".mimi-seed");
1106
+ const jenkinsPath = path7.join(dir, "jenkins.json");
1107
+ const legacyPath = path7.join(dir, "config.json");
1069
1108
  if (fs4.existsSync(jenkinsPath)) return false;
1070
1109
  let legacy;
1071
1110
  try {
@@ -1091,7 +1130,7 @@ function migrateLegacyJenkins(home = os3.homedir()) {
1091
1130
 
1092
1131
  // src/detect.ts
1093
1132
  import fs5 from "fs/promises";
1094
- import path7 from "path";
1133
+ import path8 from "path";
1095
1134
  async function readIfExists(p) {
1096
1135
  try {
1097
1136
  return await fs5.readFile(p, "utf8");
@@ -1115,9 +1154,9 @@ async function importedJsonObjects(configPath, text, root) {
1115
1154
  ];
1116
1155
  for (const match of imports) {
1117
1156
  if (!match[2].startsWith(".")) continue;
1118
- const candidate = path7.resolve(path7.dirname(configPath), match[2]);
1119
- const relative = path7.relative(root, candidate);
1120
- if (relative.startsWith(`..${path7.sep}`) || relative === ".." || path7.isAbsolute(relative)) continue;
1157
+ const candidate = path8.resolve(path8.dirname(configPath), match[2]);
1158
+ const relative = path8.relative(root, candidate);
1159
+ if (relative.startsWith(`..${path8.sep}`) || relative === ".." || path8.isAbsolute(relative)) continue;
1121
1160
  const jsonText = await readIfExists(candidate);
1122
1161
  if (!jsonText) continue;
1123
1162
  try {
@@ -1161,9 +1200,9 @@ async function walk(root, match, maxDepth = 5) {
1161
1200
  for (const e of entries) {
1162
1201
  if (e.isDirectory()) {
1163
1202
  if (skipDirs.has(e.name)) continue;
1164
- await visit(path7.join(dir, e.name), depth + 1);
1203
+ await visit(path8.join(dir, e.name), depth + 1);
1165
1204
  } else if (e.isFile() && match(e.name)) {
1166
- found.push(path7.join(dir, e.name));
1205
+ found.push(path8.join(dir, e.name));
1167
1206
  }
1168
1207
  }
1169
1208
  }
@@ -1173,7 +1212,7 @@ async function walk(root, match, maxDepth = 5) {
1173
1212
  async function detectHints(cwd) {
1174
1213
  const hints = [];
1175
1214
  for (const fname of ["app.json", "app.config.json"]) {
1176
- const txt = await readIfExists(path7.join(cwd, fname));
1215
+ const txt = await readIfExists(path8.join(cwd, fname));
1177
1216
  if (!txt) continue;
1178
1217
  try {
1179
1218
  const json = JSON.parse(txt);
@@ -1193,7 +1232,7 @@ async function detectHints(cwd) {
1193
1232
  }
1194
1233
  }
1195
1234
  for (const fname of ["app.config.js", "app.config.cjs", "app.config.mjs", "app.config.ts"]) {
1196
- const configPath = path7.join(cwd, fname);
1235
+ const configPath = path8.join(cwd, fname);
1197
1236
  const txt = await readIfExists(configPath);
1198
1237
  if (!txt) continue;
1199
1238
  const imports = await importedJsonObjects(configPath, txt, cwd);
@@ -1215,7 +1254,7 @@ async function detectHints(cwd) {
1215
1254
  if (m?.[1]) {
1216
1255
  const pkg = m[1];
1217
1256
  if (!hints.some((h) => h.packageName === pkg)) {
1218
- hints.push({ packageName: pkg, source: [path7.relative(cwd, f)] });
1257
+ hints.push({ packageName: pkg, source: [path8.relative(cwd, f)] });
1219
1258
  }
1220
1259
  }
1221
1260
  }
@@ -1230,7 +1269,7 @@ async function detectHints(cwd) {
1230
1269
  const bid = m[1];
1231
1270
  if (bid.includes("$(PRODUCT_BUNDLE_IDENTIFIER)")) continue;
1232
1271
  if (!hints.some((h) => h.bundleId === bid)) {
1233
- hints.push({ bundleId: bid, source: [path7.relative(cwd, f)] });
1272
+ hints.push({ bundleId: bid, source: [path8.relative(cwd, f)] });
1234
1273
  }
1235
1274
  }
1236
1275
  }
@@ -1243,11 +1282,11 @@ async function detectHints(cwd) {
1243
1282
  const bid = m[1].trim().replace(/^["']|["']$/g, "");
1244
1283
  if (!bid || bid.includes("$")) continue;
1245
1284
  if (!hints.some((h) => h.bundleId === bid)) {
1246
- hints.push({ bundleId: bid, source: [path7.relative(cwd, f)] });
1285
+ hints.push({ bundleId: bid, source: [path8.relative(cwd, f)] });
1247
1286
  }
1248
1287
  }
1249
1288
  }
1250
- const unitySettings = path7.join(cwd, "ProjectSettings", "ProjectSettings.asset");
1289
+ const unitySettings = path8.join(cwd, "ProjectSettings", "ProjectSettings.asset");
1251
1290
  const unityText = await readIfExists(unitySettings);
1252
1291
  if (unityText) {
1253
1292
  const lines = unityText.split(/\r?\n/);
@@ -1271,11 +1310,11 @@ async function detectHints(cwd) {
1271
1310
  name,
1272
1311
  packageName,
1273
1312
  bundleId,
1274
- source: [path7.relative(cwd, unitySettings)]
1313
+ source: [path8.relative(cwd, unitySettings)]
1275
1314
  });
1276
1315
  }
1277
1316
  }
1278
- const pkgJson = await readIfExists(path7.join(cwd, "package.json"));
1317
+ const pkgJson = await readIfExists(path8.join(cwd, "package.json"));
1279
1318
  if (pkgJson) {
1280
1319
  try {
1281
1320
  const json = JSON.parse(pkgJson);
@@ -1311,7 +1350,7 @@ async function detectHints(cwd) {
1311
1350
  return merged.filter((h) => h.packageName || h.bundleId);
1312
1351
  }
1313
1352
  async function hasAnyProjectSignal(cwd) {
1314
- return await pathExists(path7.join(cwd, "package.json")) || await pathExists(path7.join(cwd, "app.json")) || await pathExists(path7.join(cwd, "android")) || await pathExists(path7.join(cwd, "ios")) || await pathExists(path7.join(cwd, "ProjectSettings", "ProjectSettings.asset"));
1353
+ return await pathExists(path8.join(cwd, "package.json")) || await pathExists(path8.join(cwd, "app.json")) || await pathExists(path8.join(cwd, "android")) || await pathExists(path8.join(cwd, "ios")) || await pathExists(path8.join(cwd, "ProjectSettings", "ProjectSettings.asset"));
1315
1354
  }
1316
1355
 
1317
1356
  // src/deploy.ts
@@ -1321,10 +1360,10 @@ import { randomUUID as randomUUID2 } from "crypto";
1321
1360
 
1322
1361
  // src/config.ts
1323
1362
  import fs6 from "fs/promises";
1324
- import path8 from "path";
1363
+ import path9 from "path";
1325
1364
  import os4 from "os";
1326
- var CONFIG_DIR2 = path8.join(os4.homedir(), ".mimi-seed");
1327
- var CONFIG_PATH = path8.join(CONFIG_DIR2, "config.json");
1365
+ var CONFIG_DIR2 = path9.join(os4.homedir(), ".mimi-seed");
1366
+ var CONFIG_PATH = path9.join(CONFIG_DIR2, "config.json");
1328
1367
  async function readConfig() {
1329
1368
  try {
1330
1369
  const txt = await fs6.readFile(CONFIG_PATH, "utf8");
@@ -1448,7 +1487,7 @@ async function consumeDeployStream(reader, onEvent) {
1448
1487
 
1449
1488
  // src/project-link.ts
1450
1489
  import fs7 from "fs/promises";
1451
- import path9 from "path";
1490
+ import path10 from "path";
1452
1491
 
1453
1492
  // ../core/src/http-errors.ts
1454
1493
  function endpointLabel(input, fallback) {
@@ -1528,9 +1567,9 @@ function isLink(value) {
1528
1567
  return link.schema === 1 && typeof link.webBase === "string" && !!link.webBase && typeof link.appId === "string" && !!link.appId && (link.packageName === void 0 || typeof link.packageName === "string") && (link.bundleId === void 0 || typeof link.bundleId === "string");
1529
1568
  }
1530
1569
  async function findProjectLink(cwd) {
1531
- let dir = path9.resolve(cwd);
1570
+ let dir = path10.resolve(cwd);
1532
1571
  for (let depth = 0; depth <= 8; depth++) {
1533
- const file = path9.join(dir, PROJECT_LINK_FILENAME);
1572
+ const file = path10.join(dir, PROJECT_LINK_FILENAME);
1534
1573
  try {
1535
1574
  const parsed = JSON.parse(await fs7.readFile(file, "utf8"));
1536
1575
  if (!isLink(parsed)) throw new Error(M3().invalidFile);
@@ -1538,7 +1577,7 @@ async function findProjectLink(cwd) {
1538
1577
  } catch (error) {
1539
1578
  if (error.code !== "ENOENT") throw error;
1540
1579
  }
1541
- const parent = path9.dirname(dir);
1580
+ const parent = path10.dirname(dir);
1542
1581
  if (parent === dir) break;
1543
1582
  dir = parent;
1544
1583
  }
@@ -1581,10 +1620,10 @@ async function linkProject(cwd, webBase, token, hint) {
1581
1620
  throw new Error(M3().mismatch);
1582
1621
  }
1583
1622
  if (!existing) {
1584
- await fs7.writeFile(path9.join(cwd, PROJECT_LINK_FILENAME), `${JSON.stringify(link, null, 2)}
1623
+ await fs7.writeFile(path10.join(cwd, PROJECT_LINK_FILENAME), `${JSON.stringify(link, null, 2)}
1585
1624
  `, { mode: 384, flag: "wx" });
1586
1625
  }
1587
- const ignorePath = path9.join(cwd, ".gitignore");
1626
+ const ignorePath = path10.join(cwd, ".gitignore");
1588
1627
  const ignore = await fs7.readFile(ignorePath, "utf8").catch((error) => {
1589
1628
  if (error.code !== "ENOENT") throw error;
1590
1629
  return "";
@@ -1636,7 +1675,7 @@ var M4 = catalog({
1636
1675
 
1637
1676
  // src/jenkins-project.ts
1638
1677
  import fs8 from "fs";
1639
- import path10 from "path";
1678
+ import path11 from "path";
1640
1679
  var M5 = catalog({
1641
1680
  invalidManifest: "\uD504\uB85C\uC81D\uD2B8 .mimi-seed.json\uC740 \uC62C\uBC14\uB978 JSON \uAC1D\uCCB4\uC5EC\uC57C \uD569\uB2C8\uB2E4.",
1642
1681
  controllerMismatch: "\uD504\uB85C\uC81D\uD2B8 Jenkins URL\uACFC \uB85C\uCEEC\uC5D0\uC11C \uC778\uC99D\uB41C \uCEE8\uD2B8\uB864\uB7EC\uAC00 \uB2E4\uB985\uB2C8\uB2E4.",
@@ -1650,9 +1689,9 @@ var M5 = catalog({
1650
1689
  });
1651
1690
  function resolveProjectJenkins(cfg, platform, cwd = process.cwd()) {
1652
1691
  const field = platform === "android" ? "jobAndroid" : "jobIos";
1653
- let dir = path10.resolve(cwd);
1692
+ let dir = path11.resolve(cwd);
1654
1693
  for (let depth = 0; depth <= 8; depth++) {
1655
- const file = path10.join(dir, MANIFEST_FILENAME);
1694
+ const file = path11.join(dir, MANIFEST_FILENAME);
1656
1695
  if (fs8.existsSync(file)) {
1657
1696
  let manifest;
1658
1697
  try {
@@ -1669,7 +1708,7 @@ function resolveProjectJenkins(cfg, platform, cwd = process.cwd()) {
1669
1708
  }
1670
1709
  return { job: validateJob(service?.[field]), source: file };
1671
1710
  }
1672
- const parent = path10.dirname(dir);
1711
+ const parent = path11.dirname(dir);
1673
1712
  if (parent === dir) break;
1674
1713
  dir = parent;
1675
1714
  }
@@ -1706,7 +1745,7 @@ function jenkinsBuildParameters(platform, ref, appId) {
1706
1745
 
1707
1746
  // src/ci-providers.ts
1708
1747
  import fs9 from "fs";
1709
- import path11 from "path";
1748
+ import path12 from "path";
1710
1749
  import os5 from "os";
1711
1750
 
1712
1751
  // ../core/src/ci.ts
@@ -1730,7 +1769,7 @@ function gitlabProjectId(cfg) {
1730
1769
  }
1731
1770
 
1732
1771
  // src/ci-providers.ts
1733
- var CI_CONFIG_PATH = path11.join(os5.homedir(), ".mimi-seed", "ci.json");
1772
+ var CI_CONFIG_PATH = path12.join(os5.homedir(), ".mimi-seed", "ci.json");
1734
1773
  var M6 = catalog(
1735
1774
  {
1736
1775
  badToken: (provider, status) => `${provider} ${status} \u2014 \uD1A0\uD070\uC774 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC544`,
@@ -2565,7 +2604,7 @@ function isLangUnset(home = os6.homedir()) {
2565
2604
  // src/telemetry.ts
2566
2605
  import fs11 from "fs";
2567
2606
  import os7 from "os";
2568
- import path12 from "path";
2607
+ import path13 from "path";
2569
2608
  import { createHmac, randomUUID as randomUUID3 } from "crypto";
2570
2609
  var ENDPOINT = "https://mimi-seed.pryzm.gg/api/sdk-usage";
2571
2610
  var M8 = catalog(
@@ -2582,7 +2621,7 @@ var M8 = catalog(
2582
2621
  invalid: "Usage: mimi-seed telemetry on|off|status\n"
2583
2622
  }
2584
2623
  );
2585
- var location = () => path12.join(os7.homedir(), ".mimi-seed", "telemetry.json");
2624
+ var location = () => path13.join(os7.homedir(), ".mimi-seed", "telemetry.json");
2586
2625
  function readConsent() {
2587
2626
  try {
2588
2627
  return JSON.parse(fs11.readFileSync(location(), "utf8"));
@@ -2615,9 +2654,9 @@ function cmdTelemetry(argv) {
2615
2654
  process.stdout.write(telemetryEnabled() ? M8().enabled : M8().disabled);
2616
2655
  }
2617
2656
  function frameworkAt(root) {
2618
- if (fs11.existsSync(path12.join(root, "ProjectSettings", "ProjectSettings.asset"))) return "unity";
2657
+ if (fs11.existsSync(path13.join(root, "ProjectSettings", "ProjectSettings.asset"))) return "unity";
2619
2658
  try {
2620
- const pkg = JSON.parse(fs11.readFileSync(path12.join(root, "package.json"), "utf8"));
2659
+ const pkg = JSON.parse(fs11.readFileSync(path13.join(root, "package.json"), "utf8"));
2621
2660
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
2622
2661
  if (deps.expo) return "expo";
2623
2662
  if (deps["react-native"]) return "react-native";
@@ -2633,7 +2672,7 @@ function usageRun(command, projectPath) {
2633
2672
  const installationId = consent.installationId ?? randomUUID3();
2634
2673
  const salt = consent.salt ?? randomUUID3();
2635
2674
  if (!consent.installationId || !consent.salt) writeConsent({ enabled: consent.enabled, installationId, salt });
2636
- let normalized = path12.resolve(projectPath);
2675
+ let normalized = path13.resolve(projectPath);
2637
2676
  try {
2638
2677
  normalized = fs11.realpathSync(normalized);
2639
2678
  } catch {
@@ -2763,7 +2802,8 @@ function printObtain(spec) {
2763
2802
  async function ensureLangChosen() {
2764
2803
  if (!isLangUnset()) return;
2765
2804
  const answer = await ask(t().lang.ask);
2766
- const lang = answer.trim() === "2" || answer.trim().toLowerCase() === "en" ? "en" : "ko";
2805
+ const choice = answer.trim().toLowerCase();
2806
+ const lang = choice === "1" || choice === "ko" ? "ko" : choice === "2" || choice === "en" ? "en" : resolveLang();
2767
2807
  writeSettings({ lang });
2768
2808
  process.env.MIMI_SEED_LANG = lang;
2769
2809
  log2(kleur2.green(t().lang.saved(lang)));
@@ -2936,6 +2976,7 @@ export {
2936
2976
  detectAll,
2937
2977
  isSatisfied,
2938
2978
  version,
2979
+ absoluteWindowsPathDirs,
2939
2980
  MCP_PKG,
2940
2981
  runMcpBin,
2941
2982
  migrateLegacyJenkins,