mimi-seed 0.6.0 → 0.7.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-47TS72IP.js} +287 -378
- 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-NQHLA3AJ.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) {
|
|
@@ -517,9 +487,7 @@ async function runMcpBin(bin, extraArgs = []) {
|
|
|
517
487
|
env: { ...process.env, MIMI_SEED_LANG: resolveLang() }
|
|
518
488
|
});
|
|
519
489
|
child.on("error", (e) => {
|
|
520
|
-
process.stderr.write(
|
|
521
|
-
\u274C ${cmd} \uC2E4\uD589 \uC2E4\uD328: ${e.message}
|
|
522
|
-
`);
|
|
490
|
+
process.stderr.write(t().auth.npxFailed(cmd, e.message));
|
|
523
491
|
resolve(1);
|
|
524
492
|
});
|
|
525
493
|
child.on("exit", (code) => resolve(code ?? 0));
|
|
@@ -527,28 +495,28 @@ async function runMcpBin(bin, extraArgs = []) {
|
|
|
527
495
|
}
|
|
528
496
|
|
|
529
497
|
// 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 =
|
|
498
|
+
import fs2 from "fs";
|
|
499
|
+
import os2 from "os";
|
|
500
|
+
import path2 from "path";
|
|
501
|
+
var CONFIG_DIR = path2.join(os2.homedir(), ".mimi-seed");
|
|
502
|
+
var JENKINS_PATH = path2.join(CONFIG_DIR, "jenkins.json");
|
|
503
|
+
var LEGACY_PATH = path2.join(CONFIG_DIR, "config.json");
|
|
504
|
+
function loadJenkinsConfig(home = os2.homedir()) {
|
|
537
505
|
try {
|
|
538
|
-
const p =
|
|
539
|
-
return JSON.parse(
|
|
506
|
+
const p = path2.join(home, ".mimi-seed", "jenkins.json");
|
|
507
|
+
return JSON.parse(fs2.readFileSync(p, "utf-8"));
|
|
540
508
|
} catch {
|
|
541
509
|
return null;
|
|
542
510
|
}
|
|
543
511
|
}
|
|
544
|
-
function migrateLegacyJenkins(home =
|
|
545
|
-
const dir =
|
|
546
|
-
const jenkinsPath =
|
|
547
|
-
const legacyPath =
|
|
548
|
-
if (
|
|
512
|
+
function migrateLegacyJenkins(home = os2.homedir()) {
|
|
513
|
+
const dir = path2.join(home, ".mimi-seed");
|
|
514
|
+
const jenkinsPath = path2.join(dir, "jenkins.json");
|
|
515
|
+
const legacyPath = path2.join(dir, "config.json");
|
|
516
|
+
if (fs2.existsSync(jenkinsPath)) return false;
|
|
549
517
|
let legacy;
|
|
550
518
|
try {
|
|
551
|
-
legacy = JSON.parse(
|
|
519
|
+
legacy = JSON.parse(fs2.readFileSync(legacyPath, "utf-8"));
|
|
552
520
|
} catch {
|
|
553
521
|
return false;
|
|
554
522
|
}
|
|
@@ -562,28 +530,28 @@ function migrateLegacyJenkins(home = os3.homedir()) {
|
|
|
562
530
|
...j.jobAndroid ? { jobAndroid: j.jobAndroid } : {},
|
|
563
531
|
...j.jobIos ? { jobIos: j.jobIos } : {}
|
|
564
532
|
};
|
|
565
|
-
|
|
566
|
-
|
|
533
|
+
fs2.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
534
|
+
fs2.writeFileSync(jenkinsPath, JSON.stringify(migrated, null, 2), { mode: 384 });
|
|
567
535
|
delete legacy.jenkins;
|
|
568
536
|
const tmp = `${legacyPath}.tmp`;
|
|
569
|
-
|
|
570
|
-
|
|
537
|
+
fs2.writeFileSync(tmp, JSON.stringify(legacy, null, 2), { mode: 384 });
|
|
538
|
+
fs2.renameSync(tmp, legacyPath);
|
|
571
539
|
return true;
|
|
572
540
|
}
|
|
573
541
|
|
|
574
542
|
// src/detect.ts
|
|
575
|
-
import
|
|
576
|
-
import
|
|
543
|
+
import fs3 from "fs/promises";
|
|
544
|
+
import path3 from "path";
|
|
577
545
|
async function readIfExists(p) {
|
|
578
546
|
try {
|
|
579
|
-
return await
|
|
547
|
+
return await fs3.readFile(p, "utf8");
|
|
580
548
|
} catch {
|
|
581
549
|
return null;
|
|
582
550
|
}
|
|
583
551
|
}
|
|
584
552
|
async function pathExists(p) {
|
|
585
553
|
try {
|
|
586
|
-
await
|
|
554
|
+
await fs3.access(p);
|
|
587
555
|
return true;
|
|
588
556
|
} catch {
|
|
589
557
|
return false;
|
|
@@ -605,16 +573,16 @@ async function walk(root, match, maxDepth = 5) {
|
|
|
605
573
|
if (depth > maxDepth) return;
|
|
606
574
|
let entries;
|
|
607
575
|
try {
|
|
608
|
-
entries = await
|
|
576
|
+
entries = await fs3.readdir(dir, { withFileTypes: true });
|
|
609
577
|
} catch {
|
|
610
578
|
return;
|
|
611
579
|
}
|
|
612
580
|
for (const e of entries) {
|
|
613
581
|
if (e.isDirectory()) {
|
|
614
582
|
if (skipDirs.has(e.name)) continue;
|
|
615
|
-
await visit(
|
|
583
|
+
await visit(path3.join(dir, e.name), depth + 1);
|
|
616
584
|
} else if (e.isFile() && match(e.name)) {
|
|
617
|
-
found.push(
|
|
585
|
+
found.push(path3.join(dir, e.name));
|
|
618
586
|
}
|
|
619
587
|
}
|
|
620
588
|
}
|
|
@@ -624,7 +592,7 @@ async function walk(root, match, maxDepth = 5) {
|
|
|
624
592
|
async function detectHints(cwd) {
|
|
625
593
|
const hints = [];
|
|
626
594
|
for (const fname of ["app.json", "app.config.json"]) {
|
|
627
|
-
const txt = await readIfExists(
|
|
595
|
+
const txt = await readIfExists(path3.join(cwd, fname));
|
|
628
596
|
if (!txt) continue;
|
|
629
597
|
try {
|
|
630
598
|
const json = JSON.parse(txt);
|
|
@@ -655,7 +623,7 @@ async function detectHints(cwd) {
|
|
|
655
623
|
if (m?.[1]) {
|
|
656
624
|
const pkg = m[1];
|
|
657
625
|
if (!hints.some((h) => h.packageName === pkg)) {
|
|
658
|
-
hints.push({ packageName: pkg, source: [
|
|
626
|
+
hints.push({ packageName: pkg, source: [path3.relative(cwd, f)] });
|
|
659
627
|
}
|
|
660
628
|
}
|
|
661
629
|
}
|
|
@@ -670,7 +638,7 @@ async function detectHints(cwd) {
|
|
|
670
638
|
let bid = m[1];
|
|
671
639
|
if (bid.includes("$(PRODUCT_BUNDLE_IDENTIFIER)")) continue;
|
|
672
640
|
if (!hints.some((h) => h.bundleId === bid)) {
|
|
673
|
-
hints.push({ bundleId: bid, source: [
|
|
641
|
+
hints.push({ bundleId: bid, source: [path3.relative(cwd, f)] });
|
|
674
642
|
}
|
|
675
643
|
}
|
|
676
644
|
}
|
|
@@ -683,11 +651,11 @@ async function detectHints(cwd) {
|
|
|
683
651
|
const bid = m[1].trim().replace(/^["']|["']$/g, "");
|
|
684
652
|
if (!bid || bid.includes("$")) continue;
|
|
685
653
|
if (!hints.some((h) => h.bundleId === bid)) {
|
|
686
|
-
hints.push({ bundleId: bid, source: [
|
|
654
|
+
hints.push({ bundleId: bid, source: [path3.relative(cwd, f)] });
|
|
687
655
|
}
|
|
688
656
|
}
|
|
689
657
|
}
|
|
690
|
-
const pkgJson = await readIfExists(
|
|
658
|
+
const pkgJson = await readIfExists(path3.join(cwd, "package.json"));
|
|
691
659
|
if (pkgJson) {
|
|
692
660
|
try {
|
|
693
661
|
const json = JSON.parse(pkgJson);
|
|
@@ -723,7 +691,7 @@ async function detectHints(cwd) {
|
|
|
723
691
|
return merged.filter((h) => h.packageName || h.bundleId);
|
|
724
692
|
}
|
|
725
693
|
async function hasAnyProjectSignal(cwd) {
|
|
726
|
-
return await pathExists(
|
|
694
|
+
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
695
|
}
|
|
728
696
|
|
|
729
697
|
// src/deploy.ts
|
|
@@ -731,28 +699,28 @@ import kleur from "kleur";
|
|
|
731
699
|
import * as readline from "readline";
|
|
732
700
|
|
|
733
701
|
// src/config.ts
|
|
734
|
-
import
|
|
735
|
-
import
|
|
736
|
-
import
|
|
737
|
-
var CONFIG_DIR2 =
|
|
738
|
-
var CONFIG_PATH =
|
|
702
|
+
import fs4 from "fs/promises";
|
|
703
|
+
import path4 from "path";
|
|
704
|
+
import os3 from "os";
|
|
705
|
+
var CONFIG_DIR2 = path4.join(os3.homedir(), ".mimi-seed");
|
|
706
|
+
var CONFIG_PATH = path4.join(CONFIG_DIR2, "config.json");
|
|
739
707
|
async function readConfig() {
|
|
740
708
|
try {
|
|
741
|
-
const txt = await
|
|
709
|
+
const txt = await fs4.readFile(CONFIG_PATH, "utf8");
|
|
742
710
|
return JSON.parse(txt);
|
|
743
711
|
} catch {
|
|
744
712
|
return null;
|
|
745
713
|
}
|
|
746
714
|
}
|
|
747
715
|
async function writeConfig(cfg) {
|
|
748
|
-
await
|
|
749
|
-
await
|
|
716
|
+
await fs4.mkdir(CONFIG_DIR2, { recursive: true });
|
|
717
|
+
await fs4.writeFile(CONFIG_PATH, JSON.stringify(cfg, null, 2));
|
|
750
718
|
if (process.platform !== "win32") {
|
|
751
|
-
await
|
|
719
|
+
await fs4.chmod(CONFIG_PATH, 384);
|
|
752
720
|
}
|
|
753
721
|
}
|
|
754
722
|
async function deleteConfig() {
|
|
755
|
-
await
|
|
723
|
+
await fs4.rm(CONFIG_PATH, { force: true });
|
|
756
724
|
}
|
|
757
725
|
var CONFIG_LOCATION = CONFIG_PATH;
|
|
758
726
|
async function getEffectiveConfig() {
|
|
@@ -771,13 +739,28 @@ async function getEffectiveConfig() {
|
|
|
771
739
|
}
|
|
772
740
|
|
|
773
741
|
// src/ci-providers.ts
|
|
774
|
-
import
|
|
775
|
-
import
|
|
776
|
-
import
|
|
777
|
-
var CI_CONFIG_PATH =
|
|
742
|
+
import fs5 from "fs";
|
|
743
|
+
import path5 from "path";
|
|
744
|
+
import os4 from "os";
|
|
745
|
+
var CI_CONFIG_PATH = path5.join(os4.homedir(), ".mimi-seed", "ci.json");
|
|
746
|
+
var M = catalog(
|
|
747
|
+
{
|
|
748
|
+
badToken: (provider, status) => `${provider} ${status} \u2014 \uD1A0\uD070\uC774 \uC720\uD6A8\uD558\uC9C0 \uC54A\uC544`,
|
|
749
|
+
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.`,
|
|
750
|
+
pollFailed: (provider) => `${provider} API \uC5F0\uC18D \uC624\uB958 3\uD68C`,
|
|
751
|
+
pollFailedHttp: (provider, status) => `${provider} API \uC5F0\uC18D \uC624\uB958 (HTTP ${status})`
|
|
752
|
+
},
|
|
753
|
+
{
|
|
754
|
+
badToken: (provider, status) => `${provider} ${status} \u2014 the token is not valid`,
|
|
755
|
+
noScope: (scopes) => `The token is missing the \`workflow\` scope (currently: ${scopes || "none"}). Triggering a workflow will be blocked with a 403.`,
|
|
756
|
+
// 프로바이더 이름("GitHub API")은 두 언어 모두에 남는다 — 테스트가 그걸로 단언한다.
|
|
757
|
+
pollFailed: (provider) => `${provider} API failed 3 times in a row`,
|
|
758
|
+
pollFailedHttp: (provider, status) => `${provider} API failed 3 times in a row (HTTP ${status})`
|
|
759
|
+
}
|
|
760
|
+
);
|
|
778
761
|
function loadCiProviderConfig() {
|
|
779
762
|
try {
|
|
780
|
-
const cfg = JSON.parse(
|
|
763
|
+
const cfg = JSON.parse(fs5.readFileSync(CI_CONFIG_PATH, "utf-8"));
|
|
781
764
|
const host = normalizeHost(cfg.host);
|
|
782
765
|
return host ? { ...cfg, host } : { ...cfg, host: void 0 };
|
|
783
766
|
} catch {
|
|
@@ -791,15 +774,15 @@ function normalizeHost(host) {
|
|
|
791
774
|
return withScheme.replace(/\/+$/, "");
|
|
792
775
|
}
|
|
793
776
|
function saveCiProviderConfig(cfg) {
|
|
794
|
-
const dir =
|
|
795
|
-
if (!
|
|
796
|
-
|
|
777
|
+
const dir = path5.dirname(CI_CONFIG_PATH);
|
|
778
|
+
if (!fs5.existsSync(dir)) {
|
|
779
|
+
fs5.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
797
780
|
}
|
|
798
781
|
const normalized = { ...cfg, host: normalizeHost(cfg.host) };
|
|
799
782
|
if (!normalized.host) delete normalized.host;
|
|
800
|
-
|
|
783
|
+
fs5.writeFileSync(CI_CONFIG_PATH, JSON.stringify(normalized, null, 2));
|
|
801
784
|
if (process.platform !== "win32") {
|
|
802
|
-
|
|
785
|
+
fs5.chmodSync(CI_CONFIG_PATH, 384);
|
|
803
786
|
}
|
|
804
787
|
}
|
|
805
788
|
async function verifyCiToken(cfg) {
|
|
@@ -810,21 +793,18 @@ async function verifyCiToken(cfg) {
|
|
|
810
793
|
headers: { Authorization: `Bearer ${probe.token}`, Accept: "application/vnd.github+json" }
|
|
811
794
|
});
|
|
812
795
|
if (!res2.ok) {
|
|
813
|
-
return { ok: false, reason:
|
|
796
|
+
return { ok: false, reason: M().badToken("GitHub", res2.status) };
|
|
814
797
|
}
|
|
815
798
|
const user2 = await res2.json();
|
|
816
799
|
const scopes = res2.headers.get("x-oauth-scopes");
|
|
817
800
|
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
|
-
};
|
|
801
|
+
return { ok: false, reason: M().noScope(scopes) };
|
|
822
802
|
}
|
|
823
803
|
return { ok: true, login: user2.login };
|
|
824
804
|
}
|
|
825
805
|
const res = await fetch(`${glBase(probe)}/user`, { headers: { "PRIVATE-TOKEN": probe.token } });
|
|
826
806
|
if (!res.ok) {
|
|
827
|
-
return { ok: false, reason:
|
|
807
|
+
return { ok: false, reason: M().badToken("GitLab", res.status) };
|
|
828
808
|
}
|
|
829
809
|
const user = await res.json();
|
|
830
810
|
return { ok: true, login: user.username };
|
|
@@ -882,12 +862,12 @@ async function ghPollRun(cfg, runId, onTick, timeoutMs = 30 * 60 * 1e3, interval
|
|
|
882
862
|
);
|
|
883
863
|
} catch {
|
|
884
864
|
consecutiveErrors++;
|
|
885
|
-
if (consecutiveErrors >= 3) throw new Error("GitHub
|
|
865
|
+
if (consecutiveErrors >= 3) throw new Error(M().pollFailed("GitHub"));
|
|
886
866
|
continue;
|
|
887
867
|
}
|
|
888
868
|
if (!res.ok) {
|
|
889
869
|
consecutiveErrors++;
|
|
890
|
-
if (consecutiveErrors >= 3) throw new Error(
|
|
870
|
+
if (consecutiveErrors >= 3) throw new Error(M().pollFailedHttp("GitHub", res.status));
|
|
891
871
|
continue;
|
|
892
872
|
}
|
|
893
873
|
consecutiveErrors = 0;
|
|
@@ -933,12 +913,12 @@ async function glPollPipeline(cfg, pipelineId, onTick, timeoutMs = 30 * 60 * 1e3
|
|
|
933
913
|
);
|
|
934
914
|
} catch {
|
|
935
915
|
consecutiveErrors++;
|
|
936
|
-
if (consecutiveErrors >= 3) throw new Error("GitLab
|
|
916
|
+
if (consecutiveErrors >= 3) throw new Error(M().pollFailed("GitLab"));
|
|
937
917
|
continue;
|
|
938
918
|
}
|
|
939
919
|
if (!res.ok) {
|
|
940
920
|
consecutiveErrors++;
|
|
941
|
-
if (consecutiveErrors >= 3) throw new Error(
|
|
921
|
+
if (consecutiveErrors >= 3) throw new Error(M().pollFailedHttp("GitLab", res.status));
|
|
942
922
|
continue;
|
|
943
923
|
}
|
|
944
924
|
consecutiveErrors = 0;
|
|
@@ -964,6 +944,144 @@ var PHASE_ICON = {
|
|
|
964
944
|
function log(msg) {
|
|
965
945
|
process.stdout.write(msg + "\n");
|
|
966
946
|
}
|
|
947
|
+
var M2 = catalog(
|
|
948
|
+
{
|
|
949
|
+
// Jenkins / 빌드
|
|
950
|
+
jenkinsTriggerFailed: (status, body) => `Jenkins \uD2B8\uB9AC\uAC70 \uC2E4\uD328 ${status}: ${body}`,
|
|
951
|
+
buildStatusFailed: (status) => `\uBE4C\uB4DC \uC0C1\uD0DC \uC870\uD68C \uC2E4\uD328 ${status}`,
|
|
952
|
+
jenkinsConnErrorFatal: "Jenkins \uC5F0\uACB0 \uC624\uB958 3\uD68C \uC5F0\uC18D \u2014 \uB124\uD2B8\uC6CC\uD06C\uB97C \uD655\uC778\uD558\uC138\uC694",
|
|
953
|
+
jenkinsConnErrorRetry: (n) => `Jenkins \uC5F0\uACB0 \uC624\uB958 (${n}/3\uD68C), \uC7AC\uC2DC\uB3C4...`,
|
|
954
|
+
buildRunning: "\uBE4C\uB4DC \uC9C4\uD589 \uC911",
|
|
955
|
+
buildTimeout: "\uBE4C\uB4DC \uD0C0\uC784\uC544\uC6C3 (30\uBD84)",
|
|
956
|
+
// 서버 스트림
|
|
957
|
+
serverDeployFailed: (status, body) => `\uC11C\uBC84 \uBC30\uD3EC \uC2E4\uD328 ${status}: ${body}`,
|
|
958
|
+
noSseStream: "SSE \uC2A4\uD2B8\uB9BC \uC5C6\uC74C",
|
|
959
|
+
// CI provider 설정 프롬프트
|
|
960
|
+
githubSetupTitle: "GitHub Actions \uC124\uC815",
|
|
961
|
+
gitlabSetupTitle: "GitLab CI \uC124\uC815",
|
|
962
|
+
githubTokenPrompt: " GitHub Personal Access Token (repo+workflow \uC2A4\uCF54\uD504): ",
|
|
963
|
+
gitlabTokenPrompt: " GitLab Personal Access Token: ",
|
|
964
|
+
githubOwnerPrompt: " Owner (org/user): ",
|
|
965
|
+
gitlabOwnerPrompt: " Namespace/group: ",
|
|
966
|
+
repoPrompt: " Repo \uC774\uB984 (\uACBD\uB85C \uC5C6\uC774): ",
|
|
967
|
+
githubHostPrompt: " GitHub Enterprise host (\uC120\uD0DD, \uC5D4\uD130=github.com): ",
|
|
968
|
+
gitlabHostPrompt: " GitLab self-hosted URL (\uC120\uD0DD, \uC5D4\uD130=gitlab.com): ",
|
|
969
|
+
githubSaved: "\u2705 GitHub Actions \uC124\uC815 \uC800\uC7A5\uB428 \u2192 ~/.mimi-seed/ci.json",
|
|
970
|
+
gitlabSaved: "\u2705 GitLab CI \uC124\uC815 \uC800\uC7A5\uB428 \u2192 ~/.mimi-seed/ci.json",
|
|
971
|
+
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",
|
|
972
|
+
// GitHub / GitLab 빌드
|
|
973
|
+
workflowRequired: "--workflow \uD544\uC694 (\uC608: --workflow deploy.yml)",
|
|
974
|
+
ghTrigger: (workflow, ref) => `\u{1F528} GitHub Actions \uD2B8\uB9AC\uAC70: ${workflow} @ ${ref}`,
|
|
975
|
+
ghRunIdFailed: "GitHub Actions run_id \uC870\uD68C \uC2E4\uD328. \uC7A0\uC2DC \uD6C4 ci_list_recent_builds \uB85C \uD655\uC778\uD558\uC138\uC694.",
|
|
976
|
+
ghRunId: (id, url) => ` Run ID: ${id} \u2192 ${url}`,
|
|
977
|
+
glTrigger: (ref) => `\u{1F528} GitLab Pipeline \uD2B8\uB9AC\uAC70: ${ref}`,
|
|
978
|
+
glPipelineId: (id, url) => ` Pipeline ID: ${id} \u2192 ${url}`,
|
|
979
|
+
waitingForCompletion: " \uC644\uB8CC \uB300\uAE30 \uC911...",
|
|
980
|
+
buildSucceeded: (n) => `\u2705 \uBE4C\uB4DC #${n} \uC131\uACF5`,
|
|
981
|
+
buildEnded: (result) => `\uBE4C\uB4DC \uC885\uB8CC: ${result}`,
|
|
982
|
+
alreadyBuiltHint: (versionCode, platform) => ` \uBE4C\uB4DC\uAC00 \uC774\uBBF8 \uC644\uB8CC\uB410\uB2E4\uBA74: mimi-seed deploy --skip-build --version-code ${versionCode} --platform ${platform}`,
|
|
983
|
+
// cmdDeploy
|
|
984
|
+
noAccount: "\uC5F0\uACB0\uB41C \uACC4\uC815 \uC5C6\uC74C. `mimi-seed init` \uC2E4\uD589.",
|
|
985
|
+
title: (platform) => `mimi-seed deploy \u2014 ${platform}`,
|
|
986
|
+
dryRunNotice: " [dry-run \uBAA8\uB4DC] \uC2E4\uC81C \uBC30\uD3EC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4",
|
|
987
|
+
ciLine: (kind) => ` CI: ${kind}`,
|
|
988
|
+
noJenkinsConfig: "Jenkins \uC124\uC815 \uC5C6\uC74C. `mimi-seed deploy setup-jenkins` \uB85C \uC124\uC815\uD558\uAC70\uB098 --skip-build \uC0AC\uC6A9.",
|
|
989
|
+
noJenkinsJob: (platform) => `${platform} Jenkins job\uC774 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. setup-jenkins \uC2E4\uD589.`,
|
|
990
|
+
jenkinsTrigger: (job) => `\u{1F528} Jenkins \uBE4C\uB4DC \uD2B8\uB9AC\uAC70: ${job}`,
|
|
991
|
+
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.",
|
|
992
|
+
queueItem: (id) => ` Queue item: ${id}`,
|
|
993
|
+
waitingForBuildNumber: " \uBE4C\uB4DC \uBC88\uD638 \uB300\uAE30 \uC911...",
|
|
994
|
+
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.",
|
|
995
|
+
buildStarted: (n) => ` \uBE4C\uB4DC #${n} \uC2DC\uC791\uB428. \uC644\uB8CC \uB300\uAE30 \uC911...`,
|
|
996
|
+
buildFailed: (result) => `\uBE4C\uB4DC \uC2E4\uD328: ${result}`,
|
|
997
|
+
jenkinsLink: (url) => ` Jenkins: ${url}`,
|
|
998
|
+
versionCodeFromBuild: (n) => ` versionCode = buildNumber (${n})`,
|
|
999
|
+
noProviderConfig: (kind) => `${kind} \uC124\uC815\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. setup-${kind} \uC2E4\uD589.`,
|
|
1000
|
+
versionCodeUnsuitable: (kind, buildId) => `\u2717 versionCode \uBBF8\uC9C0\uC815 (${kind} run_id ${buildId}\uB294 versionCode\uB85C \uBD80\uC801\uD569)`,
|
|
1001
|
+
recommendation: " \uAD8C\uC7A5 \uC0AC\uD56D:",
|
|
1002
|
+
recommendationCi: " \u2022 CI \uC6CC\uD06C\uD50C\uB85C \uC548\uC5D0\uC11C versionCode\uB97C \uACB0\uC815\uD558\uACE0 \uACB0\uACFC\uB97C \uCD9C\uB825",
|
|
1003
|
+
recommendationNext: " \u2022 \uB2E4\uC74C \uC2E4\uD589: mimi-seed deploy --skip-build --version-code <N>",
|
|
1004
|
+
versionCodeUnknown: "versionCode\uB97C \uC54C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. --version-code <N> \uC73C\uB85C \uC9C0\uC815\uD558\uC138\uC694.",
|
|
1005
|
+
appLine: (name, id) => ` \uC571: ${name} (${id})`,
|
|
1006
|
+
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.",
|
|
1007
|
+
// 프로덕션 확인
|
|
1008
|
+
targetIos: "App Store \uC2EC\uC0AC \uC81C\uCD9C",
|
|
1009
|
+
targetAndroid: "Play Store production \uD2B8\uB799",
|
|
1010
|
+
realDeploy: (platform, versionCode, target) => `\u26A0 \uC2E4\uC81C \uBC30\uD3EC: ${platform} \xB7 versionCode ${versionCode} \u2192 ${target}`,
|
|
1011
|
+
confirmPrompt: "\uACC4\uC18D \uC9C4\uD589\uD560\uAE4C\uC694? [y/N]: ",
|
|
1012
|
+
confirmCancelled: "\uCDE8\uC18C\uB428. (--yes \uB85C \uD655\uC778 \uC0DD\uB7B5 \uAC00\uB2A5)",
|
|
1013
|
+
pipelineStarting: "\u{1F4E1} \uC11C\uBC84 \uBC30\uD3EC \uD30C\uC774\uD504\uB77C\uC778 \uC2DC\uC791...",
|
|
1014
|
+
done: "\uC644\uB8CC. Play Console\uC5D0\uC11C \uBC30\uD3EC \uC0C1\uD0DC\uB97C \uD655\uC778\uD558\uC138\uC694."
|
|
1015
|
+
},
|
|
1016
|
+
{
|
|
1017
|
+
// Jenkins / build
|
|
1018
|
+
jenkinsTriggerFailed: (status, body) => `Jenkins trigger failed ${status}: ${body}`,
|
|
1019
|
+
buildStatusFailed: (status) => `Failed to fetch build status ${status}`,
|
|
1020
|
+
jenkinsConnErrorFatal: "Jenkins connection failed 3 times in a row \u2014 check your network",
|
|
1021
|
+
jenkinsConnErrorRetry: (n) => `Jenkins connection error (${n}/3), retrying...`,
|
|
1022
|
+
buildRunning: "Build running",
|
|
1023
|
+
buildTimeout: "Build timed out (30 min)",
|
|
1024
|
+
// Server stream
|
|
1025
|
+
serverDeployFailed: (status, body) => `Server deploy failed ${status}: ${body}`,
|
|
1026
|
+
noSseStream: "No SSE stream",
|
|
1027
|
+
// CI provider setup prompts
|
|
1028
|
+
githubSetupTitle: "GitHub Actions setup",
|
|
1029
|
+
gitlabSetupTitle: "GitLab CI setup",
|
|
1030
|
+
githubTokenPrompt: " GitHub Personal Access Token (repo+workflow scopes): ",
|
|
1031
|
+
gitlabTokenPrompt: " GitLab Personal Access Token: ",
|
|
1032
|
+
githubOwnerPrompt: " Owner (org/user): ",
|
|
1033
|
+
gitlabOwnerPrompt: " Namespace/group: ",
|
|
1034
|
+
repoPrompt: " Repo name (without the path): ",
|
|
1035
|
+
githubHostPrompt: " GitHub Enterprise host (optional, Enter = github.com): ",
|
|
1036
|
+
gitlabHostPrompt: " GitLab self-hosted URL (optional, Enter = gitlab.com): ",
|
|
1037
|
+
githubSaved: "\u2705 GitHub Actions config saved \u2192 ~/.mimi-seed/ci.json",
|
|
1038
|
+
gitlabSaved: "\u2705 GitLab CI config saved \u2192 ~/.mimi-seed/ci.json",
|
|
1039
|
+
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",
|
|
1040
|
+
// GitHub / GitLab build
|
|
1041
|
+
workflowRequired: "--workflow is required (e.g. --workflow deploy.yml)",
|
|
1042
|
+
ghTrigger: (workflow, ref) => `\u{1F528} Triggering GitHub Actions: ${workflow} @ ${ref}`,
|
|
1043
|
+
ghRunIdFailed: "Could not resolve the GitHub Actions run_id. Check with ci_list_recent_builds in a moment.",
|
|
1044
|
+
ghRunId: (id, url) => ` Run ID: ${id} \u2192 ${url}`,
|
|
1045
|
+
glTrigger: (ref) => `\u{1F528} Triggering GitLab Pipeline: ${ref}`,
|
|
1046
|
+
glPipelineId: (id, url) => ` Pipeline ID: ${id} \u2192 ${url}`,
|
|
1047
|
+
waitingForCompletion: " Waiting for it to finish...",
|
|
1048
|
+
buildSucceeded: (n) => `\u2705 Build #${n} succeeded`,
|
|
1049
|
+
buildEnded: (result) => `Build ended: ${result}`,
|
|
1050
|
+
alreadyBuiltHint: (versionCode, platform) => ` If the build already finished: mimi-seed deploy --skip-build --version-code ${versionCode} --platform ${platform}`,
|
|
1051
|
+
// cmdDeploy
|
|
1052
|
+
noAccount: "No account connected. Run `mimi-seed init`.",
|
|
1053
|
+
title: (platform) => `mimi-seed deploy \u2014 ${platform}`,
|
|
1054
|
+
dryRunNotice: " [dry-run] nothing will actually be deployed",
|
|
1055
|
+
ciLine: (kind) => ` CI: ${kind}`,
|
|
1056
|
+
noJenkinsConfig: "Jenkins is not configured. Run `mimi-seed deploy setup-jenkins`, or use --skip-build.",
|
|
1057
|
+
noJenkinsJob: (platform) => `No Jenkins job configured for ${platform}. Run setup-jenkins.`,
|
|
1058
|
+
jenkinsTrigger: (job) => `\u{1F528} Triggering Jenkins build: ${job}`,
|
|
1059
|
+
noQueueItem: " \u26A0 Could not read the queue item ID. The build may have started anyway.",
|
|
1060
|
+
queueItem: (id) => ` Queue item: ${id}`,
|
|
1061
|
+
waitingForBuildNumber: " Waiting for the build number...",
|
|
1062
|
+
noBuildNumber: " Could not read the build number. Retry with --skip-build + --version-code.",
|
|
1063
|
+
buildStarted: (n) => ` Build #${n} started. Waiting for it to finish...`,
|
|
1064
|
+
buildFailed: (result) => `Build failed: ${result}`,
|
|
1065
|
+
jenkinsLink: (url) => ` Jenkins: ${url}`,
|
|
1066
|
+
versionCodeFromBuild: (n) => ` versionCode = buildNumber (${n})`,
|
|
1067
|
+
noProviderConfig: (kind) => `${kind} is not configured. Run setup-${kind}.`,
|
|
1068
|
+
versionCodeUnsuitable: (kind, buildId) => `\u2717 No versionCode given (${kind} run_id ${buildId} is not usable as a versionCode)`,
|
|
1069
|
+
recommendation: " Recommended:",
|
|
1070
|
+
recommendationCi: " \u2022 Decide the versionCode inside the CI workflow and print it",
|
|
1071
|
+
recommendationNext: " \u2022 Then run: mimi-seed deploy --skip-build --version-code <N>",
|
|
1072
|
+
versionCodeUnknown: "Unknown versionCode. Pass it with --version-code <N>.",
|
|
1073
|
+
appLine: (name, id) => ` App: ${name} (${id})`,
|
|
1074
|
+
noAppId: "Could not resolve the appId. Pass --app <id>, or register the app with `mimi-seed init`.",
|
|
1075
|
+
// Production confirmation
|
|
1076
|
+
targetIos: "App Store review submission",
|
|
1077
|
+
targetAndroid: "Play Store production track",
|
|
1078
|
+
realDeploy: (platform, versionCode, target) => `\u26A0 Real deploy: ${platform} \xB7 versionCode ${versionCode} \u2192 ${target}`,
|
|
1079
|
+
confirmPrompt: "Continue? [y/N]: ",
|
|
1080
|
+
confirmCancelled: "Cancelled. (use --yes to skip this confirmation)",
|
|
1081
|
+
pipelineStarting: "\u{1F4E1} Starting the server deploy pipeline...",
|
|
1082
|
+
done: "Done. Check the deploy status in Play Console."
|
|
1083
|
+
}
|
|
1084
|
+
);
|
|
967
1085
|
function jenkinsHeaders(cfg) {
|
|
968
1086
|
const creds = Buffer.from(`${cfg.username || "admin"}:${cfg.token}`).toString("base64");
|
|
969
1087
|
return { Authorization: `Basic ${creds}`, "Content-Type": "application/json" };
|
|
@@ -973,7 +1091,7 @@ async function triggerBuild(cfg, jobName, params) {
|
|
|
973
1091
|
const url = `${cfg.url}/job/${encodeURIComponent(jobName)}/buildWithParameters?${qs}`;
|
|
974
1092
|
const res = await fetch(url, { method: "POST", headers: jenkinsHeaders(cfg) });
|
|
975
1093
|
if (!res.ok) {
|
|
976
|
-
throw new Error(
|
|
1094
|
+
throw new Error(M2().jenkinsTriggerFailed(res.status, await res.text()));
|
|
977
1095
|
}
|
|
978
1096
|
const location = res.headers.get("Location") ?? "";
|
|
979
1097
|
const match = location.match(/\/queue\/item\/(\d+)\//);
|
|
@@ -989,7 +1107,7 @@ async function getQueueBuildNumber(cfg, queueItemId) {
|
|
|
989
1107
|
async function getBuildStatus(cfg, jobName, buildNumber) {
|
|
990
1108
|
const url = `${cfg.url}/job/${encodeURIComponent(jobName)}/${buildNumber}/api/json`;
|
|
991
1109
|
const res = await fetch(url, { headers: jenkinsHeaders(cfg) });
|
|
992
|
-
if (!res.ok) throw new Error(
|
|
1110
|
+
if (!res.ok) throw new Error(M2().buildStatusFailed(res.status));
|
|
993
1111
|
const data = await res.json();
|
|
994
1112
|
return {
|
|
995
1113
|
building: data.building ?? true,
|
|
@@ -1010,18 +1128,18 @@ async function pollBuildComplete(cfg, jobName, buildNumber, timeoutMs = 30 * 60
|
|
|
1010
1128
|
consecutiveErrors = 0;
|
|
1011
1129
|
} catch {
|
|
1012
1130
|
consecutiveErrors++;
|
|
1013
|
-
if (consecutiveErrors >= 3) throw new Error(
|
|
1014
|
-
process.stdout.write(`\r \u26A0
|
|
1131
|
+
if (consecutiveErrors >= 3) throw new Error(M2().jenkinsConnErrorFatal);
|
|
1132
|
+
process.stdout.write(`\r \u26A0 ${M2().jenkinsConnErrorRetry(consecutiveErrors)} `);
|
|
1015
1133
|
continue;
|
|
1016
1134
|
}
|
|
1017
1135
|
dots = (dots + 1) % 4;
|
|
1018
|
-
process.stdout.write(`\r \u23F3
|
|
1136
|
+
process.stdout.write(`\r \u23F3 ${M2().buildRunning}${".".repeat(dots + 1)} `);
|
|
1019
1137
|
if (!status.building) {
|
|
1020
1138
|
process.stdout.write("\n");
|
|
1021
1139
|
return status.result ?? "FAILURE";
|
|
1022
1140
|
}
|
|
1023
1141
|
}
|
|
1024
|
-
throw new Error(
|
|
1142
|
+
throw new Error(M2().buildTimeout);
|
|
1025
1143
|
}
|
|
1026
1144
|
async function streamDeploy(webBase, token, body) {
|
|
1027
1145
|
const res = await fetch(`${webBase}/api/deploy`, {
|
|
@@ -1034,10 +1152,10 @@ async function streamDeploy(webBase, token, body) {
|
|
|
1034
1152
|
});
|
|
1035
1153
|
if (!res.ok) {
|
|
1036
1154
|
const text = await res.text().catch(() => "");
|
|
1037
|
-
throw new Error(
|
|
1155
|
+
throw new Error(M2().serverDeployFailed(res.status, text.slice(0, 200)));
|
|
1038
1156
|
}
|
|
1039
1157
|
const reader = res.body?.getReader();
|
|
1040
|
-
if (!reader) throw new Error(
|
|
1158
|
+
if (!reader) throw new Error(M2().noSseStream);
|
|
1041
1159
|
const decoder = new TextDecoder();
|
|
1042
1160
|
let buf = "";
|
|
1043
1161
|
while (true) {
|
|
@@ -1097,12 +1215,13 @@ async function promptGitProviderSetup(provider) {
|
|
|
1097
1215
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
1098
1216
|
const ask2 = (q) => new Promise((resolve) => rl.question(q, (a) => resolve(a.trim())));
|
|
1099
1217
|
const isGh = provider === "github";
|
|
1100
|
-
|
|
1101
|
-
|
|
1218
|
+
const m = M2();
|
|
1219
|
+
log(kleur.bold(isGh ? m.githubSetupTitle : m.gitlabSetupTitle));
|
|
1220
|
+
const tokenLabel = isGh ? m.githubTokenPrompt : m.gitlabTokenPrompt;
|
|
1102
1221
|
const token = await ask2(tokenLabel);
|
|
1103
|
-
const owner = await ask2(isGh ?
|
|
1104
|
-
const repo = await ask2(
|
|
1105
|
-
const hostPrompt = isGh ?
|
|
1222
|
+
const owner = await ask2(isGh ? m.githubOwnerPrompt : m.gitlabOwnerPrompt);
|
|
1223
|
+
const repo = await ask2(m.repoPrompt);
|
|
1224
|
+
const hostPrompt = isGh ? m.githubHostPrompt : m.gitlabHostPrompt;
|
|
1106
1225
|
const host = await ask2(hostPrompt);
|
|
1107
1226
|
rl.close();
|
|
1108
1227
|
return {
|
|
@@ -1117,38 +1236,36 @@ function resolveCi(ciOption, jenkins, ciProvider) {
|
|
|
1117
1236
|
if (ciOption !== "auto") return ciOption;
|
|
1118
1237
|
if (jenkins?.url && jenkins.token) return "jenkins";
|
|
1119
1238
|
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
|
-
);
|
|
1239
|
+
throw new Error(M2().noCiConfig);
|
|
1123
1240
|
}
|
|
1124
1241
|
async function runGitProviderBuild(cfg, args) {
|
|
1125
1242
|
let runUrl = "";
|
|
1126
1243
|
let runId;
|
|
1127
1244
|
if (cfg.provider === "github") {
|
|
1128
1245
|
if (!args.workflow) {
|
|
1129
|
-
throw new Error(
|
|
1246
|
+
throw new Error(M2().workflowRequired);
|
|
1130
1247
|
}
|
|
1131
|
-
log(
|
|
1248
|
+
log(M2().ghTrigger(kleur.cyan(args.workflow), args.ref));
|
|
1132
1249
|
const inputs = {};
|
|
1133
1250
|
if (args.appId) inputs.MIMI_APP_ID = args.appId;
|
|
1134
1251
|
inputs.PLATFORM = args.platform;
|
|
1135
1252
|
const result2 = await ghTriggerWorkflow(cfg, args.workflow, args.ref, inputs);
|
|
1136
1253
|
if (!result2) {
|
|
1137
|
-
throw new Error(
|
|
1254
|
+
throw new Error(M2().ghRunIdFailed);
|
|
1138
1255
|
}
|
|
1139
1256
|
runId = result2.runId;
|
|
1140
1257
|
runUrl = result2.url;
|
|
1141
|
-
log(kleur.dim(
|
|
1258
|
+
log(kleur.dim(M2().ghRunId(runId, runUrl)));
|
|
1142
1259
|
} else {
|
|
1143
|
-
log(
|
|
1260
|
+
log(M2().glTrigger(args.ref));
|
|
1144
1261
|
const variables = { PLATFORM: args.platform };
|
|
1145
1262
|
if (args.appId) variables.MIMI_APP_ID = args.appId;
|
|
1146
1263
|
const result2 = await glTriggerPipeline(cfg, args.ref, variables);
|
|
1147
1264
|
runId = result2.pipelineId;
|
|
1148
1265
|
runUrl = result2.url;
|
|
1149
|
-
log(kleur.dim(
|
|
1266
|
+
log(kleur.dim(M2().glPipelineId(runId, runUrl)));
|
|
1150
1267
|
}
|
|
1151
|
-
log(
|
|
1268
|
+
log(M2().waitingForCompletion);
|
|
1152
1269
|
let dots = 0;
|
|
1153
1270
|
const onTick = (status) => {
|
|
1154
1271
|
dots = (dots + 1) % 4;
|
|
@@ -1157,19 +1274,19 @@ async function runGitProviderBuild(cfg, args) {
|
|
|
1157
1274
|
const result = cfg.provider === "github" ? await ghPollRun(cfg, runId, onTick) : await glPollPipeline(cfg, runId, onTick);
|
|
1158
1275
|
process.stdout.write("\n");
|
|
1159
1276
|
if (result === "success") {
|
|
1160
|
-
log(kleur.green(
|
|
1277
|
+
log(kleur.green(M2().buildSucceeded(runId)));
|
|
1161
1278
|
return runId;
|
|
1162
1279
|
}
|
|
1163
|
-
log(kleur.red(
|
|
1280
|
+
log(kleur.red(M2().buildEnded(result)));
|
|
1164
1281
|
log(kleur.dim(` ${runUrl}`));
|
|
1165
|
-
log(kleur.dim(
|
|
1282
|
+
log(kleur.dim(M2().alreadyBuiltHint("<N>", args.platform)));
|
|
1166
1283
|
process.exit(1);
|
|
1167
1284
|
}
|
|
1168
1285
|
async function cmdDeploy(argv) {
|
|
1169
1286
|
const args = parseArgs(argv);
|
|
1170
1287
|
const cfg = await getEffectiveConfig();
|
|
1171
1288
|
if (!cfg) {
|
|
1172
|
-
log(kleur.red(
|
|
1289
|
+
log(kleur.red(M2().noAccount));
|
|
1173
1290
|
process.exit(1);
|
|
1174
1291
|
}
|
|
1175
1292
|
if (args.setupJenkins) {
|
|
@@ -1180,17 +1297,17 @@ async function cmdDeploy(argv) {
|
|
|
1180
1297
|
if (args.setupGithub) {
|
|
1181
1298
|
const ciCfg = await promptGitProviderSetup("github");
|
|
1182
1299
|
saveCiProviderConfig(ciCfg);
|
|
1183
|
-
log(kleur.green(
|
|
1300
|
+
log(kleur.green(M2().githubSaved));
|
|
1184
1301
|
return;
|
|
1185
1302
|
}
|
|
1186
1303
|
if (args.setupGitlab) {
|
|
1187
1304
|
const ciCfg = await promptGitProviderSetup("gitlab");
|
|
1188
1305
|
saveCiProviderConfig(ciCfg);
|
|
1189
|
-
log(kleur.green(
|
|
1306
|
+
log(kleur.green(M2().gitlabSaved));
|
|
1190
1307
|
return;
|
|
1191
1308
|
}
|
|
1192
|
-
log(kleur.bold(
|
|
1193
|
-
if (args.dryRun) log(kleur.yellow(
|
|
1309
|
+
log(kleur.bold(M2().title(args.platform)));
|
|
1310
|
+
if (args.dryRun) log(kleur.yellow(M2().dryRunNotice));
|
|
1194
1311
|
log("");
|
|
1195
1312
|
let versionCode = args.versionCode;
|
|
1196
1313
|
if (!args.skipBuild) {
|
|
@@ -1198,30 +1315,30 @@ async function cmdDeploy(argv) {
|
|
|
1198
1315
|
migrateLegacyJenkins();
|
|
1199
1316
|
const jenkinsCfg = loadJenkinsConfig() ?? void 0;
|
|
1200
1317
|
const kind = resolveCi(args.ci, jenkinsCfg, ciProvider);
|
|
1201
|
-
log(kleur.dim(
|
|
1318
|
+
log(kleur.dim(M2().ciLine(kind)));
|
|
1202
1319
|
if (kind === "jenkins") {
|
|
1203
1320
|
if (!jenkinsCfg?.url || !jenkinsCfg?.token) {
|
|
1204
|
-
log(kleur.yellow(
|
|
1321
|
+
log(kleur.yellow(M2().noJenkinsConfig));
|
|
1205
1322
|
process.exit(1);
|
|
1206
1323
|
}
|
|
1207
1324
|
const jenkins = jenkinsCfg;
|
|
1208
1325
|
const jobName = args.platform === "android" ? jenkins.jobAndroid : jenkins.jobIos;
|
|
1209
1326
|
if (!jobName) {
|
|
1210
|
-
log(kleur.red(
|
|
1327
|
+
log(kleur.red(M2().noJenkinsJob(args.platform)));
|
|
1211
1328
|
process.exit(1);
|
|
1212
1329
|
}
|
|
1213
|
-
log(
|
|
1330
|
+
log(M2().jenkinsTrigger(kleur.cyan(jobName)));
|
|
1214
1331
|
const buildParams = {};
|
|
1215
1332
|
if (args.appId) buildParams.MIMI_APP_ID = args.appId;
|
|
1216
1333
|
const queueItemId = await triggerBuild(jenkins, jobName, buildParams);
|
|
1217
1334
|
if (!queueItemId) {
|
|
1218
|
-
log(kleur.yellow(
|
|
1335
|
+
log(kleur.yellow(M2().noQueueItem));
|
|
1219
1336
|
} else {
|
|
1220
|
-
log(kleur.dim(
|
|
1337
|
+
log(kleur.dim(M2().queueItem(queueItemId)));
|
|
1221
1338
|
}
|
|
1222
1339
|
let buildNumber = null;
|
|
1223
1340
|
if (queueItemId) {
|
|
1224
|
-
log(
|
|
1341
|
+
log(M2().waitingForBuildNumber);
|
|
1225
1342
|
for (let i = 0; i < 6; i++) {
|
|
1226
1343
|
await new Promise((r) => setTimeout(r, 5e3));
|
|
1227
1344
|
buildNumber = await getQueueBuildNumber(jenkins, queueItemId).catch(() => null);
|
|
@@ -1229,77 +1346,77 @@ async function cmdDeploy(argv) {
|
|
|
1229
1346
|
}
|
|
1230
1347
|
}
|
|
1231
1348
|
if (!buildNumber) {
|
|
1232
|
-
log(kleur.yellow(
|
|
1349
|
+
log(kleur.yellow(M2().noBuildNumber));
|
|
1233
1350
|
process.exit(1);
|
|
1234
1351
|
}
|
|
1235
|
-
log(
|
|
1352
|
+
log(M2().buildStarted(buildNumber));
|
|
1236
1353
|
const result = await pollBuildComplete(jenkins, jobName, buildNumber);
|
|
1237
1354
|
if (result !== "SUCCESS") {
|
|
1238
|
-
log(kleur.red(
|
|
1239
|
-
log(kleur.dim(
|
|
1240
|
-
log(kleur.dim(
|
|
1355
|
+
log(kleur.red(M2().buildFailed(result)));
|
|
1356
|
+
log(kleur.dim(M2().jenkinsLink(`${jenkins.url}/job/${encodeURIComponent(jobName)}/${buildNumber}/`)));
|
|
1357
|
+
log(kleur.dim(M2().alreadyBuiltHint(String(buildNumber), args.platform)));
|
|
1241
1358
|
process.exit(1);
|
|
1242
1359
|
}
|
|
1243
|
-
log(kleur.green(
|
|
1360
|
+
log(kleur.green(M2().buildSucceeded(buildNumber)));
|
|
1244
1361
|
if (!versionCode) {
|
|
1245
1362
|
versionCode = buildNumber;
|
|
1246
|
-
log(kleur.dim(
|
|
1363
|
+
log(kleur.dim(M2().versionCodeFromBuild(versionCode)));
|
|
1247
1364
|
}
|
|
1248
1365
|
} else {
|
|
1249
1366
|
if (!ciProvider) {
|
|
1250
|
-
log(kleur.red(
|
|
1367
|
+
log(kleur.red(M2().noProviderConfig(kind)));
|
|
1251
1368
|
process.exit(1);
|
|
1252
1369
|
}
|
|
1253
1370
|
const buildId = await runGitProviderBuild(ciProvider, args);
|
|
1254
1371
|
if (!versionCode) {
|
|
1255
|
-
log(kleur.red(
|
|
1256
|
-
log(kleur.dim(
|
|
1257
|
-
log(kleur.dim(
|
|
1258
|
-
log(kleur.dim(
|
|
1372
|
+
log(kleur.red(M2().versionCodeUnsuitable(kind, buildId)));
|
|
1373
|
+
log(kleur.dim(M2().recommendation));
|
|
1374
|
+
log(kleur.dim(M2().recommendationCi));
|
|
1375
|
+
log(kleur.dim(M2().recommendationNext));
|
|
1259
1376
|
process.exit(1);
|
|
1260
1377
|
}
|
|
1261
1378
|
}
|
|
1262
1379
|
}
|
|
1263
1380
|
if (!versionCode) {
|
|
1264
|
-
log(kleur.red(
|
|
1381
|
+
log(kleur.red(M2().versionCodeUnknown));
|
|
1265
1382
|
process.exit(1);
|
|
1266
1383
|
}
|
|
1267
1384
|
let appId = args.appId;
|
|
1268
1385
|
if (!appId) {
|
|
1269
|
-
const { mcpCall } = await import("./mcp-client-
|
|
1386
|
+
const { mcpCall } = await import("./mcp-client-PVWDCYJN.js");
|
|
1270
1387
|
const r = await mcpCall(cfg.endpoint, cfg.token, "list_apps", {});
|
|
1271
1388
|
if (!r.isError) {
|
|
1272
1389
|
try {
|
|
1273
1390
|
const apps = JSON.parse(r.text);
|
|
1274
1391
|
if (apps.length > 0) {
|
|
1275
1392
|
appId = apps[0].id;
|
|
1276
|
-
log(kleur.dim(
|
|
1393
|
+
log(kleur.dim(M2().appLine(apps[0].name, appId)));
|
|
1277
1394
|
}
|
|
1278
1395
|
} catch {
|
|
1279
1396
|
}
|
|
1280
1397
|
}
|
|
1281
1398
|
}
|
|
1282
1399
|
if (!appId) {
|
|
1283
|
-
log(kleur.red(
|
|
1400
|
+
log(kleur.red(M2().noAppId));
|
|
1284
1401
|
process.exit(1);
|
|
1285
1402
|
}
|
|
1286
1403
|
const needsConfirm = !args.dryRun && !args.yes && process.stdout.isTTY && !process.env.MIMI_SEED_TOKEN;
|
|
1287
1404
|
if (needsConfirm) {
|
|
1288
|
-
const target = args.platform === "ios" ?
|
|
1405
|
+
const target = args.platform === "ios" ? M2().targetIos : M2().targetAndroid;
|
|
1289
1406
|
log("");
|
|
1290
|
-
log(kleur.yellow(
|
|
1407
|
+
log(kleur.yellow(M2().realDeploy(args.platform, versionCode, target)));
|
|
1291
1408
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
1292
1409
|
const answer = await new Promise(
|
|
1293
|
-
(resolve) => rl.question(kleur.bold(
|
|
1410
|
+
(resolve) => rl.question(kleur.bold(M2().confirmPrompt), (a) => resolve(a.trim().toLowerCase()))
|
|
1294
1411
|
);
|
|
1295
1412
|
rl.close();
|
|
1296
1413
|
if (answer !== "y" && answer !== "yes") {
|
|
1297
|
-
log(kleur.dim(
|
|
1414
|
+
log(kleur.dim(M2().confirmCancelled));
|
|
1298
1415
|
return;
|
|
1299
1416
|
}
|
|
1300
1417
|
}
|
|
1301
1418
|
log("");
|
|
1302
|
-
log(
|
|
1419
|
+
log(M2().pipelineStarting);
|
|
1303
1420
|
log("");
|
|
1304
1421
|
const deployBuildNumber = !args.skipBuild ? versionCode : void 0;
|
|
1305
1422
|
await streamDeploy(cfg.webBase, cfg.token, {
|
|
@@ -1313,214 +1430,10 @@ async function cmdDeploy(argv) {
|
|
|
1313
1430
|
dryRun: args.dryRun
|
|
1314
1431
|
});
|
|
1315
1432
|
log("");
|
|
1316
|
-
log(kleur.bold(
|
|
1433
|
+
log(kleur.bold(M2().done));
|
|
1317
1434
|
log(kleur.dim(" https://play.google.com/console/developers"));
|
|
1318
1435
|
}
|
|
1319
1436
|
|
|
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
1437
|
// src/setup.ts
|
|
1525
1438
|
function log2(msg = "") {
|
|
1526
1439
|
process.stdout.write(msg + "\n");
|
|
@@ -1651,7 +1564,7 @@ async function connectOne(spec) {
|
|
|
1651
1564
|
}
|
|
1652
1565
|
async function cmdSetup(argv) {
|
|
1653
1566
|
const opts = parseSetupArgs(argv);
|
|
1654
|
-
const home =
|
|
1567
|
+
const home = os5.homedir();
|
|
1655
1568
|
migrateLegacyJenkins(home);
|
|
1656
1569
|
if (resolveMode(opts, process.env, process.stdin.isTTY) === "interactive") {
|
|
1657
1570
|
await ensureLangChosen();
|
|
@@ -1756,9 +1669,6 @@ export {
|
|
|
1756
1669
|
deleteConfig,
|
|
1757
1670
|
CONFIG_LOCATION,
|
|
1758
1671
|
getEffectiveConfig,
|
|
1759
|
-
writeSettings,
|
|
1760
|
-
isLang,
|
|
1761
|
-
resolveLang,
|
|
1762
1672
|
credLabel,
|
|
1763
1673
|
credNote,
|
|
1764
1674
|
CREDENTIALS,
|
|
@@ -1766,7 +1676,6 @@ export {
|
|
|
1766
1676
|
detectAll,
|
|
1767
1677
|
isSatisfied,
|
|
1768
1678
|
migrateLegacyJenkins,
|
|
1769
|
-
t,
|
|
1770
1679
|
MCP_PKG,
|
|
1771
1680
|
runMcpBin,
|
|
1772
1681
|
cmdDeploy,
|