mimi-seed 0.2.8 → 0.2.10

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 (4) hide show
  1. package/LICENSE +75 -75
  2. package/README.md +309 -230
  3. package/dist/index.js +342 -127
  4. package/package.json +8 -2
package/dist/index.js CHANGED
@@ -4,10 +4,10 @@ import {
4
4
  } from "./chunk-Q5YGYAFK.js";
5
5
 
6
6
  // src/index.ts
7
- import os4 from "os";
8
- import fs5 from "fs";
9
- import path5 from "path";
10
- import kleur8 from "kleur";
7
+ import os6 from "os";
8
+ import fs7 from "fs";
9
+ import path7 from "path";
10
+ import kleur9 from "kleur";
11
11
  import open from "open";
12
12
 
13
13
  // src/detect.ts
@@ -460,8 +460,25 @@ async function cmdCheck(argv) {
460
460
  `);
461
461
  process.stdout.write("\n");
462
462
  }
463
+ const base = `${cfg.webBase}/apps/${appId}`;
464
+ const nextSteps = [];
465
+ if (data.modules) {
466
+ if ((data.modules.integration ?? 25) < 25) nextSteps.push(`\uC5F0\uACB0 \uC9C4\uB2E8 ${base}/integration`);
467
+ if ((data.modules.copy ?? 25) < 25) nextSteps.push(`\uBB38\uAD6C \uBCF4\uAC15 mimi-seed notes \uB610\uB294 ${base}/copy`);
468
+ if ((data.modules.screenshot ?? 25) < 25) nextSteps.push(`\uC2A4\uD06C\uB9B0\uC0F7 ${base}/screenshots`);
469
+ if ((data.modules.checklist ?? 25) < 25) nextSteps.push(`\uCCB4\uD06C\uB9AC\uC2A4\uD2B8 ${base}/launch`);
470
+ }
471
+ if (nextSteps.length) {
472
+ process.stdout.write(kleur2.bold("\u2192 \uB2E4\uC74C \uB2E8\uACC4:\n"));
473
+ for (const s of nextSteps) process.stdout.write(` ${kleur2.cyan("\u2022")} ${s}
474
+ `);
475
+ process.stdout.write(kleur2.dim(` \uBBF8\uB9AC\uBCF4\uAE30: mimi-seed deploy --dry-run
476
+
477
+ `));
478
+ }
463
479
  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"));
480
+ 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.
481
+ `));
465
482
  }
