mihomo-cli 3.3.0 → 3.4.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.
Files changed (3) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/index.js +332 -190
  3. package/package.json +5 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## [3.4.0] - 2026-08-15
4
+
5
+ ### 修复
6
+
7
+ - **配置 `controller_secret` 后测速与热重载失效** - 访问 external-controller 的 HTTP 客户端从不发送 `Authorization`,设置密钥后 `test`/`clean`(走主实例)所有节点返回 401 被判失败,保活的配置热重载也恒 401 回退到 sudo 重启。现测速(主实例)与热重载请求均携带 `Bearer <secret>`;隔离测速实例自身无密钥,不受影响
8
+ - **并行更新订阅时缓存临时文件互相踩踏** - `atomicWriteFileSync` 的临时文件名仅含 pid,同进程 `Promise.all` 并行更新多个订阅时写向同名临时文件,导致内容交错或 `rename` 失败。临时名改为 pid + 进程内自增序号,各写入落到独立临时文件
9
+
10
+ ### 安全
11
+
12
+ - **YAML 别名炸弹 DoS 防护(回归修复)** - 解析订阅/覆写/运行时配置的 `yaml.load` 未设别名上限,js-yaml 默认无限制,恶意配置可借指数级别名膨胀耗尽内存/CPU。现统一设 `maxAliases` 上限
13
+ - **序列化对歧义标量加引号** - 配置序列化改用会给 `on`/`off`/`yes`/`no` 等歧义标量加引号的默认 schema。此前裸输出的 `name: on` 虽被 mihomo(go-yaml v3)读作字符串,但流经 PyYAML 等 YAML 1.1 工具会被误解析为布尔,造成静默的配置损坏
14
+ - **内核下载文件名路径穿越防护** - 下载内核时临时路径直接拼接 GitHub API 返回的 asset 名,被篡改的响应/镜像可借 `../` 写出内核目录之外。现用 `basename` 剥离目录成分
15
+ - **`open` 命令 URL 参数注入防护** - 打开订阅页面/日志文件时,服务器可控的 URL(订阅响应头 `web_page_url`)若以 `-` 开头会被 `open` 当作选项。现加 `--` 终止选项解析
16
+ - **测速实例终止前校验进程身份** - 停止隔离测速实例时按 pid 文件裸值 `SIGKILL`,pid 被系统复用后可能误杀无关进程。现杀进程前校验其命令行确属该测速实例
17
+
18
+ ### 变更
19
+
20
+ - **覆写 `~proxies` 注入的节点纳入 include-all 排除** - `~key` 就地合并在同名节点不存在时会追加新节点,此前只有 `+proxies`/`proxies+` 注入的节点会从 `include-all` 分组排除,`~proxies` 追加的节点会被重复纳入。现一并排除
21
+ - **依赖升级** - `js-yaml` 5.2.1 → 5.3.0(修复 flow collections 指数解析 DoS)、`esbuild` 经 overrides 提升至 0.28.2(修复 dev server 任意文件读取)、`@types/node` → 26、`@biomejs/biome` → 2.5.8、`lint-staged`/`tsx` 跟随最新;`npm audit` 无告警
22
+
3
23
  ## [3.3.0] - 2026-08-15
4
24
 
5
25
  ### 新增
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 ?? null,
17
+ identify: options.identify,
19
18
  represent: options.represent ?? ((data) => String(data)),
20
- representTagName: options.representTagName ?? null
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 ?? null,
33
+ identify: options.identify,
35
34
  represent: options.represent ?? ((data) => data),
36
- representTagName: options.representTagName ?? null
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 ?? null,
52
+ identify: options.identify,
54
53
  represent: options.represent ?? ((data) => data),
