@tbsten/mir 0.0.2-alpha04 → 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 +283 -23
- 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";
|
|
@@ -418,7 +474,7 @@ Snippet: ${name}
|
|
|
418
474
|
Location: ${dirPath}
|
|
419
475
|
Registry: ${registryDisplay}
|
|
420
476
|
|
|
421
|
-
\u3053\u308C\u3067\u516C\u958B\u3057\u3066\u3044\
|
|
477
|
+
\u3053\u308C\u3067\u516C\u958B\u3057\u3066\u3082\u3088\u308D\u3057\u3044\u3067\u3059\u304B?`
|
|
422
478
|
);
|
|
423
479
|
if (!shouldProceed) {
|
|
424
480
|
info(t4("publish.cancelled"));
|
|
@@ -647,11 +703,13 @@ async function installSnippet(name, variableArgs, opts2 = {}, cwd = process.cwd(
|
|
|
647
703
|
const fetchOptions = opts2.timeout ? { timeoutMs: opts2.timeout * 1e3 } : {};
|
|
648
704
|
let source;
|
|
649
705
|
let definition;
|
|
706
|
+
let authorizationStatus;
|
|
650
707
|
for (const entry of registries) {
|
|
651
708
|
if (entry.url) {
|
|
652
709
|
try {
|
|
653
|
-
const remote = await fetchRemoteSnippet(entry
|
|
710
|
+
const remote = await fetchRemoteSnippet(resolveRegistryUrl(entry), name, fetchOptions);
|
|
654
711
|
definition = remote.definition;
|
|
712
|
+
authorizationStatus = remote.authorizationStatus;
|
|
655
713
|
source = { type: "remote", files: remote.files };
|
|
656
714
|
break;
|
|
657
715
|
} catch {
|
|
@@ -685,6 +743,24 @@ async function installSnippet(name, variableArgs, opts2 = {}, cwd = process.cwd(
|
|
|
685
743
|
if (!quiet && !isJson) {
|
|
686
744
|
logVariableSummary(name, variableDefs, variables, variableArgs);
|
|
687
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
|
+
}
|
|
688
764
|
if (definition.hooks?.["before-install"]?.length) {
|
|
689
765
|
if (safe) {
|
|
690
766
|
if (!quiet) {
|
|
@@ -829,11 +905,19 @@ async function resolveVariables(variableDefs, args, interactive = true) {
|
|
|
829
905
|
}
|
|
830
906
|
const description = def.description ?? def.name ?? key;
|
|
831
907
|
let answer = "";
|
|
832
|
-
|
|
908
|
+
const maxRetries = 3;
|
|
909
|
+
for (let retry = 0; retry < maxRetries; retry++) {
|
|
833
910
|
answer = await prompt(`${description} (${key}): `);
|
|
834
|
-
if (
|
|
835
|
-
|
|
836
|
-
|
|
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
|
+
);
|
|
837
921
|
}
|
|
838
922
|
variables[key] = coerceValue(answer, def.schema?.type);
|
|
839
923
|
}
|
|
@@ -1014,7 +1098,7 @@ Examples:
|
|
|
1014
1098
|
for (const entry of registries) {
|
|
1015
1099
|
if (entry.url) {
|
|
1016
1100
|
try {
|
|
1017
|
-
const remoteNames = await listRemoteSnippets(entry
|
|
1101
|
+
const remoteNames = await listRemoteSnippets(resolveRegistryUrl(entry), fetchOptions);
|
|
1018
1102
|
for (const s of remoteNames) {
|
|
1019
1103
|
if (!allSnippets.includes(s)) {
|
|
1020
1104
|
allSnippets.push(s);
|
|
@@ -1132,7 +1216,7 @@ async function listSnippets(opts2 = {}) {
|
|
|
1132
1216
|
snippets: []
|
|
1133
1217
|
};
|
|
1134
1218
|
try {
|
|
1135
|
-
regData.snippets = await listRemoteSnippets2(entry
|
|
1219
|
+
regData.snippets = await listRemoteSnippets2(resolveRegistryUrl(entry), fetchOptions);
|
|
1136
1220
|
} catch {
|
|
1137
1221
|
}
|
|
1138
1222
|
registryDataList.push(regData);
|
|
@@ -1165,7 +1249,7 @@ async function listSnippets(opts2 = {}) {
|
|
|
1165
1249
|
step(`${entry.name ?? "remote"} (${entry.url}):`);
|
|
1166
1250
|
}
|
|
1167
1251
|
try {
|
|
1168
|
-
const remoteSnippets = await listRemoteSnippets2(entry
|
|
1252
|
+
const remoteSnippets = await listRemoteSnippets2(resolveRegistryUrl(entry), fetchOptions);
|
|
1169
1253
|
for (const name of remoteSnippets) {
|
|
1170
1254
|
if (!opts2.quiet) {
|
|
1171
1255
|
fileItem(name);
|
|
@@ -1241,7 +1325,7 @@ async function showSnippetInfo(name, opts2 = {}, configPath) {
|
|
|
1241
1325
|
for (const entry of registries2) {
|
|
1242
1326
|
if (entry.url) {
|
|
1243
1327
|
try {
|
|
1244
|
-
const remoteNames = await listRemoteSnippets3(entry
|
|
1328
|
+
const remoteNames = await listRemoteSnippets3(resolveRegistryUrl(entry), fetchOptions);
|
|
1245
1329
|
for (const s of remoteNames) {
|
|
1246
1330
|
if (!allSnippets.includes(s)) {
|
|
1247
1331
|
allSnippets.push(s);
|
|
@@ -1269,7 +1353,7 @@ async function showSnippetInfo(name, opts2 = {}, configPath) {
|
|
|
1269
1353
|
for (const entry of registries) {
|
|
1270
1354
|
if (entry.url) {
|
|
1271
1355
|
try {
|
|
1272
|
-
const remote = await fetchRemoteSnippet2(entry
|
|
1356
|
+
const remote = await fetchRemoteSnippet2(resolveRegistryUrl(entry), snippetName, fetchOptions);
|
|
1273
1357
|
definition = remote.definition;
|
|
1274
1358
|
break;
|
|
1275
1359
|
} catch {
|
|
@@ -1370,13 +1454,11 @@ var SAMPLE_SNIPPET_FILES = {
|
|
|
1370
1454
|
};
|
|
1371
1455
|
var SAMPLE_MIRCONFIG = `# mir config
|
|
1372
1456
|
#
|
|
1373
|
-
# registry:
|
|
1374
|
-
# - name: default
|
|
1375
|
-
# path: ~/.mir/registry
|
|
1376
|
-
#
|
|
1377
1457
|
# locale: ja
|
|
1378
1458
|
|
|
1379
|
-
|
|
1459
|
+
registries:
|
|
1460
|
+
- name: official
|
|
1461
|
+
url: https://mir.tbsten.me
|
|
1380
1462
|
- name: default
|
|
1381
1463
|
path: ~/.mir/registry
|
|
1382
1464
|
`;
|
|
@@ -1422,6 +1504,7 @@ async function initProject(cwd = process.cwd(), opts2 = {}) {
|
|
|
1422
1504
|
fs9.writeFileSync(configPath, SAMPLE_MIRCONFIG, "utf-8");
|
|
1423
1505
|
success("\u2713 mirconfig.yaml \u3092\u4F5C\u6210\u3057\u307E\u3057\u305F");
|
|
1424
1506
|
}
|
|
1507
|
+
addToGitignore(cwd, ".mir/config.local.yaml");
|
|
1425
1508
|
info("");
|
|
1426
1509
|
step("\u521D\u671F\u5316\u304C\u5B8C\u4E86\u3057\u307E\u3057\u305F!");
|
|
1427
1510
|
info("\n\u6B21\u306E\u30B9\u30C6\u30C3\u30D7:");
|
|
@@ -1441,6 +1524,23 @@ async function initProject(cwd = process.cwd(), opts2 = {}) {
|
|
|
1441
1524
|
throw new MirError3("\u521D\u671F\u5316\u306B\u5931\u6557\u3057\u307E\u3057\u305F");
|
|
1442
1525
|
}
|
|
1443
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
|
+
}
|
|
1444
1544
|
function registerInitCommand(program2) {
|
|
1445
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", `
|
|
1446
1546
|
Examples:
|
|
@@ -1477,7 +1577,7 @@ async function previewSnippet(name, opts2 = {}, variableArgs = {}, cwd = process
|
|
|
1477
1577
|
for (const entry of registries) {
|
|
1478
1578
|
if (entry.url) {
|
|
1479
1579
|
try {
|
|
1480
|
-
const remote = await fetchRemoteSnippet3(entry
|
|
1580
|
+
const remote = await fetchRemoteSnippet3(resolveRegistryUrl(entry), name, fetchOptions);
|
|
1481
1581
|
definition = remote.definition;
|
|
1482
1582
|
source = { type: "remote", files: remote.files };
|
|
1483
1583
|
break;
|
|
@@ -1662,7 +1762,7 @@ async function searchSnippets(query, opts2 = {}) {
|
|
|
1662
1762
|
snippets: []
|
|
1663
1763
|
};
|
|
1664
1764
|
try {
|
|
1665
|
-
const allSnippets = await listRemoteSnippets4(entry
|
|
1765
|
+
const allSnippets = await listRemoteSnippets4(resolveRegistryUrl(entry));
|
|
1666
1766
|
const lowerQuery = query.toLowerCase();
|
|
1667
1767
|
result.snippets = allSnippets.filter(
|
|
1668
1768
|
(name) => name.toLowerCase().includes(lowerQuery)
|
|
@@ -1836,6 +1936,125 @@ Examples:
|
|
|
1836
1936
|
mir clone my-snippet new-name --force`);
|
|
1837
1937
|
}
|
|
1838
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
|
+
|
|
1839
2058
|
// src/lib/env.ts
|
|
1840
2059
|
function getLocaleFromEnv() {
|
|
1841
2060
|
const locale2 = process.env.MIR_LOCALE;
|
|
@@ -1847,7 +2066,46 @@ function getLocaleFromEnv() {
|
|
|
1847
2066
|
|
|
1848
2067
|
// src/cli.ts
|
|
1849
2068
|
var program = new Command();
|
|
1850
|
-
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
|
+
});
|
|
1851
2109
|
var opts = program.opts();
|
|
1852
2110
|
var locale = "en";
|
|
1853
2111
|
if (opts.locale) {
|
|
@@ -1881,6 +2139,8 @@ registerInfoCommand(program);
|
|
|
1881
2139
|
registerSearchCommand(program);
|
|
1882
2140
|
registerCloneCommand(program);
|
|
1883
2141
|
registerPreviewCommand(program);
|
|
2142
|
+
registerLoginCommand(program);
|
|
2143
|
+
registerLogoutCommand(program);
|
|
1884
2144
|
program.parseAsync().catch((err) => {
|
|
1885
2145
|
if (err instanceof SnippetNotFoundError7) {
|
|
1886
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": "*",
|