wiki-formant 0.63.1 → 0.65.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 +1 -1
- package/dist/base.css +24 -2
- package/dist/blocks.js +1 -6
- package/dist/category.d.ts +0 -4
- package/dist/combobox.js +1 -3
- package/dist/conformance.d.ts +2 -2
- package/dist/conformance.js +9 -9
- package/dist/crawlers.js +1 -5
- package/dist/headings.js +1 -8
- package/dist/maintenance.d.ts +4 -3
- package/dist/maps.js +7 -1
- package/dist/markdown.d.ts +5 -0
- package/dist/markdown.js +33 -19
- package/dist/mcp.d.ts +16 -0
- package/dist/mcp.js +59 -69
- package/dist/pagination.d.ts +0 -17
- package/dist/pagination.js +0 -19
- package/dist/react-server.d.ts +0 -34
- package/dist/react-server.js +0 -17
- package/dist/stats-figures.d.ts +1 -0
- package/dist/stats-figures.js +1 -1
- package/dist/stats.js +1 -2
- package/dist/taxonomy.js +5 -1
- package/dist/tiptap.d.ts +0 -1
- package/dist/tiptap.js +0 -1
- package/dist/validation.js +1 -1
- package/dist/versioning.d.ts +0 -1
- package/dist/versioning.js +0 -5
- package/dist/well-known.d.ts +1 -0
- package/dist/well-known.js +2 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1028,7 +1028,7 @@ the site's stylesheet gives them and the box a look.
|
|
|
1028
1028
|
|
|
1029
1029
|
## Base stylesheet
|
|
1030
1030
|
|
|
1031
|
-
`wiki-formant/base.css` is the layout the package's markup does not work without, and nothing else: columns that stack until there is room, stored tab panels that show one at a time, a copy button pinned to its block's corner and visible on focus and on touch, a table's scroll box, the stats block's grid, the code-tab strip, the banner's row and the infobox's wrapping, the breadcrumb row, the `aria-sort` arrow as a mask over `currentColor`, the stats page's grid and bars, and the chart's height and pinned buttons. It also carries the shape and motion of the primitives every site re-implemented and forked — `.spinner` (a `currentColor` ring sized by `--spinner-size`), `.skeleton`'s pulse, `.empty-state`, the wrap rule for long tokens in inline `code` — and the reduced-motion guard none of them had. No colour and no scale, so a design system's own rules override it at equal specificity.
|
|
1031
|
+
`wiki-formant/base.css` is the layout the package's markup does not work without, and nothing else: columns that stack until there is room, stored tab panels that show one at a time, a copy button pinned to its block's corner and visible on focus and on touch, a table's scroll box, the stats block's grid, the code-tab strip, the banner's row and the infobox's wrapping, the breadcrumb row, the `aria-sort` arrow as a mask over `currentColor`, the stats page's grid and bars, and the chart's height and pinned buttons. It also carries the shape and motion of the primitives every site re-implemented and forked — `.spinner` (a `currentColor` ring sized by `--spinner-size`), `.skeleton`'s pulse, `.empty-state`, the wrap rule for long tokens in inline `code` — and the reduced-motion guard none of them had. No colour and no scale, so a design system's own rules override it at equal specificity. The one set of tokens it declares is the page frame every site lays out by: `--content-width` (72rem, gutters inside), `--sidebar-width` (18rem) and `--page-pad` (16 / 24 / 32px at base / 640 / 1024). They sit in the components layer, so a site never restates them in `@theme`, which would lose; an element that must differ sets its own.
|
|
1032
1032
|
|
|
1033
1033
|
```css
|
|
1034
1034
|
@import "wiki-formant/base.css" layer(components);
|
package/dist/base.css
CHANGED
|
@@ -11,6 +11,25 @@
|
|
|
11
11
|
panel showed at once; one never received the utility classes ColumnsView
|
|
12
12
|
used to emit, so two of its four alignments did nothing. */
|
|
13
13
|
|
|
14
|
+
/* ---- the page frame ---------------------------------------------------------
|
|
15
|
+
The three numbers every site's page is laid out by, and the one exception to
|
|
16
|
+
"no design token": they are the frame, not a look, and four sites restating
|
|
17
|
+
them is how one of them came to draw an 80rem page while the rest drew 72.
|
|
18
|
+
The column is 72rem with its gutters inside it, the rail 18rem, and the
|
|
19
|
+
gutter 16 / 24 / 32px at base / 640 / 1024, the header, column and footer
|
|
20
|
+
reading the same one so they line up. STRUCTURE.md D8 is the spec.
|
|
21
|
+
|
|
22
|
+
This file loads into the components layer, which outranks Tailwind's theme
|
|
23
|
+
layer: a site does not restate these in `@theme`, and one that must differ
|
|
24
|
+
sets the property on the element that differs. */
|
|
25
|
+
:root {
|
|
26
|
+
--content-width: 72rem;
|
|
27
|
+
--sidebar-width: 18rem;
|
|
28
|
+
--page-pad: 1rem;
|
|
29
|
+
}
|
|
30
|
+
@media (min-width: 40rem) { :root { --page-pad: 1.5rem; } }
|
|
31
|
+
@media (min-width: 64rem) { :root { --page-pad: 2rem; } }
|
|
32
|
+
|
|
14
33
|
/* ---- ColumnsView ----------------------------------------------------------
|
|
15
34
|
Stacked until there is room for a row. `data-gap` and `data-align` replace
|
|
16
35
|
the Tailwind utilities the view used to emit, which only reached a site whose
|
|
@@ -93,7 +112,7 @@
|
|
|
93
112
|
position: sticky;
|
|
94
113
|
top: var(--rail-top, 0px);
|
|
95
114
|
flex-shrink: 0;
|
|
96
|
-
width: var(--sidebar-width
|
|
115
|
+
width: var(--sidebar-width);
|
|
97
116
|
height: calc(100dvh - var(--rail-top, 0px));
|
|
98
117
|
overflow: hidden;
|
|
99
118
|
border-inline-end: var(--rail-border, none);
|
|
@@ -109,7 +128,7 @@ html[data-sidebar='closed'] .wiki-sidebar { width: 0; }
|
|
|
109
128
|
.wiki-sidebar__scroll {
|
|
110
129
|
display: flex;
|
|
111
130
|
flex-direction: column;
|
|
112
|
-
width: var(--sidebar-width
|
|
131
|
+
width: var(--sidebar-width);
|
|
113
132
|
height: 100%;
|
|
114
133
|
overflow-y: auto;
|
|
115
134
|
}
|
|
@@ -148,6 +167,9 @@ html[data-sidebar='closed'] .wiki-sidebar { width: 0; }
|
|
|
148
167
|
.code-tabs-btn { cursor: pointer; }
|
|
149
168
|
.editorial-banner { display: flex; }
|
|
150
169
|
.infobox { overflow-wrap: anywhere; }
|
|
170
|
+
/* A link grid's description is prose, so it stops at the site's measure: it
|
|
171
|
+
sits outside the article's prose box, and on radix.wiki ran 709px. */
|
|
172
|
+
.link-grid-group-description { max-width: var(--measure); }
|
|
151
173
|
.infobox-series { display: flex; flex-direction: column; }
|
|
152
174
|
.heading-anchor,
|
|
153
175
|
.ref-backlink,
|
package/dist/blocks.js
CHANGED
|
@@ -145,12 +145,7 @@ export async function mapBlockTreeAsync(blocks, map, shape) {
|
|
|
145
145
|
* so a code block inside an infobox shipped unhighlighted.
|
|
146
146
|
*/
|
|
147
147
|
export function someBlock(blocks, predicate, containers) {
|
|
148
|
-
return blocks.some(
|
|
149
|
-
const groups = containers(block);
|
|
150
|
-
if (!groups)
|
|
151
|
-
return predicate(block);
|
|
152
|
-
return groups.some(group => someBlock(group, predicate, containers));
|
|
153
|
-
});
|
|
148
|
+
return leafBlocks(blocks, containers).some(predicate);
|
|
154
149
|
}
|
|
155
150
|
// ---- the shared leaf renderers ----------------------------------------------
|
|
156
151
|
/**
|
package/dist/category.d.ts
CHANGED
|
@@ -58,7 +58,3 @@ export declare function categoryView<P extends FacetablePage & {
|
|
|
58
58
|
sortHref: (to: "title" | "recent") => string;
|
|
59
59
|
sections: CategorySection[];
|
|
60
60
|
}>;
|
|
61
|
-
export type CategoryView<P> = Awaited<ReturnType<typeof categoryView<P & FacetablePage & {
|
|
62
|
-
tagPath: string;
|
|
63
|
-
slug: string;
|
|
64
|
-
}>>>;
|
package/dist/combobox.js
CHANGED
|
@@ -10,9 +10,7 @@
|
|
|
10
10
|
// the attribute that announces the highlighted row as the reader arrows
|
|
11
11
|
// through it. A combobox without it is a text field that silently changes what
|
|
12
12
|
// Enter does.
|
|
13
|
-
/** The id of one option row
|
|
14
|
-
* highlighted row into view has to find it by the same id the input points at. */
|
|
15
|
-
/** @internal */
|
|
13
|
+
/** The id of one option row, which `aria-activedescendant` names. @internal */
|
|
16
14
|
export function optionId(baseId, listKey, index) {
|
|
17
15
|
return `${listId(baseId, listKey)}-opt-${index}`;
|
|
18
16
|
}
|
package/dist/conformance.d.ts
CHANGED
|
@@ -139,6 +139,8 @@ export declare function agentCardParity(t: Tester): Promise<void>;
|
|
|
139
139
|
* will pass is a check that measures nothing.
|
|
140
140
|
*/
|
|
141
141
|
export declare function conditionalGetChecks(t: Tester, paths: readonly string[]): Promise<void>;
|
|
142
|
+
/** The JSON descriptors every S10 origin serves: the two agent-card paths, the OpenAPI pair, the MCP manifest and the server card. */
|
|
143
|
+
export declare const S10_DESCRIPTORS: readonly string[];
|
|
142
144
|
/**
|
|
143
145
|
* A JSON descriptor is revalidatable — an agent card, an OpenAPI document, a
|
|
144
146
|
* registry manifest, a server card.
|
|
@@ -149,8 +151,6 @@ export declare function conditionalGetChecks(t: Tester, paths: readonly string[]
|
|
|
149
151
|
* document moving, which is worse than none. The body-derived ETag is the whole
|
|
150
152
|
* validator, and it is enough.
|
|
151
153
|
*/
|
|
152
|
-
/** The JSON descriptors every S10 origin serves: the two agent-card paths, the OpenAPI pair, the MCP manifest and the server card. */
|
|
153
|
-
export declare const S10_DESCRIPTORS: readonly string[];
|
|
154
154
|
export declare function descriptorChecks(t: Tester, paths?: readonly string[]): Promise<void>;
|
|
155
155
|
/**
|
|
156
156
|
* Documents that project one corpus at different depths carry different ETags.
|
package/dist/conformance.js
CHANGED
|
@@ -327,6 +327,15 @@ export async function conditionalGetChecks(t, paths) {
|
|
|
327
327
|
}
|
|
328
328
|
}
|
|
329
329
|
}
|
|
330
|
+
/** The JSON descriptors every S10 origin serves: the two agent-card paths, the OpenAPI pair, the MCP manifest and the server card. */
|
|
331
|
+
export const S10_DESCRIPTORS = [
|
|
332
|
+
'.well-known/agent-card.json',
|
|
333
|
+
'.well-known/agent.json',
|
|
334
|
+
'.well-known/openapi.json',
|
|
335
|
+
'openapi.json',
|
|
336
|
+
'.well-known/mcp.json',
|
|
337
|
+
'api/mcp/server-card',
|
|
338
|
+
];
|
|
330
339
|
/**
|
|
331
340
|
* A JSON descriptor is revalidatable — an agent card, an OpenAPI document, a
|
|
332
341
|
* registry manifest, a server card.
|
|
@@ -337,15 +346,6 @@ export async function conditionalGetChecks(t, paths) {
|
|
|
337
346
|
* document moving, which is worse than none. The body-derived ETag is the whole
|
|
338
347
|
* validator, and it is enough.
|
|
339
348
|
*/
|
|
340
|
-
/** The JSON descriptors every S10 origin serves: the two agent-card paths, the OpenAPI pair, the MCP manifest and the server card. */
|
|
341
|
-
export const S10_DESCRIPTORS = [
|
|
342
|
-
'.well-known/agent-card.json',
|
|
343
|
-
'.well-known/agent.json',
|
|
344
|
-
'.well-known/openapi.json',
|
|
345
|
-
'openapi.json',
|
|
346
|
-
'.well-known/mcp.json',
|
|
347
|
-
'api/mcp/server-card',
|
|
348
|
-
];
|
|
349
349
|
export async function descriptorChecks(t, paths = S10_DESCRIPTORS) {
|
|
350
350
|
for (const path of paths) {
|
|
351
351
|
const url = path.startsWith('http') ? path : `${t.base}/${path.replace(/^\//, '')}`;
|
package/dist/crawlers.js
CHANGED
|
@@ -53,10 +53,6 @@ export function detectAiBot(userAgent) {
|
|
|
53
53
|
}
|
|
54
54
|
return null;
|
|
55
55
|
}
|
|
56
|
-
/** Every token that needs its own robots.txt group — which is all of them. @internal */
|
|
57
|
-
export function aiCrawlerTokens() {
|
|
58
|
-
return AI_CRAWLERS.map(c => c.token);
|
|
59
|
-
}
|
|
60
56
|
/**
|
|
61
57
|
* The agent surface an S10 origin serves, allowed in every group. All three
|
|
62
58
|
* `robots.ts` files listed these by hand, and a path missing from one list is
|
|
@@ -110,7 +106,7 @@ export function crawlerRules(opts) {
|
|
|
110
106
|
// honestly as itself was told the endpoint was off limits. The roster is
|
|
111
107
|
// for indexing policy, not for hiding a documented endpoint.
|
|
112
108
|
{ userAgent: '*', allow: [...new Set([...[opts.allow].flat(), ...aiAllow])], disallow },
|
|
113
|
-
...
|
|
109
|
+
...AI_CRAWLERS.map(({ token: userAgent }) => ({ userAgent, allow: aiAllow, disallow })),
|
|
114
110
|
...SEARCH_ENGINES.map(userAgent => ({ userAgent, allow: '/', disallow: searchDisallow })),
|
|
115
111
|
];
|
|
116
112
|
}
|
package/dist/headings.js
CHANGED
|
@@ -79,14 +79,7 @@ export function injectHeadingIds(html, options = {}) {
|
|
|
79
79
|
* consumers use only the injector above.
|
|
80
80
|
*/
|
|
81
81
|
export function headingsFrom(html) {
|
|
82
|
-
|
|
83
|
-
for (const [, tag, attrs, content] of html.matchAll(HEADING)) {
|
|
84
|
-
const id = getAttr(attrs ?? '', 'id');
|
|
85
|
-
const text = stripTags(content ?? '');
|
|
86
|
-
if (id && text)
|
|
87
|
-
out.push({ id, text, level: Number(tag[1]) });
|
|
88
|
-
}
|
|
89
|
-
return out;
|
|
82
|
+
return headingOutline(html).filter(h => h.id);
|
|
90
83
|
}
|
|
91
84
|
/**
|
|
92
85
|
* Every heading in `html`, in document order, whether or not it carries an id —
|
package/dist/maintenance.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export type SourceListItem = string | {
|
|
|
3
3
|
name?: string;
|
|
4
4
|
url?: string;
|
|
5
5
|
};
|
|
6
|
-
|
|
6
|
+
interface SourceEntry {
|
|
7
7
|
lastChecked?: string | null;
|
|
8
8
|
note?: string;
|
|
9
9
|
list?: SourceListItem[];
|
|
@@ -13,11 +13,11 @@ export type BacklogEntry = string | {
|
|
|
13
13
|
item: string;
|
|
14
14
|
status?: string;
|
|
15
15
|
};
|
|
16
|
-
|
|
16
|
+
type FeedbackEntry = string | {
|
|
17
17
|
date?: string;
|
|
18
18
|
note: string;
|
|
19
19
|
};
|
|
20
|
-
|
|
20
|
+
interface RunEntry {
|
|
21
21
|
date?: string;
|
|
22
22
|
category?: string;
|
|
23
23
|
summary?: string;
|
|
@@ -55,3 +55,4 @@ export declare function render(state: LogState, routine: string, newId?: () => s
|
|
|
55
55
|
type: "content";
|
|
56
56
|
text: string;
|
|
57
57
|
}[];
|
|
58
|
+
export {};
|
package/dist/maps.js
CHANGED
|
@@ -54,7 +54,13 @@ export function toMapEmbedUrl(url) {
|
|
|
54
54
|
if (/google\.[a-z.]+\/maps/.test(url)) {
|
|
55
55
|
const place = url.match(/\/place\/([^/@]+)/);
|
|
56
56
|
if (place) {
|
|
57
|
-
|
|
57
|
+
// A stray `%` makes decodeURIComponent throw; the segment is then used as pasted.
|
|
58
|
+
let name = place[1];
|
|
59
|
+
try {
|
|
60
|
+
name = decodeURIComponent(name);
|
|
61
|
+
}
|
|
62
|
+
catch { }
|
|
63
|
+
const q = encodeURIComponent(name.replace(/\+/g, ' '));
|
|
58
64
|
return `https://maps.google.com/maps?q=${q}&output=embed`;
|
|
59
65
|
}
|
|
60
66
|
}
|
package/dist/markdown.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One pass, so a decoded `&` never starts a second entity (`&lt;` is the
|
|
3
|
+
* text `<`), and a numeric reference past U+10FFFF stays as written rather
|
|
4
|
+
* than throwing out of the twin's route.
|
|
5
|
+
*/
|
|
1
6
|
export declare function decodeEntities(s: string): string;
|
|
2
7
|
/** Inline-level HTML → markdown. Applied inside cells, list items, headings. */
|
|
3
8
|
export declare function inlineToMarkdown(html: string): string;
|
package/dist/markdown.js
CHANGED
|
@@ -37,11 +37,18 @@ const NAMED_ENTITIES = {
|
|
|
37
37
|
mu: 'μ', nu: 'ν', pi: 'π', rho: 'ρ', sigma: 'σ', tau: 'τ', phi: 'φ', omega: 'ω',
|
|
38
38
|
Delta: 'Δ', Sigma: 'Σ', Omega: 'Ω', Lambda: 'Λ', Phi: 'Φ', Pi: 'Π',
|
|
39
39
|
};
|
|
40
|
+
/**
|
|
41
|
+
* One pass, so a decoded `&` never starts a second entity (`&lt;` is the
|
|
42
|
+
* text `<`), and a numeric reference past U+10FFFF stays as written rather
|
|
43
|
+
* than throwing out of the twin's route.
|
|
44
|
+
*/
|
|
40
45
|
export function decodeEntities(s) {
|
|
41
|
-
return s
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
return s.replace(/&(?:#x([0-9a-fA-F]{1,6})|#(\d{1,7})|([a-zA-Z][a-zA-Z0-9]{1,9}));/g, (m, hex, dec, name) => {
|
|
47
|
+
if (name)
|
|
48
|
+
return NAMED_ENTITIES[name] ?? m;
|
|
49
|
+
const code = hex ? parseInt(hex, 16) : Number(dec);
|
|
50
|
+
return code <= 0x10ffff ? String.fromCodePoint(code) : m;
|
|
51
|
+
});
|
|
45
52
|
}
|
|
46
53
|
/** Inline-level HTML → markdown. Applied inside cells, list items, headings. */
|
|
47
54
|
export function inlineToMarkdown(html) {
|
|
@@ -71,7 +78,7 @@ export function tableToMarkdown(html) {
|
|
|
71
78
|
const pad = (r) => [...r, ...Array(width - r.length).fill('')];
|
|
72
79
|
// A table whose first row is all <th> has a header; otherwise synthesise an
|
|
73
80
|
// empty one, since GFM has no headerless table form.
|
|
74
|
-
const headed = /<th\b/i.test(html.slice(0, html.
|
|
81
|
+
const headed = /<th\b/i.test(html.slice(0, html.search(/<\/tr>/i) + 1));
|
|
75
82
|
const [head, ...body] = headed
|
|
76
83
|
? [pad(rows[0]), ...rows.slice(1).map(pad)]
|
|
77
84
|
: [Array(width).fill(''), ...rows.map(pad)];
|
|
@@ -83,6 +90,8 @@ export function tableToMarkdown(html) {
|
|
|
83
90
|
}
|
|
84
91
|
// The spaces either side go with it: at a block boundary they are not text.
|
|
85
92
|
const BLOCK_TOKEN = /[ \t]*\u0000(\d+)\u0000[ \t]*/g;
|
|
93
|
+
/** A list that holds no other list. */
|
|
94
|
+
const LIST = /<(ul|ol)\b[^>]*>((?:(?!<(?:ul|ol)\b)[\s\S])*?)<\/\1>/gi;
|
|
86
95
|
/** Block-level HTML → markdown. */
|
|
87
96
|
export function htmlToMarkdown(html) {
|
|
88
97
|
let out = html;
|
|
@@ -102,21 +111,26 @@ export function htmlToMarkdown(html) {
|
|
|
102
111
|
].join('\n');
|
|
103
112
|
// Tables first — their inner markup must not be eaten by the generic rules.
|
|
104
113
|
out = out.replace(/<table\b[^>]*>[\s\S]*?<\/table>/gi, m => block(tableToMarkdown(m)));
|
|
105
|
-
// Lists
|
|
106
|
-
//
|
|
107
|
-
// a
|
|
108
|
-
//
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
// Lists, innermost first: a list holding no other list converts, and the
|
|
115
|
+
// pass repeats until none is left, so a list nested in one of its own kind
|
|
116
|
+
// is a block before its parent reads it. A lazy match from the outer `<ul>`
|
|
117
|
+
// ended at the inner `</ul>` and ran both lists onto one line. `<ol>`
|
|
118
|
+
// numbering is computed per-list, which is why this cannot be a single regex
|
|
119
|
+
// with a `$1` backreference — inside a replace callback `$1` is a literal,
|
|
120
|
+
// not a substitution. (That exact bug shipped once and rendered every
|
|
121
|
+
// ordered list as a column of `1. $1`.)
|
|
122
|
+
for (let prev = ''; prev !== out;) {
|
|
123
|
+
prev = out;
|
|
124
|
+
out = out.replace(LIST, (_m, tag, body) => {
|
|
125
|
+
const ordered = tag.toLowerCase() === 'ol';
|
|
126
|
+
const items = [...body.matchAll(/<li\b[^>]*>([\s\S]*?)<\/li>/gi)].map((i, n) => listItem(ordered ? `${n + 1}.` : '-', i[1]));
|
|
127
|
+
return block(items.join('\n'));
|
|
128
|
+
});
|
|
129
|
+
}
|
|
117
130
|
out = out
|
|
118
|
-
.replace(
|
|
119
|
-
|
|
131
|
+
.replace(
|
|
132
|
+
// `<code>` is optional: a stored block may be `<pre><code>` or a bare `<pre>`.
|
|
133
|
+
/<pre\b[^>]*>\s*(?:<code\b[^>]*>)?([\s\S]*?)(?:<\/code>\s*)?<\/pre>/gi, (_m, code) => block(`\`\`\`\n${decodeEntities(code).trim()}\n\`\`\``))
|
|
120
134
|
.replace(/<blockquote\b[^>]*>([\s\S]*?)<\/blockquote>/gi, (_m, body) => block(inlineToMarkdown(body)
|
|
121
135
|
.split('\n')
|
|
122
136
|
.map(l => `> ${l}`)
|
package/dist/mcp.d.ts
CHANGED
|
@@ -105,6 +105,22 @@ export interface McpTool {
|
|
|
105
105
|
};
|
|
106
106
|
handler: (args: Record<string, unknown>, ctx: ToolContext) => Promise<unknown>;
|
|
107
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* A tool as every surface advertises it — `tools/list`, the agent card and
|
|
110
|
+
* `/.well-known/mcp.json`. The handler and the A2A skill stay behind.
|
|
111
|
+
*
|
|
112
|
+
* One projection because the two copies drifted: the manifest's had no
|
|
113
|
+
* `outputSchema`, so a descriptor said a tool answers with prose while
|
|
114
|
+
* `tools/list` said it answers with `structuredContent`.
|
|
115
|
+
*/
|
|
116
|
+
export declare function toolCard(tool: {
|
|
117
|
+
name: string;
|
|
118
|
+
title?: string;
|
|
119
|
+
description: string;
|
|
120
|
+
inputSchema: unknown;
|
|
121
|
+
outputSchema?: unknown;
|
|
122
|
+
annotations?: unknown;
|
|
123
|
+
}): Record<string, unknown>;
|
|
108
124
|
export interface McpResource {
|
|
109
125
|
uri: string;
|
|
110
126
|
name: string;
|
package/dist/mcp.js
CHANGED
|
@@ -67,6 +67,24 @@ function requestProtocol(request) {
|
|
|
67
67
|
/** JSON-RPC batching was removed in 2025-06-18 and stays removed; it is legal only below that. */
|
|
68
68
|
const allowsBatch = (v) => v === '2025-03-26' || v === '2024-11-05';
|
|
69
69
|
import { clientKey, rateLimit, rateLimitHeaders, withRateLimit } from './rate-limit.js';
|
|
70
|
+
/**
|
|
71
|
+
* A tool as every surface advertises it — `tools/list`, the agent card and
|
|
72
|
+
* `/.well-known/mcp.json`. The handler and the A2A skill stay behind.
|
|
73
|
+
*
|
|
74
|
+
* One projection because the two copies drifted: the manifest's had no
|
|
75
|
+
* `outputSchema`, so a descriptor said a tool answers with prose while
|
|
76
|
+
* `tools/list` said it answers with `structuredContent`.
|
|
77
|
+
*/
|
|
78
|
+
export function toolCard(tool) {
|
|
79
|
+
return {
|
|
80
|
+
name: tool.name,
|
|
81
|
+
...(tool.title ? { title: tool.title } : {}),
|
|
82
|
+
description: tool.description,
|
|
83
|
+
inputSchema: tool.inputSchema,
|
|
84
|
+
...(tool.outputSchema ? { outputSchema: tool.outputSchema } : {}),
|
|
85
|
+
...(tool.annotations ? { annotations: tool.annotations } : {}),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
70
88
|
/**
|
|
71
89
|
* A caller-fixable failure inside a handler (page not found, empty input).
|
|
72
90
|
* Reported as a tool result with `isError` so the model sees the text and can
|
|
@@ -151,6 +169,15 @@ function typeOf(v) {
|
|
|
151
169
|
return 'null';
|
|
152
170
|
return typeof v;
|
|
153
171
|
}
|
|
172
|
+
/** A JSON-RPC success envelope. The error twin is `rpcError` below. */
|
|
173
|
+
const ok = (id, result) => ({ jsonrpc: '2.0', id, result });
|
|
174
|
+
/**
|
|
175
|
+
* The -32602 a lookup miss answers with: what was asked for, then everything
|
|
176
|
+
* this server does expose, as prose one retry can act on.
|
|
177
|
+
*/
|
|
178
|
+
const notFound = (id, lead, kind, names, dataKey) => rpcError(id, -32602, `${lead} This server exposes: ${names.length ? quote(names) : `no ${kind}`}.`, {
|
|
179
|
+
[dataKey]: names,
|
|
180
|
+
});
|
|
154
181
|
const rpcError = (id, code, message, data) => ({
|
|
155
182
|
jsonrpc: '2.0',
|
|
156
183
|
id,
|
|
@@ -265,6 +292,13 @@ const capabilitiesOf = (config) => ({
|
|
|
265
292
|
...(config.prompts?.length ? { prompts: {} } : {}),
|
|
266
293
|
});
|
|
267
294
|
async function handleRpc(req, config, dispatch) {
|
|
295
|
+
// The body is the caller's JSON, typed or not: a `null` in a batch would
|
|
296
|
+
// throw here and take the whole response with it, CORS headers included.
|
|
297
|
+
const entry = req;
|
|
298
|
+
if (!entry || typeof entry !== 'object' || typeof entry.method !== 'string') {
|
|
299
|
+
const id = entry?.id;
|
|
300
|
+
return rpcError(typeof id === 'string' || typeof id === 'number' ? id : null, -32600, 'Invalid Request: expected a JSON-RPC object with a string "method".');
|
|
301
|
+
}
|
|
268
302
|
const { id, method, params } = req;
|
|
269
303
|
const p = (params ?? {});
|
|
270
304
|
const resources = config.resources ?? [];
|
|
@@ -277,104 +311,60 @@ async function handleRpc(req, config, dispatch) {
|
|
|
277
311
|
try {
|
|
278
312
|
switch (method) {
|
|
279
313
|
case 'initialize':
|
|
280
|
-
return {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
serverInfo: config.serverInfo,
|
|
287
|
-
instructions: config.instructions,
|
|
288
|
-
},
|
|
289
|
-
};
|
|
314
|
+
return ok(id, {
|
|
315
|
+
protocolVersion: negotiateProtocol(p.protocolVersion),
|
|
316
|
+
capabilities: capabilitiesOf(config),
|
|
317
|
+
serverInfo: config.serverInfo,
|
|
318
|
+
instructions: config.instructions,
|
|
319
|
+
});
|
|
290
320
|
// What `initialize` tells a legacy client, asked the modern way. The
|
|
291
321
|
// transport adds `resultType`, the cache hints and `_meta` serverInfo.
|
|
292
322
|
case 'server/discover':
|
|
293
|
-
return {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
capabilities: capabilitiesOf(config),
|
|
299
|
-
instructions: config.instructions,
|
|
300
|
-
},
|
|
301
|
-
};
|
|
323
|
+
return ok(id, {
|
|
324
|
+
supportedVersions: [...MCP_PROTOCOL_VERSIONS],
|
|
325
|
+
capabilities: capabilitiesOf(config),
|
|
326
|
+
instructions: config.instructions,
|
|
327
|
+
});
|
|
302
328
|
// Notifications have no response at all.
|
|
303
329
|
case 'notifications/initialized':
|
|
304
330
|
case 'notifications/cancelled':
|
|
305
331
|
return null;
|
|
306
332
|
case 'ping':
|
|
307
|
-
return
|
|
333
|
+
return ok(id, {});
|
|
308
334
|
case 'tools/list':
|
|
309
|
-
return {
|
|
310
|
-
jsonrpc: '2.0',
|
|
311
|
-
id,
|
|
312
|
-
result: {
|
|
313
|
-
tools: config.tools.map(({ name, title, description, inputSchema, outputSchema, annotations }) => ({
|
|
314
|
-
name,
|
|
315
|
-
...(title ? { title } : {}),
|
|
316
|
-
description,
|
|
317
|
-
inputSchema,
|
|
318
|
-
...(outputSchema ? { outputSchema } : {}),
|
|
319
|
-
...(annotations ? { annotations } : {}),
|
|
320
|
-
})),
|
|
321
|
-
},
|
|
322
|
-
};
|
|
335
|
+
return ok(id, { tools: config.tools.map(toolCard) });
|
|
323
336
|
case 'resources/list':
|
|
324
|
-
return {
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
result: {
|
|
328
|
-
resources: resources.map(({ uri, name, description, mimeType }) => ({
|
|
329
|
-
uri,
|
|
330
|
-
name,
|
|
331
|
-
description,
|
|
332
|
-
mimeType,
|
|
333
|
-
})),
|
|
334
|
-
},
|
|
335
|
-
};
|
|
337
|
+
return ok(id, {
|
|
338
|
+
resources: resources.map(({ uri, name, description, mimeType }) => ({ uri, name, description, mimeType })),
|
|
339
|
+
});
|
|
336
340
|
// Declared `resources` makes a client ask for templates too. There are
|
|
337
341
|
// none to give — every resource here is a fixed URI — but an empty list
|
|
338
342
|
// is the answer to that question, where -32601 reads as a broken server.
|
|
339
343
|
case 'resources/templates/list':
|
|
340
|
-
return
|
|
344
|
+
return ok(id, { resourceTemplates: [] });
|
|
341
345
|
case 'resources/read': {
|
|
342
346
|
const { uri } = p;
|
|
343
347
|
const resource = uri ? resources.find(r => r.uri === uri) : undefined;
|
|
344
348
|
const content = resource ? await resource.read() : null;
|
|
345
349
|
if (content == null) {
|
|
346
|
-
const uris = resources.map(r => r.uri);
|
|
347
350
|
const lead = uri ? `Unknown resource "${uri}".` : 'Missing "uri" in params.';
|
|
348
|
-
return
|
|
351
|
+
return notFound(id, lead, 'resources', resources.map(r => r.uri), 'availableResources');
|
|
349
352
|
}
|
|
350
|
-
return {
|
|
351
|
-
jsonrpc: '2.0',
|
|
352
|
-
id,
|
|
353
|
-
result: { contents: [{ uri, mimeType: resource.mimeType, text: content }] },
|
|
354
|
-
};
|
|
353
|
+
return ok(id, { contents: [{ uri, mimeType: resource.mimeType, text: content }] });
|
|
355
354
|
}
|
|
356
355
|
case 'prompts/list':
|
|
357
|
-
return {
|
|
358
|
-
jsonrpc: '2.0',
|
|
359
|
-
id,
|
|
360
|
-
result: { prompts: prompts.map(({ name, description }) => ({ name, description })) },
|
|
361
|
-
};
|
|
356
|
+
return ok(id, { prompts: prompts.map(({ name, description }) => ({ name, description })) });
|
|
362
357
|
case 'prompts/get': {
|
|
363
358
|
const { name } = p;
|
|
364
359
|
const prompt = name ? prompts.find(x => x.name === name) : undefined;
|
|
365
360
|
if (!prompt) {
|
|
366
|
-
const names = prompts.map(x => x.name);
|
|
367
361
|
const lead = name ? `Unknown prompt "${name}".` : 'Missing "name" in params.';
|
|
368
|
-
return
|
|
362
|
+
return notFound(id, lead, 'prompts', prompts.map(x => x.name), 'availablePrompts');
|
|
369
363
|
}
|
|
370
|
-
return {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
description: prompt.description,
|
|
375
|
-
messages: [{ role: 'user', content: { type: 'text', text: prompt.text } }],
|
|
376
|
-
},
|
|
377
|
-
};
|
|
364
|
+
return ok(id, {
|
|
365
|
+
description: prompt.description,
|
|
366
|
+
messages: [{ role: 'user', content: { type: 'text', text: prompt.text } }],
|
|
367
|
+
});
|
|
378
368
|
}
|
|
379
369
|
case 'tools/call': {
|
|
380
370
|
const { name, arguments: rawArgs = {} } = p;
|
package/dist/pagination.d.ts
CHANGED
|
@@ -42,20 +42,3 @@ export declare function listEnvelope<T>(pages: T[], total: number, page: number,
|
|
|
42
42
|
note?: string;
|
|
43
43
|
pages: T[];
|
|
44
44
|
};
|
|
45
|
-
/**
|
|
46
|
-
* The entries either side of the current one in an already-ordered list.
|
|
47
|
-
*
|
|
48
|
-
* The ordering is the caller's, deliberately — it is the one thing here that is
|
|
49
|
-
* never portable. A wiki's sequence is its section's configured sort, a
|
|
50
|
-
* knowledge base's is a taxonomy walk, and a company log's is `updatedAt` desc.
|
|
51
|
-
*
|
|
52
|
-
* `null` on both sides when the page is not in the list, so a page reached by a
|
|
53
|
-
* URL its own section does not list renders no nav rather than a wrong one.
|
|
54
|
-
*
|
|
55
|
-
* No query. Callers already hold the ordered siblings for something else, a
|
|
56
|
-
* related-pages panel or a section listing, so the neighbours cost no lookups.
|
|
57
|
-
*/
|
|
58
|
-
export declare function adjacentPages<T>(ordered: readonly T[], isCurrent: (page: T) => boolean): {
|
|
59
|
-
prev: T | null;
|
|
60
|
-
next: T | null;
|
|
61
|
-
};
|
package/dist/pagination.js
CHANGED
|
@@ -52,22 +52,3 @@ export function listEnvelope(pages, total, page, pageSize, emptyNote) {
|
|
|
52
52
|
pages,
|
|
53
53
|
};
|
|
54
54
|
}
|
|
55
|
-
/**
|
|
56
|
-
* The entries either side of the current one in an already-ordered list.
|
|
57
|
-
*
|
|
58
|
-
* The ordering is the caller's, deliberately — it is the one thing here that is
|
|
59
|
-
* never portable. A wiki's sequence is its section's configured sort, a
|
|
60
|
-
* knowledge base's is a taxonomy walk, and a company log's is `updatedAt` desc.
|
|
61
|
-
*
|
|
62
|
-
* `null` on both sides when the page is not in the list, so a page reached by a
|
|
63
|
-
* URL its own section does not list renders no nav rather than a wrong one.
|
|
64
|
-
*
|
|
65
|
-
* No query. Callers already hold the ordered siblings for something else, a
|
|
66
|
-
* related-pages panel or a section listing, so the neighbours cost no lookups.
|
|
67
|
-
*/
|
|
68
|
-
export function adjacentPages(ordered, isCurrent) {
|
|
69
|
-
const i = ordered.findIndex(isCurrent);
|
|
70
|
-
if (i < 0)
|
|
71
|
-
return { prev: null, next: null };
|
|
72
|
-
return { prev: ordered[i - 1] ?? null, next: ordered[i + 1] ?? null };
|
|
73
|
-
}
|
package/dist/react-server.d.ts
CHANGED
|
@@ -195,40 +195,6 @@ export declare function Breadcrumbs({ items, base, className, link: Link, lastAs
|
|
|
195
195
|
export declare function BreadcrumbsRow({ actions, className, ...props }: BreadcrumbsProps & {
|
|
196
196
|
actions?: ReactNode;
|
|
197
197
|
}): import("react").JSX.Element;
|
|
198
|
-
/** One end of the foot nav: where it goes and what it is called. */
|
|
199
|
-
export interface PageNavRef {
|
|
200
|
-
title: string;
|
|
201
|
-
href: string;
|
|
202
|
-
}
|
|
203
|
-
export interface PageNavProps {
|
|
204
|
-
prev?: PageNavRef | null;
|
|
205
|
-
next?: PageNavRef | null;
|
|
206
|
-
link?: WikiLinkComponent;
|
|
207
|
-
/** The landmark's accessible name. */
|
|
208
|
-
label?: string;
|
|
209
|
-
prevLabel?: string;
|
|
210
|
-
nextLabel?: string;
|
|
211
|
-
/**
|
|
212
|
-
* The arrows. `ReactNode` rather than a string because both wikis draw them
|
|
213
|
-
* with an icon component, and this package is not acquiring an icon peer to
|
|
214
|
-
* hold two glyphs.
|
|
215
|
-
*/
|
|
216
|
-
prevGlyph?: ReactNode;
|
|
217
|
-
nextGlyph?: ReactNode;
|
|
218
|
-
}
|
|
219
|
-
/**
|
|
220
|
-
* The sequential read at the foot of an article — the move the infobox rail's
|
|
221
|
-
* lateral links do not cover.
|
|
222
|
-
*
|
|
223
|
-
* Ordering is entirely the caller's; pair this with `adjacentPages` from
|
|
224
|
-
* `wiki-formant/pagination` over a list you already hold.
|
|
225
|
-
*
|
|
226
|
-
* The `page-nav__*` class names are NOT props: they are the convention every
|
|
227
|
-
* stylesheet implements, and making them configurable is how a convention
|
|
228
|
-
* forks. The empty `<div>` holds the first article's left column so the next
|
|
229
|
-
* link stays in the right one.
|
|
230
|
-
*/
|
|
231
|
-
export declare function PageNav({ prev, next, link: Link, label, prevLabel, nextLabel, prevGlyph, nextGlyph, }: PageNavProps): import("react").JSX.Element | null;
|
|
232
198
|
export interface InfoboxAsideProps {
|
|
233
199
|
/** The landmark's accessible name, e.g. `Key facts about ${title}`. */
|
|
234
200
|
label: string;
|
package/dist/react-server.js
CHANGED
|
@@ -148,23 +148,6 @@ export function Breadcrumbs({ items, base, className = '', link: Link = Anchor,
|
|
|
148
148
|
export function BreadcrumbsRow({ actions, className = '', ...props }) {
|
|
149
149
|
return (_jsxs("div", { className: `breadcrumbs-row ${actions ? 'spread' : ''} ${className}`.trim(), children: [_jsx(Breadcrumbs, { ...props }), actions] }));
|
|
150
150
|
}
|
|
151
|
-
/**
|
|
152
|
-
* The sequential read at the foot of an article — the move the infobox rail's
|
|
153
|
-
* lateral links do not cover.
|
|
154
|
-
*
|
|
155
|
-
* Ordering is entirely the caller's; pair this with `adjacentPages` from
|
|
156
|
-
* `wiki-formant/pagination` over a list you already hold.
|
|
157
|
-
*
|
|
158
|
-
* The `page-nav__*` class names are NOT props: they are the convention every
|
|
159
|
-
* stylesheet implements, and making them configurable is how a convention
|
|
160
|
-
* forks. The empty `<div>` holds the first article's left column so the next
|
|
161
|
-
* link stays in the right one.
|
|
162
|
-
*/
|
|
163
|
-
export function PageNav({ prev, next, link: Link = Anchor, label = 'Article navigation', prevLabel = 'Previous', nextLabel = 'Next', prevGlyph = '\u2190', nextGlyph = '\u2192', }) {
|
|
164
|
-
if (!prev && !next)
|
|
165
|
-
return null;
|
|
166
|
-
return (_jsxs("nav", { className: "page-nav", "aria-label": label, children: [prev ? (_jsxs(Link, { href: prev.href, className: "page-nav-link", rel: "prev", children: [_jsxs("span", { className: "page-nav-label", children: [prevGlyph, prevLabel] }), _jsx("span", { className: "page-nav-title", children: prev.title })] })) : (_jsx("div", {})), next && (_jsxs(Link, { href: next.href, className: "page-nav-link page-nav-link--end", rel: "next", children: [_jsxs("span", { className: "page-nav-label page-nav-label--end", children: [nextLabel, nextGlyph] }), _jsx("span", { className: "page-nav-title", children: next.title })] }))] }));
|
|
167
|
-
}
|
|
168
151
|
/**
|
|
169
152
|
* The facts panel beside an article. Named, because two of the three asides
|
|
170
153
|
* this replaced had no accessible name, and a complementary landmark without
|
package/dist/stats-figures.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
2
|
import type { Digest } from './analytics.js';
|
|
3
|
+
export declare const count: (n: number) => string;
|
|
3
4
|
/**
|
|
4
5
|
* The figures as `.stats-figures button[aria-pressed]`, each with its change
|
|
5
6
|
* as `.stats-delta[data-better]` for a stylesheet to colour, and the pressed one per
|
package/dist/stats-figures.js
CHANGED
|
@@ -8,7 +8,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
8
8
|
import { startAuthentication, startRegistration } from '@simplewebauthn/browser';
|
|
9
9
|
import { useMemo, useState } from 'react';
|
|
10
10
|
import { TimeChart, stepDecimals } from './chart.js';
|
|
11
|
-
const count = (n) => n.toLocaleString('en');
|
|
11
|
+
export const count = (n) => n.toLocaleString('en');
|
|
12
12
|
// Whole seconds and percentages, unless an axis tick's step needs more to tell it from the next.
|
|
13
13
|
const places = (step) => (step ? stepDecimals(step) : 0);
|
|
14
14
|
const duration = (s, step) => (s < 60 ? `${s.toFixed(places(step))}s` : `${Math.floor(s / 60)}m ${Math.round(s % 60)}s`);
|
package/dist/stats.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { STATS_FILTERS } from './analytics.js';
|
|
3
|
-
import { PasskeyButton, PasskeySignOut, StatsFigures } from './stats-figures.js';
|
|
3
|
+
import { PasskeyButton, PasskeySignOut, StatsFigures, count } from './stats-figures.js';
|
|
4
4
|
/** The windows the stats page offers, in days; `Infinity` is all time. */
|
|
5
5
|
const STATS_RANGES = [1, 7, 30, 90, 365, Infinity];
|
|
6
6
|
/** A window as its `?days=` value. */
|
|
@@ -31,7 +31,6 @@ const href = (days, filter) => {
|
|
|
31
31
|
q.set(k, filter[k]);
|
|
32
32
|
return `?${q}`;
|
|
33
33
|
};
|
|
34
|
-
const count = (n) => n.toLocaleString('en');
|
|
35
34
|
const regions = new Intl.DisplayNames(['en'], { type: 'region' });
|
|
36
35
|
const country = (code) => {
|
|
37
36
|
try {
|
package/dist/taxonomy.js
CHANGED
|
@@ -37,7 +37,11 @@ export function hrefBuilder(prefix = '') {
|
|
|
37
37
|
/** Categories mounted at the root. */
|
|
38
38
|
export const defaultHref = hrefBuilder();
|
|
39
39
|
const DEFAULT_ALPHA_INDEX_MIN_PAGES = 40;
|
|
40
|
-
|
|
40
|
+
/** A key's value as text. Metadata is untyped JSON, and a number or a list stored under a key must not throw. */
|
|
41
|
+
const metaValue = (page, key) => {
|
|
42
|
+
const value = page.metadata?.[key];
|
|
43
|
+
return typeof value === 'string' ? value.trim() : typeof value === 'number' ? String(value) : '';
|
|
44
|
+
};
|
|
41
45
|
/** Bucket for titles that don't start with a letter (numerals, `$CAPER`). @internal */
|
|
42
46
|
export function firstLetter(title) {
|
|
43
47
|
const ch = title.trim()[0]?.toUpperCase() ?? '';
|
package/dist/tiptap.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
2
|
import { Extension, Node as TiptapNode } from '@tiptap/core';
|
|
3
|
-
/** Local `cn`. Both wikis import one; the package will not depend on one. */
|
|
4
3
|
/**
|
|
5
4
|
* An embed's address, if it is https on a host the sanitiser and the CSP
|
|
6
5
|
* admit; otherwise null, and the node draws an empty frame. The editor draws
|
package/dist/tiptap.js
CHANGED
|
@@ -23,7 +23,6 @@ import { useClickOutside } from './react.js';
|
|
|
23
23
|
import { cx } from './html.js';
|
|
24
24
|
import { slugifyHeading, uniqueHeadingId } from './headings.js';
|
|
25
25
|
import { CODE_LANGS, DEFAULT_LANG } from './blocks.js';
|
|
26
|
-
/** Local `cn`. Both wikis import one; the package will not depend on one. */
|
|
27
26
|
// ---- iframe -----------------------------------------------------------------
|
|
28
27
|
/**
|
|
29
28
|
* An embed's address, if it is https on a host the sanitiser and the CSP
|
package/dist/validation.js
CHANGED
|
@@ -56,7 +56,7 @@ export function validateLinkGroups(groups) {
|
|
|
56
56
|
Array.isArray(g.links) &&
|
|
57
57
|
g.links.every(l => isRecord(l) && typeof l.label === 'string' && okUrl(l.href))));
|
|
58
58
|
}
|
|
59
|
-
/** `[{ label, language?, code }]` — a code-tabs block's tabs. `code`
|
|
59
|
+
/** `[{ label, language?, code }]` — a code-tabs block's tabs. `code` is source text, escaped when it renders. @internal */
|
|
60
60
|
export function validateCodeTabs(tabs) {
|
|
61
61
|
return (Array.isArray(tabs) &&
|
|
62
62
|
tabs.every(t => isRecord(t) &&
|
package/dist/versioning.d.ts
CHANGED
|
@@ -10,4 +10,3 @@ export declare function formatVersion(version: SemVer): string;
|
|
|
10
10
|
export declare function incrementVersion(version: SemVer, changeType: ChangeType): SemVer;
|
|
11
11
|
/** Bump a version string in one step — the call site almost always wants this. */
|
|
12
12
|
export declare function bump(version: string | null | undefined, changeType: ChangeType): string;
|
|
13
|
-
export declare function compareVersions(a: string, b: string): number;
|
package/dist/versioning.js
CHANGED
|
@@ -33,8 +33,3 @@ export function incrementVersion(version, changeType) {
|
|
|
33
33
|
export function bump(version, changeType) {
|
|
34
34
|
return formatVersion(incrementVersion(parseVersion(version), changeType));
|
|
35
35
|
}
|
|
36
|
-
export function compareVersions(a, b) {
|
|
37
|
-
const x = parseVersion(a);
|
|
38
|
-
const y = parseVersion(b);
|
|
39
|
-
return x.major - y.major || x.minor - y.minor || x.patch - y.patch;
|
|
40
|
-
}
|
package/dist/well-known.d.ts
CHANGED
package/dist/well-known.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// Nothing here touches a framework: these return plain values, and the caller
|
|
10
10
|
// wraps them in whatever its router wants. That keeps this package free of a
|
|
11
11
|
// Next dependency and keeps each app's route a two-liner.
|
|
12
|
-
import { MCP_PROTOCOL_VERSION, MCP_PROTOCOL_VERSIONS } from './mcp.js';
|
|
12
|
+
import { MCP_PROTOCOL_VERSION, MCP_PROTOCOL_VERSIONS, toolCard } from './mcp.js';
|
|
13
13
|
import { MCP_RATE_LIMIT_TEXT } from './rate-limit.js';
|
|
14
14
|
import { descriptorResponse } from './http.js';
|
|
15
15
|
/**
|
|
@@ -195,13 +195,7 @@ export function mcpManifest(config) {
|
|
|
195
195
|
rateLimit: MCP_RATE_LIMIT_TEXT,
|
|
196
196
|
},
|
|
197
197
|
...extra,
|
|
198
|
-
tools: tools.map(
|
|
199
|
-
name,
|
|
200
|
-
...(title ? { title } : {}),
|
|
201
|
-
description,
|
|
202
|
-
inputSchema,
|
|
203
|
-
...(annotations ? { annotations } : {}),
|
|
204
|
-
})),
|
|
198
|
+
tools: tools.map(toolCard),
|
|
205
199
|
};
|
|
206
200
|
}
|
|
207
201
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wiki-formant",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.65.0",
|
|
4
4
|
"description": "The portable half of a wiki: derived taxonomy and facet controls, a version-negotiating MCP transport, markdown twins, block rendering, a rich-text editor engine, conditional-GET plumbing, and the headers and CSP every origin sends.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|