55
- representTagName: options.representTagName ?? null
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 MERGE_KEY;
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 = new Date(Date.UTC(year, month, day));
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 = new Date(Date.UTC(year, month, day, hour, minute, second, fraction));
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) => container[String(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) => container[String(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
- function throwErrorAt(source, position, message, filename = "") {
835
- let line = 0;
836
- let lineStart = 0;
837
- for (let index = 0; index < position; index++) {
838
- const ch = source.charCodeAt(index);
839
- if (ch === 10) {
840
- line++;
841
- lineStart = index + 1;
842
- } else if (ch === 13) {
843
- line++;
844
- if (source.charCodeAt(index + 1) === 10) index++;
845
- lineStart = index + 1;
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
- const mark = {
849
- name: filename,
850
- buffer: source,
851
- position,
852
- line,
853
- column: position - lineStart
854
- };
855
- mark.snippet = makeSnippet(mark);
856
- throw new YAMLException(message, mark);
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 === 3) result += "\n".repeat(didReadContent ? 1 + emptyLines : emptyLines);
1056
- else if (chomping !== 2) {
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 2:
1199
+ case SCALAR_STYLE.SINGLE_QUOTED:
1067
1200
  return getSingleQuotedValue(input, valueStart, valueEnd);
1068
- case 3:
1201
+ case SCALAR_STYLE.DOUBLE_QUOTED:
1069
1202
  return getDoubleQuotedValue(input, valueStart, valueEnd);
1070
- case 4:
1203
+ case SCALAR_STYLE.LITERAL_BLOCK:
1071
1204
  return getBlockValue(input, valueStart, valueEnd, scalar.indent, scalar.chomping, false);
1072
- case 5:
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
- throwErrorAt(state.source, state.position, message, state.filename);
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
- throwErrorAt(state.source, position, error instanceof Error ? error.message : String(error), state.filename);
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 = lookupTag(state.schema.exact.scalar, state.schema.prefix.scalar, tagName);
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 = lookupTag(state.schema.exact.mapping, state.schema.prefix.mapping, tagName) ?? lookupTag(state.schema.exact.sequence, state.schema.prefix.sequence, tagName);
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 === 1) {
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 collectionTag(state, event, exact, prefix, defaultTagName, nodeKind) {
1297
+ function collectionTagName(state, event, defaultTagName) {
1183
1298
  const rawTag = event.tagStart === NO_RANGE$2 ? "" : state.source.slice(event.tagStart, event.tagEnd);
1184
- const tagName = rawTag === "" || rawTag === "!" ? defaultTagName : tagNameFull(rawTag, state.tagHandlers);
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) mergeKeys(state, frame, element, frame.tag);
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 (key === MERGE_KEY) {
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 (frame.merge) {
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 1:
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 4: {
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 2: {
1290
- const definition = collectionTag(state, event, state.schema.exact.sequence, state.schema.prefix.sequence, "tag:yaml.org,2002:seq", "sequence");
1291
- const value = definition.tag.create(definition.tagName);
1292
- const anchor = storeAnchor(state, event, value, definition.tag, definition.tag.carrierIsResult);
1293
- const parent = state.frames[state.frames.length - 1];
1294
- const merge = parent !== void 0 && parent.kind === "mapping" && parent.hasKey && parent.key === MERGE_KEY;
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: definition.tag,
1415
+ tag,
1300
1416
  anchor,
1301
- index: 0,
1302
- merge
1417
+ index: 0
1303
1418
  });
1304
1419
  break;
1305
1420
  }
1306
- case 3: {
1307
- const definition = collectionTag(state, event, state.schema.exact.mapping, state.schema.prefix.mapping, "tag:yaml.org,2002:map", "mapping");
1308
- const value = definition.tag.create(definition.tagName);
1309
- const anchor = storeAnchor(state, event, value, definition.tag, definition.tag.carrierIsResult);
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: definition.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 5: {
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 6: {
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: 1,
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: 2,
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: 3,
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 addScalarEvent(state, valueStart, valueEnd, anchorStart, anchorEnd, tagStart, tagEnd, style, chomping = 1, indent = -1, fast = false) {
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: 4,
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: 5,
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: 6 });
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, 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
- throwErrorAt(state.input.slice(0, state.length), state.position, message, state.filename);
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, 2, 1, -1, simple);
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, 3, 1, -1, simple);
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 = 1;
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 ? 4 : 5;
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 !== 1) throwError(state, "repeat of a chomping mode identifier");
1681
- chomping = current === 43 ? 3 : 2;
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, 1, 1, -1, !multiline);
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, 2);
1812
- else addSequenceEvent(state, start2, props.anchorStart, props.anchorEnd, props.tagStart, props.tagEnd, 2);
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
- restoreState(state, entryStart);
1841
- addMappingEvent(state, entryStart.position, NO_RANGE$1, NO_RANGE$1, NO_RANGE$1, NO_RANGE$1, 2);
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
- restoreState(state, entryStart);
1856
- addMappingEvent(state, entryStart.position, NO_RANGE$1, NO_RANGE$1, NO_RANGE$1, NO_RANGE$1, 2);
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, 1);
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, 1);
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, 1);
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 === 3) {
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 === 3) hasContent = true;
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, 1);
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 === 1) documentEvent.explicitEnd = explicitEnd;
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) throwErrorAt(input, nullpos, "null byte is not allowed in input", state.filename);
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 && tag.identify(object)) {
2349
+ if (tag.identify(object)) {
2225
2350
  let tagName;
2226
- if (tag.matchByTagPrefix && tag.representTagName) tagName = tag.representTagName(object);
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 || resolveImplicitTag(state, string) === node.tag) return STYLE_PLAIN;
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 && resolveImplicitTag(state, string) !== node.tag) return state.quoteStyle === "double" ? STYLE_DOUBLE : STYLE_SINGLE;
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[0] === " ";
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] === " ") return line;
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: DEFAULT_DUMP_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) });
@@ -3581,6 +3705,15 @@ function isProcessRunning(pid) {
3581
3705
  return false;
3582
3706
  }
