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.
Files changed (113) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +274 -0
  3. package/dist/hooks/error-lookup.d.ts +4 -0
  4. package/dist/hooks/error-lookup.d.ts.map +1 -0
  5. package/dist/hooks/error-lookup.js +92 -0
  6. package/dist/hooks/error-lookup.js.map +1 -0
  7. package/dist/hooks/post-task.d.ts +15 -0
  8. package/dist/hooks/post-task.d.ts.map +1 -0
  9. package/dist/hooks/post-task.js +246 -0
  10. package/dist/hooks/post-task.js.map +1 -0
  11. package/dist/hooks/prompt-enrich.d.ts +16 -0
  12. package/dist/hooks/prompt-enrich.d.ts.map +1 -0
  13. package/dist/hooks/prompt-enrich.js +141 -0
  14. package/dist/hooks/prompt-enrich.js.map +1 -0
  15. package/dist/hooks/session-start-cli.d.ts +3 -0
  16. package/dist/hooks/session-start-cli.d.ts.map +1 -0
  17. package/dist/hooks/session-start-cli.js +81 -0
  18. package/dist/hooks/session-start-cli.js.map +1 -0
  19. package/dist/hooks/session-start.d.ts +4 -0
  20. package/dist/hooks/session-start.d.ts.map +1 -0
  21. package/dist/hooks/session-start.js +134 -0
  22. package/dist/hooks/session-start.js.map +1 -0
  23. package/dist/src/audit.d.ts +63 -0
  24. package/dist/src/audit.d.ts.map +1 -0
  25. package/dist/src/audit.js +229 -0
  26. package/dist/src/audit.js.map +1 -0
  27. package/dist/src/cache.d.ts +54 -0
  28. package/dist/src/cache.d.ts.map +1 -0
  29. package/dist/src/cache.js +167 -0
  30. package/dist/src/cache.js.map +1 -0
  31. package/dist/src/config.d.ts +52 -0
  32. package/dist/src/config.d.ts.map +1 -0
  33. package/dist/src/config.js +175 -0
  34. package/dist/src/config.js.map +1 -0
  35. package/dist/src/entry.d.ts +154 -0
  36. package/dist/src/entry.d.ts.map +1 -0
  37. package/dist/src/entry.js +469 -0
  38. package/dist/src/entry.js.map +1 -0
  39. package/dist/src/errors.d.ts +65 -0
  40. package/dist/src/errors.d.ts.map +1 -0
  41. package/dist/src/errors.js +121 -0
  42. package/dist/src/errors.js.map +1 -0
  43. package/dist/src/frontmatter.d.ts +28 -0
  44. package/dist/src/frontmatter.d.ts.map +1 -0
  45. package/dist/src/frontmatter.js +111 -0
  46. package/dist/src/frontmatter.js.map +1 -0
  47. package/dist/src/index.d.ts +35 -0
  48. package/dist/src/index.d.ts.map +1 -0
  49. package/dist/src/index.js +188 -0
  50. package/dist/src/index.js.map +1 -0
  51. package/dist/src/maturity.d.ts +31 -0
  52. package/dist/src/maturity.d.ts.map +1 -0
  53. package/dist/src/maturity.js +96 -0
  54. package/dist/src/maturity.js.map +1 -0
  55. package/dist/src/quality.d.ts +23 -0
  56. package/dist/src/quality.d.ts.map +1 -0
  57. package/dist/src/quality.js +236 -0
  58. package/dist/src/quality.js.map +1 -0
  59. package/dist/src/search.d.ts +35 -0
  60. package/dist/src/search.d.ts.map +1 -0
  61. package/dist/src/search.js +263 -0
  62. package/dist/src/search.js.map +1 -0
  63. package/dist/src/similarity.d.ts +42 -0
  64. package/dist/src/similarity.d.ts.map +1 -0
  65. package/dist/src/similarity.js +111 -0
  66. package/dist/src/similarity.js.map +1 -0
  67. package/dist/src/stats.d.ts +56 -0
  68. package/dist/src/stats.d.ts.map +1 -0
  69. package/dist/src/stats.js +198 -0
  70. package/dist/src/stats.js.map +1 -0
  71. package/dist/src/templates.d.ts +63 -0
  72. package/dist/src/templates.d.ts.map +1 -0
  73. package/dist/src/templates.js +347 -0
  74. package/dist/src/templates.js.map +1 -0
  75. package/dist/src/transfer.d.ts +92 -0
  76. package/dist/src/transfer.d.ts.map +1 -0
  77. package/dist/src/transfer.js +215 -0
  78. package/dist/src/transfer.js.map +1 -0
  79. package/dist/src/types.d.ts +270 -0
  80. package/dist/src/types.d.ts.map +1 -0
  81. package/dist/src/types.js +153 -0
  82. package/dist/src/types.js.map +1 -0
  83. package/dist/src/validate.d.ts +90 -0
  84. package/dist/src/validate.d.ts.map +1 -0
  85. package/dist/src/validate.js +295 -0
  86. package/dist/src/validate.js.map +1 -0
  87. package/hooks/error-lookup.ts +110 -0
  88. package/hooks/hooks.json +49 -0
  89. package/hooks/post-task.ts +309 -0
  90. package/hooks/prompt-enrich.ts +162 -0
  91. package/hooks/session-start-cli.ts +96 -0
  92. package/hooks/session-start.ts +159 -0
  93. package/package.json +40 -0
  94. package/scripts/error-lookup.py +64 -0
  95. package/scripts/post-task.py +60 -0
  96. package/scripts/prompt-enrich.py +64 -0
  97. package/scripts/session-start.py +64 -0
  98. package/skills/wiki/SKILL.md +61 -0
  99. package/skills/wiki-add/SKILL.md +90 -0
  100. package/skills/wiki-browse/SKILL.md +108 -0
  101. package/skills/wiki-capture/SKILL.md +265 -0
  102. package/skills/wiki-explorer/SKILL.md +223 -0
  103. package/skills/wiki-export/SKILL.md +101 -0
  104. package/skills/wiki-fix/SKILL.md +86 -0
  105. package/skills/wiki-flag/SKILL.md +47 -0
  106. package/skills/wiki-import/SKILL.md +128 -0
  107. package/skills/wiki-init/SKILL.md +72 -0
  108. package/skills/wiki-scan/SKILL.md +98 -0
  109. package/skills/wiki-search/SKILL.md +86 -0
  110. package/skills/wiki-stats/SKILL.md +129 -0
  111. package/skills/wiki-status/SKILL.md +78 -0
  112. package/skills/wiki-test-trigger/SKILL.md +173 -0
  113. 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"}