@milo4jo/contextkit 0.1.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.
Files changed (110) hide show
  1. package/README.md +181 -0
  2. package/dist/commands/index-cmd.d.ts +3 -0
  3. package/dist/commands/index-cmd.d.ts.map +1 -0
  4. package/dist/commands/index-cmd.js +111 -0
  5. package/dist/commands/index-cmd.js.map +1 -0
  6. package/dist/commands/init.d.ts +3 -0
  7. package/dist/commands/init.d.ts.map +1 -0
  8. package/dist/commands/init.js +56 -0
  9. package/dist/commands/init.js.map +1 -0
  10. package/dist/commands/select.d.ts +3 -0
  11. package/dist/commands/select.d.ts.map +1 -0
  12. package/dist/commands/select.js +64 -0
  13. package/dist/commands/select.js.map +1 -0
  14. package/dist/commands/source/add.d.ts +3 -0
  15. package/dist/commands/source/add.d.ts.map +1 -0
  16. package/dist/commands/source/add.js +87 -0
  17. package/dist/commands/source/add.js.map +1 -0
  18. package/dist/commands/source/index.d.ts +3 -0
  19. package/dist/commands/source/index.d.ts.map +1 -0
  20. package/dist/commands/source/index.js +14 -0
  21. package/dist/commands/source/index.js.map +1 -0
  22. package/dist/commands/source/list.d.ts +3 -0
  23. package/dist/commands/source/list.d.ts.map +1 -0
  24. package/dist/commands/source/list.js +46 -0
  25. package/dist/commands/source/list.js.map +1 -0
  26. package/dist/commands/source/remove.d.ts +3 -0
  27. package/dist/commands/source/remove.d.ts.map +1 -0
  28. package/dist/commands/source/remove.js +38 -0
  29. package/dist/commands/source/remove.js.map +1 -0
  30. package/dist/commands/source.d.ts +3 -0
  31. package/dist/commands/source.d.ts.map +1 -0
  32. package/dist/commands/source.js +153 -0
  33. package/dist/commands/source.js.map +1 -0
  34. package/dist/config/index.d.ts +38 -0
  35. package/dist/config/index.d.ts.map +1 -0
  36. package/dist/config/index.js +100 -0
  37. package/dist/config/index.js.map +1 -0
  38. package/dist/config/types.d.ts +21 -0
  39. package/dist/config/types.d.ts.map +1 -0
  40. package/dist/config/types.js +5 -0
  41. package/dist/config/types.js.map +1 -0
  42. package/dist/db/index.d.ts +14 -0
  43. package/dist/db/index.d.ts.map +1 -0
  44. package/dist/db/index.js +63 -0
  45. package/dist/db/index.js.map +1 -0
  46. package/dist/errors/index.d.ts +30 -0
  47. package/dist/errors/index.d.ts.map +1 -0
  48. package/dist/errors/index.js +51 -0
  49. package/dist/errors/index.js.map +1 -0
  50. package/dist/index.d.ts +3 -0
  51. package/dist/index.d.ts.map +1 -0
  52. package/dist/index.js +90 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/indexer/chunker.d.ts +44 -0
  55. package/dist/indexer/chunker.d.ts.map +1 -0
  56. package/dist/indexer/chunker.js +102 -0
  57. package/dist/indexer/chunker.js.map +1 -0
  58. package/dist/indexer/discovery.d.ts +34 -0
  59. package/dist/indexer/discovery.d.ts.map +1 -0
  60. package/dist/indexer/discovery.js +66 -0
  61. package/dist/indexer/discovery.js.map +1 -0
  62. package/dist/indexer/embeddings.d.ts +32 -0
  63. package/dist/indexer/embeddings.d.ts.map +1 -0
  64. package/dist/indexer/embeddings.js +85 -0
  65. package/dist/indexer/embeddings.js.map +1 -0
  66. package/dist/indexer/index.d.ts +37 -0
  67. package/dist/indexer/index.d.ts.map +1 -0
  68. package/dist/indexer/index.js +123 -0
  69. package/dist/indexer/index.js.map +1 -0
  70. package/dist/selector/budget.d.ts +26 -0
  71. package/dist/selector/budget.d.ts.map +1 -0
  72. package/dist/selector/budget.js +75 -0
  73. package/dist/selector/budget.js.map +1 -0
  74. package/dist/selector/formatter.d.ts +44 -0
  75. package/dist/selector/formatter.d.ts.map +1 -0
  76. package/dist/selector/formatter.js +114 -0
  77. package/dist/selector/formatter.js.map +1 -0
  78. package/dist/selector/index.d.ts +37 -0
  79. package/dist/selector/index.d.ts.map +1 -0
  80. package/dist/selector/index.js +67 -0
  81. package/dist/selector/index.js.map +1 -0
  82. package/dist/selector/scoring.d.ts +26 -0
  83. package/dist/selector/scoring.d.ts.map +1 -0
  84. package/dist/selector/scoring.js +113 -0
  85. package/dist/selector/scoring.js.map +1 -0
  86. package/dist/selector/search.d.ts +29 -0
  87. package/dist/selector/search.d.ts.map +1 -0
  88. package/dist/selector/search.js +48 -0
  89. package/dist/selector/search.js.map +1 -0
  90. package/dist/utils/cli.d.ts +20 -0
  91. package/dist/utils/cli.d.ts.map +1 -0
  92. package/dist/utils/cli.js +19 -0
  93. package/dist/utils/cli.js.map +1 -0
  94. package/dist/utils/format.d.ts +30 -0
  95. package/dist/utils/format.d.ts.map +1 -0
  96. package/dist/utils/format.js +44 -0
  97. package/dist/utils/format.js.map +1 -0
  98. package/dist/utils/output.d.ts +42 -0
  99. package/dist/utils/output.d.ts.map +1 -0
  100. package/dist/utils/output.js +62 -0
  101. package/dist/utils/output.js.map +1 -0
  102. package/dist/utils/prompts.d.ts +23 -0
  103. package/dist/utils/prompts.d.ts.map +1 -0
  104. package/dist/utils/prompts.js +46 -0
  105. package/dist/utils/prompts.js.map +1 -0
  106. package/dist/utils/streams.d.ts +40 -0
  107. package/dist/utils/streams.d.ts.map +1 -0
  108. package/dist/utils/streams.js +61 -0
  109. package/dist/utils/streams.js.map +1 -0
  110. package/package.json +67 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/indexer/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Budget Fitting Module