3583
3707
  }
3708
+ function isProcessCommandMatching(pid, needle) {
3709
+ if (!pid) return false;
3710
+ try {
3711
+ const result = spawnSync("ps", ["-p", String(pid), "-o", "command="], { encoding: "utf8", timeout: 5e3 });
3712
+ return (result.stdout || "").includes(needle);
3713
+ } catch {
3714
+ return false;
3715
+ }
3716
+ }
3584
3717
  function isProcessRoot(pid) {
3585
3718
  if (!pid) return false;
3586
3719
  try {
@@ -3591,7 +3724,8 @@ function isProcessRoot(pid) {
3591
3724
  }
3592
3725
  }
3593
3726
  function createHttpClient(options = {}) {
3594
- const { timeout = 6e4 } = options;
3727
+ const { timeout = 6e4, secret } = options;
3728
+ const authHeaders = secret ? { Authorization: `Bearer ${secret}` } : {};
3595
3729
  return {
3596
3730
  async get(url, config) {
3597
3731
  const controller = new AbortController();
@@ -3600,7 +3734,7 @@ function createHttpClient(options = {}) {
3600
3734
  try {
3601
3735
  const response = await fetch(url, {
3602
3736
  signal,
3603
- headers: { "User-Agent": `mihomo-cli/${VERSION}` }
3737
+ headers: { "User-Agent": `mihomo-cli/${VERSION}`, ...authHeaders }
3604
3738
  });
3605
3739
  if (!response.ok) {
3606
3740
  const error = new Error(`HTTP ${response.status}`);
@@ -3699,12 +3833,16 @@ function isProxyValid(proxy) {
3699
3833
  }
3700
3834
 
3701
3835
  // src/config.ts
3836
+ var SAFE_YAML_LOAD_OPTIONS = { maxAliases: 200 };
3837
+ function loadYamlSafe(content) {
3838
+ return load(content, SAFE_YAML_LOAD_OPTIONS);
3839
+ }
3702
3840
  function parseYamlOrJson(content, errorMsg) {
3703
3841
  if (!content?.trim()) {
3704
3842
  throw new Error(`${errorMsg || "\u5185\u5BB9"}\u4E3A\u7A7A`);
3705
3843
  }
3706
3844
  try {
3707
- const result = load(content);
3845
+ const result = loadYamlSafe(content);
3708
3846
  if (result != null && typeof result === "object" && !Array.isArray(result)) return result;
3709
3847
  } catch {
3710
3848
  }
@@ -3715,13 +3853,13 @@ function parseYamlOrJson(content, errorMsg) {
3715
3853
  }
3716
3854
  }
3717
3855
  function dumpYaml(obj) {
3718
- return dump(obj, { indent: 2, lineWidth: -1, schema: CORE_SCHEMA });
3856
+ return dump(obj, { indent: 2, lineWidth: -1 });
3719
3857
  }
3720
3858
  function collectOverwriteProxyNames(overwriteFiles) {
3721
3859
  const names = [];
3722
3860
  for (const file of overwriteFiles) {
3723
3861
  for (const [key, value] of Object.entries(file.config)) {
3724
- if ((key === "+proxies" || key === "proxies+") && Array.isArray(value)) {
3862
+ if ((key === "+proxies" || key === "proxies+" || key === "~proxies") && Array.isArray(value)) {
3725
3863
  for (const proxy of value) {
3726
3864
  if (proxy && typeof proxy === "object" && "name" in proxy) {
3727
3865
  const name = proxy.name;
@@ -3916,7 +4054,7 @@ function getConfigInfo() {
3916
4054
  if (!hasConfig()) return null;
3917
4055
  try {
3918
4056
  const content = fs4.readFileSync(PATHS.configFile, "utf8");
3919
- const cfg = load(content);
4057
+ const cfg = loadYamlSafe(content);
3920
4058
  if (!cfg) return null;
3921
4059
  const proxies = cfg.proxies;
3922
4060
  const proxyGroups = cfg["proxy-groups"];
@@ -4535,7 +4673,7 @@ function getLogPathByName(name) {
4535
4673
  }
4536
4674
  function openUrl(url) {
4537
4675
  try {
4538
- const child = spawn("open", [url], { stdio: "ignore", detached: true });
4676
+ const child = spawn("open", ["--", url], { stdio: "ignore", detached: true });
4539
4677
  child.unref();
4540
4678
  child.on("error", () => {
4541
4679
  });
@@ -4723,10 +4861,13 @@ function disableDaemon() {
4723
4861
  async function tryHotReload() {
4724
4862
  const controller = new AbortController();
4725
4863
  const timer = setTimeout(() => controller.abort(), HOT_RELOAD_TIMEOUT_MS);
4864
+ const secret = readSettings().controller_secret;
4865
+ const headers = { "Content-Type": "application/json" };
4866
+ if (secret) headers.Authorization = `Bearer ${secret}`;
4726
4867
  try {
4727
4868
  const res = await fetch(`${CONTROLLER_BASE_URL}/configs?force=true`, {
4728
4869
  method: "PUT",
4729
- headers: { "Content-Type": "application/json" },
4870
+ headers,
4730
4871
  body: "{}",
4731
4872
  signal: controller.signal
4732
4873
  });
@@ -5124,7 +5265,8 @@ async function testSubscriptionProxies(subName, options = {}) {
5124
5265
  if (proxies.length === 0) {
5125
5266
  return { total: 0, alive: 0, dead: 0, results: [] };
5126
5267
  }
5127
- const client = createHttpClient({ timeout: timeout + 3e3 });
5268
+ const secret = apiBase === CONTROLLER_BASE_URL ? readSettings().controller_secret : void 0;
5269
+ const client = createHttpClient({ timeout: timeout + 3e3, secret });
5128
5270
  const results = new Array(proxies.length);
5129
5271
  let completedCount = 0;
5130
5272
  let nextIndex = 0;
@@ -5576,7 +5718,7 @@ async function downloadKernel(progressCallback, mirror, releaseInfo) {
5576
5718
  \u5E73\u53F0: ${platform}, \u67B6\u6784: ${arch}${hint}`);
5577
5719
  }
5578
5720
  const downloadUrl = withMirror(asset.browser_download_url, mirror);
5579
- const tempPath = path6.join(DIRS.kernel, asset.name);
5721
+ const tempPath = path6.join(DIRS.kernel, path6.basename(asset.name));
5580
5722
  const sizeMB = (asset.size / 1024 / 1024).toFixed(2);
5581
5723
  if (mirror && progressCallback) {
5582
5724
  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");
@@ -6484,7 +6626,7 @@ function stopTestInstance() {
6484
6626
  } catch {
6485
6627
  return;
6486
6628
  }
6487
- if (pid > 0 && isProcessRunning(pid)) {
6629
+ if (pid > 0 && isProcessRunning(pid) && isProcessCommandMatching(pid, TEST_PATHS.configFile)) {
6488
6630
  process.kill(pid, "SIGKILL");
6489
6631
  for (let i = 0; i < 20; i++) {
6490
6632
  if (!isProcessRunning(pid)) break;
@@ -7249,5 +7391,5 @@ main().catch((e) => {
7249
7391
  /*! Bundled license information:
7250
7392
 
7251
7393
  js-yaml/dist/js-yaml.mjs:
7252
- (*! js-yaml 5.2.1 https://github.com/nodeca/js-yaml @license MIT *)
7394
+ (*! js-yaml 5.3.0 https://github.com/nodeca/js-yaml @license MIT *)
7253
7395
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mihomo-cli",
3
- "version": "3.3.0",
3
+ "version": "3.4.0",
4
4
  "type": "module",
5
5
  "description": "A terminal-based mihomo (Clash.Meta) client for macOS",
6
6
  "bin": {
@@ -47,9 +47,12 @@
47
47
  "lint-staged": {
48
48
  "*.{ts,json,md}": "biome check --fix --no-errors-on-unmatched"
49
49
  },
50
+ "overrides": {
51
+ "esbuild": "^0.28.0"
52
+ },
50
53
  "devDependencies": {
51
54
  "@biomejs/biome": "^2.5.4",
52
- "@types/node": "^22.20.1",
55
+ "@types/node": "^26.2.0",
53
56
  "husky": "^9.1.7",
54
57
  "lint-staged": "^17.0.8",
55
58
  "tsup": "^8.5.1",