@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 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,10 @@
1
+ import {
2
+ buildCitationDocuments,
3
+ resolveCitation,
4
+ resolveCitations
5
+ } from "../chunk-3FEHRHFQ.js";
6
+ export {
7
+ buildCitationDocuments,
8
+ resolveCitation,
9
+ resolveCitations
10
+ };
@@ -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 };
@@ -0,0 +1,10 @@
1
+ import {
2
+ PLACEHOLDER_PATTERNS,
3
+ filterPlaceholders,
4
+ generateContext
5
+ } from "../chunk-KKABP4K4.js";
6
+ export {
7
+ PLACEHOLDER_PATTERNS,
8
+ filterPlaceholders,
9
+ generateContext
10
+ };
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 { FusedResult, RankedResult, ScoredChunk, SearchResult, deduplicateChunks, reciprocalRankFusion } from './search/index.js';
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
  };
@@ -1,40 +1,5 @@
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
- }
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 { type FusedResult, type RankedResult, type ScoredChunk, type SearchResult, deduplicateChunks, reciprocalRankFusion };
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.2",
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
  },