@fragments-sdk/context 0.1.2 → 0.1.4
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 +62 -0
- package/dist/chunk-3FEHRHFQ.js +103 -0
- package/dist/chunk-KKABP4K4.js +228 -0
- package/dist/citations/index.d.ts +94 -0
- package/dist/citations/index.js +10 -0
- package/dist/generate/index.d.ts +43 -0
- package/dist/generate/index.js +10 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.js +16 -0
- package/dist/search/index.d.ts +3 -38
- package/dist/types/index.d.ts +170 -0
- package/dist/types/index.js +0 -0
- package/dist/types-B7duBj6U.d.ts +39 -0
- package/package.json +14 -2
package/README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# @fragments-sdk/context
|
|
2
|
+
|
|
3
|
+
Code intelligence and RAG primitives for codebase indexing and search.
|
|
4
|
+
|
|
5
|
+
## Modules
|
|
6
|
+
|
|
7
|
+
### Chunking (`@fragments-sdk/context/chunking`)
|
|
8
|
+
|
|
9
|
+
Split source files into semantically meaningful chunks for embedding.
|
|
10
|
+
|
|
11
|
+
- **`chunkFile(content, filePath, language)`** — Auto-selects AST or line-based chunking
|
|
12
|
+
- **`chunkByAST(content, filePath, language, grammar)`** — Tree-sitter AST-aware chunking (preserves functions, classes, etc.)
|
|
13
|
+
- **`chunkByLines(content, filePath, language)`** — Sliding-window fallback
|
|
14
|
+
|
|
15
|
+
AST chunking supports: TypeScript, TSX, JavaScript, Python, Go, Rust, Java.
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { chunkFile } from "@fragments-sdk/context/chunking";
|
|
19
|
+
|
|
20
|
+
const chunks = await chunkFile(code, "src/auth.ts", "typescript");
|
|
21
|
+
// Each chunk has: content, filePath, startLine, endLine, language, symbolName?, scopeChain?
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Embeddings (`@fragments-sdk/context/embeddings`)
|
|
25
|
+
|
|
26
|
+
Generate code-optimized embeddings via Voyage AI.
|
|
27
|
+
|
|
28
|
+
- **`generateEmbeddings(texts, options)`** — Batch embed with `voyage-code-3`
|
|
29
|
+
- **`rerankResults(query, documents, options)`** — Cross-encoder reranking with `rerank-2.5`
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import { generateEmbeddings } from "@fragments-sdk/context/embeddings";
|
|
33
|
+
|
|
34
|
+
const vectors = await generateEmbeddings(chunks.map(c => c.content), {
|
|
35
|
+
apiKey: process.env.VOYAGE_API_KEY!,
|
|
36
|
+
inputType: "document",
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Search (`@fragments-sdk/context/search`)
|
|
41
|
+
|
|
42
|
+
Post-retrieval utilities for combining and deduplicating results.
|
|
43
|
+
|
|
44
|
+
- **`reciprocalRankFusion(resultSets)`** — Merge multiple ranked lists (e.g. vector + keyword)
|
|
45
|
+
- **`deduplicateChunks(chunks)`** — Remove near-duplicate results
|
|
46
|
+
|
|
47
|
+
### Indexing (`@fragments-sdk/context/indexing`)
|
|
48
|
+
|
|
49
|
+
File filtering, change detection, and language detection.
|
|
50
|
+
|
|
51
|
+
- **`shouldIndexFile(path, size)`** — Filter by extension, size, ignored dirs
|
|
52
|
+
- **`detectLanguage(path)`** — Map file extension to language name
|
|
53
|
+
- **`resolveChanges(oldFiles, newFiles)`** — Diff two file trees for incremental re-indexing
|
|
54
|
+
- **`hashContent(content)`** — Content hashing for change detection
|
|
55
|
+
|
|
56
|
+
## Install
|
|
57
|
+
|
|
58
|
+
```sh
|
|
59
|
+
pnpm add @fragments-sdk/context
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Requires Node.js 18+. Tree-sitter WASM grammars are included as dependencies.
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// src/citations/document-builder.ts
|
|
2
|
+
function buildCitationDocuments(chunks, options) {
|
|
3
|
+
const documents = [];
|
|
4
|
+
const documentMap = [];
|
|
5
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
6
|
+
for (const chunk of chunks) {
|
|
7
|
+
const existing = byFile.get(chunk.filePath);
|
|
8
|
+
if (existing) {
|
|
9
|
+
existing.push(chunk);
|
|
10
|
+
} else {
|
|
11
|
+
byFile.set(chunk.filePath, [chunk]);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
for (const [filePath, fileChunks] of byFile) {
|
|
15
|
+
const docIndex = documents.length;
|
|
16
|
+
const contentBlocks = fileChunks.map((chunk) => ({
|
|
17
|
+
type: "text",
|
|
18
|
+
text: chunk.content
|
|
19
|
+
}));
|
|
20
|
+
const contextLines = fileChunks.map((chunk, i) => {
|
|
21
|
+
const parts = [`Block ${i}: lines ${chunk.startLine}-${chunk.endLine} (${chunk.language})`];
|
|
22
|
+
if (chunk.symbolName) parts.push(`symbol: ${chunk.symbolName}`);
|
|
23
|
+
return parts.join(", ");
|
|
24
|
+
});
|
|
25
|
+
documents.push({
|
|
26
|
+
type: "document",
|
|
27
|
+
source: { type: "content", content: contentBlocks },
|
|
28
|
+
title: filePath,
|
|
29
|
+
context: contextLines.join("\n"),
|
|
30
|
+
citations: { enabled: true }
|
|
31
|
+
});
|
|
32
|
+
documentMap.push({
|
|
33
|
+
documentIndex: docIndex,
|
|
34
|
+
filePath,
|
|
35
|
+
sourceType: "code",
|
|
36
|
+
chunks: fileChunks.map((chunk, i) => ({
|
|
37
|
+
blockIndex: i,
|
|
38
|
+
startLine: chunk.startLine,
|
|
39
|
+
endLine: chunk.endLine,
|
|
40
|
+
language: chunk.language,
|
|
41
|
+
symbolName: chunk.symbolName,
|
|
42
|
+
score: chunk.score
|
|
43
|
+
}))
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
if (options?.additionalDocuments) {
|
|
47
|
+
for (const doc of options.additionalDocuments) {
|
|
48
|
+
if (!doc.content.trim()) continue;
|
|
49
|
+
const docIndex = documents.length;
|
|
50
|
+
documents.push({
|
|
51
|
+
type: "document",
|
|
52
|
+
source: {
|
|
53
|
+
type: "text",
|
|
54
|
+
media_type: "text/plain",
|
|
55
|
+
data: doc.content
|
|
56
|
+
},
|
|
57
|
+
title: doc.title,
|
|
58
|
+
citations: { enabled: true }
|
|
59
|
+
});
|
|
60
|
+
documentMap.push({
|
|
61
|
+
documentIndex: docIndex,
|
|
62
|
+
filePath: doc.title,
|
|
63
|
+
sourceType: "plaintext",
|
|
64
|
+
chunks: []
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return { documents, documentMap };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// src/citations/resolver.ts
|
|
72
|
+
function resolveCitation(raw, documentMap, citationIndex, textOffset) {
|
|
73
|
+
const mapping = documentMap[raw.document_index];
|
|
74
|
+
const base = {
|
|
75
|
+
index: citationIndex,
|
|
76
|
+
citedText: raw.cited_text,
|
|
77
|
+
documentTitle: raw.document_title,
|
|
78
|
+
filePath: mapping?.filePath ?? raw.document_title ?? "unknown",
|
|
79
|
+
sourceType: mapping?.sourceType ?? "plaintext",
|
|
80
|
+
textOffset
|
|
81
|
+
};
|
|
82
|
+
if (raw.type === "content_block_location" && mapping?.sourceType === "code" && raw.start_block_index != null) {
|
|
83
|
+
const chunk = mapping.chunks[raw.start_block_index];
|
|
84
|
+
if (chunk) {
|
|
85
|
+
base.startLine = chunk.startLine;
|
|
86
|
+
base.endLine = chunk.endLine;
|
|
87
|
+
base.language = chunk.language;
|
|
88
|
+
base.symbolName = chunk.symbolName;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return base;
|
|
92
|
+
}
|
|
93
|
+
function resolveCitations(raws, documentMap, textOffsets) {
|
|
94
|
+
return raws.map(
|
|
95
|
+
(raw, i) => resolveCitation(raw, documentMap, i + 1, textOffsets[i] ?? 0)
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export {
|
|
100
|
+
buildCitationDocuments,
|
|
101
|
+
resolveCitation,
|
|
102
|
+
resolveCitations
|
|
103
|
+
};
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
// src/generate/index.ts
|
|
2
|
+
var PLACEHOLDER_PATTERNS = [
|
|
3
|
+
/^\w+ component is needed$/i,
|
|
4
|
+
/^Alternative component is more appropriate$/i,
|
|
5
|
+
/^Use \w+ when you need/i
|
|
6
|
+
];
|
|
7
|
+
function filterPlaceholders(items) {
|
|
8
|
+
if (!items) return [];
|
|
9
|
+
return items.filter(
|
|
10
|
+
(item) => !PLACEHOLDER_PATTERNS.some((pattern) => pattern.test(item.trim()))
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
function generateContext(segments, options = {}, blocks) {
|
|
14
|
+
const format = options.format ?? "markdown";
|
|
15
|
+
const compact = options.compact ?? false;
|
|
16
|
+
const include = {
|
|
17
|
+
props: options.include?.props ?? true,
|
|
18
|
+
variants: options.include?.variants ?? true,
|
|
19
|
+
usage: options.include?.usage ?? true,
|
|
20
|
+
relations: options.include?.relations ?? false,
|
|
21
|
+
code: options.include?.code ?? false
|
|
22
|
+
};
|
|
23
|
+
const sorted = [...segments].sort((a, b) => {
|
|
24
|
+
const catCompare = a.meta.category.localeCompare(b.meta.category);
|
|
25
|
+
if (catCompare !== 0) return catCompare;
|
|
26
|
+
return a.meta.name.localeCompare(b.meta.name);
|
|
27
|
+
});
|
|
28
|
+
if (format === "json") {
|
|
29
|
+
return generateJsonContext(sorted, include, compact, blocks);
|
|
30
|
+
}
|
|
31
|
+
return generateMarkdownContext(sorted, include, compact, blocks);
|
|
32
|
+
}
|
|
33
|
+
function generateMarkdownContext(segments, include, compact, blocks) {
|
|
34
|
+
const lines = [];
|
|
35
|
+
lines.push("# Design System Reference");
|
|
36
|
+
lines.push("");
|
|
37
|
+
lines.push("## Quick Reference");
|
|
38
|
+
lines.push("");
|
|
39
|
+
lines.push("| Component | Category | Use For |");
|
|
40
|
+
lines.push("|-----------|----------|---------|");
|
|
41
|
+
for (const segment of segments) {
|
|
42
|
+
const filteredWhen = filterPlaceholders(segment.usage.when);
|
|
43
|
+
const useFor = filteredWhen.slice(0, 2).join(", ") || segment.meta.description;
|
|
44
|
+
lines.push(`| ${segment.meta.name} | ${segment.meta.category} | ${truncate(useFor, 50)} |`);
|
|
45
|
+
}
|
|
46
|
+
lines.push("");
|
|
47
|
+
if (compact) {
|
|
48
|
+
const content2 = lines.join("\n");
|
|
49
|
+
return { content: content2, tokenEstimate: estimateTokens(content2) };
|
|
50
|
+
}
|
|
51
|
+
lines.push("## Components");
|
|
52
|
+
lines.push("");
|
|
53
|
+
for (const segment of segments) {
|
|
54
|
+
lines.push(`### ${segment.meta.name}`);
|
|
55
|
+
lines.push("");
|
|
56
|
+
const statusParts = [`**Category:** ${segment.meta.category}`];
|
|
57
|
+
if (segment.meta.status) {
|
|
58
|
+
statusParts.push(`**Status:** ${segment.meta.status}`);
|
|
59
|
+
}
|
|
60
|
+
lines.push(statusParts.join(" | "));
|
|
61
|
+
lines.push("");
|
|
62
|
+
if (segment.meta.description) {
|
|
63
|
+
lines.push(segment.meta.description);
|
|
64
|
+
lines.push("");
|
|
65
|
+
}
|
|
66
|
+
const whenFiltered = filterPlaceholders(segment.usage.when);
|
|
67
|
+
const whenNotFiltered = filterPlaceholders(segment.usage.whenNot);
|
|
68
|
+
if (include.usage && (whenFiltered.length > 0 || whenNotFiltered.length > 0)) {
|
|
69
|
+
if (whenFiltered.length > 0) {
|
|
70
|
+
lines.push("**When to use:**");
|
|
71
|
+
for (const when of whenFiltered) {
|
|
72
|
+
lines.push(`- ${when}`);
|
|
73
|
+
}
|
|
74
|
+
lines.push("");
|
|
75
|
+
}
|
|
76
|
+
if (whenNotFiltered.length > 0) {
|
|
77
|
+
lines.push("**When NOT to use:**");
|
|
78
|
+
for (const whenNot of whenNotFiltered) {
|
|
79
|
+
lines.push(`- ${whenNot}`);
|
|
80
|
+
}
|
|
81
|
+
lines.push("");
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (include.props && Object.keys(segment.props).length > 0) {
|
|
85
|
+
lines.push("**Props:**");
|
|
86
|
+
for (const [name, prop] of Object.entries(segment.props)) {
|
|
87
|
+
lines.push(`- \`${name}\`: ${formatPropType(prop)}${prop.required ? " (required)" : ""}`);
|
|
88
|
+
}
|
|
89
|
+
lines.push("");
|
|
90
|
+
}
|
|
91
|
+
if (include.variants && segment.variants.length > 0) {
|
|
92
|
+
const variantNames = segment.variants.map((v) => v.name).join(", ");
|
|
93
|
+
lines.push(`**Variants:** ${variantNames}`);
|
|
94
|
+
lines.push("");
|
|
95
|
+
if (include.code) {
|
|
96
|
+
for (const variant of segment.variants) {
|
|
97
|
+
if (variant.code) {
|
|
98
|
+
lines.push(`*${variant.name}:*`);
|
|
99
|
+
lines.push("```tsx");
|
|
100
|
+
lines.push(variant.code);
|
|
101
|
+
lines.push("```");
|
|
102
|
+
lines.push("");
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (include.relations && segment.relations && segment.relations.length > 0) {
|
|
108
|
+
lines.push("**Related:**");
|
|
109
|
+
for (const relation of segment.relations) {
|
|
110
|
+
lines.push(`- ${relation.component} (${relation.relationship}): ${relation.note}`);
|
|
111
|
+
}
|
|
112
|
+
lines.push("");
|
|
113
|
+
}
|
|
114
|
+
lines.push("---");
|
|
115
|
+
lines.push("");
|
|
116
|
+
}
|
|
117
|
+
if (blocks && blocks.length > 0) {
|
|
118
|
+
lines.push("## Blocks");
|
|
119
|
+
lines.push("");
|
|
120
|
+
lines.push("Composition patterns showing how components wire together.");
|
|
121
|
+
lines.push("");
|
|
122
|
+
for (const block of blocks) {
|
|
123
|
+
lines.push(`### ${block.name}`);
|
|
124
|
+
lines.push("");
|
|
125
|
+
lines.push(block.description);
|
|
126
|
+
lines.push("");
|
|
127
|
+
lines.push(`**Category:** ${block.category}`);
|
|
128
|
+
lines.push(`**Components:** ${block.components.join(", ")}`);
|
|
129
|
+
if (block.tags && block.tags.length > 0) {
|
|
130
|
+
lines.push(`**Tags:** ${block.tags.join(", ")}`);
|
|
131
|
+
}
|
|
132
|
+
lines.push("");
|
|
133
|
+
lines.push("```tsx");
|
|
134
|
+
lines.push(block.code);
|
|
135
|
+
lines.push("```");
|
|
136
|
+
lines.push("");
|
|
137
|
+
lines.push("---");
|
|
138
|
+
lines.push("");
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const content = lines.join("\n");
|
|
142
|
+
return { content, tokenEstimate: estimateTokens(content) };
|
|
143
|
+
}
|
|
144
|
+
function generateJsonContext(segments, include, compact, blocks) {
|
|
145
|
+
const categories = [...new Set(segments.map((s) => s.meta.category))].sort();
|
|
146
|
+
const components = {};
|
|
147
|
+
for (const segment of segments) {
|
|
148
|
+
const component = {
|
|
149
|
+
category: segment.meta.category,
|
|
150
|
+
description: segment.meta.description
|
|
151
|
+
};
|
|
152
|
+
if (segment.meta.status) {
|
|
153
|
+
component.status = segment.meta.status;
|
|
154
|
+
}
|
|
155
|
+
if (!compact) {
|
|
156
|
+
if (include.usage) {
|
|
157
|
+
const whenFiltered = filterPlaceholders(segment.usage.when);
|
|
158
|
+
const whenNotFiltered = filterPlaceholders(segment.usage.whenNot);
|
|
159
|
+
if (whenFiltered.length > 0) component.whenToUse = whenFiltered;
|
|
160
|
+
if (whenNotFiltered.length > 0) component.whenNotToUse = whenNotFiltered;
|
|
161
|
+
}
|
|
162
|
+
if (include.props && Object.keys(segment.props).length > 0) {
|
|
163
|
+
component.props = {};
|
|
164
|
+
for (const [name, prop] of Object.entries(segment.props)) {
|
|
165
|
+
component.props[name] = {
|
|
166
|
+
type: formatPropType(prop),
|
|
167
|
+
description: prop.description
|
|
168
|
+
};
|
|
169
|
+
if (prop.required) component.props[name].required = true;
|
|
170
|
+
if (prop.default !== void 0) component.props[name].default = prop.default;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (include.variants && segment.variants.length > 0) {
|
|
174
|
+
component.variants = segment.variants.map((v) => v.name);
|
|
175
|
+
}
|
|
176
|
+
if (include.relations && segment.relations && segment.relations.length > 0) {
|
|
177
|
+
component.relations = segment.relations.map((r) => ({
|
|
178
|
+
component: r.component,
|
|
179
|
+
relationship: r.relationship,
|
|
180
|
+
note: r.note
|
|
181
|
+
}));
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
components[segment.meta.name] = component;
|
|
185
|
+
}
|
|
186
|
+
const blocksMap = blocks && blocks.length > 0 ? Object.fromEntries(blocks.map((b) => [b.name, {
|
|
187
|
+
description: b.description,
|
|
188
|
+
category: b.category,
|
|
189
|
+
components: b.components,
|
|
190
|
+
code: b.code,
|
|
191
|
+
tags: b.tags
|
|
192
|
+
}])) : void 0;
|
|
193
|
+
const output = {
|
|
194
|
+
version: "1.0",
|
|
195
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
196
|
+
summary: {
|
|
197
|
+
totalComponents: segments.length,
|
|
198
|
+
categories,
|
|
199
|
+
...blocksMap && { totalBlocks: blocks.length }
|
|
200
|
+
},
|
|
201
|
+
components,
|
|
202
|
+
...blocksMap && { blocks: blocksMap }
|
|
203
|
+
};
|
|
204
|
+
const content = JSON.stringify(output, null, 2);
|
|
205
|
+
return { content, tokenEstimate: estimateTokens(content) };
|
|
206
|
+
}
|
|
207
|
+
function formatPropType(prop) {
|
|
208
|
+
if (prop.type === "enum" && prop.values) {
|
|
209
|
+
return prop.values.map((v) => `"${v}"`).join(" | ");
|
|
210
|
+
}
|
|
211
|
+
if (prop.default !== void 0) {
|
|
212
|
+
return `${prop.type} (default: ${JSON.stringify(prop.default)})`;
|
|
213
|
+
}
|
|
214
|
+
return prop.type;
|
|
215
|
+
}
|
|
216
|
+
function truncate(str, maxLength) {
|
|
217
|
+
if (str.length <= maxLength) return str;
|
|
218
|
+
return str.slice(0, maxLength - 3) + "...";
|
|
219
|
+
}
|
|
220
|
+
function estimateTokens(text) {
|
|
221
|
+
return Math.ceil(text.length / 4);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export {
|
|
225
|
+
PLACEHOLDER_PATTERNS,
|
|
226
|
+
filterPlaceholders,
|
|
227
|
+
generateContext
|
|
228
|
+
};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { a as ScoredChunk } from '../types-B7duBj6U.js';
|
|
2
|
+
|
|
3
|
+
interface CitationDocumentBlock {
|
|
4
|
+
type: "document";
|
|
5
|
+
source: {
|
|
6
|
+
type: "content";
|
|
7
|
+
content: Array<{
|
|
8
|
+
type: "text";
|
|
9
|
+
text: string;
|
|
10
|
+
}>;
|
|
11
|
+
} | {
|
|
12
|
+
type: "text";
|
|
13
|
+
media_type: "text/plain";
|
|
14
|
+
data: string;
|
|
15
|
+
};
|
|
16
|
+
title?: string | null;
|
|
17
|
+
context?: string | null;
|
|
18
|
+
citations: {
|
|
19
|
+
enabled: true;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
interface ChunkMapping {
|
|
23
|
+
/** Position in the content array of the document block. */
|
|
24
|
+
blockIndex: number;
|
|
25
|
+
startLine: number;
|
|
26
|
+
endLine: number;
|
|
27
|
+
language: string;
|
|
28
|
+
symbolName?: string;
|
|
29
|
+
score: number;
|
|
30
|
+
}
|
|
31
|
+
interface DocumentMapping {
|
|
32
|
+
/** Index of this document in the documents array sent to Anthropic. */
|
|
33
|
+
documentIndex: number;
|
|
34
|
+
filePath: string;
|
|
35
|
+
sourceType: "code" | "plaintext";
|
|
36
|
+
chunks: ChunkMapping[];
|
|
37
|
+
}
|
|
38
|
+
interface ResolvedCitation {
|
|
39
|
+
/** 1-indexed display number. */
|
|
40
|
+
index: number;
|
|
41
|
+
citedText: string;
|
|
42
|
+
documentTitle: string | null;
|
|
43
|
+
filePath: string;
|
|
44
|
+
sourceType: "code" | "plaintext";
|
|
45
|
+
startLine?: number;
|
|
46
|
+
endLine?: number;
|
|
47
|
+
language?: string;
|
|
48
|
+
symbolName?: string;
|
|
49
|
+
/** Character position in the response text where this citation appears. */
|
|
50
|
+
textOffset: number;
|
|
51
|
+
}
|
|
52
|
+
interface CitationDocumentOptions {
|
|
53
|
+
/** Extra plain-text documents to include (e.g. spec content, commit history). */
|
|
54
|
+
additionalDocuments?: Array<{
|
|
55
|
+
title: string;
|
|
56
|
+
content: string;
|
|
57
|
+
}>;
|
|
58
|
+
}
|
|
59
|
+
interface RawCitation {
|
|
60
|
+
type: "content_block_location" | "char_location";
|
|
61
|
+
cited_text: string;
|
|
62
|
+
document_index: number;
|
|
63
|
+
document_title: string | null;
|
|
64
|
+
start_block_index?: number;
|
|
65
|
+
end_block_index?: number;
|
|
66
|
+
start_char_index?: number;
|
|
67
|
+
end_char_index?: number;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
interface BuildResult {
|
|
71
|
+
documents: CitationDocumentBlock[];
|
|
72
|
+
documentMap: DocumentMapping[];
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Converts deduplicated ScoredChunk[] into Anthropic-compatible citation
|
|
76
|
+
* document blocks with a mapping table for resolving raw citations back
|
|
77
|
+
* to source file/line metadata.
|
|
78
|
+
*
|
|
79
|
+
* Pipeline position: after deduplicateChunks() → before Anthropic API call.
|
|
80
|
+
*/
|
|
81
|
+
declare function buildCitationDocuments(chunks: ScoredChunk[], options?: CitationDocumentOptions): BuildResult;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Resolves a single raw Anthropic citation against the document map,
|
|
85
|
+
* producing a fully enriched ResolvedCitation with file/line metadata.
|
|
86
|
+
*/
|
|
87
|
+
declare function resolveCitation(raw: RawCitation, documentMap: DocumentMapping[], citationIndex: number, textOffset: number): ResolvedCitation;
|
|
88
|
+
/**
|
|
89
|
+
* Batch-resolves an array of raw citations. Auto-increments citation index
|
|
90
|
+
* starting from 1.
|
|
91
|
+
*/
|
|
92
|
+
declare function resolveCitations(raws: RawCitation[], documentMap: DocumentMapping[], textOffsets: number[]): ResolvedCitation[];
|
|
93
|
+
|
|
94
|
+
export { type ChunkMapping, type CitationDocumentBlock, type CitationDocumentOptions, type DocumentMapping, type RawCitation, type ResolvedCitation, buildCitationDocuments, resolveCitation, resolveCitations };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { CompiledSegment, CompiledBlock } from '../types/index.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Context generation for AI agents.
|
|
5
|
+
*
|
|
6
|
+
* Generates AI-ready context documents from compiled fragment data.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Placeholder patterns to filter out from usage text.
|
|
11
|
+
*/
|
|
12
|
+
declare const PLACEHOLDER_PATTERNS: RegExp[];
|
|
13
|
+
/**
|
|
14
|
+
* Filter out placeholder text from usage arrays
|
|
15
|
+
*/
|
|
16
|
+
declare function filterPlaceholders(items: string[] | undefined): string[];
|
|
17
|
+
/**
|
|
18
|
+
* Options for context generation
|
|
19
|
+
*/
|
|
20
|
+
interface ContextOptions {
|
|
21
|
+
format?: "markdown" | "json";
|
|
22
|
+
include?: {
|
|
23
|
+
props?: boolean;
|
|
24
|
+
variants?: boolean;
|
|
25
|
+
usage?: boolean;
|
|
26
|
+
relations?: boolean;
|
|
27
|
+
code?: boolean;
|
|
28
|
+
};
|
|
29
|
+
compact?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Result of context generation
|
|
33
|
+
*/
|
|
34
|
+
interface ContextResult {
|
|
35
|
+
content: string;
|
|
36
|
+
tokenEstimate: number;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Generate AI-ready context from compiled segments and optional blocks
|
|
40
|
+
*/
|
|
41
|
+
declare function generateContext(segments: CompiledSegment[], options?: ContextOptions, blocks?: CompiledBlock[]): ContextResult;
|
|
42
|
+
|
|
43
|
+
export { type ContextOptions, type ContextResult, PLACEHOLDER_PATTERNS, filterPlaceholders, generateContext };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
export { AIMetadata, CompiledBlock, CompiledSegment, CompiledSegmentsFile, CompiledTokenData, CompiledTokenEntry, ComponentRelation, PropDefinition, SegmentContract, SegmentGenerated, SegmentMeta, SegmentUsage, Theme, VerifyResult } from './types/index.js';
|
|
2
|
+
export { ContextOptions, ContextResult, PLACEHOLDER_PATTERNS, filterPlaceholders, generateContext } from './generate/index.js';
|
|
1
3
|
export { ASTChunkerOptions, ChunkOptions, CodeChunk, chunkByAST, chunkByLines, chunkFile } from './chunking/index.js';
|
|
2
4
|
export { EmbeddingOptions, EmbeddingResult, RerankOptions, RerankResult, generateEmbeddings, rerankResults } from './embeddings/voyage.js';
|
|
3
|
-
export {
|
|
5
|
+
export { deduplicateChunks, reciprocalRankFusion } from './search/index.js';
|
|
6
|
+
export { F as FusedResult, R as RankedResult, a as ScoredChunk, S as SearchResult } from './types-B7duBj6U.js';
|
|
4
7
|
export { AST_SUPPORTED_LANGUAGES, ChangedFiles, FileEntry, GrammarMapping, INDEXABLE_EXTENSIONS, detectLanguage, getTreeSitterGrammar, hashContent, resolveChanges, shouldIndexFile } from './indexing/index.js';
|
|
8
|
+
export { ChunkMapping, CitationDocumentBlock, CitationDocumentOptions, DocumentMapping, RawCitation, ResolvedCitation, buildCitationDocuments, resolveCitation, resolveCitations } from './citations/index.js';
|
package/dist/index.js
CHANGED
|
@@ -22,19 +22,35 @@ import {
|
|
|
22
22
|
getTreeSitterGrammar,
|
|
23
23
|
shouldIndexFile
|
|
24
24
|
} from "./chunk-JFV27WLV.js";
|
|
25
|
+
import {
|
|
26
|
+
PLACEHOLDER_PATTERNS,
|
|
27
|
+
filterPlaceholders,
|
|
28
|
+
generateContext
|
|
29
|
+
} from "./chunk-KKABP4K4.js";
|
|
30
|
+
import {
|
|
31
|
+
buildCitationDocuments,
|
|
32
|
+
resolveCitation,
|
|
33
|
+
resolveCitations
|
|
34
|
+
} from "./chunk-3FEHRHFQ.js";
|
|
25
35
|
export {
|
|
26
36
|
AST_SUPPORTED_LANGUAGES,
|
|
27
37
|
INDEXABLE_EXTENSIONS,
|
|
38
|
+
PLACEHOLDER_PATTERNS,
|
|
39
|
+
buildCitationDocuments,
|
|
28
40
|
chunkByAST,
|
|
29
41
|
chunkByLines,
|
|
30
42
|
chunkFile,
|
|
31
43
|
deduplicateChunks,
|
|
32
44
|
detectLanguage,
|
|
45
|
+
filterPlaceholders,
|
|
46
|
+
generateContext,
|
|
33
47
|
generateEmbeddings,
|
|
34
48
|
getTreeSitterGrammar,
|
|
35
49
|
hashContent,
|
|
36
50
|
reciprocalRankFusion,
|
|
37
51
|
rerankResults,
|
|
38
52
|
resolveChanges,
|
|
53
|
+
resolveCitation,
|
|
54
|
+
resolveCitations,
|
|
39
55
|
shouldIndexFile
|
|
40
56
|
};
|
package/dist/search/index.d.ts
CHANGED
|
@@ -1,40 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
id: string;
|
|
4
|
-
/** Rank position in the result list (0-indexed). */
|
|
5
|
-
rank: number;
|
|
6
|
-
/** Optional score from the search system. */
|
|
7
|
-
score?: number;
|
|
8
|
-
}
|
|
9
|
-
interface RankedResult extends SearchResult {
|
|
10
|
-
/** The content or document associated with this result. */
|
|
11
|
-
content: string;
|
|
12
|
-
/** File path of the source. */
|
|
13
|
-
filePath: string;
|
|
14
|
-
/** Start line in the source file. */
|
|
15
|
-
startLine: number;
|
|
16
|
-
/** End line in the source file. */
|
|
17
|
-
endLine: number;
|
|
18
|
-
}
|
|
19
|
-
interface FusedResult {
|
|
20
|
-
/** Unique identifier for the result. */
|
|
21
|
-
id: string;
|
|
22
|
-
/** Fused RRF score across all result sets. */
|
|
23
|
-
fusedScore: number;
|
|
24
|
-
/** Which result sets contributed to this result. */
|
|
25
|
-
sources: string[];
|
|
26
|
-
}
|
|
27
|
-
interface ScoredChunk {
|
|
28
|
-
id: string;
|
|
29
|
-
content: string;
|
|
30
|
-
filePath: string;
|
|
31
|
-
startLine: number;
|
|
32
|
-
endLine: number;
|
|
33
|
-
language: string;
|
|
34
|
-
score: number;
|
|
35
|
-
symbolName?: string;
|
|
36
|
-
chunkType?: string;
|
|
37
|
-
}
|
|
1
|
+
import { S as SearchResult, F as FusedResult, a as ScoredChunk } from '../types-B7duBj6U.js';
|
|
2
|
+
export { R as RankedResult } from '../types-B7duBj6U.js';
|
|
38
3
|
|
|
39
4
|
/**
|
|
40
5
|
* Reciprocal Rank Fusion (RRF) — merges multiple ranked result lists
|
|
@@ -61,4 +26,4 @@ declare function reciprocalRankFusion(resultSets: Array<{
|
|
|
61
26
|
*/
|
|
62
27
|
declare function deduplicateChunks(chunks: ScoredChunk[]): ScoredChunk[];
|
|
63
28
|
|
|
64
|
-
export {
|
|
29
|
+
export { FusedResult, ScoredChunk, SearchResult, deduplicateChunks, reciprocalRankFusion };
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compiled fragment types — shared between CLI and MCP packages.
|
|
3
|
+
*
|
|
4
|
+
* These are the JSON-serializable types used in fragments.json and consumed
|
|
5
|
+
* by AI agents, MCP servers, and context generators.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Component metadata
|
|
9
|
+
*/
|
|
10
|
+
interface SegmentMeta {
|
|
11
|
+
name: string;
|
|
12
|
+
description: string;
|
|
13
|
+
category: string;
|
|
14
|
+
tags?: string[];
|
|
15
|
+
status?: "stable" | "beta" | "deprecated" | "experimental";
|
|
16
|
+
since?: string;
|
|
17
|
+
figma?: string;
|
|
18
|
+
figmaProps?: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Usage guidelines for AI agents and developers
|
|
22
|
+
*/
|
|
23
|
+
interface SegmentUsage {
|
|
24
|
+
when: string[];
|
|
25
|
+
whenNot: string[];
|
|
26
|
+
guidelines?: string[];
|
|
27
|
+
accessibility?: string[];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Definition for a single prop
|
|
31
|
+
*/
|
|
32
|
+
interface PropDefinition {
|
|
33
|
+
type: string;
|
|
34
|
+
values?: readonly string[];
|
|
35
|
+
default?: unknown;
|
|
36
|
+
description: string;
|
|
37
|
+
required?: boolean;
|
|
38
|
+
constraints?: string[];
|
|
39
|
+
typeDetails?: Record<string, unknown>;
|
|
40
|
+
controlType?: string;
|
|
41
|
+
controlOptions?: {
|
|
42
|
+
min?: number;
|
|
43
|
+
max?: number;
|
|
44
|
+
step?: number;
|
|
45
|
+
presetColors?: string[];
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Relationship to another component
|
|
50
|
+
*/
|
|
51
|
+
interface ComponentRelation {
|
|
52
|
+
component: string;
|
|
53
|
+
relationship: string;
|
|
54
|
+
note: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Agent-optimized contract metadata
|
|
58
|
+
*/
|
|
59
|
+
interface SegmentContract {
|
|
60
|
+
propsSummary?: string[];
|
|
61
|
+
a11yRules?: string[];
|
|
62
|
+
bans?: Array<{
|
|
63
|
+
pattern: string;
|
|
64
|
+
message: string;
|
|
65
|
+
}>;
|
|
66
|
+
scenarioTags?: string[];
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Provenance tracking for generated segments
|
|
70
|
+
*/
|
|
71
|
+
interface SegmentGenerated {
|
|
72
|
+
source: "storybook" | "manual" | "ai";
|
|
73
|
+
sourceFile?: string;
|
|
74
|
+
confidence?: number;
|
|
75
|
+
timestamp?: string;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* AI-specific metadata
|
|
79
|
+
*/
|
|
80
|
+
interface AIMetadata {
|
|
81
|
+
compositionPattern?: "compound" | "simple" | "controlled";
|
|
82
|
+
subComponents?: string[];
|
|
83
|
+
requiredChildren?: string[];
|
|
84
|
+
commonPatterns?: string[];
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Compiled segment data (JSON-serializable for AI consumption)
|
|
88
|
+
*/
|
|
89
|
+
interface CompiledSegment {
|
|
90
|
+
filePath: string;
|
|
91
|
+
meta: SegmentMeta;
|
|
92
|
+
usage: SegmentUsage;
|
|
93
|
+
props: Record<string, PropDefinition>;
|
|
94
|
+
relations?: ComponentRelation[];
|
|
95
|
+
variants: Array<{
|
|
96
|
+
name: string;
|
|
97
|
+
description: string;
|
|
98
|
+
code?: string;
|
|
99
|
+
figma?: string;
|
|
100
|
+
args?: Record<string, unknown>;
|
|
101
|
+
}>;
|
|
102
|
+
contract?: SegmentContract;
|
|
103
|
+
ai?: AIMetadata;
|
|
104
|
+
_generated?: SegmentGenerated;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Compiled block data (JSON-serializable for AI consumption)
|
|
108
|
+
*/
|
|
109
|
+
interface CompiledBlock {
|
|
110
|
+
filePath: string;
|
|
111
|
+
name: string;
|
|
112
|
+
description: string;
|
|
113
|
+
category: string;
|
|
114
|
+
components: string[];
|
|
115
|
+
code: string;
|
|
116
|
+
tags?: string[];
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* A single token entry in the compiled output
|
|
120
|
+
*/
|
|
121
|
+
interface CompiledTokenEntry {
|
|
122
|
+
name: string;
|
|
123
|
+
description?: string;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Compiled token data stored in fragments.json
|
|
127
|
+
*/
|
|
128
|
+
interface CompiledTokenData {
|
|
129
|
+
prefix: string;
|
|
130
|
+
total: number;
|
|
131
|
+
categories: Record<string, CompiledTokenEntry[]>;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* The compiled fragments.json structure
|
|
135
|
+
*/
|
|
136
|
+
interface CompiledSegmentsFile {
|
|
137
|
+
version: string;
|
|
138
|
+
generatedAt: string;
|
|
139
|
+
packageName?: string;
|
|
140
|
+
segments: Record<string, CompiledSegment>;
|
|
141
|
+
blocks?: Record<string, CompiledBlock>;
|
|
142
|
+
tokens?: CompiledTokenData;
|
|
143
|
+
/** @deprecated Use blocks instead */
|
|
144
|
+
recipes?: Record<string, CompiledBlock>;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Theme identifier
|
|
148
|
+
*/
|
|
149
|
+
type Theme = "light" | "dark";
|
|
150
|
+
/**
|
|
151
|
+
* Verification result
|
|
152
|
+
*/
|
|
153
|
+
interface VerifyResult {
|
|
154
|
+
verdict: "pass" | "fail" | "error";
|
|
155
|
+
matches: boolean;
|
|
156
|
+
diffPercentage: number;
|
|
157
|
+
screenshot: string;
|
|
158
|
+
baseline: string;
|
|
159
|
+
diffImage?: string;
|
|
160
|
+
notes: string[];
|
|
161
|
+
error?: string;
|
|
162
|
+
timing: {
|
|
163
|
+
renderMs: number;
|
|
164
|
+
captureMs: number;
|
|
165
|
+
diffMs: number;
|
|
166
|
+
totalMs: number;
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export type { AIMetadata, CompiledBlock, CompiledSegment, CompiledSegmentsFile, CompiledTokenData, CompiledTokenEntry, ComponentRelation, PropDefinition, SegmentContract, SegmentGenerated, SegmentMeta, SegmentUsage, Theme, VerifyResult };
|
|
File without changes
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
interface SearchResult {
|
|
2
|
+
/** Unique identifier for the result. */
|
|
3
|
+
id: string;
|
|
4
|
+
/** Rank position in the result list (0-indexed). */
|
|
5
|
+
rank: number;
|
|
6
|
+
/** Optional score from the search system. */
|
|
7
|
+
score?: number;
|
|
8
|
+
}
|
|
9
|
+
interface RankedResult extends SearchResult {
|
|
10
|
+
/** The content or document associated with this result. */
|
|
11
|
+
content: string;
|
|
12
|
+
/** File path of the source. */
|
|
13
|
+
filePath: string;
|
|
14
|
+
/** Start line in the source file. */
|
|
15
|
+
startLine: number;
|
|
16
|
+
/** End line in the source file. */
|
|
17
|
+
endLine: number;
|
|
18
|
+
}
|
|
19
|
+
interface FusedResult {
|
|
20
|
+
/** Unique identifier for the result. */
|
|
21
|
+
id: string;
|
|
22
|
+
/** Fused RRF score across all result sets. */
|
|
23
|
+
fusedScore: number;
|
|
24
|
+
/** Which result sets contributed to this result. */
|
|
25
|
+
sources: string[];
|
|
26
|
+
}
|
|
27
|
+
interface ScoredChunk {
|
|
28
|
+
id: string;
|
|
29
|
+
content: string;
|
|
30
|
+
filePath: string;
|
|
31
|
+
startLine: number;
|
|
32
|
+
endLine: number;
|
|
33
|
+
language: string;
|
|
34
|
+
score: number;
|
|
35
|
+
symbolName?: string;
|
|
36
|
+
chunkType?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export type { FusedResult as F, RankedResult as R, SearchResult as S, ScoredChunk as a };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fragments-sdk/context",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Code intelligence and RAG primitives for design system and codebase indexing",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -26,6 +26,18 @@
|
|
|
26
26
|
"./indexing": {
|
|
27
27
|
"types": "./dist/indexing/index.d.ts",
|
|
28
28
|
"import": "./dist/indexing/index.js"
|
|
29
|
+
},
|
|
30
|
+
"./types": {
|
|
31
|
+
"types": "./dist/types/index.d.ts",
|
|
32
|
+
"import": "./dist/types/index.js"
|
|
33
|
+
},
|
|
34
|
+
"./generate": {
|
|
35
|
+
"types": "./dist/generate/index.d.ts",
|
|
36
|
+
"import": "./dist/generate/index.js"
|
|
37
|
+
},
|
|
38
|
+
"./citations": {
|
|
39
|
+
"types": "./dist/citations/index.d.ts",
|
|
40
|
+
"import": "./dist/citations/index.js"
|
|
29
41
|
}
|
|
30
42
|
},
|
|
31
43
|
"publishConfig": {
|
|
@@ -38,7 +50,7 @@
|
|
|
38
50
|
"build": "tsup",
|
|
39
51
|
"dev": "tsup --watch",
|
|
40
52
|
"lint": "eslint src",
|
|
41
|
-
"test": "vitest run",
|
|
53
|
+
"test": "vitest run --passWithNoTests",
|
|
42
54
|
"typecheck": "tsc --noEmit",
|
|
43
55
|
"clean": "rm -rf dist"
|
|
44
56
|
},
|