mimi-seed 0.6.0 → 0.9.0
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/dist/{chunk-R3LS4FY2.js → chunk-BXN3EMF6.js} +289 -379
- package/dist/{chunk-DW3LOLPJ.js → chunk-QU2IDWJ2.js} +8 -1
- package/dist/chunk-SZQFVTEW.js +252 -0
- package/dist/index.js +895 -332
- package/dist/{mcp-client-SLIKR42C.js → mcp-client-PVWDCYJN.js} +2 -1
- package/dist/{setup-G2JY35UW.js → setup-3XTSGFEF.js} +2 -1
- package/package.json +1 -1
|
@@ -1,51 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
catalog,
|
|
4
|
+
isLangUnset,
|
|
5
|
+
resolveLang,
|
|
6
|
+
t,
|
|
7
|
+
writeSettings
|
|
8
|
+
} from "./chunk-SZQFVTEW.js";
|
|
2
9
|
|
|
3
10
|
// src/setup.ts
|
|
4
11
|
import kleur2 from "kleur";
|
|
5
12
|
import * as readline2 from "readline";
|
|
6
|
-
import
|
|
13
|
+
import os5 from "os";
|
|
7
14
|
|
|
8
15
|
// src/credentials.ts
|
|
9
|
-
import fs2 from "fs";
|
|
10
|
-
import os2 from "os";
|
|
11
|
-
import path2 from "path";
|
|
12
|
-
|
|
13
|
-
// src/settings.ts
|
|
14
16
|
import fs from "fs";
|
|
15
17
|
import os from "os";
|
|
16
18
|
import path from "path";
|
|
17
|
-
var DEFAULT_LANG = "ko";
|
|
18
|
-
function settingsPath(home) {
|
|
19
|
-
return path.join(home, ".mimi-seed", "settings.json");
|
|
20
|
-
}
|
|
21
|
-
function readSettings(home = os.homedir()) {
|
|
22
|
-
try {
|
|
23
|
-
return JSON.parse(fs.readFileSync(settingsPath(home), "utf-8"));
|
|
24
|
-
} catch {
|
|
25
|
-
return {};
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
function writeSettings(next, home = os.homedir()) {
|
|
29
|
-
const dir = path.join(home, ".mimi-seed");
|
|
30
|
-
fs.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
31
|
-
const merged = { ...readSettings(home), ...next };
|
|
32
|
-
fs.writeFileSync(settingsPath(home), JSON.stringify(merged, null, 2));
|
|
33
|
-
}
|
|
34
|
-
function isLangUnset(home = os.homedir()) {
|
|
35
|
-
return !process.env.MIMI_SEED_LANG && !readSettings(home).lang;
|
|
36
|
-
}
|
|
37
|
-
function isLang(v) {
|
|
38
|
-
return v === "ko" || v === "en";
|
|
39
|
-
}
|
|
40
|
-
function resolveLang(home = os.homedir()) {
|
|
41
|
-
const env = process.env.MIMI_SEED_LANG?.toLowerCase();
|
|
42
|
-
if (isLang(env)) return env;
|
|
43
|
-
const saved = readSettings(home).lang;
|
|
44
|
-
if (isLang(saved)) return saved;
|
|
45
|
-
return DEFAULT_LANG;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// src/credentials.ts
|
|
49
19
|
function credLabel(spec, lang = resolveLang()) {
|
|
50
20
|
return spec.label[lang];
|
|
51
21
|
}
|
|
@@ -56,21 +26,21 @@ function credObtain(spec, lang = resolveLang()) {
|
|
|
56
26
|
return spec.obtain[lang];
|
|
57
27
|
}
|
|
58
28
|
function credDir(home) {
|
|
59
|
-
return
|
|
29
|
+
return path.join(home, ".mimi-seed");
|
|
60
30
|
}
|
|
61
31
|
function hasFile(home, name) {
|
|
62
|
-
return
|
|
32
|
+
return fs.existsSync(path.join(credDir(home), name));
|
|
63
33
|
}
|
|
64
34
|
function anyFileStarting(home, prefix) {
|
|
65
35
|
try {
|
|
66
|
-
return
|
|
36
|
+
return fs.readdirSync(credDir(home)).some((f) => f.startsWith(prefix));
|
|
67
37
|
} catch {
|
|
68
38
|
return false;
|
|
69
39
|
}
|
|
70
40
|
}
|
|
71
41
|
function readJson(home, name) {
|
|
72
42
|
try {
|
|
73
|
-
return JSON.parse(
|
|
43
|
+
return JSON.parse(fs.readFileSync(path.join(credDir(home), name), "utf-8"));
|
|
74
44
|
} catch {
|
|
75
45
|
return null;
|
|
76
46
|
}
|
|
@@ -78,7 +48,7 @@ function readJson(home, name) {
|
|
|
78
48
|
function hasPlaySa(home) {
|
|
79
49
|
if (hasFile(home, "play-service-account.json")) return true;
|
|
80
50
|
try {
|
|
81
|
-
return
|
|
51
|
+
return fs.readdirSync(path.join(credDir(home), "play-service-accounts")).some((f) => f.endsWith(".json"));
|
|
82
52
|
} catch {
|
|
83
53
|
return false;
|
|
84
54
|
}
|
|
@@ -464,7 +434,7 @@ var CREDENTIALS = [
|
|
|
464
434
|
function tryCredById(id) {
|
|
465
435
|
return CREDENTIALS.find((c) => c.id === id);
|
|
466
436
|
}
|
|
467
|
-
function detectAll(home =
|
|
437
|
+
function detectAll(home = os.homedir()) {
|
|
468
438
|
return new Map(CREDENTIALS.map((c) => [c.id, c.detect(home)]));
|
|
469
439
|
}
|
|
470
440
|
function isSatisfied(spec, detected) {
|
|
@@ -509,7 +479,8 @@ function resolveOnPath(bin) {
|
|
|
509
479
|
async function runMcpBin(bin, extraArgs = []) {
|
|
510
480
|
const local = resolveOnPath(bin);
|
|
511
481
|
const cmd = local ? bin : "npx";
|
|
512
|
-
const
|
|
482
|
+
const pkg = process.env.MIMI_SEED_FORCE_NPX ? `${MCP_PKG}@latest` : MCP_PKG;
|
|
483
|
+
const args = local ? extraArgs : ["-y", pkg, bin, ...extraArgs];
|
|
513
484
|
return new Promise((resolve) => {
|
|
514
485
|
const child = spawn(cmd, args, {
|
|
515
486
|
stdio: "inherit",
|
|
@@ -517,9 +488,7 @@ async function runMcpBin(bin, extraArgs = []) {
|
|
|
517
488
|
env: { ...process.env, MIMI_SEED_LANG: resolveLang() }
|
|
518
489
|
});
|
|
519
490
|
child.on("error", (e) => {
|
|
520
|
-
process.stderr.write(
|
|
521
|
-
\u274C ${cmd} \uC2E4\uD589 \uC2E4\uD328: ${e.message}
|
|
522
|
-
`);
|
|
491
|
+
process.stderr.write(t().auth.npxFailed(cmd, e.message));
|
|
523
492
|
resolve(1);
|
|
524
493
|
});
|
|
525
494
|
child.on("exit", (code) => resolve(code ?? 0));
|
|
@@ -527,28 +496,28 @@ async function runMcpBin(bin, extraArgs = []) {
|
|
|
527
496
|
}
|
|
528
497
|
|
|
529
498
|
// src/jenkins-config.ts
|
|
530
|
-
import
|
|
531
|
-
import
|
|
532
|
-
import
|
|
533
|
-
var CONFIG_DIR =
|
|
534
|
-
var JENKINS_PATH =
|
|
535
|
-
var LEGACY_PATH =
|
|
536
|
-
function loadJenkinsConfig(home =
|
|
499
|
+
import fs2 from "fs";
|
|
500
|
+
import os2 from "os";
|
|
501
|
+
import path2 from "path";
|
|
502
|
+
var CONFIG_DIR = path2.join(os2.homedir(), ".mimi-seed");
|
|
503
|
+
var JENKINS_PATH = path2.join(CONFIG_DIR, "jenkins.json");
|
|
504
|
+
var LEGACY_PATH = path2.join(CONFIG_DIR, "config.json");
|
|
505
|
+
function loadJenkinsConfig(home = os2.homedir()) {
|
|
537
506
|
try {
|
|
538
|
-
const p =
|
|
539
|
-
return JSON.parse(
|
|
507
|
+
const p = path2.join(home, ".mimi-seed", "jenkins.json");
|
|
508
|
+
return JSON.parse(fs2.readFileSync(p, "utf-8"));
|
|
540
509
|
} catch {
|
|
541
510
|
return null;
|
|
542
511
|
}
|
|
543
512
|
}
|
|
544
|
-
function migrateLegacyJenkins(home =
|
|
545
|
-
const dir =
|
|
546
|
-
const jenkinsPath =
|
|
547
|
-
const legacyPath =
|
|
548
|
-
if (
|
|
513
|
+
function migrateLegacyJenkins(home = os2.homedir()) {
|
|
514
|
+
const dir = path2.join(home, ".mimi-seed");
|
|
515
|
+
const jenkinsPath = path2.join(dir, "jenkins.json");
|
|
516
|
+
const legacyPath = path2.join(dir, "config.json");
|
|
517
|
+
if (fs2.existsSync(jenkinsPath)) return false;
|
|
549
518
|
let legacy;
|
|
550
519
|
try {
|
|
551
|
-
legacy = JSON.parse(
|
|
520
|
+
legacy = JSON.parse(fs2.readFileSync(legacyPath, "utf-8"));
|
|
552
521
|
} catch {
|
|
553
522
|
return false;
|
|
554
523
|
}
|
|
@@ -562,28 +531,28 @@ function migrateLegacyJenkins(home = os3.homedir()) {
|
|
|
562
531
|
...j.jobAndroid ? { jobAndroid: j.jobAndroid } : {},
|
|
563
532
|
...j.jobIos ? { jobIos: j.jobIos } : {}
|
|
564
533
|
};
|
|
565
|
-
|
|
566
|
-
|
|
534
|
+
fs2.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
535
|
+
fs2.writeFileSync(jenkinsPath, JSON.stringify(migrated, null, 2), { mode: 384 });
|
|
567
536
|
delete legacy.jenkins;
|
|
568
537
|
const tmp = `${legacyPath}.tmp`;
|
|
569
|
-
|
|
570
|
-
|
|
538
|
+
fs2.writeFileSync(tmp, JSON.stringify(legacy, null, 2), { mode: 384 });
|
|
539
|
+
fs2.renameSync(tmp, legacyPath);
|
|
571
540
|
return true;
|
|
572
541
|
}
|
|
573
542
|
|
|
574
543
|
// src/detect.ts
|
|
575
|
-
import
|
|
576
|
-
import
|
|
544
|
+
import fs3 from "fs/promises";
|
|
545
|
+
import path3 from "path";
|
|
577
546
|
async function readIfExists(p) {
|
|
578
547
|
try {
|
|
579
|
-
return await
|
|
548
|
+
return await fs3.readFile(p, "utf8");
|
|
580
549
|
} catch {
|
|
581
550
|
return null;
|
|
582
551
|
}
|
|
583
552
|
}
|
|
584
553
|
async function pathExists(p) {
|
|
585
554
|
try {
|
|
586
|
-
await
|
|
555
|
+
await fs3.access(p);
|
|
587
556
|
return true;
|
|
588
557
|
} catch {
|
|
589
558
|
return false;
|
|
@@ -605,16 +574,16 @@ async function walk(root, match, maxDepth = 5) {
|
|
|
605
574
|
if (depth > maxDepth) return;
|
|
606
575
|
let entries;
|
|
607
576
|
try {
|
|
608
|
-
entries = await
|
|
577
|
+
entries = await fs3.readdir(dir, { withFileTypes: true });
|
|
609
578
|
} catch {
|
|
610
579
|
return;
|
|
611
580
|
}
|
|
612
581
|
for (const e of entries) {
|
|
613
582
|
if (e.isDirectory()) {
|
|
614
583
|
if (skipDirs.has(e.name)) continue;
|
|
615
|
-
await visit(
|
|
584
|
+
await visit(path3.join(dir, e.name), depth + 1);
|
|
616
585
|
} else if (e.isFile() && match(e.name)) {
|
|
617
|
-
found.push(
|
|
586
|
+
found.push(path3.join(dir, e.name));
|
|
618
587
|
}
|
|
619
588
|
}
|
|
620
589
|
}
|
|
@@ -624,7 +593,7 @@ async function walk(root, match, maxDepth = 5) {
|
|
|
624
593
|
async function detectHints(cwd) {
|
|
625
594
|
const hints = [];
|
|
626
595
|
for (const fname of ["app.json", "app.config.json"]) {
|
|
627
|
-
const txt = await readIfExists(
|
|
596
|
+
const txt = await readIfExists(path3.join(cwd, fname));
|
|
628
597
|
if (!txt) continue;
|
|
629
598
|
try {
|
|
630
599
|
const json = JSON.parse(txt);
|
|
@@ -655,7 +624,7 @@ async function detectHints(cwd) {
|
|
|
655
624
|
if (m?.[1]) {
|
|
656
625
|
const pkg = m[1];
|
|
657
626
|
if (!hints.some((h) => h.packageName === pkg)) {
|
|
658
|
-
hints.push({ packageName: pkg, source: [
|
|
627
|
+
hints.push({ packageName: pkg, source: [path3.relative(cwd, f)] });
|
|
659
628
|
}
|
|
660
629
|
}
|
|
661
630
|
}
|
|
@@ -670,7 +639,7 @@ async function detectHints(cwd) {
|
|
|
670
639
|
let bid = m[1];
|
|
671
640
|
if (bid.includes("$(PRODUCT_BUNDLE_IDENTIFIER)")) continue;
|
|
672
641
|
if (!hints.some((h) => h.bundleId === bid)) {
|
|
673
|
-
hints.push({ bundleId: bid, source: [
|
|
642
|
+
hints.push({ bundleId: bid, source: [path3.relative(cwd, f)] });
|
|
674
643
|
}
|
|
675
644
|
}
|
|
676
645
|
}
|
|
@@ -683,11 +652,11 @@ async function detectHints(cwd) {
|
|
|
683
652
|
const bid = m[1].trim().replace(/^["']|["']$/g, "");
|
|
684
653
|
if (!bid || bid.includes("$")) continue;
|
|
685
654
|
if (!hints.some((h) => h.bundleId === bid)) {
|
|
686
|
-
hints.push({ bundleId: bid, source: [
|
|
655
|
+
hints.push({ bundleId: bid, source: [path3.relative(cwd, f)] });
|
|
687
656
|
}
|
|
688
657
|
}
|
|
689
658
|
}
|
|
690
|
-
const pkgJson = await readIfExists(
|
|
659
|
+
const pkgJson = await readIfExists(path3.join(cwd, "package.json"));
|
|
691
660
|
if (pkgJson) {
|
|
692
661
|
try {
|
|
693
662
|
const json = JSON.parse(pkgJson);
|
|
@@ -723,7 +692,7 @@ async function detectHints(cwd) {
|
|
|
723
692
|
return merged.filter((h) => h.packageName || h.bundleId);
|
|
724
693
|
}
|
|
725
694
|
async function hasAnyProjectSignal(cwd) {
|
|
726
|
-
return await pathExists(
|
|
695
|
+
return await pathExists(path3.join(cwd, "package.json")) || await pathExists(path3.join(cwd, "app.json")) || await pathExists(path3.join(cwd, "android")) || await pathExists(path3.join(cwd, "ios"));
|
|
727
696
|
}
|
|
728
697
|
|
|
729
698
|
// src/deploy.ts
|
|
@@ -731,28 +700,28 @@ import kleur from "kleur";
|
|
|
731
700
|
import * as readline from "readline";
|
|
732
701
|
|
|
733
702
|
// src/config.ts
|
|
734
|
-
import
|
|
735
|
-
import
|
|
736
|
-
import
|
|
737
|
-
var CONFIG_DIR2 =
|
|
738
|
-
var CONFIG_PATH =
|
|
703
|
+
import fs4 from "fs/promises";
|
|
704
|
+
import path4 from "path";
|
|
705
|
+
import os3 from "os";
|
|
706
|
+
var CONFIG_DIR2 = path4.join(os3.homedir(), ".mimi-seed");
|
|
707
|
+
var CONFIG_PATH = path4.join(CONFIG_DIR2, "config.json");
|
|
739
708
|
async function readConfig() {
|
|
740
709
|
try {
|
|
741
|
-
const txt = await
|
|
710
|
+
const txt = await fs4.readFile(CONFIG_PATH, "utf8");
|
|
742
711
|
return JSON.parse(txt);
|
|
743
712
|
} catch {
|
|
744
713
|
return null;
|
|
745
714
|
}
|
|
746
715
|
}
|
|
747
716
|
async function writeConfig(cfg) {
|
|
748
|
-
await
|
|
749
|
-
await
|
|
717
|
+
await fs4.mkdir(CONFIG_DIR2, { recursive: true });
|
|
718
|
+
await fs4.writeFile(CONFIG_PATH, JSON.stringify(cfg, null, 2));
|
|
750
719
|
if (process.platform !== "win32") {
|
|
751
|
-
await
|
|
720
|
+
await fs4.chmod(CONFIG_PATH, 384);
|
|
752
721
|
}
|
|
753
722
|
}
|
|
754
723
|
async function deleteConfig() {
|
|
755
|
-
await
|
|
724
|
+
await fs4.rm(CONFIG_PATH, { force: true });
|
|
756
725
|
}
|
|
757
726
|
var CONFIG_LOCATION = CONFIG_PATH;
|
|
758
727
|
async function getEffectiveConfig() {
|
|
@@ -771,13 +740,28 @@ async function getEffectiveConfig() {
|
|
|
771
740
|
}
|
|
772
741
|
|
|
773
742
|
// src/ci-providers.ts
|
|
774
|
-
import
|
|
775
|
-
import
|
|
776
|
-
import
|
|
777
|
-
var CI_CONFIG_PATH =
|
|
743
|
+
import fs5 from "fs";
|
|
744
|
+
import path5 from "path";
|
|
745
|
+
import os4 from "os";
|
|
746
|
+
var CI_CONFIG_PATH = path5.join(os4.homedir(), ".mimi-seed", "ci.json");
|
|
747
|
+
var M = catalog(
|
|
748
|
+
{
|
|
749
|
+
badToken: (provider, status) => `${provider} ${status} \u2014 \uD1A0\uD070\uC774 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC544`,
|
|
750
|
+
noScope: (scopes) => `\uD1A0\uD070\uC5D0 \`workflow\` \uC2A4\uCF54\uD504\uAC00 \uC5C6\uC5B4 (\uD604\uC7AC: ${scopes || "\uC5C6\uC74C"}). \uC6CC\uD06C\uD50C\uB85C \uC2E4\uD589\uC774 403 \uC73C\uB85C \uB9C9\uD78C\uB2E4.`,
|
|
751
|
+
pollFailed: (provider) => `${provider} API \uC5F0\uC18D \uC624\uB958 3\uD68C`,
|
|
752
|
+
pollFailedHttp: (provider, status) => `${provider} API \uC5F0\uC18D \uC624\uB958 (HTTP ${status})`
|
|
753
|
+
},
|
|
754
|
+
{
|
|
755
|
+
badToken: (provider, status) => `${provider} ${status} \u2014 the token is not valid`,
|
|
756
|
+
noScope: (scopes) => `The token is missing the \`workflow\` scope (currently: ${scopes || "none"}). Triggering a workflow will be blocked with a 403.`,
|
|
757
|
+
// 프로바이더 이름("GitHub API")은 두 언어 모두에 남는다 — 테스트가 그걸로 단언한다.
|
|
758
|
+
pollFailed: (provider) => `${provider} API failed 3 times in a row`,
|
|
759
|
+
pollFailedHttp: (provider, status) => `${provider} API failed 3 times in a row (HTTP ${status})`
|
|
760
|
+
}
|
|
761
|
+
);
|
|
778
762
|
function loadCiProviderConfig() {
|
|
779
763
|
try {
|
|
780
|
-
const cfg = JSON.parse(
|
|
764
|
+
const cfg = JSON.parse(fs5.readFileSync(CI_CONFIG_PATH, "utf-8"));
|
|
781
765
|
const host = normalizeHost(cfg.host);
|
|
782
766
|
return host ? { ...cfg, host } : { ...cfg, host: void 0 };
|
|
783
767
|
} catch {
|
|
@@ -791,15 +775,15 @@ function normalizeHost(host) {
|
|
|
791
775
|
return withScheme.replace(/\/+$/, "");
|
|
792
776
|
}
|
|
793
777
|
function saveCiProviderConfig(cfg) {
|
|
794
|
-
const dir =
|
|
795
|
-
if (!
|
|
796
|
-
|
|
778
|
+
const dir = path5.dirname(CI_CONFIG_PATH);
|
|
779
|
+
if (!fs5.existsSync(dir)) {
|
|
780
|
+
fs5.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
797
781
|
}
|
|
798
782
|
const normalized = { ...cfg, host: normalizeHost(cfg.host) };
|
|
799
783
|
if (!normalized.host) delete normalized.host;
|
|
800
|
-
|
|
784
|
+
fs5.writeFileSync(CI_CONFIG_PATH, JSON.stringify(normalized, null, 2));
|
|
801
785
|
if (process.platform !== "win32") {
|
|
802
|
-
|
|
786
|
+
fs5.chmodSync(CI_CONFIG_PATH, 384);
|
|
803
787
|
}
|
|
804
788
|
}
|
|
805
789
|
async function verifyCiToken(cfg) {
|
|
@@ -810,21 +794,18 @@ async function verifyCiToken(cfg) {
|
|
|
810
794
|
headers: { Authorization: `Bearer ${probe.token}`, Accept: "application/vnd.github+json" }
|
|
811
795
|
});
|
|
812
796
|
if (!res2.ok) {
|
|
813
|
-
return { ok: false, reason:
|
|
797
|
+
return { ok: false, reason: M().badToken("GitHub", res2.status) };
|
|
814
798
|
}
|
|
815
799
|
const user2 = await res2.json();
|
|
816
800
|
const scopes = res2.headers.get("x-oauth-scopes");
|
|
817
801
|
if (scopes !== null && !scopes.split(/,\s*/).filter(Boolean).includes("workflow")) {
|
|
818
|
-
return {
|
|
819
|
-
ok: false,
|
|
820
|
-
reason: `\uD1A0\uD070\uC5D0 \`workflow\` \uC2A4\uCF54\uD504\uAC00 \uC5C6\uC5B4 (\uD604\uC7AC: ${scopes || "\uC5C6\uC74C"}). \uC6CC\uD06C\uD50C\uB85C \uC2E4\uD589\uC774 403 \uC73C\uB85C \uB9C9\uD78C\uB2E4.`
|
|
821
|
-
};
|
|
802
|
+
return { ok: false, reason: M().noScope(scopes) };
|
|
822
803
|
}
|
|
823
804
|
return { ok: true, login: user2.login };
|
|
824
805
|
}
|
|
825
806
|
const res = await fetch(`${glBase(probe)}/user`, { headers: { "PRIVATE-TOKEN": probe.token } });
|
|
826
807
|
if (!res.ok) {
|
|
827
|
-
return { ok: false, reason:
|
|
808
|
+
return { ok: false, reason: M().badToken("GitLab", res.status) };
|
|
828
809
|
}
|
|
829
810
|
const user = await res.json();
|
|
830
811
|
return { ok: true, login: user.username };
|
|
@@ -882,12 +863,12 @@ async function ghPollRun(cfg, runId, onTick, timeoutMs = 30 * 60 * 1e3, interval
|
|
|
882
863
|
);
|
|
883
864
|
} catch {
|
|
884
865
|
consecutiveErrors++;
|
|
885
|
-
if (consecutiveErrors >= 3) throw new Error("GitHub
|
|
866
|
+
if (consecutiveErrors >= 3) throw new Error(M().pollFailed("GitHub"));
|
|
886
867
|
continue;
|
|
887
868
|
}
|
|
888
869
|
if (!res.ok) {
|
|
889
870
|
consecutiveErrors++;
|
|
890
|
-
if (consecutiveErrors >= 3) throw new Error(
|
|
871
|
+
if (consecutiveErrors >= 3) throw new Error(M().pollFailedHttp("GitHub", res.status));
|
|
891
872
|
continue;
|
|
892
873
|
}
|
|
893
874
|
consecutiveErrors = 0;
|
|
@@ -933,12 +914,12 @@ async function glPollPipeline(cfg, pipelineId, onTick, timeoutMs = 30 * 60 * 1e3
|
|
|
933
914
|
);
|
|
934
915
|
} catch {
|
|
935
916
|
consecutiveErrors++;
|
|
936
|
-
if (consecutiveErrors >= 3) throw new Error("GitLab
|
|
917
|
+
if (consecutiveErrors >= 3) throw new Error(M().pollFailed("GitLab"));
|
|
937
918
|
continue;
|
|
938
919
|
}
|
|
939
920
|
if (!res.ok) {
|
|
940
921
|
consecutiveErrors++;
|
|
941
|
-
if (consecutiveErrors >= 3) throw new Error(
|
|
922
|
+
if (consecutiveErrors >= 3) throw new Error(M().pollFailedHttp("GitLab", res.status));
|
|
942
923
|
continue;
|
|
943
924
|
}
|
|
944
925
|
consecutiveErrors = 0;
|
|
@@ -964,6 +945,144 @@ var PHASE_ICON = {
|
|
|
964
945
|
function log(msg) {
|
|
965
946
|
process.stdout.write(msg + "\n");
|
|
966
947
|
}
|
|
948
|
+
var M2 = catalog(
|
|
949
|
+
{
|
|
950
|
+
// Jenkins / 빌드
|
|
951
|
+
jenkinsTriggerFailed: (status, body) => `Jenkins \uD2B8\uB9AC\uAC70 \uC2E4\uD328 ${status}: ${body}`,
|
|
952
|
+
buildStatusFailed: (status) => `\uBE4C\uB4DC \uC0C1\uD0DC \uC870\uD68C \uC2E4\uD328 ${status}`,
|
|
953
|
+
jenkinsConnErrorFatal: "Jenkins \uC5F0\uACB0 \uC624\uB958 3\uD68C \uC5F0\uC18D \u2014 \uB124\uD2B8\uC6CC\uD06C\uB97C \uD655\uC778\uD558\uC138\uC694",
|
|
954
|
+
jenkinsConnErrorRetry: (n) => `Jenkins \uC5F0\uACB0 \uC624\uB958 (${n}/3\uD68C), \uC7AC\uC2DC\uB3C4...`,
|
|
955
|
+
buildRunning: "\uBE4C\uB4DC \uC9C4\uD589 \uC911",
|
|
956
|
+
buildTimeout: "\uBE4C\uB4DC \uD0C0\uC784\uC544\uC6C3 (30\uBD84)",
|
|
957
|
+
// 서버 스트림
|
|
958
|
+
serverDeployFailed: (status, body) => `\uC11C\uBC84 \uBC30\uD3EC \uC2E4\uD328 ${status}: ${body}`,
|
|
959
|
+
noSseStream: "SSE \uC2A4\uD2B8\uB9BC \uC5C6\uC74C",
|
|
960
|
+
// CI provider 설정 프롬프트
|
|
961
|
+
githubSetupTitle: "GitHub Actions \uC124\uC815",
|
|
962
|
+
gitlabSetupTitle: "GitLab CI \uC124\uC815",
|
|
963
|
+
githubTokenPrompt: " GitHub Personal Access Token (repo+workflow \uC2A4\uCF54\uD504): ",
|
|
964
|
+
gitlabTokenPrompt: " GitLab Personal Access Token: ",
|
|
965
|
+
githubOwnerPrompt: " Owner (org/user): ",
|
|
966
|
+
gitlabOwnerPrompt: " Namespace/group: ",
|
|
967
|
+
repoPrompt: " Repo \uC774\uB984 (\uACBD\uB85C \uC5C6\uC774): ",
|
|
968
|
+
githubHostPrompt: " GitHub Enterprise host (\uC120\uD0DD, \uC5D4\uD130=github.com): ",
|
|
969
|
+
gitlabHostPrompt: " GitLab self-hosted URL (\uC120\uD0DD, \uC5D4\uD130=gitlab.com): ",
|
|
970
|
+
githubSaved: "\u2705 GitHub Actions \uC124\uC815 \uC800\uC7A5\uB428 \u2192 ~/.mimi-seed/ci.json",
|
|
971
|
+
gitlabSaved: "\u2705 GitLab CI \uC124\uC815 \uC800\uC7A5\uB428 \u2192 ~/.mimi-seed/ci.json",
|
|
972
|
+
noCiConfig: "CI \uC124\uC815 \uC5C6\uC74C. \uB2E4\uC74C \uC911 \uD558\uB098 \uC2E4\uD589:\n \u2022 mimi-seed deploy setup-jenkins\n \u2022 mimi-seed deploy setup-github\n \u2022 mimi-seed deploy setup-gitlab",
|
|
973
|
+
// GitHub / GitLab 빌드
|
|
974
|
+
workflowRequired: "--workflow \uD544\uC694 (\uC608: --workflow deploy.yml)",
|
|
975
|
+
ghTrigger: (workflow, ref) => `\u{1F528} GitHub Actions \uD2B8\uB9AC\uAC70: ${workflow} @ ${ref}`,
|
|
976
|
+
ghRunIdFailed: "GitHub Actions run_id \uC870\uD68C \uC2E4\uD328. \uC7A0\uC2DC \uD6C4 ci_list_recent_builds \uB85C \uD655\uC778\uD558\uC138\uC694.",
|
|
977
|
+
ghRunId: (id, url) => ` Run ID: ${id} \u2192 ${url}`,
|
|
978
|
+
glTrigger: (ref) => `\u{1F528} GitLab Pipeline \uD2B8\uB9AC\uAC70: ${ref}`,
|
|
979
|
+
glPipelineId: (id, url) => ` Pipeline ID: ${id} \u2192 ${url}`,
|
|
980
|
+
waitingForCompletion: " \uC644\uB8CC \uB300\uAE30 \uC911...",
|
|
981
|
+
buildSucceeded: (n) => `\u2705 \uBE4C\uB4DC #${n} \uC131\uACF5`,
|
|
982
|
+
buildEnded: (result) => `\uBE4C\uB4DC \uC885\uB8CC: ${result}`,
|
|
983
|
+
alreadyBuiltHint: (versionCode, platform) => ` \uBE4C\uB4DC\uAC00 \uC774\uBBF8 \uC644\uB8CC\uB410\uB2E4\uBA74: mimi-seed deploy --skip-build --version-code ${versionCode} --platform ${platform}`,
|
|
984
|
+
// cmdDeploy
|
|
985
|
+
noAccount: "\uC5F0\uACB0\uB41C \uACC4\uC815 \uC5C6\uC74C. `mimi-seed init` \uC2E4\uD589.",
|
|
986
|
+
title: (platform) => `mimi-seed deploy \u2014 ${platform}`,
|
|
987
|
+
dryRunNotice: " [dry-run \uBAA8\uB4DC] \uC2E4\uC81C \uBC30\uD3EC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4",
|
|
988
|
+
ciLine: (kind) => ` CI: ${kind}`,
|
|
989
|
+
noJenkinsConfig: "Jenkins \uC124\uC815 \uC5C6\uC74C. `mimi-seed deploy setup-jenkins` \uB85C \uC124\uC815\uD558\uAC70\uB098 --skip-build \uC0AC\uC6A9.",
|
|
990
|
+
noJenkinsJob: (platform) => `${platform} Jenkins job\uC774 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. setup-jenkins \uC2E4\uD589.`,
|
|
991
|
+
jenkinsTrigger: (job) => `\u{1F528} Jenkins \uBE4C\uB4DC \uD2B8\uB9AC\uAC70: ${job}`,
|
|
992
|
+
noQueueItem: " \u26A0 Queue item ID\uB97C \uAC00\uC838\uC624\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uBE4C\uB4DC\uB294 \uC2DC\uC791\uB410\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
|
|
993
|
+
queueItem: (id) => ` Queue item: ${id}`,
|
|
994
|
+
waitingForBuildNumber: " \uBE4C\uB4DC \uBC88\uD638 \uB300\uAE30 \uC911...",
|
|
995
|
+
noBuildNumber: " \uBE4C\uB4DC \uBC88\uD638\uB97C \uAC00\uC838\uC624\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. --skip-build + --version-code \uB85C \uC7AC\uC2DC\uB3C4 \uAC00\uB2A5.",
|
|
996
|
+
buildStarted: (n) => ` \uBE4C\uB4DC #${n} \uC2DC\uC791\uB428. \uC644\uB8CC \uB300\uAE30 \uC911...`,
|
|
997
|
+
buildFailed: (result) => `\uBE4C\uB4DC \uC2E4\uD328: ${result}`,
|
|
998
|
+
jenkinsLink: (url) => ` Jenkins: ${url}`,
|
|
999
|
+
versionCodeFromBuild: (n) => ` versionCode = buildNumber (${n})`,
|
|
1000
|
+
noProviderConfig: (kind) => `${kind} \uC124\uC815\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. setup-${kind} \uC2E4\uD589.`,
|
|
1001
|
+
versionCodeUnsuitable: (kind, buildId) => `\u2717 versionCode \uBBF8\uC9C0\uC815 (${kind} run_id ${buildId}\uB294 versionCode\uB85C \uBD80\uC801\uD569)`,
|
|
1002
|
+
recommendation: " \uAD8C\uC7A5 \uC0AC\uD56D:",
|
|
1003
|
+
recommendationCi: " \u2022 CI \uC6CC\uD06C\uD50C\uB85C \uC548\uC5D0\uC11C versionCode\uB97C \uACB0\uC815\uD558\uACE0 \uACB0\uACFC\uB97C \uCD9C\uB825",
|
|
1004
|
+
recommendationNext: " \u2022 \uB2E4\uC74C \uC2E4\uD589: mimi-seed deploy --skip-build --version-code <N>",
|
|
1005
|
+
versionCodeUnknown: "versionCode\uB97C \uC54C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. --version-code <N> \uC73C\uB85C \uC9C0\uC815\uD558\uC138\uC694.",
|
|
1006
|
+
appLine: (name, id) => ` \uC571: ${name} (${id})`,
|
|
1007
|
+
noAppId: "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.",
|
|
1008
|
+
// 프로덕션 확인
|
|
1009
|
+
targetIos: "App Store \uC2EC\uC0AC \uC81C\uCD9C",
|
|
1010
|
+
targetAndroid: "Play Store production \uD2B8\uB799",
|
|
1011
|
+
realDeploy: (platform, versionCode, target) => `\u26A0 \uC2E4\uC81C \uBC30\uD3EC: ${platform} \xB7 versionCode ${versionCode} \u2192 ${target}`,
|
|
1012
|
+
confirmPrompt: "\uACC4\uC18D \uC9C4\uD589\uD560\uAE4C\uC694? [y/N]: ",
|
|
1013
|
+
confirmCancelled: "\uCDE8\uC18C\uB428. (--yes \uB85C \uD655\uC778 \uC0DD\uB7B5 \uAC00\uB2A5)",
|
|
1014
|
+
pipelineStarting: "\u{1F4E1} \uC11C\uBC84 \uBC30\uD3EC \uD30C\uC774\uD504\uB77C\uC778 \uC2DC\uC791...",
|
|
1015
|
+
done: "\uC644\uB8CC. Play Console\uC5D0\uC11C \uBC30\uD3EC \uC0C1\uD0DC\uB97C \uD655\uC778\uD558\uC138\uC694."
|
|
1016
|
+
},
|
|
1017
|
+
{
|
|
1018
|
+
// Jenkins / build
|
|
1019
|
+
jenkinsTriggerFailed: (status, body) => `Jenkins trigger failed ${status}: ${body}`,
|
|
1020
|
+
buildStatusFailed: (status) => `Failed to fetch build status ${status}`,
|
|
1021
|
+
jenkinsConnErrorFatal: "Jenkins connection failed 3 times in a row \u2014 check your network",
|
|
1022
|
+
jenkinsConnErrorRetry: (n) => `Jenkins connection error (${n}/3), retrying...`,
|
|
1023
|
+
buildRunning: "Build running",
|
|
1024
|
+
buildTimeout: "Build timed out (30 min)",
|
|
1025
|
+
// Server stream
|
|
1026
|
+
serverDeployFailed: (status, body) => `Server deploy failed ${status}: ${body}`,
|
|
1027
|
+
noSseStream: "No SSE stream",
|
|
1028
|
+
// CI provider setup prompts
|
|
1029
|
+
githubSetupTitle: "GitHub Actions setup",
|
|
1030
|
+
gitlabSetupTitle: "GitLab CI setup",
|
|
1031
|
+
githubTokenPrompt: " GitHub Personal Access Token (repo+workflow scopes): ",
|
|
1032
|
+
gitlabTokenPrompt: " GitLab Personal Access Token: ",
|
|
1033
|
+
githubOwnerPrompt: " Owner (org/user): ",
|
|
1034
|
+
gitlabOwnerPrompt: " Namespace/group: ",
|
|
1035
|
+
repoPrompt: " Repo name (without the path): ",
|
|
1036
|
+
githubHostPrompt: " GitHub Enterprise host (optional, Enter = github.com): ",
|
|
1037
|
+
gitlabHostPrompt: " GitLab self-hosted URL (optional, Enter = gitlab.com): ",
|
|
1038
|
+
githubSaved: "\u2705 GitHub Actions config saved \u2192 ~/.mimi-seed/ci.json",
|
|
1039
|
+
gitlabSaved: "\u2705 GitLab CI config saved \u2192 ~/.mimi-seed/ci.json",
|
|
1040
|
+
noCiConfig: "No CI configured. Run one of:\n \u2022 mimi-seed deploy setup-jenkins\n \u2022 mimi-seed deploy setup-github\n \u2022 mimi-seed deploy setup-gitlab",
|
|
1041
|
+
// GitHub / GitLab build
|
|
1042
|
+
workflowRequired: "--workflow is required (e.g. --workflow deploy.yml)",
|
|
1043
|
+
ghTrigger: (workflow, ref) => `\u{1F528} Triggering GitHub Actions: ${workflow} @ ${ref}`,
|
|
1044
|
+
ghRunIdFailed: "Could not resolve the GitHub Actions run_id. Check with ci_list_recent_builds in a moment.",
|
|
1045
|
+
ghRunId: (id, url) => ` Run ID: ${id} \u2192 ${url}`,
|
|
1046
|
+
glTrigger: (ref) => `\u{1F528} Triggering GitLab Pipeline: ${ref}`,
|
|
1047
|
+
glPipelineId: (id, url) => ` Pipeline ID: ${id} \u2192 ${url}`,
|
|
1048
|
+
waitingForCompletion: " Waiting for it to finish...",
|
|
1049
|
+
buildSucceeded: (n) => `\u2705 Build #${n} succeeded`,
|
|
1050
|
+
buildEnded: (result) => `Build ended: ${result}`,
|
|
1051
|
+
alreadyBuiltHint: (versionCode, platform) => ` If the build already finished: mimi-seed deploy --skip-build --version-code ${versionCode} --platform ${platform}`,
|
|
1052
|
+
// cmdDeploy
|
|
1053
|
+
noAccount: "No account connected. Run `mimi-seed init`.",
|
|
1054
|
+
title: (platform) => `mimi-seed deploy \u2014 ${platform}`,
|
|
1055
|
+
dryRunNotice: " [dry-run] nothing will actually be deployed",
|
|
1056
|
+
ciLine: (kind) => ` CI: ${kind}`,
|
|
1057
|
+
noJenkinsConfig: "Jenkins is not configured. Run `mimi-seed deploy setup-jenkins`, or use --skip-build.",
|
|
1058
|
+
noJenkinsJob: (platform) => `No Jenkins job configured for ${platform}. Run setup-jenkins.`,
|
|
1059
|
+
jenkinsTrigger: (job) => `\u{1F528} Triggering Jenkins build: ${job}`,
|
|
1060
|
+
noQueueItem: " \u26A0 Could not read the queue item ID. The build may have started anyway.",
|
|
1061
|
+
queueItem: (id) => ` Queue item: ${id}`,
|
|
1062
|
+
waitingForBuildNumber: " Waiting for the build number...",
|
|
1063
|
+
noBuildNumber: " Could not read the build number. Retry with --skip-build + --version-code.",
|
|
1064
|
+
buildStarted: (n) => ` Build #${n} started. Waiting for it to finish...`,
|
|
1065
|
+
buildFailed: (result) => `Build failed: ${result}`,
|
|
1066
|
+
jenkinsLink: (url) => ` Jenkins: ${url}`,
|
|
1067
|
+
versionCodeFromBuild: (n) => ` versionCode = buildNumber (${n})`,
|
|
1068
|
+
noProviderConfig: (kind) => `${kind} is not configured. Run setup-${kind}.`,
|
|
1069
|
+
versionCodeUnsuitable: (kind, buildId) => `\u2717 No versionCode given (${kind} run_id ${buildId} is not usable as a versionCode)`,
|
|
1070
|
+
recommendation: " Recommended:",
|
|
1071
|
+
recommendationCi: " \u2022 Decide the versionCode inside the CI workflow and print it",
|
|
1072
|
+
recommendationNext: " \u2022 Then run: mimi-seed deploy --skip-build --version-code <N>",
|
|
1073
|
+
versionCodeUnknown: "Unknown versionCode. Pass it with --version-code <N>.",
|
|
1074
|
+
appLine: (name, id) => ` App: ${name} (${id})`,
|
|
1075
|
+
noAppId: "Could not resolve the appId. Pass --app <id>, or register the app with `mimi-seed init`.",
|
|
1076
|
+
// Production confirmation
|
|
1077
|
+
targetIos: "App Store review submission",
|
|
1078
|
+
targetAndroid: "Play Store production track",
|
|
1079
|
+
realDeploy: (platform, versionCode, target) => `\u26A0 Real deploy: ${platform} \xB7 versionCode ${versionCode} \u2192 ${target}`,
|
|
1080
|
+
confirmPrompt: "Continue? [y/N]: ",
|
|
1081
|
+
confirmCancelled: "Cancelled. (use --yes to skip this confirmation)",
|
|
1082
|
+
pipelineStarting: "\u{1F4E1} Starting the server deploy pipeline...",
|
|
1083
|
+
done: "Done. Check the deploy status in Play Console."
|
|
1084
|
+
}
|
|
1085
|
+
);
|
|
967
1086
|
function jenkinsHeaders(cfg) {
|
|
968
1087
|
const creds = Buffer.from(`${cfg.username || "admin"}:${cfg.token}`).toString("base64");
|
|
969
1088
|
return { Authorization: `Basic ${creds}`, "Content-Type": "application/json" };
|
|
@@ -973,7 +1092,7 @@ async function triggerBuild(cfg, jobName, params) {
|
|
|
973
1092
|
const url = `${cfg.url}/job/${encodeURIComponent(jobName)}/buildWithParameters?${qs}`;
|
|
974
1093
|
const res = await fetch(url, { method: "POST", headers: jenkinsHeaders(cfg) });
|
|
975
1094
|
if (!res.ok) {
|
|
976
|
-
throw new Error(
|
|
1095
|
+
throw new Error(M2().jenkinsTriggerFailed(res.status, await res.text()));
|
|
977
1096
|
}
|
|
978
1097
|
const location = res.headers.get("Location") ?? "";
|
|
979
1098
|
const match = location.match(/\/queue\/item\/(\d+)\//);
|
|
@@ -989,7 +1108,7 @@ async function getQueueBuildNumber(cfg, queueItemId) {
|
|
|
989
1108
|
async function getBuildStatus(cfg, jobName, buildNumber) {
|
|
990
1109
|
const url = `${cfg.url}/job/${encodeURIComponent(jobName)}/${buildNumber}/api/json`;
|
|
991
1110
|
const res = await fetch(url, { headers: jenkinsHeaders(cfg) });
|
|
992
|
-
if (!res.ok) throw new Error(
|
|
1111
|
+
if (!res.ok) throw new Error(M2().buildStatusFailed(res.status));
|
|
993
1112
|
const data = await res.json();
|
|
994
1113
|
return {
|
|
995
1114
|
building: data.building ?? true,
|
|
@@ -1010,18 +1129,18 @@ async function pollBuildComplete(cfg, jobName, buildNumber, timeoutMs = 30 * 60
|
|
|
1010
1129
|
consecutiveErrors = 0;
|
|
1011
1130
|
} catch {
|
|
1012
1131
|
consecutiveErrors++;
|
|
1013
|
-
if (consecutiveErrors >= 3) throw new Error(
|
|
1014
|
-
process.stdout.write(`\r \u26A0
|
|
1132
|
+
if (consecutiveErrors >= 3) throw new Error(M2().jenkinsConnErrorFatal);
|
|
1133
|
+
process.stdout.write(`\r \u26A0 ${M2().jenkinsConnErrorRetry(consecutiveErrors)} `);
|
|
1015
1134
|
continue;
|
|
1016
1135
|
}
|
|
1017
1136
|
dots = (dots + 1) % 4;
|
|
1018
|
-
process.stdout.write(`\r \u23F3
|
|
1137
|
+
process.stdout.write(`\r \u23F3 ${M2().buildRunning}${".".repeat(dots + 1)} `);
|
|
1019
1138
|
if (!status.building) {
|
|
1020
1139
|
process.stdout.write("\n");
|
|
1021
1140
|
return status.result ?? "FAILURE";
|
|
1022
1141
|
}
|
|
1023
1142
|
}
|
|
1024
|
-
throw new Error(
|
|
1143
|
+
throw new Error(M2().buildTimeout);
|
|
1025
1144
|
}
|
|
1026
1145
|
async function streamDeploy(webBase, token, body) {
|
|
1027
1146
|
const res = await fetch(`${webBase}/api/deploy`, {
|
|
@@ -1034,10 +1153,10 @@ async function streamDeploy(webBase, token, body) {
|
|
|
1034
1153
|
});
|
|
1035
1154
|
if (!res.ok) {
|
|
1036
1155
|
const text = await res.text().catch(() => "");
|
|
1037
|
-
throw new Error(
|
|
1156
|
+
throw new Error(M2().serverDeployFailed(res.status, text.slice(0, 200)));
|
|
1038
1157
|
}
|
|
1039
1158
|
const reader = res.body?.getReader();
|
|
1040
|
-
if (!reader) throw new Error(
|
|
1159
|
+
if (!reader) throw new Error(M2().noSseStream);
|
|
1041
1160
|
const decoder = new TextDecoder();
|
|
1042
1161
|
let buf = "";
|
|
1043
1162
|
while (true) {
|
|
@@ -1097,12 +1216,13 @@ async function promptGitProviderSetup(provider) {
|
|
|
1097
1216
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
1098
1217
|
const ask2 = (q) => new Promise((resolve) => rl.question(q, (a) => resolve(a.trim())));
|
|
1099
1218
|
const isGh = provider === "github";
|
|
1100
|
-
|
|
1101
|
-
|
|
1219
|
+
const m = M2();
|
|
1220
|
+
log(kleur.bold(isGh ? m.githubSetupTitle : m.gitlabSetupTitle));
|
|
1221
|
+
const tokenLabel = isGh ? m.githubTokenPrompt : m.gitlabTokenPrompt;
|
|
1102
1222
|
const token = await ask2(tokenLabel);
|
|
1103
|
-
const owner = await ask2(isGh ?
|
|
1104
|
-
const repo = await ask2(
|
|
1105
|
-
const hostPrompt = isGh ?
|
|
1223
|
+
const owner = await ask2(isGh ? m.githubOwnerPrompt : m.gitlabOwnerPrompt);
|
|
1224
|
+
const repo = await ask2(m.repoPrompt);
|
|
1225
|
+
const hostPrompt = isGh ? m.githubHostPrompt : m.gitlabHostPrompt;
|
|
1106
1226
|
const host = await ask2(hostPrompt);
|
|
1107
1227
|
rl.close();
|
|
1108
1228
|
return {
|
|
@@ -1117,38 +1237,36 @@ function resolveCi(ciOption, jenkins, ciProvider) {
|
|
|
1117
1237
|
if (ciOption !== "auto") return ciOption;
|
|
1118
1238
|
if (jenkins?.url && jenkins.token) return "jenkins";
|
|
1119
1239
|
if (ciProvider) return ciProvider.provider;
|
|
1120
|
-
throw new Error(
|
|
1121
|
-
"CI \uC124\uC815 \uC5C6\uC74C. \uB2E4\uC74C \uC911 \uD558\uB098 \uC2E4\uD589:\n \u2022 mimi-seed deploy setup-jenkins\n \u2022 mimi-seed deploy setup-github\n \u2022 mimi-seed deploy setup-gitlab"
|
|
1122
|
-
);
|
|
1240
|
+
throw new Error(M2().noCiConfig);
|
|
1123
1241
|
}
|
|
1124
1242
|
async function runGitProviderBuild(cfg, args) {
|
|
1125
1243
|
let runUrl = "";
|
|
1126
1244
|
let runId;
|
|
1127
1245
|
if (cfg.provider === "github") {
|
|
1128
1246
|
if (!args.workflow) {
|
|
1129
|
-
throw new Error(
|
|
1247
|
+
throw new Error(M2().workflowRequired);
|
|
1130
1248
|
}
|
|
1131
|
-
log(
|
|
1249
|
+
log(M2().ghTrigger(kleur.cyan(args.workflow), args.ref));
|
|
1132
1250
|
const inputs = {};
|
|
1133
1251
|
if (args.appId) inputs.MIMI_APP_ID = args.appId;
|
|
1134
1252
|
inputs.PLATFORM = args.platform;
|
|
1135
1253
|
const result2 = await ghTriggerWorkflow(cfg, args.workflow, args.ref, inputs);
|
|
1136
1254
|
if (!result2) {
|
|
1137
|
-
throw new Error(
|
|
1255
|
+
throw new Error(M2().ghRunIdFailed);
|
|
1138
1256
|
}
|
|
1139
1257
|
runId = result2.runId;
|
|
1140
1258
|
runUrl = result2.url;
|
|
1141
|
-
log(kleur.dim(
|
|
1259
|
+
log(kleur.dim(M2().ghRunId(runId, runUrl)));
|
|
1142
1260
|
} else {
|
|
1143
|
-
log(
|
|
1261
|
+
log(M2().glTrigger(args.ref));
|
|
1144
1262
|
const variables = { PLATFORM: args.platform };
|
|
1145
1263
|
if (args.appId) variables.MIMI_APP_ID = args.appId;
|
|
1146
1264
|
const result2 = await glTriggerPipeline(cfg, args.ref, variables);
|
|
1147
1265
|
runId = result2.pipelineId;
|
|
1148
1266
|
runUrl = result2.url;
|
|
1149
|
-
log(kleur.dim(
|
|
1267
|
+
log(kleur.dim(M2().glPipelineId(runId, runUrl)));
|
|
1150
1268
|
}
|
|
1151
|
-
log(
|
|
1269
|
+
log(M2().waitingForCompletion);
|
|
1152
1270
|
let dots = 0;
|
|
1153
1271
|
const onTick = (status) => {
|
|
1154
1272
|
dots = (dots + 1) % 4;
|
|
@@ -1157,19 +1275,19 @@ async function runGitProviderBuild(cfg, args) {
|
|
|
1157
1275
|
const result = cfg.provider === "github" ? await ghPollRun(cfg, runId, onTick) : await glPollPipeline(cfg, runId, onTick);
|
|
1158
1276
|
process.stdout.write("\n");
|
|
1159
1277
|
if (result === "success") {
|
|
1160
|
-
log(kleur.green(
|
|
1278
|
+
log(kleur.green(M2().buildSucceeded(runId)));
|
|
1161
1279
|
return runId;
|
|
1162
1280
|
}
|
|
1163
|
-
log(kleur.red(
|
|
1281
|
+
log(kleur.red(M2().buildEnded(result)));
|
|
1164
1282
|
log(kleur.dim(` ${runUrl}`));
|
|
1165
|
-
log(kleur.dim(
|
|
1283
|
+
log(kleur.dim(M2().alreadyBuiltHint("<N>", args.platform)));
|
|
1166
1284
|
process.exit(1);
|
|
1167
1285
|
}
|
|
1168
1286
|
async function cmdDeploy(argv) {
|
|
1169
1287
|
const args = parseArgs(argv);
|
|
1170
1288
|
const cfg = await getEffectiveConfig();
|
|
1171
1289
|
if (!cfg) {
|
|
1172
|
-
log(kleur.red(
|
|
1290
|
+
log(kleur.red(M2().noAccount));
|
|
1173
1291
|
process.exit(1);
|
|
1174
1292
|
}
|
|
1175
1293
|
if (args.setupJenkins) {
|
|
@@ -1180,17 +1298,17 @@ async function cmdDeploy(argv) {
|
|
|
1180
1298
|
if (args.setupGithub) {
|
|
1181
1299
|
const ciCfg = await promptGitProviderSetup("github");
|
|
1182
1300
|
saveCiProviderConfig(ciCfg);
|
|
1183
|
-
log(kleur.green(
|
|
1301
|
+
log(kleur.green(M2().githubSaved));
|
|
1184
1302
|
return;
|
|
1185
1303
|
}
|
|
1186
1304
|
if (args.setupGitlab) {
|
|
1187
1305
|
const ciCfg = await promptGitProviderSetup("gitlab");
|
|
1188
1306
|
saveCiProviderConfig(ciCfg);
|
|
1189
|
-
log(kleur.green(
|
|
1307
|
+
log(kleur.green(M2().gitlabSaved));
|
|
1190
1308
|
return;
|
|
1191
1309
|
}
|
|
1192
|
-
log(kleur.bold(
|
|
1193
|
-
if (args.dryRun) log(kleur.yellow(
|
|
1310
|
+
log(kleur.bold(M2().title(args.platform)));
|
|
1311
|
+
if (args.dryRun) log(kleur.yellow(M2().dryRunNotice));
|
|
1194
1312
|
log("");
|
|
1195
1313
|
let versionCode = args.versionCode;
|
|
1196
1314
|
if (!args.skipBuild) {
|
|
@@ -1198,30 +1316,30 @@ async function cmdDeploy(argv) {
|
|
|
1198
1316
|
migrateLegacyJenkins();
|
|
1199
1317
|
const jenkinsCfg = loadJenkinsConfig() ?? void 0;
|
|
1200
1318
|
const kind = resolveCi(args.ci, jenkinsCfg, ciProvider);
|
|
1201
|
-
log(kleur.dim(
|
|
1319
|
+
log(kleur.dim(M2().ciLine(kind)));
|
|
1202
1320
|
if (kind === "jenkins") {
|
|
1203
1321
|
if (!jenkinsCfg?.url || !jenkinsCfg?.token) {
|
|
1204
|
-
log(kleur.yellow(
|
|
1322
|
+
log(kleur.yellow(M2().noJenkinsConfig));
|
|
1205
1323
|
process.exit(1);
|
|
1206
1324
|
}
|
|
1207
1325
|
const jenkins = jenkinsCfg;
|
|
1208
1326
|
const jobName = args.platform === "android" ? jenkins.jobAndroid : jenkins.jobIos;
|
|
1209
1327
|
if (!jobName) {
|
|
1210
|
-
log(kleur.red(
|
|
1328
|
+
log(kleur.red(M2().noJenkinsJob(args.platform)));
|
|
1211
1329
|
process.exit(1);
|
|
1212
1330
|
}
|
|
1213
|
-
log(
|
|
1331
|
+
log(M2().jenkinsTrigger(kleur.cyan(jobName)));
|
|
1214
1332
|
const buildParams = {};
|
|
1215
1333
|
if (args.appId) buildParams.MIMI_APP_ID = args.appId;
|
|
1216
1334
|
const queueItemId = await triggerBuild(jenkins, jobName, buildParams);
|
|
1217
1335
|
if (!queueItemId) {
|
|
1218
|
-
log(kleur.yellow(
|
|
1336
|
+
log(kleur.yellow(M2().noQueueItem));
|
|
1219
1337
|
} else {
|
|
1220
|
-
log(kleur.dim(
|
|
1338
|
+
log(kleur.dim(M2().queueItem(queueItemId)));
|
|
1221
1339
|
}
|
|
1222
1340
|
let buildNumber = null;
|
|
1223
1341
|
if (queueItemId) {
|
|
1224
|
-
log(
|
|
1342
|
+
log(M2().waitingForBuildNumber);
|
|
1225
1343
|
for (let i = 0; i < 6; i++) {
|
|
1226
1344
|
await new Promise((r) => setTimeout(r, 5e3));
|
|
1227
1345
|
buildNumber = await getQueueBuildNumber(jenkins, queueItemId).catch(() => null);
|
|
@@ -1229,77 +1347,77 @@ async function cmdDeploy(argv) {
|
|
|
1229
1347
|
}
|
|
1230
1348
|
}
|
|
1231
1349
|
if (!buildNumber) {
|
|
1232
|
-
log(kleur.yellow(
|
|
1350
|
+
log(kleur.yellow(M2().noBuildNumber));
|
|
1233
1351
|
process.exit(1);
|
|
1234
1352
|
}
|
|
1235
|
-
log(
|
|
1353
|
+
log(M2().buildStarted(buildNumber));
|
|
1236
1354
|
const result = await pollBuildComplete(jenkins, jobName, buildNumber);
|
|
1237
1355
|
if (result !== "SUCCESS") {
|
|
1238
|
-
log(kleur.red(
|
|
1239
|
-
log(kleur.dim(
|
|
1240
|
-
log(kleur.dim(
|
|
1356
|
+
log(kleur.red(M2().buildFailed(result)));
|
|
1357
|
+
log(kleur.dim(M2().jenkinsLink(`${jenkins.url}/job/${encodeURIComponent(jobName)}/${buildNumber}/`)));
|
|
1358
|
+
log(kleur.dim(M2().alreadyBuiltHint(String(buildNumber), args.platform)));
|
|
1241
1359
|
process.exit(1);
|
|
1242
1360
|
}
|
|
1243
|
-
log(kleur.green(
|
|
1361
|
+
log(kleur.green(M2().buildSucceeded(buildNumber)));
|
|
1244
1362
|
if (!versionCode) {
|
|
1245
1363
|
versionCode = buildNumber;
|
|
1246
|
-
log(kleur.dim(
|
|
1364
|
+
log(kleur.dim(M2().versionCodeFromBuild(versionCode)));
|
|
1247
1365
|
}
|
|
1248
1366
|
} else {
|
|
1249
1367
|
if (!ciProvider) {
|
|
1250
|
-
log(kleur.red(
|
|
1368
|
+
log(kleur.red(M2().noProviderConfig(kind)));
|
|
1251
1369
|
process.exit(1);
|
|
1252
1370
|
}
|
|
1253
1371
|
const buildId = await runGitProviderBuild(ciProvider, args);
|
|
1254
1372
|
if (!versionCode) {
|
|
1255
|
-
log(kleur.red(
|
|
1256
|
-
log(kleur.dim(
|
|
1257
|
-
log(kleur.dim(
|
|
1258
|
-
log(kleur.dim(
|
|
1373
|
+
log(kleur.red(M2().versionCodeUnsuitable(kind, buildId)));
|
|
1374
|
+
log(kleur.dim(M2().recommendation));
|
|
1375
|
+
log(kleur.dim(M2().recommendationCi));
|
|
1376
|
+
log(kleur.dim(M2().recommendationNext));
|
|
1259
1377
|
process.exit(1);
|
|
1260
1378
|
}
|
|
1261
1379
|
}
|
|
1262
1380
|
}
|
|
1263
1381
|
if (!versionCode) {
|
|
1264
|
-
log(kleur.red(
|
|
1382
|
+
log(kleur.red(M2().versionCodeUnknown));
|
|
1265
1383
|
process.exit(1);
|
|
1266
1384
|
}
|
|
1267
1385
|
let appId = args.appId;
|
|
1268
1386
|
if (!appId) {
|
|
1269
|
-
const { mcpCall } = await import("./mcp-client-
|
|
1387
|
+
const { mcpCall } = await import("./mcp-client-PVWDCYJN.js");
|
|
1270
1388
|
const r = await mcpCall(cfg.endpoint, cfg.token, "list_apps", {});
|
|
1271
1389
|
if (!r.isError) {
|
|
1272
1390
|
try {
|
|
1273
1391
|
const apps = JSON.parse(r.text);
|
|
1274
1392
|
if (apps.length > 0) {
|
|
1275
1393
|
appId = apps[0].id;
|
|
1276
|
-
log(kleur.dim(
|
|
1394
|
+
log(kleur.dim(M2().appLine(apps[0].name, appId)));
|
|
1277
1395
|
}
|
|
1278
1396
|
} catch {
|
|
1279
1397
|
}
|
|
1280
1398
|
}
|
|
1281
1399
|
}
|
|
1282
1400
|
if (!appId) {
|
|
1283
|
-
log(kleur.red(
|
|
1401
|
+
log(kleur.red(M2().noAppId));
|
|
1284
1402
|
process.exit(1);
|
|
1285
1403
|
}
|
|
1286
1404
|
const needsConfirm = !args.dryRun && !args.yes && process.stdout.isTTY && !process.env.MIMI_SEED_TOKEN;
|
|
1287
1405
|
if (needsConfirm) {
|
|
1288
|
-
const target = args.platform === "ios" ?
|
|
1406
|
+
const target = args.platform === "ios" ? M2().targetIos : M2().targetAndroid;
|
|
1289
1407
|
log("");
|
|
1290
|
-
log(kleur.yellow(
|
|
1408
|
+
log(kleur.yellow(M2().realDeploy(args.platform, versionCode, target)));
|
|
1291
1409
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
1292
1410
|
const answer = await new Promise(
|
|
1293
|
-
(resolve) => rl.question(kleur.bold(
|
|
1411
|
+
(resolve) => rl.question(kleur.bold(M2().confirmPrompt), (a) => resolve(a.trim().toLowerCase()))
|
|
1294
1412
|
);
|
|
1295
1413
|
rl.close();
|
|
1296
1414
|
if (answer !== "y" && answer !== "yes") {
|
|
1297
|
-
log(kleur.dim(
|
|
1415
|
+
log(kleur.dim(M2().confirmCancelled));
|
|
1298
1416
|
return;
|
|
1299
1417
|
}
|
|
1300
1418
|
}
|
|
1301
1419
|
log("");
|
|
1302
|
-
log(
|
|
1420
|
+
log(M2().pipelineStarting);
|
|
1303
1421
|
log("");
|
|
1304
1422
|
const deployBuildNumber = !args.skipBuild ? versionCode : void 0;
|
|
1305
1423
|
await streamDeploy(cfg.webBase, cfg.token, {
|
|
@@ -1313,214 +1431,10 @@ async function cmdDeploy(argv) {
|
|
|
1313
1431
|
dryRun: args.dryRun
|
|
1314
1432
|
});
|
|
1315
1433
|
log("");
|
|
1316
|
-
log(kleur.bold(
|
|
1434
|
+
log(kleur.bold(M2().done));
|
|
1317
1435
|
log(kleur.dim(" https://play.google.com/console/developers"));
|
|
1318
1436
|
}
|
|
1319
1437
|
|
|
1320
|
-
// src/i18n.ts
|
|
1321
|
-
var ko = {
|
|
1322
|
-
common: {
|
|
1323
|
-
yes: "y",
|
|
1324
|
-
optional: "\uC120\uD0DD",
|
|
1325
|
-
required: "\uD544\uC218",
|
|
1326
|
-
skip: "\uAC74\uB108\uB700",
|
|
1327
|
-
cancelled: "\uCDE8\uC18C\uB428",
|
|
1328
|
-
unknownCommand: (cmd) => `\uC54C \uC218 \uC5C6\uB294 \uBA85\uB839: ${cmd}`,
|
|
1329
|
-
error: (msg) => `\uC624\uB958: ${msg}`,
|
|
1330
|
-
checkWith: "\uC810\uAC80: mimi-seed doctor"
|
|
1331
|
-
},
|
|
1332
|
-
lang: {
|
|
1333
|
-
ask: " \uC5B8\uC5B4\uB97C \uC120\uD0DD\uD574\uC918 [1] \uD55C\uAD6D\uC5B4 [2] English (\uC5D4\uD130=\uD55C\uAD6D\uC5B4): ",
|
|
1334
|
-
saved: (l) => ` \u2705 \uC5B8\uC5B4: ${l === "ko" ? "\uD55C\uAD6D\uC5B4" : "English"} (\uB098\uC911\uC5D0 \uBC14\uAFB8\uAE30: mimi-seed lang en)`,
|
|
1335
|
-
usage: `${"mimi-seed lang"} \u2014 CLI \uCD9C\uB825 \uC5B8\uC5B4
|
|
1336
|
-
|
|
1337
|
-
mimi-seed lang \uD604\uC7AC \uC5B8\uC5B4 \uD45C\uC2DC
|
|
1338
|
-
mimi-seed lang ko \uD55C\uAD6D\uC5B4
|
|
1339
|
-
mimi-seed lang en English
|
|
1340
|
-
|
|
1341
|
-
\uD658\uACBD\uBCC0\uC218 MIMI_SEED_LANG \uAC00 \uC788\uC73C\uBA74 \uADF8\uAC8C \uC6B0\uC120\uD569\uB2C8\uB2E4.`,
|
|
1342
|
-
current: (l) => `\uD604\uC7AC \uC5B8\uC5B4: ${l === "ko" ? "\uD55C\uAD6D\uC5B4 (ko)" : "English (en)"}`,
|
|
1343
|
-
invalid: (v) => `\uC54C \uC218 \uC5C6\uB294 \uC5B8\uC5B4: ${v} (ko \uB610\uB294 en)`
|
|
1344
|
-
},
|
|
1345
|
-
setup: {
|
|
1346
|
-
title: "mimi-seed setup",
|
|
1347
|
-
platformsDetected: (p) => ` \uAC10\uC9C0\uB41C \uD50C\uB7AB\uD3FC: ${p}`,
|
|
1348
|
-
statusTitle: "\uC5F0\uACB0 \uC0C1\uD0DC",
|
|
1349
|
-
statusDir: "(~/.mimi-seed)",
|
|
1350
|
-
groupCore: "\uD575\uC2EC",
|
|
1351
|
-
groupCi: "\uBE4C\uB4DC / CI",
|
|
1352
|
-
groupMarketing: "\uB9C8\uCF00\uD305 \xB7 AI",
|
|
1353
|
-
fallbackWorking: "\uD3F4\uBC31\uC73C\uB85C \uB3D9\uC791 \uC911",
|
|
1354
|
-
missingRequired: " \uD544\uC218 \uD56D\uBAA9 \uB204\uB77D:",
|
|
1355
|
-
cannotInteract: " \u2717 \uC774 \uC790\uACA9\uC99D\uBA85\uC740 \uB300\uD654\uD615 \uC785\uB825\uC774 \uD544\uC694\uD574\uC11C \uC5EC\uAE30\uC11C\uB294 \uC124\uC815\uD560 \uC218 \uC5C6\uC5B4:",
|
|
1356
|
-
cannotInteractHint: " \uD130\uBBF8\uB110\uC5D0\uC11C \uC2E4\uD589\uD574\uC918 (Git Bash \uB4F1 TTY \uBBF8\uAC10\uC9C0 \uD658\uACBD\uC774\uBA74 --interactive).",
|
|
1357
|
-
runInTerminal: " \uB300\uD654\uD615\uC73C\uB85C \uC5F0\uACB0\uD558\uB824\uBA74 \uD130\uBBF8\uB110\uC5D0\uC11C: mimi-seed setup",
|
|
1358
|
-
onlyAlreadyDone: " \u2705 \uC694\uCCAD\uD55C \uD56D\uBAA9\uC740 \uC774\uBBF8 \uC5F0\uACB0\uB3FC \uC788\uC5B4.",
|
|
1359
|
-
onlyReconnectHint: " \uB2E4\uC2DC \uC124\uC815\uD558\uB824\uBA74: mimi-seed setup --reconnect <id>",
|
|
1360
|
-
allDone: " \u2705 \uC5F0\uACB0\uD560 \uAC8C \uB354 \uC5C6\uC5B4. \uB2E4 \uB410\uB2E4.",
|
|
1361
|
-
planCount: (n) => ` ${n}\uAC1C \uD56D\uBAA9\uC744 \uC21C\uC11C\uB300\uB85C \uBB3C\uC5B4\uBCFC\uAC8C. \uC5B8\uC81C\uB4E0 s=\uAC74\uB108\uB6F0\uAE30, q=\uC885\uB8CC.`,
|
|
1362
|
-
prompt: " [c] \uC5F0\uACB0 [s] \uAC74\uB108\uB6F0\uAE30 [?] \uC774\uAC74 \uC5B4\uB5BB\uAC8C \uAD6C\uD558\uB098\uC694 [q] \uC885\uB8CC : ",
|
|
1363
|
-
promptInvalid: " c / s / ? / q \uC911\uC5D0\uC11C \uACE8\uB77C\uC918.",
|
|
1364
|
-
quit: " \uC911\uB2E8\uD588\uC5B4. \uC774\uC5B4\uC11C \uD558\uB824\uBA74 \uB2E4\uC2DC: mimi-seed setup",
|
|
1365
|
-
skipped: (fix) => ` \uAC74\uB108\uB700. \uB098\uC911\uC5D0: ${fix}`,
|
|
1366
|
-
obtainTitle: (label) => ` ${label} \u2014 \uBBF8\uB9AC \uC900\uBE44\uD560 \uAC83`,
|
|
1367
|
-
obtainMore: (anchor) => ` \uC790\uC138\uD788: docs/credentials.md#${anchor}`,
|
|
1368
|
-
neededFor: (platform) => `(${platform} \uBC30\uD3EC\uC5D0 \uD544\uC694)`,
|
|
1369
|
-
binFailed: (label, code, fix) => ` \u26A0 ${label} \uC124\uC815\uC774 \uC644\uB8CC\uB418\uC9C0 \uC54A\uC558\uC5B4 (exit ${code}). \uB098\uC911\uC5D0 \uB2E4\uC2DC: ${fix}`,
|
|
1370
|
-
verifying: " \u{1F50E} \uD1A0\uD070 \uAC80\uC99D \uC911...",
|
|
1371
|
-
verifyFailed: (reason) => ` \u274C \uD1A0\uD070 \uAC80\uC99D \uC2E4\uD328: ${reason}`,
|
|
1372
|
-
notSaved: (fix) => ` \uC800\uC7A5\uD558\uC9C0 \uC54A\uC558\uC5B4. \uB2E4\uC2DC: ${fix}`,
|
|
1373
|
-
ciSaved: (label, who) => ` \u2705 ${label} \uC5F0\uACB0\uB428${who} \u2192 ~/.mimi-seed/ci.json`,
|
|
1374
|
-
runSeparately: (cmd) => ` \uC774\uAC74 \uBCC4\uB3C4 \uBA85\uB839\uC73C\uB85C \uC2E4\uD589\uD574\uC918: ${cmd}`,
|
|
1375
|
-
envVar: " \uD658\uACBD\uBCC0\uC218\uB85C \uC124\uC815\uD558\uB294 \uD56D\uBAA9\uC774\uC57C:",
|
|
1376
|
-
pressEnter: " (\uC5D4\uD130\uB97C \uB204\uB974\uBA74 \uACC4\uC18D) ",
|
|
1377
|
-
stillMissing: " \uC544\uC9C1 \uD544\uC218 \uD56D\uBAA9\uC774 \uB0A8\uC544 \uC788\uC5B4:",
|
|
1378
|
-
requiredDone: " \u2705 \uD544\uC218 \uC5F0\uACB0 \uC644\uB8CC.",
|
|
1379
|
-
nextSteps: " \uC810\uAC80: mimi-seed doctor \xB7 \uBC30\uD3EC: mimi-seed deploy"
|
|
1380
|
-
},
|
|
1381
|
-
doctor: {
|
|
1382
|
-
title: "mimi-seed doctor",
|
|
1383
|
-
secAuth: "\uC778\uC99D",
|
|
1384
|
-
secCreds: "\uB85C\uCEEC \uC790\uACA9\uC99D\uBA85 (~/.mimi-seed)",
|
|
1385
|
-
secEnv: "\uB85C\uCEEC \uD658\uACBD",
|
|
1386
|
-
secApps: "\uC571 \uAC10\uC9C0",
|
|
1387
|
-
noToken: "Mimi Seed \uD1A0\uD070 \uC5C6\uC74C",
|
|
1388
|
-
noTokenFix: "`mimi-seed init` \uC2E4\uD589 \uD544\uC694",
|
|
1389
|
-
tokenSaved: "\uD1A0\uD070 \uC800\uC7A5\uB428",
|
|
1390
|
-
endpoint: "\uC5D4\uB4DC\uD3EC\uC778\uD2B8",
|
|
1391
|
-
ciMode: "CI \uBAA8\uB4DC",
|
|
1392
|
-
ciModeDetail: "MIMI_SEED_TOKEN \uD658\uACBD\uBCC0\uC218 \uC0AC\uC6A9 \uC911",
|
|
1393
|
-
tokenInvalid: "\uD1A0\uD070 \uAC80\uC99D \uC2E4\uD328",
|
|
1394
|
-
serverOk: "Mimi Seed \uC11C\uBC84 \uC5F0\uACB0\uB428",
|
|
1395
|
-
appCount: (n) => `\uC571 ${n}\uAC1C`,
|
|
1396
|
-
unknownService: (id) => `${id} (\uC54C \uC218 \uC5C6\uB294 \uC11C\uBE44\uC2A4)`,
|
|
1397
|
-
credsHint: " \uC804\uBD80 \uC5F0\uACB0\uD558\uAE30: mimi-seed setup \xB7 OAuth \uC2E0\uC120\uB3C4: mimi-seed auth status\n",
|
|
1398
|
-
nodeTooOld: (v) => `${v} \u2014 v20 \uC774\uC0C1 \uD544\uC694 (.nvmrc \uCC38\uACE0)`,
|
|
1399
|
-
gitRepo: "Git \uC800\uC7A5\uC18C",
|
|
1400
|
-
gitTag: (t2) => `\uCD5C\uC2E0 \uD0DC\uADF8: ${t2}`,
|
|
1401
|
-
gitCommits: (n) => `\uCEE4\uBC0B ${n}\uAC1C`,
|
|
1402
|
-
noGit: "Git \uC800\uC7A5\uC18C \uC5C6\uC74C",
|
|
1403
|
-
noGitDetail: "mimi-seed notes \uC0AC\uC6A9 \uBD88\uAC00",
|
|
1404
|
-
noApp: "\uC571 \uAC10\uC9C0 \uC5C6\uC74C",
|
|
1405
|
-
noAppDetail: "app.json / build.gradle / Info.plist \uC5C6\uC74C",
|
|
1406
|
-
unnamed: "(\uC774\uB984 \uBBF8\uC0C1)",
|
|
1407
|
-
requirements: (proj) => `${proj} \uC694\uAD6C\uC0AC\uD56D (.mimi-seed.json)`,
|
|
1408
|
-
thisProject: "\uC774 \uD504\uB85C\uC81D\uD2B8"
|
|
1409
|
-
},
|
|
1410
|
-
auth: {
|
|
1411
|
-
title: "mimi-seed auth \u2014 \uB85C\uCEEC \uC790\uACA9\uC99D\uBA85 \uC778\uC99D/\uAD00\uB9AC",
|
|
1412
|
-
statusTitle: "\uB85C\uCEEC \uC790\uACA9\uC99D\uBA85 \uC0C1\uD0DC",
|
|
1413
|
-
connectAll: "\n \uD55C \uBC88\uC5D0 \uC5F0\uACB0: mimi-seed setup",
|
|
1414
|
-
unknownSub: (sub) => `\uC54C \uC218 \uC5C6\uB294 auth \uC11C\uBE0C\uBA85\uB839: ${sub}`,
|
|
1415
|
-
npxFailed: (cmd, msg) => `
|
|
1416
|
-
\u274C ${cmd} \uC2E4\uD589 \uC2E4\uD328: ${msg}
|
|
1417
|
-
`
|
|
1418
|
-
}
|
|
1419
|
-
};
|
|
1420
|
-
var en = {
|
|
1421
|
-
common: {
|
|
1422
|
-
yes: "y",
|
|
1423
|
-
optional: "optional",
|
|
1424
|
-
required: "required",
|
|
1425
|
-
skip: "skipped",
|
|
1426
|
-
cancelled: "Cancelled",
|
|
1427
|
-
unknownCommand: (cmd) => `Unknown command: ${cmd}`,
|
|
1428
|
-
error: (msg) => `Error: ${msg}`,
|
|
1429
|
-
checkWith: "Check with: mimi-seed doctor"
|
|
1430
|
-
},
|
|
1431
|
-
lang: {
|
|
1432
|
-
ask: " Choose a language [1] \uD55C\uAD6D\uC5B4 [2] English (Enter = \uD55C\uAD6D\uC5B4): ",
|
|
1433
|
-
saved: (l) => ` \u2705 Language: ${l === "ko" ? "\uD55C\uAD6D\uC5B4" : "English"} (change later: mimi-seed lang ko)`,
|
|
1434
|
-
usage: `mimi-seed lang \u2014 CLI output language
|
|
1435
|
-
|
|
1436
|
-
mimi-seed lang show current language
|
|
1437
|
-
mimi-seed lang ko \uD55C\uAD6D\uC5B4
|
|
1438
|
-
mimi-seed lang en English
|
|
1439
|
-
|
|
1440
|
-
MIMI_SEED_LANG takes precedence when set.`,
|
|
1441
|
-
current: (l) => `Current language: ${l === "ko" ? "\uD55C\uAD6D\uC5B4 (ko)" : "English (en)"}`,
|
|
1442
|
-
invalid: (v) => `Unknown language: ${v} (use ko or en)`
|
|
1443
|
-
},
|
|
1444
|
-
setup: {
|
|
1445
|
-
title: "mimi-seed setup",
|
|
1446
|
-
platformsDetected: (p) => ` Detected platforms: ${p}`,
|
|
1447
|
-
statusTitle: "Connection status",
|
|
1448
|
-
statusDir: "(~/.mimi-seed)",
|
|
1449
|
-
groupCore: "Core",
|
|
1450
|
-
groupCi: "Build / CI",
|
|
1451
|
-
groupMarketing: "Marketing \xB7 AI",
|
|
1452
|
-
fallbackWorking: "working via fallback",
|
|
1453
|
-
missingRequired: " Missing required:",
|
|
1454
|
-
cannotInteract: " \u2717 These need interactive input and cannot be set up here:",
|
|
1455
|
-
cannotInteractHint: " Run it in a terminal (add --interactive if your shell hides the TTY, e.g. Git Bash).",
|
|
1456
|
-
runInTerminal: " To connect interactively, run: mimi-seed setup",
|
|
1457
|
-
onlyAlreadyDone: " \u2705 What you asked for is already connected.",
|
|
1458
|
-
onlyReconnectHint: " To redo it: mimi-seed setup --reconnect <id>",
|
|
1459
|
-
allDone: " \u2705 Nothing left to connect. You're set.",
|
|
1460
|
-
planCount: (n) => ` I'll walk you through ${n} item(s). s = skip, q = quit, anytime.`,
|
|
1461
|
-
prompt: " [c] connect [s] skip [?] how do I get this [q] quit : ",
|
|
1462
|
-
promptInvalid: " Please choose c / s / ? / q.",
|
|
1463
|
-
quit: " Stopped. To pick up where you left off: mimi-seed setup",
|
|
1464
|
-
skipped: (fix) => ` Skipped. Later: ${fix}`,
|
|
1465
|
-
obtainTitle: (label) => ` ${label} \u2014 what to get first`,
|
|
1466
|
-
obtainMore: (anchor) => ` Details: docs/credentials.md#${anchor}`,
|
|
1467
|
-
neededFor: (platform) => `(needed to ship to ${platform})`,
|
|
1468
|
-
binFailed: (label, code, fix) => ` \u26A0 ${label} was not completed (exit ${code}). Try again later: ${fix}`,
|
|
1469
|
-
verifying: " \u{1F50E} Verifying token...",
|
|
1470
|
-
verifyFailed: (reason) => ` \u274C Token verification failed: ${reason}`,
|
|
1471
|
-
notSaved: (fix) => ` Nothing was saved. Retry: ${fix}`,
|
|
1472
|
-
ciSaved: (label, who) => ` \u2705 ${label} connected${who} \u2192 ~/.mimi-seed/ci.json`,
|
|
1473
|
-
runSeparately: (cmd) => ` Run this one separately: ${cmd}`,
|
|
1474
|
-
envVar: " This one is set through an environment variable:",
|
|
1475
|
-
pressEnter: " (press Enter to continue) ",
|
|
1476
|
-
stillMissing: " Still missing, and required:",
|
|
1477
|
-
requiredDone: " \u2705 All required credentials connected.",
|
|
1478
|
-
nextSteps: " Check: mimi-seed doctor \xB7 Ship: mimi-seed deploy"
|
|
1479
|
-
},
|
|
1480
|
-
doctor: {
|
|
1481
|
-
title: "mimi-seed doctor",
|
|
1482
|
-
secAuth: "Account",
|
|
1483
|
-
secCreds: "Local credentials (~/.mimi-seed)",
|
|
1484
|
-
secEnv: "Environment",
|
|
1485
|
-
secApps: "App detection",
|
|
1486
|
-
noToken: "No Mimi Seed token",
|
|
1487
|
-
noTokenFix: "run `mimi-seed init`",
|
|
1488
|
-
tokenSaved: "Token stored",
|
|
1489
|
-
endpoint: "Endpoint",
|
|
1490
|
-
ciMode: "CI mode",
|
|
1491
|
-
ciModeDetail: "using MIMI_SEED_TOKEN",
|
|
1492
|
-
tokenInvalid: "Token rejected",
|
|
1493
|
-
serverOk: "Connected to Mimi Seed",
|
|
1494
|
-
appCount: (n) => `${n} app(s)`,
|
|
1495
|
-
unknownService: (id) => `${id} (unknown service)`,
|
|
1496
|
-
credsHint: " Connect everything: mimi-seed setup \xB7 OAuth freshness: mimi-seed auth status\n",
|
|
1497
|
-
nodeTooOld: (v) => `${v} \u2014 v20+ required (see .nvmrc)`,
|
|
1498
|
-
gitRepo: "Git repository",
|
|
1499
|
-
gitTag: (t2) => `latest tag: ${t2}`,
|
|
1500
|
-
gitCommits: (n) => `${n} commit(s)`,
|
|
1501
|
-
noGit: "Not a git repository",
|
|
1502
|
-
noGitDetail: "mimi-seed notes is unavailable",
|
|
1503
|
-
noApp: "No app detected",
|
|
1504
|
-
noAppDetail: "no app.json / build.gradle / Info.plist",
|
|
1505
|
-
unnamed: "(unnamed)",
|
|
1506
|
-
requirements: (proj) => `${proj} requirements (.mimi-seed.json)`,
|
|
1507
|
-
thisProject: "This project"
|
|
1508
|
-
},
|
|
1509
|
-
auth: {
|
|
1510
|
-
title: "mimi-seed auth \u2014 local credential setup",
|
|
1511
|
-
statusTitle: "Local credential status",
|
|
1512
|
-
connectAll: "\n Connect everything at once: mimi-seed setup",
|
|
1513
|
-
unknownSub: (sub) => `Unknown auth subcommand: ${sub}`,
|
|
1514
|
-
npxFailed: (cmd, msg) => `
|
|
1515
|
-
\u274C Failed to run ${cmd}: ${msg}
|
|
1516
|
-
`
|
|
1517
|
-
}
|
|
1518
|
-
};
|
|
1519
|
-
var CATALOGS = { ko, en };
|
|
1520
|
-
function t() {
|
|
1521
|
-
return CATALOGS[resolveLang()];
|
|
1522
|
-
}
|
|
1523
|
-
|
|
1524
1438
|
// src/setup.ts
|
|
1525
1439
|
function log2(msg = "") {
|
|
1526
1440
|
process.stdout.write(msg + "\n");
|
|
@@ -1651,7 +1565,7 @@ async function connectOne(spec) {
|
|
|
1651
1565
|
}
|
|
1652
1566
|
async function cmdSetup(argv) {
|
|
1653
1567
|
const opts = parseSetupArgs(argv);
|
|
1654
|
-
const home =
|
|
1568
|
+
const home = os5.homedir();
|
|
1655
1569
|
migrateLegacyJenkins(home);
|
|
1656
1570
|
if (resolveMode(opts, process.env, process.stdin.isTTY) === "interactive") {
|
|
1657
1571
|
await ensureLangChosen();
|
|
@@ -1756,9 +1670,6 @@ export {
|
|
|
1756
1670
|
deleteConfig,
|
|
1757
1671
|
CONFIG_LOCATION,
|
|
1758
1672
|
getEffectiveConfig,
|
|
1759
|
-
writeSettings,
|
|
1760
|
-
isLang,
|
|
1761
|
-
resolveLang,
|
|
1762
1673
|
credLabel,
|
|
1763
1674
|
credNote,
|
|
1764
1675
|
CREDENTIALS,
|
|
@@ -1766,7 +1677,6 @@ export {
|
|
|
1766
1677
|
detectAll,
|
|
1767
1678
|
isSatisfied,
|
|
1768
1679
|
migrateLegacyJenkins,
|
|
1769
|
-
t,
|
|
1770
1680
|
MCP_PKG,
|
|
1771
1681
|
runMcpBin,
|
|
1772
1682
|
cmdDeploy,
|