mihomo-cli 3.3.0 → 3.5.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/CHANGELOG.md +32 -0
- package/dist/index.js +1351 -1253
- package/package.json +6 -2
package/dist/index.js
CHANGED
|
@@ -6,7 +6,6 @@ import fs4 from "fs";
|
|
|
6
6
|
|
|
7
7
|
// node_modules/js-yaml/dist/js-yaml.mjs
|
|
8
8
|
var NOT_RESOLVED = /* @__PURE__ */ Symbol("NOT_RESOLVED");
|
|
9
|
-
var MERGE_KEY = /* @__PURE__ */ Symbol("MERGE_KEY");
|
|
10
9
|
function defineScalarTag(tagName, options) {
|
|
11
10
|
return {
|
|
12
11
|
tagName,
|
|
@@ -15,9 +14,9 @@ function defineScalarTag(tagName, options) {
|
|
|
15
14
|
matchByTagPrefix: options.matchByTagPrefix ?? false,
|
|
16
15
|
implicitFirstChars: options.implicitFirstChars ?? null,
|
|
17
16
|
resolve: options.resolve,
|
|
18
|
-
identify: options.identify
|
|
17
|
+
identify: options.identify,
|
|
19
18
|
represent: options.represent ?? ((data) => String(data)),
|
|
20
|
-
representTagName: options.representTagName ??
|
|
19
|
+
representTagName: options.representTagName ?? (() => tagName)
|
|
21
20
|
};
|
|
22
21
|
}
|
|
23
22
|
function defineSequenceTag(tagName, options) {
|
|
@@ -31,9 +30,9 @@ function defineSequenceTag(tagName, options) {
|
|
|
31
30
|
addItem: options.addItem,
|
|
32
31
|
finalize: options.finalize ?? ((carrier) => carrier),
|
|
33
32
|
carrierIsResult,
|
|
34
|
-
identify: options.identify
|
|
33
|
+
identify: options.identify,
|
|
35
34
|
represent: options.represent ?? ((data) => data),
|
|
36
|
-
representTagName: options.representTagName ??
|
|
35
|
+
representTagName: options.representTagName ?? (() => tagName)
|
|
37
36
|
};
|
|
38
37
|
}
|
|
39
38
|
function defineMappingTag(tagName, options) {
|
|
@@ -50,9 +49,9 @@ function defineMappingTag(tagName, options) {
|
|
|
50
49
|
get: options.get,
|
|
51
50
|
finalize: options.finalize ?? ((carrier) => carrier),
|
|
52
51
|
carrierIsResult,
|
|
53
|
-
identify: options.identify
|
|
52
|
+
identify: options.identify,
|
|
54
53
|
represent: options.represent ?? ((data) => data),
|
|
55
|
-
representTagName: options.representTagName ??
|
|
54
|
+
representTagName: options.representTagName ?? (() => tagName)
|
|
56
55
|
};
|
|
57
56
|
}
|
|
58
57
|
var strTag = defineScalarTag("tag:yaml.org,2002:str", {
|
|
@@ -401,9 +400,10 @@ var mergeTag = defineScalarTag("tag:yaml.org,2002:merge", {
|
|
|
401
400
|
implicit: true,
|
|
402
401
|
implicitFirstChars: ["<"],
|
|
403
402
|
resolve: (source, isExplicit) => {
|
|
404
|
-
if (source === "<<" || isExplicit && source === "") return
|
|
403
|
+
if (source === "<<" || isExplicit && source === "") return "<<";
|
|
405
404
|
return NOT_RESOLVED;
|
|
406
|
-
}
|
|
405
|
+
},
|
|
406
|
+
identify: () => false
|
|
407
407
|
});
|
|
408
408
|
var BASE64_PATTERN = /^[A-Za-z0-9+/]*={0,2}$/;
|
|
409
409
|
function resolveYamlBinary(source) {
|
|
@@ -426,6 +426,11 @@ var binaryTag = defineScalarTag("tag:yaml.org,2002:binary", {
|
|
|
426
426
|
});
|
|
427
427
|
var YAML_DATE_REGEXP = /* @__PURE__ */ new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$");
|
|
428
428
|
var YAML_TIMESTAMP_REGEXP = /* @__PURE__ */ new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$");
|
|
429
|
+
function makeUtcDate(year, month, day, hour = 0, minute = 0, second = 0, fraction = 0) {
|
|
430
|
+
const date = new Date(Date.UTC(year, month, day, hour, minute, second, fraction));
|
|
431
|
+
date.setUTCFullYear(year, month, day);
|
|
432
|
+
return date;
|
|
433
|
+
}
|
|
429
434
|
function resolveYamlTimestamp(source) {
|
|
430
435
|
let match = YAML_DATE_REGEXP.exec(source);
|
|
431
436
|
if (match === null) match = YAML_TIMESTAMP_REGEXP.exec(source);
|
|
@@ -434,7 +439,7 @@ function resolveYamlTimestamp(source) {
|
|
|
434
439
|
const month = +match[2] - 1;
|
|
435
440
|
const day = +match[3];
|
|
436
441
|
if (!match[4]) {
|
|
437
|
-
const date2 =
|
|
442
|
+
const date2 = makeUtcDate(year, month, day);
|
|
438
443
|
if (date2.getUTCFullYear() !== year || date2.getUTCMonth() !== month || date2.getUTCDate() !== day) return NOT_RESOLVED;
|
|
439
444
|
return date2;
|
|
440
445
|
}
|
|
@@ -448,7 +453,7 @@ function resolveYamlTimestamp(source) {
|
|
|
448
453
|
while (value.length < 3) value += "0";
|
|
449
454
|
fraction = +value;
|
|
450
455
|
}
|
|
451
|
-
const date =
|
|
456
|
+
const date = makeUtcDate(year, month, day, hour, minute, second, fraction);
|
|
452
457
|
if (date.getUTCFullYear() !== year || date.getUTCMonth() !== month || date.getUTCDate() !== day) return NOT_RESOLVED;
|
|
453
458
|
if (match[9]) {
|
|
454
459
|
const offsetHour = +match[10];
|
|
@@ -503,7 +508,8 @@ var omapTag = defineSequenceTag("tag:yaml.org,2002:omap", {
|
|
|
503
508
|
carrier.list.push(item);
|
|
504
509
|
return "";
|
|
505
510
|
},
|
|
506
|
-
finalize: (carrier) => carrier.list
|
|
511
|
+
finalize: (carrier) => carrier.list,
|
|
512
|
+
identify: () => false
|
|
507
513
|
});
|
|
508
514
|
var pairsTag = defineSequenceTag("tag:yaml.org,2002:pairs", {
|
|
509
515
|
create: () => [],
|
|
@@ -519,7 +525,8 @@ var pairsTag = defineSequenceTag("tag:yaml.org,2002:pairs", {
|
|
|
519
525
|
if (keys.length !== 1) return "cannot resolve a pairs item";
|
|
520
526
|
container.push([keys[0], object[keys[0]]]);
|
|
521
527
|
return "";
|
|
522
|
-
}
|
|
528
|
+
},
|
|
529
|
+
identify: () => false
|
|
523
530
|
});
|
|
524
531
|
var mapTag = defineMappingTag("tag:yaml.org,2002:map", {
|
|
525
532
|
create: () => ({}),
|
|
@@ -546,7 +553,11 @@ var mapTag = defineMappingTag("tag:yaml.org,2002:map", {
|
|
|
546
553
|
return Object.prototype.hasOwnProperty.call(container, String(key));
|
|
547
554
|
},
|
|
548
555
|
keys: (container) => Object.keys(container),
|
|
549
|
-
get: (container, key) =>
|
|
556
|
+
get: (container, key) => {
|
|
557
|
+
const normalizedKey = String(key);
|
|
558
|
+
if (!Object.prototype.hasOwnProperty.call(container, normalizedKey)) return null;
|
|
559
|
+
return container[normalizedKey];
|
|
560
|
+
}
|
|
550
561
|
});
|
|
551
562
|
var setTag = defineMappingTag("tag:yaml.org,2002:set", {
|
|
552
563
|
create: () => /* @__PURE__ */ new Set(),
|
|
@@ -567,9 +578,9 @@ var setTag = defineMappingTag("tag:yaml.org,2002:set", {
|
|
|
567
578
|
});
|
|
568
579
|
function createTagDefinitionMap() {
|
|
569
580
|
return {
|
|
570
|
-
scalar:
|
|
571
|
-
sequence:
|
|
572
|
-
mapping:
|
|
581
|
+
scalar: /* @__PURE__ */ Object.create(null),
|
|
582
|
+
sequence: /* @__PURE__ */ Object.create(null),
|
|
583
|
+
mapping: /* @__PURE__ */ Object.create(null)
|
|
573
584
|
};
|
|
574
585
|
}
|
|
575
586
|
function createTagDefinitionListMap() {
|
|
@@ -596,11 +607,35 @@ function compileTags(tags) {
|
|
|
596
607
|
}
|
|
597
608
|
var Schema = class Schema2 {
|
|
598
609
|
tags;
|
|
610
|
+
/** @internal */
|
|
599
611
|
implicitScalarTags;
|
|
612
|
+
/**
|
|
613
|
+
* Dispatch implicit scalar resolvers by `source.charAt(0)`. Each bucket holds
|
|
614
|
+
* the resolvers that may match that key, in schema order; a key absent from
|
|
615
|
+
* the map uses
|
|
616
|
+
* {@link Schema.implicitScalarAnyFirstChar}
|
|
617
|
+
* (resolvers that declared no first-char constraint, so they apply to any
|
|
618
|
+
* first character).
|
|
619
|
+
*/
|
|
600
620
|
implicitScalarByFirstChar;
|
|
601
621
|
implicitScalarAnyFirstChar;
|
|
622
|
+
/**
|
|
623
|
+
* The default scalar tag (`!!str`), resolved once so the composer's fallback
|
|
624
|
+
* for unresolved plain scalars avoids a keyed lookup per scalar.
|
|
625
|
+
*
|
|
626
|
+
* @internal
|
|
627
|
+
*/
|
|
602
628
|
defaultScalarTag;
|
|
629
|
+
/**
|
|
630
|
+
* The default container tags (`!!seq` / `!!map`), used by the dumper: when a
|
|
631
|
+
* value is identified by its default tag, the tag is implicit and not
|
|
632
|
+
* printed. Undefined if the schema does not define them (then such values
|
|
633
|
+
* can't be dumped).
|
|
634
|
+
*
|
|
635
|
+
* @internal
|
|
636
|
+
*/
|
|
603
637
|
defaultSequenceTag;
|
|
638
|
+
/** @internal */
|
|
604
639
|
defaultMappingTag;
|
|
605
640
|
exact;
|
|
606
641
|
prefix;
|
|
@@ -646,6 +681,52 @@ var Schema = class Schema2 {
|
|
|
646
681
|
this.exact = exact;
|
|
647
682
|
this.prefix = prefix;
|
|
648
683
|
}
|
|
684
|
+
/** @internal */
|
|
685
|
+
lookupScalarTag(tagName) {
|
|
686
|
+
const exactTag = this.exact.scalar[tagName];
|
|
687
|
+
if (exactTag) return exactTag;
|
|
688
|
+
for (const tag of this.prefix.scalar) if (tagName.startsWith(tag.tagName)) return tag;
|
|
689
|
+
}
|
|
690
|
+
/** @internal */
|
|
691
|
+
lookupSequenceTag(tagName) {
|
|
692
|
+
const exactTag = this.exact.sequence[tagName];
|
|
693
|
+
if (exactTag) return exactTag;
|
|
694
|
+
for (const tag of this.prefix.sequence) if (tagName.startsWith(tag.tagName)) return tag;
|
|
695
|
+
}
|
|
696
|
+
/** @internal */
|
|
697
|
+
lookupMappingTag(tagName) {
|
|
698
|
+
const exactTag = this.exact.mapping[tagName];
|
|
699
|
+
if (exactTag) return exactTag;
|
|
700
|
+
for (const tag of this.prefix.mapping) if (tagName.startsWith(tag.tagName)) return tag;
|
|
701
|
+
}
|
|
702
|
+
/** @internal */
|
|
703
|
+
resolveImplicitScalarTag(source) {
|
|
704
|
+
const candidates = this.implicitScalarByFirstChar.get(source.charAt(0)) ?? this.implicitScalarAnyFirstChar;
|
|
705
|
+
for (const tag2 of candidates) {
|
|
706
|
+
const value = tag2.resolve(source, false, tag2.tagName);
|
|
707
|
+
if (value !== NOT_RESOLVED) return {
|
|
708
|
+
value,
|
|
709
|
+
tag: tag2
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
const tag = this.defaultScalarTag;
|
|
713
|
+
return {
|
|
714
|
+
value: tag.resolve(source, false, tag.tagName),
|
|
715
|
+
tag
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
/**
|
|
719
|
+
* Creates a new schema with the specified tags added. If a tag already
|
|
720
|
+
* exists, it is replaced by the specified tag.
|
|
721
|
+
*
|
|
722
|
+
* @example
|
|
723
|
+
*
|
|
724
|
+
* ```javascript
|
|
725
|
+
* import { CORE_SCHEMA, mergeTag, realMapTag } from 'js-yaml'
|
|
726
|
+
*
|
|
727
|
+
* const schema = CORE_SCHEMA.withTags(mergeTag, realMapTag)
|
|
728
|
+
* ```
|
|
729
|
+
*/
|
|
649
730
|
withTags(...tags) {
|
|
650
731
|
let flatTags = [];
|
|
651
732
|
for (const tag of tags) flatTags = flatTags.concat(tag);
|
|
@@ -684,6 +765,19 @@ var YAML11_SCHEMA = new Schema([
|
|
|
684
765
|
pairsTag,
|
|
685
766
|
setTag
|
|
686
767
|
]);
|
|
768
|
+
var DUMP_SCHEMA = YAML11_SCHEMA.withTags({
|
|
769
|
+
...intYaml11Tag,
|
|
770
|
+
resolve: (source, isExplicit, tagName) => {
|
|
771
|
+
const result = intYaml11Tag.resolve(source, isExplicit, tagName);
|
|
772
|
+
return result === NOT_RESOLVED ? intCoreTag.resolve(source, isExplicit, tagName) : result;
|
|
773
|
+
}
|
|
774
|
+
}, {
|
|
775
|
+
...floatYaml11Tag,
|
|
776
|
+
resolve: (source, isExplicit, tagName) => {
|
|
777
|
+
const result = floatYaml11Tag.resolve(source, isExplicit, tagName);
|
|
778
|
+
return result === NOT_RESOLVED ? floatCoreTag.resolve(source, isExplicit, tagName) : result;
|
|
779
|
+
}
|
|
780
|
+
});
|
|
687
781
|
var realMapTag = defineMappingTag("tag:yaml.org,2002:map", {
|
|
688
782
|
create: () => /* @__PURE__ */ new Map(),
|
|
689
783
|
addPair: (container, key, value) => {
|
|
@@ -739,7 +833,11 @@ var legacyMapTag = defineMappingTag("tag:yaml.org,2002:map", {
|
|
|
739
833
|
return normalizedKey !== null && Object.prototype.hasOwnProperty.call(container, normalizedKey);
|
|
740
834
|
},
|
|
741
835
|
keys: (container) => Object.keys(container),
|
|
742
|
-
get: (container, key) =>
|
|
836
|
+
get: (container, key) => {
|
|
837
|
+
const normalizedKey = String(key);
|
|
838
|
+
if (!Object.prototype.hasOwnProperty.call(container, normalizedKey)) return null;
|
|
839
|
+
return container[normalizedKey];
|
|
840
|
+
}
|
|
743
841
|
});
|
|
744
842
|
var DEFAULT_SNIPPET_OPTIONS = {
|
|
745
843
|
maxLength: 79,
|
|
@@ -816,9 +914,13 @@ function formatError(exception, compact) {
|
|
|
816
914
|
${exception.mark.snippet}`;
|
|
817
915
|
return `${exception.reason} ${where}`;
|
|
818
916
|
}
|
|
819
|
-
var YAMLException = class extends Error {
|
|
917
|
+
var YAMLException = class YAMLException2 extends Error {
|
|
820
918
|
reason;
|
|
821
919
|
mark;
|
|
920
|
+
/**
|
|
921
|
+
* Optional `mark` contains source snippet data. Usually, use
|
|
922
|
+
* {@link YAMLException.throwAt} instead of passing it directly.
|
|
923
|
+
*/
|
|
822
924
|
constructor(reason, mark) {
|
|
823
925
|
super();
|
|
824
926
|
this.name = "YAMLException";
|
|
@@ -827,34 +929,65 @@ var YAMLException = class extends Error {
|
|
|
827
929
|
this.message = formatError(this, false);
|
|
828
930
|
if (Error.captureStackTrace) Error.captureStackTrace(this, this.constructor);
|
|
829
931
|
}
|
|
932
|
+
/**
|
|
933
|
+
* Returns the formatted error, omitting the source snippet in compact mode.
|
|
934
|
+
*/
|
|
830
935
|
toString(compact) {
|
|
831
936
|
return `${this.name}: ${formatError(this, compact)}`;
|
|
832
937
|
}
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
938
|
+
/**
|
|
939
|
+
* Builds a YAMLException with a source snippet and throws it. `source` is
|
|
940
|
+
* the raw input text; `position` is an offset into it.
|
|
941
|
+
*/
|
|
942
|
+
static throwAt(source, position, message, filename = "") {
|
|
943
|
+
let line = 0;
|
|
944
|
+
let lineStart = 0;
|
|
945
|
+
for (let index = 0; index < position; index++) {
|
|
946
|
+
const ch = source.charCodeAt(index);
|
|
947
|
+
if (ch === 10) {
|
|
948
|
+
line++;
|
|
949
|
+
lineStart = index + 1;
|
|
950
|
+
} else if (ch === 13) {
|
|
951
|
+
line++;
|
|
952
|
+
if (source.charCodeAt(index + 1) === 10) index++;
|
|
953
|
+
lineStart = index + 1;
|
|
954
|
+
}
|
|
846
955
|
}
|
|
956
|
+
const mark = {
|
|
957
|
+
name: filename,
|
|
958
|
+
buffer: source,
|
|
959
|
+
position,
|
|
960
|
+
line,
|
|
961
|
+
column: position - lineStart
|
|
962
|
+
};
|
|
963
|
+
mark.snippet = makeSnippet(mark);
|
|
964
|
+
throw new YAMLException2(message, mark);
|
|
847
965
|
}
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
966
|
+
};
|
|
967
|
+
var EVENT_ID = {
|
|
968
|
+
DOCUMENT: 1,
|
|
969
|
+
SEQUENCE: 2,
|
|
970
|
+
MAPPING: 3,
|
|
971
|
+
SCALAR: 4,
|
|
972
|
+
ALIAS: 5,
|
|
973
|
+
POP: 6
|
|
974
|
+
};
|
|
975
|
+
var SCALAR_STYLE = {
|
|
976
|
+
PLAIN: 1,
|
|
977
|
+
SINGLE_QUOTED: 2,
|
|
978
|
+
DOUBLE_QUOTED: 3,
|
|
979
|
+
LITERAL_BLOCK: 4,
|
|
980
|
+
FOLDED_BLOCK: 5
|
|
981
|
+
};
|
|
982
|
+
var COLLECTION_STYLE = {
|
|
983
|
+
BLOCK: 1,
|
|
984
|
+
FLOW: 2
|
|
985
|
+
};
|
|
986
|
+
var CHOMPING_MODE = {
|
|
987
|
+
CLIP: 1,
|
|
988
|
+
STRIP: 2,
|
|
989
|
+
KEEP: 3
|
|
990
|
+
};
|
|
858
991
|
var NO_RANGE$3 = -1;
|
|
859
992
|
function simpleEscapeSequence(c) {
|
|
860
993
|
switch (c) {
|
|
@@ -1052,8 +1185,8 @@ function getBlockValue(input, start2, end, indent, chomping, folded) {
|
|
|
1052
1185
|
didReadContent = true;
|
|
1053
1186
|
emptyLines = 0;
|
|
1054
1187
|
}
|
|
1055
|
-
if (chomping ===
|
|
1056
|
-
else if (chomping !==
|
|
1188
|
+
if (chomping === CHOMPING_MODE.KEEP) result += "\n".repeat(didReadContent ? 1 + emptyLines : emptyLines);
|
|
1189
|
+
else if (chomping !== CHOMPING_MODE.STRIP) {
|
|
1057
1190
|
if (didReadContent) result += "\n";
|
|
1058
1191
|
}
|
|
1059
1192
|
return result;
|
|
@@ -1063,22 +1196,22 @@ function getScalarValue(input, scalar) {
|
|
|
1063
1196
|
const { valueStart, valueEnd } = scalar;
|
|
1064
1197
|
if (scalar.fast) return input.slice(valueStart, valueEnd);
|
|
1065
1198
|
switch (scalar.style) {
|
|
1066
|
-
case
|
|
1199
|
+
case SCALAR_STYLE.SINGLE_QUOTED:
|
|
1067
1200
|
return getSingleQuotedValue(input, valueStart, valueEnd);
|
|
1068
|
-
case
|
|
1201
|
+
case SCALAR_STYLE.DOUBLE_QUOTED:
|
|
1069
1202
|
return getDoubleQuotedValue(input, valueStart, valueEnd);
|
|
1070
|
-
case
|
|
1203
|
+
case SCALAR_STYLE.LITERAL_BLOCK:
|
|
1071
1204
|
return getBlockValue(input, valueStart, valueEnd, scalar.indent, scalar.chomping, false);
|
|
1072
|
-
case
|
|
1205
|
+
case SCALAR_STYLE.FOLDED_BLOCK:
|
|
1073
1206
|
return getBlockValue(input, valueStart, valueEnd, scalar.indent, scalar.chomping, true);
|
|
1074
1207
|
default:
|
|
1075
1208
|
return getPlainValue(input, valueStart, valueEnd);
|
|
1076
1209
|
}
|
|
1077
1210
|
}
|
|
1078
|
-
var DEFAULT_TAG_HANDLERS = {
|
|
1211
|
+
var DEFAULT_TAG_HANDLERS = Object.assign(/* @__PURE__ */ Object.create(null), {
|
|
1079
1212
|
"!": "!",
|
|
1080
1213
|
"!!": "tag:yaml.org,2002:"
|
|
1081
|
-
};
|
|
1214
|
+
});
|
|
1082
1215
|
function tagPercentEncode(source) {
|
|
1083
1216
|
return encodeURI(source).replace(/!/g, "%21");
|
|
1084
1217
|
}
|
|
@@ -1099,6 +1232,7 @@ function tagNameShort(fullTag) {
|
|
|
1099
1232
|
return `!<${tagPercentEncode(tag)}>`;
|
|
1100
1233
|
}
|
|
1101
1234
|
var NO_RANGE$2 = -1;
|
|
1235
|
+
var MERGE_TAG_NAME = "tag:yaml.org,2002:merge";
|
|
1102
1236
|
var DEFAULT_CONSTRUCTOR_OPTIONS = {
|
|
1103
1237
|
filename: "",
|
|
1104
1238
|
schema: CORE_SCHEMA,
|
|
@@ -1114,26 +1248,16 @@ function eventPosition$1(event) {
|
|
|
1114
1248
|
return 0;
|
|
1115
1249
|
}
|
|
1116
1250
|
function throwError$1(state, message) {
|
|
1117
|
-
|
|
1251
|
+
YAMLException.throwAt(state.source, state.position, message, state.filename);
|
|
1118
1252
|
}
|
|
1119
1253
|
function finalizeCollection(state, position, tag, carrier) {
|
|
1120
1254
|
try {
|
|
1121
1255
|
return tag.finalize(carrier);
|
|
1122
1256
|
} catch (error) {
|
|
1123
1257
|
if (error instanceof YAMLException) throw error;
|
|
1124
|
-
|
|
1258
|
+
YAMLException.throwAt(state.source, position, error instanceof Error ? error.message : String(error), state.filename);
|
|
1125
1259
|
}
|
|
1126
1260
|
}
|
|
1127
|
-
function lookupTag(exact, prefix, tagName) {
|
|
1128
|
-
const exactTag = exact[tagName];
|
|
1129
|
-
if (exactTag) return exactTag;
|
|
1130
|
-
for (const tag of prefix) if (tagName.startsWith(tag.tagName)) return tag;
|
|
1131
|
-
}
|
|
1132
|
-
function findExplicitTag(state, exact, prefix, tagName, nodeKind) {
|
|
1133
|
-
const tag = lookupTag(exact, prefix, tagName);
|
|
1134
|
-
if (tag) return tag;
|
|
1135
|
-
throwError$1(state, `unknown ${nodeKind} tag !<${tagName}>`);
|
|
1136
|
-
}
|
|
1137
1261
|
function constructScalar(state, event) {
|
|
1138
1262
|
const source = getScalarValue(state.source, event);
|
|
1139
1263
|
const rawTag = event.tagStart === NO_RANGE$2 ? "" : state.source.slice(event.tagStart, event.tagEnd);
|
|
@@ -1144,7 +1268,7 @@ function constructScalar(state, event) {
|
|
|
1144
1268
|
tag: strTag2
|
|
1145
1269
|
};
|
|
1146
1270
|
const tagName = tagNameFull(rawTag, state.tagHandlers);
|
|
1147
|
-
const scalarTag =
|
|
1271
|
+
const scalarTag = state.schema.lookupScalarTag(tagName);
|
|
1148
1272
|
if (scalarTag) {
|
|
1149
1273
|
const result = scalarTag.resolve(source, true, tagName);
|
|
1150
1274
|
if (result === NOT_RESOLVED) throwError$1(state, `cannot resolve a node with !<${tagName}> explicit tag`);
|
|
@@ -1153,7 +1277,7 @@ function constructScalar(state, event) {
|
|
|
1153
1277
|
tag: scalarTag
|
|
1154
1278
|
};
|
|
1155
1279
|
}
|
|
1156
|
-
const collectionTagDef =
|
|
1280
|
+
const collectionTagDef = state.schema.lookupMappingTag(tagName) ?? state.schema.lookupSequenceTag(tagName);
|
|
1157
1281
|
if (collectionTagDef) {
|
|
1158
1282
|
if (source !== "") throwError$1(state, `cannot resolve a node with !<${tagName}> explicit tag`);
|
|
1159
1283
|
const carrier = collectionTagDef.create(tagName);
|
|
@@ -1164,28 +1288,15 @@ function constructScalar(state, event) {
|
|
|
1164
1288
|
}
|
|
1165
1289
|
throwError$1(state, `unknown scalar tag !<${tagName}>`);
|
|
1166
1290
|
}
|
|
1167
|
-
if (event.style ===
|
|
1168
|
-
const candidates = state.schema.implicitScalarByFirstChar.get(source.charAt(0)) ?? state.schema.implicitScalarAnyFirstChar;
|
|
1169
|
-
for (const tag of candidates) {
|
|
1170
|
-
const result = tag.resolve(source, false, tag.tagName);
|
|
1171
|
-
if (result !== NOT_RESOLVED) return {
|
|
1172
|
-
value: result,
|
|
1173
|
-
tag
|
|
1174
|
-
};
|
|
1175
|
-
}
|
|
1176
|
-
}
|
|
1291
|
+
if (event.style === SCALAR_STYLE.PLAIN) return state.schema.resolveImplicitScalarTag(source);
|
|
1177
1292
|
return {
|
|
1178
1293
|
value: strTag2.resolve(source, false, strTag2.tagName),
|
|
1179
1294
|
tag: strTag2
|
|
1180
1295
|
};
|
|
1181
1296
|
}
|
|
1182
|
-
function
|
|
1297
|
+
function collectionTagName(state, event, defaultTagName) {
|
|
1183
1298
|
const rawTag = event.tagStart === NO_RANGE$2 ? "" : state.source.slice(event.tagStart, event.tagEnd);
|
|
1184
|
-
|
|
1185
|
-
return {
|
|
1186
|
-
tagName,
|
|
1187
|
-
tag: findExplicitTag(state, exact, prefix, tagName, nodeKind)
|
|
1188
|
-
};
|
|
1299
|
+
return rawTag === "" || rawTag === "!" ? defaultTagName : tagNameFull(rawTag, state.tagHandlers);
|
|
1189
1300
|
}
|
|
1190
1301
|
function isMappingTag(tag) {
|
|
1191
1302
|
return tag.nodeKind === "mapping";
|
|
@@ -1202,12 +1313,16 @@ function mergeKeys(state, frame, source, sourceTag) {
|
|
|
1202
1313
|
function mergeSource(state, frame, source, sourceTag) {
|
|
1203
1314
|
state.position = frame.keyPosition;
|
|
1204
1315
|
if (isMappingTag(sourceTag)) mergeKeys(state, frame, source, sourceTag);
|
|
1205
|
-
else if (sourceTag.nodeKind === "sequence" && Array.isArray(source)) for (const element of source)
|
|
1316
|
+
else if (sourceTag.nodeKind === "sequence" && Array.isArray(source)) for (const element of source) {
|
|
1317
|
+
const elementTag = state.nodeTags.get(element);
|
|
1318
|
+
if (!elementTag) throwError$1(state, "cannot merge mappings; the provided source object is unacceptable");
|
|
1319
|
+
mergeKeys(state, frame, element, elementTag);
|
|
1320
|
+
}
|
|
1206
1321
|
else throwError$1(state, "cannot merge mappings; the provided source object is unacceptable");
|
|
1207
1322
|
}
|
|
1208
1323
|
function addMappingValue(state, frame, key, value, tag) {
|
|
1209
1324
|
state.position = frame.keyPosition;
|
|
1210
|
-
if (
|
|
1325
|
+
if (frame.keyIsMerge) {
|
|
1211
1326
|
mergeSource(state, frame, value, tag);
|
|
1212
1327
|
return;
|
|
1213
1328
|
}
|
|
@@ -1222,9 +1337,7 @@ function addValue(state, value, tag) {
|
|
|
1222
1337
|
frame.value = value;
|
|
1223
1338
|
frame.hasValue = true;
|
|
1224
1339
|
} else if (frame.kind === "sequence") {
|
|
1225
|
-
if (
|
|
1226
|
-
if (!isMappingTag(tag)) throwError$1(state, "cannot merge mappings; the provided source object is unacceptable");
|
|
1227
|
-
}
|
|
1340
|
+
if (isMappingTag(tag)) state.nodeTags.set(value, tag);
|
|
1228
1341
|
const err = frame.tag.addItem(frame.value, value, frame.index++);
|
|
1229
1342
|
if (err) throwError$1(state, err);
|
|
1230
1343
|
} else if (frame.hasKey) {
|
|
@@ -1236,6 +1349,7 @@ function addValue(state, value, tag) {
|
|
|
1236
1349
|
frame.key = value;
|
|
1237
1350
|
frame.keyPosition = state.position;
|
|
1238
1351
|
frame.hasKey = true;
|
|
1352
|
+
frame.keyIsMerge = tag.tagName === MERGE_TAG_NAME;
|
|
1239
1353
|
}
|
|
1240
1354
|
}
|
|
1241
1355
|
function storeAnchor(state, event, value, tag, isValueFinal) {
|
|
@@ -1260,6 +1374,7 @@ function constructFromEvents(events, options) {
|
|
|
1260
1374
|
position: 0,
|
|
1261
1375
|
frames: [],
|
|
1262
1376
|
anchors: /* @__PURE__ */ new Map(),
|
|
1377
|
+
nodeTags: /* @__PURE__ */ new Map(),
|
|
1263
1378
|
tagHandlers: /* @__PURE__ */ Object.create(null),
|
|
1264
1379
|
totalMergeKeys: 0,
|
|
1265
1380
|
aliasCount: 0
|
|
@@ -1268,8 +1383,9 @@ function constructFromEvents(events, options) {
|
|
|
1268
1383
|
const event = state.events[state.eventIndex++];
|
|
1269
1384
|
state.position = eventPosition$1(event);
|
|
1270
1385
|
switch (event.type) {
|
|
1271
|
-
case
|
|
1386
|
+
case EVENT_ID.DOCUMENT:
|
|
1272
1387
|
state.anchors = /* @__PURE__ */ new Map();
|
|
1388
|
+
state.nodeTags = /* @__PURE__ */ new Map();
|
|
1273
1389
|
state.aliasCount = 0;
|
|
1274
1390
|
state.tagHandlers = /* @__PURE__ */ Object.create(null);
|
|
1275
1391
|
for (const directive of event.directives) if (directive.kind === "tag") state.tagHandlers[directive.handle] = directive.prefix;
|
|
@@ -1280,47 +1396,49 @@ function constructFromEvents(events, options) {
|
|
|
1280
1396
|
hasValue: false
|
|
1281
1397
|
});
|
|
1282
1398
|
break;
|
|
1283
|
-
case
|
|
1399
|
+
case EVENT_ID.SCALAR: {
|
|
1284
1400
|
const { value, tag } = constructScalar(state, event);
|
|
1285
1401
|
storeAnchor(state, event, value, tag, true);
|
|
1286
1402
|
addValue(state, value, tag);
|
|
1287
1403
|
break;
|
|
1288
1404
|
}
|
|
1289
|
-
case
|
|
1290
|
-
const
|
|
1291
|
-
const
|
|
1292
|
-
|
|
1293
|
-
const
|
|
1294
|
-
const
|
|
1405
|
+
case EVENT_ID.SEQUENCE: {
|
|
1406
|
+
const tagName = collectionTagName(state, event, "tag:yaml.org,2002:seq");
|
|
1407
|
+
const tag = state.schema.lookupSequenceTag(tagName);
|
|
1408
|
+
if (!tag) throwError$1(state, `unknown sequence tag !<${tagName}>`);
|
|
1409
|
+
const value = tag.create(tagName);
|
|
1410
|
+
const anchor = storeAnchor(state, event, value, tag, tag.carrierIsResult);
|
|
1295
1411
|
state.frames.push({
|
|
1296
1412
|
kind: "sequence",
|
|
1297
1413
|
position: state.position,
|
|
1298
1414
|
value,
|
|
1299
|
-
tag
|
|
1415
|
+
tag,
|
|
1300
1416
|
anchor,
|
|
1301
|
-
index: 0
|
|
1302
|
-
merge
|
|
1417
|
+
index: 0
|
|
1303
1418
|
});
|
|
1304
1419
|
break;
|
|
1305
1420
|
}
|
|
1306
|
-
case
|
|
1307
|
-
const
|
|
1308
|
-
const
|
|
1309
|
-
|
|
1421
|
+
case EVENT_ID.MAPPING: {
|
|
1422
|
+
const tagName = collectionTagName(state, event, "tag:yaml.org,2002:map");
|
|
1423
|
+
const tag = state.schema.lookupMappingTag(tagName);
|
|
1424
|
+
if (!tag) throwError$1(state, `unknown mapping tag !<${tagName}>`);
|
|
1425
|
+
const value = tag.create(tagName);
|
|
1426
|
+
const anchor = storeAnchor(state, event, value, tag, tag.carrierIsResult);
|
|
1310
1427
|
state.frames.push({
|
|
1311
1428
|
kind: "mapping",
|
|
1312
1429
|
position: state.position,
|
|
1313
1430
|
value,
|
|
1314
|
-
tag
|
|
1431
|
+
tag,
|
|
1315
1432
|
anchor,
|
|
1316
1433
|
key: void 0,
|
|
1317
1434
|
keyPosition: state.position,
|
|
1318
1435
|
hasKey: false,
|
|
1436
|
+
keyIsMerge: false,
|
|
1319
1437
|
overridable: null
|
|
1320
1438
|
});
|
|
1321
1439
|
break;
|
|
1322
1440
|
}
|
|
1323
|
-
case
|
|
1441
|
+
case EVENT_ID.ALIAS: {
|
|
1324
1442
|
if (state.maxAliases !== -1 && ++state.aliasCount > state.maxAliases) throwError$1(state, `aliases exceeded maxAliases (${state.maxAliases})`);
|
|
1325
1443
|
const name = state.source.slice(event.anchorStart, event.anchorEnd);
|
|
1326
1444
|
const anchor = state.anchors.get(name);
|
|
@@ -1329,8 +1447,12 @@ function constructFromEvents(events, options) {
|
|
|
1329
1447
|
addValue(state, anchor.value, anchor.tag);
|
|
1330
1448
|
break;
|
|
1331
1449
|
}
|
|
1332
|
-
case
|
|
1450
|
+
case EVENT_ID.POP: {
|
|
1333
1451
|
const frame = state.frames.pop();
|
|
1452
|
+
if (frame.kind === "mapping" && frame.hasKey) {
|
|
1453
|
+
state.position = frame.keyPosition;
|
|
1454
|
+
throwError$1(state, "incomplete mapping pair in event stream");
|
|
1455
|
+
}
|
|
1334
1456
|
if (frame.kind === "document") state.documents.push(frame.value);
|
|
1335
1457
|
else {
|
|
1336
1458
|
const value = frame.tag.carrierIsResult ? frame.value : finalizeCollection(state, frame.position, frame.tag, frame.value);
|
|
@@ -1366,7 +1488,7 @@ var DEFAULT_PARSER_OPTIONS = {
|
|
|
1366
1488
|
};
|
|
1367
1489
|
function addDocumentEvent(state, explicitStart, explicitEnd) {
|
|
1368
1490
|
state.events.push({
|
|
1369
|
-
type:
|
|
1491
|
+
type: EVENT_ID.DOCUMENT,
|
|
1370
1492
|
explicitStart,
|
|
1371
1493
|
explicitEnd,
|
|
1372
1494
|
directives: state.directives
|
|
@@ -1374,7 +1496,7 @@ function addDocumentEvent(state, explicitStart, explicitEnd) {
|
|
|
1374
1496
|
}
|
|
1375
1497
|
function addSequenceEvent(state, start2, anchorStart, anchorEnd, tagStart, tagEnd, style) {
|
|
1376
1498
|
state.events.push({
|
|
1377
|
-
type:
|
|
1499
|
+
type: EVENT_ID.SEQUENCE,
|
|
1378
1500
|
start: start2,
|
|
1379
1501
|
anchorStart,
|
|
1380
1502
|
anchorEnd,
|
|
@@ -1385,7 +1507,7 @@ function addSequenceEvent(state, start2, anchorStart, anchorEnd, tagStart, tagEn
|
|
|
1385
1507
|
}
|
|
1386
1508
|
function addMappingEvent(state, start2, anchorStart, anchorEnd, tagStart, tagEnd, style) {
|
|
1387
1509
|
state.events.push({
|
|
1388
|
-
type:
|
|
1510
|
+
type: EVENT_ID.MAPPING,
|
|
1389
1511
|
start: start2,
|
|
1390
1512
|
anchorStart,
|
|
1391
1513
|
anchorEnd,
|
|
@@ -1394,9 +1516,20 @@ function addMappingEvent(state, start2, anchorStart, anchorEnd, tagStart, tagEnd
|
|
|
1394
1516
|
style
|
|
1395
1517
|
});
|
|
1396
1518
|
}
|
|
1397
|
-
function
|
|
1519
|
+
function insertFlowPairMappingEvent(state, snapshot) {
|
|
1520
|
+
state.events.splice(snapshot.eventsLength, 0, {
|
|
1521
|
+
type: EVENT_ID.MAPPING,
|
|
1522
|
+
start: snapshot.position,
|
|
1523
|
+
anchorStart: NO_RANGE$1,
|
|
1524
|
+
anchorEnd: NO_RANGE$1,
|
|
1525
|
+
tagStart: NO_RANGE$1,
|
|
1526
|
+
tagEnd: NO_RANGE$1,
|
|
1527
|
+
style: COLLECTION_STYLE.FLOW
|
|
1528
|
+
});
|
|
1529
|
+
}
|
|
1530
|
+
function addScalarEvent(state, valueStart, valueEnd, anchorStart, anchorEnd, tagStart, tagEnd, style, chomping = CHOMPING_MODE.CLIP, indent = -1, fast = false) {
|
|
1398
1531
|
state.events.push({
|
|
1399
|
-
type:
|
|
1532
|
+
type: EVENT_ID.SCALAR,
|
|
1400
1533
|
valueStart,
|
|
1401
1534
|
valueEnd,
|
|
1402
1535
|
anchorStart,
|
|
@@ -1411,16 +1544,16 @@ function addScalarEvent(state, valueStart, valueEnd, anchorStart, anchorEnd, tag
|
|
|
1411
1544
|
}
|
|
1412
1545
|
function addAliasEvent(state, anchorStart, anchorEnd) {
|
|
1413
1546
|
state.events.push({
|
|
1414
|
-
type:
|
|
1547
|
+
type: EVENT_ID.ALIAS,
|
|
1415
1548
|
anchorStart,
|
|
1416
1549
|
anchorEnd
|
|
1417
1550
|
});
|
|
1418
1551
|
}
|
|
1419
1552
|
function addPopEvent(state) {
|
|
1420
|
-
state.events.push({ type:
|
|
1553
|
+
state.events.push({ type: EVENT_ID.POP });
|
|
1421
1554
|
}
|
|
1422
1555
|
function addEmptyScalarEvent(state) {
|
|
1423
|
-
addScalarEvent(state, NO_RANGE$1, NO_RANGE$1, NO_RANGE$1, NO_RANGE$1, NO_RANGE$1, NO_RANGE$1,
|
|
1556
|
+
addScalarEvent(state, NO_RANGE$1, NO_RANGE$1, NO_RANGE$1, NO_RANGE$1, NO_RANGE$1, NO_RANGE$1, SCALAR_STYLE.PLAIN);
|
|
1424
1557
|
}
|
|
1425
1558
|
function emptyProperties() {
|
|
1426
1559
|
return {
|
|
@@ -1449,7 +1582,7 @@ function restoreState(state, snapshot) {
|
|
|
1449
1582
|
state.events.length = snapshot.eventsLength;
|
|
1450
1583
|
}
|
|
1451
1584
|
function throwError(state, message) {
|
|
1452
|
-
|
|
1585
|
+
YAMLException.throwAt(state.input.slice(0, state.length), state.position, message, state.filename);
|
|
1453
1586
|
}
|
|
1454
1587
|
function isEol(c) {
|
|
1455
1588
|
return c === 10 || c === 13;
|
|
@@ -1617,7 +1750,7 @@ function readSingleQuotedScalar(state, nodeIndent, props) {
|
|
|
1617
1750
|
}
|
|
1618
1751
|
const end = state.position;
|
|
1619
1752
|
state.position++;
|
|
1620
|
-
addScalarEvent(state, start2, end, props.anchorStart, props.anchorEnd, props.tagStart, props.tagEnd,
|
|
1753
|
+
addScalarEvent(state, start2, end, props.anchorStart, props.anchorEnd, props.tagStart, props.tagEnd, SCALAR_STYLE.SINGLE_QUOTED, CHOMPING_MODE.CLIP, -1, simple);
|
|
1621
1754
|
return true;
|
|
1622
1755
|
}
|
|
1623
1756
|
if (isEol(ch)) {
|
|
@@ -1639,7 +1772,7 @@ function readDoubleQuotedScalar(state, nodeIndent, props) {
|
|
|
1639
1772
|
if (ch === 34) {
|
|
1640
1773
|
const end = state.position;
|
|
1641
1774
|
state.position++;
|
|
1642
|
-
addScalarEvent(state, start2, end, props.anchorStart, props.anchorEnd, props.tagStart, props.tagEnd,
|
|
1775
|
+
addScalarEvent(state, start2, end, props.anchorStart, props.anchorEnd, props.tagStart, props.tagEnd, SCALAR_STYLE.DOUBLE_QUOTED, CHOMPING_MODE.CLIP, -1, simple);
|
|
1643
1776
|
return true;
|
|
1644
1777
|
}
|
|
1645
1778
|
if (ch === 92) {
|
|
@@ -1667,18 +1800,18 @@ function readDoubleQuotedScalar(state, nodeIndent, props) {
|
|
|
1667
1800
|
}
|
|
1668
1801
|
function readBlockScalar(state, parentIndent, props) {
|
|
1669
1802
|
const ch = state.input.charCodeAt(state.position);
|
|
1670
|
-
let chomping =
|
|
1803
|
+
let chomping = CHOMPING_MODE.CLIP;
|
|
1671
1804
|
let indent = -1;
|
|
1672
1805
|
let detectedIndent = false;
|
|
1673
1806
|
if (ch !== 124 && ch !== 62) return false;
|
|
1674
|
-
const style = ch === 124 ?
|
|
1807
|
+
const style = ch === 124 ? SCALAR_STYLE.LITERAL_BLOCK : SCALAR_STYLE.FOLDED_BLOCK;
|
|
1675
1808
|
state.position++;
|
|
1676
1809
|
while (state.input.charCodeAt(state.position) !== 0) {
|
|
1677
1810
|
const current = state.input.charCodeAt(state.position);
|
|
1678
1811
|
const digit = fromDecimalCode(current);
|
|
1679
1812
|
if (current === 43 || current === 45) {
|
|
1680
|
-
if (chomping !==
|
|
1681
|
-
chomping = current === 43 ?
|
|
1813
|
+
if (chomping !== CHOMPING_MODE.CLIP) throwError(state, "repeat of a chomping mode identifier");
|
|
1814
|
+
chomping = current === 43 ? CHOMPING_MODE.KEEP : CHOMPING_MODE.STRIP;
|
|
1682
1815
|
state.position++;
|
|
1683
1816
|
} else if (digit >= 0) {
|
|
1684
1817
|
if (digit === 0) throwError(state, "bad explicit indentation width of a block scalar; it cannot be less than one");
|
|
@@ -1793,7 +1926,7 @@ function readPlainScalar(state, nodeIndent, nodeContext, props) {
|
|
|
1793
1926
|
}
|
|
1794
1927
|
if (end === start2) return false;
|
|
1795
1928
|
checkPrintable(state, start2, end);
|
|
1796
|
-
addScalarEvent(state, start2, end, props.anchorStart, props.anchorEnd, props.tagStart, props.tagEnd,
|
|
1929
|
+
addScalarEvent(state, start2, end, props.anchorStart, props.anchorEnd, props.tagStart, props.tagEnd, SCALAR_STYLE.PLAIN, CHOMPING_MODE.CLIP, -1, !multiline);
|
|
1797
1930
|
return true;
|
|
1798
1931
|
}
|
|
1799
1932
|
function skipFlowSeparationSpace(state, nodeIndent) {
|
|
@@ -1808,8 +1941,8 @@ function readFlowCollection(state, nodeIndent, props) {
|
|
|
1808
1941
|
let readNext = true;
|
|
1809
1942
|
if (ch !== 91 && ch !== 123) return false;
|
|
1810
1943
|
const terminator = isMapping ? 125 : 93;
|
|
1811
|
-
if (isMapping) addMappingEvent(state, start2, props.anchorStart, props.anchorEnd, props.tagStart, props.tagEnd,
|
|
1812
|
-
else addSequenceEvent(state, start2, props.anchorStart, props.anchorEnd, props.tagStart, props.tagEnd,
|
|
1944
|
+
if (isMapping) addMappingEvent(state, start2, props.anchorStart, props.anchorEnd, props.tagStart, props.tagEnd, COLLECTION_STYLE.FLOW);
|
|
1945
|
+
else addSequenceEvent(state, start2, props.anchorStart, props.anchorEnd, props.tagStart, props.tagEnd, COLLECTION_STYLE.FLOW);
|
|
1813
1946
|
state.position++;
|
|
1814
1947
|
while (state.input.charCodeAt(state.position) !== 0) {
|
|
1815
1948
|
skipFlowSeparationSpace(state, nodeIndent);
|
|
@@ -1837,12 +1970,8 @@ function readFlowCollection(state, nodeIndent, props) {
|
|
|
1837
1970
|
state.position++;
|
|
1838
1971
|
skipFlowSeparationSpace(state, nodeIndent);
|
|
1839
1972
|
if (!isMapping) {
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
if (!parseNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true)) addEmptyScalarEvent(state);
|
|
1843
|
-
skipFlowSeparationSpace(state, nodeIndent);
|
|
1844
|
-
state.position++;
|
|
1845
|
-
skipFlowSeparationSpace(state, nodeIndent);
|
|
1973
|
+
insertFlowPairMappingEvent(state, entryStart);
|
|
1974
|
+
if (!keyWasRead) addEmptyScalarEvent(state);
|
|
1846
1975
|
} else if (!keyWasRead) addEmptyScalarEvent(state);
|
|
1847
1976
|
if (!parseNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true)) addEmptyScalarEvent(state);
|
|
1848
1977
|
skipFlowSeparationSpace(state, nodeIndent);
|
|
@@ -1852,9 +1981,8 @@ function readFlowCollection(state, nodeIndent, props) {
|
|
|
1852
1981
|
addEmptyScalarEvent(state);
|
|
1853
1982
|
} else if (isMapping) addEmptyScalarEvent(state);
|
|
1854
1983
|
else if (isPair) {
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
parseNode(state, nodeIndent, CONTEXT_FLOW_IN, false, true);
|
|
1984
|
+
insertFlowPairMappingEvent(state, entryStart);
|
|
1985
|
+
if (!keyWasRead) addEmptyScalarEvent(state);
|
|
1858
1986
|
addEmptyScalarEvent(state);
|
|
1859
1987
|
addPopEvent(state);
|
|
1860
1988
|
}
|
|
@@ -1868,7 +1996,7 @@ function readFlowCollection(state, nodeIndent, props) {
|
|
|
1868
1996
|
}
|
|
1869
1997
|
function readBlockSequence(state, nodeIndent, props) {
|
|
1870
1998
|
if (state.firstTabInLine !== -1 || state.input.charCodeAt(state.position) !== 45 || !isWsOrEolOrEnd(state.input.charCodeAt(state.position + 1))) return false;
|
|
1871
|
-
addSequenceEvent(state, state.position, props.anchorStart, props.anchorEnd, props.tagStart, props.tagEnd,
|
|
1999
|
+
addSequenceEvent(state, state.position, props.anchorStart, props.anchorEnd, props.tagStart, props.tagEnd, COLLECTION_STYLE.BLOCK);
|
|
1872
2000
|
while (state.input.charCodeAt(state.position) === 45 && isWsOrEolOrEnd(state.input.charCodeAt(state.position + 1))) {
|
|
1873
2001
|
if (state.firstTabInLine !== -1) {
|
|
1874
2002
|
state.position = state.firstTabInLine;
|
|
@@ -1904,7 +2032,7 @@ function readBlockMapping(state, nodeIndent, flowIndent, props) {
|
|
|
1904
2032
|
const entryLine = state.line;
|
|
1905
2033
|
if ((ch === 63 || ch === 58) && isWsOrEolOrEnd(following)) {
|
|
1906
2034
|
if (!mappingOpened) {
|
|
1907
|
-
addMappingEvent(state, state.position, props.anchorStart, props.anchorEnd, props.tagStart, props.tagEnd,
|
|
2035
|
+
addMappingEvent(state, state.position, props.anchorStart, props.anchorEnd, props.tagStart, props.tagEnd, COLLECTION_STYLE.BLOCK);
|
|
1908
2036
|
mappingOpened = true;
|
|
1909
2037
|
}
|
|
1910
2038
|
if (ch === 63) {
|
|
@@ -1934,7 +2062,7 @@ function readBlockMapping(state, nodeIndent, flowIndent, props) {
|
|
|
1934
2062
|
if (!isWsOrEolOrEnd(ch)) throwError(state, "a whitespace character is expected after the key-value separator within a block mapping");
|
|
1935
2063
|
if (!mappingOpened) {
|
|
1936
2064
|
restoreState(state, beforeKey);
|
|
1937
|
-
addMappingEvent(state, beforeKey.position, props.anchorStart, props.anchorEnd, props.tagStart, props.tagEnd,
|
|
2065
|
+
addMappingEvent(state, beforeKey.position, props.anchorStart, props.anchorEnd, props.tagStart, props.tagEnd, COLLECTION_STYLE.BLOCK);
|
|
1938
2066
|
mappingOpened = true;
|
|
1939
2067
|
parseNode(state, flowIndent, CONTEXT_FLOW_OUT, false, true);
|
|
1940
2068
|
ch = state.input.charCodeAt(state.position);
|
|
@@ -1995,10 +2123,6 @@ function parseNode(state, parentIndent, nodeContext, allowToSeek, allowCompact,
|
|
|
1995
2123
|
else if (state.lineIndent === parentIndent) indentStatus = 0;
|
|
1996
2124
|
else indentStatus = -1;
|
|
1997
2125
|
}
|
|
1998
|
-
if (state.position === state.lineStart && testDocumentSeparator(state)) {
|
|
1999
|
-
state.depth--;
|
|
2000
|
-
return false;
|
|
2001
|
-
}
|
|
2002
2126
|
if (indentStatus === 1) while (true) {
|
|
2003
2127
|
const ch = state.input.charCodeAt(state.position);
|
|
2004
2128
|
const propertyState = snapshotState(state);
|
|
@@ -2006,7 +2130,7 @@ function parseNode(state, parentIndent, nodeContext, allowToSeek, allowCompact,
|
|
|
2006
2130
|
if (atNewLine && allowBlockStyles && (props.tagStart !== NO_RANGE$1 || props.anchorStart !== NO_RANGE$1) && (ch === 33 || ch === 38)) {
|
|
2007
2131
|
const fallbackState = snapshotState(state);
|
|
2008
2132
|
const flowIndent = parentIndent + 1;
|
|
2009
|
-
if (readBlockMapping(state, state.position - state.lineStart, flowIndent, props) && state.events[fallbackState.eventsLength]?.type ===
|
|
2133
|
+
if (readBlockMapping(state, state.position - state.lineStart, flowIndent, props) && state.events[fallbackState.eventsLength]?.type === EVENT_ID.MAPPING) {
|
|
2010
2134
|
state.depth--;
|
|
2011
2135
|
return true;
|
|
2012
2136
|
}
|
|
@@ -2034,7 +2158,7 @@ function parseNode(state, parentIndent, nodeContext, allowToSeek, allowCompact,
|
|
|
2034
2158
|
const fallbackState = snapshotState(state);
|
|
2035
2159
|
const propertyIndent = propertyStart.position - propertyStart.lineStart;
|
|
2036
2160
|
restoreState(state, propertyStart);
|
|
2037
|
-
if (readBlockMapping(state, propertyIndent, flowIndent, emptyProperties()) && state.events[fallbackState.eventsLength]?.type ===
|
|
2161
|
+
if (readBlockMapping(state, propertyIndent, flowIndent, emptyProperties()) && state.events[fallbackState.eventsLength]?.type === EVENT_ID.MAPPING) hasContent = true;
|
|
2038
2162
|
else restoreState(state, fallbackState);
|
|
2039
2163
|
}
|
|
2040
2164
|
if (!hasContent && (allowBlockScalars && readBlockScalar(state, flowIndent, props) || readSingleQuotedScalar(state, flowIndent, props) || readDoubleQuotedScalar(state, flowIndent, props) || readAlias(state, props) || readPlainScalar(state, flowIndent, nodeContext, props))) hasContent = true;
|
|
@@ -2043,7 +2167,7 @@ function parseNode(state, parentIndent, nodeContext, allowToSeek, allowCompact,
|
|
|
2043
2167
|
}
|
|
2044
2168
|
allowBlockScalars = allowBlockScalars && !hasContent;
|
|
2045
2169
|
if (!hasContent && (props.anchorStart !== NO_RANGE$1 || props.tagStart !== NO_RANGE$1 || allowBlockScalars)) {
|
|
2046
|
-
addScalarEvent(state, NO_RANGE$1, NO_RANGE$1, props.anchorStart, props.anchorEnd, props.tagStart, props.tagEnd,
|
|
2170
|
+
addScalarEvent(state, NO_RANGE$1, NO_RANGE$1, props.anchorStart, props.anchorEnd, props.tagStart, props.tagEnd, SCALAR_STYLE.PLAIN);
|
|
2047
2171
|
hasContent = true;
|
|
2048
2172
|
}
|
|
2049
2173
|
state.depth--;
|
|
@@ -2128,7 +2252,7 @@ function readDocument(state) {
|
|
|
2128
2252
|
}
|
|
2129
2253
|
}
|
|
2130
2254
|
const documentEvent = state.events[documentEventIndex];
|
|
2131
|
-
if (documentEvent?.type ===
|
|
2255
|
+
if (documentEvent?.type === EVENT_ID.DOCUMENT) documentEvent.explicitEnd = explicitEnd;
|
|
2132
2256
|
addPopEvent(state);
|
|
2133
2257
|
if (!explicitEnd && state.position < state.length && !(state.position === state.lineStart && testDocumentSeparator(state))) throwError(state, "end of the stream or a document separator is expected");
|
|
2134
2258
|
}
|
|
@@ -2150,7 +2274,7 @@ function parseEvents(input, options) {
|
|
|
2150
2274
|
events: []
|
|
2151
2275
|
};
|
|
2152
2276
|
const nullpos = input.indexOf("\0");
|
|
2153
|
-
if (nullpos !== -1)
|
|
2277
|
+
if (nullpos !== -1) YAMLException.throwAt(input, nullpos, "null byte is not allowed in input", state.filename);
|
|
2154
2278
|
if (state.input.charCodeAt(state.position) === 65279) state.position++;
|
|
2155
2279
|
while (state.position < state.length) {
|
|
2156
2280
|
skipSeparationSpace(state, true);
|
|
@@ -2186,6 +2310,7 @@ function load(input, options) {
|
|
|
2186
2310
|
throw new YAMLException("expected a single document in the stream, but found more");
|
|
2187
2311
|
}
|
|
2188
2312
|
var Style = class {
|
|
2313
|
+
/** Whether to print the node's tag explicitly. */
|
|
2189
2314
|
tagged = false;
|
|
2190
2315
|
flow = false;
|
|
2191
2316
|
singleQuoted = false;
|
|
@@ -2221,9 +2346,9 @@ function buildRepresentTypes(schema) {
|
|
|
2221
2346
|
function matchTag(state, object) {
|
|
2222
2347
|
for (let index = 0, length = state.representTypes.length; index < length; index += 1) {
|
|
2223
2348
|
const { tag, implicitTag } = state.representTypes[index];
|
|
2224
|
-
if (tag.identify
|
|
2349
|
+
if (tag.identify(object)) {
|
|
2225
2350
|
let tagName;
|
|
2226
|
-
if (tag.matchByTagPrefix
|
|
2351
|
+
if (tag.matchByTagPrefix) tagName = tag.representTagName(object);
|
|
2227
2352
|
else tagName = tag.tagName;
|
|
2228
2353
|
return {
|
|
2229
2354
|
tag,
|
|
@@ -2423,8 +2548,7 @@ function createPresenterState(options) {
|
|
|
2423
2548
|
};
|
|
2424
2549
|
return {
|
|
2425
2550
|
...opts,
|
|
2426
|
-
defaultScalarTagName: opts.schema.defaultScalarTag.tagName
|
|
2427
|
-
implicitResolvers: opts.schema.implicitScalarTags
|
|
2551
|
+
defaultScalarTagName: opts.schema.defaultScalarTag.tagName
|
|
2428
2552
|
};
|
|
2429
2553
|
}
|
|
2430
2554
|
function encodeNonPrintable(character) {
|
|
@@ -2465,13 +2589,6 @@ function scalarLayout(state, level) {
|
|
|
2465
2589
|
lineWidth: state.lineWidth === -1 ? -1 : Math.max(Math.min(state.lineWidth, 40), state.lineWidth - indent)
|
|
2466
2590
|
};
|
|
2467
2591
|
}
|
|
2468
|
-
function resolveImplicitTag(state, str) {
|
|
2469
|
-
for (let index = 0, length = state.implicitResolvers.length; index < length; index += 1) {
|
|
2470
|
-
const tagDefinition = state.implicitResolvers[index];
|
|
2471
|
-
if (tagDefinition.resolve(str, false, tagDefinition.tagName) !== NOT_RESOLVED) return tagDefinition.tagName;
|
|
2472
|
-
}
|
|
2473
|
-
return state.defaultScalarTagName;
|
|
2474
|
-
}
|
|
2475
2592
|
function isWhitespace(c) {
|
|
2476
2593
|
return c === CHAR_SPACE || c === CHAR_TAB;
|
|
2477
2594
|
}
|
|
@@ -2491,7 +2608,7 @@ function isNsCharOrWhitespace(c) {
|
|
|
2491
2608
|
function isPlainSafe(c, prev, inblock) {
|
|
2492
2609
|
const cIsNsCharOrWhitespace = isNsCharOrWhitespace(c);
|
|
2493
2610
|
const cIsNsChar = cIsNsCharOrWhitespace && !isWhitespace(c);
|
|
2494
|
-
return (inblock ? cIsNsCharOrWhitespace : cIsNsCharOrWhitespace && c !== CHAR_COMMA && c !== CHAR_LEFT_SQUARE_BRACKET && c !== CHAR_RIGHT_SQUARE_BRACKET && c !== CHAR_LEFT_CURLY_BRACKET && c !== CHAR_RIGHT_CURLY_BRACKET) && c !== CHAR_SHARP && !(prev === CHAR_COLON && !cIsNsChar) || isNsCharOrWhitespace(prev) && !isWhitespace(prev) && c === CHAR_SHARP || prev === CHAR_COLON && cIsNsChar;
|
|
2611
|
+
return (inblock ? cIsNsCharOrWhitespace : cIsNsCharOrWhitespace && c !== CHAR_COMMA && c !== CHAR_LEFT_SQUARE_BRACKET && c !== CHAR_RIGHT_SQUARE_BRACKET && c !== CHAR_LEFT_CURLY_BRACKET && c !== CHAR_RIGHT_CURLY_BRACKET) && c !== CHAR_SHARP && !(prev === CHAR_COLON && !cIsNsChar) || isNsCharOrWhitespace(prev) && !isWhitespace(prev) && c === CHAR_SHARP || prev === CHAR_COLON && cIsNsChar && (inblock || c !== CHAR_COMMA && c !== CHAR_LEFT_SQUARE_BRACKET && c !== CHAR_RIGHT_SQUARE_BRACKET && c !== CHAR_LEFT_CURLY_BRACKET && c !== CHAR_RIGHT_CURLY_BRACKET);
|
|
2495
2612
|
}
|
|
2496
2613
|
function isPlainSafeFirst(c) {
|
|
2497
2614
|
return isPrintable(c) && c !== CHAR_BOM && !isWhitespace(c) && c !== CHAR_MINUS && c !== CHAR_QUESTION && c !== CHAR_COLON && c !== CHAR_COMMA && c !== CHAR_LEFT_SQUARE_BRACKET && c !== CHAR_RIGHT_SQUARE_BRACKET && c !== CHAR_LEFT_CURLY_BRACKET && c !== CHAR_RIGHT_CURLY_BRACKET && c !== CHAR_SHARP && c !== CHAR_AMPERSAND && c !== CHAR_ASTERISK && c !== CHAR_EXCLAMATION && c !== CHAR_VERTICAL_LINE && c !== CHAR_EQUALS && c !== CHAR_GREATER_THAN && c !== CHAR_SINGLE_QUOTE && c !== CHAR_DOUBLE_QUOTE && c !== CHAR_PERCENT && c !== CHAR_COMMERCIAL_AT && c !== CHAR_GRAVE_ACCENT;
|
|
@@ -2547,14 +2664,14 @@ function chooseScalarStyle(state, string, layout, singleLineOnly, forceQuote, in
|
|
|
2547
2664
|
if (char === CHAR_LINE_FEED) {
|
|
2548
2665
|
hasLineBreak = true;
|
|
2549
2666
|
if (shouldTrackWidth) {
|
|
2550
|
-
hasFoldableLine = hasFoldableLine || i - previousLineBreak - 1 > lineWidth && string[previousLineBreak + 1]
|
|
2667
|
+
hasFoldableLine = hasFoldableLine || i - previousLineBreak - 1 > lineWidth && !isMoreIndented(string[previousLineBreak + 1]);
|
|
2551
2668
|
previousLineBreak = i;
|
|
2552
2669
|
}
|
|
2553
2670
|
} else if (!isPrintable(char)) return STYLE_DOUBLE;
|
|
2554
2671
|
plain = plain && isPlainSafe(char, prevChar, inblock);
|
|
2555
2672
|
prevChar = char;
|
|
2556
2673
|
}
|
|
2557
|
-
hasFoldableLine = hasFoldableLine || shouldTrackWidth && i - previousLineBreak - 1 > lineWidth && string[previousLineBreak + 1]
|
|
2674
|
+
hasFoldableLine = hasFoldableLine || shouldTrackWidth && i - previousLineBreak - 1 > lineWidth && !isMoreIndented(string[previousLineBreak + 1]);
|
|
2558
2675
|
}
|
|
2559
2676
|
if (!hasLineBreak && !hasFoldableLine) {
|
|
2560
2677
|
if (plain && !forceQuote) return STYLE_PLAIN;
|
|
@@ -2588,11 +2705,11 @@ function resolveScalarStyle(state, node, layout, iskey, inblock) {
|
|
|
2588
2705
|
}
|
|
2589
2706
|
const string = node.value;
|
|
2590
2707
|
if (string.length === 0) {
|
|
2591
|
-
if (node.style.tagged ||
|
|
2708
|
+
if (node.style.tagged || state.schema.resolveImplicitScalarTag(string).tag.tagName === node.tag) return STYLE_PLAIN;
|
|
2592
2709
|
return state.quoteStyle === "double" ? STYLE_DOUBLE : STYLE_SINGLE;
|
|
2593
2710
|
}
|
|
2594
2711
|
const style = chooseScalarStyle(state, string, layout, singleLineOnly, state.forceQuotes && !iskey, inblock);
|
|
2595
|
-
if (style === STYLE_PLAIN && !node.style.tagged &&
|
|
2712
|
+
if (style === STYLE_PLAIN && !node.style.tagged && state.schema.resolveImplicitScalarTag(string).tag.tagName !== node.tag) return state.quoteStyle === "double" ? STYLE_DOUBLE : STYLE_SINGLE;
|
|
2596
2713
|
return style;
|
|
2597
2714
|
}
|
|
2598
2715
|
function blockHeader(string, indentPerLevel) {
|
|
@@ -2619,27 +2736,30 @@ function encodeFlowBreaks(string, indent) {
|
|
|
2619
2736
|
function dropEndingNewline(string) {
|
|
2620
2737
|
return string[string.length - 1] === "\n" ? string.slice(0, -1) : string;
|
|
2621
2738
|
}
|
|
2739
|
+
function isMoreIndented(char) {
|
|
2740
|
+
return char === " " || char === " ";
|
|
2741
|
+
}
|
|
2622
2742
|
function foldBlockScalar(string, width) {
|
|
2623
2743
|
const lineRe = /(\n+)([^\n]*)/g;
|
|
2624
2744
|
let nextLF = string.indexOf("\n");
|
|
2625
2745
|
if (nextLF === -1) nextLF = string.length;
|
|
2626
2746
|
lineRe.lastIndex = nextLF;
|
|
2627
2747
|
let result = foldLine(string.slice(0, nextLF), width);
|
|
2628
|
-
let prevMoreIndented = string[0] === "\n" || string[0]
|
|
2748
|
+
let prevMoreIndented = string[0] === "\n" || isMoreIndented(string[0]);
|
|
2629
2749
|
let moreIndented;
|
|
2630
2750
|
let match;
|
|
2631
2751
|
while (match = lineRe.exec(string)) {
|
|
2632
2752
|
const prefix = match[1];
|
|
2633
2753
|
const line = match[2];
|
|
2634
|
-
moreIndented = line
|
|
2754
|
+
moreIndented = line !== "" && isMoreIndented(line[0]);
|
|
2635
2755
|
result += prefix + (!prevMoreIndented && !moreIndented && line !== "" ? "\n" : "") + foldLine(line, width);
|
|
2636
2756
|
prevMoreIndented = moreIndented;
|
|
2637
2757
|
}
|
|
2638
2758
|
return result;
|
|
2639
2759
|
}
|
|
2640
2760
|
function foldLine(line, width) {
|
|
2641
|
-
if (line === "" || line[0]
|
|
2642
|
-
const breakRe = / [^ ]/g;
|
|
2761
|
+
if (line === "" || isMoreIndented(line[0])) return line;
|
|
2762
|
+
const breakRe = / [^ \t]/g;
|
|
2643
2763
|
let match;
|
|
2644
2764
|
let start2 = 0;
|
|
2645
2765
|
let end;
|
|
@@ -2873,22 +2993,9 @@ function present(documents, options) {
|
|
|
2873
2993
|
}
|
|
2874
2994
|
return result;
|
|
2875
2995
|
}
|
|
2876
|
-
var DEFAULT_DUMP_SCHEMA = YAML11_SCHEMA.withTags({
|
|
2877
|
-
...intYaml11Tag,
|
|
2878
|
-
resolve: (source, isExplicit, tagName) => {
|
|
2879
|
-
const result = intYaml11Tag.resolve(source, isExplicit, tagName);
|
|
2880
|
-
return result === NOT_RESOLVED ? intCoreTag.resolve(source, isExplicit, tagName) : result;
|
|
2881
|
-
}
|
|
2882
|
-
}, {
|
|
2883
|
-
...floatYaml11Tag,
|
|
2884
|
-
resolve: (source, isExplicit, tagName) => {
|
|
2885
|
-
const result = floatYaml11Tag.resolve(source, isExplicit, tagName);
|
|
2886
|
-
return result === NOT_RESOLVED ? floatCoreTag.resolve(source, isExplicit, tagName) : result;
|
|
2887
|
-
}
|
|
2888
|
-
});
|
|
2889
2996
|
var DEFAULT_DUMP_OPTIONS = {
|
|
2890
2997
|
...DEFAULT_PRESENTER_OPTIONS,
|
|
2891
|
-
schema:
|
|
2998
|
+
schema: DUMP_SCHEMA,
|
|
2892
2999
|
skipInvalid: false,
|
|
2893
3000
|
noRefs: false,
|
|
2894
3001
|
flowLevel: -1,
|
|
@@ -2915,6 +3022,22 @@ function dump(input, options = {}) {
|
|
|
2915
3022
|
schema: opts.schema
|
|
2916
3023
|
});
|
|
2917
3024
|
}
|
|
3025
|
+
var EVENT_DOCUMENT = EVENT_ID.DOCUMENT;
|
|
3026
|
+
var EVENT_SEQUENCE = EVENT_ID.SEQUENCE;
|
|
3027
|
+
var EVENT_MAPPING = EVENT_ID.MAPPING;
|
|
3028
|
+
var EVENT_SCALAR = EVENT_ID.SCALAR;
|
|
3029
|
+
var EVENT_ALIAS = EVENT_ID.ALIAS;
|
|
3030
|
+
var EVENT_POP = EVENT_ID.POP;
|
|
3031
|
+
var SCALAR_STYLE_PLAIN = SCALAR_STYLE.PLAIN;
|
|
3032
|
+
var SCALAR_STYLE_SINGLE_QUOTED = SCALAR_STYLE.SINGLE_QUOTED;
|
|
3033
|
+
var SCALAR_STYLE_DOUBLE_QUOTED = SCALAR_STYLE.DOUBLE_QUOTED;
|
|
3034
|
+
var SCALAR_STYLE_LITERAL_BLOCK = SCALAR_STYLE.LITERAL_BLOCK;
|
|
3035
|
+
var SCALAR_STYLE_FOLDED_BLOCK = SCALAR_STYLE.FOLDED_BLOCK;
|
|
3036
|
+
var COLLECTION_STYLE_BLOCK = COLLECTION_STYLE.BLOCK;
|
|
3037
|
+
var COLLECTION_STYLE_FLOW = COLLECTION_STYLE.FLOW;
|
|
3038
|
+
var CHOMPING_CLIP = CHOMPING_MODE.CLIP;
|
|
3039
|
+
var CHOMPING_STRIP = CHOMPING_MODE.STRIP;
|
|
3040
|
+
var CHOMPING_KEEP = CHOMPING_MODE.KEEP;
|
|
2918
3041
|
|
|
2919
3042
|
// src/constants.ts
|
|
2920
3043
|
var AVAILABLE_MIRRORS = ["v6.gh-proxy.org", "gh-proxy.org", "hk.gh-proxy.org", "cdn.gh-proxy.org"];
|
|
@@ -3027,8 +3150,9 @@ function ensureDirs() {
|
|
|
3027
3150
|
}
|
|
3028
3151
|
}
|
|
3029
3152
|
}
|
|
3153
|
+
var atomicWriteSeq = 0;
|
|
3030
3154
|
function atomicWriteFileSync(filePath, content, options) {
|
|
3031
|
-
const tmp = `${filePath}.${process.pid}.tmp`;
|
|
3155
|
+
const tmp = `${filePath}.${process.pid}.${atomicWriteSeq++}.tmp`;
|
|
3032
3156
|
try {
|
|
3033
3157
|
fs.writeFileSync(tmp, content, options);
|
|
3034
3158
|
fs.renameSync(tmp, filePath);
|
|
@@ -3401,7 +3525,7 @@ function loadOverwriteFile() {
|
|
|
3401
3525
|
const filePath = path3.join(dir, file);
|
|
3402
3526
|
try {
|
|
3403
3527
|
const content = fs3.readFileSync(filePath, "utf8");
|
|
3404
|
-
const parsed = load(content);
|
|
3528
|
+
const parsed = load(content, { maxAliases: 200 });
|
|
3405
3529
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
3406
3530
|
const { match, ...config } = parsed;
|
|
3407
3531
|
results.push({ name: file, path: filePath, config, match: normalizeMatch(match, file) });
|
|
@@ -3478,6 +3602,18 @@ var TimeoutError = class extends Error {
|
|
|
3478
3602
|
this.name = "TimeoutError";
|
|
3479
3603
|
}
|
|
3480
3604
|
};
|
|
3605
|
+
var CliError = class extends Error {
|
|
3606
|
+
hint;
|
|
3607
|
+
label;
|
|
3608
|
+
exitCode;
|
|
3609
|
+
constructor(message, options = {}) {
|
|
3610
|
+
super(message);
|
|
3611
|
+
this.name = "CliError";
|
|
3612
|
+
this.label = options.label ?? "\u9519\u8BEF";
|
|
3613
|
+
this.hint = options.hint === void 0 ? [] : Array.isArray(options.hint) ? options.hint : [options.hint];
|
|
3614
|
+
this.exitCode = options.exitCode ?? 1;
|
|
3615
|
+
}
|
|
3616
|
+
};
|
|
3481
3617
|
function withTimeout(promise, ms) {
|
|
3482
3618
|
return new Promise((resolve, reject) => {
|
|
3483
3619
|
const timer = setTimeout(() => reject(new TimeoutError()), ms);
|
|
@@ -3581,6 +3717,15 @@ function isProcessRunning(pid) {
|
|
|
3581
3717
|
return false;
|
|
3582
3718
|
}
|
|
3583
3719
|
}
|
|
3720
|
+
function isProcessCommandMatching(pid, needle) {
|
|
3721
|
+
if (!pid) return false;
|
|
3722
|
+
try {
|
|
3723
|
+
const result = spawnSync("ps", ["-p", String(pid), "-o", "command="], { encoding: "utf8", timeout: 5e3 });
|
|
3724
|
+
return (result.stdout || "").includes(needle);
|
|
3725
|
+
} catch {
|
|
3726
|
+
return false;
|
|
3727
|
+
}
|
|
3728
|
+
}
|
|
3584
3729
|
function isProcessRoot(pid) {
|
|
3585
3730
|
if (!pid) return false;
|
|
3586
3731
|
try {
|
|
@@ -3591,7 +3736,8 @@ function isProcessRoot(pid) {
|
|
|
3591
3736
|
}
|
|
3592
3737
|
}
|
|
3593
3738
|
function createHttpClient(options = {}) {
|
|
3594
|
-
const { timeout = 6e4 } = options;
|
|
3739
|
+
const { timeout = 6e4, secret } = options;
|
|
3740
|
+
const authHeaders = secret ? { Authorization: `Bearer ${secret}` } : {};
|
|
3595
3741
|
return {
|
|
3596
3742
|
async get(url, config) {
|
|
3597
3743
|
const controller = new AbortController();
|
|
@@ -3600,7 +3746,7 @@ function createHttpClient(options = {}) {
|
|
|
3600
3746
|
try {
|
|
3601
3747
|
const response = await fetch(url, {
|
|
3602
3748
|
signal,
|
|
3603
|
-
headers: { "User-Agent": `mihomo-cli/${VERSION}
|
|
3749
|
+
headers: { "User-Agent": `mihomo-cli/${VERSION}`, ...authHeaders }
|
|
3604
3750
|
});
|
|
3605
3751
|
if (!response.ok) {
|
|
3606
3752
|
const error = new Error(`HTTP ${response.status}`);
|
|
@@ -3699,12 +3845,16 @@ function isProxyValid(proxy) {
|
|
|
3699
3845
|
}
|
|
3700
3846
|
|
|
3701
3847
|
// src/config.ts
|
|
3848
|
+
var SAFE_YAML_LOAD_OPTIONS = { maxAliases: 200 };
|
|
3849
|
+
function loadYamlSafe(content) {
|
|
3850
|
+
return load(content, SAFE_YAML_LOAD_OPTIONS);
|
|
3851
|
+
}
|
|
3702
3852
|
function parseYamlOrJson(content, errorMsg) {
|
|
3703
3853
|
if (!content?.trim()) {
|
|
3704
3854
|
throw new Error(`${errorMsg || "\u5185\u5BB9"}\u4E3A\u7A7A`);
|
|
3705
3855
|
}
|
|
3706
3856
|
try {
|
|
3707
|
-
const result =
|
|
3857
|
+
const result = loadYamlSafe(content);
|
|
3708
3858
|
if (result != null && typeof result === "object" && !Array.isArray(result)) return result;
|
|
3709
3859
|
} catch {
|
|
3710
3860
|
}
|
|
@@ -3715,13 +3865,13 @@ function parseYamlOrJson(content, errorMsg) {
|
|
|
3715
3865
|
}
|
|
3716
3866
|
}
|
|
3717
3867
|
function dumpYaml(obj) {
|
|
3718
|
-
return dump(obj, { indent: 2, lineWidth: -1
|
|
3868
|
+
return dump(obj, { indent: 2, lineWidth: -1 });
|
|
3719
3869
|
}
|
|
3720
3870
|
function collectOverwriteProxyNames(overwriteFiles) {
|
|
3721
3871
|
const names = [];
|
|
3722
3872
|
for (const file of overwriteFiles) {
|
|
3723
3873
|
for (const [key, value] of Object.entries(file.config)) {
|
|
3724
|
-
if ((key === "+proxies" || key === "proxies+") && Array.isArray(value)) {
|
|
3874
|
+
if ((key === "+proxies" || key === "proxies+" || key === "~proxies") && Array.isArray(value)) {
|
|
3725
3875
|
for (const proxy of value) {
|
|
3726
3876
|
if (proxy && typeof proxy === "object" && "name" in proxy) {
|
|
3727
3877
|
const name = proxy.name;
|
|
@@ -3916,7 +4066,7 @@ function getConfigInfo() {
|
|
|
3916
4066
|
if (!hasConfig()) return null;
|
|
3917
4067
|
try {
|
|
3918
4068
|
const content = fs4.readFileSync(PATHS.configFile, "utf8");
|
|
3919
|
-
const cfg =
|
|
4069
|
+
const cfg = loadYamlSafe(content);
|
|
3920
4070
|
if (!cfg) return null;
|
|
3921
4071
|
const proxies = cfg.proxies;
|
|
3922
4072
|
const proxyGroups = cfg["proxy-groups"];
|
|
@@ -4535,7 +4685,7 @@ function getLogPathByName(name) {
|
|
|
4535
4685
|
}
|
|
4536
4686
|
function openUrl(url) {
|
|
4537
4687
|
try {
|
|
4538
|
-
const child = spawn("open", [url], { stdio: "ignore", detached: true });
|
|
4688
|
+
const child = spawn("open", ["--", url], { stdio: "ignore", detached: true });
|
|
4539
4689
|
child.unref();
|
|
4540
4690
|
child.on("error", () => {
|
|
4541
4691
|
});
|
|
@@ -4723,10 +4873,13 @@ function disableDaemon() {
|
|
|
4723
4873
|
async function tryHotReload() {
|
|
4724
4874
|
const controller = new AbortController();
|
|
4725
4875
|
const timer = setTimeout(() => controller.abort(), HOT_RELOAD_TIMEOUT_MS);
|
|
4876
|
+
const secret = readSettings().controller_secret;
|
|
4877
|
+
const headers = { "Content-Type": "application/json" };
|
|
4878
|
+
if (secret) headers.Authorization = `Bearer ${secret}`;
|
|
4726
4879
|
try {
|
|
4727
4880
|
const res = await fetch(`${CONTROLLER_BASE_URL}/configs?force=true`, {
|
|
4728
4881
|
method: "PUT",
|
|
4729
|
-
headers
|
|
4882
|
+
headers,
|
|
4730
4883
|
body: "{}",
|
|
4731
4884
|
signal: controller.signal
|
|
4732
4885
|
});
|
|
@@ -4875,6 +5028,13 @@ function getActiveSubscription() {
|
|
|
4875
5028
|
}
|
|
4876
5029
|
return subs[0];
|
|
4877
5030
|
}
|
|
5031
|
+
function requireActiveSubscription(emptyMsg = "\u6CA1\u6709\u8BA2\u9605\uFF0C\u8BF7\u5148\u6DFB\u52A0\u8BA2\u9605") {
|
|
5032
|
+
const sub = getActiveSubscription();
|
|
5033
|
+
if (!sub) {
|
|
5034
|
+
throw new CliError(emptyMsg);
|
|
5035
|
+
}
|
|
5036
|
+
return sub;
|
|
5037
|
+
}
|
|
4878
5038
|
function findSubscriptionFuzzy(subs, pattern) {
|
|
4879
5039
|
const lowerPattern = pattern.toLowerCase();
|
|
4880
5040
|
const exact = [];
|
|
@@ -4896,14 +5056,15 @@ function findSubscriptionFuzzy(subs, pattern) {
|
|
|
4896
5056
|
}
|
|
4897
5057
|
function pickSingleSubscription(subs, pattern) {
|
|
4898
5058
|
if (subs.length === 0) {
|
|
4899
|
-
|
|
4900
|
-
process.exit(1);
|
|
5059
|
+
throw new CliError(`\u672A\u627E\u5230\u5339\u914D "${pattern}" \u7684\u8BA2\u9605`);
|
|
4901
5060
|
}
|
|
4902
5061
|
if (subs.length === 1) return subs[0];
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
5062
|
+
throw new CliError("\u5339\u914D\u5230\u591A\u4E2A\u8BA2\u9605\uFF0C\u8BF7\u66F4\u7CBE\u786E\u6307\u5B9A", {
|
|
5063
|
+
hint: ["", "\u5339\u914D\u7684\u8BA2\u9605:", ...subs.map((s) => ` ${s.name}`)]
|
|
5064
|
+
});
|
|
5065
|
+
}
|
|
5066
|
+
function resolveSubscription(subs, pattern) {
|
|
5067
|
+
return pickSingleSubscription(findSubscriptionFuzzy(subs, pattern), pattern);
|
|
4907
5068
|
}
|
|
4908
5069
|
async function downloadSubscription(url, subName = "default", signal, persist = true) {
|
|
4909
5070
|
let response;
|
|
@@ -5124,7 +5285,8 @@ async function testSubscriptionProxies(subName, options = {}) {
|
|
|
5124
5285
|
if (proxies.length === 0) {
|
|
5125
5286
|
return { total: 0, alive: 0, dead: 0, results: [] };
|
|
5126
5287
|
}
|
|
5127
|
-
const
|
|
5288
|
+
const secret = apiBase === CONTROLLER_BASE_URL ? readSettings().controller_secret : void 0;
|
|
5289
|
+
const client = createHttpClient({ timeout: timeout + 3e3, secret });
|
|
5128
5290
|
const results = new Array(proxies.length);
|
|
5129
5291
|
let completedCount = 0;
|
|
5130
5292
|
let nextIndex = 0;
|
|
@@ -5272,843 +5434,847 @@ async function autoCleanSubscription(subName, options = {}) {
|
|
|
5272
5434
|
return { summary, removedProxies, updatedGroups, removedGroups, skipped };
|
|
5273
5435
|
}
|
|
5274
5436
|
|
|
5275
|
-
// src/
|
|
5276
|
-
function
|
|
5277
|
-
|
|
5278
|
-
|
|
5279
|
-
|
|
5280
|
-
|
|
5281
|
-
|
|
5282
|
-
|
|
5283
|
-
|
|
5284
|
-
console.log("");
|
|
5285
|
-
if (status.enabled) {
|
|
5286
|
-
console.log("\u5173\u95ED\u4FDD\u6D3B: mihomo daemon off");
|
|
5287
|
-
} else {
|
|
5288
|
-
console.log("\u5F00\u542F\u4FDD\u6D3B: mihomo daemon on");
|
|
5289
|
-
console.log(colors.gray(" \u5F00\u673A\u81EA\u542F + \u5D29\u6E83\u81EA\u52A8\u91CD\u542F\uFF08\u4EC5 Mixed \u6A21\u5F0F\uFF09"));
|
|
5437
|
+
// src/runtime.ts
|
|
5438
|
+
function getRuntimeMode() {
|
|
5439
|
+
if (isDaemonEnabled()) return "mixed";
|
|
5440
|
+
return getConfigInfo()?.tun ? "tun" : "mixed";
|
|
5441
|
+
}
|
|
5442
|
+
function getRunningState() {
|
|
5443
|
+
if (isDaemonEnabled()) {
|
|
5444
|
+
const daemon = getDaemonStatus();
|
|
5445
|
+
return { running: isDaemonRunning(daemon), pid: daemon.pid, daemon: true };
|
|
5290
5446
|
}
|
|
5291
|
-
|
|
5447
|
+
const status = getStatus();
|
|
5448
|
+
return { running: status.running, pid: status.pid, daemon: false };
|
|
5292
5449
|
}
|
|
5293
|
-
|
|
5294
|
-
|
|
5295
|
-
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
}
|
|
5300
|
-
const sub = getActiveSubscription();
|
|
5301
|
-
if (!sub) {
|
|
5302
|
-
console.error("\u9519\u8BEF: \u6CA1\u6709\u8BA2\u9605\uFF0C\u8BF7\u5148\u6DFB\u52A0\u8BA2\u9605");
|
|
5303
|
-
process.exit(1);
|
|
5304
|
-
}
|
|
5305
|
-
let configInfo;
|
|
5306
|
-
try {
|
|
5307
|
-
configInfo = prepareConfigForStart("mixed", sub.name);
|
|
5308
|
-
} catch (e) {
|
|
5309
|
-
console.error(`${colors.red("\u914D\u7F6E\u9519\u8BEF:")} ${e.message}`);
|
|
5310
|
-
process.exit(1);
|
|
5311
|
-
}
|
|
5312
|
-
console.log(colors.gray("\u5C06\u8BF7\u6C42\u7BA1\u7406\u5458\u6743\u9650\u4EE5\u5B89\u88C5\u7CFB\u7EDF\u7EA7\u4FDD\u6D3B\u670D\u52A1\uFF08LaunchDaemon\uFF09"));
|
|
5313
|
-
console.log(colors.gray("\u7CFB\u7EDF\u7EA7\u4FDD\u6D3B\u9700\u8981 root\uFF0C\u4EE5\u89E3\u51B3\u5C40\u57DF\u7F51\u8BBF\u95EE\u53D7\u9650\u95EE\u9898"));
|
|
5314
|
-
try {
|
|
5315
|
-
enableDaemon();
|
|
5316
|
-
} catch (e) {
|
|
5317
|
-
console.error(`${colors.red("\u542F\u7528\u4FDD\u6D3B\u5931\u8D25:")} ${e.message}`);
|
|
5318
|
-
process.exit(1);
|
|
5319
|
-
}
|
|
5320
|
-
console.log(`${colors.green("\u5DF2\u542F\u7528\u4FDD\u6D3B")} \xB7 ${sub.name} \xB7 ${formatProxySummary(configInfo)}`);
|
|
5321
|
-
console.log(colors.gray("\u5F00\u673A\u81EA\u542F + \u5D29\u6E83\u81EA\u52A8\u91CD\u542F\uFF0C\u4EE3\u7406\u5C06\u5728\u540E\u53F0\u5E38\u9A7B"));
|
|
5322
|
-
console.log("");
|
|
5450
|
+
function isRestartNeededOnChange() {
|
|
5451
|
+
return isDaemonEnabled() || getStatus().running;
|
|
5452
|
+
}
|
|
5453
|
+
async function launchOrRestart(mode) {
|
|
5454
|
+
if (isDaemonEnabled()) {
|
|
5455
|
+
await restartDaemon();
|
|
5323
5456
|
await sleep(DAEMON_BOOT_WAIT_MS);
|
|
5324
|
-
|
|
5325
|
-
return;
|
|
5326
|
-
}
|
|
5327
|
-
if (action === "off" || action === "disable") {
|
|
5328
|
-
if (!isDaemonEnabled()) {
|
|
5329
|
-
console.log("\u4FDD\u6D3B\u5DF2\u662F\u5173\u95ED\u72B6\u6001");
|
|
5330
|
-
console.log("");
|
|
5331
|
-
printDaemonStatus();
|
|
5332
|
-
return;
|
|
5333
|
-
}
|
|
5334
|
-
console.log(colors.gray("\u5C06\u8BF7\u6C42\u7BA1\u7406\u5458\u6743\u9650\u4EE5\u79FB\u9664\u7CFB\u7EDF\u7EA7\u4FDD\u6D3B\u670D\u52A1"));
|
|
5335
|
-
try {
|
|
5336
|
-
disableDaemon();
|
|
5337
|
-
} catch (e) {
|
|
5338
|
-
console.error(`${colors.red("\u5173\u95ED\u4FDD\u6D3B\u5931\u8D25:")} ${e.message}`);
|
|
5339
|
-
process.exit(1);
|
|
5340
|
-
}
|
|
5341
|
-
console.log(`${colors.green("\u5DF2\u5173\u95ED\u4FDD\u6D3B")}\uFF0C\u4EE3\u7406\u5DF2\u505C\u6B62`);
|
|
5342
|
-
console.log(colors.gray("\u91CD\u65B0\u542F\u7528: mihomo daemon on"));
|
|
5343
|
-
console.log("");
|
|
5344
|
-
return;
|
|
5345
|
-
}
|
|
5346
|
-
if (action !== void 0 && action !== "status") {
|
|
5347
|
-
console.error(`\u9519\u8BEF: \u672A\u77E5\u7684 daemon \u5B50\u547D\u4EE4: ${action}`);
|
|
5348
|
-
console.log("");
|
|
5349
|
-
console.log("\u53EF\u7528\u5B50\u547D\u4EE4: on, off, status");
|
|
5350
|
-
process.exit(1);
|
|
5457
|
+
return getDaemonStatus().pid;
|
|
5351
5458
|
}
|
|
5352
|
-
|
|
5353
|
-
|
|
5459
|
+
const result = await start(mode);
|
|
5460
|
+
return result.pid;
|
|
5354
5461
|
}
|
|
5355
5462
|
|
|
5356
|
-
// src/
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5463
|
+
// src/progress.ts
|
|
5464
|
+
var IS_TTY = process.stdout.isTTY === true;
|
|
5465
|
+
var BAR_WIDTH = 20;
|
|
5466
|
+
function createProgressPrinter(totalRounds = 1) {
|
|
5467
|
+
let alive = 0;
|
|
5468
|
+
let dead = 0;
|
|
5469
|
+
const resultMap = /* @__PURE__ */ new Map();
|
|
5470
|
+
function render(done, total) {
|
|
5471
|
+
if (!IS_TTY) return;
|
|
5472
|
+
const pct = Math.round(done / total * 100);
|
|
5473
|
+
const filled = Math.round(done / total * BAR_WIDTH);
|
|
5474
|
+
const bar = "\u2588".repeat(filled) + "\u2591".repeat(BAR_WIDTH - filled);
|
|
5475
|
+
process.stdout.write(`\r${bar} ${done}/${total} (${pct}%) | ${colors.green(`\u2713${alive}`)} ${colors.red(`\u2717${dead}`)}`);
|
|
5476
|
+
}
|
|
5477
|
+
return {
|
|
5478
|
+
onResult(result, index, total, round = 1) {
|
|
5479
|
+
if (resultMap.size === 0 && totalRounds > 1) {
|
|
5480
|
+
console.log(`--- \u7B2C 1 \u8F6E\u6D4B\u8BD5 (${total} \u4E2A\u8282\u70B9) ---`);
|
|
5366
5481
|
}
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
if (targetInfo) {
|
|
5372
|
-
const targetPath = targetInfo.path || USER_DATA_DIR;
|
|
5373
|
-
console.log(`\u6B63\u5728\u6253\u5F00: ${targetInfo.label}`);
|
|
5374
|
-
const success = openUrl(targetPath);
|
|
5375
|
-
if (!success) {
|
|
5376
|
-
console.log(`\u8BF7\u624B\u52A8\u6253\u5F00: ${targetPath}`);
|
|
5482
|
+
const prev = resultMap.get(result.name);
|
|
5483
|
+
if (prev) {
|
|
5484
|
+
if (prev.result.delay !== null) alive--;
|
|
5485
|
+
else dead--;
|
|
5377
5486
|
}
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5487
|
+
if (result.delay !== null) alive++;
|
|
5488
|
+
else dead++;
|
|
5489
|
+
resultMap.set(result.name, { result, round });
|
|
5490
|
+
render(index + 1, total);
|
|
5491
|
+
},
|
|
5492
|
+
onRetryRound(round, count) {
|
|
5493
|
+
if (IS_TTY) {
|
|
5494
|
+
process.stdout.write("\n");
|
|
5495
|
+
}
|
|
5496
|
+
console.log(`--- \u7B2C ${round} \u8F6E\u91CD\u8BD5 (${count} \u4E2A\u8282\u70B9) ---`);
|
|
5497
|
+
alive = 0;
|
|
5498
|
+
dead = 0;
|
|
5499
|
+
},
|
|
5500
|
+
finish() {
|
|
5501
|
+
if (IS_TTY) {
|
|
5502
|
+
process.stdout.write("\n");
|
|
5503
|
+
}
|
|
5504
|
+
console.log("");
|
|
5505
|
+
if (!IS_TTY) return;
|
|
5506
|
+
const entries = [...resultMap.values()];
|
|
5507
|
+
entries.sort((a, b) => a.result.name.localeCompare(b.result.name));
|
|
5508
|
+
const total = entries.length;
|
|
5509
|
+
console.log("\u8282\u70B9\u6700\u7EC8\u72B6\u6001:");
|
|
5510
|
+
for (let i = 0; i < entries.length; i++) {
|
|
5511
|
+
const { result, round } = entries[i];
|
|
5512
|
+
const prefix = `[${i + 1}/${total}]`;
|
|
5513
|
+
if (result.delay !== null) {
|
|
5514
|
+
const delayColor = result.delay < 300 ? colors.green : result.delay < 800 ? colors.yellow : colors.red;
|
|
5515
|
+
const retryNote = round > 1 ? colors.gray(` (\u7B2C${round}\u8F6E\u901A\u8FC7)`) : "";
|
|
5516
|
+
console.log(`${prefix} ${colors.green("\u2713")} ${result.name} ${delayColor(`${result.delay}ms`)}${retryNote}`);
|
|
5517
|
+
} else {
|
|
5518
|
+
console.log(`${prefix} ${colors.red("\u2717")} ${result.name} ${colors.gray(result.error || "timeout")}`);
|
|
5519
|
+
}
|
|
5387
5520
|
}
|
|
5521
|
+
console.log("");
|
|
5388
5522
|
}
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
console.log(" - cache.json (\u8BA2\u9605\u7F13\u5B58\uFF1A\u66F4\u65B0\u65F6\u95F4\u3001\u6D41\u91CF\u7B49)");
|
|
5400
|
-
console.log(" - xxx.yaml (\u8BA2\u9605\u539F\u59CB\u914D\u7F6E)");
|
|
5401
|
-
console.log(` \u8FD0\u884C\u65F6\u76EE\u5F55: ${DIRS.runtime}`);
|
|
5402
|
-
console.log(" - config.yaml (\u542F\u52A8\u65F6\u751F\u6210\uFF0Cstop \u81EA\u52A8\u6E05\u9664)");
|
|
5403
|
-
console.log(" - pid (PID \u6587\u4EF6\uFF0Cstop \u81EA\u52A8\u6E05\u9664)");
|
|
5404
|
-
console.log(` \u65E5\u5FD7\u6587\u4EF6: ${PATHS.logFile}`);
|
|
5405
|
-
console.log(` mihomo \u6570\u636E: ${DIRS.data}`);
|
|
5406
|
-
console.log(" - cache.db, Geo*.dat \u7B49 (mihomo \u81EA\u884C\u7BA1\u7406)");
|
|
5407
|
-
console.log("");
|
|
5408
|
-
console.log("\u6253\u5F00\u76EE\u5F55:");
|
|
5409
|
-
console.log(" mihomo dir open \u6253\u5F00\u6839\u76EE\u5F55");
|
|
5410
|
-
console.log(" mihomo dir open subs \u6253\u5F00\u8BA2\u9605\u76EE\u5F55");
|
|
5411
|
-
console.log(" mihomo dir open logs \u6253\u5F00\u65E5\u5FD7\u76EE\u5F55");
|
|
5412
|
-
console.log(" mihomo dir open data \u6253\u5F00 mihomo \u6570\u636E\u76EE\u5F55");
|
|
5413
|
-
console.log(" mihomo dir open runtime \u6253\u5F00\u8FD0\u884C\u65F6\u76EE\u5F55");
|
|
5414
|
-
console.log(" mihomo dir open kernel \u6253\u5F00\u5185\u6838\u76EE\u5F55");
|
|
5415
|
-
console.log("");
|
|
5416
|
-
console.log("\u73AF\u5883\u53D8\u91CF:");
|
|
5417
|
-
console.log(" MIHOMO_CLI_DIR: \u81EA\u5B9A\u4E49\u6839\u76EE\u5F55\u4F4D\u7F6E");
|
|
5418
|
-
console.log("");
|
|
5523
|
+
};
|
|
5524
|
+
}
|
|
5525
|
+
function formatCleanSummary(result) {
|
|
5526
|
+
const parts = [`\u79FB\u9664 ${result.removedProxies} \u4E2A\u8282\u70B9`];
|
|
5527
|
+
if (result.removedGroups > 0) parts.push(`\u5220\u9664 ${result.removedGroups} \u4E2A\u7A7A\u5206\u7EC4`);
|
|
5528
|
+
if (result.updatedGroups > 0) parts.push(`\u66F4\u65B0 ${result.updatedGroups} \u4E2A\u5206\u7EC4`);
|
|
5529
|
+
return parts.join(", ");
|
|
5530
|
+
}
|
|
5531
|
+
function formatTestSummary(summary) {
|
|
5532
|
+
return `\u7ED3\u679C: ${colors.green(`${summary.alive} \u5B58\u6D3B`)} / ${colors.red(`${summary.dead} \u5931\u8D25`)} / ${summary.total} \u603B\u8BA1`;
|
|
5419
5533
|
}
|
|
5420
5534
|
|
|
5421
|
-
// src/
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5535
|
+
// src/commands/status.ts
|
|
5536
|
+
function printStatus() {
|
|
5537
|
+
const status = getStatus();
|
|
5538
|
+
const state = getRunningState();
|
|
5539
|
+
const info = getConfigInfo();
|
|
5540
|
+
const overwriteEnabled = isOverwriteEnabled();
|
|
5541
|
+
const overwriteFiles = listOverwriteFile().files;
|
|
5542
|
+
const activeSub = getActiveSubscription();
|
|
5543
|
+
const { running, pid, daemon: daemonManaged } = state;
|
|
5544
|
+
console.log("");
|
|
5545
|
+
let modeLabel = "";
|
|
5546
|
+
if (info) {
|
|
5547
|
+
modeLabel = colors.cyan(info.tun ? " (TUN)" : " (Mixed)");
|
|
5431
5548
|
}
|
|
5432
|
-
const
|
|
5433
|
-
|
|
5434
|
-
|
|
5549
|
+
const statusText = running ? colors.green("\u25CF \u8FD0\u884C\u4E2D") : colors.yellow("\u4E0D\u5728\u8FD0\u884C");
|
|
5550
|
+
console.log(`${colors.gray("\u72B6\u6001: ")}${statusText}${modeLabel}`);
|
|
5551
|
+
console.log(`${colors.gray("\u5185\u6838: ")}${status.kernelVersion || "\u672A\u5B89\u88C5"}`);
|
|
5552
|
+
if (pid) {
|
|
5553
|
+
console.log(`${colors.gray("PID: ")}${pid}`);
|
|
5554
|
+
if (!daemonManaged && status.processInfo) {
|
|
5555
|
+
console.log(`${colors.gray("\u5185\u5B58: ")}${status.processInfo.memory}`);
|
|
5556
|
+
}
|
|
5435
5557
|
}
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
};
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
|
|
5448
|
-
const [ap, bp] = forceType(tryParse(a), tryParse(b));
|
|
5449
|
-
if (ap > bp)
|
|
5450
|
-
return 1;
|
|
5451
|
-
if (ap < bp)
|
|
5452
|
-
return -1;
|
|
5453
|
-
return 0;
|
|
5454
|
-
};
|
|
5455
|
-
var compareSegments = (a, b) => {
|
|
5456
|
-
for (let i = 0; i < Math.max(a.length, b.length); i++) {
|
|
5457
|
-
const r = compareStrings(a[i] || "0", b[i] || "0");
|
|
5458
|
-
if (r !== 0)
|
|
5459
|
-
return r;
|
|
5558
|
+
if (info) {
|
|
5559
|
+
if (info.tun) {
|
|
5560
|
+
const extra = info.mixedPort ? `\uFF0C\u53E6\u76D1\u542C ${info.mixedPort}` : "";
|
|
5561
|
+
console.log(`${colors.gray("\u7AEF\u53E3: ")}TUN \u63A5\u7BA1${extra}`);
|
|
5562
|
+
} else if (info.mixedPort) {
|
|
5563
|
+
console.log(`${colors.gray("\u7AEF\u53E3: ")}${info.mixedPort}`);
|
|
5564
|
+
} else {
|
|
5565
|
+
const ports = [];
|
|
5566
|
+
if (info.httpPort) ports.push(`HTTP:${info.httpPort}`);
|
|
5567
|
+
if (info.socksPort) ports.push(`SOCKS:${info.socksPort}`);
|
|
5568
|
+
console.log(`${colors.gray("\u7AEF\u53E3: ")}${ports.length > 0 ? ports.join(", ") : "\u672A\u77E5"}`);
|
|
5569
|
+
}
|
|
5460
5570
|
}
|
|
5461
|
-
|
|
5462
|
-
}
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
const p2 = n2.pop();
|
|
5470
|
-
const r = compareSegments(n1, n2);
|
|
5471
|
-
if (r !== 0)
|
|
5472
|
-
return r;
|
|
5473
|
-
if (p1 && p2) {
|
|
5474
|
-
return compareSegments(p1.split("."), p2.split("."));
|
|
5475
|
-
} else if (p1 || p2) {
|
|
5476
|
-
return p1 ? -1 : 1;
|
|
5571
|
+
if (activeSub) {
|
|
5572
|
+
let subLine = `${colors.gray("\u8BA2\u9605: ")}${activeSub.name}`;
|
|
5573
|
+
if (info) {
|
|
5574
|
+
subLine += ` (${formatProxySummary(info)})`;
|
|
5575
|
+
}
|
|
5576
|
+
console.log(subLine);
|
|
5577
|
+
} else {
|
|
5578
|
+
console.log(`${colors.gray("\u8BA2\u9605: ")}\u672A\u914D\u7F6E`);
|
|
5477
5579
|
}
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5484
|
-
|
|
5485
|
-
var HTTP_CLIENT2 = createHttpClient({ timeout: KERNEL_HTTP_TIMEOUT });
|
|
5486
|
-
function withMirror(url, mirror) {
|
|
5487
|
-
if (mirror && (url.startsWith("https://github.com/") || url.startsWith("https://api.github.com/"))) {
|
|
5488
|
-
return mirror + url;
|
|
5580
|
+
if (overwriteEnabled && overwriteFiles.length > 0) {
|
|
5581
|
+
const names = overwriteFiles.map((f) => f.name.replace(/^overwrite\.?/, "").replace(/\.ya?ml$/, "") || "\u4E3B\u6587\u4EF6").join(", ");
|
|
5582
|
+
console.log(`${colors.gray("\u8986\u5199: ")}${colors.green("\u5DF2\u542F\u7528")} (${names})`);
|
|
5583
|
+
} else if (overwriteEnabled) {
|
|
5584
|
+
console.log(`${colors.gray("\u8986\u5199: ")}${colors.green("\u5DF2\u542F\u7528")} (\u65E0\u6587\u4EF6)`);
|
|
5585
|
+
} else {
|
|
5586
|
+
console.log(`${colors.gray("\u8986\u5199: ")}${colors.yellow("\u5DF2\u7981\u7528")}`);
|
|
5489
5587
|
}
|
|
5490
|
-
|
|
5491
|
-
}
|
|
5492
|
-
function getArch() {
|
|
5493
|
-
const arch = process.arch;
|
|
5494
|
-
if (arch === "arm64") return "arm64";
|
|
5495
|
-
if (arch === "x64") return "amd64";
|
|
5496
|
-
return arch;
|
|
5497
|
-
}
|
|
5498
|
-
function findMatchingAsset(assets, platform, arch) {
|
|
5499
|
-
const prefix = `mihomo-${platform}-${arch}`;
|
|
5500
|
-
const matchingAssets = assets.filter(
|
|
5501
|
-
(a) => a.name.startsWith(prefix) && a.name.endsWith(".gz") || a.name.startsWith(`${prefix}-`) && a.name.endsWith(".gz")
|
|
5502
|
-
);
|
|
5503
|
-
if (matchingAssets.length === 0) return null;
|
|
5504
|
-
if (matchingAssets.length === 1) return matchingAssets[0];
|
|
5505
|
-
const standardAsset = matchingAssets.find((a) => {
|
|
5506
|
-
const nameWithoutGz = a.name.slice(0, -3);
|
|
5507
|
-
const parts = nameWithoutGz.split("-");
|
|
5508
|
-
const lastPart = parts[parts.length - 1];
|
|
5509
|
-
return /^v?\d+\.\d+\.\d+/.test(lastPart) && !nameWithoutGz.includes("-go") && !nameWithoutGz.includes("-compatible");
|
|
5510
|
-
});
|
|
5511
|
-
return standardAsset || matchingAssets[0];
|
|
5512
|
-
}
|
|
5513
|
-
async function getLatestRelease(repo, mirror) {
|
|
5514
|
-
const url = withMirror(`https://api.github.com/repos/${repo}/releases`, mirror);
|
|
5515
|
-
const response = await HTTP_CLIENT2.get(url, { responseType: "json" });
|
|
5516
|
-
const releases = response.data;
|
|
5517
|
-
if (!Array.isArray(releases) || releases.length === 0) {
|
|
5518
|
-
throw new Error("\u65E0\u6CD5\u83B7\u53D6\u7248\u672C\u4FE1\u606F");
|
|
5588
|
+
if (isDaemonEnabled()) {
|
|
5589
|
+
console.log(`${colors.gray("\u4FDD\u6D3B: ")}${colors.green("\u5DF2\u542F\u7528")} ${colors.gray("(\u5F00\u673A\u81EA\u542F + \u5D29\u6E83\u91CD\u542F)")}`);
|
|
5519
5590
|
}
|
|
5520
|
-
|
|
5521
|
-
(r) => !r.prerelease && !r.tag_name.toLowerCase().includes("alpha") && !r.tag_name.toLowerCase().includes("beta") && !r.tag_name.toLowerCase().includes("prerelease")
|
|
5522
|
-
);
|
|
5523
|
-
return stableReleases.length > 0 ? stableReleases[0] : releases[0];
|
|
5591
|
+
console.log("");
|
|
5524
5592
|
}
|
|
5525
|
-
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
|
|
5530
|
-
const currentDisplay = currentVersion || "\u672A\u5B89\u88C5";
|
|
5531
|
-
if (!currentVersion) {
|
|
5532
|
-
needsUpdate = true;
|
|
5533
|
-
} else {
|
|
5534
|
-
try {
|
|
5535
|
-
needsUpdate = compareVersions(latestVersion.replace(/^v/, ""), currentVersion.replace(/^v/, "")) > 0;
|
|
5536
|
-
} catch {
|
|
5537
|
-
needsUpdate = latestVersion !== currentVersion;
|
|
5538
|
-
}
|
|
5593
|
+
|
|
5594
|
+
// src/commands/stop.ts
|
|
5595
|
+
function handleStopResult(result) {
|
|
5596
|
+
if (result.remaining && result.remaining.length > 0) {
|
|
5597
|
+
throw new CliError(result.remaining.join(", "), { label: "\u90E8\u5206\u8FDB\u7A0B\u672A\u7EC8\u6B62", hint: "\u8BF7\u624B\u52A8\u8FD0\u884C: sudo pkill -9 mihomo" });
|
|
5539
5598
|
}
|
|
5540
|
-
return {
|
|
5541
|
-
current: currentDisplay,
|
|
5542
|
-
latest: latestVersion,
|
|
5543
|
-
needsUpdate,
|
|
5544
|
-
assets: latest.assets,
|
|
5545
|
-
release: latest
|
|
5546
|
-
};
|
|
5547
5599
|
}
|
|
5548
|
-
function
|
|
5549
|
-
if (
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
const stat = fs7.statSync(fullPath);
|
|
5554
|
-
if (stat.isDirectory()) {
|
|
5555
|
-
const found = findBinaryInDir(fullPath, maxDepth - 1);
|
|
5556
|
-
if (found) return found;
|
|
5557
|
-
continue;
|
|
5558
|
-
}
|
|
5559
|
-
if (f === "mihomo") return fullPath;
|
|
5560
|
-
if (f.includes("mihomo") && !f.endsWith(".gz")) return fullPath;
|
|
5600
|
+
async function cmdStop() {
|
|
5601
|
+
if (isDaemonEnabled()) {
|
|
5602
|
+
console.log(colors.yellow("\u4FDD\u6D3B\u5DF2\u542F\u7528\uFF0C\u4EE3\u7406\u7531 launchd \u6258\u7BA1"));
|
|
5603
|
+
console.log("\u76F4\u63A5\u505C\u6B62\u4F1A\u88AB\u81EA\u52A8\u91CD\u65B0\u62C9\u8D77\uFF0C\u8BF7\u7528: mihomo daemon off");
|
|
5604
|
+
return;
|
|
5561
5605
|
}
|
|
5562
|
-
|
|
5606
|
+
const pids = getMihomoPids();
|
|
5607
|
+
if (pids.length === 0) {
|
|
5608
|
+
console.log(colors.yellow("\u4E0D\u5728\u8FD0\u884C"));
|
|
5609
|
+
return;
|
|
5610
|
+
}
|
|
5611
|
+
console.log(`\u505C\u6B62 ${pids.length} \u4E2A\u8FDB\u7A0B...`);
|
|
5612
|
+
handleStopResult(stop());
|
|
5613
|
+
console.log(colors.green("\u5DF2\u505C\u6B62\u8FDB\u7A0B"));
|
|
5563
5614
|
}
|
|
5564
|
-
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
const asset = findMatchingAsset(latest.assets, platform, arch);
|
|
5570
|
-
if (!asset) {
|
|
5571
|
-
const available = latest.assets.map((a) => a.name).join(", ");
|
|
5572
|
-
let hint = "";
|
|
5573
|
-
if (available) hint = `
|
|
5574
|
-
\u53EF\u7528\u7248\u672C: ${available}`;
|
|
5575
|
-
throw new Error(`\u672A\u627E\u5230\u5339\u914D\u7684\u5185\u6838\u6587\u4EF6
|
|
5576
|
-
\u5E73\u53F0: ${platform}, \u67B6\u6784: ${arch}${hint}`);
|
|
5615
|
+
|
|
5616
|
+
// src/commands/start.ts
|
|
5617
|
+
async function cmdStart(args) {
|
|
5618
|
+
if (!hasKernel()) {
|
|
5619
|
+
throw new CliError('\u672A\u627E\u5230\u5185\u6838\uFF0C\u8BF7\u8FD0\u884C "mihomo kernel"');
|
|
5577
5620
|
}
|
|
5578
|
-
const
|
|
5579
|
-
const
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
progressCallback("\u63D0\u793A: \u7ECF\u7B2C\u4E09\u65B9\u955C\u50CF\u4E2D\u8F6C\u4E0B\u8F7D\uFF0C\u65E0\u6CD5\u9A8C\u8BC1\u6765\u6E90\u5B8C\u6574\u6027\uFF0C\u5EFA\u8BAE\u76F4\u8FDE\u6216\u81EA\u884C\u6821\u9A8C\u4EA7\u7269");
|
|
5621
|
+
const targetMode = args[1] === "tun" ? "tun" : "mixed";
|
|
5622
|
+
const daemonEnabled = isDaemonEnabled();
|
|
5623
|
+
if (targetMode === "tun" && daemonEnabled) {
|
|
5624
|
+
throw new CliError("\u4FDD\u6D3B\u5DF2\u542F\u7528\uFF08\u4EC5\u652F\u6301 Mixed \u6A21\u5F0F\uFF09\uFF0C\u65E0\u6CD5\u542F\u52A8 TUN", { hint: "\u8BF7\u5148\u5173\u95ED\u4FDD\u6D3B: mihomo daemon off" });
|
|
5583
5625
|
}
|
|
5584
|
-
|
|
5585
|
-
|
|
5626
|
+
const rounds = parseIntArg(args, "-r", "--rounds", DEFAULT_CLEAN_ROUNDS);
|
|
5627
|
+
const timeout = parseIntArg(args, "-t", "--timeout", DEFAULT_TEST_TIMEOUT);
|
|
5628
|
+
const concurrency = parseIntArg(args, "-j", "--concurrency", DEFAULT_TEST_CONCURRENCY);
|
|
5629
|
+
const skipUpdate = hasFlag(args, "-s", "--no-update");
|
|
5630
|
+
const skipClean = hasFlag(args, "--no-clean");
|
|
5631
|
+
const updateTimeout = parseIntArg(args, "-u", "--update-timeout", DEFAULT_AUTO_UPDATE_TIMEOUT);
|
|
5632
|
+
const sub = requireActiveSubscription("\u6CA1\u6709\u8BA2\u9605\uFF0C\u8BF7\u5148\u6DFB\u52A0\u8BA2\u9605");
|
|
5633
|
+
if (!skipUpdate) {
|
|
5634
|
+
await autoUpdateStaleSubscription({ timeout: updateTimeout });
|
|
5586
5635
|
}
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
if (curlResult.error) {
|
|
5593
|
-
if (curlResult.error.code === "ENOENT") {
|
|
5594
|
-
throw new Error("\u672A\u627E\u5230 curl \u547D\u4EE4\uFF0C\u8BF7\u5148\u5B89\u88C5 curl \u540E\u91CD\u8BD5");
|
|
5636
|
+
if (!daemonEnabled) {
|
|
5637
|
+
if (hasRootResidue()) {
|
|
5638
|
+
throw new CliError("\u5B58\u5728\u9700\u8981 root \u6743\u9650\u6E05\u7406\u7684\u6B8B\u7559\u8FDB\u7A0B/\u6587\u4EF6", {
|
|
5639
|
+
hint: [`\u8BF7\u5148\u624B\u52A8\u6E05\u7406: sudo pkill -9 mihomo && sudo rm -f ${PATHS.pidFile}`, "\u6216\u5207\u6362\u5230 TUN \u6A21\u5F0F\u542F\u52A8\uFF08\u81EA\u52A8\u6E05\u7406\uFF09: mihomo start tun"]
|
|
5640
|
+
});
|
|
5595
5641
|
}
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
}
|
|
5642
|
+
const status = getStatus();
|
|
5643
|
+
const hasProcess = status.running || status.allProcesses.length > 0;
|
|
5644
|
+
if (hasProcess) {
|
|
5645
|
+
const count = status.allProcesses.length > 0 ? status.allProcesses.length : 1;
|
|
5646
|
+
console.log(`\u505C\u6B62 ${count} \u4E2A\u8FDB\u7A0B...`);
|
|
5647
|
+
}
|
|
5648
|
+
handleStopResult(stop());
|
|
5649
|
+
if (hasProcess) {
|
|
5650
|
+
console.log(`${colors.green("\u5DF2\u505C\u6B62\u8FDB\u7A0B")}
|
|
5651
|
+
`);
|
|
5602
5652
|
}
|
|
5603
|
-
throw new Error(`\u4E0B\u8F7D\u5931\u8D25 (curl \u9000\u51FA\u7801 ${curlResult.status})`);
|
|
5604
|
-
}
|
|
5605
|
-
if (!fs7.existsSync(tempPath)) {
|
|
5606
|
-
throw new Error("\u4E0B\u8F7D\u5931\u8D25: \u6587\u4EF6\u672A\u751F\u6210");
|
|
5607
5653
|
}
|
|
5608
|
-
|
|
5609
|
-
|
|
5654
|
+
let configInfo;
|
|
5655
|
+
try {
|
|
5656
|
+
configInfo = prepareConfigForStart(targetMode, sub.name);
|
|
5657
|
+
} catch (e) {
|
|
5658
|
+
if (e instanceof CliError) throw e;
|
|
5659
|
+
throw new CliError(e.message, { label: "\u914D\u7F6E\u9519\u8BEF" });
|
|
5610
5660
|
}
|
|
5611
|
-
const
|
|
5612
|
-
|
|
5661
|
+
const modeLabel = targetMode === "tun" ? "TUN" : "Mixed";
|
|
5662
|
+
console.log([colors.cyan(modeLabel), sub.name, formatProxySummary(configInfo)].join(" \xB7 "));
|
|
5613
5663
|
try {
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5664
|
+
const pid = await launchOrRestart(targetMode);
|
|
5665
|
+
const label = daemonEnabled ? "\u5DF2\u542F\u52A8 (\u4FDD\u6D3B)" : "\u5DF2\u542F\u52A8";
|
|
5666
|
+
console.log(`${colors.green(label)}${pid ? ` (PID ${pid})` : ""}`);
|
|
5667
|
+
} catch (e) {
|
|
5668
|
+
if (e instanceof CliError) throw e;
|
|
5669
|
+
const lines = e.message.split("\n");
|
|
5670
|
+
throw new CliError(lines[0], { label: "\u542F\u52A8\u5931\u8D25", hint: lines.slice(1) });
|
|
5671
|
+
}
|
|
5672
|
+
const cleanThreshold = isGithubUrl(sub.url) ? AUTO_CLEAN_THRESHOLD_GITHUB : AUTO_CLEAN_THRESHOLD;
|
|
5673
|
+
if (!skipClean && configInfo.proxies > cleanThreshold) {
|
|
5674
|
+
const cache = readSubscriptionCache();
|
|
5675
|
+
const lastCleanAt = cache[sub.name]?.last_auto_clean_at;
|
|
5676
|
+
const withinCooldown = !!lastCleanAt && Date.now() - new Date(lastCleanAt).getTime() < AUTO_CLEAN_COOLDOWN_HOURS * 60 * 60 * 1e3;
|
|
5677
|
+
if (!withinCooldown) {
|
|
5678
|
+
console.log("");
|
|
5679
|
+
console.log(`\u8282\u70B9\u6570 ${configInfo.proxies} \u8D85\u8FC7 ${cleanThreshold}\uFF0C\u81EA\u52A8\u6E05\u7406\uFF08${AUTO_CLEAN_COOLDOWN_HOURS}h \u5185\u4EC5\u4E00\u6B21\uFF0C--no-clean \u8DF3\u8FC7\uFF09...`);
|
|
5680
|
+
console.log("");
|
|
5681
|
+
await sleep(1e3);
|
|
5682
|
+
const progress = createProgressPrinter(rounds);
|
|
5683
|
+
const cleanResult = await autoCleanSubscription(sub.name, {
|
|
5684
|
+
timeout,
|
|
5685
|
+
concurrency,
|
|
5686
|
+
rounds,
|
|
5687
|
+
onResult: progress.onResult,
|
|
5688
|
+
onRetryRound: progress.onRetryRound
|
|
5689
|
+
});
|
|
5690
|
+
progress.finish();
|
|
5691
|
+
console.log(formatTestSummary(cleanResult.summary));
|
|
5692
|
+
if (cleanResult.skipped) {
|
|
5693
|
+
console.log(colors.yellow("\u5B58\u6D3B\u8282\u70B9\u4E0D\u8DB3 1%\uFF0C\u8DF3\u8FC7\u6E05\u7406\u3002\u8BF7\u68C0\u67E5\u539F\u59CB\u8BA2\u9605\u662F\u5426\u6709\u6548"));
|
|
5694
|
+
} else if (cleanResult.removedProxies > 0) {
|
|
5695
|
+
console.log(`${colors.green("\u5DF2\u6E05\u7406")}: ${formatCleanSummary(cleanResult)}`);
|
|
5696
|
+
console.log("");
|
|
5697
|
+
console.log("\u91CD\u65B0\u52A0\u8F7D\u914D\u7F6E...");
|
|
5698
|
+
if (!daemonEnabled) handleStopResult(stop());
|
|
5699
|
+
try {
|
|
5700
|
+
configInfo = prepareConfigForStart(targetMode, sub.name);
|
|
5701
|
+
const pid = await launchOrRestart(targetMode);
|
|
5702
|
+
console.log(`${colors.green("\u5DF2\u91CD\u542F")}${pid ? ` (PID ${pid})` : ""} \xB7 ${formatProxySummary(configInfo)}`);
|
|
5703
|
+
} catch (e) {
|
|
5704
|
+
if (e instanceof CliError) throw e;
|
|
5705
|
+
throw new CliError(e.message.split("\n")[0], { label: "\u91CD\u542F\u5931\u8D25" });
|
|
5622
5706
|
}
|
|
5623
5707
|
}
|
|
5624
|
-
|
|
5625
|
-
if (tarResult.error) throw tarResult.error;
|
|
5626
|
-
if (tarResult.status !== 0) throw new Error(`tar \u9000\u51FA\u7801 ${tarResult.status}`);
|
|
5627
|
-
} else if (tempPath.endsWith(".gz")) {
|
|
5628
|
-
const baseName = path6.basename(tempPath, ".gz");
|
|
5629
|
-
const outputPath = path6.join(extractPath, baseName);
|
|
5630
|
-
const gzipResult = spawnSync5("gzip", ["-dc", tempPath], { maxBuffer: 256 * 1024 * 1024, timeout: 6e4 });
|
|
5631
|
-
if (gzipResult.error) throw gzipResult.error;
|
|
5632
|
-
if (gzipResult.status !== 0) throw new Error(`gzip \u9000\u51FA\u7801 ${gzipResult.status}`);
|
|
5633
|
-
fs7.writeFileSync(outputPath, gzipResult.stdout, { mode: 493 });
|
|
5634
|
-
extractedBinary = outputPath;
|
|
5635
|
-
}
|
|
5636
|
-
} catch (e) {
|
|
5637
|
-
try {
|
|
5638
|
-
fs7.unlinkSync(tempPath);
|
|
5639
|
-
} catch {
|
|
5708
|
+
saveSubscriptionCache(sub.name, { last_auto_clean_at: (/* @__PURE__ */ new Date()).toISOString() });
|
|
5640
5709
|
}
|
|
5641
|
-
throw new Error(`\u89E3\u538B\u5931\u8D25: ${e.message}`);
|
|
5642
5710
|
}
|
|
5643
|
-
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5711
|
+
printStatus();
|
|
5712
|
+
}
|
|
5713
|
+
|
|
5714
|
+
// src/commands/shared.ts
|
|
5715
|
+
async function dispatchSubcommand(args, table, options) {
|
|
5716
|
+
const action = args[1];
|
|
5717
|
+
if (action) {
|
|
5718
|
+
const cmd = table.find((c) => c.name === action || c.aliases?.includes(action));
|
|
5719
|
+
if (cmd) return cmd.handler(args);
|
|
5720
|
+
if (options.onUnknown) return options.onUnknown(action);
|
|
5650
5721
|
}
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
}
|
|
5659
|
-
}
|
|
5660
|
-
fs7.renameSync(foundBinary, targetPath);
|
|
5722
|
+
return options.fallback(args);
|
|
5723
|
+
}
|
|
5724
|
+
function requireRunning() {
|
|
5725
|
+
const state = getRunningState();
|
|
5726
|
+
if (!state.running) {
|
|
5727
|
+
const hint = state.daemon ? "mihomo daemon on" : "mihomo start";
|
|
5728
|
+
throw new CliError(`mihomo \u672A\u8FD0\u884C\uFF0C\u8BF7\u5148\u542F\u52A8 (${hint})`);
|
|
5661
5729
|
}
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
|
|
5730
|
+
}
|
|
5731
|
+
async function restartToApply(args) {
|
|
5732
|
+
if (!isRestartNeededOnChange()) return false;
|
|
5733
|
+
const currentMode = getRuntimeMode();
|
|
5734
|
+
console.log("");
|
|
5735
|
+
await cmdStart(["start", currentMode, ...extractStartOptions(args)]);
|
|
5736
|
+
return true;
|
|
5737
|
+
}
|
|
5738
|
+
|
|
5739
|
+
// src/commands/daemon.ts
|
|
5740
|
+
function printDaemonStatus() {
|
|
5741
|
+
const status = getDaemonStatus();
|
|
5742
|
+
const stateText = status.enabled ? colors.green("\u5DF2\u542F\u7528") : colors.yellow("\u5DF2\u7981\u7528");
|
|
5743
|
+
console.log(`${colors.gray("\u4FDD\u6D3B: ")}${stateText}`);
|
|
5744
|
+
if (status.enabled) {
|
|
5745
|
+
const runText = isDaemonRunning(status) ? colors.green(`\u8FD0\u884C\u4E2D (PID ${status.pid})`) : colors.yellow("\u672A\u8FD0\u884C");
|
|
5746
|
+
console.log(`${colors.gray("\u5185\u6838: ")}${runText}`);
|
|
5665
5747
|
}
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
}
|
|
5673
|
-
try {
|
|
5674
|
-
fs7.unlinkSync(tempPath);
|
|
5675
|
-
} catch {
|
|
5676
|
-
}
|
|
5677
|
-
throw new Error(`\u5185\u6838\u81EA\u68C0\u5931\u8D25\uFF08\u53EF\u80FD\u4E0B\u8F7D\u635F\u574F\u6216\u67B6\u6784\u4E0D\u5339\u914D\uFF09\uFF0C\u5DF2\u5220\u9664
|
|
5678
|
-
\u9000\u51FA\u7801: ${check.status}
|
|
5679
|
-
\u8F93\u51FA: ${checkOutput || "(\u7A7A)"}`);
|
|
5748
|
+
console.log("");
|
|
5749
|
+
if (status.enabled) {
|
|
5750
|
+
console.log("\u5173\u95ED\u4FDD\u6D3B: mihomo daemon off");
|
|
5751
|
+
} else {
|
|
5752
|
+
console.log("\u5F00\u542F\u4FDD\u6D3B: mihomo daemon on");
|
|
5753
|
+
console.log(colors.gray(" \u5F00\u673A\u81EA\u542F + \u5D29\u6E83\u81EA\u52A8\u91CD\u542F\uFF08\u4EC5 Mixed \u6A21\u5F0F\uFF09"));
|
|
5680
5754
|
}
|
|
5755
|
+
console.log("");
|
|
5756
|
+
}
|
|
5757
|
+
async function daemonOn() {
|
|
5758
|
+
if (!hasKernel()) {
|
|
5759
|
+
throw new CliError('\u672A\u627E\u5230\u5185\u6838\uFF0C\u8BF7\u8FD0\u884C "mihomo kernel"');
|
|
5760
|
+
}
|
|
5761
|
+
const sub = requireActiveSubscription("\u6CA1\u6709\u8BA2\u9605\uFF0C\u8BF7\u5148\u6DFB\u52A0\u8BA2\u9605");
|
|
5762
|
+
let configInfo;
|
|
5681
5763
|
try {
|
|
5682
|
-
|
|
5683
|
-
} catch {
|
|
5764
|
+
configInfo = prepareConfigForStart("mixed", sub.name);
|
|
5765
|
+
} catch (e) {
|
|
5766
|
+
if (e instanceof CliError) throw e;
|
|
5767
|
+
throw new CliError(e.message, { label: "\u914D\u7F6E\u9519\u8BEF" });
|
|
5684
5768
|
}
|
|
5685
|
-
|
|
5686
|
-
|
|
5769
|
+
console.log(colors.gray("\u5C06\u8BF7\u6C42\u7BA1\u7406\u5458\u6743\u9650\u4EE5\u5B89\u88C5\u7CFB\u7EDF\u7EA7\u4FDD\u6D3B\u670D\u52A1\uFF08LaunchDaemon\uFF09"));
|
|
5770
|
+
console.log(colors.gray("\u7CFB\u7EDF\u7EA7\u4FDD\u6D3B\u9700\u8981 root\uFF0C\u4EE5\u89E3\u51B3\u5C40\u57DF\u7F51\u8BBF\u95EE\u53D7\u9650\u95EE\u9898"));
|
|
5771
|
+
try {
|
|
5772
|
+
enableDaemon();
|
|
5773
|
+
} catch (e) {
|
|
5774
|
+
if (e instanceof CliError) throw e;
|
|
5775
|
+
throw new CliError(e.message, { label: "\u542F\u7528\u4FDD\u6D3B\u5931\u8D25" });
|
|
5776
|
+
}
|
|
5777
|
+
console.log(`${colors.green("\u5DF2\u542F\u7528\u4FDD\u6D3B")} \xB7 ${sub.name} \xB7 ${formatProxySummary(configInfo)}`);
|
|
5778
|
+
console.log(colors.gray("\u5F00\u673A\u81EA\u542F + \u5D29\u6E83\u81EA\u52A8\u91CD\u542F\uFF0C\u4EE3\u7406\u5C06\u5728\u540E\u53F0\u5E38\u9A7B"));
|
|
5779
|
+
console.log("");
|
|
5780
|
+
await sleep(DAEMON_BOOT_WAIT_MS);
|
|
5781
|
+
printDaemonStatus();
|
|
5687
5782
|
}
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
const mirrorInfo = parseMirrorArg(args);
|
|
5692
|
-
const effectiveMirror = mirrorInfo.mirror;
|
|
5693
|
-
if (effectiveMirror) {
|
|
5694
|
-
const mirrorDesc = mirrorInfo.type === "all" ? " (API\u548C\u4E0B\u8F7D\u5747\u4F7F\u7528\u955C\u50CF)" : " (\u4E0B\u8F7D\u65F6\u4F7F\u7528\u955C\u50CF)";
|
|
5695
|
-
console.log(`\u955C\u50CF: ${effectiveMirror}${mirrorDesc}`);
|
|
5783
|
+
function daemonOff() {
|
|
5784
|
+
if (!isDaemonEnabled()) {
|
|
5785
|
+
console.log("\u4FDD\u6D3B\u5DF2\u662F\u5173\u95ED\u72B6\u6001");
|
|
5696
5786
|
console.log("");
|
|
5787
|
+
printDaemonStatus();
|
|
5788
|
+
return;
|
|
5697
5789
|
}
|
|
5698
|
-
console.log("\
|
|
5790
|
+
console.log(colors.gray("\u5C06\u8BF7\u6C42\u7BA1\u7406\u5458\u6743\u9650\u4EE5\u79FB\u9664\u7CFB\u7EDF\u7EA7\u4FDD\u6D3B\u670D\u52A1"));
|
|
5699
5791
|
try {
|
|
5700
|
-
|
|
5701
|
-
const info = await checkUpdate(apiMirror);
|
|
5702
|
-
console.log(`\u5F53\u524D: ${info.current}`);
|
|
5703
|
-
console.log(`\u6700\u65B0: ${info.latest}`);
|
|
5704
|
-
if (!info.needsUpdate) {
|
|
5705
|
-
console.log("\u5DF2\u662F\u6700\u65B0\u7248\u672C");
|
|
5706
|
-
} else {
|
|
5707
|
-
console.log("\n\u6B63\u5728\u4E0B\u8F7D...");
|
|
5708
|
-
const result = await downloadKernel((msg) => console.log(msg), mirrorInfo.mirror, info.release);
|
|
5709
|
-
console.log(`
|
|
5710
|
-
\u5DF2\u66F4\u65B0\u5230 ${result.version}`);
|
|
5711
|
-
}
|
|
5792
|
+
disableDaemon();
|
|
5712
5793
|
} catch (e) {
|
|
5713
|
-
|
|
5714
|
-
\
|
|
5715
|
-
const err = e;
|
|
5716
|
-
if (err.response?.data) {
|
|
5717
|
-
if (err.response.data.message) {
|
|
5718
|
-
console.error(`\u539F\u56E0: ${err.response.data.message}`);
|
|
5719
|
-
}
|
|
5720
|
-
if (err.response.data.documentation_url) {
|
|
5721
|
-
console.error(`\u6587\u6863: ${err.response.data.documentation_url}`);
|
|
5722
|
-
}
|
|
5723
|
-
}
|
|
5724
|
-
if (!effectiveMirror) {
|
|
5725
|
-
console.error("");
|
|
5726
|
-
console.error("\u63D0\u793A: \u76F4\u8FDE\u5931\u8D25\u6216\u4E0B\u8F7D\u8FC7\u6162\u65F6\u53EF\u4F7F\u7528\u955C\u50CF:");
|
|
5727
|
-
console.error(" mihomo kernel --mirror [\u955C\u50CF] # \u4E0B\u8F7D\u8D70\u955C\u50CF\uFF08\u9ED8\u8BA4 v6.gh-proxy.org\uFF09");
|
|
5728
|
-
console.error(" mihomo kernel --mirror-all [\u955C\u50CF] # API \u548C\u4E0B\u8F7D\u90FD\u8D70\u955C\u50CF");
|
|
5729
|
-
console.error(` \u53EF\u7528\u955C\u50CF: ${AVAILABLE_MIRRORS.join(", ")}`);
|
|
5730
|
-
}
|
|
5731
|
-
process.exit(1);
|
|
5794
|
+
if (e instanceof CliError) throw e;
|
|
5795
|
+
throw new CliError(e.message, { label: "\u5173\u95ED\u4FDD\u6D3B\u5931\u8D25" });
|
|
5732
5796
|
}
|
|
5797
|
+
console.log(`${colors.green("\u5DF2\u5173\u95ED\u4FDD\u6D3B")}\uFF0C\u4EE3\u7406\u5DF2\u505C\u6B62`);
|
|
5798
|
+
console.log(colors.gray("\u91CD\u65B0\u542F\u7528: mihomo daemon on"));
|
|
5799
|
+
console.log("");
|
|
5733
5800
|
}
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
const logPath = getLogPath();
|
|
5738
|
-
if (hasFlag(args, "-o", "--open")) {
|
|
5739
|
-
openLogFile(logPath);
|
|
5740
|
-
return;
|
|
5741
|
-
}
|
|
5742
|
-
viewLogWithTail(logPath, { follow: true, lines: 50 });
|
|
5801
|
+
function printStatusView() {
|
|
5802
|
+
console.log("");
|
|
5803
|
+
printDaemonStatus();
|
|
5743
5804
|
}
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
const archiveLogs = listLogs();
|
|
5756
|
-
const archive = archiveLogs.archives[parsedIdx - 1];
|
|
5757
|
-
if (!archive) {
|
|
5758
|
-
console.error(`\u9519\u8BEF: \u672A\u627E\u5230\u65E5\u5FD7 "${targetName}"`);
|
|
5759
|
-
console.log('\u4F7F\u7528 "mihomo logs" \u67E5\u770B\u53EF\u7528\u65E5\u5FD7\u5217\u8868');
|
|
5760
|
-
process.exit(1);
|
|
5761
|
-
}
|
|
5762
|
-
logPath = archive.path;
|
|
5763
|
-
} else {
|
|
5764
|
-
logPath = getLogPathByName(targetName);
|
|
5765
|
-
}
|
|
5766
|
-
}
|
|
5767
|
-
if (!logPath) {
|
|
5768
|
-
console.error(`\u9519\u8BEF: \u672A\u627E\u5230\u65E5\u5FD7 "${targetName}"`);
|
|
5769
|
-
console.log('\u4F7F\u7528 "mihomo logs" \u67E5\u770B\u53EF\u7528\u65E5\u5FD7\u5217\u8868');
|
|
5770
|
-
process.exit(1);
|
|
5805
|
+
var SUBCOMMANDS = [
|
|
5806
|
+
{ name: "on", aliases: ["enable"], handler: daemonOn },
|
|
5807
|
+
{ name: "off", aliases: ["disable"], handler: daemonOff },
|
|
5808
|
+
{ name: "status", handler: printStatusView }
|
|
5809
|
+
];
|
|
5810
|
+
async function cmdDaemon(args) {
|
|
5811
|
+
await dispatchSubcommand(args, SUBCOMMANDS, {
|
|
5812
|
+
// 无 action → 显示状态;未知 action → 报错
|
|
5813
|
+
fallback: printStatusView,
|
|
5814
|
+
onUnknown: (action) => {
|
|
5815
|
+
throw new CliError(`\u672A\u77E5\u7684 daemon \u5B50\u547D\u4EE4: ${action}`, { hint: ["", "\u53EF\u7528\u5B50\u547D\u4EE4: on, off, status"] });
|
|
5771
5816
|
}
|
|
5772
|
-
|
|
5773
|
-
|
|
5774
|
-
|
|
5817
|
+
});
|
|
5818
|
+
}
|
|
5819
|
+
|
|
5820
|
+
// src/commands/directory.ts
|
|
5821
|
+
function openDirectory(args) {
|
|
5822
|
+
const target = args[2];
|
|
5823
|
+
if (!target || target === "root") {
|
|
5824
|
+
console.log("\u6B63\u5728\u6253\u5F00: \u6839\u76EE\u5F55");
|
|
5825
|
+
const success = openUrl(USER_DATA_DIR);
|
|
5826
|
+
if (!success) {
|
|
5827
|
+
console.log(`\u8BF7\u624B\u52A8\u6253\u5F00: ${USER_DATA_DIR}`);
|
|
5775
5828
|
}
|
|
5776
|
-
viewLogWithTail(logPath, { follow: false, lines });
|
|
5777
5829
|
return;
|
|
5778
5830
|
}
|
|
5779
|
-
const
|
|
5780
|
-
const
|
|
5781
|
-
if (
|
|
5782
|
-
|
|
5783
|
-
|
|
5784
|
-
|
|
5831
|
+
const key = target.toLowerCase();
|
|
5832
|
+
const targetInfo = Object.hasOwn(DIRECTORY_TARGETS, key) ? DIRECTORY_TARGETS[key] : void 0;
|
|
5833
|
+
if (targetInfo) {
|
|
5834
|
+
const targetPath = targetInfo.path || USER_DATA_DIR;
|
|
5835
|
+
console.log(`\u6B63\u5728\u6253\u5F00: ${targetInfo.label}`);
|
|
5836
|
+
const success = openUrl(targetPath);
|
|
5837
|
+
if (!success) {
|
|
5838
|
+
console.log(`\u8BF7\u624B\u52A8\u6253\u5F00: ${targetPath}`);
|
|
5839
|
+
}
|
|
5785
5840
|
return;
|
|
5786
5841
|
}
|
|
5842
|
+
const hint = ["", "\u53EF\u7528\u76EE\u6807:", " root (\u9ED8\u8BA4) \u6839\u76EE\u5F55"];
|
|
5843
|
+
for (const [k, val] of Object.entries(DIRECTORY_TARGETS)) {
|
|
5844
|
+
if (k !== "root") {
|
|
5845
|
+
hint.push(` ${k.padEnd(14)}${val.label}`);
|
|
5846
|
+
}
|
|
5847
|
+
}
|
|
5848
|
+
throw new CliError(`\u672A\u77E5\u7684\u76EE\u5F55\u76EE\u6807 "${target}"`, { hint });
|
|
5849
|
+
}
|
|
5850
|
+
function printDirectoryInfo() {
|
|
5787
5851
|
console.log("");
|
|
5788
|
-
console.log("\
|
|
5789
|
-
console.log(
|
|
5790
|
-
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
|
|
5798
|
-
|
|
5799
|
-
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
console.log("\
|
|
5810
|
-
console.log("
|
|
5811
|
-
console.log("
|
|
5812
|
-
console.log("
|
|
5813
|
-
console.log(" mihomo logs 1 -o # \u7528\u7CFB\u7EDF\u9ED8\u8BA4\u7A0B\u5E8F\u6253\u5F00");
|
|
5852
|
+
console.log("\u6570\u636E\u76EE\u5F55\u4F4D\u7F6E:");
|
|
5853
|
+
console.log(` \u6839\u76EE\u5F55: ${USER_DATA_DIR}`);
|
|
5854
|
+
console.log(` \u5168\u5C40\u8BBE\u7F6E: ${PATHS.settingsFile}`);
|
|
5855
|
+
console.log(` \u5185\u6838\u76EE\u5F55: ${DIRS.kernel}`);
|
|
5856
|
+
console.log(` \u5185\u6838\u6587\u4EF6: ${PATHS.mihomoBinary}`);
|
|
5857
|
+
console.log(` \u8BA2\u9605\u76EE\u5F55: ${DIRS.subscriptions}`);
|
|
5858
|
+
console.log(" - cache.json (\u8BA2\u9605\u7F13\u5B58\uFF1A\u66F4\u65B0\u65F6\u95F4\u3001\u6D41\u91CF\u7B49)");
|
|
5859
|
+
console.log(" - xxx.yaml (\u8BA2\u9605\u539F\u59CB\u914D\u7F6E)");
|
|
5860
|
+
console.log(` \u8FD0\u884C\u65F6\u76EE\u5F55: ${DIRS.runtime}`);
|
|
5861
|
+
console.log(" - config.yaml (\u542F\u52A8\u65F6\u751F\u6210\uFF0Cstop \u81EA\u52A8\u6E05\u9664)");
|
|
5862
|
+
console.log(" - pid (PID \u6587\u4EF6\uFF0Cstop \u81EA\u52A8\u6E05\u9664)");
|
|
5863
|
+
console.log(` \u65E5\u5FD7\u6587\u4EF6: ${PATHS.logFile}`);
|
|
5864
|
+
console.log(` mihomo \u6570\u636E: ${DIRS.data}`);
|
|
5865
|
+
console.log(" - cache.db, Geo*.dat \u7B49 (mihomo \u81EA\u884C\u7BA1\u7406)");
|
|
5866
|
+
console.log("");
|
|
5867
|
+
console.log("\u6253\u5F00\u76EE\u5F55:");
|
|
5868
|
+
console.log(" mihomo dir open \u6253\u5F00\u6839\u76EE\u5F55");
|
|
5869
|
+
console.log(" mihomo dir open subs \u6253\u5F00\u8BA2\u9605\u76EE\u5F55");
|
|
5870
|
+
console.log(" mihomo dir open logs \u6253\u5F00\u65E5\u5FD7\u76EE\u5F55");
|
|
5871
|
+
console.log(" mihomo dir open data \u6253\u5F00 mihomo \u6570\u636E\u76EE\u5F55");
|
|
5872
|
+
console.log(" mihomo dir open runtime \u6253\u5F00\u8FD0\u884C\u65F6\u76EE\u5F55");
|
|
5873
|
+
console.log(" mihomo dir open kernel \u6253\u5F00\u5185\u6838\u76EE\u5F55");
|
|
5874
|
+
console.log("");
|
|
5875
|
+
console.log("\u73AF\u5883\u53D8\u91CF:");
|
|
5876
|
+
console.log(" MIHOMO_CLI_DIR: \u81EA\u5B9A\u4E49\u6839\u76EE\u5F55\u4F4D\u7F6E");
|
|
5814
5877
|
console.log("");
|
|
5815
5878
|
}
|
|
5879
|
+
var SUBCOMMANDS2 = [{ name: "open", handler: openDirectory }];
|
|
5880
|
+
function cmdDirectory(args) {
|
|
5881
|
+
void dispatchSubcommand(args, SUBCOMMANDS2, { fallback: printDirectoryInfo });
|
|
5882
|
+
}
|
|
5816
5883
|
|
|
5817
|
-
// src/
|
|
5818
|
-
import
|
|
5884
|
+
// src/kernel.ts
|
|
5885
|
+
import { spawnSync as spawnSync5 } from "child_process";
|
|
5886
|
+
import fs7 from "fs";
|
|
5887
|
+
import path6 from "path";
|
|
5819
5888
|
|
|
5820
|
-
//
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
function getRunningState() {
|
|
5826
|
-
if (isDaemonEnabled()) {
|
|
5827
|
-
const daemon = getDaemonStatus();
|
|
5828
|
-
return { running: isDaemonRunning(daemon), pid: daemon.pid, daemon: true };
|
|
5889
|
+
// node_modules/compare-versions/lib/esm/utils.js
|
|
5890
|
+
var semver = /^[v^~<>=]*?(\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+))?(?:-([\da-z\-]+(?:\.[\da-z\-]+)*))?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?)?)?$/i;
|
|
5891
|
+
var validateAndParse = (version) => {
|
|
5892
|
+
if (typeof version !== "string") {
|
|
5893
|
+
throw new TypeError("Invalid argument expected string");
|
|
5829
5894
|
}
|
|
5830
|
-
const
|
|
5831
|
-
|
|
5895
|
+
const match = version.match(semver);
|
|
5896
|
+
if (!match) {
|
|
5897
|
+
throw new Error(`Invalid argument not valid semver ('${version}' received)`);
|
|
5898
|
+
}
|
|
5899
|
+
match.shift();
|
|
5900
|
+
return match;
|
|
5901
|
+
};
|
|
5902
|
+
var isWildcard = (s) => s === "*" || s === "x" || s === "X";
|
|
5903
|
+
var tryParse = (v) => {
|
|
5904
|
+
const n = parseInt(v, 10);
|
|
5905
|
+
return isNaN(n) ? v : n;
|
|
5906
|
+
};
|
|
5907
|
+
var forceType = (a, b) => typeof a !== typeof b ? [String(a), String(b)] : [a, b];
|
|
5908
|
+
var compareStrings = (a, b) => {
|
|
5909
|
+
if (isWildcard(a) || isWildcard(b))
|
|
5910
|
+
return 0;
|
|
5911
|
+
const [ap, bp] = forceType(tryParse(a), tryParse(b));
|
|
5912
|
+
if (ap > bp)
|
|
5913
|
+
return 1;
|
|
5914
|
+
if (ap < bp)
|
|
5915
|
+
return -1;
|
|
5916
|
+
return 0;
|
|
5917
|
+
};
|
|
5918
|
+
var compareSegments = (a, b) => {
|
|
5919
|
+
for (let i = 0; i < Math.max(a.length, b.length); i++) {
|
|
5920
|
+
const r = compareStrings(a[i] || "0", b[i] || "0");
|
|
5921
|
+
if (r !== 0)
|
|
5922
|
+
return r;
|
|
5923
|
+
}
|
|
5924
|
+
return 0;
|
|
5925
|
+
};
|
|
5926
|
+
|
|
5927
|
+
// node_modules/compare-versions/lib/esm/compareVersions.js
|
|
5928
|
+
var compareVersions = (v1, v2) => {
|
|
5929
|
+
const n1 = validateAndParse(v1);
|
|
5930
|
+
const n2 = validateAndParse(v2);
|
|
5931
|
+
const p1 = n1.pop();
|
|
5932
|
+
const p2 = n2.pop();
|
|
5933
|
+
const r = compareSegments(n1, n2);
|
|
5934
|
+
if (r !== 0)
|
|
5935
|
+
return r;
|
|
5936
|
+
if (p1 && p2) {
|
|
5937
|
+
return compareSegments(p1.split("."), p2.split("."));
|
|
5938
|
+
} else if (p1 || p2) {
|
|
5939
|
+
return p1 ? -1 : 1;
|
|
5940
|
+
}
|
|
5941
|
+
return 0;
|
|
5942
|
+
};
|
|
5943
|
+
|
|
5944
|
+
// src/kernel.ts
|
|
5945
|
+
var GITHUB_REPO = "MetaCubeX/mihomo";
|
|
5946
|
+
var KERNEL_HTTP_TIMEOUT = 12e4;
|
|
5947
|
+
var KERNEL_DOWNLOAD_TIMEOUT = 18e4;
|
|
5948
|
+
var HTTP_CLIENT2 = createHttpClient({ timeout: KERNEL_HTTP_TIMEOUT });
|
|
5949
|
+
function withMirror(url, mirror) {
|
|
5950
|
+
if (mirror && (url.startsWith("https://github.com/") || url.startsWith("https://api.github.com/"))) {
|
|
5951
|
+
return mirror + url;
|
|
5952
|
+
}
|
|
5953
|
+
return url;
|
|
5832
5954
|
}
|
|
5833
|
-
function
|
|
5834
|
-
|
|
5955
|
+
function getArch() {
|
|
5956
|
+
const arch = process.arch;
|
|
5957
|
+
if (arch === "arm64") return "arm64";
|
|
5958
|
+
if (arch === "x64") return "amd64";
|
|
5959
|
+
return arch;
|
|
5835
5960
|
}
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5961
|
+
function findMatchingAsset(assets, platform, arch) {
|
|
5962
|
+
const prefix = `mihomo-${platform}-${arch}`;
|
|
5963
|
+
const matchingAssets = assets.filter(
|
|
5964
|
+
(a) => a.name.startsWith(prefix) && a.name.endsWith(".gz") || a.name.startsWith(`${prefix}-`) && a.name.endsWith(".gz")
|
|
5965
|
+
);
|
|
5966
|
+
if (matchingAssets.length === 0) return null;
|
|
5967
|
+
if (matchingAssets.length === 1) return matchingAssets[0];
|
|
5968
|
+
const standardAsset = matchingAssets.find((a) => {
|
|
5969
|
+
const nameWithoutGz = a.name.slice(0, -3);
|
|
5970
|
+
const parts = nameWithoutGz.split("-");
|
|
5971
|
+
const lastPart = parts[parts.length - 1];
|
|
5972
|
+
return /^v?\d+\.\d+\.\d+/.test(lastPart) && !nameWithoutGz.includes("-go") && !nameWithoutGz.includes("-compatible");
|
|
5973
|
+
});
|
|
5974
|
+
return standardAsset || matchingAssets[0];
|
|
5975
|
+
}
|
|
5976
|
+
async function getLatestRelease(repo, mirror) {
|
|
5977
|
+
const url = withMirror(`https://api.github.com/repos/${repo}/releases`, mirror);
|
|
5978
|
+
const response = await HTTP_CLIENT2.get(url, { responseType: "json" });
|
|
5979
|
+
const releases = response.data;
|
|
5980
|
+
if (!Array.isArray(releases) || releases.length === 0) {
|
|
5981
|
+
throw new Error("\u65E0\u6CD5\u83B7\u53D6\u7248\u672C\u4FE1\u606F");
|
|
5841
5982
|
}
|
|
5842
|
-
const
|
|
5843
|
-
|
|
5983
|
+
const stableReleases = releases.filter(
|
|
5984
|
+
(r) => !r.prerelease && !r.tag_name.toLowerCase().includes("alpha") && !r.tag_name.toLowerCase().includes("beta") && !r.tag_name.toLowerCase().includes("prerelease")
|
|
5985
|
+
);
|
|
5986
|
+
return stableReleases.length > 0 ? stableReleases[0] : releases[0];
|
|
5844
5987
|
}
|
|
5845
|
-
|
|
5846
|
-
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
|
|
5853
|
-
|
|
5854
|
-
|
|
5855
|
-
|
|
5856
|
-
|
|
5857
|
-
|
|
5858
|
-
|
|
5988
|
+
async function checkUpdate(mirror) {
|
|
5989
|
+
const currentVersion = getKernelVersion();
|
|
5990
|
+
const latest = await getLatestRelease(GITHUB_REPO, mirror);
|
|
5991
|
+
const latestVersion = latest.tag_name;
|
|
5992
|
+
let needsUpdate = false;
|
|
5993
|
+
const currentDisplay = currentVersion || "\u672A\u5B89\u88C5";
|
|
5994
|
+
if (!currentVersion) {
|
|
5995
|
+
needsUpdate = true;
|
|
5996
|
+
} else {
|
|
5997
|
+
try {
|
|
5998
|
+
needsUpdate = compareVersions(latestVersion.replace(/^v/, ""), currentVersion.replace(/^v/, "")) > 0;
|
|
5999
|
+
} catch {
|
|
6000
|
+
needsUpdate = latestVersion !== currentVersion;
|
|
6001
|
+
}
|
|
5859
6002
|
}
|
|
5860
6003
|
return {
|
|
5861
|
-
|
|
5862
|
-
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
|
|
5866
|
-
|
|
5867
|
-
|
|
5868
|
-
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
|
|
5873
|
-
|
|
5874
|
-
|
|
5875
|
-
|
|
5876
|
-
if (
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
|
|
5882
|
-
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5889
|
-
|
|
5890
|
-
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
|
|
6004
|
+
current: currentDisplay,
|
|
6005
|
+
latest: latestVersion,
|
|
6006
|
+
needsUpdate,
|
|
6007
|
+
assets: latest.assets,
|
|
6008
|
+
release: latest
|
|
6009
|
+
};
|
|
6010
|
+
}
|
|
6011
|
+
function findBinaryInDir(dir, maxDepth = 4) {
|
|
6012
|
+
if (maxDepth <= 0) return null;
|
|
6013
|
+
const files = fs7.readdirSync(dir);
|
|
6014
|
+
for (const f of files) {
|
|
6015
|
+
const fullPath = path6.join(dir, f);
|
|
6016
|
+
const stat = fs7.statSync(fullPath);
|
|
6017
|
+
if (stat.isDirectory()) {
|
|
6018
|
+
const found = findBinaryInDir(fullPath, maxDepth - 1);
|
|
6019
|
+
if (found) return found;
|
|
6020
|
+
continue;
|
|
6021
|
+
}
|
|
6022
|
+
if (f === "mihomo") return fullPath;
|
|
6023
|
+
if (f.includes("mihomo") && !f.endsWith(".gz")) return fullPath;
|
|
6024
|
+
}
|
|
6025
|
+
return null;
|
|
6026
|
+
}
|
|
6027
|
+
async function downloadKernel(progressCallback, mirror, releaseInfo) {
|
|
6028
|
+
ensureDirs();
|
|
6029
|
+
const latest = releaseInfo || await getLatestRelease(GITHUB_REPO, mirror);
|
|
6030
|
+
const arch = getArch();
|
|
6031
|
+
const platform = process.platform;
|
|
6032
|
+
const asset = findMatchingAsset(latest.assets, platform, arch);
|
|
6033
|
+
if (!asset) {
|
|
6034
|
+
const available = latest.assets.map((a) => a.name).join(", ");
|
|
6035
|
+
let hint = "";
|
|
6036
|
+
if (available) hint = `
|
|
6037
|
+
\u53EF\u7528\u7248\u672C: ${available}`;
|
|
6038
|
+
throw new Error(`\u672A\u627E\u5230\u5339\u914D\u7684\u5185\u6838\u6587\u4EF6
|
|
6039
|
+
\u5E73\u53F0: ${platform}, \u67B6\u6784: ${arch}${hint}`);
|
|
6040
|
+
}
|
|
6041
|
+
const downloadUrl = withMirror(asset.browser_download_url, mirror);
|
|
6042
|
+
const tempPath = path6.join(DIRS.kernel, path6.basename(asset.name));
|
|
6043
|
+
const sizeMB = (asset.size / 1024 / 1024).toFixed(2);
|
|
6044
|
+
if (mirror && progressCallback) {
|
|
6045
|
+
progressCallback("\u63D0\u793A: \u7ECF\u7B2C\u4E09\u65B9\u955C\u50CF\u4E2D\u8F6C\u4E0B\u8F7D\uFF0C\u65E0\u6CD5\u9A8C\u8BC1\u6765\u6E90\u5B8C\u6574\u6027\uFF0C\u5EFA\u8BAE\u76F4\u8FDE\u6216\u81EA\u884C\u6821\u9A8C\u4EA7\u7269");
|
|
6046
|
+
}
|
|
6047
|
+
if (progressCallback) {
|
|
6048
|
+
progressCallback(`\u4E0B\u8F7D\u5185\u6838: ${asset.name} (${sizeMB} MB)`);
|
|
6049
|
+
}
|
|
6050
|
+
const curlResult = spawnSync5(
|
|
6051
|
+
"curl",
|
|
6052
|
+
["-L", "--progress-bar", "--connect-timeout", "30", "--max-time", String(Math.floor(KERNEL_DOWNLOAD_TIMEOUT / 1e3)), "-o", tempPath, downloadUrl],
|
|
6053
|
+
{ stdio: "inherit" }
|
|
6054
|
+
);
|
|
6055
|
+
if (curlResult.error) {
|
|
6056
|
+
if (curlResult.error.code === "ENOENT") {
|
|
6057
|
+
throw new Error("\u672A\u627E\u5230 curl \u547D\u4EE4\uFF0C\u8BF7\u5148\u5B89\u88C5 curl \u540E\u91CD\u8BD5");
|
|
6058
|
+
}
|
|
6059
|
+
throw new Error(`\u4E0B\u8F7D\u5931\u8D25: ${curlResult.error.message}`);
|
|
6060
|
+
}
|
|
6061
|
+
if (curlResult.status !== 0) {
|
|
6062
|
+
try {
|
|
6063
|
+
fs7.unlinkSync(tempPath);
|
|
6064
|
+
} catch {
|
|
6065
|
+
}
|
|
6066
|
+
throw new Error(`\u4E0B\u8F7D\u5931\u8D25 (curl \u9000\u51FA\u7801 ${curlResult.status})`);
|
|
6067
|
+
}
|
|
6068
|
+
if (!fs7.existsSync(tempPath)) {
|
|
6069
|
+
throw new Error("\u4E0B\u8F7D\u5931\u8D25: \u6587\u4EF6\u672A\u751F\u6210");
|
|
6070
|
+
}
|
|
6071
|
+
if (progressCallback) {
|
|
6072
|
+
progressCallback("\u89E3\u538B\u5185\u6838...");
|
|
6073
|
+
}
|
|
6074
|
+
const extractPath = DIRS.kernel;
|
|
6075
|
+
let extractedBinary = null;
|
|
6076
|
+
try {
|
|
6077
|
+
if (tempPath.endsWith(".tar.gz") || tempPath.endsWith(".tgz")) {
|
|
6078
|
+
const listResult = spawnSync5("tar", ["-tzf", tempPath], { encoding: "utf8", timeout: 6e4 });
|
|
6079
|
+
if (listResult.error) throw listResult.error;
|
|
6080
|
+
if (listResult.status !== 0) throw new Error(`tar \u5217\u8868\u9000\u51FA\u7801 ${listResult.status}`);
|
|
6081
|
+
const entries = (listResult.stdout || "").split("\n").filter(Boolean);
|
|
6082
|
+
for (const entry of entries) {
|
|
6083
|
+
if (entry.startsWith("/") || entry.split("/").includes("..")) {
|
|
6084
|
+
throw new Error(`\u5F52\u6863\u542B\u975E\u6CD5\u8DEF\u5F84\u6761\u76EE: ${entry}`);
|
|
5902
6085
|
}
|
|
5903
6086
|
}
|
|
5904
|
-
|
|
6087
|
+
const tarResult = spawnSync5("tar", ["-xzf", tempPath, "-C", extractPath], { stdio: ["ignore", "ignore", "inherit"], timeout: 6e4 });
|
|
6088
|
+
if (tarResult.error) throw tarResult.error;
|
|
6089
|
+
if (tarResult.status !== 0) throw new Error(`tar \u9000\u51FA\u7801 ${tarResult.status}`);
|
|
6090
|
+
} else if (tempPath.endsWith(".gz")) {
|
|
6091
|
+
const baseName = path6.basename(tempPath, ".gz");
|
|
6092
|
+
const outputPath = path6.join(extractPath, baseName);
|
|
6093
|
+
const gzipResult = spawnSync5("gzip", ["-dc", tempPath], { maxBuffer: 256 * 1024 * 1024, timeout: 6e4 });
|
|
6094
|
+
if (gzipResult.error) throw gzipResult.error;
|
|
6095
|
+
if (gzipResult.status !== 0) throw new Error(`gzip \u9000\u51FA\u7801 ${gzipResult.status}`);
|
|
6096
|
+
fs7.writeFileSync(outputPath, gzipResult.stdout, { mode: 493 });
|
|
6097
|
+
extractedBinary = outputPath;
|
|
5905
6098
|
}
|
|
5906
|
-
}
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
|
|
5910
|
-
if (result.removedGroups > 0) parts.push(`\u5220\u9664 ${result.removedGroups} \u4E2A\u7A7A\u5206\u7EC4`);
|
|
5911
|
-
if (result.updatedGroups > 0) parts.push(`\u66F4\u65B0 ${result.updatedGroups} \u4E2A\u5206\u7EC4`);
|
|
5912
|
-
return parts.join(", ");
|
|
5913
|
-
}
|
|
5914
|
-
function formatTestSummary(summary) {
|
|
5915
|
-
return `\u7ED3\u679C: ${colors.green(`${summary.alive} \u5B58\u6D3B`)} / ${colors.red(`${summary.dead} \u5931\u8D25`)} / ${summary.total} \u603B\u8BA1`;
|
|
5916
|
-
}
|
|
5917
|
-
|
|
5918
|
-
// src/commands/status.ts
|
|
5919
|
-
function printStatus() {
|
|
5920
|
-
const status = getStatus();
|
|
5921
|
-
const state = getRunningState();
|
|
5922
|
-
const info = getConfigInfo();
|
|
5923
|
-
const overwriteEnabled = isOverwriteEnabled();
|
|
5924
|
-
const overwriteFiles = listOverwriteFile().files;
|
|
5925
|
-
const activeSub = getActiveSubscription();
|
|
5926
|
-
const { running, pid, daemon: daemonManaged } = state;
|
|
5927
|
-
console.log("");
|
|
5928
|
-
let modeLabel = "";
|
|
5929
|
-
if (info) {
|
|
5930
|
-
modeLabel = colors.cyan(info.tun ? " (TUN)" : " (Mixed)");
|
|
5931
|
-
}
|
|
5932
|
-
const statusText = running ? colors.green("\u25CF \u8FD0\u884C\u4E2D") : colors.yellow("\u4E0D\u5728\u8FD0\u884C");
|
|
5933
|
-
console.log(`${colors.gray("\u72B6\u6001: ")}${statusText}${modeLabel}`);
|
|
5934
|
-
console.log(`${colors.gray("\u5185\u6838: ")}${status.kernelVersion || "\u672A\u5B89\u88C5"}`);
|
|
5935
|
-
if (pid) {
|
|
5936
|
-
console.log(`${colors.gray("PID: ")}${pid}`);
|
|
5937
|
-
if (!daemonManaged && status.processInfo) {
|
|
5938
|
-
console.log(`${colors.gray("\u5185\u5B58: ")}${status.processInfo.memory}`);
|
|
6099
|
+
} catch (e) {
|
|
6100
|
+
try {
|
|
6101
|
+
fs7.unlinkSync(tempPath);
|
|
6102
|
+
} catch {
|
|
5939
6103
|
}
|
|
6104
|
+
throw new Error(`\u89E3\u538B\u5931\u8D25: ${e.message}`);
|
|
5940
6105
|
}
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
|
|
5945
|
-
}
|
|
5946
|
-
console.log(`${colors.gray("\u7AEF\u53E3: ")}${info.mixedPort}`);
|
|
5947
|
-
} else {
|
|
5948
|
-
const ports = [];
|
|
5949
|
-
if (info.httpPort) ports.push(`HTTP:${info.httpPort}`);
|
|
5950
|
-
if (info.socksPort) ports.push(`SOCKS:${info.socksPort}`);
|
|
5951
|
-
console.log(`${colors.gray("\u7AEF\u53E3: ")}${ports.length > 0 ? ports.join(", ") : "\u672A\u77E5"}`);
|
|
6106
|
+
const foundBinary = extractedBinary || findBinaryInDir(extractPath);
|
|
6107
|
+
if (!foundBinary) {
|
|
6108
|
+
try {
|
|
6109
|
+
fs7.unlinkSync(tempPath);
|
|
6110
|
+
} catch {
|
|
5952
6111
|
}
|
|
6112
|
+
throw new Error("\u89E3\u538B\u540E\u672A\u627E\u5230\u53EF\u6267\u884C\u6587\u4EF6");
|
|
5953
6113
|
}
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
if (
|
|
5957
|
-
|
|
6114
|
+
const targetPath = PATHS.mihomoBinary;
|
|
6115
|
+
if (foundBinary !== targetPath) {
|
|
6116
|
+
if (fs7.existsSync(targetPath)) {
|
|
6117
|
+
fs7.chmodSync(targetPath, 493);
|
|
6118
|
+
try {
|
|
6119
|
+
fs7.unlinkSync(targetPath);
|
|
6120
|
+
} catch {
|
|
6121
|
+
}
|
|
5958
6122
|
}
|
|
5959
|
-
|
|
5960
|
-
} else {
|
|
5961
|
-
console.log(`${colors.gray("\u8BA2\u9605: ")}\u672A\u914D\u7F6E`);
|
|
6123
|
+
fs7.renameSync(foundBinary, targetPath);
|
|
5962
6124
|
}
|
|
5963
|
-
|
|
5964
|
-
|
|
5965
|
-
|
|
5966
|
-
} else if (overwriteEnabled) {
|
|
5967
|
-
console.log(`${colors.gray("\u8986\u5199: ")}${colors.green("\u5DF2\u542F\u7528")} (\u65E0\u6587\u4EF6)`);
|
|
5968
|
-
} else {
|
|
5969
|
-
console.log(`${colors.gray("\u8986\u5199: ")}${colors.yellow("\u5DF2\u7981\u7528")}`);
|
|
6125
|
+
fs7.chmodSync(targetPath, 493);
|
|
6126
|
+
if (progressCallback) {
|
|
6127
|
+
progressCallback("\u6821\u9A8C\u5185\u6838...");
|
|
5970
6128
|
}
|
|
5971
|
-
|
|
5972
|
-
|
|
6129
|
+
const check = spawnSync5(targetPath, ["-v"], { encoding: "utf8", timeout: 5e3 });
|
|
6130
|
+
const checkOutput = `${check.stdout || ""}${check.stderr || ""}`.trim();
|
|
6131
|
+
if (check.error || check.status !== 0 || !/v?\d+\.\d+\.\d+/.test(checkOutput)) {
|
|
6132
|
+
try {
|
|
6133
|
+
fs7.unlinkSync(targetPath);
|
|
6134
|
+
} catch {
|
|
6135
|
+
}
|
|
6136
|
+
try {
|
|
6137
|
+
fs7.unlinkSync(tempPath);
|
|
6138
|
+
} catch {
|
|
6139
|
+
}
|
|
6140
|
+
throw new Error(`\u5185\u6838\u81EA\u68C0\u5931\u8D25\uFF08\u53EF\u80FD\u4E0B\u8F7D\u635F\u574F\u6216\u67B6\u6784\u4E0D\u5339\u914D\uFF09\uFF0C\u5DF2\u5220\u9664
|
|
6141
|
+
\u9000\u51FA\u7801: ${check.status}
|
|
6142
|
+
\u8F93\u51FA: ${checkOutput || "(\u7A7A)"}`);
|
|
5973
6143
|
}
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
// src/commands/stop.ts
|
|
5978
|
-
function handleStopResult(result) {
|
|
5979
|
-
if (result.remaining && result.remaining.length > 0) {
|
|
5980
|
-
console.error(`${colors.red("\u90E8\u5206\u8FDB\u7A0B\u672A\u7EC8\u6B62:")} ${result.remaining.join(", ")}`);
|
|
5981
|
-
console.error("\u8BF7\u624B\u52A8\u8FD0\u884C: sudo pkill -9 mihomo");
|
|
5982
|
-
process.exit(1);
|
|
6144
|
+
try {
|
|
6145
|
+
fs7.unlinkSync(tempPath);
|
|
6146
|
+
} catch {
|
|
5983
6147
|
}
|
|
6148
|
+
clearKernelVersionCache();
|
|
6149
|
+
return { version: latest.tag_name, path: targetPath };
|
|
5984
6150
|
}
|
|
5985
|
-
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
6151
|
+
|
|
6152
|
+
// src/commands/kernel.ts
|
|
6153
|
+
async function cmdKernel(args) {
|
|
6154
|
+
const mirrorInfo = parseMirrorArg(args);
|
|
6155
|
+
const effectiveMirror = mirrorInfo.mirror;
|
|
6156
|
+
if (effectiveMirror) {
|
|
6157
|
+
const mirrorDesc = mirrorInfo.type === "all" ? " (API\u548C\u4E0B\u8F7D\u5747\u4F7F\u7528\u955C\u50CF)" : " (\u4E0B\u8F7D\u65F6\u4F7F\u7528\u955C\u50CF)";
|
|
6158
|
+
console.log(`\u955C\u50CF: ${effectiveMirror}${mirrorDesc}`);
|
|
6159
|
+
console.log("");
|
|
5990
6160
|
}
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
6161
|
+
console.log("\u68C0\u67E5\u5185\u6838\u66F4\u65B0...");
|
|
6162
|
+
try {
|
|
6163
|
+
const apiMirror = mirrorInfo.type === "all" ? effectiveMirror : null;
|
|
6164
|
+
const info = await checkUpdate(apiMirror);
|
|
6165
|
+
console.log(`\u5F53\u524D: ${info.current}`);
|
|
6166
|
+
console.log(`\u6700\u65B0: ${info.latest}`);
|
|
6167
|
+
if (!info.needsUpdate) {
|
|
6168
|
+
console.log("\u5DF2\u662F\u6700\u65B0\u7248\u672C");
|
|
6169
|
+
} else {
|
|
6170
|
+
console.log("\n\u6B63\u5728\u4E0B\u8F7D...");
|
|
6171
|
+
const result = await downloadKernel((msg) => console.log(msg), mirrorInfo.mirror, info.release);
|
|
6172
|
+
console.log(`
|
|
6173
|
+
\u5DF2\u66F4\u65B0\u5230 ${result.version}`);
|
|
6174
|
+
}
|
|
6175
|
+
} catch (e) {
|
|
6176
|
+
if (e instanceof CliError) throw e;
|
|
6177
|
+
const err = e;
|
|
6178
|
+
const hint = [];
|
|
6179
|
+
if (err.response?.data?.message) {
|
|
6180
|
+
hint.push(`\u539F\u56E0: ${err.response.data.message}`);
|
|
6181
|
+
}
|
|
6182
|
+
if (err.response?.data?.documentation_url) {
|
|
6183
|
+
hint.push(`\u6587\u6863: ${err.response.data.documentation_url}`);
|
|
6184
|
+
}
|
|
6185
|
+
if (!effectiveMirror) {
|
|
6186
|
+
hint.push(
|
|
6187
|
+
"",
|
|
6188
|
+
"\u63D0\u793A: \u76F4\u8FDE\u5931\u8D25\u6216\u4E0B\u8F7D\u8FC7\u6162\u65F6\u53EF\u4F7F\u7528\u955C\u50CF:",
|
|
6189
|
+
" mihomo kernel --mirror [\u955C\u50CF] # \u4E0B\u8F7D\u8D70\u955C\u50CF\uFF08\u9ED8\u8BA4 v6.gh-proxy.org\uFF09",
|
|
6190
|
+
" mihomo kernel --mirror-all [\u955C\u50CF] # API \u548C\u4E0B\u8F7D\u90FD\u8D70\u955C\u50CF",
|
|
6191
|
+
` \u53EF\u7528\u955C\u50CF: ${AVAILABLE_MIRRORS.join(", ")}`
|
|
6192
|
+
);
|
|
6193
|
+
}
|
|
6194
|
+
throw new CliError(err.message, { label: "\u66F4\u65B0\u5931\u8D25", hint });
|
|
5995
6195
|
}
|
|
5996
|
-
console.log(`\u505C\u6B62 ${pids.length} \u4E2A\u8FDB\u7A0B...`);
|
|
5997
|
-
handleStopResult(stop());
|
|
5998
|
-
console.log(colors.green("\u5DF2\u505C\u6B62\u8FDB\u7A0B"));
|
|
5999
6196
|
}
|
|
6000
6197
|
|
|
6001
|
-
// src/commands/
|
|
6002
|
-
|
|
6003
|
-
|
|
6004
|
-
|
|
6005
|
-
|
|
6006
|
-
|
|
6007
|
-
const targetMode = args[1] === "tun" ? "tun" : "mixed";
|
|
6008
|
-
const daemonEnabled = isDaemonEnabled();
|
|
6009
|
-
if (targetMode === "tun" && daemonEnabled) {
|
|
6010
|
-
console.error(`${colors.red("\u9519\u8BEF:")} \u4FDD\u6D3B\u5DF2\u542F\u7528\uFF08\u4EC5\u652F\u6301 Mixed \u6A21\u5F0F\uFF09\uFF0C\u65E0\u6CD5\u542F\u52A8 TUN`);
|
|
6011
|
-
console.error("\u8BF7\u5148\u5173\u95ED\u4FDD\u6D3B: mihomo daemon off");
|
|
6012
|
-
process.exit(1);
|
|
6013
|
-
}
|
|
6014
|
-
const rounds = parseIntArg(args, "-r", "--rounds", DEFAULT_CLEAN_ROUNDS);
|
|
6015
|
-
const timeout = parseIntArg(args, "-t", "--timeout", DEFAULT_TEST_TIMEOUT);
|
|
6016
|
-
const concurrency = parseIntArg(args, "-j", "--concurrency", DEFAULT_TEST_CONCURRENCY);
|
|
6017
|
-
const skipUpdate = hasFlag(args, "-s", "--no-update");
|
|
6018
|
-
const skipClean = hasFlag(args, "--no-clean");
|
|
6019
|
-
const updateTimeout = parseIntArg(args, "-u", "--update-timeout", DEFAULT_AUTO_UPDATE_TIMEOUT);
|
|
6020
|
-
const sub = getActiveSubscription();
|
|
6021
|
-
if (!sub) {
|
|
6022
|
-
console.error("\u9519\u8BEF: \u6CA1\u6709\u8BA2\u9605\uFF0C\u8BF7\u5148\u6DFB\u52A0\u8BA2\u9605");
|
|
6023
|
-
process.exit(1);
|
|
6024
|
-
}
|
|
6025
|
-
if (!skipUpdate) {
|
|
6026
|
-
await autoUpdateStaleSubscription({ timeout: updateTimeout });
|
|
6198
|
+
// src/commands/log.ts
|
|
6199
|
+
function cmdLog(args) {
|
|
6200
|
+
const logPath = getLogPath();
|
|
6201
|
+
if (hasFlag(args, "-o", "--open")) {
|
|
6202
|
+
openLogFile(logPath);
|
|
6203
|
+
return;
|
|
6027
6204
|
}
|
|
6028
|
-
|
|
6029
|
-
|
|
6030
|
-
|
|
6031
|
-
|
|
6032
|
-
|
|
6033
|
-
|
|
6205
|
+
viewLogWithTail(logPath, { follow: true, lines: 50 });
|
|
6206
|
+
}
|
|
6207
|
+
function cmdLogs(args) {
|
|
6208
|
+
const targetName = getNonFlagArg(args, 1);
|
|
6209
|
+
const lines = parseIntArg(args, "-n", "--lines", 100);
|
|
6210
|
+
const openInViewer = hasFlag(args, "-o", "--open");
|
|
6211
|
+
if (targetName) {
|
|
6212
|
+
let logPath;
|
|
6213
|
+
if (targetName === "current" || targetName === "0") {
|
|
6214
|
+
logPath = getLogPath();
|
|
6215
|
+
} else {
|
|
6216
|
+
const parsedIdx = parseInt(targetName, 10);
|
|
6217
|
+
if (!Number.isNaN(parsedIdx) && parsedIdx > 0 && String(parsedIdx) === targetName) {
|
|
6218
|
+
const archiveLogs = listLogs();
|
|
6219
|
+
const archive = archiveLogs.archives[parsedIdx - 1];
|
|
6220
|
+
if (!archive) {
|
|
6221
|
+
throw new CliError(`\u672A\u627E\u5230\u65E5\u5FD7 "${targetName}"`, { hint: '\u4F7F\u7528 "mihomo logs" \u67E5\u770B\u53EF\u7528\u65E5\u5FD7\u5217\u8868' });
|
|
6222
|
+
}
|
|
6223
|
+
logPath = archive.path;
|
|
6224
|
+
} else {
|
|
6225
|
+
logPath = getLogPathByName(targetName);
|
|
6226
|
+
}
|
|
6034
6227
|
}
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
if (hasProcess) {
|
|
6038
|
-
const count = status.allProcesses.length > 0 ? status.allProcesses.length : 1;
|
|
6039
|
-
console.log(`\u505C\u6B62 ${count} \u4E2A\u8FDB\u7A0B...`);
|
|
6228
|
+
if (!logPath) {
|
|
6229
|
+
throw new CliError(`\u672A\u627E\u5230\u65E5\u5FD7 "${targetName}"`, { hint: '\u4F7F\u7528 "mihomo logs" \u67E5\u770B\u53EF\u7528\u65E5\u5FD7\u5217\u8868' });
|
|
6040
6230
|
}
|
|
6041
|
-
|
|
6042
|
-
|
|
6043
|
-
|
|
6044
|
-
`);
|
|
6231
|
+
if (openInViewer) {
|
|
6232
|
+
openLogFile(logPath);
|
|
6233
|
+
return;
|
|
6045
6234
|
}
|
|
6235
|
+
viewLogWithTail(logPath, { follow: false, lines });
|
|
6236
|
+
return;
|
|
6046
6237
|
}
|
|
6047
|
-
|
|
6048
|
-
|
|
6049
|
-
|
|
6050
|
-
|
|
6051
|
-
|
|
6052
|
-
|
|
6238
|
+
const logs = listLogs();
|
|
6239
|
+
const all = [];
|
|
6240
|
+
if (logs.current) all.push(logs.current);
|
|
6241
|
+
all.push(...logs.archives);
|
|
6242
|
+
if (all.length === 0) {
|
|
6243
|
+
console.log("\u6682\u65E0\u65E5\u5FD7");
|
|
6244
|
+
return;
|
|
6053
6245
|
}
|
|
6054
|
-
|
|
6055
|
-
console.log(
|
|
6056
|
-
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
for (const line of lines.slice(1)) console.error(line);
|
|
6246
|
+
console.log("");
|
|
6247
|
+
console.log("\u65E5\u5FD7\u5217\u8868:");
|
|
6248
|
+
console.log("");
|
|
6249
|
+
let archiveCounter = 0;
|
|
6250
|
+
for (const log of all) {
|
|
6251
|
+
let num;
|
|
6252
|
+
if (log.isCurrent) {
|
|
6253
|
+
num = " 0";
|
|
6254
|
+
} else {
|
|
6255
|
+
archiveCounter++;
|
|
6256
|
+
num = archiveCounter < 10 ? ` ${archiveCounter}` : `${archiveCounter}`;
|
|
6066
6257
|
}
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
|
|
6071
|
-
|
|
6072
|
-
|
|
6073
|
-
|
|
6074
|
-
if (!withinCooldown) {
|
|
6075
|
-
console.log("");
|
|
6076
|
-
console.log(`\u8282\u70B9\u6570 ${configInfo.proxies} \u8D85\u8FC7 ${cleanThreshold}\uFF0C\u81EA\u52A8\u6E05\u7406\uFF08${AUTO_CLEAN_COOLDOWN_HOURS}h \u5185\u4EC5\u4E00\u6B21\uFF0C--no-clean \u8DF3\u8FC7\uFF09...`);
|
|
6077
|
-
console.log("");
|
|
6078
|
-
await sleep(1e3);
|
|
6079
|
-
const progress = createProgressPrinter(rounds);
|
|
6080
|
-
const cleanResult = await autoCleanSubscription(sub.name, {
|
|
6081
|
-
timeout,
|
|
6082
|
-
concurrency,
|
|
6083
|
-
rounds,
|
|
6084
|
-
onResult: progress.onResult,
|
|
6085
|
-
onRetryRound: progress.onRetryRound
|
|
6086
|
-
});
|
|
6087
|
-
progress.finish();
|
|
6088
|
-
console.log(formatTestSummary(cleanResult.summary));
|
|
6089
|
-
if (cleanResult.skipped) {
|
|
6090
|
-
console.log(colors.yellow("\u5B58\u6D3B\u8282\u70B9\u4E0D\u8DB3 1%\uFF0C\u8DF3\u8FC7\u6E05\u7406\u3002\u8BF7\u68C0\u67E5\u539F\u59CB\u8BA2\u9605\u662F\u5426\u6709\u6548"));
|
|
6091
|
-
} else if (cleanResult.removedProxies > 0) {
|
|
6092
|
-
console.log(`${colors.green("\u5DF2\u6E05\u7406")}: ${formatCleanSummary(cleanResult)}`);
|
|
6093
|
-
console.log("");
|
|
6094
|
-
console.log("\u91CD\u65B0\u52A0\u8F7D\u914D\u7F6E...");
|
|
6095
|
-
if (!daemonEnabled) handleStopResult(stop());
|
|
6096
|
-
try {
|
|
6097
|
-
configInfo = prepareConfigForStart(targetMode, sub.name);
|
|
6098
|
-
const pid = await launchOrRestart(targetMode);
|
|
6099
|
-
console.log(`${colors.green("\u5DF2\u91CD\u542F")}${pid ? ` (PID ${pid})` : ""} \xB7 ${formatProxySummary(configInfo)}`);
|
|
6100
|
-
} catch (e) {
|
|
6101
|
-
console.error(`${colors.red("\u91CD\u542F\u5931\u8D25:")} ${e.message.split("\n")[0]}`);
|
|
6102
|
-
process.exit(1);
|
|
6103
|
-
}
|
|
6104
|
-
}
|
|
6105
|
-
saveSubscriptionCache(sub.name, { last_auto_clean_at: (/* @__PURE__ */ new Date()).toISOString() });
|
|
6258
|
+
const time = formatDate(log.mtime);
|
|
6259
|
+
const size = formatBytes(log.size);
|
|
6260
|
+
const name = log.isCurrent ? "mihomo.log (\u5F53\u524D\u8FD0\u884C\u4E2D)" : log.name;
|
|
6261
|
+
console.log(` ${num}. ${name}`);
|
|
6262
|
+
console.log(` \u65F6\u95F4: ${time} \u5927\u5C0F: ${size}`);
|
|
6263
|
+
if (!log.isCurrent) {
|
|
6264
|
+
console.log(` \u67E5\u770B: mihomo logs ${archiveCounter} \u6216 mihomo logs ${archiveCounter} -o`);
|
|
6106
6265
|
}
|
|
6266
|
+
console.log("");
|
|
6107
6267
|
}
|
|
6108
|
-
|
|
6268
|
+
console.log("\u7528\u6CD5:");
|
|
6269
|
+
console.log(" mihomo logs 0 # \u67E5\u770B\u5F53\u524D\u65E5\u5FD7 (\u6700\u540E 100 \u884C)");
|
|
6270
|
+
console.log(" mihomo logs 1 # \u67E5\u770B\u7B2C 1 \u4E2A\u5F52\u6863\u65E5\u5FD7\uFF08\u6700\u65B0\uFF09");
|
|
6271
|
+
console.log(" mihomo logs 1 -n 200 # \u67E5\u770B 200 \u884C");
|
|
6272
|
+
console.log(" mihomo logs 1 -o # \u7528\u7CFB\u7EDF\u9ED8\u8BA4\u7A0B\u5E8F\u6253\u5F00");
|
|
6273
|
+
console.log("");
|
|
6109
6274
|
}
|
|
6110
6275
|
|
|
6111
6276
|
// src/commands/overwrite.ts
|
|
6277
|
+
import path7 from "path";
|
|
6112
6278
|
function printOverwriteList() {
|
|
6113
6279
|
const info = listOverwriteFile();
|
|
6114
6280
|
const statusText = info.enabled ? colors.green("\u5DF2\u542F\u7528") : colors.yellow("\u5DF2\u7981\u7528");
|
|
@@ -6140,48 +6306,30 @@ function printOverwriteList() {
|
|
|
6140
6306
|
console.log("\u7981\u7528\u8986\u5199: mihomo ow off");
|
|
6141
6307
|
console.log("");
|
|
6142
6308
|
}
|
|
6143
|
-
async function
|
|
6144
|
-
|
|
6145
|
-
|
|
6146
|
-
const restartNeeded = isRestartNeededOnChange();
|
|
6147
|
-
if (action === "on" || action === "enable") {
|
|
6148
|
-
if (isOverwriteEnabled()) {
|
|
6149
|
-
console.log("\u8986\u5199\u914D\u7F6E\u5DF2\u662F\u542F\u7528\u72B6\u6001");
|
|
6150
|
-
console.log("");
|
|
6151
|
-
printOverwriteList();
|
|
6152
|
-
return;
|
|
6153
|
-
}
|
|
6154
|
-
setOverwriteEnabled(true);
|
|
6155
|
-
console.log("\u5DF2\u542F\u7528\u8986\u5199\u914D\u7F6E");
|
|
6156
|
-
if (restartNeeded) {
|
|
6157
|
-
console.log("");
|
|
6158
|
-
await cmdStart(["start", currentMode, ...extractStartOptions(args)]);
|
|
6159
|
-
return;
|
|
6160
|
-
}
|
|
6309
|
+
async function setOverwrite(enabled, args) {
|
|
6310
|
+
if (isOverwriteEnabled() === enabled) {
|
|
6311
|
+
console.log(`\u8986\u5199\u914D\u7F6E\u5DF2\u662F${enabled ? "\u542F\u7528" : "\u7981\u7528"}\u72B6\u6001`);
|
|
6161
6312
|
console.log("");
|
|
6162
6313
|
printOverwriteList();
|
|
6163
6314
|
return;
|
|
6164
6315
|
}
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
|
|
6316
|
+
setOverwriteEnabled(enabled);
|
|
6317
|
+
console.log(`\u5DF2${enabled ? "\u542F\u7528" : "\u7981\u7528"}\u8986\u5199\u914D\u7F6E`);
|
|
6318
|
+
if (await restartToApply(args)) return;
|
|
6319
|
+
console.log("");
|
|
6320
|
+
printOverwriteList();
|
|
6321
|
+
}
|
|
6322
|
+
var SUBCOMMANDS3 = [
|
|
6323
|
+
{ name: "on", aliases: ["enable"], handler: (args) => setOverwrite(true, args) },
|
|
6324
|
+
{ name: "off", aliases: ["disable"], handler: (args) => setOverwrite(false, args) }
|
|
6325
|
+
];
|
|
6326
|
+
async function cmdOverwrite(args) {
|
|
6327
|
+
await dispatchSubcommand(args, SUBCOMMANDS3, {
|
|
6328
|
+
fallback: () => {
|
|
6168
6329
|
console.log("");
|
|
6169
6330
|
printOverwriteList();
|
|
6170
|
-
return;
|
|
6171
6331
|
}
|
|
6172
|
-
|
|
6173
|
-
console.log("\u5DF2\u7981\u7528\u8986\u5199\u914D\u7F6E");
|
|
6174
|
-
if (restartNeeded) {
|
|
6175
|
-
console.log("");
|
|
6176
|
-
await cmdStart(["start", currentMode, ...extractStartOptions(args)]);
|
|
6177
|
-
return;
|
|
6178
|
-
}
|
|
6179
|
-
console.log("");
|
|
6180
|
-
printOverwriteList();
|
|
6181
|
-
return;
|
|
6182
|
-
}
|
|
6183
|
-
console.log("");
|
|
6184
|
-
printOverwriteList();
|
|
6332
|
+
});
|
|
6185
6333
|
}
|
|
6186
6334
|
|
|
6187
6335
|
// src/commands/reset.ts
|
|
@@ -6291,10 +6439,7 @@ async function cmdReset(args) {
|
|
|
6291
6439
|
const KNOWN_FLAGS = /* @__PURE__ */ new Set(["--full", "--yes", "-y"]);
|
|
6292
6440
|
const unknownFlags = flags.filter((f) => !KNOWN_FLAGS.has(f));
|
|
6293
6441
|
if (unknownFlags.length > 0) {
|
|
6294
|
-
|
|
6295
|
-
console.log("");
|
|
6296
|
-
console.log("\u53EF\u7528\u9009\u9879: --full\uFF08\u5220\u5168\u90E8\uFF09, -y/--yes\uFF08\u8DF3\u8FC7\u786E\u8BA4\uFF09");
|
|
6297
|
-
process.exit(1);
|
|
6442
|
+
throw new CliError(`\u672A\u77E5\u7684\u9009\u9879: ${unknownFlags.join(", ")}`, { hint: ["", "\u53EF\u7528\u9009\u9879: --full\uFF08\u5220\u5168\u90E8\uFF09, -y/--yes\uFF08\u8DF3\u8FC7\u786E\u8BA4\uFF09"] });
|
|
6298
6443
|
}
|
|
6299
6444
|
const fullReset = flags.includes("--full");
|
|
6300
6445
|
const skipConfirm = flags.includes("--yes") || flags.includes("-y");
|
|
@@ -6304,16 +6449,18 @@ async function cmdReset(args) {
|
|
|
6304
6449
|
} else if (names.length > 0) {
|
|
6305
6450
|
const { matched, unmatched } = resolveResetTargets(names);
|
|
6306
6451
|
if (unmatched.length > 0) {
|
|
6307
|
-
|
|
6308
|
-
|
|
6309
|
-
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
|
|
6315
|
-
|
|
6316
|
-
|
|
6452
|
+
throw new CliError(`\u672A\u77E5\u7684\u91CD\u7F6E\u76EE\u6807: ${unmatched.join(", ")}`, {
|
|
6453
|
+
hint: [
|
|
6454
|
+
"",
|
|
6455
|
+
`\u53EF\u7528\u76EE\u6807: ${RESET_TARGETS.map((t) => t.aliases[0]).join(", ")}`,
|
|
6456
|
+
"",
|
|
6457
|
+
"\u793A\u4F8B:",
|
|
6458
|
+
" mihomo reset sub log # \u5220\u9664\u8BA2\u9605\u548C\u65E5\u5FD7",
|
|
6459
|
+
" mihomo reset kernel # \u53EA\u5220\u5185\u6838",
|
|
6460
|
+
" mihomo reset --full # \u5220\u9664\u5168\u90E8",
|
|
6461
|
+
" mihomo reset # \u5220\u9664\u5168\u90E8\uFF08\u4FDD\u7559\u8BBE\u7F6E\u3001\u5185\u6838\u3001\u8986\u5199\uFF09"
|
|
6462
|
+
]
|
|
6463
|
+
});
|
|
6317
6464
|
}
|
|
6318
6465
|
targets = matched;
|
|
6319
6466
|
} else {
|
|
@@ -6484,7 +6631,7 @@ function stopTestInstance() {
|
|
|
6484
6631
|
} catch {
|
|
6485
6632
|
return;
|
|
6486
6633
|
}
|
|
6487
|
-
if (pid > 0 && isProcessRunning(pid)) {
|
|
6634
|
+
if (pid > 0 && isProcessRunning(pid) && isProcessCommandMatching(pid, TEST_PATHS.configFile)) {
|
|
6488
6635
|
process.kill(pid, "SIGKILL");
|
|
6489
6636
|
for (let i = 0; i < 20; i++) {
|
|
6490
6637
|
if (!isProcessRunning(pid)) break;
|
|
@@ -6522,21 +6669,18 @@ function githubRepoUrl(rawUrl) {
|
|
|
6522
6669
|
function resolveTestTarget(args) {
|
|
6523
6670
|
const subs = getSubscriptions();
|
|
6524
6671
|
if (subs.length === 0) {
|
|
6525
|
-
|
|
6526
|
-
process.exit(1);
|
|
6672
|
+
throw new CliError("\u6CA1\u6709\u8BA2\u9605");
|
|
6527
6673
|
}
|
|
6528
6674
|
const nameArg = getNonFlagArg(args, 2);
|
|
6529
6675
|
const timeout = parseIntArg(args, "-t", "--timeout", DEFAULT_TEST_TIMEOUT);
|
|
6530
6676
|
const concurrency = parseIntArg(args, "-j", "--concurrency", DEFAULT_TEST_CONCURRENCY);
|
|
6531
6677
|
let target;
|
|
6532
6678
|
if (nameArg) {
|
|
6533
|
-
|
|
6534
|
-
target = pickSingleSubscription(matches, nameArg);
|
|
6679
|
+
target = resolveSubscription(subs, nameArg);
|
|
6535
6680
|
} else {
|
|
6536
6681
|
const activeSub = getActiveSubscription();
|
|
6537
6682
|
if (!activeSub) {
|
|
6538
|
-
|
|
6539
|
-
process.exit(1);
|
|
6683
|
+
throw new CliError("\u6CA1\u6709\u6D3B\u8DC3\u8BA2\u9605\uFF0C\u8BF7\u6307\u5B9A\u8BA2\u9605\u540D\u79F0");
|
|
6540
6684
|
}
|
|
6541
6685
|
target = activeSub;
|
|
6542
6686
|
}
|
|
@@ -6597,274 +6741,231 @@ function printSubscriptionList() {
|
|
|
6597
6741
|
console.log("\u6253\u5F00\u9875\u9762: mihomo sub web [name]");
|
|
6598
6742
|
console.log("");
|
|
6599
6743
|
}
|
|
6600
|
-
async function
|
|
6601
|
-
const
|
|
6602
|
-
|
|
6603
|
-
|
|
6604
|
-
|
|
6744
|
+
async function subAdd(args) {
|
|
6745
|
+
const url = args[2]?.trim();
|
|
6746
|
+
const name = args[3] || "default";
|
|
6747
|
+
if (!url) {
|
|
6748
|
+
throw new CliError("\u8BF7\u63D0\u4F9B\u6709\u6548\u7684\u8BA2\u9605 URL");
|
|
6605
6749
|
}
|
|
6606
|
-
if (
|
|
6607
|
-
const
|
|
6608
|
-
|
|
6609
|
-
|
|
6610
|
-
console.error("\u9519\u8BEF: \u8BF7\u63D0\u4F9B\u6709\u6548\u7684\u8BA2\u9605 URL");
|
|
6611
|
-
process.exit(1);
|
|
6612
|
-
}
|
|
6613
|
-
if (isMultiUrl(url)) {
|
|
6614
|
-
const urls = splitUrls(url);
|
|
6615
|
-
if (urls.length === 0) {
|
|
6616
|
-
console.error("\u9519\u8BEF: \u8BF7\u63D0\u4F9B\u6709\u6548\u7684\u8BA2\u9605 URL");
|
|
6617
|
-
process.exit(1);
|
|
6618
|
-
}
|
|
6619
|
-
for (const u of urls) {
|
|
6620
|
-
if (!isValidHttpUrl(u)) {
|
|
6621
|
-
console.error(`\u9519\u8BEF: \u65E0\u6548\u7684 URL: ${u}`);
|
|
6622
|
-
process.exit(1);
|
|
6623
|
-
}
|
|
6624
|
-
}
|
|
6625
|
-
const normalizedUrl = urls.join(",");
|
|
6626
|
-
console.log(`\u6DFB\u52A0\u5408\u5E76\u8BA2\u9605: ${name} (${urls.length} \u4E2A\u6E90)`);
|
|
6627
|
-
try {
|
|
6628
|
-
addSubscription(normalizedUrl, name);
|
|
6629
|
-
setDefaultSubscription(name);
|
|
6630
|
-
const info = await downloadMergedSubscription(urls, name);
|
|
6631
|
-
console.log(`\u5DF2\u6DFB\u52A0\u5E76\u5207\u6362\u5230 "${name}" (${formatProxySummary(info)}, \u5408\u5E76 ${urls.length} \u6E90)`);
|
|
6632
|
-
} catch (e) {
|
|
6633
|
-
removeSubscription(name);
|
|
6634
|
-
console.error(`\u6DFB\u52A0\u5931\u8D25: ${e.message}`);
|
|
6635
|
-
process.exit(1);
|
|
6636
|
-
}
|
|
6637
|
-
} else {
|
|
6638
|
-
if (!isValidHttpUrl(url)) {
|
|
6639
|
-
console.error("\u9519\u8BEF: \u8BF7\u63D0\u4F9B\u6709\u6548\u7684\u8BA2\u9605 URL\uFF08\u9700\u4EE5 http:// \u6216 https:// \u5F00\u5934\uFF09");
|
|
6640
|
-
process.exit(1);
|
|
6641
|
-
}
|
|
6642
|
-
console.log(`\u6DFB\u52A0\u8BA2\u9605: ${name}`);
|
|
6643
|
-
try {
|
|
6644
|
-
addSubscription(url, name);
|
|
6645
|
-
setDefaultSubscription(name);
|
|
6646
|
-
const info = await downloadSubscription(url, name);
|
|
6647
|
-
const repoUrl = githubRepoUrl(url);
|
|
6648
|
-
if (repoUrl) saveSubscriptionCache(name, { web_page_url: repoUrl });
|
|
6649
|
-
console.log(`\u5DF2\u6DFB\u52A0\u5E76\u5207\u6362\u5230 "${name}" (${formatProxySummary(info)})`);
|
|
6650
|
-
} catch (e) {
|
|
6651
|
-
removeSubscription(name);
|
|
6652
|
-
console.error(`\u6DFB\u52A0\u5931\u8D25: ${e.message}`);
|
|
6653
|
-
process.exit(1);
|
|
6654
|
-
}
|
|
6750
|
+
if (isMultiUrl(url)) {
|
|
6751
|
+
const urls = splitUrls(url);
|
|
6752
|
+
if (urls.length === 0) {
|
|
6753
|
+
throw new CliError("\u8BF7\u63D0\u4F9B\u6709\u6548\u7684\u8BA2\u9605 URL");
|
|
6655
6754
|
}
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
}
|
|
6660
|
-
if (action === "update") {
|
|
6661
|
-
const name = args[2];
|
|
6662
|
-
const subs = getSubscriptions();
|
|
6663
|
-
if (subs.length === 0) {
|
|
6664
|
-
console.error("\u9519\u8BEF: \u6CA1\u6709\u8BA2\u9605");
|
|
6665
|
-
process.exit(1);
|
|
6666
|
-
}
|
|
6667
|
-
if (!name) {
|
|
6668
|
-
console.log(`\u66F4\u65B0\u6240\u6709 ${subs.length} \u4E2A\u8BA2\u9605...`);
|
|
6669
|
-
const results = await Promise.all(subs.map((sub) => tryUpdateOne(sub)));
|
|
6670
|
-
let ok = 0;
|
|
6671
|
-
for (const r of results) {
|
|
6672
|
-
if (r.success) ok++;
|
|
6673
|
-
printUpdateResult(r);
|
|
6755
|
+
for (const u of urls) {
|
|
6756
|
+
if (!isValidHttpUrl(u)) {
|
|
6757
|
+
throw new CliError(`\u65E0\u6548\u7684 URL: ${u}`);
|
|
6674
6758
|
}
|
|
6675
|
-
if (ok === 0) process.exit(1);
|
|
6676
|
-
console.log("");
|
|
6677
|
-
printRestartHintIfRunning();
|
|
6678
|
-
printSubscriptionList();
|
|
6679
|
-
return;
|
|
6680
6759
|
}
|
|
6681
|
-
const
|
|
6682
|
-
|
|
6683
|
-
|
|
6684
|
-
|
|
6685
|
-
|
|
6686
|
-
|
|
6687
|
-
|
|
6760
|
+
const normalizedUrl = urls.join(",");
|
|
6761
|
+
console.log(`\u6DFB\u52A0\u5408\u5E76\u8BA2\u9605: ${name} (${urls.length} \u4E2A\u6E90)`);
|
|
6762
|
+
try {
|
|
6763
|
+
addSubscription(normalizedUrl, name);
|
|
6764
|
+
setDefaultSubscription(name);
|
|
6765
|
+
const info = await downloadMergedSubscription(urls, name);
|
|
6766
|
+
console.log(`\u5DF2\u6DFB\u52A0\u5E76\u5207\u6362\u5230 "${name}" (${formatProxySummary(info)}, \u5408\u5E76 ${urls.length} \u6E90)`);
|
|
6767
|
+
} catch (e) {
|
|
6768
|
+
removeSubscription(name);
|
|
6769
|
+
throw new CliError(e.message, { label: "\u6DFB\u52A0\u5931\u8D25" });
|
|
6688
6770
|
}
|
|
6689
|
-
|
|
6690
|
-
|
|
6691
|
-
|
|
6692
|
-
printSubscriptionList();
|
|
6693
|
-
return;
|
|
6694
|
-
}
|
|
6695
|
-
if (action === "use") {
|
|
6696
|
-
const name = args[2];
|
|
6697
|
-
const subs = getSubscriptions();
|
|
6698
|
-
if (!name) {
|
|
6699
|
-
console.error("\u9519\u8BEF: \u8BF7\u6307\u5B9A\u8BA2\u9605\u540D\u79F0");
|
|
6700
|
-
if (subs.length > 0) {
|
|
6701
|
-
console.log("\n\u53EF\u7528\u8BA2\u9605:");
|
|
6702
|
-
for (const s of subs) console.log(` ${s.name}`);
|
|
6703
|
-
}
|
|
6704
|
-
process.exit(1);
|
|
6705
|
-
}
|
|
6706
|
-
const matches = findSubscriptionFuzzy(subs, name);
|
|
6707
|
-
const target = pickSingleSubscription(matches, name);
|
|
6708
|
-
const currentDefault = getActiveSubscription();
|
|
6709
|
-
const isAlreadyDefault = currentDefault && currentDefault.name === target.name;
|
|
6710
|
-
if (isAlreadyDefault) {
|
|
6711
|
-
console.log(`"${target.name}" \u5DF2\u662F\u5F53\u524D\u4F7F\u7528\u7684\u8BA2\u9605`);
|
|
6712
|
-
console.log("");
|
|
6713
|
-
printSubscriptionList();
|
|
6714
|
-
return;
|
|
6771
|
+
} else {
|
|
6772
|
+
if (!isValidHttpUrl(url)) {
|
|
6773
|
+
throw new CliError("\u8BF7\u63D0\u4F9B\u6709\u6548\u7684\u8BA2\u9605 URL\uFF08\u9700\u4EE5 http:// \u6216 https:// \u5F00\u5934\uFF09");
|
|
6715
6774
|
}
|
|
6716
|
-
|
|
6717
|
-
|
|
6718
|
-
|
|
6719
|
-
|
|
6720
|
-
|
|
6721
|
-
|
|
6722
|
-
|
|
6723
|
-
|
|
6775
|
+
console.log(`\u6DFB\u52A0\u8BA2\u9605: ${name}`);
|
|
6776
|
+
try {
|
|
6777
|
+
addSubscription(url, name);
|
|
6778
|
+
setDefaultSubscription(name);
|
|
6779
|
+
const info = await downloadSubscription(url, name);
|
|
6780
|
+
const repoUrl = githubRepoUrl(url);
|
|
6781
|
+
if (repoUrl) saveSubscriptionCache(name, { web_page_url: repoUrl });
|
|
6782
|
+
console.log(`\u5DF2\u6DFB\u52A0\u5E76\u5207\u6362\u5230 "${name}" (${formatProxySummary(info)})`);
|
|
6783
|
+
} catch (e) {
|
|
6784
|
+
removeSubscription(name);
|
|
6785
|
+
throw new CliError(e.message, { label: "\u6DFB\u52A0\u5931\u8D25" });
|
|
6724
6786
|
}
|
|
6725
|
-
|
|
6726
|
-
|
|
6727
|
-
|
|
6728
|
-
|
|
6787
|
+
}
|
|
6788
|
+
console.log("");
|
|
6789
|
+
printSubscriptionList();
|
|
6790
|
+
}
|
|
6791
|
+
async function subUpdate(args) {
|
|
6792
|
+
const name = args[2];
|
|
6793
|
+
const subs = getSubscriptions();
|
|
6794
|
+
if (subs.length === 0) {
|
|
6795
|
+
throw new CliError("\u6CA1\u6709\u8BA2\u9605");
|
|
6796
|
+
}
|
|
6797
|
+
if (!name) {
|
|
6798
|
+
console.log(`\u66F4\u65B0\u6240\u6709 ${subs.length} \u4E2A\u8BA2\u9605...`);
|
|
6799
|
+
const results = await Promise.all(subs.map((sub) => tryUpdateOne(sub)));
|
|
6800
|
+
let ok = 0;
|
|
6801
|
+
for (const r of results) {
|
|
6802
|
+
if (r.success) ok++;
|
|
6803
|
+
printUpdateResult(r);
|
|
6729
6804
|
}
|
|
6805
|
+
if (ok === 0) throw new CliError("\u5168\u90E8\u8BA2\u9605\u66F4\u65B0\u5931\u8D25");
|
|
6730
6806
|
console.log("");
|
|
6807
|
+
printRestartHintIfRunning();
|
|
6731
6808
|
printSubscriptionList();
|
|
6732
6809
|
return;
|
|
6733
6810
|
}
|
|
6734
|
-
|
|
6735
|
-
|
|
6736
|
-
|
|
6737
|
-
|
|
6738
|
-
|
|
6739
|
-
process.exit(1);
|
|
6740
|
-
}
|
|
6741
|
-
let target;
|
|
6742
|
-
if (name) {
|
|
6743
|
-
const matches = findSubscriptionFuzzy(subs, name);
|
|
6744
|
-
target = pickSingleSubscription(matches, name);
|
|
6745
|
-
} else {
|
|
6746
|
-
target = getActiveSubscription() || subs[0];
|
|
6747
|
-
}
|
|
6748
|
-
const cached = subs.find((s) => s.name === target.name);
|
|
6749
|
-
let webPageUrl = cached?.web_page_url;
|
|
6750
|
-
if (!webPageUrl) {
|
|
6751
|
-
console.log("\u8BA2\u9605\u4FE1\u606F\u4E2D\u7F3A\u5C11\u9875\u9762\u5730\u5740\uFF0C\u6B63\u5728\u67E5\u8BE2\u8BA2\u9605...");
|
|
6752
|
-
try {
|
|
6753
|
-
const info = isMultiUrl(target.url) ? await downloadMergedSubscription(splitUrls(target.url), target.name, void 0, false) : await downloadSubscription(target.url, target.name, void 0, false);
|
|
6754
|
-
if (info.webPageUrl) {
|
|
6755
|
-
webPageUrl = info.webPageUrl;
|
|
6756
|
-
} else {
|
|
6757
|
-
console.error("\u9519\u8BEF: \u8BE5\u8BA2\u9605\u6CA1\u6709\u63D0\u4F9B\u9875\u9762\u5730\u5740");
|
|
6758
|
-
process.exit(1);
|
|
6759
|
-
}
|
|
6760
|
-
} catch (e) {
|
|
6761
|
-
console.error(`\u67E5\u8BE2\u5931\u8D25: ${e.message}`);
|
|
6762
|
-
process.exit(1);
|
|
6763
|
-
}
|
|
6764
|
-
}
|
|
6765
|
-
console.log(`\u6253\u5F00\u8BA2\u9605\u9875\u9762: ${webPageUrl}`);
|
|
6766
|
-
const opened = openUrl(webPageUrl);
|
|
6767
|
-
if (!opened) {
|
|
6768
|
-
console.log("\u8BF7\u624B\u52A8\u8BBF\u95EE\u4E0A\u9762\u7684\u5730\u5740");
|
|
6769
|
-
}
|
|
6770
|
-
return;
|
|
6811
|
+
const target = resolveSubscription(subs, name);
|
|
6812
|
+
console.log(`\u66F4\u65B0\u8BA2\u9605: ${target.name}`);
|
|
6813
|
+
const result = await tryUpdateOne(target);
|
|
6814
|
+
if (!result.success) {
|
|
6815
|
+
throw new CliError((result.error || "").split("\n")[0], { label: "\u66F4\u65B0\u5931\u8D25" });
|
|
6771
6816
|
}
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
|
|
6779
|
-
|
|
6780
|
-
|
|
6781
|
-
|
|
6782
|
-
|
|
6783
|
-
|
|
6784
|
-
|
|
6785
|
-
|
|
6786
|
-
|
|
6787
|
-
|
|
6788
|
-
|
|
6789
|
-
}
|
|
6817
|
+
console.log(`\u5DF2\u66F4\u65B0 (${formatProxySummary(result)})`);
|
|
6818
|
+
console.log("");
|
|
6819
|
+
printRestartHintIfRunning();
|
|
6820
|
+
printSubscriptionList();
|
|
6821
|
+
}
|
|
6822
|
+
async function subUse(args) {
|
|
6823
|
+
const name = args[2];
|
|
6824
|
+
const subs = getSubscriptions();
|
|
6825
|
+
if (!name) {
|
|
6826
|
+
throw new CliError("\u8BF7\u6307\u5B9A\u8BA2\u9605\u540D\u79F0", {
|
|
6827
|
+
hint: subs.length > 0 ? ["", "\u53EF\u7528\u8BA2\u9605:", ...subs.map((s) => ` ${s.name}`)] : void 0
|
|
6828
|
+
});
|
|
6829
|
+
}
|
|
6830
|
+
const target = resolveSubscription(subs, name);
|
|
6831
|
+
const currentDefault = getActiveSubscription();
|
|
6832
|
+
const isAlreadyDefault = currentDefault && currentDefault.name === target.name;
|
|
6833
|
+
if (isAlreadyDefault) {
|
|
6834
|
+
console.log(`"${target.name}" \u5DF2\u662F\u5F53\u524D\u4F7F\u7528\u7684\u8BA2\u9605`);
|
|
6790
6835
|
console.log("");
|
|
6791
6836
|
printSubscriptionList();
|
|
6792
6837
|
return;
|
|
6793
6838
|
}
|
|
6794
|
-
|
|
6795
|
-
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
|
|
6799
|
-
|
|
6800
|
-
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
6819
|
-
|
|
6820
|
-
|
|
6839
|
+
const success = setDefaultSubscription(target.name);
|
|
6840
|
+
if (!success) {
|
|
6841
|
+
throw new CliError(`\u672A\u627E\u5230\u8BA2\u9605 "${name}"`);
|
|
6842
|
+
}
|
|
6843
|
+
console.log(`\u5DF2\u5207\u6362\u5230 "${target.name}"`);
|
|
6844
|
+
if (await restartToApply(args)) return;
|
|
6845
|
+
console.log("");
|
|
6846
|
+
printSubscriptionList();
|
|
6847
|
+
}
|
|
6848
|
+
async function subWeb(args) {
|
|
6849
|
+
const name = args[2];
|
|
6850
|
+
const subs = getSubscriptionsWithCache();
|
|
6851
|
+
if (subs.length === 0) {
|
|
6852
|
+
throw new CliError("\u6CA1\u6709\u8BA2\u9605");
|
|
6853
|
+
}
|
|
6854
|
+
let target;
|
|
6855
|
+
if (name) {
|
|
6856
|
+
target = resolveSubscription(subs, name);
|
|
6857
|
+
} else {
|
|
6858
|
+
target = getActiveSubscription() || subs[0];
|
|
6859
|
+
}
|
|
6860
|
+
const cached = subs.find((s) => s.name === target.name);
|
|
6861
|
+
let webPageUrl = cached?.web_page_url;
|
|
6862
|
+
if (!webPageUrl) {
|
|
6863
|
+
console.log("\u8BA2\u9605\u4FE1\u606F\u4E2D\u7F3A\u5C11\u9875\u9762\u5730\u5740\uFF0C\u6B63\u5728\u67E5\u8BE2\u8BA2\u9605...");
|
|
6864
|
+
try {
|
|
6865
|
+
const info = isMultiUrl(target.url) ? await downloadMergedSubscription(splitUrls(target.url), target.name, void 0, false) : await downloadSubscription(target.url, target.name, void 0, false);
|
|
6866
|
+
if (!info.webPageUrl) {
|
|
6867
|
+
throw new CliError("\u8BE5\u8BA2\u9605\u6CA1\u6709\u63D0\u4F9B\u9875\u9762\u5730\u5740");
|
|
6821
6868
|
}
|
|
6869
|
+
webPageUrl = info.webPageUrl;
|
|
6870
|
+
} catch (e) {
|
|
6871
|
+
if (e instanceof CliError) throw e;
|
|
6872
|
+
throw new CliError(e.message, { label: "\u67E5\u8BE2\u5931\u8D25" });
|
|
6822
6873
|
}
|
|
6823
|
-
return;
|
|
6824
6874
|
}
|
|
6825
|
-
|
|
6826
|
-
|
|
6827
|
-
|
|
6828
|
-
console.log(
|
|
6829
|
-
console.log("");
|
|
6830
|
-
const progress = createProgressPrinter();
|
|
6831
|
-
const summary = await withTestInstance(target.name, async (apiBase) => {
|
|
6832
|
-
return testSubscriptionProxies(target.name, {
|
|
6833
|
-
timeout,
|
|
6834
|
-
concurrency,
|
|
6835
|
-
apiBase,
|
|
6836
|
-
onResult: progress.onResult
|
|
6837
|
-
});
|
|
6838
|
-
});
|
|
6839
|
-
progress.finish();
|
|
6840
|
-
console.log(formatTestSummary(summary));
|
|
6841
|
-
return;
|
|
6875
|
+
console.log(`\u6253\u5F00\u8BA2\u9605\u9875\u9762: ${webPageUrl}`);
|
|
6876
|
+
const opened = openUrl(webPageUrl);
|
|
6877
|
+
if (!opened) {
|
|
6878
|
+
console.log("\u8BF7\u624B\u52A8\u8BBF\u95EE\u4E0A\u9762\u7684\u5730\u5740");
|
|
6842
6879
|
}
|
|
6843
|
-
console.error("\u9519\u8BEF: \u672A\u77E5\u7684\u8BA2\u9605\u547D\u4EE4");
|
|
6844
|
-
console.log("\u7528\u6CD5: mihomo sub [list|use|add|update|remove|web|test|clean]");
|
|
6845
|
-
process.exit(1);
|
|
6846
6880
|
}
|
|
6847
|
-
|
|
6848
|
-
|
|
6849
|
-
|
|
6850
|
-
|
|
6851
|
-
|
|
6852
|
-
|
|
6853
|
-
|
|
6854
|
-
process.exit(1);
|
|
6881
|
+
function subRemove(args) {
|
|
6882
|
+
const name = args[2];
|
|
6883
|
+
const subs = getSubscriptions();
|
|
6884
|
+
if (!name) {
|
|
6885
|
+
throw new CliError("\u8BF7\u6307\u5B9A\u8981\u5220\u9664\u7684\u8BA2\u9605\u540D\u79F0", {
|
|
6886
|
+
hint: subs.length > 0 ? ["", "\u53EF\u7528\u8BA2\u9605:", ...subs.map((s) => ` ${s.name}`)] : void 0
|
|
6887
|
+
});
|
|
6855
6888
|
}
|
|
6889
|
+
const target = resolveSubscription(subs, name);
|
|
6890
|
+
const switchedTo = removeSubscription(target.name);
|
|
6891
|
+
console.log(`\u5DF2\u5220\u9664\u8BA2\u9605 "${target.name}"`);
|
|
6892
|
+
if (switchedTo) {
|
|
6893
|
+
console.log(`\u5DF2\u81EA\u52A8\u5207\u6362\u5230 "${switchedTo}"`);
|
|
6894
|
+
}
|
|
6895
|
+
console.log("");
|
|
6896
|
+
printSubscriptionList();
|
|
6856
6897
|
}
|
|
6857
|
-
function
|
|
6858
|
-
const
|
|
6859
|
-
|
|
6860
|
-
|
|
6861
|
-
|
|
6898
|
+
async function subClean(args) {
|
|
6899
|
+
const { target, timeout, concurrency } = resolveTestTarget(args);
|
|
6900
|
+
const rounds = parseIntArg(args, "-r", "--rounds", DEFAULT_CLEAN_ROUNDS);
|
|
6901
|
+
console.log(`\u6E05\u7406\u8BA2\u9605 "${target.name}"...`);
|
|
6902
|
+
console.log(`\u8D85\u65F6: ${timeout}ms \u5E76\u53D1: ${concurrency}`);
|
|
6903
|
+
console.log("");
|
|
6904
|
+
const progress = createProgressPrinter(rounds);
|
|
6905
|
+
const result = await withTestInstance(target.name, async (apiBase) => {
|
|
6906
|
+
return autoCleanSubscription(target.name, {
|
|
6907
|
+
timeout,
|
|
6908
|
+
concurrency,
|
|
6909
|
+
rounds,
|
|
6910
|
+
apiBase,
|
|
6911
|
+
onResult: progress.onResult,
|
|
6912
|
+
onRetryRound: progress.onRetryRound
|
|
6913
|
+
});
|
|
6914
|
+
});
|
|
6915
|
+
progress.finish();
|
|
6916
|
+
console.log(formatTestSummary(result.summary));
|
|
6917
|
+
if (result.skipped) {
|
|
6918
|
+
console.log("");
|
|
6919
|
+
console.log(colors.yellow("\u5B58\u6D3B\u8282\u70B9\u4E0D\u8DB3 1%\uFF0C\u8DF3\u8FC7\u6E05\u7406\u3002\u8BF7\u68C0\u67E5\u539F\u59CB\u8BA2\u9605\u662F\u5426\u6709\u6548"));
|
|
6920
|
+
} else if (result.removedProxies > 0) {
|
|
6921
|
+
console.log(`${colors.green("\u5DF2\u6E05\u7406")}: ${formatCleanSummary(result)}`);
|
|
6922
|
+
if (getRunningState().running) {
|
|
6923
|
+
console.log("");
|
|
6924
|
+
console.log("\u63D0\u793A: \u9700\u8981\u91CD\u542F mihomo \u4F7F\u66F4\u6539\u751F\u6548 (mihomo start)");
|
|
6925
|
+
}
|
|
6862
6926
|
}
|
|
6863
|
-
return activeSub;
|
|
6864
6927
|
}
|
|
6928
|
+
async function subTest(args) {
|
|
6929
|
+
const { target, timeout, concurrency } = resolveTestTarget(args);
|
|
6930
|
+
console.log(`\u6D4B\u8BD5\u8BA2\u9605 "${target.name}" \u7684\u8282\u70B9\u8FDE\u901A\u6027...`);
|
|
6931
|
+
console.log(`\u8D85\u65F6: ${timeout}ms \u5E76\u53D1: ${concurrency}`);
|
|
6932
|
+
console.log("");
|
|
6933
|
+
const progress = createProgressPrinter();
|
|
6934
|
+
const summary = await withTestInstance(target.name, async (apiBase) => {
|
|
6935
|
+
return testSubscriptionProxies(target.name, {
|
|
6936
|
+
timeout,
|
|
6937
|
+
concurrency,
|
|
6938
|
+
apiBase,
|
|
6939
|
+
onResult: progress.onResult
|
|
6940
|
+
});
|
|
6941
|
+
});
|
|
6942
|
+
progress.finish();
|
|
6943
|
+
console.log(formatTestSummary(summary));
|
|
6944
|
+
}
|
|
6945
|
+
var SUBCOMMANDS4 = [
|
|
6946
|
+
{ name: "list", handler: printSubscriptionList },
|
|
6947
|
+
{ name: "add", handler: subAdd },
|
|
6948
|
+
{ name: "update", handler: subUpdate },
|
|
6949
|
+
{ name: "use", handler: subUse },
|
|
6950
|
+
{ name: "web", aliases: ["open"], handler: subWeb },
|
|
6951
|
+
{ name: "remove", aliases: ["rm", "delete"], handler: subRemove },
|
|
6952
|
+
{ name: "clean", handler: subClean },
|
|
6953
|
+
{ name: "test", handler: subTest }
|
|
6954
|
+
];
|
|
6955
|
+
async function cmdSubscription(args) {
|
|
6956
|
+
await dispatchSubcommand(args, SUBCOMMANDS4, {
|
|
6957
|
+
// 无子命令 → 列表;未知子命令 → 报错
|
|
6958
|
+
fallback: printSubscriptionList,
|
|
6959
|
+
onUnknown: () => {
|
|
6960
|
+
throw new CliError("\u672A\u77E5\u7684\u8BA2\u9605\u547D\u4EE4", { hint: "\u7528\u6CD5: mihomo sub [list|use|add|update|remove|web|test|clean]" });
|
|
6961
|
+
}
|
|
6962
|
+
});
|
|
6963
|
+
}
|
|
6964
|
+
|
|
6965
|
+
// src/commands/test.ts
|
|
6865
6966
|
async function cmdTest(args) {
|
|
6866
6967
|
requireRunning();
|
|
6867
|
-
const activeSub =
|
|
6968
|
+
const activeSub = requireActiveSubscription("\u6CA1\u6709\u6D3B\u8DC3\u8BA2\u9605");
|
|
6868
6969
|
const timeout = parseIntArg(args, "-t", "--timeout", DEFAULT_TEST_TIMEOUT);
|
|
6869
6970
|
const concurrency = parseIntArg(args, "-j", "--concurrency", DEFAULT_TEST_CONCURRENCY);
|
|
6870
6971
|
console.log(`\u6D4B\u8BD5 "${activeSub.name}" \u8282\u70B9\u8FDE\u901A\u6027...`);
|
|
@@ -6881,7 +6982,7 @@ async function cmdTest(args) {
|
|
|
6881
6982
|
}
|
|
6882
6983
|
async function cmdClean(args) {
|
|
6883
6984
|
requireRunning();
|
|
6884
|
-
const activeSub =
|
|
6985
|
+
const activeSub = requireActiveSubscription("\u6CA1\u6709\u6D3B\u8DC3\u8BA2\u9605");
|
|
6885
6986
|
const timeout = parseIntArg(args, "-t", "--timeout", DEFAULT_TEST_TIMEOUT);
|
|
6886
6987
|
const concurrency = parseIntArg(args, "-j", "--concurrency", DEFAULT_TEST_CONCURRENCY);
|
|
6887
6988
|
const rounds = parseIntArg(args, "-r", "--rounds", DEFAULT_CLEAN_ROUNDS);
|
|
@@ -6912,9 +7013,7 @@ async function cmdClean(args) {
|
|
|
6912
7013
|
try {
|
|
6913
7014
|
if (!daemonManaged) {
|
|
6914
7015
|
if (hasRootResidue()) {
|
|
6915
|
-
|
|
6916
|
-
console.error("\u8BF7\u6539\u7528 mihomo sub clean\uFF08\u9694\u79BB\u5B9E\u4F8B\u6D4B\u901F\uFF0C\u65E0\u9700\u505C\u6B62\u4E3B\u5B9E\u4F8B\uFF09");
|
|
6917
|
-
process.exit(1);
|
|
7016
|
+
throw new CliError("\u4E3B\u5B9E\u4F8B\u4EE5 root \u8FD0\u884C\uFF08TUN\uFF09\uFF0C\u505C\u6B62\u5B83\u9700\u8981 sudo", { hint: "\u8BF7\u6539\u7528 mihomo sub clean\uFF08\u9694\u79BB\u5B9E\u4F8B\u6D4B\u901F\uFF0C\u65E0\u9700\u505C\u6B62\u4E3B\u5B9E\u4F8B\uFF09" });
|
|
6918
7017
|
}
|
|
6919
7018
|
handleStopResult(stop());
|
|
6920
7019
|
}
|
|
@@ -6923,8 +7022,8 @@ async function cmdClean(args) {
|
|
|
6923
7022
|
const label = daemonManaged ? "\u5DF2\u91CD\u542F (\u4FDD\u6D3B)" : "\u5DF2\u91CD\u542F";
|
|
6924
7023
|
console.log(`${colors.green(label)}${pid ? ` (PID ${pid})` : ""} \xB7 ${formatProxySummary(configInfo)}`);
|
|
6925
7024
|
} catch (e) {
|
|
6926
|
-
|
|
6927
|
-
|
|
7025
|
+
if (e instanceof CliError) throw e;
|
|
7026
|
+
throw new CliError(e.message.split("\n")[0], { label: "\u91CD\u542F\u5931\u8D25" });
|
|
6928
7027
|
}
|
|
6929
7028
|
}
|
|
6930
7029
|
}
|
|
@@ -6933,9 +7032,7 @@ async function cmdClean(args) {
|
|
|
6933
7032
|
function cmdUI(args) {
|
|
6934
7033
|
const uiName = args[1] || "zash";
|
|
6935
7034
|
if (!Object.hasOwn(UI_URLS, uiName)) {
|
|
6936
|
-
|
|
6937
|
-
console.error("\u53EF\u7528 UI: zash (\u9ED8\u8BA4), dash, yacd");
|
|
6938
|
-
process.exit(1);
|
|
7035
|
+
throw new CliError(`\u672A\u77E5\u7684 UI "${uiName}"`, { hint: "\u53EF\u7528 UI: zash (\u9ED8\u8BA4), dash, yacd" });
|
|
6939
7036
|
}
|
|
6940
7037
|
const url = UI_URLS[uiName];
|
|
6941
7038
|
console.log(`\u6253\u5F00 Web UI: ${uiName}`);
|
|
@@ -6959,23 +7056,18 @@ async function cmdUpdate() {
|
|
|
6959
7056
|
console.log("");
|
|
6960
7057
|
console.log("\u6B63\u5728\u66F4\u65B0 mihomo-cli...");
|
|
6961
7058
|
console.log("");
|
|
6962
|
-
await new Promise((resolve) => {
|
|
7059
|
+
await new Promise((resolve, reject) => {
|
|
6963
7060
|
const npm = spawn3("npm", ["install", "-g", "mihomo-cli"], { stdio: "inherit" });
|
|
6964
7061
|
npm.on("close", (code) => {
|
|
6965
7062
|
if (code === 0) {
|
|
6966
7063
|
resolve();
|
|
6967
7064
|
} else {
|
|
6968
|
-
|
|
6969
|
-
process.exit(code || 1);
|
|
7065
|
+
reject(new CliError("\u66F4\u65B0\u5931\u8D25\u3002\u82E5\u4E3A\u6743\u9650\u95EE\u9898\uFF08EACCES\uFF09\uFF0C\u53EF\u5C1D\u8BD5: sudo npm install -g mihomo-cli", { exitCode: code || 1 }));
|
|
6970
7066
|
}
|
|
6971
7067
|
});
|
|
6972
7068
|
npm.on("error", (e) => {
|
|
6973
|
-
|
|
6974
|
-
|
|
6975
|
-
} else {
|
|
6976
|
-
console.error(`\u6267\u884C\u5931\u8D25: ${e.message}`);
|
|
6977
|
-
}
|
|
6978
|
-
process.exit(1);
|
|
7069
|
+
const perm = e.message.includes("EACCES") || e.message.includes("permission");
|
|
7070
|
+
reject(perm ? new CliError("\u6743\u9650\u4E0D\u8DB3\uFF0C\u53EF\u5C1D\u8BD5: sudo npm install -g mihomo-cli") : new CliError(`\u6267\u884C\u5931\u8D25: ${e.message}`));
|
|
6979
7071
|
});
|
|
6980
7072
|
});
|
|
6981
7073
|
try {
|
|
@@ -7235,19 +7327,25 @@ async function main() {
|
|
|
7235
7327
|
const token = args[0].toLowerCase();
|
|
7236
7328
|
const command = findCommand(token);
|
|
7237
7329
|
if (!command) {
|
|
7238
|
-
|
|
7239
|
-
console.error('\u4F7F\u7528 "mihomo help" \u67E5\u770B\u5E2E\u52A9');
|
|
7240
|
-
process.exit(1);
|
|
7330
|
+
throw new CliError(`\u672A\u77E5\u547D\u4EE4: ${token}`, { hint: '\u4F7F\u7528 "mihomo help" \u67E5\u770B\u5E2E\u52A9' });
|
|
7241
7331
|
}
|
|
7242
7332
|
await command.handler(command.rewrite ? command.rewrite(args) : args);
|
|
7243
7333
|
}
|
|
7244
7334
|
main().catch((e) => {
|
|
7245
|
-
|
|
7335
|
+
if (e instanceof CliError) {
|
|
7336
|
+
console.error(`${colors.red(`${e.label}:`)} ${e.message}`);
|
|
7337
|
+
for (const line of e.hint) console.error(line);
|
|
7338
|
+
runCleanup();
|
|
7339
|
+
process.exit(e.exitCode);
|
|
7340
|
+
}
|
|
7341
|
+
const err = e;
|
|
7342
|
+
console.error(`${colors.red("\u9519\u8BEF:")} ${err.message}`);
|
|
7343
|
+
if (err.stack) console.error(err.stack.split("\n").slice(1).join("\n"));
|
|
7246
7344
|
runCleanup();
|
|
7247
7345
|
process.exit(1);
|
|
7248
7346
|
});
|
|
7249
7347
|
/*! Bundled license information:
|
|
7250
7348
|
|
|
7251
7349
|
js-yaml/dist/js-yaml.mjs:
|
|
7252
|
-
(*! js-yaml 5.
|
|
7350
|
+
(*! js-yaml 5.3.0 https://github.com/nodeca/js-yaml @license MIT *)
|
|
7253
7351
|
*/
|