mimi-seed 0.2.9 → 0.2.11

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 (2) hide show
  1. package/dist/index.js +240 -74
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4,9 +4,9 @@ import {
4
4
  } from "./chunk-Q5YGYAFK.js";
5
5
 
6
6
  // src/index.ts
7
- import os5 from "os";
8
- import fs6 from "fs";
9
- import path6 from "path";
7
+ import os7 from "os";
8
+ import fs8 from "fs";
9
+ import path8 from "path";
10
10
  import kleur9 from "kleur";
11
11
  import open from "open";
12
12
 
@@ -255,6 +255,9 @@ async function getEffectiveConfig() {
255
255
  }
256
256
 
257
257
  // src/doctor.ts
258
+ import fs3 from "fs";
259
+ import os2 from "os";
260
+ import path3 from "path";
258
261
  import kleur from "kleur";
259
262
 
260
263
  // src/git.ts
@@ -335,6 +338,34 @@ async function cmdDoctor() {
335
338
  ok("Mimi Seed \uC11C\uBC84 \uC5F0\uACB0\uB428", `\uC571 ${lines.length}\uAC1C`);
336
339
  }
337
340
  }
341
+ section("\uB85C\uCEEC MCP \uC790\uACA9\uC99D\uBA85 (~/.mimi-seed)");
342
+ const credDir = path3.join(os2.homedir(), ".mimi-seed");
343
+ const hasFile = (name) => fs3.existsSync(path3.join(credDir, name));
344
+ const hasPrefix = (prefix) => {
345
+ try {
346
+ return fs3.readdirSync(credDir).some((f) => f.startsWith(prefix));
347
+ } catch {
348
+ return false;
349
+ }
350
+ };
351
+ const hasPlaySa = hasFile("play-service-account.json") || (() => {
352
+ try {
353
+ return fs3.readdirSync(path3.join(credDir, "play-service-accounts")).some((f) => f.endsWith(".json"));
354
+ } catch {
355
+ return false;
356
+ }
357
+ })();
358
+ const creds = [
359
+ ["Google OAuth (Firebase/AdMob/Play/Ads)", hasFile("tokens.json"), "mimi-seed auth login"],
360
+ ["App Store Connect", hasFile("appstore.json"), "mimi-seed auth appstore"],
361
+ ["Play \uC11C\uBE44\uC2A4 \uACC4\uC815 (\uC120\uD0DD \u2014 OAuth\uB85C\uB3C4 \uAC00\uB2A5)", hasPlaySa, "mimi-seed auth playstore"],
362
+ ["BigQuery \uC11C\uBE44\uC2A4 \uACC4\uC815", hasPrefix("bigquery"), "mimi-seed auth bigquery"]
363
+ ];
364
+ for (const [label, present, cmd] of creds) {
365
+ if (present) ok(label);
366
+ else warn(label, `\u2192 ${cmd}`);
367
+ }
368
+ process.stdout.write(kleur.dim(" OAuth \uD1A0\uD070 \uC2E0\uC120\uB3C4 \uD655\uC778: mimi-seed auth status\n"));
338
369
  section("\uB85C\uCEEC \uD658\uACBD");
339
370
  const nodeVer = process.version;
340
371
  const [, major] = nodeVer.match(/v(\d+)/) ?? [];
