solvdex 1.0.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/LICENSE +21 -0
- package/README.md +274 -0
- package/dist/hooks/error-lookup.d.ts +4 -0
- package/dist/hooks/error-lookup.d.ts.map +1 -0
- package/dist/hooks/error-lookup.js +92 -0
- package/dist/hooks/error-lookup.js.map +1 -0
- package/dist/hooks/post-task.d.ts +15 -0
- package/dist/hooks/post-task.d.ts.map +1 -0
- package/dist/hooks/post-task.js +246 -0
- package/dist/hooks/post-task.js.map +1 -0
- package/dist/hooks/prompt-enrich.d.ts +16 -0
- package/dist/hooks/prompt-enrich.d.ts.map +1 -0
- package/dist/hooks/prompt-enrich.js +141 -0
- package/dist/hooks/prompt-enrich.js.map +1 -0
- package/dist/hooks/session-start-cli.d.ts +3 -0
- package/dist/hooks/session-start-cli.d.ts.map +1 -0
- package/dist/hooks/session-start-cli.js +81 -0
- package/dist/hooks/session-start-cli.js.map +1 -0
- package/dist/hooks/session-start.d.ts +4 -0
- package/dist/hooks/session-start.d.ts.map +1 -0
- package/dist/hooks/session-start.js +134 -0
- package/dist/hooks/session-start.js.map +1 -0
- package/dist/src/audit.d.ts +63 -0
- package/dist/src/audit.d.ts.map +1 -0
- package/dist/src/audit.js +229 -0
- package/dist/src/audit.js.map +1 -0
- package/dist/src/cache.d.ts +54 -0
- package/dist/src/cache.d.ts.map +1 -0
- package/dist/src/cache.js +167 -0
- package/dist/src/cache.js.map +1 -0
- package/dist/src/config.d.ts +52 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +175 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/entry.d.ts +154 -0
- package/dist/src/entry.d.ts.map +1 -0
- package/dist/src/entry.js +469 -0
- package/dist/src/entry.js.map +1 -0
- package/dist/src/errors.d.ts +65 -0
- package/dist/src/errors.d.ts.map +1 -0
- package/dist/src/errors.js +121 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/frontmatter.d.ts +28 -0
- package/dist/src/frontmatter.d.ts.map +1 -0
- package/dist/src/frontmatter.js +111 -0
- package/dist/src/frontmatter.js.map +1 -0
- package/dist/src/index.d.ts +35 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +188 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/maturity.d.ts +31 -0
- package/dist/src/maturity.d.ts.map +1 -0
- package/dist/src/maturity.js +96 -0
- package/dist/src/maturity.js.map +1 -0
- package/dist/src/quality.d.ts +23 -0
- package/dist/src/quality.d.ts.map +1 -0
- package/dist/src/quality.js +236 -0
- package/dist/src/quality.js.map +1 -0
- package/dist/src/search.d.ts +35 -0
- package/dist/src/search.d.ts.map +1 -0
- package/dist/src/search.js +263 -0
- package/dist/src/search.js.map +1 -0
- package/dist/src/similarity.d.ts +42 -0
- package/dist/src/similarity.d.ts.map +1 -0
- package/dist/src/similarity.js +111 -0
- package/dist/src/similarity.js.map +1 -0
- package/dist/src/stats.d.ts +56 -0
- package/dist/src/stats.d.ts.map +1 -0
- package/dist/src/stats.js +198 -0
- package/dist/src/stats.js.map +1 -0
- package/dist/src/templates.d.ts +63 -0
- package/dist/src/templates.d.ts.map +1 -0
- package/dist/src/templates.js +347 -0
- package/dist/src/templates.js.map +1 -0
- package/dist/src/transfer.d.ts +92 -0
- package/dist/src/transfer.d.ts.map +1 -0
- package/dist/src/transfer.js +215 -0
- package/dist/src/transfer.js.map +1 -0
- package/dist/src/types.d.ts +270 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +153 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/validate.d.ts +90 -0
- package/dist/src/validate.d.ts.map +1 -0
- package/dist/src/validate.js +295 -0
- package/dist/src/validate.js.map +1 -0
- package/hooks/error-lookup.ts +110 -0
- package/hooks/hooks.json +49 -0
- package/hooks/post-task.ts +309 -0
- package/hooks/prompt-enrich.ts +162 -0
- package/hooks/session-start-cli.ts +96 -0
- package/hooks/session-start.ts +159 -0
- package/package.json +40 -0
- package/scripts/error-lookup.py +64 -0
- package/scripts/post-task.py +60 -0
- package/scripts/prompt-enrich.py +64 -0
- package/scripts/session-start.py +64 -0
- package/skills/wiki/SKILL.md +61 -0
- package/skills/wiki-add/SKILL.md +90 -0
- package/skills/wiki-browse/SKILL.md +108 -0
- package/skills/wiki-capture/SKILL.md +265 -0
- package/skills/wiki-explorer/SKILL.md +223 -0
- package/skills/wiki-export/SKILL.md +101 -0
- package/skills/wiki-fix/SKILL.md +86 -0
- package/skills/wiki-flag/SKILL.md +47 -0
- package/skills/wiki-import/SKILL.md +128 -0
- package/skills/wiki-init/SKILL.md +72 -0
- package/skills/wiki-scan/SKILL.md +98 -0
- package/skills/wiki-search/SKILL.md +86 -0
- package/skills/wiki-stats/SKILL.md +129 -0
- package/skills/wiki-status/SKILL.md +78 -0
- package/skills/wiki-test-trigger/SKILL.md +173 -0
- package/skills/wiki-validate/SKILL.md +62 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// src/quality.ts
|
|
3
|
+
// Entry quality validation and rules
|
|
4
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
5
|
+
if (k2 === undefined) k2 = k;
|
|
6
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
7
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
8
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
9
|
+
}
|
|
10
|
+
Object.defineProperty(o, k2, desc);
|
|
11
|
+
}) : (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
o[k2] = m[k];
|
|
14
|
+
}));
|
|
15
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
16
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
17
|
+
}) : function(o, v) {
|
|
18
|
+
o["default"] = v;
|
|
19
|
+
});
|
|
20
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
21
|
+
var ownKeys = function(o) {
|
|
22
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
23
|
+
var ar = [];
|
|
24
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
25
|
+
return ar;
|
|
26
|
+
};
|
|
27
|
+
return ownKeys(o);
|
|
28
|
+
};
|
|
29
|
+
return function (mod) {
|
|
30
|
+
if (mod && mod.__esModule) return mod;
|
|
31
|
+
var result = {};
|
|
32
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
33
|
+
__setModuleDefault(result, mod);
|
|
34
|
+
return result;
|
|
35
|
+
};
|
|
36
|
+
})();
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
exports.getDefaultConfidence = void 0;
|
|
39
|
+
exports.validateEntryQuality = validateEntryQuality;
|
|
40
|
+
exports.validateAllEntryQuality = validateAllEntryQuality;
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
const types_js_1 = require("./types.js");
|
|
44
|
+
const entry_js_1 = require("./entry.js");
|
|
45
|
+
const config_js_1 = require("./config.js");
|
|
46
|
+
// Re-export getDefaultConfidence for consumers of this module
|
|
47
|
+
var config_js_2 = require("./config.js");
|
|
48
|
+
Object.defineProperty(exports, "getDefaultConfidence", { enumerable: true, get: function () { return config_js_2.getDefaultConfidence; } });
|
|
49
|
+
/**
|
|
50
|
+
* Pattern for valid wiki links: [[path/to/entry]]
|
|
51
|
+
*/
|
|
52
|
+
const WIKI_LINK_PATTERN = /\[\[([^\]]+)\]\]/g;
|
|
53
|
+
/**
|
|
54
|
+
* Validate the quality of an entry
|
|
55
|
+
*/
|
|
56
|
+
function validateEntryQuality(projectRoot, entryPath) {
|
|
57
|
+
const entry = (0, entry_js_1.readEntry)(projectRoot, entryPath);
|
|
58
|
+
if (!entry) {
|
|
59
|
+
return [{
|
|
60
|
+
type: 'broken_wiki_link',
|
|
61
|
+
message: `Entry not found: ${entryPath}`,
|
|
62
|
+
entryPath
|
|
63
|
+
}];
|
|
64
|
+
}
|
|
65
|
+
const issues = [];
|
|
66
|
+
// Check Related section format
|
|
67
|
+
issues.push(...validateRelatedSection(projectRoot, entry));
|
|
68
|
+
// Check for trigger pattern in issues
|
|
69
|
+
issues.push(...validateIssueTrigger(entry));
|
|
70
|
+
// Check for empty sections
|
|
71
|
+
issues.push(...validateContentCompleteness(entry));
|
|
72
|
+
// Check wiki links exist
|
|
73
|
+
issues.push(...validateWikiLinks(projectRoot, entry));
|
|
74
|
+
// Check confidence level
|
|
75
|
+
issues.push(...validateConfidenceLevel(entry));
|
|
76
|
+
return issues;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Pattern for lines that are acceptable as plain text in Related section
|
|
80
|
+
* - Git: references (commit hashes)
|
|
81
|
+
* - Compliance: references (regulatory context)
|
|
82
|
+
* - ADRs: references (can be plain text ADR names)
|
|
83
|
+
*/
|
|
84
|
+
const ACCEPTABLE_PLAIN_TEXT = /^- (?:Git|Compliance|ADRs?):/;
|
|
85
|
+
/**
|
|
86
|
+
* Pattern for lines that should have proper link format
|
|
87
|
+
* - See also: should use [[wiki-link]]
|
|
88
|
+
* - Entries: should use [[wiki-link]]
|
|
89
|
+
* - Source: should use [[wiki-link]] or [title](url)
|
|
90
|
+
* - Docs: should use [title](url) or [[wiki-link]]
|
|
91
|
+
*/
|
|
92
|
+
const SHOULD_BE_LINKED_PREFIX = /^- (?:See also|Entries?|Source|Docs):/;
|
|
93
|
+
/**
|
|
94
|
+
* Pattern to detect valid links (wiki links or external links)
|
|
95
|
+
*/
|
|
96
|
+
const HAS_VALID_LINK = /\[\[[^\]]+\]\]|\[[^\]]+\]\([^)]+\)/;
|
|
97
|
+
/**
|
|
98
|
+
* Validate the Related section has proper link formats
|
|
99
|
+
*/
|
|
100
|
+
function validateRelatedSection(projectRoot, entry) {
|
|
101
|
+
const issues = [];
|
|
102
|
+
const content = entry.content;
|
|
103
|
+
// Find Related section
|
|
104
|
+
const relatedMatch = content.match(/# Related\n([\s\S]*?)(?=\n#|$)/);
|
|
105
|
+
if (!relatedMatch) {
|
|
106
|
+
return issues; // No Related section, that's OK
|
|
107
|
+
}
|
|
108
|
+
const relatedContent = relatedMatch[1];
|
|
109
|
+
const lines = relatedContent.split('\n');
|
|
110
|
+
for (const line of lines) {
|
|
111
|
+
const trimmedLine = line.trim();
|
|
112
|
+
// Skip empty lines and acceptable plain text
|
|
113
|
+
if (!trimmedLine || ACCEPTABLE_PLAIN_TEXT.test(trimmedLine)) {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
// Check if line should have a link but doesn't
|
|
117
|
+
if (SHOULD_BE_LINKED_PREFIX.test(trimmedLine) && !HAS_VALID_LINK.test(trimmedLine)) {
|
|
118
|
+
issues.push({
|
|
119
|
+
type: 'invalid_related_format',
|
|
120
|
+
message: `Related line should use [[wiki-link]] or [title](url): "${trimmedLine}"`,
|
|
121
|
+
entryPath: entry.path
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return issues;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Validate issue entries have trigger patterns
|
|
129
|
+
*/
|
|
130
|
+
function validateIssueTrigger(entry) {
|
|
131
|
+
const issues = [];
|
|
132
|
+
if (entry.category === 'issues' && !entry.frontmatter.trigger) {
|
|
133
|
+
issues.push({
|
|
134
|
+
type: 'missing_trigger',
|
|
135
|
+
message: 'Issue entries should have a trigger pattern for auto-lookup',
|
|
136
|
+
entryPath: entry.path
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return issues;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Validate content completeness
|
|
143
|
+
*/
|
|
144
|
+
function validateContentCompleteness(entry) {
|
|
145
|
+
const issues = [];
|
|
146
|
+
const content = entry.content;
|
|
147
|
+
// Check for TODO placeholders
|
|
148
|
+
if (/<!--\s*TODO/i.test(content)) {
|
|
149
|
+
issues.push({
|
|
150
|
+
type: 'has_todo',
|
|
151
|
+
message: 'Entry contains TODO placeholder that should be filled in',
|
|
152
|
+
entryPath: entry.path
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
// Check for empty sections (heading followed by another heading or end)
|
|
156
|
+
const emptySection = /# \w+[\s\n]*(?=# |\n*$)/;
|
|
157
|
+
if (emptySection.test(content)) {
|
|
158
|
+
issues.push({
|
|
159
|
+
type: 'empty_section',
|
|
160
|
+
message: 'Entry has empty section(s) that should be filled in',
|
|
161
|
+
entryPath: entry.path
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
// Check for sections with only whitespace
|
|
165
|
+
const sections = content.split(/(?=^# )/m);
|
|
166
|
+
for (const section of sections) {
|
|
167
|
+
const lines = section.split('\n');
|
|
168
|
+
if (lines.length > 0) {
|
|
169
|
+
const heading = lines[0];
|
|
170
|
+
const body = lines.slice(1).join('\n').trim();
|
|
171
|
+
if (heading.startsWith('# ') && body === '') {
|
|
172
|
+
issues.push({
|
|
173
|
+
type: 'empty_section',
|
|
174
|
+
message: `Section "${heading.replace('# ', '')}" is empty`,
|
|
175
|
+
entryPath: entry.path
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return issues;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Validate wiki links point to existing entries
|
|
184
|
+
*/
|
|
185
|
+
function validateWikiLinks(projectRoot, entry) {
|
|
186
|
+
const issues = [];
|
|
187
|
+
const wikiPath = (0, config_js_1.getWikiPath)(projectRoot);
|
|
188
|
+
// Find all wiki links
|
|
189
|
+
const matches = entry.content.matchAll(WIKI_LINK_PATTERN);
|
|
190
|
+
for (const match of matches) {
|
|
191
|
+
const linkPath = match[1];
|
|
192
|
+
// Skip C3 references (they're validated elsewhere)
|
|
193
|
+
if (linkPath.startsWith('c3-')) {
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
// Check if the linked entry exists
|
|
197
|
+
const targetPath = linkPath.endsWith('.md') ? linkPath : `${linkPath}.md`;
|
|
198
|
+
const fullPath = path.join(wikiPath, targetPath);
|
|
199
|
+
if (!fs.existsSync(fullPath)) {
|
|
200
|
+
issues.push({
|
|
201
|
+
type: 'broken_wiki_link',
|
|
202
|
+
message: `Wiki link [[${linkPath}]] points to non-existent entry`,
|
|
203
|
+
entryPath: entry.path
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return issues;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Validate confidence level - flag entries with low confidence
|
|
211
|
+
*/
|
|
212
|
+
function validateConfidenceLevel(entry) {
|
|
213
|
+
const issues = [];
|
|
214
|
+
if (entry.frontmatter.confidence < types_js_1.CONFIDENCE.THRESHOLD) {
|
|
215
|
+
issues.push({
|
|
216
|
+
type: 'low_confidence_convention',
|
|
217
|
+
message: `Entry has low confidence (${entry.frontmatter.confidence}) - needs validation`,
|
|
218
|
+
entryPath: entry.path
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
return issues;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Validate all entries in the wiki
|
|
225
|
+
*/
|
|
226
|
+
async function validateAllEntryQuality(projectRoot) {
|
|
227
|
+
const { listEntries } = await import('./entry.js');
|
|
228
|
+
const entries = await listEntries(projectRoot);
|
|
229
|
+
const allIssues = [];
|
|
230
|
+
for (const entry of entries) {
|
|
231
|
+
const issues = validateEntryQuality(projectRoot, entry.path);
|
|
232
|
+
allIssues.push(...issues);
|
|
233
|
+
}
|
|
234
|
+
return allIssues;
|
|
235
|
+
}
|
|
236
|
+
//# sourceMappingURL=quality.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quality.js","sourceRoot":"","sources":["../../src/quality.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { SearchResult } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Options for searching wiki entries.
|
|
4
|
+
*/
|
|
5
|
+
export interface SearchOptions {
|
|
6
|
+
query?: string;
|
|
7
|
+
tags?: string[];
|
|
8
|
+
category?: string;
|
|
9
|
+
status?: 'active' | 'flagged' | 'deprecated';
|
|
10
|
+
minConfidence?: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Searches wiki entries based on the provided options.
|
|
14
|
+
*
|
|
15
|
+
* @param projectRoot - The root directory of the project
|
|
16
|
+
* @param options - Search options including query, tags, category, status, minConfidence
|
|
17
|
+
* @returns Array of SearchResult objects sorted by score (highest first)
|
|
18
|
+
*/
|
|
19
|
+
export declare function searchWiki(projectRoot: string, options?: SearchOptions): Promise<SearchResult[]>;
|
|
20
|
+
/**
|
|
21
|
+
* Matches error text against trigger regex patterns in wiki entries.
|
|
22
|
+
*
|
|
23
|
+
* @param projectRoot - The root directory of the project
|
|
24
|
+
* @param errorText - The error text to match against trigger patterns
|
|
25
|
+
* @returns Array of SearchResult objects for entries with matching triggers, sorted by score
|
|
26
|
+
*/
|
|
27
|
+
export declare function matchTrigger(projectRoot: string, errorText: string): Promise<SearchResult[]>;
|
|
28
|
+
/**
|
|
29
|
+
* Gets the best (highest scoring) match from search results.
|
|
30
|
+
*
|
|
31
|
+
* @param results - Array of SearchResult objects
|
|
32
|
+
* @returns The highest scoring SearchResult, or null if no results
|
|
33
|
+
*/
|
|
34
|
+
export declare function getBestMatch(results: SearchResult[]): SearchResult | null;
|
|
35
|
+
//# sourceMappingURL=search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/search.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,YAAY,EAAE,MAAM,YAAY,CAAC;AAGrD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,YAAY,CAAC;IAC7C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAgID;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,YAAY,EAAE,CAAC,CAiEzB;AAkCD;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,YAAY,EAAE,CAAC,CA6CzB;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,YAAY,GAAG,IAAI,CASzE"}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.searchWiki = searchWiki;
|
|
4
|
+
exports.matchTrigger = matchTrigger;
|
|
5
|
+
exports.getBestMatch = getBestMatch;
|
|
6
|
+
const entry_js_1 = require("./entry.js");
|
|
7
|
+
/**
|
|
8
|
+
* Scoring constants for search relevance.
|
|
9
|
+
*/
|
|
10
|
+
const SCORE = {
|
|
11
|
+
TITLE_EXACT: 50,
|
|
12
|
+
TITLE_WORD: 15,
|
|
13
|
+
TAG_MATCH: 10,
|
|
14
|
+
CONTENT_EXACT: 20,
|
|
15
|
+
CONTENT_WORD: 5,
|
|
16
|
+
TRIGGER_MATCH: 100,
|
|
17
|
+
STUB_PENALTY: -10
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Calculates the confidence boost score for an entry.
|
|
21
|
+
* Scales 0-100 confidence to a reasonable boost (0-20 range).
|
|
22
|
+
*
|
|
23
|
+
* @param confidence - The entry's confidence level (0-100)
|
|
24
|
+
* @returns The confidence boost score
|
|
25
|
+
*/
|
|
26
|
+
function getConfidenceBoost(confidence) {
|
|
27
|
+
return Math.floor(confidence / 5);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Calculates the search score for an entry based on query matching.
|
|
31
|
+
*
|
|
32
|
+
* @param entry - The wiki entry to score
|
|
33
|
+
* @param query - The search query
|
|
34
|
+
* @returns Object with score and matched fields
|
|
35
|
+
*/
|
|
36
|
+
function calculateQueryScore(entry, query) {
|
|
37
|
+
let score = 0;
|
|
38
|
+
const matchedOn = [];
|
|
39
|
+
const queryLower = query.toLowerCase();
|
|
40
|
+
const queryWords = queryLower.split(/\s+/).filter(w => w.length > 0);
|
|
41
|
+
// Title matching
|
|
42
|
+
const titleLower = entry.frontmatter.title.toLowerCase();
|
|
43
|
+
if (titleLower === queryLower) {
|
|
44
|
+
score += SCORE.TITLE_EXACT;
|
|
45
|
+
matchedOn.push('title');
|
|
46
|
+
}
|
|
47
|
+
else if (titleLower.includes(queryLower)) {
|
|
48
|
+
score += SCORE.TITLE_EXACT;
|
|
49
|
+
matchedOn.push('title');
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
let titleWordMatches = 0;
|
|
53
|
+
for (const word of queryWords) {
|
|
54
|
+
if (titleLower.includes(word)) {
|
|
55
|
+
titleWordMatches++;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (titleWordMatches > 0) {
|
|
59
|
+
score += titleWordMatches * SCORE.TITLE_WORD;
|
|
60
|
+
matchedOn.push('title');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Content matching
|
|
64
|
+
const contentLower = entry.content.toLowerCase();
|
|
65
|
+
if (contentLower.includes(queryLower)) {
|
|
66
|
+
score += SCORE.CONTENT_EXACT;
|
|
67
|
+
if (!matchedOn.includes('content')) {
|
|
68
|
+
matchedOn.push('content');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
let contentWordMatches = 0;
|
|
73
|
+
for (const word of queryWords) {
|
|
74
|
+
if (contentLower.includes(word)) {
|
|
75
|
+
contentWordMatches++;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (contentWordMatches > 0) {
|
|
79
|
+
score += contentWordMatches * SCORE.CONTENT_WORD;
|
|
80
|
+
if (!matchedOn.includes('content')) {
|
|
81
|
+
matchedOn.push('content');
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return { score, matchedOn };
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Calculates the tag match score for an entry.
|
|
89
|
+
*
|
|
90
|
+
* @param entry - The wiki entry to score
|
|
91
|
+
* @param tags - The tags to match against
|
|
92
|
+
* @returns Object with score and whether tags were matched
|
|
93
|
+
*/
|
|
94
|
+
function calculateTagScore(entry, tags) {
|
|
95
|
+
let matchCount = 0;
|
|
96
|
+
const entryTags = entry.frontmatter.tags.map(t => t.toLowerCase());
|
|
97
|
+
for (const tag of tags) {
|
|
98
|
+
if (entryTags.includes(tag.toLowerCase())) {
|
|
99
|
+
matchCount++;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
score: matchCount * SCORE.TAG_MATCH,
|
|
104
|
+
matched: matchCount > 0
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Checks if an entry meets the minimum confidence threshold.
|
|
109
|
+
*
|
|
110
|
+
* @param entry - The wiki entry to check
|
|
111
|
+
* @param minConfidence - The minimum confidence level required (0-100)
|
|
112
|
+
* @returns True if the entry meets or exceeds the threshold
|
|
113
|
+
*/
|
|
114
|
+
function meetsConfidenceThreshold(entry, minConfidence) {
|
|
115
|
+
return entry.frontmatter.confidence >= minConfidence;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Searches wiki entries based on the provided options.
|
|
119
|
+
*
|
|
120
|
+
* @param projectRoot - The root directory of the project
|
|
121
|
+
* @param options - Search options including query, tags, category, status, minConfidence
|
|
122
|
+
* @returns Array of SearchResult objects sorted by score (highest first)
|
|
123
|
+
*/
|
|
124
|
+
async function searchWiki(projectRoot, options = {}) {
|
|
125
|
+
const { query, tags, category, status, minConfidence } = options;
|
|
126
|
+
// Get all entries, optionally filtered by category and status
|
|
127
|
+
const entries = await (0, entry_js_1.listEntries)(projectRoot, {
|
|
128
|
+
category,
|
|
129
|
+
status
|
|
130
|
+
});
|
|
131
|
+
const results = [];
|
|
132
|
+
for (const entry of entries) {
|
|
133
|
+
// Check confidence threshold
|
|
134
|
+
if (minConfidence && !meetsConfidenceThreshold(entry, minConfidence)) {
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
let score = 0;
|
|
138
|
+
const matchedOn = [];
|
|
139
|
+
// Calculate query score if query is provided
|
|
140
|
+
if (query) {
|
|
141
|
+
const queryResult = calculateQueryScore(entry, query);
|
|
142
|
+
score += queryResult.score;
|
|
143
|
+
matchedOn.push(...queryResult.matchedOn);
|
|
144
|
+
}
|
|
145
|
+
// Calculate tag score if tags are provided
|
|
146
|
+
if (tags && tags.length > 0) {
|
|
147
|
+
const tagResult = calculateTagScore(entry, tags);
|
|
148
|
+
score += tagResult.score;
|
|
149
|
+
if (tagResult.matched) {
|
|
150
|
+
matchedOn.push('tags');
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Only include results that match something (unless no query/tags specified)
|
|
154
|
+
if (score === 0 && (query || (tags && tags.length > 0))) {
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
// Add confidence boost
|
|
158
|
+
score += getConfidenceBoost(entry.frontmatter.confidence);
|
|
159
|
+
// Apply stub penalty
|
|
160
|
+
if (entry.frontmatter.stub) {
|
|
161
|
+
score += SCORE.STUB_PENALTY;
|
|
162
|
+
}
|
|
163
|
+
// If no query or tags, include all entries with base score from confidence
|
|
164
|
+
if (!query && (!tags || tags.length === 0)) {
|
|
165
|
+
// No specific match criteria, so matchedOn stays empty
|
|
166
|
+
}
|
|
167
|
+
results.push({
|
|
168
|
+
entry,
|
|
169
|
+
score,
|
|
170
|
+
matchedOn
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
// Sort by score descending
|
|
174
|
+
results.sort((a, b) => b.score - a.score);
|
|
175
|
+
return results;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Validate a regex pattern for safety (prevent ReDoS attacks).
|
|
179
|
+
*
|
|
180
|
+
* Checks for common catastrophic backtracking patterns that could cause
|
|
181
|
+
* Regular Expression Denial of Service (ReDoS) attacks.
|
|
182
|
+
*
|
|
183
|
+
* @param pattern - The regex pattern to validate
|
|
184
|
+
* @returns Validation result with valid flag and optional reason
|
|
185
|
+
*/
|
|
186
|
+
function validateRegexPattern(pattern) {
|
|
187
|
+
// Check for catastrophic backtracking patterns
|
|
188
|
+
const dangerousPatterns = [
|
|
189
|
+
/\(.+\)\+\+/, // (x+)+ - nested quantifiers
|
|
190
|
+
/\(.+\)\*\+/, // (x*)+ - nested quantifiers
|
|
191
|
+
/\(.+\+\)\+/, // (x+)+ - nested quantifiers
|
|
192
|
+
/\(.+\)\{\d+,\}/ // (x){n,} - unbounded quantifiers
|
|
193
|
+
];
|
|
194
|
+
for (const dangerous of dangerousPatterns) {
|
|
195
|
+
if (dangerous.test(pattern)) {
|
|
196
|
+
return { valid: false, reason: 'Potential ReDoS vulnerability - nested quantifiers detected' };
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
// Check pattern length (extremely long patterns can be problematic)
|
|
200
|
+
if (pattern.length > 500) {
|
|
201
|
+
return { valid: false, reason: 'Pattern exceeds maximum length (500 characters)' };
|
|
202
|
+
}
|
|
203
|
+
return { valid: true };
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Matches error text against trigger regex patterns in wiki entries.
|
|
207
|
+
*
|
|
208
|
+
* @param projectRoot - The root directory of the project
|
|
209
|
+
* @param errorText - The error text to match against trigger patterns
|
|
210
|
+
* @returns Array of SearchResult objects for entries with matching triggers, sorted by score
|
|
211
|
+
*/
|
|
212
|
+
async function matchTrigger(projectRoot, errorText) {
|
|
213
|
+
// Get all active entries
|
|
214
|
+
const entries = await (0, entry_js_1.listEntries)(projectRoot, { status: 'active' });
|
|
215
|
+
const results = [];
|
|
216
|
+
for (const entry of entries) {
|
|
217
|
+
// Skip entries without triggers
|
|
218
|
+
if (!entry.frontmatter.trigger) {
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
try {
|
|
222
|
+
// VALIDATE PATTERN BEFORE USING
|
|
223
|
+
const validation = validateRegexPattern(entry.frontmatter.trigger);
|
|
224
|
+
if (!validation.valid) {
|
|
225
|
+
console.warn(`[Solvdex] Skipping unsafe trigger in ${entry.path}: ${validation.reason}`);
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
// Pattern is safe - proceed with matching
|
|
229
|
+
const regex = new RegExp(entry.frontmatter.trigger, 'i');
|
|
230
|
+
const matches = regex.test(errorText);
|
|
231
|
+
if (matches) {
|
|
232
|
+
let score = SCORE.TRIGGER_MATCH;
|
|
233
|
+
score += getConfidenceBoost(entry.frontmatter.confidence);
|
|
234
|
+
if (entry.frontmatter.stub) {
|
|
235
|
+
score += SCORE.STUB_PENALTY;
|
|
236
|
+
}
|
|
237
|
+
results.push({ entry, score, matchedOn: ['trigger'] });
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
catch (error) {
|
|
241
|
+
// Handle invalid regex patterns gracefully
|
|
242
|
+
console.warn(`[Solvdex] Invalid trigger pattern in ${entry.path}: ${error instanceof Error ? error.message : String(error)}`);
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
// Sort by score descending
|
|
247
|
+
results.sort((a, b) => b.score - a.score);
|
|
248
|
+
return results;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Gets the best (highest scoring) match from search results.
|
|
252
|
+
*
|
|
253
|
+
* @param results - Array of SearchResult objects
|
|
254
|
+
* @returns The highest scoring SearchResult, or null if no results
|
|
255
|
+
*/
|
|
256
|
+
function getBestMatch(results) {
|
|
257
|
+
if (results.length === 0) {
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
// Results should already be sorted, but ensure we get the highest score
|
|
261
|
+
return results.reduce((best, current) => current.score > best.score ? current : best);
|
|
262
|
+
}
|
|
263
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/search.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { WikiEntry } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Calculates similarity between two strings using Levenshtein distance.
|
|
4
|
+
* Returns a score between 0 (completely different) and 1 (identical).
|
|
5
|
+
*/
|
|
6
|
+
export declare function stringSimilarity(a: string, b: string): number;
|
|
7
|
+
/**
|
|
8
|
+
* Calculates tag overlap between two tag arrays.
|
|
9
|
+
* Returns a score between 0 (no overlap) and 1 (identical).
|
|
10
|
+
*/
|
|
11
|
+
export declare function tagSimilarity(tagsA: string[], tagsB: string[]): number;
|
|
12
|
+
/**
|
|
13
|
+
* Result of a duplicate check.
|
|
14
|
+
*/
|
|
15
|
+
export interface DuplicateCheckResult {
|
|
16
|
+
isDuplicate: boolean;
|
|
17
|
+
similarity: number;
|
|
18
|
+
matchedEntry?: WikiEntry;
|
|
19
|
+
reason?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Checks if a new entry might be a duplicate of existing entries.
|
|
23
|
+
*
|
|
24
|
+
* @param title - The title of the new entry
|
|
25
|
+
* @param tags - The tags of the new entry
|
|
26
|
+
* @param category - The category of the new entry
|
|
27
|
+
* @param existingEntries - List of existing entries to check against
|
|
28
|
+
* @param threshold - Similarity threshold (default 0.7)
|
|
29
|
+
* @returns DuplicateCheckResult with matched entry if found
|
|
30
|
+
*/
|
|
31
|
+
export declare function checkForDuplicate(title: string, tags: string[], category: string, existingEntries: WikiEntry[], threshold?: number): DuplicateCheckResult;
|
|
32
|
+
/**
|
|
33
|
+
* Finds related entries based on tag and title similarity.
|
|
34
|
+
*
|
|
35
|
+
* @param entry - The entry to find relations for
|
|
36
|
+
* @param allEntries - All wiki entries
|
|
37
|
+
* @param maxResults - Maximum number of related entries to return
|
|
38
|
+
* @param threshold - Minimum similarity threshold
|
|
39
|
+
* @returns Array of related entry paths sorted by similarity
|
|
40
|
+
*/
|
|
41
|
+
export declare function findRelatedEntries(entry: WikiEntry, allEntries: WikiEntry[], maxResults?: number, threshold?: number): string[];
|
|
42
|
+
//# sourceMappingURL=similarity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"similarity.d.ts","sourceRoot":"","sources":["../../src/similarity.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAe7D;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAWtE;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EAAE,EACd,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,SAAS,EAAE,EAC5B,SAAS,GAAE,MAAY,GACtB,oBAAoB,CAmCtB;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,EAChB,UAAU,EAAE,SAAS,EAAE,EACvB,UAAU,GAAE,MAAU,EACtB,SAAS,GAAE,MAAY,GACtB,MAAM,EAAE,CAyBV"}
|