466
483
  } catch {
467
484
  for (const line of readinessResult.text.split("\n")) process.stdout.write(" " + line + "\n");
@@ -599,6 +616,7 @@ async function cmdNotes(argv) {
599
616
  return;
600
617
  }
601
618
  let selectedText = result.concise;
619
+ let userSelectedTone = false;
602
620
  if (shouldPrompt) {
603
621
  const choice = await promptUser("\uC801\uC6A9\uD560 \uBC84\uC804 [1=\uAC04\uACB0/2=\uC0C1\uC138/3=\uB9C8\uCF00\uD305/Enter=\uAC74\uB108\uB700]: ");
604
622
  if (!choice) {
@@ -607,6 +625,7 @@ async function cmdNotes(argv) {
607
625
  }
608
626
  if (choice === "2") selectedText = result.detailed;
609
627
  else if (choice === "3") selectedText = result.marketing;
628
+ userSelectedTone = true;
610
629
  }
611
630
  const appsResult = await mcpCall(cfg.endpoint, cfg.token, "list_apps", {});
612
631
  if (appsResult.isError) {
@@ -619,13 +638,17 @@ async function cmdNotes(argv) {
619
638
  process.stdout.write(kleur3.yellow("\uB4F1\uB85D\uB41C \uC571\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.\n"));
620
639
  return;
621
640
  }
641
+ if (userSelectedTone && args.locales.length > 1) {
642
+ 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"));
643
+ }
622
644
  process.stdout.write("Play Store\uC5D0 \uC801\uC6A9 \uC911...\n");
623
645
  for (const locale of args.locales) {
646
+ const text = userSelectedTone ? selectedText : result.localized[locale] ?? selectedText;
624
647
  const r = await mcpCall(cfg.endpoint, cfg.token, "apply_release_notes", {
625
648
  app_id: app.id,
626
649
  platform: "android",
627
650
  locale,
628
- text: result.localized[locale] ?? selectedText
651
+ text
629
652
  });
630
653
  process.stdout.write(r.isError ? kleur3.red(`${locale} \uC801\uC6A9 \uC2E4\uD328: ${r.text}
631
654
  `) : kleur3.green(`\u2713 ${locale} \uC801\uC6A9\uB428
@@ -783,30 +806,42 @@ async function cmdReview(argv) {
783
806
 
784
807
  // src/auth.ts
785
808
  import { spawn } from "child_process";
809
+ import fs3 from "fs";
810
+ import os2 from "os";
811
+ import path3 from "path";
786
812
  import kleur5 from "kleur";
787
813
  var MCP_PKG = "@yoonion/mimi-seed-mcp";
814
+ var MIMI_DIR = path3.join(os2.homedir(), ".mimi-seed");
788
815
  function log(msg) {
789
816
  process.stdout.write(msg + "\n");
790
817
  }
791
818
  function printAuthHelp() {
792
- log(`${kleur5.bold("mimi-seed auth")} \u2014 Google OAuth \uC778\uC99D (Firebase / AdMob / Play Store)
819
+ log(`${kleur5.bold("mimi-seed auth")} \u2014 \uB85C\uCEEC \uC790\uACA9\uC99D\uBA85 \uC778\uC99D/\uAD00\uB9AC
820
+
821
+ ${kleur5.bold("Google OAuth (Firebase / AdMob / Play):")}
822
+ ${kleur5.cyan("mimi-seed auth login")} \uBE0C\uB77C\uC6B0\uC800\uB85C \uB85C\uADF8\uC778 (\uC774\uBBF8 \uC788\uC73C\uBA74 \uC790\uB3D9 refresh \uC2DC\uB3C4)
823
+ ${kleur5.cyan("mimi-seed auth status")} \uD604\uC7AC OAuth \uD1A0\uD070 \uC0C1\uD0DC
824
+ ${kleur5.cyan("mimi-seed auth refresh")} refresh_token\uC73C\uB85C \uAC31\uC2E0\uB9CC \uC2DC\uB3C4 (\uBE0C\uB77C\uC6B0\uC800 X)
825
+ ${kleur5.cyan("mimi-seed auth logout")} OAuth \uD1A0\uD070 \uC0AD\uC81C
826
+
827
+ ${kleur5.bold("\uD50C\uB7AB\uD3FC\uBCC4 \uC790\uACA9\uC99D\uBA85:")}
828
+ ${kleur5.cyan("mimi-seed auth appstore")} App Store Connect API \uD0A4 (appstore.json)
829
+ ${kleur5.cyan("mimi-seed auth playstore")} Play \uC11C\uBE44\uC2A4 \uACC4\uC815 JSON \uB4F1\uB85D
830
+ ${kleur5.cyan("mimi-seed auth bigquery")} BigQuery \uC11C\uBE44\uC2A4 \uACC4\uC815 (Crashlytics export \uB4F1)
793
831
 
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
832
+ ${kleur5.bold("\uC804\uCCB4 \uC0C1\uD0DC:")}
833
+ ${kleur5.cyan("mimi-seed auth status --all")} 4\uAC1C \uC790\uACA9\uC99D\uBA85 \uBCF4\uC720 \uC5EC\uBD80 \uD55C\uB208\uC5D0
799
834
 
800
835
  ${kleur5.bold("login \uC635\uC158:")}
801
836
  --no-browser URL \uC790\uB3D9 \uC624\uD508 \uC548 \uD568 (\uC9C1\uC811 \uBCF5\uBD99)
802
837
  --timeout <\uCD08> \uCF5C\uBC31 \uB300\uAE30 \uC2DC\uAC04 (\uAE30\uBCF8 600)
803
838
  --force \uAE30\uC874 \uD1A0\uD070 \uBB34\uC2DC\uD558\uACE0 \uAC15\uC81C \uC7AC\uB85C\uADF8\uC778
804
839
 
805
- ${kleur5.dim(`\uB0B4\uBD80\uC801\uC73C\uB85C ${MCP_PKG} \uC758 mimi-seed-auth CLI\uB97C \uD638\uCD9C\uD569\uB2C8\uB2E4.`)}`);
840
+ ${kleur5.dim(`\uB0B4\uBD80\uC801\uC73C\uB85C ${MCP_PKG} \uC758 mimi-seed-*-auth CLI\uB97C \uD638\uCD9C\uD569\uB2C8\uB2E4.`)}`);
806
841
  }
807
- async function runMcpAuth(extraArgs) {
842
+ async function runMcpBin(bin, extraArgs) {
808
843
  return new Promise((resolve) => {
809
- const child = spawn("npx", ["-y", `${MCP_PKG}`, "mimi-seed-auth", ...extraArgs], {
844
+ const child = spawn("npx", ["-y", `${MCP_PKG}`, bin, ...extraArgs], {
810
845
  stdio: "inherit",
811
846
  shell: true
812
847
  });
@@ -819,6 +854,30 @@ async function runMcpAuth(extraArgs) {
819
854
  child.on("exit", (code) => resolve(code ?? 0));
820
855
  });
821
856
  }
857
+ function fileExists(name) {
858
+ return fs3.existsSync(path3.join(MIMI_DIR, name));
859
+ }
860
+ function anyFileStarting(prefix) {
861
+ try {
862
+ return fs3.readdirSync(MIMI_DIR).some((f) => f.startsWith(prefix));
863
+ } catch {
864
+ return false;
865
+ }
866
+ }
867
+ function printAllCredStatus() {
868
+ log(kleur5.bold("\uB85C\uCEEC \uC790\uACA9\uC99D\uBA85 \uC0C1\uD0DC ") + kleur5.dim("(~/.mimi-seed)"));
869
+ const rows = [
870
+ ["Google OAuth (Firebase/AdMob/Play)", fileExists("tokens.json"), "mimi-seed auth login"],
871
+ ["App Store Connect", fileExists("appstore.json"), "mimi-seed auth appstore"],
872
+ ["Play \uC11C\uBE44\uC2A4 \uACC4\uC815", anyFileStarting("play-service-account"), "mimi-seed auth playstore"],
873
+ ["BigQuery \uC11C\uBE44\uC2A4 \uACC4\uC815", anyFileStarting("bigquery"), "mimi-seed auth bigquery"]
874
+ ];
875
+ for (const [label, ok2, cmd] of rows) {
876
+ const mark = ok2 ? kleur5.green("\u2713") : kleur5.red("\u2717");
877
+ const hint = ok2 ? "" : kleur5.dim(` \u2192 ${cmd}`);
878
+ log(` ${mark} ${label}${hint}`);
879
+ }
880
+ }
822
881
  async function cmdAuth(args) {
823
882
  const sub = args[0];
824
883
  const rest = args.slice(1);
@@ -826,6 +885,13 @@ async function cmdAuth(args) {
826
885
  printAuthHelp();
827
886
  return;
828
887
  }
888
+ if (sub === "status" && rest.includes("--all")) {
889
+ printAllCredStatus();
890
+ return;
891
+ }
892
+ if (sub === "appstore") return void exitWith(await runMcpBin("mimi-seed-appstore-auth", rest));
893
+ if (sub === "playstore") return void exitWith(await runMcpBin("mimi-seed-playstore-auth", rest));
894
+ if (sub === "bigquery") return void exitWith(await runMcpBin("mimi-seed-bigquery-auth", rest));
829
895
  let mcpArgs;
830
896
  switch (sub) {
831
897
  case void 0:
@@ -846,7 +912,9 @@ async function cmdAuth(args) {
846
912
  printAuthHelp();
847
913
  process.exit(1);
848
914
  }
849
- const code = await runMcpAuth(mcpArgs);
915
+ exitWith(await runMcpBin("mimi-seed-auth", mcpArgs));
916
+ }
917
+ function exitWith(code) {
850
918
  if (code !== 0) process.exit(code);
851
919
  }
852
920
 
@@ -855,25 +923,25 @@ import kleur6 from "kleur";
855
923
  import * as readline from "readline";
856
924
 
857
925
  // 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");
926
+ import fs4 from "fs";
927
+ import path4 from "path";
928
+ import os3 from "os";
929
+ var CI_CONFIG_PATH = path4.join(os3.homedir(), ".mimi-seed", "ci.json");
862
930
  function loadCiProviderConfig() {
863
931
  try {
864
- return JSON.parse(fs3.readFileSync(CI_CONFIG_PATH, "utf-8"));
932
+ return JSON.parse(fs4.readFileSync(CI_CONFIG_PATH, "utf-8"));
865
933
  } catch {
866
934
  return null;
867
935
  }
868
936
  }
869
937
  function saveCiProviderConfig(cfg) {
870
- const dir = path3.dirname(CI_CONFIG_PATH);
871
- if (!fs3.existsSync(dir)) {
872
- fs3.mkdirSync(dir, { recursive: true, mode: 448 });
938
+ const dir = path4.dirname(CI_CONFIG_PATH);
939
+ if (!fs4.existsSync(dir)) {
940
+ fs4.mkdirSync(dir, { recursive: true, mode: 448 });
873
941
  }
874
- fs3.writeFileSync(CI_CONFIG_PATH, JSON.stringify(cfg, null, 2));
942
+ fs4.writeFileSync(CI_CONFIG_PATH, JSON.stringify(cfg, null, 2));
875
943
  if (process.platform !== "win32") {
876
- fs3.chmodSync(CI_CONFIG_PATH, 384);
944
+ fs4.chmodSync(CI_CONFIG_PATH, 384);
877
945
  }
878
946
  }
879
947
  function ghBase(cfg) {
@@ -1110,6 +1178,7 @@ function parseArgs4(argv) {
1110
1178
  platform: "android",
1111
1179
  language: "ko-KR",
1112
1180
  dryRun: false,
1181
+ yes: false,
1113
1182
  skipBuild: false,
1114
1183
  setupJenkins: false,
1115
1184
  setupGithub: false,
@@ -1125,6 +1194,7 @@ function parseArgs4(argv) {
1125
1194
  if (argv[i] === "--to" && argv[i + 1]) args.toRef = argv[++i];
1126
1195
  if (argv[i] === "--language" && argv[i + 1]) args.language = argv[++i];
1127
1196
  if (argv[i] === "--dry-run") args.dryRun = true;
1197
+ if (argv[i] === "--yes" || argv[i] === "-y") args.yes = true;
1128
1198
  if (argv[i] === "--skip-build") args.skipBuild = true;
1129
1199
  if (argv[i] === "--ci" && argv[i + 1]) args.ci = argv[++i];
1130
1200
  if (argv[i] === "--workflow" && argv[i + 1]) args.workflow = argv[++i];
@@ -1336,6 +1406,21 @@ async function cmdDeploy(argv) {
1336
1406
  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
1407
  process.exit(1);
1338
1408
  }
1409
+ const needsConfirm = !args.dryRun && !args.yes && process.stdout.isTTY && !process.env.MIMI_SEED_TOKEN;
1410
+ if (needsConfirm) {
1411
+ const target = args.platform === "ios" ? "App Store \uC2EC\uC0AC \uC81C\uCD9C" : "Play Store production \uD2B8\uB799";
1412
+ log2("");
1413
+ log2(kleur6.yellow(`\u26A0 \uC2E4\uC81C \uBC30\uD3EC: ${args.platform} \xB7 versionCode ${versionCode} \u2192 ${target}`));
1414
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
1415
+ const answer = await new Promise(
1416
+ (resolve) => rl.question(kleur6.bold("\uACC4\uC18D \uC9C4\uD589\uD560\uAE4C\uC694? [y/N]: "), (a) => resolve(a.trim().toLowerCase()))
1417
+ );
1418
+ rl.close();
1419
+ if (answer !== "y" && answer !== "yes") {
1420
+ log2(kleur6.dim("\uCDE8\uC18C\uB428. (--yes \uB85C \uD655\uC778 \uC0DD\uB7B5 \uAC00\uB2A5)"));
1421
+ return;
1422
+ }
1423
+ }
1339
1424
  log2("");
1340
1425
  log2("\u{1F4E1} \uC11C\uBC84 \uBC30\uD3EC \uD30C\uC774\uD504\uB77C\uC778 \uC2DC\uC791...");
1341
1426
  log2("");
@@ -1357,17 +1442,17 @@ async function cmdDeploy(argv) {
1357
1442
 
1358
1443
  // src/mcp-restart.ts
1359
1444
  import { execSync as execSync2 } from "child_process";
1360
- import fs4 from "fs";
1361
- import os3 from "os";
1362
- import path4 from "path";
1445
+ import fs5 from "fs";
1446
+ import os4 from "os";
1447
+ import path5 from "path";
1363
1448
  import kleur7 from "kleur";
1364
1449
  function log3(msg) {
1365
1450
  process.stdout.write(msg + "\n");
1366
1451
  }
1367
1452
  function readClaudeJson() {
1368
- const p = path4.join(os3.homedir(), ".claude.json");
1453
+ const p = path5.join(os4.homedir(), ".claude.json");
1369
1454
  try {
1370
- return JSON.parse(fs4.readFileSync(p, "utf8"));
1455
+ return JSON.parse(fs5.readFileSync(p, "utf8"));
1371
1456
  } catch {
1372
1457
  return {};
1373
1458
  }
@@ -1383,7 +1468,7 @@ function findProcessMarker(cfg) {
1383
1468
  return meaningful.at(-1) ?? null;
1384
1469
  }
1385
1470
  function killByMarker(marker) {
1386
- const isWin = os3.platform() === "win32";
1471
+ const isWin = os4.platform() === "win32";
1387
1472
  if (isWin) {
1388
1473
  const escaped = marker.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
1389
1474
  let pids = [];
@@ -1453,6 +1538,63 @@ async function cmdRestart(args) {
1453
1538
  log3(kleur7.cyan(" \uC5F0\uACB0 \uD655\uC778: Claude Code\uC5D0\uC11C /mcp \uC2E4\uD589"));
1454
1539
  }
1455
1540
 
1541
+ // src/mcp-config.ts
1542
+ import fs6 from "fs/promises";
1543
+ import path6 from "path";
1544
+ import os5 from "os";
1545
+ import kleur8 from "kleur";
1546
+ var SERVER_NAME = "mimi-seed";
1547
+ function tomlString(value) {
1548
+ return JSON.stringify(value);
1549
+ }
1550
+ function codexBlock(cfg) {
1551
+ return [
1552
+ `[mcp_servers.${SERVER_NAME}]`,
1553
+ `url = ${tomlString(cfg.endpoint)}`,
1554
+ `enabled = true`,
1555
+ `http_headers = { Authorization = ${tomlString(`Bearer ${cfg.token}`)} }`,
1556
+ ""
1557
+ ].join("\n");
1558
+ }
1559
+ function replaceTomlBlock(input, tableName, block) {
1560
+ const header = `[${tableName}]`;
1561
+ const start = input.indexOf(header);
1562
+ if (start < 0) {
1563
+ const trimmed = input.trimEnd();
1564
+ return `${trimmed}${trimmed ? "\n\n" : ""}${block}`;
1565
+ }
1566
+ const next = input.slice(start + header.length).search(/\n\[[^\]]+\]/);
1567
+ const end = next < 0 ? input.length : start + header.length + next + 1;
1568
+ return `${input.slice(0, start)}${block}${input.slice(end).replace(/^\n+/, "\n")}`;
1569
+ }
1570
+ function printMcpSetup(cfg) {
1571
+ process.stdout.write(
1572
+ [
1573
+ kleur8.dim("Claude Code MCP \uB4F1\uB85D:"),
1574
+ kleur8.dim(` claude mcp add --transport http ${SERVER_NAME} ${cfg.endpoint} \\`),
1575
+ kleur8.dim(` --header "Authorization: Bearer ${cfg.prefix}..."`),
1576
+ "",
1577
+ kleur8.dim("Codex MCP \uB4F1\uB85D:"),
1578
+ kleur8.dim(" mimi-seed mcp codex --write"),
1579
+ kleur8.dim(" # \uB610\uB294 \uC218\uB3D9\uC73C\uB85C ~/.codex/config.toml \uC5D0 [mcp_servers.mimi-seed] \uCD94\uAC00")
1580
+ ].join("\n") + "\n"
1581
+ );
1582
+ }
1583
+ async function writeCodexMcpConfig(cfg) {
1584
+ const configDir = path6.join(os5.homedir(), ".codex");
1585
+ const configPath = path6.join(configDir, "config.toml");
1586
+ await fs6.mkdir(configDir, { recursive: true });
1587
+ let current = "";
1588
+ try {
1589
+ current = await fs6.readFile(configPath, "utf8");
1590
+ } catch {
1591
+ current = "";
1592
+ }
1593
+ const next = replaceTomlBlock(current, `mcp_servers.${SERVER_NAME}`, codexBlock(cfg));
1594
+ await fs6.writeFile(configPath, next);
1595
+ return configPath;
1596
+ }
1597
+
1456
1598
  // src/index.ts
1457
1599
  var DEFAULT_WEB_BASE = process.env.MIMI_SEED_WEB_BASE ?? "https://mimi-seed.pryzm.gg";
1458
1600
  var DEFAULT_MCP_ENDPOINT = `${DEFAULT_WEB_BASE}/api/mcp`;
@@ -1461,54 +1603,54 @@ function log4(msg) {
1461
1603
  }
1462
1604
  async function cmdInit() {
1463
1605
  const cwd = process.cwd();
1464
- log4(kleur8.bold("Mimi Seed CLI \u2014 init"));
1465
- log4(kleur8.dim(cwd));
1606
+ log4(kleur9.bold("Mimi Seed CLI \u2014 init"));
1607
+ log4(kleur9.dim(cwd));
1466
1608
  log4("");
1467
1609
  if (!await hasAnyProjectSignal(cwd)) {
1468
- log4(kleur8.yellow("\u26A0 package.json / app.json / android / ios \uB97C \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uADF8\uB798\uB3C4 \uC9C4\uD589\uD569\uB2C8\uB2E4."));
1610
+ log4(kleur9.yellow("\u26A0 package.json / app.json / android / ios \uB97C \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uADF8\uB798\uB3C4 \uC9C4\uD589\uD569\uB2C8\uB2E4."));
1469
1611
  }
1470
1612
  log4("\u{1F50D} \uC571 \uAC10\uC9C0 \uC911...");
1471
1613
  const hints = await detectHints(cwd);
1472
1614
  if (hints.length === 0) {
1473
- log4(kleur8.yellow("\uAC10\uC9C0\uB41C \uC571 \uC5C6\uC74C. \uC6F9\uC5D0\uC11C \uC218\uB3D9 \uB4F1\uB85D \uAC00\uB2A5."));
1615
+ log4(kleur9.yellow("\uAC10\uC9C0\uB41C \uC571 \uC5C6\uC74C. \uC6F9\uC5D0\uC11C \uC218\uB3D9 \uB4F1\uB85D \uAC00\uB2A5."));
1474
1616
  } else {
1475
1617
  for (const h of hints) {
1476
1618
  const tag = [h.packageName && `android:${h.packageName}`, h.bundleId && `ios:${h.bundleId}`].filter(Boolean).join(" ");
1477
- log4(` \u2022 ${h.name ?? "(\uC774\uB984 \uBBF8\uC0C1)"} ${kleur8.dim(tag)}`);
1619
+ log4(` \u2022 ${h.name ?? "(\uC774\uB984 \uBBF8\uC0C1)"} ${kleur9.dim(tag)}`);
1478
1620
  }
1479
1621
  }
1480
1622
  log4("");
1481
1623
  if (process.env.MIMI_SEED_TOKEN) {
1482
1624
  const cfg2 = await getEffectiveConfig();
1483
1625
  if (cfg2 && hints.length > 0) {
1484
- log4(kleur8.dim("CI \uBAA8\uB4DC: MIMI_SEED_TOKEN \uC0AC\uC6A9"));
1626
+ log4(kleur9.dim("CI \uBAA8\uB4DC: MIMI_SEED_TOKEN \uC0AC\uC6A9"));
1485
1627
  const payload = hints.map((h) => ({ name: h.name, packageName: h.packageName, bundleId: h.bundleId }));
1486
1628
  const result = await mcpCall(cfg2.endpoint, cfg2.token, "sync_apps", { hints: payload });
1487
1629
  if (result.isError) {
1488
- log4(kleur8.red("\uB4F1\uB85D \uC2E4\uD328: " + result.text));
1630
+ log4(kleur9.red("\uB4F1\uB85D \uC2E4\uD328: " + result.text));
1489
1631
  } else {
1490
1632
  for (const line of result.text.split("\n")) log4(" " + line);
1491
1633
  }
1492
1634
  }
1493
- log4(kleur8.bold("\u2713 \uC644\uB8CC (CI \uBAA8\uB4DC)"));
1635
+ log4(kleur9.bold("\u2713 \uC644\uB8CC (CI \uBAA8\uB4DC)"));
1494
1636
  return;
1495
1637
  }
1496
1638
  log4("\u{1F510} \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uB85C\uADF8\uC778 \uB300\uAE30...");
1497
- const hostName = os4.hostname().slice(0, 32);
1639
+ const hostName = os6.hostname().slice(0, 32);
1498
1640
  const name = `cli-${hostName}`;
1499
1641
  const { port, promise } = await awaitHandshake(5 * 60 * 1e3);
1500
1642
  const callback = `http://127.0.0.1:${port}/cb`;
1501
1643
  const connectUrl = `${DEFAULT_WEB_BASE}/cli/connect?callback=${encodeURIComponent(callback)}&name=${encodeURIComponent(name)}`;
1502
- log4(kleur8.dim(` ${connectUrl}`));
1644
+ log4(kleur9.dim(` ${connectUrl}`));
1503
1645
  await open(connectUrl);
1504
1646
  let handshake;
1505
1647
  try {
1506
1648
  handshake = await promise;
1507
1649
  } catch (e) {
1508
- log4(kleur8.red("\uC5F0\uACB0 \uC2E4\uD328: " + e.message));
1650
+ log4(kleur9.red("\uC5F0\uACB0 \uC2E4\uD328: " + e.message));
1509
1651
  process.exit(1);
1510
1652
  }
1511
- log4(kleur8.green("\u2713 \uD1A0\uD070 \uC218\uC2E0"));
1653
+ log4(kleur9.green("\u2713 \uD1A0\uD070 \uC218\uC2E0"));
1512
1654
  const cfg = {
1513
1655
  token: handshake.token,
1514
1656
  prefix: handshake.prefix,
@@ -1517,124 +1659,160 @@ async function cmdInit() {
1517
1659
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
1518
1660
  };
1519
1661
  await writeConfig(cfg);
1520
- log4(kleur8.dim(` \uC800\uC7A5\uB428: ${CONFIG_LOCATION}`));
1662
+ log4(kleur9.dim(` \uC800\uC7A5\uB428: ${CONFIG_LOCATION}`));
1521
1663
  log4("");
1522
1664
  if (hints.length > 0) {
1523
1665
  log4("\u{1F504} \uC571 \uB4F1\uB85D \uC911...");
1524
1666
  const payload = hints.map((h) => ({ name: h.name, packageName: h.packageName, bundleId: h.bundleId }));
1525
1667
  const result = await mcpCall(cfg.endpoint, cfg.token, "sync_apps", { hints: payload });
1526
1668
  if (result.isError) {
1527
- log4(kleur8.red("\uB4F1\uB85D \uC2E4\uD328: " + result.text));
1669
+ log4(kleur9.red("\uB4F1\uB85D \uC2E4\uD328: " + result.text));
1528
1670
  } else {
1529
1671
  for (const line of result.text.split("\n")) log4(" " + line);
1530
1672
  }
1531
1673
  log4("");
1532
1674
  }
1533
- const claudeDir = path5.join(cwd, ".claude");
1534
- const agentMdPath = path5.join(claudeDir, "mimi-seed.md");
1535
- if (!fs5.existsSync(agentMdPath)) {
1536
- fs5.mkdirSync(claudeDir, { recursive: true });
1537
- const appLines = hints.flatMap((h) => {
1538
- const parts = [
1539
- h.name && ` name: ${h.name}`,
1540
- h.packageName && ` packageName: ${h.packageName}`,
1541
- h.bundleId && ` bundleId: ${h.bundleId}`
1542
- ].filter(Boolean);
1543
- return parts;
1544
- });
1545
- const agentMd = [
1546
- "# Mimi Seed Agent",
1547
- "",
1548
- "Mimi Seed MCP\uAC00 \uC774 \uD504\uB85C\uC81D\uD2B8\uC5D0 \uC5F0\uACB0\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4.",
1549
- "Google Play \xB7 App Store \xB7 Firebase \xB7 AdMob\uC744 \uB3C4\uAD6C\uB85C \uC9C1\uC811 \uC81C\uC5B4\uD569\uB2C8\uB2E4.",
1550
- "",
1551
- "## \uCD9C\uC2DC \uC694\uCCAD \uCC98\uB9AC \uC21C\uC11C",
1552
- "",
1553
- "1. \uD56D\uC0C1 `playstore_check_submission_risks` / `appstore_check_submission_risks` \uB85C \uBE14\uB85C\uCEE4 \uBA3C\uC800 \uD655\uC778",
1554
- "2. \uB9B4\uB9AC\uC988 \uB178\uD2B8: `generate_release_notes_from_commits` \u2192 \uC0AC\uC6A9\uC790 \uD655\uC778 \uD6C4 \uC801\uC6A9",
1555
- "3. \uC2A4\uD1A0\uC5B4 **\uC4F0\uAE30** \uC791\uC5C5(submit, apply, reply)\uC740 \uBC18\uB4DC\uC2DC \uC0AC\uC6A9\uC790 \uBA85\uC2DC \uB3D9\uC758 \uD6C4 \uC2E4\uD589",
1556
- "4. \uC644\uB8CC \uD6C4 \uACB0\uACFC \uC694\uC57D \uC81C\uACF5",
1557
- "",
1558
- "## \uC571 \uC815\uBCF4",
1559
- ...appLines.length > 0 ? appLines : [" (mimi-seed status \uB85C \uD655\uC778)"],
1560
- "",
1561
- "## \uC2AC\uB798\uC2DC \uCEE4\uB9E8\uB4DC",
1562
- "",
1563
- "- `/mimi-seed:deploy` \u2014 \uC804\uCCB4 \uCD9C\uC2DC \uD30C\uC774\uD504\uB77C\uC778",
1564
- "- `/mimi-seed:health` \u2014 \uC5F0\uACB0 \uC0C1\uD0DC \uBE60\uB978 \uD655\uC778",
1565
- "- `/mimi-seed:review-inbox` \u2014 \uBBF8\uB2F5\uBCC0 \uB9AC\uBDF0 \uB2F5\uBCC0"
1566
- ].join("\n");
1567
- fs5.writeFileSync(agentMdPath, agentMd, { mode: 420 });
1568
- log4(kleur8.dim(` \uC5D0\uC774\uC804\uD2B8 \uC124\uC815: .claude/mimi-seed.md`));
1569
- }
1570
- log4(kleur8.bold("\u2713 \uC900\uBE44 \uC644\uB8CC."));
1675
+ const appLines = hints.flatMap((h) => {
1676
+ const parts = [
1677
+ h.name && ` name: ${h.name}`,
1678
+ h.packageName && ` packageName: ${h.packageName}`,
1679
+ h.bundleId && ` bundleId: ${h.bundleId}`
1680
+ ].filter(Boolean);
1681
+ return parts;
1682
+ });
1683
+ const agentMd = [
1684
+ "# Mimi Seed Agent",
1685
+ "",
1686
+ "Mimi Seed MCP\uAC00 \uC774 \uD504\uB85C\uC81D\uD2B8\uC5D0 \uC5F0\uACB0\uB418\uC5B4 \uC788\uC2B5\uB2C8\uB2E4.",
1687
+ "Google Play \xB7 App Store \xB7 Firebase \xB7 AdMob\uC744 \uB3C4\uAD6C\uB85C \uC9C1\uC811 \uC81C\uC5B4\uD569\uB2C8\uB2E4.",
1688
+ "",
1689
+ "## \uCD9C\uC2DC \uC694\uCCAD \uCC98\uB9AC \uC21C\uC11C",
1690
+ "",
1691
+ "1. \uD56D\uC0C1 `playstore_check_submission_risks` / `appstore_check_submission_risks` \uB85C \uBE14\uB85C\uCEE4 \uBA3C\uC800 \uD655\uC778",
1692
+ "2. \uB9B4\uB9AC\uC988 \uB178\uD2B8: `generate_release_notes_from_commits` \u2192 \uC0AC\uC6A9\uC790 \uD655\uC778 \uD6C4 \uC801\uC6A9",
1693
+ "3. \uC2A4\uD1A0\uC5B4 **\uC4F0\uAE30** \uC791\uC5C5(submit, apply, reply)\uC740 \uBC18\uB4DC\uC2DC \uC0AC\uC6A9\uC790 \uBA85\uC2DC \uB3D9\uC758 \uD6C4 \uC2E4\uD589",
1694
+ "4. \uC644\uB8CC \uD6C4 \uACB0\uACFC \uC694\uC57D \uC81C\uACF5",
1695
+ "",
1696
+ "## \uC571 \uC815\uBCF4",
1697
+ ...appLines.length > 0 ? appLines : [" (mimi-seed status \uB85C \uD655\uC778)"],
1698
+ "",
1699
+ "## \uC2AC\uB798\uC2DC \uCEE4\uB9E8\uB4DC",
1700
+ "",
1701
+ "- `/mimi-seed:deploy` \u2014 \uC804\uCCB4 \uCD9C\uC2DC \uD30C\uC774\uD504\uB77C\uC778",
1702
+ "- `/mimi-seed:health` \u2014 \uC5F0\uACB0 \uC0C1\uD0DC \uBE60\uB978 \uD655\uC778",
1703
+ "- `/mimi-seed:review-inbox` \u2014 \uBBF8\uB2F5\uBCC0 \uB9AC\uBDF0 \uB2F5\uBCC0"
1704
+ ].join("\n");
1705
+ const claudeDir = path7.join(cwd, ".claude");
1706
+ const claudeAgentPath = path7.join(claudeDir, "mimi-seed.md");
1707
+ if (!fs7.existsSync(claudeAgentPath)) {
1708
+ fs7.mkdirSync(claudeDir, { recursive: true });
1709
+ fs7.writeFileSync(claudeAgentPath, agentMd, { mode: 420 });
1710
+ log4(kleur9.dim(` Claude \uC5D0\uC774\uC804\uD2B8 \uC124\uC815: .claude/mimi-seed.md`));
1711
+ }
1712
+ const codexAgentPath = path7.join(cwd, "AGENTS.md");
1713
+ if (!fs7.existsSync(codexAgentPath)) {
1714
+ fs7.writeFileSync(codexAgentPath, agentMd, { mode: 420 });
1715
+ log4(kleur9.dim(` Codex \uC5D0\uC774\uC804\uD2B8 \uC124\uC815: AGENTS.md`));
1716
+ }
1717
+ log4(kleur9.bold("\u2713 \uC900\uBE44 \uC644\uB8CC."));
1571
1718
  log4("");
1572
- log4("Claude Code\uC5D0\uC11C \uC774\uB807\uAC8C \uBB3C\uC5B4\uBCF4\uC138\uC694:");
1573
- log4(kleur8.cyan(' "\uB0B4 \uC571 \uCD9C\uC2DC \uC900\uBE44\uB410\uC5B4?"'));
1574
- log4(kleur8.cyan(' "\uB9B4\uB9AC\uC988 \uB178\uD2B8 \uC368\uC918"'));
1575
- log4(kleur8.cyan(' "\uB4F1\uB85D\uB41C \uC571 \uBAA9\uB85D \uBCF4\uC5EC\uC918"'));
1719
+ log4("Claude Code \uB610\uB294 Codex\uC5D0\uC11C \uC774\uB807\uAC8C \uBB3C\uC5B4\uBCF4\uC138\uC694:");
1720
+ log4(kleur9.cyan(' "\uB0B4 \uC571 \uCD9C\uC2DC \uC900\uBE44\uB410\uC5B4?"'));
1721
+ log4(kleur9.cyan(' "\uB9B4\uB9AC\uC988 \uB178\uD2B8 \uC368\uC918"'));
1722
+ log4(kleur9.cyan(' "\uB4F1\uB85D\uB41C \uC571 \uBAA9\uB85D \uBCF4\uC5EC\uC918"'));
1576
1723
  log4("");
1577
- log4(`\uB300\uC2DC\uBCF4\uB4DC: ${kleur8.underline(DEFAULT_WEB_BASE + "/apps")}`);
1724
+ log4(`\uB300\uC2DC\uBCF4\uB4DC: ${kleur9.underline(DEFAULT_WEB_BASE + "/apps")}`);
1578
1725
  log4("");
1579
- log4(
1580
- kleur8.dim(
1581
- `Claude Code MCP \uB4F1\uB85D:
1582
- claude mcp add --transport http mimi-seed ${DEFAULT_MCP_ENDPOINT} \\
1583
- --header "Authorization: Bearer ${cfg.prefix}..."`
1584
- )
1585
- );
1726
+ printMcpSetup(cfg);
1586
1727
  }
1587
1728
  async function cmdStatus() {
1588
1729
  const cfg = await getEffectiveConfig();
1589
1730
  if (!cfg) {
1590
- log4(kleur8.yellow("\uC5F0\uACB0\uB41C Mimi Seed \uACC4\uC815\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. `mimi-seed init` \uC2E4\uD589."));
1731
+ log4(kleur9.yellow("\uC5F0\uACB0\uB41C Mimi Seed \uACC4\uC815\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. `mimi-seed init` \uC2E4\uD589."));
1591
1732
  process.exit(1);
1592
1733
  }
1593
- log4(kleur8.bold("Mimi Seed \uC5F0\uACB0 \uC0C1\uD0DC"));
1734
+ log4(kleur9.bold("Mimi Seed \uC5F0\uACB0 \uC0C1\uD0DC"));
1594
1735
  log4(` \uD1A0\uD070: ${cfg.prefix}\u2026 (${cfg.createdAt.slice(0, 10)})`);
1595
1736
  log4(` \uC5D4\uB4DC\uD3EC\uC778\uD2B8: ${cfg.endpoint}`);
1596
1737
  log4("");
1597
1738
  log4("\u{1F4CB} \uC571 \uBAA9\uB85D:");
1598
1739
  const r = await mcpCall(cfg.endpoint, cfg.token, "list_apps", {});
1599
1740
  if (r.isError) {
1600
- log4(kleur8.red("\uC870\uD68C \uC2E4\uD328: " + r.text));
1741
+ log4(kleur9.red("\uC870\uD68C \uC2E4\uD328: " + r.text));
1601
1742
  process.exit(1);
1602
1743
  }
1603
1744
  for (const line of r.text.split("\n")) log4(" " + line);
1604
1745
  }
1605
1746
  async function cmdLogout() {
1606
1747
  await deleteConfig();
1607
- log4(kleur8.green("\u2713 \uB85C\uCEEC \uC124\uC815 \uC0AD\uC81C \uC644\uB8CC."));
1608
- log4(kleur8.dim("\uC6F9\uC5D0\uC11C \uD1A0\uD070 \uD574\uC9C0: /workspace/api-tokens"));
1748
+ log4(kleur9.green("\u2713 \uB85C\uCEEC \uC124\uC815 \uC0AD\uC81C \uC644\uB8CC."));
1749
+ log4(kleur9.dim("\uC6F9\uC5D0\uC11C \uD1A0\uD070 \uD574\uC9C0: /workspace/api-tokens"));
1609
1750
  }
1610
- function printHelp() {
1611
- log4(`${kleur8.bold("mimi-seed")} \u2014 Claude Code\uC5D0\uC11C \uC571 \uCD9C\uC2DC \uC6B4\uC601
1751
+ async function cmdMcp(args) {
1752
+ const target = args[0] ?? "help";
1753
+ const cfg = await getEffectiveConfig();
1754
+ if (!cfg) {
1755
+ log4(kleur9.yellow("\uC5F0\uACB0\uB41C Mimi Seed \uACC4\uC815\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. `mimi-seed init` \uC2E4\uD589."));
1756
+ process.exit(1);
1757
+ }
1758
+ if (target === "codex") {
1759
+ if (args.includes("--write")) {
1760
+ const configPath = await writeCodexMcpConfig(cfg);
1761
+ log4(kleur9.green("\u2713 Codex MCP \uC124\uC815 \uC644\uB8CC"));
1762
+ log4(kleur9.dim(` ${configPath}`));
1763
+ 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)."));
1764
+ log4("");
1765
+ log4("Codex\uB97C \uC0C8\uB85C \uC5F4\uACE0 `/mcp` \uB610\uB294 `codex mcp list`\uB85C \uD655\uC778\uD558\uC138\uC694.");
1766
+ return;
1767
+ }
1768
+ log4(kleur9.bold("Codex MCP \uB4F1\uB85D"));
1769
+ log4("");
1770
+ log4("\uC790\uB3D9 \uB4F1\uB85D:");
1771
+ log4(kleur9.cyan(" mimi-seed mcp codex --write"));
1772
+ log4("");
1773
+ log4("\uC218\uB3D9 \uB4F1\uB85D \uC608\uC2DC (~/.codex/config.toml):");
1774
+ log4(`[mcp_servers.mimi-seed]
1775
+ url = "${cfg.endpoint}"
1776
+ enabled = true
1777
+ http_headers = { Authorization = "Bearer ${cfg.prefix}..." }`);
1778
+ return;
1779
+ }
1780
+ if (target === "claude") {
1781
+ log4(kleur9.bold("Claude Code MCP \uB4F1\uB85D"));
1782
+ log4(kleur9.cyan(` claude mcp add --transport http mimi-seed ${cfg.endpoint} \\`));
1783
+ log4(kleur9.cyan(` --header "Authorization: Bearer ${cfg.prefix}..."`));
1784
+ return;
1785
+ }
1786
+ printMcpSetup(cfg);
1787
+ }
1788
+ var CMD_USAGE = {
1789
+ init: `${kleur9.bold("mimi-seed init")} \u2014 \uD604\uC7AC \uD504\uB85C\uC81D\uD2B8\uB97C Mimi Seed\uC5D0 \uC5F0\uACB0
1790
+
1791
+ \uC571 \uC790\uB3D9 \uAC10\uC9C0(Expo/Gradle/Info.plist/pbxproj) \u2192 \uBE0C\uB77C\uC6B0\uC800 PAT \uBC1C\uAE09 \u2192 \uC571 \uB4F1\uB85D
1792
+ + .claude/mimi-seed.md, AGENTS.md \uC0DD\uC131. \uC635\uC158 \uC5C6\uC74C.`,
1793
+ status: `${kleur9.bold("mimi-seed status")} \u2014 \uC5F0\uACB0 \uC0C1\uD0DC + \uB4F1\uB85D \uC571 \uBAA9\uB85D. \uC635\uC158 \uC5C6\uC74C.`,
1794
+ 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.`,
1795
+ logout: `${kleur9.bold("mimi-seed logout")} \u2014 \uB85C\uCEEC \uC124\uC815(config.json) \uC0AD\uC81C. \uC635\uC158 \uC5C6\uC74C.`,
1796
+ restart: `${kleur9.bold("mimi-seed restart")} \u2014 MCP \uC11C\uBC84 \uD504\uB85C\uC138\uC2A4 \uC7AC\uC2DC\uC791 (\uAE30\uBCF8: mimi-seed)
1612
1797
 
1613
- ${kleur8.bold("\uBA85\uB839\uC5B4:")}
1614
- ${kleur8.cyan("mimi-seed init")} \uD604\uC7AC \uD504\uB85C\uC81D\uD2B8\uB97C Mimi Seed\uC5D0 \uC5F0\uACB0
1615
- ${kleur8.cyan("mimi-seed status")} \uC5F0\uACB0 \uC0C1\uD0DC + \uB4F1\uB85D \uC571 \uBAA9\uB85D
1616
- ${kleur8.cyan("mimi-seed auth")} Google OAuth \uC778\uC99D (Firebase/AdMob/Play). 'mimi-seed auth --help'
1617
- ${kleur8.cyan("mimi-seed doctor")} \uD658\uACBD \uC9C4\uB2E8 (\uD1A0\uD070\xB7Git\xB7\uD504\uB85C\uC81D\uD2B8\xB7CI \uCCB4\uD06C)
1618
- ${kleur8.cyan("mimi-seed check")} \uCD9C\uC2DC \uC804 Readiness \uC810\uAC80
1619
- ${kleur8.cyan("mimi-seed notes")} \uB9B4\uB9AC\uC988 \uB178\uD2B8 \uC0DD\uC131 (git log \u2192 AI \u2192 \uB9C8\uCF13 \uC801\uC6A9)
1620
- ${kleur8.cyan("mimi-seed review")} \uB9AC\uBDF0 \uB2F5\uBCC0 AI \uCD08\uC548 \uC0DD\uC131 \uBC0F Play Store \uAC8C\uC2DC
1621
- ${kleur8.cyan("mimi-seed deploy")} \uC571 \uC790\uB3D9 \uBC30\uD3EC (Jenkins \u2192 Play Store/App Store)
1622
- ${kleur8.cyan("mimi-seed restart")} MCP \uC11C\uBC84 \uD504\uB85C\uC138\uC2A4 \uC7AC\uC2DC\uC791 (\uAE30\uBCF8: mimi-seed)
1623
- ${kleur8.cyan("mimi-seed logout")} \uB85C\uCEEC \uC124\uC815 \uC0AD\uC81C
1798
+ mimi-seed restart [server-name]`,
1799
+ notes: `${kleur9.bold("mimi-seed notes")} \u2014 \uB9B4\uB9AC\uC988 \uB178\uD2B8 \uC0DD\uC131 (git log \u2192 AI \u2192 \uB9C8\uCF13 \uC801\uC6A9)
1624
1800
 
1625
- ${kleur8.bold("mimi-seed notes \uC635\uC158:")}
1801
+ \uC635\uC158:
1626
1802
  --from <ref> \uC2DC\uC791 \uCEE4\uBC0B/\uD0DC\uADF8 (\uAE30\uBCF8: \uCD5C\uC2E0 \uD0DC\uADF8)
1627
1803
  --to <ref> \uB05D \uCEE4\uBC0B (\uAE30\uBCF8: HEAD)
1628
1804
  --locale ko,en-US \uB300\uC0C1 \uB85C\uCF00\uC77C (\uC27C\uD45C \uAD6C\uBD84)
1629
1805
  --apply \uC0DD\uC131 \uD6C4 \uC2A4\uD1A0\uC5B4\uC5D0 \uBC14\uB85C \uC801\uC6A9
1630
1806
  --no-interactive CI \uBAA8\uB4DC (\uD504\uB86C\uD504\uD2B8 \uC5C6\uC74C)
1631
- --limit <n> \uCD5C\uB300 \uCEE4\uBC0B \uC218 (\uAE30\uBCF8: 30)
1807
+ --limit <n> \uCD5C\uB300 \uCEE4\uBC0B \uC218 (\uAE30\uBCF8: 30)`,
1808
+ check: `${kleur9.bold("mimi-seed check")} \u2014 \uCD9C\uC2DC \uC804 Readiness \uC810\uAC80
1632
1809
 
1633
- ${kleur8.bold("mimi-seed check \uC635\uC158:")}
1810
+ \uC635\uC158:
1634
1811
  --app <id> \uC571 ID \uC9C0\uC815
1635
- --fail-on-blocker \uBE14\uB85C\uCEE4 \uC788\uC73C\uBA74 exit 1 (CI\uC6A9)
1812
+ --fail-on-blocker \uBE14\uB85C\uCEE4 \uC788\uC73C\uBA74 exit 1 (CI\uC6A9)`,
1813
+ review: `${kleur9.bold("mimi-seed review")} \u2014 \uB9AC\uBDF0 \uB2F5\uBCC0 AI \uCD08\uC548 \uC0DD\uC131 \uBC0F Play Store \uAC8C\uC2DC
1636
1814
 
1637
- ${kleur8.bold("mimi-seed review \uC635\uC158:")}
1815
+ \uC635\uC158:
1638
1816
  --text <\uB0B4\uC6A9> \uB9AC\uBDF0 \uC6D0\uBB38 (\uBBF8\uC785\uB825 \uC2DC \uB300\uD654\uD615 \uD504\uB86C\uD504\uD2B8)
1639
1817
  --rating <1-5> \uBCC4\uC810
1640
1818
  --tone <tone> friendly / professional / empathetic / brief (\uAE30\uBCF8: friendly)
@@ -1643,9 +1821,10 @@ ${kleur8.bold("mimi-seed review \uC635\uC158:")}
1643
1821
  --apply \uB2F5\uBCC0\uC744 Play Store\uC5D0 \uAC8C\uC2DC
1644
1822
  --review-id <id> \uB9AC\uBDF0 ID (--apply \uC2DC \uD544\uC694)
1645
1823
  --package-name <p> \uD328\uD0A4\uC9C0\uBA85 (--apply \uC2DC \uD544\uC694)
1646
- --no-interactive CI \uBAA8\uB4DC
1824
+ --no-interactive CI \uBAA8\uB4DC`,
1825
+ deploy: `${kleur9.bold("mimi-seed deploy")} \u2014 \uC571 \uC790\uB3D9 \uBC30\uD3EC (CI \uBE4C\uB4DC \u2192 Play Store/App Store)
1647
1826
 
1648
- ${kleur8.bold("mimi-seed deploy \uC635\uC158:")}
1827
+ \uC635\uC158:
1649
1828
  --platform android|ios \uBC30\uD3EC \uD50C\uB7AB\uD3FC (\uAE30\uBCF8: android)
1650
1829
  --app <id> \uC571 ID \uC9C0\uC815
1651
1830
  --version-code <n> \uBE4C\uB4DC \uBC88\uD638 \uC9C1\uC811 \uC9C0\uC815 (--skip-build \uC640 \uD568\uAED8)
@@ -1653,15 +1832,45 @@ ${kleur8.bold("mimi-seed deploy \uC635\uC158:")}
1653
1832
  --to <ref> \uCEE4\uBC0B \uBC94\uC704 \uB05D (\uAE30\uBCF8: HEAD)
1654
1833
  --language <\uCF54\uB4DC> \uB9B4\uB9AC\uC988 \uB178\uD2B8 \uC5B8\uC5B4 (\uAE30\uBCF8: ko-KR)
1655
1834
  --dry-run \uC2E4\uC81C \uBC30\uD3EC \uC5C6\uC774 \uD30C\uC774\uD504\uB77C\uC778 \uD14C\uC2A4\uD2B8
1835
+ --yes, -y \uBC30\uD3EC \uD655\uC778 \uD504\uB86C\uD504\uD2B8 \uC0DD\uB7B5 (\uC2A4\uD06C\uB9BD\uD2B8/\uC790\uB3D9\uD654\uC6A9)
1656
1836
  --skip-build CI \uBE4C\uB4DC \uAC74\uB108\uB700 (--version-code \uD544\uC218)
1657
1837
  --ci jenkins|github|gitlab CI \uAC15\uC81C \uC120\uD0DD (\uAE30\uBCF8: auto)
1658
1838
  --workflow <file> GitHub workflow \uD30C\uC77C (\uC608: deploy.yml)
1659
1839
  --ref <branch|tag> GitHub/GitLab \uBE0C\uB79C\uCE58/\uD0DC\uADF8 (\uAE30\uBCF8: main)
1660
- setup-jenkins Jenkins \uC124\uC815 \uB300\uD654\uD615 \uB4F1\uB85D
1661
- setup-github GitHub Actions \uC124\uC815 \uB300\uD654\uD615 \uB4F1\uB85D
1662
- setup-gitlab GitLab CI \uC124\uC815 \uB300\uD654\uD615 \uB4F1\uB85D
1840
+ setup-jenkins / setup-github / setup-gitlab CI \uC124\uC815 \uB300\uD654\uD615 \uB4F1\uB85D`,
1841
+ mcp: `${kleur9.bold("mimi-seed mcp")} \u2014 Claude/Codex MCP \uC5F0\uACB0
1842
+
1843
+ \uC11C\uBE0C\uBA85\uB839:
1844
+ mimi-seed mcp \uD604\uC7AC \uC124\uC815 + \uB4F1\uB85D \uC548\uB0B4
1845
+ mimi-seed mcp claude Claude Code \uB4F1\uB85D \uBA85\uB839 \uCD9C\uB825
1846
+ mimi-seed mcp codex Codex \uB4F1\uB85D \uC548\uB0B4
1847
+ mimi-seed mcp codex --write ~/.codex/config.toml\uC5D0 \uC9C1\uC811 \uAE30\uB85D (\u26A0 \uC2E4\uC81C \uD1A0\uD070 \uD3C9\uBB38 \uC800\uC7A5)`
1848
+ };
1849
+ function printCommandHelp(cmd) {
1850
+ const usage = CMD_USAGE[cmd];
1851
+ if (!usage) return false;
1852
+ log4(usage);
1853
+ return true;
1854
+ }
1855
+ function printHelp() {
1856
+ log4(`${kleur9.bold("mimi-seed")} \u2014 Claude Code/Codex\uC5D0\uC11C \uC571 \uCD9C\uC2DC \uC6B4\uC601
1857
+
1858
+ ${kleur9.bold("\uBA85\uB839\uC5B4:")}
1859
+ ${kleur9.cyan("mimi-seed init")} \uD604\uC7AC \uD504\uB85C\uC81D\uD2B8\uB97C Mimi Seed\uC5D0 \uC5F0\uACB0
1860
+ ${kleur9.cyan("mimi-seed status")} \uC5F0\uACB0 \uC0C1\uD0DC + \uB4F1\uB85D \uC571 \uBAA9\uB85D
1861
+ ${kleur9.cyan("mimi-seed auth")} \uB85C\uCEEC \uC778\uC99D (Google OAuth / App Store / Play / BigQuery)
1862
+ ${kleur9.cyan("mimi-seed doctor")} \uD658\uACBD \uC9C4\uB2E8 (\uD1A0\uD070\xB7Git\xB7\uD504\uB85C\uC81D\uD2B8\xB7CI \uCCB4\uD06C)
1863
+ ${kleur9.cyan("mimi-seed check")} \uCD9C\uC2DC \uC804 Readiness \uC810\uAC80
1864
+ ${kleur9.cyan("mimi-seed notes")} \uB9B4\uB9AC\uC988 \uB178\uD2B8 \uC0DD\uC131 (git log \u2192 AI \u2192 \uB9C8\uCF13 \uC801\uC6A9)
1865
+ ${kleur9.cyan("mimi-seed review")} \uB9AC\uBDF0 \uB2F5\uBCC0 AI \uCD08\uC548 \uC0DD\uC131 \uBC0F Play Store \uAC8C\uC2DC
1866
+ ${kleur9.cyan("mimi-seed deploy")} \uC571 \uC790\uB3D9 \uBC30\uD3EC (CI \u2192 Play Store/App Store)
1867
+ ${kleur9.cyan("mimi-seed mcp")} Claude/Codex MCP \uC5F0\uACB0 \uC548\uB0B4 \uBC0F Codex \uC124\uC815 \uC4F0\uAE30
1868
+ ${kleur9.cyan("mimi-seed restart")} MCP \uC11C\uBC84 \uD504\uB85C\uC138\uC2A4 \uC7AC\uC2DC\uC791 (\uAE30\uBCF8: mimi-seed)
1869
+ ${kleur9.cyan("mimi-seed logout")} \uB85C\uCEEC \uC124\uC815 \uC0AD\uC81C
1870
+
1871
+ ${kleur9.dim("\uAC01 \uBA85\uB839 \uC0C1\uC138 \uC635\uC158:")} ${kleur9.cyan("mimi-seed <command> --help")}
1663
1872
 
1664
- ${kleur8.bold("\uD658\uACBD\uBCC0\uC218:")}
1873
+ ${kleur9.bold("\uD658\uACBD\uBCC0\uC218:")}
1665
1874
  MIMI_SEED_TOKEN PAT \uD1A0\uD070 (CI/CD \uBB34\uC778\uC99D \uBAA8\uB4DC)
1666
1875
  MIMI_SEED_WEB_BASE \uC11C\uBC84 \uC8FC\uC18C (\uAE30\uBCF8: https://mimi-seed.pryzm.gg)
1667
1876
  ANTHROPIC_API_KEY AI \uB178\uD2B8 \uC0DD\uC131 \uD65C\uC131\uD654 (\uC120\uD0DD)
@@ -1670,6 +1879,9 @@ ${kleur8.bold("\uD658\uACBD\uBCC0\uC218:")}
1670
1879
  async function main() {
1671
1880
  const cmd = process.argv[2];
1672
1881
  const restArgs = process.argv.slice(3);
1882
+ if (cmd && cmd !== "auth" && (restArgs.includes("--help") || restArgs.includes("-h"))) {
1883
+ if (printCommandHelp(cmd)) return;
1884
+ }
1673
1885
  try {
1674
1886
  switch (cmd) {
1675
1887
  case "init":
@@ -1696,6 +1908,9 @@ async function main() {
1696
1908
  case "deploy":
1697
1909
  await cmdDeploy(restArgs);
1698
1910
  break;
1911
+ case "mcp":
1912
+ await cmdMcp(restArgs);
1913
+ break;
1699
1914
  case "restart":
1700
1915
  await cmdRestart(restArgs);
1701
1916
  break;
@@ -1708,12 +1923,12 @@ async function main() {
1708
1923
  printHelp();
1709
1924
  break;
1710
1925
  default:
1711
- log4(kleur8.red(`\uC54C \uC218 \uC5C6\uB294 \uBA85\uB839: ${cmd}`));
1926
+ log4(kleur9.red(`\uC54C \uC218 \uC5C6\uB294 \uBA85\uB839: ${cmd}`));
1712
1927
  printHelp();
1713
1928
  process.exit(1);
1714
1929
  }
1715
1930
  } catch (e) {
1716
- log4(kleur8.red(`\uC624\uB958: ${e.message}`));
1931
+ log4(kleur9.red(`\uC624\uB958: ${e.message}`));
1717
1932
  if (process.env.DEBUG) log4(e.stack ?? "");
1718
1933
  process.exit(1);
1719
1934
  }