@ladderkitlab/hub-kb 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -224,6 +224,10 @@ var RULE_LABELS = {
224
224
  };
225
225
  var ATOMS = [...new Set([...Object.values(RULE_LABELS), CREDENTIAL_MASK].map((s) => s.trim()))].sort((a, b) => b.length - a.length);
226
226
  var FIRST = new Set(ATOMS.map((a) => a[0]));
227
+ function placeholderEndingAt(text, end) {
228
+ for (const a of ATOMS) if (end >= a.length && text.startsWith(a, end - a.length)) return a.length;
229
+ return 0;
230
+ }
227
231
  function placeholderAt(text, i) {
228
232
  if (i >= text.length || !FIRST.has(text[i])) return 0;
229
233
  for (const a of ATOMS) if (text.startsWith(a, i)) return a.length;
@@ -231,8 +235,8 @@ function placeholderAt(text, i) {
231
235
  }
232
236
 
233
237
  // ../redact/value.ts
234
- function newScan(text, limit) {
235
- return { text, n: text.length, budget: new Budget(text.length, limit), values: /* @__PURE__ */ new Map(), unfinished: text.length };
238
+ function newScan(text, limit, raw = text) {
239
+ return { text, raw, n: text.length, budget: new Budget(text.length, limit), values: /* @__PURE__ */ new Map(), unfinished: text.length };
236
240
  }
237
241
  var IP_LITERAL_MAX = 64;
238
242
  var isHexCode = (c) => c >= 48 && c <= 57 || c >= 97 && c <= 102 || c >= 65 && c <= 70;
@@ -432,14 +436,7 @@ function interpretUrlValue(s, start) {
432
436
  } else if (segments === 0) {
433
437
  record = { state: "none", judgeEnd: start, displayEnd: start, next: start };
434
438
  } else if (content) {
435
- if (!wide && lastEnd < n && isInlineWs(t[lastEnd])) {
436
- let k = lastEnd;
437
- while (k < n && isInlineWs(t[k])) k++;
438
- s.budget.tick(k - lastEnd);
439
- const d = t[k];
440
- if (k < n && (placeholderAt(t, k) > 0 || isPrintableAscii(t.charCodeAt(k)) && d !== "&" && d !== "#" && d !== ";" && d !== ")")) wide = true;
441
- } else if (!wide && continuationStarts(t, n, lastEnd)) wide = true;
442
- const displayEnd = wide ? restEnd(s, lastEnd) : lastEnd;
439
+ const displayEnd = contentDisplayEnd(s, lastEnd, wide);
443
440
  record = { state: "content", judgeEnd: lastEnd, displayEnd, next: displayEnd };
444
441
  } else {
445
442
  record = { state: placeholder ? "placeholder" : "blank", judgeEnd: lastEnd, displayEnd: lastEnd, next: lastEnd };
@@ -447,6 +444,18 @@ function interpretUrlValue(s, start) {
447
444
  s.values.set(start, record);
448
445
  return record;
449
446
  }
447
+ function contentDisplayEnd(s, judgeEnd, wide = false) {
448
+ const t = s.text;
449
+ const n = s.n;
450
+ if (!wide && judgeEnd < n && isInlineWs(t[judgeEnd])) {
451
+ let k = judgeEnd;
452
+ while (k < n && isInlineWs(t[k])) k++;
453
+ s.budget.tick(k - judgeEnd);
454
+ const d = t[k];
455
+ if (k < n && (placeholderAt(t, k) > 0 || isPrintableAscii(t.charCodeAt(k)) && d !== "&" && d !== "#" && d !== ";" && d !== ")")) wide = true;
456
+ } else if (!wide && continuationStarts(t, n, judgeEnd)) wide = true;
457
+ return wide ? restEnd(s, judgeEnd) : judgeEnd;
458
+ }
450
459
  var hasCredentialValue = (v) => v.state === "content" || v.state === "uncertain";
451
460
 
452
461
  // ../redact/named-credential.ts
@@ -512,6 +521,9 @@ function urlNameClass(rawName) {
512
521
  if (m) return m[1] === PROSE_KEY_NAME ? "key" : "prose";
513
522
  return URL_NAME_SET.has(name) ? "url" : null;
514
523
  }
524
+ function isUrlCredentialName(rawName) {
525
+ return urlNameClass(rawName) !== null;
526
+ }
515
527
  function keyThresholdEnd(s, from) {
516
528
  const t = s.text;
517
529
  let k = from;
@@ -762,119 +774,312 @@ function proxySchemeStart(t, colon) {
762
774
  return -1;
763
775
  }
764
776
 
765
- // ../redact/index.ts
766
- var isAlnumCode2 = (x) => x >= 48 && x <= 57 || x >= 65 && x <= 90 || x >= 97 && x <= 122;
767
- var isWordCode = (x) => isAlnumCode2(x) || x === 95;
768
- var isTokenCode = (x) => isWordCode(x) || x === 45;
769
- var isHexCode2 = (x) => x >= 48 && x <= 57 || x >= 65 && x <= 70 || x >= 97 && x <= 102;
770
- function stopPositions(s) {
771
- return /* @__PURE__ */ new Set([...proseNamedHits(s).map((h) => h.index), ...inviteSpans(s).map((h) => h.index)]);
772
- }
773
- var LINK_END = (c) => isWs(c) || c === ")" || c === "]" || c === ">" || c === '"' || c === "'";
777
+ // ../redact/link.ts
778
+ var AMP = 1;
779
+ var HASH = 2;
780
+ var SEMI = 4;
774
781
  function httpHeadAt(t, i) {
775
782
  if (t[i] !== "h" && t[i] !== "H") return 0;
776
783
  const head = t.slice(i, i + 8).toLowerCase();
777
784
  return head.startsWith("https://") ? 8 : head.startsWith("http://") ? 7 : 0;
778
785
  }
786
+ var ENCODED_HEAD = /https?(?::|%(?:25)?3a)(?:\/|%(?:25)?2f)(?:\/|%(?:25)?2f)/iy;
787
+ function encodedHeadAt(t, i) {
788
+ if (t[i] !== "h" && t[i] !== "H") return 0;
789
+ ENCODED_HEAD.lastIndex = i;
790
+ if (!ENCODED_HEAD.test(t)) return 0;
791
+ const len = ENCODED_HEAD.lastIndex - i;
792
+ return t.slice(i, i + len).includes("%") ? len : 0;
793
+ }
779
794
  var SOCKS_HEADS = [...SOCKS_URI_SCHEMES].sort((x, y) => y.length - x.length).map((x) => `${x}://`);
780
- function userinfoHeadAt(t, i) {
781
- const h = httpHeadAt(t, i);
782
- if (h) return h;
795
+ function socksHeadAt(t, i) {
783
796
  if (t[i] !== "s" && t[i] !== "S") return 0;
784
797
  const head = t.slice(i, i + 10).toLowerCase();
785
798
  for (const p of SOCKS_HEADS) if (head.startsWith(p)) return p.length;
786
799
  return 0;
787
800
  }
788
- function valueLimits(s, creds = urlCredentialSpans(s)) {
789
- const t = s.text;
790
- const ends = creds.filter((sp) => sp.end < s.n && (t[sp.end] === "&" || t[sp.end] === "#" || t[sp.end] === ";" || CJK_STOPS.includes(t[sp.end])));
791
- let k = 0;
792
- return (pos) => {
793
- while (k < ends.length && ends[k].end <= pos) k++;
794
- return k < ends.length && ends[k].index <= pos ? ends[k].end : -1;
795
- };
801
+ function hasSchemeSeparator(text) {
802
+ return text.includes("://");
803
+ }
804
+ var ENCODED_UNIT = { "3A": ":", "2F": "/", "3F": "?", "23": "#", "40": "@", "5B": "[", "5D": "]", "28": "(", "29": ")" };
805
+ var ONCE = 1;
806
+ var TWICE = 2;
807
+ function headDepth(head) {
808
+ return (/%(?:3a|2f)/i.test(head) ? ONCE : 0) | (/%25(?:3a|2f)/i.test(head) ? TWICE : 0);
796
809
  }
797
- function bracketSpan(t, i, end) {
798
- const stop = Math.min(end, i + IP_LITERAL_MAX + 2);
799
- for (let j = i + 1; j < stop; j++) {
800
- if (t[j] === "]") return { len: j - i + 1, scanned: j - i };
801
- if (t[j] === "[" || /\s/.test(t[j])) return { len: 0, scanned: j - i };
810
+ function unitAt(t, j, depth) {
811
+ if (depth && t[j] === "%") {
812
+ const hex = t.slice(j + 1, j + 3).toUpperCase();
813
+ if (depth & ONCE && ENCODED_UNIT[hex]) return { ch: ENCODED_UNIT[hex], len: 3, encodedChar: true };
814
+ if (depth & TWICE && hex === "25") {
815
+ const h2 = t.slice(j + 3, j + 5).toUpperCase();
816
+ if (ENCODED_UNIT[h2]) return { ch: ENCODED_UNIT[h2], len: 5, encodedChar: true };
817
+ }
802
818
  }
803
- return { len: 0, scanned: stop - i };
819
+ return { ch: t[j], len: 1, encodedChar: false };
804
820
  }
805
- var AUTHORITY_END = /* @__PURE__ */ new Set(["/", "?", "#"]);
806
- function spanHasStop(stops, from, to) {
807
- for (let k = from; k < to; k++) if (stops.has(k)) return true;
808
- return false;
821
+ function valueContextAt(s, start) {
822
+ const t = s.text;
823
+ if (start === 0 || t[start - 1] !== "=") return false;
824
+ let p = start - 1;
825
+ while (p > 0 && /[A-Za-z0-9_.%-]/.test(t[p - 1])) p--;
826
+ s.budget.tick(start - p + 1);
827
+ if (p === 0 || !"?&#;".includes(t[p - 1])) return false;
828
+ return paramNameEnd(t, p) === start - 1 && isUrlCredentialName(t.slice(p, start - 1));
829
+ }
830
+ function headAt(s, i, inherited) {
831
+ const t = s.text;
832
+ let kind = null;
833
+ let start = i;
834
+ let contentStart = 0;
835
+ const hl = httpHeadAt(t, i);
836
+ if (hl) {
837
+ kind = "http";
838
+ contentStart = i + hl;
839
+ } else {
840
+ const el = encodedHeadAt(t, i);
841
+ if (el) {
842
+ kind = "encoded";
843
+ contentStart = i + el;
844
+ } else if (t[i] === ":" && t[i + 1] === "/" && t[i + 2] === "/") {
845
+ const ps = proxySchemeStart(t, i);
846
+ s.budget.tick(9);
847
+ if (ps >= 0) {
848
+ kind = "proxy";
849
+ start = ps;
850
+ contentStart = i + 3;
851
+ }
852
+ }
853
+ }
854
+ if (!kind) return null;
855
+ const extra = inherited | (valueContextAt(s, start) ? AMP | HASH | SEMI : 0) | (kind === "encoded" ? AMP | HASH : 0);
856
+ const displayable = kind === "proxy" || placeholderAt(t, contentStart) === 0;
857
+ const depth = kind === "encoded" ? headDepth(t.slice(i, contentStart)) : 0;
858
+ return { start, kind, contentStart, extra, userinfo: null, scanEnd: contentStart, displayEnd: contentStart, displayable, depth };
859
+ }
860
+ var isNonAscii = (s, j) => s.raw.charCodeAt(j) > 127;
861
+ var isExtraEnd = (c, extra) => (extra & AMP) !== 0 && c === "&" || (extra & HASH) !== 0 && c === "#" || (extra & SEMI) !== 0 && c === ";";
862
+ var KI_WRAP = (c) => c === ")" || c === "]" || c === ">" || c === '"' || c === "'";
863
+ function locateUserinfo(s, from, encoded) {
864
+ const t = s.text;
865
+ const n = s.n;
866
+ let j = from;
867
+ let at = null;
868
+ let afterAtom = false;
869
+ while (j < n && !isWs(t[j])) {
870
+ const a = placeholderAt(t, j);
871
+ if (a) {
872
+ afterAtom = true;
873
+ j += a;
874
+ continue;
875
+ }
876
+ if (afterAtom && isNonAscii(s, j)) break;
877
+ if (encoded && (t[j] === "&" || t[j] === "#")) break;
878
+ const u = unitAt(t, j, encoded);
879
+ if (u.ch === "/" || u.ch === "?" || u.ch === "#") break;
880
+ if (u.ch === "@") at = [j, j + u.len];
881
+ j += u.len;
882
+ }
883
+ s.budget.tick(j - from + 1);
884
+ return at;
809
885
  }
810
- function urlSpans(s) {
886
+ function linkTable(s) {
887
+ if (s.links) return s.links;
811
888
  const t = s.text;
812
889
  const n = s.n;
813
890
  const out = [];
814
- const stops = stopPositions(s);
815
- const creds = urlCredentialSpans(s);
816
- let ci = 0;
817
- const inCredValue = (pos) => {
818
- while (ci < creds.length && creds[ci].end <= pos) ci++;
819
- return ci < creds.length && creds[ci].index <= pos;
891
+ const backoff = /* @__PURE__ */ new Map();
892
+ const open = (rec) => {
893
+ out.push(rec);
894
+ const encoded = rec.depth;
895
+ const at = locateUserinfo(s, rec.contentStart, encoded);
896
+ if (at) rec.userinfo = { index: rec.contentStart, end: at[0] };
897
+ return { rec, encoded, kiT62: !at && rec.kind === "proxy", j: at ? at[1] : rec.contentStart, paren: 0, bracket: 0 };
898
+ };
899
+ const close = (f) => {
900
+ const rec = f.rec;
901
+ rec.scanEnd = f.j;
902
+ if (f.kiT62) {
903
+ let b = backoff.get(f.j);
904
+ if (b === void 0) {
905
+ b = f.j;
906
+ while (b > 0 && KI_WRAP(t[b - 1]) && placeholderEndingAt(t, b) === 0) b--;
907
+ s.budget.tick(f.j - b + 1);
908
+ backoff.set(f.j, b);
909
+ }
910
+ rec.displayEnd = Math.max(b, rec.contentStart);
911
+ } else rec.displayEnd = f.j;
820
912
  };
821
- const limitAt = valueLimits(s, creds);
822
913
  let i = 0;
823
914
  while (i < n) {
824
915
  if (!s.budget.tick()) {
825
916
  s.unfinished = Math.min(s.unfinished, i);
826
917
  break;
827
918
  }
828
- const len = httpHeadAt(t, i);
829
- if (!len) {
919
+ const top = headAt(s, i, 0);
920
+ if (!top) {
830
921
  i++;
831
922
  continue;
832
923
  }
833
- if (placeholderAt(t, i + len) > 0) {
834
- i++;
835
- continue;
836
- }
837
- const limit = limitAt(i);
838
- const end = limit >= 0 ? limit : n;
839
- let j = i + len;
840
- let lastAt = -1;
841
- let k = i + len;
842
- for (; k < end && !stops.has(k) && !AUTHORITY_END.has(t[k]); k++) {
843
- if (t[k] === "[") {
844
- const b = bracketSpan(t, k, end);
845
- if (!b.len) {
846
- s.budget.tick(b.scanned);
847
- break;
848
- }
849
- k += b.len - 1;
850
- continue;
924
+ const stack = [open(top)];
925
+ while (stack.length) {
926
+ const f = stack[stack.length - 1];
927
+ const j = f.j;
928
+ if (!s.budget.tick()) {
929
+ s.unfinished = Math.min(s.unfinished, j);
930
+ f.j = n;
851
931
  }
852
- if (LINK_END(t[k])) break;
853
- if (t[k] === "@") lastAt = k;
854
- }
855
- s.budget.tick(k - (i + len));
856
- const ipl = lastAt >= 0 ? 0 : ipLiteralAt(s, j);
857
- if (ipl && j + ipl <= end && !spanHasStop(stops, j, j + ipl)) j += ipl;
858
- let inAuthority = true;
859
- while (j < end && !LINK_END(t[j]) && !stops.has(j)) {
860
- if (AUTHORITY_END.has(t[j])) inAuthority = false;
861
- if (t[j] === "[") {
862
- const host = inAuthority && j - 1 === lastAt ? ipLiteralAt(s, j) : 0;
863
- if (!host || j + host > end || spanHasStop(stops, j, j + host)) break;
864
- j += host;
932
+ const atom = j < n ? placeholderAt(t, j) : 0;
933
+ if (atom && f.rec.kind === "proxy") {
934
+ f.j = j + atom;
865
935
  continue;
866
936
  }
867
- j++;
937
+ let ended = j >= n || isWs(t[j]) || isNonAscii(s, j) || isExtraEnd(t[j], f.rec.extra);
938
+ if (!ended && !f.kiT62) {
939
+ const c = t[j];
940
+ if (c === '"' || c === ">" || !f.encoded && c === "'") ended = true;
941
+ else if (atom) ended = true;
942
+ }
943
+ if (!ended) {
944
+ const child = headAt(s, j, f.rec.extra);
945
+ if (child && child.start >= f.rec.contentStart) {
946
+ stack.push(open(child));
947
+ continue;
948
+ }
949
+ const u = unitAt(t, j, f.encoded);
950
+ if (u.ch === "(") f.paren++;
951
+ else if (u.ch === "[") f.bracket++;
952
+ else if (u.ch === ")" || u.ch === "]") {
953
+ const isParen = u.ch === ")";
954
+ const count = isParen ? f.paren : f.bracket;
955
+ if (count > 0) {
956
+ if (isParen) f.paren--;
957
+ else f.bracket--;
958
+ } else if (!u.encodedChar && !f.kiT62) ended = true;
959
+ }
960
+ if (!ended) {
961
+ f.j = j + u.len;
962
+ continue;
963
+ }
964
+ }
965
+ f.j = Math.min(f.j, n);
966
+ close(f);
967
+ stack.pop();
968
+ const parent = stack[stack.length - 1];
969
+ if (parent) {
970
+ parent.j = Math.max(parent.j, f.rec.scanEnd);
971
+ parent.paren += f.paren;
972
+ parent.bracket += f.bracket;
973
+ }
868
974
  }
869
- s.budget.tick(j - i);
870
- if (j > i + len) {
871
- out.push({ index: i, end: j });
872
- i = j;
873
- } else i++;
975
+ i = Math.max(top.scanEnd, i + 1);
976
+ }
977
+ out.sort((a, b) => a.start - b.start);
978
+ s.links = out;
979
+ return out;
980
+ }
981
+ function linkStartingAt(s, pos) {
982
+ const links = s.links;
983
+ if (!links || links.length === 0) return null;
984
+ let lo = 0, hi = links.length - 1;
985
+ while (lo <= hi) {
986
+ const mid = lo + hi >> 1;
987
+ if (links[mid].start < pos) lo = mid + 1;
988
+ else hi = mid - 1;
989
+ }
990
+ s.budget.tick(Math.ceil(Math.log2(links.length + 1)) + 1);
991
+ const r = links[lo];
992
+ return r && r.start === pos && r.displayEnd > r.contentStart ? r : null;
993
+ }
994
+ function userinfoHasContent(s, from, end, encoded) {
995
+ const t = s.text;
996
+ s.budget.tick(end - from);
997
+ for (let k = from; k < end; ) {
998
+ const a = placeholderAt(t, k);
999
+ if (a > 0 && k + a <= end) {
1000
+ k += a;
1001
+ continue;
1002
+ }
1003
+ const u = unitAt(t, k, encoded);
1004
+ if (u.ch !== ":") return true;
1005
+ k += u.len;
1006
+ }
1007
+ return false;
1008
+ }
1009
+
1010
+ // ../redact/index.ts
1011
+ var isAlnumCode2 = (x) => x >= 48 && x <= 57 || x >= 65 && x <= 90 || x >= 97 && x <= 122;
1012
+ var isWordCode = (x) => isAlnumCode2(x) || x === 95;
1013
+ var isTokenCode = (x) => isWordCode(x) || x === 45;
1014
+ var isHexCode2 = (x) => x >= 48 && x <= 57 || x >= 65 && x <= 70 || x >= 97 && x <= 102;
1015
+ function stopPositions(s) {
1016
+ return /* @__PURE__ */ new Set([...proseNamedHits(s).map((h) => h.index), ...inviteSpans(s).map((h) => h.index)]);
1017
+ }
1018
+ var linkedCreds = /* @__PURE__ */ new WeakMap();
1019
+ var isSeparatorEnd = (s, pos) => pos < s.n && (s.text[pos] === "&" || s.text[pos] === "#" || s.text[pos] === ";" || CJK_STOPS.includes(s.text[pos]));
1020
+ function credSpans(s) {
1021
+ const hit = linkedCreds.get(s);
1022
+ if (hit) return hit;
1023
+ const creds = urlCredentialSpans(s).map((sp) => ({ index: sp.index, end: sp.end }));
1024
+ const recs = [];
1025
+ for (const r of s.links) recs.push({ start: r.start, end: r.displayEnd, userinfo: r.userinfo, socks: false });
1026
+ for (const k of socksScan(s)) recs.push({ start: k.start, end: k.authEnd, userinfo: k.userinfo, socks: true });
1027
+ recs.sort((a, b) => a.start - b.start);
1028
+ let ci = 0;
1029
+ for (const r of recs) {
1030
+ s.budget.tick();
1031
+ while (ci < creds.length && creds[ci].end <= r.start) ci++;
1032
+ const c = creds[ci];
1033
+ if (!c || c.index > r.start || r.end <= c.end) continue;
1034
+ const u = r.userinfo;
1035
+ const crossesUserinfo = u !== null && u.index <= c.end && c.end < u.end;
1036
+ if (crossesUserinfo || !r.socks && !isSeparatorEnd(s, c.end)) c.end = contentDisplayEnd(s, r.end);
874
1037
  }
1038
+ const out = mergeSpans(creds, false);
1039
+ linkedCreds.set(s, out);
875
1040
  return out;
876
1041
  }
1042
+ function valueLimits(s) {
1043
+ const creds = credSpans(s);
1044
+ let k = 0;
1045
+ return (pos) => {
1046
+ while (k < creds.length && creds[k].end <= pos) k++;
1047
+ return k < creds.length && creds[k].index <= pos ? creds[k].end : -1;
1048
+ };
1049
+ }
1050
+ function mergeSpans(spans, touching) {
1051
+ const out = [];
1052
+ for (const sp of [...spans].sort((a, b) => a.index - b.index || b.end - a.end)) {
1053
+ const last = out[out.length - 1];
1054
+ if (last && (sp.index < last.end || touching && sp.index === last.end)) last.end = Math.max(last.end, sp.end);
1055
+ else if (sp.end > sp.index) out.push({ index: sp.index, end: sp.end });
1056
+ }
1057
+ return out;
1058
+ }
1059
+ function urlSpans(s) {
1060
+ const limitAt = valueLimits(s);
1061
+ const out = [];
1062
+ for (const r of s.links) {
1063
+ if (r.kind === "proxy" || !r.displayable || r.displayEnd <= r.contentStart) continue;
1064
+ s.budget.tick();
1065
+ const lim = limitAt(r.start);
1066
+ out.push({ index: r.start, end: lim >= 0 ? Math.min(r.displayEnd, lim) : r.displayEnd });
1067
+ }
1068
+ return mergeSpans(out, true);
1069
+ }
877
1070
  function userinfoSpans(s) {
1071
+ const out = [];
1072
+ for (const r of s.links) {
1073
+ const u = r.userinfo;
1074
+ if (u && u.end > u.index && userinfoHasContent(s, u.index, u.end, r.depth)) out.push({ index: u.index, end: u.end });
1075
+ }
1076
+ for (const k of socksScan(s)) if (k.userinfo && userinfoHasContent(s, k.userinfo.index, k.userinfo.end, 0)) out.push({ ...k.userinfo });
1077
+ return mergeSpans(out, false);
1078
+ }
1079
+ var socksScans = /* @__PURE__ */ new WeakMap();
1080
+ function socksScan(s) {
1081
+ const hit = socksScans.get(s);
1082
+ if (hit) return hit;
878
1083
  const t = s.text;
879
1084
  const n = s.n;
880
1085
  const out = [];
@@ -884,51 +1089,28 @@ function userinfoSpans(s) {
884
1089
  s.unfinished = Math.min(s.unfinished, i);
885
1090
  break;
886
1091
  }
887
- const len = userinfoHeadAt(t, i);
1092
+ const len = socksHeadAt(t, i);
888
1093
  if (!len) {
889
1094
  i++;
890
1095
  continue;
891
1096
  }
892
1097
  const from = i + len;
893
- if (!httpHeadAt(t, i)) {
894
- let j2 = from;
895
- let at2 = -1;
896
- while (j2 < n && !isWs(t[j2]) && t[j2] !== "?" && t[j2] !== "#") {
897
- if (t[j2] === "@") at2 = j2;
898
- j2++;
899
- }
900
- s.budget.tick(j2 - i);
901
- if (at2 > from && userinfoHasContent(s, from, at2)) out.push({ index: from, end: at2 });
902
- i = j2 > from ? j2 : from;
903
- continue;
904
- }
905
1098
  let j = from;
906
1099
  let at = -1;
907
- while (j < n && !isWs(t[j]) && t[j] !== "/" && t[j] !== "?" && t[j] !== "#") {
1100
+ const lead = placeholderAt(t, j);
1101
+ if (lead) j += lead;
1102
+ while (j < n && !isWs(t[j]) && t[j] !== "?" && t[j] !== "#" && placeholderAt(t, j) === 0 && !(lead && s.raw.charCodeAt(j) > 127)) {
908
1103
  if (t[j] === "@") at = j;
909
1104
  j++;
910
1105
  }
911
1106
  s.budget.tick(j - i);
912
- if (at > from && userinfoHasContent(s, from, at)) out.push({ index: from, end: at });
913
- i = from;
1107
+ out.push({ start: i, userinfo: at > from ? { index: from, end: at } : null, authEnd: j });
1108
+ i = j > from ? j : from;
914
1109
  }
1110
+ socksScans.set(s, out);
915
1111
  return out;
916
1112
  }
917
- function userinfoHasContent(s, from, end) {
918
- const t = s.text;
919
- s.budget.tick(end - from);
920
- for (let k = from; k < end; ) {
921
- const a = placeholderAt(t, k);
922
- if (a > 0 && k + a <= end) {
923
- k += a;
924
- continue;
925
- }
926
- if (t[k] !== ":") return true;
927
- k++;
928
- }
929
- return false;
930
- }
931
- var SUB_END = (c) => isWs(c) || c === ")" || c === "]" || c === ">" || c === '"' || c === "'";
1113
+ var KEYWORD_VALUE_END = (c) => isWs(c) || c === ")" || c === "]" || c === ">" || c === '"' || c === "'";
932
1114
  function subscriptionKeywordEnd(t, i) {
933
1115
  if (i > 0 && isWordCode(t.charCodeAt(i - 1))) return -1;
934
1116
  const c = t[i];
@@ -950,84 +1132,58 @@ function subscriptionSpans(s) {
950
1132
  const t = s.text;
951
1133
  const n = s.n;
952
1134
  const cands = [];
1135
+ const proxies = [];
1136
+ const proxyLimit = valueLimits(s);
1137
+ for (const r of s.links) {
1138
+ if (r.kind !== "proxy" || r.displayEnd <= r.contentStart) continue;
1139
+ s.budget.tick();
1140
+ const lim = proxyLimit(r.start);
1141
+ proxies.push({ index: r.start, end: lim >= 0 ? Math.min(r.displayEnd, lim) : r.displayEnd });
1142
+ }
1143
+ for (const sp of proxies) cands.push(sp);
953
1144
  const stops = stopPositions(s);
954
1145
  const limitAt = valueLimits(s);
955
1146
  const endAt = (pos) => {
956
1147
  const l = limitAt(pos);
957
1148
  return l >= 0 ? l : n;
958
1149
  };
959
- const extend = (from, end) => {
960
- let j = from;
961
- while (j < end && !SUB_END(t[j]) && !stops.has(j)) j++;
962
- s.budget.tick(j - from + 1);
963
- return j;
964
- };
965
- const extendNoStops = (from, end) => {
966
- let j = from;
967
- while (j < end && !SUB_END(t[j]) && !CJK_STOPS.includes(t[j])) j++;
968
- s.budget.tick(j - from + 1);
969
- return j;
970
- };
971
- const authorityAt = (from, end) => {
972
- let j = from, at = -1;
973
- while (j < end && !isWs(t[j]) && t[j] !== "/" && t[j] !== "?" && t[j] !== "#") {
974
- if (t[j] === "@") at = j;
975
- j++;
976
- }
977
- s.budget.tick(j - from + 1);
978
- return at;
979
- };
980
- const extendNoAt = (from, end) => {
981
- let j = from;
982
- while (j < end && !isWs(t[j]) && !CJK_STOPS.includes(t[j])) j++;
983
- const scanned = j - from;
984
- while (j > from && SUB_END(t[j - 1])) j--;
985
- s.budget.tick(scanned * 2 + 1);
986
- return j;
987
- };
988
- const proxyExtend = (from, end) => {
989
- const at = authorityAt(from, end);
990
- return at < 0 ? extendNoAt(from, end) : extendNoStops(at + 1, end);
991
- };
1150
+ let p = 0;
992
1151
  let i = 0;
993
1152
  while (i < n) {
994
1153
  if (!s.budget.tick()) {
995
1154
  s.unfinished = Math.min(s.unfinished, i);
996
1155
  break;
997
1156
  }
998
- if (t[i] === ":" && t[i + 1] === "/" && t[i + 2] === "/") {
999
- const start = proxySchemeStart(t, i);
1000
- s.budget.tick(9);
1001
- if (start >= 0) {
1002
- const j = proxyExtend(i + 3, endAt(i));
1003
- if (j > i + 3) {
1004
- cands.push({ index: start, end: j });
1005
- i = j;
1006
- continue;
1007
- }
1008
- }
1009
- i++;
1157
+ while (p < proxies.length && proxies[p].end <= i) p++;
1158
+ if (p < proxies.length && proxies[p].index <= i) {
1159
+ i = proxies[p].end;
1010
1160
  continue;
1011
1161
  }
1012
1162
  const kw = subscriptionKeywordEnd(t, i);
1013
- if (kw >= 0) {
1014
- const j = extend(kw, endAt(i));
1015
- cands.push({ index: i, end: j });
1016
- i = j;
1163
+ if (kw < 0) {
1164
+ i++;
1017
1165
  continue;
1018
1166
  }
1019
- i++;
1167
+ const end = endAt(i);
1168
+ let q = kw;
1169
+ while (q < end && isInlineWs(t[q])) q++;
1170
+ if (q < end && (t[q] === "=" || t[q] === ":" || t[q] === "\uFF1A")) {
1171
+ q++;
1172
+ while (q < end && isInlineWs(t[q])) q++;
1173
+ }
1174
+ s.budget.tick(q - kw + 1);
1175
+ const link = linkStartingAt(s, q);
1176
+ let j;
1177
+ if (link) j = Math.min(link.displayEnd, end);
1178
+ else {
1179
+ j = kw;
1180
+ while (j < end && !KEYWORD_VALUE_END(t[j]) && !stops.has(j)) j++;
1181
+ s.budget.tick(j - kw + 1);
1182
+ }
1183
+ cands.push({ index: i, end: j });
1184
+ i = Math.max(j, i + 1);
1020
1185
  }
1021
- return disjoint(cands);
1022
- }
1023
- function disjoint(spans) {
1024
- const out = [];
1025
- let last = -1;
1026
- for (const sp of [...spans].sort((a, b) => a.index - b.index)) if (sp.index >= last && sp.end > sp.index) {
1027
- out.push(sp);
1028
- last = sp.end;
1029
- }
1030
- return out;
1186
+ return mergeSpans(cands, false);
1031
1187
  }
1032
1188
  var REGISTERED_ERROR_CODE = /^(?:INSTALL_FAILED|INSTALL_PARSE_FAILED|ERR)(?:_[A-Z]{2,})+$/;
1033
1189
  function tokenSpans(s) {
@@ -1159,15 +1315,22 @@ function inviteSpans(s) {
1159
1315
  s.invites = out;
1160
1316
  return out;
1161
1317
  }
1318
+ function emailSpans(s) {
1319
+ const seps = /* @__PURE__ */ new Set();
1320
+ for (const r of s.links) if (r.userinfo) seps.add(r.userinfo.end);
1321
+ for (const k of socksScan(s)) if (k.userinfo) seps.add(k.userinfo.end);
1322
+ if (seps.size === 0) return EMAIL(s);
1323
+ return EMAIL(s).filter((sp) => !seps.has(s.text.indexOf("@", sp.index)));
1324
+ }
1162
1325
  var RULES = [
1163
1326
  ["subscription", subscriptionSpans],
1164
1327
  ["url", urlSpans],
1165
- ["email", EMAIL],
1328
+ ["email", emailSpans],
1166
1329
  ["uuid", UUID],
1167
1330
  ["ipv6", IPV6],
1168
1331
  ["ipv4", IPV4],
1169
1332
  ["token", tokenSpans],
1170
- ["urlcred", urlCredentialSpans],
1333
+ ["urlcred", credSpans],
1171
1334
  ["userinfo", userinfoSpans],
1172
1335
  ["invite", inviteSpans],
1173
1336
  ["config", configRegions]
@@ -1179,7 +1342,8 @@ function foldFullwidth(text) {
1179
1342
  return text.replace(/[\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF1D]/g, (ch) => String.fromCharCode(ch.charCodeAt(0) - 65248));
1180
1343
  }
1181
1344
  function sensitiveMatches(text, opts = {}) {
1182
- const s = newScan(foldFullwidth(text), opts.budget);
1345
+ const s = newScan(foldFullwidth(text), opts.budget, text);
1346
+ linkTable(s);
1183
1347
  const out = [];
1184
1348
  let exhaustedAt = -1;
1185
1349
  for (let order = 0; order < RULES.length; order++) {
@@ -1235,7 +1399,7 @@ function redactSensitive(text, mask, opts = {}) {
1235
1399
  var SECRET_RULES = /* @__PURE__ */ new Set(["token", "urlcred", "userinfo", "subscription", "ipv4", "ipv6", "invite", "config", "uuid", "email"]);
1236
1400
  var SHORT_WORD_KEBAB = /^[a-z0-9]+(?:-[a-z0-9]+)+$/;
1237
1401
  function isKnownFalsePositive(m) {
1238
- if (m.rule === "subscription") return /^subscri/i.test(m.text) && !m.text.includes("://");
1402
+ if (m.rule === "subscription") return /^subscri/i.test(m.text) && !hasSchemeSeparator(m.text);
1239
1403
  if (m.rule === "token") return SHORT_WORD_KEBAB.test(m.text) && m.text.split("-").every((p) => p.length <= 16);
1240
1404
  return false;
1241
1405
  }
@@ -1266,7 +1430,7 @@ var USAGE_RULES = [
1266
1430
  ` - \u4E0E\u77E5\u8BC6\u5E93\u76F8\u90BB\u4F46\u523B\u610F\u4E0D\u505A\u2014\u2014${ADJACENT_SCOPE.join("\uFF1B")}\u2014\u2014\u4E0D\u4F5C\u7B54\uFF0C\u4E5F\u4E0D\u7528\u81EA\u5DF1\u7684\u77E5\u8BC6\u8865\uFF0C\u53EA\u56DE\u7B54\u300C${OUT_OF_SCOPE_REPLY}\u300D\u3002\u8FD9\u6761\u4F18\u5148\u4E8E\u524D\u9762\u4E09\u79CD\u56DE\u7B54\uFF1A\u5373\u4F7F\u76EE\u5F55\u91CC\u6709\u770B\u8D77\u6765\u76F8\u5173\u7684\u6761\u76EE\uFF0C\u4E5F\u4E0D\u6309\u6761\u76EE\u4F5C\u7B54\u3001\u4E0D\u90E8\u5206\u4F5C\u7B54\u3001\u4E0D\u81EA\u7B54\uFF1B\u76F8\u90BB\u95EE\u9898\u4E0D\u8D70\u300C\u6CA1\u6709\u6761\u76EE\u80FD\u56DE\u7B54\u300D\u90A3\u6761\u8DEF\uFF0C\u5E26\u4E0A\u300C${NOT_KB_LABEL}\u300D\u6807\u6CE8\u81EA\u7B54\u540C\u6837\u4E0D\u884C\u3002`,
1267
1431
  "5. \u4E0D\u56DE\u663E\u8BA2\u9605\u94FE\u63A5\u3001\u5BC6\u94A5\u3001\u8282\u70B9 IP\uFF0C\u622A\u56FE\u91CC\u7684\u4E5F\u4E00\u6837\uFF1B\u53EA\u94FE\u63A5\u6761\u76EE\u91CC\u5217\u51FA\u7684\u5B98\u65B9\u6765\u6E90\u548C\u672C\u77E5\u8BC6\u5E93\u4E3B\u7AD9\u4E0A\u7684\u6761\u76EE\u9875\u9762\uFF1B\u6807\u4E3A\u300C\u4FE1\u606F\u8BF4\u660E\u300D\u7684\u6761\u76EE\u4E0D\u7ED9\u64CD\u4F5C\u6B65\u9AA4\u3002"
1268
1432
  ].join("\n");
1269
- var SKILL_DESCRIPTION = `\u4E2D\u7ACB\u7684\u4EE3\u7406\u5BA2\u6237\u7AEF\u77E5\u8BC6\u5E93\u3002\u7528\u6237\u95EE Clash Verge Rev\u3001Clash Party\u3001FlClash\u3001v2rayN\u3001v2rayNG\u3001Clash Meta for Android\u3001sing-box\u3001Karing\u3001Shadowrocket \u7B49\u4EE3\u7406\u5BA2\u6237\u7AEF\u6216 mihomo\u3001Xray \u5185\u6838\u7684\u95EE\u9898\u65F6\u4F7F\u7528\uFF1A\u8BA2\u9605\u3001\u8282\u70B9\u3001\u534F\u8BAE\u3001\u5206\u6D41\u89C4\u5219\u3001TUN\uFF08\u865A\u62DF\u7F51\u5361\uFF09\u3001\u7CFB\u7EDF\u4EE3\u7406\u662F\u4EC0\u4E48\uFF0C\u5BA2\u6237\u7AEF\u4E0E\u5185\u6838\u7684\u7248\u672C\u3001\u66F4\u65B0\u3001\u4E0B\u8F7D\uFF08\u542B\u9884\u53D1\u5E03\u4E0E autobuild\uFF09\u600E\u4E48\u9009\uFF0C\u60F3\u5B8C\u6210\u5BFC\u5165\u8BA2\u9605\u3001\u5207\u6362\u8282\u70B9\u7B49\u64CD\u4F5C\uFF0C\u6216\u9047\u5230\u8282\u70B9\u4E3A\u7A7A\u3001\u8BA2\u9605\u66F4\u65B0\u5931\u8D25\u3001\u8FDE\u4E0A\u4F46\u6253\u4E0D\u5F00\u7F51\u9875\u7B49\u95EE\u9898\uFF08\u9644\u622A\u56FE\u6C42\u52A9\u4E5F\u7B97\uFF09\uFF1B\u7528\u6237\u95EE${ADJACENT_SCOPE.join("\u3001")}\u65F6\u540C\u6837\u4F7F\u7528\uFF08\u6309\u89C4\u5219\u53EA\u56DE\u4E00\u53E5\u56FA\u5B9A\u8BDD\uFF09\u3002\u53EA\u8BFB\uFF0C\u4E0D\u8BFB\u53D6\u7528\u6237\u673A\u5668\u72B6\u6001\uFF0C\u4E0D\u5199\u5165\u3002`;
1433
+ var SKILL_DESCRIPTION = `\u4EE3\u7406\u5BA2\u6237\u7AEF\u77E5\u8BC6\u5E93\u3002\u7528\u6237\u95EE Clash Verge Rev\u3001Clash Party\u3001FlClash\u3001v2rayN\u3001v2rayNG\u3001Clash Meta for Android\u3001sing-box\u3001Karing\u3001Shadowrocket \u7B49\u4EE3\u7406\u5BA2\u6237\u7AEF\u6216 mihomo\u3001Xray \u5185\u6838\u7684\u95EE\u9898\u65F6\u4F7F\u7528\uFF1A\u8BA2\u9605\u3001\u8282\u70B9\u3001\u534F\u8BAE\u3001\u5206\u6D41\u89C4\u5219\u3001TUN\uFF08\u865A\u62DF\u7F51\u5361\uFF09\u3001\u7CFB\u7EDF\u4EE3\u7406\u662F\u4EC0\u4E48\uFF0C\u5BA2\u6237\u7AEF\u4E0E\u5185\u6838\u7684\u7248\u672C\u3001\u66F4\u65B0\u3001\u4E0B\u8F7D\uFF08\u542B\u9884\u53D1\u5E03\u4E0E autobuild\uFF09\u600E\u4E48\u9009\uFF0C\u60F3\u5B8C\u6210\u5BFC\u5165\u8BA2\u9605\u3001\u5207\u6362\u8282\u70B9\u7B49\u64CD\u4F5C\uFF0C\u6216\u9047\u5230\u8282\u70B9\u4E3A\u7A7A\u3001\u8BA2\u9605\u66F4\u65B0\u5931\u8D25\u3001\u8FDE\u4E0A\u4F46\u6253\u4E0D\u5F00\u7F51\u9875\u7B49\u95EE\u9898\uFF08\u9644\u622A\u56FE\u6C42\u52A9\u4E5F\u7B97\uFF09\uFF1B\u7528\u6237\u95EE${ADJACENT_SCOPE.join("\u3001")}\u65F6\u540C\u6837\u4F7F\u7528\uFF08\u6309\u89C4\u5219\u53EA\u56DE\u4E00\u53E5\u56FA\u5B9A\u8BDD\uFF09\u3002\u53EA\u8BFB\uFF0C\u4E0D\u8BFB\u53D6\u7528\u6237\u673A\u5668\u72B6\u6001\uFF0C\u4E0D\u5199\u5165\u3002`;
1270
1434
 
1271
1435
  // ../runtime-core/src/mcp.ts
1272
1436
  function siteOriginOf(manifest) {
@@ -1712,6 +1876,20 @@ async function createStdioServer(deps, io) {
1712
1876
  // src/exit.ts
1713
1877
  var FALLBACK = "\u52A0\u8F7D\u6216\u8FD0\u884C\u5931\u8D25\uFF08\u8BE6\u60C5\u4E0D\u56DE\u663E\uFF09";
1714
1878
  var FLUSH_TIMEOUT_MS = 2e3;
1879
+ async function flushStreams(streams, timer, clear) {
1880
+ for (const st of streams) {
1881
+ if (st.writableEnded || st.destroyed) continue;
1882
+ await new Promise((resolve) => {
1883
+ const done = timer(resolve, FLUSH_TIMEOUT_MS);
1884
+ const finish = () => {
1885
+ clear(done);
1886
+ resolve();
1887
+ };
1888
+ st.write("", finish);
1889
+ st.once("error", finish);
1890
+ });
1891
+ }
1892
+ }
1715
1893
  function makeFail(raw) {
1716
1894
  const deps = {
1717
1895
  ...raw,
@@ -1726,18 +1904,7 @@ function makeFail(raw) {
1726
1904
  } catch {
1727
1905
  }
1728
1906
  deps.error(msg);
1729
- for (const st of deps.streams) {
1730
- if (st.writableEnded || st.destroyed) continue;
1731
- await new Promise((resolve) => {
1732
- const done = deps.timer(resolve, FLUSH_TIMEOUT_MS);
1733
- const finish = () => {
1734
- deps.clear(done);
1735
- resolve();
1736
- };
1737
- st.write("", finish);
1738
- st.once("error", finish);
1739
- });
1740
- }
1907
+ await flushStreams(deps.streams, deps.timer, deps.clear);
1741
1908
  };
1742
1909
  return (e) => {
1743
1910
  if (exiting) return exiting;