@tbsten/mir 0.0.2-alpha03 → 0.0.2-alpha06
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/cli.js +300 -22
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -38,6 +38,9 @@ function globalConfigPath() {
|
|
|
38
38
|
function localConfigPath(cwd) {
|
|
39
39
|
return path.join(cwd, ".mir", "config.yaml");
|
|
40
40
|
}
|
|
41
|
+
function localPersonalConfigPath(cwd) {
|
|
42
|
+
return path.join(cwd, ".mir", "config.local.yaml");
|
|
43
|
+
}
|
|
41
44
|
function installFailuresPath() {
|
|
42
45
|
return expandTilde("~/.mir/install-failures.json");
|
|
43
46
|
}
|
|
@@ -234,8 +237,7 @@ var DEFAULT_CONFIG = {
|
|
|
234
237
|
registries: [
|
|
235
238
|
{
|
|
236
239
|
name: "official",
|
|
237
|
-
url: "https://mir.tbsten.me"
|
|
238
|
-
publish_token: process.env.MIR_PUBLISH_TOKEN || ""
|
|
240
|
+
url: "https://mir.tbsten.me"
|
|
239
241
|
},
|
|
240
242
|
{ name: "default", path: "~/.mir/registry" }
|
|
241
243
|
]
|
|
@@ -246,8 +248,25 @@ function loadMirConfig(opts2) {
|
|
|
246
248
|
}
|
|
247
249
|
const cwd = opts2?.cwd ?? process.cwd();
|
|
248
250
|
const globalConf = loadSingleConfig(globalConfigPath());
|
|
249
|
-
const localConf =
|
|
250
|
-
|
|
251
|
+
const localConf = loadOptionalConfig(localConfigPath(cwd));
|
|
252
|
+
const localPersonalConf = loadOptionalConfig(localPersonalConfigPath(cwd));
|
|
253
|
+
return mergeConfigs(localPersonalConf, mergeConfigs(localConf, globalConf));
|
|
254
|
+
}
|
|
255
|
+
var EMPTY_CONFIG = { registries: [] };
|
|
256
|
+
function loadOptionalConfig(filePath) {
|
|
257
|
+
if (!fs2.existsSync(filePath)) {
|
|
258
|
+
return { ...EMPTY_CONFIG };
|
|
259
|
+
}
|
|
260
|
+
const content = fs2.readFileSync(filePath, "utf-8");
|
|
261
|
+
const parsed = yaml.load(content);
|
|
262
|
+
if (!parsed) {
|
|
263
|
+
return { ...EMPTY_CONFIG };
|
|
264
|
+
}
|
|
265
|
+
return {
|
|
266
|
+
registries: parsed.registries ?? [],
|
|
267
|
+
defaults: parsed.defaults,
|
|
268
|
+
locale: parsed.locale
|
|
269
|
+
};
|
|
251
270
|
}
|
|
252
271
|
function loadSingleConfig(filePath) {
|
|
253
272
|
if (!fs2.existsSync(filePath)) {
|
|
@@ -284,6 +303,16 @@ function mergeConfigs(local, global) {
|
|
|
284
303
|
locale: local.locale ?? global.locale
|
|
285
304
|
};
|
|
286
305
|
}
|
|
306
|
+
function resolveRegistryUrl(entry) {
|
|
307
|
+
if (!entry.url) {
|
|
308
|
+
throw new RegistryRemoteError(entry.name);
|
|
309
|
+
}
|
|
310
|
+
const url = entry.url.replace(/\/+$/, "");
|
|
311
|
+
if (url.endsWith("/registry")) {
|
|
312
|
+
return url;
|
|
313
|
+
}
|
|
314
|
+
return `${url}/registry`;
|
|
315
|
+
}
|
|
287
316
|
function resolveRegistryPath(entry) {
|
|
288
317
|
if (!entry.path) {
|
|
289
318
|
throw new RegistryRemoteError(entry.name);
|
|
@@ -328,6 +357,33 @@ function resolveInstallRegistries(config, registryName) {
|
|
|
328
357
|
}
|
|
329
358
|
return config.registries;
|
|
330
359
|
}
|
|
360
|
+
function saveRegistryToken(registryName, token, targetConfigPath) {
|
|
361
|
+
const configPath = targetConfigPath ?? globalConfigPath();
|
|
362
|
+
const config = loadSingleConfig(configPath);
|
|
363
|
+
const entry = config.registries.find((r) => r.name === registryName);
|
|
364
|
+
if (entry) {
|
|
365
|
+
entry.publish_token = token;
|
|
366
|
+
} else {
|
|
367
|
+
config.registries.push({ name: registryName, publish_token: token });
|
|
368
|
+
}
|
|
369
|
+
writeConfig(configPath, config);
|
|
370
|
+
}
|
|
371
|
+
function removeRegistryToken(registryName, targetConfigPath) {
|
|
372
|
+
const configPath = targetConfigPath ?? globalConfigPath();
|
|
373
|
+
const config = loadSingleConfig(configPath);
|
|
374
|
+
const entry = config.registries.find((r) => r.name === registryName);
|
|
375
|
+
if (entry) {
|
|
376
|
+
delete entry.publish_token;
|
|
377
|
+
}
|
|
378
|
+
writeConfig(configPath, config);
|
|
379
|
+
}
|
|
380
|
+
function writeConfig(configPath, config) {
|
|
381
|
+
const dir = configPath.replace(/\/[^/]+$/, "");
|
|
382
|
+
if (!fs2.existsSync(dir)) {
|
|
383
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
384
|
+
}
|
|
385
|
+
fs2.writeFileSync(configPath, yaml.dump(config), "utf-8");
|
|
386
|
+
}
|
|
331
387
|
|
|
332
388
|
// src/lib/remote-publish.ts
|
|
333
389
|
import { MirError } from "@tbsten/mir-core";
|
|
@@ -410,6 +466,21 @@ async function publishSnippet(name, opts2 = {}, cwd = process.cwd(), configPath)
|
|
|
410
466
|
const definition = parseSnippetYaml(yamlContent);
|
|
411
467
|
const config = loadMirConfig(configPath ? { configPath } : { cwd });
|
|
412
468
|
const registryEntry = resolvePublishRegistry(config, opts2.registry);
|
|
469
|
+
if (opts2.interactive !== false) {
|
|
470
|
+
const registryDisplay = registryEntry.url || resolveRegistryPath(registryEntry);
|
|
471
|
+
const shouldProceed = await confirm(
|
|
472
|
+
`
|
|
473
|
+
Snippet: ${name}
|
|
474
|
+
Location: ${dirPath}
|
|
475
|
+
Registry: ${registryDisplay}
|
|
476
|
+
|
|
477
|
+
\u3053\u308C\u3067\u516C\u958B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B?`
|
|
478
|
+
);
|
|
479
|
+
if (!shouldProceed) {
|
|
480
|
+
info(t4("publish.cancelled"));
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
413
484
|
if (registryEntry.url) {
|
|
414
485
|
if (!registryEntry.publish_token) {
|
|
415
486
|
throw new Error(t4("error.publish-token-required"));
|
|
@@ -465,6 +536,9 @@ Examples:
|
|
|
465
536
|
mir publish react-hook --force
|
|
466
537
|
mir publish my-component --registry custom
|
|
467
538
|
mir publish react-hook --no-interactive`).action(async (name, opts2) => {
|
|
539
|
+
if (process.argv.includes("--no-interactive")) {
|
|
540
|
+
opts2.interactive = false;
|
|
541
|
+
}
|
|
468
542
|
let snippetName = name;
|
|
469
543
|
if (!snippetName) {
|
|
470
544
|
const snippets = listLocalSnippets(process.cwd());
|
|
@@ -629,11 +703,13 @@ async function installSnippet(name, variableArgs, opts2 = {}, cwd = process.cwd(
|
|
|
629
703
|
const fetchOptions = opts2.timeout ? { timeoutMs: opts2.timeout * 1e3 } : {};
|
|
630
704
|
let source;
|
|
631
705
|
let definition;
|
|
706
|
+
let authorizationStatus;
|
|
632
707
|
for (const entry of registries) {
|
|
633
708
|
if (entry.url) {
|
|
634
709
|
try {
|
|
635
|
-
const remote = await fetchRemoteSnippet(entry
|
|
710
|
+
const remote = await fetchRemoteSnippet(resolveRegistryUrl(entry), name, fetchOptions);
|
|
636
711
|
definition = remote.definition;
|
|
712
|
+
authorizationStatus = remote.authorizationStatus;
|
|
637
713
|
source = { type: "remote", files: remote.files };
|
|
638
714
|
break;
|
|
639
715
|
} catch {
|
|
@@ -667,6 +743,24 @@ async function installSnippet(name, variableArgs, opts2 = {}, cwd = process.cwd(
|
|
|
667
743
|
if (!quiet && !isJson) {
|
|
668
744
|
logVariableSummary(name, variableDefs, variables, variableArgs);
|
|
669
745
|
}
|
|
746
|
+
if (authorizationStatus && authorizationStatus !== "approved") {
|
|
747
|
+
const statusLabel = authorizationStatus === "examination" ? "\u5BE9\u67FB\u4E2D" : "\u5374\u4E0B\u6E08\u307F";
|
|
748
|
+
if (!quiet && !isJson) {
|
|
749
|
+
warn(`\u3053\u306E\u30B9\u30CB\u30DA\u30C3\u30C8\u306F\u73FE\u5728\u300C${statusLabel}\u300D\u3067\u3059\u3002\u516C\u5F0F\u306B\u627F\u8A8D\u3055\u308C\u3066\u3044\u307E\u305B\u3093\u3002`);
|
|
750
|
+
}
|
|
751
|
+
if (interactive) {
|
|
752
|
+
const answer = await prompt(`\u305D\u308C\u3067\u3082\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3057\u307E\u3059\u304B\uFF1F (y/N): `);
|
|
753
|
+
if (!answer || !["y", "yes"].includes(answer.toLowerCase())) {
|
|
754
|
+
info("\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3092\u30AD\u30E3\u30F3\u30BB\u30EB\u3057\u307E\u3057\u305F\u3002");
|
|
755
|
+
return {
|
|
756
|
+
success: false,
|
|
757
|
+
snippet: name,
|
|
758
|
+
error: "User cancelled due to authorization status",
|
|
759
|
+
code: "AuthorizationCancelled"
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
}
|
|
670
764
|
if (definition.hooks?.["before-install"]?.length) {
|
|
671
765
|
if (safe) {
|
|
672
766
|
if (!quiet) {
|
|
@@ -811,11 +905,19 @@ async function resolveVariables(variableDefs, args, interactive = true) {
|
|
|
811
905
|
}
|
|
812
906
|
const description = def.description ?? def.name ?? key;
|
|
813
907
|
let answer = "";
|
|
814
|
-
|
|
908
|
+
const maxRetries = 3;
|
|
909
|
+
for (let retry = 0; retry < maxRetries; retry++) {
|
|
815
910
|
answer = await prompt(`${description} (${key}): `);
|
|
816
|
-
if (
|
|
817
|
-
|
|
818
|
-
|
|
911
|
+
if (answer) break;
|
|
912
|
+
warn(t6("error.variable-empty", { key }));
|
|
913
|
+
}
|
|
914
|
+
if (!answer) {
|
|
915
|
+
throw new MirError2(
|
|
916
|
+
t6("error.variable-required", {
|
|
917
|
+
key,
|
|
918
|
+
hint: `--${key}=<value>`
|
|
919
|
+
})
|
|
920
|
+
);
|
|
819
921
|
}
|
|
820
922
|
variables[key] = coerceValue(answer, def.schema?.type);
|
|
821
923
|
}
|
|
@@ -996,7 +1098,7 @@ Examples:
|
|
|
996
1098
|
for (const entry of registries) {
|
|
997
1099
|
if (entry.url) {
|
|
998
1100
|
try {
|
|
999
|
-
const remoteNames = await listRemoteSnippets(entry
|
|
1101
|
+
const remoteNames = await listRemoteSnippets(resolveRegistryUrl(entry), fetchOptions);
|
|
1000
1102
|
for (const s of remoteNames) {
|
|
1001
1103
|
if (!allSnippets.includes(s)) {
|
|
1002
1104
|
allSnippets.push(s);
|
|
@@ -1114,7 +1216,7 @@ async function listSnippets(opts2 = {}) {
|
|
|
1114
1216
|
snippets: []
|
|
1115
1217
|
};
|
|
1116
1218
|
try {
|
|
1117
|
-
regData.snippets = await listRemoteSnippets2(entry
|
|
1219
|
+
regData.snippets = await listRemoteSnippets2(resolveRegistryUrl(entry), fetchOptions);
|
|
1118
1220
|
} catch {
|
|
1119
1221
|
}
|
|
1120
1222
|
registryDataList.push(regData);
|
|
@@ -1147,7 +1249,7 @@ async function listSnippets(opts2 = {}) {
|
|
|
1147
1249
|
step(`${entry.name ?? "remote"} (${entry.url}):`);
|
|
1148
1250
|
}
|
|
1149
1251
|
try {
|
|
1150
|
-
const remoteSnippets = await listRemoteSnippets2(entry
|
|
1252
|
+
const remoteSnippets = await listRemoteSnippets2(resolveRegistryUrl(entry), fetchOptions);
|
|
1151
1253
|
for (const name of remoteSnippets) {
|
|
1152
1254
|
if (!opts2.quiet) {
|
|
1153
1255
|
fileItem(name);
|
|
@@ -1223,7 +1325,7 @@ async function showSnippetInfo(name, opts2 = {}, configPath) {
|
|
|
1223
1325
|
for (const entry of registries2) {
|
|
1224
1326
|
if (entry.url) {
|
|
1225
1327
|
try {
|
|
1226
|
-
const remoteNames = await listRemoteSnippets3(entry
|
|
1328
|
+
const remoteNames = await listRemoteSnippets3(resolveRegistryUrl(entry), fetchOptions);
|
|
1227
1329
|
for (const s of remoteNames) {
|
|
1228
1330
|
if (!allSnippets.includes(s)) {
|
|
1229
1331
|
allSnippets.push(s);
|
|
@@ -1251,7 +1353,7 @@ async function showSnippetInfo(name, opts2 = {}, configPath) {
|
|
|
1251
1353
|
for (const entry of registries) {
|
|
1252
1354
|
if (entry.url) {
|
|
1253
1355
|
try {
|
|
1254
|
-
const remote = await fetchRemoteSnippet2(entry
|
|
1356
|
+
const remote = await fetchRemoteSnippet2(resolveRegistryUrl(entry), snippetName, fetchOptions);
|
|
1255
1357
|
definition = remote.definition;
|
|
1256
1358
|
break;
|
|
1257
1359
|
} catch {
|
|
@@ -1352,13 +1454,11 @@ var SAMPLE_SNIPPET_FILES = {
|
|
|
1352
1454
|
};
|
|
1353
1455
|
var SAMPLE_MIRCONFIG = `# mir config
|
|
1354
1456
|
#
|
|
1355
|
-
# registry:
|
|
1356
|
-
# - name: default
|
|
1357
|
-
# path: ~/.mir/registry
|
|
1358
|
-
#
|
|
1359
1457
|
# locale: ja
|
|
1360
1458
|
|
|
1361
|
-
|
|
1459
|
+
registries:
|
|
1460
|
+
- name: official
|
|
1461
|
+
url: https://mir.tbsten.me
|
|
1362
1462
|
- name: default
|
|
1363
1463
|
path: ~/.mir/registry
|
|
1364
1464
|
`;
|
|
@@ -1404,6 +1504,7 @@ async function initProject(cwd = process.cwd(), opts2 = {}) {
|
|
|
1404
1504
|
fs9.writeFileSync(configPath, SAMPLE_MIRCONFIG, "utf-8");
|
|
1405
1505
|
success("\u2713 mirconfig.yaml \u3092\u4F5C\u6210\u3057\u307E\u3057\u305F");
|
|
1406
1506
|
}
|
|
1507
|
+
addToGitignore(cwd, ".mir/config.local.yaml");
|
|
1407
1508
|
info("");
|
|
1408
1509
|
step("\u521D\u671F\u5316\u304C\u5B8C\u4E86\u3057\u307E\u3057\u305F!");
|
|
1409
1510
|
info("\n\u6B21\u306E\u30B9\u30C6\u30C3\u30D7:");
|
|
@@ -1423,6 +1524,23 @@ async function initProject(cwd = process.cwd(), opts2 = {}) {
|
|
|
1423
1524
|
throw new MirError3("\u521D\u671F\u5316\u306B\u5931\u6557\u3057\u307E\u3057\u305F");
|
|
1424
1525
|
}
|
|
1425
1526
|
}
|
|
1527
|
+
function addToGitignore(cwd, entry) {
|
|
1528
|
+
const gitignorePath = path5.join(cwd, ".gitignore");
|
|
1529
|
+
if (fs9.existsSync(gitignorePath)) {
|
|
1530
|
+
const content = fs9.readFileSync(gitignorePath, "utf-8");
|
|
1531
|
+
const lines = content.split("\n").map((l) => l.trim());
|
|
1532
|
+
if (lines.includes(entry)) {
|
|
1533
|
+
return;
|
|
1534
|
+
}
|
|
1535
|
+
const separator = content.length > 0 && !content.endsWith("\n") ? "\n" : "";
|
|
1536
|
+
fs9.appendFileSync(gitignorePath, `${separator}${entry}
|
|
1537
|
+
`, "utf-8");
|
|
1538
|
+
} else {
|
|
1539
|
+
fs9.writeFileSync(gitignorePath, `${entry}
|
|
1540
|
+
`, "utf-8");
|
|
1541
|
+
}
|
|
1542
|
+
success(`\u2713 .gitignore \u306B ${entry} \u3092\u8FFD\u52A0\u3057\u307E\u3057\u305F`);
|
|
1543
|
+
}
|
|
1426
1544
|
function registerInitCommand(program2) {
|
|
1427
1545
|
program2.command("init").description(".mir \u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u3092\u521D\u671F\u5316\u3059\u308B").option("-f, --force", "\u65E2\u5B58\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u3092\u4E0A\u66F8\u304D", false).addHelpText("after", `
|
|
1428
1546
|
Examples:
|
|
@@ -1459,7 +1577,7 @@ async function previewSnippet(name, opts2 = {}, variableArgs = {}, cwd = process
|
|
|
1459
1577
|
for (const entry of registries) {
|
|
1460
1578
|
if (entry.url) {
|
|
1461
1579
|
try {
|
|
1462
|
-
const remote = await fetchRemoteSnippet3(entry
|
|
1580
|
+
const remote = await fetchRemoteSnippet3(resolveRegistryUrl(entry), name, fetchOptions);
|
|
1463
1581
|
definition = remote.definition;
|
|
1464
1582
|
source = { type: "remote", files: remote.files };
|
|
1465
1583
|
break;
|
|
@@ -1644,7 +1762,7 @@ async function searchSnippets(query, opts2 = {}) {
|
|
|
1644
1762
|
snippets: []
|
|
1645
1763
|
};
|
|
1646
1764
|
try {
|
|
1647
|
-
const allSnippets = await listRemoteSnippets4(entry
|
|
1765
|
+
const allSnippets = await listRemoteSnippets4(resolveRegistryUrl(entry));
|
|
1648
1766
|
const lowerQuery = query.toLowerCase();
|
|
1649
1767
|
result.snippets = allSnippets.filter(
|
|
1650
1768
|
(name) => name.toLowerCase().includes(lowerQuery)
|
|
@@ -1818,6 +1936,125 @@ Examples:
|
|
|
1818
1936
|
mir clone my-snippet new-name --force`);
|
|
1819
1937
|
}
|
|
1820
1938
|
|
|
1939
|
+
// src/commands/login.ts
|
|
1940
|
+
import http from "http";
|
|
1941
|
+
import fs12 from "fs";
|
|
1942
|
+
function registerLoginCommand(program2) {
|
|
1943
|
+
program2.command("login").description("registry \u306B\u30ED\u30B0\u30A4\u30F3\u3057\u3066 publish token \u3092\u53D6\u5F97").option("--registry <name>", "\u5BFE\u8C61 registry \u540D (\u30C7\u30D5\u30A9\u30EB\u30C8: official)").option("--local", "token \u3092\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u30ED\u30FC\u30AB\u30EB\u306E config.local.yaml \u306B\u4FDD\u5B58").action(async (opts2) => {
|
|
1944
|
+
const registryName = opts2.registry || "official";
|
|
1945
|
+
const config = loadMirConfig();
|
|
1946
|
+
const registry = config.registries.find((r) => r.name === registryName);
|
|
1947
|
+
if (!registry?.url) {
|
|
1948
|
+
error(`Registry "${registryName}" \u304C\u898B\u3064\u304B\u3089\u306A\u3044\u304B\u3001URL \u304C\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u307E\u305B\u3093`);
|
|
1949
|
+
process.exit(1);
|
|
1950
|
+
}
|
|
1951
|
+
let targetConfigPath;
|
|
1952
|
+
if (opts2.local) {
|
|
1953
|
+
const mirDir = localPersonalConfigPath(process.cwd()).replace(/\/[^/]+$/, "");
|
|
1954
|
+
if (!fs12.existsSync(mirDir)) {
|
|
1955
|
+
error(".mir/ \u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u304C\u5B58\u5728\u3057\u307E\u305B\u3093\u3002\u5148\u306B `mir init` \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044");
|
|
1956
|
+
process.exit(1);
|
|
1957
|
+
}
|
|
1958
|
+
targetConfigPath = localPersonalConfigPath(process.cwd());
|
|
1959
|
+
}
|
|
1960
|
+
const registryUrl = registry.url;
|
|
1961
|
+
info(`${registryName} (${registryUrl}) \u306B\u30ED\u30B0\u30A4\u30F3\u3057\u307E\u3059...`);
|
|
1962
|
+
try {
|
|
1963
|
+
const { token, username } = await startLoginFlow(registryUrl);
|
|
1964
|
+
saveRegistryToken(registryName, token, targetConfigPath);
|
|
1965
|
+
success(`\u30ED\u30B0\u30A4\u30F3\u6210\u529F: ${username}`);
|
|
1966
|
+
const dest = opts2.local ? ".mir/config.local.yaml" : "\u30B0\u30ED\u30FC\u30D0\u30EB\u8A2D\u5B9A";
|
|
1967
|
+
info(`publish token \u304C ${dest} \u306B\u4FDD\u5B58\u3055\u308C\u307E\u3057\u305F`);
|
|
1968
|
+
} catch (error2) {
|
|
1969
|
+
if (error2 instanceof Error) {
|
|
1970
|
+
error(`\u30ED\u30B0\u30A4\u30F3\u5931\u6557: ${error2.message}`);
|
|
1971
|
+
}
|
|
1972
|
+
process.exit(1);
|
|
1973
|
+
}
|
|
1974
|
+
});
|
|
1975
|
+
}
|
|
1976
|
+
async function startLoginFlow(registryUrl) {
|
|
1977
|
+
return new Promise((resolve, reject) => {
|
|
1978
|
+
const server = http.createServer((req, res) => {
|
|
1979
|
+
const url = new URL(req.url || "/", `http://localhost`);
|
|
1980
|
+
if (url.pathname === "/callback") {
|
|
1981
|
+
const token = url.searchParams.get("token");
|
|
1982
|
+
const username = url.searchParams.get("username");
|
|
1983
|
+
if (token && username) {
|
|
1984
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
1985
|
+
res.end(`
|
|
1986
|
+
<html>
|
|
1987
|
+
<body style="font-family: monospace; text-align: center; padding: 40px;">
|
|
1988
|
+
<h1>\u30ED\u30B0\u30A4\u30F3\u6210\u529F!</h1>
|
|
1989
|
+
<p>${username} \u3068\u3057\u3066\u30ED\u30B0\u30A4\u30F3\u3057\u307E\u3057\u305F\u3002</p>
|
|
1990
|
+
<p>\u3053\u306E\u30A6\u30A3\u30F3\u30C9\u30A6\u306F\u9589\u3058\u3066\u69CB\u3044\u307E\u305B\u3093\u3002</p>
|
|
1991
|
+
</body>
|
|
1992
|
+
</html>
|
|
1993
|
+
`);
|
|
1994
|
+
server.close();
|
|
1995
|
+
resolve({ token, username });
|
|
1996
|
+
} else {
|
|
1997
|
+
res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
|
|
1998
|
+
res.end("<html><body><h1>\u30ED\u30B0\u30A4\u30F3\u5931\u6557</h1></body></html>");
|
|
1999
|
+
server.close();
|
|
2000
|
+
reject(new Error("\u30C8\u30FC\u30AF\u30F3\u306E\u53D6\u5F97\u306B\u5931\u6557\u3057\u307E\u3057\u305F"));
|
|
2001
|
+
}
|
|
2002
|
+
return;
|
|
2003
|
+
}
|
|
2004
|
+
res.writeHead(404);
|
|
2005
|
+
res.end();
|
|
2006
|
+
});
|
|
2007
|
+
server.listen(0, "127.0.0.1", () => {
|
|
2008
|
+
const addr = server.address();
|
|
2009
|
+
if (!addr || typeof addr === "string") {
|
|
2010
|
+
reject(new Error("\u30B5\u30FC\u30D0\u30FC\u306E\u8D77\u52D5\u306B\u5931\u6557\u3057\u307E\u3057\u305F"));
|
|
2011
|
+
return;
|
|
2012
|
+
}
|
|
2013
|
+
const port = addr.port;
|
|
2014
|
+
const loginUrl = `${registryUrl}/auth/login?cli=true&callback_port=${port}`;
|
|
2015
|
+
info(`\u30D6\u30E9\u30A6\u30B6\u3092\u958B\u3044\u3066\u3044\u307E\u3059: ${loginUrl}`);
|
|
2016
|
+
openBrowser(loginUrl);
|
|
2017
|
+
const timeout = setTimeout(() => {
|
|
2018
|
+
server.close();
|
|
2019
|
+
reject(new Error("\u30ED\u30B0\u30A4\u30F3\u304C\u30BF\u30A4\u30E0\u30A2\u30A6\u30C8\u3057\u307E\u3057\u305F"));
|
|
2020
|
+
}, 5 * 60 * 1e3);
|
|
2021
|
+
timeout.unref();
|
|
2022
|
+
});
|
|
2023
|
+
server.on("error", (err) => {
|
|
2024
|
+
reject(new Error(`\u30B5\u30FC\u30D0\u30FC\u30A8\u30E9\u30FC: ${err.message}`));
|
|
2025
|
+
});
|
|
2026
|
+
});
|
|
2027
|
+
}
|
|
2028
|
+
async function openBrowser(url) {
|
|
2029
|
+
const { exec } = await import("child_process");
|
|
2030
|
+
const platform = process.platform;
|
|
2031
|
+
const command = platform === "darwin" ? `open "${url}"` : platform === "win32" ? `start "${url}"` : `xdg-open "${url}"`;
|
|
2032
|
+
exec(command, (err) => {
|
|
2033
|
+
if (err) {
|
|
2034
|
+
info(`\u30D6\u30E9\u30A6\u30B6\u3092\u81EA\u52D5\u3067\u958B\u3051\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u4EE5\u4E0B\u306E URL \u3092\u624B\u52D5\u3067\u958B\u3044\u3066\u304F\u3060\u3055\u3044:`);
|
|
2035
|
+
info(url);
|
|
2036
|
+
}
|
|
2037
|
+
});
|
|
2038
|
+
}
|
|
2039
|
+
|
|
2040
|
+
// src/commands/logout.ts
|
|
2041
|
+
function registerLogoutCommand(program2) {
|
|
2042
|
+
program2.command("logout").description("registry \u304B\u3089\u30ED\u30B0\u30A2\u30A6\u30C8\uFF08\u4FDD\u5B58\u3055\u308C\u305F token \u3092\u524A\u9664\uFF09").option("--registry <name>", "\u5BFE\u8C61 registry \u540D (\u30C7\u30D5\u30A9\u30EB\u30C8: official)").option("--local", "\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u30ED\u30FC\u30AB\u30EB\u306E config.local.yaml \u304B\u3089 token \u3092\u524A\u9664").action(async (opts2) => {
|
|
2043
|
+
const registryName = opts2.registry || "official";
|
|
2044
|
+
const targetConfigPath = opts2.local ? localPersonalConfigPath(process.cwd()) : void 0;
|
|
2045
|
+
try {
|
|
2046
|
+
removeRegistryToken(registryName, targetConfigPath);
|
|
2047
|
+
const dest = opts2.local ? ".mir/config.local.yaml" : "\u30B0\u30ED\u30FC\u30D0\u30EB\u8A2D\u5B9A";
|
|
2048
|
+
success(`${registryName} \u304B\u3089\u30ED\u30B0\u30A2\u30A6\u30C8\u3057\u307E\u3057\u305F (${dest})`);
|
|
2049
|
+
} catch (error2) {
|
|
2050
|
+
if (error2 instanceof Error) {
|
|
2051
|
+
error(`\u30ED\u30B0\u30A2\u30A6\u30C8\u5931\u6557: ${error2.message}`);
|
|
2052
|
+
}
|
|
2053
|
+
process.exit(1);
|
|
2054
|
+
}
|
|
2055
|
+
});
|
|
2056
|
+
}
|
|
2057
|
+
|
|
1821
2058
|
// src/lib/env.ts
|
|
1822
2059
|
function getLocaleFromEnv() {
|
|
1823
2060
|
const locale2 = process.env.MIR_LOCALE;
|
|
@@ -1829,7 +2066,46 @@ function getLocaleFromEnv() {
|
|
|
1829
2066
|
|
|
1830
2067
|
// src/cli.ts
|
|
1831
2068
|
var program = new Command();
|
|
1832
|
-
program.name("mir").description("\u30B9\u30CB\u30DA\u30C3\u30C8\u3092\u914D\u5E03\u30FB\u53D6\u5F97\u3059\u308B CLI \u30C4\u30FC\u30EB").version("0.0.2-
|
|
2069
|
+
program.name("mir").description("\u30B9\u30CB\u30DA\u30C3\u30C8\u3092\u914D\u5E03\u30FB\u53D6\u5F97\u3059\u308B CLI \u30C4\u30FC\u30EB").version("0.0.2-alpha06", "-v, --version").showHelpAfterError(true).option("--config <path>", "\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB\u30D1\u30B9 (\u30C7\u30D5\u30A9\u30EB\u30C8: ~/.mir/config.yaml)").option("--locale <lang>", "UI \u8A00\u8A9E (ja|en)").option("--no-interactive", "\u975E\u5BFE\u8A71\u30E2\u30FC\u30C9").configureHelp({
|
|
2070
|
+
formatHelp(cmd, helper) {
|
|
2071
|
+
const bold3 = "\x1B[1m";
|
|
2072
|
+
const cyan3 = "\x1B[36m";
|
|
2073
|
+
const yellow3 = "\x1B[33m";
|
|
2074
|
+
const dim3 = "\x1B[2m";
|
|
2075
|
+
const reset3 = "\x1B[0m";
|
|
2076
|
+
const title = `${bold3}${cyan3}${cmd.name()}${reset3}`;
|
|
2077
|
+
const desc = cmd.description();
|
|
2078
|
+
const lines = [];
|
|
2079
|
+
lines.push(`${title}${desc ? ` - ${desc}` : ""}`);
|
|
2080
|
+
lines.push("");
|
|
2081
|
+
const usage = helper.commandUsage(cmd);
|
|
2082
|
+
lines.push(`${bold3}Usage:${reset3} ${usage}`);
|
|
2083
|
+
lines.push("");
|
|
2084
|
+
const cmds = helper.visibleCommands(cmd);
|
|
2085
|
+
if (cmds.length > 0) {
|
|
2086
|
+
lines.push(`${bold3}Commands:${reset3}`);
|
|
2087
|
+
const padWidth = helper.padWidth(cmd, helper);
|
|
2088
|
+
for (const sub of cmds) {
|
|
2089
|
+
const name = helper.subcommandTerm(sub).padEnd(padWidth);
|
|
2090
|
+
const subDesc = helper.subcommandDescription(sub);
|
|
2091
|
+
lines.push(` ${cyan3}${name}${reset3} ${dim3}${subDesc}${reset3}`);
|
|
2092
|
+
}
|
|
2093
|
+
lines.push("");
|
|
2094
|
+
}
|
|
2095
|
+
const opts2 = helper.visibleOptions(cmd);
|
|
2096
|
+
if (opts2.length > 0) {
|
|
2097
|
+
lines.push(`${bold3}Options:${reset3}`);
|
|
2098
|
+
const padWidth = helper.padWidth(cmd, helper);
|
|
2099
|
+
for (const opt of opts2) {
|
|
2100
|
+
const flags = helper.optionTerm(opt).padEnd(padWidth);
|
|
2101
|
+
const optDesc = helper.optionDescription(opt);
|
|
2102
|
+
lines.push(` ${yellow3}${flags}${reset3} ${dim3}${optDesc}${reset3}`);
|
|
2103
|
+
}
|
|
2104
|
+
lines.push("");
|
|
2105
|
+
}
|
|
2106
|
+
return lines.join("\n");
|
|
2107
|
+
}
|
|
2108
|
+
});
|
|
1833
2109
|
var opts = program.opts();
|
|
1834
2110
|
var locale = "en";
|
|
1835
2111
|
if (opts.locale) {
|
|
@@ -1863,6 +2139,8 @@ registerInfoCommand(program);
|
|
|
1863
2139
|
registerSearchCommand(program);
|
|
1864
2140
|
registerCloneCommand(program);
|
|
1865
2141
|
registerPreviewCommand(program);
|
|
2142
|
+
registerLoginCommand(program);
|
|
2143
|
+
registerLogoutCommand(program);
|
|
1866
2144
|
program.parseAsync().catch((err) => {
|
|
1867
2145
|
if (err instanceof SnippetNotFoundError7) {
|
|
1868
2146
|
error(err.message);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tbsten/mir",
|
|
3
|
-
"version": "0.0.2-
|
|
3
|
+
"version": "0.0.2-alpha06",
|
|
4
4
|
"description": "スニペット(ディレクトリ構造含む)を配布・取得するCLIツール",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"fast-check": "^4.5.3",
|
|
44
44
|
"tsup": "^8",
|
|
45
45
|
"typescript": "^5",
|
|
46
|
-
"vitest": "^
|
|
46
|
+
"vitest": "^4"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@tbsten/mir-core": "*",
|