mimi-seed 0.19.7 → 0.19.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -6,6 +6,13 @@ git log에서 릴리즈 노트를 생성하고, 출시 전 위험 요소를 자
|
|
|
6
6
|
|
|
7
7
|
## 빠른 시작
|
|
8
8
|
|
|
9
|
+
```bash
|
|
10
|
+
npx mimi-seed check --local
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
로그인 없이 현재 저장소의 앱 식별자, Android Target API, Google Play Billing 지원 상태를 먼저 검사합니다.
|
|
14
|
+
정책 결과에는 근거 파일과 공식 출처가 포함됩니다. 실제 스토어 상태까지 연결하려면 그다음 실행합니다.
|
|
15
|
+
|
|
9
16
|
```bash
|
|
10
17
|
npx mimi-seed init
|
|
11
18
|
```
|
|
@@ -21,7 +28,7 @@ npx mimi-seed init
|
|
|
21
28
|
| `mimi-seed status` | 연결 상태 + 등록 앱 목록 |
|
|
22
29
|
| `mimi-seed auth` | 자격증명 개별 인증 — `login` / `appstore` / `playstore` / `bigquery` / `jenkins` / `ci` / `googleads` / `facebook` / `instagram` / `threads` |
|
|
23
30
|
| `mimi-seed doctor` | 환경 진단 (토큰·Git·앱·CI 한 번에 체크) |
|
|
24
|
-
| `mimi-seed check` |
|
|
31
|
+
| `mimi-seed check` | 계정이 없으면 로컬 Release Doctor, 연결 후에는 원격 Readiness 점검 |
|
|
25
32
|
| `mimi-seed notes` | AI 릴리즈 노트 생성 (git log → 3 톤 → 다국어 → 적용) |
|
|
26
33
|
| `mimi-seed review` | AI 리뷰 답변 초안 생성 및 Play Store 게시 |
|
|
27
34
|
| `mimi-seed deploy` | 앱 자동 배포 파이프라인 (CI 빌드 → 릴리즈 노트 → 스토어 적용) |
|
|
@@ -76,13 +83,23 @@ mimi-seed notes --locale ko,en-US,ja
|
|
|
76
83
|
|
|
77
84
|
## mimi-seed check
|
|
78
85
|
|
|
79
|
-
|
|
86
|
+
계정 연결 전에는 현재 저장소를 읽기 전용으로 검사하고, 연결 후에는 원격 Readiness 점수와 블로커를
|
|
87
|
+
확인합니다. `--local`은 연결 상태와 관계없이 로컬 검사만 실행합니다.
|
|
80
88
|
|
|
81
89
|
```bash
|
|
82
90
|
mimi-seed check
|
|
83
91
|
|
|
92
|
+
# 로그인 없이 저장소만 검사
|
|
93
|
+
mimi-seed check --local
|
|
94
|
+
|
|
95
|
+
# 모노레포의 특정 앱 검사
|
|
96
|
+
mimi-seed check --local --path apps/mobile
|
|
97
|
+
|
|
84
98
|
# CI에서 블로커 있으면 exit 1
|
|
85
|
-
mimi-seed check --fail-on-blocker
|
|
99
|
+
mimi-seed check --local --fail-on-blocker
|
|
100
|
+
|
|
101
|
+
# JSON 보고서
|
|
102
|
+
mimi-seed check --local --json
|
|
86
103
|
```
|
|
87
104
|
|
|
88
105
|
### 옵션
|
|
@@ -90,6 +107,9 @@ mimi-seed check --fail-on-blocker
|
|
|
90
107
|
| 옵션 | 설명 |
|
|
91
108
|
|------|------|
|
|
92
109
|
| `--app <id>` | 앱 ID 지정 (기본: 첫 번째 등록 앱) |
|
|
110
|
+
| `--local` | 로그인 없이 현재 저장소만 검사 |
|
|
111
|
+
| `--path <dir>` | 로컬 검사 대상 경로 (기본: 현재 폴더) |
|
|
112
|
+
| `--json` | 로컬 검사 결과를 JSON으로 출력 |
|
|
93
113
|
| `--fail-on-blocker` | 블로커 존재 시 exit 1 (CI/CD용) |
|
|
94
114
|
|
|
95
115
|
---
|
|
@@ -631,22 +631,71 @@ function planSetup(detected, opts = {}) {
|
|
|
631
631
|
|
|
632
632
|
// src/mcp-bin.ts
|
|
633
633
|
import { spawn, spawnSync } from "child_process";
|
|
634
|
+
import { existsSync, readFileSync } from "fs";
|
|
635
|
+
import path3 from "path";
|
|
634
636
|
var MCP_PKG = "@yoonion/mimi-seed-mcp";
|
|
635
|
-
function resolveOnPath(bin) {
|
|
636
|
-
if (process.env.MIMI_SEED_FORCE_NPX) return
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
637
|
+
function resolveOnPath(bin, honorForceNpx = true) {
|
|
638
|
+
if (honorForceNpx && process.env.MIMI_SEED_FORCE_NPX) return null;
|
|
639
|
+
if (process.platform === "win32") {
|
|
640
|
+
const pathKey = Object.keys(process.env).find((key) => key.toLowerCase() === "path");
|
|
641
|
+
const directories = (pathKey ? process.env[pathKey] ?? "" : "").split(path3.delimiter).filter(Boolean);
|
|
642
|
+
const names = bin.toLowerCase().endsWith(".cmd") ? [bin] : [`${bin}.cmd`, bin];
|
|
643
|
+
for (const directory of directories) {
|
|
644
|
+
for (const name of names) {
|
|
645
|
+
const candidate = path3.join(directory.replace(/^"|"$/g, ""), name);
|
|
646
|
+
if (existsSync(candidate)) return candidate;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
return null;
|
|
650
|
+
}
|
|
651
|
+
const probe = "which";
|
|
652
|
+
const result = spawnSync(probe, [bin], { encoding: "utf8", shell: false });
|
|
653
|
+
if (result.status !== 0) return null;
|
|
654
|
+
const candidates = result.stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
655
|
+
return candidates[0] ?? null;
|
|
656
|
+
}
|
|
657
|
+
function resolveWindowsShimTarget(shimPath, source) {
|
|
658
|
+
const matches = [...source.matchAll(/["']([^"']+\.js)["']\s+%\*/gi)];
|
|
659
|
+
const raw = matches.at(-1)?.[1];
|
|
660
|
+
if (!raw) return null;
|
|
661
|
+
return path3.win32.normalize(raw.replace(/%~?dp0%?/gi, `${path3.win32.dirname(shimPath)}${path3.win32.sep}`));
|
|
662
|
+
}
|
|
663
|
+
function npxCliPath(shimPath) {
|
|
664
|
+
const candidates = [
|
|
665
|
+
shimPath ? path3.join(path3.dirname(shimPath), "node_modules", "npm", "bin", "npx-cli.js") : "",
|
|
666
|
+
path3.join(path3.dirname(process.execPath), "node_modules", "npm", "bin", "npx-cli.js"),
|
|
667
|
+
process.env.npm_execpath ? path3.join(path3.dirname(process.env.npm_execpath), "npx-cli.js") : ""
|
|
668
|
+
];
|
|
669
|
+
return candidates.find((candidate) => candidate && existsSync(candidate)) ?? null;
|
|
670
|
+
}
|
|
671
|
+
function windowsNodeTarget(command, shimPath) {
|
|
672
|
+
if (command === "npx") return npxCliPath(shimPath);
|
|
673
|
+
if (!shimPath) return null;
|
|
674
|
+
try {
|
|
675
|
+
const target = resolveWindowsShimTarget(shimPath, readFileSync(shimPath, "utf8"));
|
|
676
|
+
return target && existsSync(target) ? target : null;
|
|
677
|
+
} catch {
|
|
678
|
+
return null;
|
|
679
|
+
}
|
|
640
680
|
}
|
|
641
681
|
async function runMcpBin(bin, extraArgs = []) {
|
|
642
|
-
const
|
|
643
|
-
const cmd =
|
|
682
|
+
const localPath = resolveOnPath(bin);
|
|
683
|
+
const cmd = localPath ? bin : "npx";
|
|
644
684
|
const pkg = process.env.MIMI_SEED_FORCE_NPX ? `${MCP_PKG}@latest` : MCP_PKG;
|
|
645
|
-
const args =
|
|
685
|
+
const args = localPath ? extraArgs : ["-y", pkg, bin, ...extraArgs];
|
|
646
686
|
return new Promise((resolve) => {
|
|
647
|
-
const
|
|
687
|
+
const shimPath = process.platform === "win32" ? localPath ?? resolveOnPath(cmd, false) : null;
|
|
688
|
+
const nodeTarget = process.platform === "win32" ? windowsNodeTarget(cmd, shimPath) : null;
|
|
689
|
+
if (process.platform === "win32" && !nodeTarget) {
|
|
690
|
+
process.stderr.write(t().auth.npxFailed(cmd, `could not resolve the JavaScript entrypoint for ${shimPath ?? cmd}`));
|
|
691
|
+
resolve(1);
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
const executable = process.platform === "win32" ? process.execPath : localPath ?? cmd;
|
|
695
|
+
const childArgs = nodeTarget ? [nodeTarget, ...args] : args;
|
|
696
|
+
const child = spawn(executable, childArgs, {
|
|
648
697
|
stdio: "inherit",
|
|
649
|
-
shell:
|
|
698
|
+
shell: false,
|
|
650
699
|
env: { ...process.env, MIMI_SEED_LANG: resolveLang() }
|
|
651
700
|
});
|
|
652
701
|
child.on("error", (e) => {
|
|
@@ -660,22 +709,22 @@ async function runMcpBin(bin, extraArgs = []) {
|
|
|
660
709
|
// src/jenkins-config.ts
|
|
661
710
|
import fs3 from "fs";
|
|
662
711
|
import os2 from "os";
|
|
663
|
-
import
|
|
664
|
-
var CONFIG_DIR =
|
|
665
|
-
var JENKINS_PATH =
|
|
666
|
-
var LEGACY_PATH =
|
|
712
|
+
import path4 from "path";
|
|
713
|
+
var CONFIG_DIR = path4.join(os2.homedir(), ".mimi-seed");
|
|
714
|
+
var JENKINS_PATH = path4.join(CONFIG_DIR, "jenkins.json");
|
|
715
|
+
var LEGACY_PATH = path4.join(CONFIG_DIR, "config.json");
|
|
667
716
|
function loadJenkinsConfig(home = os2.homedir()) {
|
|
668
717
|
try {
|
|
669
|
-
const p =
|
|
718
|
+
const p = path4.join(home, ".mimi-seed", "jenkins.json");
|
|
670
719
|
return JSON.parse(fs3.readFileSync(p, "utf-8"));
|
|
671
720
|
} catch {
|
|
672
721
|
return null;
|
|
673
722
|
}
|
|
674
723
|
}
|
|
675
724
|
function migrateLegacyJenkins(home = os2.homedir()) {
|
|
676
|
-
const dir =
|
|
677
|
-
const jenkinsPath =
|
|
678
|
-
const legacyPath =
|
|
725
|
+
const dir = path4.join(home, ".mimi-seed");
|
|
726
|
+
const jenkinsPath = path4.join(dir, "jenkins.json");
|
|
727
|
+
const legacyPath = path4.join(dir, "config.json");
|
|
679
728
|
if (fs3.existsSync(jenkinsPath)) return false;
|
|
680
729
|
let legacy;
|
|
681
730
|
try {
|
|
@@ -704,7 +753,7 @@ function migrateLegacyJenkins(home = os2.homedir()) {
|
|
|
704
753
|
|
|
705
754
|
// src/detect.ts
|
|
706
755
|
import fs4 from "fs/promises";
|
|
707
|
-
import
|
|
756
|
+
import path5 from "path";
|
|
708
757
|
async function readIfExists(p) {
|
|
709
758
|
try {
|
|
710
759
|
return await fs4.readFile(p, "utf8");
|
|
@@ -743,9 +792,9 @@ async function walk(root, match, maxDepth = 5) {
|
|
|
743
792
|
for (const e of entries) {
|
|
744
793
|
if (e.isDirectory()) {
|
|
745
794
|
if (skipDirs.has(e.name)) continue;
|
|
746
|
-
await visit(
|
|
795
|
+
await visit(path5.join(dir, e.name), depth + 1);
|
|
747
796
|
} else if (e.isFile() && match(e.name)) {
|
|
748
|
-
found.push(
|
|
797
|
+
found.push(path5.join(dir, e.name));
|
|
749
798
|
}
|
|
750
799
|
}
|
|
751
800
|
}
|
|
@@ -755,7 +804,7 @@ async function walk(root, match, maxDepth = 5) {
|
|
|
755
804
|
async function detectHints(cwd) {
|
|
756
805
|
const hints = [];
|
|
757
806
|
for (const fname of ["app.json", "app.config.json"]) {
|
|
758
|
-
const txt = await readIfExists(
|
|
807
|
+
const txt = await readIfExists(path5.join(cwd, fname));
|
|
759
808
|
if (!txt) continue;
|
|
760
809
|
try {
|
|
761
810
|
const json = JSON.parse(txt);
|
|
@@ -786,7 +835,7 @@ async function detectHints(cwd) {
|
|
|
786
835
|
if (m?.[1]) {
|
|
787
836
|
const pkg = m[1];
|
|
788
837
|
if (!hints.some((h) => h.packageName === pkg)) {
|
|
789
|
-
hints.push({ packageName: pkg, source: [
|
|
838
|
+
hints.push({ packageName: pkg, source: [path5.relative(cwd, f)] });
|
|
790
839
|
}
|
|
791
840
|
}
|
|
792
841
|
}
|
|
@@ -801,7 +850,7 @@ async function detectHints(cwd) {
|
|
|
801
850
|
const bid = m[1];
|
|
802
851
|
if (bid.includes("$(PRODUCT_BUNDLE_IDENTIFIER)")) continue;
|
|
803
852
|
if (!hints.some((h) => h.bundleId === bid)) {
|
|
804
|
-
hints.push({ bundleId: bid, source: [
|
|
853
|
+
hints.push({ bundleId: bid, source: [path5.relative(cwd, f)] });
|
|
805
854
|
}
|
|
806
855
|
}
|
|
807
856
|
}
|
|
@@ -814,11 +863,11 @@ async function detectHints(cwd) {
|
|
|
814
863
|
const bid = m[1].trim().replace(/^["']|["']$/g, "");
|
|
815
864
|
if (!bid || bid.includes("$")) continue;
|
|
816
865
|
if (!hints.some((h) => h.bundleId === bid)) {
|
|
817
|
-
hints.push({ bundleId: bid, source: [
|
|
866
|
+
hints.push({ bundleId: bid, source: [path5.relative(cwd, f)] });
|
|
818
867
|
}
|
|
819
868
|
}
|
|
820
869
|
}
|
|
821
|
-
const pkgJson = await readIfExists(
|
|
870
|
+
const pkgJson = await readIfExists(path5.join(cwd, "package.json"));
|
|
822
871
|
if (pkgJson) {
|
|
823
872
|
try {
|
|
824
873
|
const json = JSON.parse(pkgJson);
|
|
@@ -854,7 +903,7 @@ async function detectHints(cwd) {
|
|
|
854
903
|
return merged.filter((h) => h.packageName || h.bundleId);
|
|
855
904
|
}
|
|
856
905
|
async function hasAnyProjectSignal(cwd) {
|
|
857
|
-
return await pathExists(
|
|
906
|
+
return await pathExists(path5.join(cwd, "package.json")) || await pathExists(path5.join(cwd, "app.json")) || await pathExists(path5.join(cwd, "android")) || await pathExists(path5.join(cwd, "ios"));
|
|
858
907
|
}
|
|
859
908
|
|
|
860
909
|
// src/deploy.ts
|
|
@@ -863,10 +912,10 @@ import * as readline from "readline";
|
|
|
863
912
|
|
|
864
913
|
// src/config.ts
|
|
865
914
|
import fs5 from "fs/promises";
|
|
866
|
-
import
|
|
915
|
+
import path6 from "path";
|
|
867
916
|
import os3 from "os";
|
|
868
|
-
var CONFIG_DIR2 =
|
|
869
|
-
var CONFIG_PATH =
|
|
917
|
+
var CONFIG_DIR2 = path6.join(os3.homedir(), ".mimi-seed");
|
|
918
|
+
var CONFIG_PATH = path6.join(CONFIG_DIR2, "config.json");
|
|
870
919
|
async function readConfig() {
|
|
871
920
|
try {
|
|
872
921
|
const txt = await fs5.readFile(CONFIG_PATH, "utf8");
|
|
@@ -903,9 +952,9 @@ async function getEffectiveConfig() {
|
|
|
903
952
|
|
|
904
953
|
// src/ci-providers.ts
|
|
905
954
|
import fs6 from "fs";
|
|
906
|
-
import
|
|
955
|
+
import path7 from "path";
|
|
907
956
|
import os4 from "os";
|
|
908
|
-
var CI_CONFIG_PATH =
|
|
957
|
+
var CI_CONFIG_PATH = path7.join(os4.homedir(), ".mimi-seed", "ci.json");
|
|
909
958
|
var M = catalog(
|
|
910
959
|
{
|
|
911
960
|
badToken: (provider, status) => `${provider} ${status} \u2014 \uD1A0\uD070\uC774 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC544`,
|
|
@@ -937,7 +986,7 @@ function normalizeHost(host) {
|
|
|
937
986
|
return withScheme.replace(/\/+$/, "");
|
|
938
987
|
}
|
|
939
988
|
function saveCiProviderConfig(cfg) {
|
|
940
|
-
const dir =
|
|
989
|
+
const dir = path7.dirname(CI_CONFIG_PATH);
|
|
941
990
|
if (!fs6.existsSync(dir)) {
|
|
942
991
|
fs6.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
943
992
|
}
|
package/dist/index.js
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
runMcpBin,
|
|
23
23
|
tryCredById,
|
|
24
24
|
writeConfig
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-KY6LI3CK.js";
|
|
26
26
|
import {
|
|
27
27
|
catalog,
|
|
28
28
|
isLang,
|
|
@@ -263,6 +263,11 @@ import kleur2 from "kleur";
|
|
|
263
263
|
var M2 = catalog(
|
|
264
264
|
{
|
|
265
265
|
noAccount: "\uC5F0\uACB0\uB41C \uACC4\uC815 \uC5C6\uC74C. `mimi-seed init` \uC2E4\uD589.\n",
|
|
266
|
+
missingOptionValue: (option) => `${option} \uB4A4\uC5D0 \uAC12\uC744 \uC785\uB825\uD558\uC138\uC694.`,
|
|
267
|
+
unknownOption: (option) => `\uC54C \uC218 \uC5C6\uB294 check \uC635\uC158: ${option}`,
|
|
268
|
+
unexpectedArgument: (value) => `\uC608\uC0C1\uD558\uC9C0 \uC54A\uC740 check \uC778\uC790: ${value}`,
|
|
269
|
+
localAppConflict: "--app\uC740 \uC6D0\uACA9 \uAC80\uC0AC \uC804\uC6A9\uC774\uBBC0\uB85C --local, --path, --json\uACFC \uD568\uAED8 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.\n",
|
|
270
|
+
localStarting: "Release Doctor \uC2E4\uD589 \uC911\u2026 \uCCAB \uC2E4\uD589\uC740 \uAC80\uC0AC\uAE30 \uB2E4\uC6B4\uB85C\uB4DC\uB85C \uC2DC\uAC04\uC774 \uAC78\uB9B4 \uC218 \uC788\uC2B5\uB2C8\uB2E4.\n",
|
|
266
271
|
title: "mimi-seed check \u2014 \uCD9C\uC2DC \uC804 \uC810\uAC80\n\n",
|
|
267
272
|
appsFailed: (msg) => `\uC571 \uBAA9\uB85D \uC870\uD68C \uC2E4\uD328: ${msg}
|
|
268
273
|
`,
|
|
@@ -294,6 +299,11 @@ var M2 = catalog(
|
|
|
294
299
|
},
|
|
295
300
|
{
|
|
296
301
|
noAccount: "No account connected. Run `mimi-seed init`.\n",
|
|
302
|
+
missingOptionValue: (option) => `Provide a value after ${option}.`,
|
|
303
|
+
unknownOption: (option) => `Unknown check option: ${option}`,
|
|
304
|
+
unexpectedArgument: (value) => `Unexpected check argument: ${value}`,
|
|
305
|
+
localAppConflict: "--app is remote-only and cannot be combined with --local, --path, or --json.\n",
|
|
306
|
+
localStarting: "Running Release Doctor\u2026 the first run may take longer while the checker downloads.\n",
|
|
297
307
|
title: "mimi-seed check \u2014 pre-launch check\n\n",
|
|
298
308
|
appsFailed: (msg) => `Failed to list apps: ${msg}
|
|
299
309
|
`,
|
|
@@ -324,11 +334,30 @@ Score: ${bar}
|
|
|
324
334
|
`
|
|
325
335
|
}
|
|
326
336
|
);
|
|
327
|
-
function
|
|
328
|
-
const args = {
|
|
337
|
+
function parseCheckArgs(argv) {
|
|
338
|
+
const args = {
|
|
339
|
+
projectPath: process.cwd(),
|
|
340
|
+
projectPathExplicit: false,
|
|
341
|
+
failOnBlocker: false,
|
|
342
|
+
local: false,
|
|
343
|
+
json: false
|
|
344
|
+
};
|
|
345
|
+
const takeValue = (option, index) => {
|
|
346
|
+
const value = argv[index + 1];
|
|
347
|
+
if (!value || value.startsWith("--")) throw new Error(M2().missingOptionValue(option));
|
|
348
|
+
return value;
|
|
349
|
+
};
|
|
329
350
|
for (let i = 0; i < argv.length; i++) {
|
|
330
|
-
|
|
331
|
-
if (
|
|
351
|
+
const token = argv[i];
|
|
352
|
+
if (token === "--app") args.appId = takeValue(token, i++);
|
|
353
|
+
else if (token === "--path") {
|
|
354
|
+
args.projectPath = takeValue(token, i++);
|
|
355
|
+
args.projectPathExplicit = true;
|
|
356
|
+
} else if (token === "--fail-on-blocker") args.failOnBlocker = true;
|
|
357
|
+
else if (token === "--local") args.local = true;
|
|
358
|
+
else if (token === "--json") args.json = true;
|
|
359
|
+
else if (token.startsWith("-")) throw new Error(M2().unknownOption(token));
|
|
360
|
+
else throw new Error(M2().unexpectedArgument(token));
|
|
332
361
|
}
|
|
333
362
|
return args;
|
|
334
363
|
}
|
|
@@ -345,11 +374,35 @@ var MODULE_LABELS = {
|
|
|
345
374
|
checklist: "Checklist"
|
|
346
375
|
};
|
|
347
376
|
async function cmdCheck(argv) {
|
|
348
|
-
|
|
377
|
+
let args;
|
|
378
|
+
try {
|
|
379
|
+
args = parseCheckArgs(argv);
|
|
380
|
+
} catch (error) {
|
|
381
|
+
process.stderr.write(kleur2.red(`${error instanceof Error ? error.message : String(error)}
|
|
382
|
+
`));
|
|
383
|
+
process.exitCode = 2;
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
349
386
|
const cfg = await getEffectiveConfig();
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
process.
|
|
387
|
+
const localRequested = args.local || args.json || args.projectPathExplicit;
|
|
388
|
+
if (args.appId && localRequested) {
|
|
389
|
+
process.stderr.write(kleur2.red(M2().localAppConflict));
|
|
390
|
+
process.exitCode = 2;
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
if (args.appId && !cfg) {
|
|
394
|
+
process.stderr.write(kleur2.red(M2().noAccount));
|
|
395
|
+
process.exitCode = 1;
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
if (localRequested || !cfg) {
|
|
399
|
+
const doctorArgs = [args.projectPath];
|
|
400
|
+
if (args.json) doctorArgs.push("--json");
|
|
401
|
+
if (args.failOnBlocker) doctorArgs.push("--fail-on-blocker");
|
|
402
|
+
if (!args.json) process.stderr.write(kleur2.dim(M2().localStarting));
|
|
403
|
+
const exitCode = await runMcpBin("mimi-seed-release-doctor", doctorArgs);
|
|
404
|
+
if (exitCode !== 0) process.exit(exitCode);
|
|
405
|
+
return;
|
|
353
406
|
}
|
|
354
407
|
process.stdout.write(kleur2.bold(M2().title));
|
|
355
408
|
const appsResult = await mcpCall(cfg.endpoint, cfg.token, "list_apps", {});
|
|
@@ -554,7 +607,7 @@ Update now.`,
|
|
|
554
607
|
`
|
|
555
608
|
}
|
|
556
609
|
);
|
|
557
|
-
function
|
|
610
|
+
function parseArgs(argv) {
|
|
558
611
|
const args = { to: "HEAD", locales: ["ko", "en-US"], apply: false, noInteractive: false, limit: 30 };
|
|
559
612
|
for (let i = 0; i < argv.length; i++) {
|
|
560
613
|
if (argv[i] === "--from" && argv[i + 1]) args.from = argv[++i];
|
|
@@ -611,7 +664,7 @@ function parseFirstApp(text) {
|
|
|
611
664
|
return null;
|
|
612
665
|
}
|
|
613
666
|
async function cmdNotes(argv) {
|
|
614
|
-
const args =
|
|
667
|
+
const args = parseArgs(argv);
|
|
615
668
|
const cwd = process.cwd();
|
|
616
669
|
process.stdout.write(kleur3.bold(M3().title));
|
|
617
670
|
if (!isGitRepo(cwd)) {
|
|
@@ -820,7 +873,7 @@ Respond with JSON only: { "reply": "the reply text" }`,
|
|
|
820
873
|
posted: "\u2713 Reply posted\n"
|
|
821
874
|
}
|
|
822
875
|
);
|
|
823
|
-
function
|
|
876
|
+
function parseArgs2(argv) {
|
|
824
877
|
const args = { tone: "friendly", language: "ko", apply: false, noInteractive: false };
|
|
825
878
|
for (let i = 0; i < argv.length; i++) {
|
|
826
879
|
if (argv[i] === "--text" && argv[i + 1]) args.text = argv[++i];
|
|
@@ -877,7 +930,7 @@ async function generateReply(opts) {
|
|
|
877
930
|
return parsed.reply;
|
|
878
931
|
}
|
|
879
932
|
async function cmdReview(argv) {
|
|
880
|
-
const args =
|
|
933
|
+
const args = parseArgs2(argv);
|
|
881
934
|
process.stdout.write(kleur4.bold(M4().title));
|
|
882
935
|
if (!process.env.ANTHROPIC_API_KEY) {
|
|
883
936
|
process.stdout.write(kleur4.red(M4().noApiKey));
|
|
@@ -1068,7 +1121,7 @@ async function cmdAuth(args) {
|
|
|
1068
1121
|
if (sub === "threads") return void exitWith(await runMcpBin("mimi-seed-social-auth", ["threads", ...rest]));
|
|
1069
1122
|
if (sub === "tiktok") return void exitWith(await runMcpBin("mimi-seed-tiktok-business-auth", rest));
|
|
1070
1123
|
if (sub === "ci") {
|
|
1071
|
-
const { cmdSetup: cmdSetup2 } = await import("./setup-
|
|
1124
|
+
const { cmdSetup: cmdSetup2 } = await import("./setup-RI2NDOZR.js");
|
|
1072
1125
|
await cmdSetup2(["--only", "github,gitlab", "--reconnect", "github,gitlab"]);
|
|
1073
1126
|
return;
|
|
1074
1127
|
}
|
|
@@ -1613,6 +1666,9 @@ ${kleur9.dim("setup \uB9C8\uBC95\uC0AC\uAC00 \uCCAB \uC2E4\uD589 \uB54C \uBB3C\u
|
|
|
1613
1666
|
|
|
1614
1667
|
\uC635\uC158:
|
|
1615
1668
|
--app <id> \uC571 ID \uC9C0\uC815
|
|
1669
|
+
--local \uB85C\uADF8\uC778 \uC5C6\uC774 \uD604\uC7AC \uC800\uC7A5\uC18C\uB9CC \uAC80\uC0AC
|
|
1670
|
+
--path <dir> \uB85C\uCEEC \uAC80\uC0AC \uB300\uC0C1 \uACBD\uB85C (\uAE30\uBCF8: \uD604\uC7AC \uD3F4\uB354)
|
|
1671
|
+
--json \uB85C\uCEEC \uAC80\uC0AC \uACB0\uACFC\uB97C JSON\uC73C\uB85C \uCD9C\uB825
|
|
1616
1672
|
--fail-on-blocker \uBE14\uB85C\uCEE4 \uC788\uC73C\uBA74 exit 1 (CI\uC6A9)`,
|
|
1617
1673
|
review: `${kleur9.bold("mimi-seed review")} \u2014 \uB9AC\uBDF0 \uB2F5\uBCC0 AI \uCD08\uC548 \uC0DD\uC131 \uBC0F Play Store \uAC8C\uC2DC
|
|
1618
1674
|
|
|
@@ -1779,6 +1835,9 @@ Options:
|
|
|
1779
1835
|
|
|
1780
1836
|
Options:
|
|
1781
1837
|
--app <id> app ID
|
|
1838
|
+
--local inspect the current repository without signing in
|
|
1839
|
+
--path <dir> local project path (default: current directory)
|
|
1840
|
+
--json print the local report as JSON
|
|
1782
1841
|
--fail-on-blocker exit 1 if a blocker is found (for CI)`,
|
|
1783
1842
|
review: `${kleur9.bold("mimi-seed review")} \u2014 draft a review reply with AI and post it to the Play Store
|
|
1784
1843
|
|
package/package.json
CHANGED