@@ -460,8 +491,25 @@ async function cmdCheck(argv) {
460
491
  `);
461
492
  process.stdout.write("\n");
462
493
  }
494
+ const base = `${cfg.webBase}/apps/${appId}`;
495
+ const nextSteps = [];
496
+ if (data.modules) {
497
+ if ((data.modules.integration ?? 25) < 25) nextSteps.push(`\uC5F0\uACB0 \uC9C4\uB2E8 ${base}/integration`);
498
+ if ((data.modules.copy ?? 25) < 25) nextSteps.push(`\uBB38\uAD6C \uBCF4\uAC15 mimi-seed notes \uB610\uB294 ${base}/copy`);
499
+ if ((data.modules.screenshot ?? 25) < 25) nextSteps.push(`\uC2A4\uD06C\uB9B0\uC0F7 ${base}/screenshots`);
500
+ if ((data.modules.checklist ?? 25) < 25) nextSteps.push(`\uCCB4\uD06C\uB9AC\uC2A4\uD2B8 ${base}/launch`);
501
+ }
502
+ if (nextSteps.length) {
503
+ process.stdout.write(kleur2.bold("\u2192 \uB2E4\uC74C \uB2E8\uACC4:\n"));
504
+ for (const s of nextSteps) process.stdout.write(` ${kleur2.cyan("\u2022")} ${s}
505
+ `);
506
+ process.stdout.write(kleur2.dim(` \uBBF8\uB9AC\uBCF4\uAE30: mimi-seed deploy --dry-run
507
+
508
+ `));
509
+ }
463
510
  if (!hasBlocker) {
464
- process.stdout.write(score >= 80 ? kleur2.green("\u2713 \uCD9C\uC2DC \uC900\uBE44 \uC644\uB8CC!\n") : kleur2.yellow("\uC810\uC218\uB97C \uB192\uC774\uB824\uBA74 \uB300\uC2DC\uBCF4\uB4DC\uB97C \uD655\uC778\uD558\uC138\uC694.\n"));
511
+ process.stdout.write(score >= 80 ? kleur2.green("\u2713 \uCD9C\uC2DC \uC900\uBE44 \uC644\uB8CC!\n") : kleur2.yellow(`\uC544\uC9C1 ${score}/100 \u2014 \uC704 \uB2E4\uC74C \uB2E8\uACC4\uB97C \uC9C4\uD589\uD558\uC138\uC694.
512
+ `));
465
513
  }
466
514
  } catch {
467
515
  for (const line of readinessResult.text.split("\n")) process.stdout.write(" " + line + "\n");
@@ -599,6 +647,7 @@ async function cmdNotes(argv) {
599
647
  return;
600
648
  }
601
649
  let selectedText = result.concise;
650
+ let userSelectedTone = false;
602
651
  if (shouldPrompt) {
603
652
  const choice = await promptUser("\uC801\uC6A9\uD560 \uBC84\uC804 [1=\uAC04\uACB0/2=\uC0C1\uC138/3=\uB9C8\uCF00\uD305/Enter=\uAC74\uB108\uB700]: ");
604
653
  if (!choice) {
@@ -607,6 +656,7 @@ async function cmdNotes(argv) {
607
656
  }
608
657
  if (choice === "2") selectedText = result.detailed;
609
658
  else if (choice === "3") selectedText = result.marketing;
659
+ userSelectedTone = true;
610
660
  }
611
661
  const appsResult = await mcpCall(cfg.endpoint, cfg.token, "list_apps", {});
612
662
  if (appsResult.isError) {
@@ -619,13 +669,17 @@ async function cmdNotes(argv) {
619
669
  process.stdout.write(kleur3.yellow("\uB4F1\uB85D\uB41C \uC571\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.\n"));
620
670
  return;
621
671
  }
672
+ if (userSelectedTone && args.locales.length > 1) {
673
+ process.stdout.write(kleur3.dim("\uC120\uD0DD\uD55C \uD1A4\uC744 \uBAA8\uB4E0 \uB85C\uCF00\uC77C\uC5D0 \uC801\uC6A9\uD569\uB2C8\uB2E4 (\uC790\uB3D9 \uBC88\uC5ED \uBBF8\uC801\uC6A9).\n"));
674
+ }
622
675
  process.stdout.write("Play Store\uC5D0 \uC801\uC6A9 \uC911...\n");
623
676
  for (const locale of args.locales) {
677
+ const text = userSelectedTone ? selectedText : result.localized[locale] ?? selectedText;
624
678
  const r = await mcpCall(cfg.endpoint, cfg.token, "apply_release_notes", {
625
679
  app_id: app.id,
626
680
  platform: "android",
627
681
  locale,
628
- text: result.localized[locale] ?? selectedText
682
+ text
629
683
  });
630
684
  process.stdout.write(r.isError ? kleur3.red(`${locale} \uC801\uC6A9 \uC2E4\uD328: ${r.text}
631
685
  `) : kleur3.green(`\u2713 ${locale} \uC801\uC6A9\uB428
@@ -783,30 +837,42 @@ async function cmdReview(argv) {
783
837
 
784
838
  // src/auth.ts
785
839
  import { spawn } from "child_process";
840
+ import fs4 from "fs";
841
+ import os3 from "os";
842
+ import path4 from "path";
786
843
  import kleur5 from "kleur";
787
844
  var MCP_PKG = "@yoonion/mimi-seed-mcp";
845
+ var MIMI_DIR = path4.join(os3.homedir(), ".mimi-seed");
788
846
  function log(msg) {
789
847
  process.stdout.write(msg + "\n");
790
848
  }
791
849
  function printAuthHelp() {
792
- log(`${kleur5.bold("mimi-seed auth")} \u2014 Google OAuth \uC778\uC99D (Firebase / AdMob / Play Store)
850
+ log(`${kleur5.bold("mimi-seed auth")} \u2014 \uB85C\uCEEC \uC790\uACA9\uC99D\uBA85 \uC778\uC99D/\uAD00\uB9AC
851
+
852
+ ${kleur5.bold("Google OAuth (Firebase / AdMob / Play):")}
853
+ ${kleur5.cyan("mimi-seed auth login")} \uBE0C\uB77C\uC6B0\uC800\uB85C \uB85C\uADF8\uC778 (\uC774\uBBF8 \uC788\uC73C\uBA74 \uC790\uB3D9 refresh \uC2DC\uB3C4)
854
+ ${kleur5.cyan("mimi-seed auth status")} \uD604\uC7AC OAuth \uD1A0\uD070 \uC0C1\uD0DC
855
+ ${kleur5.cyan("mimi-seed auth refresh")} refresh_token\uC73C\uB85C \uAC31\uC2E0\uB9CC \uC2DC\uB3C4 (\uBE0C\uB77C\uC6B0\uC800 X)
856
+ ${kleur5.cyan("mimi-seed auth logout")} OAuth \uD1A0\uD070 \uC0AD\uC81C
857
+
858
+ ${kleur5.bold("\uD50C\uB7AB\uD3FC\uBCC4 \uC790\uACA9\uC99D\uBA85:")}
859
+ ${kleur5.cyan("mimi-seed auth appstore")} App Store Connect API \uD0A4 (appstore.json)
860
+ ${kleur5.cyan("mimi-seed auth playstore")} Play \uC11C\uBE44\uC2A4 \uACC4\uC815 JSON \uB4F1\uB85D
861
+ ${kleur5.cyan("mimi-seed auth bigquery")} BigQuery \uC11C\uBE44\uC2A4 \uACC4\uC815 (Crashlytics export \uB4F1)
793
862
 
794
- ${kleur5.bold("\uC11C\uBE0C\uBA85\uB839:")}
795
- ${kleur5.cyan("mimi-seed auth login")} \uBE0C\uB77C\uC6B0\uC800\uB85C \uB85C\uADF8\uC778 (\uC774\uBBF8 \uC788\uC73C\uBA74 \uC790\uB3D9 refresh \uC2DC\uB3C4)
796
- ${kleur5.cyan("mimi-seed auth status")} \uD604\uC7AC \uD1A0\uD070 \uC0C1\uD0DC
797
- ${kleur5.cyan("mimi-seed auth refresh")} refresh_token\uC73C\uB85C \uAC31\uC2E0\uB9CC \uC2DC\uB3C4 (\uBE0C\uB77C\uC6B0\uC800 X)
798
- ${kleur5.cyan("mimi-seed auth logout")} \uD1A0\uD070 \uC0AD\uC81C
863
+ ${kleur5.bold("\uC804\uCCB4 \uC0C1\uD0DC:")}
864
+ ${kleur5.cyan("mimi-seed auth status --all")} 4\uAC1C \uC790\uACA9\uC99D\uBA85 \uBCF4\uC720 \uC5EC\uBD80 \uD55C\uB208\uC5D0
799
865
 
800
866
  ${kleur5.bold("login \uC635\uC158:")}
801
867
  --no-browser URL \uC790\uB3D9 \uC624\uD508 \uC548 \uD568 (\uC9C1\uC811 \uBCF5\uBD99)
802
868
  --timeout <\uCD08> \uCF5C\uBC31 \uB300\uAE30 \uC2DC\uAC04 (\uAE30\uBCF8 600)
803
869
  --force \uAE30\uC874 \uD1A0\uD070 \uBB34\uC2DC\uD558\uACE0 \uAC15\uC81C \uC7AC\uB85C\uADF8\uC778
804
870
 
805
- ${kleur5.dim(`\uB0B4\uBD80\uC801\uC73C\uB85C ${MCP_PKG} \uC758 mimi-seed-auth CLI\uB97C \uD638\uCD9C\uD569\uB2C8\uB2E4.`)}`);
871
+ ${kleur5.dim(`\uB0B4\uBD80\uC801\uC73C\uB85C ${MCP_PKG} \uC758 mimi-seed-*-auth CLI\uB97C \uD638\uCD9C\uD569\uB2C8\uB2E4.`)}`);
806
872
  }
807
- async function runMcpAuth(extraArgs) {
873
+ async function runMcpBin(bin, extraArgs) {
808
874
  return new Promise((resolve) => {
809
- const child = spawn("npx", ["-y", `${MCP_PKG}`, "mimi-seed-auth", ...extraArgs], {
875
+ const child = spawn("npx", ["-y", `${MCP_PKG}`, bin, ...extraArgs], {
810
876
  stdio: "inherit",
811
877
  shell: true
812
878
  });
@@ -819,6 +885,30 @@ async function runMcpAuth(extraArgs) {
819
885
  child.on("exit", (code) => resolve(code ?? 0));
820
886
  });
821
887
  }
888
+ function fileExists(name) {
889
+ return fs4.existsSync(path4.join(MIMI_DIR, name));
890
+ }
891
+ function anyFileStarting(prefix) {
892
+ try {
893
+ return fs4.readdirSync(MIMI_DIR).some((f) => f.startsWith(prefix));
894
+ } catch {
895
+ return false;
896
+ }
897
+ }
898
+ function printAllCredStatus() {
899
+ log(kleur5.bold("\uB85C\uCEEC \uC790\uACA9\uC99D\uBA85 \uC0C1\uD0DC ") + kleur5.dim("(~/.mimi-seed)"));
900
+ const rows = [
901
+ ["Google OAuth (Firebase/AdMob/Play)", fileExists("tokens.json"), "mimi-seed auth login"],
902
+ ["App Store Connect", fileExists("appstore.json"), "mimi-seed auth appstore"],
903
+ ["Play \uC11C\uBE44\uC2A4 \uACC4\uC815", anyFileStarting("play-service-account"), "mimi-seed auth playstore"],
904
+ ["BigQuery \uC11C\uBE44\uC2A4 \uACC4\uC815", anyFileStarting("bigquery"), "mimi-seed auth bigquery"]
905
+ ];
906
+ for (const [label, ok2, cmd] of rows) {
907
+ const mark = ok2 ? kleur5.green("\u2713") : kleur5.red("\u2717");
908
+ const hint = ok2 ? "" : kleur5.dim(` \u2192 ${cmd}`);
909
+ log(` ${mark} ${label}${hint}`);
910
+ }
911
+ }
822
912
  async function cmdAuth(args) {
823
913
  const sub = args[0];
824
914
  const rest = args.slice(1);
@@ -826,6 +916,13 @@ async function cmdAuth(args) {
826
916
  printAuthHelp();
827
917
  return;
828
918
  }
919
+ if (sub === "status" && rest.includes("--all")) {
920
+ printAllCredStatus();
921
+ return;
922
+ }
923
+ if (sub === "appstore") return void exitWith(await runMcpBin("mimi-seed-appstore-auth", rest));
924
+ if (sub === "playstore") return void exitWith(await runMcpBin("mimi-seed-playstore-auth", rest));
925
+ if (sub === "bigquery") return void exitWith(await runMcpBin("mimi-seed-bigquery-auth", rest));
829
926
  let mcpArgs;
830
927
  switch (sub) {
831
928
  case void 0:
@@ -846,7 +943,9 @@ async function cmdAuth(args) {
846
943
  printAuthHelp();
847
944
  process.exit(1);
848
945
  }
849
- const code = await runMcpAuth(mcpArgs);
946
+ exitWith(await runMcpBin("mimi-seed-auth", mcpArgs));
947
+ }
948
+ function exitWith(code) {
850
949
  if (code !== 0) process.exit(code);
851
950
  }
852
951
 
@@ -855,25 +954,25 @@ import kleur6 from "kleur";
855
954
  import * as readline from "readline";
856
955
 
857
956
  // src/ci-providers.ts
858
- import fs3 from "fs";
859
- import path3 from "path";
860
- import os2 from "os";
861
- var CI_CONFIG_PATH = path3.join(os2.homedir(), ".mimi-seed", "ci.json");
957
+ import fs5 from "fs";
958
+ import path5 from "path";
959
+ import os4 from "os";
960
+ var CI_CONFIG_PATH = path5.join(os4.homedir(), ".mimi-seed", "ci.json");
862
961
  function loadCiProviderConfig() {
863
962
  try {
864
- return JSON.parse(fs3.readFileSync(CI_CONFIG_PATH, "utf-8"));
963
+ return JSON.parse(fs5.readFileSync(CI_CONFIG_PATH, "utf-8"));
865
964
  } catch {
866
965
  return null;
867
966
  }
868
967
  }
869
968
  function saveCiProviderConfig(cfg) {
870
- const dir = path3.dirname(CI_CONFIG_PATH);
871
- if (!fs3.existsSync(dir)) {
872
- fs3.mkdirSync(dir, { recursive: true, mode: 448 });
969
+ const dir = path5.dirname(CI_CONFIG_PATH);
970
+ if (!fs5.existsSync(dir)) {
971
+ fs5.mkdirSync(dir, { recursive: true, mode: 448 });
873
972
  }
874
- fs3.writeFileSync(CI_CONFIG_PATH, JSON.stringify(cfg, null, 2));
973
+ fs5.writeFileSync(CI_CONFIG_PATH, JSON.stringify(cfg, null, 2));
875
974
  if (process.platform !== "win32") {
876
- fs3.chmodSync(CI_CONFIG_PATH, 384);
975
+ fs5.chmodSync(CI_CONFIG_PATH, 384);
877
976
  }
878
977
  }
879
978
  function ghBase(cfg) {
@@ -1110,6 +1209,7 @@ function parseArgs4(argv) {
1110
1209
  platform: "android",
1111
1210
  language: "ko-KR",
1112
1211
  dryRun: false,
1212
+ yes: false,
1113
1213
  skipBuild: false,
1114
1214
  setupJenkins: false,
1115
1215
  setupGithub: false,
@@ -1125,6 +1225,7 @@ function parseArgs4(argv) {
1125
1225
  if (argv[i] === "--to" && argv[i + 1]) args.toRef = argv[++i];
1126
1226
  if (argv[i] === "--language" && argv[i + 1]) args.language = argv[++i];
1127
1227
  if (argv[i] === "--dry-run") args.dryRun = true;
1228
+ if (argv[i] === "--yes" || argv[i] === "-y") args.yes = true;
1128
1229
  if (argv[i] === "--skip-build") args.skipBuild = true;
1129
1230
  if (argv[i] === "--ci" && argv[i + 1]) args.ci = argv[++i];
1130
1231
  if (argv[i] === "--workflow" && argv[i + 1]) args.workflow = argv[++i];
@@ -1336,6 +1437,21 @@ async function cmdDeploy(argv) {
1336
1437
  log2(kleur6.red("appId\uB97C \uD655\uC778\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. --app <id> \uB85C \uC9C0\uC815\uD558\uAC70\uB098 `mimi-seed init` \uC73C\uB85C \uC571 \uB4F1\uB85D."));
1337
1438
  process.exit(1);
1338
1439
  }
1440
+ const needsConfirm = !args.dryRun && !args.yes && process.stdout.isTTY && !process.env.MIMI_SEED_TOKEN;
1441
+ if (needsConfirm) {
1442
+ const target = args.platform === "ios" ? "App Store \uC2EC\uC0AC \uC81C\uCD9C" : "Play Store production \uD2B8\uB799";
1443
+ log2("");
1444
+ log2(kleur6.yellow(`\u26A0 \uC2E4\uC81C \uBC30\uD3EC: ${args.platform} \xB7 versionCode ${versionCode} \u2192 ${target}`));
1445
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
1446
+ const answer = await new Promise(
1447
+ (resolve) => rl.question(kleur6.bold("\uACC4\uC18D \uC9C4\uD589\uD560\uAE4C\uC694? [y/N]: "), (a) => resolve(a.trim().toLowerCase()))
1448
+ );
1449
+ rl.close();
1450
+ if (answer !== "y" && answer !== "yes") {
1451
+ log2(kleur6.dim("\uCDE8\uC18C\uB428. (--yes \uB85C \uD655\uC778 \uC0DD\uB7B5 \uAC00\uB2A5)"));
1452
+ return;
1453
+ }
1454
+ }
1339
1455
  log2("");
1340
1456
  log2("\u{1F4E1} \uC11C\uBC84 \uBC30\uD3EC \uD30C\uC774\uD504\uB77C\uC778 \uC2DC\uC791...");
1341
1457
  log2("");
@@ -1357,17 +1473,17 @@ async function cmdDeploy(argv) {
1357
1473
 
1358
1474
  // src/mcp-restart.ts
1359
1475
  import { execSync as execSync2 } from "child_process";
1360
- import fs4 from "fs";
1361
- import os3 from "os";
1362
- import path4 from "path";
1476
+ import fs6 from "fs";
1477
+ import os5 from "os";
1478
+ import path6 from "path";
1363
1479
  import kleur7 from "kleur";
1364
1480
  function log3(msg) {
1365
1481
  process.stdout.write(msg + "\n");
1366
1482
  }
1367
1483
  function readClaudeJson() {
1368
- const p = path4.join(os3.homedir(), ".claude.json");
1484
+ const p = path6.join(os5.homedir(), ".claude.json");
1369
1485
  try {
1370
- return JSON.parse(fs4.readFileSync(p, "utf8"));
1486
+ return JSON.parse(fs6.readFileSync(p, "utf8"));
1371
1487
  } catch {
1372
1488
  return {};
1373
1489
  }
@@ -1383,7 +1499,7 @@ function findProcessMarker(cfg) {
1383
1499
  return meaningful.at(-1) ?? null;
1384
1500
  }
1385
1501
  function killByMarker(marker) {
1386
- const isWin = os3.platform() === "win32";
1502
+ const isWin = os5.platform() === "win32";
1387
1503
  if (isWin) {
1388
1504
  const escaped = marker.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
1389
1505
  let pids = [];
@@ -1454,9 +1570,9 @@ async function cmdRestart(args) {
1454
1570
  }
1455
1571
 
1456
1572
  // src/mcp-config.ts
1457
- import fs5 from "fs/promises";
1458
- import path5 from "path";
1459
- import os4 from "os";
1573
+ import fs7 from "fs/promises";
1574
+ import path7 from "path";
1575
+ import os6 from "os";
1460
1576
  import kleur8 from "kleur";
1461
1577
  var SERVER_NAME = "mimi-seed";
1462
1578
  function tomlString(value) {
@@ -1496,17 +1612,17 @@ function printMcpSetup(cfg) {
1496
1612
  );
1497
1613
  }
1498
1614
  async function writeCodexMcpConfig(cfg) {
1499
- const configDir = path5.join(os4.homedir(), ".codex");
1500
- const configPath = path5.join(configDir, "config.toml");
1501
- await fs5.mkdir(configDir, { recursive: true });
1615
+ const configDir = path7.join(os6.homedir(), ".codex");
1616
+ const configPath = path7.join(configDir, "config.toml");
1617
+ await fs7.mkdir(configDir, { recursive: true });
1502
1618
  let current = "";
1503
1619
  try {
1504
- current = await fs5.readFile(configPath, "utf8");
1620
+ current = await fs7.readFile(configPath, "utf8");
1505
1621
  } catch {
1506
1622
  current = "";
1507
1623
  }
1508
1624
  const next = replaceTomlBlock(current, `mcp_servers.${SERVER_NAME}`, codexBlock(cfg));
1509
- await fs5.writeFile(configPath, next);
1625
+ await fs7.writeFile(configPath, next);
1510
1626
  return configPath;
1511
1627
  }
1512
1628
 
@@ -1516,7 +1632,8 @@ var DEFAULT_MCP_ENDPOINT = `${DEFAULT_WEB_BASE}/api/mcp`;
1516
1632
  function log4(msg) {
1517
1633
  process.stdout.write(msg + "\n");
1518
1634
  }
1519
- async function cmdInit() {
1635
+ async function cmdInit(args) {
1636
+ const local = args.includes("--local");
1520
1637
  const cwd = process.cwd();
1521
1638
  log4(kleur9.bold("Mimi Seed CLI \u2014 init"));
1522
1639
  log4(kleur9.dim(cwd));
@@ -1551,7 +1668,7 @@ async function cmdInit() {
1551
1668
  return;
1552
1669
  }
1553
1670
  log4("\u{1F510} \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uB85C\uADF8\uC778 \uB300\uAE30...");
1554
- const hostName = os5.hostname().slice(0, 32);
1671
+ const hostName = os7.hostname().slice(0, 32);
1555
1672
  const name = `cli-${hostName}`;
1556
1673
  const { port, promise } = await awaitHandshake(5 * 60 * 1e3);
1557
1674
  const callback = `http://127.0.0.1:${port}/cb`;
@@ -1617,16 +1734,16 @@ async function cmdInit() {
1617
1734
  "- `/mimi-seed:health` \u2014 \uC5F0\uACB0 \uC0C1\uD0DC \uBE60\uB978 \uD655\uC778",
1618
1735
  "- `/mimi-seed:review-inbox` \u2014 \uBBF8\uB2F5\uBCC0 \uB9AC\uBDF0 \uB2F5\uBCC0"
1619
1736
  ].join("\n");
1620
- const claudeDir = path6.join(cwd, ".claude");
1621
- const claudeAgentPath = path6.join(claudeDir, "mimi-seed.md");
1622
- if (!fs6.existsSync(claudeAgentPath)) {
1623
- fs6.mkdirSync(claudeDir, { recursive: true });
1624
- fs6.writeFileSync(claudeAgentPath, agentMd, { mode: 420 });
1737
+ const claudeDir = path8.join(cwd, ".claude");
1738
+ const claudeAgentPath = path8.join(claudeDir, "mimi-seed.md");
1739
+ if (!fs8.existsSync(claudeAgentPath)) {
1740
+ fs8.mkdirSync(claudeDir, { recursive: true });
1741
+ fs8.writeFileSync(claudeAgentPath, agentMd, { mode: 420 });
1625
1742
  log4(kleur9.dim(` Claude \uC5D0\uC774\uC804\uD2B8 \uC124\uC815: .claude/mimi-seed.md`));
1626
1743
  }
1627
- const codexAgentPath = path6.join(cwd, "AGENTS.md");
1628
- if (!fs6.existsSync(codexAgentPath)) {
1629
- fs6.writeFileSync(codexAgentPath, agentMd, { mode: 420 });
1744
+ const codexAgentPath = path8.join(cwd, "AGENTS.md");
1745
+ if (!fs8.existsSync(codexAgentPath)) {
1746
+ fs8.writeFileSync(codexAgentPath, agentMd, { mode: 420 });
1630
1747
  log4(kleur9.dim(` Codex \uC5D0\uC774\uC804\uD2B8 \uC124\uC815: AGENTS.md`));
1631
1748
  }
1632
1749
  log4(kleur9.bold("\u2713 \uC900\uBE44 \uC644\uB8CC."));
@@ -1639,6 +1756,18 @@ async function cmdInit() {
1639
1756
  log4(`\uB300\uC2DC\uBCF4\uB4DC: ${kleur9.underline(DEFAULT_WEB_BASE + "/apps")}`);
1640
1757
  log4("");
1641
1758
  printMcpSetup(cfg);
1759
+ if (local) {
1760
+ log4("");
1761
+ log4(kleur9.bold("\u2500\u2500 \uB85C\uCEEC MCP \uCD94\uAC00 \uC124\uC815 (--local) \u2500\u2500"));
1762
+ log4(kleur9.dim("\uC6D0\uACA9 MCP(16 tool, PAT)\uB294 \uC704\uC5D0\uC11C \uB05D. \uB85C\uCEEC MCP\uB294 Google OAuth\uB85C 110+ tool\uC744 \uC9C1\uC811 \uC2E4\uD589\uD569\uB2C8\uB2E4."));
1763
+ log4("");
1764
+ log4("1) Google \uB85C\uADF8\uC778 (Firebase / AdMob / Play / Ads):");
1765
+ await cmdAuth(["login"]);
1766
+ log4("");
1767
+ log4("2) \uB85C\uCEEC MCP \uC11C\uBC84 \uB4F1\uB85D (\uC6D0\uACA9 'mimi-seed' \uC640 \uBCC4\uAC1C):");
1768
+ log4(kleur9.cyan(" claude mcp add mimi-seed-local -- npx -y @yoonion/mimi-seed-mcp"));
1769
+ log4(kleur9.dim(' Codex: ~/.codex/config.toml \uC5D0 [mcp_servers.mimi-seed-local] command="npx", args=["-y","@yoonion/mimi-seed-mcp"]'));
1770
+ }
1642
1771
  }
1643
1772
  async function cmdStatus() {
1644
1773
  const cfg = await getEffectiveConfig();
@@ -1675,6 +1804,7 @@ async function cmdMcp(args) {
1675
1804
  const configPath = await writeCodexMcpConfig(cfg);
1676
1805
  log4(kleur9.green("\u2713 Codex MCP \uC124\uC815 \uC644\uB8CC"));
1677
1806
  log4(kleur9.dim(` ${configPath}`));
1807
+ log4(kleur9.dim(" \u26A0 config.toml\uC5D0 \uC2E4\uC81C \uD1A0\uD070\uC774 \uD3C9\uBB38\uC73C\uB85C \uC800\uC7A5\uB429\uB2C8\uB2E4 (\uD30C\uC77C \uAD8C\uD55C \uD655\uC778 \uAD8C\uC7A5)."));
1678
1808
  log4("");
1679
1809
  log4("Codex\uB97C \uC0C8\uB85C \uC5F4\uACE0 `/mcp` \uB610\uB294 `codex mcp list`\uB85C \uD655\uC778\uD558\uC138\uC694.");
1680
1810
  return;
@@ -1699,35 +1829,37 @@ http_headers = { Authorization = "Bearer ${cfg.prefix}..." }`);
1699
1829
  }
1700
1830
  printMcpSetup(cfg);
1701
1831
  }
1702
- function printHelp() {
1703
- log4(`${kleur9.bold("mimi-seed")} \u2014 Claude Code/Codex\uC5D0\uC11C \uC571 \uCD9C\uC2DC \uC6B4\uC601
1832
+ var CMD_USAGE = {
1833
+ init: `${kleur9.bold("mimi-seed init")} \u2014 \uD604\uC7AC \uD504\uB85C\uC81D\uD2B8\uB97C Mimi Seed\uC5D0 \uC5F0\uACB0
1704
1834
 
1705
- ${kleur9.bold("\uBA85\uB839\uC5B4:")}
1706
- ${kleur9.cyan("mimi-seed init")} \uD604\uC7AC \uD504\uB85C\uC81D\uD2B8\uB97C Mimi Seed\uC5D0 \uC5F0\uACB0
1707
- ${kleur9.cyan("mimi-seed status")} \uC5F0\uACB0 \uC0C1\uD0DC + \uB4F1\uB85D \uC571 \uBAA9\uB85D
1708
- ${kleur9.cyan("mimi-seed auth")} Google OAuth \uC778\uC99D (Firebase/AdMob/Play). 'mimi-seed auth --help'
1709
- ${kleur9.cyan("mimi-seed doctor")} \uD658\uACBD \uC9C4\uB2E8 (\uD1A0\uD070\xB7Git\xB7\uD504\uB85C\uC81D\uD2B8\xB7CI \uCCB4\uD06C)
1710
- ${kleur9.cyan("mimi-seed check")} \uCD9C\uC2DC \uC804 Readiness \uC810\uAC80
1711
- ${kleur9.cyan("mimi-seed notes")} \uB9B4\uB9AC\uC988 \uB178\uD2B8 \uC0DD\uC131 (git log \u2192 AI \u2192 \uB9C8\uCF13 \uC801\uC6A9)
1712
- ${kleur9.cyan("mimi-seed review")} \uB9AC\uBDF0 \uB2F5\uBCC0 AI \uCD08\uC548 \uC0DD\uC131 \uBC0F Play Store \uAC8C\uC2DC
1713
- ${kleur9.cyan("mimi-seed deploy")} \uC571 \uC790\uB3D9 \uBC30\uD3EC (Jenkins \u2192 Play Store/App Store)
1714
- ${kleur9.cyan("mimi-seed mcp")} Claude/Codex MCP \uC5F0\uACB0 \uC548\uB0B4 \uBC0F Codex \uC124\uC815 \uC4F0\uAE30
1715
- ${kleur9.cyan("mimi-seed restart")} MCP \uC11C\uBC84 \uD504\uB85C\uC138\uC2A4 \uC7AC\uC2DC\uC791 (\uAE30\uBCF8: mimi-seed)
1716
- ${kleur9.cyan("mimi-seed logout")} \uB85C\uCEEC \uC124\uC815 \uC0AD\uC81C
1835
+ \uC571 \uC790\uB3D9 \uAC10\uC9C0(Expo/Gradle/Info.plist/pbxproj) \u2192 \uBE0C\uB77C\uC6B0\uC800 PAT \uBC1C\uAE09(\uC6D0\uACA9 MCP) \u2192 \uC571 \uB4F1\uB85D
1836
+ + .claude/mimi-seed.md, AGENTS.md \uC0DD\uC131.
1837
+
1838
+ \uC635\uC158:
1839
+ --local \uCD94\uAC00\uB85C Google OAuth \uB85C\uADF8\uC778 + \uB85C\uCEEC 110+ tool MCP \uB4F1\uB85D \uC548\uB0B4`,
1840
+ status: `${kleur9.bold("mimi-seed status")} \u2014 \uC5F0\uACB0 \uC0C1\uD0DC + \uB4F1\uB85D \uC571 \uBAA9\uB85D. \uC635\uC158 \uC5C6\uC74C.`,
1841
+ doctor: `${kleur9.bold("mimi-seed doctor")} \u2014 \uD658\uACBD \uC9C4\uB2E8 (\uD1A0\uD070\xB7Node\xB7Git\xB7\uD504\uB85C\uC81D\uD2B8\xB7CI). \uC635\uC158 \uC5C6\uC74C.`,
1842
+ logout: `${kleur9.bold("mimi-seed logout")} \u2014 \uB85C\uCEEC \uC124\uC815(config.json) \uC0AD\uC81C. \uC635\uC158 \uC5C6\uC74C.`,
1843
+ restart: `${kleur9.bold("mimi-seed restart")} \u2014 MCP \uC11C\uBC84 \uD504\uB85C\uC138\uC2A4 \uC7AC\uC2DC\uC791 (\uAE30\uBCF8: mimi-seed)
1717
1844
 
1718
- ${kleur9.bold("mimi-seed notes \uC635\uC158:")}
1845
+ mimi-seed restart [server-name]`,
1846
+ notes: `${kleur9.bold("mimi-seed notes")} \u2014 \uB9B4\uB9AC\uC988 \uB178\uD2B8 \uC0DD\uC131 (git log \u2192 AI \u2192 \uB9C8\uCF13 \uC801\uC6A9)
1847
+
1848
+ \uC635\uC158:
1719
1849
  --from <ref> \uC2DC\uC791 \uCEE4\uBC0B/\uD0DC\uADF8 (\uAE30\uBCF8: \uCD5C\uC2E0 \uD0DC\uADF8)
1720
1850
  --to <ref> \uB05D \uCEE4\uBC0B (\uAE30\uBCF8: HEAD)
1721
1851
  --locale ko,en-US \uB300\uC0C1 \uB85C\uCF00\uC77C (\uC27C\uD45C \uAD6C\uBD84)
1722
1852
  --apply \uC0DD\uC131 \uD6C4 \uC2A4\uD1A0\uC5B4\uC5D0 \uBC14\uB85C \uC801\uC6A9
1723
1853
  --no-interactive CI \uBAA8\uB4DC (\uD504\uB86C\uD504\uD2B8 \uC5C6\uC74C)
1724
- --limit <n> \uCD5C\uB300 \uCEE4\uBC0B \uC218 (\uAE30\uBCF8: 30)
1854
+ --limit <n> \uCD5C\uB300 \uCEE4\uBC0B \uC218 (\uAE30\uBCF8: 30)`,
1855
+ check: `${kleur9.bold("mimi-seed check")} \u2014 \uCD9C\uC2DC \uC804 Readiness \uC810\uAC80
1725
1856
 
1726
- ${kleur9.bold("mimi-seed check \uC635\uC158:")}
1857
+ \uC635\uC158:
1727
1858
  --app <id> \uC571 ID \uC9C0\uC815
1728
- --fail-on-blocker \uBE14\uB85C\uCEE4 \uC788\uC73C\uBA74 exit 1 (CI\uC6A9)
1859
+ --fail-on-blocker \uBE14\uB85C\uCEE4 \uC788\uC73C\uBA74 exit 1 (CI\uC6A9)`,
1860
+ review: `${kleur9.bold("mimi-seed review")} \u2014 \uB9AC\uBDF0 \uB2F5\uBCC0 AI \uCD08\uC548 \uC0DD\uC131 \uBC0F Play Store \uAC8C\uC2DC
1729
1861
 
1730
- ${kleur9.bold("mimi-seed review \uC635\uC158:")}
1862
+ \uC635\uC158:
1731
1863
  --text <\uB0B4\uC6A9> \uB9AC\uBDF0 \uC6D0\uBB38 (\uBBF8\uC785\uB825 \uC2DC \uB300\uD654\uD615 \uD504\uB86C\uD504\uD2B8)
1732
1864
  --rating <1-5> \uBCC4\uC810
1733
1865
  --tone <tone> friendly / professional / empathetic / brief (\uAE30\uBCF8: friendly)
@@ -1736,9 +1868,10 @@ ${kleur9.bold("mimi-seed review \uC635\uC158:")}
1736
1868
  --apply \uB2F5\uBCC0\uC744 Play Store\uC5D0 \uAC8C\uC2DC
1737
1869
  --review-id <id> \uB9AC\uBDF0 ID (--apply \uC2DC \uD544\uC694)
1738
1870
  --package-name <p> \uD328\uD0A4\uC9C0\uBA85 (--apply \uC2DC \uD544\uC694)
1739
- --no-interactive CI \uBAA8\uB4DC
1871
+ --no-interactive CI \uBAA8\uB4DC`,
1872
+ deploy: `${kleur9.bold("mimi-seed deploy")} \u2014 \uC571 \uC790\uB3D9 \uBC30\uD3EC (CI \uBE4C\uB4DC \u2192 Play Store/App Store)
1740
1873
 
1741
- ${kleur9.bold("mimi-seed deploy \uC635\uC158:")}
1874
+ \uC635\uC158:
1742
1875
  --platform android|ios \uBC30\uD3EC \uD50C\uB7AB\uD3FC (\uAE30\uBCF8: android)
1743
1876
  --app <id> \uC571 ID \uC9C0\uC815
1744
1877
  --version-code <n> \uBE4C\uB4DC \uBC88\uD638 \uC9C1\uC811 \uC9C0\uC815 (--skip-build \uC640 \uD568\uAED8)
@@ -1746,13 +1879,43 @@ ${kleur9.bold("mimi-seed deploy \uC635\uC158:")}
1746
1879
  --to <ref> \uCEE4\uBC0B \uBC94\uC704 \uB05D (\uAE30\uBCF8: HEAD)
1747
1880
  --language <\uCF54\uB4DC> \uB9B4\uB9AC\uC988 \uB178\uD2B8 \uC5B8\uC5B4 (\uAE30\uBCF8: ko-KR)
1748
1881
  --dry-run \uC2E4\uC81C \uBC30\uD3EC \uC5C6\uC774 \uD30C\uC774\uD504\uB77C\uC778 \uD14C\uC2A4\uD2B8
1882
+ --yes, -y \uBC30\uD3EC \uD655\uC778 \uD504\uB86C\uD504\uD2B8 \uC0DD\uB7B5 (\uC2A4\uD06C\uB9BD\uD2B8/\uC790\uB3D9\uD654\uC6A9)
1749
1883
  --skip-build CI \uBE4C\uB4DC \uAC74\uB108\uB700 (--version-code \uD544\uC218)
1750
1884
  --ci jenkins|github|gitlab CI \uAC15\uC81C \uC120\uD0DD (\uAE30\uBCF8: auto)
1751
1885
  --workflow <file> GitHub workflow \uD30C\uC77C (\uC608: deploy.yml)
1752
1886
  --ref <branch|tag> GitHub/GitLab \uBE0C\uB79C\uCE58/\uD0DC\uADF8 (\uAE30\uBCF8: main)
1753
- setup-jenkins Jenkins \uC124\uC815 \uB300\uD654\uD615 \uB4F1\uB85D
1754
- setup-github GitHub Actions \uC124\uC815 \uB300\uD654\uD615 \uB4F1\uB85D
1755
- setup-gitlab GitLab CI \uC124\uC815 \uB300\uD654\uD615 \uB4F1\uB85D
1887
+ setup-jenkins / setup-github / setup-gitlab CI \uC124\uC815 \uB300\uD654\uD615 \uB4F1\uB85D`,
1888
+ mcp: `${kleur9.bold("mimi-seed mcp")} \u2014 Claude/Codex MCP \uC5F0\uACB0
1889
+
1890
+ \uC11C\uBE0C\uBA85\uB839:
1891
+ mimi-seed mcp \uD604\uC7AC \uC124\uC815 + \uB4F1\uB85D \uC548\uB0B4
1892
+ mimi-seed mcp claude Claude Code \uB4F1\uB85D \uBA85\uB839 \uCD9C\uB825
1893
+ mimi-seed mcp codex Codex \uB4F1\uB85D \uC548\uB0B4
1894
+ mimi-seed mcp codex --write ~/.codex/config.toml\uC5D0 \uC9C1\uC811 \uAE30\uB85D (\u26A0 \uC2E4\uC81C \uD1A0\uD070 \uD3C9\uBB38 \uC800\uC7A5)`
1895
+ };
1896
+ function printCommandHelp(cmd) {
1897
+ const usage = CMD_USAGE[cmd];
1898
+ if (!usage) return false;
1899
+ log4(usage);
1900
+ return true;
1901
+ }
1902
+ function printHelp() {
1903
+ log4(`${kleur9.bold("mimi-seed")} \u2014 Claude Code/Codex\uC5D0\uC11C \uC571 \uCD9C\uC2DC \uC6B4\uC601
1904
+
1905
+ ${kleur9.bold("\uBA85\uB839\uC5B4:")}
1906
+ ${kleur9.cyan("mimi-seed init")} \uD604\uC7AC \uD504\uB85C\uC81D\uD2B8\uB97C Mimi Seed\uC5D0 \uC5F0\uACB0
1907
+ ${kleur9.cyan("mimi-seed status")} \uC5F0\uACB0 \uC0C1\uD0DC + \uB4F1\uB85D \uC571 \uBAA9\uB85D
1908
+ ${kleur9.cyan("mimi-seed auth")} \uB85C\uCEEC \uC778\uC99D (Google OAuth / App Store / Play / BigQuery)
1909
+ ${kleur9.cyan("mimi-seed doctor")} \uD658\uACBD \uC9C4\uB2E8 (\uD1A0\uD070\xB7Git\xB7\uD504\uB85C\uC81D\uD2B8\xB7CI \uCCB4\uD06C)
1910
+ ${kleur9.cyan("mimi-seed check")} \uCD9C\uC2DC \uC804 Readiness \uC810\uAC80
1911
+ ${kleur9.cyan("mimi-seed notes")} \uB9B4\uB9AC\uC988 \uB178\uD2B8 \uC0DD\uC131 (git log \u2192 AI \u2192 \uB9C8\uCF13 \uC801\uC6A9)
1912
+ ${kleur9.cyan("mimi-seed review")} \uB9AC\uBDF0 \uB2F5\uBCC0 AI \uCD08\uC548 \uC0DD\uC131 \uBC0F Play Store \uAC8C\uC2DC
1913
+ ${kleur9.cyan("mimi-seed deploy")} \uC571 \uC790\uB3D9 \uBC30\uD3EC (CI \u2192 Play Store/App Store)
1914
+ ${kleur9.cyan("mimi-seed mcp")} Claude/Codex MCP \uC5F0\uACB0 \uC548\uB0B4 \uBC0F Codex \uC124\uC815 \uC4F0\uAE30
1915
+ ${kleur9.cyan("mimi-seed restart")} MCP \uC11C\uBC84 \uD504\uB85C\uC138\uC2A4 \uC7AC\uC2DC\uC791 (\uAE30\uBCF8: mimi-seed)
1916
+ ${kleur9.cyan("mimi-seed logout")} \uB85C\uCEEC \uC124\uC815 \uC0AD\uC81C
1917
+
1918
+ ${kleur9.dim("\uAC01 \uBA85\uB839 \uC0C1\uC138 \uC635\uC158:")} ${kleur9.cyan("mimi-seed <command> --help")}
1756
1919
 
1757
1920
  ${kleur9.bold("\uD658\uACBD\uBCC0\uC218:")}
1758
1921
  MIMI_SEED_TOKEN PAT \uD1A0\uD070 (CI/CD \uBB34\uC778\uC99D \uBAA8\uB4DC)
@@ -1763,10 +1926,13 @@ ${kleur9.bold("\uD658\uACBD\uBCC0\uC218:")}
1763
1926
  async function main() {
1764
1927
  const cmd = process.argv[2];
1765
1928
  const restArgs = process.argv.slice(3);
1929
+ if (cmd && cmd !== "auth" && (restArgs.includes("--help") || restArgs.includes("-h"))) {
1930
+ if (printCommandHelp(cmd)) return;
1931
+ }
1766
1932
  try {
1767
1933
  switch (cmd) {
1768
1934
  case "init":
1769
- await cmdInit();
1935
+ await cmdInit(restArgs);
1770
1936
  break;
1771
1937
  case "status":
1772
1938
  await cmdStatus();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mimi-seed",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
4
4
  "description": "Mimi Seed CLI — Claude Code와 Codex에서 앱 출시 운영을 관리합니다.",
5
5
  "bin": {
6
6
  "mimi-seed": "dist/index.js"