clawvault 3.2.1 → 3.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.
Files changed (150) hide show
  1. package/README.md +56 -16
  2. package/bin/clawvault.js +0 -2
  3. package/bin/command-registration.test.js +13 -1
  4. package/bin/help-contract.test.js +14 -0
  5. package/bin/register-core-commands.js +88 -0
  6. package/bin/register-core-commands.test.js +80 -0
  7. package/bin/register-maintenance-commands.js +57 -6
  8. package/bin/register-query-commands.js +10 -28
  9. package/bin/test-helpers/cli-command-fixtures.js +1 -0
  10. package/dist/chunk-2PKBIKDH.js +130 -0
  11. package/dist/{chunk-U67V476Y.js → chunk-2ZDO52B4.js} +18 -1
  12. package/dist/{chunk-ZZA73MFY.js → chunk-33DOSHTA.js} +176 -36
  13. package/dist/{chunk-AZYOKJYC.js → chunk-4PY655YM.js} +13 -1
  14. package/dist/{chunk-2JQ3O2YL.js → chunk-5EFSWZO6.js} +3 -3
  15. package/dist/{chunk-Y3TIJEBP.js → chunk-7SWP5FKU.js} +34 -613
  16. package/dist/{chunk-4VQTUVH7.js → chunk-7YZWHM36.js} +52 -26
  17. package/dist/{chunk-URXDAUVH.js → chunk-AXSJIFOJ.js} +174 -1
  18. package/dist/{chunk-4ITRXIVT.js → chunk-BLQXXX7Q.js} +6 -6
  19. package/dist/chunk-CSHO3PJB.js +684 -0
  20. package/dist/{chunk-S5OJEGFG.js → chunk-DOIUYIXV.js} +2 -2
  21. package/dist/{chunk-YXQCA6B7.js → chunk-DVOUSOR3.js} +112 -7
  22. package/dist/{chunk-YDWHS4LJ.js → chunk-ECGJYWNA.js} +205 -33
  23. package/dist/{chunk-QMHPQYUV.js → chunk-EL6UBSX5.js} +7 -6
  24. package/dist/chunk-FZ5I2NF7.js +352 -0
  25. package/dist/{chunk-WJVWINEM.js → chunk-GFCHWMGD.js} +55 -6
  26. package/dist/{chunk-GNJL4YGR.js → chunk-GJO3CFUN.js} +30 -6
  27. package/dist/chunk-H3JZIB5O.js +322 -0
  28. package/dist/chunk-HEHO7SMV.js +51 -0
  29. package/dist/{chunk-UCQAOZHW.js → chunk-HGDDW24U.js} +3 -3
  30. package/dist/chunk-J3YUXVID.js +907 -0
  31. package/dist/{chunk-Y6VJKXGL.js → chunk-KCYWJDDW.js} +1 -1
  32. package/dist/{chunk-P5EPF6MB.js → chunk-MW5C6ZQA.js} +110 -13
  33. package/dist/{chunk-YNIPYN4F.js → chunk-OFOCU2V4.js} +6 -5
  34. package/dist/{chunk-42MXU7A6.js → chunk-P62WHA27.js} +58 -47
  35. package/dist/chunk-PTWPPVC7.js +972 -0
  36. package/dist/{chunk-FAKNOB7Y.js → chunk-QFWERBDP.js} +2 -2
  37. package/dist/{chunk-IIOU45CK.js → chunk-S7N7HI5E.js} +2 -2
  38. package/dist/{chunk-ECRZL5XR.js → chunk-T7E764W3.js} +23 -7
  39. package/dist/chunk-TDWFBDAQ.js +1016 -0
  40. package/dist/{chunk-MNPUYCHQ.js → chunk-TWMI3SNN.js} +6 -5
  41. package/dist/{chunk-2RAZ4ZFE.js → chunk-VBILES4B.js} +1 -1
  42. package/dist/{chunk-PI4WMLMG.js → chunk-VXAGOLDP.js} +1 -1
  43. package/dist/chunk-YCUVAOFC.js +158 -0
  44. package/dist/{chunk-SS4B7P7V.js → chunk-YIDV4VV2.js} +1 -1
  45. package/dist/chunk-ZKWPCBYT.js +600 -0
  46. package/dist/cli/index.js +27 -21
  47. package/dist/commands/archive.js +3 -3
  48. package/dist/commands/backlog.js +1 -1
  49. package/dist/commands/benchmark.d.ts +12 -0
  50. package/dist/commands/benchmark.js +12 -0
  51. package/dist/commands/blocked.js +1 -1
  52. package/dist/commands/canvas.js +2 -2
  53. package/dist/commands/checkpoint.js +1 -1
  54. package/dist/commands/compat.js +1 -1
  55. package/dist/commands/context.js +8 -7
  56. package/dist/commands/doctor.d.ts +8 -3
  57. package/dist/commands/doctor.js +8 -22
  58. package/dist/commands/embed.js +6 -5
  59. package/dist/commands/entities.js +2 -2
  60. package/dist/commands/graph.js +4 -4
  61. package/dist/commands/inbox.d.ts +23 -0
  62. package/dist/commands/inbox.js +11 -0
  63. package/dist/commands/inject.d.ts +1 -1
  64. package/dist/commands/inject.js +5 -5
  65. package/dist/commands/kanban.js +1 -1
  66. package/dist/commands/link.js +9 -9
  67. package/dist/commands/maintain.d.ts +32 -0
  68. package/dist/commands/maintain.js +12 -0
  69. package/dist/commands/migrate-observations.js +3 -3
  70. package/dist/commands/observe.js +11 -10
  71. package/dist/commands/project.js +2 -2
  72. package/dist/commands/rebuild-embeddings.js +48 -17
  73. package/dist/commands/rebuild.js +9 -8
  74. package/dist/commands/recover.js +1 -1
  75. package/dist/commands/reflect.js +6 -6
  76. package/dist/commands/repair-session.js +1 -1
  77. package/dist/commands/replay.js +10 -9
  78. package/dist/commands/session-recap.js +1 -1
  79. package/dist/commands/setup.js +4 -3
  80. package/dist/commands/shell-init.js +1 -1
  81. package/dist/commands/sleep.d.ts +1 -1
  82. package/dist/commands/sleep.js +20 -18
  83. package/dist/commands/status.js +40 -26
  84. package/dist/commands/sync-bd.js +3 -3
  85. package/dist/commands/tailscale.js +3 -3
  86. package/dist/commands/task.js +1 -1
  87. package/dist/commands/template.js +1 -1
  88. package/dist/commands/wake.d.ts +1 -1
  89. package/dist/commands/wake.js +10 -9
  90. package/dist/index.d.ts +175 -16
  91. package/dist/index.js +277 -108
  92. package/dist/{inject-DYUrDqQO.d.ts → inject-DEb_jpLi.d.ts} +3 -1
  93. package/dist/lib/auto-linker.js +2 -2
  94. package/dist/lib/canvas-layout.js +1 -1
  95. package/dist/lib/config.js +2 -2
  96. package/dist/lib/entity-index.js +1 -1
  97. package/dist/lib/project-utils.js +2 -2
  98. package/dist/lib/session-repair.js +1 -1
  99. package/dist/lib/session-utils.js +1 -1
  100. package/dist/lib/tailscale.js +1 -1
  101. package/dist/lib/task-utils.js +1 -1
  102. package/dist/lib/template-engine.js +1 -1
  103. package/dist/lib/webdav.js +1 -1
  104. package/dist/onnxruntime_binding-5QEF3SUC.node +0 -0
  105. package/dist/onnxruntime_binding-BKPKNEGC.node +0 -0
  106. package/dist/onnxruntime_binding-FMOXGIUT.node +0 -0
  107. package/dist/onnxruntime_binding-OI2KMXC5.node +0 -0
  108. package/dist/onnxruntime_binding-UX44MLAZ.node +0 -0
  109. package/dist/onnxruntime_binding-Y2W7N7WY.node +0 -0
  110. package/dist/openclaw-plugin.d.ts +8 -0
  111. package/dist/openclaw-plugin.js +14 -0
  112. package/dist/transformers.node-A2ZRORSQ.js +46775 -0
  113. package/dist/{types-BbWJoC1c.d.ts → types-DslKvCaj.d.ts} +51 -1
  114. package/hooks/clawvault/HOOK.md +25 -8
  115. package/hooks/clawvault/handler.js +215 -78
  116. package/hooks/clawvault/handler.test.js +109 -43
  117. package/hooks/clawvault/integrity.js +112 -0
  118. package/hooks/clawvault/integrity.test.js +32 -0
  119. package/hooks/clawvault/openclaw.plugin.json +133 -15
  120. package/openclaw.plugin.json +131 -203
  121. package/package.json +10 -7
  122. package/bin/register-workgraph-commands.js +0 -451
  123. package/dist/chunk-5PJ4STIC.js +0 -465
  124. package/dist/chunk-ERNE2FZ5.js +0 -189
  125. package/dist/chunk-HR4KN6S2.js +0 -152
  126. package/dist/chunk-IJBFGPCS.js +0 -33
  127. package/dist/chunk-K7PNYS45.js +0 -93
  128. package/dist/chunk-NTOPJI7W.js +0 -207
  129. package/dist/chunk-PG56HX5T.js +0 -154
  130. package/dist/chunk-QPDDIHXE.js +0 -501
  131. package/dist/chunk-WIOLLGAD.js +0 -190
  132. package/dist/chunk-WMGIIABP.js +0 -15
  133. package/dist/ledger-B7g7jhqG.d.ts +0 -44
  134. package/dist/plugin/index.d.ts +0 -352
  135. package/dist/plugin/index.js +0 -4264
  136. package/dist/registry-BR4326o0.d.ts +0 -30
  137. package/dist/store-CA-6sKCJ.d.ts +0 -34
  138. package/dist/thread-B9LhXNU0.d.ts +0 -41
  139. package/dist/workgraph/index.d.ts +0 -5
  140. package/dist/workgraph/index.js +0 -23
  141. package/dist/workgraph/ledger.d.ts +0 -2
  142. package/dist/workgraph/ledger.js +0 -25
  143. package/dist/workgraph/registry.d.ts +0 -2
  144. package/dist/workgraph/registry.js +0 -19
  145. package/dist/workgraph/store.d.ts +0 -2
  146. package/dist/workgraph/store.js +0 -25
  147. package/dist/workgraph/thread.d.ts +0 -2
  148. package/dist/workgraph/thread.js +0 -25
  149. package/dist/workgraph/types.d.ts +0 -54
  150. package/dist/workgraph/types.js +0 -7
