@ctcstack/ctcdocs-core 0.17.0 → 0.18.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/corpus-structure.d.ts +2 -0
- package/dist/corpus-structure.js +2 -0
- package/dist/published-markdown.d.ts +11 -0
- package/dist/published-markdown.js +19 -4
- package/dist/site-configuration.d.ts +6 -3
- package/dist/site-configuration.js +1 -1
- package/package.json +1 -1
- package/src/corpus-structure.ts +4 -0
- package/src/published-markdown.ts +26 -5
- package/src/site-configuration.ts +7 -4
|
@@ -23,6 +23,8 @@ export interface CorpusDocument {
|
|
|
23
23
|
readonly shortId?: string;
|
|
24
24
|
readonly title?: string;
|
|
25
25
|
readonly modified?: string;
|
|
26
|
+
/** The Google Doc or PDF in Drive, as the page links it. */
|
|
27
|
+
readonly source?: string;
|
|
26
28
|
}
|
|
27
29
|
export interface CorpusStructure {
|
|
28
30
|
readonly rootFolderId: string | null;
|
package/dist/corpus-structure.js
CHANGED
|
@@ -65,6 +65,7 @@ export function parseCorpusStructure(manifest) {
|
|
|
65
65
|
const shortId = optional('shortId');
|
|
66
66
|
const title = optional('displayTitle');
|
|
67
67
|
const modified = optional('googleModifiedTime');
|
|
68
|
+
const source = optional('sourceUrl');
|
|
68
69
|
documents.set(id, {
|
|
69
70
|
id,
|
|
70
71
|
parentId: field(raw, 'googleParentId', path, true),
|
|
@@ -72,6 +73,7 @@ export function parseCorpusStructure(manifest) {
|
|
|
72
73
|
...(shortId ? { shortId } : {}),
|
|
73
74
|
...(title ? { title } : {}),
|
|
74
75
|
...(modified ? { modified } : {}),
|
|
76
|
+
...(source ? { source } : {}),
|
|
75
77
|
...(published === '*' ||
|
|
76
78
|
(Array.isArray(published) &&
|
|
77
79
|
published.every((group) => typeof group === 'string'))
|
|
@@ -30,4 +30,15 @@ export declare function publishedFileUrl(googleFileId: string, file: string): st
|
|
|
30
30
|
* titles, which come from Drive names and may contain any of them.
|
|
31
31
|
*/
|
|
32
32
|
export declare function inlineMarkdown(value: string): string;
|
|
33
|
+
/**
|
|
34
|
+
* The page's Markdown without its front matter: its title as a heading and
|
|
35
|
+
* its body. It is what the MCP server stores, indexes and returns from
|
|
36
|
+
* `fetch` (ADR-042), so it is also what the sync measures (ADR-043).
|
|
37
|
+
*/
|
|
38
|
+
export declare function publishedMarkdownBody(input: Pick<PublishedMarkdownInput, 'title' | 'ownershipHeader' | 'body' | 'stableSlugs' | 'permanentLinks'>): string;
|
|
39
|
+
/**
|
|
40
|
+
* The page's Markdown version (ADR-010): front matter, then
|
|
41
|
+
* `publishedMarkdownBody`. Each front matter value is one JSON string, so no
|
|
42
|
+
* value spans a line and the first `---` line after the opening one closes it.
|
|
43
|
+
*/
|
|
33
44
|
export declare function serializePublishedMarkdown(input: PublishedMarkdownInput): string;
|
|
@@ -98,8 +98,25 @@ export function inlineMarkdown(value) {
|
|
|
98
98
|
.trim()
|
|
99
99
|
.replace(/([\\`*_[\]<>#])/gu, '\\$1');
|
|
100
100
|
}
|
|
101
|
-
|
|
101
|
+
/**
|
|
102
|
+
* The page's Markdown without its front matter: its title as a heading and
|
|
103
|
+
* its body. It is what the MCP server stores, indexes and returns from
|
|
104
|
+
* `fetch` (ADR-042), so it is also what the sync measures (ADR-043).
|
|
105
|
+
*/
|
|
106
|
+
export function publishedMarkdownBody(input) {
|
|
102
107
|
const body = rewriteInternalLinks(cleanBody(input.body, input.ownershipHeader), input.stableSlugs, input.permanentLinks);
|
|
108
|
+
return [
|
|
109
|
+
`# ${inlineMarkdown(input.title)}`,
|
|
110
|
+
'',
|
|
111
|
+
...(body ? [body, ''] : []),
|
|
112
|
+
].join('\n');
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* The page's Markdown version (ADR-010): front matter, then
|
|
116
|
+
* `publishedMarkdownBody`. Each front matter value is one JSON string, so no
|
|
117
|
+
* value spans a line and the first `---` line after the opening one closes it.
|
|
118
|
+
*/
|
|
119
|
+
export function serializePublishedMarkdown(input) {
|
|
103
120
|
return [
|
|
104
121
|
'---',
|
|
105
122
|
`title: ${yamlString(input.title)}`,
|
|
@@ -110,8 +127,6 @@ export function serializePublishedMarkdown(input) {
|
|
|
110
127
|
`content_hash: ${yamlString(input.contentHash)}`,
|
|
111
128
|
'---',
|
|
112
129
|
'',
|
|
113
|
-
|
|
114
|
-
'',
|
|
115
|
-
...(body ? [body, ''] : []),
|
|
130
|
+
publishedMarkdownBody(input),
|
|
116
131
|
].join('\n');
|
|
117
132
|
}
|
|
@@ -152,13 +152,16 @@ export interface McpSearchConfiguration {
|
|
|
152
152
|
readonly chunks: number;
|
|
153
153
|
/**
|
|
154
154
|
* The vector similarity below which AI Search drops a chunk, 0 to 1. It
|
|
155
|
-
*
|
|
156
|
-
*
|
|
155
|
+
* drops only chunks vector search alone found, and AI Search ignores it
|
|
156
|
+
* while reranking is on (ADR-042), so it acts only with reranking off.
|
|
157
157
|
*/
|
|
158
158
|
readonly vectorThreshold: number;
|
|
159
159
|
/** Whether a keyword match needs every word of the query, or any. */
|
|
160
160
|
readonly keywordMatch: 'and' | 'or';
|
|
161
|
-
/**
|
|
161
|
+
/**
|
|
162
|
+
* Neighbouring chunks AI Search joins to each side of a match: 0 to 3. A
|
|
163
|
+
* chunk of AI Search's default size is already longer than a passage.
|
|
164
|
+
*/
|
|
162
165
|
readonly contextChunks: number;
|
|
163
166
|
readonly reranking: {
|
|
164
167
|
readonly enabled: boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ctcstack/ctcdocs-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "Configuration schema, project layout, generated-path allowlist and the published Markdown form shared by the CTCDocs platform packages.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ctcdocs",
|
package/src/corpus-structure.ts
CHANGED
|
@@ -37,6 +37,8 @@ export interface CorpusDocument {
|
|
|
37
37
|
readonly shortId?: string;
|
|
38
38
|
readonly title?: string;
|
|
39
39
|
readonly modified?: string;
|
|
40
|
+
/** The Google Doc or PDF in Drive, as the page links it. */
|
|
41
|
+
readonly source?: string;
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
export interface CorpusStructure {
|
|
@@ -114,6 +116,7 @@ export function parseCorpusStructure(manifest: unknown): CorpusStructure {
|
|
|
114
116
|
const shortId = optional('shortId');
|
|
115
117
|
const title = optional('displayTitle');
|
|
116
118
|
const modified = optional('googleModifiedTime');
|
|
119
|
+
const source = optional('sourceUrl');
|
|
117
120
|
documents.set(id, {
|
|
118
121
|
id,
|
|
119
122
|
parentId: field(raw, 'googleParentId', path, true),
|
|
@@ -121,6 +124,7 @@ export function parseCorpusStructure(manifest: unknown): CorpusStructure {
|
|
|
121
124
|
...(shortId ? { shortId } : {}),
|
|
122
125
|
...(title ? { title } : {}),
|
|
123
126
|
...(modified ? { modified } : {}),
|
|
127
|
+
...(source ? { source } : {}),
|
|
124
128
|
...(published === '*' ||
|
|
125
129
|
(Array.isArray(published) &&
|
|
126
130
|
published.every((group) => typeof group === 'string'))
|
|
@@ -153,14 +153,37 @@ export function inlineMarkdown(value: string): string {
|
|
|
153
153
|
.replace(/([\\`*_[\]<>#])/gu, '\\$1');
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
-
|
|
157
|
-
|
|
156
|
+
/**
|
|
157
|
+
* The page's Markdown without its front matter: its title as a heading and
|
|
158
|
+
* its body. It is what the MCP server stores, indexes and returns from
|
|
159
|
+
* `fetch` (ADR-042), so it is also what the sync measures (ADR-043).
|
|
160
|
+
*/
|
|
161
|
+
export function publishedMarkdownBody(
|
|
162
|
+
input: Pick<
|
|
163
|
+
PublishedMarkdownInput,
|
|
164
|
+
'title' | 'ownershipHeader' | 'body' | 'stableSlugs' | 'permanentLinks'
|
|
165
|
+
>,
|
|
158
166
|
): string {
|
|
159
167
|
const body = rewriteInternalLinks(
|
|
160
168
|
cleanBody(input.body, input.ownershipHeader),
|
|
161
169
|
input.stableSlugs,
|
|
162
170
|
input.permanentLinks,
|
|
163
171
|
);
|
|
172
|
+
return [
|
|
173
|
+
`# ${inlineMarkdown(input.title)}`,
|
|
174
|
+
'',
|
|
175
|
+
...(body ? [body, ''] : []),
|
|
176
|
+
].join('\n');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* The page's Markdown version (ADR-010): front matter, then
|
|
181
|
+
* `publishedMarkdownBody`. Each front matter value is one JSON string, so no
|
|
182
|
+
* value spans a line and the first `---` line after the opening one closes it.
|
|
183
|
+
*/
|
|
184
|
+
export function serializePublishedMarkdown(
|
|
185
|
+
input: PublishedMarkdownInput,
|
|
186
|
+
): string {
|
|
164
187
|
return [
|
|
165
188
|
'---',
|
|
166
189
|
`title: ${yamlString(input.title)}`,
|
|
@@ -171,8 +194,6 @@ export function serializePublishedMarkdown(
|
|
|
171
194
|
`content_hash: ${yamlString(input.contentHash)}`,
|
|
172
195
|
'---',
|
|
173
196
|
'',
|
|
174
|
-
|
|
175
|
-
'',
|
|
176
|
-
...(body ? [body, ''] : []),
|
|
197
|
+
publishedMarkdownBody(input),
|
|
177
198
|
].join('\n');
|
|
178
199
|
}
|
|
@@ -183,13 +183,16 @@ export interface McpSearchConfiguration {
|
|
|
183
183
|
readonly chunks: number;
|
|
184
184
|
/**
|
|
185
185
|
* The vector similarity below which AI Search drops a chunk, 0 to 1. It
|
|
186
|
-
*
|
|
187
|
-
*
|
|
186
|
+
* drops only chunks vector search alone found, and AI Search ignores it
|
|
187
|
+
* while reranking is on (ADR-042), so it acts only with reranking off.
|
|
188
188
|
*/
|
|
189
189
|
readonly vectorThreshold: number;
|
|
190
190
|
/** Whether a keyword match needs every word of the query, or any. */
|
|
191
191
|
readonly keywordMatch: 'and' | 'or';
|
|
192
|
-
/**
|
|
192
|
+
/**
|
|
193
|
+
* Neighbouring chunks AI Search joins to each side of a match: 0 to 3. A
|
|
194
|
+
* chunk of AI Search's default size is already longer than a passage.
|
|
195
|
+
*/
|
|
193
196
|
readonly contextChunks: number;
|
|
194
197
|
readonly reranking: {
|
|
195
198
|
readonly enabled: boolean;
|
|
@@ -224,7 +227,7 @@ export const MCP_DEFAULTS: Omit<McpConfiguration, 'enabled'> = Object.freeze({
|
|
|
224
227
|
chunks: 50,
|
|
225
228
|
vectorThreshold: 0.2,
|
|
226
229
|
keywordMatch: 'or',
|
|
227
|
-
contextChunks:
|
|
230
|
+
contextChunks: 0,
|
|
228
231
|
reranking: Object.freeze({
|
|
229
232
|
enabled: true,
|
|
230
233
|
model: '@cf/baai/bge-reranker-base',
|