@codeledger/selector 0.2.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundle-invalidation.d.ts +33 -0
- package/dist/bundle-invalidation.d.ts.map +1 -0
- package/dist/bundle-invalidation.js +98 -0
- package/dist/bundle-invalidation.js.map +1 -0
- package/dist/bundle.d.ts.map +1 -1
- package/dist/bundle.js +16 -4
- package/dist/bundle.js.map +1 -1
- package/dist/candidates.d.ts +18 -0
- package/dist/candidates.d.ts.map +1 -1
- package/dist/candidates.js +76 -2
- package/dist/candidates.js.map +1 -1
- package/dist/confidence.d.ts +2 -2
- package/dist/confidence.d.ts.map +1 -1
- package/dist/confidence.js +118 -2
- package/dist/confidence.js.map +1 -1
- package/dist/conflict-zones.d.ts +18 -0
- package/dist/conflict-zones.d.ts.map +1 -0
- package/dist/conflict-zones.js +66 -0
- package/dist/conflict-zones.js.map +1 -0
- package/dist/debt-detection.d.ts +15 -0
- package/dist/debt-detection.d.ts.map +1 -0
- package/dist/debt-detection.js +80 -0
- package/dist/debt-detection.js.map +1 -0
- package/dist/index.d.ts +18 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -1
- package/dist/index.js.map +1 -1
- package/dist/intent/drift.d.ts +31 -0
- package/dist/intent/drift.d.ts.map +1 -0
- package/dist/intent/drift.js +120 -0
- package/dist/intent/drift.js.map +1 -0
- package/dist/intent/hash.d.ts +19 -0
- package/dist/intent/hash.d.ts.map +1 -0
- package/dist/intent/hash.js +38 -0
- package/dist/intent/hash.js.map +1 -0
- package/dist/intent/index.d.ts +5 -0
- package/dist/intent/index.d.ts.map +1 -0
- package/dist/intent/index.js +4 -0
- package/dist/intent/index.js.map +1 -0
- package/dist/intent/normalize.d.ts +23 -0
- package/dist/intent/normalize.d.ts.map +1 -0
- package/dist/intent/normalize.js +35 -0
- package/dist/intent/normalize.js.map +1 -0
- package/dist/intent/types.d.ts +37 -0
- package/dist/intent/types.d.ts.map +1 -0
- package/dist/intent/types.js +2 -0
- package/dist/intent/types.js.map +1 -0
- package/dist/knowledge-bundle.d.ts +41 -0
- package/dist/knowledge-bundle.d.ts.map +1 -0
- package/dist/knowledge-bundle.js +200 -0
- package/dist/knowledge-bundle.js.map +1 -0
- package/dist/knowledge-candidates.d.ts +27 -0
- package/dist/knowledge-candidates.d.ts.map +1 -0
- package/dist/knowledge-candidates.js +123 -0
- package/dist/knowledge-candidates.js.map +1 -0
- package/dist/knowledge-excerpt.d.ts +26 -0
- package/dist/knowledge-excerpt.d.ts.map +1 -0
- package/dist/knowledge-excerpt.js +179 -0
- package/dist/knowledge-excerpt.js.map +1 -0
- package/dist/knowledge-scorer.d.ts +33 -0
- package/dist/knowledge-scorer.d.ts.map +1 -0
- package/dist/knowledge-scorer.js +234 -0
- package/dist/knowledge-scorer.js.map +1 -0
- package/dist/loop-detection.d.ts +28 -0
- package/dist/loop-detection.d.ts.map +1 -0
- package/dist/loop-detection.js +124 -0
- package/dist/loop-detection.js.map +1 -0
- package/dist/mode-detect.d.ts +23 -0
- package/dist/mode-detect.d.ts.map +1 -0
- package/dist/mode-detect.js +76 -0
- package/dist/mode-detect.js.map +1 -0
- package/dist/scope-contract.d.ts +26 -0
- package/dist/scope-contract.d.ts.map +1 -0
- package/dist/scope-contract.js +79 -0
- package/dist/scope-contract.js.map +1 -0
- package/dist/scorer.d.ts.map +1 -1
- package/dist/scorer.js +21 -2
- package/dist/scorer.js.map +1 -1
- package/dist/security-surface.d.ts +13 -0
- package/dist/security-surface.d.ts.map +1 -0
- package/dist/security-surface.js +45 -0
- package/dist/security-surface.js.map +1 -0
- package/dist/task-type.d.ts.map +1 -1
- package/dist/task-type.js +4 -2
- package/dist/task-type.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Knowledge-mode excerpt extraction.
|
|
3
|
+
*
|
|
4
|
+
* Strategies:
|
|
5
|
+
* - head: First N lines (for text, JSON, YAML)
|
|
6
|
+
* - head+headers: First N lines + all markdown headers (for .md files)
|
|
7
|
+
* - head+keyword_windows: First N lines + keyword context windows
|
|
8
|
+
*/
|
|
9
|
+
import { readFileSync, statSync } from 'node:fs';
|
|
10
|
+
import { join } from 'node:path';
|
|
11
|
+
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10 MB
|
|
12
|
+
/**
|
|
13
|
+
* Extract excerpt from a knowledge-mode file.
|
|
14
|
+
*
|
|
15
|
+
* @param root Workspace root
|
|
16
|
+
* @param filePath Relative file path
|
|
17
|
+
* @param keywords Intent keywords for window extraction
|
|
18
|
+
* @param maxLines Maximum excerpt lines (default 450)
|
|
19
|
+
* @param maxBytes Maximum excerpt bytes (default 24000)
|
|
20
|
+
*/
|
|
21
|
+
export function extractKnowledgeExcerpt(root, filePath, keywords, maxLines = 450, maxBytes = 24000) {
|
|
22
|
+
const absPath = join(root, filePath);
|
|
23
|
+
const ext = filePath.split('.').pop()?.toLowerCase() ?? '';
|
|
24
|
+
let rawContent;
|
|
25
|
+
try {
|
|
26
|
+
const size = statSync(absPath).size;
|
|
27
|
+
if (size > MAX_FILE_SIZE) {
|
|
28
|
+
return {
|
|
29
|
+
content: `[File too large: ${Math.round(size / 1024)}KB]`,
|
|
30
|
+
lines_est: 1,
|
|
31
|
+
bytes_est: 0,
|
|
32
|
+
strategy: 'head',
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
rawContent = readFileSync(absPath, 'utf-8');
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return { content: '', lines_est: 0, bytes_est: 0, strategy: 'head' };
|
|
39
|
+
}
|
|
40
|
+
// Check if file is binary
|
|
41
|
+
if (rawContent.length > 0 && rawContent.slice(0, 8192).includes('\0')) {
|
|
42
|
+
return {
|
|
43
|
+
content: '[Binary file — metadata only]',
|
|
44
|
+
lines_est: 0,
|
|
45
|
+
bytes_est: 0,
|
|
46
|
+
strategy: 'head',
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
const lines = rawContent.split('\n');
|
|
50
|
+
// If file fits within limits, return full content
|
|
51
|
+
if (lines.length <= maxLines && rawContent.length <= maxBytes) {
|
|
52
|
+
return {
|
|
53
|
+
content: rawContent,
|
|
54
|
+
lines_est: lines.length,
|
|
55
|
+
bytes_est: rawContent.length,
|
|
56
|
+
strategy: 'head',
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
// Choose strategy based on extension
|
|
60
|
+
if (ext === 'md' || ext === 'mdx') {
|
|
61
|
+
return extractHeadPlusHeaders(lines, keywords, maxLines, maxBytes);
|
|
62
|
+
}
|
|
63
|
+
if (keywords.length > 0) {
|
|
64
|
+
return extractHeadPlusKeywordWindows(lines, keywords, maxLines, maxBytes);
|
|
65
|
+
}
|
|
66
|
+
return extractHead(lines, maxLines, maxBytes);
|
|
67
|
+
}
|
|
68
|
+
function extractHead(lines, maxLines, maxBytes) {
|
|
69
|
+
const selected = [];
|
|
70
|
+
let bytes = 0;
|
|
71
|
+
for (let i = 0; i < lines.length && selected.length < maxLines; i++) {
|
|
72
|
+
const line = lines[i];
|
|
73
|
+
if (bytes + line.length + 1 > maxBytes)
|
|
74
|
+
break;
|
|
75
|
+
selected.push(line);
|
|
76
|
+
bytes += line.length + 1;
|
|
77
|
+
}
|
|
78
|
+
if (selected.length < lines.length) {
|
|
79
|
+
selected.push(`\n[... ${lines.length - selected.length} more lines omitted ...]`);
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
content: selected.join('\n'),
|
|
83
|
+
lines_est: selected.length,
|
|
84
|
+
bytes_est: bytes,
|
|
85
|
+
strategy: 'head',
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function extractHeadPlusHeaders(lines, keywords, maxLines, maxBytes) {
|
|
89
|
+
const includedLineNums = new Set();
|
|
90
|
+
// Pass 1: Include first 100 lines (head section)
|
|
91
|
+
const headSize = Math.min(100, lines.length);
|
|
92
|
+
for (let i = 0; i < headSize; i++) {
|
|
93
|
+
includedLineNums.add(i);
|
|
94
|
+
}
|
|
95
|
+
// Pass 2: Include all markdown header lines (^# ...)
|
|
96
|
+
for (let i = headSize; i < lines.length; i++) {
|
|
97
|
+
if (lines[i].match(/^#{1,6}\s/)) {
|
|
98
|
+
// Include header + next 2 lines for context
|
|
99
|
+
includedLineNums.add(i);
|
|
100
|
+
if (i + 1 < lines.length)
|
|
101
|
+
includedLineNums.add(i + 1);
|
|
102
|
+
if (i + 2 < lines.length)
|
|
103
|
+
includedLineNums.add(i + 2);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Pass 3: Include keyword windows (if keywords provided)
|
|
107
|
+
if (keywords.length > 0) {
|
|
108
|
+
const windowSize = 5;
|
|
109
|
+
for (let i = headSize; i < lines.length; i++) {
|
|
110
|
+
const lineLower = lines[i].toLowerCase();
|
|
111
|
+
for (const kw of keywords) {
|
|
112
|
+
if (lineLower.includes(kw)) {
|
|
113
|
+
const start = Math.max(0, i - windowSize);
|
|
114
|
+
const end = Math.min(lines.length - 1, i + windowSize);
|
|
115
|
+
for (let j = start; j <= end; j++) {
|
|
116
|
+
includedLineNums.add(j);
|
|
117
|
+
}
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return assembleExcerpt(lines, includedLineNums, maxLines, maxBytes, 'head+headers');
|
|
124
|
+
}
|
|
125
|
+
function extractHeadPlusKeywordWindows(lines, keywords, maxLines, maxBytes) {
|
|
126
|
+
const includedLineNums = new Set();
|
|
127
|
+
// Pass 1: Head section
|
|
128
|
+
const headSize = Math.min(100, lines.length);
|
|
129
|
+
for (let i = 0; i < headSize; i++) {
|
|
130
|
+
includedLineNums.add(i);
|
|
131
|
+
}
|
|
132
|
+
// Pass 2: Keyword windows
|
|
133
|
+
const windowSize = 8;
|
|
134
|
+
for (let i = headSize; i < lines.length; i++) {
|
|
135
|
+
const lineLower = lines[i].toLowerCase();
|
|
136
|
+
for (const kw of keywords) {
|
|
137
|
+
if (lineLower.includes(kw)) {
|
|
138
|
+
const start = Math.max(0, i - windowSize);
|
|
139
|
+
const end = Math.min(lines.length - 1, i + windowSize);
|
|
140
|
+
for (let j = start; j <= end; j++) {
|
|
141
|
+
includedLineNums.add(j);
|
|
142
|
+
}
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return assembleExcerpt(lines, includedLineNums, maxLines, maxBytes, 'head+keyword_windows');
|
|
148
|
+
}
|
|
149
|
+
function assembleExcerpt(lines, includedLineNums, maxLines, maxBytes, strategy) {
|
|
150
|
+
const sorted = [...includedLineNums].sort((a, b) => a - b);
|
|
151
|
+
const parts = [];
|
|
152
|
+
let lastLine = -2;
|
|
153
|
+
let bytes = 0;
|
|
154
|
+
let lineCount = 0;
|
|
155
|
+
for (const lineNum of sorted) {
|
|
156
|
+
if (lineCount >= maxLines || bytes >= maxBytes)
|
|
157
|
+
break;
|
|
158
|
+
if (lineNum > lastLine + 1 && lastLine >= 0) {
|
|
159
|
+
const gap = `\n[... lines ${lastLine + 2}–${lineNum} omitted ...]\n`;
|
|
160
|
+
parts.push(gap);
|
|
161
|
+
bytes += gap.length;
|
|
162
|
+
}
|
|
163
|
+
const line = lines[lineNum];
|
|
164
|
+
parts.push(line);
|
|
165
|
+
bytes += line.length + 1;
|
|
166
|
+
lineCount++;
|
|
167
|
+
lastLine = lineNum;
|
|
168
|
+
}
|
|
169
|
+
if (sorted.length > 0 && sorted[sorted.length - 1] < lines.length - 1) {
|
|
170
|
+
parts.push(`\n[... ${lines.length - (sorted[sorted.length - 1] + 1)} more lines omitted ...]`);
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
content: parts.join('\n'),
|
|
174
|
+
lines_est: lineCount,
|
|
175
|
+
bytes_est: bytes,
|
|
176
|
+
strategy,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=knowledge-excerpt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"knowledge-excerpt.js","sourceRoot":"","sources":["../src/knowledge-excerpt.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Knowledge-mode scorer — deterministic scoring for non-code workspace files.
|
|
3
|
+
*
|
|
4
|
+
* 7 weighted signals:
|
|
5
|
+
* keyword_match — IDF-weighted keyword match in content
|
|
6
|
+
* filename_match — Keyword match against filename stems
|
|
7
|
+
* path_match — Keyword match against folder path segments
|
|
8
|
+
* recency — mtime exponential decay
|
|
9
|
+
* size_penalty — Penalize large files
|
|
10
|
+
* doc_type_prior — Extension weighting (.md > .txt > .json > others)
|
|
11
|
+
* folder_proximity — Shared path segment scoring with intent-inferred anchors
|
|
12
|
+
* markdown_header_boost — Regex ^# headers matching keywords in first N lines
|
|
13
|
+
*/
|
|
14
|
+
import type { KnowledgeFeatures, KnowledgeScoredFile, KnowledgeWeights, WorkspaceFileInfo } from '@codeledger/types';
|
|
15
|
+
/** Default knowledge-mode weights (match spec signal_weights) */
|
|
16
|
+
export declare const DEFAULT_KNOWLEDGE_WEIGHTS: KnowledgeWeights;
|
|
17
|
+
/**
|
|
18
|
+
* Compute knowledge-mode features for a single file.
|
|
19
|
+
*/
|
|
20
|
+
export declare function computeKnowledgeFeatures(file: WorkspaceFileInfo, intentTokens: string[], tokenWeights: Map<string, number>, anchorFolders: string[], nowMs: number): KnowledgeFeatures;
|
|
21
|
+
/**
|
|
22
|
+
* Score a file using weighted sum of knowledge features.
|
|
23
|
+
*/
|
|
24
|
+
export declare function scoreKnowledgeFile(features: KnowledgeFeatures, weights: KnowledgeWeights): number;
|
|
25
|
+
/**
|
|
26
|
+
* Derive human-readable reason codes from features.
|
|
27
|
+
*/
|
|
28
|
+
export declare function deriveKnowledgeReasons(features: KnowledgeFeatures, _intentTokens: string[]): string[];
|
|
29
|
+
/**
|
|
30
|
+
* Score all candidates and return sorted results.
|
|
31
|
+
*/
|
|
32
|
+
export declare function scoreAllKnowledgeCandidates(candidates: WorkspaceFileInfo[], intentTokens: string[], tokenWeights: Map<string, number>, anchorFolders: string[], weights: KnowledgeWeights, nowMs: number): KnowledgeScoredFile[];
|
|
33
|
+
//# sourceMappingURL=knowledge-scorer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"knowledge-scorer.d.ts","sourceRoot":"","sources":["../src/knowledge-scorer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EACV,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,mBAAmB,CAAC;AAE3B,iEAAiE;AACjE,eAAO,MAAM,yBAAyB,EAAE,gBASvC,CAAC;AAiCF;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,iBAAiB,EACvB,YAAY,EAAE,MAAM,EAAE,EACtB,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EACjC,aAAa,EAAE,MAAM,EAAE,EACvB,KAAK,EAAE,MAAM,GACZ,iBAAiB,CA4HnB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,iBAAiB,EAC3B,OAAO,EAAE,gBAAgB,GACxB,MAAM,CAWR;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,iBAAiB,EAC3B,aAAa,EAAE,MAAM,EAAE,GACtB,MAAM,EAAE,CA8BV;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CACzC,UAAU,EAAE,iBAAiB,EAAE,EAC/B,YAAY,EAAE,MAAM,EAAE,EACtB,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EACjC,aAAa,EAAE,MAAM,EAAE,EACvB,OAAO,EAAE,gBAAgB,EACzB,KAAK,EAAE,MAAM,GACZ,mBAAmB,EAAE,CAoBvB"}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Knowledge-mode scorer — deterministic scoring for non-code workspace files.
|
|
3
|
+
*
|
|
4
|
+
* 7 weighted signals:
|
|
5
|
+
* keyword_match — IDF-weighted keyword match in content
|
|
6
|
+
* filename_match — Keyword match against filename stems
|
|
7
|
+
* path_match — Keyword match against folder path segments
|
|
8
|
+
* recency — mtime exponential decay
|
|
9
|
+
* size_penalty — Penalize large files
|
|
10
|
+
* doc_type_prior — Extension weighting (.md > .txt > .json > others)
|
|
11
|
+
* folder_proximity — Shared path segment scoring with intent-inferred anchors
|
|
12
|
+
* markdown_header_boost — Regex ^# headers matching keywords in first N lines
|
|
13
|
+
*/
|
|
14
|
+
/** Default knowledge-mode weights (match spec signal_weights) */
|
|
15
|
+
export const DEFAULT_KNOWLEDGE_WEIGHTS = {
|
|
16
|
+
keyword_match: 0.22,
|
|
17
|
+
filename_match: 0.14,
|
|
18
|
+
path_match: 0.10,
|
|
19
|
+
recency: 0.16,
|
|
20
|
+
size_penalty: 0.06,
|
|
21
|
+
doc_type_prior: 0.10,
|
|
22
|
+
folder_proximity: 0.14,
|
|
23
|
+
markdown_header_boost: 0.08,
|
|
24
|
+
};
|
|
25
|
+
/** Document type priors: higher = more likely to be useful knowledge content */
|
|
26
|
+
const DOC_TYPE_PRIORS = {
|
|
27
|
+
'.md': 1.0,
|
|
28
|
+
'.txt': 0.7,
|
|
29
|
+
'.json': 0.5,
|
|
30
|
+
'.yaml': 0.5,
|
|
31
|
+
'.yml': 0.5,
|
|
32
|
+
// Unsupported but present — metadata only
|
|
33
|
+
'.csv': 0.2,
|
|
34
|
+
'.xlsx': 0.1,
|
|
35
|
+
'.pdf': 0.1,
|
|
36
|
+
'.docx': 0.1,
|
|
37
|
+
};
|
|
38
|
+
/** Folder names that indicate high-value knowledge content */
|
|
39
|
+
const KNOWLEDGE_FOLDER_PRIORS = {
|
|
40
|
+
docs: 0.9,
|
|
41
|
+
spec: 0.9,
|
|
42
|
+
specifications: 0.9,
|
|
43
|
+
proposals: 0.8,
|
|
44
|
+
design: 0.8,
|
|
45
|
+
meetings: 0.7,
|
|
46
|
+
notes: 0.6,
|
|
47
|
+
product: 0.8,
|
|
48
|
+
reports: 0.7,
|
|
49
|
+
plans: 0.8,
|
|
50
|
+
planning: 0.8,
|
|
51
|
+
research: 0.7,
|
|
52
|
+
analysis: 0.7,
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Compute knowledge-mode features for a single file.
|
|
56
|
+
*/
|
|
57
|
+
export function computeKnowledgeFeatures(file, intentTokens, tokenWeights, anchorFolders, nowMs) {
|
|
58
|
+
const pathLower = file.path.toLowerCase();
|
|
59
|
+
const pathSegments = pathLower.split('/');
|
|
60
|
+
const basename = pathSegments[pathSegments.length - 1]?.replace(/\.\w+$/, '') ?? '';
|
|
61
|
+
const filenameStems = basename.split(/[-_]/);
|
|
62
|
+
const contentKws = file.content_keywords ?? [];
|
|
63
|
+
// 1. keyword_match — IDF-weighted match against content keywords
|
|
64
|
+
let kwScore = 0;
|
|
65
|
+
let maxPossible = 0;
|
|
66
|
+
for (const token of intentTokens) {
|
|
67
|
+
const w = tokenWeights.get(token) ?? 1;
|
|
68
|
+
if (w === 0)
|
|
69
|
+
continue;
|
|
70
|
+
maxPossible += w;
|
|
71
|
+
if (contentKws.some((ck) => ck === token || ck === token + 's' || token === ck + 's')) {
|
|
72
|
+
kwScore += w;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const keyword_match = maxPossible > 0 ? Math.min(1, kwScore / maxPossible) : 0;
|
|
76
|
+
// 2. filename_match — keyword match against filename stems
|
|
77
|
+
let fnScore = 0;
|
|
78
|
+
let fnMax = 0;
|
|
79
|
+
for (const token of intentTokens) {
|
|
80
|
+
const w = tokenWeights.get(token) ?? 1;
|
|
81
|
+
if (w === 0)
|
|
82
|
+
continue;
|
|
83
|
+
fnMax += w;
|
|
84
|
+
const isStemMatch = filenameStems.some((stem) => stem === token || stem === token + 's' || token === stem + 's');
|
|
85
|
+
if (isStemMatch) {
|
|
86
|
+
fnScore += w * 2.0; // 2x for filename stem exact match
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const filename_match = fnMax > 0 ? Math.min(1, fnScore / fnMax) : 0;
|
|
90
|
+
// 3. path_match — keyword match against folder path segments
|
|
91
|
+
let pathScore = 0;
|
|
92
|
+
let pathMax = 0;
|
|
93
|
+
for (const token of intentTokens) {
|
|
94
|
+
const w = tokenWeights.get(token) ?? 1;
|
|
95
|
+
if (w === 0)
|
|
96
|
+
continue;
|
|
97
|
+
pathMax += w;
|
|
98
|
+
if (pathLower.includes(token)) {
|
|
99
|
+
pathScore += w;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const path_match = pathMax > 0 ? Math.min(1, pathScore / pathMax) : 0;
|
|
103
|
+
// 4. recency — exponential decay based on mtime
|
|
104
|
+
const mtimeMs = new Date(file.mtime).getTime();
|
|
105
|
+
const daysSince = Math.max(0, (nowMs - mtimeMs) / (1000 * 60 * 60 * 24));
|
|
106
|
+
const recency = daysSince <= 1 ? 1.0
|
|
107
|
+
: daysSince <= 3 ? 0.9
|
|
108
|
+
: daysSince <= 7 ? 0.8
|
|
109
|
+
: daysSince <= 14 ? 0.6
|
|
110
|
+
: daysSince <= 30 ? 0.4
|
|
111
|
+
: daysSince <= 60 ? 0.2
|
|
112
|
+
: 0.1;
|
|
113
|
+
// 5. size_penalty — penalize very large files
|
|
114
|
+
const size_penalty = Math.max(0, Math.min(1, file.size_bytes / (500 * 1024)));
|
|
115
|
+
// 6. doc_type_prior — extension-based document type weighting
|
|
116
|
+
const doc_type_prior = DOC_TYPE_PRIORS[file.extension.toLowerCase()] ?? 0.05;
|
|
117
|
+
// 7. folder_proximity — shared path segments with anchor folders
|
|
118
|
+
let folder_proximity = 0;
|
|
119
|
+
if (anchorFolders.length > 0) {
|
|
120
|
+
const fileDir = pathSegments.slice(0, -1).join('/');
|
|
121
|
+
for (const anchor of anchorFolders) {
|
|
122
|
+
if (fileDir === anchor || fileDir.startsWith(anchor + '/')) {
|
|
123
|
+
folder_proximity = 1.0;
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
// Partial match: count shared segments
|
|
127
|
+
const anchorParts = anchor.split('/');
|
|
128
|
+
const fileDirParts = fileDir.split('/');
|
|
129
|
+
let shared = 0;
|
|
130
|
+
for (let i = 0; i < Math.min(anchorParts.length, fileDirParts.length); i++) {
|
|
131
|
+
if (anchorParts[i] === fileDirParts[i])
|
|
132
|
+
shared++;
|
|
133
|
+
else
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
const proximity = anchorParts.length > 0 ? shared / anchorParts.length : 0;
|
|
137
|
+
folder_proximity = Math.max(folder_proximity, proximity);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
// No anchors: use knowledge folder priors
|
|
142
|
+
for (const seg of pathSegments.slice(0, -1)) {
|
|
143
|
+
const prior = KNOWLEDGE_FOLDER_PRIORS[seg];
|
|
144
|
+
if (prior !== undefined) {
|
|
145
|
+
folder_proximity = Math.max(folder_proximity, prior);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// 8. markdown_header_boost — boost for markdown files with keyword-matching headers
|
|
150
|
+
let markdown_header_boost = 0;
|
|
151
|
+
if (file.type === 'markdown' && file.markdown_headers) {
|
|
152
|
+
const headersLower = file.markdown_headers.map((h) => h.toLowerCase());
|
|
153
|
+
let headerHits = 0;
|
|
154
|
+
for (const token of intentTokens) {
|
|
155
|
+
if (headersLower.some((h) => h.includes(token))) {
|
|
156
|
+
headerHits++;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
markdown_header_boost = intentTokens.length > 0
|
|
160
|
+
? Math.min(1, headerHits / intentTokens.length)
|
|
161
|
+
: 0;
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
keyword_match,
|
|
165
|
+
filename_match,
|
|
166
|
+
path_match,
|
|
167
|
+
recency,
|
|
168
|
+
size_penalty,
|
|
169
|
+
doc_type_prior,
|
|
170
|
+
folder_proximity,
|
|
171
|
+
markdown_header_boost,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Score a file using weighted sum of knowledge features.
|
|
176
|
+
*/
|
|
177
|
+
export function scoreKnowledgeFile(features, weights) {
|
|
178
|
+
return (features.keyword_match * weights.keyword_match +
|
|
179
|
+
features.filename_match * weights.filename_match +
|
|
180
|
+
features.path_match * weights.path_match +
|
|
181
|
+
features.recency * weights.recency -
|
|
182
|
+
features.size_penalty * weights.size_penalty +
|
|
183
|
+
features.doc_type_prior * weights.doc_type_prior +
|
|
184
|
+
features.folder_proximity * weights.folder_proximity +
|
|
185
|
+
features.markdown_header_boost * weights.markdown_header_boost);
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Derive human-readable reason codes from features.
|
|
189
|
+
*/
|
|
190
|
+
export function deriveKnowledgeReasons(features, _intentTokens) {
|
|
191
|
+
const reasons = [];
|
|
192
|
+
if (features.keyword_match > 0) {
|
|
193
|
+
// Find which tokens matched for specificity
|
|
194
|
+
reasons.push('keyword_match');
|
|
195
|
+
}
|
|
196
|
+
if (features.filename_match > 0) {
|
|
197
|
+
reasons.push('filename_match');
|
|
198
|
+
}
|
|
199
|
+
if (features.path_match > 0 && features.filename_match === 0) {
|
|
200
|
+
reasons.push('path_match');
|
|
201
|
+
}
|
|
202
|
+
if (features.recency >= 0.8) {
|
|
203
|
+
reasons.push('recency_high');
|
|
204
|
+
}
|
|
205
|
+
if (features.doc_type_prior >= 0.5) {
|
|
206
|
+
reasons.push(`doc_type_prior:${features.doc_type_prior >= 1.0 ? 'md' : 'text'}`);
|
|
207
|
+
}
|
|
208
|
+
if (features.folder_proximity >= 0.5) {
|
|
209
|
+
reasons.push('folder_proximity');
|
|
210
|
+
}
|
|
211
|
+
if (features.markdown_header_boost > 0) {
|
|
212
|
+
reasons.push('markdown_header_boost');
|
|
213
|
+
}
|
|
214
|
+
if (features.size_penalty > 0.5) {
|
|
215
|
+
reasons.push('size_penalty');
|
|
216
|
+
}
|
|
217
|
+
return reasons;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Score all candidates and return sorted results.
|
|
221
|
+
*/
|
|
222
|
+
export function scoreAllKnowledgeCandidates(candidates, intentTokens, tokenWeights, anchorFolders, weights, nowMs) {
|
|
223
|
+
const results = [];
|
|
224
|
+
for (const file of candidates) {
|
|
225
|
+
const features = computeKnowledgeFeatures(file, intentTokens, tokenWeights, anchorFolders, nowMs);
|
|
226
|
+
const score = scoreKnowledgeFile(features, weights);
|
|
227
|
+
const reasons = deriveKnowledgeReasons(features, intentTokens);
|
|
228
|
+
results.push({ path: file.path, score, features, reasons });
|
|
229
|
+
}
|
|
230
|
+
// Sort descending by score (deterministic: stable sort by path as tiebreaker)
|
|
231
|
+
results.sort((a, b) => b.score - a.score || a.path.localeCompare(b.path));
|
|
232
|
+
return results;
|
|
233
|
+
}
|
|
234
|
+
//# sourceMappingURL=knowledge-scorer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"knowledge-scorer.js","sourceRoot":"","sources":["../src/knowledge-scorer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { LoopDetectionConfig, LoopDetectionReport } from '@codeledger/types';
|
|
2
|
+
/** Default thresholds for loop detection */
|
|
3
|
+
export declare const DEFAULT_LOOP_THRESHOLDS: LoopDetectionConfig;
|
|
4
|
+
/** Entry in the session activity log — tracks tool usage for pattern detection */
|
|
5
|
+
export interface ActivityEntry {
|
|
6
|
+
type: 'test_run' | 'file_edit' | 'command';
|
|
7
|
+
target: string;
|
|
8
|
+
success: boolean;
|
|
9
|
+
/** Hash of failure output for duplicate detection */
|
|
10
|
+
output_hash?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Analyze a session's activity log for stuck patterns.
|
|
14
|
+
*
|
|
15
|
+
* All detection is numeric and deterministic — pattern matching on
|
|
16
|
+
* activity sequences with configurable thresholds.
|
|
17
|
+
*/
|
|
18
|
+
export declare function detectStuckPatterns(activities: ActivityEntry[], config?: LoopDetectionConfig): LoopDetectionReport;
|
|
19
|
+
/**
|
|
20
|
+
* Parse git log and diff output into activity entries for loop detection.
|
|
21
|
+
* This enables post-hoc analysis from git state without requiring
|
|
22
|
+
* real-time event ledger integration.
|
|
23
|
+
*/
|
|
24
|
+
export declare function buildActivityLogFromGit(_commitLog: string[], fileEdits: Map<string, number>, testResults: Array<{
|
|
25
|
+
name: string;
|
|
26
|
+
pass: boolean;
|
|
27
|
+
}>): ActivityEntry[];
|
|
28
|
+
//# sourceMappingURL=loop-detection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop-detection.d.ts","sourceRoot":"","sources":["../src/loop-detection.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAgB,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAEhG,4CAA4C;AAC5C,eAAO,MAAM,uBAAuB,EAAE,mBAIrC,CAAC;AAEF,kFAAkF;AAClF,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,UAAU,GAAG,WAAW,GAAG,SAAS,CAAC;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,qDAAqD;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,aAAa,EAAE,EAC3B,MAAM,GAAE,mBAA6C,GACpD,mBAAmB,CAqDrB;AA8DD;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAAE,EACpB,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,WAAW,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,GAClD,aAAa,EAAE,CAoBjB"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/** Default thresholds for loop detection */
|
|
2
|
+
export const DEFAULT_LOOP_THRESHOLDS = {
|
|
3
|
+
max_test_retries: 3,
|
|
4
|
+
max_file_edits: 5,
|
|
5
|
+
max_command_retries: 3,
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Analyze a session's activity log for stuck patterns.
|
|
9
|
+
*
|
|
10
|
+
* All detection is numeric and deterministic — pattern matching on
|
|
11
|
+
* activity sequences with configurable thresholds.
|
|
12
|
+
*/
|
|
13
|
+
export function detectStuckPatterns(activities, config = DEFAULT_LOOP_THRESHOLDS) {
|
|
14
|
+
const episodes = [];
|
|
15
|
+
// 1. Repeated test failures without progress
|
|
16
|
+
const testFailStreaks = detectRepeatedFailures(activities.filter((a) => a.type === 'test_run'), config.max_test_retries);
|
|
17
|
+
for (const streak of testFailStreaks) {
|
|
18
|
+
episodes.push({
|
|
19
|
+
type: 'repeated_test_failure',
|
|
20
|
+
target: streak.target,
|
|
21
|
+
count: streak.count,
|
|
22
|
+
message: `Test "${streak.target}" failed ${streak.count} consecutive times with no file changes between runs`,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
// 2. Same file edited excessively
|
|
26
|
+
const fileEditCounts = new Map();
|
|
27
|
+
for (const a of activities) {
|
|
28
|
+
if (a.type === 'file_edit') {
|
|
29
|
+
fileEditCounts.set(a.target, (fileEditCounts.get(a.target) ?? 0) + 1);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
for (const [file, count] of fileEditCounts) {
|
|
33
|
+
if (count > config.max_file_edits) {
|
|
34
|
+
episodes.push({
|
|
35
|
+
type: 'repeated_file_edit',
|
|
36
|
+
target: file,
|
|
37
|
+
count,
|
|
38
|
+
message: `File "${file}" was edited ${count} times (threshold: ${config.max_file_edits})`,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// 3. Same command fails repeatedly with identical output
|
|
43
|
+
const commandFailStreaks = detectRepeatedCommandFailures(activities.filter((a) => a.type === 'command'), config.max_command_retries);
|
|
44
|
+
for (const streak of commandFailStreaks) {
|
|
45
|
+
episodes.push({
|
|
46
|
+
type: 'repeated_command_failure',
|
|
47
|
+
target: streak.target,
|
|
48
|
+
count: streak.count,
|
|
49
|
+
message: `Command "${streak.target}" failed ${streak.count} times with identical output`,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
stuck_episodes: episodes,
|
|
54
|
+
total_episodes: episodes.length,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Find sequences of test failures with no intervening file changes.
|
|
59
|
+
* A file_edit activity between test runs resets the counter.
|
|
60
|
+
*/
|
|
61
|
+
function detectRepeatedFailures(testActivities, threshold) {
|
|
62
|
+
const streaks = [];
|
|
63
|
+
const currentStreak = new Map();
|
|
64
|
+
for (const a of testActivities) {
|
|
65
|
+
if (!a.success) {
|
|
66
|
+
const count = (currentStreak.get(a.target) ?? 0) + 1;
|
|
67
|
+
currentStreak.set(a.target, count);
|
|
68
|
+
if (count >= threshold) {
|
|
69
|
+
// Only report once per target at the threshold
|
|
70
|
+
if (count === threshold) {
|
|
71
|
+
streaks.push({ target: a.target, count });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
// Test passed — reset streak for this target
|
|
77
|
+
currentStreak.delete(a.target);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return streaks;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Find commands that fail repeatedly with the same output hash.
|
|
84
|
+
*/
|
|
85
|
+
function detectRepeatedCommandFailures(commandActivities, threshold) {
|
|
86
|
+
const streaks = [];
|
|
87
|
+
// Group by target + output_hash
|
|
88
|
+
const failCounts = new Map();
|
|
89
|
+
for (const a of commandActivities) {
|
|
90
|
+
if (!a.success && a.output_hash) {
|
|
91
|
+
const key = `${a.target}::${a.output_hash}`;
|
|
92
|
+
const count = (failCounts.get(key) ?? 0) + 1;
|
|
93
|
+
failCounts.set(key, count);
|
|
94
|
+
if (count === threshold) {
|
|
95
|
+
streaks.push({ target: a.target, count });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return streaks;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Parse git log and diff output into activity entries for loop detection.
|
|
103
|
+
* This enables post-hoc analysis from git state without requiring
|
|
104
|
+
* real-time event ledger integration.
|
|
105
|
+
*/
|
|
106
|
+
export function buildActivityLogFromGit(_commitLog, fileEdits, testResults) {
|
|
107
|
+
const activities = [];
|
|
108
|
+
// Add file edits
|
|
109
|
+
for (const [file, count] of fileEdits) {
|
|
110
|
+
for (let i = 0; i < count; i++) {
|
|
111
|
+
activities.push({ type: 'file_edit', target: file, success: true });
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Add test results
|
|
115
|
+
for (const result of testResults) {
|
|
116
|
+
activities.push({
|
|
117
|
+
type: 'test_run',
|
|
118
|
+
target: result.name,
|
|
119
|
+
success: result.pass,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return activities;
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=loop-detection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop-detection.js","sourceRoot":"","sources":["../src/loop-detection.ts"],"names":[],"mappings":"AAEA,4CAA4C;AAC5C,MAAM,CAAC,MAAM,uBAAuB,GAAwB;IAC1D,gBAAgB,EAAE,CAAC;IACnB,cAAc,EAAE,CAAC;IACjB,mBAAmB,EAAE,CAAC;CACvB,CAAC;AAWF;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CACjC,UAA2B,EAC3B,SAA8B,uBAAuB;IAErD,MAAM,QAAQ,GAAmB,EAAE,CAAC;IAEpC,6CAA6C;IAC7C,MAAM,eAAe,GAAG,sBAAsB,CAC5C,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,EAC/C,MAAM,CAAC,gBAAgB,CACxB,CAAC;IACF,KAAK,MAAM,MAAM,IAAI,eAAe,EAAE,CAAC;QACrC,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,uBAAuB;YAC7B,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,OAAO,EAAE,SAAS,MAAM,CAAC,MAAM,YAAY,MAAM,CAAC,KAAK,sDAAsD;SAC9G,CAAC,CAAC;IACL,CAAC;IAED,kCAAkC;IAClC,MAAM,cAAc,GAAG,IAAI,GAAG,EAAkB,CAAC;IACjD,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YAC3B,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACxE,CAAC;IACH,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,cAAc,EAAE,CAAC;QAC3C,IAAI,KAAK,GAAG,MAAM,CAAC,cAAc,EAAE,CAAC;YAClC,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,oBAAoB;gBAC1B,MAAM,EAAE,IAAI;gBACZ,KAAK;gBACL,OAAO,EAAE,SAAS,IAAI,gBAAgB,KAAK,sBAAsB,MAAM,CAAC,cAAc,GAAG;aAC1F,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,yDAAyD;IACzD,MAAM,kBAAkB,GAAG,6BAA6B,CACtD,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,EAC9C,MAAM,CAAC,mBAAmB,CAC3B,CAAC;IACF,KAAK,MAAM,MAAM,IAAI,kBAAkB,EAAE,CAAC;QACxC,QAAQ,CAAC,IAAI,CAAC;YACZ,IAAI,EAAE,0BAA0B;YAChC,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,OAAO,EAAE,YAAY,MAAM,CAAC,MAAM,YAAY,MAAM,CAAC,KAAK,8BAA8B;SACzF,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,cAAc,EAAE,QAAQ;QACxB,cAAc,EAAE,QAAQ,CAAC,MAAM;KAChC,CAAC;AACJ,CAAC;AAOD;;;GAGG;AACH,SAAS,sBAAsB,CAC7B,cAA+B,EAC/B,SAAiB;IAEjB,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,MAAM,aAAa,GAAG,IAAI,GAAG,EAAkB,CAAC;IAEhD,KAAK,MAAM,CAAC,IAAI,cAAc,EAAE,CAAC;QAC/B,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YACrD,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YACnC,IAAI,KAAK,IAAI,SAAS,EAAE,CAAC;gBACvB,+CAA+C;gBAC/C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;oBACxB,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;gBAC5C,CAAC;YACH,CAAC;QACH,CAAC;aAAM,CAAC;YACN,6CAA6C;YAC7C,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,SAAS,6BAA6B,CACpC,iBAAkC,EAClC,SAAiB;IAEjB,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,gCAAgC;IAChC,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE7C,KAAK,MAAM,CAAC,IAAI,iBAAiB,EAAE,CAAC;QAClC,IAAI,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;YAChC,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;YAC5C,MAAM,KAAK,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YAC7C,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YAC3B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CACrC,UAAoB,EACpB,SAA8B,EAC9B,WAAmD;IAEnD,MAAM,UAAU,GAAoB,EAAE,CAAC;IAEvC,iBAAiB;IACjB,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,SAAS,EAAE,CAAC;QACtC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/B,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;IAED,mBAAmB;IACnB,KAAK,MAAM,MAAM,IAAI,WAAW,EAAE,CAAC;QACjC,UAAU,CAAC,IAAI,CAAC;YACd,IAAI,EAAE,UAAU;YAChB,MAAM,EAAE,MAAM,CAAC,IAAI;YACnB,OAAO,EAAE,MAAM,CAAC,IAAI;SACrB,CAAC,CAAC;IACL,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC"}
|