@@ -12,7 +12,7 @@ import {
12
12
  } from "./chunk-TIGW564L.js";
13
13
  import {
14
14
  resolveVaultPath
15
- } from "./chunk-GNJL4YGR.js";
15
+ } from "./chunk-GJO3CFUN.js";
16
16
 
17
17
  // src/commands/tailscale.ts
18
18
  import * as path from "path";
@@ -4,12 +4,100 @@ import * as path from "path";
4
4
  var JSONL_SAMPLE_LIMIT = 20;
5
5
  var MARKDOWN_SIGNAL_RE = /^(#{1,6}\s|[-*+]\s|>\s)/;
6
6
  var MARKDOWN_INLINE_RE = /(\[[^\]]+\]\([^)]+\)|[*_`~])/;
7
+ var BASE64_DATA_URI_RE = /\bdata:[^;\s]+;base64,[A-Za-z0-9+/=]{24,}\b/gi;
8
+ var LONG_BASE64_TOKEN_RE = /\b[A-Za-z0-9+/]{80,}={0,2}\b/g;
9
+ var STRUCTURED_NOISE_MARKER_RE = /\b(?:tool[_-]?result|tool[_-]?use|toolcallid|tooluseid|function[_-]?(?:call|result)|stdout|stderr|exitcode|recordedat|trace(?:_|-)?id|parent(?:_|-)?id|session(?:_|-)?id|metadata|base64|mime(?:type)?)\b/i;
10
+ var NOISY_PREFIX_RE = /^(?:metadata|system metadata|session metadata)\s*:/i;
11
+ function normalizeToken(value) {
12
+ return value.trim().toLowerCase().replace(/[\s_-]+/g, "");
13
+ }
7
14
  function normalizeText(value) {
8
15
  return value.replace(/\s+/g, " ").trim();
9
16
  }
17
+ function shouldDropRole(role) {
18
+ const normalized = normalizeToken(role);
19
+ if (!normalized) {
20
+ return false;
21
+ }
22
+ if (normalized === "system" || normalized === "developer" || normalized === "metadata") {
23
+ return true;
24
+ }
25
+ return normalized.startsWith("tool");
26
+ }
27
+ function isConversationRolePrefix(role) {
28
+ const normalized = normalizeToken(role);
29
+ if (!normalized) {
30
+ return false;
31
+ }
32
+ if (normalized === "user" || normalized === "assistant" || normalized === "system") {
33
+ return true;
34
+ }
35
+ if (normalized === "developer" || normalized === "metadata") {
36
+ return true;
37
+ }
38
+ return normalized.startsWith("tool");
39
+ }
40
+ function isNoisyBlockType(value) {
41
+ if (typeof value !== "string") {
42
+ return false;
43
+ }
44
+ const normalized = normalizeToken(value);
45
+ if (!normalized || normalized === "text" || normalized === "markdown") {
46
+ return false;
47
+ }
48
+ return normalized.includes("tool") || normalized.includes("functioncall") || normalized.includes("functionresult") || normalized.includes("thinking") || normalized.includes("reason") || normalized.includes("metadata");
49
+ }
50
+ function stripNoisyData(value) {
51
+ return normalizeText(
52
+ value.replace(BASE64_DATA_URI_RE, " ").replace(LONG_BASE64_TOKEN_RE, " ")
53
+ );
54
+ }
55
+ function isLikelyStructuredNoise(value) {
56
+ const trimmed = value.trim();
57
+ if (!trimmed) {
58
+ return true;
59
+ }
60
+ if (NOISY_PREFIX_RE.test(trimmed)) {
61
+ return true;
62
+ }
63
+ const looksStructured = trimmed.startsWith("{") || trimmed.startsWith("[");
64
+ if (looksStructured && STRUCTURED_NOISE_MARKER_RE.test(trimmed) && trimmed.length >= 40) {
65
+ return true;
66
+ }
67
+ return false;
68
+ }
69
+ function sanitizeExtractedText(value) {
70
+ const stripped = stripNoisyData(value);
71
+ if (!stripped) {
72
+ return "";
73
+ }
74
+ if (isLikelyStructuredNoise(stripped)) {
75
+ return "";
76
+ }
77
+ return stripped;
78
+ }
79
+ function sanitizeParsedMessage(message) {
80
+ const normalized = normalizeText(message);
81
+ if (!normalized) {
82
+ return "";
83
+ }
84
+ const roleMatch = /^([a-z][a-z0-9_-]{1,31})\s*:\s*(.+)$/i.exec(normalized);
85
+ if (roleMatch && isConversationRolePrefix(roleMatch[1])) {
86
+ const role = normalizeRole(roleMatch[1]);
87
+ if (shouldDropRole(role)) {
88
+ return "";
89
+ }
90
+ const content = sanitizeExtractedText(roleMatch[2]);
91
+ if (!content) {
92
+ return "";
93
+ }
94
+ return role ? `${role}: ${content}` : content;
95
+ }
96
+ return sanitizeExtractedText(normalized);
97
+ }
10
98
  function extractText(value) {
11
99
  if (typeof value === "string") {
12
- return normalizeText(value);
100
+ return sanitizeExtractedText(value);
13
101
  }
14
102
  if (Array.isArray(value)) {
15
103
  const parts = [];
@@ -25,11 +113,17 @@ function extractText(value) {
25
113
  return "";
26
114
  }
27
115
  const record = value;
116
+ if (isNoisyBlockType(record.type)) {
117
+ return "";
118
+ }
28
119
  if (typeof record.text === "string") {
29
- return normalizeText(record.text);
120
+ return sanitizeExtractedText(record.text);
30
121
  }
31
122
  if (typeof record.content === "string") {
32
- return normalizeText(record.content);
123
+ return sanitizeExtractedText(record.content);
124
+ }
125
+ if (record.content !== void 0) {
126
+ return extractText(record.content);
33
127
  }
34
128
  return "";
35
129
  }
@@ -69,16 +163,18 @@ function parseJsonLine(line) {
69
163
  const entry = parsed;
70
164
  if ("role" in entry && "content" in entry) {
71
165
  const role = normalizeRole(entry.role);
166
+ if (shouldDropRole(role)) return "";
72
167
  const content = extractText(entry.content);
73
168
  if (!content) return "";
74
- return role ? `${role}: ${content}` : content;
169
+ return sanitizeParsedMessage(role ? `${role}: ${content}` : content);
75
170
  }
76
171
  if (entry.type === "message" && entry.message && typeof entry.message === "object") {
77
172
  const message = entry.message;
78
173
  const role = normalizeRole(message.role);
174
+ if (shouldDropRole(role)) return "";
79
175
  const content = extractText(message.content);
80
176
  if (!content) return "";
81
- return role ? `${role}: ${content}` : content;
177
+ return sanitizeParsedMessage(role ? `${role}: ${content}` : content);
82
178
  }
83
179
  return "";
84
180
  }
@@ -119,17 +215,21 @@ function parseMarkdown(raw) {
119
215
  if (roleMatch) {
120
216
  const role = normalizeRole(roleMatch[1]);
121
217
  const content = normalizeText(roleMatch[2]);
122
- if (content) {
123
- messages.push(`${role}: ${content}`);
218
+ const parsed2 = sanitizeParsedMessage(`${role}: ${content}`);
219
+ if (parsed2) {
220
+ messages.push(parsed2);
124
221
  }
125
222
  continue;
126
223
  }
127
- messages.push(joined);
224
+ const parsed = sanitizeParsedMessage(joined);
225
+ if (parsed) {
226
+ messages.push(parsed);
227
+ }
128
228
  }
129
229
  return messages;
130
230
  }
131
231
  function parsePlainText(raw) {
132
- return raw.split(/\r?\n/).map((line) => normalizeText(line)).filter(Boolean);
232
+ return raw.split(/\r?\n/).map((line) => sanitizeParsedMessage(line)).filter(Boolean);
133
233
  }
134
234
  function detectSessionFormat(raw, filePath) {
135
235
  const nonEmptyLines = raw.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
@@ -163,10 +263,7 @@ function parseSessionFile(filePath) {
163
263
  const raw = fs.readFileSync(resolved, "utf-8");
164
264
  const format = detectSessionFormat(raw, resolved);
165
265
  if (format === "jsonl") {
166
- const parsed = parseJsonLines(raw);
167
- if (parsed.length > 0) {
168
- return parsed;
169
- }
266
+ return parseJsonLines(raw);
170
267
  }
171
268
  if (format === "markdown") {
172
269
  const parsed = parseMarkdown(raw);
@@ -1,14 +1,14 @@
1
- import {
2
- listConfig
3
- } from "./chunk-URXDAUVH.js";
4
1
  import {
5
2
  requestLlmCompletion,
6
3
  resolveLlmProvider
7
- } from "./chunk-YXQCA6B7.js";
4
+ } from "./chunk-DVOUSOR3.js";
5
+ import {
6
+ listConfig
7
+ } from "./chunk-AXSJIFOJ.js";
8
8
  import {
9
9
  getMemoryGraph,
10
10
  loadMemoryGraphIndex
11
- } from "./chunk-ZZA73MFY.js";
11
+ } from "./chunk-33DOSHTA.js";
12
12
 
13
13
  // src/commands/inject.ts
14
14
  import * as path2 from "path";
@@ -470,6 +470,7 @@ async function addLlmIntentMatches(params) {
470
470
  provider: params.provider,
471
471
  prompt,
472
472
  model: params.model,
473
+ tier: "complex",
473
474
  temperature: 0.1,
474
475
  maxTokens: 1200,
475
476
  fetchImpl: params.fetchImpl,
@@ -14,7 +14,7 @@ function findProtectedRanges(content) {
14
14
  while ((match = codeBlockRegex.exec(content)) !== null) {
15
15
  ranges.push({ start: match.index, end: match.index + match[0].length });
16
16
  }
17
- const inlineCodeRegex = /`[^`]+`/g;
17
+ const inlineCodeRegex = /(?<!`)`[^`\n]+`(?!`)/g;
18
18
  while ((match = inlineCodeRegex.exec(content)) !== null) {
19
19
  ranges.push({ start: match.index, end: match.index + match[0].length });
20
20
  }
@@ -26,10 +26,51 @@ function findProtectedRanges(content) {
26
26
  while ((match = urlRegex.exec(content)) !== null) {
27
27
  ranges.push({ start: match.index, end: match.index + match[0].length });
28
28
  }
29
+ const filePathRegex = /(?:^|[\s([{"'])((?:~|\/)[^\s`<>\])}"']+|[A-Za-z]:\\[^\s`<>\])}"']+)/g;
30
+ while ((match = filePathRegex.exec(content)) !== null) {
31
+ const fullMatch = match[0];
32
+ const pathValue = match[1];
33
+ const start = match.index + fullMatch.indexOf(pathValue);
34
+ ranges.push({ start, end: start + pathValue.length });
35
+ }
29
36
  return ranges;
30
37
  }
31
- function isProtected(pos, ranges) {
32
- return ranges.some((r) => pos >= r.start && pos < r.end);
38
+ function isProtectedRange(start, end, ranges) {
39
+ return ranges.some((range) => start < range.end && end > range.start);
40
+ }
41
+ function createAliasRegex(alias) {
42
+ const escapedAlias = alias.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
43
+ return new RegExp(`\\b${escapedAlias}\\b`, "gi");
44
+ }
45
+ function formatWikiLink(path, originalText) {
46
+ return originalText.toLowerCase() === path.split("/").pop()?.toLowerCase() ? `[[${path}]]` : `[[${path}|${originalText}]]`;
47
+ }
48
+ function planLinks(content, index, protectedRanges) {
49
+ const sortedAliases = getSortedAliases(index);
50
+ const linkedEntities = /* @__PURE__ */ new Set();
51
+ const claimedRanges = [];
52
+ const plannedLinks = [];
53
+ for (const { alias, path } of sortedAliases) {
54
+ if (linkedEntities.has(path)) continue;
55
+ const regex = createAliasRegex(alias);
56
+ let match;
57
+ while ((match = regex.exec(content)) !== null) {
58
+ const start = match.index;
59
+ const end = start + match[0].length;
60
+ if (isProtectedRange(start, end, protectedRanges)) continue;
61
+ if (isProtectedRange(start, end, claimedRanges)) continue;
62
+ plannedLinks.push({
63
+ start,
64
+ end,
65
+ originalText: match[0],
66
+ path
67
+ });
68
+ claimedRanges.push({ start, end });
69
+ linkedEntities.add(path);
70
+ break;
71
+ }
72
+ }
73
+ return plannedLinks;
33
74
  }
34
75
  function createLineLookup(content) {
35
76
  const lines = content.split("\n");
@@ -48,56 +89,24 @@ function createLineLookup(content) {
48
89
  }
49
90
  function autoLink(content, index) {
50
91
  const protectedRanges = findProtectedRanges(content);
51
- const sortedAliases = getSortedAliases(index);
52
- const linkedEntities = /* @__PURE__ */ new Set();
92
+ const plannedLinks = planLinks(content, index, protectedRanges);
53
93
  let result = content;
54
- let offset = 0;
55
- for (const { alias, path } of sortedAliases) {
56
- if (linkedEntities.has(path)) continue;
57
- const escapedAlias = alias.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
58
- const regex = new RegExp(`\\b${escapedAlias}\\b`, "gi");
59
- let match;
60
- while ((match = regex.exec(content)) !== null) {
61
- const originalPos = match.index;
62
- const adjustedPos = originalPos + offset;
63
- if (isProtected(originalPos, protectedRanges)) continue;
64
- const beforeMatch = result.substring(0, adjustedPos);
65
- const openBrackets = (beforeMatch.match(/\[\[/g) || []).length;
66
- const closeBrackets = (beforeMatch.match(/\]\]/g) || []).length;
67
- if (openBrackets > closeBrackets) continue;
68
- const originalText = match[0];
69
- const replacement = originalText.toLowerCase() === path.split("/").pop()?.toLowerCase() ? `[[${path}]]` : `[[${path}|${originalText}]]`;
70
- result = result.substring(0, adjustedPos) + replacement + result.substring(adjustedPos + originalText.length);
71
- offset += replacement.length - originalText.length;
72
- linkedEntities.add(path);
73
- break;
74
- }
94
+ const sortedByPosition = plannedLinks.slice().sort((a, b) => b.start - a.start);
95
+ for (const planned of sortedByPosition) {
96
+ const replacement = formatWikiLink(planned.path, planned.originalText);
97
+ result = result.substring(0, planned.start) + replacement + result.substring(planned.end);
75
98
  }
76
99
  return result;
77
100
  }
78
101
  function dryRunLink(content, index) {
79
102
  const protectedRanges = findProtectedRanges(content);
80
- const sortedAliases = getSortedAliases(index);
81
- const linkedEntities = /* @__PURE__ */ new Set();
82
- const matches = [];
103
+ const plannedLinks = planLinks(content, index, protectedRanges);
83
104
  const getLineNumber = createLineLookup(content);
84
- for (const { alias, path } of sortedAliases) {
85
- if (linkedEntities.has(path)) continue;
86
- const escapedAlias = alias.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
87
- const regex = new RegExp(`\\b${escapedAlias}\\b`, "gi");
88
- let match;
89
- while ((match = regex.exec(content)) !== null) {
90
- if (isProtected(match.index, protectedRanges)) continue;
91
- matches.push({
92
- alias: match[0],
93
- path,
94
- line: getLineNumber(match.index)
95
- });
96
- linkedEntities.add(path);
97
- break;
98
- }
99
- }
100
- return matches;
105
+ return plannedLinks.map((planned) => ({
106
+ alias: planned.originalText,
107
+ path: planned.path,
108
+ line: getLineNumber(planned.start)
109
+ }));
101
110
  }
102
111
  function findUnlinkedMentions(content, index) {
103
112
  const protectedRanges = findProtectedRanges(content);
@@ -111,7 +120,9 @@ function findUnlinkedMentions(content, index) {
111
120
  const regex = new RegExp(`\\b${escapedAlias}\\b`, "gi");
112
121
  let match;
113
122
  while ((match = regex.exec(content)) !== null) {
114
- if (isProtected(match.index, protectedRanges)) continue;
123
+ const start = match.index;
124
+ const end = start + match[0].length;
125
+ if (isProtectedRange(start, end, protectedRanges)) continue;
115
126
  matches.push({
116
127
  alias: match[0],
117
128
  path,