@j0hanz/superfetch 2.2.1 → 2.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/README.md +243 -494
- package/dist/cache.d.ts +2 -3
- package/dist/cache.js +51 -241
- package/dist/config.d.ts +6 -1
- package/dist/config.js +29 -34
- package/dist/crypto.d.ts +0 -1
- package/dist/crypto.js +0 -1
- package/dist/dom-noise-removal.d.ts +5 -0
- package/dist/dom-noise-removal.js +485 -0
- package/dist/errors.d.ts +0 -1
- package/dist/errors.js +8 -6
- package/dist/fetch.d.ts +0 -1
- package/dist/fetch.js +71 -61
- package/dist/host-normalization.d.ts +1 -0
- package/dist/host-normalization.js +47 -0
- package/dist/http-native.d.ts +5 -0
- package/dist/http-native.js +693 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +1 -2
- package/dist/instructions.md +22 -20
- package/dist/json.d.ts +1 -0
- package/dist/json.js +29 -0
- package/dist/language-detection.d.ts +12 -0
- package/dist/language-detection.js +291 -0
- package/dist/markdown-cleanup.d.ts +18 -0
- package/dist/markdown-cleanup.js +283 -0
- package/dist/mcp-validator.d.ts +14 -0
- package/dist/mcp-validator.js +22 -0
- package/dist/mcp.d.ts +0 -1
- package/dist/mcp.js +0 -1
- package/dist/observability.d.ts +1 -1
- package/dist/observability.js +15 -3
- package/dist/server-tuning.d.ts +9 -0
- package/dist/server-tuning.js +30 -0
- package/dist/session.d.ts +36 -0
- package/dist/session.js +159 -0
- package/dist/tools.d.ts +0 -1
- package/dist/tools.js +23 -33
- package/dist/transform-types.d.ts +80 -0
- package/dist/transform-types.js +5 -0
- package/dist/transform.d.ts +7 -53
- package/dist/transform.js +434 -856
- package/dist/type-guards.d.ts +1 -2
- package/dist/type-guards.js +1 -2
- package/dist/workers/transform-worker.d.ts +0 -1
- package/dist/workers/transform-worker.js +52 -43
- package/package.json +11 -12
- package/dist/cache.d.ts.map +0 -1
- package/dist/cache.js.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/crypto.d.ts.map +0 -1
- package/dist/crypto.js.map +0 -1
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js.map +0 -1
- package/dist/fetch.d.ts.map +0 -1
- package/dist/fetch.js.map +0 -1
- package/dist/http.d.ts +0 -90
- package/dist/http.d.ts.map +0 -1
- package/dist/http.js +0 -1576
- package/dist/http.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/mcp.d.ts.map +0 -1
- package/dist/mcp.js.map +0 -1
- package/dist/observability.d.ts.map +0 -1
- package/dist/observability.js.map +0 -1
- package/dist/tools.d.ts.map +0 -1
- package/dist/tools.js.map +0 -1
- package/dist/transform.d.ts.map +0 -1
- package/dist/transform.js.map +0 -1
- package/dist/type-guards.d.ts.map +0 -1
- package/dist/type-guards.js.map +0 -1
- package/dist/workers/transform-worker.d.ts.map +0 -1
- package/dist/workers/transform-worker.js.map +0 -1
package/dist/instructions.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# superFetch Instructions
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Guidance for the Agent: These instructions are available as a resource (`internal://instructions`) or prompt (`get-help`). Load them when you are unsure about tool usage.
|
|
4
4
|
|
|
5
5
|
## 1. Core Capability
|
|
6
6
|
|
|
@@ -9,31 +9,33 @@
|
|
|
9
9
|
|
|
10
10
|
## 2. The "Golden Path" Workflows (Critical)
|
|
11
11
|
|
|
12
|
+
_Describe the standard order of operations using ONLY tools that exist._
|
|
13
|
+
|
|
12
14
|
### Workflow A: Fetch and Read
|
|
13
15
|
|
|
14
|
-
1. Call `fetch-url` with
|
|
15
|
-
2. Read `structuredContent.markdown` and `structuredContent.title
|
|
16
|
-
3.
|
|
16
|
+
1. Call `fetch-url` with `url`.
|
|
17
|
+
2. Read `structuredContent.markdown` and `structuredContent.title` from the result.
|
|
18
|
+
3. If content is truncated (look for `...[truncated]`), follow the returned `resource_link` URI.
|
|
19
|
+
> Constraint: Never guess resource URIs. Use the returned `resource_link` or list resources first.
|
|
20
|
+
|
|
21
|
+
### Workflow B: Retrieve Cached Content
|
|
17
22
|
|
|
18
|
-
|
|
23
|
+
1. List resources to find available cached pages (`superfetch://cache/...`).
|
|
24
|
+
2. Read the specific `superfetch://cache/markdown/{urlHash}` URI.
|
|
19
25
|
|
|
20
|
-
|
|
21
|
-
2. If content is missing, list resources and select the matching `superfetch://cache/markdown/{urlHash}` entry.
|
|
22
|
-
> **Constraint:** Never guess resource URIs. Use the returned `resource_link` or list resources first.
|
|
26
|
+
## 3. Tool Nuances & Gotchas
|
|
23
27
|
|
|
24
|
-
|
|
28
|
+
_Do NOT repeat JSON schema. Focus on behavior and pitfalls._
|
|
25
29
|
|
|
26
|
-
- **`fetch-url
|
|
27
|
-
- **
|
|
28
|
-
- **
|
|
29
|
-
- **
|
|
30
|
-
- **
|
|
31
|
-
- **
|
|
32
|
-
- **Namespace:** Only `markdown` is valid.
|
|
33
|
-
- **Discovery:** Use resource listing or the `resource_link` returned by `fetch-url`.
|
|
30
|
+
- **`fetch-url`**
|
|
31
|
+
- **Purpose:** Fetches a webpage and converts it to clean Markdown format.
|
|
32
|
+
- **Inputs:** `url` (Must be public http/https. Private patterns like localhost/127.0.0.1 are blocked).
|
|
33
|
+
- **Side effects:** Open world network request; writes to internal LRU cache.
|
|
34
|
+
- **Latency/limits:** Network-bound. Large content exceeds inline limits and returns a `resource_link`.
|
|
35
|
+
- **Common failure modes:** `VALIDATION_ERROR` (private/blocked URL), `FETCH_ERROR` (network timeout/404).
|
|
34
36
|
|
|
35
37
|
## 4. Error Handling Strategy
|
|
36
38
|
|
|
37
|
-
- **`VALIDATION_ERROR`**:
|
|
38
|
-
- **`FETCH_ERROR`**:
|
|
39
|
-
- **
|
|
39
|
+
- **`VALIDATION_ERROR`**: Ensure the URL is valid and publicly accessible.
|
|
40
|
+
- **`FETCH_ERROR`**: Retry once. If persistent, the site may be blocking automated requests.
|
|
41
|
+
- **Truncation**: If `isError` is false but content ends in `...[truncated]`, you MUST read the provided `resource_link` URI to get the full markdown.
|
package/dist/json.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function stableStringify(obj: unknown, depth?: number, seen?: WeakSet<object>): string;
|
package/dist/json.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const MAX_DEPTH = 20;
|
|
2
|
+
function processValue(obj, depth, seen) {
|
|
3
|
+
if (typeof obj !== 'object' || obj === null) {
|
|
4
|
+
return obj;
|
|
5
|
+
}
|
|
6
|
+
// Depth guard
|
|
7
|
+
if (depth > MAX_DEPTH) {
|
|
8
|
+
throw new Error(`stableStringify: Max depth (${MAX_DEPTH}) exceeded`);
|
|
9
|
+
}
|
|
10
|
+
// Cycle detection
|
|
11
|
+
if (seen.has(obj)) {
|
|
12
|
+
throw new Error('stableStringify: Circular reference detected');
|
|
13
|
+
}
|
|
14
|
+
seen.add(obj);
|
|
15
|
+
if (Array.isArray(obj)) {
|
|
16
|
+
return obj.map((item) => processValue(item, depth + 1, seen));
|
|
17
|
+
}
|
|
18
|
+
const keys = Object.keys(obj).sort((a, b) => a.localeCompare(b));
|
|
19
|
+
const record = obj;
|
|
20
|
+
const sortedObj = {};
|
|
21
|
+
for (const key of keys) {
|
|
22
|
+
sortedObj[key] = processValue(record[key], depth + 1, seen);
|
|
23
|
+
}
|
|
24
|
+
return sortedObj;
|
|
25
|
+
}
|
|
26
|
+
export function stableStringify(obj, depth = 0, seen = new WeakSet()) {
|
|
27
|
+
const processed = processValue(obj, depth, seen);
|
|
28
|
+
return JSON.stringify(processed);
|
|
29
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Language detection for code blocks.
|
|
3
|
+
* Detects programming languages from code content and HTML attributes.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Detect programming language from code content using heuristics.
|
|
7
|
+
*/
|
|
8
|
+
export declare function detectLanguageFromCode(code: string): string | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Resolve language from HTML attributes (class name and data-language).
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolveLanguageFromAttributes(className: string, dataLang: string): string | undefined;
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Language detection for code blocks.
|
|
3
|
+
* Detects programming languages from code content and HTML attributes.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Check if source contains the given word as a standalone word (not part of another word).
|
|
7
|
+
*/
|
|
8
|
+
function containsWord(source, word) {
|
|
9
|
+
return getWordRegex(word).test(source);
|
|
10
|
+
}
|
|
11
|
+
const WORD_REGEX_CACHE = new Map();
|
|
12
|
+
function getWordRegex(word) {
|
|
13
|
+
const cached = WORD_REGEX_CACHE.get(word);
|
|
14
|
+
if (cached)
|
|
15
|
+
return cached;
|
|
16
|
+
const compiled = new RegExp(`\\b${word}\\b`);
|
|
17
|
+
WORD_REGEX_CACHE.set(word, compiled);
|
|
18
|
+
return compiled;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Extract language from class name (e.g., "language-typescript", "lang-js", "hljs javascript").
|
|
22
|
+
*/
|
|
23
|
+
function extractLanguageFromClassName(className) {
|
|
24
|
+
const tokens = className.match(/\S+/g);
|
|
25
|
+
if (!tokens)
|
|
26
|
+
return undefined;
|
|
27
|
+
for (const token of tokens) {
|
|
28
|
+
const lower = token.toLowerCase();
|
|
29
|
+
if (lower.startsWith('language-'))
|
|
30
|
+
return token.slice('language-'.length);
|
|
31
|
+
if (lower.startsWith('lang-'))
|
|
32
|
+
return token.slice('lang-'.length);
|
|
33
|
+
if (lower.startsWith('highlight-')) {
|
|
34
|
+
return token.slice('highlight-'.length);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (tokens.includes('hljs')) {
|
|
38
|
+
const langClass = tokens.find((t) => t !== 'hljs' && !t.startsWith('hljs-'));
|
|
39
|
+
if (langClass)
|
|
40
|
+
return langClass;
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Resolve language from data-language attribute.
|
|
46
|
+
* Only allows word characters (alphanumeric + underscore).
|
|
47
|
+
*/
|
|
48
|
+
function resolveLanguageFromDataAttribute(dataLang) {
|
|
49
|
+
const trimmed = dataLang.trim();
|
|
50
|
+
if (!trimmed)
|
|
51
|
+
return undefined;
|
|
52
|
+
// Allow only word characters (letters, digits, underscore)
|
|
53
|
+
return /^\w+$/.test(trimmed) ? trimmed : undefined;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Check if code contains JSX-style tags (tags starting with uppercase like <Component>).
|
|
57
|
+
*/
|
|
58
|
+
function containsJsxTag(code) {
|
|
59
|
+
for (let index = 0; index < code.length - 1; index += 1) {
|
|
60
|
+
if (code[index] !== '<')
|
|
61
|
+
continue;
|
|
62
|
+
const next = code[index + 1];
|
|
63
|
+
if (!next)
|
|
64
|
+
continue;
|
|
65
|
+
if (next >= 'A' && next <= 'Z')
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
// Bash detection constants
|
|
71
|
+
const BASH_COMMANDS = ['sudo', 'chmod', 'mkdir', 'cd', 'ls', 'cat', 'echo'];
|
|
72
|
+
const BASH_PKG_MANAGERS = [
|
|
73
|
+
'npm',
|
|
74
|
+
'yarn',
|
|
75
|
+
'pnpm',
|
|
76
|
+
'npx',
|
|
77
|
+
'brew',
|
|
78
|
+
'apt',
|
|
79
|
+
'pip',
|
|
80
|
+
'cargo',
|
|
81
|
+
'go',
|
|
82
|
+
];
|
|
83
|
+
const BASH_VERBS = ['install', 'add', 'run', 'build', 'start'];
|
|
84
|
+
function isShellPrefix(line) {
|
|
85
|
+
return (line.startsWith('#!') || line.startsWith('$ ') || line.startsWith('# '));
|
|
86
|
+
}
|
|
87
|
+
function matchesBashCommand(line) {
|
|
88
|
+
return BASH_COMMANDS.some((cmd) => line === cmd || line.startsWith(`${cmd} `));
|
|
89
|
+
}
|
|
90
|
+
function matchesPackageManagerVerb(line) {
|
|
91
|
+
for (const mgr of BASH_PKG_MANAGERS) {
|
|
92
|
+
if (!line.startsWith(`${mgr} `))
|
|
93
|
+
continue;
|
|
94
|
+
const rest = line.slice(mgr.length + 1);
|
|
95
|
+
if (BASH_VERBS.some((v) => rest === v || rest.startsWith(`${v} `))) {
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
function detectBashIndicators(code) {
|
|
102
|
+
for (const line of code.split('\n')) {
|
|
103
|
+
const trimmed = line.trimStart();
|
|
104
|
+
if (trimmed &&
|
|
105
|
+
(isShellPrefix(trimmed) ||
|
|
106
|
+
matchesBashCommand(trimmed) ||
|
|
107
|
+
matchesPackageManagerVerb(trimmed))) {
|
|
108
|
+
return true;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
function detectCssStructure(code) {
|
|
114
|
+
for (const line of code.split('\n')) {
|
|
115
|
+
const trimmed = line.trimStart();
|
|
116
|
+
if (!trimmed)
|
|
117
|
+
continue;
|
|
118
|
+
const hasSelector = (trimmed.startsWith('.') || trimmed.startsWith('#')) &&
|
|
119
|
+
trimmed.includes('{');
|
|
120
|
+
if (hasSelector || (trimmed.includes(':') && trimmed.includes(';'))) {
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
function detectYamlStructure(code) {
|
|
127
|
+
for (const line of code.split('\n')) {
|
|
128
|
+
const trimmed = line.trim();
|
|
129
|
+
if (!trimmed)
|
|
130
|
+
continue;
|
|
131
|
+
const colonIdx = trimmed.indexOf(':');
|
|
132
|
+
if (colonIdx > 0) {
|
|
133
|
+
const after = trimmed[colonIdx + 1];
|
|
134
|
+
if (after === ' ' || after === '\t')
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Language detection patterns in priority order.
|
|
142
|
+
*/
|
|
143
|
+
const LANGUAGE_PATTERNS = [
|
|
144
|
+
{
|
|
145
|
+
language: 'jsx',
|
|
146
|
+
pattern: {
|
|
147
|
+
keywords: ['classname=', 'jsx:', "from 'react'", 'from "react"'],
|
|
148
|
+
custom: (code) => containsJsxTag(code),
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
language: 'typescript',
|
|
153
|
+
pattern: {
|
|
154
|
+
wordBoundary: ['interface', 'type'],
|
|
155
|
+
custom: (_, lower) => [
|
|
156
|
+
': string',
|
|
157
|
+
':string',
|
|
158
|
+
': number',
|
|
159
|
+
':number',
|
|
160
|
+
': boolean',
|
|
161
|
+
':boolean',
|
|
162
|
+
': void',
|
|
163
|
+
':void',
|
|
164
|
+
': any',
|
|
165
|
+
':any',
|
|
166
|
+
': unknown',
|
|
167
|
+
':unknown',
|
|
168
|
+
': never',
|
|
169
|
+
':never',
|
|
170
|
+
].some((hint) => lower.includes(hint)),
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
language: 'rust',
|
|
175
|
+
pattern: {
|
|
176
|
+
regex: /\b(?:fn|impl|struct|enum)\b/,
|
|
177
|
+
keywords: ['let mut'],
|
|
178
|
+
custom: (_, lower) => lower.includes('use ') && lower.includes('::'),
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
language: 'javascript',
|
|
183
|
+
pattern: {
|
|
184
|
+
regex: /\b(?:const|let|var|function|class|async|await|export|import)\b/,
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
language: 'python',
|
|
189
|
+
pattern: {
|
|
190
|
+
regex: /\b(?:def|class|import|from)\b/,
|
|
191
|
+
keywords: ['print(', '__name__'],
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
language: 'bash',
|
|
196
|
+
pattern: {
|
|
197
|
+
custom: (code) => detectBashIndicators(code),
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
language: 'css',
|
|
202
|
+
pattern: {
|
|
203
|
+
regex: /@media|@import|@keyframes/,
|
|
204
|
+
custom: (code) => detectCssStructure(code),
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
language: 'html',
|
|
209
|
+
pattern: {
|
|
210
|
+
keywords: [
|
|
211
|
+
'<!doctype',
|
|
212
|
+
'<html',
|
|
213
|
+
'<head',
|
|
214
|
+
'<body',
|
|
215
|
+
'<div',
|
|
216
|
+
'<span',
|
|
217
|
+
'<p',
|
|
218
|
+
'<a',
|
|
219
|
+
'<script',
|
|
220
|
+
'<style',
|
|
221
|
+
],
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
language: 'json',
|
|
226
|
+
pattern: {
|
|
227
|
+
startsWith: ['{', '['],
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
language: 'yaml',
|
|
232
|
+
pattern: {
|
|
233
|
+
custom: (code) => detectYamlStructure(code),
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
language: 'sql',
|
|
238
|
+
pattern: {
|
|
239
|
+
wordBoundary: [
|
|
240
|
+
'select',
|
|
241
|
+
'insert',
|
|
242
|
+
'update',
|
|
243
|
+
'delete',
|
|
244
|
+
'create',
|
|
245
|
+
'alter',
|
|
246
|
+
'drop',
|
|
247
|
+
],
|
|
248
|
+
},
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
language: 'go',
|
|
252
|
+
pattern: {
|
|
253
|
+
wordBoundary: ['package', 'func'],
|
|
254
|
+
keywords: ['import "'],
|
|
255
|
+
},
|
|
256
|
+
},
|
|
257
|
+
];
|
|
258
|
+
function matchesLanguagePattern(code, lower, pattern) {
|
|
259
|
+
if (pattern.keywords?.some((kw) => lower.includes(kw)))
|
|
260
|
+
return true;
|
|
261
|
+
if (pattern.wordBoundary?.some((w) => containsWord(lower, w)))
|
|
262
|
+
return true;
|
|
263
|
+
if (pattern.regex?.test(lower))
|
|
264
|
+
return true;
|
|
265
|
+
if (pattern.startsWith) {
|
|
266
|
+
const trimmed = code.trimStart();
|
|
267
|
+
if (pattern.startsWith.some((prefix) => trimmed.startsWith(prefix)))
|
|
268
|
+
return true;
|
|
269
|
+
}
|
|
270
|
+
if (pattern.custom?.(code, lower))
|
|
271
|
+
return true;
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Detect programming language from code content using heuristics.
|
|
276
|
+
*/
|
|
277
|
+
export function detectLanguageFromCode(code) {
|
|
278
|
+
const lower = code.toLowerCase();
|
|
279
|
+
for (const { language, pattern } of LANGUAGE_PATTERNS) {
|
|
280
|
+
if (matchesLanguagePattern(code, lower, pattern))
|
|
281
|
+
return language;
|
|
282
|
+
}
|
|
283
|
+
return undefined;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Resolve language from HTML attributes (class name and data-language).
|
|
287
|
+
*/
|
|
288
|
+
export function resolveLanguageFromAttributes(className, dataLang) {
|
|
289
|
+
const classMatch = extractLanguageFromClassName(className);
|
|
290
|
+
return classMatch ?? resolveLanguageFromDataAttribute(dataLang);
|
|
291
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown cleanup utilities for post-processing converted content.
|
|
3
|
+
*
|
|
4
|
+
* Goals:
|
|
5
|
+
* - Never mutate fenced code blocks (``` / ~~~) content.
|
|
6
|
+
* - Keep rules localized and readable.
|
|
7
|
+
* - Avoid multi-pass regexes that accidentally hit code blocks.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Clean up common markdown artifacts and formatting issues.
|
|
11
|
+
* IMPORTANT: All rules are applied ONLY outside fenced code blocks.
|
|
12
|
+
*/
|
|
13
|
+
export declare function cleanupMarkdownArtifacts(content: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Promote standalone lines that look like headings to proper markdown headings.
|
|
16
|
+
* Fence-aware: never modifies content inside fenced code blocks.
|
|
17
|
+
*/
|
|
18
|
+
export declare function promoteOrphanHeadings(markdown: string): string;
|