3
+ *
4
+ * Selects chunks to fit within a token budget.
5
+ * Prefers keeping chunks from the same file together.
6
+ */
7
+ import type { RankedChunk } from './scoring.js';
8
+ /** Selection result */
9
+ export interface BudgetResult {
10
+ /** Selected chunks */
11
+ chunks: RankedChunk[];
12
+ /** Total tokens used */
13
+ totalTokens: number;
14
+ /** Chunks that didn't fit */
15
+ excluded: number;
16
+ }
17
+ /**
18
+ * Select chunks that fit within budget
19
+ */
20
+ export declare function fitToBudget(chunks: RankedChunk[], budget: number): BudgetResult;
21
+ /**
22
+ * Merge adjacent chunks from the same file
23
+ * (Optional optimization for cleaner output)
24
+ */
25
+ export declare function mergeAdjacentChunks(chunks: RankedChunk[]): RankedChunk[];
26
+ //# sourceMappingURL=budget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.d.ts","sourceRoot":"","sources":["../../src/selector/budget.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,uBAAuB;AACvB,MAAM,WAAW,YAAY;IAC3B,sBAAsB;IACtB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,wBAAwB;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,CAsC/E;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE,CA8BxE"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Budget Fitting Module
3
+ *
4
+ * Selects chunks to fit within a token budget.
5
+ * Prefers keeping chunks from the same file together.
6
+ */
7
+ /**
8
+ * Select chunks that fit within budget
9
+ */
10
+ export function fitToBudget(chunks, budget) {
11
+ const selected = [];
12
+ let totalTokens = 0;
13
+ let excluded = 0;
14
+ // Track which files we've started including
15
+ const includedFiles = new Set();
16
+ for (const chunk of chunks) {
17
+ const wouldExceed = totalTokens + chunk.tokens > budget;
18
+ if (wouldExceed) {
19
+ excluded++;
20
+ continue;
21
+ }
22
+ // Bonus: if we've already included chunks from this file,
23
+ // slightly prefer including more from the same file
24
+ // (This is handled implicitly by processing in score order,
25
+ // but we could add explicit grouping here later)
26
+ selected.push(chunk);
27
+ totalTokens += chunk.tokens;
28
+ includedFiles.add(chunk.filePath);
29
+ }
30
+ // Re-sort selected chunks by file, then by line number for output
31
+ selected.sort((a, b) => {
32
+ const fileCompare = a.filePath.localeCompare(b.filePath);
33
+ if (fileCompare !== 0)
34
+ return fileCompare;
35
+ return a.startLine - b.startLine;
36
+ });
37
+ return {
38
+ chunks: selected,
39
+ totalTokens,
40
+ excluded,
41
+ };
42
+ }
43
+ /**
44
+ * Merge adjacent chunks from the same file
45
+ * (Optional optimization for cleaner output)
46
+ */
47
+ export function mergeAdjacentChunks(chunks) {
48
+ if (chunks.length <= 1)
49
+ return chunks;
50
+ const merged = [];
51
+ let current = { ...chunks[0] };
52
+ for (let i = 1; i < chunks.length; i++) {
53
+ const next = chunks[i];
54
+ // Check if adjacent (same file, consecutive lines)
55
+ const isAdjacent = current.filePath === next.filePath && current.endLine + 1 >= next.startLine;
56
+ if (isAdjacent) {
57
+ // Merge chunks
58
+ current = {
59
+ ...current,
60
+ content: current.content + '\n' + next.content,
61
+ endLine: next.endLine,
62
+ tokens: current.tokens + next.tokens,
63
+ score: Math.max(current.score, next.score),
64
+ similarity: Math.max(current.similarity, next.similarity),
65
+ };
66
+ }
67
+ else {
68
+ merged.push(current);
69
+ current = { ...next };
70
+ }
71
+ }
72
+ merged.push(current);
73
+ return merged;
74
+ }
75
+ //# sourceMappingURL=budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.js","sourceRoot":"","sources":["../../src/selector/budget.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAcH;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,MAAqB,EAAE,MAAc;IAC/D,MAAM,QAAQ,GAAkB,EAAE,CAAC;IACnC,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,IAAI,QAAQ,GAAG,CAAC,CAAC;IAEjB,4CAA4C;IAC5C,MAAM,aAAa,GAAG,IAAI,GAAG,EAAU,CAAC;IAExC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,WAAW,GAAG,WAAW,GAAG,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;QAExD,IAAI,WAAW,EAAE,CAAC;YAChB,QAAQ,EAAE,CAAC;YACX,SAAS;QACX,CAAC;QAED,0DAA0D;QAC1D,oDAAoD;QACpD,4DAA4D;QAC5D,iDAAiD;QAEjD,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,WAAW,IAAI,KAAK,CAAC,MAAM,CAAC;QAC5B,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC;IAED,kEAAkE;IAClE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACrB,MAAM,WAAW,GAAG,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QACzD,IAAI,WAAW,KAAK,CAAC;YAAE,OAAO,WAAW,CAAC;QAC1C,OAAO,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,MAAM,EAAE,QAAQ;QAChB,WAAW;QACX,QAAQ;KACT,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAqB;IACvD,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC;IAEtC,MAAM,MAAM,GAAkB,EAAE,CAAC;IACjC,IAAI,OAAO,GAAG,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IAE/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QAEvB,mDAAmD;QACnD,MAAM,UAAU,GAAG,OAAO,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,OAAO,GAAG,CAAC,IAAI,IAAI,CAAC,SAAS,CAAC;QAE/F,IAAI,UAAU,EAAE,CAAC;YACf,eAAe;YACf,OAAO,GAAG;gBACR,GAAG,OAAO;gBACV,OAAO,EAAE,OAAO,CAAC,OAAO,GAAG,IAAI,GAAG,IAAI,CAAC,OAAO;gBAC9C,OAAO,EAAE,IAAI,CAAC,OAAO;gBACrB,MAAM,EAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM;gBACpC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC;gBAC1C,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC;aAC1D,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACrB,OAAO,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;QACxB,CAAC;IACH,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACrB,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Output Formatter Module
3
+ *
4
+ * Formats selected chunks for display.
5
+ */
6
+ import type { BudgetResult } from './budget.js';
7
+ /** Formatted output */
8
+ export interface FormattedOutput {
9
+ /** Human-readable text output */
10
+ text: string;
11
+ /** Structured data for JSON output */
12
+ data: SelectionData;
13
+ }
14
+ /** Structured selection data */
15
+ export interface SelectionData {
16
+ query: string;
17
+ context: string;
18
+ chunks: ChunkInfo[];
19
+ stats: SelectionStats;
20
+ }
21
+ /** Chunk info for JSON output */
22
+ export interface ChunkInfo {
23
+ file: string;
24
+ lines: [number, number];
25
+ tokens: number;
26
+ score: number;
27
+ }
28
+ /** Selection statistics */
29
+ export interface SelectionStats {
30
+ totalTokens: number;
31
+ chunksConsidered: number;
32
+ chunksIncluded: number;
33
+ filesIncluded: number;
34
+ timeMs: number;
35
+ }
36
+ /**
37
+ * Format selection results for output
38
+ */
39
+ export declare function formatOutput(query: string, result: BudgetResult, totalConsidered: number, timeMs: number): FormattedOutput;
40
+ /**
41
+ * Format output with --explain details
42
+ */
43
+ export declare function formatWithExplanation(query: string, result: BudgetResult, totalConsidered: number, timeMs: number): FormattedOutput;
44
+ //# sourceMappingURL=formatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../src/selector/formatter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,uBAAuB;AACvB,MAAM,WAAW,eAAe;IAC9B,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,IAAI,EAAE,aAAa,CAAC;CACrB;AAED,gCAAgC;AAChC,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,KAAK,EAAE,cAAc,CAAC;CACvB;AAED,iCAAiC;AACjC,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,2BAA2B;AAC3B,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,YAAY,EACpB,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,GACb,eAAe,CAqDjB;AA8CD;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,YAAY,EACpB,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,GACb,eAAe,CAmBjB"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Output Formatter Module
3
+ *
4
+ * Formats selected chunks for display.
5
+ */
6
+ /**
7
+ * Format selection results for output
8
+ */
9
+ export function formatOutput(query, result, totalConsidered, timeMs) {
10
+ const { chunks, totalTokens } = result;
11
+ // Group chunks by file
12
+ const fileGroups = new Map();
13
+ for (const chunk of chunks) {
14
+ const existing = fileGroups.get(chunk.filePath) || [];
15
+ existing.push(chunk);
16
+ fileGroups.set(chunk.filePath, existing);
17
+ }
18
+ // Build text output
19
+ const textParts = [];
20
+ for (const [filePath, fileChunks] of fileGroups) {
21
+ // Sort chunks by line number within file
22
+ fileChunks.sort((a, b) => a.startLine - b.startLine);
23
+ for (const chunk of fileChunks) {
24
+ const header = `## ${filePath} (lines ${chunk.startLine}-${chunk.endLine})`;
25
+ const codeBlock = formatCodeBlock(chunk.content, filePath);
26
+ textParts.push(`${header}\n${codeBlock}`);
27
+ }
28
+ }
29
+ // Add stats footer
30
+ const filesCount = fileGroups.size;
31
+ const statsLine = `📊 ${totalTokens.toLocaleString()} tokens | ${chunks.length} chunks | ${filesCount} files`;
32
+ const text = textParts.join('\n\n') + '\n\n---\n' + statsLine;
33
+ // Build structured data
34
+ const chunkInfos = chunks.map((c) => ({
35
+ file: c.filePath,
36
+ lines: [c.startLine, c.endLine],
37
+ tokens: c.tokens,
38
+ score: Math.round(c.score * 1000) / 1000,
39
+ }));
40
+ const data = {
41
+ query,
42
+ context: textParts.join('\n\n'),
43
+ chunks: chunkInfos,
44
+ stats: {
45
+ totalTokens,
46
+ chunksConsidered: totalConsidered,
47
+ chunksIncluded: chunks.length,
48
+ filesIncluded: filesCount,
49
+ timeMs,
50
+ },
51
+ };
52
+ return { text, data };
53
+ }
54
+ /**
55
+ * Format content as a code block with language hint
56
+ */
57
+ function formatCodeBlock(content, filePath) {
58
+ const lang = getLanguage(filePath);
59
+ return '```' + lang + '\n' + content + '\n```';
60
+ }
61
+ /**
62
+ * Get language hint from file extension
63
+ */
64
+ function getLanguage(filePath) {
65
+ const ext = filePath.split('.').pop()?.toLowerCase() || '';
66
+ const langMap = {
67
+ ts: 'typescript',
68
+ tsx: 'tsx',
69
+ js: 'javascript',
70
+ jsx: 'jsx',
71
+ py: 'python',
72
+ rb: 'ruby',
73
+ go: 'go',
74
+ rs: 'rust',
75
+ java: 'java',
76
+ kt: 'kotlin',
77
+ cs: 'csharp',
78
+ cpp: 'cpp',
79
+ c: 'c',
80
+ h: 'c',
81
+ hpp: 'cpp',
82
+ md: 'markdown',
83
+ json: 'json',
84
+ yaml: 'yaml',
85
+ yml: 'yaml',
86
+ toml: 'toml',
87
+ sql: 'sql',
88
+ sh: 'bash',
89
+ bash: 'bash',
90
+ zsh: 'bash',
91
+ };
92
+ return langMap[ext] || '';
93
+ }
94
+ /**
95
+ * Format output with --explain details
96
+ */
97
+ export function formatWithExplanation(query, result, totalConsidered, timeMs) {
98
+ const base = formatOutput(query, result, totalConsidered, timeMs);
99
+ // Add explanation section
100
+ const explanations = result.chunks.map((chunk) => {
101
+ const { similarity, recency, pathMatch } = chunk.scoreBreakdown;
102
+ return ` ${chunk.filePath}:${chunk.startLine}
103
+ similarity: ${(similarity * 100).toFixed(1)}%
104
+ recency: ${(recency * 100).toFixed(1)}%
105
+ path_match: ${(pathMatch * 100).toFixed(1)}%
106
+ → score: ${(chunk.score * 100).toFixed(1)}%`;
107
+ });
108
+ const explainSection = '\n\n## Scoring Details\n\n' + explanations.join('\n\n');
109
+ return {
110
+ text: base.text + explainSection,
111
+ data: base.data,
112
+ };
113
+ }
114
+ //# sourceMappingURL=formatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatter.js","sourceRoot":"","sources":["../../src/selector/formatter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Main Selector Module
3
+ *
4
+ * Orchestrates the selection pipeline:
5
+ * 1. Search for similar chunks
6
+ * 2. Score and rank
7
+ * 3. Fit to budget
8
+ * 4. Format output
9
+ */
10
+ import Database from 'better-sqlite3';
11
+ import { type FormattedOutput } from './formatter.js';
12
+ /** Selection options */
13
+ export interface SelectOptions {
14
+ /** Query to find context for */
15
+ query: string;
16
+ /** Maximum tokens to include */
17
+ budget: number;
18
+ /** Filter to specific sources */
19
+ sources?: string[];
20
+ /** Show scoring explanation */
21
+ explain?: boolean;
22
+ }
23
+ /** Selection result */
24
+ export interface SelectResult {
25
+ /** Formatted output */
26
+ output: FormattedOutput;
27
+ /** Whether index is empty */
28
+ isEmpty: boolean;
29
+ }
30
+ /**
31
+ * Select optimal context for a query
32
+ */
33
+ export declare function selectContext(db: Database.Database, options: SelectOptions): Promise<SelectResult>;
34
+ export type { FormattedOutput, SelectionData, SelectionStats, ChunkInfo } from './formatter.js';
35
+ export type { ScoredChunk } from './search.js';
36
+ export type { RankedChunk } from './scoring.js';
37
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/selector/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAItC,OAAO,EAAuC,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAE3F,wBAAwB;AACxB,MAAM,WAAW,aAAa;IAC5B,gCAAgC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,gCAAgC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,+BAA+B;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,uBAAuB;AACvB,MAAM,WAAW,YAAY;IAC3B,uBAAuB;IACvB,MAAM,EAAE,eAAe,CAAC;IACxB,6BAA6B;IAC7B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,aAAa,CACjC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,YAAY,CAAC,CAwDvB;AAGD,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChG,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Main Selector Module
3
+ *
4
+ * Orchestrates the selection pipeline:
5
+ * 1. Search for similar chunks
6
+ * 2. Score and rank
7
+ * 3. Fit to budget
8
+ * 4. Format output
9
+ */
10
+ import { searchSimilar } from './search.js';
11
+ import { rankChunks } from './scoring.js';
12
+ import { fitToBudget, mergeAdjacentChunks } from './budget.js';
13
+ import { formatOutput, formatWithExplanation } from './formatter.js';
14
+ /**
15
+ * Select optimal context for a query
16
+ */
17
+ export async function selectContext(db, options) {
18
+ const startTime = Date.now();
19
+ // Check if index has any chunks
20
+ const countResult = db.prepare('SELECT COUNT(*) as count FROM chunks').get();
21
+ if (countResult.count === 0) {
22
+ return {
23
+ output: {
24
+ text: '',
25
+ data: {
26
+ query: options.query,
27
+ context: '',
28
+ chunks: [],
29
+ stats: {
30
+ totalTokens: 0,
31
+ chunksConsidered: 0,
32
+ chunksIncluded: 0,
33
+ filesIncluded: 0,
34
+ timeMs: 0,
35
+ },
36
+ },
37
+ },
38
+ isEmpty: true,
39
+ };
40
+ }
41
+ // Step 1: Search for similar chunks
42
+ const searchOpts = {
43
+ limit: 50,
44
+ sources: options.sources,
45
+ };
46
+ const similarChunks = await searchSimilar(db, options.query, searchOpts);
47
+ // Step 2: Score and rank
48
+ const rankedChunks = rankChunks(similarChunks, options.query);
49
+ // Step 3: Fit to budget
50
+ const budgetResult = fitToBudget(rankedChunks, options.budget);
51
+ // Step 4: Merge adjacent chunks for cleaner output
52
+ const mergedChunks = mergeAdjacentChunks(budgetResult.chunks);
53
+ const mergedResult = {
54
+ ...budgetResult,
55
+ chunks: mergedChunks,
56
+ };
57
+ // Step 5: Format output
58
+ const timeMs = Date.now() - startTime;
59
+ const output = options.explain
60
+ ? formatWithExplanation(options.query, mergedResult, similarChunks.length, timeMs)
61
+ : formatOutput(options.query, mergedResult, similarChunks.length, timeMs);
62
+ return {
63
+ output,
64
+ isEmpty: false,
65
+ };
66
+ }
67
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/selector/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,aAAa,EAAsB,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAwB,MAAM,gBAAgB,CAAC;AAsB3F;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,EAAqB,EACrB,OAAsB;IAEtB,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,gCAAgC;IAChC,MAAM,WAAW,GAAG,EAAE,CAAC,OAAO,CAAC,sCAAsC,CAAC,CAAC,GAAG,EAAuB,CAAC;IAClG,IAAI,WAAW,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO;YACL,MAAM,EAAE;gBACN,IAAI,EAAE,EAAE;gBACR,IAAI,EAAE;oBACJ,KAAK,EAAE,OAAO,CAAC,KAAK;oBACpB,OAAO,EAAE,EAAE;oBACX,MAAM,EAAE,EAAE;oBACV,KAAK,EAAE;wBACL,WAAW,EAAE,CAAC;wBACd,gBAAgB,EAAE,CAAC;wBACnB,cAAc,EAAE,CAAC;wBACjB,aAAa,EAAE,CAAC;wBAChB,MAAM,EAAE,CAAC;qBACV;iBACF;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;IAED,oCAAoC;IACpC,MAAM,UAAU,GAAkB;QAChC,KAAK,EAAE,EAAE;QACT,OAAO,EAAE,OAAO,CAAC,OAAO;KACzB,CAAC;IACF,MAAM,aAAa,GAAG,MAAM,aAAa,CAAC,EAAE,EAAE,OAAO,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IAEzE,yBAAyB;IACzB,MAAM,YAAY,GAAG,UAAU,CAAC,aAAa,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAE9D,wBAAwB;IACxB,MAAM,YAAY,GAAG,WAAW,CAAC,YAAY,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAE/D,mDAAmD;IACnD,MAAM,YAAY,GAAG,mBAAmB,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;IAC9D,MAAM,YAAY,GAAG;QACnB,GAAG,YAAY;QACf,MAAM,EAAE,YAAY;KACrB,CAAC;IAEF,wBAAwB;IACxB,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;IACtC,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO;QAC5B,CAAC,CAAC,qBAAqB,CAAC,OAAO,CAAC,KAAK,EAAE,YAAY,EAAE,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC;QAClF,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,YAAY,EAAE,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE5E,OAAO;QACL,MAAM;QACN,OAAO,EAAE,KAAK;KACf,CAAC;AACJ,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Scoring Module
3
+ *
4
+ * Calculates final scores for chunks based on multiple signals.
5
+ *
6
+ * Score = 0.6 × semantic_similarity
7
+ * + 0.2 × recency_bonus
8
+ * + 0.2 × path_match_bonus
9
+ */
10
+ import type { ScoredChunk } from './search.js';
11
+ /** Chunk with final score */
12
+ export interface RankedChunk extends ScoredChunk {
13
+ /** Final combined score */
14
+ score: number;
15
+ /** Individual score components for --explain */
16
+ scoreBreakdown: {
17
+ similarity: number;
18
+ recency: number;
19
+ pathMatch: number;
20
+ };
21
+ }
22
+ /**
23
+ * Calculate scores and rank chunks
24
+ */
25
+ export declare function rankChunks(chunks: ScoredChunk[], query: string): RankedChunk[];
26
+ //# sourceMappingURL=scoring.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoring.d.ts","sourceRoot":"","sources":["../../src/selector/scoring.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,6BAA6B;AAC7B,MAAM,WAAW,WAAY,SAAQ,WAAW;IAC9C,2BAA2B;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,cAAc,EAAE;QACd,UAAU,EAAE,MAAM,CAAC;QACnB,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AASD;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,WAAW,EAAE,CAqC9E"}
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Scoring Module
3
+ *
4
+ * Calculates final scores for chunks based on multiple signals.
5
+ *
6
+ * Score = 0.6 × semantic_similarity
7
+ * + 0.2 × recency_bonus
8
+ * + 0.2 × path_match_bonus
9
+ */
10
+ /** Scoring weights */
11
+ const WEIGHTS = {
12
+ similarity: 0.6,
13
+ recency: 0.2,
14
+ pathMatch: 0.2,
15
+ };
16
+ /**
17
+ * Calculate scores and rank chunks
18
+ */
19
+ export function rankChunks(chunks, query) {
20
+ // Extract keywords from query for path matching
21
+ const queryKeywords = extractKeywords(query);
22
+ // Find max/min for normalization (recency not used yet since we don't track it)
23
+ const ranked = chunks.map((chunk) => {
24
+ // Semantic similarity (already 0-1)
25
+ const similarityScore = chunk.similarity;
26
+ // Recency bonus (placeholder - would use indexed_at if we tracked per-chunk)
27
+ // For now, give all chunks equal recency
28
+ const recencyScore = 0.5;
29
+ // Path match bonus
30
+ const pathMatchScore = calculatePathMatch(chunk.filePath, queryKeywords);
31
+ // Combined score
32
+ const score = WEIGHTS.similarity * similarityScore +
33
+ WEIGHTS.recency * recencyScore +
34
+ WEIGHTS.pathMatch * pathMatchScore;
35
+ return {
36
+ ...chunk,
37
+ score,
38
+ scoreBreakdown: {
39
+ similarity: similarityScore,
40
+ recency: recencyScore,
41
+ pathMatch: pathMatchScore,
42
+ },
43
+ };
44
+ });
45
+ // Sort by final score descending
46
+ ranked.sort((a, b) => b.score - a.score);
47
+ return ranked;
48
+ }
49
+ /**
50
+ * Extract keywords from query for path matching
51
+ */
52
+ function extractKeywords(query) {
53
+ return query
54
+ .toLowerCase()
55
+ .split(/\s+/)
56
+ .filter((word) => word.length > 2)
57
+ .filter((word) => !STOP_WORDS.has(word));
58
+ }
59
+ /**
60
+ * Calculate path match score (0-1)
61
+ */
62
+ function calculatePathMatch(filePath, keywords) {
63
+ if (keywords.length === 0)
64
+ return 0;
65
+ const pathLower = filePath.toLowerCase();
66
+ let matches = 0;
67
+ for (const keyword of keywords) {
68
+ if (pathLower.includes(keyword)) {
69
+ matches++;
70
+ }
71
+ }
72
+ return matches / keywords.length;
73
+ }
74
+ /** Common words to ignore in path matching */
75
+ const STOP_WORDS = new Set([
76
+ 'the',
77
+ 'a',
78
+ 'an',
79
+ 'is',
80
+ 'are',
81
+ 'was',
82
+ 'were',
83
+ 'be',
84
+ 'been',
85
+ 'how',
86
+ 'what',
87
+ 'where',
88
+ 'when',
89
+ 'why',
90
+ 'who',
91
+ 'which',
92
+ 'does',
93
+ 'do',
94
+ 'did',
95
+ 'has',
96
+ 'have',
97
+ 'had',
98
+ 'this',
99
+ 'that',
100
+ 'these',
101
+ 'those',
102
+ 'and',
103
+ 'or',
104
+ 'but',
105
+ 'not',
106
+ 'with',
107
+ 'for',
108
+ 'from',
109
+ 'to',
110
+ 'in',
111
+ 'on',
112
+ ]);
113
+ //# sourceMappingURL=scoring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoring.js","sourceRoot":"","sources":["../../src/selector/scoring.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAgBH,sBAAsB;AACtB,MAAM,OAAO,GAAG;IACd,UAAU,EAAE,GAAG;IACf,OAAO,EAAE,GAAG;IACZ,SAAS,EAAE,GAAG;CACf,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,MAAqB,EAAE,KAAa;IAC7D,gDAAgD;IAChD,MAAM,aAAa,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IAE7C,gFAAgF;IAChF,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QAClC,oCAAoC;QACpC,MAAM,eAAe,GAAG,KAAK,CAAC,UAAU,CAAC;QAEzC,6EAA6E;QAC7E,yCAAyC;QACzC,MAAM,YAAY,GAAG,GAAG,CAAC;QAEzB,mBAAmB;QACnB,MAAM,cAAc,GAAG,kBAAkB,CAAC,KAAK,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QAEzE,iBAAiB;QACjB,MAAM,KAAK,GACT,OAAO,CAAC,UAAU,GAAG,eAAe;YACpC,OAAO,CAAC,OAAO,GAAG,YAAY;YAC9B,OAAO,CAAC,SAAS,GAAG,cAAc,CAAC;QAErC,OAAO;YACL,GAAG,KAAK;YACR,KAAK;YACL,cAAc,EAAE;gBACd,UAAU,EAAE,eAAe;gBAC3B,OAAO,EAAE,YAAY;gBACrB,SAAS,EAAE,cAAc;aAC1B;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,iCAAiC;IACjC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAEzC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,KAAa;IACpC,OAAO,KAAK;SACT,WAAW,EAAE;SACb,KAAK,CAAC,KAAK,CAAC;SACZ,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;SACjC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED;;GAEG;AACH,SAAS,kBAAkB,CAAC,QAAgB,EAAE,QAAkB;IAC9D,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAEpC,MAAM,SAAS,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IACzC,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YAChC,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED,OAAO,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC;AACnC,CAAC;AAED,8CAA8C;AAC9C,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC;IACzB,KAAK;IACL,GAAG;IACH,IAAI;IACJ,IAAI;IACJ,KAAK;IACL,KAAK;IACL,MAAM;IACN,IAAI;IACJ,MAAM;IACN,KAAK;IACL,MAAM;IACN,OAAO;IACP,MAAM;IACN,KAAK;IACL,KAAK;IACL,OAAO;IACP,MAAM;IACN,IAAI;IACJ,KAAK;IACL,KAAK;IACL,MAAM;IACN,KAAK;IACL,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,KAAK;IACL,IAAI;IACJ,KAAK;IACL,KAAK;IACL,MAAM;IACN,KAAK;IACL,MAAM;IACN,IAAI;IACJ,IAAI;IACJ,IAAI;CACL,CAAC,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Similarity Search Module
3
+ *
4
+ * Finds chunks most similar to a query using cosine similarity.
5
+ */
6
+ import Database from 'better-sqlite3';
7
+ /** Chunk from database with similarity score */
8
+ export interface ScoredChunk {
9
+ id: string;
10
+ sourceId: string;
11
+ filePath: string;
12
+ content: string;
13
+ startLine: number;
14
+ endLine: number;
15
+ tokens: number;
16
+ similarity: number;
17
+ }
18
+ /** Search options */
19
+ export interface SearchOptions {
20
+ /** Maximum chunks to retrieve */
21
+ limit?: number;
22
+ /** Filter to specific sources */
23
+ sources?: string[];
24
+ }
25
+ /**
26
+ * Search for chunks similar to a query
27
+ */
28
+ export declare function searchSimilar(db: Database.Database, query: string, options?: SearchOptions): Promise<ScoredChunk[]>;
29
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/selector/search.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAItC,gDAAgD;AAChD,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qBAAqB;AACrB,MAAM,WAAW,aAAa;IAC5B,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAID;;GAEG;AACH,wBAAsB,aAAa,CACjC,EAAE,EAAE,QAAQ,CAAC,QAAQ,EACrB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,WAAW,EAAE,CAAC,CAqDxB"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Similarity Search Module
3
+ *
4
+ * Finds chunks most similar to a query using cosine similarity.
5
+ */
6
+ import { embed, cosineSimilarity } from '../indexer/embeddings.js';
7
+ import { readEmbedding } from '../indexer/index.js';
8
+ const DEFAULT_LIMIT = 50;
9
+ /**
10
+ * Search for chunks similar to a query
11
+ */
12
+ export async function searchSimilar(db, query, options = {}) {
13
+ const limit = options.limit || DEFAULT_LIMIT;
14
+ // Embed the query
15
+ const queryEmbedding = await embed(query);
16
+ // Build SQL query
17
+ let sql = `
18
+ SELECT id, source_id, file_path, content, start_line, end_line, tokens, embedding
19
+ FROM chunks
20
+ `;
21
+ const params = [];
22
+ if (options.sources && options.sources.length > 0) {
23
+ const placeholders = options.sources.map(() => '?').join(', ');
24
+ sql += ` WHERE source_id IN (${placeholders})`;
25
+ params.push(...options.sources);
26
+ }
27
+ // Get all chunks (we'll sort in JS for cosine similarity)
28
+ const rows = db.prepare(sql).all(...params);
29
+ // Calculate similarity for each chunk
30
+ const scored = rows.map((row) => {
31
+ const chunkEmbedding = readEmbedding(row.embedding);
32
+ const similarity = cosineSimilarity(queryEmbedding, chunkEmbedding);
33
+ return {
34
+ id: row.id,
35
+ sourceId: row.source_id,
36
+ filePath: row.file_path,
37
+ content: row.content,
38
+ startLine: row.start_line,
39
+ endLine: row.end_line,
40
+ tokens: row.tokens,
41
+ similarity,
42
+ };
43
+ });
44
+ // Sort by similarity descending and take top N
45
+ scored.sort((a, b) => b.similarity - a.similarity);
46
+ return scored.slice(0, limit);
47
+ }
48
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/selector/search.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAsBpD,MAAM,aAAa,GAAG,EAAE,CAAC;AAEzB;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,EAAqB,EACrB,KAAa,EACb,UAAyB,EAAE;IAE3B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,aAAa,CAAC;IAE7C,kBAAkB;IAClB,MAAM,cAAc,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC;IAE1C,kBAAkB;IAClB,IAAI,GAAG,GAAG;;;GAGT,CAAC;IAEF,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,IAAI,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClD,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/D,GAAG,IAAI,wBAAwB,YAAY,GAAG,CAAC;QAC/C,MAAM,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;IAED,0DAA0D;IAC1D,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,CASxC,CAAC;IAEH,sCAAsC;IACtC,MAAM,MAAM,GAAkB,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QAC7C,MAAM,cAAc,GAAG,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACpD,MAAM,UAAU,GAAG,gBAAgB,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC;QAEpE,OAAO;YACL,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,QAAQ,EAAE,GAAG,CAAC,SAAS;YACvB,QAAQ,EAAE,GAAG,CAAC,SAAS;YACvB,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,SAAS,EAAE,GAAG,CAAC,UAAU;YACzB,OAAO,EAAE,GAAG,CAAC,QAAQ;YACrB,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,UAAU;SACX,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,+CAA+C;IAC/C,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC;IAEnD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AAChC,CAAC"}